Camera: desired_focus_position.y now directly tracks the player's global Y. The existing smooth lerp on focus_position handles interpolation, so the camera follows the player up hills and down slopes without losing vertical sight. Previously only horizontally-deadzoned XZ was tracked.
jajce_world.gd: expanded terrain-snapping coverage to include all nodes under WorldObjects (ResourceNodes, StorageSites, ActivitySites) and the FortressBlockout's children. Added a type guard so non-Node3D children are safely skipped. This prevents houses, activity props, storage crates, and resource nodes from floating above or sinking below the sculpted terrain surface.
Enable Terrain3D collision_mode=1 so the sculpted landscape provides real physical ground for player and NPCs. Disable GreyboxGround collision (layer/mask = 0) -- it is no longer the active physical floor.
NpcVisual no longer flattens nav waypoint Y to its current elevation. It now follows 3D path points and uses gravity (30 m/s^2) like the player, settling to terrain surface via is_on_floor() + Terrain3D collision. The flat NavigationMesh_greybox still provides correct lateral guidance; physics handles vertical grounding on slopes.
This fixes the player-walking-through-slopes bug and makes NPC movement follow actual terrain elevation for the village area (gentle slopes, ~2.4m noise amplitude). All 10 scenarios pass.
A 60x60 circular dial drawn at the top-center of the screen shows the current position in the day/night cycle. A filled arc sweeps clockwise from the top; the color transitions from dark blue (night) through orange (dawn), gold (day), and pink (dusk). A small glow dot marks the leading tip; a phase label (Night/Dawn/Day/Dusk) sits below. Redraws only when the cycle fraction changes. References DayNightCycle via node_path so it stays in sync with the environment lighting.
Mouse wheel up/down smoothly zooms the camera in and out. Zoom range: close-in overview (5 high, 4 back) to wide survey (16 high, 12 back). Default sits at midpoint (10 high, 8 back) matching the previous fixed offset. Configurable via min_zoom_offset, max_zoom_offset, and zoom_step exports. Zoom interpolates with the same follow_speed as position tracking for consistent feel.
Adds Elma, Mirza, and Lejla to the village alongside Amina, Tarik, and Jasmin. Profession assignment is deterministic per-NPC-id RNG so the original three retain their seeded professions. jajce_runtime_integration_test updated to expect six villagers. All 10 scenarios pass.
DayNightCycle.gd smoothly rotates DirectionalLight3D and interpolates sky colors, ambient light, fog, and procedural sky material across a configurable 240-second cycle with warm sunset/sunrise peaks and deep night ambiance. No simulation dependency — purely visual.
JajceWorld.tscn now includes visible workplace structures replacing the invisible Marker3Ds: wooden pantry crate, guard tower post, study desk, and rest bench. Each has a distinct material color matching the profession palette.
The DayNightCycle node is added to JajceWorld.tscn with node_paths wired to DirectionalLight3D and WorldEnvironment. Script reference uses path-based ext_resource (uid generation deferred to editor first load).
The file contained only 'extends Node' with no implementation, was referenced nowhere in any scene or script, and the uid sidecar was orphaned. The next interaction surface should be planned and implemented fresh when needed.
Previously get_action(), get_profession(), get_actions(), get_professions(), get_profession_ids(), and validate() reloaded all .tres files from disk on every call. These are called per-tick (action selection, task completion, NPC inspector refresh) producing unnecessary disk I/O. Now definitions are loaded once and stored in static dicts/lists keyed by ID. Add invalidate_cache() for hot-reload scenarios.
- WaterBody.tscn, WaterfallBody.tscn: gdshader files were referenced
with type="Material" instead of type="Shader". Wrapped each
shader in a ShaderMaterial sub-resource so Godot can load them.
- ChimneySmoke.tscn: reordered sub-resources so StandardMaterial3D
is defined before QuadMesh that references it.
- WaterfallMist.tscn: fixed node type GpuParticles3D -> GPUParticles3D
(case-sensitive class name in Godot 4.7).
- jajce_world.gd: added explicit Vector3 type annotation to fix
'Cannot infer the type of pos variable' parse error.
- main.tscn.uid: created missing UID mapping file. The scene header
declared uid="uid://rs3hv73svbpa" but no .uid file existed,
causing Godot to reject the scene as unsupported format.
Auto-format all GDScript files using gdformat from gdtoolkit.
This is a baseline formatting pass to ensure consistent style:
- Normalizes indentation and spacing
- Wraps long lines to 100 characters
- Removes trailing whitespace
- Standardizes blank lines between functions
68 files reformatted, 8 files left unchanged (3rd-party addon files
with parse errors excluded).
Add quality.sh (bash), quality.ps1 (PowerShell), and fix_format.sh
for automated GDScript quality checking. Includes:
- gdformat --check (formatting gate)
- gdlint (lint rules)
- godot --headless project validation (with 30s timeout)
- Optional GUT test support
- --changed mode for checking only modified .gd files
- Compact summary output with NEXT FIX suggestions
- Full logs saved to logs/quality/latest/
Add docs/local_quality_gate.md with setup and usage instructions.
- Add 3 Terrain3D texture assets (limestone, valley grass, warm soil)
- Sculpt initial Terrain3D heightmap with ridge, valley, waterfall drop
- Replace plain water with emissive-tinged material
- Add foam mesh, mist spheres, and procedural sky with valley fog
- Add 10 StylizedTree instances around village perimeter
- Enable directional light shadows with extended cascade range
- Add tree height snapping to terrain surface
- Add refined scaffold tests for material count, terrain height, foliage, sky, fog
- Add terrain texture PNGs and StylizedTree.tscn scene
- Add generate_jajce_terrain.gd tool
- Update ACTION_SYSTEM_ARCHITECTURE.md to describe the active-position
contract and visual lifecycle proof
- Mark BUILD_IN_PUBLIC_PLAN.md systems-gate section complete
- Mark LEARNING_ROADMAP.md architecture-gate section complete and
renumber post-gate implementation sequence
- Update PROJECT_CONTEXT.md immediate-milestone section to reflect
completed gate and next food-loop milestone
- Update SIMULATION_STATE_SCHEMA.md with NPCStateRecord v2 details
- Update ADR 0001 checklist to mark active-position sync done
- NpcVisual emits position_changed signal during _physics_process
- SimulationManager.synchronize_npc_position() writes active position
into SimNPC state on movement, arrival, and navigation failure
- WorldViewManager forwards position_changed and syncs before
despawn/reload
- SimNPC stores travel_target_position and has_travel_target as
versioned state; NPCStateRecord v2 persists them with v1 migration
- WorldViewManager.spawn_npc_visual() resumes travel for traveling NPCs
via SimulationManager.request_current_travel()
- WorldViewManager.despawn_npc_visual() syncs position before removal
- WorldViewManager.reload_npc_visual() spawns a visual from persisted
state without rerolling target selection
- tests/npc_visual_lifecycle_test.gd proves unload/reload preserves
action, target, reservation, position, RNG state, and checksum
- simulation_state_serialization_test adds legacy v1 NPC migration test
that does not invent an active travel target
BUILD_IN_PUBLIC_PLAN.md:
- Mark systems gate items deterministic clock and headless checksum
as complete; remaining gate work stays flagged as in-progress
- Rename TaskZone references to ActivityMarkers for consistency
LEARNING_ROADMAP.md:
- Add architecture gate progress note: first deterministic slice
(SimulationClock, seeded streams, headless checksum) is implemented
- Update recommended implementation order to reflect shifted priorities
PROJECT_CONTEXT.md:
- Note that farm and forest markers have been deleted from main.tscn
- Update activity marker description (4 remaining: guard/study/rest/food)
- Add SimulationClock.gd and deterministic_simulation_test.gd to repo map
- Update technical debt: randomness is now seeded but RNG state is not
yet serialized; clock is explicit but orchestration still lives on scene tree
- Gate status updated with completed first-slice summary
RESOURCE_NODE_MIGRATION.md:
- Mark Phase 4b (player parity) complete
- Phase 6 renamed from 'remove zone model' to 'replace activity markers'
with progress note: TaskZone container and FarmZone/ForestZone deleted
- Update divergences to note farm/forest scene nodes have been removed