# Artwork and optimization

## Tokyo and New York pavement roads

Built-in ImageGen redrew both road textures using Shenzhen as the reference: continuous pavement, raised curb, drains and matte textured asphalt with restrained damp patches. Tokyo uses white markings; New York uses worn yellow markings and a manhole. `road-redraws.json` records exact prompts, source paths, crop bounds and byte sizes. `pack-roads.cjs` removes blank framing and proportionally downsamples to 1536 pixels wide, then writes optimized quality-88 JPEGs (4:4:4 colour), totaling 237,158 bytes. The pavement-1 URL revision refreshes cached roads. Road position, parallax and six-pixel facade overlap are preserved. Road pixel/size checks, all-district scenery browser checks at three sizes, parallax and ES5/artwork checks pass. Tokyo and New York in-game screenshots were visually reviewed.

## Open-ended city blocks

The current eighteen facade sections use built-in ImageGen outputs recorded in `open-blocks.json` in the immutable asset directory. Each block has finished architectural sides and transparent ends; the game shows the full width, never a horizontal crop or crossfade. `pack-open-blocks.cjs` extracts inspected row boundaries, removes empty outer padding, centers each complete block within transparent margins and preserves alpha in 256-colour PNGs (compression level 9). No buildings are distorted. The nine optimized files total about 1.9 MB. The main scenery packer applies these assets after its legacy sources. The manifest records prompts and generation paths.

## Deliverables

The production artwork is in `src/main/immutable/app/beatemup/`, served at `/beatemup/`. Icons are in each app's directory. No remote art, font, library or audio request is needed during play.

The **built-in ImageGen tool** was used for all six humans, ten robots, their matching limb parts, both cities, adjoining storefronts, foreground, pickups/effects and the shared icon. [art-sources.json](art-sources.json) contains the accepted prompt set and generated source locations. The separate corrected robot pose is recorded in [go2-fix-source.json](go2-fix-source.json). The optimized deliverables live in this repository; the raw generation archive remains at the tool's default source location.

## Sprite formats

- `<character>.png`: tightly packed combat/source poses, with rectangles and ground anchors in [atlas.js](atlas.js). Each of the sixteen sheets contains 36 physical poses.
- `<character>-motion.png`: **8-frame full-body ImageGen walk** and **6-frame intact fighting guard** for each humanoid (the two dogs retain their 16-frame walks). Rectangles are in [motion-atlas.js](motion-atlas.js). These sheets are used for unarmed walking and standing.
- `<character>-rig.png`: archived ImageGen parts from the superseded rig approach. These files are not fetched by the game or animation review page.
- Six small `<hero>-portrait.png` files are used by the phone controller.
- `items.png`: an eight-cell atlas for three weapons, health, energy, mines, pulse bolts and explosions.
- `combat-effects.png`: 36 ImageGen effect frames in six rows: punch impact, kick impact, weapon trail, electrical shockwave, robot explosion and guard sparks. This replaces text-star impacts, the drawn overdrive circle and the stretched single-frame death explosion. The old explosion cell in `items.png` is no longer rendered for deaths.

Combat sheet row 2 contains a six-pose sampling of the corrected walk. Its rejected direct ImageGen walk attempt has been replaced. Humanoid playback uses the eight complete drawn walking poses. Rows 3–6 provide punches, kicks, jumping, damage and recovery. The row/column description is logical; the optimized file packs rectangles tightly rather than leaving a large empty grid.

The humanoid walking drawings were generated with the built-in ImageGen tool using the user's Street Fury guide, the SLYNYRD pose references and each character's design. [imagegen-walk-sources.json](imagegen-walk-sources.json) records the accepted sheets and correction prompts. `pack-walk-sheets.cjs` only crops, aligns, resizes and compresses complete drawings. It does not assemble body parts, solve joints or synthesize poses. Walking selects a whole frame from travelled distance; idle uses its own six-frame clock. Facing left mirrors the complete sprite.

## Armed character animation

The built-in ImageGen tool produced **18 complete armed sheets**, one for each of six heroes with shock baton, light sword and steel pipe. The saved files are `src/main/immutable/app/beatemup/<hero>-armed-<0|1|2>.png`; [armed-sources.json](armed-sources.json) records the prompts, accepted sources and correction history. [armed-atlas.js](armed-atlas.js) contains the frame rectangles.

Each sheet contains four armed guards, **eight walking frames edited from the accepted original walking sheet**, six weapon strikes, six kicks, six jump poses and six hurt/floor/recovery poses. The invented walking poses in the initial combat sheets are discarded. Walking preserves the original opposite-foot contact and passing sequence, with ImageGen corrections where the weapon switched hands. The weapon is drawn into the complete body, including its grip and arm; the renderer never adds a floating item or constructs limbs.

`pack-armed-sheets.cjs --pack` isolates each complete connected figure, removes faint alpha matte noise, crops, aligns and compresses it. It keeps a correction to an individual whole figure separate when the generator changed an unrelated pose. The eighteen 128-colour indexed PNGs total **4,280,718 bytes (4.08 MiB)** and approximately **58.2 MiB** decoded RGBA. [armed-sizes.json](armed-sizes.json) contains individual measurements. No new browser dependency is used.

Walking uses the same travelled-distance clock as the original animation, including through pickups and stops. The attack retains its weapon identity for the final swing after durability reaches zero. The animation review page exposes all three weapons, eight-frame contact strips, pause and quarter-speed playback.

## Format choices and measured size

- Character and motion atlases: indexed PNG, at most **128 colours**, no dithering, compression level **9**.
- Rig parts and small portraits: **96 colours**.
- Transparent scenery: indexed PNG, **192 colours**.
- Opaque skylines and street surfaces: JPEG, quality **84–85**, **4:4:4** chroma sampling to preserve coloured pixel edges.
- Cropping removes empty space before packing; source dimensions are reduced to the actual display needs with nearest-neighbour sampling.
- Canvas disables smoothing. The viewer uses integer draw positions and bounded logical resolution, rather than a device-pixel-ratio-sized canvas.

The 71 production viewer images total **13,939,618 bytes (13.29 MiB)**. This includes sixteen unarmed combat sheets, sixteen unarmed motion sheets, eighteen armed sheets, six drawn-fall sheets and twelve scenery/effect/UI images and three opening-comic panels. The new full-body walking artwork reduced the previous production set by **232,201 bytes**. Transparent walk pixels use a binary alpha threshold before palette compression to remove faint matte noise while retaining crisp pixel edges.

All immutable image artwork, including the development rigs and six phone portraits, totals **14,362,030 bytes (13.70 MiB)**. The controller action icons, 192- and 512-pixel icons for both apps and documentation screenshots are additional files. The production images would occupy approximately **169.3 MiB** if all decoded into four-byte RGBA buffers. Browser overhead, canvas buffers and caches are additional; compressed download size is not a RAM measurement. The separate [original soundtrack](SOUNDTRACK.md) adds 4.99 MiB of audio, loaded by cue after sound is enabled.

## Combat effect animation

The effects sheet is **768×768, 96-colour indexed PNG, 62,307 bytes**, with six 128-pixel cels for each effect. `pack-combat-effects.cjs` crops the regular source grid, removes faint alpha noise, downsizes complete drawings and adds transparent gutters before maximum PNG compression. It does not draw replacement effects or synthesize animation frames. The first ImageGen sheet was rejected for overlapping cells; the accepted correction separates the drawings. [combat-effects-source.json](combat-effects-source.json) records both prompts and source locations.

Hit flashes begin only when damage or a guard contact resolves. Weapon trails follow the active swing and face the attack direction, including the final swing of a breaking weapon. Electrical overdrive, robot shockwaves and mine detonations use the same atlas. Dead robots retain their floor pose until 1.1 seconds, then play the six-frame destruction sequence before removal at 1.45 seconds. Effect animation follows simulation time, so pausing freezes it. All frames work in the lean renderer.

[asset-sizes.json](asset-sizes.json) records per-source optimization, [motion-sizes.json](motion-sizes.json) records packed animation sizes, and [asset-totals.json](asset-totals.json) records the final image totals.

## Corrections made during review

- Replaced the assembled humanoid rig with complete ImageGen walking drawings after the user identified disconnected-looking hips. Regenerated sheets and individual cels with faulty foot order, overlapping figures or missing feet.
- Regenerated Kira's combat sheet because a separate kick row was missing.
- Replaced Go2's effect-only attack cell with a generated pose containing its body and all four braced legs.
- Cropped poses individually so punches, wide kicks and floor poses retain their full extent.
- Cropped transparent padding below the architectural layers using alpha coverage, aligning both panels to the same pavement baseline.
- Removed repeated reference storefronts from the beginning of the adjoining panels, so their signs and buildings do not appear twice at the join.
- Prevented rendering partly loaded rig layers, which had left a canvas transform active and rotated the scene.
- Delayed the final defeat overlay until the fallen player has reached the floor.

## Rebuild

Use the existing local Sharp and Playwright runtimes; these are development tools and are not browser dependencies. Their paths can be overridden with `BRAWL_SHARP` and `BRAWL_PLAYWRIGHT`. `BRAWL_ORIGIN` changes the local server origin.

1. Ensure the accepted raw walking sheets referenced in `imagegen-walk-sources.json` are available. Another machine must point these paths to its copy of the generation archive.
2. Run `node src/main/apps/app/beatemup/pack-walk-sheets.cjs`. The existing `bake-motion.cjs` command is a compatibility entry point for this same packing operation.
3. Open `/beatemup/animation-lab.html` to inspect the actual production sprites, including idle, walking, combat and floor transitions.
4. Run `assets.test.cjs`, `engine.test.cjs` and `animation.browser.test.cjs`. Run the multiplayer browser test after networking or controller changes.
5. Rebuild the effects with `node src/main/apps/app/beatemup/pack-combat-effects.cjs`; verify with `combat-effects.test.cjs` and `combat-effects.browser.test.cjs`.

The original `optimize-assets.cjs --scenery-only` command rebuilds environments without rewriting character sheets. To rebuild the original combat artwork, use `art-sources.json` and `go2-fix-source.json` with the source optimizer, then run the walk-sheet packer. The walk packer fails if a sheet lacks eight isolated, connected figures or a transparent background; it does not substitute a missing character.
# Drawn player knockdowns

All six humans now use dedicated ImageGen fall sheets (`<hero>-fall.png`) with six complete drawings for each equipment state: empty hands, shock baton, light sword and pipe. The sequence is recoil, buckling knees, hip impact, shoulder contact, settling legs and a horizontal floor hold. Player knockdowns never rotate the canvas or assemble body parts. Weapons remain drawn into the gripping hand. Existing robot destruction and walking artwork are retained.

`fall-sources.json` records the built-in ImageGen prompts and source paths. `pack-fall-sheets.cjs` crops whole connected drawings, registers their foot position, scales uniformly, and packs six 128-colour transparent PNGs. The 144 poses add **914,869 bytes (893 KiB)** compressed and about **14.3 MiB** decoded RGBA. `fall-atlas.js` supplies their rectangles. The last drawing is reached at 0.5 seconds and held through the downed state and initial recovery; defeat waits until at least 0.7 seconds. Stale attack effects are hidden on downed players.
# Encounter warning

`blocked-notice.png` is a built-in ImageGen pixel-art popup reading “Blocked! Destroy the robots first”. The final asset is 768×258, 64-colour indexed PNG, 74,075 bytes. The generation prompt and original source are recorded in `blocked-notice-source.json`. It appears above the play area when a living player presses right at the visible boundary while robots remain, and clears immediately after the final robot is defeated.
# Opening comic

## District boss sprite sheets

Tokyo uses Unicorn Gundam and New York uses punk Johnny Five from Short Circuit. Built-in ImageGen produced 32 full-body frames per boss: eight idle, eight walk/tread locomotion, eight attack, and eight hurt/collapse drawings. `district-boss-sources.json` records the exact prompts and source/output paths. `pack-district-bosses.cjs` packs transparent 128-colour PNGs: `unicorn-gundam.png` is now 2560x1024 (326,592 bytes), with isolated 320x256 cells and two repaired ImageGen slam poses; see `GUNDAM-CROP-FIX.md`. Johnny Five now uses `pack-johnny-five.cjs` to isolate each complete connected silhouette before packing 320x256 cells into a 2560x1024 sheet (357,371 bytes). The original ram poses cross the nominal source grid; equal-column cropping sliced off hands and copied neighbouring fragments. `johnny-five-crops.json` records the corrected per-pose bounds, uniform scale, tread pivots and floor baseline. The renderer preserves the character scale and loads revision 2. These use drawn collapse poses, never canvas rotation, and hold the wreck before the existing explosion.

## Extended districts — September 2026

### Complete roofs and consistent building scale

All eighteen street sections were redrawn with complete rooflines using built-in ImageGen. `roof-repairs.json` records the final sources, prompts, crop boundaries and optimized outputs. `pack-roof-repairs.cjs` preserves source proportions and adds transparent headroom; the general scenery packer reapplies these replacements when rebuilding. The six original facade/extension files and three sector atlases use the `roofs-3` cache revision.

Doorway measurements anchor all street sections to the original human-scale scenery (approximately 80–90 world pixels per doorway), with proportional horizontal and vertical scaling. Wide panoramas use a horizontal window instead of shrinking their buildings. Roofs retain their full vertical extent, and the distant skyline reaches the viewport top. District length remains 7,800 world units.

Built-in ImageGen supplied twelve new street panoramas (four per district), three transparent skyline layers, twelve foreground objects, eight-frame fire/smoke/steam loops and eight background vehicles. Each route uses six unique facade sections without wrapping; the added skyline, street, atmospheric effects and foreground poles move at separate depths. Smoke preserves partial alpha. Lean mode holds environmental animations still.

Production files live in `src/main/immutable/app/beatemup`: `tokyo-sectors.png`, `new-york-sectors.png`, `shenzhen-sectors.png`, the three matching `*-skyline.png` files, `scenery-props.png` and `scenery-effects.png`. The exact generation prompts, source paths and optimized byte counts are in `scenery-expansion.json`; transparency correction prompts are in `scenery-corrections.json`. `pack-scenery.cjs` crops inspected row/object boundaries, normalizes atlas cells and writes 256-colour PNGs with compression level 9. No runtime background removal or per-frame bitmap allocation is needed. Only the current district's panoramas and skyline load; props/effects are shared and reused.

## RCWeb scenery details

The four city background sections now contain eight RCWeb signs, tags, shop names and stickers, edited with built-in ImageGen. Prompts and source/output paths are in `rcweb-scenery-sources.json`; `pack-rcweb-scenery.cjs` preserves the original dimensions and compresses to 128-colour transparent PNG. Their combined size is 1,136,086 bytes. The 2030 dates remain. `rcweb-scenery.browser.test.cjs` verifies fresh asset URLs, original dimensions and rendering in both orientations; background alignment and ES5/assets checks pass. Source lettering and in-game screenshots were visually reviewed.

Three built-in ImageGen comic panels tell the backstory: a rogue signal turns service robots, cities fall as humanity goes into hiding, and six human fighters unite to reclaim the streets. `story-sources.json` records the prompts and original outputs. Production files are `story-city.jpg`, `story-uprising.jpg` and `story-resistance.jpg` under `src/main/immutable/app/beatemup/`. The uprising panel's revision 3 removes city names from its captions; `story-uprising-revision3.json` records the built-in ImageGen edit prompt and source. Its optimized 1280×853 JPEG is 293,081 bytes, smaller than the previous 313,630-byte asset.

The panels are resized to 1280×853 and encoded with optimized JPEG at quality 82: **913,140 bytes combined**. They are preloaded before Start becomes available. Each page waits for a click on the artwork or Next page, a controller next-page action, or Enter/Space. Combat remains frozen until the final page is completed. There is no whole-story skip. New games replay the comic, and its page state is included in viewer snapshots.

The 2030 revision edits the opening comic and all four street facade/extension images with built-in ImageGen. Prompts and generated source paths are in `year-2030-sources.json`; `pack-year-2030.cjs` trims transparent generation padding, preserves each background's original dimensions, and compresses backgrounds as 128-colour PNGs. Year text in the viewer and soundtrack page also uses 2030. Background alignment and controller/start tests pass with the click-through intro.
