diff --git a/client/assets/theme/shaders/dark_bay.gdshader b/client/assets/theme/shaders/dark_bay.gdshader new file mode 100644 index 0000000..ff69961 --- /dev/null +++ b/client/assets/theme/shaders/dark_bay.gdshader @@ -0,0 +1,16 @@ +shader_type canvas_item; +uniform vec4 stripe_a : source_color; +uniform vec4 stripe_b : source_color; +uniform float band_px = 16.0; // 16px bands per README +uniform float vignette = 0.55; // edge darkening strength +void fragment() { + // 135deg diagonal stripe: sum of pixel coords, banded. + vec2 px = FRAGCOORD.xy; + float diag = px.x + px.y; + float band = mod(floor(diag / band_px), 2.0); + vec4 base = mix(stripe_a, stripe_b, band); + // radial vignette centred slightly high (README: 50% 38%). + float d = distance(UV, vec2(0.5, 0.38)); + base.rgb *= 1.0 - clamp(d * vignette, 0.0, 1.0); + COLOR = base; +} diff --git a/client/assets/theme/shaders/dark_bay.gdshader.uid b/client/assets/theme/shaders/dark_bay.gdshader.uid new file mode 100644 index 0000000..d10aef5 --- /dev/null +++ b/client/assets/theme/shaders/dark_bay.gdshader.uid @@ -0,0 +1 @@ +uid://jb8clyworwr1 diff --git a/client/assets/theme/shaders/parchment.gdshader b/client/assets/theme/shaders/parchment.gdshader new file mode 100644 index 0000000..8532d89 --- /dev/null +++ b/client/assets/theme/shaders/parchment.gdshader @@ -0,0 +1,6 @@ +shader_type canvas_item; +uniform vec4 top : source_color; +uniform vec4 bottom : source_color; +void fragment() { + COLOR = mix(top, bottom, UV.y); +} diff --git a/client/assets/theme/shaders/parchment.gdshader.uid b/client/assets/theme/shaders/parchment.gdshader.uid new file mode 100644 index 0000000..4aef44d --- /dev/null +++ b/client/assets/theme/shaders/parchment.gdshader.uid @@ -0,0 +1 @@ +uid://b2heb6jhvwxxl diff --git a/client/assets/theme/shaders/vignette.gdshader b/client/assets/theme/shaders/vignette.gdshader new file mode 100644 index 0000000..ec1cb54 --- /dev/null +++ b/client/assets/theme/shaders/vignette.gdshader @@ -0,0 +1,6 @@ +shader_type canvas_item; +uniform float strength = 0.62; +void fragment() { + float d = distance(UV, vec2(0.5)); + COLOR = vec4(0.0, 0.0, 0.0, clamp(d * strength, 0.0, 1.0)); +} diff --git a/client/assets/theme/shaders/vignette.gdshader.uid b/client/assets/theme/shaders/vignette.gdshader.uid new file mode 100644 index 0000000..5334880 --- /dev/null +++ b/client/assets/theme/shaders/vignette.gdshader.uid @@ -0,0 +1 @@ +uid://b4tami4peyxaw diff --git a/client/scenes/theme/surfaces/DarkBay.tscn b/client/scenes/theme/surfaces/DarkBay.tscn new file mode 100644 index 0000000..0ada4c5 --- /dev/null +++ b/client/scenes/theme/surfaces/DarkBay.tscn @@ -0,0 +1,5 @@ +[gd_scene load_steps=2 format=3] +[ext_resource type="Script" path="res://scripts/theme/surfaces/dark_bay.gd" id="1"] +[node name="DarkBay" type="Panel"] +anchors_preset = 15 +script = ExtResource("1") diff --git a/client/scenes/theme/surfaces/ParchmentPanel.tscn b/client/scenes/theme/surfaces/ParchmentPanel.tscn new file mode 100644 index 0000000..9ca9029 --- /dev/null +++ b/client/scenes/theme/surfaces/ParchmentPanel.tscn @@ -0,0 +1,5 @@ +[gd_scene load_steps=2 format=3] +[ext_resource type="Script" path="res://scripts/theme/surfaces/parchment_panel.gd" id="1"] +[node name="ParchmentPanel" type="Panel"] +anchors_preset = 15 +script = ExtResource("1") diff --git a/client/scenes/theme/surfaces/VignetteOverlay.tscn b/client/scenes/theme/surfaces/VignetteOverlay.tscn new file mode 100644 index 0000000..4e22b68 --- /dev/null +++ b/client/scenes/theme/surfaces/VignetteOverlay.tscn @@ -0,0 +1,5 @@ +[gd_scene load_steps=2 format=3] +[ext_resource type="Script" path="res://scripts/theme/surfaces/vignette_overlay.gd" id="1"] +[node name="VignetteOverlay" type="ColorRect"] +anchors_preset = 15 +script = ExtResource("1") diff --git a/client/scripts/theme/surfaces/dark_bay.gd b/client/scripts/theme/surfaces/dark_bay.gd new file mode 100644 index 0000000..bf74224 --- /dev/null +++ b/client/scripts/theme/surfaces/dark_bay.gd @@ -0,0 +1,12 @@ +class_name DarkBay +extends Panel +## Drop-in dark stripe+vignette bay backdrop. §2: presentation. +const Palette = preload("res://scripts/theme/palette.gd") + + +func _ready() -> void: + var m := ShaderMaterial.new() + m.shader = load("res://assets/theme/shaders/dark_bay.gdshader") + m.set_shader_parameter("stripe_a", Palette.BAY_STRIPE_A) + m.set_shader_parameter("stripe_b", Palette.BAY_STRIPE_B) + material = m diff --git a/client/scripts/theme/surfaces/dark_bay.gd.uid b/client/scripts/theme/surfaces/dark_bay.gd.uid new file mode 100644 index 0000000..fc4fabf --- /dev/null +++ b/client/scripts/theme/surfaces/dark_bay.gd.uid @@ -0,0 +1 @@ +uid://24c8pl0yx8wu diff --git a/client/scripts/theme/surfaces/parchment_panel.gd b/client/scripts/theme/surfaces/parchment_panel.gd new file mode 100644 index 0000000..0db054e --- /dev/null +++ b/client/scripts/theme/surfaces/parchment_panel.gd @@ -0,0 +1,12 @@ +class_name ParchmentPanel +extends Panel +## Drop-in parchment backdrop (mockups "Dark Bay + Parchment" motif). §2: presentation. +const Palette = preload("res://scripts/theme/palette.gd") + + +func _ready() -> void: + var m := ShaderMaterial.new() + m.shader = load("res://assets/theme/shaders/parchment.gdshader") + m.set_shader_parameter("top", Palette.SHEET_TOP) + m.set_shader_parameter("bottom", Palette.SHEET_BOTTOM) + material = m diff --git a/client/scripts/theme/surfaces/parchment_panel.gd.uid b/client/scripts/theme/surfaces/parchment_panel.gd.uid new file mode 100644 index 0000000..6be5eb2 --- /dev/null +++ b/client/scripts/theme/surfaces/parchment_panel.gd.uid @@ -0,0 +1 @@ +uid://cnv1r00ane2la diff --git a/client/scripts/theme/surfaces/vignette_overlay.gd b/client/scripts/theme/surfaces/vignette_overlay.gd new file mode 100644 index 0000000..9fcbcf3 --- /dev/null +++ b/client/scripts/theme/surfaces/vignette_overlay.gd @@ -0,0 +1,11 @@ +class_name VignetteOverlay +extends ColorRect +## Drop-in edge-dim overlay for pause/dialogue dim. §2: presentation. + + +func _ready() -> void: + color = Color(0, 0, 0, 0) # base transparent; shader draws the dim + mouse_filter = Control.MOUSE_FILTER_IGNORE + var m := ShaderMaterial.new() + m.shader = load("res://assets/theme/shaders/vignette.gdshader") + material = m diff --git a/client/scripts/theme/surfaces/vignette_overlay.gd.uid b/client/scripts/theme/surfaces/vignette_overlay.gd.uid new file mode 100644 index 0000000..181a2f4 --- /dev/null +++ b/client/scripts/theme/surfaces/vignette_overlay.gd.uid @@ -0,0 +1 @@ +uid://7bc7agrl6oi0 diff --git a/client/tests/unit/test_surfaces.gd b/client/tests/unit/test_surfaces.gd new file mode 100644 index 0000000..7edb200 --- /dev/null +++ b/client/tests/unit/test_surfaces.gd @@ -0,0 +1,17 @@ +extends "res://addons/gut/test.gd" + +const SCENES := [ + "res://scenes/theme/surfaces/ParchmentPanel.tscn", + "res://scenes/theme/surfaces/DarkBay.tscn", + "res://scenes/theme/surfaces/VignetteOverlay.tscn", +] + + +func test_surfaces_instance_with_shader_material(): + for path in SCENES: + var packed = load(path) + assert_true(packed is PackedScene, "not a scene: %s" % path) + var node = packed.instantiate() + add_child_autofree(node) # triggers _ready() + assert_true(node.material is ShaderMaterial, "%s has no ShaderMaterial" % path) + assert_true(node.material.shader is Shader, "%s shader missing" % path) diff --git a/client/tests/unit/test_surfaces.gd.uid b/client/tests/unit/test_surfaces.gd.uid new file mode 100644 index 0000000..a1976d9 --- /dev/null +++ b/client/tests/unit/test_surfaces.gd.uid @@ -0,0 +1 @@ +uid://csc3r7lqoe83d