Spaces:
Running
Running
Update README.md
Browse files
README.md
CHANGED
|
@@ -10,149 +10,95 @@ short_description: Infinite procedural key-hunt in a WebGL2 labyrinth.
|
|
| 10 |
|
| 11 |
# ANTTI'S BRAIN — DESCENT
|
| 12 |
|
| 13 |
-
An infinite procedural key-hunt built on the Antti's Brain 2 engine (WebGL2 raymarcher,
|
| 14 |
-
hash-dreamed chambers, refracting crystal moons, webcam boundary). One HTML file, no
|
| 15 |
-
dependencies, no build step. No enemies, no timers, no hand-made levels — only geometry,
|
| 16 |
-
depth, and the hash.
|
| 17 |
|
| 18 |
-
|
| 19 |
|
| 20 |
-
|
| 21 |
|
| 22 |
-
|
| 23 |
-
- **A level is a run of rooms**: level 1 is 4 rooms, level 2 is 5, … capped at 10 per level.
|
| 24 |
-
- Somewhere in the level, **one crystal is the key**: it is gold and it pulses. Touch it.
|
| 25 |
-
- The corridor after the level's last room is closed by a **red seal** — a glowing
|
| 26 |
-
membrane you cannot pass. Touch the key and the seal dissolves. Walk through: next level.
|
| 27 |
-
- The **resonance meter** in the HUD is your only guide: it tells you how many rooms away
|
| 28 |
-
the key is, and once you're in the right room it runs hot with live distance. Hot / cold,
|
| 29 |
-
nothing more.
|
| 30 |
|
| 31 |
-
|
| 32 |
|
| 33 |
-
|
| 34 |
|
| 35 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 36 |
|
| 37 |
-
|
| 38 |
-
|---|---|
|
| 39 |
-
| level length | 4 rooms → 10 rooms (cap) |
|
| 40 |
-
| shape pool | 6 shapes at level 1, +1 new shape per level, 12 total by level 7 |
|
| 41 |
-
| **twist** | rooms shear around their vertical axis, stronger with depth |
|
| 42 |
-
| ripple | from level 3, walls start to breathe with a triple-sine displacement |
|
| 43 |
-
| **mass** | each room has its own mass factor (shown in HUD); moons grow heavier, lensing pulls harder |
|
| 44 |
-
| moons per room | 3 → 5 |
|
| 45 |
|
| 46 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 47 |
|
| 48 |
-
|
| 49 |
-
the classics —
|
| 50 |
-
then 7. **capsule vault** · 8. **cut crystal** (box ∩ octahedron) · 9. **ellipsoid dome** ·
|
| 51 |
-
10. **cross cathedral** · 11. **gear** (cog-rippled cylinder) · 12. **wheel** (walkable
|
| 52 |
-
torus + hub + four spokes).
|
| 53 |
|
| 54 |
-
|
| 55 |
-
new crystal shapes too. Twist applies on top of any shape, so a twisted star at level 6
|
| 56 |
-
and a twisted gear at level 9 are genuinely different rooms even with the same base index
|
| 57 |
-
math.
|
| 58 |
|
| 59 |
## Controls
|
| 60 |
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
- Sliders: mass gain, lensing strength, music volume
|
| 66 |
-
- **Music: on/off** — toggles the soundtrack
|
| 67 |
-
- **New brain** — fresh seed, back to level 1
|
| 68 |
-
|
| 69 |
-
## Music
|
| 70 |
-
|
| 71 |
-
Put `game1.mp3` … `game10.mp3` next to the HTML file. They play as an endless
|
| 72 |
-
playlist: a random track starts on your first click (browsers require a gesture
|
| 73 |
-
before audio), then they chain forever — when one ends the next begins, wrapping
|
| 74 |
-
around after `game10.mp3`. Missing files are skipped automatically; if none of
|
| 75 |
-
the ten are found the HUD says `no mp3s found` and the game plays silent.
|
| 76 |
-
Volume slider in the control panel; the Music button pauses/resumes.
|
| 77 |
-
|
| 78 |
-
## Save / load
|
| 79 |
-
|
| 80 |
-
The entire game state is six numbers: `{version, seed, level, room index, key flag,
|
| 81 |
-
max level reached}`. Everything else is re-dreamed from the hash on load, including the
|
| 82 |
-
key's location and the walk direction of the chain (reconstructed by replaying the turn
|
| 83 |
-
angles — verified bit-exact).
|
| 84 |
-
|
| 85 |
-
- **Save** — writes to localStorage (when the browser allows it) and keeps a code ready.
|
| 86 |
-
- **Save code** — prints the save as a short base64 string and copies it to the clipboard.
|
| 87 |
-
This works everywhere, including `file://` pages and sandboxes where localStorage is
|
| 88 |
-
blocked. Paste it into a text file, an email, a commit message.
|
| 89 |
-
- **Load** — reads the local save, or accepts a pasted code.
|
| 90 |
-
- The game **autosaves** on every level-up and key pickup, and silently resumes on launch
|
| 91 |
-
if a local save exists.
|
| 92 |
-
|
| 93 |
-
Walking backward is always allowed. Levels you have already beaten stay open (the game
|
| 94 |
-
remembers your max level, so re-crossing an old seal never re-locks it), but the current
|
| 95 |
-
level's key must be found each fresh descent into new territory.
|
| 96 |
-
|
| 97 |
-
## How the infinity works
|
| 98 |
-
|
| 99 |
-
Same principle as Brain 2, extended:
|
| 100 |
-
|
| 101 |
-
- `rng(index, salt)` — an integer hash (multiply/xor/shift mix of `SEED`, index, salt).
|
| 102 |
-
Any room at any depth can be queried in O(1) without generating the rooms before it.
|
| 103 |
-
- `roomDef(i)` now first computes which level room `i` belongs to (cumulative level
|
| 104 |
-
depths are a closed-form loop), then draws shape / size / twist / ripple / mass / turn /
|
| 105 |
-
name from independent salts, with the level scaling the ranges.
|
| 106 |
-
- Per level, a second hash stream `rngL(level, salt)` places the key room. The key is
|
| 107 |
-
always moon 0 of that room, so it can never be hidden by settings.
|
| 108 |
-
- Only 3 rooms exist at a time (prev / current / next). The seal is a single sphere SDF
|
| 109 |
-
in the exit corridor, present only while the key is unfound and you are in the exit room —
|
| 110 |
-
blocked in the JS collision twin and rendered as a pulsing membrane in the shader.
|
| 111 |
-
|
| 112 |
-
## Technical notes
|
| 113 |
-
|
| 114 |
-
- Single fragment shader, one fullscreen triangle, raymarched SDFs with real Snell
|
| 115 |
-
refraction + total internal reflection through the moons and Beer–Lambert tinting.
|
| 116 |
-
- Rooms and moons share one 12-way shape function; moons are derived from it via
|
| 117 |
-
const scale/rounding tables, which roughly halves the shader the driver must
|
| 118 |
-
compile. Well loops use dynamic bounds so ANGLE doesn't unroll them 15-wide.
|
| 119 |
-
- Shader compilation is deferred until after first paint and uses
|
| 120 |
-
KHR_parallel_shader_compile when available, with a shimmer bar and elapsed
|
| 121 |
-
timer on the boot screen. Loop bounds (march steps, glass-refraction steps,
|
| 122 |
-
wall-escape steps) are uniforms, which blocks driver loop unrolling — the
|
| 123 |
-
main cause of minutes-long first compiles on Windows.
|
| 124 |
-
- The wheel room's four spokes fold to two by symmetry (|x|,|z|), an exact
|
| 125 |
-
identity that trims the hottest SDF.
|
| 126 |
-
- The key crystal orbits wide (up to ~0.34 × room size off the center line) with a
|
| 127 |
-
tight pickup radius, so finding the key room via resonance is only half the hunt.
|
| 128 |
-
- Twist and ripple are applied as domain modifications with a Lipschitz correction
|
| 129 |
-
factor on the returned distance, so marching stays conservative and never tunnels.
|
| 130 |
-
- Every SDF has a JavaScript twin used for collision and gate transitions; the twelve
|
| 131 |
-
room shapes were tested to guarantee the room center is deep interior (transition
|
| 132 |
-
trigger fires at −1.0), so no shape can ever strand you in a wall.
|
| 133 |
-
- Webcam feeds the boundary texture; falls back to an animated test pattern.
|
| 134 |
-
- WebGL2 required.
|
| 135 |
|
| 136 |
-
##
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 137 |
|
| 138 |
-
|
| 139 |
-
same folder. Allow the camera if you want the walls to be you; decline and the
|
| 140 |
-
pattern takes over.
|
| 141 |
|
| 142 |
-
|
| 143 |
|
| 144 |
-
|
| 145 |
-
|
| 146 |
-
|
| 147 |
-
time rather than a fake percentage). This happens on the FIRST launch only —
|
| 148 |
-
the driver caches the compiled shader on disk, so later launches are near
|
| 149 |
-
instant.
|
| 150 |
|
| 151 |
-
|
| 152 |
-
|
| 153 |
-
|
| 154 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 155 |
|
| 156 |
-
`
|
| 157 |
-
on the boot screen in red with the actual message — send that text and it can
|
| 158 |
-
be fixed.
|
|
|
|
| 10 |
|
| 11 |
# ANTTI'S BRAIN — DESCENT
|
| 12 |
|
| 13 |
+
An infinite procedural key-hunt built on the Antti's Brain 2 engine (WebGL2 raymarcher, hash-dreamed chambers, refracting crystal moons, webcam boundary). One HTML file, no dependencies, no build step. No enemies, no timers, no hand-made levels — only geometry, depth, and the hash.
|
|
|
|
|
|
|
|
|
|
| 14 |
|
| 15 |
+
Do not hype. Do not lie. Just show.
|
| 16 |
|
| 17 |
+
---
|
| 18 |
|
| 19 |
+
## The Divergence: Trying to Build It "Like Normal"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 20 |
|
| 21 |
+
During development, we took a weird side step trying to make the engine work "like normal." We tried to force variety by writing *more code*. We explicitly coded 12 discrete chamber shapes (cubes, cylinders, stars, gears) using a branched shape function and finite-difference normals. We also abandoned surface optics and forced light rays to march through the volumetric bulk of the glass objects to calculate Snell refraction and Beer-Lambert absorption.
|
| 22 |
|
| 23 |
+
**The Result:** The GPU rejected it. The branches multiplied by the interior loops created a compile-time bomb that choked the driver for minutes. The heavy bulk transport caused the driver to TDR (Timeout Detection and Recovery) and crash. We had tried to put the complexity into the shader's execution paths, prioritizing physical bulk over constraint-driven beauty.
|
| 24 |
|
| 25 |
+
## The Lesson: Complexity Belongs in Data, Not Code
|
| 26 |
+
|
| 27 |
+
We learned that to survive the frame budget, we had to return to the logic of the original "Aeon Forge" and the meaning of *Rajapinta* (Boundary). The GPU merely enforced the engine's own metaphysics: information belongs on surfaces, and light travels in a vacuum.
|
| 28 |
+
|
| 29 |
+
The fix wasn't to optimize the 12 shapes; it was to delete them. We replaced the shape zoo with **one branchless law**—a single p-norm parametric superellipsoid kernel. Now, a room is no longer a hardcoded shape; it is a point in a continuous shape space defined by a parameter vector (cross-section exponent, profile exponent, squash, angular ripple, torus blend) drawn from the hash. Complexity is encoded entirely into data parameters, not shader branches.
|
| 30 |
+
|
| 31 |
+
By returning optics to the boundary—reflecting, accumulating, and lensing at the surface without penetrating the bulk—the engine regained its elegance. The shader stays fixed and small, compiling instantly, while generating infinite variety.
|
| 32 |
+
|
| 33 |
+
---
|
| 34 |
+
|
| 35 |
+
## The Game
|
| 36 |
+
|
| 37 |
+
The brain is an endless chain of chambers, a pure function of (SEED, room index).
|
| 38 |
+
A level is a run of rooms: level 1 is 4 rooms, level 2 is 5, … capped at 10 per level.
|
| 39 |
+
|
| 40 |
+
Somewhere in the level, one crystal is the key: it is gold and it pulses. Touch it. The corridor after the level's last room is closed by a red seal — a glowing membrane you cannot pass. Touch the key and the seal dissolves. Walk through: next level.
|
| 41 |
+
|
| 42 |
+
The resonance meter in the HUD is your only guide: it tells you how many rooms away the key is, and once you're in the right room it runs hot with live distance. Hot / cold, nothing more. There is no way to lose. There is only further down.
|
| 43 |
+
|
| 44 |
+
## What Deepens with the Level
|
| 45 |
|
| 46 |
+
Everything below is still deterministic — same seed, same descent.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 47 |
|
| 48 |
+
| Property | How it grows |
|
| 49 |
+
| :--- | :--- |
|
| 50 |
+
| **Level length** | 4 rooms → 10 rooms (cap) |
|
| 51 |
+
| **Shape pool** | Rooms morph continuously with depth. Level 1 yields soft orbs; by Level 12 you walk twisted stars; by Level 21 the rooms become rings. The descent widens the parameter distribution. |
|
| 52 |
+
| **Twist** | Rooms shear around their vertical axis, stronger with depth. |
|
| 53 |
+
| **Ripple** | From level 3, walls start to breathe with a triple-sine displacement. |
|
| 54 |
+
| **Mass** | Each room has its own mass factor (shown in HUD); moons grow heavier, lensing pulls harder. |
|
| 55 |
+
| **Moons per room** | 3 → 5 |
|
| 56 |
|
| 57 |
+
The moons wear their room's shape, shrunk and rounded into optical glass, meaning new room parameters yield new crystal shapes instantly. Twist and ripple apply on top of any shape vector.
|
|
|
|
|
|
|
|
|
|
|
|
|
| 58 |
|
| 59 |
+
---
|
|
|
|
|
|
|
|
|
|
| 60 |
|
| 61 |
## Controls
|
| 62 |
|
| 63 |
+
* **W A S D** — move
|
| 64 |
+
* **Q / E** — down / up
|
| 65 |
+
* **Shift** — boost
|
| 66 |
+
* **Drag** — look (horizontal inverted, as tradition demands)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 67 |
|
| 68 |
+
### Modes
|
| 69 |
+
* **Boundary:** The walls are your camera; the moons are curved mirrors that lens and reflect them.
|
| 70 |
+
* **Projection:** The moons carry your face; every wall is a mirror. The image emanates from the bulk (the holographic swap).
|
| 71 |
+
* **Cascade:** Every crystal wears your face and mirrors its neighbors. Holographic accumulation with a capped bounce depth.
|
| 72 |
+
* **Glass:** The honest-physics exhibit. Heavy optics where the ray refracts through the crystal bulk (Snell + Beer-Lambert). Safe to run here because rays terminate at the image wall.
|
| 73 |
+
|
| 74 |
+
### Toggles
|
| 75 |
+
* **Sliders:** Mass gain, lensing strength, music volume
|
| 76 |
+
* **Music:** on/off — toggles the soundtrack
|
| 77 |
+
* **New brain:** Fresh seed, back to level 1
|
| 78 |
+
|
| 79 |
+
---
|
| 80 |
|
| 81 |
+
## Save / Load
|
|
|
|
|
|
|
| 82 |
|
| 83 |
+
The entire game state is six numbers: `{version, seed, level, room index, key flag, max level reached}`. Everything else is re-dreamed from the hash on load, including the key's location and the walk direction of the chain (reconstructed by replaying the turn angles — verified bit-exact).
|
| 84 |
|
| 85 |
+
* **Save:** Writes to localStorage (when the browser allows it) and keeps a code ready.
|
| 86 |
+
* **Save code:** Prints the save as a short base64 string and copies it to the clipboard. This works everywhere, including `file://` pages and sandboxes where localStorage is blocked. Paste it into a text file, an email, a commit message.
|
| 87 |
+
* **Load:** Reads the local save, or accepts a pasted code.
|
|
|
|
|
|
|
|
|
|
| 88 |
|
| 89 |
+
The game autosaves on every level-up and key pickup, and silently resumes on launch if a local save exists. Walking backward is always allowed. Levels you have already beaten stay open (the game remembers your max level, so re-crossing an old seal never re-locks it), but the current level's key must be found each fresh descent into new territory.
|
| 90 |
+
|
| 91 |
+
---
|
| 92 |
+
|
| 93 |
+
## Technical Notes
|
| 94 |
+
|
| 95 |
+
* **Single Fragment Shader:** One fullscreen triangle, raymarched SDFs.
|
| 96 |
+
* **Unified Parametric SDF:** Rooms and moons share one branchless shape function, driven by a 6-number vector. There are no discrete shape loops to unroll and no finite-difference normal overhead for the analytical bases.
|
| 97 |
+
* **Guaranteed Transitions:** Every SDF has a JavaScript twin used for collision and gate transitions. The deterministic pure function guarantees the room center is deep interior (transition trigger fires at −1.0), so no parametric shape configuration can ever strand you in a wall.
|
| 98 |
+
* **Lipshitz Continuity:** Twist and ripple are applied as domain modifications with a Lipschitz correction factor on the returned distance, so marching stays conservative and never tunnels (guarded against radial singularity blow-ups).
|
| 99 |
+
* **First Paint Compilation:** Shader compilation is deferred until after first paint and uses `KHR_parallel_shader_compile` when available. Loop bounds (march steps, glass-refraction steps, wall-escape steps) are passed as **uniforms**. This forces the D3D/ANGLE compiler to compile the loop body exactly once rather than unrolling a 180-step march, eliminating the compile-time bomb.
|
| 100 |
+
* **O(1) Hash Generation:** `rng(index, salt)` handles the integer hash. Any room at any depth can be queried in O(1) without generating the rooms before it. Only 3 rooms exist at a time (prev / current / next).
|
| 101 |
+
|
| 102 |
+
## Running
|
| 103 |
|
| 104 |
+
Open `anttis-brain-descent.html` in any WebGL2 browser. Place `game1.mp3` ... `game10.mp3` in the same directory for endless chained audio. Allow the camera if you want the boundary texture to be you; decline, and the animated test pattern takes over.
|
|
|
|
|
|