October 26, 2026
Claude Opus 5.5 was given the prompt “64k intro or demo” and nothing else. It made Hollow Lattice, one HTML file with six ray-marched scenes and a synthesized soundtrack. This record explains how it works and how it was built.
ai-generated 64k intro webgl web audio glsl

Word Count: 1327

The Prompt

I gave Claude Opus 5.5 the prompt “64k intro or demo” and nothing else. It came back with Hollow Lattice, one HTML file that draws six ray-marched scenes and synthesizes about a minute and a half of music in the browser. There are no images, audio files, fonts, or libraries. Everything on screen and everything you hear is computed from the text of the page.

Watch Hollow Lattice

It needs a browser with WebGL 2. Press Play with sound. Space pauses, the arrow keys change scene, M turns the sound on and off, F goes full screen, and H hides the controls.

The model also explained how it built the intro. This record is that explanation, checked against the code.

Intro or Demo

In the demoscene, a computer-art subculture that began on 1980s home computers, demo is the general word for a real-time audiovisual program. Competitions at demoparties, the scene’s festivals, split demos by size. A demo with no other label usually has no size limit, or a large one, and can ship textures, models, and recorded music. An intro is a demo with a hard size limit. The two common limits are 64k (65,536 bytes) and 4k (4,096 bytes). Neither leaves room for stored pictures or sound, so an intro computes them as it runs.

The prompt allowed either. The model chose a 64k intro, one kind of demo, because the size limit forces everything to be generated in code.

What Is in the File

Item Value
Size 27,625 bytes as a file, 10,891 bytes after gzip -9
Length 50 bars at 124 BPM, 96.8 seconds
Graphics One WebGL 2 fragment shader, six scenes, up to 128 march steps per pixel
Audio Web Audio API, nine synthesized voices, reverb, delay, compressor
External requests None. System fonts only
Libraries None

When the page loads, it measures its own size and shows the result against 65,536 bytes. That count runs a few bytes over the file’s, because the page measures itself as the browser rebuilt it. The source is not minified, so a lot of it is whitespace, readable names, and comments.

How It Works

The file has three parts: a shader, a synthesizer, and a thin shell that keeps them in sync.

Graphics

The picture comes from one fragment shader, a GLSL program that the graphics card runs once for every pixel. There are no meshes or textures. Each scene is a signed distance function (SDF), a function that returns how far a point is from the nearest surface. A sphere takes one line of SDF code; a mesh of the same sphere takes kilobytes. That is why size-limited work leans on SDFs. Inigo Quilez’s article on distance functions is a common reference.

The shader finds surfaces by ray marching, in the form called sphere tracing. For each pixel it casts a ray and steps forward by the distance the SDF reports, because no surface can be closer than that. It stops when the distance is tiny or the ray goes past the scene’s limit:

for(int i=0;i<128;i++){h=map(ro+rd*t);
  if(h.y==3.||h.y==9.)gl+=.012/(.02+h.x*h.x*30.);   // glow near emissive parts
  if(abs(h.x)<.0007*t||t>mx)break;t+=h.x;}

The six scenes:

# Scene How the shape is made
1 Lattice One cell repeated forever with mod: three rods and a sphere at each joint
2 Tunnel An inverted cylinder whose radius wobbles, twisted along its length, with a ring every 4 units
3 Fold A Sierpinski tetrahedron from 6 rounds of plane folds
4 Mercury Five spheres on sine paths, blended together, above a checker floor
5 Ridge A heightfield from 5 octaves of value noise
6 Orbit A sphere whose ripples swell on each kick, inside two thin rings

The blobs in Mercury and the joints in Lattice use a smooth minimum instead of a hard union, so shapes merge rather than intersect. Shading is a short list: normals from 4 extra SDF samples, 5-sample ambient occlusion, per-scene fog, a glow gathered during the march, then tone mapping, a vignette, film grain, and a short fade at each cut. There are no shadows or reflections; each would need another march per pixel.

The shader is expensive, so the page renders below screen resolution and adjusts as it goes. Every 60 frames it checks the average frame time. Over 24 ms, it lowers the render scale by 15%, to no less than 40%; under 14 ms, it raises the scale by 8%.

Audio

The music is built from oscillators and filtered noise with the Web Audio API. The only buffers are 3 seconds of white noise and a 2.6-second reverb tail made from decaying noise, both generated when you press play.

The nine voices are kick, clap, hi-hat, crash, bass, pad, arpeggio, lead, and a noise riser. The song is in A minor at 124 BPM, and its chords cycle Am–F–C–G, two bars each. Its 48 bars split into six 8-bar sections, one per scene, plus a 2-bar ending. The arrangement builds a section at a time: pad and arpeggio, then kick and hi-hats, then bass and clap, then the lead. The fifth section drops back to a breakdown, and the sixth brings everything back.

JavaScript timers drift by a few milliseconds, which you can hear on drums. The audio clock does not. So a timer is used only to look ahead: every 25 ms it schedules each sixteenth note that falls in the next 150 ms, at an exact time on the audio clock. This is the look-ahead pattern from Chris Wilson’s article “A Tale of Two Clocks.” When the tab is hidden, browsers slow timers to about once a second, so the look-ahead widens to 1.5 seconds.

Sync

One clock drives everything: the audio clock minus the start time. The picture reads that clock once per frame, so sound and picture cannot drift apart. The kick pulse that makes the joints, rings, and blobs throb is calculated from the clock, not measured from the audio. That works only because the music and the picture read the same arrangement table.

How It Was Built

The model wrote the intro in one pass as readable code, with no minifier or build step. The timeline came first, so every later decision hung off bar numbers. The model then tested the page headlessly with Playwright in Chromium on a software GPU, using a temporary hook to jump into each scene and take a screenshot. The hook is not in the published file.

The screenshots caught three problems, none of which raised an error:

Symptom Cause Fix
The start button could not be clicked A CSS display: flex overrode the hidden attribute, so hidden panels sat on top of the button [hidden] { display: none !important }
Orange blotches showed on the lattice joints The blend radius was large next to the joint radius, and the color switched exactly at the blend A smaller blend radius and a bias toward the joint color
The Fold scene was unreadable noise The first fractal made detail far smaller than a pixel A Sierpinski fold in place of a box fold, and 6 rounds instead of 7

Limits

Three things were not checked:

  • Speed on laptops and phones. The software GPU proves the shader compiles and renders, not that it is fast. A laptop with integrated graphics or a phone will most likely drop to a soft, low-resolution picture.
  • How it sounds. The audio ran without errors with the sound muted. Nobody checked the mix on speakers.
  • Safari and Firefox. Only Chromium was tested.

It is also not a competition entry. Most 64k competitions expect a native executable, and the rules vary from party to party. More than a third of this file is the start card, the controls, and their styles. A competition build would drop most of that, minify the shader, pack the JavaScript, and spend the freed bytes on more scenes.