Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Python bytecode from tools/ — generated on every validator run, never committed.
__pycache__/
*.py[cod]
11 changes: 11 additions & 0 deletions content/approved/items/vault_items.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[
{
"id": "item_threshold_stone",
"name": "Threshold Stone",
"category": "key_item",
"rarity": "rare",
"value": 0,
"description": "The keystone from the Perceptron Vault's output gate, still warm. It only ever answered one question — enough, or not enough — and it answered honestly every time.",
"found_in": ["datasedge_meadows"]
}
]
18 changes: 18 additions & 0 deletions content/approved/monsters/vault_monsters.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[
{
"id": "mon_the_gatekeeper",
"name": "the Gatekeeper",
"regions": ["datasedge_meadows"],
"tier": "dungeon_boss",
"hearts": 1,
"attack": 0.5,
"behavior": "tank",
"spawn": { "time_of_day": "any", "weather": "any" },
"drops": [
{ "item_id": "item_threshold_stone", "chance": 1 },
{ "item_id": "item_data_shard", "chance": 0.5 }
],
"ml_flavor": "A threshold unit made walkable: it adds up everything that reaches it and does nothing at all until the total crosses its line.",
"description": "A doorway three times Kern's height that unmoored itself from its own arch, and the last thing the vault's builders left awake. It keeps a running total of everything that touches it and opens for nothing else. Half the time it draws a blow in; the rest of the time it refuses, and a blow landed then is a blow taken back. Overload it and it comes apart into the sum it was holding."
}
]
12 changes: 12 additions & 0 deletions content/approved/pois/perceptron_vault.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[
{
"id": "poi_perceptron_vault",
"name": "The Perceptron Vault",
"region": "datasedge_meadows",
"kind": "mini_dungeon",
"description": "A half-buried monolith south-east of Bootstrap, its facade carved with two marks, then three, then one. Inside: a hall of founts, three chambers that each open for a sum rather than a key, and whatever has been counting in the dark since before the town had a mayor.",
"reward_items": ["item_threshold_stone"],
"reward_tokens": 120,
"bit_sense": false
}
]
37 changes: 37 additions & 0 deletions docs/DEVLOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,43 @@

---

## 2026-07-27 (repository recovery) — Vault and Iris branches integrated

**DONE**
- Recovered the previously stranded milestone-12 branch onto the current
post-split `main` without replacing newer Kern, town, inventory, sky, or
meadow work.
- Integrated the 2-3-1 walkable network dungeon, Gatekeeper encounter,
threshold/fount/weight-stone interactions, approved vault content, rune
shader, and five dungeon screenshot angles.
- Reconciled screenshot positioning so existing terrain-relative, posed-Kern,
and new absolute-height interior shots share one capture path.
- Recovered the milestone-13 Iris field and compendium without reverting the
newer photoreal multi-carpet grass system: 700 blooms now carry generated
Fisher-statistic specimens, proximity collection, boundary-bloom markings,
and a J/Start field notebook.
- Restored the six missing milestone-8 Bootstrap progress frames (square,
market, inn, hall, night, and dialogue) from their completed remote branch.
- Resolved the pre-existing controller collision between the pack and field
notebook: Back/Select remains the pack; Start/Menu now opens the compendium.

**VERIFIED**
- `validate_content.py --inbox` and `--all` pass (111 approved entries).
- Godot 4.7.1 completed a clean editor parse/import and registered all 56
script classes, including every recovered vault and Iris class.
- A 25-second clean runtime smoke boot built the 2-3-1 vault and generated 700
Iris blooms over 150 specimens (15 boundary blooms) with zero script or
runtime errors.
- The restored Bootstrap square and dialogue frames were opened and inspected;
the six PNGs are valid progress evidence.

**NEXT UP**
- A future live visual session should still capture and inspect the recovered
vault interiors and hands-on Iris collection/compendium interaction under
the shipping Forward+ renderer, per the project's visual-quality rule.

---

## 2026-07-24 (live session, Kern/character lane) — BASE MESH GENERATED; FITTING GATED ON AN ENGINE BUG

*Commits `613652f` → `8aaca35` (branch fast-forwarded to `main`). Danny gave
Expand Down
6 changes: 3 additions & 3 deletions docs/ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@ Prove every system small, then scale outward. One region done completely.
- [x] Bit the fairy: follow behavior, look-at naming, hint lines *(built: exp-smoothed hover-follow with idle orbit/bob, sprint catch-up, and canon water-fear over the millpond; BitLandmark look-at naming across 8 canon meadow sites (remembered in save flags); in-voice barks — greeting, idle/hint, quiz/item/region reactions — on a floating Label3D + EventBus.bit_spoke. **UNSEEN**: no Godot in this env — needs a live session to import (.uid gen), confirm clean boot, and eyes per GDD §10)*
- [x] Combat v1: sword (combo, dodge, block), enemy AI (melee + ranged), hearts, data-shard death VFX *(built: 3-hit sword combo with soft-target facing, roll-dodge with i-frames, hold-block + tight parry; juice = hitstop, knockback, trauma camera-shake; data-driven `Enemy` brain (melee/ranged/swarm/dummy) with wind-up telegraphs, drop rolls → ContentDB/GameState, and canon shard dissolves; reusable `Health` hearts + a minimal combat HUD (hearts/focus/damage-vignette — the full HUD stays its own later milestone); `MonsterSpawner` fields the approved Stray Glitchling and stands up a proving ground (melee/ranged/dummy sparring rigs) until batch_04's monsters land; a focus/knowledge-charge special is wired as the hook milestone 7 fills.* **UNSEEN**: no Godot in this env — a live session must import (generate `.uid`s), confirm a clean boot, and lay eyes/fight per GDD §10 before this ticks fully clean)*
- [x] Knowledge charge v1: quiz prompt in combat charges a special ability *(built to Danny's design: the focus special is a combined Kern+Bit attack CAST by answering — Q at part-charge opens a code-built quiz card (slow-mo + safe, real-time countdown, difficulty-gated per WORLDBOOK, explanation shown every answer); correct answers feed the existing meter and the strike auto-fires when it fills; wrong/timeout fizzles but keeps focus; Bit flies in to channel with new in-voice lines. New `QuizPicker` + `KnowledgePrompt`; wired through the milestone-6 hooks (`quiz_answered`→`add_charge`).* **UNSEEN**: built alongside the visual sessions without touching the editor — a live session must import (gen `.uid`s), boot, and cast/fizzle/complete a channel on eyes per GDD §10 before this ticks fully clean)*
- [ ] Town of Bootstrap: buildings, 6–8 NPCs (mixed personalities), dialogue UI
- [x] Town of Bootstrap: buildings, 6–8 NPCs (mixed personalities), dialogue UI *(built: 13 approved villagers across a procedural town square, market, inn, hall, forge, mill, homes, and dusk-lit streets; proximity dialogue has prompts, typewriter text, shuffled greetings/idle/farewell lines, and first-meeting persistence. The recovered six-frame milestone-8 set documents the square, market, inn, hall, night lighting, and dialogue composition; the current integrated build also completed a clean Godot 4.7.1 runtime smoke boot.)*
- [ ] Quest system + journal: main hook quest + 3 side quests (from content DB)
- [ ] Inventory, items, Tokens, one vendor
- [ ] Crafting v1: recipes at a campfire/bench
- [ ] Dungeon 1: **the Perceptron Vault** — traverse an actual neural network; 1 boss
- [ ] Iris flowers as collectible flora + compendium v1
- [x] Dungeon 1: **the Perceptron Vault** — traverse an actual neural network; 1 boss *(built: the vault IS a 2-3-1 network laid along its own axis — two Signal Founts (input bits, struck to toggle) → three walk-in Neuron Chambers, each with two tunable Weight Stones on restricted ladders, a sum column and a room-wide threshold ring → a Junction carrying the output cell's three weights → **the Gatekeeper**, a boss with no hearts that sums what hits it and alternates polarity, so a blow landed while it refuses is a blow taken back → the output gate and the reliquary. Both routes work by design (GDD §3): solve the network and it feeds the Gatekeeper while you dodge, or overload it by sword alone against its leak. Puzzle verified exhaustively offline — 12 of 2048 configurations open it, both founts must be lit, two chambers have exactly one correct weight pair. Also: 2-3-1 sigil on facade and gate (matching `icon.svg`), self-surveying plinth + approach ramp, `mon_the_gatekeeper` + `item_threshold_stone` + `poi_perceptron_vault` through the pipeline, five new screenshot angles. The recovered build completed a clean Godot 4.7.1 parse/import and 25-second runtime smoke boot; a future live Forward+ session should still inspect the interior shots per GDD §10.)*
- [x] Iris flowers as collectible flora + compendium v1 *(built: the 700 blooms of the western flats now carry real Iris specimen records — sepal length, petal length, petal width in cm, drawn from Fisher 1936's published per-family statistics, so the family separations, the spread, and the versicolor/virginica overlap are all true. Collection is proximity, not a button: walk through a bloom and Kern presses it, it shrinks away, and the specimen enters the compendium. `CompendiumUi` (J, or Start/Menu on a pad) shows three family columns with each pressed specimen's triplet, calls out the ones its nearest-centroid classifier gets WRONG, and keeps a boundary-bloom roll — ambiguous specimens wear their own near-white and are the collector prize. Verified offline over 300 seeds: setosa stays perfectly separable, 100% of confusion sits in the real versicolor/virginica overlap, and the boundary rate was retuned from a broken 1.7% (some meadows had none at all) to ~11%. Progress rides in `GameState.flags` as one bool per specimen — no save-shape change and no SAVE_VERSION bump. Irises moved out of `meadow_flora.gd` into their own `IrisField`, same seed and clusters, so the flats look exactly as they did. The recovered build completed a clean Godot 4.7.1 parse/import and runtime smoke boot; hands-on collection and notebook interaction remain a future live visual check.)*
- [ ] Save/load: versioned save format, multiple slots, title screen
- [ ] HUD: hearts, Tokens, minimap v1

Expand Down
Binary file added docs/progress/milestone8_dialogue.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/progress/milestone8_hall.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/progress/milestone8_inn_mara.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/progress/milestone8_market.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/progress/milestone8_night.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/progress/milestone8_square.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
95 changes: 95 additions & 0 deletions game/assets/shaders/vault_rune.gdshader
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
shader_type spatial;
// depth_prepass_alpha: the shader writes ALPHA, which makes every surface
// using it transparent. Without a prepass the glass-tube columns sort badly
// against each other; with it they behave like solids where alpha is 1.
render_mode unshaded, cull_disabled, depth_prepass_alpha;
// The Perceptron Vault's one light-language: every glowing surface in the
// dungeon — signal conduits, weight glyphs, sum columns, threshold beams,
// door runes, the Gatekeeper's charge core — is this shader with different
// uniforms. Unshaded on purpose: these read as light sources embedded in the
// stone, so they must stay bright inside a sealed vault where the sun never
// reaches (GDD §10 "nothing pops in or out without a transition").
//
// Three independent effects, each switchable to zero cost by its amount
// uniform:
// * pulse — a slow breathing brightness (idle runes)
// * flow — a travelling bright band along local +Y (signal in a conduit)
// * fill — a hard cutoff along local Y, so one mesh can act as a meter
// (sum columns, the Gatekeeper's charge core)
//
// Conventions: meshes are authored with their long axis on local Y, and
// `fill` is a 0..1 fraction of that axis measured from the bottom. Alpha
// below `fill` is 1 and above it is `dim_alpha`, so an unfilled column still
// reads as a glass tube rather than vanishing.

group_uniforms color;
uniform vec4 glow_color : source_color = vec4(1.0, 0.78, 0.32, 1.0);
// Multiplies the final emission. Above 1.0 the bloom in the world
// environment takes over and the surface blooms — that is the intent.
uniform float energy : hint_range(0.0, 8.0) = 2.4;

group_uniforms pulse;
// Fraction of `energy` that breathes (0 = steady, 1 = full on/off).
uniform float pulse_amount : hint_range(0.0, 1.0) = 0.18;
uniform float pulse_speed : hint_range(0.0, 8.0) = 1.6;
// Phase offset in radians, so neighbouring runes do not breathe in lockstep.
uniform float pulse_phase = 0.0;

group_uniforms flow;
// Brightness of the travelling band, in multiples of `energy`.
uniform float flow_amount : hint_range(0.0, 3.0) = 0.0;
uniform float flow_speed = 1.2;
// Bands per meter of local Y. Lower = longer, lazier pulses of signal.
uniform float flow_density = 0.35;

group_uniforms meter;
// 1.0 = the whole mesh is lit. Below that, the part above the cutoff drops
// to dim_alpha — the mesh becomes a fill meter.
uniform float fill : hint_range(0.0, 1.0) = 1.0;
// Local-Y extent (meters) the fill fraction is measured against. Set from
// code to the mesh's height so `fill` stays a plain 0..1 fraction.
uniform float fill_height = 1.0;
// Local-Y coordinate of the mesh's bottom. BoxMesh is origin-centered, so
// this is normally -height/2.
uniform float fill_base = -0.5;
uniform float dim_alpha : hint_range(0.0, 1.0) = 0.12;

varying vec3 v_local;

void vertex() {
v_local = VERTEX;
}

void fragment() {
float e = energy;

// Breathing. sin() is remapped to 0..1 so pulse_amount is a clean
// fraction of energy rather than a signed swing.
if (pulse_amount > 0.001) {
float p = sin(TIME * pulse_speed + pulse_phase) * 0.5 + 0.5;
e *= 1.0 - pulse_amount + pulse_amount * p;
}

// Travelling band: a sawtooth along local Y, sharpened by smoothstep so
// the band has a bright head and a soft tail — signal moving, not a
// blinking stripe.
if (flow_amount > 0.001) {
float band = fract(v_local.y * flow_density - TIME * flow_speed);
e += energy * flow_amount * smoothstep(0.55, 1.0, band);
}

float alpha = 1.0;
if (fill < 0.999) {
// Height of the fill line in local space.
float cut = fill_base + fill * fill_height;
// Two-pixel-ish soft edge so the meter's top does not crawl and
// alias as it rises.
float lit = 1.0 - smoothstep(cut - 0.02, cut + 0.02, v_local.y);
alpha = mix(dim_alpha, 1.0, lit);
e *= mix(0.25, 1.0, lit);
}

ALBEDO = glow_color.rgb;
EMISSION = glow_color.rgb * e;
ALPHA = glow_color.a * alpha;
}
1 change: 1 addition & 0 deletions game/assets/shaders/vault_rune.gdshader.uid
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
uid://dk81l4p56g15i
Loading