Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
a0fd710
kits: Super Mario, a System One harness plays a platform game in a br…
richard-epsilla Sep 20, 2026
ae389cf
mario: the panes fill the viewport and the panel scrolls; the list ke…
richard-epsilla Sep 20, 2026
b4fa314
mario: the page is the kits' shape, the frame streams, and a tall pip…
richard-epsilla Sep 20, 2026
b037693
mario: the state names enemies behind and question blocks, and the en…
richard-epsilla Sep 20, 2026
0a6502b
mario: the fourth pipe is cleared, and Mario is never left inside one
richard-epsilla Sep 20, 2026
ededfc6
mario: a question block Mario stands under is 'right overhead', never…
richard-epsilla Sep 20, 2026
df36b4f
mario: the README says where the runs stand
richard-epsilla Sep 20, 2026
20810b0
mario: New run starts over
richard-epsilla Sep 20, 2026
328fdbd
mario: what the recordings showed
richard-epsilla Sep 20, 2026
b0cbb77
mario: momentary actions, no waits: what the Jev demo does
richard-epsilla Sep 20, 2026
0d12ca1
mario: the environment executes key states and times nothing; the fac…
richard-epsilla Sep 20, 2026
c6c6769
mario: the state says what the facts call for now
richard-epsilla Sep 20, 2026
9e389fa
mario: the Now line speaks for the moment the decision lands, and the…
richard-epsilla Sep 20, 2026
9cdb6d8
mario: the Now line keeps the jump held while rising and lets an enem…
richard-epsilla Sep 20, 2026
a863b8c
mario: from standing the arriving enemy is jumped with jump_right, an…
richard-epsilla Sep 20, 2026
e72ddfe
mario: jump means press jump
richard-epsilla Sep 20, 2026
33a7a34
mario: the pipe and the gap ask for full speed, and a follower is let…
richard-epsilla Sep 20, 2026
21e06fa
mario: at a gap the jump waits for a clear landing
richard-epsilla Sep 20, 2026
08178eb
mario: a ledge enemy counts in the landing zone whichever way it walk…
richard-epsilla Sep 20, 2026
7d48c06
mario: the state projects by the loop's measured pace, and the page c…
richard-epsilla Sep 20, 2026
431770e
mario: the kit prompt carries every measured rule
richard-epsilla Sep 20, 2026
e093ecb
mario: in the air, walk_left brakes the landing short of a gap or an …
richard-epsilla Sep 20, 2026
66f087c
mario: enemies are named from 16 tiles
richard-epsilla Sep 20, 2026
cd5d88f
mario: the gap is named from 14 tiles and every jump goes before the …
richard-epsilla Sep 20, 2026
c6dca12
mario: the ground is a profile, a jump held in the air goes again on …
richard-epsilla Sep 20, 2026
49b860d
mario: the ledge wait never fires with a gap at Mario's feet, and the…
richard-epsilla Sep 20, 2026
385b136
Merge branch 'main' into kit-mario
richard-epsilla Sep 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 21 additions & 5 deletions kits.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,32 @@
"that talks to that Harness as its backend. Launching one provisions the Harness and opens",
"the app; there is no separate service to deploy and no database to configure.",
"",
"include — build this kit into the image. false leaves it in the repo and out of the",
"include \u2014 build this kit into the image. false leaves it in the repo and out of the",
" image, which is how a kit under development stays unshipped.",
"",
"Everything else a kit needs lives in kits/<name>/kit.json, next to the code it describes,",
"so adding a kit does not mean editing this file beyond one line."
],
"kits": [
{ "name": "slides", "include": true },
{ "name": "sheets", "include": true },
{ "name": "dashboard", "include": true },
{ "name": "video", "include": true }
{
"name": "slides",
"include": true
},
{
"name": "sheets",
"include": true
},
{
"name": "dashboard",
"include": true
},
{
"name": "video",
"include": true
},
{
"name": "mario",
"include": true
}
]
}
96 changes: 96 additions & 0 deletions kits/mario/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# Super Mario kit

A System One model plays a platform game, several decisions a second, and you watch the browser
it plays in.

## How it is put together

- **The harness** is a fork of the `systemone` base (the open-source
[System One Harness](https://github.com/HarnessRouter/SystemOneHarness)) with this kit's
instructions and one plugin. The base is general and knows nothing about this game; everything
about the game lives in the plugin, which is what a fork of a base is for.
- **The plugin** (`plugin/`) ships an MCP server, `bin/mario-env`, that is the environment: it
opens the game in a headless Chromium inside the deployment, reads the game's own state each step
and says it as short literal sentences (where Mario is, whether he is on the ground, the nearest
enemy, gap and wall with distances in tiles, and which hold clears the wall), and acts by holding
the keys the game listens to (`run_right`, `jump_right`, `jump`, `walk_left`, `wait`, each with a
hold length). The model never sees a pixel and never writes text; it chooses.
- **The page** (`app/`) is the same shape as the other kits: the stage on the left streams the
browser the model is playing in, and the conversation on the right is the run itself, every
decision with the game's reply, in the shared chat column the other kits mount. Play starts a
run with the default goal; the composer takes any other. The app bar has the way back to
HarnessRouter.

### The frame

The environment turns on the browser's own screencast and writes every third frame the game
draws to `frame.jpg` in the session's workspace, about twenty a second at 7 KB each. The page reads
that file through the session's live workspace, a few requests in flight at a time, shows a frame
once it has decoded and drops any that arrives after a newer one. The rate the page shows is the
rate of frames it actually displayed.

### What is measured, not tuned

The state is literal and the numbers in it come from the game: where Mario is and whether he is
on the ground, the ground ahead as a profile (the next gap, the next drop and what follows it, the
next step or wall and its height), the nearest enemy ahead and whether it walks toward him, the
nearest enemy behind him, the block rows overhead, the next question block, how far one decision
carries him at the loop's own measured pace, and a closing line beginning "Now:" that says what the
measured facts call for at this moment. The environment executes key states and times nothing:
an action sets the keys and returns, the keys stay set until the next action, and the model
chooses every step. Two things about the keys are the input layer's, the way a thumb plays:

- **A jump means a press.** `jump_right` or `jump` on the ground with the jump key still held from
the last jump lets it go and presses it again; the game wants the release.
- **A jump held in the air goes again on landing.** `jump_right` chosen while Mario is in the air
keeps the key down and presses it the moment he lands (any later action cancels it), so hops
chain the way they do under a held button. Recorded nine times in a row before this: the jump
over the fourth pipe comes down a tile before the first gap, and no decision could arrive in
time; the hop is now chosen in the air.

The facts the "Now:" line and the kit's instructions carry were measured on the live game, not
tuned: a running jump started 1.5 to 4 tiles before the first Goomba survives, 5 to 9 tiles hits
the block row and drops onto it, so when that window cannot be hit at the loop's pace the stop and
the standing jump (1 to 2.5 tiles, eight of eight) take over; a 4-tile pipe is cleared only at a
full run with the jump held long, taken 2 to 3 tiles before it; a gap or a drop is left from its
edge; a one-tile step is a hop and a stair is a hop per step; the ground is read from Mario's level
rather than his feet, so the floor is still there when he is below its top (read from his feet it
vanished, and three lives went to a "gap 12 tiles wide"); and the nearest thing ahead decides (a
gap five tiles on outranked the one-tile step he was pressed against for 284 decisions, until the
clock ran out). Each of these came from a recording: a copy of every frame the page shows, cut into
a contact sheet around each death, read, then measured with a probe before the environment changed.

A player that obeys the state's own "Now:" line with a model-like delay of 0.2 s is the
environment's test bench, apart from any model: on the level's current environment it clears 1-1
in 50 game seconds with one death (2026-09-20). The model's own runs are recorded the same way.

### Launching again after an update

A launch captures the kit's package onto the harness. A kit updated afterwards (a new image)
leaves the harness on the old package until something launches it again, so the page compares
the package version it was built with against the harness and relaunches it in place when they
differ. The base declares no built-in tools: its actions are the environment's, so the harness
settings list none.

## Credits

- The game is **Full Screen Mario**, played at [supermarioplay.com](https://supermarioplay.com/game/mario.html?v=1.0.1).
Mario and its characters belong to Nintendo; this kit plays the page as a person would and ships
none of the game's files.
- The browser is driven with [Browser Use](https://github.com/browser-use/browser-use) (MIT) over the
Chrome DevTools Protocol.
- The model is [Jev](https://typesafe.ai) by TypeSafe, a System One model, reached through OpenRouter.

## Running it

Launch the kit from Starter Kits with an OpenRouter key connected. The first launch on a fresh
install adds a Chromium beside the System One base (about a minute). Then press Play.

## Developing the page

```
cd kits/mario/app
npm install
npm run dev # against a console at the same origin, or set a proxy for /api and /kits
npm run build # what the image serves at /kits/mario
```
13 changes: 13 additions & 0 deletions kits/mario/app/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Super Mario</title>
<link rel="icon" href="/kits/mario/icon.svg" type="image/svg+xml" />
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>
Loading
Loading