diff --git a/locale/ui_en.properties b/locale/ui_en.properties
index 6fbd52d..b5f3de2 100644
--- a/locale/ui_en.properties
+++ b/locale/ui_en.properties
@@ -266,3 +266,6 @@ tools/unsaved_discard_text = There are unsaved changes. Discard them?
tools/window_maximize = Maximize / restore (double-click the title)
tools/window_close = Close
tools/menu_title = Tools
+
+# --- Development cover ---
+ui/cover/in_development = In development
diff --git a/locale/ui_es.properties b/locale/ui_es.properties
index 02eb876..d123637 100644
--- a/locale/ui_es.properties
+++ b/locale/ui_es.properties
@@ -266,3 +266,6 @@ tools/unsaved_discard_text = Hay cambios sin guardar. ¿Descartarlos?
tools/window_maximize = Maximizar / restaurar (doble clic en el título)
tools/window_close = Cerrar
tools/menu_title = Herramientas
+
+# --- Development cover ---
+ui/cover/in_development = En desarrollo
diff --git a/locale/ui_ja.properties b/locale/ui_ja.properties
index fdae693..833281f 100644
--- a/locale/ui_ja.properties
+++ b/locale/ui_ja.properties
@@ -266,3 +266,6 @@ tools/unsaved_discard_text = 保存していない変更があります。破棄
tools/window_maximize = 最大化 / 元に戻す(タイトルをダブルクリック)
tools/window_close = 閉じる
tools/menu_title = ツール
+
+# --- Development cover ---
+ui/cover/in_development = 開発中
diff --git a/locale/ui_ko.properties b/locale/ui_ko.properties
index 4184c1a..7c4a6d6 100644
--- a/locale/ui_ko.properties
+++ b/locale/ui_ko.properties
@@ -266,3 +266,6 @@ tools/unsaved_discard_text = 저장하지 않은 변경이 있습니다. 버릴
tools/window_maximize = 최대화 / 복원 (제목 더블클릭)
tools/window_close = 닫기
tools/menu_title = 도구
+
+# --- Development cover ---
+ui/cover/in_development = 개발 중
diff --git a/locale/ui_ru.properties b/locale/ui_ru.properties
index a302d5b..f985478 100644
--- a/locale/ui_ru.properties
+++ b/locale/ui_ru.properties
@@ -266,3 +266,6 @@ tools/unsaved_discard_text = Есть несохранённые изменен
tools/window_maximize = Развернуть / восстановить (двойной клик по заголовку)
tools/window_close = Закрыть
tools/menu_title = Инструменты
+
+# --- Development cover ---
+ui/cover/in_development = В разработке
diff --git a/locale/ui_vi.properties b/locale/ui_vi.properties
index cbb78ad..13fb7ca 100644
--- a/locale/ui_vi.properties
+++ b/locale/ui_vi.properties
@@ -266,3 +266,6 @@ tools/unsaved_discard_text = Có thay đổi chưa lưu. Bỏ chúng?
tools/window_maximize = Phóng to / khôi phục (nhấp đúp vào tiêu đề)
tools/window_close = Đóng
tools/menu_title = Công cụ
+
+# --- Development cover ---
+ui/cover/in_development = Đang phát triển
diff --git a/locale/ui_zh.properties b/locale/ui_zh.properties
index fc0e202..abcd2df 100644
--- a/locale/ui_zh.properties
+++ b/locale/ui_zh.properties
@@ -266,3 +266,6 @@ tools/unsaved_discard_text = 有未保存的更改。要放弃吗?
tools/window_maximize = 最大化 / 还原(双击标题)
tools/window_close = 关闭
tools/menu_title = 工具
+
+# --- Development cover ---
+ui/cover/in_development = 开发中
diff --git a/scenes/ui/development_frame.tscn b/scenes/ui/development_frame.tscn
new file mode 100644
index 0000000..a882e92
--- /dev/null
+++ b/scenes/ui/development_frame.tscn
@@ -0,0 +1,56 @@
+[gd_scene format=3]
+
+[ext_resource type="Texture2D" path="ui_images/development_frame.png" id="1_frame"]
+[ext_resource type="Texture2D" path="ui_images/development_plaque_blank.png" id="2_blank"]
+[ext_resource type="Script" path="res://mods/ui_base/src/Theming/DevelopmentFrame.cs" id="3_script"]
+
+[node name="DevelopmentFrame" type="TextureRect"]
+layout_mode = 1
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+mouse_filter = 2
+texture = ExtResource("1_frame")
+expand_mode = 1
+stretch_mode = 0
+script = ExtResource("3_script")
+
+[node name="Plaque" type="Control" parent="."]
+layout_mode = 0
+offset_right = 1536.0
+offset_bottom = 1024.0
+mouse_filter = 2
+
+[node name="Backing" type="ColorRect" parent="Plaque"]
+layout_mode = 0
+offset_left = 440.0
+offset_top = 895.0
+offset_right = 1096.0
+offset_bottom = 1005.0
+mouse_filter = 2
+color = Color(0, 0, 0, 1)
+
+[node name="Blank" type="TextureRect" parent="Plaque"]
+layout_mode = 0
+offset_left = 440.0
+offset_top = 895.0
+offset_right = 1096.0
+offset_bottom = 1005.0
+mouse_filter = 2
+texture = ExtResource("2_blank")
+expand_mode = 1
+
+[node name="Caption" type="Label" parent="Plaque"]
+layout_mode = 0
+offset_left = 440.0
+offset_top = 895.0
+offset_right = 1096.0
+offset_bottom = 1005.0
+mouse_filter = 2
+theme_override_colors/font_color = Color(1, 0.9, 0, 1)
+theme_override_font_sizes/font_size = 72
+text = "ui/cover/in_development"
+horizontal_alignment = 1
+vertical_alignment = 1
diff --git a/src/Theming/DevelopmentFrame.cs b/src/Theming/DevelopmentFrame.cs
new file mode 100644
index 0000000..0d30aef
--- /dev/null
+++ b/src/Theming/DevelopmentFrame.cs
@@ -0,0 +1,43 @@
+using Godot;
+
+namespace Cthangover.Mods.Interface.Theming
+{
+ ///
+ /// Keeps the localized plaque in the artwork's coordinate system so the same
+ /// prefab fits both small gallery covers and large detail views.
+ ///
+ public partial class DevelopmentFrame : TextureRect
+ {
+ private Control _plaque;
+ private TextureRect _blank;
+ private AtlasTexture _blankTexture;
+
+ public override void _Ready()
+ {
+ _plaque = GetNode("Plaque");
+ _blank = _plaque.GetNode("Blank");
+ // Only the generated blank plaque is used; the original frame keeps
+ // its border and transparent opening. Geometry comes from the prefab.
+ _blankTexture = new AtlasTexture { Atlas = _blank.Texture, Region = _blank.GetRect() };
+ _blank.Texture = _blankTexture;
+ Resized += FitPlaque;
+ FitPlaque();
+ }
+
+ public override void _ExitTree()
+ {
+ Resized -= FitPlaque;
+ if (_blankTexture != null)
+ {
+ _blank.Texture = null;
+ _blankTexture.Dispose();
+ _blankTexture = null;
+ }
+ }
+
+ private void FitPlaque()
+ {
+ _plaque.Scale = Size / Texture.GetSize();
+ }
+ }
+}
diff --git a/src/Theming/UiKit.cs b/src/Theming/UiKit.cs
index 3d25dc8..1629e1a 100644
--- a/src/Theming/UiKit.cs
+++ b/src/Theming/UiKit.cs
@@ -1,4 +1,6 @@
using Cthangover.Core.Mods.Resolvers;
+using Cthangover.Core.Scenes;
+using Cthangover.Core.Utils;
using Godot;
using Cthangover.Core.UI.Theming;
@@ -26,6 +28,14 @@ namespace Cthangover.Mods.Interface.Theming
///
public static class UiKit
{
+ /// Creates a non-interactive cover overlay; its scene owns the generated art and layout.
+ public static Control DevelopmentFrame(string version)
+ {
+ var frame = (Control)TscnScenes.LoadAndBuild("scenes/ui/development_frame.tscn");
+ frame.Visible = VersionHelper.IsInDevelopment(version);
+ return frame;
+ }
+
/// Rounded frame from tokens; pass transparent border to omit it.
public static StyleBoxFlat Frame(int radius, Color background, Color? border = null, int borderWidth = 1)
{
diff --git a/tests/DevelopmentFrameTests.cs b/tests/DevelopmentFrameTests.cs
new file mode 100644
index 0000000..495a73d
--- /dev/null
+++ b/tests/DevelopmentFrameTests.cs
@@ -0,0 +1,32 @@
+namespace Cthangover.Mods.Interface.Theming.Tests
+{
+ using Cthangover.Core.Mods.Testing;
+ using Godot;
+
+ /// Checks the real shared prefab and decoded alpha, including the release version without an overlay.
+ public class DevelopmentFrameTests
+ {
+ [ModTest("covers/development_frame")]
+ static void DevelopmentFrame(ModTestContext ctx)
+ {
+ var frame = UiKit.DevelopmentFrame("0.1.0");
+ var release = UiKit.DevelopmentFrame("1.0.0");
+ try
+ {
+ ModAssert.True(frame.Visible, "zero major is marked");
+ ModAssert.False(release.Visible, "released package is unmarked");
+ ModAssert.Equal((int)Control.MouseFilterEnum.Ignore, (int)frame.MouseFilter, "frame does not intercept cover clicks");
+ var texture = ((TextureRect)frame).Texture;
+ ModAssert.True(texture != null, "generated texture resolves through the mod provider");
+ using var image = texture.GetImage();
+ ModAssert.True(image.GetPixel(image.GetWidth() / 2, image.GetHeight() / 2).A == 0, "centre leaves the game art visible");
+ ModAssert.True(image.GetPixel(image.GetWidth() / 2, 4).A > 0.9f, "hazard tape is visible");
+ }
+ finally
+ {
+ frame.Free();
+ release.Free();
+ }
+ }
+ }
+}
diff --git a/ui_images/development_frame.png b/ui_images/development_frame.png
new file mode 100644
index 0000000..36a39e0
Binary files /dev/null and b/ui_images/development_frame.png differ
diff --git a/ui_images/development_plaque_blank.png b/ui_images/development_plaque_blank.png
new file mode 100644
index 0000000..792a6ad
Binary files /dev/null and b/ui_images/development_plaque_blank.png differ