# UnlockMe Nokia 8310 — private working preview Updated 12 November 2026. NHM-7 MCU 6.20, PPM c. Owner-private preview; the live UnlockMe website is unchanged. The original firmware reaches standby, operates its menus, draws Snake II, and responds to numeric direction keys. The normal-startup Python reference, native mGBA core, and WebAssembly version all reach the same standby pixels. Native and WASM Snake II output and the tested upward turn match byte for byte. The 13-note Nokia ringtone is observed through firmware buzzer calls; it is not the startup chime. The startup chime is now a layered reconstruction of the supplied handset reference, because this provisional core does not render its DSP audio path. ## Preview files - `dist/`: buildless static preview, approved silver handset artwork, white LCD/keypad lighting, worker, optional sound and WebAssembly build. The prepared firmware state is approximately 9.9 MB compressed. - `src/core/`: provisional NHM-7 board and mGBA ARM core, with bundled licences and attribution. - `src/build.sh`: builds the core into `dist/` when Emscripten is available. - `tools/prepare-startup.cjs`: captures the complete original startup animation using a slower diagnostic timer, then packs its unchanged LCD pixels into a 10.6 KB presentation asset. `dist/8310-startup.json` records pixel hashes, source hashes and the reference-based timing. - `tools/startup-test.cjs`: checks every captured animation frame byte for byte, the logo hold, total duration, pause/resume, Restart, delayed callbacks and final live standby. - `tools/worker-test.cjs`: loads the actual worker with Node Web APIs and checks boot, the Messages frame and pause behavior. - `tools/prepare-snake.cjs`: reproduces the opening Snake II checkpoint by executing original firmware and keypad input; validates save/restore against the expected framebuffer. `dist/8310-snake.json` records source/core/state hashes. - `tools/game-worker-test.cjs`: runs the actual WASM worker against a deterministic virtual clock to check pace, real firmware turn response, queue bounds and pause/resume. The full research archive contains the reference implementation, captures and additional parity tests. The notes below preserve that research history; those additional tests are not bundled with this smaller web repository. ## Browser preview check — 12 November 2026 Chrome desktop: the handset loads the prepared state, displays standby and opens the original Messages menu through the handset's left soft key. Snake now opens directly from a fresh, zero-score board. The large Up control turns the snake, and a pointer drag across the LCD also changes direction. Pause disables steering; Resume continues the same game. The white-light control switches the LCD and keypad treatment. A 390-pixel iframe in Chrome checks the narrow viewport layout; the usable 375-pixel content width has no horizontal overflow, and the game controls fit within the 844-pixel frame. This is responsive-layout validation, not Safari or physical touchscreen validation. iPad/iPhone Safari and physical touch use are still unverified. The current deterministic worker test verifies original changed-board frames at 256 / 128 / 85.33 ms for Gentle / Normal / Brisk, including sustained direction input and turns. At Normal pace a new direction changes the original board at the next movement deadline (128 simulated milliseconds from a fresh start). This is not a measured real-device latency. Hiding the page freezes execution, returning requires Resume, delayed timers do not replay missed moves, and the input queue stays bounded at two turns. Handset boot/Messages/pause checks also pass. The user supplied two screen recordings on 12 November: the previous preview and a real 8310 startup. Comparison exposed missing poses and a missing final NOKIA logo, not just excessive speed. Diagnostic runs with slower clock dividers recovered the original sequence; divider 4096 yields 20 nonblank animation frames, plus a final clear. The boot screen now replays these unchanged firmware LCD captures on a separate presentation timeline while the normal firmware boot runs underneath. This is a presentation repair, not a hardware-clock correction or live rendering of those animation frames. No imagery or audio from the supplied recording is redistributed. The timeline is approximately matched to the reference: 1.62 seconds for hand movement and logo reveal, a 1.04-second full-logo hold, then fade/clear; 2.92 seconds total. The deterministic worker check measures 2,927 ms including scheduler rounding and verifies all captured pixel hashes in order, the full-logo hold, pause/resume, Restart, and retention of every pose under delayed callbacks. The phone becomes interactive only when both animation and boot have completed. Actual duration may increase on a busy device. Physical LCD response, recording compression and its precise firmware revision are not replicated. Menus and Snake retain their existing live emulation and timing. ## Verified in this session 1. Normal startup with ADC6=410 (original battery category 4), ADC12=580 and power-on bit 3. All ten executed startup self-tests pass. The extra AUX DA GPIO6→7 loopback was the missing self-test connection. 2. LCD DMA sends one CPU byte followed by 503 DMA bytes to the 84×48 monochrome panel. 3. Key matrix: 26 isolated scanner cases pass. Rows 1–4 work, row 0 is unused by this scanner. `1 → 12 → Clear → Clear` was observed in the reference. 4. Offline SIM transport reaches 78 exchanges with a synthetic BCCH file and 20,000-step reply delay. No subscriber account, live network or uploaded PM identity is used. 5. Reference/native standby pixels match. Native/WASM standby and Messages frames match. WASM save/restore preserves the tested menu frame. 6. Snake II runs in the independent Python reference and the native core. Native/WASM game frames and upward-turn frames match exactly. Left-turn response was also observed natively. 7. The browser worker runs under a Node Web-API harness: loads, reaches standby, opens Messages, and pauses without further frames, including when hidden during initial loading. This is not a full Safari or browser-layout test. 8. Buzzer call 0x12d9dac exposes frequency and level. The ringtone-menu Nokia tune trace contains 13 audible note intervals; this is not a startup trace. The player observes these requests without changing guest state. ## Exactness and unfinished work This is original firmware on an incomplete hardware model. It is not a reset-vector, hardware-accurate emulator. Missing internal ROM services are approximated; device 0x7c is explicitly registered as ready in RAM. Factory identity remains absent and erased records are not decrypted. The supplied PM files are not loaded. Starting Snake requires a synthetic deterministic random mixer. The only accepted NHM-7 tuple is destination 0x43868, length 8, key context 0x228, mode 0x90, wrapper return 0x12d478b, and saved caller 0x12f4203 at SP+16. This is a SHA-256 research substitute, not Nokia cryptography. The actual game code remains unchanged, but its random sequence is not an original handset sequence. Timing is approximate. Handset mode uses 262,144 instruction steps/second after boot, with short acceleration for navigation. The direct Snake board uses a display deadline of 256,000 divided by the selected 1/2/3-million-step pace, giving 256 / 128 / 85.33 ms between moves. The worker executes original firmware until the next changed board, allowing extra keypad processing without slowing movement; no game instructions or pixels are replaced. Non-board screens retain the nominal instruction clock. Audio follows the selected mode's nominal clock. Game pace is a preview usability setting, not a calibrated hardware speed. Key pulses remain 150,000 steps with a 250,000-step minimum gap. The game queue holds two distinct turns, delivers at most one per movement frame, and expires entries after two movement intervals plus 100 ms. Redundant direction samples are discarded. Pointer-down input retains a separate keyboard/accessibility click path. Blank clears and unchanged keypad redraws are hidden, and the browser paints game frames on requestAnimationFrame. Startup presentation is visually timed against the supplied handset recording; the underlying clock, audio tempo and game speed remain uncalibrated. The ringtone triangle waveform, volume and speaker character are approximations. Startup uses separate reference-derived tonal layers. Sound is off before interaction; starting/restarting the phone enables it directly in the user gesture. The visible switch can mute it at any time. Pause, mode changes and hiding the page silence current playback. The original research session did not validate browser layout. The Chrome desktop preview has since been checked as described above. Audible output and iPad/iPhone Safari remain unverified. Browser save/load controls are not included yet (core save/restore has a smoke test). Flash erase is deliberately unsupported; the preview stops explicitly if reached. Snowboarding reached its animated player-selection stage but actual sports gameplay was not verified. Bumper has not been tested. ## Rebuild and checks With Emscripten activated, run `bash src/build.sh` from the repository root. After any core rebuild, run `node tools/prepare-snake.cjs` to regenerate the build-specific Snake checkpoint. `node tools/prepare-startup.cjs` reproduces the startup captures with the current WASM core (about 400 million diagnostic instruction steps). Run `node tools/startup-test.cjs`, `node tools/worker-test.cjs` and `node tools/game-worker-test.cjs` with Node supporting Web APIs and DecompressionStream. Test output is written under `test-results/` (ignored by Git). The supplied WASM build matches the retained core source. The prepared state can be decompressed from `dist/8310-start.bin.gz`. `D8_INPUT=1` and `D8_MESSAGES=1` enable native diagnostic logging; these host observations are disabled in ordinary use. Next: test Safari, calibrate the live hardware clock and audio against a handset or trustworthy recording, inspect Bumper and Snowboarding controls, then integrate with the collection only after further checks. ## Mobile sizing — 12 November 2026 The mobile handset now uses the available width in both phone and game modes. A nested artwork coordinate system crops transparent side gutters (80 pixels from each side of the 980-pixel asset) without moving the LCD, lighting or keypad hit areas relative to the shell. The real 980×1605 image dimensions are declared in HTML. At a 393-pixel mobile viewport without a reserved scrollbar, the artwork scales from 275 to about 441 CSS pixels, approximately 60% larger; the visible handset occupies about 88% of viewport width. The full handset stays available by vertical scrolling. Direction buttons and the pace selector are enlarged on mobile. Chrome iframe checks at 393 and 320 pixels (usable widths 378 and 305 with desktop scrollbars) show no horizontal overflow. Snake loads at both widths and Pause/Resume remains usable below the enlarged handset, with LCD and controls visible together after scrolling. Desktop layout was visually checked. This is responsive-layout validation; physical iPhone Safari verification remains with the owner. ## Standby branding — 12 November 2026 A presentation-only decorator adds lowercase unlockme and seven signal segments to the exact original standby bitmap. It is gated by all 4,032 original pixels and phone mode; the core framebuffer is never changed. No network connection is implied or created. Menus, Snake and all 21 startup captures remain untouched. `node tools/standby-test.cjs` verifies these boundaries against the actual WASM core. Desktop browser standby rendering was visually checked. ## Startup and keypad sound — 12 November 2026 The current core emits no startup buzzer events, and the home-screen key tests produced either no tone or only a zero-volume stop event. A separate presentation voice therefore supplies a synthesised 13-note Nokia-style startup melody and a short 1 kHz keypad beep. These are approximations, not recovered original 8310 startup/key audio; menu ringtone playback still follows observed firmware events. The startup cue triggers once at the first animation frame. The Sound switch mutes both paths and cancels scheduled notes. Start/Restart enables and resumes Web Audio inside the tap, with a silent buffer unlock; key taps also recover an interrupted context. All 18 matrix keys were exercised independently from standby: numeric keys, star/hash and four navigation/softkeys changed the display; call/end returned unchanged standby with no active call. Browser checks verified 123 entry, Clear to 12, Menu, muting and automatic re-enabling on Restart. Numeric keys now receive the same bounded response acceleration as navigation. `node tools/home-keys-test.cjs`, `node tools/sound-test.cjs` and `node tools/worker-test.cjs` cover core responses, audio scheduling/cancellation and one startup trigger. These tests do not establish acoustic fidelity or physical iPhone Safari playback. ## Consecutive phone-key input — 12 November 2026 A real-time worker reproduction at 60 ms between digits exposed a final-digit redraw delay of 1,448 ms. Successive phone keys could be injected before the prior redraw had settled, allowing an earlier frame to end the new key's acceleration too soon. The six-entry queue also discarded the last three digits of a simultaneous 1–9 burst. Phone inputs now wait for the preceding redraw/release window, and a nonempty phone queue keeps processing accelerated. The phone queue holds 32 entries; Snake retains its existing two-entry queue and timing. No firmware bytes are patched. `node tools/phone-input-test.cjs` compares all prefixes and final output against independent leisurely original-core inputs at 400, 200, 100 and 60 ms intervals and as a simultaneous nine-key burst. `node tools/phone-input-real-test.cjs` checks actual elapsed time at 200, 100 and 60 ms intervals. The first corrected 60 ms run delivered all digits with 99–142 ms latency. Browser entry of 123456789 was also verified. Worker/menu and Snake regression checks passed. Performance figures are from this environment, not a physical iPhone benchmark. ## Menu navigation response — 12 November 2026 The original firmware emits a partial LCD frame before completing menu navigation. Ending the processing boost 750,000 instructions after that partial frame left redraw work running at the slow idle rate. A repeatable Messages → Call register → Profiles → Settings → Messages sequence showed roughly 616–633 ms response for middle moves and 1,603 ms for the last move. Navigation/softkeys now receive a minimum three-million-instruction processing window, while preserving the serialized key queue and original key pulse/release. Numeric keys and Snake timing are unchanged. `node tools/menu-input-test.cjs` checks the original menu-index pixels (excluding animated icons and scrolling titles) against independent core reference frames, at 600, 200 and 100 ms input intervals. The verified run completed each up/down move in about 40–74 ms; initial menu opening took 80–105 ms. Browser taps moved down three items to Settings and up three to Messages. Numeric-input, worker/menu, and Snake regression checks passed. These timings measure this test environment rather than physical iPhone performance. ## Menu icon animation pace — 12 November 2026 Compared the supplied 6.07-second real-handset screen recording (Profiles/“Modes”). It shows roughly one second holding the first icon pose, then about 2.4 seconds of musical-note motion, then a final still pose. CPU acceleration used for quick menu input had been compressing these original icon frames. The display now separates the main-menu icon region (x=0..77, y=21..38) from live text, menu index and softkeys. `tools/prepare-menu-icons.cjs` captures original icon sequences for all 12 root menus with the existing unmodified WASM firmware, preserving distinct poses. `dist/menu-icons.js` contains only packed original icon pixels; no imagery from the reference video is redistributed. A 1,000 ms first-pose hold and approximately 100 ms pose cadence follow the reference. Profiles has 25 poses and finishes at about 3.3 seconds from menu appearance. Other menus use the same cadence. Timing is an approximate presentation calibration, not a corrected emulated hardware clock. Exact Select/Exit footer pixels plus a numeric menu-index region gate the playback. Changing menus replaces the old sequence immediately; help/submenus/standby/Snake pass through. Hiding the tab pauses presentation without catching up rapidly. The previously verified three-million-step navigation window and numeric/game timing remain unchanged. `node tools/menu-animation-test.cjs` verifies original Profiles poses, cadence, immediate text, cancellation and game/hidden-state exclusions. Menu input checks pass at 600/200/100 ms press intervals. Number-entry, worker and Snake checks were also exercised. Browser rendering was checked on Profiles and Call register. Physical iPhone behaviour remains for owner review. ## Snake steering and loading — 12 November 2026 Reproduced an input-related movement slowdown: the prior instruction-paced loop moved every approximately 128 ms when travelling straight, but repeated Up inputs at 200 ms intervals stretched moves to about 208–248 ms. Key handling and repeated identical LCD redraws consumed the same budget as gameplay. Active-board rendering now uses evenly spaced movement deadlines, with at most one distinct queued turn applied per move. Original firmware is stepped until its next changed image; work is bounded to six milliseconds per task and one million instructions per seek. A stationary/non-board screen returns to the nominal clock. Missed visible/hidden time is discarded. Consecutive swipe samples for the same direction are filtered in both the touch handler and worker. Snake previously fetched a separate 10,084,061-byte compressed snapshot containing another copy of the firmware. `dist/8310-snake.delta.gz` is 91,487 bytes (99.1% smaller) and shares `8310-start.bin.gz` with phone mode. `checkpoint.js` validates and reconstructs the original 34,295,616-byte D8R1 snapshot; its SHA-256 and opening-frame SHA-256 are unchanged. `tools/snake-delta.cjs` creates the delta and verifies byte-for-byte reconstruction; the normal checkpoint preparation tool now emits that format. The obsolete full Snake download is removed. Initial use still needs the approximately 10 MB shared handset download. WASM startup and asset fetches run concurrently. After the artwork loads, idle warmup fetches and reconstructs the state and initializes the core callbacks without running CPU instructions, showing frames or playing audio. Save-Data connections skip automatic warmup. User starts share any in-flight requests. Restart reuses cached state and initialized callbacks instead of re-downloading or initializing the entire core again. Phone mode also warms the small delta. Failures remain retryable. `game-worker-test.cjs` verifies 270 evenly timed movement updates across all three paces and straight/repeated/turning input, original-core pixels for all four direction keys, exact checkpoint reconstruction, concurrent warmup/start request sharing, zero extra reset downloads, two rapid Gentle turns, and pause/visible-stall handling. `snake-realtime-test.cjs` exercises the actual WASM worker with 100 ms input samples and records launch/restart times and movement intervals. Local real-time measurements are in the ignored test-results directory and are not physical iPhone or network benchmarks. Phone number entry, menu navigation/animation, standby decoration, audio scheduling and worker startup regressions pass. Browser QA covers warmed Play, new game, direction controls, and pause. Physical iPhone Safari remains unverified. ## Snake entered through handset menus — 12 November 2026 The owner's recording showed the handset-ready status during Snake. The direct Play button selected game timing, but navigating the original firmware menus left the worker in phone mode. Numeric steering therefore triggered the phone's large processing boost and advanced gameplay too far. The first recognized Snake board now switches the existing running state into Snake mode, cancels the menu boost and pending menu inputs, and notifies the UI to enable its game controls. It does not reload the checkpoint or replace game pixels. Original-menu entry and direct Play now share the same game pacing. `tools/menu-snake-entry-test.cjs` executes the original menu journey and checks automatic mode switching plus two queued turns at consecutive 128 ms deadlines without any remaining phone boost. Direct-game cadence, number entry, menu icon animation and real-time steering regression checks pass. This correction was verified against the WASM worker, not on a physical iPhone. Previous four-pixel measurements alone did not explain the owner's excessive turn distance; the recording exposed the separate menu-entry path. ## Leaving Snake restores menu response — 12 November 2026 Back previously left the worker in Snake mode even after the original menu appeared, so menu keys did not receive phone-mode response acceleration. A delivered Back key now marks an exit in progress. Once a nonblank, non-board frame appears, the worker restores phone mode and its bounded menu response boost, retaining queued inputs and the current firmware state. Blank LCD clears alone do not trigger the transition. The existing board detector restores game mode when Continue/New game reaches the board again. `tools/snake-exit-test.cjs` exercises Back, repeated down/up moves, return to the original item, and continuing the game. It checks mode transitions, actual changed menu pixels, the navigation processing window and cancellation of acceleration on game re-entry. Menu-entry, all three game paces/rapid turns and menu-animation checks pass. These are actual WASM-core tests with simulated worker timers; physical iPhone timing is not measured. ## Stable handset position across game/menu transitions — 12 November 2026 Separate the persistent compact presentation from the worker's game/phone mode. Once Snake is opened, Back and Continue retain the same introduction visibility, handset sizing, spacing and footer layout. A fixed action grid reserves the Restart slot, status text has consistent height, and a shared control region reserves room for either control set. Mode changes still select the correct input/timing behavior. No scroll-to-top or corrective scrolling is introduced. Browser QA in a 393 px mobile iframe verified Back with the handset already scrolled into view: handset top remained 58 px, width 354 px, scroll position 149 px and document height 1192 px before and after the transition. Continue was exercised as well. Physical iPhone Safari remains for owner review. ## Snake II splash timing (12 November 2026) The supplied real-handset recording shows the Snake II logo for approximately two seconds. An actual-WASM worker regression reproduced 6,726 ms from the complete logo to the player menu. The worker now recognizes that original bitmap and runs its firmware wait at 1.7M instructions/second, cancelling the preceding menu-key boost. This yields 1,920 ms in the same test. It restores the normal phone clock when the artwork changes; no firmware, game movement, menu animation, or page layout changes. `tools/snake-splash-test.cjs` follows the original menu route and checks the complete logo and player menu hashes with a 1.8–2.3 second timing bound. Timing is approximate and can stretch on an overloaded device. ## Snake splash animation follow-up (12 November 2026) The second iPhone recording revealed that the splash CPU animation was compressed before the final still image. Captured all six complete original firmware head/mouth poses at 8,192-instruction sampling (tools/capture-snake-splash.cjs). The worker now presents these unchanged pixels at 250 ms per pose, holding the last until the original firmware opens its player menu. A splash-only 2.05M instruction clock keeps the whole sequence near two seconds (1,960 ms in the actual-WASM regression). Recognize every captured pose rather than only the final image; ignore the firmware's intermediate blank clears. No CSS, layout, game mechanics, or menu icon timing changes. The regression now asserts every pose hash in order, frame spacing and total duration. This supersedes the previous final-image-only splash pacing. ## Handset button-edge refinement (12 November 2026) Retouched the handset artwork using the built-in image editor: smooth continuous satin-chrome edges and restrained reflections on the navigation, softkey and call buttons, preserving the canvas, silhouette, screen and keypad locations. New asset `nokia-8310-refined.png` is 980 × 1605 RGBA like the original; original retained. Updated the HTML image reference. Visually checked a 393px-wide browser preview: softer button highlights, aligned display and keypad, unchanged layout. No emulator or interaction code changes. ## Red End key home-screen latency (12 November 2026) Boot → Menu → red End reproduced a 1.385–1.673 second return-to-standby delay. End uses keypad [3,0], so it was excluded from the navigation minimum instruction budget and dropped to the slow phone clock after an intermediate redraw. Include this specific key in the same 3M-instruction transition budget as the navigation keys. Digit timing, game timing, firmware and artwork are unchanged. tools/end-key-test.cjs exercises the sequence with 100/500/1500 ms between Menu and End and checks the exact standby framebuffer within 300 ms; REALTIME=1 also runs using actual timers. ## Green Call key offline fallback (12 November 2026) The original core accepts matrix [2,0] but returns unchanged standby/dialled digits; even 8M extra instructions did not complete call handling. Added a presentation-only fallback (call-preview.js): exact standby → empty Dialled numbers screen; digit-entry footer or in-flight digit intent → Offline preview / No network. No call records are invented, calls are not sent, and firmware state is not patched. Back restores the underlying screen and entered digits. End also reaches the original firmware to clear digits and return Home. Other menu/game contexts retain native key dispatch. Reset clears the overlay. Automated actual-core frame checks and browser touch-target tests verify the empty list, offline notice and red-key return to branded Home. This is an explicit interface workaround, not restored firmware telephony; disclosed in About. ## Home Up/Down shortcut stability (12 November 2026) Both original Home arrow inputs [2,1] and [3,1] reproduced a completely blank LCD after about 12 simulated ms, still blank after 10 seconds. Extend the explicit offline Home shortcut fallback to show Names / No names saved immediately for either arrow, without sending the failing shortcut to the core. Repeated arrows keep this empty state stable. Back restores the untouched underlying Home; End also dispatches to the firmware. No fictitious contacts. Only the exact original standby screen triggers this fallback; arrows in original firmware menus and Snake still use their existing paths. About discloses this presentation workaround. Actual-core fixture tests cover both initial arrows, 40 repeated alternating arrows, background redraws, nonblank content, Back/End, and menu/game isolation. ## Snake red-key exit restores Home presentation (12 November 2026) Reproduced red End returning the original firmware to standby while worker mode remained snake. This prevented standby branding and kept game controls/timing active. Recognize both Back [4,1] and End [3,0] as game-exit inputs in the paced and nominal execution paths, switching back to phone when the first nonblank non-board image arrives. The existing ready event restores phone UI and applies the unchanged exact-standby decorator. No firmware changes. New actual-WASM regression covers red-key exit after play at all three paces, original Home pixels, restored branding, Home shortcut recognition and opening Menu afterwards. Existing Back/Continue, menu game-entry and standby pixel-boundary checks pass. ## First Snake launch layout stability (12 November 2026) The supplied recording showed first menu-driven game entry hiding the introduction and moving the handset upward. setMode added compact-layout only on first Snake entry. Removed this state-dependent layout switch; mode still swaps game/phone controls. Apply reserved action columns, Restart space, status height, interaction-panel and hint height in all modes from initial load. The first launch therefore has the same geometry as subsequent exits. A 393px mobile iframe browser check measured identical phone bounds before direct launch, during game and after red-key Home: top 417.546875px, width 369px, height 722.25px. Original firmware menu entry calls the same setMode path. No emulator timing/game changes. ## Startup tone reference transcription (12 November 2026) Analysed the supplied 16:22:29 screen recording's mono audio using windowed spectra. The audible startup phrase starts around 7.00 s and its final F# decays beyond 9.0 s. Replaced the previous 13-note Nokia-ringtone-style placeholder with an approximate eight-note startup transcription: G#5 F#5 G#5 A#5 G#5 A#5 C#6 F#5. Onsets follow the measured reference; the final note is 0.68 s plus a 0.22 s tail, sustaining through 90% of its main duration before fading. The phrase totals about 2.4 s; the ending is longer than the previous 0.42 s ending. Triangle synthesis remains an approximation: recording noise, room echo, speaker distortion and other audio are not copied. Key cues and firmware ringtone path are unchanged. Audio scheduling tests verify pitches, final sustain/zero-gain timing, mute cancellation, gesture unlock, keypad cues and interrupted-context recovery. Worker startup still emits its cue once. Physical iPhone audio remains for user comparison. ## Restore preferred startup melody (12 November 2026) Owner rejected the attempted reference transcription. Restored sound.js from the preceding version, preserving all 13 pitches, their onsets, triangle timbre and envelope behaviour. The sole audible change from that preferred version is extending the final A4 from 0.42 to 0.92 seconds (+0.50 seconds). Total phrase is 3.44 seconds plus the 10ms scheduling lead; the original proportional release now fades across the final approximately 0.20 seconds. This supersedes the eight-note transcription above. Tests assert all pitches, every onset and oscillator stop, final silence timing, mute, keypad and interruption recovery. No claim of perceptual matching to the noisy video. ## Layered startup chime reconstruction — 12 November 2026 The supplied 16:44:40 recording shows the real handset; 16:46:27 is the web preview. Spectral analysis confirms the web version plays E5 D5 F#4 G#4 … (the Nokia ringtone-style phrase) with triangle synthesis and no overlapping notes. This was the wrong sound for the 8310 startup. The earlier eight-note attempt had approximately the right lead pitches but still removed the overlapping layers and used the wrong timbre. Both previous implementations are superseded. Source investigation distinguishes the two paths. `tools/probe-startup-audio.py` builds a temporary native core with read-only request logging and runs the prepared state for 24 million instructions. Startup sends audio-service/configuration requests (including payload `00140407000000010308000000090000` through caller 0x10acf35); it produces zero calls to buzzer routine 0x12d9dac. The retained original `wasm-tone-test.cjs` research trace obtains its 13 pitches only after navigating the ringtone menu. This core does not implement DSP PCM output. Exploratory calls into other tone helpers did not recover a startup recording and were not added to the emulator. No guest code, core binaries or checkpoints were changed for this fix. The replacement is additive resynthesis, not a cleaned-up audio sample or native DSP emulation. `tools/prepare-startup-tone.py` measures only the stable pitched components in the real handset clip, subtracts a pre-tone noise estimate, smooths their amplitude envelopes, and tunes their frequencies to the measured notes. Twelve independent components preserve the lead, lower harmony and strong even harmonics. The approximate prominent lead onsets are G#5 (0), F#5 (0.23), G#5 (0.32), A#5 (0.48), G#5 (0.61), A#5 (0.73), C#6 (0.94), F#5 (1.49 seconds); other layers continue ringing under them. These are reference-derived timings, not a recovered firmware score. Late noisy amplitude fluctuations are replaced by a smoothly joined exponential decay. The complete buffer lasts 2.8 seconds, with a gentle final fade. No voice, room noise or recorded waveform is included. Acoustic phase, microphone/speaker response and exact hardware synthesis remain approximations. `dist/8310-startup-tone.json` records the reference hash, analysis choices and independent envelopes. `dist/startup-tone.js` generates 61,740 mono samples at 22,050 Hz once per AudioContext and caches them. The browser resamples as needed. Startup schedules the complete buffer on the audio clock; becoming ready does not stop it. Start/Restart still unlocks/resumes Web Audio inside the tap; mute/hiding/reset cancel active playback. Key beeps and observed ringtone playback are unchanged. The new script is about 15 KB and requires no audio download/decoder dependency. Validation: `tools/startup-tone-test.cjs` renders the actual browser synthesis function and checks opening pitch, strong even harmonic, simultaneous notes, both high-note octave layers, final harmony, headroom, audible tail and near-zero final sample. `tools/sound-test.cjs` checks gesture unlock, buffer caching, natural completion, replacement, mute, all 18 keypad cues and interrupted-context recovery. `tools/worker-test.cjs` checks actual firmware startup and a single audio trigger. Chrome checks confirm successful boot and real AudioBuffer playback/cleanup. The comparison is spectral and programmatic; no claim of a listening test or physical iPhone Safari verification. ## LCD glass fit and original standby indicators — 12 November 2026 The owner's close-up showed the old opaque rounded rectangle crossing the photographed LCD's tapered lower corners. Retain the refined handset PNG unchanged and render only the active LCD ink: a reusable presentation ImageData buffer copies each input frame and makes only the unlit pixels transparent. Firmware, animation and offline-preview buffers remain unchanged. A small inline SVG traces the original glass contour in the 980×1605 artwork coordinate system; a clipped, two-source-pixel feather blends the white backlight or unlit tint into the existing inset rim. The original glass texture, inner shadow and bezel remain visible. All key hit areas and page-layout dimensions are unchanged. The 84×48 display now uses 92% of the measured glass bounds in each dimension, reproducing the reference's slightly taller physical pixels and reducing the old excessive top/bottom margin. The native framebuffer remains 84×48 with nearest-neighbour scaling. This is a visual calibration to the supplied photographs, not a physical screen measurement. The Home operator label moves from row 14 to row 8 to match the reference's upper position. Replace the seven invented short signal segments with a mirror of the unmodified original battery bitmap: four bars with widths 4/3/2/2 and heights 7/7/7/6, aligned at rows 0/8/16/24. The firmware battery, antenna and battery-outline icons are preserved. The exact-standby and phone-mode gates still prevent decorating menus, startup or games. Validation: standby-test.cjs passes, including original battery and antenna preservation, mirrored four-segment geometry, input/core immutability, menu/game exclusion and all 21 original startup frames. worker-test.cjs passes with the original standby/menu hashes and one startup audio trigger. Browser visual checks cover magnified Home edges, lights on/off, Messages, mobile Home, Snake and red-key return with restored indicators. Screenshot: docs/8310-lcd-fit.jpg. Mobile checks use a narrow browser iframe, not physical iPhone Safari. The accepted layered startup sound is unchanged. ## Four-source keypad illumination — 12 November 2026 Replace the 18 generic key-shaped highlights with four white LED sources behind the graphite keypad fascia. The owner's YouTube Shorts link QBdGprIr5tk opened, but its player remained on a buffering spinner after a reload; no video timing or frame comparison is claimed. Placement is calibrated from the owner's earlier red-handset photograph IMG_8897.jpeg, which shows the inter-key light pools, and the existing 980×1605 silver artwork. The supplied NHM-7 user-interface schematic was also inspected; its LED bank supports using four shared sources. No external imagery or video is incorporated. keypad-lights.svg uses artwork-space positions (385,1157), (601,1157), (408,1370), (576,1370). Each source has a soft white core, a diffuse asymmetric pool and broader cool-white transmission. A fascia outline and twelve feathered key-cap shapes attenuate light through the opaque caps. Screen blending preserves the underlying plastic texture and reflections; none of the handset bitmap, LCD alignment or touch targets changed. The vector overlay scales with the existing artwork at every viewport width. KeypadLight is a presentation controller with one inactivity timer. Startup/first frame/ready and accepted handset keys wake all four lights together. The rise is 480 ms; after 8.5 s without activity they fade down over 2.2 s. The existing White lights switch disables the effect, including subsequent key presses, until re-enabled. Hiding the page clears the timer/light state; returning wakes an enabled, powered handset. Startup failure switches the keypad off. Existing reduced-motion CSS removes transitions. The LCD light preference remains controlled by its existing switch; this idle effect applies only to the four requested keypad lights. This is an artistic backlight approximation, not emulated UEM LED-drive timing. No periodic pulse or animation loop is added. Validation: keypad-light-test.cjs verifies power, one timer, idle expiry, extended hold after activity, manual disable/re-enable, hidden-page cleanup and timer receiver handling. Browser QA found and corrected a Window timer receiver binding error before publication, then confirmed successful firmware boot, opacity 1 at full light, opacity 0 after idle, and a measured intermediate opacity 0.816827 during the 480 ms key-press fade-in. Manual White lights off remains respected after a numeric key. Visual checks cover normal desktop comparison and a 393px mobile iframe. docs/8310-keypad-lights.jpg records the lit/unlit rendering. No physical iPhone Safari test or successful playback of the linked video is claimed. ## Ruby-red fascia and colour selection — 12 November 2026 Create a second polished handset skin from the accepted silver artwork and the owner's IMG_8899.jpeg colour reference. The generated transparent PNG uses rich translucent ruby plastic, a pearl faceplate and bottom trim, ivory 2/5/8/0 keys with dark-red legends, and translucent red side keys with pale legends. Chrome controls and the call-key colours are retained. The generated 1002×1570 artwork differs slightly in geometry from the 980×1605 silver image, so each skin has separately calibrated LCD bounds, glass contour and all eighteen button targets. Both render into the same established page dimensions. The original silver bitmap is unchanged. docs/ruby-fascia-generation.txt records the image-edit mode and full prompt. Native Silver / Ruby red radio controls switch only the cosmetic skin. FasciaPicker waits for both the handset and its light overlay to decode before changing the artwork, contour and targets together. A request counter ensures the last choice wins during rapid changes. Failed loads preserve the current skin and can be retried. The choice is remembered locally when browser storage is available. No emulator reset, framebuffer mutation, audio change or game-state change occurs. Idle preloading of the red assets respects the existing data-saving gate. The red LED overlay has warm white cores and ruby transmission spill, with separately aligned sources at (389,1151), (612,1151), (412,1357), (588,1357). Its mask allows more light through the translucent side caps and attenuates the opaque pearl centre caps. It reuses the accepted fade-in, inactivity and fade-out controller, including the manual White lights switch. No extra animation loop is introduced. Validation: fascia-test.cjs passes atomic loading, last-choice-wins, failure/retry, saved preference, invalid-name rejection and calibrated target checks. Syntax checks and git diff whitespace checks pass. Browser testing verifies boot, all 1–9 handset inputs, preservation of entered digits after a colour switch, and a paused original Snake game switching colour and resuming. Both skins have identical measured desktop phone bounds (380×622.34375) and 393px mobile bounds (369×722.25 at top 492.546875); the mobile document has no horizontal overflow. Red selection restores after navigation. Visual checks cover normal desktop, mobile, magnified LCD edges and the four lights. docs/8310-ruby-fascia.jpg is the finished preview. Mobile QA uses a narrow Chrome iframe, not physical iPhone Safari. ## Audio activation reliability — 12 November 2026 Investigated reported silence after the ruby release. The fascia code does not change the audio object. Two existing activation gaps were found: a cold Play Snake II start never enabled audio, and startup() discarded its cue while AudioContext was suspended. A third iPhone-specific risk is Web Audio's default ambient/silent-switch behaviour; WebKit issue 251532 documents playback-session handling (https://bugs.webkit.org/show_bug.cgi?id=251532). The exact cause on the owner's device cannot be confirmed remotely. Sound enable now requests navigator.audioSession.type=playback when supported, within the user's activation. Unsupported or restricted session APIs are safely ignored. The existing silent-buffer unlock and synchronous resume remain. A startup request arriving before resume is retained and played once after the context runs; silence, mute and reset cancel it. Closed contexts can be recreated on enable. A cold direct Snake start enables audio, while subsequent new games preserve the current mute choice. Enabling Sound gives a short existing keypad cue as confirmation. The accepted startup model, notes, envelopes, level and complete 2.8-second tail are unchanged. Validation: sound-test.cjs covers playback session selection, delayed resume with exactly one startup, cancellation before resume, existing gesture unlock, mute, interruption recovery and key cues. startup-tone-test.cjs confirms unchanged 12-layer PCM (2.8 seconds, peak 0.32). A temporary browser QA page measured a running real AudioContext and startup waveform peak 0.32, generated keypad oscillators in both fascias, no cue while muted, and a confirmation beep plus key cue after re-enabling. Cold Play Snake II enabled the running context; after red-key exit, the keypad generated sound without a separate toggle. The QA meter observes source nodes (key oscillator peak is pre-gain), not device speaker volume. No physical iPhone Safari or speaker-listening verification is claimed. Temporary QA instrumentation was removed before publication; docs/8310-audio-check.jpg records its result. ## Names menu animation collision — 12 November 2026 Reproduced Home → right softkey Names showing Search with its lower options overwritten by the Messages icon. MenuAnimation recognised only Select/Exit footer pixels and the top-right numeric identifier. The native Names list shares both with root menu 1, so the captured root icon was composited over rows 21–38 of the contacts list. This was a presentation-layer collision, not a corrupt firmware contacts screen. Exclude native inverted list-selection rows from root icon detection. The list's uninterrupted 70-pixel selection border is distinct from the root icon layouts. Unrecognised/list frames pass through unchanged and reset the old animation queue. No shortcut fallback replaces Names; the original Search/Add name/Edit name menu remains usable. No audio, artwork, input timing, core or game changes. Validation: names-display-test.cjs loads the original WASM checkpoint and checks 24 Names menu positions while navigating down and up, exact unmodified frame passthrough, cancellation of an old Messages animation, and continued recognition of all twelve root menus. menu-animation-test.cjs passes its 25-pose, initial-hold, 100ms interval, text-immediacy, game isolation and hidden-page checks. Browser QA reproduces the original defect, then confirms clean Names, scrolling, Exit to branded Home and reopening. Screenshot: docs/8310-names-fixed.jpg. ## Menu and input audit — 12 November 2026 Ran 206 recorded baseline actions using the real WASM core and worker: 89 across all twelve root menus and SMS entry, plus 117 opening 39 submenu positions, backing out and returning Home. Setup/navigation presses are additional. Groups include Messages, Call register, Profiles, Settings, Games, Calculator, To-do, Calendar, Infrared, Radio, Extras and Services. This is a broad sweep, not exhaustive coverage of every nested branch/game. Captures were visually reviewed. The deterministic sweeps detect blank/stalled states; their timings are not real-device latency. Reusable harnesses: tools/menu-audit.cjs and tools/menu-depth-audit.cjs. Results: docs/menu-qa-results.json. Reproduced the SMS delay with real timers: an early cursor/footer redraw appeared almost immediately, but the first letter took about 665 ms. LCD frame_serial advances per 84-pixel page. The old worker interpreted a partial redraw as completion and slowed the CPU before the character appeared. SMS boosts now wait for actual body ink changes, excluding the nine-pixel caret, then a quiet instruction chunk. Space/case changes use header response; Options/End wait for the editor to leave. Recognition requires both the original pencil and Options footer, excluding the symbol chooser. Text taps use a 50,000-instruction pulse and 100,000-instruction spacing; formatting keys retain their standard pulse. Other menus and Snake retain established timing. Native firmware and WASM binary are unchanged. Final real-timer run: visible letters 23–33 ms; the full set including space and Clear peaked at 33 ms. Symbol entry, Back, Options and End also passed. Home digits 1–9 were correct at 200, 100 and 60 ms tap intervals; maximum measured response 76 ms. These are host measurements, not physical iPhone Safari latency. Browser visual checks are separate and do not establish those timing figures. Calendar time confirmation produced a blank screen for at least 60 virtual seconds and did not recover with Back/End. Infrared returned to altered standby whose native shortcuts went blank; Radio did not open. These three incomplete hardware-dependent root selections now show a clearly labelled unavailable-in-preview notice. This prevents broken paths; it does not implement Calendar, infrared or FM hardware. Back dismisses the notice to the retained original root menu; End returns Home. Exact root heading/footer fingerprints exclude animated icon pixels. Both presentation and worker-dispatch guards prevent queued navigation bypass. tools/hardware-menu-test.cjs checks all twelve roots, scope, worker dispatch, repeated keys, dismissal and Home return. Known remaining issue: fast repeated presses of one SMS key can commit separate letters rather than reliably cycle A/B/C. Direct-core experiments confirm native multi-tap exists, but the instruction-driven board clock expires it during accelerated redraw. Pulse/settling experiments did not solve this reliably. Further board-clock work is needed; fully authentic text composition is not claimed. Empty call logs and network/DSP-dependent operations remain incomplete. No real messages or calls can be sent. Regression checks cover real/virtual phone input, menu navigation, Names list passthrough, root animation timing, worker visibility/pause, hardware guards, SMS, original Snake cadence at all three paces, menu game entry, Back/End exits, splash timing, audio activation and the unchanged 2.8-second startup tone. Real-timer normal Snake averaged 128 ms per move without errors. Browser tests use the actual handset controls; physical iPhone hardware is not available here. Browser follow-up: replaced zero-delay nested timers with MessageChannel task scheduling where available, retaining the six-millisecond work budget and normal paced timers. Generation tickets cancel posted work on pause/reset; tools/worker-scheduler-test.cjs exercises that branch with a deterministic message-channel mock. The actual cloud browser completed all eight typed letters, case changes and symbols, showed the Calendar notice, and returned through Back and End to branded Home. Rapid input still queued in this cloud browser: the host benchmark improvement must not be presented as equivalent browser/iPhone timing or a complete end-to-end latency fix. Screenshot: docs/8310-menu-qa.jpg. ## Text burst queue optimisation — 12 November 2026, follow-up The worker held each text key until the preceding full redraw/boost completed. Allow a following numeric text key to enter the original firmware queue after the existing key-release gap, while the preceding text digit is still being processed. Only known SMS-editor digit sequences overlap. Navigation, Clear, formatting and game keys retain their ordering. Preserve the recognised editor context through partial redraws. No firmware, native timer, glyph or WASM changes. Actual-WASM tests compare 8-, 24- and 32-key bursts with the prior serialised path. Every character, case, remaining-character counter and line wrap matches, excluding only the blinking caret. Work falls from 11.05M to 3.32M, 32.86M to 6.56M, and 44.22M to 8.22M instructions respectively (70–81% less). Virtual-time completion is 51→14, 147→27 and 195→34 ms; these are simulated times. tools/text-burst-test.cjs reproduces the comparison, and docs/text-burst-results.json records it. A temporary browser comparison exercised the real original WASM worker before/after under the same browser, with eight digit events submitted together and completion detected only when the complete expected original framebuffer matched (caret excluded). Before runs: 181 and 207 ms. After runs: 53 and 45 ms. All eight letters were correct in all four runs. This measures browser worker-to-frame burst completion, not physical iPhone touch-to-paint latency or a universal 4x speedup. Screenshot: docs/8310-typing-comparison.jpg. The reusable comparison HTML is retained under tools; temporary baseline worker and expected-frame files were removed from dist before packaging. Actual handset controls were also checked: eight letters, Options, Back restoring the message, and End returning to branded Home. Regression checks passed phone digits, real SMS typing/Clear/case/symbols, message scheduler pause/reset, menu navigation, Names passthrough, menu Snake entry and red-key exits at all paces. An Options key queued directly after an eight-digit burst also reaches Options and returns to the editor correctly. Remaining limitation: queued simultaneous presses on the same numeric key now use the original multi-tap cycle (three queued 2 presses yield C), but normally spaced repeated presses can still commit separate letters. The instruction-driven firmware timeout remains uncalibrated; multi-tap is not fully fixed.