ワンクリックで
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。