Spaces:
Running
Download docs/ARCHITECTURE.md from osolmaz/microquack: direct link, hf CLI and curl.
- Browser
- Download file 5.49 kB
-
https://huggingface.co/spaces/osolmaz/microquack/resolve/main/docs/ARCHITECTURE.md
- Command line
-
hf download hf://spaces/osolmaz/microquack/docs/ARCHITECTURE.md
-
curl -L -o ARCHITECTURE.md https://huggingface.co/spaces/osolmaz/microquack/resolve/main/docs/ARCHITECTURE.md
Architecture
One engine, many hosts
crates/microquack-core crates/microquack-llm
(canonical: all sound (the droid mind: tiny
behavior) transformer inference)
\ / |
crates/microquack-wasm trained in llm/
/ (browser binding) (PyTorch -> binary weights)
crates/microquack-cli
(render / validate / fit / schema)
|
apps/web (TypeScript: UI, canvas, WebAudio, 3D stage only)
|
microduck robot (native crates, 48 kHz PCM) <- planned consumer
microquack-core contains everything that affects the sound: score types and
parsing, pitch curves, envelopes, oscillators and partials, ring modulation,
noise, the seeded PRNG, phrase grammar, the canonical semantic emotion
registry and voice-mode shaping, contour output for motion, and rendering β
both full-phrase (render_score) and incremental
blocks (Engine::render_into, which render_score itself uses, so offline
and streaming output are identical). It contains no WebAudio, WASM APIs,
device access, filesystem loading, browser code, or Python-specific code.
The score contract
A score is a JSON list of syllables with snake_case fields (f0_start,
amp_points, ...), defined once as Serde types in microquack-core.
schema/score.schema.json is generated from those types (pnpm run schema);
nothing else defines the format. schema/emotions.json and
apps/web/src/emotions.generated.ts are likewise generated from the Rust
registry with pnpm run emotions. Python uses the JSON file for teacher-data
generation. Scores use seconds and hertz, so they are sample-rate
independent; the renderer owns all rate-specific behavior. The TypeScript app
treats scores as opaque JSON strings β it never reimplements or redeclares the
format.
The chat and the droid mind
The visitor reads and writes English; the robot answers in droid speak with
an English gloss. crates/microquack-llm runs a ~1.3M-parameter
character-level transformer (trained from scratch in llm/ on a synthetic
space-adventure corpus) with a KV cache and greedy decoding, compiled into
the same WASM module as the synth. Its output is (emotion, reply); the
emotion drives phrase generation and the body-language gestures. Rust/
PyTorch parity is enforced by cargo test -p microquack-llm against the
committed model (apps/web/public/assets/llm/droidmind.bin) and test
vectors. The current model artifact supports its original eight emotions.
Rust validates that list against the canonical 73-state registry, then maps
each semantic state to one of 12 broad voice modes and four shared affect
values. The expanded 1,000-row teacher set is review data only; it does not
replace the production weights. Between conversations the robot utters an
idle thought every 10β15 seconds.
The web app
apps/web owns UI, canvas, and WebAudio only:
src/wasm/β generated wasm-bindgen output (pnpm run build:wasm).robot.tsβ assembles the real microduck from its mesh library (microduck.glb) and kinematic tree (kinematics.json, MuJoCo convention), exposes head joints and a synthetic jaw hinge.scene.tsβ the procedural night-plain world (three moons, stars, rocks) and the speech-driven articulation.mind.ts/droidtext.ts/gestures.tsβ the chat brain wrapper, droid-speak captions, and generic body language driven by the Rust voice mode and affect values. TypeScript does not map the 73 semantic states.- Short phrases render whole (
render_scoreβAudioBuffer). Continuous synthesis, when it arrives, must run theEnginein an AudioWorklet β WASM alone does not prevent main-thread stalls.
Research
Fitting is a CLI subcommand (microquack fit): it analyzes a real WAV
(pitch track, envelope, harmonics, noisiness) and emits a breakpoint score,
rendering every candidate through the same engine that ships. research/
holds the fitted corpus (scores/fits.json), pregenerated phrase scores,
and the frozen conformance fixtures.
Conformance gate
crates/microquack-core/tests/conformance.rs renders all 90 frozen scores
(79 fitted + 6 phrases + 5 presets) against research/fixtures/: exact
sample counts, RMS/peak within 1e-6, and 21 full waveforms within 1e-4 per
sample. Streaming must equal offline rendering exactly, and phrase generation
must be seed-deterministic. Any DSP change that breaks these is a behavior
change and requires refreezing fixtures deliberately.
Device integration (planned)
The Microduck repository consumes microquack-core at an exact version
(microquack-core = "=x.y.z", or a pinned git revision until published) β
never vendored source. The device adapter feeds Engine::render_into into
its existing 48 kHz PCM path and reads ControlFrame values to animate the
physical beak and body. The 79 fitted scores must be revalidated at 48 kHz
before the robot ships them.
Release model
One git tag should produce, all reporting the same version and commit:
- the
microquack-corecrate (device), - the WASM/npm package (website),
- the CLI binary (render, validate, fit, schema, emotions),
- the score corpus and generated schemas.
Roadmap
See VISION.md: preset conversations, the droid-speak language
model, procedural full-body motion, and browser-side locomotion policies from
microduck_rl via ONNX Runtime Web.