# CD-Man: the forest and the Pacific

**Development paused by Pieter on 15 September 2026.** Resume only when requested.
Current saved build: `arch-detail-fullscreen-2026-09-15`.

UI shell restyle, same day (requested for the public site `projects/cd-man-site`): `index.html`
and `style.css` now use a modern layout (Nunito, dock bar, settings panel, rounded cabinet,
`assets/cd-man-icon.png` rendered from `smooth-art.js`). Every element id, data attribute,
fullscreen rule and the `--board-ratio` sizing formula are unchanged; `app.js` is untouched.
Previous files: `checkpoints/ui-before-modern-shell-2026-09-15.zip`. The header brand links to `/`.

Future TODO: the expanded background visibly looks like separate pieces stitched
together. Revisit the transitions between the original artwork and generated
extensions, matching texture, sharpness, scale and lighting so the scenery reads
as one continuous painting. The latest smaller-section approach is not visually
accepted as finished. Preserve the original maze, dot positions and gameplay.
This is deferred work; do not start further graphics changes while paused.

A new, editable JavaScript browser remake of the two completed worlds from the
1989 shareware game. The shipped game does not use DOSBox, WebAssembly, or the
original executable. The original executable is retained only as research input.

The target is **version 1**, with the original yellow character. Its later
international shareware distribution contains the same game binary and sounds
as the June 1989 source used here; see the byte comparison in `SOURCES.md`.
Only land and sea are playable, even though that release also contained space.

## Reference HD and the saved classic version

Build `arch-detail-fullscreen-2026-09-15` shifts the original Pacific arch 12 image
pixels left and gives its tunnel a separate painted rock foreground. Pacific
side detail now comes from a tall, separately generated strip sheet, reduced to
display size. Victory keeps its broad grin through the last pose. **View
animations** at the bottom opens a silent viewer with replay, speed and frame
controls (`animations.html`).

HD fullscreen fills aspect ratios from 16:10 through 16:9: the forest reveals
extra decorative ground below the board, and the Pacific crops only outer side
scenery. Resize events update it when the viewport/display changes; gameplay
coordinates and timing remain fixed. Other aspect ratios and classic graphics
use a contained view to keep the maze visible. Browser tests verified 1280×720
and 1280×800, including resizing while fullscreen; physical monitor transfer was
not separately tested.

Build `pacific-coast-2026-09-15` refines the decorative Pacific side artwork and
closes the upper-right extension with a rocky jungle coast. The playable board
and dot layout stay unchanged. Asset provenance and prompt are in
`research/hd-references/WIDESCREEN.md`.

The game now defaults to **HD artwork**, based on Pieter's two supplied art
references. The **Graphics** button switches back to **Original 1989** immediately,
without resetting the current game. The two renderers share the same game engine,
dot coordinates, scoring, routes, sounds and enemy timing.

**Power-up pulse** changes orb pulsing (default 55%). Enemy limb/wake poses follow
the original paired movement substeps, independently of this slider.
CD-Man's bite follows the next dot and closes at collection, independent of that
slider. Background textures stay static. `smooth-art.js` draws clean curves for
characters, spiders, dorsal fins, keys, fruit, fish and power-ups. The forest
gate uses transparent leaves cut from the supplied painting. Earlier
per-pixel SVG traces remain as reference assets but are no longer loaded.

Build `fidelity-polish-2026-09-15` revisits the original sprite sheet: broad,
mottled spiders with angular legs, red eyes and white fangs; upright vertical
shark fins with stronger sway and directional wakes. Sea dots now compensate
for the artwork's unequal horizontal/vertical scale so they appear circular.
The forest bonus sequence includes the original watermelon, orange and coconut.
HUD letters are transparent cutouts, and cleanup borders blend into the texture.
`presentation.js` handles painted forest tunnel masks. Its visual paths do not
change maze coordinates or the original tunnel timing. The later cadence update
below replaces this build's large victory celebration.
The previous source is in `checkpoints/smooth-before-fidelity-polish-2026-09-15.zip`.
**Game speed** still controls the original common simulation clock. HD movement
interpolates between simulation steps at the browser's frame rate; it does not
add extra simulation ticks. Original graphics retain the original frame cadence.

Before the HD work, all source, artwork, tests and research were archived in
`checkpoints/classic-v1-before-hd-2026-09-15.zip`. Its 160 files were verified
against the included SHA-256 manifest. Logs and Python caches are excluded.
To run that exact saved version, extract the ZIP into a **new folder**, run
`py -3.13 serve.py 8797` there, and open `http://127.0.0.1:8797`. This leaves the
current version intact. The checkpoint predates the forest arch exit correction.

One gameplay bug was fixed after that checkpoint: the junction at forest cell
`(13,7)` now permits the left turn into `(12,7)`, matching the reverse route.
The arch's walls and tunnel pairing are unchanged.

Power-ups activate on contact before reaching their centre. The underlying dot
then becomes visible and still needs collecting: touch an orb, reverse, and leave
that dot. Ten points are awarded only for the dot, keeping the same level totals.
Touch radii are 20x18 logical pixels, restricted to current/next traversed cells
and disabled during tunnel transit. These thresholds implement Pieter's requested
behaviour; they are not claimed as recovered EXE constants. After death, CD-Man respawns at the exact collision position with a brief
protection period; new rounds retain the initial spawn. The previous HD source
is saved in `checkpoints/reference-hd-before-smooth-2026-09-15.zip`.

## Play locally

Open **Play.cmd**, or run `py -3.13 serve.py` in this directory, then visit
<http://127.0.0.1:8796>. The server binds only to this computer.

- Arrow keys / WASD: move. You can press the next direction before a junction.
- Escape / Space / P: pause and resume. Escape never exits the remake.
- Enter: start, resume a paused game, or play again after game over.
- F: fullscreen. M: sound. F1: toggle endless lives.
- Sound on/off is saved immediately in local storage, including during tests.
  Updated game tabs follow the same preference; reloads retain the last choice.
- Speed defaults to **50%**, adjustable from 20% to 150%. The choice is saved.
- Select either world directly. There are three rounds per world; clearing the
  third Pacific round ends the game. No other worlds are included in the remake.

The browser accumulates time at 120 Hz and runs the recovered eight-substep movement
loop at 34 ticks per second, multiplied by the speed control. Enemy releases,
colour durations, keys, gates, tunnels, and sound notes share this clock. Faster
computers do not make the game faster. Background tabs pause. Idle menus stop
rendering. Scores and preferences stay in local browser storage.

## Change the game

| File | What to edit |
| --- | --- |
| `engine.js` | Movement, enemies, speed, scoring, lives, pills, gate, tunnels, progression. No DOM or graphics dependencies. |
| `levels.js` | The two 19×11 maze grids: space is floor, `0` is scenery. Special passages and gates live in the engine. |
| `renderer.js` | Drawing, sprite selection, animation, HUD. It consumes engine state without changing it. |
| `hd-renderer.js` | Separate background, dots, gate, actor and HUD drawing; smooth artwork and movement interpolation. |
| `assets/hd/*-reference.png` | Unchanged copies of Pieter's supplied artwork, including water and ground textures. |
| `assets/hd/*-cleanup.png`, `plates.json` | Generated removal patches and explicit masks for baked dots, actors and HUD. Only masked areas are composited. |
| `smooth-art.js` | Smooth curve artwork, mouth timing and procedural object animation. |
| `assets/hd/sprites1.svg`, `sprites2.svg` | Previous pixel-contour traces retained for comparison; no longer loaded at runtime. |
| `scripts/prepare_hd_assets.py` | Regenerates SVG traces and cleanup mask metadata. Requires Pillow, numpy and OpenCV. |
| `assets/world1.png`, `assets/world2.png` | Background scenery. |
| `assets/sprites1*.png`, `assets/sprites2*.png` | Original sprite sheets, with opaque and transparent versions. |
| `audio.js` | Single-channel PC-speaker synthesis from original PIT divisors. |
| `original-data.js` | Extracted sound, release, bonus, score, and sprite tables. |
| `app.js` | Input, controls, storage, frame scheduling, UI, development diagnostics. |
| `performance.js` | Bounded frame measurements, bottom performance panel and JSON report export. |
| `style.css`, `index.html` | The surrounding browser interface. |

Logical coordinates are deliberately separate from display size. Cell centers
are `(32 + column × 32, 70 + row × 24)`. Sprites are usually 32×24. For a future
graphics upgrade, retain these logical coordinates while replacing the renderer
and artwork. That preserves maze behavior and lets us increase render resolution
without rewriting movement or enemy logic. CSS already scales the original pixel
art without filtering.

HD uses the native reference sizes: forest 1695×928 and Pacific 1448×1086.
Each entire image keeps its aspect ratio. An affine transform places the original
logical grid over its artwork. Scenery stays in its supplied position. Generated
cleanup patches remove baked gameplay objects, with local colour matching and
feathered boundaries. Every pixel outside the masks remains unchanged. Smooth artwork is rasterized once at 3x logical resolution into small immutable bitmap frames; dots are cached until collected.
The **Explore layers** link opens `/tests/hd-visual.html`, where each layer can be
hidden independently and either clean background saved as PNG. The references are illustrations with small layout differences,
so their scenery outlines are not authoritative collision geometry.

The earlier `scenery-layout.js` and `*-painting.png` files are retained for history
but unused: Pieter rejected that first art reconstruction and its invented animals.
See `research/hd-references/GENERATION.md` for the art prompts and inputs.

The source has no build step and the game has no third-party runtime dependencies.
Keep the server running while editing. An idle, unstarted menu reloads on source
changes. An active or paused game is preserved; reload manually between games to
pick up changes.

## Verification and diagnostics

Run `node --test tests/*.test.js` (or `npm test`). Tests cover map dimensions,
reachability, gate unlocking, tunnel pairs, buffered turns, reversal, speed,
pause, collision, lives, all six rounds, and enemy movement through both mazes.
Fidelity tests compare sound tables against EXE bytes and check relative movement
rates, independent colour timers, release paths, return delays, key relocation,
mouth cadence, and the 27-step tunnel journey. `/tests/visual.html` renders static
spawn/colour scenarios and all 32 directional mouth frames without changing a
live game. Horizontal movement uses the original 40-pixel intermediate strips;
vertical movement alternates the original two rows. Diagnostic snapshots include
a build identifier so stale browser tabs can be identified.

The bottom performance counter shows browser callback FPS, game ticks per second,
95th-percentile frame interval and session stalls (intervals longer than 50 ms).
Expand it for simulation/drawing/UI costs, redraw rate, long tasks, errors and
diagnostic capture overhead. The recent window holds at most 600 frames; session
counters retain totals until reset. Export saves JSON with the recent raw samples.
Paused/hidden time is excluded. Callback FPS does not measure physical display
presentation; JS timings exclude asynchronous GPU work and the monitor's own work.

`logs/browser.jsonl` captures errors, major game events, and active 15-second status
and performance reports. Frame/JS spikes are logged at most once per five seconds.
Enable **Save diagnostic frames** in the performance panel to save canvas images to
`logs/world1-latest.png` and `logs/world2-latest.png`. Capture is now off by default,
including on old `?capture=1` URLs. It uses asynchronous PNG encoding, only while
playing and only after the image changes. `logs/server.pid` records the server
launched during development. There is no scheduled task or autostart.

Diagnostic captures remain 640×350 to bound PNG encoding/upload overhead in
HD mode. The live canvas uses the reference's native size. Performance report metadata identifies
the renderer and canvas size. `/tests/hd-visual.html` checks both worlds and
confirms rendering and graphics switches leave the engine snapshot unchanged.

The **Performance benchmark** link opens `/?benchmark=1`. Press Play for four
12-second stages: both worlds at 70%, forest at 150%, then Pacific with captures.
It steers an invulnerable player and shows/logs the results. Pausing stops the
stage clock. This mode never saves scores or gameplay preferences; sound changes still persist. Return to `/` for normal
play. This is a short repeatable diagnostic, not proof of long-session stability.

To regenerate assets, run `py -3.13 scripts/extract_assets.py` with Pillow
installed and the archived shareware extracted to `research/original/`.
**This overwrites `levels.js` and the extracted artwork.** It does not overwrite
the game engine. The optional disassembler requires Capstone.

Run `python scripts/extract_rules.py` to regenerate `original-data.js` directly
from the retained executable. This needs only Python's standard library.

See [SOURCES.md](SOURCES.md) for sources, verified internals, and fidelity limits.

The Pacific barrel below the cage is restored from the supplied reference. Power-up circles compensate for the map display transform. Directional body proportions stay constant and leftward eyes stay above the mouth. `/tests/smooth-art.html` shows enlarged artwork and all four character directions.

The active renderer restores only areas around changing objects. `tests/dirty-render.html` compares these updates with full redraws, allowing a maximum 1/255 channel difference from raster rounding. Smooth frames use separate small bitmaps; `smooth-art.js` is the editable artwork, and `smooth-atlas.js` builds the cache.


## Original cadence update

Build `original-cadence-2026-09-15` restores the original on-character grin/wink
and flattening/RIP sequence, with no win popup. Classic mode uses the exact
16 source frames; HD uses smooth interpretations of those poses. The left forest
tunnel remains horizontal and is clipped against the painted stone edge.
The Pacific opening net uses the reference ropes gathered upward, with its top
edge anchored. Its original eight-step release timing is unchanged.

Enemy animations use four poses paired across eight movement substeps. Frightened
spiders are darker gray. The shared original pursuit routine now targets the tile
CD-Man is entering, rather than his departed tile. Its random-choice threshold
starts at 200 and decreases by 20 on losing a life; the previous world/round-based
formula was unsupported. No separate coordinated shark/spider intelligence was
found in this routine.

Bite notes follow the original mouth substep indices, and audio retains each note
when several simulation ticks occur during one browser frame. Muted play does
not initialize audio. The previous main renderer/engine source is retained in
`checkpoints/fidelity-polish-before-original-cadence-2026-09-15.zip`.

59 Node tests pass. `tests/cadence-review.html` compares original/HD poses, net
states, tunnel entry and the two sea landmarks. It also checks partial against
full redraws for gate, death and win states in both worlds. The prior browser
scheduling issue remains unresolved; see `AUDIT.md` before interpreting FPS.


## Warm warning and fruit polish

Build `white-sharks-2026-09-15` corrects the misheard request: harmless sharks
are whiter, not wider. Original fin proportions are restored. During the existing last 50 vulnerability ticks,
all enemies alternate their harmless color and muted red every six ticks,
independently of movement. Sharks are pale white; spiders remain darker gray.
The blink is a requested visual cue; danger timing and collision rules are unchanged.

The death sequence keeps its timing and poses with brighter yellow and a shaded
ivory/amber RIP marker. The winning turn, smile and eyelid use eased transitions
with cached quarter-pose intermediates; classic frames and sequence duration stay
unchanged. Watermelon artwork now has a curved rind, pale inner rind, shaded red
flesh and teardrop seeds. `tests/warm-warning.html` shows all changes, including a
short moving preview. The preceding art is saved in
`checkpoints/original-cadence-before-warm-warning-2026-09-15.zip`.


`enemy-audit-2026-09-15` rechecks source movement and direction routines: normal
enemies average16/15 of player speed, frightened enemies7/8, including warning.
Both species share random ordering mixed with coordinate-based pursuit/flight.
It corrects the secondary direction preference when aligned on the same row or
column. All63 tests pass, including12000 source-order comparisons. See AUDIT.md
for evidence and the distinction between relative rates and absolute DOS pace.


## Queued turn indicator

Build `queued-turn-2026-09-15` adds a tiny, non-pulsing chevron outside CD-Man
while a requested direction is waiting. It disappears when the turn is taken,
and is hidden inside tunnels and during death/finish screens. **Queued turn arrow**
in Visual settings enables/disables it; localStorage `cd-man.turn-arrow` remembers
the choice (default on). Both HD and classic rendering support it.

Buffered directions already persist until legal. Keyboard auto-repeat now cannot
overwrite a newer press, and a command entered during a tunnel is retained after
emerging. New presses replace the queued direction; immediate reversal remains.
The marker draws immediately on input, including classic mode. 67 tests pass,
with zero partial/full redraw differences in the two-world indicator gallery at
`tests/queued-turn.html`. Turning the indicator off never changes the turn queue.


## Widescreen, collection audio and contact checks

Build `widescreen-collection-2026-09-15` presents both HD worlds in exact16:9
frames (forest1696×954; Pacific1936×1089). The Pacific adds AI-painted shorelines
left/right; the native playable center stays at its original scale, translated
244 pixels right and1 down. The forest gains a narrow border without stretching.
Classic artwork stays640×350 inside a16:9 cabinet. Dots, actors, HUD and animated
gates share the same centered placement. The barrel remains below the cage.

The skeleton beside the hut is replaced with generated water in an80×57 native
pixel patch. The original backgrounds remain intact on disk; only the added
Pacific sides and this removal use generated pixels, with shore-edge feathering.
The layer inspector can export the complete widescreen backgrounds. Asset source
and composition details are in `research/hd-references/WIDESCREEN.md`.

The optional queued-turn chevron is now white. Dot feedback uses the original
two audible PIT divisors, triggered only by a successful dot deletion/score event.
Reversing before arrival produces no dot cue; the last-dot cue survives the clear
transition. The cue interrupts queued speaker output to avoid delayed feedback.
This is a deliberate user-requested change from approach-based DOS timing.

Enemy contact is checked after each movement substep, including both normal
extra steps. Power activation precedes same-tick contact; warning enemies remain
edible through their last positive timer tick. Individual expiry is independent
of other enemies. The existing19×14 half-extent contact box, early orb-contact
ellipse and portal/respawn protection remain intentional remake conventions,
not claims of exact DOS collision geometry.75 tests pass. Testing stays muted;
audio scheduling is checked with a fake AudioContext rather than auditioned.

Pre-change sources: `checkpoints/queued-turn-before-collection-audio-2026-09-15.zip`
and `checkpoints/hd-before-widescreen-2026-09-15.zip`.
