Files
roam/trmnassets.org
T
2026-06-19 18:09:39 +03:00

103 lines
6.4 KiB
Org Mode
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
:PROPERTIES:
:ID: 4d5e6bc8-32eb-469f-a69f-84b14458c55b
:END:
#+title: trmn/assets
#+filetags: :project: :knowledge: :assets:
[[id:6293baa2-c8a8-4c49-9284-1fa2eed75032][trmn]] — asset pipeline: SVG sprites + GLB objects + location scenes
** Architecture
Three asset types, all served from ~$out/assets/~ by Caddy:
- *Sprites*: SVG files in ~assets/sprites/{eyes,nose,mouth}/~, static/committed, no build step
- *3D objects*: GLB files in ~assets/objects/~, generated during ~nix build~ by Node.js scripts in ~scripts/~
- *Location scenes*: ~.blend~ files in ~assets/scenes/**~ are the source of truth; Blender exports GLBs at build time, then packed into ~assets/scenes/scenes.pack~ (single binary, one browser fetch)
Face compositing at runtime: load SVG parts → draw onto ~OffscreenCanvas(128,128)~~THREE.CanvasTexture~.
Applied to the +z front face (index 4) of the head ~BoxGeometry~ via a material array.
** Location Scene Pipeline
~.blend~ files are the source of truth (edit in Blender, commit ~.blend~, GLBs are build artifacts):
1. ~flake.nix~ buildPhase: ~blender --background file.blend --python scripts/export-glb.py -- out.glb~ for each ~.blend~ in ~assets/scenes/**~
2. ~scripts/pack-scenes.mjs glb_tmp assets/scenes/scenes.pack~: validates all SCENES location IDs have a GLB (warn by default, ~STRICT_LOCATIONS=1~ to error), concatenates into ~scenes.pack~
3. Pack format: ~[4-byte LE uint32: manifest len][JSON manifest][...GLB bytes]~
4. Runtime: ~loadPack()~ fetches once, ~loadLocationScene(id)~ slices + parses per scene, cached
34 unique location IDs (e.g. ~home/bedroom~, ~office~, ~school/classroom~). Directory mirrors IDs: ~assets/scenes/home/bedroom.blend~ → ID ~home/bedroom~. Full mapping in ~ASSETS.md~.
** Blender Naming Conventions (procedural overrides)
- ~IF_<NAME>~ meshes: toggled visible/hidden at runtime by ~applyLocationProps()~
Examples: ~IF_CRIB~ (age<3), ~IF_ADULT_BED~ (age≥13), ~IF_TV_LARGE~ (wealthLevel>70)
- ~WALLS~, ~FLOOR~: material color replaced at runtime with deterministic palette color
- All other mesh names: always visible, untouched
Full ~IF_*~ table and authoring guide in ~ASSETS.md~.
** Blender Scene Setup
- Character is ~2 units tall; typical interior: 58 units wide, 3 units tall
- Camera: pos ~(0.5, 1.6, 6.5)~, looks at ~(0, 1.0, 0)~, FOV 26°, aspect 2.39:1
- No lights in .blend files — runtime adds ambient + two directional lights
- Materials: Diffuse BSDF (flat color); Principled BSDF works but is overkill under Lambert
- ~export_apply=True~ in export script — modifiers applied; no armatures/animations
- Poly budget: ~500 triangles/scene; outdoor scenes skip WALLS/FLOOR (no runtime error)
- Run ~nix develop~ to get a shell with ~blender~ on PATH for authoring
** Runtime API (~index.html~ Three.js block)
- ~loadPack()~: called once at init; gracefully no-ops if pack not built yet
- ~loadLocationScene(locationId)~: returns ~THREE.Group~ (cloned from cache), or ~null~ if not in pack
- ~applyLocationProps(threeScene, props)~: traverses scene, applies ~IF_*~ visibility + WALLS/FLOOR colors
- ~generateLocationProps(locationId, masterSeed, playerState, eventLog?)~ from ~locations.js~
- ~window.__sceneLoader.loadAndShow(locationId, props)~: removes previous loc scene, loads + applies new one
** Debug Panel (~▸ scene debug~ in browser)
Collapsible ~<details>~ panel below the chat box. Controls:
- Location dropdown (all 34 IDs, populated from ~SCENES~ at runtime)
- Sliders: age, wealth, children, job tier, moves (home move count)
- *sync from today*: pulls actual simulated state from ~window.__life~
- *load scene*: calls ~window.__sceneLoader.loadAndShow()~; shows ~[not in pack]~ if .blend missing
- Live props display: wall/floor color swatches + hex, visible ~IF_*~ mesh names
Props update on every slider move even without a loaded scene.
** locations.js
ES module, imported by Three.js block and debug module. Exports ~generateLocationProps~.
- Home: seeded from ~makeRng(masterSeed, 200000 + moveIndex)~ where moveIndex = count of ~move_city~ events ≤ currentDay → new house each time player moves
- Office: offset 300000; School: 301000; University/dorm: 302000; others: hash into 303000399999
- ~playerState~ fields: ~{ age, wealthLevel, numChildren, jobTier, inCollege, retired, currentDay }~
** PRNG Offset Allocation (all streams)
| Range | Owner |
|---|---|
| -2 to -1 | Family layout + protagonist traits |
| 0 36,500 | Life simulation daily |
| 50,000+ | Schedule (per-day, offset 50000) |
| 200,000 + moveIndex | Home appearance (per house) |
| 300,000 | Workplace |
| 301,000 | School |
| 302,000 | University / dorm |
| 303,000399,999 | Other locations (hashed from ID) |
** Conventions
- All sprite SVGs are 128×128; composite with ~drawImage(img, 0, 0, 128, 128)~
- Face part selection seeded from ~window.__life.masterSeed~ via inline ~mulberry32~ in Three.js block
- GLB generators: pure Node.js stdlib only (no npm), accept output path as arg
- ~pkgs.blender~ in ~nativeBuildInputs~ (build) and ~devShells.buildInputs~ (~nix develop~ shell)
** Gotchas
- ~src = ./.~ only includes git-tracked files. Run ~git add assets/scenes/ scripts/export-glb.py scripts/pack-scenes.mjs locations.js~ before ~nix build~ or they are silently excluded.
- ~BoxGeometry~ material array face order: ~[+x, -x, +y, -y, +z, -z]~ → index 4 is front face
- GLB generator runs in Nix buildPhase and writes to build dir; ~cp -r assets $out/assets~ picks up generated files
- ~locations.js~ imports ~makeRng~ from ~./life.js~; served by Caddy alongside other JS modules
- Blender headless needs ~--background~ flag; no X11 required in stdenvNoCC sandbox
** Key Files
- ~assets/sprites/eyes/eyes_{1,2}.svg~ — wide-open vs narrow/tired eyes
- ~assets/sprites/nose/nose_{1,2}.svg~ — dot vs nostrils nose
- ~assets/sprites/mouth/mouth_{1,2}.svg~ — smile vs neutral mouth
- ~assets/objects/book.glb~ — generated at build time; dark-red flat box 0.14×0.18×0.03
- ~assets/scenes/~~.blend~ source files, mirroring location ID hierarchy
- ~assets/scenes/scenes.pack~ — build artifact; binary pack of all location GLBs
- ~scripts/gen-book.mjs~ — pure Node.js GLB writer for book object
- ~scripts/export-glb.py~ — Blender Python: exports active scene to GLB
- ~scripts/pack-scenes.mjs~ — validates + concatenates GLBs into ~scenes.pack~
- ~locations.js~~generateLocationProps(locationId, masterSeed, playerState, eventLog?)~
- ~ASSETS.md~ — full authoring guide: location→file map, IF_* table, Blender setup, workflow