THE FINDING THAT CHANGES THE PREMISE: "1 rigged model in 4,442" was measured
with the BROKEN GLB probe (the gLUF magic bug). With the probe fixed the
library holds 36 rigged models across three rigs:
41 joints — 9 KayKit heroes + undead, up to 95 clips
7 joints — 22 KENNEY civilians (male/female a-f, orc, human, archer, shop
employees, skaters, soldiers), 32 clips
6 joints — 5 Kenney platformer characters, 25 clips
So a village can be populated with 22 visually distinct civilians TODAY, with
no third-party pack at all. Every conclusion drawn from that probe before it
was fixed needs re-checking, not just this one.
KayKit: 9 characters fetched (Adventurers + Skeletons), pinned by commit +
sha256, 37 MB, gitignored. CC0 verified by READING LICENSE.txt at each pinned
commit, recorded in the script header and CREDITS.toml.
THE SHARED RIG HOLDS ACROSS PACKS, proven rather than assumed: hashing the
joint-name list of all nine files yields the SAME digest — 41 joints, same
names, same order — despite two separate repositories. Skeleton clips are a
strict superset (95 = the adventurers' 76 + 19 undead extras: awaken,
resurrect, spawn, taunt). So a clip authored for the knight plays on the
skeleton warrior and one animation path drives the cast. A test pins this,
including that both packs are present, so a version bump cannot silently break
it.
The texture trap that cost the Kenney fetch three attempts does NOT apply:
KayKit GLBs EMBED their atlas (image/png in a bufferView), verified by parsing
all nine.
tests/rigged.rs parses all 36 rigged models through makepad_game_render::skin
— the loader the app actually runs — and asserts the index's joint and clip
counts match it. Deliberate: the index's own probe was wrong for the entire
library once and survived because the fixture encoded the same error.
find_cast groups by JOINT COUNT rather than pack, because the valuable fact is
cross-pack interchangeability. Cast states are the INTERSECTION, not the union
— advertising a state one member cannot perform is worse than a shorter list.
Added the state words the skeletons needed (spawn/resurrect/taunt/use):
Skeletons_Awaken_Floor previously matched nothing, so "an undead that rises
from the ground" was unfindable.
One bug found in its own work: casts_to_json emitted a doubled closing brace —
malformed JSON that still looked fine in a log. Fixed with a structural test.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
108 lines
5.3 KiB
Markdown
108 lines
5.3 KiB
Markdown
# Makepad Arcade
|
||
|
||
Networked AI game sandbox (plan: repo-root game.md). Run with:
|
||
|
||
cargo run -p makepad-arcade
|
||
|
||
## Stock assets
|
||
|
||
Arcade ships with a searchable library of CC0 models and sounds. The binaries
|
||
are **not** vendored in git — fetch them once:
|
||
|
||
./apps/arcade/download_assets.sh # core packs, ~75 MB
|
||
./apps/arcade/download_assets.sh --packs=all # everything, ~185 MB
|
||
./apps/arcade/download_assets.sh --list # show packs, download nothing
|
||
|
||
The default fetches a **core** set (~1900 models) so a fresh clone isn't forced
|
||
to pull the lot; `--packs=all` gets the full Kenney 3D catalogue (**4669 models
|
||
across 47 packs**), and `--packs=nature-kit,car-kit` picks specific ones. Add
|
||
the 556 sounds and the nine rigged KayKit characters and the full library is
|
||
~5000 searchable assets — of which **36 are rigged and animated**.
|
||
|
||
Everything is gitignored and pinned — starter kits to exact GitHub commits, the
|
||
rest to content-hashed kenney.nl URLs — and every file is sha256-verified, so a
|
||
moved or tampered upstream fails loudly instead of silently changing the
|
||
library. Downloads are sequential with a delay: this is someone else's
|
||
bandwidth.
|
||
|
||
### Mirroring
|
||
|
||
`resources/MIRROR.toml` lists every pack with its canonical URL, sha256, size
|
||
and model count. Because these assets are CC0, anyone may re-host them, and
|
||
that file is what makes a mirror reproducible and verifiable. Point at one with:
|
||
|
||
ARCADE_ASSET_MIRROR=https://your.host/assets ./apps/arcade/download_assets.sh
|
||
./apps/arcade/download_assets.sh --mirror=https://your.host/assets
|
||
|
||
A mirror is expected to serve `<base>/<slug>.zip`. **The sha256 from
|
||
MIRROR.toml is verified identically whichever host served the bytes** — a
|
||
mirror is never trusted more than upstream; the hash is the authority.
|
||
|
||
Everything degrades gracefully without them: the demo runs with primitive
|
||
shapes, and tests that need real assets skip with a hint.
|
||
|
||
**Audio is Ogg Vorbis.** Every Kenney audio pack ships `.ogg` only — no WAV
|
||
variant exists upstream — and this tree has no vorbis decoder. The sounds are
|
||
therefore indexed and searchable by the AI but **not yet playable**; adding a
|
||
decoder (or running `download_assets.sh --transcode`, which converts to WAV
|
||
when ffmpeg is installed) is what closes that gap.
|
||
|
||
### Finding assets
|
||
|
||
The library is queried by *description*, never by filename, via
|
||
`makepad-game-assets`. The agent gets a `find_model` tool and a one-paragraph
|
||
summary — it searches, it never receives the catalogue (5000 entries would not
|
||
fit in a prompt, and the summary stays ~480 characters however large the
|
||
library grows). Ids look like `kenney/racing/vehicle-truck-yellow` and are
|
||
stable across re-downloads, because generated game code writes them.
|
||
|
||
Findability is built in three layers so it scales past 4000 models:
|
||
per-pack theme curation (~55 rows, giving every model its setting), filename
|
||
token parsing (free, and Kenney's names are systematic), and a hand-curated
|
||
query-time synonym table (~240 rows) that applies to the whole catalogue at
|
||
once. Item-level curation is spent only on the few hundred most-requested
|
||
things. At the full 4,999-entry catalogue: index build ~120 ms, a search
|
||
~0.2 ms, ~2.1 MB of heap (release).
|
||
|
||
Query-side stemming means an inflected request still reaches a base-form
|
||
alias ("smashing" → the `smash` alias), and when two entries tie on score the
|
||
kind the query implies wins — an unqualified noun like "spaceship" is an
|
||
object request, while "metal clang" or "win music" wants something audible.
|
||
|
||
## Credits
|
||
|
||
Every asset here is CC0 (public domain). Attribution isn't required by the
|
||
licence — we credit anyway, because these libraries exist because someone chose
|
||
to give them away.
|
||
|
||
- **Kenney** — <https://kenney.nl/assets> — 47 model packs totalling ~4,670
|
||
models (nature, city, castle, space, food, furniture, vehicles, dungeons,
|
||
characters and more), the five starter kits, and all seven sound packs
|
||
(impact, interface, sci-fi, music jingles, UI, RPG and digital audio). Thank
|
||
you for the extraordinary breadth of free, consistent, genuinely usable game
|
||
assets — this library is most of what Arcade can build with.
|
||
- **KayKit / Kay Lousberg** — <https://kaylousberg.itch.io/> — nine rigged and
|
||
animated characters: five adventurers (Knight, Barbarian, Mage, Rogue,
|
||
Rogue_Hooded) and four skeletons (Warrior, Mage, Rogue, Minion). All nine
|
||
share one 41-joint skeleton, so an animation authored for any of them plays
|
||
on every one — the adventurers ship 76 clips and the skeletons those same 76
|
||
plus 19 undead extras. Thank you for giving away rigs and animation sets,
|
||
which are the expensive part.
|
||
|
||
### Rigged characters
|
||
|
||
`find_cast` lists the animated casts. A cast is a set of characters sharing one
|
||
skeleton, so any state works on any member and a part can be recast without
|
||
touching animation code:
|
||
|
||
| rig | members | clips | notable states |
|
||
|-----|---------|-------|----------------|
|
||
| 41 joints (KayKit) | 9 | 76–95 | block, dodge, hurt, dance, sleep, carry |
|
||
| 7 joints (Kenney mini) | 22 | 25–32 | walk, run, jump, attack, sit, wave |
|
||
| 6 joints (Kenney platformer) | 5 | 25 | walk, run, jump, attack |
|
||
|
||
Pick members from ONE cast for a scene, and use different members so a crowd
|
||
isn't clones — the same rule that applies to props.
|
||
|
||
Machine-readable attribution lives in `resources/CREDITS.toml` so a published
|
||
game package can carry credit with it.
|