Retro mini-games are a slice of the AI-built games pipeline tuned for short, deterministic arcade loops on a pixel canvas. A prompt like "retro snake" or "pico-8 pinball" routes to the retro renderer + a matching template + a palette + post-fx preset, then the codegen agent fills in the gameplay TSX. The result is a 60fps arcade game that runs as a deterministic engine after compile, exactly like the rest of the arcade family.Retro mini-games are a slice of the AI-built games pipeline tuned for short, deterministic arcade loops on a pixel canvas. A prompt like "retro snake" or "pico-8 pinball" routes to the retro renderer + a matching template + a palette + post-fx preset, then the codegen agent fills in the gameplay TSX. The result is a 60fps arcade game that runs as a deterministic engine after compile, exactly like the rest of the arcade family.
#What "retro" means on wilds
A retro mini-game on wilds.ai is any blueprint whose visualStyleOverride is one of:
retro_pico_8retro_gameboyretro_c64retro_arcade_cab
When the blueprint carries one of those values, the runtime mounts the @wilds/retro-renderer package instead of the usual scene-painting pipeline. That package ships:
- A canvas-2D renderer with a 16-color palette plus a 5x5 monospace bitmap font.
- Drawing-history collision detection, so any retro shape registers a hit-box the next draw can query.
- Algo-chip synthesized SFX routed through the same
SFX_CUE_IDStaxonomy every other family uses. - Four theme presets that swap palette + post-fx defaults without changing the underlying game code.
- A
<CrtPostFx>wrapper that composes scanlines, RGB chromatic aberration, barrel distortion, and bloom on top of any retro canvas via pure CSS + SVG filters (no PixiJS dep; iframe-safe).
The codegen agent never sees a different runtime contract. It still emits TSX, dispatches score_update / play_sfx / game_over through the arcade bundle contract, and gets graded by the same judge tracks. Retro is a visual + primitive substrate, not a new family.
#The four theme presets
Each theme is a palette + post-fx default + an accessibility rating. Themes only affect the rendered canvas; they never change the gameplay tick rate, the hit-box semantics, or the score wire format.
| Theme | Palette feel | Default post-fx | Color-blind safety |
|---|---|---|---|
retro_pico_8 | 16-color saturated, classic pixel-art console look | None | Moderate (red + green pair may confuse protanopia / deuteranopia at low saturation) |
retro_gameboy | 4-shade greyscale-green ramp | Subtle scanlines | High (luminance ramp is safe for every color vision deficiency) |
retro_c64 | VIC-II inspired purples + blues + earth tones | None | Moderate (slightly safer than pico-8 due to luminance variance) |
retro_arcade_cab | High-saturation primaries | Scanlines + chromatic + barrel + bloom | Low (near-equal-luminance saturated primaries; surface a CVD warning) |
The Studio's retro theme picker shows these tradeoffs inline so the creator can swap before publishing. The four ids are the canonical schema values; the Studio is the only path that should set them on a blueprint.
#Primitives the codegen agent reaches for
Every retro mini-game is a composition of step functions plus the renderer. The full primitive set:
#Movement + collision
useGridMover2D+useSnakeBody2D. Integer-cell movement with a queued body. Snake, Pac-Man-style chasers, sliding puzzles.useGridCollision2D. Sparse occupancy grid with O(1) lookups + out-of-bounds-as-wall semantics. Maze cells, level walls, pellet collection.useDrawingHistoryCollision2D. Returns{ isColliding: { rect, text, char } }against everything drawn this frame.
#Physics
useVariableJump2D. Held-button-extends-jump platformer physics with coyote-time + jump-buffer windows.useChargeRelease2D. Hold-aim-release input. Golf, slingshot, bomb throws.usePaddleBounce2D. Ball-vs-paddle physics with off-center deflection and wall bounces. Pong.useBrickGrid2D. Brick wall + per-brick HP + AABB collision with reflection. Breakout.usePinballFlipper2D. Two-flipper swing physics + segment-vs-ball contact. Pinball.useFruitMerge2D. Two touching same-type fruits combine into the next tier. Suika.useSlideWind2D. Frictionless / windswept movement with input acceleration + speed cap. Ice puzzle, conveyor belts.useInertia2D. Asteroids-style rotate + thrust + drift with space drag.
#Scrolling
useEndlessScroller2D+useScreenWrap2D. Right-to-left scrolling lanes plus wrap / clamp / bounce edge behaviors. Endless runners, avoiders, asteroids-style motion.useLaneSpawner2D. Frogger-style lane traffic. Per-lane direction + speed + spawn cadence + weighted entity types.
#Puzzle
useTileFallStack2D. Tetris-style falling pieces. Ships with all 7 standard tetrominoes (TETROMINO_SHAPES: I / O / T / S / Z / L / J), SRS-style horizontal wall-kicks (in-place → ±1 col → ±2 cols), line clearing, and game-over on spawn-blocked. Grids narrower than 5 cols fall back to single-cell pieces for mini variants.useColorMatch2D. Mastermind-style code-breaker. Tracks pattern + guesses + per-row feedback (correctPos+correctColorwith no double-counting on duplicates).
#Audio + clock
useAlgoChipSfx. Deterministic SFX synthesis cached by(blueprintId, seed, cue). Cold synthesis runs under 2ms; cached plays are sub-millisecond.useRetroClock. 60Hz-clamped fixed-timestep tick + difficulty curve + seeded PRNG.
All step functions in @wilds/game-primitives-types are pure: same (state, input, cfg, dt, rng) produces the same output. The agent's sandbox grader replays each retro game's first N ticks deterministically, which is what powers the new judge tracks.
#How a prompt picks a retro template
The compiler runs routeVisualStyle() over the prompt before the codegen agent starts. The router is a pure regex helper and walks four decision steps in order:
- Theme-specific keywords win first.
pico-8,gameboy,c64,commodore,arcade cab,crt,scanlinepin a specific retro theme with confidence ~0.95. - Generic retro keywords bump into the retro band.
retro,8-bit,lo-fi,classic arcade,old-school,nostalgic, plus classic-game names (snake,pong,pinball,suika,flappy,asteroids,pac-man,tetris,mastermind,frogger,breakout,ice puzzle, etc.) all default toretro_pico_8with confidence scaling by signal count. - Explicit modern style (
anime,photorealistic,noir,painterly,cartoon,oil painting,comic book) wins next. - Pixel-without-retro signals route to
pixel_art(the non-retro pixel-art preset). - Universal fallback is
photorealisticwith low confidence; the blueprint's other signals usually override before compile finishes.
That hint becomes one of two things: a soft filter on PickTemplate so the codegen agent biases toward the right template, and the persisted visualStyleOverride on the blueprint so the runtime mounts the retro renderer. The agent can still override the hint at compile-time if other prompt signals contradict it.
#Templates
The retro renderer ships twelve registered templates covering the classic-arcade canon. All twelve route via PickTemplate and carry MIT attribution to crisp-game-lib (study-don't-copy reference). Each has an authored scene-graph + 3-4 few-shot prompt examples for the codegen agent.
| Template | Primitives | Pitch |
|---|---|---|
retro-snake | useGridMover2D + useSnakeBody2D + useGridCollision2D | Grid snake on a retro canvas. |
retro-pong | usePaddleBounce2D | Two paddles, one ball. |
retro-paddle-breakout | useBrickGrid2D + usePaddleBounce2D | Paddle deflects a ball into a brick wall. |
retro-flappy | useEndlessScroller2D + useVariableJump2D | Tap to flap, dodge pipes. |
retro-suika | useFruitMerge2D | Drop fruits; same-type pairs merge to the next tier. |
retro-pinball | usePinballFlipper2D + gravity loop | Two flippers, gravity-fed ball, bumpers + targets. |
retro-asteroids | useInertia2D + useScreenWrap2D + bullet/spawner | Rotate, thrust, drift, fire. |
retro-frogger | useLaneSpawner2D + cell-snap movement | Hop one cell at a time. Dodge cars, ride logs. |
retro-tetris | useTileFallStack2D | Falling tetrominoes, line clearing, speed ramps with level. |
retro-mastermind | useColorMatch2D | Crack the 4-peg color code in 10 attempts or fewer. |
retro-ice-slide | useSlideWind2D + useGridCollision2D | Slide on frictionless floor until you hit a wall. |
retro-pacman | useGridMover2D + useGridCollision2D + enemy AI hooks | Sweep a maze for pellets; power pellet flips the chase. |
Each template ships its scene-graph rooted at <RetroCanvas2D> with placeholder bindings for gameState.*. The codegen agent extends the skeleton via ComposeSceneGraph (Spec 4) and GenerateEntryComponent to materialize the per-blueprint TSX.
#Curated games shipping now
Nine pre-compiled curated entries appear in the catalog the moment a creator browses /app/browse. Each is a GameDefinition in @wilds/games pinned to one of the retro themes + audioMode: 'algo-chip' + runtimeMode: 'deterministic'. The codegen agent's retro template handles prompt-driven forks; the curated entry is the fork-able starting point.
| Curated | Theme | Backing template |
|---|---|---|
retro-snake-classic | pico-8 | retro-snake |
retro-pong-classic | pico-8 | retro-pong |
retro-pinball-classic | arcade-cab | retro-pinball |
retro-asteroids-classic | pico-8 | retro-asteroids |
retro-frogger-classic | arcade-cab | retro-frogger |
retro-tetris-classic | gameboy | retro-tetris |
retro-mastermind-classic | pico-8 | retro-mastermind |
retro-ice-slide-classic | gameboy | retro-ice-slide |
retro-pacman-classic | arcade-cab | retro-pacman |
Curated entries bypass the codegen loop on first load. A creator forking one inherits the metadata + template anchor + visual style; the codegen agent fills in any customizations the new prompt asks for.
#CRT post-FX
<CrtPostFx> wraps any retro canvas with four optional effects:
<CrtPostFx scanlines chromatic barrel bloom respectReducedMotion>
<RetroCanvas2D ...>{children}</RetroCanvas2D>
</CrtPostFx>- scanlines: CSS
repeating-linear-gradientoverlay withmix-blend-mode: multiply. Pure CSS, no SVG dep. - chromatic: SVG
<filter>withfeColorMatrixchannel split +feOffset±0.6px on R / B. Mimics CRT phosphor RGB-stripe misalignment. - barrel: SVG
<filter>withfeTurbulence+feDisplacementMap. Subtle outward bulge, static (no animation driving the turbulence). - bloom: native CSS
brightness(1.06) saturate(1.12)on the content. Cheap, GPU-accelerated, no SVG dep.
Pass respectReducedMotion and the wrapper suppresses chromatic + barrel (the motion-heavy effects) under prefers-reduced-motion: reduce. Scanlines + bloom stay on — neither animates so they're motion-safe.
The implementation is pure CSS + inline SVG. No PixiJS peer dep; iframe-safe by design so vibe-coded games in sandboxed iframes still get the look. The 4 themes' default post-fx settings map directly onto the <CrtPostFx> flags — retro_arcade_cab sets all four, retro_gameboy sets scanlines only, retro_pico_8 + retro_c64 skip the wrapper entirely.
#Studio panels for retro blueprints
When the Studio detects visualStyleOverride starting with retro_, three extra panels appear automatically:
- Retro Theme picker. Radio dialog for the four themes with palette swatches + CVD warnings.
- Retro Audio mode. Routes SFX through algo-chip synthesis (default, zero asset cost), the Kenney stock pack, or AI-forged effects (Forge tier).
- Retro Difficulty curve. Gentle / medium / punishing presets that drive how fast
useRetroClock.difficultyramps.
Each panel persists to the existing blueprint draft via the standard save() debounced patch. None of them touch the gameplay code the codegen agent emitted; they only adjust theme, audio backend, and difficulty curve.
#Judge tracks specific to retro
The codegen sandbox grades every retro bundle on four additional tracks alongside the base arcade contract:
grid_movement_intelligible. If the bundle usesuseGridMover2D, positions are integer cells and the facing display matches the next move. Launch-blocking.retro_palette_coheres. Every draw call uses palette colors; no inline hex strings or rgb() literals outside palette mapping. Polish.visual_style_matches_prompt. The picked template + visualStyleOverride agrees with the prompt's aesthetic signals. A "retro pong" prompt that produces a photorealistic bundle fails this track. Polish.drawing_history_safe. The per-frame hit-box count stays within the template's declaredmaxHitHistorycap (default 1024). Polish.
Bundles ship with these tracks visible in the lobby's Build quality roll-up alongside the universal arcade tracks (no_runtime_errors, hud_renders, controls_intelligible, etc.).
#Prompt patterns that route well
A few patterns the router handles cleanly:
"retro snake". Routes toretro_pico_8+retro-snaketemplate. Default audio = algo-chip, default theme = pico-8."gameboy tetris". Theme keywordgameboypinsretro_gameboy; the agent usesuseTileFallStack2Dwith the 7 standard tetrominoes."crt arcade pinball".crtpinsretro_arcade_cabfor the full scanline + chromatic look. The agent usesusePinballFlipper2Dfor the flipper physics."commodore 64 frogger clone".commodorepinsretro_c64. The agent picksuseLaneSpawner2Dand threads c64 palette colors through the lanes."mastermind color code". Routes toretro_pico_8+retro-mastermindtemplate viauseColorMatch2D."asteroids with screen wrap". Routes toretro_pico_8+retro-asteroids. The agent composesuseInertia2D+useScreenWrap2Dmodewrap.
When the agent can route to either retro or modern (e.g. "a beautiful pixel-art adventure"), the router prefers pixel-art-without-retro since pixel alone does not signal a retro game. Adding retro pixel-art or 8-bit pixel-art flips it.
#Performance budget
The retro foundation targets a 2020-era MacBook Air baseline. Mean times measured by perf.bench.ts run via npx vitest bench:
- Algo-chip SFX synthesis: 1.7ms cold (target 2ms), under 0.1ms cached (LRU at 64 entries per session).
- Per-frame step function cost: every primitive runs 1000 iterations under the 16.6ms 60fps budget except
stepLaneSpawner(~23ms for 1000 sims because of per-lane entity advancement; the real per-frame cost is ~0.023ms since live games only run one tick per frame). - Puzzle steps (
stepTileFallStack+stepColorMatch) target 200 iterations under 16ms. - Hit-history cap: default 1024 records per frame, configurable per template via
<RetroCanvas2D maxHitHistory={N}>. - CRT post-FX: zero runtime cost when no effects are enabled (component renders children as a fragment). SVG defs sheet mounts only when chromatic or barrel are active; scanlines / bloom skip the SVG entirely.
Regressions show up in the bench output before they show up in production.
#What's still gating playability
The wave-2 surface — primitives, hooks, templates, curated blueprints, CRT post-FX, tetrominoes — ships behind one remaining lift:
- Codegen orchestrator wiring. The 10 templates ship with
behaviors: []empty arrays. The codegen orchestrator's compile step needs to materialize the matching runtime behaviors from primitive composition before a template becomes playable end-to-end. ThePickTemplatetool can match prompts to template ids today; the orchestrator hookup is the next gate.
Everything else — schema, runtime, renderer, primitives, themes, curated catalog, prompt routing, judge tracks — is forward-compatible. A creator who ships a retro blueprint today gets every wave-2 primitive automatically.
#See also
- AI-built games. Umbrella explainer for codegen-driven arcade games on wilds.
- Writing great prompts. Prompt patterns that route correctly across retro and modern templates.
- Customizing an AI-built game. Studio walkthrough for editing themes, audio modes, and difficulty curves.
The retro stack lives at packages/runtime/retro-renderer/, the step functions at packages/runtime/game-primitives-types/src/ (grid + physics + scrolling + puzzle), the React hooks at packages/runtime/game-primitives/src/ (grid + physics + scrolling + puzzle + step-guard), templates at packages/runtime/game-templates/src/templates/retro-*/, and curated blueprints at packages/platform/games/src/curated/retro-*-classic/.