create-pixifact 0.17.0 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/README.md +16 -1
  2. package/dist/createPixifactProject.d.ts +3 -2
  3. package/dist/index.js +34 -14
  4. package/dist/skills/pixifact/SKILL.md +27 -4
  5. package/dist/skills/pixifact/agents/openai.yaml +2 -2
  6. package/dist/skills/pixifact/references/scene-authoring-decisions.md +2 -0
  7. package/dist/skills/pixifact/references/scene-hierarchy-patterns.md +38 -0
  8. package/dist/skills/pixifact/references/scene-objects.md +40 -2
  9. package/package.json +5 -2
  10. package/templates/game/.env +1 -0
  11. package/templates/game/README.md +119 -0
  12. package/templates/game/assets/ui/button.png +0 -0
  13. package/templates/game/assets/ui/panel.png +0 -0
  14. package/templates/game/bunfig.toml +1 -0
  15. package/templates/game/index.html +12 -0
  16. package/templates/game/package.json +24 -0
  17. package/templates/game/pixifact.project.json +11 -0
  18. package/templates/game/src/GameApp.ts +118 -0
  19. package/templates/game/src/core/GameSession.ts +43 -0
  20. package/templates/game/src/core/ScreenManager.ts +26 -0
  21. package/templates/game/src/core/WebRecordStore.ts +14 -0
  22. package/templates/game/src/main.ts +64 -0
  23. package/templates/game/src/screens/MainMenu.scene +57 -0
  24. package/templates/game/src/screens/MainMenu.ts +101 -0
  25. package/templates/game/src/screens/PlayScreen.scene +13 -0
  26. package/templates/game/src/screens/PlayScreen.ts +31 -0
  27. package/templates/game/src/screens/ResultScreen.scene +13 -0
  28. package/templates/game/src/screens/ResultScreen.ts +25 -0
  29. package/templates/game/src/styles.css +21 -0
  30. package/templates/game/src/ui/Button.scene +10 -0
  31. package/templates/game/src/ui/Button.ts +84 -0
  32. package/templates/game/src/ui/Dialog.scene +10 -0
  33. package/templates/game/src/ui/Dialog.ts +31 -0
  34. package/templates/game/src/ui/Panel.scene +7 -0
  35. package/templates/game/src/ui/Panel.ts +11 -0
  36. package/templates/game/src/ui/ProgressBar.scene +4 -0
  37. package/templates/game/src/ui/ProgressBar.ts +25 -0
  38. package/templates/game/src/ui/nine/ButtonBackground.scene +3 -0
  39. package/templates/game/src/ui/nine/ButtonBackground.ts +5 -0
  40. package/templates/game/src/ui/nine/PanelBackground.scene +3 -0
  41. package/templates/game/src/ui/nine/PanelBackground.ts +5 -0
  42. package/templates/game/src/vite-env.d.ts +2 -0
  43. package/templates/game/tsconfig.json +15 -0
  44. package/templates/game/vite.config.ts +9 -0
  45. package/templates/minimal/package.json +2 -2
package/README.md CHANGED
@@ -11,6 +11,17 @@ bun install
11
11
  bun run dev
12
12
  ```
13
13
 
14
+ 创建包含基础游戏流程和可替换 UI 库的项目:
15
+
16
+ ```bash
17
+ bun create pixifact my-game --template game
18
+ cd my-game
19
+ bun install
20
+ bun run dev
21
+ ```
22
+
23
+ `game` 模板默认打开 Button / Panel / Dialog / ProgressBar 的交互展台,演示按钮禁用、点击反馈、进度边界和弹窗。底部入口提供竖屏 Web 游戏/暂停/结算流程,包含纯 TypeScript 游戏状态、页面销毁与订阅清理、最高分保存。模板只提供一套基础 UI,用户直接覆盖 `assets/ui/button.png` 和 `assets/ui/panel.png` 即可更换对应背景,保持 96 × 96 尺寸与四边各 24 像素的九宫格边距。详细模块和自定义方式见 [模板说明](./templates/game/README.md)。默认不指定 `--template` 时仍创建最小项目。
24
+
14
25
  生成的项目包含:
15
26
 
16
27
  - `pixifact.project.json`
@@ -27,7 +38,7 @@ bun run dev
27
38
 
28
39
  | 命令 | 用途 |
29
40
  | --- | --- |
30
- | `bun run dev` | 启动 Web 开发服务 |
41
+ | `bun run dev` | 启动 Web 开发服务和 Bun Inspector,均支持局域网访问 |
31
42
  | `bun run build` | 构建 Web 生产版本 |
32
43
  | `bun run compile` | 独立编译 `.scene` 到 `.pixifact/generated` |
33
44
  | `bun run editor` | 启动 Pixifact 编辑器 |
@@ -35,6 +46,10 @@ bun run dev
35
46
 
36
47
  模板的 `.env` 默认设置 `VITE_PLATFORM=web`。`dev` 和 `build` 会自动处理 Scene 编译,也可以使用 `compile` 单独编译 Scene。
37
48
 
49
+ `dev` 脚本直接执行 `pixifact dev`,CLI 会自动启用 Bun Inspector 并在终端输出调试地址。用户和 Agent 直接运行 `bun run dev` 即可同时启动开发服务和调试入口。
50
+
51
+ 同一局域网设备可打开启动结果 `urls.network` 中的游戏地址。远程连接 Inspector 时,将 Bun 输出的调试链接中的 `0.0.0.0` 替换为开发电脑的局域网 IP,保留端口和路径。
52
+
38
53
  ## 观察运行中的游戏
39
54
 
40
55
  ```bash
@@ -1,11 +1,12 @@
1
+ export type PixifactProjectTemplate = 'minimal' | 'game';
1
2
  export interface CreatePixifactProjectOptions {
2
3
  cwd?: string;
3
4
  name: string;
4
- template?: 'minimal';
5
+ template?: PixifactProjectTemplate;
5
6
  }
6
7
  export interface CreatePixifactProjectResult {
7
8
  name: string;
8
9
  root: string;
9
- template: 'minimal';
10
+ template: PixifactProjectTemplate;
10
11
  }
11
12
  export declare function createPixifactProject(options: CreatePixifactProjectOptions): Promise<CreatePixifactProjectResult>;
package/dist/index.js CHANGED
@@ -1,20 +1,36 @@
1
1
  #!/usr/bin/env bun
2
2
  import { createPixifactProject } from './createPixifactProject';
3
+ import { parseArgs } from 'node:util';
3
4
  function usage() {
4
5
  return [
5
6
  '用法:',
6
- ' bun create pixifact <project-name>',
7
+ ' bun create pixifact <project-name> [--template minimal|game]',
8
+ ' minimal:最小 Scene 项目;game:基础游戏框架和一套基础 UI。',
7
9
  '',
8
10
  ].join('\n');
9
11
  }
10
- const name = process.argv[2];
11
- if (!name || name === '--help' || name === '-h') {
12
- process.stdout.write(usage());
13
- process.exitCode = name ? 0 : 1;
14
- }
15
- else {
16
- try {
17
- const result = await createPixifactProject({ name });
12
+ try {
13
+ const { values, positionals } = parseArgs({
14
+ args: process.argv.slice(2),
15
+ allowPositionals: true,
16
+ options: {
17
+ template: { type: 'string', default: 'minimal' },
18
+ help: { type: 'boolean', short: 'h' },
19
+ },
20
+ });
21
+ const name = positionals[0];
22
+ if (!name || values.help) {
23
+ process.stdout.write(usage());
24
+ process.exitCode = values.help ? 0 : 1;
25
+ }
26
+ else {
27
+ if (positionals.length !== 1)
28
+ throw new Error('请指定一个项目名称。');
29
+ const template = values.template;
30
+ if (template !== 'minimal' && template !== 'game') {
31
+ throw new Error('模板必须为 minimal 或 game。');
32
+ }
33
+ const result = await createPixifactProject({ name, template });
18
34
  process.stdout.write(`已创建 ${result.name}:${result.root}\n`);
19
35
  process.stdout.write('已初始化 Git 仓库,并安装 Pixifact skill 到 .agents/skills/pixifact/。\n');
20
36
  process.stdout.write([
@@ -23,17 +39,21 @@ else {
23
39
  ' bun install',
24
40
  '',
25
41
  '项目命令:',
26
- ' bun run dev 启动 Web 开发服务',
42
+ ' bun run dev 启动 Web 开发服务(预览和 --inspect 调试均支持局域网)',
27
43
  ' bun run build 构建 Web 生产版本',
28
44
  ' bun run compile 编译 Scene',
29
45
  ' bun run editor 启动 Pixifact 编辑器',
30
46
  ' bun run validate 校验项目',
31
47
  '',
32
48
  ].join('\n'));
49
+ if (template === 'game') {
50
+ process.stdout.write(' bun run typecheck 检查游戏 TypeScript\n');
51
+ process.stdout.write('更换 UI 素材:直接替换 assets/ui/ 中的同名 PNG,保持图片尺寸和九宫格边距;然后重启开发服务。详见 README。\n');
52
+ }
33
53
  }
34
- catch (error) {
35
- process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
36
- process.exitCode = 1;
37
- }
54
+ }
55
+ catch (error) {
56
+ process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
57
+ process.exitCode = 1;
38
58
  }
39
59
  export { createPixifactProject };
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: pixifact
3
- description: 用于下游 Pixifact 游戏项目:编辑项目相对 .scene 文件、维护同名 Scene 脚本契约、运行 validate / compile 并截取任意 Scene 的静态预览;以及在 Vite Web 开发模式下通过 pixifact runtime 读取运行中游戏的 PixiJS 节点、业务状态和日志,发送标准输入并验证行为。适用于 UI、HUD、menu、轻量 Scene、交互逻辑、视觉检查、运行时验证和诊断任务。
3
+ description: 用于下游 Pixifact 游戏项目:编辑项目相对 .scene 文件、维护同名 Scene 脚本契约、运行 validate / compile 并截取任意 Scene 的静态预览;读取 Editor 当前 Scene 和 selection、确认修改同步并截图;以及在 Vite Web 开发模式下通过 pixifact runtime 读取运行中游戏的 PixiJS 节点、业务状态和日志,发送标准输入并验证行为。适用于 UI、HUD、menu、轻量 Scene、Editor 协作、交互逻辑、视觉检查、运行时验证和诊断任务。
4
4
  ---
5
5
 
6
6
  # Pixifact
@@ -9,7 +9,7 @@ description: 用于下游 Pixifact 游戏项目:编辑项目相对 .scene 文
9
9
 
10
10
  ## Scene 工作流
11
11
 
12
- 处理 Scene、UI、HUD、menu、layout 或视觉资产任务时,优先编辑项目相对 `.scene` 源文件。
12
+ 处理 Scene、UI、HUD、menu、layout 或视觉资产任务时,优先编辑项目相对 `.scene` 源文件。用户指向 Editor 当前 Scene 或选中节点时,先按下面的「Editor 协作工作流」确定目标。
13
13
 
14
14
  1. 读取 `package.json`、`pixifact.project.json` 和目标 `.scene` / `.ts` 文件。
15
15
  2. 开始任何非纯查阅的 Scene 改动前,按 `references/scene-authoring-decisions.md` 做短决策;新建或大改 Scene 时先读全文。
@@ -37,11 +37,11 @@ description: 用于下游 Pixifact 游戏项目:编辑项目相对 .scene 文
37
37
  ```bash
38
38
  pixifact scene validate --all
39
39
  ```
40
- 10. 视觉任务在校验通过后截取目标 Scene,不需要启动 Editor:
40
+ 10. 视觉任务默认在校验通过后直接截取指定 Scene,Editor 未启动时也可使用:
41
41
  ```bash
42
42
  pixifact scene screenshot --scene src/scenes/MainMenu.scene --output /tmp/main-menu.png
43
43
  ```
44
- 查看 PNG 后继续调整 `.scene`,直到静态画面符合目标;此命令需要本机 Google Chrome,不执行游戏脚本。游戏运行状态用 `runtime screenshot` 验证。
44
+ 命令从磁盘读取目标 `.scene`、配对脚本接口和项目资源,不需要启动 Editor 或游戏,也不切换已打开的 Editor Scene。查看 PNG 后继续调整 `.scene`,直到静态画面符合目标;此命令需要本机 Google Chrome,不执行游戏脚本。游戏运行状态用 `runtime screenshot` 验证。
45
45
  11. 校验通过后编译:
46
46
  ```bash
47
47
  pixifact compile-scenes
@@ -58,6 +58,29 @@ description: 用于下游 Pixifact 游戏项目:编辑项目相对 .scene 文
58
58
 
59
59
  默认项目根是当前工作目录;不在项目根运行时再加 `--project-root <path>`。项目自己的 `bun run build`、`bun run dev` 等命令只作为后续检查或预览入口。
60
60
 
61
+ ## UI 最佳实践
62
+
63
+ - 九宫格 UI 素材推荐每张 PNG 对应一个 `.scene` / `.ts` 文件对,在 Scene 内集中设置 `NineImage` 的图片路径和四边切片参数;按钮、面板等调用方直接引用该 Scene,只设置位置和盒子尺寸。封装、引用和换图示例见 [NineImage](references/scene-objects.md#nineimage)。
64
+ - `HBoxContainer`、`VBoxContainer`、`GridContainer` 会接管直接子节点的 `x/y`;横排的 `y`、竖排的 `x` 也会被对齐结果覆盖。需要单独微调时,让一个明确尺寸的 `Group` 参与排列,再调整其内部节点。示例和占位尺寸规则见 [排列容器中的单独偏移](references/scene-hierarchy-patterns.md#排列容器中的单独偏移)。
65
+
66
+ ## Editor 协作工作流
67
+
68
+ 静态视觉检查沿用上面的 `scene screenshot` 流程。用户需要打开 Editor 浏览、选择或人工微调时,在项目根目录运行 `pixifact editor`;已运行时复用。用户指向已打开 Editor 的当前 Scene、选中节点或当前画面时:
69
+
70
+ 1. 修改前读取只读上下文:
71
+ ```bash
72
+ pixifact editor context
73
+ ```
74
+ 核对 `projectRoot`,用 `scene.path` 确定活动 Scene,读取 `scene.revision`、`scene.syncState`、`selection` 和 `openScenes`。`selection.kind="scene"` 表示 Scene 根;`kind="node"` 时用返回的 `locator` 和节点 `id` 定位源码,不凭名称猜目标。需要节点详情时使用 `pixifact node inspect --scene <scene.path> --node <locator>`;层级变化后重新获取 locator。
75
+ 2. 检查目标文件的同步状态。活动 Scene 未同步时 `editor context` 会拒绝返回上下文;成功返回也不代表其他标签已同步,编辑其他已打开 Scene 前检查 `openScenes` 中对应路径的 `syncState`。`saving` 或 context 正在更新时等待后重读;`unsaved` 或 `conflict` 时先让用户保存草稿或解决冲突,再重新读取 context 和磁盘源文件;`error` 时结合 CLI 错误和 Editor 提示排查。保留用户未保存内容,不擅自覆盖或放弃草稿。没有活动 Editor 或 Scene 时,已知目标路径就直接走 Scene 工作流;任务依赖当前选择且目标不明确时,先请用户明确目标。
76
+ 3. 按 Scene 工作流直接编辑目标 `.scene` 和必要的同名 `.ts`,运行 validate、compile 和项目最小相关检查。`editor context` 不提供修改入口。
77
+ 4. 外部改动会自动刷新已同步的标签;有未保存修改的标签会保留草稿,保存时可能出现版本冲突。改完后再次运行 `pixifact editor context`,确认活动 `scene.path` 仍是目标且 `scene.syncState="synced"`;成功返回表示该 context 的 revision 与当前磁盘文件一致。若仍在更新,等待后重读;若用户已切换 Scene,不能据此宣称目标 Scene 的预览已确认。
78
+ 5. 需要检查当前 Editor 画面时,确认目标 Scene 已同步且 `scene.previewState="ready"`,再截图并查看 PNG:
79
+ ```bash
80
+ pixifact editor screenshot --output /tmp/editor-scene.png
81
+ ```
82
+ 核对截图返回的 Scene 路径和 revision,避免把切换后的其他 Scene 当成目标。截图使用 Scene 设计尺寸,不包含 Editor UI 或选择框,不受画布 zoom / pan 影响,也不执行项目脚本。检查指定 Scene 的磁盘版本时用 `scene screenshot --scene <path>`;检查游戏运行后的状态时用 `runtime screenshot`。
83
+
61
84
  ## 运行时验证工作流
62
85
 
63
86
  任务影响 Vite Web 游戏行为、交互或运行时状态,或者需要诊断运行中游戏时,先完整阅读 `references/runtime-observation.md`,再按以下顺序操作:
@@ -1,4 +1,4 @@
1
1
  interface:
2
2
  display_name: "Pixifact"
3
- short_description: "在 Pixifact 项目中编辑 Scene、维护脚本契约并验证运行中游戏"
4
- default_prompt: "使用 $pixifact 编辑下游游戏的 Scene 或逻辑,并通过 CLI 校验和 Runtime 验证运行结果。"
3
+ short_description: "在 Pixifact 项目中编辑 Scene、与 Editor 协作并验证运行中游戏"
4
+ default_prompt: "使用 $pixifact 编辑下游游戏的 Scene 或逻辑,需要时读取 Editor 当前 Scene 和选择,并通过 CLI 校验、预览与 Runtime 验证结果。"
@@ -41,6 +41,7 @@ Decision:
41
41
  优先不拆。只有满足下面至少一条时才新建子 Scene:
42
42
 
43
43
  - 会在多个父 Scene 中复用。
44
+ - 九宫格 UI 素材需要集中维护图片路径和切片参数,采用每张 PNG 一个素材 Scene 的推荐写法,见 [NineImage](scene-objects.md#nineimage)。
44
45
  - 有独立 public props、events 或 slots。
45
46
  - 自身有明确交互行为,例如按钮、列表项、弹窗。
46
47
  - 层级足够复杂,拆出后能减少父 Scene 噪音。
@@ -88,6 +89,7 @@ Decision:
88
89
  | 横向资源条、工具栏 | `HBoxContainer` |
89
90
  | 纵向菜单、任务列表 | `VBoxContainer` |
90
91
  | 背包、关卡卡片、固定列 | `GridContainer` |
92
+ | 排列中的单个元素需要位置微调 | 明确尺寸的 `Group` 参与排列,偏移写在内部节点;见 [排列容器中的单独偏移](scene-hierarchy-patterns.md#排列容器中的单独偏移) |
91
93
  | 长列表、背包滚动区 | `ScrollContainer` + 内部 `VBoxContainer` / `GridContainer` |
92
94
  | 纯分组、统一移动或显隐 | `Container` |
93
95
 
@@ -129,6 +129,44 @@ Graphics
129
129
 
130
130
  不要手写大量 `x/y` 去模拟横排、竖排或网格,除非每个元素确实需要独立位置。
131
131
 
132
+ ## 排列容器中的单独偏移
133
+
134
+ 排列容器管理的是直接子节点的两个坐标:
135
+
136
+ | 父容器 | 子节点 `x` | 子节点 `y` |
137
+ | --- | --- | --- |
138
+ | `HBoxContainer` | 顺序排列与 `gap` / `justify` | `alignY` 对齐 |
139
+ | `VBoxContainer` | `alignX` 对齐 | 顺序排列与 `gap` / `justify` |
140
+ | `GridContainer` | 列位置与 `alignX` | 行位置与 `alignY` |
141
+
142
+ 所以横排子节点的 `y`、竖排子节点的 `x` 也不能作为自由偏移使用;直接写 `x/y` 会在重新布局时被覆盖。不要用直接子节点的 frame layout 约束或脚本反复改位置来绕过排列。
143
+
144
+ 整组对齐用父容器的 `alignY` / `alignX`,间距和分布用 `gap` / `justify`。只需微调一个元素时,用明确宽高的 `Group` 作为排列占位,内部节点保留自由位置。
145
+
146
+ 横排中把第一个元素单独下移 `8`:
147
+
148
+ ```xml
149
+ <HBoxContainer id="buttonRow" width="280" height="80" gap="16" alignY="center">
150
+ <Group id="firstSlot" width="120" height="64">
151
+ <Label id="firstLabel" y="8" width="120" height="48" text="下移 8" fontSize="24" />
152
+ </Group>
153
+ <Label id="secondLabel" width="120" height="64" text="保持对齐" fontSize="24" />
154
+ </HBoxContainer>
155
+ ```
156
+
157
+ 竖排中把第一个元素单独右移 `8`:
158
+
159
+ ```xml
160
+ <VBoxContainer id="buttonColumn" width="180" height="160" gap="16" alignX="center">
161
+ <Group id="firstSlot" width="120" height="64">
162
+ <Label id="firstLabel" x="8" width="104" height="64" text="右移 8" fontSize="24" />
163
+ </Group>
164
+ <Label id="secondLabel" width="120" height="64" text="保持对齐" fontSize="24" />
165
+ </VBoxContainer>
166
+ ```
167
+
168
+ 排列按外层 `Group.width` / `height` 计算,不会因为内部节点偏移自动扩大占位。需要为内容留出空间时,显式调整占位尺寸;同时检查是否与邻项重叠或被滚动区域裁剪。内部节点若也设置了同轴 frame layout 约束,其 `x/y` 仍会被该约束覆盖。
169
+
132
170
  ## ScrollContainer 标准结构
133
171
 
134
172
  滚动容器通常只直接承载一个内容 layout container:
@@ -166,6 +166,8 @@
166
166
 
167
167
  横向排列直接子节点。
168
168
 
169
+ 直接子节点的 `x/y` 都由容器管理,`y` 由 `alignY` 决定。单独上下微调时,使用明确尺寸的 `Group` 占位并调整内部节点,见 [排列容器中的单独偏移](scene-hierarchy-patterns.md#排列容器中的单独偏移)。
170
+
169
171
  | 属性 | 类型 | 可选值 / 说明 |
170
172
  | --- | --- | --- |
171
173
  | `gap` | number | 子节点之间的基础横向间距。 |
@@ -183,6 +185,8 @@
183
185
 
184
186
  纵向排列直接子节点。
185
187
 
188
+ 直接子节点的 `x/y` 都由容器管理,`x` 由 `alignX` 决定。单独左右微调时,使用明确尺寸的 `Group` 占位并调整内部节点,见 [排列容器中的单独偏移](scene-hierarchy-patterns.md#排列容器中的单独偏移)。
189
+
186
190
  | 属性 | 类型 | 可选值 / 说明 |
187
191
  | --- | --- | --- |
188
192
  | `gap` | number | 子节点之间的基础纵向间距。 |
@@ -323,10 +327,42 @@ Pixifact runtime 九宫格图片,推荐用于按钮底图、弹窗面板、提
323
327
  | `anchorY` | number | 纵向 anchor。 |
324
328
  | `tint` | color | 图片 tint。 |
325
329
 
330
+ 推荐每张九宫格 PNG 对应一个素材 Scene,集中维护 `texture` 和四边切片参数;使用相同图片的按钮、面板、弹窗直接引用该 Scene,避免在各处重复配置。
331
+
332
+ 例如 `assets/ui/panel.png` 为 `96 × 96`、四边切片各 `24` 的素材,在 `src/ui/nine/PanelBackground.scene` 中设置:
333
+
334
+ ```xml
335
+ <Scene name="PanelBackground" width="96" height="96" eventMode="none">
336
+ <NineImage id="image" texture="assets/ui/panel.png"
337
+ left="0" right="0" top="0" bottom="0"
338
+ leftWidth="24" rightWidth="24" topHeight="24" bottomHeight="24"
339
+ eventMode="none" />
340
+ </Scene>
341
+ ```
342
+
343
+ 配对的 `src/ui/nine/PanelBackground.ts` 只需要声明 Scene:
344
+
345
+ ```ts
346
+ import { Group } from 'pixifact/runtime';
347
+ import { scene } from 'pixifact/scene';
348
+
349
+ @scene()
350
+ export class PanelBackground extends Group {}
351
+ ```
352
+
353
+ 调用方 `src/ui/Panel.scene` 只负责位置与尺寸,内部 `NineImage` 随 Scene 盒子铺满:
354
+
326
355
  ```xml
327
- <NineImage id="dialogPanel" texture="assets/ui/panel.png" horizontal="0" vertical="0" width="620" height="420" leftWidth="32" rightWidth="32" topHeight="32" bottomHeight="32" />
356
+ <Scene name="Panel" width="620" height="420">
357
+ <PanelBackground id="background" scene="./nine/PanelBackground.scene"
358
+ left="0" right="0" top="0" bottom="0" />
359
+ </Scene>
328
360
  ```
329
361
 
362
+ 调用方仍需同名 `Panel.ts`。纯背景的 `eventMode="none"` 让输入由外层组件处理。
363
+
364
+ 图片尺寸和切片值按素材实际像素设置,`96` / `24` 是示例,不是固定规格。替换同名、同尺寸、同切片边距的 PNG 即可换外观;素材规格变化时,集中修改对应素材 Scene 的图片路径、切片参数和必要的默认盒子尺寸,再校验所有引用并检查不同尺寸下的效果。布局中改变背景尺寸时,使用 Scene 的 `width/height` 或 frame layout;`scaleX/scaleY` 会把边角一起缩放。
365
+
330
366
  ### TileImage
331
367
 
332
368
  Pixifact runtime 平铺图片,推荐用于重复背景或可滚动纹理。
@@ -509,7 +545,7 @@ declare disabled: boolean;
509
545
 
510
546
  ```xml
511
547
  <Scene name="PrimaryButton" width="420" height="88">
512
- <NineImage id="background" texture="assets/ui/button.png" left="0" right="0" top="0" bottom="0" leftWidth="24" rightWidth="24" topHeight="24" bottomHeight="24" />
548
+ <ButtonBackground id="background" scene="./nine/ButtonBackground.scene" left="0" right="0" top="0" bottom="0" />
513
549
  <HBoxContainer id="content" horizontal="0" vertical="0" gap="12" alignY="center">
514
550
  <slot name="icon" />
515
551
  <Text id="label" text="Button" fontSize="28" fill="#ffffff" />
@@ -519,6 +555,8 @@ declare disabled: boolean;
519
555
 
520
556
  `<slot />` 省略 `name` 时表示 `default` slot。
521
557
 
558
+ `ButtonBackground` 按上面的 `NineImage` 推荐方式封装 `assets/ui/button.png`,并配对同名 `.ts`。
559
+
522
560
  ## Events
523
561
 
524
562
  事件属性写在子 Scene instance 上,绑定值是 action name:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-pixifact",
3
- "version": "0.17.0",
3
+ "version": "0.19.0",
4
4
  "description": "创建 Pixifact 游戏项目。",
5
5
  "packageManager": "bun@1.3.13",
6
6
  "type": "module",
@@ -9,7 +9,10 @@
9
9
  },
10
10
  "files": [
11
11
  "dist/",
12
- "templates/"
12
+ "templates/",
13
+ "!templates/**/.pixifact/**",
14
+ "!templates/**/dist/**",
15
+ "!templates/**/node_modules/**"
13
16
  ],
14
17
  "repository": {
15
18
  "type": "git",
@@ -0,0 +1 @@
1
+ VITE_PLATFORM=web
@@ -0,0 +1,119 @@
1
+ # Pixifact 基础游戏模板
2
+
3
+ 这是可以直接复制开发新游戏的 Web 项目。默认设计尺寸为竖屏 `1080 × 1920`,适配模式为 `fixedWidth`。启动首页集中展示可替换外观的基础 UI 组件,并附带游戏、暂停、结算和最高分保存的代码示例。
4
+
5
+ 本模板使用 Bun `1.3.13` 验证;需要本机安装 Bun 和 Git。
6
+
7
+ ## 运行
8
+
9
+ ```bash
10
+ bun install
11
+ bun run dev
12
+ ```
13
+
14
+ 打开终端输出的地址,先在组件展台试用:
15
+
16
+ - **Button**:大、中、小三种尺寸、轻微按压回弹、图标、禁用状态、启用/禁用切换与点击计数。
17
+ - **ProgressBar**:每次增减 25%,到达 0% 或 100% 后禁用对应方向的按钮。
18
+ - **Panel**:标题和内容区组合;展台各区块也复用同一个 Panel。
19
+ - **Dialog**:确认/取消、结果反馈与模态遮罩;弹窗期间不能操作底层组件,关闭后保留展台状态。
20
+
21
+ 点击底部「体验游戏流程」,收集 8 份星光即可结算;可以暂停、继续、返回组件展台和重玩。暂停期间不能得分。最高记录保存在当前浏览器,同一地址刷新后仍可读取;页面切到后台时自动暂停。返回展台会创建新的展示页,组件演示状态恢复初始值。
22
+
23
+ ```bash
24
+ bun run validate
25
+ bun run compile
26
+ bun run typecheck
27
+ bun run build
28
+ bun run editor
29
+ ```
30
+
31
+ `dev` / `build` 自动编译 Scene;独立执行 `compile` 便于检查生成结果。生成目录 `.pixifact/` 和构建目录 `dist/` 不作为源码维护。
32
+
33
+ `fixedWidth` 使用屏幕宽度除以 1080 作为缩放比例,再由屏幕高度反推 Scene 的可用高度。页面背景和弹窗遮罩随视口铺满;组件展台和游戏示例的内容在短窗口中可以纵向滚动。
34
+
35
+ ## 基础代码
36
+
37
+ | 位置 | 职责 |
38
+ | --- | --- |
39
+ | `src/main.ts` | Application、Assets、Scene 准备、视口适配、后台暂停、开发期 Runtime |
40
+ | `src/GameApp.ts` | 连接组件预览弹窗、游戏状态、页面事件、暂停和存档 |
41
+ | `src/core/GameSession.ts` | 纯 TypeScript 规则和状态,可替换为自己的玩法 |
42
+ | `src/core/ScreenManager.ts` | 页面替换、断开外部订阅、销毁旧节点;共享纹理继续复用 |
43
+ | `src/core/WebRecordStore.ts` | 显式读写最高分;使用 Web 原生 localStorage |
44
+ | `src/screens/` | 页面 `.scene` 外观和同名 `.ts` 行为契约 |
45
+ | `src/screens/MainMenu.scene/.ts` | 默认组件展台、演示状态和次要游戏入口 |
46
+ | `src/ui/` | 当前生效的基础 UI Scene 与脚本 |
47
+ | `src/ui/nine/` | 每张九宫格素材对应的 Scene,集中设置图片路径和切片参数 |
48
+ | `assets/ui/` | 当前生效的按钮和面板九宫格 PNG 图片(96 × 96,透明 RGBA) |
49
+
50
+ 开始开发自己的游戏时,先修改 `GameSession` 中的规则,再修改 `PlayScreen` 的视觉和公开事件,最后在 `GameApp` 中连接数据流。游戏规则不读取 UI 内部节点。给新页面增加同目录同 basename 的 `.scene/.ts`,启动前用 `prepareSceneClass()` 准备,再交给 `ScreenManager.replace()`。
51
+
52
+ `ScreenManager.track(event.connect(handler))` 注册当前页面的外部连接,必须在 `replace()` 之后调用。移除页面和关闭弹窗时会统一取消这些连接。GameApp 的初始尺寸读取项目设计分辨率;页面、模态管理器和当前 Scene 通过 frame layout 跟随可用视口。切换设计分辨率时同步修改页面与 Dialog 的根尺寸及页面内容坐标。
53
+
54
+ ## UI 库契约
55
+
56
+ | 组件 | 公开契约 | 组合方式 |
57
+ | --- | --- | --- |
58
+ | Button | `text`、`disabled`、`size`,`clicked` 事件 | `icon` slot;禁用状态禁止触发事件和按压动画 |
59
+ | Panel | `title` | `content` slot |
60
+ | Dialog | `title`、`message`、`confirmText`、`cancelText`;`confirmed` / `cancelled` 事件 | 全屏遮罩和居中面板,用于模态操作 |
61
+ | ProgressBar | `setProgress(value, max)`,`max > 0` | 可改变宽高;填充比例保持不变 |
62
+
63
+ 例如,在自己的页面 `.scene` 中使用:
64
+
65
+ ```xml
66
+ <Button id="startButton" scene="../ui/Button.scene"
67
+ horizontal="0" top="400" width="360" height="96" size="large"
68
+ text="开始游戏" @clicked="start" />
69
+ ```
70
+
71
+ `size` 默认为 `medium`,可在 Scene 中指定或在脚本中赋值。三种尺寸同步调整按钮默认宽高、字号和图标区域:
72
+
73
+ | size | 默认宽 × 高 | 字号 | 图标区域 |
74
+ | --- | --- | --- | --- |
75
+ | `large` | 360 × 96 | 42 | 36 × 36 |
76
+ | `medium` | 280 × 80 | 36 | 32 × 32 |
77
+ | `small` | 200 × 64 | 32 | 28 × 28 |
78
+
79
+ Scene 的 `width` / `height` 或 frame layout 可覆盖默认宽高。按下时视觉缩小到 97%,松开后约 140ms 平滑回到原位;移出按钮、在按钮外松开或取消触摸也会复位。动画仅缩放内部 `visual` 节点,按钮布局和命中区域保持稳定;节点移除后不再执行渲染回调。
80
+
81
+ 页面的 `start()` action 负责发出业务事件。文字通过 Prop Binding 更新,父页面依赖公开事件和 slot,不依赖 Button 背景、Panel 内部节点等实现细节。
82
+
83
+ ## 直接替换图片素材
84
+
85
+ 模板只提供一套基础 UI。开发自己的游戏时,直接替换同名 PNG 即可更换对应背景,无需修改 Scene、组件脚本或游戏逻辑。
86
+
87
+ | 图片 | 素材 Scene | 用途 | 默认尺寸/切片边距 |
88
+ | --- | --- | --- | --- |
89
+ | `assets/ui/button.png` | `src/ui/nine/ButtonBackground.scene` | 所有尺寸按钮的背景 | 96 × 96/四边各 24 像素 |
90
+ | `assets/ui/panel.png` | `src/ui/nine/PanelBackground.scene` | 面板和弹窗的背景 | 96 × 96/四边各 24 像素 |
91
+
92
+ 新素材保持文件名、路径、尺寸与透明 PNG 格式。四个角保持原形,边缘沿单轴拉伸,中间区域随组件尺寸拉伸;将需要保留的边框和圆角放在 24 像素的切片区域内。大、中、小按钮共用同一张图片,文字和点击动画由组件负责。
93
+
94
+ 每张九宫格 PNG 只在对应素材 Scene 中配置一个 `NineImage`。图片路径和 `leftWidth`、`rightWidth`、`topHeight`、`bottomHeight` 集中维护;Button、Panel、Dialog 引用素材 Scene,自身只设置背景的位置和尺寸。例如,在 `src/ui/` 的组件中铺满面板背景:
95
+
96
+ ```xml
97
+ <PanelBackground id="background" scene="./nine/PanelBackground.scene"
98
+ left="0" right="0" top="0" bottom="0" />
99
+ ```
100
+
101
+ 需要调整切片边距或换成不同规格图片时,只修改对应素材 Scene 的 `NineImage` 参数;所有引用位置会使用同一份配置。新增九宫格素材也按一张 PNG 一个 `.scene/.ts` 配对文件组织,素材 Scene 的根和内部图像均设为 `eventMode="none"`,内部图像通过四边为 0 铺满实例。
102
+
103
+ 覆盖图片后,重新启动开发服务并刷新预览;发布构建使用 `bun run build`。PNG 负责上述背景,文字、禁用蒙层和进度条由 Scene 节点渲染;需要调整这些部分的颜色或布局时,再编辑对应 `.scene`。
104
+
105
+ 每个 `.scene` 与同目录同名 `.ts` 配对;`@scene()` 类继承 `Group`,不声明自定义构造参数。非 Prop 依赖用显式方法传入。新增视觉节点或修改事件后运行 `pixifact scene validate --all`,避免外观替换破坏组件契约。
106
+
107
+ ## Agent 观察
108
+
109
+ 开发服务运行且浏览器打开后,在项目根目录执行:
110
+
111
+ ```bash
112
+ pixifact runtime state
113
+ pixifact runtime tree
114
+ pixifact runtime screenshot
115
+ ```
116
+
117
+ 业务快照包含 `phase`、`score`、`goal`、`bestScore`、`modalOpen`;首页额外提供 `showcase`,包含 `buttonClicks`、`previewDisabled`、`progress`、`dialogResult`,进入游戏后为 `null`。可以结合真实节点树检查组件状态、弹窗隔离、页面切换、暂停和最高分保存。
118
+
119
+ 首版入口和存档使用 Web API。接入微信/抖音时,按 Pixifact 的平台文档接入现有平台包,并将 DOM 入口、visibility 事件和 WebRecordStore 替换为对应平台实现。
@@ -0,0 +1 @@
1
+ env = false
@@ -0,0 +1,12 @@
1
+ <!doctype html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Pixifact UI 组件展示</title>
7
+ </head>
8
+ <body>
9
+ <div id="game"></div>
10
+ <script type="module" src="/src/main.ts"></script>
11
+ </body>
12
+ </html>
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "pixifact-game-starter",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "packageManager": "bun@1.3.13",
6
+ "type": "module",
7
+ "scripts": {
8
+ "dev": "pixifact dev --mode development --project-root .",
9
+ "build": "pixifact build --mode production --project-root .",
10
+ "compile": "pixifact compile-scenes --project-root .",
11
+ "editor": "pixifact editor --project-root .",
12
+ "validate": "pixifact validate --mode production --project-root .",
13
+ "typecheck": "tsc --noEmit"
14
+ },
15
+ "dependencies": {
16
+ "pixi.js": "8.18.1",
17
+ "pixifact": "^0.19.0"
18
+ },
19
+ "devDependencies": {
20
+ "pixifact-cli": "^0.19.0",
21
+ "typescript": "^5.3.3",
22
+ "vite": "^8.0.10"
23
+ }
24
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "version": 2,
3
+ "name": "Pixifact Game Starter",
4
+ "resolution": { "width": 1080, "height": 1920 },
5
+ "viewport": { "mode": "fixedWidth" },
6
+ "scenes": {
7
+ "mainMenu": "src/screens/MainMenu.scene",
8
+ "play": "src/screens/PlayScreen.scene",
9
+ "result": "src/screens/ResultScreen.scene"
10
+ }
11
+ }