Ben Crowder / Blog

Blog: #generative-art

16 posts / tag feed / about the blog / archive / tags

Thoughts on a little language for generative art

I’ve been thinking about resurrecting the Marks idea, partly because I’d like to use it for my art and partly because I want to have my 12in23 project (for at least some of the languages) be a simplified Marks parser. (And a little bit because my dad’s name was Mark.)

As a refresher: Marks is going to be a DSL for generative art. In its newest incarnation, it could also be used more generally for composition, but generative art is the focus.

The current plan is to have a number of types of top-level blocks: layers, brushes, path profiles, color definitions, functions, and properties, and probably a few others I haven’t fully thought through yet. A rough draft, which still needs a lot of refining, and which doesn’t yet include a lot of the ideas I’ll include in the notes below:

size 7500x7500
background white
color black #000
color red hsl(0 50% 50%)
seed 24601

brush circles {
  random.xy0(num: 50).each {
    circle(x, y, r: random(0.1), fill: black)
  }
}

pathprofile mytaper {
  0.0
  1.0
  0.8
  0.6
  0.4
  0.2
  0.1
}

layer.svg some shapes {
  subtract {
    circle(x: $width/2, y: $height/2, r: $height/2*.8, fill: red)
    rectangle(x: random.x, y: random.y, w: random($width - $x), h: 50, fill: red.lighten(0.2))
  }
  mask {
    line(x1: random.x, y1: random.y, x2: random.x, y2: random.y, strokeWidth: random(5, 20), brush: circles)
  }
  blend soft-light
}

layer.raster noise {
  xy.each {
    red.jitter(hue: 0.2)
  }
  blend soft-light
  opacity 0.2
}

Notes, acknowledging that this is mostly brainstorming and not a final, consolidated list:

  • Layers are the fundamental block, in that nothing gets output if there aren’t any layers.
  • Layers can be SVG (which then gets rendered to raster once the layer is done) or raster.
  • The background property adds a bottom layer filled with the color (leaving it out allows for transparency).
  • There’s a debug flag that exports each layer to a file individually (minus blending mode and opacity), so you can see what happened.
  • SVG layer commands include CSG booleans.
  • The “some shapes” and “noise” bits on the layers are layer names.
  • This isn’t shown here, but layers can be different sizes and can be positioned.
  • I’m leaning towards having Marks be as purely declarative as possible, though I suspect I’ll still need some imperative support (a random walk, for example, would be more difficult to do declaratively) (though I’m still going to see if I can make it work somehow). I’m thinking the top-level function blocks would be where imperative code happens, maybe.
  • random.x would get a random X coordinate within the canvas.
  • Layers can be masked, and within the mask there can be any rendering commands (still working on nomenclature here) that are available for the current layer type (which mostly means raster commands aren’t available on SVG layers except in places where an image is expected).
  • For SVG layers, the layer blending mode and opacity only apply after rasterization.
  • The xy variable returns an array of all the coordinates of the rasterized canvas.
  • Numbers and colors have a jitter method that allows for jittering within a set range .
  • The brush block allows using rendering commands to create a brush that can then be used to stroke paths or fill shapes.
  • The pathprofile block needs (a lot of) work, but the idea is to have some way to describe the profile of a path, so you can have paths with the width varying along the stroke. Ideally, this would support both relative percentage-based profiles (leading to different effects for short paths vs. long paths) and absolute profiles (so the effect is the same for any length of path that matches the values) and possibly a mix of both (absolute for the first 50px and then relatively fade out for the rest, however long that is, for example).
  • Good support for path navigation and manipulation. Be able to easily work with points every 20px along the path, for example, or every control point, or fifty random points along the path. Also be able to get normals and tangents for any points along the path.
  • Importing images from disk will of course be included.
  • This is a lower priority for me: animation support. There would be access to a frame variable. Each frame could use the same global random seed (with each layer getting seeded individually to try to preserve behavior) or could use a different seed.
  • This is moving more into pie in the sky territory, but I’ve become enamored of the idea of having Marks support 3D, including programmatic generation of the canvas texture in 3D and being able to layer paint (and then scrape some off to see layers underneath) and get impasto effects and all that. This would also support moving the camera around and creating/modifying 3D models to some extent. I like this a lot and I think it fits conceptually, but it may be a bit Too Much. (Part of me thinks it would make far more sense to do this separately as something in Blender, where you get so many 3D features for free.)
  • Marks files can import other Marks files.
  • Custom fill functions can be written, where you provide some code that then generates the content for whatever polygon is filled (clipped to the polygon boundary).
  • Shape packing helpers are planned, too, so you can fill a polygon with circles or any other shape. I’d like this to be programmatic, so that each shape could be different.
  • Layer filters will be included, too — blur, threshold, erosion/dilation, etc. — and these will apply to masks as well.
  • Colors can be defined in the usual formats (HSL, RGB, hex) and also LCH, and they can be modified dynamically (lightened, darkened, etc.).

There will undoubtedly be simplification along the way, since this is…a lot. The initial core implementation would (in my mind) be layers (both SVG and render, with a basic set of commands, excluding masks but including blending modes and opacity), colors, the random generator, debug mode, and exporting a final image. That’s enough base functionality for it to be usable.

I’m going to be working on a BNF grammar for this soon, once I get the syntax finalized enough that writing a parser is feasible.


Reply via email or office hours

New artwork: Behold My Beloved Son. Basically a Christ Visits the Nephites but with a different title, one actually from the scriptures.

I painted this in Procreate, and goodness, it messed up my back a bit. (Which is unfortunate because I really like the woodcut-style look on the white triangle. I may still do occasional pieces this way, when there’s not a billion little circles like I have here.) It’s frustrating when my spondylolisthesis keeps me from making art the way I want to. At some point I’ll probably try to figure out a way to do this style with code. (Speaking of which, I generated the circles here with a little bit of JavaScript. It was fun doing a piece that’s a little more three-dimensional.)

Behold My Beloved Son

Reply via email or office hours

Projects — Prints 2.8

New story: Unlocked. About fifteen pages long, fantasy.

Also, some new generative art. For these, the fundamental idea was to lay out horizontal bands, where each band was composed of rectangles of random widths, rotations, and color variations on a base hue for the band. I wrote some JavaScript to generative the patterns as SVGs and rendered them to 4500px-wide PNGs via headless Inkscape. I painted textures on them in Procreate on my iPad, mostly using MattyB’s canvas brushes. I upscaled them 2x via Real-ESRGAN on the command line, added noise in Affinity Photo (12% monochrome), and scaled them down to 7500px wide. Real-ESRGAN was a brand-new addition to my workflow but it turned out quite well, I think.

Pattern 005
Pattern 005. Bricks overgrown by vegetation, loosely.
Pattern 006
Pattern 006. A slightly stained glass kind of feel.
Pattern 007
Pattern 007. Going for a less saturated look here.
Pattern 008
Pattern 008. My favorite, even with the imperfections at the bottom.

Reply via email or office hours

Lately I’ve been thinking about small VMs, thanks to Uxn. Long-term sustainability and portability interests me, and doing something similar (a small VM for the tools I’ve written) is intriguing.

At the same time, I’m not sure a VM would be a good enough fit for my tools (particularly the web frontends), so if I do anything in this space, it’ll probably be either just for fun or a more-specific VM (focusing on something like generative art).


Reply via email or office hours

Links #48

George Francis on Voronoi tessellations in generative art. Enjoyed this. Seems like a decent alternative to circle packing at least some of the time.

Elise Hein on her experience with stackless dev. The minimalist in me is pretty much always interested in this angle on web development.

WebComponents.dev on all the ways to make a web component. Lots of charts. Prism and Svelte look intriguing.

Josh Comeau on designing beautiful shadows in CSS. The techniques definitely make a difference.

Fleta Selmani’s Escheresque impossible type (via Kottke). Love this.


Reply via email or office hours

Links #47

Stephanie Eckles on practical uses of CSS math functions. Some great examples here.

Matt DesLauriers on pen plotter art and algorithms. I keep thinking about buying or building a plotter. Someday…

Paul Foster’s HTML tags memory test. Got 70.

Sakira Ventura’s world map of female composers. Love this.

Eric Bailey’s introduction to macOS Voice Control. Both this and Head Pointer are really quite impressive.


Reply via email or office hours

New artwork: The Gathering of Israel. For a few months I’d been thinking about how to symbolically represent this idea and eventually settled on a vector field (with artistic license rashly taken) as the best fit, at least for this version. The textures all generated in SVG via a small Python script.


Reply via email or office hours

Links #43

Tyler Hobbs on color arrangement in generative art. I haven’t done much generative art lately (and don’t know how much I’ll end up actually doing in the future), but I like Tyler’s work and this is a good writeup.

Phil Plait on David Novick’s colored spheres optical illusion. Wow.

Shawn Wang on quality vs. consistency. Which is something I feel I could do much, much better at here on this site.

Matthias Ott about personal websites. A good thing to remember.

Jason Kottke linking to a map of the world’s lighthouses. Look at Norway!


Reply via email or office hours

Links #41

Rob Weychert’s Plus Equals, a new zine about algorithmic art. The first issue was good, looking forward to future installments.

Riccardo Scalco’s Textures.js, SVG patterns for d3.js. Yum. I don’t even use d3 (at least not right now), but I’m tempted to do something with it just so I can use these.

Jason Kottke on the invention of a new pasta shape. Max sauceability as a concept will stick with me for a long time, I think.

Rytis Bieliunas on some of the darker corners of Go (the programming language). I’m writing a lot of Go at work now and this was helpful.

Austin Kleon on blogging as a forgiving medium. The idea of continually editing and refining posts after publishing them intrigues me. I fix typos if I find them, but that’s about it at the moment.


Reply via email or office hours

Links #35


Reply via email or office hours