一键导入
pyreact-ui-builder
指导 agents 在网易我的世界基岩版 ModSDK 环境中使用 Pyreact 编写业务 UI,而不是修改 Pyreact 框架本身。
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
指导 agents 在网易我的世界基岩版 ModSDK 环境中使用 Pyreact 编写业务 UI,而不是修改 Pyreact 框架本身。
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
| name | pyreact-ui-builder |
| description | 指导 agents 在网易我的世界基岩版 ModSDK 环境中使用 Pyreact 编写业务 UI,而不是修改 Pyreact 框架本身。 |
| compatibility | opencode |
| metadata | {"audience":"agents","domain":"pyreact-ui","platform":"netease-minecraft-bedrock-modsdk"} |
pyreact 公开 API 编写业务 UI。style。key、ref、布局和分辨率适配规范。当任务满足以下任一条件时,加载本 skill:
Panel / Image / Label / Item / PaperDoll / Button / Input / Scroll。FilledButton / ImageButton / Animated。style、props、key、ref 或 hooks 的写法。ScreenNode。不要在以下场景只依赖本 skill:
pyreact/core、pyreact/layout、PyreactRuntimeScript、JsonUI/PyreactBase.json)。这属于开发本库,必须同时遵守仓库根目录 AGENTS.md。默认目标是:
from pyreact import ... 使用公开 API。@Component + primitives + hooks 描述页面。render_app(...) 挂载到已有 ScreenNode / JsonUI root。只有当用户明确要求“扩展框架能力 / 修改 renderer / 新增 style 属性 / 改 runtime 映射”时,才进入框架开发路径。
必须遵守仓库 AGENTS.md:
clientApi.GetSystem(...) / serverApi.GetSystem(...),不要直接 import 其他模组系统。clientApi / serverApi 能力。优先看 pyreact/__init__.py。
可直接使用的核心导出:
ComponentPanel、Image、Label、Item、PaperDoll、Button、Input、ScrollFilledButton、ImageButton、AnimatedAnimation、Transition、Easing、fadeIn、fadeOut、slideInUp、slideInDown、slideInLeft、slideInRight、slideOutUp、slideOutDown、slideOutLeft、slideOutRightStyle、AlignItems、JustifyContent、FlexDirection、FlexWrap、FontSize、TextAlign、Position、ButtonState、RenderTypeColor、ColorsuseState、useEffect、useMemo、useCallback、useRefclone_component、render_app、flat_button_builder_preset当前运行链路:
业务组件函数
-> VNode 树
-> Shadow Tree + Flex 布局
-> Diff mutations
-> Native Runtime 增量提交
-> NetEase ScreenNode / JsonUI 控件
当前分支不是废弃 grid 方案;不要把 old 分支的 grid/pool/typed-grid 经验套到当前 runtime。
顺序必须是:
UiInitFinished 中 RegisterUI(...)。PushScreen(...) 显示界面。ScreenNode.Create() 内调用 render_app(...)。ScreenNode.Destroy() 内调用 runtime UnmountApp(...)。最小模板:
# -*- coding: utf-8 -*-
import mod.client.extraClientApi as clientApi
from pyreact import Component, Panel, Label, Style, render_app
ScreenNode = clientApi.GetScreenNodeCls()
@Component
def SimpleApp():
return Panel(
style=Style(width='100%', height='100%'),
children=[Label(content='Hello Pyreact')],
)
class MyScreen(ScreenNode):
def Create(self):
render_app(
root=SimpleApp,
bind={
'screen': self,
'root': '/root',
'app_id': 'my_ui_app',
'base_namespace': 'PyreactBase',
},
)
def Destroy(self):
runtime = clientApi.GetSystem('PyreactRuntimeMod', 'PyreactRuntimeClientSystem')
if runtime is not None:
runtime.UnmountApp({'app_id': 'my_ui_app'})
@Component 规则所有自定义业务组件都必须加 @Component。
原因:
render_app(root=...) 会校验 root 是否带 @Component。@Component 负责处理 key / ref,业务函数不用手动声明它们。正确:
@Component
def UserCard(name, level):
return Panel(children=[Label(content='%s Lv.%s' % (name, level))])
不要把普通业务函数直接传给 render_app。
Panel用途:通用容器、布局节点、动画子树根。
常用 props:
stylechildren要点:
panelBase 控件;不要按 old 分支把 Panel 理解为纯虚拟节点。Image用途:贴图、纯色底板、按钮背景、图标。
常用 props:
srccolorgrayscaleclipRatiouv / uvSizeresizeModeimageAdaptionTypenineSlice / nineSliceTyperotation / rotatePivotonClick要点:
style。src 为空时 runtime 回退到 textures/ui/white_bg,可用 Image + color 做纯色底。Style(position=Position.absolute, top=0, right=0, bottom=0, left=0)。Label用途:文本展示。
常用 props:
contentcolorfontSizefonttextAlignlinePaddingshadow要点:
style。\n 和 Minecraft § 格式码。style.width / minWidth 等宽度约束后可触发自动换行。Label + \n / 空格 / § 格式码,减少控件数。Item用途:渲染物品图标。
常用 props:
identifierauxenchantuserDataitemDict要点:
itemDict。newItemName / itemName、newAuxValue / auxValue。PaperDoll用途:渲染网易纸娃娃控件,例如实体、骨骼模型或方块几何模型预览。
常用 props:
renderType:优先用 RenderType.entity / RenderType.skeleton / RenderType.blockGeometryentityIdentityIdentifierskeletonModelNameanimationanimationLoopedblockGeometryModelNamescalerenderDepthinitRotX / initRotY / initRotZmolangDictrotationAxislightDirection要点:
style。style。style.zIndex。RenderEntity / RenderSkeletonModel / RenderBlockGeometryModel。Button用途:可点击容器,支持 default / hover / pressed 三态。
常用 props:
stylechildrenonClickbuttonBuilder要点:
Label / Image / Panel。buttonBuilder 时使用默认三态。buttonBuilder 时一般写 def builder(state): return Image(...)。width='100%'、height='100%' 的 Image 时,runtime 会直接复用 JSONUI 三态槽位;复杂三态内容会走通用子树挂载。FilledButton,图片三态优先用 ImageButton。Input用途:文本输入。
常用 props:
valueonChangeplaceholder要点:
value + onChange 受控写法。useState。Scroll用途:滚动列表容器。
常用 props:
stylechildrenshowScrollbarref要点:
Scroll。ref.current.asScrollView() 访问原生 ScrollView。FilledButton纯色三态按钮封装。
FilledButton(
default=Colors.black.withAlpha(0.45),
hover=Colors.black.withAlpha(0.60),
pressed=Colors.black.withAlpha(0.75),
style=Style(width=120, height=32),
children=[Label(content='OK', color=Colors.white)],
)
回退规则:只传 default 时三态都用 default;缺 hover 时回退到 pressed;缺 pressed 时回退到 hover。
ImageButton图片三态按钮封装。
def build_image(src, state):
return Image(src=src, nineSlice=(4, 4, 4, 4))
ImageButton(
default='textures/ui/button_default',
hover='textures/ui/button_hover',
pressed='textures/ui/button_pressed',
imageBuilder=build_image,
style=Style(width=120, height=32),
children=[Label(content='Buy', color=Colors.white)],
)
imageBuilder 支持 imageBuilder(src) 或 imageBuilder(src, state),必须返回 Image(...)。
Animated声明式入场、出场和连续过渡包装器。
Animated(
key='row_42_anim',
enter=slideInUp(distance=12, duration=180),
exit=fadeOut(duration=140),
children=Panel(style=Style(width='100%', height=36), children=[...]),
)
要点:
ComponentNode;多个节点先用 Panel 聚合。opacity 会在 runtime 中递归传播到完整子树和 Button 三态槽位。alpha 只作用到动画根和直接子组件,不会传播到更深后代。Color.alpha;不要用父节点颜色 alpha 当作整棵子树透明度。enter 只在真正新建逻辑节点时播放; keyed MOVE 不重放 enter,而走布局移动动画。__pyreact_exit_* ghost 播放 exit,并立即释放原路径给新布局。Animated 或根节点稳定业务 key,不要用随机值或易变文案。动画由 Python runtime 监听 GameRenderTickEvent 驱动。
AnimationAnimation(
duration=300,
delay=0,
easing=Easing.easeOutQuad,
from_={'opacity': 0.0, 'translateY': 20.0},
to={'opacity': 1.0, 'translateY': 0.0},
)
TransitionAnimated(
animate=Transition(values={'opacity': opacity}, duration=220),
children=Panel(style=Style(width=120, height=40)),
)
opacity:递归传播到完整子树与按钮槽位,并保留每个节点自己的 Color.alphaalpha:只作用到动画根和直接子组件,不会传播到更深后代translateX / translateY:基于 layout 本地位置的视觉偏移,不影响兄弟布局width / height:通过原生 size 更新;Label 会跳过尺寸动画预设包括 fadeIn、fadeOut、slideInUp、slideInDown、slideInLeft、slideInRight、slideOutUp、slideOutDown、slideOutLeft、slideOutRight。
props 与 style 的分工style 只放布局、定位和通用显示属性:
width、height、minWidth、maxWidth、minHeight、maxHeight、minSize、maxSizepadding、paddingTop、paddingRight、paddingBottom、paddingLeft、margin、marginTop、marginRight、marginBottom、marginLeftflex、flexDirection、justifyContent、alignItems、alignSelf、flexWrapposition、top、right、bottom、leftopacity、display、zIndex透明度规则:
style.opacity 会继承,子节点最终透明度会乘上所有祖先的 style.opacity。Color.fromRGBA(..., alpha)、withAlpha() 的 alpha 只作用于当前节点颜色,不继承到子节点。style.opacity * 当前节点 Color.alpha”。opacity 会递归作用到完整子树和按钮槽位,但不能覆盖后代自己的 rgba alpha。alpha 的语义与 Color.alpha 一致,只影响该动画根和直接子组件,不会传播到孙级及更深组件。以下必须写 props:
Image:src、color、grayscale、clipRatio、uv、uvSize、resizeMode、imageAdaptionType、nineSlice、nineSliceType、rotation、rotatePivotLabel:content、color、fontSize、font、textAlign、linePadding、shadowButton:onClick、buttonBuilderInput:value、onChange、placeholderItem:identifier、aux、enchant、userData、itemDictPaperDoll:renderType、entityId、entityIdentifier、skeletonModelName、animation、animationLooped、blockGeometryModelName、scale、renderDepth、initRotX/Y/Z、molangDict、rotationAxis、lightDirectionAnimated:enter、animate、exit判断不清时,先查:
pyreact/components/primitives.pypyreact/components/style.pyPyreactRuntimeScript/native_runtime/props_mixin.py不要凭 Web/React/Unity/其他 Minecraft 平台经验猜。
Style(...) 常见写法不填写 width / height 时,该轴会按内容包裹:容器取非绝对子节点边界,Label 取文本测量结果,无内容的普通节点为 0。如果在 Flex 主轴上设置了 flex,主轴尺寸会按剩余空间分配;如果交叉轴继承或设置了 alignItems / alignSelf=stretch,且父节点该交叉轴有确定尺寸,则交叉轴会被拉伸。
Panel(
style=Style(
flexDirection=FlexDirection.row,
alignItems=AlignItems.center,
justifyContent=JustifyContent.spaceBetween,
),
children=[...],
)
未设置 position 时等同于 Position.relative。相对定位节点保留原本 Flex 流占位,只按 top/right/bottom/left 做视觉偏移;同轴冲突时 left 优先于 right,top 优先于 bottom。
Image(style=Style(width=40, height=20, left=6, top=3))
Position.absolute 会让节点脱离 Flex 流,按父节点内容区定位,不占据兄弟节点空间。左右同时设置且未设置 width 时会撑满剩余宽度;上下同时设置且未设置 height 时会撑满剩余高度。
Image(
style=Style(
position=Position.absolute,
top=0,
right=0,
bottom=0,
left=0,
),
color=Colors.black.withAlpha(0.4),
)
display / opacity / zIndexdisplay='none' 隐藏控件。opacity 建议使用 0.0 ~ 1.0。zIndex 映射到原生 layer,适合浮层微调。key 规则动态列表、筛选结果、排序、tab 内容切换、动画列表必须使用稳定 key。
正确:
Animated(
key='item_%s_anim' % item['id'],
enter=slideInUp(),
exit=fadeOut(),
children=Panel(key='item_%s' % item['id'], children=[...]),
)
不要使用随机数、当前时间、易变文案作为 key。没有稳定 key 时,列表项状态、动画状态、输入框、滚动引用都可能错位。
ref 规则需要拿到底层控件实例时使用 useRef:
scroll_ref = useRef(None)
Scroll(
ref=scroll_ref,
style=Style(flex=1),
children=[...],
)
调用前要判断 ref.current 是否已存在。
useState:选中项、输入框内容、弹窗显隐、筛选条件。useEffect:订阅/解绑、一次性副作用、依赖变化后同步外部系统;可返回 cleanup。useMemo:大列表过滤、昂贵映射、依赖确定的派生数据。useCallback:稳定事件回调或传给子组件的函数。useRef:原生控件引用或不触发重渲染的可变对象。当前 Color API:
Color(0xFFFF0000)
Color.fromRGB(255, 0, 0)
Color.fromRGBA(255, 0, 0, 0.5)
Color.fromHex('#80FF0000')
Colors.white
Colors.black.withAlpha(0.3)
可用属性和方法:
valuealpha8 / red / green / bluealphawithAlpha() / withAlpha8()withRed() / withGreen() / withBlue()toRGBUnitTuple() / toRGBAUnitTuple()注意:当前实现没有 fromARGB / fromRGBO / toCSSRGBA。
Color 中的 alpha 是当前节点颜色透明度,不是继承属性。需要让整组 UI 一起半透明时,给共同父节点写 Style(opacity=...);只需要某张图或某段文字半透明时,才使用 Color.fromRGBA(...) / withAlpha(...)。
FontSize 预设:
| fontSize | 数值 | 原生 scale |
|---|---|---|
FontSize.small | 5 | 0.5 |
FontSize.normal | 10 | 1.0 |
FontSize.large | 20 | 2.0 |
FontSize.extraLarge | 40 | 4.0 |
建议:
extraLarge 很大,除非特殊场景不要用。\n;格式化文本用 Minecraft § 代码。Label(content='§a成功§r:任务完成')
320 x 210 左右设计;PC 基岩版常见参考约 376 x 250。320 x 210 内,避免手机越界。挂载 root 建议继承 PyreactBase.rootBase:
{
"main": {
"type": "screen",
"controls": [
{
"root@PyreactBase.rootBase": {}
}
]
},
"namespace": "YourNamespace"
}
PyreactBase.json 当前提供:panelBase / imageBase / textBase / itemBase / paperDollBase / buttonBase / inputBase / scrollBase。
Panel,什么时候用 ImagePanel。Image。Button 而不是 Panel(onClick=...)Button。Panel(onClick=...),但复杂可交互元素仍优先 Button。exit,新增用 enter;排序/删除导致的 MOVE 由 runtime 处理。用四边绝对定位:
Image(
style=Style(position=Position.absolute, top=0, right=0, bottom=0, left=0),
color=Colors.black,
)
pyreact/__init__.pypyreact/components/primitives.pypyreact/components/style.pyPyreactRuntimeScript/native_runtime/props_mixin.pypyreact/layout/flexbox.pypyreact/core、pyreact/layout、PyreactRuntimeScript 来实现普通页面需求。style。@Component。key。@Component + primitives + hooks 编写?style 是否分工正确?key?ref?RegisterUI -> PushScreen -> render_app -> UnmountApp 顺序接入?接到 Pyreact UI 任务时,按这个顺序执行:
render_app(...) 挂载。pyreact/__init__.py 确认可用组件、hooks、composites 和动画 API。