TinyWorld Crowd Layer
Use this skill when changing TinyWorld's 2.5D crowd/person sprite system.
Shape
- Runtime:
vendor/tiny-crowd-layer.js, exposed aswindow.TinyCrowdLayer. - Assets:
crowd/, copied todist/crowd/bypublish.sh. - Integration:
tiny-world-builder.htmlcreates one ambient crowd layer underworldGroup.
Rules
- Keep people out of
world[x][z]andcellMeshes; they are moving runtime entities, not terrain/object intent. - If replacing 2.5D people with rigged/model characters, keep
TinyCrowdLayeras the movement/zone simulation source and mirror its people into transient scene actors. Hide sprites throughshowSprites/setSpritesVisible, but do not persist the character actors into world state. - Rigged/model crowd actors should route animation through the reusable
createRiggedCharacterRuntime()/updateRiggedCharacterRuntime()helpers. GLTF/GLB clips driveAnimationMixeractions; do not cut or infer limbs from a T-pose mesh. - Use
tilePos(x, z)for map placement and a terrain-height callback for feet height. - Preserve the original crowd demo's
Pconfig surface (count,size,slices,bob,sway,headSway,leg,squash,lean,hipLine,cadence,speed, etc.) when tuning animation. - Render movement through the original slice-wave canvas animation, then upload that canvas into a
THREE.CanvasTextureused by aTHREE.Sprite. - Three.js r185 uses
texture.colorSpace = THREE.SRGBColorSpace; if code may run before00-prelude.js, setcolorSpacedirectly with anencodingfallback instead of calling TinyWorld helper functions. - Size people against known TinyWorld model proportions: default door height is about
0.48world units, and people should be below that. - Choose
down/up/left/rightframes from the camera's horizontal angle relative to the person's heading; steep overhead views use a baked collapsed-bodytopframe. - Each person has a circular zone (
radius) around its 3D point for collision, hit testing, visibility, and later avoidance. - Keep the crowd layer vanilla JS with no bundler and no npm runtime dependencies.
- Toggling & State: The crowd can be enabled/disabled via the global variable
crowdEnabled(persisted inlocalStorageviaRENDER_LS.crowdEnabled, starting from settings version'21').- When
crowdEnabledis false,seedCrowdPeople()clears the sprites and exits early, and the update loop is bypassed. - When toggled on, the layer is initialized lazily via
initCrowdLayer()or populated/re-seeded viaseedCrowdPeople(). - Toggles must be present in both the Settings Modal and the Live Crowd Panel, and synchronized via
syncControls()andapplyFromControls(). - Worlds room play temporarily suppresses ambient crowd visuals through
window.__tinyworldCrowd.setRuntimeVisible(false)and restores the prior runtime-visible state on leave. Do not persist this ascrowdEnabled=false; it is a room-lifecycle visibility guard so playable avatars are not mixed with ambient people.
- When
- UI & Interaction: The live Crowd Controls panel uses the same glassmorphism design parameters as the map panel (translucent background, thin white border, inset glow, saturate backdrop-blur filter).
- The panel is draggable using pointer capture events on its header/chrome, clamping positions within the viewport and saving state to
localStorageundertinyworld:crowd.pos. - The panel is collapsible off-screen to the right (via
transform: translateX(...)), and triggers a👥right-edge handle button when closed. The collapsed state is persisted tolocalStorageundertinyworld:crowd.collapsed.
- The panel is draggable using pointer capture events on its header/chrome, clamping positions within the viewport and saving state to
Asset contract
- Character sets need four PNG views:
down,up,right, andleft. - Animatable 3D character replacements must come from model stamps with real skins and animation clips. OBJ/MTL character stamps can replace sprites visually in other contexts, but they do not carry skeleton animation clips and should not be used as animated crowd actors.
- The imported source repo has a misspelled
charachters/path; preserve it in copied asset URLs unless migrating all references at once. - If a sprite fails to load, the layer should degrade to a visible fallback texture instead of breaking app boot.
Integration checks
npm testnpm run build- Browser page load has no console errors.
- Camera orbit changes swap the visible crowd angle without flickering.
- Reset/load reseeds ambience without saving crowd people into the world schema.