@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.
- package/CHANGELOG.md +54 -1
- package/README.md +56 -6
- package/assets/animate.ts +521 -0
- package/assets/render-page.ts +77 -4
- package/bin/homie-studio.mjs +13 -4
- package/lib/art-cli.mjs +105 -5
- package/lib/art-tools.mjs +168 -1
- package/lib/asset-check.mjs +72 -5
- package/lib/characters.mjs +380 -0
- package/lib/clips.mjs +417 -0
- package/lib/decisions.mjs +38 -8
- package/lib/mcp-tools.mjs +1 -1
- package/lib/mcp.mjs +2 -2
- package/lib/optimise.mjs +79 -3
- package/lib/perf.mjs +15 -7
- package/lib/render3d.mjs +2 -0
- package/lib/rig.mjs +431 -0
- package/lib/scaffold.mjs +7 -0
- package/lib/site.mjs +14 -3
- package/lib/studio.mjs +18 -3
- package/lib/style-board.mjs +3 -1
- package/lib/template-history.json +78 -0
- package/mcp/ui/animation.js +56 -0
- package/mcp/ui/card.css +4 -0
- package/mcp/ui/cast.js +36 -2
- package/mcp/ui/lineup.js +7 -7
- package/netplay/NETPLAY.md +38 -2
- package/netplay/netplay.ts +58 -3
- package/package.json +5 -1
- package/site/SITE.md +19 -1
- package/starters/gem-rush/game.json +2 -1
- package/starters/gem-rush-3d/game.json +2 -1
- package/starters/hero-rush-3d/assets/RIGHTS.md +163 -0
- package/starters/hero-rush-3d/assets/manifest.json +1471 -0
- package/starters/hero-rush-3d/credits.json +40 -0
- package/starters/hero-rush-3d/game.json +12 -0
- package/starters/hero-rush-3d/index.html +20 -0
- package/starters/hero-rush-3d/lab.json +32 -0
- package/starters/hero-rush-3d/src/main.ts +2588 -0
- package/starters/hero-rush-3d/style.json +68 -0
- package/starters/hero-rush-3d/tunables.json +32 -0
- package/worker/arrival.mjs +207 -0
- package/worker/pages.mjs +23 -5
- package/worker/site.mjs +26 -4
- 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
|
|
100
|
-
|
|
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.
|
|
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
|
|
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;
|
|
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`). |
|