Landing now has two entries again: "Quick Start →" (restored Start → Lab with
seeded parents) and "✏️ Build from scratch" (re-added). Both route through the
Lab before any splice can happen, which mounts the lazily-mounted screen_lab and
fixes the blank-screen bug on the reveal's "← Back" (next_btn → screen_lab: an
unmounted Lab, half-mounted by do_fuse's slots_view/tree_view writes, rendered
blank).
Splice Bench input box is now fully model-free in both runtimes: LlamaCpp
generate_creature (pick_exemplar only) and edit_creature (keyword → assemble_part,
dropped the _freeform_edit_creature model fallback) match MockRuntime. The only
model call left in the app is fuse_creatures (Splice).
Reveal Share/Back are hidden over the fuse loading state via CSS
(.screen:has(.buddy-reveal-row) .buddy-reveal-actions) instead of gr.update(
visible=), which races on the freshly-revealed lazy column.
Docs/wiki: README hook + "How it works" + How-to-play and wiki system-overview /
index / log / grad…
refactor(runtime): single Gemma 4 12B model + Hatchimera rename
Drop the dual Qwen2.5-3B / SmolLM2-1.7B recipe-model setup. Every AI moment —
freeform generation and hatch fusion — now runs through a single model,
Gemma 4 12B, the only family that draws hard voxel forms in the model-selection
spike. LlamaRuntimeConfig defaults and env overrides collapse onto the freeform
model; the now-dead fallback-model fields and Qwen/SmolLM references are removed.
Retitle the project to "Hatchimera — Voxel Pet Fusion" across the README and
wiki, and align the wiki (deployment, hackathon, overview, local-dev, voice)
with the single-model story.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
feat(edit): replace small-model selector with keyword + parametric assembler
Edit path is now pure Python: an English keyword parser maps the instruction to
a catalog part plus count/scale/anchor/rotation/color, and the assembler snaps it
on deterministically (symmetric pairs first, overflow to rear; float scale rounded
to the grid; exact 90deg integer-grid rotation). Instant, no GPU. Gemma 12B stays
only for full generation, hatch fusion, and the freeform-edit safety valve.
Removes select_part, the MiniCPM selector constants/preflight/warmup bench, and
SELECT_SCHEMA/build_select_messages.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
feat(runtime): log selector picks; fake edit keyword-matches the catalog
Print [selector] picked part=.. anchor=.. scale=.. on each catalog hit so the
Space log shows what the small model chose. FakeBuddyRuntime.edit_creature now
keyword-matches the instruction to a catalog part (not always horns) so local UI
testing exercises the whole part set.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
feat(runtime): default selector to MiniCPM5-1B-GGUF with auto-fallback to Qwen
Wire the selector default to openbmb/MiniCPM5-1B-GGUF / MiniCPM5-1B-Q4_K_M.gguf
(the base openbmb/MiniCPM5-1B has no GGUF). If it fails to load on the Space's
llama-cpp-python 0.3.19 (e.g. chat-template unknown tag), select_part logs it,
switches the container to Qwen2.5-3B, and retries immediately so the edit still
lands fast — no repeated attempts on the broken model. Override via
BUDDY_SELECTOR_MODEL_REPO/_FILE.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
feat(runtime): selector->assembler edit path with freeform fallback
Route edit_creature through a small grammar-enforced selector (select_part) that
maps free text to {part, anchor, scale, color} from the catalog; assemble_part
snaps it on (~2-3s). Off-catalog / transform / selector miss falls through to the
freeform Gemma edit (renamed _freeform_edit_creature); model failure is logged,
not swallowed. Selector model is env-configurable (BUDDY_SELECTOR_MODEL_REPO/_FILE),
default Qwen2.5-3B; env-gated _selector_preflight() prints load ok/FAILED so a
0.3.19 chat-template failure (e.g. when trying MiniCPM5-1B) is visible.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
On-Space bench: Gemma-4-12B freeform decodes ~17-22 tok/s WITH the GBNF grammar
vs 35.9 tok/s without (same 400-token prompt) — grammar costs ~2x, and it is
intrinsic per-token CPU sampling overhead, not schema bloat (BOX_SCHEMA is
already lean). Two levers:
- A: BUDDY_FREEFORM_NO_GRAMMAR=1 drops the grammar on the freeform box path only
(heavy=True calls: generate/fuse/edit), leaning on parse_json_object +
repair_boxes for the unconstrained output. Recipe GENOME_* calls always keep
the grammar (fragile without it). Env-gated so it can be A/B'd live and
reverted instantly.
- B: lower the default BUDDY_FREEFORM_MAX_TOKENS 1500 -> 1000. Trims the typical
wait and closes the residual crash edge (1500 tok / ~20 tok/s ~= 75s overran
the duration=60 budget; 1000 -> ~50s fits).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
fix(runtime): grammar bench measures OFF only to avoid ZeroGPU abort
Running grammar-on + grammar-off back-to-back inside the single demo.load
warmup handler stacked a 3rd GPU acquisition after the warmup gen, which
ZeroGPU aborted ("GPU task aborted"). grammar-on throughput is already the
normal [zerogpu-bench] number every real freeform call prints (~17-22 tok/s),
so measure only the unconstrained grammar-off run here — keeping the handler
to 2 GPU acquisitions (warmup + bench), the range the log shows succeeds.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
perf(runtime): give freeform 12B calls their own GPU budget + grammar bench
Freeform Gemma-4-12B calls generate 300-600 tokens at ~20 tok/s and hit
25-31s total, overrunning the shared ZeroGPU duration=30 budget and crashing
mid-decode (ggml_cuda_mul_mat_q CUDA abort -> the call dies and the user gets
the fallback after a full wait). Route generate/fuse/edit through a separate
duration=60 wrapper (BUDDY_FREEFORM_GPU_DURATION); recipe calls keep 30.
Add an env-gated grammar A/B bench (BUDDY_GRAMMAR_BENCH=1) that runs the same
freeform prompt with and without the GBNF grammar to isolate whether
grammar-constrained sampling is the ~20 tok/s throttle vs raw 12B decode.
edit_creature now returns the edited geometry AND the next 4 tweak hints in
ONE completion (EDIT_SCHEMA), so a bench tweak is a single ZeroGPU call
instead of edit + a separate suggest_tweaks call.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
feat(bench): big 3D scenes + Gemma-suggested hint bubbles in a halo arc
Splice Bench redesign from user feedback:
- Title centered to the VIEWPORT (Back pulled out of flow), not the row.
- Each side becomes a large 3D scene (440x380); the creature fills it and the
name is merged into the A/B header. The colour-swatch card is removed.
- The 4 quick-tweak chips become glassy hint bubbles floating in a halo arc
across the top of the scene (outer-low, inner-high; right side anchored with
right: so fixed-width pills never clip). Gentle float animation
(reduced-motion-aware). They keep the buddy-chip class, so clicks still route
through the existing buddyChip -> on_chip bridge (no JS change).
- Hints are full imperative sentences ("Add two curved horns"), shown verbatim
and sent as the tweak prompt.
- Hints are now AI-driven: first render samples a static pool; after EVERY tweak
on a side, Gemma regenerates that side's 4 hints for the new form
(runtime.suggest_tweaks + build_freeform_suggest_messages + TWEAK_SCHEMA;
fake runtime / model failure…
feat(freeform): route the whole main flow through the freeform path
Phase 1 of all-freeform: ancestors seed as freeform (exemplars, stopgap for the
compendium), AI Tweak edits box geometry via a new edit_creature path instead of
the recipe interpret_genome_command (which stripped boxes), splice already routes
to fuse_creatures for box parents, Draw-from-prompt moved into the Lab, warmup
fires the Gemma freeform model. Qwen recipe code kept dormant.
New: prompts.build_freeform_edit_messages, fallback.edit_boxes_fallback
(deterministic box editor), runtime.edit_creature (Protocol + Fake + LlamaCpp).
Verified end-to-end on the fake runtime (seed -> tweak -> splice -> reveal).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add an opt-in freeform path where the model draws raw box-layout geometry
({name, boxes:[{x,y,z,w,h,d,color}]}) instead of the recipe, so creatures can
take cross-form shapes (five arms, a house on the head) the closed recipe
vocabulary cannot express. Gemma 4 12B (the model-selection spike winner),
grammar-enforced, seeded with a hand-authored reference exemplar.
Freeform creatures are first-class: they enter the family tree and breed. A
splice routes to a Gemma "merge two creatures" call when either parent carries
boxes (freeform x freeform and freeform x recipe both yield a box child);
otherwise the recipe fuse runs. Fallbacks (fake runtime / model failure) use a
reference exemplar or a deterministic box merge, so the app never renders empty.
- genome: optional Genome.boxes + freeform_genome(); round-trips, recipe
creatures stay box-free
- prompts: BOX_SCHEMA, build_freeform_messages, build_freeform_fuse_messages
- runtime: generate_creature / fuse_creatures on Gemma via per-cal…
fix: enforce genome schema via json_object response_format; default to Qwen2.5-3B
response_format used the OpenAI-style {"type":"json_schema"}, which
llama-cpp-python silently ignores, leaving fuse/tweak output unconstrained
and forcing every edit onto the keyword-editor fallback. Switch to
{"type":"json_object","schema":...} so the schema is enforced as a GBNF grammar.
Also default to Qwen2.5-3B: with the fix it follows the genome schema
(including Chinese instructions); Llama-3.2-3B overran the token budget and
produced truncated JSON. Runs on the Space-pinned llama-cpp-python 0.3.19,
so no requirements/README pin changes are needed.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
fix: AI tweak no-op on the real model when the edit is empty
interpret_genome_command merged the model edit as `edit.get(x) or
genome.get(x)`, so a valid-but-empty model edit silently kept the original
genome with no exception — bypassing the keyword-editor fallback (which only
fired on exception). On the small ZeroGPU model this made every tweak look
like it did nothing.
When the model's result leaves the rendered look (archetype/palette/parts)
unchanged but the deterministic keyword editor does change it, surface the
keyword-editor result instead so a tweak always lands. Add LlamaCppBuddyRuntime
tests for the empty-edit fallback and the model-edit-used paths.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
feat: Build Buddy — voxel pet fusion (AI genetics engine)
Hatch two voxel ancestors, voice-tweak them, and let a small local model
splice their genomes into an unpredictable next-generation chimera that
joins the family tree. AI is the load-bearing genetics engine; a
deterministic voxelizer renders Crossy-Road-style animals from the
recipe-level genome the model produces.