Rendering and presentation - Shared surface-material module (src/game/materials.gd) with per-surface roughness/metallic/uv profiles; ACES tonemapping, glow, fog and phase-driven sky energy. WorldBuilder rebuilt on those profiles with facade windows that light up, door trim/handles, curb, lane dashes, bollards, bench, bin and planter foliage. - NPC silhouettes: per-role clothing palettes, caps/hoods/backpacks/sunglasses, hands and shoes, arm/leg walk swing. - Six generated low-poly GLB props (bollards, bench, bin, planter, newspaper box, hydrant) built by tools/model_pipeline.py, loaded by WorldBuilder with a procedural fallback; ADR-0012. Selection and movement - Focus ranking by view angle then distance (NpcFocus.rank_indices); Tab and the mouse wheel cycle nearby people initially, right click clears focus with a re-acquire grace, HUD shows the candidate count, Shift walks at half speed. ADR-0011. Windowed smoke extended to cover wheel cycling and clearing. QA tooling - screen_designs.py catalogue grown to 19 screens (8 scene, 11 UI) plus a `list` subcommand; draft generation keeps existing AI references unless --force. Web export - New Web preset using the non-threaded Godot template (static hosting, no COOP/COEP). tools/build_releases.sh exports build/web and packages build/step-line-web-<ver>.zip; publish_release.sh uploads it with the desktop artifacts. test_web_export.gd covers the preset and release wiring. Verification - Headless suite 177 -> 181, Python tooling 53 tests, all eight smokes pass (including the windowed focus/wheel smoke). Web bundle serves index.html, index.wasm (35 MB) and index.pck (30 MB) with HTTP 200 from a static server. - Version 0.3.0; README, PLAN, RELEASING, TODO/DONE and MEMORY updated.
66 lines
2.9 KiB
GDScript
66 lines
2.9 KiB
GDScript
extends RefCounted
|
|
## Web export target: the preset exists, uses the non-threaded template (so it
|
|
## runs on plain static hosting without COOP/COEP headers), and the release
|
|
## scripts build and publish it.
|
|
|
|
func _preset() -> String:
|
|
## Return the `[preset.N]` block whose name is Web plus its `.options` block.
|
|
var lines := FileAccess.get_file_as_string("res://export_presets.cfg").split("\n")
|
|
var sections := {}
|
|
var current := ""
|
|
var web_id := ""
|
|
for line in lines:
|
|
if line.begins_with("[") and line.ends_with("]"):
|
|
current = line
|
|
sections[current] = PackedStringArray()
|
|
continue
|
|
if sections.has(current):
|
|
# PackedStringArray is a value type: mutate a local and write it back.
|
|
var block: PackedStringArray = sections[current]
|
|
block.append(line)
|
|
sections[current] = block
|
|
if line == 'name="Web"':
|
|
web_id = current.trim_prefix("[").trim_suffix("]")
|
|
if web_id == "":
|
|
return ""
|
|
var out: PackedStringArray = []
|
|
out.append("[%s]" % web_id)
|
|
out.append_array(sections.get("[%s]" % web_id, PackedStringArray()))
|
|
var options := "[%s.options]" % web_id
|
|
if sections.has(options):
|
|
out.append(options)
|
|
out.append_array(sections[options])
|
|
return "\n".join(out)
|
|
|
|
func test_web_preset_exists() -> bool:
|
|
var preset := _preset()
|
|
var a := TestUtils.check(preset != "", "a Web export preset exists")
|
|
var b := TestUtils.check(preset.contains('platform="Web"'), "preset targets the Web platform")
|
|
var c := TestUtils.check(preset.contains('export_path="build/web/index.html"'), "preset writes build/web/index.html")
|
|
return a and b and c
|
|
|
|
func test_web_preset_is_static_hosting_friendly() -> bool:
|
|
var preset := _preset()
|
|
return TestUtils.check(preset.contains("variant/thread_support=false"),
|
|
"threads are disabled so no COOP/COEP headers are required")
|
|
|
|
func test_release_scripts_build_the_web_zip() -> bool:
|
|
var build := FileAccess.get_file_as_string("res://tools/build_releases.sh")
|
|
var a := TestUtils.check(build.contains('--export-release "Web"'), "build script exports Web")
|
|
var b := TestUtils.check(build.contains("step-line-web-${VERSION}.zip"), "build script names the web zip")
|
|
var publish := FileAccess.get_file_as_string("res://tools/publish_release.sh")
|
|
var c := TestUtils.check(publish.contains("step-line-web-$VERSION.zip"), "publish script uploads the web zip")
|
|
return a and b and c
|
|
|
|
func test_web_build_files_present_when_exported() -> bool:
|
|
## Only asserts shape if a web build exists in build/web (created by the
|
|
## release script); missing build output is not a test failure by itself.
|
|
var index := "res://build/web/index.html"
|
|
if not FileAccess.file_exists(index):
|
|
return true
|
|
var html := FileAccess.get_file_as_string(index)
|
|
var a := TestUtils.check(html.contains("index.js"), "index.html loads index.js")
|
|
var b := TestUtils.check(FileAccess.file_exists("res://build/web/index.wasm"), "wasm payload exists")
|
|
var c := TestUtils.check(FileAccess.file_exists("res://build/web/index.pck"), "pck payload exists")
|
|
return a and b and c
|