跪拜 Guibai
← Back to the summary

Four 3D Games in 3.82MB: Inside Claude's One-Shot Build Pipeline

AI Field Test · Engineering Teardown

~15 min read. Requires some Three.js basics; code snippets are reconstructions based on public descriptions, not repo originals. Focus on the approach.

Look at four things first.

A 1.42MB FPS that calls itself "Domestic 3A", with a title screen, mission briefing, three relays, mechanical enemies, action rating, and results panel.

An 862KB CF transport ship, 6v6, four guns, four difficulty levels, two lighting sets for day and dusk.

A 718KB QQ Speed, four tracks, drift charge, mini boost, double boost, start boost, landing boost — all present.

An 818KB pelican cycling game, procedural modeling, two-bone IK, Verlet scarf, Gerstner ocean, day/night cycle, and 14 achievements.

All four together are 3.82MB. No texture packs, no glTF, no MP3, no backend. Each is an HTML file you open and play.

Three online demos come from the GitHub repo riba2534/claude-opus-5-5-demo. The author's stated setup: Claude Opus 5.5, Claude Code CLI, single session, zero manual code edits. The fourth, "Ji Mao" (Cat), is also a single file, title screen says "developed with Fable5.2 proprietary". It has a public link but no attribution. It's not in that repo, so don't attribute it to the same author.

This post doesn't discuss "AI is amazing". It only breaks down four things: how one-sentence prompts become engineering constraints, what exactly is inside 3.82MB, which pitfalls only appear after generation, and what this method can't do yet.

1. The results: technical baseline of four demos

Demo Type Size Code organization Key techniques
Ji Mao FPS 1.42MB Single file Three.js, Bloom, FXAA, ShadowMap, InstancedMesh, WebAudio
Transport Ship FPS 862KB 18 modules Three.js, procedural weapons and map, AI bots
QQ Speed Racing 718KB 15 modules Three.js, track generation script, drift state machine
Pelican Cycling Casual 818KB 11 modules Two-bone IK, Verlet fabric, Gerstner ocean, day/night cycle

A few easily overlooked numbers:

"Single file" and "small size" are not the same thing. A single file can be large; small size can still be split into many requests. These four demos achieve both, not through compression but by switching to a different asset production method.

2. The truth about one-shot: four layers of constraints behind one sentence

First, put out the three original prompts.

Pelican:

Generate a 3D page of a pelican riding a bicycle, use all your abilities as much as possible.
Then upload to CDN and give me the access link.

Transport Ship:

As realistically as possible, recreate the transport ship map from CrossFire. I need a real shooting game, generate a 3D page, use all your abilities as much as possible. After finishing, upload to CDN and send me the link.

QQ Speed:

As realistically as possible, recreate the game map from QQ Speed. I need a real QQ Speed game, including all key binds and drift mechanics, generate a 3D page, use all your abilities as much as possible. After finishing, upload to CDN and send me the link.

All three are short, but information-dense. Breaking them down reveals four layers of constraints:

Words in prompt Corresponding engineering action
"As realistically as possible" First search the web for official map layout, key binds, rules, then start
"Include all key binds and drift mechanics" Input system, vehicle physics, drift/nitro state machine — not just visuals
"Generate a 3D page" Runs directly in browser, single-file delivery, no local environment dependencies
"Upload to CDN, send me the link" Build, deploy, cache purge, domain and cert — full chain
"Use all your abilities as much as possible" Let the model choose tech stack, asset strategy, testing approach

The last one is the most valuable. It hands "what to do, how to do it, how to verify" all to the model.

So one-shot is not "one API call produces a page". Its precise meaning is: complete the loop from research, design, coding, testing, to deployment within one session. There are still failures, fixes, and re-runs in between — just that the model strings these steps together itself, without a human taking over piece by piece.

The repo also has several hard rules:

These rules determine every subsequent technical choice. No external assets means procedural; single file means inlining; one-sentence delivery means testing and deployment also go to the model.

3. How 3.82MB fits four games

A conventional 3D web game asset directory looks something like: glTF models, PNG or KTX2 textures, MP3 audio, animation clips, fonts. Four games would easily be tens of MB.

These four demos have an empty asset directory.

3.1 Geometry: parametric generation, not modeling export

Containers are boxes, guardrails are cylinders, tires are toruses, trees are cones plus cylinders. These shapes stack from Three.js primitives. Parameterizing them allows batch generation of variants in different sizes and colors.

Repeated objects suit InstancedMesh. Containers in the port, trees along the track, chairs in the stands — drawing the same geometry many times doesn't make draw calls grow linearly with count. That's one key reason a single file can still hold frame rate.

3.2 Textures: drawn with Canvas 2D, not PNG

Container numbering, weight limits, inspection dates — these details are not PNGs. They're drawn directly on Canvas. After drawing, convert to CanvasTexture and cache on demand, avoiding re-creation every frame.

// Procedural texture cache: draw only once per key
const cache = new Map();

function canvasTexture(key, draw, size = 512) {
  if (cache.has(key)) return cache.get(key);

  const canvas = document.createElement('canvas');
  canvas.width = canvas.height = size;
  const ctx = canvas.getContext('2d');
  draw(ctx, size);

  const tex = new THREE.CanvasTexture(canvas);
  tex.colorSpace = THREE.SRGBColorSpace; // color space since r152+
  tex.anisotropy = 4;                     // don't blur at oblique angles
  cache.set(key, tex);
  return tex;
}

The benefit is not saving a few images; it's "mutability". The same container function, given different numbers, weights, colors, generates an entire yard. With PNGs, you'd need to make dozens of images first.

Cost: first frame has to draw. So real projects pre-generate common textures during loading, not when entering the game.

3.3 Audio: oscillators and noise, not MP3

Gunshots, engines, waves, bird calls — all synthesized with WebAudio. Noise plus filters for gunshots, low-frequency oscillators for engines, multiple sine waves stacked for music. Saves size, saves copyright.

Cost: "how close it sounds" depends entirely on parameter tuning. Synthesizing a convincing gunshot is no easier than finding a sound effect.

3.4 Bundling: esbuild inlines into one HTML

// build.mjs — inline JS into HTML, producing a double-clickable file
import { build } from 'esbuild';
import fs from 'node:fs';

const template = fs.readFileSync('index.html', 'utf8');

await build({
  entryPoints: ['src/main.js'],
  bundle: true,
  minify: true,
  format: 'iife',
  target: ['es2020'],
  write: false,
  plugins: [{
    name: 'inline-html',
    setup(b) {
      b.onEnd((result) => {
        const js = result.outputFiles[0].text;
        const html = template.replace('<!--APP-->', `<script>${js}</script>`);
        fs.writeFileSync('dist/index.html', html);
      });
    },
  }],
});

write: false keeps the output in memory; the plugin replaces a template placeholder with the string, and writes once at the end. No separate JS/CSS requests.

Single file is not a belief; it's a delivery constraint. It has clear pros and cons:

Dimension Single file Conventional split
Deploy One file, zero config Needs static server, MIME, cache policy
First package One request, everything at once Can split by route/scene
Cache Change one character, whole file invalid Third-party libs can be cached long-term
Debug Sourcemap requires extra handling Clear module boundaries
Review A several-thousand-line file Review per module
Suitable for Demo, vertical slice, teaching, portfolio Long-term operation, large worlds, multiplayer

These four demos are all "vertical slices": complete gameplay loop, limited content volume. Single file is a fit.

4. Four demos, four engineering challenges

4.1 Ji Mao: 1.42MB of "3A syntax"

The most 3A-like thing about Ji Mao isn't the visuals; it's the flow.

Title screen has mission code B4, squad name, time 05:42; entering the game gives a mission briefing: "Harbor defense system failed. Cut three relays, break the blockade, and extract by boat." The three relays are in the yard, warehouse, and dock; enemies are mechanical seagulls, mechanical hounds, mechanical guards; the extraction boat is at the south dock gangway.

01-jimao-title.jpg

After finishing, an action rating: perfect assault, precise decisive, steady, perilous. Results panel statistics: time, hit rate, mechanicals destroyed, retries. Death screen too — survival time and relays cut.

This is nothing new; 3A FPS has used it for years. The new part is it's packed into 1.42MB.

Subsystem Implementation
Rendering Three.js + Bloom + FXAA + ShadowMap
Level Harbor single level, three relays, linear progression
Combat Rifle, melee, hit feedback and directional damage indicator
Enemies Mechanical seagull, mechanical hound, mechanical guard
UI Title, briefing, pause, settings, results, death
Input Keyboard/mouse, gamepad, touch — three mapping sets
Audio WebAudio synthesized ambient, gunshots, radio

Technically it's standard pipeline: Bloom for neon and signal lights, FXAA for anti-aliasing, ShadowMap for harbor shadows, InstancedMesh for repeated containers and guardrails. Container numbers, weight limits, inspection dates — all Canvas-drawn.

It also has clear boundaries: single level, three enemy types, no multiplayer, no cinematic set pieces. The project intro says it plainly: "Currently the project is still under continuous development and optimization; there is still a gap from international top-tier 3A standards."

That sentence is more honest than any technical metric. It's not 3A; it's a development experience version using 3A's syntax.

4.2 Transport Ship: search guides first, then build

CF's transport ship is a map with strong memory. The model didn't build from memory; it searched official layout and guides before starting.

The structure that ends up in code:

Area Role Cost
Bow/stern cabins Both spawns Few exits, easy to camp
Mid V-shaped slant container Main combat zone Crossfire, long exposure
L-shaped box stacks on both sides Flank advance Narrow view, many corners
Left/right one-way container tunnels Flanking behind Single entrance, hard to retreat
Second floor above tunnels Sniper points Fixed position, easy to pre-aim

These boxes aren't decoration; they're map design language. Every lane gives you one advantage while charging a cost.

02-cf-transport.jpg

Parameters are generous: 4v4, 6v6, 8v8; target kills 30, 50, 100; difficulty easy, normal, hard, hell; primary weapons AK-47, M4A1, AWM, MP5; lighting day, dusk.

18 modules and 862KB must fit the map, guns, ballistics, recoil, aiming, reloading, weapon switch, melee, throwables, AI, HUD, scoreboard. Module splitting is necessary here; one file would become unmanageable later.

Its hardest part isn't modeling; it's "likeness". Gun proportions, aiming FOV, recoil rhythm, AI push routes — any off, and players of CF spot it instantly.

4.3 QQ Speed: Fingertip feel is a state machine, not effects

QQ Speed's key binds and mechanics are explicitly named in the prompt. This part best demonstrates engineering ability.

Mechanic Trigger Effect
Drift Shift + direction Charge boost, change car posture
Nitro Charge full Max two stored, gives acceleration
Mini boost Tap up at drift exit Short acceleration
Double boost Mini + nitro Stacked acceleration
Start boost Tap up at countdown GO Start acceleration
Landing boost Tap up at landing from jump Landing compensation
Speed strip Blue arrow Direct acceleration
Reset R Return to track

Writing these as code, the core is a state machine:

// Pseudo-code: only state transitions, not full vehicle physics
const S = { IDLE: 0, DRIFT: 1 };
let state = S.IDLE;
let charge = 0;
let nitro = 0;

function onFrame(dt, input) {
  // 1. Must meet speed condition to start drift
  if (state === S.IDLE && input.shift && input.speed > 40) {
    state = S.DRIFT;
    charge = 0;
  }

  // 2. Drift charges; releasing Shift settles nitro
  if (state === S.DRIFT) {
    charge = Math.min(1, charge + dt * 0.9);
    if (!input.shift) {
      state = S.IDLE;
      if (charge >= 0.85) nitro = Math.min(2, nitro + 1);
    }
  }

  // 3. Mini boost at steering-back; holding nitro stacks as double
  if (state === S.IDLE && input.justReleasedShift && input.up) {
    const double = input.nitro && nitro > 0;
    if (double) nitro -= 1;
    boost(double ? 1.6 : 1.0);
  }
}

Beyond the state machine, two details:

First, fixed timestep. Drift timing, nitro duration, collision detection must not follow frame rate, otherwise 120Hz and 60Hz feel different.

const STEP = 1 / 120;
let acc = 0;
let last = performance.now();

function loop(now) {
  const dt = Math.min(0.1, (now - last) / 1000);
  last = now;
  acc += dt;

  while (acc >= STEP) {
    update(STEP);
    acc -= STEP;
  }

  render(acc / STEP); // interpolate, avoid visual jitter
  requestAnimationFrame(loop);
}

Second, input buffering. If the player taps up 100ms before exiting a corner, that press must not be swallowed because the car hasn't steered back. Keep a small input queue and consume it on the steering-back frame.

03-qq-speed.jpg

Track isn't hand-placed either. The author first generated a top-down view with a script, checked corner angles and intersections, then built the road in 3D. Four tracks: 11 City, Aegean Love, Pharaoh Pyramid, Snow Adventure; eight car colors; three AI levels; 1/2/3/5 laps; race and item modes. 718KB, the smallest of the four.

4.4 Pelican: the hardest part is there's no IP to copy

CF and QQ Speed have tons of public material: maps, key binds, guides, videos. The model's job is "recreation".

04-pelican.jpg

The pelican has none. A white pelican with helmet and sunglasses rides a vintage bike, a wicker basket on the front, chasing fish along a coastal road. This image has no existing reference; every choice must be made by itself.

Technique Approach
Pelican Procedural modeling, no external model
Pedaling Two-bone IK, foot follows pedal
Scarf Verlet cloth, affected by speed and wind
Ocean Gerstner waves, multiple layers
Sky Day/night cycle, dusk to starry
Music Real-time browser synthesis, rhythm follows cadence
Content 14 achievements, 5 camera modes, fish-catching mini game, bell

Two-bone IK is the most typical "looks simple, writes full of constraints" thing here. Known hip joint, pedal position, thigh and shin lengths — find knee position:

// Two-bone IK: intersection of two circles, pick the forward one
function solveKnee(hip, pedal, thigh, shin, bendDir) {
  const d = hip.distanceTo(pedal);

  // Law of cosines: projection length of knee on hip-pedal line
  const a = (thigh * thigh - shin * shin + d * d) / (2 * d);
  const h = Math.sqrt(Math.max(0, thigh * thigh - a * a));

  const base = hip.clone().lerp(pedal, a / d);
  const axis = new THREE.Vector3().subVectors(pedal, hip).normalize();
  // Project bendDir perpendicular to the bone axis; knee bends that way
  const bend = bendDir.clone().addScaledVector(axis, -bendDir.dot(axis)).normalize();

  return base.addScaledVector(bend, h);
}

The formula is just the first step. The real difficulty is constraints: pedal trajectory is determined by crank angle, foot must stay on the pedal, knee must not hyperextend, body must gently bob with cadence. Any one of these off, and viewers instantly feel "fake".

The ocean uses Gerstner waves; the vertex shader stacks several layers of waves with different directions and wavelengths:

// Vertex shader: single Gerstner wave; actual stacks 3–4 layers
vec3 gerstner(vec3 p, vec2 dir, float steepness, float wavelength, float speed, float t) {
  float k = 6.28318 / wavelength;
  float c = sqrt(9.8 / k);          // deep-water wave speed
  vec2 d = normalize(dir);
  float f = k * (dot(d, p.xz) - c * speed * t);
  float a = steepness / k;

  return vec3(d.x * a * cos(f), a * sin(f), d.y * a * cos(f));
}

The scarf uses Verlet: each particle keeps current and previous position, maintains length via constraint iterations, then adds wind. No physics engine needed; a few dozen lines make it flutter.

Background music is synthesized in real time, tempo follows cadence. That's clever: the on-screen pelican pedals faster, music speeds up, and viewers think the whole scene is "alive".

5. Three pitfalls: problems that only appear after generation

The most valuable part of these four demos is the problems they expose; what they did right is less important.

5.1 320-second soak test

The pelican ran a 320-second soak test before launch, spanning a full day/night cycle. Check items aren't frame rate: geometry count, texture count, and JS heap are the focus.

"One run is fine" and "one day is fine" are two different things. The most common 3D bug is creating a geometry or material per frame; memory explodes in minutes. Soak testing catches this.

5.2 Intermittent black screen after release

More troublesome: intermittent black screens that only appear after going live.

The author's approach was to inject NaN to reproduce, eventually pinpointing Bloom: invalid pixels spread during the bloom pass, turning the whole screen black. Fix in two steps:

  1. Add a cleanup pass before bloom that clamps NaN/Inf pixels.
  2. Fix the Fresnel calculation on the ocean, removing the source of invalid values.
// Cleanup before bloom: NaN via x != x, Inf via upper clamp
vec4 c = texture2D(tDiffuse, vUv);

if (any(notEqual(c, c))) {
  c = vec4(0.0);          // NaN
}
c = min(c, vec4(64.0));   // Inf clamp, 64 far above normal HDR range
gl_FragColor = c;

This kind of bug is hard to find by "reading code". It needs real execution, reproduction conditions, and knowledge of HDR pipeline edge cases.

5.3 12 issues before delivery

The repo also mentions a detail: before delivery, a sub-agent independently reviewed and found 12 issues, all fixed.

This shows one-shot's "one" means session count, not attempt count. The model still iterates, just within the same session: it looks up information itself, writes tests itself, runs headless browser itself, fixes bugs itself, redeploys itself.

Human work becomes defining acceptance criteria, reviewing results, making decisions.

6. Capability boundary: what can be copied, what can't

Looking at the four demos together, the boundary is clear.

Can do Cannot do
Genres with abundant public references: CF maps, QQ keys, 3A FPS camera Original gameplay, emotion, and feel with no reference
Combination of mature tech: Three.js + IK + cloth + ocean Animation, level design, balance needing a decade of accumulation
Single-player vertical slices: one level, one map, one track Long-term content, multiplayer sync, anti-cheat, operations
Procedural assets: geometry, Canvas textures, synthesized audio 3A motion capture, voice acting, scanning, art consistency
Rapid validation: one session to get a playable link Large-scale team collaboration and project management

The threshold for 3A has never been visuals; it's money, people, and time. A team of hundreds, three to five years, hundreds of millions in budget, motion capture, scanning, voice, level design, balance, optimization, QA, publishing, operations.

A 1.42MB HTML, however similar, is only "3A visual syntax", not 3A's production system.

But it's moving another cake: the demo layer.

Previously, a game idea had to survive by writing a PPT, drawing concept art, making a gray-box, then finding money to hire a team to build a playable version. Now, a designer, a frontend engineer, or even a non-coding designer can get a running, viewable, linkable vertical slice in one session.

Investors and bosses no longer have to imagine; they click the link.

Once this threshold collapses, the division of labor in the game industry gets rearranged. People making concept demos become fewer; those who can judge "what's worth making" become more expensive; execution value goes down, aesthetics, design, and project management go up.

For frontend engineers, the impact is more direct: being able to only call Three.js APIs becomes less valuable; what's valuable is knowing which effects are worth building, how to make them look real, and where the performance budget goes.

7. To reproduce: a prompt and an acceptance checklist

If you want to run it yourself, don't start with "write a function for me". Give a complete delivery goal.

Make a directly openable 3D <type>, theme is <theme>.

Requirements:
1. Single-file HTML, Three.js, no external images/models/audio;
2. Recreate <specific map/gameplay/key binds>, search official material first;
3. Include menu, settings, results, mobile touch;
4. Run one match with headless browser, check memory, frame rate, boundaries;
5. Deploy to <platform>, send me the link.

This is longer than the original three-sentence prompts, but better for engineering delivery. The original prompts test the model's capability ceiling; this one sets acceptance criteria.

I generally check ten items:

Check Pass standard
First screen Interactive picture appears within 3s, not white screen
Controls At least keyboard/mouse and touch; key hints
Gameplay Has start, goal, results, restart
Visuals No obvious clipping, flicker, Z-fighting
Performance 30fps+ on mid-range phone, 60fps on desktop
Memory Play 10 minutes, heap does not grow
Boundaries Long time, long distance, repeated restarts no errors
Audio Only plays after first interaction, no autoplay
Deploy Link accessible, refresh no 404
Copyright Fan/original clearly marked, no stolen assets

A few easy-to-flip places:

Problem Cause Handle
First package too large Single file stuffs libraries and assets Compress, delay generation, lower asset precision
Mobile black screen WebGL context limits / VRAM Lower resolution, lower quality, detect context loss
Audio silent Browser autoplay policy Resume AudioContext after first click/touch
Touch unresponsive Only keyboard listeners Unified input layer, map touch to actions
Old version after deploy CDN/browser cache Hash file names or add version query parameter
Fan copyright violation Using original textures/models Only recreate gameplay and layout; all assets self-made

8. Quick reference

Task Tool
Single-file 3D delivery Three.js + esbuild inline
No art assets Procedural geometry + CanvasTexture + WebAudio
Recreate a map Search official layout, build gray-box, add details
Racing feel State machine + fixed timestep + input buffering
Character pedaling Two-bone IK + pedal trajectory constraint
Ocean Gerstner wave multi-layer stacking
Scarf/flag Verlet cloth
Long-run stability Soak test + geometry/texture/heap monitoring
HDR black block NaN/Inf cleanup pass + root cause
Delivery acceptance Headless browser one match + accessible link

A single sentence can generate a game, but cannot generate a "game worth playing".

What the model is best at are genres with abundant public references: CF maps, QQ Speed key binds, 3A FPS camera language. The internet is full of tutorials and screenshots; it only needs to reorganize them into code. What's truly hard is things without reference — a new mechanic, an emotion no one has seen, a feel that takes a decade to refine.

So the pelican is the most precious. It has no IP to copy; every choice must be made on its own.

All four games are playable online now:

Source: https://github.com/riba2534/claude-opus-5-5-demo

This is post 1 in the "AI Field Test" series. Next: breaking this one-shot flow into a directly copiable prompt template.

Note: CF and QQ Speed related demos are fan tribute works; copyright belongs to the original studios; Ji Mao is a development experience version, not an actual commercial 3A project.