scenario-godot-ui
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseGodot 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 (); unattended, proceed from tool schemas and flag the gap.
npx skills add scenario-labs/skills --skill <name>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 中,请要求用户安装它();在无人值守模式下,则根据 tool schemas 继续,并标记这一缺口。
npx skills add scenario-labs/skills --skill <name>必需背景: scenario-godot-expert(channels、review loop、6.3 个陷阱)。
Stance (the expert delta)
核心准则(专家级差异)
- Pick the base size for the extremes, not for 1080p. A square base (720x720) with +
canvas_itemsand Handheld Orientationexpandgives 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.sensor - 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; alone keeps the old offsets (a 50x50 child stays 50x50 on FULL_RECT), so use
set_anchors_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].set_anchors_and_offsets_preset() - 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).
- Focus is explicit. Nothing has focus at scene start, so does nothing until something calls
ui_down(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).grab_focus() - 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).
- Text is keys, never literals. Named placeholders with ,
format()for plurals, context for identical English, auto translate disabled on dynamic text (docs, Internationalizing games). Fonts get fallbacks, not remaps.tr_n() - HUD is passive and signal-driven. Its root and wrappers ignore the mouse; values change on signals, not in (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
_process, 1 after reassigning), so state arrays emit their own signal (NoBSGodot Yuw7CK5H8eA 00:05:06, measured).append - Verify at device sizes headless, then look. Headless, 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].
root.size
- 根据极端尺寸而不是 1080p 选择基础尺寸。 使用 720x720 的正方形基础尺寸,配合 +
canvas_items和 Handheld Orientationexpand,可为竖屏和横屏提供统一缩放(docs,Multiple resolutions)。实测:1080x2400 手机在两个方向上均为 1.5x,4K 上为 3x。1152x648 基础尺寸在同一手机上会得到 0.9375x canvas 和三个过小的按钮 [added, measured]。Godotneers 的 1920x1080 基础尺寸(1_OFJLyqlXI)仅适合桌面端。sensor - 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;仅调用 会保留旧 offsets(在 FULL_RECT 上,50x50 子节点仍为 50x50),因此应使用
set_anchors_preset()(Karto 00:05:24,measured)。角落元素还必须设置 grow direction,否则较长的文字会扩展到屏幕外 [added,measured:在 1152 canvas 中宽达 1462 px]。set_anchors_and_offsets_preset() - **所有视觉样式都集中在一个以代码构建的 Theme resource 中,**使用 type variations,而不是逐节点 override(docs,Theme type variations)。StyleBoxes 是共享 Resource:复用在两个节点上的 override 会同时改变两者(Karto 00:19:00)。
- Focus 是显式的。 场景启动时没有任何内容获得 focus,因此直到某个节点调用 前,
grab_focus()都不会执行任何操作(docs,Controller navigation;measured)。维护一个 menu stack,用于禁用被覆盖的面板,并将焦点还给打开它的元素(Mostly Mad Productions ecJZipjUj6k 00:08:57)。ui_down - **当前选中项必须是屏幕上对比度最高的元素,**正文文本优先,字体最多使用两三种,outro 要比 intro 更快(Rawb Herb,GodotCon 2025,sjmAD1ZLBcE 00:31:42、00:21:34、00:55:38)。
- 文本必须是 key,绝不能是字面量。 使用带命名 placeholders 的 ,使用
format()处理 plurals,为相同的英文文本提供 context,并对动态文本禁用 auto translate(docs,Internationalizing games)。Fonts 使用 fallbacks,而不是 remaps。tr_n() - HUD 应保持被动并由 signal 驱动。 其 root 和 wrappers 忽略鼠标;数值通过 signals 变化,而不是在 中变化(1_OFJLyqlXI、Yuw7CK5H8eA、f90ieBOoIYQ 的共识)。新字符串会触发重新排版(200 个 labels:每帧 1.1 至 1.5 ms CPU);为相同字符串赋值会提前退出,因此开销来自变化的文本,而不是赋值操作本身 [added, measured]。原地修改 array 永远不会调用 setter(
_process后调用 0 次,重新赋值后调用 1 次),因此 state arrays 应发出自己的 signal(NoBSGodot Yuw7CK5H8eA 00:05:06,measured)。append - 先在设备尺寸下进行 headless 验证,再目视检查。 在 headless 模式下,可接受任意尺寸并应用项目 stretch,因此 layout matrix 数秒即可运行;随后通过 windowed capture,以实际设备尺寸渲染每个目标并绘制刘海区域 [added, measured]。
root.size
Establish first
首先确定
| Input | Changes | Default if nobody says |
|---|---|---|
| Platforms and orientations | base size, orientation, touch target size | phone portrait + landscape, desktop to 4K: base 720x720, |
| Art style | stretch mode and scale mode | vector or high-res: |
| Input devices | focus work, rebind screen, touch sizes | mouse, keyboard, pad, touch |
| Languages | fonts, RTL, Text Server Data on export | en plus one long (de), one CJK (ja), one RTL (ar) for tests |
| Accessibility bar | screen reader, UI scale slider, contrast | WCAG 4.5:1 body text, UI scale 0.75 to 2.0 via |
| Renderer | upscaler choice in settings | Forward+ (Jolt kept); Compatibility forces bilinear 3D scaling |
| 输入 | 更改内容 | 未另行说明时的默认值 |
|---|---|---|
| 平台与方向 | 基础尺寸、方向、触控目标尺寸 | 手机竖屏 + 横屏,以及桌面端到 4K:基础尺寸 720x720, |
| 美术风格 | stretch mode 和 scale mode | 矢量或高分辨率: |
| 输入设备 | focus 工作、rebind 界面、触控尺寸 | 鼠标、键盘、手柄、触控 |
| 语言 | 字体、RTL、导出时的 Text Server Data | en,外加一个字符较长的语言(de)、一个 CJK 语言(ja)和一个 RTL 语言(ar)用于测试 |
| 无障碍基线 | screen reader、UI scale 滑块、对比度 | 正文文字符合 WCAG 4.5:1;通过 |
| Renderer | 设置中的 upscaler 选择 | Forward+(保留 Jolt);Compatibility 强制使用 bilinear 3D scaling |
Workflow
Workflow
1. Project settings. Write the stretch keys explicitly: a hand-written project.godot gets and (deltas). for , , , , . Check that and the renderer survived.
GATE: for each target gives the expected logical size and scale (port matches the engine on 224 cases, origin and scale included).
disabledkeepgd_env.set_project_settingdisplay/window/size/viewport_width/heightstretch/modestretch/aspecthandheld/orientationgui/theme/custom3d/physics_engine="Jolt Physics"gd_ui.stretch_math(window, base, ...)2. Theme in code. 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 , 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: or the font's , 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 counts, and runtime Theme edits propagate at once (measured).
GATE: body pairs >= 4.5:1 (worst measured 4.37 is the disabled state, allowed); finds no misspelt variation.
ui_theme.gdbuild(overrides).tresgui/theme/default_font_multichannel_signed_distance_fieldmultichannel_signed_distance_fieldadd_theme_*_overridecontrast_report()check_variations()3. Scenes in code. Root Control full rect, a 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 , AspectRatioContainer for the minimap; a round minimap or portrait frame is a mask (Clip Only on a rounded Panel), but a child with another 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). recomputes on (top margin 104 at 1.5x, 82 at 2x, measured). builds the whole G7 set.
GATE: returns no , , , , , .
safe_area.gdMOUSE_FILTER_IGNOREclip_childrenz_indexsafe_area.gdsize_changedexamples/build_g7.gdui_audit.gdaudit_tree()hud_blocks_inputicon_keep_sizegrows_offscreen_*no_accessible_nameshared_stylebox_overrideunknown_variation4. Layout matrix headless. 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.
gd_ui.layout_matrix(P, scene, targets, min_touch_px=..., safe_insets=..., locale=..., pseudo=True)5. Capture matrix windowed, then look. renders each target at its physical size with black bars and red notch bands, and builds a contact sheet. Open the sheet.
GATE: 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 : it draws unscaled (P13, measured).
gd_ui.capture_matrix(P, scene, targets, safe_insets=...)image_checkscontent_scale_*6. Focus and input. pushes actions through and records the focus owner; 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.
gd_ui.focus_walk(P, scene, steps)ui_*push_inputui_focus.graph()7. Rebinding. : 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 (windowed only): on a French layout physical Q reads "A" (measured). Add pad buttons yourself: in 4.7.2 and 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.
ui_rebind.gdDisplayServer.keyboard_get_label_from_physical()ui_acceptui_cancel8. Localization. CSV with a column, offline, , then . Run en, fr, de, ja, ar and pseudolocalization; defaults to 0.0, so set 0.3 to 0.4 and call (measured). is the non-persistent test. Animated text is a RichTextEffect: var plus , options from (Cashew OldDew KMqYeRae6rM 00:14:01; measured read 6.0), installed with .
GATE: no missing keys per locale; Arabic mirrors (anchors and HBox order); plurals right in en and fr; layout matrix clean.
?pluralgd_ui.check_csv--importgd_ui.register_translationsexpansion_ratioreload_pseudolocalization()--language frbbcode_process_custom_fx(char_fx)char_fx.env[lift px=6]install_effect()9. Settings and cost. autoload applies window mode, vsync, render scale and upscaler, quality, UI scale, bus volumes, locale; saves and reloads.
GATE: save and load round trip; 1.5 turns a 1280x720 canvas into 853x480.
ui_settings.gdui_scale1. 项目设置。 明确写出 stretch keys:手写的 project.godot 会得到 和 (deltas)。使用 设置 、、、、。确认 和 renderer 均已保留。
GATE:对每个目标调用 ,得到预期的 logical size 和 scale(移植实现与引擎在 224 个用例中一致,包括 origin 和 scale)。
disabledkeepgd_env.set_project_settingdisplay/window/size/viewport_width/heightstretch/modestretch/aspecthandheld/orientationgui/theme/custom3d/physics_engine="Jolt Physics"gd_ui.stretch_math(window, base, ...)2. 以代码构建 Theme。 的 返回一个 Theme:包含带粗 accent focus box 的 Button 状态、Label、面板、滑块、标签页、ProgressBar,以及 TitleLabel、HudLabel、HudValue、PrimaryButton、HudPanel、HealthBar、TrailBar 等 variations。将其保存为 ,将默认字体设为带 CJK 和 Arabic fallbacks 的 SystemFont,字体最多使用两三种。以多种缩放级别绘制的文字(例如放大 3x 的 HUD 数字)应使用 MSDF: 或字体的 ,两者默认均为 false(Karto 5Hog6a0EYa0 00:20:50,measured)。Default Theme Scale 只读取一次:运行时设置不会产生变化(measured)。在编辑器中修改 Theme 后,需要重新加载场景才能重绘(Godotneers 00:22:10);override 在勾选其复选框前不会生效(Karto 00:17:25);在代码中只有 生效,而运行时 Theme 修改会立即传播(measured)。
GATE: 显示正文颜色组合均 >= 4.5:1(实测最差值 4.37 来自 disabled 状态,允许); 未发现拼写错误的 variation。
ui_theme.gdbuild(overrides).tresgui/theme/default_font_multichannel_signed_distance_fieldmultichannel_signed_distance_fieldadd_theme_*_overridecontrast_report()check_variations()3. 以代码构建 Scenes。 根节点为铺满全屏的 Control,随后是 MarginContainer,再其后是各个 containers。以 720 为基础尺寸时,按钮逻辑高度为 88(手机上以 1.5x 缩放后为 132 px)。设置项放在 TabContainer 内的 ScrollContainers 中。HUD 位于 CanvasLayer 上,root 使用 ,小地图使用 AspectRatioContainer;圆形小地图或竖屏边框使用 遮罩(圆角 Panel 上使用 Clip Only),但具有另一个 的子节点会逃出遮罩(GDQuest W4j4tnQLcTA 00:03:47,measured),因此被遮罩内容应保持在 z 0,或改用 SubViewport。Toggles 以“On”/“Off”文本显示(CoffeeCrow 9H_fN4OxyIE 00:08:11)。 在 时重新计算边距(1.5x 时顶部边距为 104,2x 时为 82,measured)。 会构建完整的 G7 集合。
GATE: 的 不应返回 、、、、 或 。
safe_area.gdMOUSE_FILTER_IGNOREclip_childrenz_indexsafe_area.gdsize_changedexamples/build_g7.gdui_audit.gdaudit_tree()hud_blocks_inputicon_keep_sizegrows_offscreen_*no_accessible_nameshared_stylebox_overrideunknown_variation4. Headless Layout Matrix。 对 8 个目标运行 (手机竖屏和横屏、4:3 平板、1366x768、1080p、21:9、4K、800x600)。
GATE:每个 scene 在 en、de 以及扩展 0.4 倍的伪本地化环境下,offscreen、outside_safe、small_target、text(裁切或溢出)、overlap 和 collapsed 问题均为零。
gd_ui.layout_matrix(P, scene, targets, min_touch_px=..., safe_insets=..., locale=..., pseudo=True)5. Windowed Capture Matrix,然后目视检查。 会按各目标的物理尺寸进行渲染,显示黑边和红色刘海条带,并生成 contact sheet。打开 contact sheet。
GATE: 不报告任何问题;目视检查:选中项可见,CJK 和 Arabic 字形完整,刘海条带仅覆盖背景,黑边和边框保持完整。绝不要通过带有 的 embedded Window 进行 capture:它会按未缩放方式绘制(P13,measured)。
gd_ui.capture_matrix(P, scene, targets, safe_insets=...)image_checkscontent_scale_*6. Focus 与输入。 通过 推送 actions,并记录 focus owner; 列出无法到达的 focusables。Menu stack:打开、取消,并将焦点恢复到打开者。
GATE:每个 focusable 都能从默认项到达;首次按键时焦点会落在默认项上;被覆盖的面板不可到达。
gd_ui.focus_walk(P, scene, steps)push_inputui_*ui_focus.graph()7. Rebinding。 :接受绑定时不产生回显、不响应 Escape,摇杆值需大于 0.5;标准化 physical keycode、device -1 和 axis sign;报告冲突,并交换或拒绝冲突绑定;保存为 ConfigFile,并从项目设置重置。通过 显示按键(仅限 windowed):在 French 布局中,physical Q 显示为“A”(measured)。需要自行添加手柄按钮:在 4.7.2 中, 和 仅绑定键盘按键(Enter、Kp Enter、Space;Escape),因此应添加 Joypad Button 0 和 1(Mostly Mad ecJZipjUj6k 00:12:00,measured)。
GATE:保存并重新加载后,绑定在键盘和任意手柄上都能匹配。
ui_rebind.gdDisplayServer.keyboard_get_label_from_physical()ui_acceptui_cancel8. 本地化。 CSV 包含 列,离线运行 ,然后执行 和 。运行 en、fr、de、ja、ar 和 pseudolocalization; 默认为 0.0,因此应设置为 0.3 至 0.4,并调用 (measured)。 是非持久化测试方式。动画文字使用 RichTextEffect:包含 var 和 ,选项来自 (Cashew OldDew KMqYeRae6rM 00:14:01;实测 读取为 6.0),并通过 安装。
GATE:每个 locale 均无缺失 key;Arabic 正确镜像(anchors 和 HBox 顺序);en 和 fr 的 plurals 正确;layout matrix 无问题。
?pluralgd_ui.check_csv--importgd_ui.register_translationsexpansion_ratioreload_pseudolocalization()--language frbbcode_process_custom_fx(char_fx)char_fx.env[lift px=6]install_effect()9. 设置与开销。 autoload 应用 window mode、vsync、render scale、upscaler、quality、UI scale、bus volumes 和 locale;并负责保存与重新加载。
GATE:保存和加载 round trip 正常; 为 1.5 时,1280x720 canvas 会变为 853x480。
ui_settings.gdui_scaleNumbers
数值
| Value | Relative to | Source |
|---|---|---|
Base 720x720, | phone portrait and landscape plus desktop | docs, Multiple resolutions |
| Scale 1.5 on 1080x2400 and 2400x1080, 3.0 on 3840x2160, 1.0672 on 1366x768 | base 720x720 | measured [added] |
Base 720x1280 on a 2400x1080 phone: | why a square base beats an aspect choice | measured [added] |
Pixel art 640x360 | 720p to 4K | docs, 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 size | docs, 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 720 | 132 px on a phone | [added, measured] |
| WCAG 4.5:1 body, 3:1 large text | text vs its background | WCAG 2 [added] |
| Damage trail: one-shot timer 0.4 s, restarted per hit; heal instant | health change | DashNothing f90ieBOoIYQ 00:01:26 |
| Text Server Data ~4 MB | export size, for no-space scripts | docs |
| 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 Max | measured [added] |
| 数值 | 相对于 | 来源 |
|---|---|---|
基础尺寸 720x720, | 手机竖屏和横屏,以及桌面端 | docs,Multiple resolutions |
| 1080x2400 和 2400x1080 上缩放为 1.5,3840x2160 上为 3.0,1366x768 上为 1.0672 | 基础尺寸 720x720 | measured [added] |
2400x1080 手机采用 720x1280 基础尺寸: | 说明为何正方形基础尺寸优于按宽高比选择 | measured [added] |
像素艺术使用 640x360 | 720p 到 4K | docs,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: 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 正常。
test_ui_live.py视觉检查:每个 scene 和 locale 都要有一张 contact sheet(menu、HUD、settings ja、menu ar、settings pseudo),并实际打开检查:focus 可见,字形完整,没有内容位于刘海区域下方,letterbox 出现在预期位置,选中项在灰度下仍然可见(Rawb Herb)。
Common mistakes
常见错误
| Mistake | What it looks like | Fix |
|---|---|---|
| 1920x1080 or 1152x648 base for a phone game | tiny buttons in portrait (scale 0.9375 at 1080x2400) | square base 720x720 + expand |
| Stretch keys left out of an agent-written project.godot | UI fixed size, black space on 4K | write mode and aspect explicitly |
| Full-rect Control with default STOP filter over the game | clicks never reach | |
| Corner preset without grow direction | score text runs off the right edge | |
No | pad does nothing | menu stack grabs the default on the first nav event |
TextureRect left on | a 512 px icon makes a 64 px row 614x512; | |
| OptionButton items as literal English | Japanese screen shows "Windowed" | items as keys ( |
| Tabs left at theme default | tabs too small to touch | tab styleboxes with content margins; the matrix checks the TabBar |
| Stored binding with device 0 from a synthesized event | pad 2 or the real keyboard (device 16) do not trigger | normalize to device -1 |
| Pseudolocalization on, expansion untouched or no reload | no padding (default ratio 0.0) | set |
| POT generation trusted for custom nodes in old tutorials | strings 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 settings | ships in French | clear it; use |
Hiding a container child with | siblings jump (relayout) | |
| Expecting a focus ring after a mouse click | ring only on the next key or pad press | by design: |
| 错误 | 表现 | 修复方式 |
|---|---|---|
| 为手机游戏使用 1920x1080 或 1152x648 基础尺寸 | 竖屏中按钮过小(1080x2400 上缩放为 0.9375) | 使用正方形基础尺寸 720x720 + |
| 由 agent 编写的 project.godot 中遗漏 stretch keys | UI 尺寸固定,在 4K 上出现黑色空白 | 明确写入 mode 和 aspect |
| Full-rect Control 使用默认 STOP filter 覆盖游戏 | 点击永远无法到达 | 在 HUD root 和 wrappers 上使用 |
| Corner preset 未设置 grow direction | 分数文字超出右边缘 | |
打开界面时未调用 | 手柄没有任何响应 | Menu stack 在首次导航事件时将焦点交给默认项 |
容器中的 TextureRect 保持 | 一个 512 px icon 会使 64 px 行变成 614x512; | |
| OptionButton items 使用英文字面量 | Japanese 界面仍显示“Windowed” | 将 items 改为 key( |
| Tabs 保持 Theme 默认样式 | 标签页过小,难以触控 | 使用带 content margins 的 tab styleboxes;matrix 应检查 TabBar |
| 合成事件保存的绑定使用 device 0 | 手柄 2 或真实键盘(device 16)无法触发 | 标准化为 device -1 |
| 已开启 pseudolocalization,但未调整 expansion 或重新加载 | 没有 padding(默认 ratio 为 0.0) | 设置 |
| 旧教程中依赖 POT generation 处理自定义节点 | 字符串缺失(4.2 bug) | 4.3 已修复(Cashew OldDew v0tJPsNNOM8 00:08:00,未重跑);使用 CSV keys 可避免 POT |
| 项目设置中启用了 Locale Test | 产品以 French 发布 | 清除该设置;使用 |
通过将 container child 的 | 相邻项跳动并触发重新布局 | 使用 |
| 预期鼠标点击后立刻出现 focus ring | focus ring 只会在下一次键盘或手柄操作后出现 | 这是设计如此: |
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, motion (scenario-godot-animation);
offset_transformfor CI (scenario-godot-pipeline-automation).test_ui_live.py
- 传入: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、motion(scenario-godot-animation);用于 CI 的
offset_transform(scenario-godot-pipeline-automation)。test_ui_live.py
Godot 4.7 notes
Godot 4.7 notes
- (4.7) moves container children without relayout;
offset_transform_*defaults to true, so clicks hit the layout rect (measured).offset_transform_visual_only(4.7) for center pivots;pivot_offset_ratio(4.6).grab_focus(hide_focus) - (4.7),
AccessibilityServer,accessibility_name(RichTextLabel default);FOCUS_ACCESSIBILITY0 Auto runs only with an assistive app active.accessibility_support - replaced
auto_translate_mode;auto_translate(4.5),FoldableContainer,VirtualJoystick(4.7);PopupMenu.allow_searchtakes[img]/width_unit. Upscalers: FSR2=2, MetalFX spatial=3, temporal=4.height_unit - takes logical coordinates. Godot 3 names (
push_input(event, true),rect_size,add_color_override, stretchmargin_*,2d) are gone.process_custom_fx
- (4.7)无需重新布局即可移动 container children;
offset_transform_*默认为 true,因此点击仍会命中布局矩形(measured)。offset_transform_visual_only(4.7)用于中心 pivot;pivot_offset_ratio(4.6)。grab_focus(hide_focus) - (4.7)、
AccessibilityServer、accessibility_name(RichTextLabel 默认值);FOCUS_ACCESSIBILITY0 Auto 仅在辅助功能应用处于活动状态时运行。accessibility_support - 取代了
auto_translate_mode;auto_translate(4.5)、FoldableContainer、VirtualJoystick(4.7);PopupMenu.allow_search支持[img]/width_unit。Upscalers:FSR2=2,MetalFX spatial=3,temporal=4。height_unit - 接受 logical coordinates。Godot 3 的名称(
push_input(event, true)、rect_size、add_color_override、stretchmargin_*、2d)均已移除。process_custom_fx
References
References
- : P1 to P15 with full code paths, live test ids and results.
references/procedures.md - : what each source teaches, with timestamps.
references/expert-notes.md - : the rubric for judging a UI build and its captures.
references/critique.md - : the same steps through the editor for a computer-use agent.
references/gui-paths.md - : every source, credentials, URLs, best timestamps.
references/sources.md - ,
scripts/gd_ui.py,scripts/agentkit/ui/*.gd.scripts/agentkit/ui/examples/build_g7.gd
- :P1 到 P15,包含完整代码路径、live test ids 和结果。
references/procedures.md - :说明每个来源提供的知识,并附时间戳。
references/expert-notes.md - :用于评判 UI build 及其 captures 的 rubric。
references/critique.md - :面向 computer-use agent,通过编辑器执行相同步骤的指南。
references/gui-paths.md - :所有来源、credentials、URLs 和最佳时间戳。
references/sources.md - 、
scripts/gd_ui.py、scripts/agentkit/ui/*.gd。scripts/agentkit/ui/examples/build_g7.gd