A newer version of the Gradio SDK is available: 6.20.0
title: Hatchimera - Voxel Pet Fusion
emoji: π§¬
colorFrom: purple
colorTo: yellow
sdk: gradio
sdk_version: 6.15.2
python_version: '3.12'
app_file: app.py
short_description: Draw voxel pets, splice two, breed a family tree
pinned: false
license: mit
tags:
- track:wood
- achievement:offgrid
- achievement:offbrand
- achievement:llama
- achievement:sharing
- achievement:fieldnotes
Hatchimera β Voxel Pet Fusion
Hatchimera = hatch a chimera β draw two voxel pets, splice them, breed something new.
Draw voxel pets from a sentence, splice two into a chimera no menu could give you, and breed a whole family tree. The model does the drawing. Hatchimera is the toy that doesn't exist without it.
The hook
Pick two voxel creatures, hit Splice, and watch Gemma 4 12B recombine their box geometry into a chimera no menu could give you: one parent's body, the other's signature feature, plus a mutation it makes up on the spot. The newborn lands on a 3D stage and joins the family tree, where it can breed again. You can't reproduce it from a dropdown, and it is the main thing on screen.
How it works
One moment is the model β the splice; everything around it is deterministic code.
| Layer | What runs |
|---|---|
| Splice | fuse_creatures β one Gemma 4 12B call merges two box layouts into a chimeric child β the only model call in the app |
| Draw / Tweak | model-free: a keyword picks a reference body template (pick_exemplar), and edit_parser maps "add two horns" onto a ~100-part catalog that assemble_part snaps on β instant, no GPU |
| Render | a Three.js voxelizer turns the box layout into an InstancedMesh stage, an animated pedigree tree, and a Figma-style lab canvas |
| Runtime | the model runs through llama.cpp (llama-cpp-python), on ZeroGPU on the Space; no cloud APIs |
The split is deliberate: the model is load-bearing where it earns its tokens β recombining two creatures into something new β and the predictable parts (a starter body, snapping on catalog parts) stay deterministic on the CPU. If inference is unavailable or returns junk, the splice falls back to a deterministic box-merge, so the demo never crashes; it just gets less surprising.
Run it
pip install -r requirements.txt
# Fake runtime β no model, instant; for UI / interaction work
BUDDY_FORCE_FAKE_RUNTIME=1 python app.py # or: scripts/start-local.sh
# Real model β Gemma 4 12B through llama.cpp
scripts/start-local-real-model.sh
Both scripts bind 0.0.0.0:7860, auto-pick a free port, and honor PORT= /
HOST=. Tests: python -m pytest -q.
Real-time real-model inference needs a GPU β on the Space that's ZeroGPU. On a plain CPU the CUDA wheel can't initialize, so every model action silently falls back to the deterministic path (still playable, just templated). Gemma 4 12B is heavy to run on a local CPU.
How to play
- Landing β Quick Start drops you into the Lab with two random starter parents on the tree; βοΈ Build from scratch instead opens an empty bench to describe both parents yourself (a fresh family).
- Lab (the pedigree tree) β tap two creatures to stage them as A / B,
πinspects one in live 3D, or βοΈ Build from scratch adds a fresh buddy. Staging two opens the Splice Bench. - Splice Bench β tweak each side in its box (or
π²for a random buddy) β tweaks snap catalog parts on instantly, model-free; Splice! is the one model call that breeds the two into a child. - Reveal β the newborn appears beside its parents and joins the family tree.
- Keep breeding β every child stays in the tree, ready to be staged again.
The model, and how we got here
Hatchimera started as the opposite of what it is now, and the rewrite is the whole story.
v1 β recipe-level on a small model. The first design had the model pick from a closed vocabulary (archetype + parts + palette + mutation) and let a deterministic voxelizer build the geometry. The bet: small models are weak at spatial reasoning, so don't ask them to draw; ask them to choose. It kept a 3B model reliable, but it could never draw "five arms" or "a house on its head". The AI felt like a garnish.
The bug that hid every model. For a long stretch, tweaks looked like they
ignored the model. The cause wasn't the model. It was response_format.
llama-cpp-python honors {"type": "json_object", "schema": β¦} and silently
ignores the OpenAI-style {"type": "json_schema"}. With the wrong key the model
was completely unconstrained, returned malformed JSON, and every edit fell through
to the deterministic fallback. Fixing the key compiles the schema to a GBNF
grammar, and only then is any model's real capability visible. Lesson: measure
model quality after grammar enforcement works, never before.
The spike. To find out whether a small model could draw freehand at all, we benchmarked 19 models across 9 families, 1Bβ32B, on box-layout geometry. The findings ran against intuition:
- Grammar enforcement fixes JSON validity across the board; it's a prerequisite, not a model trait.
- Geometry quality tracks neither size nor family. A 12B isn't "better at shapes" than a 3B by default; most models produce schema-valid but shapeless blobs.
- Gemma 4 is the only family that draws recognizable hard forms freehand. Not the biggest, not a whole tier β one family.
So Hatchimera went all-freeform on Gemma 4 12B. The earlier model ranking (Qwen2.5-3B followed the genome schema best, Llama-3.2-3B overran its token budget, SmolLM2 was middling) didn't carry over at all: schema-following and shape-drawing turned out to be different skills.
Shipping a 12B on ZeroGPU. Two lessons stuck:
- Grammar costs ~2Γ throughput. The GBNF per-token allowed-set check is serial CPU work that doesn't ride the GPU: 16.7 tok/s on vs 35.9 off on the same prompt. Intrinsic to constrained decode, not schema bloat.
- The wheel pin is load-bearing. Gemma 4's chat template throws
unknown tagon llama-cpp-python 0.3.19's old Jinja engine, so the Space pins 0.3.29 (installed via apy3-none-manylinuxwheel, sopython_version "3.12"stays put). ZeroGPU here is an RTX Pro 6000 Blackwell.
Full measurements live in the wiki: per-call timing, the grammar bench, the model spike report.
The wiki is the project's memory
This repo carries a git-tracked engineering wiki under wiki/, and the
coding agents actually read and write it.
- It loads itself. A
SessionStarthook injectswiki/index.mdinto every coding-agent session, so the agent starts with the project's hard-won knowledge instead of re-deriving it. - Writes are gated, not trusted. The policy lives in
wiki.config.json. Underauto, aPreToolUsegate judges every wiki write by theconfidencethe author assigns it:highis allowed (and its diff is shown to a human), anything lower (or a delete, or a write to the wrong path) is blocked and must be proposed instead. It fails closed. - It's maintained. Every change updates
index.mdand appends towiki/log.md; aStophook checks that each session actually evaluated whether it learned something worth recording. Codex runs the same flow via.codex/.
The point: the messy middle (the json_object bug, the 19-model spike, the
ZeroGPU timing, the wheel-pin saga above) gets captured where the next person or
agent will find it, instead of evaporating. Start at
wiki/index.md; model-selection-spike.md
and deployment-strategy.md are that journey in
full.
Layout
app.py entry point; loads buddy_fusion.fusion_ui
src/buddy_fusion/
runtime.py BuddyRuntime: fake + llama.cpp; the single Gemma model
fusion_ui.py the Gradio Blocks game flow, all CSS, the JSβPython bridges
voxel_embed.py the Three.js voxelizer, pedigree, detail modal
fusion.py Creature / Lineage store + splice routing
prompts.py box-layout schema + few-shot message builders
edit_parser.py / assembler.py / parts_data.py the model-free Tweak path
fallback.py / exemplars.py deterministic content; never-crash net
wiki/ the engineering wiki (see above)
scripts/ start-local.sh (fake) / start-local-real-model.sh (real)
tools/ the model-selection spike + parts-catalog reports
Built for the Build Small Hackathon
Track: Thousand Token Wood β a delightful AI toy that wouldn't exist without the model doing the interesting work. Badges this build claims:
- Off the Grid β no cloud APIs; the model runs in front of you.
- Off-Brand β a custom Three.js voxel frontend, well past the default Gradio look.
- Llama Champion β the model runs through the llama.cpp runtime.
- Sharing is Caring β agent traces shared on the Hub.
- Field Notes β the wiki above, plus the spike report, are the write-up.
Submission
- Team (Hugging Face):
arkai2025 - Demo video: https://www.youtube.com/watch?v=CZ5-xUl1l-M
- Social post: https://www.linkedin.com/posts/arkai_buildsmallhackathon-gradio-huggingface-share-7472427797077139456-XG1F/
