@coze-arch/cli 0.0.36-alpha.dd2af3 → 0.0.36-alpha.e6ca88

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 (83) hide show
  1. package/README.md +65 -114
  2. package/docs/deploy.md +2 -1
  3. package/lib/__templates__/native-static/.coze +2 -0
  4. package/lib/__templates__/native-static/scripts/serve.ps1 +7 -0
  5. package/lib/__templates__/nextjs/.coze +5 -0
  6. package/lib/__templates__/nextjs/scripts/build.ps1 +16 -0
  7. package/lib/__templates__/nextjs/scripts/dev.ps1 +63 -0
  8. package/lib/__templates__/nextjs/scripts/dev.sh +80 -8
  9. package/lib/__templates__/nextjs/scripts/prepare.ps1 +18 -0
  10. package/lib/__templates__/nextjs/scripts/start.ps1 +11 -0
  11. package/lib/__templates__/nextjs/scripts/validate.ps1 +8 -0
  12. package/lib/__templates__/nuxt-vue/.coze +5 -0
  13. package/lib/__templates__/nuxt-vue/scripts/build.ps1 +12 -0
  14. package/lib/__templates__/nuxt-vue/scripts/dev.ps1 +63 -0
  15. package/lib/__templates__/nuxt-vue/scripts/dev.sh +82 -1
  16. package/lib/__templates__/nuxt-vue/scripts/prepare.ps1 +12 -0
  17. package/lib/__templates__/nuxt-vue/scripts/start.ps1 +11 -0
  18. package/lib/__templates__/nuxt-vue/scripts/validate.ps1 +8 -0
  19. package/lib/__templates__/phaser/.coze +5 -0
  20. package/lib/__templates__/phaser/README.md +8 -0
  21. package/lib/__templates__/phaser/scripts/build.ps1 +12 -0
  22. package/lib/__templates__/phaser/scripts/dev.ps1 +49 -0
  23. package/lib/__templates__/phaser/scripts/prepare.ps1 +8 -0
  24. package/lib/__templates__/phaser/scripts/start.ps1 +49 -0
  25. package/lib/__templates__/phaser/scripts/validate.ps1 +7 -0
  26. package/lib/__templates__/phaser/src/global.d.ts +3 -0
  27. package/lib/__templates__/phaser/src/scene/BootScene.ts +4 -0
  28. package/lib/__templates__/phaser/src/scene/DevLoadingScene.ts +3 -0
  29. package/lib/__templates__/phaser/src/utils/mark-editable.ts +8 -1
  30. package/lib/__templates__/phaser-static/.coze +15 -0
  31. package/lib/__templates__/phaser-static/README.md +40 -0
  32. package/lib/__templates__/phaser-static/_gitignore +6 -0
  33. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0001.png +0 -0
  34. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0002.png +0 -0
  35. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0003.png +0 -0
  36. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0004.png +0 -0
  37. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0005.png +0 -0
  38. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0006.png +0 -0
  39. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0007.png +0 -0
  40. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0008.png +0 -0
  41. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0009.png +0 -0
  42. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0010.png +0 -0
  43. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0011.png +0 -0
  44. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0012.png +0 -0
  45. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0013.png +0 -0
  46. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0014.png +0 -0
  47. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0015.png +0 -0
  48. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0016.png +0 -0
  49. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0017.png +0 -0
  50. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0018.png +0 -0
  51. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0019.png +0 -0
  52. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0020.png +0 -0
  53. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0021.png +0 -0
  54. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0022.png +0 -0
  55. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0023.png +0 -0
  56. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/frame_0024.png +0 -0
  57. package/lib/__templates__/phaser-static/assets/image_sequence/coze-game-loading/manifest.json +11 -0
  58. package/lib/__templates__/phaser-static/debug-runtime/flow-graph.json +20 -0
  59. package/lib/__templates__/phaser-static/index.html +17 -0
  60. package/lib/__templates__/phaser-static/scripts/serve.ps1 +7 -0
  61. package/lib/__templates__/phaser-static/src/assets.js +15 -0
  62. package/lib/__templates__/phaser-static/src/main.js +26 -0
  63. package/lib/__templates__/phaser-static/src/phaser.js +7 -0
  64. package/lib/__templates__/phaser-static/src/scene/BootScene.js +205 -0
  65. package/lib/__templates__/phaser-static/src/scene/DevLoadingScene.js +67 -0
  66. package/lib/__templates__/phaser-static/src/style.css +28 -0
  67. package/lib/__templates__/phaser-static/src/utils/asset-loader.js +267 -0
  68. package/lib/__templates__/phaser-static/src/utils/index.js +2 -0
  69. package/lib/__templates__/phaser-static/src/utils/mark-editable.js +3 -0
  70. package/lib/__templates__/phaser-static/template.config.js +35 -0
  71. package/lib/__templates__/taro/.cozeproj/scripts/dev_run.sh +53 -22
  72. package/lib/__templates__/templates.json +18 -0
  73. package/lib/__templates__/vite/.coze +5 -0
  74. package/lib/__templates__/vite/scripts/build.ps1 +16 -0
  75. package/lib/__templates__/vite/scripts/dev.ps1 +63 -0
  76. package/lib/__templates__/vite/scripts/dev.sh +82 -1
  77. package/lib/__templates__/vite/scripts/prepare.ps1 +18 -0
  78. package/lib/__templates__/vite/scripts/start.ps1 +11 -0
  79. package/lib/__templates__/vite/scripts/validate.ps1 +8 -0
  80. package/lib/cli.js +186 -155
  81. package/lib/deploy/package-project.js +22 -4
  82. package/lib/deploy/package-project.py +18 -3
  83. package/package.json +1 -1
@@ -32,8 +32,89 @@ kill_port_if_listening() {
32
32
  fi
33
33
  }
34
34
 
35
+ <% if (process.env.NODE_ENV === 'test') { %>
36
+ echo "Clearing port ${DEPLOY_RUN_PORT} before start."
37
+ kill_port_if_listening
38
+ echo "Starting Nuxt dev server on port ${DEPLOY_RUN_PORT}..."
39
+
40
+ # 测试环境保持服务为前台进程,便于 e2e 收集输出并停止进程。
41
+ exec env PORT="${DEPLOY_RUN_PORT}" pnpm nuxt dev
42
+ <% } else { %>
43
+ LOG_DIR="${COZE_LOG_DIR:-${COZE_WORKSPACE_PATH}/logs}"
44
+ LOG_FILE="${LOG_DIR}/server.log"
45
+ PID_FILE="${LOG_DIR}/server.pid"
46
+
47
+ # coze-daemon 会在 runtime shell 退出时清理原进程组。
48
+ # 通过 Node detached spawn 创建独立 session/进程组,并将 stdio 直接写入日志。
49
+ spawn_detached() {
50
+ local cwd="$1"
51
+ local log_file="$2"
52
+ shift 2
53
+
54
+ node - "$cwd" "$log_file" "$@" <<'NODE'
55
+ const fs = require('node:fs');
56
+ const { spawn } = require('node:child_process');
57
+
58
+ const [cwd, logFile, command, ...args] = process.argv.slice(2);
59
+ if (!cwd || !logFile || !command) {
60
+ throw new Error('spawn_detached 缺少 cwd、log_file 或 command');
61
+ }
62
+
63
+ const logFd = fs.openSync(logFile, 'a');
64
+ try {
65
+ const child = spawn(command, args, {
66
+ cwd,
67
+ detached: true,
68
+ env: process.env,
69
+ stdio: ['ignore', logFd, logFd],
70
+ });
71
+ child.unref();
72
+ process.stdout.write(String(child.pid));
73
+ } finally {
74
+ fs.closeSync(logFd);
75
+ }
76
+ NODE
77
+ }
78
+
79
+ stop_detached() {
80
+ local pid="${1:-}"
81
+ if [[ -z "${pid}" ]]; then
82
+ return
83
+ fi
84
+
85
+ kill -TERM -- "-${pid}" 2>/dev/null || kill -TERM "${pid}" 2>/dev/null || true
86
+ sleep 1
87
+ kill -KILL -- "-${pid}" 2>/dev/null || true
88
+ }
89
+
90
+ # 监听端口的是孙进程(pnpm -> nuxt -> node),只清端口会漏掉上层 pnpm/nuxt,
91
+ # 所以先按上次记录的 PID 把整个进程组回收掉。
92
+ if [[ -f "${PID_FILE}" ]]; then
93
+ stop_detached "$(cat "${PID_FILE}" 2>/dev/null || true)"
94
+ rm -f "${PID_FILE}"
95
+ fi
96
+
35
97
  echo "Clearing port ${DEPLOY_RUN_PORT} before start."
36
98
  kill_port_if_listening
37
99
  echo "Starting Nuxt dev server on port ${DEPLOY_RUN_PORT}..."
38
100
 
39
- PORT=${DEPLOY_RUN_PORT} pnpm nuxt dev
101
+ mkdir -p "${LOG_DIR}"
102
+ : > "${LOG_FILE}"
103
+
104
+ export PORT="${DEPLOY_RUN_PORT}"
105
+ server_pid="$(spawn_detached "${COZE_WORKSPACE_PATH}" "${LOG_FILE}" \
106
+ "$(command -v pnpm)" nuxt dev)"
107
+ echo "${server_pid}" > "${PID_FILE}"
108
+
109
+ sleep 1
110
+ if [[ -z "${server_pid}" ]] || ! kill -0 "${server_pid}" 2>/dev/null; then
111
+ echo "Dev server failed to start. See ${LOG_FILE}." >&2
112
+ tail -n 20 "${LOG_FILE}" >&2 || true
113
+ rm -f "${PID_FILE}"
114
+ exit 1
115
+ fi
116
+
117
+ echo "Dev server started (PID: ${server_pid})."
118
+ echo "Log file: ${LOG_FILE}"
119
+ echo "PID file: ${PID_FILE}"
120
+ <% } %>
@@ -0,0 +1,12 @@
1
+ $ErrorActionPreference = "Stop"
2
+
3
+ $workspace = if ($env:COZE_WORKSPACE_PATH) { $env:COZE_WORKSPACE_PATH } else { (Get-Location).Path }
4
+ Set-Location $workspace
5
+
6
+ Write-Host "Installing dependencies..."
7
+ & pnpm install --prefer-frozen-lockfile --prefer-offline
8
+ if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
9
+
10
+ Write-Host "Preparing Nuxt..."
11
+ & pnpm exec nuxt prepare
12
+ exit $LASTEXITCODE
@@ -0,0 +1,11 @@
1
+ $ErrorActionPreference = "Stop"
2
+
3
+ $workspace = if ($env:COZE_WORKSPACE_PATH) { $env:COZE_WORKSPACE_PATH } else { (Get-Location).Path }
4
+ $defaultPort = <%= port %>
5
+ $port = if ($env:DEPLOY_RUN_PORT) { $env:DEPLOY_RUN_PORT } elseif ($env:PORT) { $env:PORT } else { $defaultPort }
6
+ Set-Location $workspace
7
+
8
+ Write-Host "Starting Nuxt.js service on port $port for production..."
9
+ $env:PORT = "$port"
10
+ & node .output/server/index.mjs
11
+ exit $LASTEXITCODE
@@ -0,0 +1,8 @@
1
+ $ErrorActionPreference = "Stop"
2
+
3
+ $workspace = if ($env:COZE_WORKSPACE_PATH) { $env:COZE_WORKSPACE_PATH } else { (Get-Location).Path }
4
+ Set-Location $workspace
5
+
6
+ Write-Host "Running validate..."
7
+ & pnpm validate
8
+ exit $LASTEXITCODE
@@ -5,9 +5,14 @@ game_type = "phaser"
5
5
 
6
6
  [dev]
7
7
  build = ["bash", "./scripts/prepare.sh"]
8
+ build_win = ["powershell.exe", "-NoProfile", "-ExecutionPolicy", "Bypass", "-File", "./scripts/prepare.ps1"]
8
9
  run = ["bash", "./scripts/dev.sh"]
10
+ run_win = ["powershell.exe", "-NoProfile", "-ExecutionPolicy", "Bypass", "-File", "./scripts/dev.ps1"]
9
11
  validate = ["bash", "./scripts/validate.sh"]
12
+ validate_win = ["powershell.exe", "-NoProfile", "-ExecutionPolicy", "Bypass", "-File", "./scripts/validate.ps1"]
10
13
 
11
14
  [deploy]
12
15
  build = ["bash", "./scripts/build.sh"]
16
+ build_win = ["powershell.exe", "-NoProfile", "-ExecutionPolicy", "Bypass", "-File", "./scripts/build.ps1"]
13
17
  run = ["bash", "./scripts/start.sh"]
18
+ run_win = ["powershell.exe", "-NoProfile", "-ExecutionPolicy", "Bypass", "-File", "./scripts/start.ps1"]
@@ -35,3 +35,11 @@ coze-dev start # 预览生产构建
35
35
  - 开发和生产都使用稳定的 `assets/...` 路径,生产构建原样复制素材目录。
36
36
 
37
37
  `IMAGES`、`IMAGE_SEQUENCES`、`VIDEOS` 和 `AUDIOS` 是四个素材分类表。
38
+
39
+ ## 可视化编辑标识
40
+
41
+ 用 `markEditable` 标记可在编辑器中调整的对象;第三个参数可选,仅用于编辑器展示名称:
42
+
43
+ ```ts
44
+ markEditable('ui.start-button', button, { label: '开始按钮' });
45
+ ```
@@ -0,0 +1,12 @@
1
+ $ErrorActionPreference = "Stop"
2
+
3
+ $workspace = if ($env:COZE_WORKSPACE_PATH) { $env:COZE_WORKSPACE_PATH } else { (Get-Location).Path }
4
+ Set-Location $workspace
5
+
6
+ Write-Host "Installing dependencies..."
7
+ & pnpm install --prefer-frozen-lockfile --prefer-offline --reporter=append-only
8
+ if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
9
+
10
+ $env:COZE_PHASER_GAME_ENV = "PROD"
11
+ & pnpm build
12
+ exit $LASTEXITCODE
@@ -0,0 +1,49 @@
1
+ $ErrorActionPreference = "Stop"
2
+
3
+ function Stop-ProcessTree([int] $processId) {
4
+ if ($processId -gt 0 -and (Get-Process -Id $processId -ErrorAction SilentlyContinue)) {
5
+ & taskkill.exe /PID $processId /T /F *> $null
6
+ }
7
+ }
8
+
9
+ function Stop-ListeningProcess([int] $port) {
10
+ $connections = Get-NetTCPConnection -LocalPort $port -State Listen -ErrorAction SilentlyContinue
11
+ $connections | Select-Object -ExpandProperty OwningProcess -Unique | ForEach-Object {
12
+ Stop-ProcessTree $_
13
+ }
14
+ }
15
+
16
+ $workspace = if ($env:COZE_WORKSPACE_PATH) { $env:COZE_WORKSPACE_PATH } else { (Get-Location).Path }
17
+ $defaultPort = <%= port %>
18
+ $port = if ($env:DEPLOY_RUN_PORT) { [int] $env:DEPLOY_RUN_PORT } elseif ($env:PORT) { [int] $env:PORT } else { $defaultPort }
19
+ Set-Location $workspace
20
+ Stop-ListeningProcess $port
21
+ $env:COZE_PHASER_GAME_ENV = "DEV"
22
+
23
+ <% if (process.env.NODE_ENV === 'test') { %>
24
+ & pnpm vite --port $port --host 127.0.0.1 --strictPort
25
+ exit $LASTEXITCODE
26
+ <% } else { %>
27
+ $logDirectory = if ($env:COZE_LOG_DIR) { $env:COZE_LOG_DIR } else { Join-Path $workspace "logs" }
28
+ $logFile = Join-Path $logDirectory "phaser-dev.log"
29
+ $errorLogFile = Join-Path $logDirectory "phaser-dev-error.log"
30
+ $pidFile = Join-Path $logDirectory "phaser-dev.pid"
31
+ New-Item -ItemType Directory -Force -Path $logDirectory | Out-Null
32
+
33
+ if (Test-Path $pidFile) {
34
+ Stop-ProcessTree ([int] (Get-Content $pidFile -Raw))
35
+ Remove-Item $pidFile -Force
36
+ }
37
+
38
+ $process = Start-Process -FilePath $env:ComSpec -ArgumentList @("/d", "/s", "/c", "pnpm vite --port $port --host 127.0.0.1 --strictPort") -WorkingDirectory $workspace -RedirectStandardOutput $logFile -RedirectStandardError $errorLogFile -PassThru
39
+ $process.Id | Set-Content $pidFile
40
+ Start-Sleep -Seconds 1
41
+ if ($process.HasExited) {
42
+ Get-Content $errorLogFile -Tail 20 -ErrorAction SilentlyContinue
43
+ Remove-Item $pidFile -Force -ErrorAction SilentlyContinue
44
+ exit 1
45
+ }
46
+
47
+ Write-Host "Phaser dev server started (PID: $($process.Id))."
48
+ Write-Host "Log file: $logFile"
49
+ <% } %>
@@ -0,0 +1,8 @@
1
+ $ErrorActionPreference = "Stop"
2
+
3
+ $workspace = if ($env:COZE_WORKSPACE_PATH) { $env:COZE_WORKSPACE_PATH } else { (Get-Location).Path }
4
+ Set-Location $workspace
5
+
6
+ Write-Host "Installing dependencies..."
7
+ & pnpm install --prefer-frozen-lockfile --prefer-offline --reporter=append-only
8
+ exit $LASTEXITCODE
@@ -0,0 +1,49 @@
1
+ $ErrorActionPreference = "Stop"
2
+
3
+ function Stop-ProcessTree([int] $processId) {
4
+ if ($processId -gt 0 -and (Get-Process -Id $processId -ErrorAction SilentlyContinue)) {
5
+ & taskkill.exe /PID $processId /T /F *> $null
6
+ }
7
+ }
8
+
9
+ function Stop-ListeningProcess([int] $port) {
10
+ $connections = Get-NetTCPConnection -LocalPort $port -State Listen -ErrorAction SilentlyContinue
11
+ $connections | Select-Object -ExpandProperty OwningProcess -Unique | ForEach-Object {
12
+ Stop-ProcessTree $_
13
+ }
14
+ }
15
+
16
+ $workspace = if ($env:COZE_WORKSPACE_PATH) { $env:COZE_WORKSPACE_PATH } else { (Get-Location).Path }
17
+ $defaultPort = <%= port %>
18
+ $port = if ($env:DEPLOY_RUN_PORT) { [int] $env:DEPLOY_RUN_PORT } elseif ($env:PORT) { [int] $env:PORT } else { $defaultPort }
19
+ Set-Location $workspace
20
+ Stop-ListeningProcess $port
21
+ $env:COZE_PHASER_GAME_ENV = "PROD"
22
+
23
+ <% if (process.env.NODE_ENV === 'test') { %>
24
+ & pnpm vite preview --port $port --host 127.0.0.1 --strictPort
25
+ exit $LASTEXITCODE
26
+ <% } else { %>
27
+ $logDirectory = if ($env:COZE_LOG_DIR) { $env:COZE_LOG_DIR } else { Join-Path $workspace "logs" }
28
+ $logFile = Join-Path $logDirectory "phaser-start.log"
29
+ $errorLogFile = Join-Path $logDirectory "phaser-start-error.log"
30
+ $pidFile = Join-Path $logDirectory "phaser-start.pid"
31
+ New-Item -ItemType Directory -Force -Path $logDirectory | Out-Null
32
+
33
+ if (Test-Path $pidFile) {
34
+ Stop-ProcessTree ([int] (Get-Content $pidFile -Raw))
35
+ Remove-Item $pidFile -Force
36
+ }
37
+
38
+ $process = Start-Process -FilePath $env:ComSpec -ArgumentList @("/d", "/s", "/c", "pnpm vite preview --port $port --host 127.0.0.1 --strictPort") -WorkingDirectory $workspace -RedirectStandardOutput $logFile -RedirectStandardError $errorLogFile -PassThru
39
+ $process.Id | Set-Content $pidFile
40
+ Start-Sleep -Seconds 1
41
+ if ($process.HasExited) {
42
+ Get-Content $errorLogFile -Tail 20 -ErrorAction SilentlyContinue
43
+ Remove-Item $pidFile -Force -ErrorAction SilentlyContinue
44
+ exit 1
45
+ }
46
+
47
+ Write-Host "Phaser production server started (PID: $($process.Id))."
48
+ Write-Host "Log file: $logFile"
49
+ <% } %>
@@ -0,0 +1,7 @@
1
+ $ErrorActionPreference = "Stop"
2
+
3
+ $workspace = if ($env:COZE_WORKSPACE_PATH) { $env:COZE_WORKSPACE_PATH } else { (Get-Location).Path }
4
+ Set-Location $workspace
5
+
6
+ & pnpm validate
7
+ exit $LASTEXITCODE
@@ -19,6 +19,9 @@ declare global {
19
19
  markEditable?: <T extends Phaser.GameObjects.GameObject>(
20
20
  stableId: string,
21
21
  gameObject: T,
22
+ options?: {
23
+ label?: string;
24
+ },
22
25
  ) => T;
23
26
  markImageAssetMap?: (images: Record<string, string>) => void;
24
27
  markImageSequenceAssetMap?: (
@@ -95,6 +95,7 @@ export class BootScene extends Phaser.Scene {
95
95
  .sprite(centerX, centerY - 58, DEV_LOADING_RUNTIME_KEYS.texture)
96
96
  .setScale(0.56)
97
97
  .play(DEV_LOADING_RUNTIME_KEYS.animation),
98
+ { label: '加载吉祥物' },
98
99
  );
99
100
 
100
101
  this.loadingText = markEditable(
@@ -107,11 +108,13 @@ export class BootScene extends Phaser.Scene {
107
108
  LOADING_TEXT_STYLE,
108
109
  )
109
110
  .setOrigin(0.5),
111
+ { label: '加载状态文案' },
110
112
  );
111
113
 
112
114
  this.progressBar = markEditable(
113
115
  'boot.loading-progress-bar',
114
116
  this.add.graphics(),
117
+ { label: '加载进度条' },
115
118
  );
116
119
  this.renderProgressBar(0);
117
120
 
@@ -120,6 +123,7 @@ export class BootScene extends Phaser.Scene {
120
123
  this.add
121
124
  .text(centerX, centerY + 190, '0%', LOADING_TEXT_STYLE)
122
125
  .setOrigin(0.5),
126
+ { label: '加载进度文本' },
123
127
  );
124
128
  }
125
129
 
@@ -21,6 +21,7 @@ export class DevLoadingScene extends Phaser.Scene {
21
21
  .sprite(centerX, centerY - 82, DEV_LOADING_RUNTIME_KEYS.texture)
22
22
  .setScale(0.64)
23
23
  .play(DEV_LOADING_RUNTIME_KEYS.animation),
24
+ { label: '开发中吉祥物' },
24
25
  );
25
26
 
26
27
  markEditable(
@@ -33,6 +34,7 @@ export class DevLoadingScene extends Phaser.Scene {
33
34
  fontStyle: 'bold',
34
35
  })
35
36
  .setOrigin(0.5),
37
+ { label: '开发中标题' },
36
38
  );
37
39
 
38
40
  markEditable(
@@ -44,6 +46,7 @@ export class DevLoadingScene extends Phaser.Scene {
44
46
  fontSize: '18px',
45
47
  })
46
48
  .setOrigin(0.5),
49
+ { label: '开发中说明文案' },
47
50
  );
48
51
 
49
52
  const loadingDots = Array.from({ length: 3 }, (_value, index) =>
@@ -1,6 +1,13 @@
1
1
  import type Phaser from 'phaser';
2
2
 
3
+ export interface MarkEditableOptions {
4
+ label?: string;
5
+ }
6
+
3
7
  export const markEditable = <T extends Phaser.GameObjects.GameObject>(
4
8
  locator: string,
5
9
  gameObject: T,
6
- ): T => window.PhaserBridge?.markEditable?.(locator, gameObject) ?? gameObject;
10
+ options?: MarkEditableOptions,
11
+ ): T =>
12
+ window.PhaserBridge?.markEditable?.(locator, gameObject, options) ??
13
+ gameObject;
@@ -0,0 +1,15 @@
1
+ [project]
2
+ entrypoint = "index.html"
3
+ requires = ["python-3.12"]
4
+ project_type = "game"
5
+ game_type = "phaser"
6
+
7
+ [dev]
8
+ build = []
9
+ run = ["sh", "-c", "python -m http.server ${DEPLOY_RUN_PORT} --bind 0.0.0.0"]
10
+ run_win = ["powershell.exe", "-NoProfile", "-ExecutionPolicy", "Bypass", "-File", "./scripts/serve.ps1"]
11
+
12
+ [deploy]
13
+ build = []
14
+ run = ["sh", "-c", "python -m http.server ${DEPLOY_RUN_PORT} --bind 0.0.0.0"]
15
+ run_win = ["powershell.exe", "-NoProfile", "-ExecutionPolicy", "Bypass", "-File", "./scripts/serve.ps1"]
@@ -0,0 +1,40 @@
1
+ # <%= appName %>
2
+
3
+ 这是一个基于浏览器原生 JavaScript ESM 的 Phaser 2D 游戏项目,由扣子编程 CLI 创建。
4
+
5
+ Phaser 3.90.0 与 Phaser Bridge 从 CDN 加载;项目不依赖 npm、Vite 或 TypeScript。请用静态 HTTP 服务访问,直接打开 `index.html` 不支持 ESM 模块与素材加载。
6
+
7
+ ## 快速开始
8
+
9
+ ```bash
10
+ coze-dev dev
11
+ coze-dev build
12
+ coze-dev start
13
+ ```
14
+
15
+ `build` 没有编译步骤;开发与生产预览均由 Python `http.server` 提供静态文件服务。
16
+
17
+ ## 文件结构
18
+
19
+ ```text
20
+ ├── assets/ # 图片、序列帧、视频和音频
21
+ ├── debug-runtime/ # 调试 Flow
22
+ ├── src/assets.js # 素材 key 与路径
23
+ ├── src/main.js # 游戏入口
24
+ ├── src/phaser.js # Phaser 全局对象的 ESM 包装
25
+ ├── src/scene/BootScene.js # 启动与全量加载
26
+ └── src/utils/asset-loader.js # 批量和单素材加载
27
+ ```
28
+
29
+ - 素材按类型放在 `assets/`,并登记到 `src/assets.js` 对应的分类表。
30
+ - 序列帧只登记文件夹;Loader 从 `manifest.json` 读取帧数和帧率。
31
+ - `BootScene` 加载游戏素材;运行时可用 `loadAsset(this, key)` 单独加载。
32
+ - 所有本地模块都使用原生 ESM 的显式 `.js` 后缀。
33
+
34
+ ## 可视化编辑标识
35
+
36
+ 用 `markEditable` 标记可在编辑器中调整的对象;第三个参数可选,仅用于编辑器展示名称:
37
+
38
+ ```js
39
+ markEditable('ui.start-button', button, { label: '开始按钮' });
40
+ ```
@@ -0,0 +1,6 @@
1
+ .codegraph/
2
+ .cozeproj/reduction
3
+ .preview
4
+
5
+ .DS_Store
6
+ ._*
@@ -0,0 +1,11 @@
1
+ {
2
+ "schema_version": "1.0",
3
+ "id": "coze-game-loading",
4
+ "type": "image_sequence",
5
+ "properties": {
6
+ "fps": 12.0,
7
+ "frame_count": 24
8
+ },
9
+ "name": "Coze Game Loading",
10
+ "sources": []
11
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "schema_version": 1,
3
+ "graphs": [
4
+ {
5
+ "id": "main",
6
+ "label": "主流程",
7
+ "nodes": [
8
+ {
9
+ "id": "start",
10
+ "label": "开始游戏",
11
+ "input_schema": {
12
+ "type": "object",
13
+ "properties": {}
14
+ }
15
+ }
16
+ ],
17
+ "transitions": []
18
+ }
19
+ ]
20
+ }
@@ -0,0 +1,17 @@
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
+ <meta name="description" content="Phaser 纯静态游戏模板" />
7
+ <title><%= appName %></title>
8
+ <link rel="icon" href="data:," />
9
+ <link rel="stylesheet" href="./src/style.css" />
10
+ <script src="https://unpkg.byted-static.com/phaser/3.90.0/dist/phaser.min.js"></script>
11
+ <script src="https://lf-coze-web-cdn.coze.cn/obj/eden-cn/lm-lgvj/ljhwZthlaukjlkulzlp/coze-game/js/phaser-bridge.min.js"></script>
12
+ </head>
13
+ <body>
14
+ <main id="game" aria-label="Phaser game canvas"></main>
15
+ <script type="module" src="./src/main.js"></script>
16
+ </body>
17
+ </html>
@@ -0,0 +1,7 @@
1
+ $ErrorActionPreference = "Stop"
2
+
3
+ $port = if ($env:DEPLOY_RUN_PORT) { $env:DEPLOY_RUN_PORT } else { "8000" }
4
+
5
+ Write-Host "Starting Phaser static server on port $port..."
6
+ & python -m http.server $port --bind 0.0.0.0
7
+ exit $LASTEXITCODE
@@ -0,0 +1,15 @@
1
+ export const IMAGES = {};
2
+
3
+ export const IMAGE_SEQUENCES = {
4
+ 'coze-game-loading': 'assets/image_sequence/coze-game-loading',
5
+ };
6
+
7
+ export const VIDEOS = {};
8
+
9
+ export const AUDIOS = {};
10
+
11
+ // 注册素材到 PhaserBridge,可以在扣子网页游戏开发中定位
12
+ window.PhaserBridge?.markImageAssetMap?.(IMAGES);
13
+ window.PhaserBridge?.markImageSequenceAssetMap?.(IMAGE_SEQUENCES);
14
+ window.PhaserBridge?.markVideoAssetMap?.(VIDEOS);
15
+ window.PhaserBridge?.markAudioAssetMap?.(AUDIOS);
@@ -0,0 +1,26 @@
1
+ import { Phaser } from './phaser.js';
2
+ import { BootScene } from './scene/BootScene.js';
3
+ import { DevLoadingScene } from './scene/DevLoadingScene.js';
4
+
5
+ const createGame = () =>
6
+ new Phaser.Game({
7
+ type: Phaser.AUTO,
8
+ pixelArt: true,
9
+ parent: 'game',
10
+ // TODO 根据游戏的要求进行尺寸
11
+ width: 540,
12
+ height: 960,
13
+ backgroundColor: '#ffffff',
14
+ scale: {
15
+ mode: Phaser.Scale.FIT,
16
+ autoCenter: Phaser.Scale.CENTER_BOTH,
17
+ },
18
+ scene: [BootScene, DevLoadingScene],
19
+ });
20
+
21
+ // 注册游戏到 PhaserBridge,可以在扣子网页游戏开发中编辑评论
22
+ if (window.PhaserBridge) {
23
+ window.PhaserBridge.bind({ launchGame: createGame });
24
+ } else {
25
+ createGame();
26
+ }
@@ -0,0 +1,7 @@
1
+ const Phaser = window.Phaser;
2
+
3
+ if (!Phaser) {
4
+ throw new Error('Phaser CDN failed to load before the game module.');
5
+ }
6
+
7
+ export { Phaser };