---
title: The game that never shipped
summary: A trailer, a playthrough or a title sequence for a game that looks like it came off a real 16, 32, 64 or 128-bit console, because it is drawn on GroundSlate's console kit and cannot do anything that console could not show. Your agent invents the game with you, picks the era, builds the level as a page that plays itself, scores it on the era's own sound chip, and renders it on your Mac.
lede: A game from a console generation, played on screen, that never existed
tools: get_context, list_profiles, composition_doctor, list_kits, get_kit, write_composition, preview_html, render_html, render_ffmpeg, generate_music, generate_sound_effect, sample_frames, create_project, commit_to_library, add_project_note, request_review, review_status, review_reply, job_wait
works_with: agent-skills
order: 11
---

Fake retro games usually give themselves away in the first second. A sprite turns smoothly on a machine that could only flip it. A menu fades on hardware that had no transparency. The title is set in a system font, a gradient sits behind it, and the pixels are not quite square. Anyone who played those consoles can tell straight away, and after that nothing on screen is believable.

This skill builds the video on GroundSlate's console kit, which holds a page to what its console could draw. On the 16-bit profile, rotating a sprite, drawing a gradient or setting a transparency is refused with a sentence saying what the era did instead. On the 32-bit profile, textures swim as the camera turns, because that is how the hardware mapped them. On the 64-bit profile, textures are small and soft, because there were only 4 KB for them. Too many triangles, a light too many or a modern material stops the render on the first frame that uses it, before it ships.

[The console kit](/software/groundslate/features/console-kit) shows each era, what the kit refuses on it, and the sound of its chip.

The game is yours: a platformer, a racer, a shooter, a quest. The agent invents the level and the hero with you and builds the level as a page that plays itself. The soundtrack comes from the era's own sound chip, held to that chip's voices and memory, or from a music bed written on your Mac. Everything renders locally.

> Use /groundslate-retro-game-video: make me a <<LENGTH>> <<TRAILER, PLAYTHROUGH OR TITLE SEQUENCE>> for <<YOUR GAME IDEA>>, as a <<16, 32, 64 OR 128>>-bit console game, in GroundSlate profile <<PROFILE ID OR NAME>>. Build it on GroundSlate's console kit and keep it inside the era: if the kit refuses something, change the design, never route around the refusal. Invent an original hero and world, or use my own brand and characters, and never a real console, game or someone else's character. The level plays itself, the camera follows the action, and the only text on screen is the game's own HUD and titles. Score it on that era's sound chip if you can run it, otherwise write a bed in GroundSlate. Show me the design and three style frames before you render, and tell me what did not resolve.

Everything in <<double brackets>> is yours. Fill it in before you paste. If you are not sure which era suits the idea, leave the number out and ask the agent to recommend one.

## Install it

Copy or download SKILL.md above.

For Claude Code, save it as `~/.claude/skills/groundslate-retro-game-video/SKILL.md`.

For claude.ai and the Claude desktop app, put it in a folder named `groundslate-retro-game-video`, zip the folder, and upload it under Settings, Capabilities, Skills.

## The skill

````markdown
---
name: groundslate-retro-game-video
description: Make a trailer, playthrough or title sequence for an original game that looks like it came off a real 16, 32, 64 or 128-bit console, built on GroundSlate's built-in console kit, which refuses anything the era could not show. The level plays itself as a seek-pure page, scored on the era's own sound chip, rendered locally.
---

# The game that never shipped

A video of a game from one console generation that holds up to people who played
those machines. The console kit enforces the era; your job is to design inside it.
The code blocks are literal.

## Before you start

```
list_profiles(); get_context()
composition_doctor()
list_kits(collection="groundslate", profile=...)
get_kit(name="console kit", collection="groundslate", file="CONSOLE_KIT.md", profile=...)
```

- `get_context` is machine scoped and names the ACTIVE profile. Confirm the
  profile with the user, then pass `profile=` on every dataset call.
- `composition_doctor` wants Playwright, headless Chromium and ffmpeg. Relay its
  install line and stop.
- If `list_kits` has no **console kit**, the installed GroundSlate is older than
  the kit. Tell the user to update from the app, and stop.
- Read CONSOLE_KIT.md in full before writing a line. It is the contract: the four
  profiles, what each allows and refuses, and the exact calls. The worked
  examples are in the kit too (`get_kit(..., file="examples/scene-16bit.js")` and
  the other eras): read the one for your era, keep its shape, and draw your own
  game's art.

## Three questions, then work

1. **The game.** The hero, the world, the one thing the player does. A hook, not
   a genre.
2. **The era.** Recommend one if they have not chosen, from what each looks like:
   16-bit is sprites and parallax, flat colour, no rotation, no transparency;
   32-bit is early 3D, swimming textures, snapped vertices, dithered shading;
   64-bit is soft filtered textures, fog, antialiased edges, small textures;
   128-bit is smooth shading, reflections, specular highlights, many triangles.
3. **The format.** Trailer, playthrough or title sequence; length; 16:9 or 9:16.

Never ask about sprites, palettes, tiles or timing. Those are the job. Then write
the design: the level as a sequence of moments (a jump, a pickup, an enemy, a
reveal), the hero's moves, the HUD, the camera, the music. Show it with three
style frames before you render anything.

## Invent everything, or use what the user owns

The hero, the world, the logo and the title are original, or they are the user's
own: their brand, their mascot, their product, their characters. Never a real
console name, maker, controller or logo, and never a game or character someone
else owns, and no screen that imitates one. The era is the look, not a brand.

## One page per console, on the kit

```
write_composition(name="<the game>-level-1", html="<the page>", profile=...)
```

Reference the kit from the built-in collection; never copy it into the folder:

```html
<canvas id="screen"></canvas>
<script src="_kit/_groundslate/console-kit/gs-console.js"></script>
<script src="_kit/_groundslate/console-kit/gs-console-fonts.js"></script>
<script>
  // build(con) makes the level, step(state, tick, con) plays one tick, draw(ctx, tick, state, con) paints it
  const con = GSConsole.boot({ profile: '16bit', native: [320, 180], output: [1920, 1080], canvas: 'screen' });
  GSConsole.run(con, { duration: 12, init: build, step, draw });
</script>
```

For 3D (32, 64 and 128-bit) add the importmap and the module. The address must
start with `./`:

```html
<script type="importmap">{"imports":{"three":"./_kit/_groundslate/puppet-engine-3d/three.module.min.js"}}</script>
<script type="module">
  import { boot3d } from './_kit/_groundslate/console-kit/gs-console-3d.js';
</script>
```

- **Output is an exact multiple of the native picture**: 320x180 at 6x, 384x216
  at 5x, 480x270 at 4x, 640x360 at 3x for 1920x1080. A console pixel is always
  a square block.
- **The level plays itself.** A game is a simulation that steps forward: pass
  `init(con)` and `step(state, tick, con)` to `run`, and let a bot play it (the
  hero runs, jumps at the gaps, takes the pickups). A seek backwards replays from
  the start, so every render is identical. No `Math.random()` and no clock:
  `GSConsole.rng(seed)` and `GSConsole.hash2(x, y)` are the noise.
- **Animation steps on the era's own tick** (60 or 30 a second), whatever the
  video's frame rate.
- **Several eras in one video** share one canvas: `GSConsole.sequence([...])`
  plays consoles one after another.

## Art the kit can check

- Sprites are string arrays with a palette: `GSConsole.sprite(frame, palette)`.
  Tiles, parallax layers and animation helpers are in the core.
- A picture you build yourself is `GSConsole.canvas(profile, w, h)`, drawn through
  the guard it hands back.
- Art the user supplies arrives as an image (a PNG), fully opaque or fully clear
  on the eras without transparency.
- Never a canvas the page made itself, an SVG, an image made at run time, or a
  video. The kit refuses them, because nothing checked how they were drawn.
- Text on screen is the bitmap fonts: `GSConsole.font8` (8x8) and
  `GSConsole.bigfont` (16 px display). No system font reaches the frame.

## 3D, the era's way

- Every mesh draws with `con.material(...)`, every texture comes from
  `con.texture(...)`, and a model from elsewhere goes through `con.adopt(...)`.
- Lights are `con.lights` and fog is `con.fog`, never three.js lights or fog.
- Stay inside the triangle budget: 4,000 a frame on 32-bit, 6,000 on 64-bit.
  Build low: a hero of a few hundred triangles, a world of boxes and slopes.
- The HUD is `con.hud` (opaque, drawn in `draw`). A HUD that fades or blends
  goes in `run`'s `overlay`.

## A refusal is the brief

When the kit refuses, the page stops and the render fails with a sentence: what
the era could not do, and what it did instead. Read the sentence and change the
design. Never step round it: a page that turns its own canvas into an image, or
feeds the renderer something the kit cannot see, produces a video that looks
wrong to exactly the people it is for.

## The sound

**The era's chip**, when you can run JavaScript outside the page (Claude Code, or
any agent with a shell and Node). The kit's `gs-console-audio.js` renders a score
on the era's chip, held to its voices, sample memory and effects, and writes a
WAV. `get_kit(name="console kit", collection="groundslate", file="gs-console-audio.js", ...)`
returns the file's `path` on this Mac; the kit's folder holds `gs-console.js`
beside it. Load both from there and run:

```js
const kit = '<the folder get_kit named>';
require(kit + '/gs-console.js'); require(kit + '/gs-console-audio.js');
const A = GSConsoleAudio;
const out = A.render('16bit', {
  bpm: 150, length: 12,
  tracks: [{ instrument: 'lead', notes: [[0, 1, 67], [1, 1, 69]] },
           { instrument: 'bass', notes: [[0, 2, 43]] },
           { instrument: 'taiko', notes: [[0, 0.5, 60], [2, 0.5, 60]] }],
  sounds: [{ t: 1.6, name: 'jump' }, { t: 2.1, name: 'grain' }],
  effects: { echo: { delay: 0.24, feedback: 0.42, mix: 0.28 } },
});
require('fs').writeFileSync('<the composition folder>/score.wav', A.wav(A.level(out, -15, -1)));
```

A note is `[beat, beats, midi, velocity]`; a sound is a one-shot at a time in
seconds. Put each jump and pickup at the time the level plays it: read the times
off your own simulation, never guess them. `GSConsoleAudio.patches` lists the
instruments. A refusal here reads like a graphics one (`too_many_voices`,
`sample_memory`, an effect the chip did not have): change the score.

**Otherwise**, write a bed in GroundSlate and add the effects:

```
generate_music(prompt="<era> console game music: <instruments>, <tempo>, <mood>, looping, instrumental",
               seconds=<length>, profile=...)
generate_sound_effect(prompt="<the jump or pickup, as a retro console sound>", seconds=4, profile=...)
```

Ask for four seconds of each effect and trim it: a very short take comes back
clipped.

## Render, then put the sound under it

```
render_html(html_path="<the page>", out_path="<picture>.mp4", width=1920, height=1080,
            fps=30, frames="png", profile=...)
render_ffmpeg(argv=["-y", "-i", "<picture>.mp4", "-i", "<score>.wav", "-map", "0:v:0",
                    "-map", "1:a:0", "-c:v", "copy", "-c:a", "aac", "-b:a", "256k",
                    "-shortest", "<film>.mp4"],
              out_path="<film>.mp4", profile=...)
```

`frames="png"` keeps pixel edges exact. A render that fails with a console
refusal is the kit doing its job: fix the page and render again.

## Look at it, then deliver

```
preview_html(html_path="<the page>", at=[0.5, 3, 6, 9], profile=...)
sample_frames(path="<film>.mp4", count=8, sheet=True, profile=...)
request_review(source="<film>.mp4", ask="<what to look at>", profile=...)
create_project(name="<the game>", kind="personal", profile=...)
commit_to_library(path="<film>.mp4", project="prj_0a1b2c3d4e", profile=...)
add_project_note(project_id="prj_0a1b2c3d4e", title="Build", body="<the era, the design,
    the pages, the score, anything the kit refused and what changed>", profile=...)
```

Check every frame for pixels that are not square blocks, smoothing on a hard-edged
era, a HUD that is hard to read, and anything on screen that is not the game.
Then report the era, the design, what the kit refused and how the design changed,
and what did not resolve.

## Nothing on screen but the game

No labels, captions, chapter numbers, credits or commentary unless the user asked
for them. No em dash in anything the game sets. Titles and the HUD are the game's
own, in the bitmap fonts.
````
