# Sonic Lighting Test — Java Green Hill Zone Act 1

Editable Java reconstruction of the supplied Sonic the Hedgehog REV00 first act. Java owns the player, collision sensors, objects, rings, enemies, platforms, checkpoints, damage, powers, lives, clock, camera, animation and signpost/results progression. TeaVM compiles that Java into the browser engine. The page contains no cartridge emulator, native emulator core, savestate or ROM image.

The playable scope is **Green Hill Zone Act 1**, from the normal controlled-play start at (80,944) to the end signpost and bonus tally. The original preservation player and its saves remain separate. This is a new implementation of the first act, not a port of the entire game. Later acts, title/menu boot flow and special-stage gameplay are outside this release. Native graphics loading/title-card latency is not simulated.

## Build and run

Use JDK 17 and Maven with the pinned dependencies in `pom.xml` (TeaVM 0.16.0). Run Maven `-DskipTests process-classes`, or edit `build.ps1` to point to your installed JDK/Maven and run it. The local script uses an existing read-only toolchain path and a private dependency cache; those caches are not shipped. Serve `web/` over HTTP and open its `index.html`. The compiled output is `web/engine/sonic-engine.js`, with readable Java source and source maps for inspection.

The source download includes editable `data/data.json` and `tools/generate-stage-source.py`. Run that Python tool to regenerate the Java terrain/object arrays before rebuilding. A new stage also needs matching visual planes and animation metadata; changing collision data alone does not redraw the artwork. The generator reproduces the current compiled data byte-for-byte.

Arrow keys or WASD move; Space/Z/X jumps. Down rolls while moving, up looks up. P pauses, R restarts. Touch buttons and the browser Gamepad API feed the same Java input bits. Generic HID controllers have a mapping wizard. No WebHID device permission is required. Mapping is local to the browser. Physical controller play has not been independently verified.

The three independent assists are no enemy damage hitbox, keep rings when hurt, and unlimited lives. They are off by default. Falling into a death pit remains lethal. Watch verified route replays ordinary held inputs from the start; it does not teleport Sonic or edit his state.

## How the physics works

The fixed simulation runs at 60 updates per second. Java stores world positions as signed 16.16 integers and velocities as signed 8.8 values. One world pixel is 65,536 position units; one velocity unit is 1/256 pixel per update. The renderer converts these to pixels without changing simulation state.

Ground speed follows the contacted surface. Two sensors sample original height profiles; their selected angle projects that speed into X/Y using the original sine table. Acceleration, opposite-direction braking, passive friction, slope forces and rolling friction happen in their original branches and integer order. Rolling trades steering/acceleration for lower friction. Jumping adds a surface-normal impulse, cuts upward speed when jump is released and retains the original air-drag/steering rules. Slow wall or ceiling contact detaches rather than gluing Sonic to a loop.

Sonic's world position and camera position are separate. Horizontal scrolling keeps Sonic within the original 144–159 pixel tracking window, with the original asymmetric movement limits. Airborne vertical tracking has a wider window; grounded tracking uses source speed-dependent caps. Looking up/down shifts the window. Clouds/mountains, hills and water use the original separate scanline parallax calculations. This is why the screen can move while Sonic appears almost stationary on it.

Animation uses the original 31 scripts, mapping frame IDs and sprite flips. It does not rotate an upright sprite continuously around loops. Stage objects occupy the original source slot range and run in source order. Data and source comments retain links between behavior and the matching REV00 routines.

## Source and artwork

Reference: Sonic Retro `s1disasm`, commit `89c0e0e06b51fd9ebac44d988e4a89bd643fd031`, Revision 0, FixBugs 0. The supplied canonical cartridge SHA-256 is `46160baa06362c711c9f1a5017cb7371026444936c8af5e93a78996cf32ff2a6`. Original bytes and prior frozen preservation packages are retained unchanged outside this public build.

All original Sonic mapping frames, GHZ1 object contexts, HUD, pattern animation and palette animation are extracted from that supplied ROM. Public art verification records document their comparisons. Lighting normals/materials are inferred metadata for the new effect; they are not fields stored in the Genesis sprites. Sonic and the original art/music belong to SEGA.

JavaScript supplies the browser launch UI, keyboard/touch/Gamepad input, Canvas drawing, audio playback and the supplied FITS lighting/weather presentation. Select Original to disable new lighting/weather. The new visual clock never changes Java game time, physics or object behavior. Four supplied sky paintings and material lighting are used; this is not a separately painted four-period GHZ scenery catalog.

Original music/sound renders are played from the existing verified extraction. Music uses sample-based loop start/end points so its intro plays once and the native interval repeats. Audio presentation uses prerecorded command renders rather than a live Genesis synthesizer; sound-channel contention, interrupt/restart timing and the speed-shoes tempo approximation are not proven identical to original hardware.

TeaVM runtime/class-library source retains its original copyright headers. Its Apache 2.0 license is included at `web/engine/TeaVM-LICENSE.txt`.

## Verification and limits

`web/verification/` contains the release record, tested route and comparison reports. Selected movement/camera/animation trajectories, terrain queries, SolidObject cases and object behaviors are compared with the unchanged ROM or exact source-derived fixtures. The actual TeaVM output is replayed and compared with the JVM at every route update. These checks establish the reported cases, not bit-for-bit identity for every possible input sequence.

The same 2,960 ordinary input updates also reach the original ROM's signpost and exhaust its bonuses, with 51 rings, three lives, 15,900 points and no deaths. All 32,571 comparisons of the eleven reported player-movement fields match. Ring/life counters match throughout. One camera snapshot differs; a native sampling boundary is a possible explanation. Intermediate tally timing differs because the measured original graphics queue adds 42 loading visits before the card moves. Browser graphics are already decoded. The original boot fixture starts with 30 elapsed timer updates; this launcher starts controlled play at zero. These bounded differences remain explicit in the native completion summary.

Native Canvas and page-module tests exercise the renderer/assets and browser wiring with DOM stubs. Interactive browser automation is unavailable because local browser use is disabled in Work settings; these checks must not be described as an interactive browser playthrough. Original power/tile timing, activation rules and game-specific edge cases should continue to be audited against independent native traces. Absolute animation/oscillator phase immediately after the original title/PLC load is not independently established by the cleared-state Java start.

Preserve earlier archives, test reports, source provenance and save namespaces when extending this build. This page has no game save feature and never reads or writes the original emulated player's saves.
