The kit that plays drum scores is now a sample player over the Salamander Drumkit (velocity layers with round-robins, derived toms, a synthesised clap), loaded off the audio thread and swapped in atomically. The physically modelled kit stays as makepad-drumkit-phys for a later pass.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
apps/fabric runs SAM 3D Body in-process (install + licence through the hub panel), measures the rest-pose body mesh (libs/fabric/measure: 25 tape measurements from plane slices and landmarks) and drafts parametric patterns (libs/fabric/draft: T-shirt, A-line skirt, easy trousers; nesting, true-scale SVG, tiled A4 PDF). Live mode streams the webcam at a few frames a second, shows the posed body with the measurement rings riding on it, and re-drafts when the numbers settle. Measurements sit in a DataGrid that copies as tab-separated text.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A View can now say event_order: EventOrder.Down in script. The DataGrid cached its geometry at draw time, before a Fill sibling could shift it, so clicks in a right-hand column landed outside; it re-anchors to its drawn rect on every event.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Eight song sections by drums, bass, vocals, other and mix; launch and swap on the bar, right-click halves and quarters, per-cell waveforms with score blocks, a full-width score popup (drums, bass tab, melody with lyrics) played back through the piano and the sample kit, an NMF drum transcriber, Basic Pitch for pitched stems and Beat This! grid refinement when installed, beat jump and phase-flip buttons, a loading overlay for the grid, and the shared model install panel in INSTALL MODELS.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
libs/score_view carries the engraving, spacing, font and document code out of the score app so any app can show notation: a ScoreView widget with width/page/content fits, pan and zoom, a playhead, a dark palette, drum-key labels, lyrics under melody notes, and builders for drum, pitched and bass-tab scores. The score app uses it. Vector glyphs no longer write depth for transparent fragments, and the Metal screenshot staging sizes itself from the source texture.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
LocalModels runs registry models in-process (install state, resumable downloads, recorded licence acknowledgements at $MAKEPAD_HOME/license_acks.json, weight paths by file role) and libs/ai/hub_ui is the install panel + licence modal every app can embed. New native ports: Beat This! (beats + downbeats) and Basic Pitch (note transcription) with their registry entries; the Salamander Drumkit samples (CC BY-SA 3.0, 37 files pinned by size and sha256) as a sample bank the downloader fetches like a model.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Chunks keep the player's bytes apart from the composed density: plan
presses land in an owner-keyed PlanTerrainPatch that is retracted with
its feature and never touches history, so removing a railway takes its
bed with it and a human fill under it survives. Surface queries answer
Surface | Hole | Outside instead of pretending the heightfield continues
over a hole or past the border; landforms issued inside a plan eval are
plan, outside it history. Seven tests pin the layering, including
same-inputs-twice equality.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The last two hub commits staged whole files and carried uncommitted hunks
of another lane (beats-native, notes-native, the local runner, new
domains and license keys) that reference files not yet in the tree. This
restores those files to the body changes only; the other lane's edits
stay in its working tree.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The native port covers everything the Python reference worker did (body,
hands, mask prompt, multi-person), so the subprocess backend, its fake
worker harness, the sam3dbody-ref registry entry and the
MAKEPAD_SAM3DBODY_* environment go. The packet validator moves to the
native backend.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The sam3dbody backend reads its options from the request's prompt string
(`hands`, `detect`, `persons=N`): `hands` runs the full mode and the
packet carries which hands were fused and their boxes; `detect` finds up
to N persons with SAM 3.1 (an optional native-segment role on the body
entry, the same artifact the segment entry pins) and runs one body pass
per person with its box and mask, so the packet's people array grows.
The body crate shares one body pass between the packet, mask and hands
entry points, and infer_full takes the mask prompt too.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
BodyModel::infer_masked takes a provided person box and its full-frame 0/1
mask: the mask is warped with the crop's own affine (bilinear, rounded back
to 0/1 like the reference's uint8 warp), encoded by the prompt encoder's
mask CNN (four stride-2 convolutions with channel LayerNorm and erf GELU,
then a 1x1 to 1280) and added to the backbone tokens before the ray
conditioning, replacing the folded no-mask term. Oracle parity on the
mask fixture: warp exact, every CNN stage within f32 accumulation noise,
conditioned context 8e-4, end to end kp3d 2.2 mm / kp2d 0.25 px. 41 tests.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
BodyModel::infer_full runs the reference's full mode natively: the body
pass's hand boxes become two 512 crops (the left one cut from the mirrored
image, padding 0.9), each goes through the backbone, its own ray
conditioning and the hand decoder (the body decoder with the *_hand
tensors), the hand-mode rig pre-transform (local_to_world_wrist, wrist and
root offsets, non-hand parameters zeroed) and the hand camera head's
scale factor of 10; the left result is un-mirrored. The fusion gates each
hand (wrist angle, box size, keypoint spread, wrist distance), re-prompts
the body decoder with the trusted wrists and elbows as point prompts (the
decoder now takes N prompt tokens and a previous estimate), and writes the
fused wrist angles, hand parameters and hand scale/shape back before the
final rig pass. pose.rs gains the roma xyz (extrinsic) and XZY (intrinsic)
euler pairs; mhr.rs returns joint global rotations.
Oracle parity on both full-mode fixtures: every hand-decoder stage per
step (tokens 7e-3, heads 4e-4, rig params 1e-4), fusion reports as the
reference (one hand trusted on the standing photo, both on the crop), and
end to end kp3d 1.6 mm / kp2d 0.85 px. 36 tests.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
One backend call per SAM-style decoder layer (PE norms, token
self-attention, token-to-image cross-attention, erf-GELU feed-forward,
final norm) inside one command buffer, with the layer's f32 weights cached
on the device under their content identity and pooled transients.
gpu_two_way_layer_resident in the common backend; CUDA declines and the
per-op path stays. Body decoder loop on the M3 Max: layers 100 -> 9 ms,
frame 405 -> 266 ms, oracle parity unchanged (kp3d 1.5 mm).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
gpu_linear_f32_resident promised a resident weight but the Metal tensor
backend re-uploaded it every call, which for the MHR rig's 664 MB pose
corrective matrix cost 50 ms a step. Metal tensors now carry a content
identity (fresh at creation and after every in-place write, so a cache
keyed by it can never serve a stale weight), and the resident linear caches
the device buffer under it. Body frame on the M3 Max: 705 -> 405 ms (rig
302 -> 20 ms, refine 41 -> 13 ms, heads 10 -> 6 ms).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The Metal tensor backend is host-Vec based: every op copied its inputs up
and its result back, which put the DINOv3 backbone at 2.1 s a frame on an
M3 Max. try_vit_backbone_resident_f32 runs a whole pre-norm ViT stack
(LayerNorm, q/k/v, rotate-half rope from tables, flash attention, out,
LayerNorm, SwiGLU, down; residuals in place) inside one command buffer
against cached bf16 weights, with a new kernel_makepad_rope_half_tables_f32
kernel for the rope. The precompiled metallib now carries the bf16 GEMM
kernels the runtime source compile already enabled on bfloat devices.
The common backend exposes it as gpu_vit_backbone_resident (CUDA declines;
its per-op path is already resident) and the body backbone tries it first:
233 ms a frame on the M3 Max, same oracle parity (kp3d 1.5 mm).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The FP8 backbone mode added each linear's bias by downloading, tiling and
re-uploading it per call, which cost more than the FP8 GEMM saved. A
gpu_add_cols_broadcast op (CUDA kernel; host loop on the Metal tensor
backend) adds a cols-wide bias to every row on the device, and each linear
keeps its bias resident after the first upload.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
BodyModel::set_backbone_fp8 quantises every backbone weight to E4M3 with
a per-tensor absmax scale and runs the tensor-core FP8 GEMM (bias
broadcast after). A backend without FP8 turns it off per layer on the
first refusal, so Metal keeps bf16. The oracle test reports its
accuracy and timing next to bf16; the default stays bf16 until the
numbers say otherwise.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The backbone's linears now take the cuBLASLt bias-epilogue / bf16 mm
paths (bf16 operands, f32 accumulation, bf16 output — the reference's
precision) with the f32-accumulating GEMM as the fallback. The rig's
pose correctives run on the final refinement step only by default: the
intermediate steps only feed keypoints back into the decoder, and the
oracle shows the difference is 0.4 mm (2.1 vs 1.7 mm against the
reference) for half the loop's rig time; `correctives_every_step` keeps
the exact mode.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The backbone, conditioning and decoder now take any square crop whose
side is a multiple of 16 (512 is the trained size); BodyModel::set_crop_size
selects it and caches the dense positional grid per size. Measured on the
oracle image against the reference: 512 gives 1.7 mm mean keypoint error,
384 and 256 about 2 cm mean (6 to 7 cm worst joint), 192 falls apart —
the knob is a real accuracy trade, not free speed. The decoder loop
reports its split (layer chain, heads, rig+camera, refinement) so the
next optimisation is chosen on numbers.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Apps ask the hub for a recognizer or a voice and get one; where it runs is
the hub's decision. AiHub::start_stt / start_tts return poll-driven
sessions shaped like the chat session. The Auto ladder is Whisper/Kokoro in
this process (weights present, machine election), on the machine node over
loopback, on a LAN node, else the OS engine; SpeechReach::Local is the
"don't reach out" knob. Audio always comes back as PCM: the app owns the
device.
Three layers:
- makepad-ai-speech is the whole speech model family, engines only.
libs/voice (Whisper + Silero VAD) folds in as the `whisper` and `vad`
modules next to kokoro and indextts, each a cargo feature; the Apple
bridges and the Speaker/VoiceTranscriber selection leave it.
- makepad-system-speech (new) is the OS speech services as blocking fns:
Apple SpeechAnalyzer/AVSpeechSynthesizer via Swift, Windows.Media.Speech*
on the vendored bindings, Android SpeechRecognizer/TextToSpeech through
MakepadSpeech.java (API 26 floor), espeak-ng on Linux. It models the two
STT shapes honestly: PCM in (Whisper, Apple) versus an engine that owns
the microphone (Android, Windows), with capabilities the caller reads.
- the hub grows speech sessions, in-process Whisper/Kokoro workers with the
residency election, a `whisper` wire backend (stt domain, registry entry
pinned to ggerganov/whisper.cpp) so a Mac can serve a Quest, and a
`language` field on the generate request.
Consumers: the Window voice input runs on an STT session and switches to
engine-mic mode when the recognizer owns the microphone; converse's
SpeechOutput is a lazily started TTS session plus a pump thread; route
drops its private speech copy for converse; vj's lyrics fallback and the
alignment bakes call the engines directly.
Verified here: speech-roundtrip through the real sessions (Apple voice in,
in-process Whisper on Metal out, 4.3% WER); system-speech-test TTS->STT
verbatim; hub/converse/system-speech unit tests; msvc, aarch64-android and
linux-gnu cross-checks; Java against android-34. Windows, Android and Linux
bridges are compile-checked only.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
libs/windows/windows-rs/src/Windows/mod.rs was a hand-pruned snapshot with
no recipe behind it; adding a WinRT namespace meant hand-copying vtables.
Now tools/windows_bindgen (standalone, windows-bindgen 0.62.1) regenerates
it from filter.txt: package mode with the COM `_Impl` traits, Win32 imports
linked through windows_core, upstream's 800-column rustfmt (the repo-root
rustfmt.toml disables formatting and has to be overridden), the filter
closed over every dependency the generator would otherwise skip a member
for, the namespace tree folded into one file with every feature gate kept,
and the two spots where the published 0.62.1 generator predates the vendored
core 0.62.2 normalized (Error::from_thread, imp::array_proxy).
The filter is the old file's item list plus Windows.Globalization.Language,
Windows.Media.SpeechRecognition and Windows.Media.SpeechSynthesis for the
OS speech engines. The generated `deprecated` gate is declared as a feature.
Checked on x86_64-pc-windows-msvc: platform, video, network, mpterm,
system-speech.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The backbone (20 heads) and the decoder (8 heads) both have 64-wide
heads, which the stack's FA2 kernel covers: f16 operands with f32
softmax and accumulation, the reference's own precision class, instead
of the composite path that materialises the 1029 x 1029 scores per head.
The composite path stays as the fallback where a backend lacks the
kernel. Oracle parity unchanged.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The ray-conditioning conv used to download the 1024 x 1280 embedding,
concatenate the 99 ray features on the host and upload the result; it is
now two resident linears over the two column blocks with the no-mask
term folded into the bias, plus an add (32 ms -> a few on the 4090).
The decoder loop downloaded the whole normalised token block every
layer for its one pose row; it now slices that row and fetches the
block once at the end (or per layer under a trace). Same numbers.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
On the 4090 the frame was 885 ms of which 840 were host scalar loops in
the decoder loop: the three 70-row refinement FFNs (about 240M
multiply-adds a step), the two heads, and the rig's 55k x 3000
corrective output layer plus its identity blendshape sum. Those are now
GPU-resident linears (heads.rs GpuStepHeads, MhrRig::prepare_gpu), the
skinning computes one transform per joint instead of one per influence,
and the results are identical (all 29 oracle tests unchanged). The rig
still runs entirely on the host when no GPU side was prepared.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The recut in a6341981d applied its patch against the wrong directory
and restored the six shared files to the previous tree without the
body-native hunks. This commit adds exactly those: the `body-native`
feature and optional dependency, the pinned `sam3dbody` registry entry
and its test, the backend arms and the module declaration. Working
tree untouched.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
66e5e2f11 committed the working tree of the shared hub files and with it
another lane's uncommitted edits (a new domain, request fields, a
backend arm, manifest lines). This commit restores those files to the
previous tree plus only the body-native hunks. The working tree is
untouched: the peer's edits stay on disk as their uncommitted work,
exactly as before.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
model.rs closes the loop: crop -> backbone -> ray-conditioned context ->
six decoder steps, each through the pose head, the rig, the camera and
the projection, then the packet the sandbox already reads (kp3d/kp2d in
camera axes, the 204 rig parameters, global rotation, camera translation,
joint positions). Against the reference on the oracle image, on Metal:
3D keypoints within 1.7 mm, 2D within 0.4 px, rig parameters, camera
and rotation within 2e-3. packet.rs writes the JSON by hand with the
reference worker's rounding and field order.
The hub gains the `body-native` feature (default on): registry entry
`sam3dbody` pinned to the Comfy-Org repack by revision, size and sha,
body_native_backend.rs beside the subprocess reference backend with the
same live_step contract, the `body` capability advertised when the
feature is compiled, and a stubbed test double for the CPU-only tests.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
decoder.rs builds the 145-row token set (pose, previous, prompt, two
hand-box rows, 70 keypoint rows, 70 3D-keypoint rows), runs the six
layers with the SAM-style repeated positional encoding (none on the
first layer's self-attention), cross-attends against the ray-conditioned
context, and after each step hands the normalised pose token to the
heads and updates the keypoint rows from the caller's feedback: the
2D-keypoint positional FFN and the bilinearly sampled context features
on the valid rows, the pelvis-centred 3D positional FFN on the rest.
heads.rs holds the host-side ReLU FFN heads, the refinement FFNs, the
hand-box MLP and the hand classifier. Against the oracle on Metal, every
layer's residual stream is within 6e-3, every step's pose head within
8e-4 and camera head within 2e-5; token assembly and the host heads
match to 1e-4.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
dino.rs is the 32-block ViT-H+/16 on the gpu_* surface after the TRELLIS
conditioner: bf16-resident linears with f32 accumulation, layer scale
folded into the output projections, rotate-half rope, SwiGLU, the
model's own final norm. preprocess.rs is the crop (box -> 1.25 pad ->
3:4 -> square -> 512 bilinear warp, ImageNet normalisation), the CLIFF
condition vector and the patch rays; condition.rs is the dense
positional encoding and the ray-conditioned decoder context. Against the
reference oracle on Metal: backbone 1.1% mean relative (bf16 noise),
ray-conditioned context 8e-5, crop within one u8 rounding step, rays and
dense PE 1e-7. One reference detail the paper does not state: its shrink
of the ray field is an antialiased filter whose taps clip at the image
edge, so the two edge patches sample inside their block centre (9.03 and
501.97 rather than 7.5 and 503.5); block centres left 0.1 of error.
The Metal tensor backend was missing rope_half (it aliased the
interleaved layout) and layer_norm_mul_add; both now exist with the
CUDA contract, which is what lets this backbone run on Apple silicon.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
mhr.rs is the Momentum Human Rig on the CPU: blendshapes, the 889x249
parameter transform, parents-first similarity kinematics (x,y,z,w
quaternions, Rz Ry Rx eulers, 2^s scales), the sparse-then-dense pose
corrective MLP over joints 2.., linear blend skinning and the 308-row
keypoint regression. pose.rs decodes the 519-wide head output: 6d
rotations, the 23 ball / 58 hinge / 6 translation body layout, the
mixed-dof hand layout, scale and hand component bases, the camera
translation and the perspective projection. Against the reference
oracle: vertices within 1e-4 cm with correctives on, keypoints within
1e-6 m, rig parameters within 1e-7. Two conventions the spec could not
settle on paper are now settled by the fixture: the head's global
rotation triple arrives Z,Y,X-ordered, and the corrective features start
at joint 2 (750 wide). Fixture tests skip cleanly without the oracle
directory or the weights.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
makepad-ai-body joins the AI model workspace: the constants of the
architecture (DINOv3 ViT-H+/16 at 512, the 6-layer promptable decoder,
the 519-wide pose head, the 127-joint / 18439-vertex MHR rig) and the
single-file safetensors reader for the Comfy-Org repack, which fails
closed on a Meta checkpoint-style header and checks the shapes the port
is written for at load. The backbone, decoder and rig modules follow
in their own lanes against the spec under local/agent_state/sam3dbody.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
encode_intra_frame_mp4 on Windows and Linux now goes through the
platform file encoder (Media Foundation sink writer, GStreamer): one
keyframe-only stream, one frame, a scratch file read back and removed.
It pays the container machinery the Apple session path avoids, but a
tile tape baked on any machine reads on any other, which is what the
image-tiles library sits on. A round-trip test encodes a frame and
decodes it through the platform decoder on whichever platform runs it.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
encode_intra_frame_mp4 was macOS-only, and libs/image_tiles imports it
unconditionally, so image-tiles, its example and source-library did not
build for Windows (found by a Windows-target cargo check sweep of the
workspace; every other crate checks clean). Other platforms now get the
same signature answering with an error, the way the rest of this file
stubs what it cannot do yet.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The doctrine catches up with the engine: landforms and tunnels are one
call and digging works anywhere; railways and roads are edited by their
path points (crossings generate, styles switch, any model drives);
freshly modeled aliases are live immediately — never park a display
substitute.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The voxel layer's volume gate is gone — any edit materializes chunks
anywhere on the map (volumes remain as styling), with the lazy-chunk
economics proven by test: zero storage until the first op. The composed
surface seam (GameWorld::surface_height_at: heightfield where untouched,
voxel surface where a chunk owns it) is what ground queries, senses and
the drape corridor read, so a mountain raised mid-game and a dug crater
are the same truth the vehicles drive on. landform.rs adds the macro
shapes (mountain/hill/ridge/valley/crater/plateau, fbm detail, slope
rock + snow recolor) and the tunnel op rides the capsule-filtered
materialization.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
searchdb imported std::os::unix::fs::FileExt for read_exact_at, which
does not exist on Windows (reported from a Windows checkout of work).
A small ReadExactAt trait now wraps unix pread and Windows seek_read,
both cursor-free, so the shared reader keeps serving lookups from
several threads without a lock. Checked on x86_64-pc-windows-msvc.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A realtime feed session parked in its wait-for-a-frame loop forever when
the client died without sending stop (a sandbox quit left job-2 live on
.123 for five minutes holding the GPU slot). The wait loop now returns
to the top of the session loop once no socket is left, where the idle
timeout counts a socketless session down. Test covers it.
SkinnedModel gains node_parent/node_count, joint_skinned_centroid (the
direction a leaf limb actually runs, from the flesh it skins) and
from_nodes (a mesh-less rig for hierarchy-maths tests) — what the
sandbox's webcam mocap retarget needs.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B626urtY1Xo4hQdLzvSK6F
EmitterAnchor::EntityLocal carries an offset that yaws with the entity —
a locomotive's chimney keeps its smoke over the funnel through every
corner. The step lookup resolves (position, yaw) instead of position.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Same orphaning as the sandbox: context::assemble had no caller post-P8,
so gen/vj sessions ran brief-less. The executor's capability doc leads
with the assembled profile layer.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The verbs existed with the right doc strings, but the model reads the
brief, not the verb table — and the brief's ONE CALL list never said
railway, so it hand-placed track pieces, horrendously. Now it says it,
with the two-line essential shape.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The Source Library wall's pixel engine, extracted for anyone's pictures:
libs/image_tiles carries the NV12 slot pyramid, the 32x32 shard atlas
geometry and the one-HEVC-intra-frame-per-file tape codec (tape.rs), a
small SQLite index (db.rs), a priority decode pool (store.rs), and the
TileGrid widget — instanced tiles batched per atlas page, anchor-locked
wheel zoom with log-space glide, continuous per-shard LOD with
crossfades, full-resolution promotion under byte budgets with LRU
eviction, and uniform-only re-presents inside the pad of the last build.
image-tiles-bake downloads a manifest of URLs (fetch pool free to be
wide, encode pool hard-capped — concurrent VT session churn has panicked
the encoder's IOMMU) and bakes a library; examples/image_tiles views one.
No JPEGs on disk; decode and encode are the hardware's.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Post-P8 the game session still advertised assets.query/assets.schema but
the in-process executor answered both Unavailable — the model's main
alias-search tool was dead, and every "find me X" turn gave up on the
store. Both now execute over the server's bounded /v1/assets/query route
(schema via sqlite_master plus the usage notes). The game brief gains the
new-game-vs-edit rule, interior design law, generate-after-search, and
explicit y semantics so player_pos().y stops being pasted into
ground-relative fields.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
One DrawSceneScreen serves both the in-world video screen and every
sprite billboard, and the sprite loop left its last pose, size and atlas
behind — so the next frame's "is there a screen" gate (zero screen_size
draws nothing) read the leftover and drew the whole spritemap as one
opaque quad: under the last-drawn unit in C&C, and hanging in the sky of
any level that draws no sprites at all. Snapshot the host's pos/size/
texture before the lane and restore after.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>