scenario-godot-ui

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Godot UI (UI developer)

Godot UI(UI 开发者)

Target: Godot 4.7.2.stable, macOS Apple Silicon.
Expert level here means one layout proven, by numbers and images, from a 1080x2400 phone in portrait to a 3840x2160 monitor, in every language, with mouse, pad and screen reader. The stretch transform scales, containers place, one Theme built in code styles, and nothing ships before a layout matrix and a contact sheet say so. If a sibling skill named here is missing from your available skills, ask the user to install it (
npx skills add scenario-labs/skills --skill <name>
); unattended, proceed from tool schemas and flag the gap.
REQUIRED BACKGROUND: scenario-godot-expert (channels, review loop, 6.3 traps).
目标环境:Godot 4.7.2.stable,macOS Apple Silicon。
这里的专家级意味着:通过数字和图像验证同一套布局,从竖屏 1080x2400 手机到 3840x2160 显示器,在所有语言下均可配合鼠标、手柄和 screen reader 使用。stretch transform 负责缩放,containers 负责放置,一个以代码构建的 Theme 负责样式;在 layout matrix 和 contact sheet 给出结论之前,不会发布任何内容。如果此处提到的某个 sibling skill 不在可用 skills 中,请要求用户安装它(
npx skills add scenario-labs/skills --skill <name>
);在无人值守模式下,则根据 tool schemas 继续,并标记这一缺口。
必需背景: scenario-godot-expert(channels、review loop、6.3 个陷阱)。

Stance (the expert delta)

核心准则(专家级差异)

  1. Pick the base size for the extremes, not for 1080p. A square base (720x720) with
    canvas_items
    +
    expand
    and Handheld Orientation
    sensor
    gives one scale for portrait and landscape (docs, Multiple resolutions). Measured: 1.5x on a 1080x2400 phone in both orientations, 3x on 4K. A 1152x648 base gives a 0.9375x canvas on the same phone and three undersized buttons [added, measured]. Godotneers' 1920x1080 base (1_OFJLyqlXI) suits desktop only.
  2. Containers place, anchors pin. Sizing is a negotiation: the minimum size is the floor, Expand claims leftover space, Fill uses it (Godotneers 1_OFJLyqlXI 00:35:00, Karto 5Hog6a0EYa0 00:14:39). Measured in a 400 px HBox: Expand without Fill leaves the claimed space empty (sibling pushed to x 380); Fill or a stretch ratio without Expand changes nothing; ratios are summed, 1:3 gives 96 and 290 of 386 px (Karto 00:15:45). Anchor presets are relative to the parent;
    set_anchors_preset()
    alone keeps the old offsets (a 50x50 child stays 50x50 on FULL_RECT), so use
    set_anchors_and_offsets_preset()
    (Karto 00:05:24, measured). A corner element also needs its grow direction, or longer text grows off screen [added, measured 1462 px wide in a 1152 px canvas].
  3. The look lives in one Theme resource built in code, with type variations instead of per-node overrides (docs, Theme type variations). StyleBoxes are shared Resources: an override reused on two nodes changes both (Karto 00:19:00).
  4. Focus is explicit. Nothing has focus at scene start, so
    ui_down
    does nothing until something calls
    grab_focus()
    (docs, Controller navigation; measured). Keep a menu stack that disables covered panels and returns focus to the opener (Mostly Mad Productions ecJZipjUj6k 00:08:57).
  5. The current selection is the highest-contrast element on screen, body text comes first, two or three fonts at most, and the outro is faster than the intro (Rawb Herb, GodotCon 2025, sjmAD1ZLBcE 00:31:42, 00:21:34, 00:55:38).
  6. Text is keys, never literals. Named placeholders with
    format()
    ,
    tr_n()
    for plurals, context for identical English, auto translate disabled on dynamic text (docs, Internationalizing games). Fonts get fallbacks, not remaps.
  7. HUD is passive and signal-driven. Its root and wrappers ignore the mouse; values change on signals, not in
    _process
    (consensus of 1_OFJLyqlXI, Yuw7CK5H8eA, f90ieBOoIYQ). A new string reshapes (200 labels: 1.1 to 1.5 ms of CPU per frame); assigning the identical string is an early-out, so the cost is the changed text, not the assignment [added, measured]. In-place array mutations never call a setter (0 calls after
    append
    , 1 after reassigning), so state arrays emit their own signal (NoBSGodot Yuw7CK5H8eA 00:05:06, measured).
  8. Verify at device sizes headless, then look. Headless,
    root.size
    takes any size and applies the project stretch, so a layout matrix runs in seconds; a windowed capture then renders each device with the notch drawn in [added, measured].
  1. 根据极端尺寸而不是 1080p 选择基础尺寸。 使用 720x720 的正方形基础尺寸,配合
    canvas_items
    +
    expand
    和 Handheld Orientation
    sensor
    ,可为竖屏和横屏提供统一缩放(docs,Multiple resolutions)。实测:1080x2400 手机在两个方向上均为 1.5x,4K 上为 3x。1152x648 基础尺寸在同一手机上会得到 0.9375x canvas 和三个过小的按钮 [added, measured]。Godotneers 的 1920x1080 基础尺寸(1_OFJLyqlXI)仅适合桌面端。
  2. Containers 负责放置,anchors 负责固定。 尺寸分配是一场协商:minimum size 是下限,Expand 占用剩余空间,Fill 使用这些空间(Godotneers 1_OFJLyqlXI 00:35:00,Karto 5Hog6a0EYa0 00:14:39)。在 400 px HBox 中实测:不带 Fill 的 Expand 会让其占用的空间保持为空(相邻项被推到 x=380);不带 Expand 的 Fill 或 stretch ratio 不会改变任何内容;比例会相加,1:3 在总计 386 px 中分配为 96 和 290 px(Karto 00:15:45)。Anchor presets 相对于 parent;仅调用
    set_anchors_preset()
    会保留旧 offsets(在 FULL_RECT 上,50x50 子节点仍为 50x50),因此应使用
    set_anchors_and_offsets_preset()
    (Karto 00:05:24,measured)。角落元素还必须设置 grow direction,否则较长的文字会扩展到屏幕外 [added,measured:在 1152 canvas 中宽达 1462 px]。
  3. **所有视觉样式都集中在一个以代码构建的 Theme resource 中,**使用 type variations,而不是逐节点 override(docs,Theme type variations)。StyleBoxes 是共享 Resource:复用在两个节点上的 override 会同时改变两者(Karto 00:19:00)。
  4. Focus 是显式的。 场景启动时没有任何内容获得 focus,因此直到某个节点调用
    grab_focus()
    前,
    ui_down
    都不会执行任何操作(docs,Controller navigation;measured)。维护一个 menu stack,用于禁用被覆盖的面板,并将焦点还给打开它的元素(Mostly Mad Productions ecJZipjUj6k 00:08:57)。
  5. **当前选中项必须是屏幕上对比度最高的元素,**正文文本优先,字体最多使用两三种,outro 要比 intro 更快(Rawb Herb,GodotCon 2025,sjmAD1ZLBcE 00:31:42、00:21:34、00:55:38)。
  6. 文本必须是 key,绝不能是字面量。 使用带命名 placeholders 的
    format()
    ,使用
    tr_n()
    处理 plurals,为相同的英文文本提供 context,并对动态文本禁用 auto translate(docs,Internationalizing games)。Fonts 使用 fallbacks,而不是 remaps。
  7. HUD 应保持被动并由 signal 驱动。 其 root 和 wrappers 忽略鼠标;数值通过 signals 变化,而不是在
    _process
    中变化(1_OFJLyqlXI、Yuw7CK5H8eA、f90ieBOoIYQ 的共识)。新字符串会触发重新排版(200 个 labels:每帧 1.1 至 1.5 ms CPU);为相同字符串赋值会提前退出,因此开销来自变化的文本,而不是赋值操作本身 [added, measured]。原地修改 array 永远不会调用 setter(
    append
    后调用 0 次,重新赋值后调用 1 次),因此 state arrays 应发出自己的 signal(NoBSGodot Yuw7CK5H8eA 00:05:06,measured)。
  8. 先在设备尺寸下进行 headless 验证,再目视检查。 在 headless 模式下,
    root.size
    可接受任意尺寸并应用项目 stretch,因此 layout matrix 数秒即可运行;随后通过 windowed capture,以实际设备尺寸渲染每个目标并绘制刘海区域 [added, measured]。

Establish first

首先确定

InputChangesDefault if nobody says
Platforms and orientationsbase size, orientation, touch target sizephone portrait + landscape, desktop to 4K: base 720x720,
canvas_items
,
expand
, orientation 6 (sensor)
Art stylestretch mode and scale modevector or high-res:
canvas_items
+ fractional; pixel art:
viewport
, base 640x360, integer, Exclusive Fullscreen (docs)
Input devicesfocus work, rebind screen, touch sizesmouse, keyboard, pad, touch
Languagesfonts, RTL, Text Server Data on exporten plus one long (de), one CJK (ja), one RTL (ar) for tests
Accessibility barscreen reader, UI scale slider, contrastWCAG 4.5:1 body text, UI scale 0.75 to 2.0 via
content_scale_factor
Rendererupscaler choice in settingsForward+ (Jolt kept); Compatibility forces bilinear 3D scaling
输入更改内容未另行说明时的默认值
平台与方向基础尺寸、方向、触控目标尺寸手机竖屏 + 横屏,以及桌面端到 4K:基础尺寸 720x720,
canvas_items
,
expand
,orientation 6(sensor)
美术风格stretch mode 和 scale mode矢量或高分辨率:
canvas_items
+ fractional;像素艺术:
viewport
,基础尺寸 640x360,integer,Exclusive Fullscreen(docs)
输入设备focus 工作、rebind 界面、触控尺寸鼠标、键盘、手柄、触控
语言字体、RTL、导出时的 Text Server Dataen,外加一个字符较长的语言(de)、一个 CJK 语言(ja)和一个 RTL 语言(ar)用于测试
无障碍基线screen reader、UI scale 滑块、对比度正文文字符合 WCAG 4.5:1;通过
content_scale_factor
提供 0.75 至 2.0 的 UI scale
Renderer设置中的 upscaler 选择Forward+(保留 Jolt);Compatibility 强制使用 bilinear 3D scaling

Workflow

Workflow

1. Project settings. Write the stretch keys explicitly: a hand-written project.godot gets
disabled
and
keep
(deltas).
gd_env.set_project_setting
for
display/window/size/viewport_width/height
,
stretch/mode
,
stretch/aspect
,
handheld/orientation
,
gui/theme/custom
. Check that
3d/physics_engine="Jolt Physics"
and the renderer survived. GATE:
gd_ui.stretch_math(window, base, ...)
for each target gives the expected logical size and scale (port matches the engine on 224 cases, origin and scale included).
2. Theme in code.
ui_theme.gd
build(overrides)
returns a Theme: Button states with a thick accent focus box, Label, panels, sliders, tabs, ProgressBar, variations TitleLabel, HudLabel, HudValue, PrimaryButton, HudPanel, HealthBar, TrailBar. Save it as
.tres
, set the default font to a SystemFont with CJK and Arabic fallbacks, two or three fonts at most. Text drawn at many scales (HUD numerals at 3x) gets MSDF:
gui/theme/default_font_multichannel_signed_distance_field
or the font's
multichannel_signed_distance_field
, both false by default (Karto 5Hog6a0EYa0 00:20:50, measured). Default Theme Scale is read once: a runtime set changed nothing (measured). In the editor a Theme edit needs a scene reload to repaint (Godotneers 00:22:10) and an override is inactive until its checkbox is ticked (Karto 00:17:25); in code only
add_theme_*_override
counts, and runtime Theme edits propagate at once (measured). GATE:
contrast_report()
body pairs >= 4.5:1 (worst measured 4.37 is the disabled state, allowed);
check_variations()
finds no misspelt variation.
3. Scenes in code. Root Control full rect, a
safe_area.gd
MarginContainer, then containers. Buttons 88 logical tall at a 720 base (132 px on a phone at 1.5x). Settings rows in ScrollContainers inside a TabContainer. HUD on a CanvasLayer, root
MOUSE_FILTER_IGNORE
, AspectRatioContainer for the minimap; a round minimap or portrait frame is a
clip_children
mask (Clip Only on a rounded Panel), but a child with another
z_index
escapes it (GDQuest W4j4tnQLcTA 00:03:47, measured), so keep masked content at z 0 or use a SubViewport. Toggles read "On"/"Off" as text (CoffeeCrow 9H_fN4OxyIE 00:08:11).
safe_area.gd
recomputes on
size_changed
(top margin 104 at 1.5x, 82 at 2x, measured).
examples/build_g7.gd
builds the whole G7 set. GATE:
ui_audit.gd
audit_tree()
returns no
hud_blocks_input
,
icon_keep_size
,
grows_offscreen_*
,
no_accessible_name
,
shared_stylebox_override
,
unknown_variation
.
4. Layout matrix headless.
gd_ui.layout_matrix(P, scene, targets, min_touch_px=..., safe_insets=..., locale=..., pseudo=True)
for 8 targets (phone portrait and landscape, 4:3 tablet, 1366x768, 1080p, 21:9, 4K, 800x600). GATE: zero offscreen, outside_safe, small_target, text (clipped or overflowing), overlap and collapsed issues for each scene, in en, de and pseudolocalized at 0.4 expansion.
5. Capture matrix windowed, then look.
gd_ui.capture_matrix(P, scene, targets, safe_insets=...)
renders each target at its physical size with black bars and red notch bands, and builds a contact sheet. Open the sheet. GATE:
image_checks
flags none; by eye: selection visible, no clipped glyphs (CJK, Arabic), notch bands over background only, bars and frames intact. Never capture through an embedded Window with
content_scale_*
: it draws unscaled (P13, measured).
6. Focus and input.
gd_ui.focus_walk(P, scene, steps)
pushes
ui_*
actions through
push_input
and records the focus owner;
ui_focus.graph()
lists unreachable focusables. Menu stack: open, cancel, focus back on the opener. GATE: every focusable reachable from the default; first key press from no focus lands on the default; covered panels unreachable.
7. Rebinding.
ui_rebind.gd
: accept (no echo, no Escape, sticks over 0.5), normalize (physical keycode, device -1, axis sign), report conflicts, swap or refuse, save as ConfigFile, reset from project settings. Show the key with
DisplayServer.keyboard_get_label_from_physical()
(windowed only): on a French layout physical Q reads "A" (measured). Add pad buttons yourself: in 4.7.2
ui_accept
and
ui_cancel
hold keys only (Enter, Kp Enter, Space; Escape), so add Joypad Button 0 and 1 (Mostly Mad ecJZipjUj6k 00:12:00, measured). GATE: binding matches on keyboard and on any pad after a save and load round trip.
8. Localization. CSV with a
?plural
column,
gd_ui.check_csv
offline,
--import
, then
gd_ui.register_translations
. Run en, fr, de, ja, ar and pseudolocalization;
expansion_ratio
defaults to 0.0, so set 0.3 to 0.4 and call
reload_pseudolocalization()
(measured).
--language fr
is the non-persistent test. Animated text is a RichTextEffect:
bbcode
var plus
_process_custom_fx(char_fx)
, options from
char_fx.env
(Cashew OldDew KMqYeRae6rM 00:14:01; measured
[lift px=6]
read 6.0), installed with
install_effect()
. GATE: no missing keys per locale; Arabic mirrors (anchors and HBox order); plurals right in en and fr; layout matrix clean.
9. Settings and cost.
ui_settings.gd
autoload applies window mode, vsync, render scale and upscaler, quality, UI scale, bus volumes, locale; saves and reloads. GATE: save and load round trip;
ui_scale
1.5 turns a 1280x720 canvas into 853x480.
1. 项目设置。 明确写出 stretch keys:手写的 project.godot 会得到
disabled
和
keep
(deltas)。使用
gd_env.set_project_setting
设置
display/window/size/viewport_width/height
、
stretch/mode
、
stretch/aspect
、
handheld/orientation
、
gui/theme/custom
。确认
3d/physics_engine="Jolt Physics"
和 renderer 均已保留。 GATE:对每个目标调用
gd_ui.stretch_math(window, base, ...)
,得到预期的 logical size 和 scale(移植实现与引擎在 224 个用例中一致,包括 origin 和 scale)。
2. 以代码构建 Theme。
ui_theme.gd
的
build(overrides)
返回一个 Theme:包含带粗 accent focus box 的 Button 状态、Label、面板、滑块、标签页、ProgressBar,以及 TitleLabel、HudLabel、HudValue、PrimaryButton、HudPanel、HealthBar、TrailBar 等 variations。将其保存为
.tres
,将默认字体设为带 CJK 和 Arabic fallbacks 的 SystemFont,字体最多使用两三种。以多种缩放级别绘制的文字(例如放大 3x 的 HUD 数字)应使用 MSDF:
gui/theme/default_font_multichannel_signed_distance_field
或字体的
multichannel_signed_distance_field
,两者默认均为 false(Karto 5Hog6a0EYa0 00:20:50,measured)。Default Theme Scale 只读取一次:运行时设置不会产生变化(measured)。在编辑器中修改 Theme 后,需要重新加载场景才能重绘(Godotneers 00:22:10);override 在勾选其复选框前不会生效(Karto 00:17:25);在代码中只有
add_theme_*_override
生效,而运行时 Theme 修改会立即传播(measured)。 GATE:
contrast_report()
显示正文颜色组合均 >= 4.5:1(实测最差值 4.37 来自 disabled 状态,允许);
check_variations()
未发现拼写错误的 variation。
3. 以代码构建 Scenes。 根节点为铺满全屏的 Control,随后是
safe_area.gd
MarginContainer,再其后是各个 containers。以 720 为基础尺寸时,按钮逻辑高度为 88(手机上以 1.5x 缩放后为 132 px)。设置项放在 TabContainer 内的 ScrollContainers 中。HUD 位于 CanvasLayer 上,root 使用
MOUSE_FILTER_IGNORE
,小地图使用 AspectRatioContainer;圆形小地图或竖屏边框使用
clip_children
遮罩(圆角 Panel 上使用 Clip Only),但具有另一个
z_index
的子节点会逃出遮罩(GDQuest W4j4tnQLcTA 00:03:47,measured),因此被遮罩内容应保持在 z 0,或改用 SubViewport。Toggles 以“On”/“Off”文本显示(CoffeeCrow 9H_fN4OxyIE 00:08:11)。
safe_area.gd
在
size_changed
时重新计算边距(1.5x 时顶部边距为 104,2x 时为 82,measured)。
examples/build_g7.gd
会构建完整的 G7 集合。 GATE:
ui_audit.gd
的
audit_tree()
不应返回
hud_blocks_input
、
icon_keep_size
、
grows_offscreen_*
、
no_accessible_name
、
shared_stylebox_override
或
unknown_variation
。
4. Headless Layout Matrix。 对 8 个目标运行
gd_ui.layout_matrix(P, scene, targets, min_touch_px=..., safe_insets=..., locale=..., pseudo=True)
(手机竖屏和横屏、4:3 平板、1366x768、1080p、21:9、4K、800x600)。 GATE:每个 scene 在 en、de 以及扩展 0.4 倍的伪本地化环境下,offscreen、outside_safe、small_target、text(裁切或溢出)、overlap 和 collapsed 问题均为零。
5. Windowed Capture Matrix,然后目视检查。
gd_ui.capture_matrix(P, scene, targets, safe_insets=...)
会按各目标的物理尺寸进行渲染,显示黑边和红色刘海条带,并生成 contact sheet。打开 contact sheet。 GATE:
image_checks
不报告任何问题;目视检查:选中项可见,CJK 和 Arabic 字形完整,刘海条带仅覆盖背景,黑边和边框保持完整。绝不要通过带有
content_scale_*
的 embedded Window 进行 capture:它会按未缩放方式绘制(P13,measured)。
6. Focus 与输入。
gd_ui.focus_walk(P, scene, steps)
通过
push_input
推送
ui_*
actions,并记录 focus owner;
ui_focus.graph()
列出无法到达的 focusables。Menu stack:打开、取消,并将焦点恢复到打开者。 GATE:每个 focusable 都能从默认项到达;首次按键时焦点会落在默认项上;被覆盖的面板不可到达。
7. Rebinding。
ui_rebind.gd
:接受绑定时不产生回显、不响应 Escape,摇杆值需大于 0.5;标准化 physical keycode、device -1 和 axis sign;报告冲突,并交换或拒绝冲突绑定;保存为 ConfigFile,并从项目设置重置。通过
DisplayServer.keyboard_get_label_from_physical()
显示按键(仅限 windowed):在 French 布局中,physical Q 显示为“A”(measured)。需要自行添加手柄按钮:在 4.7.2 中,
ui_accept
和
ui_cancel
仅绑定键盘按键(Enter、Kp Enter、Space;Escape),因此应添加 Joypad Button 0 和 1(Mostly Mad ecJZipjUj6k 00:12:00,measured)。 GATE:保存并重新加载后,绑定在键盘和任意手柄上都能匹配。
8. 本地化。 CSV 包含
?plural
列,离线运行
gd_ui.check_csv
,然后执行
--import
和
gd_ui.register_translations
。运行 en、fr、de、ja、ar 和 pseudolocalization;
expansion_ratio
默认为 0.0,因此应设置为 0.3 至 0.4,并调用
reload_pseudolocalization()
(measured)。
--language fr
是非持久化测试方式。动画文字使用 RichTextEffect:包含
bbcode
var 和
_process_custom_fx(char_fx)
,选项来自
char_fx.env
(Cashew OldDew KMqYeRae6rM 00:14:01;实测
[lift px=6]
读取为 6.0),并通过
install_effect()
安装。 GATE:每个 locale 均无缺失 key;Arabic 正确镜像(anchors 和 HBox 顺序);en 和 fr 的 plurals 正确;layout matrix 无问题。
9. 设置与开销。
ui_settings.gd
autoload 应用 window mode、vsync、render scale、upscaler、quality、UI scale、bus volumes 和 locale;并负责保存与重新加载。 GATE:保存和加载 round trip 正常;
ui_scale
为 1.5 时,1280x720 canvas 会变为 853x480。

Numbers

数值

ValueRelative toSource
Base 720x720,
canvas_items
,
expand
, orientation sensor
phone portrait and landscape plus desktopdocs, Multiple resolutions
Scale 1.5 on 1080x2400 and 2400x1080, 3.0 on 3840x2160, 1.0672 on 1366x768base 720x720measured [added]
Base 720x1280 on a 2400x1080 phone:
expand
2844x1280 at 0.844x (UI shrinks),
keep_width
897 px side bars;
keep_height
on 1080x2400: 240 px bars
why a square base beats an aspect choicemeasured [added]
Pixel art 640x360
viewport
integer;
viewport
at fractional 1.0672 (1366x768) resamples and blurs text
720p to 4Kdocs, measured
Default Theme Scale 2.0 to 3.0 for a 4K base, 1.5 to 2.0 mobile 1080p base; read once (runtime set: no change)base sizedocs, measured
Touch target 126 px phone, 96 px tablet (48 dp at about 420 and 320 dpi)physical pixels[added]
Button 88 logical at base 720132 px on a phone[added, measured]
WCAG 4.5:1 body, 3:1 large texttext vs its backgroundWCAG 2 [added]
Damage trail: one-shot timer 0.4 s, restarted per hit; heal instanthealth changeDashNothing f90ieBOoIYQ 00:01:26
Text Server Data ~4 MBexport size, for no-space scriptsdocs
200 labels: 1.1 to 1.5 ms new text every frame, 0.17 to 0.23 ms for 10 per frame, under 0.1 ms same text (as idle)CPU per frame, headless M5 Maxmeasured [added]
数值相对于来源
基础尺寸 720x720,
canvas_items
,
expand
,orientation sensor
手机竖屏和横屏,以及桌面端docs,Multiple resolutions
1080x2400 和 2400x1080 上缩放为 1.5,3840x2160 上为 3.0,1366x768 上为 1.0672基础尺寸 720x720measured [added]
2400x1080 手机采用 720x1280 基础尺寸:
expand
得到 2844x1280、缩放 0.844x(UI 缩小),
keep_width
产生 897 px 侧边栏;1080x2400 上使用
keep_height
会产生 240 px 边条
说明为何正方形基础尺寸优于按宽高比选择measured [added]
像素艺术使用 640x360
viewport
和 integer;在 1366x768 上以 fractional 1.0672 使用
viewport
会重新采样并使文字模糊
720p 到 4Kdocs,measured
4K 基础尺寸的 Default Theme Scale 为 2.0 至 3.0,手机 1080p 基础尺寸为 1.5 至 2.0;只读取一次(运行时设置:无变化)基础尺寸docs,measured
手机触控目标 126 px,平板 96 px(约 420 和 320 dpi 下为 48 dp)物理像素[added]
以 720 为基础尺寸时,按钮逻辑高度为 88手机上为 132 px[added, measured]
WCAG:正文 4.5:1,大号文字 3:1文字与其背景WCAG 2 [added]
伤害拖尾:单次计时器 0.4 s,每次受击重新开始;治疗立即生效生命值变化DashNothing f90ieBOoIYQ 00:01:26
Text Server Data 约 4 MB导出体积,用于无空格脚本docs
200 个 labels:每帧更新新文字耗时 1.1 至 1.5 ms;每帧更新 10 个耗时 0.17 至 0.23 ms;文字相同时低于 0.1 ms(等同空闲状态)headless M5 Max 上的每帧 CPU 开销measured [added]

Quality gates

Quality gates

Measurable:
test_ui_live.py
U1 to U15 green (compile, stretch parity, CSV, layout matrix, capture, focus, rebind, HUD, localization, engine facts, theme and settings, cost, embedded Window, round-2 layout and theme facts, clip mask and text effect); zero issues in the layout matrix for each scene and locale; audit clean; contrast >= 4.5:1 on body pairs; save and load round trips. Visual: one contact sheet per scene and locale (menu, HUD, settings ja, menu ar, settings pseudo), opened: focus visible, glyphs complete, nothing under the notch, letterbox where expected, selection still visible in grayscale (Rawb Herb).
可量化检查:
test_ui_live.py
的 U1 到 U15 全部通过(compile、stretch parity、CSV、layout matrix、capture、focus、rebind、HUD、localization、engine facts、theme 和 settings、cost、embedded Window、第二轮 layout 和 theme facts、clip mask 和 text effect);每个 scene 和 locale 的 layout matrix 均为零问题;audit 无异常;正文颜色组合 >= 4.5:1;保存和加载 round trip 正常。
视觉检查:每个 scene 和 locale 都要有一张 contact sheet(menu、HUD、settings ja、menu ar、settings pseudo),并实际打开检查:focus 可见,字形完整,没有内容位于刘海区域下方,letterbox 出现在预期位置,选中项在灰度下仍然可见(Rawb Herb)。

Common mistakes

常见错误

MistakeWhat it looks likeFix
1920x1080 or 1152x648 base for a phone gametiny buttons in portrait (scale 0.9375 at 1080x2400)square base 720x720 + expand
Stretch keys left out of an agent-written project.godotUI fixed size, black space on 4Kwrite mode and aspect explicitly
Full-rect Control with default STOP filter over the gameclicks never reach
_unhandled_input
(0 of 1)
MOUSE_FILTER_IGNORE
on HUD roots and wrappers
Corner preset without grow directionscore text runs off the right edge
grow_horizontal = GROW_DIRECTION_BEGIN
No
grab_focus()
on open
pad does nothingmenu stack grabs the default on the first nav event
TextureRect left on
KEEP_SIZE
in a container
a 512 px icon makes a 64 px row 614x512;
IGNORE_SIZE
with no minimum collapses to width 0
EXPAND_FIT_WIDTH_PROPORTIONAL
(64x64 measured) or ignore size + min size, Stretch Keep Aspect Centered (Godotneers 1_OFJLyqlXI 00:10:28)
OptionButton items as literal EnglishJapanese screen shows "Windowed"items as keys (
OPT_WINDOWED
)
Tabs left at theme defaulttabs too small to touchtab styleboxes with content margins; the matrix checks the TabBar
Stored binding with device 0 from a synthesized eventpad 2 or the real keyboard (device 16) do not triggernormalize to device -1
Pseudolocalization on, expansion untouched or no reloadno padding (default ratio 0.0)set
expansion_ratio
,
TranslationServer.reload_pseudolocalization()
POT generation trusted for custom nodes in old tutorialsstrings missing (4.2 bug)fixed in 4.3 (Cashew OldDew v0tJPsNNOM8 00:08:00, not rerun); CSV keys avoid POT
Locale Test set in project settingsships in Frenchclear it; use
--language fr
Hiding a container child with
visible = false
for an effect
siblings jump (relayout)
modulate.a = 0
or
offset_transform_scale
(MrElipteach pK2vI2-jCH4 00:02:54)
Expecting a focus ring after a mouse clickring only on the next key or pad pressby design:
gui/common/show_focus_state_on_pointer_event
1 (text inputs only)
错误表现修复方式
为手机游戏使用 1920x1080 或 1152x648 基础尺寸竖屏中按钮过小(1080x2400 上缩放为 0.9375)使用正方形基础尺寸 720x720 +
expand
由 agent 编写的 project.godot 中遗漏 stretch keysUI 尺寸固定,在 4K 上出现黑色空白明确写入 mode 和 aspect
Full-rect Control 使用默认 STOP filter 覆盖游戏点击永远无法到达
_unhandled_input
(0 of 1)
在 HUD root 和 wrappers 上使用
MOUSE_FILTER_IGNORE
Corner preset 未设置 grow direction分数文字超出右边缘
grow_horizontal = GROW_DIRECTION_BEGIN
打开界面时未调用
grab_focus()
手柄没有任何响应Menu stack 在首次导航事件时将焦点交给默认项
容器中的 TextureRect 保持
KEEP_SIZE
一个 512 px icon 会使 64 px 行变成 614x512;
IGNORE_SIZE
且没有 minimum 会使宽度塌缩为 0
EXPAND_FIT_WIDTH_PROPORTIONAL
(实测为 64x64),或 ignore size + min size、Stretch Keep Aspect Centered(Godotneers 1_OFJLyqlXI 00:10:28)
OptionButton items 使用英文字面量Japanese 界面仍显示“Windowed”将 items 改为 key(
OPT_WINDOWED
)
Tabs 保持 Theme 默认样式标签页过小,难以触控使用带 content margins 的 tab styleboxes;matrix 应检查 TabBar
合成事件保存的绑定使用 device 0手柄 2 或真实键盘(device 16)无法触发标准化为 device -1
已开启 pseudolocalization,但未调整 expansion 或重新加载没有 padding(默认 ratio 为 0.0)设置
expansion_ratio
,并调用
TranslationServer.reload_pseudolocalization()
旧教程中依赖 POT generation 处理自定义节点字符串缺失(4.2 bug)4.3 已修复(Cashew OldDew v0tJPsNNOM8 00:08:00,未重跑);使用 CSV keys 可避免 POT
项目设置中启用了 Locale Test产品以 French 发布清除该设置;使用
--language fr
通过将 container child 的
visible = false
来实现效果
相邻项跳动并触发重新布局使用
modulate.a = 0
或
offset_transform_scale
(MrElipteach pK2vI2-jCH4 00:02:54)
预期鼠标点击后立刻出现 focus ringfocus ring 只会在下一次键盘或手柄操作后出现这是设计如此:
gui/common/show_focus_state_on_pointer_event
设为 1(仅适用于文本输入)

Handoffs

交接

  • In: state autoloads and signals (scenario-godot-architecture), input actions and values (scenario-godot-gameplay), bus names Master, Music, SFX (scenario-godot-audio), icons, panels, fonts (scenario-* skills; nine-patch margins set in code).
  • Out: render scale and upscaler contract (scenario-godot-rendering-lighting); Text Server Data, real-device safe area and touch (scenario-godot-performance-export); intro and outro tracks,
    offset_transform
    motion (scenario-godot-animation);
    test_ui_live.py
    for CI (scenario-godot-pipeline-automation).
  • 传入:state autoloads 和 signals(scenario-godot-architecture)、input actions 和 values(scenario-godot-gameplay)、bus 名称 Master、Music、SFX(scenario-godot-audio)、icons、panels、fonts(scenario-* skills;nine-patch margins 在代码中设置)。
  • 传出:render scale 和 upscaler contract(scenario-godot-rendering-lighting);Text Server Data、真机 safe area 和 touch(scenario-godot-performance-export);intro 和 outro tracks、
    offset_transform
    motion(scenario-godot-animation);用于 CI 的
    test_ui_live.py
    (scenario-godot-pipeline-automation)。

Godot 4.7 notes

Godot 4.7 notes

  • offset_transform_*
    (4.7) moves container children without relayout;
    offset_transform_visual_only
    defaults to true, so clicks hit the layout rect (measured).
    pivot_offset_ratio
    (4.7) for center pivots;
    grab_focus(hide_focus)
    (4.6).
  • AccessibilityServer
    (4.7),
    accessibility_name
    ,
    FOCUS_ACCESSIBILITY
    (RichTextLabel default);
    accessibility_support
    0 Auto runs only with an assistive app active.
  • auto_translate_mode
    replaced
    auto_translate
    ;
    FoldableContainer
    (4.5),
    VirtualJoystick
    ,
    PopupMenu.allow_search
    (4.7);
    [img]
    takes
    width_unit
    /
    height_unit
    . Upscalers: FSR2=2, MetalFX spatial=3, temporal=4.
  • push_input(event, true)
    takes logical coordinates. Godot 3 names (
    rect_size
    ,
    add_color_override
    ,
    margin_*
    , stretch
    2d
    ,
    process_custom_fx
    ) are gone.
  • offset_transform_*
    (4.7)无需重新布局即可移动 container children;
    offset_transform_visual_only
    默认为 true,因此点击仍会命中布局矩形(measured)。
    pivot_offset_ratio
    (4.7)用于中心 pivot;
    grab_focus(hide_focus)
    (4.6)。
  • AccessibilityServer
    (4.7)、
    accessibility_name
    、
    FOCUS_ACCESSIBILITY
    (RichTextLabel 默认值);
    accessibility_support
    0 Auto 仅在辅助功能应用处于活动状态时运行。
  • auto_translate_mode
    取代了
    auto_translate
    ;
    FoldableContainer
    (4.5)、
    VirtualJoystick
    、
    PopupMenu.allow_search
    (4.7);
    [img]
    支持
    width_unit
    /
    height_unit
    。Upscalers:FSR2=2,MetalFX spatial=3,temporal=4。
  • push_input(event, true)
    接受 logical coordinates。Godot 3 的名称(
    rect_size
    、
    add_color_override
    、
    margin_*
    、stretch
    2d
    、
    process_custom_fx
    )均已移除。

References

References

  • references/procedures.md
    : P1 to P15 with full code paths, live test ids and results.
  • references/expert-notes.md
    : what each source teaches, with timestamps.
  • references/critique.md
    : the rubric for judging a UI build and its captures.
  • references/gui-paths.md
    : the same steps through the editor for a computer-use agent.
  • references/sources.md
    : every source, credentials, URLs, best timestamps.
  • scripts/gd_ui.py
    ,
    scripts/agentkit/ui/*.gd
    ,
    scripts/agentkit/ui/examples/build_g7.gd
    .
  • references/procedures.md
    :P1 到 P15,包含完整代码路径、live test ids 和结果。
  • references/expert-notes.md
    :说明每个来源提供的知识,并附时间戳。
  • references/critique.md
    :用于评判 UI build 及其 captures 的 rubric。
  • references/gui-paths.md
    :面向 computer-use agent,通过编辑器执行相同步骤的指南。
  • references/sources.md
    :所有来源、credentials、URLs 和最佳时间戳。
  • scripts/gd_ui.py
    、
    scripts/agentkit/ui/*.gd
    、
    scripts/agentkit/ui/examples/build_g7.gd
    。