Patterns

An experiment in natural language parsing and play.

Play with the tool!

Katherine Yang

Jan 9, 2026

Tech is enamoured with natural language these days, but not in a way that sparks my imagination and excitement. I don’t want to look into the cold, blinking mouth of a chatbot and try to exercise my artistic creativity through a simulated conversation.

Instead, I’ve always been interested in using code to celebrate what’s already rich and beautiful to me about language — the structures inherent in the technology, the miracle of understanding each other’s complicated sentences and fragments, how full of meaning and ritual the whole dance can be.


This pattern language interprets a limited set of natural language instructions to paint a graphical picture. Write the word “triangle” and out pops a triangle on the screen. Call it a “red triangle” and the picture adjusts accordingly.

In contrast to a typical graphics programming library, the tool is heavy on constraints. You can only use six colors and a handful of shapes. But when we’ve stripped language down to this set of parameters and we start to play with them, interesting questions start to puddle out, like: what do color words mean?

Colors

In the first iteration, any of the approximately 150 CSS named colors were recognised, so you could have a “rebeccapurple square” or a “palegoldenrod triangle". Colors written in the text box were plugged straight into ctx.fillStyle.

A version of the UI with a big canvas and big text box and very bright colors.
An earlier iteration of the color system and the UI. I’m really glad I was able to come back and redesign the whole thing!

I tend to have a soft spot for playing with the raw materials of the web, so I was happy playing with this for a while. But with some feedback from my coworkers, I decided to try limiting the color palette and was really delighted by the results.

The current version only allows for six named colors: red, orange, yellow, green, blue, and purple — the primary and secondary colors on the color wheel. This gave me an opportunity to decide what exactly “red” or “blue” should mean.

Instead of using hard and raw values like #ff0000 for “red”, maybe “red” could be a variable that had a handful of possible values. It could mean #ea3546 or #e58383 or #c44536, which are the values of “red” from the palettes currently in the tool.

Shapes and colors in a brighter palette Shapes and colors in a light pastel palette Shapes and colors in a darker, more muted palette
The same color keywords and composition in three different palettes.

Viewing the same shapes and colors through different palettes suddenly casts a completely different mood and feel over the picture.

Layout

The layout engine is currently very straightforward. It lays every shape or group of shapes in a vertical line from top to bottom, reflecting the order of the text. (A fun side effect of this is that while the text primarily serves as the code or instruction for the graphic, it also happens to function as the corresponding alt text!)

Adding a count will generate copies of the shape and arrange them in a circle, applying rotation.

A vertical layout of groups of circles, squares, and triangles

Specifying “along edge” will create a border with that color and shape.

A yellow background with orange circles along the edge and three purple diamonds in the center.

More recently, I began loosening the reins to play with a tiny bit of randomness: use the keyword “anywhere” to take a shape out of the vertical layout and place it randomly on the canvas. It's still so simple, but the effect kind of thrilled me. Having stared at the strict vertical arrangement of one to three shape patterns for so long, just this tiny bit of randomness and juxtaposition felt like a reward.

A mustard yellow background with a teal blue square in the center and a red triangle juxtaposed on top A blue background with three red diamonds in the center and a yellow circle juxtaposed on top

This layout system would be pretty adaptable to a landscape orientation — just lay the shapes out in a horizontal line instead of a vertical one.

I think the next challenge here would be to figure out if there’s a systematic way to allow for more flexibility in composition. I have plans for a little bit of variation in size (“small” and “big” keywords), but how could you get different layouts and combinations of layouts? Could you arrange shapes diagonally, in a repeating pattern background, overlay patterns on top of each other, assemble complex column and row layouts?

The hard part is always pulling back from seeing the possibilities and deciding what the useful boundaries of the system should be.

Speaking of the system…

How does it work?

In my first iteration, I used some pretty rough code to “parse” the text, line by line, identifying recognisable words and using those to build the shapes on the canvas.

After I hit a wall with that, I went back to write a proper parser, using what I had learned when writing Coem but trying to follow a different tutorial this time. This isn’t a traditional programming language, but materials like these, combined with some rusty knowledge from syntactic linguistics classes, help me understand how programming languages work and how I can use that to build something useful for my purposes.

The parser first runs through the text to build a stream of tokens. Then, it creates meaningful groups out of those tokens, building an object for each pattern, modelled after noun phrases in language.

The text “a slowly rotating red square” becomes:

[
  {
    "type": "det",
    "value": "a"
  },
  {
    "type": "vp",
    "vp": {
      "adv": "slowly",
      "verb": "rotating"
    }
  },
  {
    "type": "adj",
    "value": "red"
  },
  {
    "type": "noun",
    "value": "square"
  }
]

That’s the system for now! There’s so much that I feel like I could play with, but I’m excited to put it down and share what I have.

A list of possible things I have written down to think about: