@homie-rocks/studio 0.49.0 → 0.50.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/bin/homie-studio.mjs +5 -5
  3. package/functions/FUNCTIONS.md +1 -1
  4. package/guides/app/SKILL.md +107 -1
  5. package/guides/art/SKILL.md +154 -0
  6. package/guides/art/references/RIGHTS.md +20 -0
  7. package/guides/art/scripts/art.mjs +308 -0
  8. package/guides/models/SKILL.md +198 -0
  9. package/guides/models/references/RIGHTS.md +46 -0
  10. package/guides/models/references/models.json +175 -0
  11. package/guides/models/scripts/models.mjs +483 -0
  12. package/guides/music/SKILL.md +197 -0
  13. package/guides/music/references/COMPOSITION.md +59 -0
  14. package/guides/music/references/GAME-AUDIO.md +50 -0
  15. package/guides/music/references/RIGHTS.md +43 -0
  16. package/guides/music/scripts/lib/audio.mjs +258 -0
  17. package/guides/music/scripts/lib/eleven.mjs +260 -0
  18. package/guides/music/scripts/lib/studio.mjs +147 -0
  19. package/guides/music/scripts/music.mjs +644 -0
  20. package/guides/plan/SKILL.md +126 -0
  21. package/guides/plan/references/CODEX.md +105 -0
  22. package/guides/plan/references/INTERVIEW.md +86 -0
  23. package/guides/playtest/SKILL.md +205 -0
  24. package/guides/playtest/references/METHOD.md +124 -0
  25. package/guides/playtest/references/REVIEWER.md +78 -0
  26. package/guides/playtest/scripts/lib/exit.mjs +31 -0
  27. package/guides/playtest/scripts/lib/judge.mjs +502 -0
  28. package/guides/playtest/scripts/lib/pixels.mjs +128 -0
  29. package/guides/playtest/scripts/lib/preflight.mjs +69 -0
  30. package/guides/playtest/scripts/playtest.mjs +870 -0
  31. package/guides/shop/SKILL.md +4 -0
  32. package/guides/sound/SKILL.md +156 -0
  33. package/guides/sound/references/GAME-SOUND.md +100 -0
  34. package/guides/sound/references/SCORE.md +131 -0
  35. package/guides/sound/references/TRAPS.md +93 -0
  36. package/guides/sound/scripts/lib/measure.mjs +252 -0
  37. package/guides/sound/scripts/lib/score.mjs +415 -0
  38. package/guides/sound/scripts/lib/sfx.mjs +222 -0
  39. package/guides/sound/scripts/lib/synth.mjs +509 -0
  40. package/guides/sound/scripts/sound.mjs +520 -0
  41. package/guides/style/SKILL.md +105 -0
  42. package/lib/app-needs.mjs +63 -0
  43. package/lib/check.mjs +10 -4
  44. package/lib/codex.mjs +95 -18
  45. package/lib/decisions.mjs +9 -7
  46. package/lib/handoff.mjs +1 -1
  47. package/lib/mcp-tools.mjs +10 -9
  48. package/lib/mcp.mjs +1 -1
  49. package/lib/scaffold.mjs +13 -5
  50. package/lib/studio.mjs +3 -3
  51. package/lib/template-history.json +42 -0
  52. package/package.json +1 -1
  53. package/shop/SHOP.md +4 -0
  54. package/shop/shop.ts +4 -4
  55. package/worker/build-id.mjs +1 -1
  56. package/worker/functions-schema.mjs +15 -0
  57. package/worker/shop-page.mjs +1 -1
  58. package/worker/shop.mjs +6 -2
  59. package/worker/version.mjs +1 -1
@@ -0,0 +1,126 @@
1
+ ---
2
+ name: plan
3
+ description: Plan a game or app with the person before building it — sensible defaults from their request, with an interview only when requested that ends in the game's Game Codex, games/<id>/CODEX.md, drawn as a page in the game's own palette, fonts and art that anyone can read and steer (a Claude artifact where the app has artifacts, else a page in their browser, and a private page on the studio's site), kept true as decisions change, with the build's progress on it. Use for step 4 of a new studio, or when someone says "let's plan my game", "what should my game be", "make a design doc, a game bible or a codex", "show me the plan", or before a big change to a game.
4
+ ---
5
+
6
+ **One planning mechanism for games and apps.** For an app, use this workflow with `apps/<id>/CODEX.md`, created by `codex new <id> --kind app`. Its page, style decisions and build status use the same renderer as a game. Read the app skill's dream/scene/people/offers/needs instructions and fill those sections from the person's words; skip game-only sections and interviews. Build with the app skill, then prove its Codex needs on wall and phone. A starter is plumbing, never the planned scene. Choose engineering yourself and continue unless essential real-world information is missing.
7
+
8
+ # Plan a game: defaults and its Game Codex
9
+
10
+ You are in a Homie studio (a folder with `studio.json`) with a game in `games/<id>/`. The plan
11
+ comes out as the game's **Game Codex**: `games/<id>/CODEX.md` (the source of truth, in the studio's
12
+ repository) and a page drawn from it in the game's own look, with cards, tables and a Build status
13
+ tab. People who never read code see the game in it and steer it; you keep it true.
14
+
15
+ The implementation default is rules plus view on a server room, up to 32 seats.
16
+ Choose engineering details yourself; never ask the person to choose hosting, ownership,
17
+ tick rate or serialization. Capture the requested mechanic, controls, outcomes and visual
18
+ identity in the Codex. Read the game skill's RULES.md before implementing. A live app uses
19
+ the same transient rooms, without mandatory scores/bots/rounds, plus authorized records.
20
+
21
+ ## 1. Decide from the request
22
+
23
+ Default to doing the planning yourself. Choose genre, controls, camera, palette, room size,
24
+ round length, bots and scope from the person's premise. Use phones and computers, a small first
25
+ version, CC0 art and local sound. Infer cloud saves for persistent characters and collections;
26
+ short standalone rounds need none. Record decisions in the codex and continue building.
27
+ Never route engineering or design questions to the person. A pub or charity may want an app;
28
+ do not force a game interview onto it. Ask only when the intended outcome is missing.
29
+
30
+ When the person explicitly asks to plan together, use references/INTERVIEW.md as an optional
31
+ conversation aid. Their earlier answers count. Paid media needs a budget; use local assets until then.
32
+ Run `style init <id> --prompt "<their words>"` with automatic defaults unless they requested hands-on styling.
33
+
34
+ ### While planning: what already exists
35
+
36
+ Before the scope is fixed, look for what the game can be built from, two different things, and tell the person in a
37
+ line each:
38
+
39
+ - the `@homie-rocks/*` packages (npm) for the general mechanism: camera, input, audio, effects;
40
+ - `parts_find` for pieces other studios shared: a creature, a level generator, a bot brain. (With a shell and no
41
+ chat tools: `npx --no-install homie-studio parts find "<words>"`.)
42
+
43
+ Both go in the codex under **Built from**, with the game and studio each part came from and what will be written
44
+ from scratch (the `parts` skill).
45
+
46
+ ## 2. Write the codex
47
+
48
+ ```sh
49
+ npx --no-install homie-studio codex new <id> # games/<id>/CODEX.md with every section, in the studio's colours
50
+ ```
51
+
52
+ A new studio has no game yet: its game is planned before it is made. With no game `<id>`, `codex new <id> --name
53
+ "<Name>"` starts the game's folder with only the codex in it, and once you have recorded the plan, `game new <id> --from
54
+ gem-rush --name "<Name>"` makes the game around it (the codex stays).
55
+
56
+ Never replace an existing codex: change it. Fill every section from the request and your defaults (the format, with an
57
+ example: `references/CODEX.md`):
58
+
59
+ - **The look in the frontmatter**: the game's own `palette` (`bg`, `ink`, `accent` for headings,
60
+ `accent2`, `danger`, `good`), `fonts` (a Google Fonts family that fits: "Press Start 2P" or "Silkscreen"
61
+ for pixel games, a font file from the game's folder, or none), `pixel: true` for pixel art, a `cover`
62
+ from the game's folder, an `eyebrow` and a `tagline`.
63
+ - **Cards, not prose**, wherever there are several of a thing: characters, creatures, classes, items,
64
+ places, levels. Each `### Name` has its picture, a chip line (`` `C-01` `good: Ally` `danger: Boss` ``),
65
+ an italic one-line subtitle, a sentence, and `**Key:** value` stats.
66
+ - **Controls** as a table with a column per device; **Milestones** as a checklist (`- [x]` done) that
67
+ matches the scope; **Latest** as dated decisions (`- 2026-10-01: ...`); **Open questions** as a list.
68
+ - **Pictures** only from the studio's folder (a real frame of the game, its sprites, its cover, art the
69
+ `art` skill made). Until the game has art, a card without a picture is fine; never present a mock-up
70
+ as the game.
71
+
72
+ ## 3. Draw it and show it
73
+
74
+ ```sh
75
+ npx --no-install homie-studio codex <id> # .studio/codex/<id>.html; says what is not decided yet
76
+ ```
77
+
78
+ It reports the sections still empty (`missing`), the open questions and any picture it could not use.
79
+ Then show it where the person is:
80
+
81
+ - **An app with artifacts** (Claude Code's Artifact tool, the Claude app): `codex <id> --artifact`
82
+ writes `.studio/codex/<id>.artifact.html`, one self-contained page made to be published as an
83
+ artifact. Publish it (private to the person until they share it), and update the same artifact each
84
+ time the codex changes.
85
+ - **Otherwise**: `codex <id> --open` opens the page in their browser. It redraws itself whenever the
86
+ build's progress changes, and refreshes by itself while a build runs.
87
+ - **On their phone or anywhere else**, after a deploy: the site has it at `/_studio/codex/<id>/` for the
88
+ owner only, never listed; `npx --no-install homie-studio codex link <id>` gives a one-time link.
89
+
90
+ In the chat, say what you chose in one line, show the page, and continue. They can change it by asking.
91
+
92
+ ## 4. Keep it true
93
+
94
+ - **Every decision that changes the plan goes into CODEX.md in the same change**, with a dated line
95
+ under Latest, and the page is redrawn (and the artifact updated).
96
+ - Tick milestones as they land; move answered open questions into their section.
97
+ - "Where are we?" or "how far along is it?": the codex's Build status tab (or
98
+ `npx --no-install homie-studio progress show`), in a line or two.
99
+
100
+ ## 5. Progress, baked in
101
+
102
+ Open a progress feed for every build, titled with the milestone it works on:
103
+
104
+ ```sh
105
+ npx --no-install homie-studio progress start <id> --title "Milestone 2: the valley and hand-offs"
106
+ npx --no-install homie-studio progress stage plan done --note "<the plan in one line>"
107
+ ```
108
+
109
+ `build`, `check` and `deploy` report into it; mark what only you know with `progress check`,
110
+ `progress spend` and `progress log`; end it with `progress end passed|failed|stopped`. The codex's
111
+ **Build status** tab shows it: a percentage, each step and check going green, a "Ready to try" box (the
112
+ address and the codex's `try:` line), and what was spent. In Claude Code the status line shows one line
113
+ of it (offered in the setup step: `homie-studio statusline --install`). Codex CLI has no command status
114
+ line (its `tui.status_line` takes only built-in items), and Homie installs none in Grok Build, so in both the
115
+ codex page is the progress view.
116
+
117
+ ## 6. The look, before the first model
118
+
119
+ Before anything is made for the game's look, its decisions exist (`style init`, above): the automatic path says
120
+ one line ("Look: flat low-poly, autumn grove palette, golden hour, high three-quarter camera; open the codex to
121
+ change anything"); the hands-on path shows the style board (`style_explore`, or `style board <id>`) and lets them
122
+ pick, mix, steer and lock. Models then come from the `models` skill, free routes first.
123
+
124
+ ## 7. Then build
125
+
126
+ Build with the `game` skill, one agent by default. Use parallel agents when the person requested them.
@@ -0,0 +1,105 @@
1
+ # The Game Codex: the format
2
+
3
+ `games/<id>/CODEX.md` is plain Markdown that reads well on GitHub, plus a few conventions that
4
+ `homie-studio codex <id>` turns into a page in the game's own look. Everything in it is shown as text:
5
+ HTML in it is escaped, and an HTML comment (`<!-- … -->`) is a note for you that never shows.
6
+
7
+ ## Frontmatter: the look
8
+
9
+ ```yaml
10
+ ---
11
+ eyebrow: The Ashen Reach # a small label over each section's heading
12
+ tagline: Outrun the fire. Carry the last ember home.
13
+ cover: hero/wide.jpg # behind the title: a picture in the game's folder
14
+ palette:
15
+ bg: "#120c0a" # the page
16
+ ink: "#f6e7d3" # the text
17
+ accent: "#f4b23c" # headings, the title
18
+ accent2: "#7ad38a" # eyebrows, links, the tab bar's Build tab
19
+ danger: "#ff5a4e" # danger tags
20
+ good: "#5fdc8b" # good tags, ticks
21
+ gold: "#f2c14e" # rare tags, the Ready to try box
22
+ fonts:
23
+ display: Press Start 2P # a Google Fonts family name, or a .woff2/.ttf in the game's folder
24
+ body: Inter
25
+ mono: JetBrains Mono
26
+ pixel: true # pictures keep hard pixel edges when scaled
27
+ try: Arrow keys or WASD to run, Space to dash. Open a second tab to see two runners in one room.
28
+ ---
29
+ ```
30
+
31
+ Every key is optional. A colour that is missing comes from the game's landing theme (game.json
32
+ `landing.theme`), then the studio's `site/theme.json`. Colours are `#hex`, `rgb()` or `hsl()`; a font is a
33
+ family name of letters, digits and spaces, or a file; anything else is left out with a warning. A light
34
+ `bg` draws a light page.
35
+
36
+ ## The body
37
+
38
+ - `# Name` is the title (else game.json's name). The paragraph under it is the pitch.
39
+ - Every `## Section` is a tab, in the order written. The usual ones, which `codex` counts as decided once
40
+ they have something in them: **Concept**, **World**, **Characters**, **Art direction**, **Controls**,
41
+ **Rooms and players**, **Music and sound**, **Milestones**, **Open questions**, with **Latest** first.
42
+ Name others freely (Items, Classes, Levels, Story, Death, Quests…); they are tabs too.
43
+ - The **Build status** tab is added by itself, from the game's progress feed.
44
+
45
+ ## Cards: `### Name` under any section
46
+
47
+ ```markdown
48
+ ## Creatures
49
+
50
+ Wisps chase whoever holds the ember; moths only fight back.
51
+
52
+ ### Cinder Wisp
53
+ ![Cinder Wisp](art/cinder-wisp.png)
54
+ `M-01` `danger: Aggressive · 6 tiles` `gold: Rare at night`
55
+ *Level 1–3 · the burning floor*
56
+ Drifts toward whoever holds the ember; touching it costs a spark.
57
+ - **Where:** everywhere the grass is burning
58
+ - **Health:** 2 hits
59
+ - **Drops:** a short speed boost
60
+ ```
61
+
62
+ - The first picture is the card's art (a sprite or a portrait; small pictures stay crisp with `pixel: true`).
63
+ - A line of only `` `code` `` chips: one like `M-01` or `C-12` is the card's id; the rest are tags. A tag's
64
+ colour comes from `good:`, `danger:`, `gold:` or `info:` in front, else from its words (aggressive,
65
+ boss, enemy are danger; passive, ally, player are good; rare, elite, legendary are gold).
66
+ - A line in italics is the card's subtitle (level, place, class).
67
+ - A list where every item is `**Key:** value` (or `Key: value`) is the card's stats, in the mono font.
68
+ - Anything else is the card's text.
69
+
70
+ Text before the first `###` of a section is its introduction.
71
+
72
+ ## Tables, checklists, the decision log, pictures
73
+
74
+ ```markdown
75
+ ## Controls
76
+
77
+ | Action | Phone | Computer | TV and phones |
78
+ | --- | --- | --- | --- |
79
+ | Run | drag from the lower left | WASD or arrows | each phone is a pad |
80
+ | Dash | tap the right side | Space | the pad's A |
81
+
82
+ ## Milestones
83
+
84
+ - [x] Step 1: a working copy of the starter plays in two browsers
85
+ - [ ] Step 2: the valley, the wisps and hand-offs, checked with two browsers
86
+
87
+ ## Latest
88
+
89
+ - 2026-10-01: Rounds go to 90 seconds; the valley needs time to cross.
90
+ - 2026-09-30: Pixel art at 16 px, scaled 4x, no smoothing.
91
+ ```
92
+
93
+ - Under **Latest**, a list item that starts with a date is a decision; the page shows them newest first.
94
+ - A picture on a line of its own is a figure; several in a row are a gallery. Pictures come only from
95
+ inside the studio (a path from the game's folder, or from the studio's root) and are embedded in the
96
+ page: png, jpg, webp, gif or svg, up to 2.5 MB each and 10 MB in all. A web address is not loaded.
97
+ - **Open questions** are drawn as numbered question cards.
98
+
99
+ ## Keeping it true
100
+
101
+ - One codex per game; change it, never replace it.
102
+ - A changed decision: change its section, add a dated line under Latest, redraw (`codex <id>`), and update
103
+ the artifact if there is one.
104
+ - The codex is the person's plan, not a public page: it is not served
105
+ with a game's files, and on the site only at `/_studio/codex/<id>/` for the owner.
@@ -0,0 +1,86 @@
1
+ # Plan interview: questions with options
2
+
3
+ Only for a person who explicitly requests an interview. Otherwise infer these choices from the premise and continue building. Adapt the options to what the person has
4
+ said; these are starting points, not a script.
5
+
6
+ ## 1. Game type and genre
7
+
8
+ - "What kind of game? A brawl in an arena, a race, a co-op survival, a puzzle versus, a party game of
9
+ quick rounds, an adventure with a world to explore? From what you changed, I'd guess a brawl."
10
+ - "What does a player do in the first ten seconds?" (move and grab, aim and shoot, draw, guess, build)
11
+ - "How does a round end? First to a score, last one standing, the most points when the clock runs out?"
12
+ - Multiplayer shape: "Everyone against everyone, two teams, or all together against the game?"
13
+
14
+ ## 2. Style and art direction
15
+
16
+ - "Pixel art, painterly, low-poly 3D, clean vector shapes, neon on black, hand-drawn? For phones at a
17
+ glance I'd pick pixel or vector: they read small."
18
+ - "Name a game, film or picture it should feel like." (Two or three references are plenty.)
19
+ - "Day or night, cosy or tense, bright or moody?" Then propose a palette of four or five colours.
20
+ - Fonts: suggest one display font that fits (pixel: "Press Start 2P", "Silkscreen"; storybook: "Fraunces";
21
+ sci-fi: "Orbitron", "Exo 2"; clean: "Inter").
22
+ - If they want to discuss it: "Do you want to steer the look closely (I'll show you three directions, drawn by the game itself,
23
+ and you lock what you like), or should I pick and show you?" Hands-on: the `style` skill's board. Pick for me:
24
+ `style init` with their words, then one line about the look.
25
+ - And once: "Art budget: free only (the starter library and the engine), a small budget on your own fal account
26
+ (I'd suggest US$5 for a handful of generated props), or your own number?" Free only means no generated assets
27
+ at all; the number is a hard cap (the `models` skill's `budget`).
28
+
29
+ ## 3. Devices
30
+
31
+ - "People will play on phones and computers. Should it also work on a TV with phones as controllers, so
32
+ friends on one couch play together?" (Say what that adds: the big screen view and each phone a pad.)
33
+ - Per device: "On a phone you steer from the lower left and press on the right; on a computer, keys.
34
+ Anything that needs more than that?"
35
+
36
+ ## 4. Players and rooms
37
+
38
+ - "How many in a room: 2 to 4 for a duel feel, 6 to 8 for a party, larger rooms for a crowd?"
39
+ - "Rounds of 60 seconds, 90, or longer?" (Short rounds keep strangers.)
40
+ - "Bots fill empty seats. Should they be easy, or play to win?"
41
+ - "Someone who joins mid-round takes a bot's place. Do they keep the bot's score or start at zero?"
42
+
43
+ ## 5. Progress and saves
44
+
45
+ For an explicitly requested interview only: **"Does progress need to persist across sessions or devices?"** Then, if it does:
46
+
47
+ - "What does a player keep between visits: a character and its level, an inventory, unlocks, a collection,
48
+ their settings? I'd keep the hero in one save, so it always saves whole."
49
+ - "Should it follow them to their phone and their laptop? Then they make an account with a passkey (Face ID or
50
+ a fingerprint, no password); until they do, they play as a guest and keep it on that device."
51
+ - "Lifetime numbers that never reset: kills, gold earned, time played, best level?"
52
+ - "Can a death be forever? A hardcore mode wipes the character and writes its name in a hall of the fallen."
53
+ - No persistence (a match is all there is): say so in one line and move on; nothing to wire.
54
+
55
+ ## 6. Art and film
56
+
57
+ - "Who are the characters, creatures or pieces? Name them and I'll give each a card."
58
+ - "Places: one arena, or several levels or zones?"
59
+ - "A cover and a trailer come from the game itself, free. Painted art or generated video is on your own
60
+ fal account with a budget you set: want any of it, and how much at most?"
61
+ - For a 3D game: "Models come free from the engine and Homie's CC0 starter library first; a few signature props
62
+ can be generated in your locked style for about US$0.54 each. Any you already own to bring in?"
63
+
64
+ ## 7. Music and sound
65
+
66
+ - "A theme that loops while you play: fast and driving, calm, spooky, heroic? About what tempo?"
67
+ - "Which moments need a sound you'd recognise with your eyes closed?" (pick-up, hit, win, countdown)
68
+ - "Synthesized here for free, or a song from ElevenLabs on your own plan (quoted first)?"
69
+
70
+ ## 8. Scope
71
+
72
+ - "For the first playable version: the core loop, one place, two or three characters, bots. Then art,
73
+ sound and the landing page. Then more places or modes. Sound right?"
74
+ - "Anything that must be in the very first version?"
75
+ - "Anything you don't want at all?"
76
+
77
+ ## Genre starters
78
+
79
+ | Genre | Ask about | A good default |
80
+ | --- | --- | --- |
81
+ | Arena brawl | knock-back, power-ups, the arena's hazards | 6–8 players, 60 s rounds, most knock-outs wins |
82
+ | Race | track shape, boosts, catch-up | 4–8 players, three laps or 90 s, first across wins |
83
+ | Co-op survival | waves, the enemies, reviving | 2–6 players, waves of 30 s, survive as many as you can |
84
+ | Party / quick rounds | the minigames, scoring across rounds | 4–8 players, 30 s rounds, five rounds a match |
85
+ | Puzzle versus | the board, sending trouble to others | 2–4 players, until one board fills |
86
+ | Adventure / RPG | classes, monsters, loot, zones, death, what persists | 2–8 players in a shared world, rounds as days or quests; the hero in cloud saves (start from the `ember-vale` starter) |
@@ -0,0 +1,205 @@
1
+ ---
2
+ name: playtest
3
+ description: Playtest a studio's app against its owner's Codex needs, or its game the way Homie holds its own games to a bar — real browsers on a computer and a phone held both ways, the first ten seconds timed, the look measured (black or flat frames, contrast, detail), how much of the screen the UI covers, the game's real sound captured and measured, a round played with one person trying and one doing nothing, the owner control tests and two strangers finishing a round — then a blind review by a fresh reviewer that never saw the code, and a ranked list of what is weak. Use when someone asks to playtest, test, review, critique or judge a game, asks what is weak or what to fix next, before calling a game finished or publishing it, and after every change that should make it better.
4
+ ---
5
+
6
+ ## Apps: judge the place against its owner’s words
7
+
8
+ For an app, read `apps/<id>/CODEX.md` first. This is the app branch of the same playtest: no rounds, scores or invented entertainment. Run build and `check <id> --shots .checks` (including its Codex needs), then open the wall and phone in real Chrome. The game script below measures games; do not run a round instrument on an app.
9
+
10
+ Walk in as the owner. Read **Their words** aloud to yourself, then inspect the wall capture: is the pictured place there, do recognisable things move/fill/arrive/light up as requested, and can someone across the room understand the work? A generic board of boxes fails a living-scene request even if every label is correct. Check an empty and a busy state without passing invented records off as real customers. Inspect state before and after a real action, not only a pretty still.
11
+
12
+ Now arrive as a new customer on a phone: find the offer and correct price, book/give/log/sign up, understand success or failure, save the return link, reload and follow your own record. Use a second phone to check the link follows the same thing. As staff, sign in and perform the real work; as a public visitor, verify privileged writes are refused. Close all browsers and return: the work must remain. A simulated paid event is not a real charge; record payment connection gaps honestly.
13
+
14
+ For every need, write `met / partly / not`, the exact capture or flow that demonstrates it, and what remains. Check phone portrait/landscape, wall readability, kiosk reset if present, native controls, keyboard focus and reduced motion. Do not infer usability from a build or a shared counter. Inspect the saved captures yourself; automated selector assertions cannot judge the dreamed scene. Copy the verdict and evidence into the Codex and redraw its page. Keep unfinished needs visibly unfinished. No approval question is needed for local checks or your visual review.
15
+
16
+ A local review is labelled local, not independent. If a fresh reviewer was requested, give that reviewer the owner's original request, the Codex and real captures/flow addresses; ask them to judge as owner and customer, need by need. When comparing several businesses, they must read as different places with different work, not a common template recoloured. If one fails, identify what the builder read or skipped, repair that making path, and build/test again before saying done.
17
+
18
+ # Playtest a game
19
+
20
+ The question is never "does it run". It is: **would a stranger who pressed Play stay for a whole
21
+ round, and come back?** Instruments measure what can be measured; a fresh reviewer who never saw
22
+ the code answers the rest. A builder never grades its own work.
23
+
24
+ One script: `scripts/playtest.mjs` in this skill's folder (Claude Code:
25
+ `node "${CLAUDE_PLUGIN_ROOT}/skills/playtest/scripts/playtest.mjs" <command>`), run from inside the
26
+ studio. It needs Node 22, Chrome and the studio's `@homie-rocks/studio` (for puppeteer-core and its
27
+ checks). It opens at most two browsers at a time, all muted: nothing plays out loud.
28
+
29
+ For rules games, build first: the guard, strict types and deterministic play check must pass
30
+ before Chrome opens. Both online browsers are replicas of a server host; killing the first
31
+ browser tests continuity, not host election. Use the real predicted pose in the probe, never
32
+ fake movement or scores. Test local movement with 150 ms delay and also verify hits, scores,
33
+ turns and results agree after authority arrives. A turn game, quiz or live app needs its actual
34
+ buttons and workflow exercised: movement-only rows do not prove it works, and an app has no
35
+ required game round. Use the app check for shared actions and reconnect. Report inapplicable
36
+ rows honestly, and add a manual two-browser trial of the requested mechanic.
37
+
38
+ ## 1. Run the site and the instruments
39
+
40
+ Start the site as a background task that outlives the command (Claude Code: the Bash tool's
41
+ `run_in_background`), wait until the play page answers, then:
42
+
43
+ ```sh
44
+ npm run dev # background: http://127.0.0.1:8787 (another port: npx --no-install homie-studio dev --port <n>)
45
+ node <playtest.mjs> run <game id> --url http://127.0.0.1:8787
46
+ ```
47
+
48
+ It takes five to ten minutes; poll its output, never end your turn while it runs, and do not rebuild
49
+ while it runs (a rebuild under `npm run dev` can stop the dev server). `--only first,look,ui,sound`
50
+ runs some rows; `--seconds 30` plays longer. The live site works too (`--url` the studio's address).
51
+ Stop the site afterwards with `npx --no-install homie-studio dev --stop`.
52
+
53
+ | row | what it does | fails when |
54
+ | --- | --- | --- |
55
+ | `first <device>` | opens the play page like a stranger on a computer, a phone, a phone on its side, and times four separate things: a seat, the page's first paint (the loading card, not the game), the loading cover lifting, and the first picture of the game itself (cover gone, the game's own frames advancing); frames per second; the GPU | no seat, a cover that never lifts, or no picture of the game in 10 s |
56
+ | `move <device>` | waits for a live round and a body that is the player's, then presses right and times the body moving; when nothing moves it presses left too and reports both, with the position, round phase and time left at each press | the body answers after 1.5 s, or neither way moves it in a live round. WARN when only the opposite way moved (a wall on that side looks like this). BLOCKED when no press fit inside a live round with a free body |
57
+ | `look <device>` | plays like a person (holds a direction most of a second, sometimes the action, changes its mind) and shoots the screen: brightness, contrast, colour, visible detail, black or one-colour frames, holes where nothing drew, frames that did not change | a black or one-colour frame, pure-black holes; WARN for dark, flat, featureless or still frames |
58
+ | `ui <phone>` | waits for active play, holds the thumb on the stick, hides the world, paints the page black then white, and counts what stays: the share of the screen the DOM UI covers and what is opaque in the middle third. Both frames are saved with the game's state at each | over 12% covered, or anything opaque in the middle, during active play. N/A when the screen was the results card, a spectator view, the loading cover or a browser cut off from its room (measured, labelled, not judged by that bar). BLOCKED when the game changed state between the two frames. WARN when it would pass and a DOM HUD element sits under one of the play page's own controls (the room button, the server or chat pill, the banner): the row names the element and the control |
59
+ | `sound` | copies what the game sends to its speaker while it is played (no autoplay flag: the real first-touch rule); loudness overall and through a phone speaker, true peak, clipping, gaps, whether each action press answers with a sound, whether music started | silence, clipping; WARN for quiet, gaps, actions without sound, what a phone loses |
60
+ | `play` | a computer plays (direction holds and the game's primary action) and a phone does nothing, in the same public room, for a round that starts after both are in: places, scores, round length against `game.json`, lead changes, and which inputs the script really pressed | no round finishes; WARN when doing nothing scores as well as playing, everyone ties, or a bot is far ahead (a measured gap in one scripted round, never "people cannot win") |
61
+ | `controls` | the owner tests from `homie-studio port check`: hold a direction 5 s (one straight line, the camera's yaw moves under 10°), alternate directions 10 s (every press goes the pressed way), real touch on Android Chrome (and iPhone WebKit when Playwright's WebKit is installed; otherwise that row says skip), the first browser closing (server continuity; host election only for older games), a late joiner, the big screen, audio unlock, errors | any of them (`port` skill: `references/CHECKS.md` says what each failure usually means) |
62
+ | `round` | `homie-studio check`: two fresh browsers press Play, meet in one room and both see a round finish with both of them in the results; reconnects are reported beside completion | they do not. WARN when the round finished and a browser reconnected on the way |
63
+ | `errors` | uncaught errors and failed requests seen along the way | any uncaught error |
64
+
65
+ **BLOCKED is never PASS.** A browser rendering at a few frames a second (a software renderer, a
66
+ machine under heavy load) makes any game look stuck: the rows say BLOCKED and judge nothing. Run
67
+ again on a quieter machine. "Could not test" and "tested and fine" must never sound the same.
68
+ The same goes for the instrument's own faults: a screenshot decoder that does not finish in 20 s
69
+ is stopped, that device's rows say BLOCKED, the browser is closed and the run exits non-zero; a
70
+ site address this computer's Node.js cannot look up (a browser may still open it) stops the run as
71
+ BLOCKED, "network preflight failed, before any page or game was opened" (the words `check`, `perf`
72
+ and `port check` use for it too), and offers the local site. **N/A** means the row did not apply to what
73
+ was on screen. One scripted run is one run: report a gap as measured once, and repeat before
74
+ concluding.
75
+
76
+ ### What the game tells the instruments
77
+
78
+ Every press and every picture is recorded with the game's state, read from its port probe
79
+ (`exposePort`, the `port` skill) and the play page: round phase and time left, whether the body is
80
+ the player's to steer (`busy`), where it is. A game with no probe still runs, and its rows say the
81
+ phase was unknown. Three optional things make the rows sharper; none is required:
82
+
83
+ - In `exposePort(net, { extra: { ... } })`: `alive: () => boolean` (false: spectating until the
84
+ next round), `mode: () => string` (the control mode on screen), `loadout: () => string` (what
85
+ the player holds, when it changes which controls show), `touchHeld: () => boolean`, and
86
+ `drawCalls` / `triangles` (`renderer.info.render.calls` / `.triangles`: the look row then
87
+ reports measured runtime scene cost, which is not the asset inventory's estimate).
88
+ - In `game.json`, the primary action, so a shooter is played by firing and not by the space bar:
89
+
90
+ ```json
91
+ "playtest": { "primary": { "label": "fire",
92
+ "computer": { "mouse": "left" },
93
+ "phone": { "selector": "[data-action=fire]" } } }
94
+ ```
95
+
96
+ `computer` is `{ "key": "<KeyboardEvent.code>" }` or `{ "mouse": "left|right|middle", "at": [x, y] }`;
97
+ `phone` is `{ "selector": "<css, in the game's frame>" }` or `{ "region": [x, y, w, h] }`
98
+ (fractions of the screen). Undeclared, the script presses the space bar and taps a fixed spot,
99
+ says that was a guess, and qualifies anything it concludes from the scores. It does not aim.
100
+ - In `game.json`, `"scoring": "together"`: every result row carries the room's one shared total,
101
+ so the play row marks the active-against-idle comparison not applicable.
102
+
103
+ The UI row measures DOM coverage only. A HUD, labels or hints drawn inside the canvas are hidden
104
+ with the world and are not checked for coverage or overlap; REPORT.md says so beside the result.
105
+
106
+ The UI row also lays the game's visible DOM HUD against the play page's own controls, which the
107
+ page draws over the game's frame and reports as `window.__shell.rects` (the game reads the same as
108
+ `net.shell` / `net.on('shell')`). A HUD element under a control that stays is a WARN with both
109
+ named; under the "N playing" chip, which fades, it is a note. Fix it by laying the HUD out around
110
+ `net.shell`'s rectangles, or by moving the page's controls (`game.json` `screen.share`,
111
+ `screen.chat`). A page that reports no layout (an older studio) is said to be unchecked.
112
+
113
+ A reading taken while the browser was not in its room is labelled, never judged as play: the
114
+ helper's link (`window.__homieNet.link`, and `window.__shell.link.state`) says `reconnecting`,
115
+ `alone` (the room never answered; an older browser-hosted game may play locally), `offline` or `closed`, and a
116
+ press, a picture or a UI frame sampled then is BLOCKED or N/A with "CUT OFF from its room" in its
117
+ state. The round row says a browser "was seen cut off" beside completion.
118
+
119
+ The run writes `.playtest/<game>/<time>/` in the studio (added to `.gitignore`): `REPORT.md`,
120
+ `report.json`, contact sheets (`sheet-desk.png`, `sheet-phone.png`, `sheet-phone-landscape.png`),
121
+ every screenshot (the UI row's pair as `*-ui-on-black.png` and `*-ui-on-white.png`), `sound-capture.wav` and its spectrogram, and the owner-test receipts.
122
+ **Open the contact sheets and look at every picture before believing any number.**
123
+
124
+ ## 2. The blind review
125
+
126
+ For a rules game with maxSpeed 0 on every player kind, the toolkit marks the
127
+ movement probe stationary. First-move rows say N/A and directional owner tests
128
+ say not applicable, never PASS. Exercise its actual choices/taps/turns in two
129
+ browsers and measure local feedback separately from authoritative acceptance.
130
+ Do not add movement, fake pose samples or a board-direction probe to silence a check.
131
+ A hold entirely inside a hiding countdown, death or stun is blocked evidence.
132
+ Wait for an active, steerable phase and repeat the real controls in both browsers;
133
+ record that directed result beside the generic row. Keep the mechanic and honest
134
+ busy/alive probes; never remove a freeze or disguise it to turn a row green.
135
+
136
+ ```sh
137
+ node <playtest.mjs> review .playtest/<game>/<time>
138
+ ```
139
+
140
+ It writes `REVIEW.md` in that folder: a brief for a FRESH reviewer, with the pictures, the numbers and
141
+ a rubric.
142
+
143
+ **An outside review is optional, only when requested.** Finish local checks and your own visual review without an extra question. When an outside review is requested, it hands screenshots outside this session: use the authorization already given, or ask once if the destination was not specified.
144
+ The command prints `approval`: one self-contained question naming every file it sends (REVIEW.md,
145
+ report.json and the listed pictures), the report folder they come from, and the destination (name
146
+ it with `--to "<the reviewer>"`: a subagent in this session, or an external command such as a
147
+ second coding agent). For a requested outside review without prior destination consent, ask that question once. One yes covers that report
148
+ folder and that reviewer; another folder or reviewer is a new question. `review-request.json` in
149
+ the folder keeps the same list. A host that reviews what an agent sends may still refuse the
150
+ transfer: that is the host's decision. Do not rephrase and retry it, and do not send the pictures
151
+ another way. Then one of:
152
+
153
+ - `node <playtest.mjs> review <folder> --local` writes `REVIEW-LOCAL.md`: the same rubric for
154
+ this session to score the contact sheets itself. Nothing leaves the session. It is the builder
155
+ grading its own build, so it is labelled **not independent** everywhere, and you say so in the
156
+ first sentence when you report it.
157
+ Read that brief and every listed picture, follow its JSON rubric and write
158
+ `VERDICT.json` with `"review": "local"` in this exact run folder BEFORE calling
159
+ `reviewed --kind local`. The `reviewed` command records a verdict; it does not create one.
160
+ Rubric parts use 0–10; the overall JSON `score` and `--score` use **0–100**
161
+ (for example, an overall seven out of ten is `--score 70`, not `7`).
162
+ - Record what happened, always: `node <playtest.mjs> reviewed <folder> --kind independent --by
163
+ "<who>"`, `--kind local --reason "<why>"`, or `--kind none --reason "<why>"`. REPORT.md and
164
+ `report <folder>` then say which review this run had. With no record, or `none`, the review line
165
+ is BLOCKED: a missing review never reads as a passed one. Hand its WHOLE TEXT, unchanged, to a reviewer that has not seen the code, the plan or your
166
+ summary (Claude Code: the Agent tool with the file's full contents as the prompt, never just its path
167
+ or your summary of it; Codex: a new session). Add nothing about what you built or changed. It plays the game itself, scores it
168
+ 0-100 in eight parts, and returns gaps ranked by impact, each with evidence it saw and one concrete
169
+ fix. Its verdict outranks yours. Put it in the run folder as `VERDICT.json`.
170
+
171
+ Comparing against other games (the person's references, the studio's last version, a game they
172
+ admire): give the reviewer frames of each under shuffled labels, scored before the labels are revealed.
173
+ A reference is a bar ("is it as good as that"), never a template ("make it look like that").
174
+
175
+ A game with models: give the reviewer the style board, the golden images and the lineup pictures
176
+ (`homie-studio assets lineup <id>`, in `.studio/art/<id>/`) beside the frames, and add one question: "does every
177
+ frame look like ONE game?" (1-10, naming outliers). Record it with `homie-studio assets review <id> --score <n>
178
+ --outliers <ids>`.
179
+
180
+ ## 3. Say what is weak
181
+
182
+ Lead with the numbers and the review, most important first: what fails, then what the reviewer would
183
+ fix first. Group findings by cause before proposing work (five complaints about flat shapes are one
184
+ missing lighting model, not five jobs). Name the one change that would matter most. Then, if the
185
+ person wants, fix it and run the same instruments again; a change that does not measure better than
186
+ the version before it is a regression, not progress. When the weak thing is speed (a low frame rate in
187
+ `first`, a slow first ten seconds, a phone that struggles), the `perf` skill measures it properly: frame
188
+ times and CPU per frame for player browsers (server tick work is separate), alternating runs,
189
+ and only changes that beat the noise.
190
+ When the weak thing is how a move feels (a hit that does not land, a floaty jump), the `lab` skill compares the
191
+ change with the last commit frame by frame, with the person.
192
+
193
+ `references/METHOD.md` has the method behind the rows: playing like a person, the five numbers a
194
+ round owes you, the scenarios, seats with different strategies, the do-nothing test, the ten-second
195
+ test, and the traps that make an instrument lie.
196
+
197
+ ## Never
198
+
199
+ - Never call a game good, fixed or finished from the code, a build that passed, or your own look at it.
200
+ - Never report a local review as a blind one, and never read a BLOCKED or N/A row, or a missing review, as a pass.
201
+ - Never turn one scripted round into a rule ("people cannot win", "input does not matter"): say what was measured, and run it again.
202
+ - Never call the builder's local verdict an independent review: an independent reviewer is fresh every time.
203
+ - Never script a player to make a number look good; the instruments play like a person on purpose.
204
+ - Never leave a room open on a live site: the playtest's browsers leave when it ends; do not start
205
+ more than two browsers of your own beside it.