diff --git a/docs/BUILD_IN_PUBLIC_PLAN.md b/docs/BUILD_IN_PUBLIC_PLAN.md index 42ded52..771637d 100644 --- a/docs/BUILD_IN_PUBLIC_PLAN.md +++ b/docs/BUILD_IN_PUBLIC_PLAN.md @@ -629,11 +629,13 @@ Completed: 9. Terrain3D-derived playable-loop navigation: `JajceWorld` now uses an external baked navigation resource generated from Terrain3D source geometry, and runtime tests reject partial paths that do not reach their targets. +10. `Jajce Lookdev 01` capture and review: a reproducible capture tool writes + the daytime lookdev baseline to `docs/baselines/jajce_lookdev_01.png`, and + the review notes the current strengths and visual follow-ups. Next: -1. Capture and visually review “Jajce Lookdev 01.” -2. Capture “Simulation Garden 01.” +1. Capture “Simulation Garden 01.” Do not start with GIS data, a full city, a large asset pack, or more NPC mechanics. The next proof is a beautiful stage for the systems that already diff --git a/docs/LEARNING_ROADMAP.md b/docs/LEARNING_ROADMAP.md index 4e7a307..0c9bc60 100644 --- a/docs/LEARNING_ROADMAP.md +++ b/docs/LEARNING_ROADMAP.md @@ -678,6 +678,8 @@ Recently completed: Terrain3D-derived navigation mesh resource generated by `tools/bake_jajce_navigation.gd`; route tests now also reject partial paths that do not reach their requested targets. +- `Jajce Lookdev 01` is captured and reviewed with a project-owned capture + script and a daytime baseline image under `docs/baselines/`. This order strengthens the simulation while regularly producing visible progress suitable for public development updates. diff --git a/docs/PROJECT_CONTEXT.md b/docs/PROJECT_CONTEXT.md index eea7e6b..b5f32fc 100644 --- a/docs/PROJECT_CONTEXT.md +++ b/docs/PROJECT_CONTEXT.md @@ -195,6 +195,9 @@ study, and patrol target typed activity sites. The migration is documented in - **Jajce runtime:** reusable 512 m Terrain3D seed, greybox landmarks, stable ResourceNode placement, lookdev camera, and Terrain3D-derived runtime navigation with collision guardrails +- **Lookdev baseline:** `Jajce Lookdev 01` is captured at + `docs/baselines/jajce_lookdev_01.png` with + `tools/capture_jajce_lookdev.gd` - **Terrain compatibility floor:** Godot 4.4 according to the bundled extension - **Version control:** Git - **Primary branch:** `main` @@ -334,6 +337,8 @@ distance with resource `safety_risk`, `comfort_distance`, and their targets, and compare required navigation paths against the Terrain3D height field; - a look-development scene and camera. +- a reproducible daytime lookdev capture and review note under + `docs/baselines/`. This is a runtime integration proof, not the final terrain composition. Terrain3D startup requires several physics frames before reliable @@ -544,7 +549,8 @@ These are expected prototype constraints, not necessarily isolated bugs: playable-loop pass, so future terrain sculpting should rerun the bake tool and recheck reachability rather than hand-editing navigation polygons. - Terrain3D and the bounded Jajce beauty baseline now run in the main game - scene; final visual review and character/profession readability remain. + scene; `Jajce Lookdev 01` is captured, while the runtime `Simulation Garden + 01` capture remains the next presentation checkpoint. - Combat, companions, factions, politics, trade, rumours, quests, persistence, and regional travel do not yet exist. - Placeholder geometry is sufficient for debugging but not for build-in-public diff --git a/docs/baselines/JAJCE_LOOKDEV_01.md b/docs/baselines/JAJCE_LOOKDEV_01.md new file mode 100644 index 0000000..25e8946 --- /dev/null +++ b/docs/baselines/JAJCE_LOOKDEV_01.md @@ -0,0 +1,46 @@ +# Jajce Lookdev 01 + +- **Captured:** 2026-07-08 +- **Scene:** `res://world/jajce/JajceLookdev.tscn` +- **Image:** [`jajce_lookdev_01.png`](jajce_lookdev_01.png) +- **Capture tool:** `res://tools/capture_jajce_lookdev.gd` + +## Contract + +This checkpoint captures the first readable Jajce visual stage after the +Terrain3D-derived navigation pass. It is a visual composition baseline, not a +gameplay regression test. + +The image should show: + +- the broad shaped valley terrain; +- the village and fortress blockouts; +- water, waterfall/foam, and bridge silhouettes; +- visible foliage clusters; +- warm daylight/fog treatment; +- stable enough framing to compare future terrain, lighting, and asset passes. + +## Review + +The scene now reads as a coherent daytime valley rather than the previous dark +startup view. The terrain, homes, bridge, water, waterfall, smoke/mist, and +first foliage clusters are all visible in one frame. + +Known follow-up work: + +- reduce the heavy haze if it hides terrain color and landmark silhouettes; +- improve fortress/waterfall readability from the beauty-camera angle; +- replace blockout architecture and placeholder resource markers gradually; +- capture a runtime `Simulation Garden 01` view with active NPC behavior. + +## Command + +Run with a real display driver, not `--headless`; headless Godot uses the dummy +renderer on this machine and cannot read back a viewport image. + +```powershell +$env:APPDATA = "$PWD\logs\quality\godot_profile" +$env:LOCALAPPDATA = "$PWD\logs\quality\godot_profile" +& "C:\Users\Rijad\Downloads\tools\Godot_v4.7-stable_win64.exe\Godot_v4.7-stable_win64_console.exe" ` + --path "$PWD" --script res://tools/capture_jajce_lookdev.gd +``` diff --git a/docs/baselines/jajce_lookdev_01.png b/docs/baselines/jajce_lookdev_01.png new file mode 100644 index 0000000..1039f7a Binary files /dev/null and b/docs/baselines/jajce_lookdev_01.png differ diff --git a/tools/capture_jajce_lookdev.gd b/tools/capture_jajce_lookdev.gd new file mode 100644 index 0000000..5a894f0 --- /dev/null +++ b/tools/capture_jajce_lookdev.gd @@ -0,0 +1,71 @@ +extends SceneTree + +const OUTPUT_PATH := "res://docs/baselines/jajce_lookdev_01.png" +const SCENE_PATH := "res://world/jajce/JajceLookdev.tscn" +const CAPTURE_SIZE := Vector2i(1280, 720) +const WARMUP_FRAMES := 90 + + +func _initialize() -> void: + call_deferred("_run") + + +func _run() -> void: + root.size = CAPTURE_SIZE + var scene := load(SCENE_PATH) as PackedScene + if scene == null: + push_error("Could not load %s" % SCENE_PATH) + quit(1) + return + + var lookdev := scene.instantiate() as Node3D + root.add_child(lookdev) + await process_frame + for _frame in WARMUP_FRAMES: + await process_frame + + var image := root.get_texture().get_image() + if image == null or image.is_empty(): + push_error("Lookdev capture produced no image") + quit(1) + return + + var analysis := _analyze_image(image) + if analysis.get("range", 0.0) < 0.05: + push_error("Lookdev capture is too uniform: %s" % analysis) + quit(1) + return + + var error := image.save_png(OUTPUT_PATH) + if error != OK: + push_error("Could not save %s: %s" % [OUTPUT_PATH, error_string(error)]) + quit(1) + return + + print("[TOOL] Saved %s | %s" % [OUTPUT_PATH, analysis]) + quit(0) + + +func _analyze_image(image: Image) -> Dictionary: + var min_luma := INF + var max_luma := -INF + var total_luma := 0.0 + var samples := 0 + var step_x = maxi(1, image.get_width() / 64) + var step_y = maxi(1, image.get_height() / 36) + + for y in range(0, image.get_height(), step_y): + for x in range(0, image.get_width(), step_x): + var color := image.get_pixel(x, y) + var luma := color.r * 0.2126 + color.g * 0.7152 + color.b * 0.0722 + min_luma = minf(min_luma, luma) + max_luma = maxf(max_luma, luma) + total_luma += luma + samples += 1 + + return { + "size": "%sx%s" % [image.get_width(), image.get_height()], + "samples": samples, + "average_luma": total_luma / samples, + "range": max_luma - min_luma, + } diff --git a/world/jajce/JajceLookdev.tscn b/world/jajce/JajceLookdev.tscn index cd86b1c..065eca8 100644 --- a/world/jajce/JajceLookdev.tscn +++ b/world/jajce/JajceLookdev.tscn @@ -7,6 +7,9 @@ [node name="JajceWorld" parent="." instance=ExtResource("1_world")] +[node name="DayNightCycle" parent="JajceWorld" index="9"] +initial_cycle = 0.38 + [node name="BeautyCamera" type="Camera3D" parent="."] position = Vector3(44, 34, 44) current = true diff --git a/world/jajce/day_night_cycle.gd b/world/jajce/day_night_cycle.gd index c2ed4f0..7c653a7 100644 --- a/world/jajce/day_night_cycle.gd +++ b/world/jajce/day_night_cycle.gd @@ -1,6 +1,7 @@ extends Node @export var cycle_duration_seconds := 240.0 +@export_range(0.0, 1.0, 0.01) var initial_cycle := 0.35 @export var directional_light: DirectionalLight3D @export var world_environment: WorldEnvironment @@ -37,6 +38,12 @@ const SUNRISE_SUNSET_ENERGY := 0.8 var elapsed := 0.0 +func _ready() -> void: + elapsed = cycle_duration_seconds * initial_cycle + _apply_light_rotation(initial_cycle) + _apply_environment(initial_cycle) + + func _process(delta: float) -> void: elapsed += delta if elapsed >= cycle_duration_seconds: