All articles
6 min read

Generative Art Under Constraints: What Happens When Every World Must Be Different

generative artcreative codingshadersconstraints

Every micro-world on Lumitree uses a different visual technique. Not just a different color palette or layout — a fundamentally different approach to rendering. One world might use Canvas 2D particle physics. The next might be a WebGL fragment shader doing SDF raymarching. The one after that might be an SVG-based L-system. This rule exists because without it, everything would start looking the same.

The rules

Each generated micro-world must follow these constraints:

  • Maximum 50KB total file size
  • Everything inline — no external dependencies, no CDN imports
  • Must be visually rich from the first frame (no loading states)
  • Uses one of: Canvas 2D, WebGL fragment shaders, SVG, CSS art, or Web Audio API
  • Must use a different technique than recently created worlds
  • requestAnimationFrame only, object pooling for performance

These constraints sound limiting. They are. That's the point.

What happens under constraints

When you can't import Three.js, you learn how to write a raymarcher from scratch in 30 lines of GLSL. When you can't use p5.js, you implement Perlin noise yourself. When you're limited to 50KB, every byte matters — and the code becomes surprisingly elegant.

Some examples of what the constraints produce:

Flow fields

Classic generative art technique: a grid of angle values (usually from Perlin noise) that guide particles across the screen. In under 50KB, you can build a beautiful flow field with thousands of particles, color gradients that shift over time, and smooth trails that create organic patterns.

SDF raymarching

Signed distance functions in a fragment shader. The entire 3D scene is defined mathematically — no geometry, no meshes, just math. A raymarcher steps through the scene, querying the distance function at each point to find surfaces. Surprisingly complex scenes (smooth-blended shapes, reflections, soft shadows) fit in very little code.

L-systems

Lindenmayer systems — recursive string rewriting rules that produce fractal-like structures. Start with an axiom, apply production rules, interpret the result as drawing commands. Trees, ferns, corals, branching patterns — all from a handful of rules. Perfect for the 50KB constraint because the rules are tiny but the output is rich.

Cellular automata

Grid-based systems where each cell's state depends on its neighbors. Conway's Game of Life is the most famous, but the color-mapped variants used in Lumitree worlds produce gorgeous evolving patterns. The entire simulation logic fits in a few dozen lines.

Particle systems with spring physics

Particles connected by springs, creating cloth-like simulations, jellyfish tentacles, or bouncing networks. The physics is simple (Hooke's law), but the visual results are complex and organic.

The variety problem

Without the "different technique" rule, AI would default to the same approach every time. It knows Canvas 2D best, so everything would be Canvas 2D particle systems. Beautiful, but monotonous. The rule forces exploration of the full creative coding spectrum.

This mirrors a real creative coding principle: constraints breed creativity. The Demoscene community has known this for decades — when you're limited to 4KB or 64KB, you find solutions that would never occur to you with unlimited resources.

What we've learned

  1. Small files can be visually rich. 50KB is more than enough for a stunning interactive experience when every byte is intentional.
  2. Variety requires enforcement. Without rules, AI defaults to what it knows best. The technique rotation rule is essential.
  3. Inline code forces elegance. No build tools, no bundlers, no tree-shaking. Just raw HTML, CSS, and JavaScript. The code has to be clean because there's nowhere to hide complexity.
  4. Fragment shaders are underrated for web art. A single <canvas> element with a WebGL context and a fragment shader can produce 3D scenes, organic patterns, and animated landscapes in remarkably little code.

Want to see what these techniques look like in practice? Visit the explore page and browse the micro-worlds. Each one is different. That's the whole point.