# Spritesheets to make The game runs fine without any art (it bakes placeholder patterns), but these are the sheets it will pick up automatically the moment the PNG files exist. No code changes needed — the paths and frame numbers below come straight from `src/config/*.json`, so if you rearrange anything, update the JSON to match. ## Format rules (all sheets) - **PNG**, laid out as a **horizontal strip of square frames**, left to right. - Frame size is **192×192 px** (set by `textureSize` in `walls.json` for the wall sheet and by `TEX_SIZE` in `src/engine/registry.js` for the rest; everything is baked to 192×192 internally, so larger source frames just get downscaled). - `frame` in the config JSON is the **0-based index** into the strip. - The view renders at 960×600 (1:1 with the display canvas), so wall textures are seen at roughly full detail at one cell's distance. Draw with **neutral, flat lighting** — the engine adds its own directional shade (east/west faces darker) and distance dimming. - Different entries may point at different files; each unique path is loaded once. A sheet that is missing, or too narrow for a requested frame, falls back to the placeholder for that entry only. ## 1. `assets/textures/walls.png` — wall textures **7 frames → 1344×192 px. Opaque** (no transparency; these fill the whole wall). | Frame | Pixels | Wall (`walls.json`) | Placeholder it replaces | | ----- | --------- | ------------------------ | ------------------------------ | | 0 | 0–191 | id 1 — Gray Brick | gray `#9a9a9a` brick courses | | 1 | 192–383 | id 2 — Blue Stone | blue `#4a6fa5` pattern | | 2 | 384–575 | id 3 — Red Brick | red `#a5503f` pattern | | 3 | 576–767 | id 4 — Wood | brown `#8a6a3a` planks | | 4 | 768–959 | id 5 — Door | gold `#c8a838` pattern | | 5 | 960–1151 | id 6 — Gold Door (locked)| gold `#d4af37` pattern | | 6 | 1152–1343 | id 7 — Silver Door (locked)| silver `#a8a8c0` pattern | Notes: - One texture covers one full grid cell (all four faces use the same image; the engine un-mirrors back faces so text/asymmetric details stay readable). - Make the texture **tileable left-to-right** if you want long runs of the same wall type to look continuous. - Door frames (4–6) are drawn on the sliding panel itself — it slides sideways as the door opens, so avoid critical detail hugging the left edge (that's the edge that disappears first). Locked doors should visually hint at their key color. ## 2. `assets/textures/overlays.png` — wall overlays **3 frames → 576×192 px. Transparent background required** — these are alpha-composited *over* the wall texture, so every transparent pixel shows the wall behind. | Frame | Pixels | Overlay (`overlays.json`) | Intended look | | ----- | ------- | ------------------------- | ------------------------------ | | 0 | 0–191 | `painting1` — Portrait | framed picture, centered | | 1 | 192–383 | `banner` — Banner | hanging cloth banner | | 2 | 384–575 | `vines` — Vines | creeping foliage over the wall | Notes: - The 192×192 frame maps to the **entire wall face**; leave generous transparent margins (the placeholder uses ~30 px) so it reads as an object *on* the wall. - One overlay per wall cell, shown on all faces of that block. ## 3. `assets/sprites/items.png` — decorative items **3 frames → 576×192 px. Transparent background required** — rendered as floor-anchored billboards that always face the player. | Frame | Pixels | Item (`items.json`) | In-game height (`scale`) | Blocks? | | ----- | ------- | ---------------------- | ------------------------ | ------- | | 0 | 0–191 | `plant` — Potted Plant | 0.6 × wall height | yes | | 1 | 192–383 | `lamp` — Floor Lamp | 0.8 × wall height | yes | | 2 | 384–575 | `rubble` — Rubble | 0.4 × wall height | no | Notes: - **Fill the frame** with the object (touching the bottom edge) — the engine handles sizing via `scale` and anchors the frame's bottom to the floor, so empty space at the bottom of the frame makes the item float. ## 4. `assets/sprites/enemy_*.png` — enemies (one sheet per enemy) **13 frames → 2496×192 px each. Transparent background required** — full-wall-height billboards. One PNG per enemy type: | File | Enemy (`enemies.json`) | Stats to suggest visually | | -------------------------------- | ---------------------- | ------------------------------------ | | `assets/sprites/enemy_guard.png` | `guard` | baseline: 50 hp, average speed | | `assets/sprites/enemy_heavy.png` | `heavy` | tanky: 120 hp, slow — bulkier build | | `assets/sprites/enemy_scout.png` | `scout` | fragile: 25 hp, fast — lighter build | Every sheet uses the same fixed frame order (`ENEMY_FRAME_ORDER` in `src/engine/registry.js`), offset from the enemy's `frame` base index in `enemies.json` (0 for a dedicated file; a nonzero base lets several enemies share one long strip): | Offset | Pose | Shown when | | ------ | ----------- | --------------------------------------------------- | | 0 | `front` | facing the player, standing | | 1 | `frontWalk` | facing the player, walk-cycle alternate | | 2 | `left` | facing left (its left shoulder toward you), standing| | 3 | `leftWalk` | walk-cycle alternate | | 4 | `right` | facing right, standing | | 5 | `rightWalk` | walk-cycle alternate | | 6 | `back` | facing away, standing | | 7 | `backWalk` | walk-cycle alternate | | 8 | `aim` | spotted the player, weapon raised (reaction window / between shots) | | 9 | `fire` | flashed for ~150 ms after each shot | | 10 | `pain` | flinch while hurt (~120 ms after a non-fatal hit) | | 11 | `dying` | first 0.5 s after death (falling) | | 12 | `dead` | corpse — held 3 s, then fades out over 1 s | Notes: - Walk frames alternate with their standing pose while the enemy patrols (cadence tracks the enemy's speed); `aim`/`fire` are **front-facing only** — enemies turn to face the player whenever they engage. - Enemies are drawn at full wall height and stand on the floor; have the feet touch the bottom edge of the frame. The `dying`/`dead` frames live in the same full-height square, so draw the corpse lying along the bottom edge. - The hurt flash is generated automatically (white-tinted copy of the `pain` frame) — you don't need to draw one. - Any missing/short sheet falls back per-frame to pose-specific placeholder art, so partial sheets are fine while you work. ## 5. `assets/sprites/pickups.png` — pickups & keys **16 frames → 3072×192 px. Transparent background required** — small floor-anchored billboards (drawn at 0.5 × wall height by default; add a `scale` field in `pickups.json` to change per pickup). | Frame | Pixels | Pickup (`pickups.json`) | Placeholder it replaces | | ----- | --------- | -------------------------------- | ----------------------- | | 0 | 0–191 | `ammo` — Ammo | yellow diamond | | 1 | 192–383 | `health` — Health | green diamond | | 2 | 384–575 | `treasure` — Treasure | gold diamond | | 3 | 576–767 | `key_gold` — Gold Key | gold key glyph | | 4 | 768–959 | `key_silver` — Silver Key | silver key glyph | | 5 | 960–1151 | `ammo_mg` — MG Ammo | orange diamond | | 6 | 1152–1343 | `ammo_gatling` — Gatling Ammo | orange diamond | | 7 | 1344–1535 | `ammo_plasma` — Plasma Cells | teal diamond | | 8 | 1536–1727 | `gun_machinegun` — Machine Gun | brown diamond | | 9 | 1728–1919 | `gun_gatling` — Gatling Gun | rust diamond | | 10 | 1920–2111 | `gun_plasma` — Plasma Gun | teal diamond | | 11 | 2112–2303 | `ammo_rocket` — Rockets | red-orange diamond | | 12 | 2304–2495 | `gun_rocket` — Rocket Launcher | dark-red diamond | | 13 | 2496–2687 | `ammo_shells` — Shells | amber diamond | | 14 | 2688–2879 | `gun_shotgun` — Shotgun | tan diamond | | 15 | 2880–3071 | `gun_doubleshotgun` — Double Shotgun | brown diamond | Notes: - Key colors should match their door and their HUD chip (the chip uses the pickup's `color` from `pickups.json`). ## Not needed (yet) - The **exit** uses a built-in generated marker (it's a level mechanic, not a configurable pickup). - **Floors/ceilings** are flat colors (`FLOOR_COLOR` / `CEILING_COLOR` in `src/engine/constants.js`); textured floors are a separate engine feature. - **Weapon/hands** on the HUD is a gray rectangle stub (`HudScene`). ## Adding more content later New wall/overlay/item/pickup = one new 192×192 frame appended to the relevant strip + one JSON entry in `src/config/` pointing at its `frame` index. A new enemy = a fresh 13-frame sheet (see section 4) + its JSON entry. Nothing else. You can also start a fresh PNG per entry if you prefer — the `texture` path is per-entry, not global. ## Changing resolution later Frame size and render resolution are independent knobs: `TEX_SIZE` in `src/engine/registry.js` (+ `textureSize` in `walls.json`) for textures, `RENDER_WIDTH`/`RENDER_HEIGHT` in `src/engine/constants.js` for the view. Existing art keeps working after a change — frames are scaled at bake time — but redraw at the new size for full sharpness.