The Generator

Artificial Noodles ·

Inspired by Crystallographic point group on Wikipedia

Built with Three.js · InstancedMesh · Custom ShaderMaterial · Additive Blending

Techniques Group Closure Computation · Hermann-Mauguin Notation · 2D Symmetry Matrices · Critically-Damped Spring Physics · Instanced Trail Rendering

Direction Constraint creates beauty. Thirty-two symmetry patterns govern all crystalline matter — no more, no fewer.

Result A single luminous point that multiplies itself through pure mathematics until forty-eight particles orbit in the complete symmetry of a cubic crystal

The Story

In 1830, German physician and mineralogist Johann Friedrich Christian Hessel sat down to answer an exhaustive question: how many distinct ways can symmetry operations — rotations, reflections, inversions — combine while remaining compatible with a crystal lattice? The answer was thirty-two. Exactly thirty-two crystallographic point groups. Not approximately. Not “many.” Thirty-two. Every crystal that has ever formed or will ever form obeys one of these thirty-two patterns. Diamond, salt, quartz, ice, calcite — each one slots into the same finite catalog.

The richest of these is m3̄m, the full symmetry of the cubic system. It is the symmetry of a cube itself: forty-eight operations that map the cube onto itself. Three-fold rotations along the body diagonals, four-fold rotations through the face centers, two-fold rotations through the edge midpoints, mirror planes slicing through every axis, and an inversion that sends each point through the center to its antipode. Forty-eight operations. One point, acted upon by all of them, produces forty-eight images — a constellation that encodes the complete symmetry of the most symmetric crystal class.

The mathematics uses a notation called Hermann-Mauguin, developed in the 1920s and 1930s. Each symbol encodes the generators: “2” means a 180-degree rotation. “mm2” adds mirror planes. “4mm” introduces four-fold symmetry. “432” brings in the three-fold rotations of the cube’s diagonals. “m3̄m” is the final form — every symmetry the cubic system allows. The notation reads like a compression algorithm for geometry. A few symbols contain forty-eight operations.


The Take

The experience begins with one particle. A single luminous point orbiting in darkness on a charcoal field. A title fades: “The Generator. Constraint creates beauty.” Then the title dissolves and a count appears at the center of the screen — enormous, translucent: “1.” Beneath it, the Hermann-Mauguin symbol: “1.” The identity. One point, unchanged.

At 8.5 seconds, the first operation arrives. “rotate 180.” The particle splits — a new point emerges from its parent and glides on a spring-damped arc to the diametrically opposite position. The count jumps to 2. The notation reads “2.” Two particles now orbit in lockstep, 180 degrees apart.

At 12.5 seconds: “reflect.” A mirror plane bisects the constellation. Two becomes four. The notation reads “mm2.” Each new particle spawns from its closest existing neighbor, sliding into position along a critically-damped spring — no overshoot, no oscillation, just a smooth arrival at mathematical inevitability.

At 17 seconds: “rotate 90.” Four-fold symmetry snaps into place. The count jumps to eight. “4mm.” The particles form a symmetric ring, evenly distributed, each the image of the original under a different combination of the accumulated operations.

At 23 seconds: “rotate 120.” This is the cubic diagonal — the rotation that lifts the pattern from a flat square symmetry into something three-dimensional projected down. Eight becomes twenty-four. “432.” The jump is dramatic. Sixteen new particles cascade outward from their parents, each finding its computed position in the group.

At 30 seconds: “invert.” The final operation. Twenty-four particles double to forty-eight. The new particles don’t orbit at the same radius — they settle into a tighter inner ring at 62% of the outer radius, representing the inversion through the center. “m3̄m.” Two concentric rings of twenty-four, orbiting together. The full cubic symmetry, generated from a single point.

Three seconds later, the final text arrives: “Forty-eight reflections of a single point. Every crystal obeys one of thirty-two such patterns. There are no others.”

After the build completes, the cursor gains a gravitational influence. Moving across the screen gently pulls nearby particles toward the pointer — stretching the constellation, deforming the perfect symmetry, which the spring physics then restore. The attractor is the mathematics. You can disturb it. You cannot break it.


The Tech

Group Closure: Computing All 48 Positions from Generators

The symmetry group is not hardcoded. At each step, new generators (2x2 matrices) are accumulated into a master list, and the full group is recomputed from scratch by closure. Starting from a single seed position, the algorithm applies every generator to every known position, checks whether the result is new (within epsilon 0.3 units), and adds it if so. This loops until no new positions are produced — the mathematical definition of group closure.

The seed position is placed at PI/7 radians (~25.7 degrees), deliberately chosen to avoid all symmetry axes (0, 30, 45, 60, 90 degrees). A seed on an axis would be a fixed point of some operations, producing fewer than the expected number of images. The general position guarantees that every operation produces a distinct point. The safety cap of 60 positions and 50 iterations prevents runaway computation, though the cubic group converges well within these limits.

Generators are real 2x2 matrices: [-1,0,0,-1] for 180-degree rotation, [1,0,0,-1] for reflection across the x-axis, [0,-1,1,0] for 90-degree rotation, and the standard rotation matrix at 2*PI/3 for 120 degrees. The inversion step is handled separately — it doubles the existing particles onto an inner ring at 62% radius, representing the 3D inversion projected into the 2D orbital plane.

Spring-Damped Particle Animation

When a new particle spawns, it is placed at its parent’s current position and given a target at its computed group position. The transition uses a critically-damped second-order spring: acceleration equals omega^2 * displacement - 2 * omega * zeta * velocity, with omega = 4.5 and zeta = 1.0 (critical damping). This produces the fastest convergence to the target without oscillation — the particle glides to its position in roughly 0.8 seconds, decelerating smoothly.

Critical damping is the exact boundary between underdamped (bouncy) and overdamped (sluggish). It is the physical equivalent of the mathematical constraint: the particle arrives at the only position it can occupy, and it arrives without drama. The spring constant was tuned so that 24 simultaneous particle births (the 120-degree step) don’t produce visual chaos — each particle follows its own smooth arc.

Instanced Rendering: Particles and Trails

All particles are rendered as a single THREE.InstancedMesh — 64 pre-allocated instances of a PlaneGeometry quad. Each instance gets a per-instance transform matrix (position) and a custom aFlash attribute that drives a warm color shift on spawn. The fragment shader computes a radial Gaussian glow (exp(-dist^2 * 3.0)) to produce soft, luminous circles rather than hard-edged sprites. Additive blending means overlapping particles accumulate brightness — the center of the constellation glows hotter than the edges.

Trails use a second InstancedMesh with up to 2,560 instances (64 particles times 40 trail positions). Each particle maintains a FIFO buffer of its last 40 positions. The trail opacity fades linearly from 12% at the head to zero at the tail, creating ghostly arcs that show the orbital motion. The trail shader uses a tighter Gaussian (exp(-dist^2 * 4.0)) for smaller, more delicate points. Both meshes use THREE.AdditiveBlending and depthWrite: false for correct transparency compositing.

Orbital Motion and Breathing

All particles orbit around the center at 0.18 radians per second — slow, meditative, completing a full revolution in roughly 35 seconds. The orbit is rigid-body: a single globalAngle variable rotates every particle’s target position by the same amount each frame, maintaining the group’s symmetry relationships exactly.

A per-particle breathing modulation adds subtle radial oscillation. Each particle’s radius pulses with a sine wave at period 5 seconds, offset by i * 0.7 radians to prevent synchronization. The amplitude is 6 pixels (scaled). This breathing gives the constellation an organic quality — the mathematical positions are exact, but the particles seem alive, pulsing gently like a luminous organism.

Guide Lines and Visual Hierarchy

When a reflection generator is added, the simulation detects it by checking the matrix determinant (det = -1 for reflections) and computes the mirror axis from the eigenvector. A faint white line at 3.5% opacity is drawn through the origin along this axis, rotating with the constellation. These guide lines are barely visible — they read as structural hints rather than annotations, suggesting the invisible axes that govern the symmetry.

The text layer uses a strict visual hierarchy. The particle count is rendered at enormous scale (up to 220px on desktop) at 12% opacity in Manrope Light — a ghostly background number that fills the center without competing with the particles. The Hermann-Mauguin notation sits below it in Courier New at dimmer opacity, reading as technical annotation. Operation labels (“rotate 180,” “reflect”) appear briefly at the lower third and fade after 2.5 seconds. The final narrative text uses Courier New at the notation opacity level — factual, quiet, not competing for attention.

Cursor Interaction: Post-Build Gravitational Pull

After the full 48-particle build completes, mouse and touch input activates a gravitational influence. Each particle within range of the cursor receives a displacement toward the pointer, scaled by a Gaussian falloff (exp(-dist^2 / 25000)) and multiplied by 20 units per second. The pull is gentle enough to visibly deform the constellation without breaking it — the spring physics continuously restore each particle to its correct orbital position. The interaction creates a push-pull between mathematical order and human perturbation, where symmetry always wins but temporarily bends.

Touch input is handled through both touchstart and touchmove events with passive: false on move to prevent scroll interference. The coordinate mapping converts screen space to the orthographic camera’s centered coordinate system.

Orthographic Camera and Scale

The scene uses a THREE.OrthographicCamera rather than perspective — the view is a clean top-down 2D plane with no depth distortion. The camera spans the full viewport (-W/2 to W/2, -H/2 to H/2), and all positions are computed in pixel space scaled by min(W, H) / 600. The orbital radius is 140 units times this scale factor, so the constellation fills roughly 47% of the smallest viewport dimension. On resize, the camera frustum, renderer, and scale factor are all recomputed. Mobile viewports get the same experience — the scale factor handles the adaptation.


Experience: The Generator


This blog post was AI generated with Claude Code. Authored by Artificial Noodles.