Player/Agent Sprite Implementation Plan¶
Purpose¶
This plan covers the first implementation slice for player and agent sprite rendering.
Always update this plan when changing player/agent sprite data contracts, render snapshots, render passes, atlas assets, interpolation behavior, height-based visuals, RD controls, swarm/animal visual integration, player visual integration, or validation coverage.
Agents are stateful moving entities owned by gameplay or simulation runtimes: the player, NPCs, ground animals, birds, hawks, and later other creatures. They are not sprite details, decals, or structures. They may reuse the same low-level atlas-backed map-space quad renderer as structures, but their owner runtimes and gameplay truth remain separate.
The first goal is visual replacement/addition, not gameplay rewrite:
- preserve existing authoritative player movement and swarm simulation
- feed sprite render data from owner runtimes
- keep smooth render positions continuous
- use height for flying-agent visual scale
- avoid deriving gameplay truth from rendered sprites
Dependencies¶
- Sprite rendering design context:
docs/SPRITE_DETAILS_RENDERING_DESIGN.md - Current structure sprite renderer precedent:
src/render/mapSpriteRenderer.jssrc/render/passes/structurePass.jsdocs/STRUCTURES_IMPLEMENTATION_PLAN.md - Existing player/movement/activity ownership:
src/gameplay/movementSystem.jssrc/gameplay/playerActivityRuntime.jssrc/gameplay/playerTravelActivityRuntime.jssrc/gameplay/playerRuntimeBinding.jssrc/core/state.js - Existing swarm ownership and interpolation:
src/gameplay/swarmGameplayRuntime.jssrc/gameplay/swarmRenderSetupRuntime.jssrc/gameplay/swarmInterpolation.jssrc/gameplay/swarmLoopRuntime.jssrc/render/swarmLitRenderer.js - Render pipeline integration:
src/render/renderPipelineRuntime.jssrc/render/renderer.jssrc/app/renderShellAssemblyRuntime.js - RD/debug UI conventions:
docs/RD_UI_ARCHITECTURE.mddocs/UI_LAYOUT_GRID.mdsrc/ui/rd/panels/agentsPanelHtml.js
Current Status¶
Implementation has started with the pure shared model layer and renderer coverage needed before runtime integration.
Already available foundation:
mapSpriteRenderercan draw atlas-backed map-space quads and is proven by Structures.- Structure rendering has validated atlas generation from individual PNGs, source-image orientation, nearest filtering, binary alpha cutouts, and lightweight terrain lighting.
- Swarm simulation already owns continuous
x/y/zstate for birds and hawks. - Swarm interpolation already exposes smoothed render positions through
writeInterpolatedSwarmAgentPos()andwriteInterpolatedSwarmHawkPos(). - Existing lit/unlit swarm square rendering provides a known fallback visual while sprite agents are developed.
Implemented in this slice:
src/gameplay/agentSpriteModel.jsnormalizes sprite definitions, resolves cardinal/8-way direction indices, clamps height-derived scale, resolves velocity-based rotation, resolves pivoted visual bounds, and builds renderer-compatible render items.tests/agentSpriteModel.test.jscovers direction, fallback direction, height scale, visual bounds, and gameplay-neutral render item shape.tests/mapSpriteRenderer.test.jsnow explicitly covers fractional map-space coordinates for map-sprite quads.src/gameplay/playerSpriteRuntime.jsproduces the first player sprite render snapshot and tracks player facing from movement-step notifications. Authored player sprite colors render untinted; the old overlay player dot is only a fallback when the player sprite visibility toggle is off.src/gameplay/swarmAgentSpriteRuntime.jsproduces bird/hawk sprite render snapshots from existing swarm state and interpolation callbacks. Birds and hawks use their simulation velocity vector to rotate one sprite slot instead of consuming directional atlas slots.- Bird sprites support render-time keyframe animation from a horizontal sprite
strip. The frame count is metadata-driven, not hardcoded; render snapshots
choose
spriteSlot + animationFrameIndex, and the atlas builder expands all strip frames into consecutive fixed-grid slots. Swarm snapshots grow atlas rows when a large frame count would exceed the default16columns. - Directional agent sprites reserve the full directional source span in render
items (
directionCount * frameCount) so changing direction does not point at an unpacked atlas slot during async atlas rebuilds. If a source PNG has only one authored frame, that frame is repeated into each reserved direction slot. - Agent sprite snapshots now receive the render frame time from the render pass, so render-time animation advances independently from game-time speed.
- Map-sprite rendering treats sprite alpha as binary cutout: alpha
0discards the fragment, any non-zero alpha renders fully opaque after lighting. - Bird source sprites may use exact white (
#ffffff) as an authored background instead of an alpha channel. During atlas construction, matching white pixels are converted to alpha0with tolerance0; this is source-import behavior, not a shader branch. - A reusable grayscale LUT recoloring path is implemented for agent sprites.
assets/data/render_luts.jsondefines sharedgrayscale-rampLUTs and generated two-digit variant families;src/render/renderLutRegistry.jsresolves those definitions into a256xNLUT atlas. Bird metadata references LUTs bypalette.lutRefs, including explicit IDs and theanimal.bird.dark.variant.00..15range. Swarm birds choose a stable LUT row from stable agent IDs, andmapSpriteRenderersamples the LUT before applying terrain lighting. src/render/passes/agentSpritePass.jsdraws the combined agent snapshot after Structures through the sharedmapSpriteRenderer.src/render/renderer.jsnow executes optionalagentSpritesafterstructures, preserving the planned category order.src/main.jswires player and swarm sprite snapshots into the render pipeline. Swarm sprites and legacy square rendering are now mutually exclusive through shared RD controls.RD > Agents > SwarmandRD > Sprites > Agentsexpose the same swarm sprite-mode toggle. When swarm sprite mode is on, lit and unlit swarm square render paths are suppressed.RD > Sprites > Agentsexposes a player sprite visibility toggle for the first debug slice. The same toggle gates the legacy 2D overlay player marker so the marker does not cover the authored player sprite.assets/sprites/agents/default/exists as the default source-art folder.- Agent sprite definitions now load from owner-scoped JSON files using one
shared schema:
assets/data/agents/player_sprites.jsonfor player visuals andassets/data/agents/swarm_sprites.jsonfor bird/hawk visuals. - The current player sprite contract is a single
64x64source image:slotWidth: 64,slotHeight: 64,directionCount: 1,frameCount: 1. This is source-art resolution only; gameplay footprint remains separate from visual source dimensions. - Agent render items carry explicit
sourceSlotWidth/sourceSlotHeightso the shared atlas builder can crop animated strips correctly even when the combined runtime atlas uses a larger slot size. These fields are opt-in source-crop metadata; structure sprites without them still consume the whole authored PNG. - Player readability needs separate treatment from gameplay footprint and art: the current documented options are ground halo/shadow, outline/stroke, modest visual scale increase, player lighting bias, stronger sprite color/value rules, and low-zoom UI markers.
- Browser-served sprite PNG URLs are cache-busted during image loading so
replacing source art under
assets/sprites/agents/default/is visible after a reload.
Not implemented yet:
- detailed per-type sprite-agent visibility/debugging
Phase 0: Scope Lock¶
- Decide first visible proof target.
- Option A: player sprite first.
- Option B: birds/hawks first.
- Option C: player plus birds/hawks in one shared pass.
- Recommended v1: player plus birds/hawks in one shared agent pass, with visibility toggles so fallback point rendering can stay available.
- Decide first sprite art source.
- Use individual PNGs under
assets/sprites/agents/default/. - Add separate subfolders for scoped sets:
assets/sprites/agents/<mapOrSetName>/. - Use placeholder generated atlas if PNGs are missing.
- Decide first slot size.
- Recommended v1 started as
32x32source slots. - Player now uses a
64x64source slot for more authored detail. - Birds and hawks keep
32x32source slots. - The combined runtime atlas uses the maximum active source slot size so mixed player/swarm source sizes can share one pass.
- Preserve mixed source-size rendering by treating
sourceSlotWidthandsourceSlotHeightas explicit agent crop metadata only; non-agent structure PNGs without these fields are not implicitly cropped to32x32. - Decide first render order.
- Terrain.
- Material detail.
- Sprite details.
- Runtime ground decals.
- Structures.
- Ground agents.
- Flying agents.
- UI overlays.
- Decide first direction model.
- Recommended v1: cardinal or 8-way direction index selected CPU-side.
- Swarm birds/hawks now use free velocity rotation because readability requires their flight direction to match simulation movement.
- Keep player/NPC direction policy separate until their art/readability is evaluated.
- Decide first height model.
- Recommended v1: modest scale from
1.0xto1.5xor1.6xbased on normalizedz. - Defer projected ground shadows until base sprites read well.
Phase 1: Data Contract¶
- Create
docs/AGENT_SPRITE_DATA_CONTRACT.mdif implementation needs a standalone contract. - Define global/shared file names.
- Define optional map-local override behavior.
- Define atlas metadata.
- Define sprite type IDs.
- Define direction/frame metadata.
- Define owner-to-sprite mapping.
- Define height-scale metadata.
- Define fallback behavior for missing assets.
- Decide first asset source layout.
-
assets/sprites/agents/default/player.png. -
assets/sprites/agents/default/bird.png. -
assets/sprites/agents/default/hawk.png. - Future directional variants can use suffixes or metadata.
- Define ID rules.
- Stable sprite IDs independent from atlas slot numbers.
- Gameplay agent IDs remain owned by player/swarm/NPC runtimes.
- Render sprite IDs do not become gameplay IDs.
- Define coordinate rules.
- Render positions are continuous map coordinates.
- Player gameplay position can remain grid/path-step based.
- Swarm gameplay positions remain simulation-owned.
- Render snapshots may include interpolated positions.
- Define footprint rules.
- Separate gameplay footprint from render footprint.
- Renderer only consumes visual bounds, pivot, scale, and atlas data.
- Pathfinding/collision must not read sprite visual bounds.
Phase 2: Shared Agent Sprite Model¶
- Add a pure helper module if needed, for example
src/gameplay/agentSpriteModel.js. - Normalize agent sprite definitions.
- Resolve direction index from velocity or facing vector.
- Resolve optional velocity-based rotation from source-sprite forward orientation.
- Resolve height scale from
z. - Resolve visual bounds from anchor/pivot/scale.
- Build compact render items compatible with
mapSpriteRenderer. - Add tests.
- Direction quantization is deterministic.
- Rotation from velocity is deterministic.
- Height scale clamps.
- Missing velocity keeps previous/default direction.
- Visual bounds respect pivot and scale.
- Render item shape stays renderer-owned and gameplay-neutral.
Phase 3: Player Render Snapshot¶
- Decide owner boundary for player visual state.
- Prefer a small player sprite runtime/binding over adding state paths to
main.js. - Player movement/gameplay state remains authoritative elsewhere.
- Add player sprite snapshot producer.
- Current map position.
- Optional smoothed/interpolated render position.
- Current facing/direction.
- Sprite ID/slot.
- Visual width/height in map pixels.
- Pivot/offset.
- Opacity/tint/debug state.
- Decide first player interpolation.
- If movement queue exposes enough lifecycle data, render between previous and current path-step positions.
- Otherwise v1 may draw player at current gameplay pixel and defer interpolation.
- Add tests.
- Player snapshot is clone-safe.
- Direction follows movement deltas where available.
- Snapshot does not mutate player gameplay state.
Phase 4: Swarm Agent Render Snapshot¶
- Add sprite render snapshot for birds.
- Use
writeInterpolatedSwarmAgentPos()for renderx/y/z. - Use velocity for render rotation.
- Select render-time animation frame from metadata.
- Support arbitrary bird frame counts, with stable per-agent phase.
- Load bird sprite metadata from
assets/data/agents/swarm_sprites.json. - Use height-derived scale.
- Skip dead/removed agents through existing count/ID rules.
- Add sprite render snapshot for hawks.
- Use
writeInterpolatedSwarmHawkPos()for renderx/y/z. - Use hawk velocity for render rotation.
- Load hawk sprite metadata from
assets/data/agents/swarm_sprites.json. - Use height-derived scale.
- Preserve authoritative swarm state.
- Do not change simulation coordinates for visual readability.
- Do not change scout possession validity or targeting to use render sprites.
- Do not infer gameplay from sprite scale.
- Add tests.
- Bird sprite snapshots use interpolated positions.
- Hawk sprite snapshots use interpolated positions.
- Height scale differs for low/high
z. - Stable swarm IDs prevent interpolation across remove-swap changes.
Phase 5: Renderer Backend¶
- Decide whether to extend
mapSpriteRendereror add an agent-specific wrapper. - Recommended: reuse/extend
mapSpriteRendererfor generic map-space sprite items. - Add
src/render/passes/agentSpritePass.jsas the category-specific render pass. - Extend render item support if needed.
- Continuous
pixelX/pixelY. - Visual width/height from scale.
- Pivot/offset.
- Optional per-item rotation around the render origin.
- Sprite slot.
- Animation frame index.
- Tint.
- Binary alpha cutout; no semi-transparent sprite opacity.
- Optional render layer: ground or flying.
- Optional sort key.
- Decide lighting path.
- Reuse first-pass terrain normal/shadow/point-light lighting from structures.
- Keep flying-agent lighting readable even when terrain normal is not a perfect semantic match.
- Defer true airborne lighting/shadow model.
- Add tests.
- Vertex packing handles fractional map coordinates.
- Vertex packing handles scale and pivot.
- Vertex packing handles rotation.
- Empty render list skips draw.
- Atlas slot math remains deterministic.
- Rotated quad vertex positions stay deterministic.
Phase 6: Atlas And Assets¶
- Add default agent sprite folder.
- Create
assets/sprites/agents/default/. - Track folder with
.gitkeepuntil real art exists. - Add first placeholder or authored sprites.
- Player placeholder.
- Bird placeholder.
- Hawk placeholder.
- Add runtime atlas generation or shared atlas loader.
- Reuse structure atlas generation where practical.
- Use nearest filtering.
- Keep source PNGs in normal orientation.
- Expand horizontal sprite strips into consecutive atlas slots when
sourceFrameCount > 1. - Expand directional source spans into consecutive atlas slots so player direction changes do not flicker while atlas loading/repacking is async.
- Repeat a too-small single-frame image across animated slots instead of cropping it into unusable slivers.
- Apply optional exact transparent-color keying during atlas construction.
- Flip atlas V coordinates in vertex packing if needed, not in source files.
- Combined player/swarm snapshot preserves the maximum atlas row count requested by owner snapshots.
- Add fallback behavior.
- Missing sprite source uses generated placeholder slot.
- Missing optional metadata uses defaults.
- Invalid metadata surfaces a visible load/status error if blocking.
- Avoid stale browser image caches for source PNG edits.
- Browser-served image URLs receive a cache-busting query token.
-
file:,asset:,blob:, anddata:image URLs are left unchanged.
Phase 7: Render Pass Integration¶
- Add agent sprite render pass.
- Register after structures for ground agents.
- Support or split flying agents after ground agents.
- Set and restore alpha blending intentionally.
- Keep sprite output alpha binary even while blending is enabled.
- Draw only when terrain/map is visible.
- Keep existing swarm point/lit renderer available while sprite pass is developed.
- RD toggle can choose point/lit fallback vs sprite agents.
- Avoid deleting fallback until sprite readability is proven.
- Wire render-shell dependencies.
- Player sprite snapshot provider.
- Swarm sprite snapshot provider.
- Atlas/image load lifecycle.
- Visibility toggles.
- Add tests where practical.
- Pass skips renderer when visibility is disabled.
- Pass submits combined player/bird/hawk snapshot when visible.
- Render order runs Structures before agent sprites.
Phase 8: RD Debug UI¶
- Add controls under
RD > Agents. - Shared swarm square-vs-sprite mode toggle under
RD > Agents > Swarm. - Global sprite agent visibility toggle.
- Player sprite visibility toggle under
RD > Sprites > Agents. - Bird sprite visibility toggle.
- Hawk sprite visibility toggle.
- Fallback point/lit swarm visibility is selected by disabling swarm sprite mode.
- Height scale max slider.
- Direction debug readout.
- Render count readout.
- Add mirrored controls under
RD > Sprites > Agents. - Shared swarm square-vs-sprite mode toggle.
- Player sprite visibility toggle.
- Player sprite visibility suppresses the legacy overlay marker so only one player visual path draws.
- Keep panel compact.
- Do not resize fixed side panel slots.
- Use existing
RD > Agentssubpanel structure. - Add UI tests if a standalone runtime helper is introduced.
Phase 9: Player Gameplay Integration Boundaries¶
- Verify player sprite rendering does not alter movement at the ownership boundary.
- Pathfinding still owns movement target/path.
- Movement system still owns queued step execution.
- Activity runtimes still own activity lifecycle.
- Decide player facing source.
- Last movement direction.
- Current path segment direction.
- Cursor/focus direction for future interactions.
- Idle default.
- Decide how selection/inspection treats player sprite.
- Rendering alone should not add click targets.
- Future click/hover affordances must route through gameplay/UI owners.
Phase 10: Swarm/Scout Integration Boundaries¶
- Verify scout possession uses authoritative swarm state.
- Possession validity remains based on stable agent IDs and simulation position.
- Discovery reveal remains based on authoritative or explicitly intended possession position, not visual sprite bounds.
- Camera follow continues to use existing smoothing unless explicitly changed.
- Verify hunting logic does not read sprite render data.
- Hunting availability remains trail/grid based.
- Kill/removal remains swarm-runtime based.
- Sprite pass updates visually after existing runtime changes.
Phase 11: Ordering And Sorting¶
- Implement first simple ordering.
- Structures before agents.
- Ground agents before flying agents.
- UI overlays last.
- Decide if per-agent sort is needed in v1.
- If all sprites are small, category order is enough.
- If tall agents/structures overlap badly, add y-sort later.
- Add future y-sort notes.
- Shared ground-agent/structure y-sort may be needed for tall objects.
- Flying agents can remain a separate later pass.
Phase 12: Performance And Limits¶
- Define initial render caps.
- Player: 1.
- Birds: current swarm count.
- Hawks: current hawk count.
- Future NPC/animals: separate caps.
- Avoid per-frame allocations where practical.
- Reuse render item arrays or typed buffers.
- Reuse scratch objects for interpolated positions.
- Avoid per-agent object creation in hot render paths if count is high.
- Avoid per-frame atlas rebuilds for animation frame changes by collecting every frame from an animated source strip into the atlas key.
- Avoid movement-direction flicker by collecting every directional source slot into the atlas key, not only the currently selected direction slot.
- Profile before removing existing point renderer.
- Compare point/lit rendering vs sprite quad rendering.
- Track cost at normal and high swarm counts.
- Add render-count debug readout.
Phase 12A: Player Readability¶
- Document readability options.
- Ground halo or selection shadow.
- Sprite outline or stroke.
- Slight visual scale increase independent from gameplay footprint.
- Player lighting bias or minimum brightness.
- Color/value art direction rule.
- Low-zoom UI marker.
- Implement first readability aid.
- Recommended: player-only ground halo/shadow.
- Consider
visualWidthPx/visualHeightPx: 1.25after halo test. - Keep authored player sprite untinted.
Phase 13: Documentation¶
- Update
AI_CONTEXT.md. - Add this implementation plan as the required progress tracker.
- Add first pure agent sprite model helper.
- Add render order after implementation exists.
- Add RD swarm sprite-mode control behavior.
- Add asset folder/metadata contract after implementation exists.
- Update
docs/SPRITE_DETAILS_RENDERING_DESIGN.mdif implementation choices differ from the Agents section. - Add
docs/AGENT_SPRITE_DATA_CONTRACT.mdif a data contract file is created. - Update
README.mdonly if asset requirements or run steps change.
Phase 14: Validation¶
- Run focused JS syntax checks.
-
node --check src\gameplay\agentSpriteDefinitionRegistry.jsif changed. -
node --check src\gameplay\agentSpriteModel.jsif created. -
node --check src\gameplay\playerSpriteRuntime.jsif created. -
node --check src\gameplay\swarmAgentSpriteRuntime.jsif created. -
node --check src\render\passes\agentSpritePass.jsif created. -
node --check src\render\mapSpriteRenderer.jsif changed. -
node --check src\render\renderPipelineRuntime.jsif changed. -
node --check src\main.jsif integration wiring changes. -
node --check src\render\frameSwarmRenderRuntime.jsif swarm render gating changes. -
node --check src\ui\overlays\drawOverlay.jsif player overlay marker gating changes. -
node --check src\render\renderSupportRuntime.jsif image loading changes. - Run focused tests.
- Agent sprite definition registry tests.
- Agent sprite model tests.
- Map sprite renderer tests.
- Player sprite snapshot tests.
- Swarm sprite snapshot tests.
- Agent sprite pass tests.
- Renderer pass-order tests.
- Frame swarm render gating tests.
- Render support image cache-busting tests.
- Run broader tests after integration.
-
node --test tests\*.test.js - Run docs lint.
-
npm run lint:md - Manual smoke test.
- Load default map.
- Confirm player sprite renders.
- Confirm player sprite toggle switches between authored sprite and legacy overlay marker.
- Confirm player movement still works.
- Confirm player sprite does not affect pathfinding.
- Confirm birds render as sprites.
- Confirm hawks render as sprites.
- Confirm flying height scale reads clearly.
- Confirm scout possession/camera still works.
- Confirm hunting still works.
- Confirm structures still render below agents.
Suggested Implementation Order¶
- Phase 1: data contract or minimal in-code defaults.
- Phase 2: pure model helpers and tests.
- Phase 5: renderer backend extension tests.
- Phase 3: player render snapshot.
- Phase 4: swarm render snapshots.
- Phase 6: atlas/assets fallback.
- Phase 7: render pass integration.
- Phase 8: RD debug controls.
- Phase 9: player gameplay boundary validation.
- Phase 10: swarm/scout boundary validation.
- Phase 11: ordering/sorting validation.
- Phase 12: performance review.
- Phase 13: documentation updates.
- Phase 14: validation.