@homie-rocks/studio 0.24.5 → 0.26.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 (45) hide show
  1. package/CHANGELOG.md +54 -1
  2. package/README.md +56 -6
  3. package/assets/animate.ts +521 -0
  4. package/assets/render-page.ts +77 -4
  5. package/bin/homie-studio.mjs +13 -4
  6. package/lib/art-cli.mjs +105 -5
  7. package/lib/art-tools.mjs +168 -1
  8. package/lib/asset-check.mjs +72 -5
  9. package/lib/characters.mjs +380 -0
  10. package/lib/clips.mjs +417 -0
  11. package/lib/decisions.mjs +38 -8
  12. package/lib/mcp-tools.mjs +1 -1
  13. package/lib/mcp.mjs +2 -2
  14. package/lib/optimise.mjs +79 -3
  15. package/lib/perf.mjs +15 -7
  16. package/lib/render3d.mjs +2 -0
  17. package/lib/rig.mjs +431 -0
  18. package/lib/scaffold.mjs +7 -0
  19. package/lib/site.mjs +14 -3
  20. package/lib/studio.mjs +18 -3
  21. package/lib/style-board.mjs +3 -1
  22. package/lib/template-history.json +78 -0
  23. package/mcp/ui/animation.js +56 -0
  24. package/mcp/ui/card.css +4 -0
  25. package/mcp/ui/cast.js +36 -2
  26. package/mcp/ui/lineup.js +7 -7
  27. package/netplay/NETPLAY.md +38 -2
  28. package/netplay/netplay.ts +58 -3
  29. package/package.json +5 -1
  30. package/site/SITE.md +19 -1
  31. package/starters/gem-rush/game.json +2 -1
  32. package/starters/gem-rush-3d/game.json +2 -1
  33. package/starters/hero-rush-3d/assets/RIGHTS.md +163 -0
  34. package/starters/hero-rush-3d/assets/manifest.json +1471 -0
  35. package/starters/hero-rush-3d/credits.json +40 -0
  36. package/starters/hero-rush-3d/game.json +12 -0
  37. package/starters/hero-rush-3d/index.html +20 -0
  38. package/starters/hero-rush-3d/lab.json +32 -0
  39. package/starters/hero-rush-3d/src/main.ts +2588 -0
  40. package/starters/hero-rush-3d/style.json +68 -0
  41. package/starters/hero-rush-3d/tunables.json +32 -0
  42. package/worker/arrival.mjs +207 -0
  43. package/worker/pages.mjs +23 -5
  44. package/worker/site.mjs +26 -4
  45. package/worker/version.mjs +1 -1
package/CHANGELOG.md CHANGED
@@ -17,9 +17,62 @@ To bring a studio up to date, tell Claude: "Upgrade my studio to the newest Homi
17
17
  `npx -y @homie-rocks/studio@latest upgrade`, which shows what's new since the version your studio pins (from this
18
18
  file) and what the upgrade would change, and changes nothing until you agree.
19
19
 
20
+ ## [0.26.0] - 2026-10-03
21
+
22
+ **Plugin 0.27.0** · [#40](https://github.com/homie-rocks/homie/pull/40)
23
+
24
+ A game's first minute: Play never opens on a blank screen, a bright game gets a bright landing in its own palette, and in Hero Rush 3D a new player's first round is a race they are in.
25
+
26
+ ### Added
27
+
28
+ - The arrival card. From the play page's first paint (and the big screen's), the game's own look covers its frame while the room connects and the game loads: its title and pitch, its key art (the landing's hero still, a trailer's poster or its cover, drifting slowly), a progress line that says what is happening ("Finding a room…", "Room 4 · 3 playing · 2 AI", "Loading the game…", "Joining Room 4…", the game's own "Loading the heroes… 60%"), and the controls for this device from `landing.controls`. It is drawn in the game's palette (style.json), else its landing's colours, else the studio's, and it fades the moment the game is playable. `?arrive=0` leaves it out.
29
+ - The netplay helper tells the play page when the game is playable (NETPLAY.md section 21): by itself once the browser is seated and has the room's state, or, for a game that keeps loading after that (models, textures, a baked world), at the game's own `net.playable()` (`createNetplay({ arrival: 'game' })`), with `net.loading(fraction, 'the heroes')` for the progress line. Nothing crosses the relay; the wire stays revision 8.
30
+ - `homie-studio perf` measures the time to the first meaningful frame (`load.look`: the arrival card on the screen), and its time to playable waits for the card to lift. The perf skill's goals include it ("it opens on a blank screen").
31
+
32
+ ### Changed
33
+
34
+ - A game with its own palette (style.json) and no `landing.scheme` or `landing.theme` of its own gets its landing in that palette: its paper as the page, its ink as the words, its accents, light or dark as its paper is, when the ink reads on the paper (4.5:1). Its footage keeps its colour, and the words sit on a soft panel of its paper. A bright game is no longer shown on the studio's dark page. A scheme or colours the owner set, a page of the studio's own and `site/theme.css` still win; a game without a style.json keeps the studio's look.
35
+ - Hero Rush 3D: the bots never swamp a new player. In somebody's first round in the room, when nobody set the AI dial, the bots play a level easier. A bot far ahead of the best person in the room eases off (it walks, reacts later, swings less, then races for the coins near that person, or keeps near them, up their screen, without taking coins) and plays at its dial again once it is within its lead: Rookie −1, Steady 1, Fair 2, Strong 5, Maxed none. Scores stay honest (no score is ever changed, no coin given, taken or faked), and every bot is labelled, the phone's compact board too ("bot" or "AI" after the name). A casual player's first round at the default dial ended 61 coins behind the best bot before, and about 4 behind now; a player who chases the coins still wins clearly, and Maxed bots still beat a casual player.
36
+ - Hero Rush 3D on a phone held upright: the camera follows lower and closer (30 degrees, about 5.5 m across), so every hero reads as a character (a mage was the top of its hat), and your name chip says what you are ("You · Mage"). The game passes `arrival: 'game'`: the card lifts on your own hero in its real model, never a stand-in. Your own hero is asked for first, the moment your seat is known, then the other heroes, then the skeletons (on an emulated slow phone your real hero is drawn at about 1.4 s instead of 2.1 s, the same bytes), the in-game title card is gone (the arrival card has the title), the "×2" mark moves off your hero and the controls hint sits above the touch buttons.
37
+
38
+ ### Upgrade notes
39
+
40
+ - Nothing to do: `homie-studio upgrade` brings the arrival card to every game, and a game built before 0.26.0 lifts it once it has a seat. A game whose world keeps loading after its first state can say when it is ready: `createNetplay({ …, arrival: 'game' })`, `net.loading(p, 'what')` while it loads, and `net.playable()` once its world and the player's own body are drawn. A game made from Hero Rush 3D before 0.26.0 keeps its own code: tell Claude "bring the starter's first-round bots and phone camera into my game" if you want them.
41
+
42
+ ## [0.25.0] - 2026-10-03
43
+
44
+ **Plugin 0.26.0** · [#38](https://github.com/homie-rocks/homie/pull/38) · [release-2026-10-03-studio-0.25.0](https://github.com/homie-rocks/homie/releases/tag/release-2026-10-03-studio-0.25.0)
45
+
46
+ Animated characters for 3D games: free CC0 heroes or one generated and auto-rigged on your fal account, on one skeleton standard with the library's clips retargeted onto it, and a shared player that runs, jumps and swings with IK feet and springs.
47
+
48
+ ### Added
49
+
50
+ - A skeleton standard (`lib/rig.mjs`): a humanoid family with VRM 1.0 bone names, a mini family for one-piece limbs (Kenney's mini and blocky characters), a quadruped and a rigid "parts" family. A rig from Mixamo, KayKit, Blender, Unreal or Meshy is mapped onto it by name and by its hierarchy, and recorded with a skeleton id (`humanoid-3fa2c1`): characters with the same skeleton share one clip library.
51
+ - `homie-studio assets add` takes animated characters from the free library (KayKit's adventurers and skeletons, Kenney's mini and blocky characters, all CC0) and `--file <model> --kind character --rigged` for your own. The shipped character is phone-sized: joints renamed to the standard, helper bones dropped, skinned parts and the accessories you keep (`--keep sword,shield`) merged into one draw call, its clips moved out.
52
+ - Clip libraries: `public/anims/<skeleton>.glb` holds one clip per verb (idle, walk, run, jump, fall, land, attack, cast, hit, die, ...), 30 frames a second, compressed, with where each clip came from. Clips are retargeted at build time from the library's CC0 sources onto any humanoid or mini skeleton (rest-pose alignment per bone, hips scaled by leg height, loops kept in place).
53
+ - `homie-studio cast <id>`: the characters, with their proportions, silhouette, palette, skeleton family and clips. `homie-studio anim plan|add|preview <id>`: each character's clips against the verbs the game needs, more verbs retargeted on, and looping previews (animated WebP) with a sheet.
54
+ - `@homie-rocks/studio/animate`: one shared three.js `AnimationMixer` player. `loadCharacter` finds a character's clip library from the model; `createCharacter` blends idle, walk and run by speed, plays upper-body actions while running, an additive hit flinch and hit-stop, jump, fall and land with squash and stretch on a spring, lean into turns, look-at, springs and two-bone IK feet, and a cheaper crowd mode past a dozen characters. `ANIM_TUNING` is what the Game Lab tunes.
55
+ - A 3D starter with animated heroes, `hero-rush-3d`: knights, mages, rogues and barbarians race for coins in a clearing, jump, dodge and swing at each other, on a phone (Jump and Swing buttons) and a computer, multiplayer with skeleton bots in empty seats. Each round opens on a close-up of your own hero that pulls back to play, and the Game Lab has takes for the jump and the swing.
56
+ - Generated characters (paid, on your own fal account): the models skill's `character` command makes an A-pose concept in the game's style (`--like` a library character's thumbnail), then Meshy 7.1 image-to-3D with its auto-rig (about US$1.40 with textures and the rig), then free: made phone-sized, mapped to the standard and given the library's clips. Both calls have receipts under the budget.
57
+ - MCP tools and cards: `cast_plan` (the cast card), `character_make` (the lineup with a character beside the others), `anim_plan`, `anim_add` and `anim_preview` (an Animation card of looping clips: Add is free, Feel opens the Game Lab on that move, New against Today).
58
+ - An `animate` skill: the skeleton standard, retargeting, clip rights (KayKit and Kenney CC0; Quaternius's own licence since 2026-08-28 is not CC0 and is not used; text-to-motion models are not offered, because the ones available are non-commercial in effect).
59
+ - In Claude Code, `/cast` and `/clips`, and the Studio pane's Art tab shows the characters (skeleton, bones, clips) and the skinning cost on a phone.
60
+
61
+ ### Changed
62
+
63
+ - `assets check` checks skinned meshes: more than four bone influences per vertex, a character without its clip library or missing a verb the game needs, clip libraries over 1 MB (3 MB is a problem) or over 30 frames a second, and the skinning cost of every player's character at once against a phone's budget (skinned vertices and bones), with crowd mode past twelve characters.
64
+ - A rigged model is measured by its skin (its joints' positions), so a character exported in centimetres is no longer 100 times too big, and it is centred by a wrapper node instead of moving its skeleton.
65
+ - The lineup poses rigged characters in their idle clip and draws their silhouettes from the posed skin.
66
+ - `style init` on a starter keeps what the starter already draws (its `style.json`: render, palette, materials, light, camera, fonts) as the automatic picks, and the clip decision lists the clips the game has.
67
+ - The fal price check adds a model page's add-ons (Meshy's textures and rig) and quotes the higher of fal's pricing API and the page.
68
+
69
+ ### Upgrade notes
70
+
71
+ - Nothing to do: games without characters are unchanged. To animate a 3D game's characters, tell Claude: "Give my game animated characters."
72
+
20
73
  ## [0.24.5] - 2026-10-03
21
74
 
22
- **Plugin 0.25.5** · [#39](https://github.com/homie-rocks/homie/pull/39)
75
+ **Plugin 0.25.5** · [#39](https://github.com/homie-rocks/homie/pull/39) · [release-2026-10-03-studio-0.24.5](https://github.com/homie-rocks/homie/releases/tag/release-2026-10-03-studio-0.24.5)
23
76
 
24
77
  Room chat keeps off your game's HUD: on a phone the Chat pill is a round icon, as the room button is, and your game can say where the strip of new lines sits, or keep new lines in the Chat sheet, so a game with a busy HUD keeps typed chat.
25
78
 
package/README.md CHANGED
@@ -96,11 +96,14 @@ licence its owner picked in game.json `"license"`: `"remix-with-credit"` (the de
96
96
  `"no-remix"`, which `game remix` refuses. Every page ends with "Made with Homie". Anything the studio puts in `site/` wins: a whole page, a partial, its tokens, its CSS, its
97
97
  files. `site/SITE.md` says all of it.
98
98
 
99
- The play page writes its room into the address, and a small room button at the edge shares it: Invite, Big
100
- screen and the room code. game.json's `screen.share` puts it where each game has room, per device (a corner or
99
+ The play page never opens blank (0.26.0): from its first paint an arrival card shows the game's own look (its title,
100
+ pitch and key art in its palette, a progress line that says what is happening, and the controls for the device) until
101
+ the game says it is playable (`NETPLAY.md` section 21; `worker/arrival.mjs`). It writes its room into the address, and
102
+ a small room button at the edge shares it: Invite, Big screen and the room code. game.json's `screen.share` puts it where each game has room, per device (a corner or
101
103
  the top's middle, moved in by `x` / `y`, or kept a small icon), so it never covers a scoreboard. A game whose
102
104
  picture is white or cream gets a light landing (`landing.scheme: "light"`). Every card and the directory show a
103
- game's landing still. Every HTML answer is `no-transform`, and the site's pages are never framed by another
105
+ game's landing still. A game with its own palette (style.json) and no landing colours of its own gets its landing
106
+ in that palette, light or dark as its paper is (0.26.0). Every HTML answer is `no-transform`, and the site's pages are never framed by another
104
107
  site. A game made with Homie's arcade controls that knocks for a Homie box (`/__homie/call`) is told
105
108
  `not-a-homie`, at the site's root as under the game.
106
109
 
@@ -519,7 +522,8 @@ rules, the bots, the snapshots) and a replica, both a computer (1280x800 at 2x)
519
522
  on a fast computer is less than its rate). They play the same seeded presses through a warm-up and a measured
520
523
  window, and each run's JSON says, per browser: the time between animation frames (median, p95, p99, the share over 33
521
524
  and 50 ms), the game's JavaScript per frame (every requestAnimationFrame callback timed), the main thread per frame
522
- (Chrome's TaskDuration), time to the first frame, to a seat and to playable, the game's files on the wire, the heap
525
+ (Chrome's TaskDuration), time to the first meaningful frame (`load.look`: the play page's arrival card), to the
526
+ game's first frame, to a seat and to playable, the game's files on the wire, the heap
523
527
  after a garbage collection, and netplay messages and kilobytes a second each way. `--profile` adds a CPU profile per
524
528
  browser in a window of its own (a `.cpuprofile` for Chrome DevTools) and its hottest functions, read through the
525
529
  game's source map when the build kept one (`homie-studio build --maps` keeps it in `.studio/maps/<id>/`, never in
@@ -601,7 +605,7 @@ npx homie-studio assets remove crown-thief lantern # the record and the co
601
605
 
602
606
  A game's look is a set of decisions (`games/<id>/codex/decisions.json`, private like the codex, drawn in its Art
603
607
  direction tab): render style, palette, shape, proportions, materials, light, camera, fonts and effects; the cast, its
604
- library family, scale and phone budgets; rigs and animation (later phases). Each starts as an automatic pick with a
608
+ library family, scale and phone budgets; the skeleton standard and the clips each role needs. Each starts as an automatic pick with a
605
609
  why. A person's nudge makes it steered, their lock freezes it, and the first asset built on an automatic one pins it.
606
610
  Every asset records the revision of each decision it was made under, so changing one lists exactly what went stale and
607
611
  what remaking it would cost; nothing is remade by itself. `games/<id>/style.json` (public) is the palette, fonts, light
@@ -631,6 +635,52 @@ The local MCP's `style_explore`, `decision_set`, `assets_plan`, `assets_find`, `
631
635
  `asset_check`, `asset_lineup` and `asset_rights` do the same with cards. Generated props (on the person's own fal
632
636
  account, under a budget, receipted) are the Homie plugin's `models` skill.
633
637
 
638
+ ## Characters, rigs and clips (`homie-studio cast`, `homie-studio anim`)
639
+
640
+ ```sh
641
+ npx homie-studio assets find "knight" --kind character # animated CC0 characters: KayKit, Kenney
642
+ npx homie-studio assets add heroes kaykit-adventurers/knight --as knight --height 1.45 \
643
+ --keep "1H_Sword,Round_Shield,Knight_Helmet,Knight_Cape" --verbs idle,walk,run,jump,attack,hit,die
644
+ npx homie-studio assets add heroes --file ./hero.glb --kind character --rigged --license own --as hero
645
+ npx homie-studio cast heroes # proportions, palette, skeleton family, every character
646
+ npx homie-studio anim plan heroes # each character's clips against the verbs the game needs
647
+ npx homie-studio anim add heroes knight --verbs block,dodge # more, retargeted onto its skeleton (free)
648
+ npx homie-studio anim preview heroes --asset knight # looping previews and a sheet: .studio/art/<id>/anim/
649
+ ```
650
+
651
+ A rigged character comes in as two files: `public/models/<asset>.glb` (its joints renamed to the skeleton standard:
652
+ VRM 1.0 humanoid names, a mini family for one-piece limbs, a quadruped family; helper bones that move nothing removed;
653
+ every part and every held thing it keeps merged into one skinned mesh, one draw call; phone-sized) and its skeleton's
654
+ clip library `public/anims/<skeleton>.glb`, shared by every character with that skeleton. Clips are its own where it
655
+ has them, else retargeted at build time from the starter library's CC0 humanoid clips (KayKit's): every bone turns in
656
+ the world the way the source's turned from its rest, after the two rest poses are lined up bone by bone, so a T-pose
657
+ clip plays on an A-pose rig; a one-piece limb aims where the source's whole limb points. It is plain matrix math in
658
+ Node (no renderer), so it runs in CI and a cloud session too. `assets check` holds characters to four influences a
659
+ vertex, the tier's bones, a clip library of 1 MB at 30 samples a second, every verb the game's `anim.clips` names,
660
+ and the skinning a room costs on a phone (players times the heaviest character: 60,000 vertices and 1,200 bones a
661
+ frame).
662
+
663
+ In the game, `@homie-rocks/studio/animate`:
664
+
665
+ ```ts
666
+ import { crowd, loadCharacter, ANIM_TUNING } from '@homie-rocks/studio/animate';
667
+ const knight = await loadCharacter(models, './models/knight.glb', { tune: T }); // finds its clip library itself
668
+ scene.add(knight.root);
669
+ // each frame: knight.root.position.set(x, h, z); knight.face(yaw, dt); knight.move(speed); knight.air(onGround, vy); knight.update(dt);
670
+ // events: knight.jump(); knight.act('attack', { from: 0.15 }); knight.hit(dx, dz); knight.die(); knight.hold('win');
671
+ crowd(characters, camera); // far and off-screen characters pose less often
672
+ ```
673
+
674
+ Idle, walk and run blend by ground speed at the rate the feet need; an action while moving plays on the upper body;
675
+ a hit is an additive flinch with a hit-stop; jump, fall and land squash and stretch on springs; it leans into turns,
676
+ turns its head toward a point, swings tails and capes on springs and plants humanoid feet on slopes. Every number is
677
+ an `ANIM_TUNING` entry for the game's tunables.json, so the Game Lab tunes it New beside Today.
678
+ `game new <id> --from hero-rush-3d` is the arena with KayKit's animated heroes and skeletons: run, jump, swing, a
679
+ cheer for the winner. The local MCP's `cast_plan`, `anim_plan` (looping previews; Feel opens the Game Lab on the
680
+ move), `anim_add`, `anim_preview` and `character_make` do the same with cards. A generated, rigged character (a concept
681
+ in the locked style, then Meshy's mesh and auto-rig on the person's own fal account, about US$1.44, priced and
682
+ receipted) is the Homie plugin's `models` skill; rigs, clips and feel are its `animate` skill.
683
+
634
684
  ## Checks on a computer without a GPU
635
685
 
636
686
  `check`, `port check` and `look` run Chrome headless. On a Mac they use its GPU. On Linux (a Claude Code cloud
@@ -712,7 +762,7 @@ npx homie-studio port check my-game --url http://127.0.0.1:8787 # the owner te
712
762
  | `lib/port-check.mjs` | `port check`: held and alternating directions on keys, Android Chrome and iPhone WebKit touch, UI cover, two browsers finishing a round, a killed host, a late joiner, the big screen. |
713
763
  | `port/` | The port toolkit (`@homie-rocks/studio/port`, or `window.HomiePort` from `homie-port.js` in a static game): `createRoom`, the touch kit, keys, camera rules, bots, a HUD, sandbox shims, first-touch audio, `exposePort`; `fitView` and `createLabels` (`port/view.ts`): a flat world on every screen (the whole of it where it reads, else filling a phone held upright and following the player) and names that never pile up when bodies crowd (yours placed first, the rest moved or faded). |
714
764
  | `worker/index.mjs` | The site Worker and the `Table` (netplay relay, `room.mjs`) and `Lobby` Durable Objects; `/<game>/tv` is the big screen with a join QR (`qr.mjs`); `/<game>/watch` watches a live room from any player's view (NETPLAY.md section 16); `/music/<slug>/` and `/videos/<slug>/` are song and video pages (their files served with byte ranges, from the site's files or, once moved, from the studio's R2 at the same address; a loose file from `media put` at `/media/<key>`). `seats.mjs`: room sizes (up to 32). |
715
- | `worker/site.mjs`, `lib/site.mjs`, `lib/markdown.mjs`, `site/SITE.md` | The site: its sections, each game's landing, posts and their feeds, the look (theme tokens) and what the studio's `site/` folder overrides; the safe markdown posts are written in. `worker/pages.mjs`: the play page. |
765
+ | `worker/site.mjs`, `lib/site.mjs`, `lib/markdown.mjs`, `site/SITE.md` | The site: its sections, each game's landing, posts and their feeds, the look (theme tokens) and what the studio's `site/` folder overrides; the safe markdown posts are written in. `worker/pages.mjs`: the play page; `worker/arrival.mjs`: its arrival card. |
716
766
  | `worker/stats.mjs`, `worker/stats-page.mjs`, `lib/stats.mjs` | The studio's own stats: what is counted and how, the owner-only `/api/stats` and `/_studio/stats`, and `homie-studio stats`. |
717
767
  | `lib/media.mjs`, `media/MEDIA.md` | The `music/` and `videos/` manifests: which entries get a page, and where each file's bytes come from (the site itself up to 25 MiB a file, the studio's R2, or a link). `media list` shows it; `media move` puts the big ones in R2 and records each one's SHA-256; `media put` uploads a loose file to `/media/<key>`. |
718
768
  | `netplay/` | The netplay contract (`NETPLAY.md`) and its game helper (`@homie-rocks/studio/netplay`). |