# Neural Engine / 009 — Lucid neural worlds Open **https://neural-flappy.vercel.app/world.html** for the new immersive research prototype. It combines a pretrained language director, image generator, and single-image 3D Gaussian reconstruction. Move through four saved worlds, generate an arbitrary environment, transform a scene, or hold a point and request a local edit. Return restores the preceding field and camera. The shortcut is to generate a persistent 3D memory, then render it cheaply between edits. This is a hybrid architecture: learned language, imagery and geometry; conventional projection, compositing and UI. Live generation uses the connected RTX 5080 via a temporary HTTPS tunnel and requires the desktop to remain running. Saved worlds are static and remain available without it. Four public HTTP tests took **2.92–3.13 seconds of server work**, or **4.31–4.56 seconds including polling and downloading the field** from this connection. Each saved mobile field is about **3.4 MB / 130k Gaussians**. Native GPU draws measured 0.19–0.31 ms at 1280x720 on the RTX 5080; these are not phone FPS measurements. 57 tests pass. Actual browser and phone interaction remain unverified because local browser automation is disabled. Movement is bounded around each reference view. Hidden surfaces, topology, complete physics, and continuously generated video are not solved. Full transforms can change scene structure. Explore onward is image-conditioned continuation, not a spatially registered expanding map. See [architecture, limitations, licenses and reproducibility](world/notes.txt) and [measured results](world/report.json). SHARP is licensed for research; this is a noncommercial scientific experiment. # Neural Engine / 008 — Generative Studio Open **https://neural-flappy.vercel.app/studio.html**. Load the creative model, then try `Build a brown table.`, `Make the table blue.`, `Move the table 4 units to the right.`, or `Build a purple chair next to a green tree.` The original weather experiment and games remain available at the main URL. The shortcut is **learn construction programs, not pixels**. SmolLM2-360M-Instruct generates a variable-length composition of solid parts and edits. A conventional compiler translates each accepted program into neural rendering and collision weights. The live game evaluates those neural graphs. There is no runtime lookup from object names to templates, and no neural image/video renderer needs to be trained. Shapes in the procedural training generator are supervision, not an inference-time object library. For a novel object, describe its parts and relationships. This was generated correctly for an invented object name: > Build a zorblatt: a purple core of size 4 by 4 by 4 on the ground. Put a cyan panel (6 x 1 x 2) touching the core on the left. Put a gold fin (2 x 6 x 1) touching the core on the above. The corresponding learned output is: ```text box("zorblatt.core",0,2,0,4,4,4,"purple") attach("zorblatt.panel","zorblatt.core","left",6,1,2,"cyan") attach("zorblatt.fin","zorblatt.core","above",2,6,1,"gold") ``` `attach` and `place` carry geometric relationships into the compiler, so the language model does not have to learn coordinate arithmetic. The same boxes drive pixels and collisions. Generated structures remain solid when the player walks and jumps around them. The initial arch/stairs/tree scene is explicitly labeled as an authored demo. ## What learned, and what did not The pretrained causal transformer has 361,821,120 base parameters. We trained 2,621,440 LoRA parameters in its query, value and output attention projections (rank 16, alpha 32, 32 layers). Two stages each use 8,000 synthetic scene-program examples: the first teaches 20 object families, assembly and edits; the second adds natural relation phrasing and chains of attached parts. There are 3,200 optimizer steps, taking 521.6 seconds of measured training/validation time on an RTX 5080, excluding model loading. The language base was pretrained by Hugging Face; it was not trained from scratch here. No images or videos were used for this adaptation. Training uses the exact dequantized values from the pinned upstream 4-bit model. Training on full-precision values and only quantizing afterward degraded the generated geometry in an earlier attempt. The final export keeps the base frozen and packed, adds 96 float16 LoRA branches, projects only the last hidden token into vocabulary logits, and computes the greedy token on the GPU. Measured results are in [studio/report.json](studio/report.json), with all tested prompts, generated programs and limitations. [studio/examples.png](studio/examples.png) includes successes and failures. - Before adaptation, 1/14 development probes produced a valid applicable program; afterward, 13/14 did. The unrelated joke request is rejected by the recipe parser. Valid syntax is not a visual-quality score. - Of 54 synthetic validation requests, **52 produced the exact expected scene including names**: 24/24 familiar families/edits, 18/20 generic assemblies with held-out names, and 10/10 relative edits. One extra zero-distance move makes program text differ while leaving the correct geometry. - **10/10 actual WebGPU creation and edit checks passed**, including table creation → recoloring → translation → copying → selective removal → clearing, a robot, chair/tree placement, a chained beacon and the invented sculpture. These are development checks, not an arbitrary-English benchmark. - Strict manual review of **eight open-ended unfamiliar-subject probes found none fully satisfied the request**. Castles, aircraft and similar subjects still need explicit part descriptions. The model can ignore details or generate malformed commands. This is a bounded compositional prototype, not unrestricted visual understanding. - 53 unit/interface tests pass. Newly compiled scene physics matches an independent simulator for 12,000 transitions. Complete neural frames match CPU inference on an actual offscreen GPU for **72 frames / 1,843,200 pixels**, with maximum difference one RGB level. - The quantized ONNX export matches a PyTorch prefill with logit RMSE 0.0124 across 49,152 logits; tokenizer IDs and top token match. Actual CPU and WebGPU sequence checks are also included. The scene language supports `box`, `attach`, `place`, `move`, `paint`, `scale`, `copy`, `remove` and `clear`. It is parsed as bounded data, never executed as JavaScript. Invalid programs fail atomically. Accepted programs can still be semantically wrong; Undo restores the previous scene. The world supports 48 boxes, quarter-unit coordinates, named or hex colors, four orthographic camera angles, and fixed walking/jumping/box-collision mechanics. It does not produce arbitrary meshes, textures, skeletal animation, photographs or new game rules. A taller edit currently scales the whole group; the model may misunderstand that distinction. ## Browser cost and optimization The opt-in download is 272,737,275 bytes of pinned upstream weights plus a 5,552,968-byte editor graph, then tokenizer/runtime assets. The browser caches base weights when storage permits. It needs WebGPU with `shader-f16`; on unsupported devices, the authored scene and manual recipe editor still work. Prompts are processed locally. Tokenizer and runtime files come from Hugging Face and jsDelivr; no generation API is used. The exported graph references tensor byte offsets inside the unchanged public ONNX file. This avoids hosting a second copy of the entire base. The KV cache stays on the GPU and only the selected token returns to JavaScript. The model and scene compiler each run in a worker, and no language model runs in the frame loop. The neural renderer uses state factoring, cached unchanged frames and adaptive resolution. Scene compilation occurs once per edit. Observed desktop WebGPU creation times were roughly 1.8–7.3 seconds; short edits took about 0.13–0.42 seconds. These are development-run measurements, not isolated phone benchmarks. The desktop's 48-part scene simulation and GPU draw timings are in the report. Browser layout, actual mobile compatibility, thermal behavior and mobile frame rates were **not directly tested**. Model download/cache/session construction may exceed a phone's memory budget. Shader creation can cause a brief pause when a new world is installed. ## Run, train or inspect the studio ```text npm ci npm run build:studio npm start npm test npm run test:studio-runtime npm run test:studio-webgpu npm run test:studio-gpu ``` Open `/studio.html`. The native CPU check uses Node's `--no-js-float16array` flag because the installed native ORT binding cannot accept Node 24's Float16Array cache buffers; the browser WebGPU path was tested separately through Dawn and does not need that flag. The WebGPU check uses `webgpu`/Dawn headless compute, not browser automation. GPU frame verification requires Python `moderngl`, `numpy` and Pillow; the script also recognizes the original local `artifacts/gpu-deps` install. To reproduce the language adaptation, install Python PyTorch with CUDA support, `transformers`, `peft`, `onnx`, `onnxruntime`, `safetensors`, `huggingface_hub` and `numpy`, then run `python scripts/studio/reproduce.py`. It downloads the pinned pretrained files, trains on the included first-stage data, generates second-stage data, continues training and exports/evaluates the adapter. Tested versions include PyTorch 2.11.0, Transformers 5.5.4, PEFT 0.19.1, ONNX 1.21.0 and ONNX Runtime 1.25.0. Hardware/library changes can alter training numerics. `npm run train:studio` starts a fresh one-stage experiment from the current generator; it is not the exact two-stage reproduction command. The source archive includes the editor graph, training recipes, first-stage data, reports and browser source. Large pretrained tensor files and PyTorch checkpoints are not bundled. For native runtime checks, run `scripts/studio/reproduce.py` or download the pinned base and use `scripts/studio/prepare-runtime.py`; browser inference fetches it automatically. Model and bundled dependency attribution is in [studio/NOTICE.txt](studio/NOTICE.txt) and [studio/MODEL-LICENSE.txt](studio/MODEL-LICENSE.txt). ## Previous version / 007 — Text to world Play **https://neural-flappy.vercel.app/?game=isles-text**. Type `snow`, `snow at night`, `warm sunset`, `neon with rain`, `light fog`, `no snow`, or `original world`. The interface applies accepted edits after 700 ms without typing, or immediately with Enter, the button, or an example chip. Unmentioned settings persist. Text inference runs locally; prompts are not sent to a server. This is an actual trained, bounded English controller and conditional neural renderer. It does not generate arbitrary objects, new mechanics, photographs, or executable code. Some reasonable paraphrases are rejected; short explicit instructions work best. Ordinary game restart keeps the environment; `original world` clears weather and restores the original palette without resetting gameplay. ## Architecture and training 1. A **20-dimensional word embedding → 48-unit GRU → five categorical heads** learns snow, rain, fog, palette and supported-request intent. Its 14,729 parameters train from scratch on 45,136 synthetic examples. A generic tokenizer, categorical decoder and confidence/vocabulary gate interpret the outputs; there is no runtime keyword-to-effect table. The exported packed FP32 model is **56,484 gzip bytes**. The GRU follows PyTorch's reset-gate convention, with both cuDNN and matrix TF32 disabled during training for export parity. 2. A **10→48→48→3 ReLU network**, with 3,027 trained parameters, maps scene RGB, six palette indicators and fog amount to RGB. It learns authored synthetic color responses, not photographic style. Held-out mean error falls from **128.68 to 1.93 RGB levels** on 8,192 samples after 4,500 Adam steps. 3. The existing neural simulation gains five recurrent values: snow, rain, fog, palette, and a 512-tick weather clock. Model outputs become control pulses; an `edit_only` neural gate holds every original game-state value during an edit. Movement, score, collision, camera and pilot rules remain exact. Weather changes are included in normal save/replay data. 4. The renderer's affine/ReLU graph includes **20 snowflakes, 12 rain streaks and five snow-covered surfaces**, with neural motion, camera projection and depth visibility. These geometry/motion circuits are hand-authored. The learned color network runs before the original HUD. The entire game frame is still neural RGB output; interface elements remain ordinary HTML. The appearance changes are immediate. There is no retraining, network request, shader rebuild or generated code per prompt. The same GPU shader handles every supported weather/palette combination. One-time shader compilation, state factoring, packed weights, cached frames and adaptive resolution reuse the existing runtime. The weather clock stops when snow/rain are both off. The 780 state-feature floats require 195 uniform vectors, leaving room within WebGL2's minimum fragment uniform budget. ## Results and limits | Check | Measured result | | --- | --- | | Synthetic language validation | 99.40% exact edit prediction on supported requests; 96.21% accepted; 99.84% of accepted requests correct; 0 of 249 unsupported requests accepted | | Development prompt checks | 30/30, including combinations, short negation, and unsupported requests | | Fresh audit after final training | 22/30 handled as intended: 12 supported requests accepted correctly, 10 out-of-scope/ambiguous requests rejected, 8 supported requests rejected; no wrong accepted edit in this small audit | | Language export | Maximum logit difference from PyTorch 0.000040 over 128 samples; identical acceptance across all 3,571 validation requests | | Color export | Maximum discrepancy 0.000046 RGB levels over 288 samples | | New GPU verification | 12 full frames, 442,368 pixels, maximum CPU/GPU discrepancy one RGB byte | | GPU cost at 192² | About 0.230 ms for the new renderer versus 0.0315 ms for the original scene on the same RTX 5080 | | Local text inference | 0.018 ms median / 0.035 ms p95 for short prompts in Node 24 on the workstation | | Downloaded model data | 119,679 compressed bytes total: language + simulation + renderer, excluding interface/runtime files | Synthetic validation shares vocabulary and grammar with training and was used during development. The 30 development prompts also informed iterations. The separate final audit was not used to retrain or change thresholds; it exposes limited generalization, including rejection of `a snowy night` despite accepting `snow at night`. The confidence gate is conservative, not a guarantee: the larger synthetic validation still contains five wrong accepted edits. Full prompts, predictions, curves, measurements and scope are in `text-world/report.json`. **48 passing Node tests** include 20,000 mixed original-versus-edited game transitions, pilot completion in exactly 248 gameplay ticks in all four camera views, replay, actual packed text loading, negation, live input, IME handling, unchanged state on rejection, and the earlier engine/experiment tests. The 12 new GPU frames add to the previous 49 verified frames. GPU times are offscreen draw measurements excluding compilation, transfers and browser composition; text times are Node measurements. Neither measures phone performance. Responsive CSS and DOM behavior are implemented; real-browser layout and phone touch/GPU behavior remain unverified. ```sh npm ci python -m pip install numpy torch Pillow moderngl npm run train:text npm test npm run build:site ``` Training supports CPU or CUDA; the verification script requires an OpenGL 3.3 context. `scripts/text-world/train.py` generates the data and trains both networks; `evaluate.mjs` packs and audits the language model; `build.mjs` composes the neural game and renderer; `verify.py` checks independent PyTorch and actual GPU outputs. The downloadable source archive includes the trained weights and required test data. Earlier games and all six studies remain available. ## Version 006 — Six experiments Explore all six studies at **https://neural-flappy.vercel.app/experiments.html**. The page pairs reference outputs with live exported neural inference, offers conventional-baseline comparisons, and links the measured results. The original games and earlier training variants remain available. | Study | Result | Conventional comparison | | --- | --- | --- | | Learned lighting | 2.01 RGB-level held-out MAE; about 14× faster than sampled lighting in the PyTorch GPU batch benchmark | A small trilinear lookup gets 1.30 MAE, uses fewer bytes, and draws faster on the same desktop GPU | | Renderer distillation | 5,139 trained parameters versus 17,976 original; about 4× cheaper GPU draw at 128² | 10.72 overall RGB error and 35.07 around the player; silhouettes and text are visibly degraded | | Learned material | 150-weight local membrane model; 0.00287 mean height RMSE across a 1,000-step rollout | One RK4 step is more accurate and about 18× faster in the actual JavaScript comparison | | Motion from demonstrations | Four fitted parameters; held-out position RMSE falls from 5.57 to 0.00187 world units | Finite-difference least squares gives 0.01059 RMSE on the same noisy observations | | Inverse level design | Neural surrogate proposes a 300-tick level; exact neural gameplay takes **301 ticks** | Searching the existing training examples already finds a 300-tick layout | | Texture compression | Nine material channels, 32.48 dB PSNR, 19,662 compressed FP32 weight bytes | 64² PNG images plus bilinear upsampling give 53.35 dB in 14,087 bytes | The evidence supports parameter fitting and bounded approximation, but **none of these rendering/physics substitutions beats the strongest simple baseline on both cost and quality**. Neural representation alone is not a speed advantage. These are synthetic studies of specific small problems, not a general trained game engine or a competitive general-purpose path tracer. ## What each experiment actually does 1. **Lighting:** A 3→48→48→48→3 ReLU MLP predicts the display RGB of a floor point given its position and a movable area light. The teacher integrates 16 direct samples and 12 colored-wall samples, each with four light samples. It includes box visibility, soft shadows and one diffuse bounce; the box footprint uses a fixed display color. Nine light positions train the model; eight interleaved positions are held out. The baseline stores 24×24×9 quantized RGB samples and interpolates them. In the viewer, the left output is a precomputed reference or baseline; the right is evaluated from neural weights. 2. **Distillation:** The actual hand-built Isles renderer supplies 202,752 training pixels and 34,816 held-out pixels at separate states along one pilot route. The camera, lighting, HUD state and collectibles are fixed; player X/Y/Z vary. The student has three 48-neuron hidden layers. Whole-frame error is accompanied by a moving-player crop check. A frozen original image gets only 0.38 mean RGB error because most of the frame is static; this baseline cannot follow the player, and demonstrates why the aggregate score is insufficient. This failed student is a separate lab view, not the game's default renderer. 3. **Material:** A 16×16 periodic linear spring membrane is advanced by a learned 5×5 neighborhood convolution. It sees height, velocity and force (75 inputs), and predicts next height/velocity. Least-squares training fits 150 coefficients on 12,288 patches; 4,096 patches and a separate 1,000-step impact sequence are held out. The reference takes 16 RK4 substeps. A single RK4 step has mean rollout RMSE 0.000466. PyTorch favors batched neural inference (0.052 ms versus 0.168 ms for one RK4 step), but the actual JavaScript implementation measures roughly 0.0525 ms neural, 0.00290 ms one RK4, and 0.0456 ms 16 RK4 substeps. Backend and implementation matter. The viewer uses live neural recurrence with recorded input impulses; colors show displacement. This is not nonlinear jelly, cloth contact or a fluid model. 4. **Motion:** Three 24-tick airborne position demonstrations, with Gaussian observation noise standard deviation 0.02, fit gravity, jump speed, acceleration and drag. Three new action sequences test the result. Learned values are approximately [0.31994, 4.49952, 0.30022, 0.84982], for targets [0.32, 4.5, 0.3, 0.85]. Coefficients are exported to an affine/ReLU recurrent cell. The comparison uses ordinary least squares on vertical positions and horizontal finite differences. A conventional nonlinear optimizer using the same full-trajectory objective could achieve the same fit; this is not a capability exclusive to neural engines. Contact and collision are excluded. 5. **Level design:** 320 exact rollouts vary platform distance scale in [0.8,1.4] and height scale in [0.8,1.7], with coordinates rounded to the game's valid lattice. A 2→32→32→1 network learns completion time from 256 layouts, with 64 held out (1.20-tick MAE). Gradient optimization of its two inputs proposes a layout for 300 ticks. Exact evaluation gives 301 ticks and all four crystals in every camera orientation. The pilot and physics stay fixed. A scan of the training layouts hits 300 exactly and avoids the additional training/inversion cost. The proposed world is nevertheless playable at **https://neural-flappy.vercel.app/?game=isles-designed**. 6. **Textures:** One coordinate MLP learns nine channels of an authored synthetic material: color, encoded normals, roughness, metal and height. It trains on 49,152 random coordinates and is evaluated on a separate 256² grid. Its 5,289 coefficients occupy 19,662 bytes when compressed as shared FP32 weights, versus 113,857 bytes for the full PNG set. The stronger 64² PNG baseline occupies 14,087 bytes with far better reconstruction. The web prototype exports separate three-channel graphs for inspection (60,791 packed bytes for all three views), so the shared-weight figure is an isolated representation comparison, not the total viewer download size. The preview downsamples the reference PNG; reported baseline metrics sample the analytic source directly at 64². ## Validation and reproduction - **41 passing Node tests** cover the previous games, all new exports, live comparison controls, baseline switching, replay, resource disposal, and the designed level in all four views. - PyTorch and the exported JavaScript fields agree within **0.000162 RGB levels** across 640 samples. The motion export differs by at most 0.00000191 world units; membrane checkpoints by 0.000000075 height units. - **49 actual offscreen GPU frames / 2,467,456 pixels**: 30 game frames plus 19 experiment frames. CPU/GPU output differs by at most one RGB byte. - Experiment GPU timings use the same RTX 5080, 128² resolution and timing procedure for the original renderer, student networks and lighting lookup. They exclude compilation, upload, readback and browser composition. They are **not phone performance measurements**. - DOM tests verify control wiring, and exported PNGs are visually inspected. Real-browser responsive layout and phone touch/GPU performance remain unverified. - Raw measurements, training curves, limits and runtime timings: `experiments/report.json`. Repeated hardware/library runs may vary despite fixed seeds. ```sh npm ci python -m pip install numpy torch Pillow moderngl npm run experiments npm test npm run test:engine-gpu npm run build:site ``` CUDA is optional for training; the GPU verification step requires an OpenGL 3.3 context. The archive includes all training/export/verification scripts, compact trained models, reference images, reports and test fixtures. Larger generated datasets are rebuilt by `scripts/experiments/prepare.mjs`. The game still evaluates only neural simulation/rendering models. Conventional teachers and solvers run during offline experiments; reference images and trajectory charts in the comparison page are explicitly labeled analysis views. ## Earlier Training Lab (version 005) A reusable neural game engine with a playable **3D** cartridge and trained variants, hosted at **https://neural-flappy.vercel.app/?game=isles-sunset**. Neural Isles lets you walk around a solid platform arena, jump to collect four crystals, and rotate the view. Flappy and Pong remain available. All cartridges use the same inference runtime; gameplay transitions and every game-frame RGB pixel come from neural weights. ## Actual training experiments The Training Lab compares the original world, an untrained appearance head, two trained color heads, and fitted physics. Appearance switches preserve the current world and pause state; changing physics starts a compatible new world. Training happened offline in PyTorch 2.11.0; the phone downloads small exported weights and performs inference locally. | Experiment | Held-out result | What was learned | | --- | --- | --- | | Sunset appearance | Mean color error **117.35 → 1.00** RGB levels | 387 parameters in a 3→16→16→3 ReLU color head | | Glacier appearance | Mean color error **122.45 → 1.56** RGB levels | A second color head of the same size | | Gravity and jump | **1.9999992 / 25.999994**, targets 2 / 26 | Two tied physical parameters | | Unrestricted simulator | Normalized prediction MSE fell about **49%**, but **21.5%** of transitions had invalid Boolean flags | All existing sparse coefficients and biases were allowed to change | These are deliberately small experiments using **synthetic targets**. The two appearance networks learn authored color-response curves from 8,192 sampled colors and are evaluated on 4,096 independently sampled colors. They do not learn geometry, artistic style from photographs, or new worlds. Each uses Adam for 1,500 steps; the existing 2,896-neuron geometry/rendering graph stays frozen. The exported color head and clamps add 41 neurons and run inside the same affine/ReLU pixel network. “Before training” uses the saved initial weights shared by the two appearance runs. The physics experiment fits gravity and jump speed to 18 synthetic airborne position observations, using the differentiable trajectory formula `y(t) = t*jump - t*(t-1)*gravity/2`. Six held-out fractional times have **0.00000474 world-unit RMSE**. This is two-parameter system identification, not backpropagation through the whole recurrent simulator. The fitted values are rounded to integers and compiled into its neural coefficients, preserving the state lattice and exact Boolean/contact circuits. The same frozen neural pilot then finishes the supplied level in **193 ticks versus 248**, from the same start in each camera view. Faster completion is a side effect of changed physics, not the optimization objective or evidence of a better policy. The unrestricted stress test trains the actual sparse simulator on 4,096 next-state examples from the changed-physics target, with 2,048 held-out examples from separate episodes. Even at Adam learning rate 0.000001 over 160 steps, lower one-step MSE does not preserve discrete rule correctness. At a Boolean tolerance of 0.0001, **21.5%** of held-out PyTorch transitions and **16.2%** of exported JavaScript transitions contain invalid bits. We publish that checkpoint in the source archive for inspection, but provide no playable cartridge for it. No long-horizon reliability is claimed. Across 256 cross-runtime samples the original integer graph matches exactly, while the unrestricted checkpoint differs by up to **0.04445 state units** due to floating-point accumulation order. The useful result is a modular training path: keep exact rule circuits fixed, fit constrained physical parameters, and train small continuous appearance networks. Full unconstrained fine-tuning needs stronger constraints and recurrent validation before it is suitable for this engine. ### Training validation and overhead - **35 passing tests**, including 20,000 independent reference-physics steps for the fitted simulator, exact replay for every exported variant, frozen geometry checks, and DOM comparison controls. - The trained appearance exports match PyTorch within **0.000046 RGB levels** over 1,024 sampled pixels. - Actual offscreen GPU inference and presentation match CPU output within **one RGB byte** across **27 frames / 1,951,680 pixels**. No pixel exceeds that tolerance. - At 240×240 on the development RTX 5080, original GPU inference is about **0.0858 ms** and trained appearances about **0.0887 ms**, roughly **3.4%** additional draw time. This excludes browser overhead and is not a phone FPS measurement. - Full metrics and recorded learning curves: [training-report.json](https://neural-flappy.vercel.app/training-report.json). All runs use seed 713; numerical results may vary across hardware and library versions. To reproduce the experiments: ```sh npm ci python -m pip install numpy torch npm run build npm run train npm test npm run build:site ``` CUDA is optional; CPU training is supported. `npm run train` generates synthetic data, trains the models, exports weights, verifies PyTorch/JavaScript agreement, and rebuilds the compressed cartridges. No optimizer or Python runtime is shipped into the game. The source archive includes the training scripts, fitted heads, report and unrestricted research checkpoint; larger generated datasets are reproducible with `scripts/training/prepare.mjs`. ## 3D engine The camera is **orthographic**, with four selectable quarter-turn views. Player state has independent X, Y and Z coordinates. Geometry occupies 3D volume: objects occlude each other according to ray/surface depth, and moving above a platform changes collision and visibility. This version supports bounded convex scenes and axis-aligned player/solid collision; it does not implement perspective free-look, arbitrary mesh import or a general rigid-body solver. - **Mobile:** hold the directional pad to move; tap Jump or the game frame to jump; use ↶ / ↷ to rotate the camera. - **Keyboard:** WASD/arrows move relative to the current view; Space jumps; Q/E rotate; R resets; P pauses. - **Neural pilot:** completes the level using a policy encoded in the transition weights. Record/replay, manual stepping, quality selection and inspection work in 3D too. - **3D authoring:** `NeuralPhysics3D` compiles movement, gravity, wall sliding, landing and ceiling collision into a recurrent neural cell. `NeuralScene3D` compiles boxes and convex plane-defined solids into a coordinate-conditioned RGB network. Neither authoring class runs in the browser. The scene contains 28 convex solids, including a ground grid, four platforms, faceted crystals and the player. The recurrent model has **393 ReLU neurons / 2,015 parameters**, with 16 state values and 9 binary controls. The full-frame renderer has **2,896 ReLU neurons / 17,976 parameters**: 204 state-only nodes are evaluated once per frame; 2,692 coordinate-dependent nodes run per pixel. Only 184 float32 features cross into GPU uniforms. The two compressed models total **29,545 bytes**, excluding runtime and manifest. For a pixel, the neural camera constructs an orthographic ray. In the camera frame, with screen offsets `u=(pixel_x-240)/2`, `v=(pixel_y-264)/2`: ```text ray(t) = (u/2 + v, 0, -u/2 + v) + t(1,1,1) ``` Each convex face is a fixed affine plane `n·p <= d`. Substituting the ray produces lower/upper intervals for `t`. The plane normals and ray direction are constants for each compiled camera frame, so their reciprocal coefficients are fixed weights. Neural min/max intersects the intervals; ReLU threshold circuits test occupancy; neural selectors choose the nearest visible surface and its facet color. Camera rotation, dynamic body centers, depth, glyphs and final RGB are all inside the graph. No conventional ray caster, depth buffer, object renderer or sprite lookup runs alongside the model. The GPU uses one full-screen triangle only to schedule network evaluations. The supplied geometry uses dyadic coordinates and plane coefficients so thresholds are exact on its 1/64 ray-margin lattice. The collision simulation uses quarter-unit integer positions. Bounds are explicit: player X/Z stay in [-200,200] quarter-units, gravity clamps vertical speed at -24 quarter-units/tick, and the scene compiler assumes candidate ray depths within [-512,512]. New geometry must respect these bounds and float32-representable coefficients or adjust the construction. `convex()` planes are camera-local; `box()` rotates extents for each view, while the crystal shape is quarter-turn symmetric. Example authoring (build time): ```js import { ReLUBuilder } from './scripts/lib/relu-builder.mjs'; import { NeuralScene3D } from './scripts/lib/neural-scene3d.mjs'; const b = new ReLUBuilder(['x', 'y', 'camera', 'player_x', 'player_y', 'player_z']); const scene = new NeuralScene3D(b, { camera: b.input('camera') }); scene.box({ min: [-20, 0, -20], max: [20, 8, 20], color: [120, 180, 160] }); scene.box({ center: ['player_x', 'player_y', 'player_z'].map(name => b.input(name)), half: [2, 5, 2], color: [240, 240, 220], }); const model = b.finish(scene.outputs(), { format: 'sparse-relu-field-v1', coordinateInputs: [0, 1], logicalSize: [480, 640], }); ``` See `scripts/build-isles.mjs` and `scripts/levels/isles.mjs` for a complete cartridge. Run `npm run build:3d` to regenerate it. The runtime needs no 3D-specific rendering code or new inference operators: the model still contains only affine connections, ReLU activations and affine readouts. ## 3D validation and performance - **35 passing tests** across all cartridges and training exports. Original Isles matches an independent ordinary-code physics oracle for 50,000 mixed-input ticks and 20,000 randomized bounded states, including camera changes and simultaneous controls. - Wall sliding, movement above obstacles, exact platform landing, jumping, ceiling contact, completion/reset and all four pilot views are checked directly. - A separate analytical ray/box caster matches the neural scene at 20,000 sampled pixels, with moving solids, all camera views and explicit front/behind occlusion checks. - All three cartridges reproduce 10,000-tick recordings exactly. DOM tests exercise game switching, 3D input, jump, camera turns and completion. - Actual offscreen GPU inference and cached texture presentation are compared with CPU output across **27 frames / 1,951,680 pixels**, including seven original 3D scenes and twelve training-variant scenes. Maximum discrepancy is **one RGB byte**, consistent with output quantization. No pixel exceeds that tolerance. - On the development RTX 5080, the 3D neural draw takes a median **0.086 ms at 240×240**, or **0.104 ms at 372×240**. This excludes shader compilation, browser composition, readback and UI overhead; it is not a mobile FPS measurement. - Sharing bounded depth/color intermediates avoids repeated affine expansion, cutting nonzero renderer connections from 24,638 to 15,077. During optimization, a seven-trial warm CPU benchmark at 120×160 improved from 253 ms to 111 ms. The final square viewport measures **88.12 ms at 120×120**; 100,000 simulation ticks take **68.06 ms**, on Node 24.15 / Windows x64. The neural CPU fallback remains much slower than the GPU and adapts down in resolution. Reproduce with `npm test`, `npm run benchmark:3d`, and `npm run test:engine-gpu`. Raw timings are at `/benchmarks/3d.json` and `/benchmarks/gpu.json`. Real phone layout, touch behavior and browser-specific performance have not been directly verified; DOM interaction tests and offscreen GPU checks cover different parts of the system. ## Shared engine features and earlier 2D optimization - Model cartridges separate simulation weights, rendering weights, and ordinary UI/input metadata. No game-specific simulation or scene renderer is dispatched by the engine. - Fixed 60 Hz simulation, independent rendering, bounded catch-up (at most 8 ticks per animation callback), pause, speed and single-step. Hidden tabs do not accumulate simulation debt. - Deterministic save/restore and input recording/replay. Saves are tied to the cartridge ID and model revision. Replays end paused and are bounded in memory; the UI records up to 18,000 ticks (five simulated minutes). Replays are session-local. - Generic numeric kernel compilation in small chunks, reusable typed state/input buffers, and state-only partial evaluation before parallel pixel inference. - WebGL2 GPU inference into a cached RGBA texture; unchanged states require only a presentation pass. Rendering requests up to 60 fps. Quality uses measured GPU time where supported, conservative frame cadence otherwise, hysteresis, and a 200,000-pixel budget. Explicit Battery saver / Sharp settings are available. - Worker CPU fallback evaluates the same weights, reuses transferred pixel buffers, and lowers resolution when inference exceeds budget. CPU throughput may still be low on slower devices. - Explicit disposal for shaders, programs, textures, framebuffers, queries, workers and context listeners; context restoration recreates GPU resources. - Compressed loading chooses binary sparse FP32 or gzip JSON according to actual payload size. Plain JSON fallback is retained. Flappy's two model payloads total **21,310 bytes**; Pong's total **17,541 bytes**, excluding manifests/runtime and transport overhead. - Live weight/activation inspection and separate CPU submission / GPU execution timing. A CPU submission measurement is never labeled GPU completion time. Measured on this Windows x64 development computer with Node 24.15, using unchanged Flappy weights, seven warm trials and median timings: | Workload | Previous runtime | Engine 003 | Speedup | | --- | ---: | ---: | ---: | | Neural CPU frame, 120×160 pixels | 277.59 ms | 64.18 ms | **4.33×** | | 100,000 neural simulation ticks | 125.94 ms | 44.24 ms | **2.85×** | These are isolated kernel benchmarks, not end-to-end FPS or mobile measurements. Output bytes and final states are checked for exact equality. Reproduce with `npm run benchmark`; the previous inference implementation is preserved in `scripts/benchmarks/baseline/`. Raw results are in `artifacts/engine-benchmark.json` and hosted at `/benchmarks/cpu.json`. Actual offscreen GPU inference **and cached texture presentation** match CPU output exactly across eight Flappy/Pong scenes: **698,880 pixels**, including ready, playing, debug/pause, wide-aspect, and game-over frames. The NVIDIA RTX 5080 measured 0.028–0.050 ms median neural draw time at the tested 240×320 / 372×320 resolutions; this excludes compilation, browser overhead, composition and readback. It is not a phone performance claim. Raw GPU results are at `/benchmarks/gpu.json`. Run `npm run test:engine-gpu` with NumPy, Pillow and moderngl installed. Pong's network has 115 simulation neurons and 1,881 renderer neurons. The player uses the holdable ↑/↓ touch buttons or arrow keys; tap/Space serves. First to nine wins. Both the rival and optional player pilot are neural. Its rules match an independent oracle for 50,000 mixed-input ticks and 20,000 random bounded states. Both 2D cartridges reproduce 10,000-tick recordings exactly. Fixed-step tests compare 60 Hz and 144 Hz display schedules. ## Use the engine ```js import { NeuralEngine, loadCartridge } from './src/engine/engine.js'; const cartridge = await loadCartridge('./cartridges/flappy.json'); const canvas = document.querySelector('canvas'); const engine = new NeuralEngine(cartridge, { canvas, rendererOptions: { quality: 'auto', targetFps: 60, maxPixels: 200000 }, }); engine.resize(480, 640); canvas.addEventListener('pointerdown', () => engine.pulse('flap')); function frame(time) { engine.advance(time); engine.render(time); requestAnimationFrame(frame); } requestAnimationFrame(frame); // The same engine also runs headlessly by omitting canvas. const saved = engine.save(); engine.startRecording(); engine.setControl('autopilot', 1); engine.step(600); const replay = engine.stopRecording(); engine.playReplay(replay); // Later: engine.restore(saved); engine.dispose(); ``` Supported controls are binary and named by the cartridge. `snapshot()` returns a reused view; copy it to retain history. `save()` returns a detached serializable snapshot. `step()` runs explicit ticks even when paused. `advance()` honors pause and limits catch-up work. `setSpeed()` accepts (0,4]. `info()` exposes simulation, rendering and dropped-tick metrics. Recordings store input bits and the starting state; game logic is never recorded as executable callbacks. To author another game: 1. Use `scripts/lib/relu-builder.mjs` to create a sparse transition cell. Inputs must be state names in order, followed by control names; output names/order must match the state. Encode reset as a control. Keep state bounds explicit so threshold and selector circuits remain exact. 2. Build an RGB field with inputs `[x,y,...stateNames,'debug','paused']`. `scripts/lib/neural-painter.mjs` supplies authoring-only shape, text, digit and compositing helpers. They compile to weights and are never shipped as runtime rendering code. 3. Add a cartridge entry to `scripts/build-cartridges.mjs`. Its manifest supplies asset locations, revision, input labels and inspector mappings. The current demo UI expects `alive`, `started`, `score`, and an `autopilot` control; the engine itself binds arbitrary state names and renderer inputs. 4. Run `npm run build`, add an independent behavioral oracle, and run the tests. No training is required. The example build scripts show both simulation and image construction. Model compilation uses `new Function` on validated numeric indices/coefficients. A deployment that enforces a strict CSP must allow this numeric JIT or provide an alternate interpreter. WebGL2 shader complexity and supported uniform budgets vary across devices; the CPU backend remains neural. Audio, a scene editor, networking, unbounded worlds and learned game generation are outside this version's implemented scope. **Every game-frame pixel and every game rule comes from hand-weighted ReLU networks.** The engine is a recurrent transition network; the renderer is a state-conditioned RGB field. Gravity, flapping, collisions, pipe movement and recycling, procedural gaps, scoring, best score, death, restart, and the optional autopilot are all computed by the model. Each cartridge supplies two weight files to a shared generic engine. There is no conventional scene renderer, game simulator, sprite atlas, image texture, training, LLM, API key, or inference service. The surrounding controls, inspector, and page layout remain ordinary HTML/CSS. ## Original Flappy cartridge Public mobile version: **https://neural-flappy.vercel.app**. ```sh npm start ``` Open **http://localhost:5173**. The checked-in weight files are ready to use; playing requires no package installation. Node 24.15 is used for development; the test dependencies also support Node 22.22.2 and Node 26+. - **Space / ↑ / tap:** flap. After death, the same input resets the network; the next input starts a new flight. - **R:** restart. Session best is retained by the network. - **P:** pause or resume inference. - **1 tick:** pause and run one forward pass. Flap while paused to advance one tick with flap input. - **Neural pilot:** restart and let the hand-weighted policy fly. - **Inspect:** pause and switch between the game engine and pixel renderer to view actual coefficients, biases, and activations. Renderer activations are sampled at pixel (240, 320). - **Collision geometry:** display the precise rectangular hitboxes. The decorative beak and feathers extend outside the hitbox. The debug outlines themselves are neural RGB outputs. The interface includes a live activation map, state values, speed controls, and downloadable weights. Fonts have system fallbacks; game-frame glyphs are neural weights. All gameplay and rendering inference runs locally on the viewing device. ## Why this architecture Use a **sparse, skip-connected ReLU transition network with recurrent state feedback**: ```text 14 state values + 3 control bits ↓ 183 hand-weighted ReLU neurons, 18 sequential ReLU stages ↓ 14 affine readouts → feed state back into the next tick ↓ State + (x, y) + debug/pause bits → ReLU pixel network → RGB ``` This is an explicitly constructed neural circuit. Its behavior comes from its weights, connectivity, and ReLU activations. It does not learn or generalize the game rules. ReLU is useful here because the discrete game's arithmetic and decisions have exact piecewise-linear implementations. Recurrence supplies persistent game state. A transformer would introduce unnecessary attention and context management; sigmoid/tanh gating would complicate exact Boolean decisions. This design is small, inspectable, and deterministic. **Game-engine size:** 183 hidden neurons, 869 nonzero connection weights, and 197 bias slots: **1,066 scalar parameters**. Bias slots include zeros. The 18-stage count excludes the affine readout. Optional diagnostic probes are excluded from the core parameter count. ONNX uses zero-padded dense matrices for portability, so its storage count is larger. ReLU's piecewise-linear structure is well established; see [Rolnick & Kording, ICML 2020](https://proceedings.mlr.press/v119/rolnick20a.html). The formulas and game construction below are implemented and tested directly in this repository. ## How the weights encode rules Let `R(x) = max(0, x)`. ### Integer decisions ```text GE(x) = R(x + 1) − R(x) ``` For **integer** x, this is exactly 1 when x ≥ 0 and 0 when x < 0. A pair of ordinary ReLUs therefore implements an exact threshold on the game's integer state lattice. Between integers the function is continuous; it is not a discontinuous comparator on arbitrary real inputs. ### Logic and selection For Boolean values: ```text AND(a, b) = R(a + b − 1) OR(a, b) = a + b − R(a + b − 1) NOT(a) = 1 − a ``` For a Boolean selector b and bounded `|x| ≤ M`, use: ```text G(x, b) = R(x − M(1 − b)) − R(−x − M(1 − b)) SELECT(b, yes, no) = no + G(yes − no, b) ``` Flappy uses `M = 32768`; Pong uses `M = 4096`. This performs conditional state updates with fixed affine weights and ReLUs, without runtime multiplication of two variable signals or game-specific branching. The authoring compiler expands these formulas into coefficients. ### Physics Vertical coordinates and velocity use **1/16-pixel integer units**. At a fixed 60 Hz: ```text v_candidate = SELECT(flap, −104, MIN(v + 6, 144)) y_candidate = y + v_candidate ``` `MIN(a,b) = a − R(a−b)`. Ground clamping, collision comparisons, and alive/dead state selection use the same primitives. Every resulting recurrent state remains integral. The implementation uses Float32Array storage; ONNX Runtime independently verifies float32 inference. ### Pipes, score, and memory Three pipes move 3 pixels per tick, stay 240 pixels apart, and recycle after their right edge leaves the field. Their 178-pixel gaps come from a small neural pseudo-random generator: ```text z_next = (5z + 1) mod 256 ``` Modulo is encoded as four threshold circuits and fixed subtractions. There is no runtime `%` operator in neural inference. The seed is 73, so restarts replay a deterministic obstacle sequence. The generator has a 256-update period; sampled pipe gaps repeat sooner. This is a compact procedural sequence, not unpredictable randomness. A score point comes from detecting a pipe's right-edge crossing, provided that tick has no collision. Scores saturate at 9,999 to preserve the bounded construction. Best score is computed with neural max and survives resets within the session. Death freezes the world. Initial/reset state is selected by weights, including the first inference from an all-zero state. The optional pilot selects the nearest pipe that still overlaps or lies ahead and flaps when the bird is at least 22 pixels below that gap's center. Both target selection and action selection are in the neural graph. ## Model / wrapper boundary | In the network | In the wrapper | | --- | --- | | Gravity, velocity, flaps, position | Keyboard/pointer events → input bits | | Pipe movement, recycling, gap sequence | Fixed-step clock, pause, speed, manual stepping | | Collision, alive/dead, frozen state | Generic weighted-sum/ReLU inference | | Score, session best, reset/initialization | Feedback of the model's state vector | | Optional autopilot | Inspector and surrounding HTML interface | | Every game pixel: scenery, pipes, bird, score, status cards, debug outlines | Coordinate-grid sampling, generic GPU inference, RGB presentation | The renderer is a second feed-forward ReLU network. The wrapper has no bird/pipe/ground drawing routines and no game-frame DOM overlays. A full-screen GPU triangle schedules parallel neural evaluations; its shader is generated mechanically from numeric weights. The CPU fallback uses the same network and presents its result with `putImageData`. The conventional simulator in `tests/model.test.mjs` is an independent test oracle and is not imported by the application. The `sparse-relu-rnn-v1` format contains indexed affine connections, ReLU nodes, and affine outputs. Hidden nodes may connect to the original input and any earlier node. It is an acyclic transition cell with external recurrent feedback, not an LSTM or a dense one-layer Elman RNN. Inputs: 14 state entries followed by `[flap, reset, autopilot]`. All controls must be 0 or 1. Outputs use this state order: | Index | State | Units | | --- | --- | --- | | 0 | bird_y | integer sixteenths of a pixel | | 1 | velocity | integer sixteenths of a pixel per tick | | 2–3 | alive, started | bits | | 4–5 | score, best | integers, 0…9999 | | 6 | random | integer, 0…255 | | 7 | phase | scrolling phase, 0…239 pixels | | 8–13 | pipe_0_x, pipe_0_gap, pipe_1_x, pipe_1_gap, pipe_2_x, pipe_2_gap | integer pixels | Exactness is scoped to this game's valid bounded integer states and Boolean controls. It is not claimed for arbitrary real vectors, corrupted state, or endlessly growing scores. Pipe collision is axis-aligned box contact, including touching boundaries. Best score is session-local and resets when the page reloads. ## Standard ONNX model `model/flappy.onnx` is a standalone standard ONNX transition cell. Its only operators are **MatMul, Add, Relu, and Concat**. There are no custom operators, `If`, `Where`, `Loop`, threshold activations, or embedded game-code callbacks. Input `state_and_controls` is float32 with shape `[batch, 17]`; output `next_state` is `[batch, 14]`. Feed output back into the first 14 slots. Initialize with zeros and one reset pulse. A batched API allows many independent worlds to run together. ```python import numpy as np import onnxruntime as ort session = ort.InferenceSession("model/flappy.onnx") x = np.zeros((1, 17), dtype=np.float32) x[0, 15] = 1 # reset input state = session.run(None, {"state_and_controls": x})[0] for tick in range(600): x[:, :14] = state x[:, 14:] = [0, 0, 1] # human flap=0, reset=0, neural pilot=1 state = session.run(None, {"state_and_controls": x})[0] print("score:", state[0, 4]) ``` ## Rebuild and verify ```sh npm ci npm run build npm test # Optional: only needed to re-export or test the ONNX artifact python -m pip install numpy onnx onnxruntime npm run export:onnx ``` `npm run build` regenerates the hand-authored base weights deterministically and repackages saved training exports. Use `npm run train` to retrain the experimental variants. After changing Flappy weights, also re-export ONNX to update that artifact. Validation completed: - 35 passing Node tests, including independent conventional simulators, replay, lifecycle, codec, fixed timestep, quality, renderer integration and training exports. - 40,000 sequential mixed-input steps and 20,000 random bounded states match exactly. - All 256 pseudo-random seed transitions; collision contact and one-subpixel clearance; score crossing, saturation, freezing, initialization, and reset. - 100,000-tick neural autopilot run, alive throughout and over 1,000 pipes cleared. - DOM integration tests for loading, play/death/restart, keyboard input, pause, step, speed, mode switching, best-score retention, and the actual weight table. The WebGL API is stubbed in the DOM tests; real offscreen GPU inference is tested separately. - ONNX checker passes; ONNX Runtime matches 10,000 JavaScript transitions (140,000 state outputs) exactly, including 4,000 randomized bounded states. - A separate 10,000-tick recurrent ONNX rollout stays alive and scores 124. **Verification limitation:** real-browser visual and interaction verification could not be completed. Direct browser automation was disabled, and the native Chrome UI checker stopped because it could not reliably determine the current browser URL. Real neural frame pixels are verified by an independent offscreen OpenGL test and visually inspected from exported images. The DOM tests do not validate responsive browser layout or real phone touch behavior. Mobile GPU performance remains device-dependent. ## Files - `scripts/build-model.mjs` — hand-weight compiler; contains the mathematical construction. - `model/flappy.weights.json` — executable sparse neural model used by the browser. - `model/flappy.onnx` — portable standard neural model. - `src/network.js` — generic neural evaluator, independent of game semantics. - `src/app.js` — controls, clock, and live inspector; no scene drawing. - `tests/model.test.mjs` — independent reference simulation and model tests. - `tests/interface.test.mjs` — DOM integration test. - `scripts/export-onnx.py` — ONNX export and cross-runtime equivalence checks. - `scripts/serve.mjs` — local static server, bound to loopback only. ## Entire-frame neural renderer (version 002) The renderer is a **conditional implicit neural representation**: ```text RGB(x, y) = F_theta(x, y, game_state, debug, paused) ``` Its 18 scalar inputs are `[x, y, ...14 game state values, debug, paused]`. It returns three float32 values in the range 0..255. Sampling that function across the coordinate grid produces the complete frame. This includes the sky, clouds, hills, moving pipes, bird, ground, score, best score, ready/game-over cards, pause symbol, and collision outlines. The coordinate-to-signal architecture is related to implicit neural representations such as [Sitzmann et al., NeurIPS 2020](https://www.computationalimaging.org/publications/siren/). This implementation uses **hand-set ReLU weights**, not their trained sinusoidal SIREN model. Flat colors and polygonal pixel art suit exact piecewise-linear construction. **Renderer size:** 2,069 ReLU neurons, 16,689 scalar parameters. Of these neurons, 352 depend only on state and run once per frame; 1,717 depend on pixel coordinates. Only 96 scalar values cross that dependency boundary, packed into 24 `vec4` GPU uniforms. This factorization is partial evaluation of the same network, not a different rendering algorithm. ### Encoding images as weights An axis-aligned rectangle is an intersection of four affine half-planes. Its signed interior margin is a neural minimum of those four values. A pair of ReLUs turns that margin into an occupancy mask on the sixteenth-pixel lattice. Octagonal bird/cloud shapes add diagonal half-planes. Hand-set ReLU linear splines form the hills and grass. Text glyphs and seven-segment digits are compiled into the network at build time. Score decomposition and digit selection are neural arithmetic, evaluated once per frame. No runtime glyph table, texture lookup, conventional text draw, or sprite renderer is present. Neural visibility masks encode painter's order. Processing foreground to background: ```text visible_i = ReLU(mask_i - covered) covered = covered + visible_i RGB = sky_RGB + sum(visible_i * (color_i - sky_RGB)) ``` Colors are constants, so that final sum is an ordinary affine readout. The mask weights partition the interval 0..1. This also defines continuous transitions between lattice points; it is not a general differentiable alpha-compositing renderer. ### GPU and fallback `src/neural-field.js` validates the graph and emits straight-line GLSL consisting of affine expressions and `max(0, x)`. The shader contains no scene-specific branches, geometry helpers, texture sampling, or image inputs. WebGL2 evaluates the network once per output pixel. Output resolution is roughly half the logical coordinate resolution (240×320 for a 480×640 view, with the full visible canvas covered at other aspect ratios). Presentation scales those pixels with a pixel-art style. Rendering now targets up to 60 frames/second independently of the 60 Hz neural game clock (version 003). Identical states reuse a cached GPU framebuffer and a cheap presentation pass. If WebGL2 is unavailable or shader setup fails, the same network runs at lower resolution in a Web Worker where available. The fallback is slower and visibly coarser; the inspector reports the actual backend and resolution. No conventional renderer is used as a fallback. The game frame is completely neural. Browser scheduling, coordinate sampling, state feedback, byte quantization, GPU submission, and pixel presentation are wrapper operations. Page controls and the live inspector are deliberately outside the neural game frame. ### Renderer verification and portability - The factored evaluator exactly matches an independent, unfactored network interpreter at 800 conditioned pixels. - All ten score digits are checked at all four display positions. - Ready, flight, score/debug/pause, and game-over frames were generated by both the JavaScript evaluator and an offscreen NVIDIA GPU: **307,200 pixels / 921,600 RGB channels match byte-for-byte** across four 240×320 frames. - Those tests caught and fixed a coordinate-grid rounding discrepancy before deployment. - `model/renderer.onnx` is an optional dense portability export using only **MatMul, Add, Relu, Concat**. ONNX Runtime matches 512 conditioned pixel samples (1,536 RGB channels) exactly. The 7.1 MB dense artifact is local; the web app loads the compact sparse JSON instead. - Offscreen GPU tests validate actual shader execution and frame pixels, but do not substitute for testing a particular mobile browser or GPU. ```sh npm run build:renderer npm test # Optional offscreen GPU validation; requires a supported local OpenGL context python -m pip install numpy Pillow moderngl npm run test:render # Optional portable renderer model python -m pip install numpy onnx onnxruntime npm run export:renderer-onnx # Static hosting bundle (only public runtime files) npm run build:site ``` Additional files: - `scripts/lib/relu-builder.mjs` — generic affine/ReLU weight-authoring DSL. - `scripts/build-renderer.mjs` — complete hand-authored image construction, compiled into weights. - `model/renderer.weights.json` — portable sparse pixel field used by the app. - `src/neural-field.js` — generic CPU inference and GPU compiler. - `src/neural-frame.js` — GPU/CPU presentation and scheduling. - `src/neural-frame-worker.js` — neural CPU fallback worker. - `tests/renderer.test.mjs` — independent evaluator parity, pixel semantics, glyphs, and fallback checks. - `scripts/render-neural-fixtures.mjs` — reference frames and generated shaders. - `scripts/verify-neural-gpu.py` — offscreen GPU parity and PNG artifacts. - `scripts/export-renderer-onnx.py` — standard ONNX export and independent runtime verification.