@next2d/builder 0.1.8 → 0.1.11

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 (67) hide show
  1. package/dist/cli.d.ts +59 -0
  2. package/dist/cli.js +141 -0
  3. package/dist/constants.d.ts +53 -0
  4. package/dist/constants.js +64 -0
  5. package/dist/context.d.ts +29 -0
  6. package/dist/context.js +19 -0
  7. package/dist/electron.d.ts +10 -0
  8. package/dist/electron.js +142 -0
  9. package/dist/index.js +18 -790
  10. package/dist/native.d.ts +27 -0
  11. package/dist/native.js +123 -0
  12. package/dist/utils.d.ts +27 -0
  13. package/dist/utils.js +40 -0
  14. package/dist/web.d.ts +18 -0
  15. package/dist/web.js +70 -0
  16. package/dist/xbox.d.ts +62 -0
  17. package/dist/xbox.js +426 -0
  18. package/package.json +11 -9
  19. package/templates/xbox/CMakeLists.txt +47 -11
  20. package/templates/xbox/README.md +18 -0
  21. package/templates/xbox/js/bootstrap.js +120 -0
  22. package/templates/xbox/src/AssetLoader.cpp +115 -12
  23. package/templates/xbox/src/AssetLoader.h +4 -0
  24. package/templates/xbox/src/EmbeddedAssets.cpp +149 -0
  25. package/templates/xbox/src/EmbeddedAssets.h +60 -0
  26. package/templates/xbox/src/EventLoop.cpp +0 -15
  27. package/templates/xbox/src/bindings/Audio.cpp +118 -22
  28. package/templates/xbox/src/bindings/Canvas.cpp +32 -2
  29. package/templates/xbox/src/bindings/Canvas2D.cpp +495 -39
  30. package/templates/xbox/src/bindings/Console.cpp +6 -1
  31. package/templates/xbox/src/bindings/DomShims.cpp +18 -2
  32. package/templates/xbox/src/bindings/EventTarget.cpp +9 -0
  33. package/templates/xbox/src/bindings/Image.cpp +83 -57
  34. package/templates/xbox/src/bindings/Polyfills.cpp +671 -236
  35. package/templates/xbox/src/bindings/RasterCore.h +105 -1
  36. package/templates/xbox/src/bindings/Video.cpp +57 -3
  37. package/templates/xbox/src/bindings/webgpu/WebGPU.cpp +29 -3
  38. package/templates/xbox/src/bindings/webgpu/WebGPUCommon.h +4 -1
  39. package/templates/xbox/src/bindings/webgpu/WebGPUEnums.h +32 -0
  40. package/templates/xbox/src/gpu/DawnContext.cpp +167 -16
  41. package/templates/xbox/src/main.cpp +385 -16
  42. package/templates/xbox/src/platform/AudioDecoder.cpp +121 -0
  43. package/templates/xbox/src/platform/AudioDecoder.h +18 -0
  44. package/templates/xbox/src/platform/AudioEngine.cpp +28 -3
  45. package/templates/xbox/src/platform/DecodeQueue.cpp +136 -0
  46. package/templates/xbox/src/platform/DecodeQueue.h +27 -0
  47. package/templates/xbox/src/platform/ImageDecoder.cpp +44 -0
  48. package/templates/xbox/src/platform/ImageDecoder.h +18 -0
  49. package/templates/xbox/src/platform/StbTextRasterizer.cpp +324 -0
  50. package/templates/xbox/src/platform/StbTextRasterizer.h +37 -0
  51. package/templates/xbox/src/platform/TextRasterizer.cpp +32 -0
  52. package/templates/xbox/src/platform/WicDecoder.cpp +19 -0
  53. package/templates/xbox/src/v8/CodeCache.h +223 -0
  54. package/templates/xbox/src/v8/V8Runtime.cpp +34 -33
  55. package/templates/xbox/src/v8/V8Util.h +54 -4
  56. package/templates/xbox/src/worker/WorkerRuntime.cpp +165 -65
  57. package/templates/xbox/src/worker/WorkerRuntime.h +23 -3
  58. package/templates/xbox/tests/check_local.sh +5 -1
  59. package/templates/xbox/tests/gamecore_api_probe.cpp +172 -0
  60. package/templates/xbox/tests/raster_test.cpp +50 -0
  61. package/templates/xbox/tests/windows_platform_test.cpp +75 -3
  62. package/templates/xbox/third_party/LICENSES.md +14 -0
  63. package/templates/xbox/third_party/dr_mp3.h +5412 -0
  64. package/templates/xbox/third_party/dr_wav.h +9131 -0
  65. package/templates/xbox/third_party/stb_image.h +7988 -0
  66. package/templates/xbox/third_party/stb_truetype.h +5079 -0
  67. package/templates/xbox/third_party/stb_vorbis.c +5584 -0
package/dist/xbox.js ADDED
@@ -0,0 +1,426 @@
1
+ // Xbox (GDK ネイティブ) ビルド。V8 に Next2D の JS を載せ、Dawn(WebGPU/D3D12)で
2
+ // 描画する C++ ホストを、テンプレートのスキャフォールド → 資材配置 → pak 埋め込み →
3
+ // CMake/GDK ビルドの順で書き出す。
4
+ import pc from "picocolors";
5
+ import fs from "fs";
6
+ import os from "os";
7
+ import path from "path";
8
+ import cp from "child_process";
9
+ import { minifySync } from "vite";
10
+ import { ctx } from "./context.js";
11
+ import { getTemplateDir } from "./utils.js";
12
+ import { XBOX_DIR_NAME, XBOX_CONFIG_NAME, XBOX_V8_VERSION, XBOX_V8_REVISION, XBOX_SCAFFOLD_EXCLUDES } from "./constants.js";
13
+ /**
14
+ * @description XboxホストのC++/CMake一式をbuilder同梱テンプレートから毎回更新する。
15
+ * ホストは「エンジン相当」でユーザーは編集しない前提のため、常に最新へ上書きする。
16
+ * ただし各ゲーム固有の `MicrosoftGame.config` は対象外(injectGameConfigが扱う)。
17
+ * Refresh the Xbox host (C++/CMake) from the builder's bundled template.
18
+ *
19
+ * @return {Promise}
20
+ * @method
21
+ * @private
22
+ */
23
+ const refreshXboxHost = () => {
24
+ return new Promise((resolve, reject) => {
25
+ const projectDir = `${process.cwd()}/${XBOX_DIR_NAME}`;
26
+ const templateDir = getTemplateDir("xbox");
27
+ if (!fs.existsSync(templateDir)) {
28
+ return reject(`Xbox template not found: ${templateDir}`);
29
+ }
30
+ try {
31
+ fs.cpSync(templateDir, projectDir, {
32
+ "recursive": true,
33
+ // ゲーム固有設定と builder 側の開発用ファイルはスキャフォールドしない
34
+ "filter": (src) => !XBOX_SCAFFOLD_EXCLUDES.has(path.basename(src))
35
+ });
36
+ console.log(pc.green(`Successfully refreshed \`${XBOX_DIR_NAME}\` host.`));
37
+ resolve();
38
+ }
39
+ catch (error) {
40
+ reject(`Failed to refresh ${XBOX_DIR_NAME} host. ${error}`);
41
+ }
42
+ });
43
+ };
44
+ /**
45
+ * @description ゲームルートの `MicrosoftGame.config` をXboxホストへ注入する。
46
+ * 未配置ならbuilder同梱の既定をフォールバックとして使い、作成を促す。
47
+ * Inject the game-root `MicrosoftGame.config` into the Xbox host.
48
+ *
49
+ * @return {Promise}
50
+ * @method
51
+ * @private
52
+ */
53
+ const injectGameConfig = () => {
54
+ return new Promise((resolve, reject) => {
55
+ const rootConfig = `${process.cwd()}/${XBOX_CONFIG_NAME}`;
56
+ const hostConfig = `${process.cwd()}/${XBOX_DIR_NAME}/${XBOX_CONFIG_NAME}`;
57
+ try {
58
+ if (fs.existsSync(rootConfig)) {
59
+ fs.cpSync(rootConfig, hostConfig);
60
+ console.log(pc.green(`Applied project \`${XBOX_CONFIG_NAME}\`.`));
61
+ }
62
+ else {
63
+ // フォールバック: builder同梱の既定を配置し、ルートへの作成を促す
64
+ fs.cpSync(`${getTemplateDir("xbox")}/${XBOX_CONFIG_NAME}`, hostConfig);
65
+ console.log(pc.yellow(`\`${XBOX_CONFIG_NAME}\` not found at project root. Using the default template.`));
66
+ console.log(pc.yellow(`Create \`${XBOX_CONFIG_NAME}\` at your project root (like capacitor.config.json) to set TitleId/StoreId/logos.`));
67
+ }
68
+ resolve();
69
+ }
70
+ catch (error) {
71
+ reject(`Failed to apply ${XBOX_CONFIG_NAME}. ${error}`);
72
+ }
73
+ });
74
+ };
75
+ /**
76
+ * @description ビルド済みWeb資材(JS/HTML/アセット)をXboxホストのassetsへ配置
77
+ * Deploy built web resources (JS/HTML/assets) into the Xbox host assets
78
+ *
79
+ * @return {Promise}
80
+ * @method
81
+ * @private
82
+ */
83
+ const copyXboxResources = () => {
84
+ return new Promise((resolve, reject) => {
85
+ const assetsDir = `${process.cwd()}/${XBOX_DIR_NAME}/assets/app`;
86
+ try {
87
+ // reset
88
+ fs.rmSync(assetsDir, { "recursive": true, "force": true });
89
+ fs.mkdirSync(assetsDir, { "recursive": true });
90
+ // copy built web resources (JS/HTML/assets)
91
+ fs.cpSync(`${ctx.buildDir}/`, assetsDir, { "recursive": true });
92
+ console.log(pc.green("Successfully copy built resources to Xbox host."));
93
+ resolve();
94
+ }
95
+ catch (error) {
96
+ reject(`Failed to copy built resources to Xbox host. ${error}`);
97
+ }
98
+ });
99
+ };
100
+ /**
101
+ * @description ディレクトリを再帰的に走査し、各ファイルの
102
+ * [posix 相対キー, 絶対パス] を集める。
103
+ * Walk a directory recursively, collecting [posixRelKey, absPath] pairs.
104
+ *
105
+ * @param {string} rootDir 走査ルート
106
+ * @param {string} [prefix] キーへ付与する接頭辞 (例 "" / "assets/")
107
+ * @return {Array<[string, string]>}
108
+ * @method
109
+ * @public
110
+ */
111
+ export const walkFiles = (rootDir, prefix = "") => {
112
+ const out = [];
113
+ if (!fs.existsSync(rootDir)) {
114
+ return out;
115
+ }
116
+ for (const entry of fs.readdirSync(rootDir, { "withFileTypes": true })) {
117
+ const abs = path.join(rootDir, entry.name);
118
+ const key = prefix ? `${prefix}${entry.name}` : entry.name;
119
+ if (entry.isDirectory()) {
120
+ out.push(...walkFiles(abs, `${key}/`));
121
+ }
122
+ else if (entry.isFile()) {
123
+ out.push([key, abs]);
124
+ }
125
+ }
126
+ return out;
127
+ };
128
+ /**
129
+ * @description (key, データ) の並びを exe 埋め込み用 pak バイナリへ直列化する純関数。
130
+ * host 側 EmbeddedAssets.cpp の ParseEmbeddedPak と対になる。
131
+ * フォーマット (リトルエンディアン uint32):
132
+ * magic "N2DA" / version(=1) / count / [keyLen,key,dataLen,data]...
133
+ * Serialize (key, data) entries into the embedded pak binary.
134
+ *
135
+ * @param {Array<[string, Buffer]>} entries
136
+ * @return {Buffer}
137
+ * @method
138
+ * @public
139
+ */
140
+ export const buildPak = (entries) => {
141
+ const chunks = [];
142
+ const header = Buffer.alloc(12);
143
+ header.write("N2DA", 0, "ascii");
144
+ header.writeUInt32LE(1, 4); // version
145
+ header.writeUInt32LE(entries.length, 8); // count
146
+ chunks.push(header);
147
+ for (const [key, data] of entries) {
148
+ const keyBuf = Buffer.from(key, "utf8");
149
+ const meta = Buffer.alloc(4);
150
+ meta.writeUInt32LE(keyBuf.length, 0);
151
+ chunks.push(meta, keyBuf);
152
+ const meta2 = Buffer.alloc(4);
153
+ meta2.writeUInt32LE(data.length, 0);
154
+ chunks.push(meta2, data);
155
+ }
156
+ return Buffer.concat(chunks);
157
+ };
158
+ /**
159
+ * @description assets.pak を RCDATA "N2DASSETS" として取り込む .rc の内容を生成する純関数。
160
+ * 相対パスだと rc.exe の CWD (build ディレクトリ) 基準で探して見つからない
161
+ * (RC2135) ため絶対パスを埋める。RC はフォワードスラッシュを受理する。
162
+ * 文字列は必ずダブルクォート (RC 仕様。シングルクォートは不可)。
163
+ * Render the .rc content that embeds assets.pak as RCDATA.
164
+ *
165
+ * @param {string} pakAbsPath assets.pak の絶対パス
166
+ * @return {string}
167
+ * @method
168
+ * @public
169
+ */
170
+ export const renderAssetsRc = (pakAbsPath) => {
171
+ const forward = pakAbsPath.replace(/\\/g, "/");
172
+ return `N2DASSETS RCDATA "${forward}"\n`;
173
+ };
174
+ /**
175
+ * @description ホストスクリプト(js/bootstrap.js 等)を minify + 難読化する純関数。
176
+ * Oxc(vite 同梱)でコメント除去・空白圧縮・ローカル識別子マングルを行う。
177
+ * `globalThis.*` 等のグローバル名はゲームが参照するため保持される。
178
+ * 失敗時は元コードをそのまま返す(埋め込み自体は継続)。
179
+ * Minify/obfuscate a host script; returns the original on failure.
180
+ *
181
+ * @param {string} name ファイル名 (拡張子で構文判定)
182
+ * @param {string} code 元の JavaScript
183
+ * @return {string}
184
+ * @method
185
+ * @public
186
+ */
187
+ export const minifyJs = (name, code) => {
188
+ try {
189
+ const result = minifySync(name, code);
190
+ if (result.errors && result.errors.length > 0) {
191
+ const msg = result.errors[0]?.message ?? String(result.errors[0]);
192
+ console.log(pc.yellow(`Xbox: minify skipped for ${name} (${msg}); embedding as-is.`));
193
+ return code;
194
+ }
195
+ return result.code;
196
+ }
197
+ catch (error) {
198
+ console.log(pc.yellow(`Xbox: minify failed for ${name}; embedding as-is. ${error}`));
199
+ return code;
200
+ }
201
+ };
202
+ /**
203
+ * @description Xbox ホストの assets/app とホストスクリプト(js/bootstrap.js 等)を
204
+ * 単一の pak バイナリへまとめ、`assets.pak` と RCDATA 参照用の
205
+ * `assets.rc` を xbox/ 直下へ生成する。CMake が assets.rc を検出して
206
+ * これらを exe 内リソースへ**必ず**埋め込み、平文 JS/HTML を配布物に残さない。
207
+ * 埋め込みは必須(非埋め込みの選択肢は無い)。資材が無ければハードエラー。
208
+ *
209
+ * pak フォーマット (リトルエンディアン uint32):
210
+ * magic "N2DA" / version(=1) / count / [keyLen,key,dataLen,data]...
211
+ * キーは assets/app 基準の posix 相対パス、または "js/bootstrap.js"。
212
+ * host 側 EmbeddedAssets.cpp の ParseEmbeddedPak と対になる。
213
+ *
214
+ * @return {Promise}
215
+ * @method
216
+ * @private
217
+ */
218
+ const embedXboxAssets = () => {
219
+ return new Promise((resolve, reject) => {
220
+ const xboxDir = `${process.cwd()}/${XBOX_DIR_NAME}`;
221
+ const pakPath = `${xboxDir}/assets.pak`;
222
+ const rcPath = `${xboxDir}/assets.rc`;
223
+ try {
224
+ // 収集: assets/app 一式 (キーは app 基準) + host スクリプト (js/ 基準)。
225
+ const entries = [];
226
+ entries.push(...walkFiles(`${xboxDir}/assets/app`, ""));
227
+ const bootstrap = `${xboxDir}/js/bootstrap.js`;
228
+ if (fs.existsSync(bootstrap)) {
229
+ entries.push(["js/bootstrap.js", bootstrap]);
230
+ }
231
+ const selftest = `${xboxDir}/js/selftest.js`;
232
+ if (fs.existsSync(selftest)) {
233
+ entries.push(["js/selftest.js", selftest]);
234
+ }
235
+ if (entries.length === 0) {
236
+ return reject("No Xbox assets found to embed (assets/app is empty).");
237
+ }
238
+ // (key, データ) を読み込み、pak バイナリへ直列化する。
239
+ // js/ のホストスクリプト(bootstrap.js/selftest.js)は minify + 難読化する。
240
+ // assets/app の JS は vite が本番ビルドで minify 済みのためそのまま。
241
+ let minified = 0;
242
+ const pakEntries = entries.map(([key, abs]) => {
243
+ if (key.startsWith("js/") && key.endsWith(".js")) {
244
+ const src = fs.readFileSync(abs, { "encoding": "utf8" });
245
+ const out = minifyJs(key, src);
246
+ if (out.length < src.length) {
247
+ ++minified;
248
+ }
249
+ return [key, Buffer.from(out, "utf8")];
250
+ }
251
+ return [key, fs.readFileSync(abs)];
252
+ });
253
+ const pak = buildPak(pakEntries);
254
+ if (minified > 0) {
255
+ console.log(pc.green(`Minified ${minified} host script(s) before embedding.`));
256
+ }
257
+ fs.writeFileSync(pakPath, pak);
258
+ // rc.exe が assets.pak を RCDATA "N2DASSETS" として取り込む .rc を生成する。
259
+ fs.writeFileSync(rcPath, renderAssetsRc(path.resolve(pakPath)), "utf8");
260
+ console.log(pc.green(`Embedded ${entries.length} Xbox asset file(s) into assets.pak `
261
+ + `(${(pak.length / 1024 / 1024).toFixed(2)} MB).`));
262
+ // 埋め込み済みの平文 `assets/`・`js/` は書き出し一覧から除外する。
263
+ // これらは assets.pak (=exe 内 RCDATA) に格納済みで、CMake も埋め込みモードでは
264
+ // exe 隣へステージしないため、xbox/ 直下に残しても不要かつ平文流出になる。
265
+ fs.rmSync(`${xboxDir}/assets`, { "recursive": true, "force": true });
266
+ fs.rmSync(`${xboxDir}/js`, { "recursive": true, "force": true });
267
+ console.log(pc.green("Excluded plaintext `assets/` and `js/` from the export (embedded in exe)."));
268
+ resolve();
269
+ }
270
+ catch (error) {
271
+ reject(`Failed to embed Xbox assets. ${error}`);
272
+ }
273
+ });
274
+ };
275
+ /**
276
+ * @description Xbox ビルドに使う V8 のパスを解決する。優先順:
277
+ * 1. `--v8-root` 引数
278
+ * 2. 環境変数 `V8_ROOT`
279
+ * 3. キャッシュ済みの prebuilt (%LOCALAPPDATA%/next2d/v8/<version>)
280
+ * 4. GitHub Releases (build-v8.yml が発行) から自動ダウンロード
281
+ * 3・4 により、通常は何も指定せずに `--platform xbox` だけでビルドできる。
282
+ * Resolve the V8 path for the Xbox build.
283
+ *
284
+ * @return {Promise<string>}
285
+ * @method
286
+ * @private
287
+ */
288
+ const resolveXboxV8Root = async () => {
289
+ // 1. --v8-root 引数
290
+ if (ctx.v8Root) {
291
+ return path.resolve(process.cwd(), ctx.v8Root);
292
+ }
293
+ // 2. 環境変数 V8_ROOT
294
+ if (process.env.V8_ROOT) {
295
+ return process.env.V8_ROOT;
296
+ }
297
+ // 3. キャッシュ済み prebuilt
298
+ const cacheBase = process.env.LOCALAPPDATA
299
+ ? `${process.env.LOCALAPPDATA}/next2d`
300
+ : `${os.homedir()}/.cache/next2d`;
301
+ const cacheDir = `${cacheBase}/v8/${XBOX_V8_VERSION}-${XBOX_V8_REVISION}`;
302
+ if (fs.existsSync(`${cacheDir}/include/v8.h`)) {
303
+ return cacheDir;
304
+ }
305
+ // 4. GitHub Releases から自動ダウンロード (マシンごとに初回のみ)
306
+ const assetName = `v8-monolith-${XBOX_V8_VERSION}-windows-x64.zip`;
307
+ const url = `https://github.com/Next2D/builder/releases/download/v8-${XBOX_V8_VERSION}-windows-x64-${XBOX_V8_REVISION}/${assetName}`;
308
+ console.log(pc.green(`Downloading prebuilt V8 ${XBOX_V8_VERSION} (first time only) ...`));
309
+ console.log(url);
310
+ const response = await fetch(url);
311
+ if (!response.ok) {
312
+ throw new Error(`download failed: HTTP ${response.status}`);
313
+ }
314
+ fs.mkdirSync(cacheDir, { "recursive": true });
315
+ const zipPath = `${cacheDir}/${assetName}.tmp`;
316
+ fs.writeFileSync(zipPath, Buffer.from(await response.arrayBuffer()));
317
+ // Windows 10+ 標準の tar (bsdtar) は zip も展開できる
318
+ const extract = cp.spawnSync("tar", ["-xf", zipPath, "-C", cacheDir], { "stdio": "inherit" });
319
+ fs.rmSync(zipPath, { "force": true });
320
+ if (extract.status !== 0 || !fs.existsSync(`${cacheDir}/include/v8.h`)) {
321
+ fs.rmSync(cacheDir, { "recursive": true, "force": true });
322
+ throw new Error("failed to extract the prebuilt V8 archive");
323
+ }
324
+ console.log(pc.green(`Prebuilt V8 cached at: ${cacheDir}`));
325
+ return cacheDir;
326
+ };
327
+ /**
328
+ * @description Xbox(GDKネイティブ)用アプリの書き出し関数。
329
+ * V8にNext2DのJSを載せ、Dawn(WebGPU/D3D12)で描画するC++ホストをビルドする。
330
+ * Export function for Xbox (GDK native) apps.
331
+ *
332
+ * @return {Promise}
333
+ * @method
334
+ * @public
335
+ */
336
+ export const buildXbox = async () => {
337
+ // C++/CMake ホストを最新へ更新 (ゲーム固有設定は除外)
338
+ await refreshXboxHost();
339
+ // ゲームルートの MicrosoftGame.config を注入
340
+ await injectGameConfig();
341
+ // ビルド済みWeb資材を配置
342
+ await copyXboxResources();
343
+ // assets/app + host スクリプトを exe 埋め込み用 pak (+ rc) へまとめる
344
+ await embedXboxAssets();
345
+ /**
346
+ * GDK ビルドは Windows + Visual Studio + Microsoft GDK が必須。
347
+ * それ以外の環境ではスキャフォールドと資材配置のみを行い、手順を案内する。
348
+ * The GDK build requires Windows + Visual Studio + Microsoft GDK.
349
+ */
350
+ if (process.platform !== "win32") {
351
+ console.log();
352
+ console.log(pc.yellow("Xbox host project has been generated and assets were copied."));
353
+ console.log(pc.yellow("The GDK build must run on Windows with Visual Studio and the Microsoft GDK installed."));
354
+ console.log(pc.yellow(`See ${XBOX_DIR_NAME}/README.md for the build steps.`));
355
+ console.log();
356
+ return;
357
+ }
358
+ /**
359
+ * @type {string}
360
+ * GDK の対象コンソール世代。既定は Xbox Series X|S (Scarlett)。
361
+ */
362
+ const gdkArch = process.env.NEXT2D_XBOX_ARCH || "Gaming.Xbox.Scarlett.x64";
363
+ const cmakeBuildDir = `${process.cwd()}/${ctx.outDir}/${ctx.platformDir}/build`;
364
+ /**
365
+ * prebuilt V8 のパスを解決する (--v8-root > V8_ROOT > キャッシュ > 自動ダウンロード)。
366
+ */
367
+ let resolvedV8Root = "";
368
+ try {
369
+ resolvedV8Root = await resolveXboxV8Root();
370
+ }
371
+ catch (error) {
372
+ console.log(pc.red(`Failed to prepare the prebuilt V8: ${error}`));
373
+ console.log(pc.red("Fallbacks:"));
374
+ console.log(pc.red(" 1) Retry later (the download may have failed temporarily)."));
375
+ console.log(pc.red(" 2) Build V8 yourself and pass `--v8-root <path>`:"));
376
+ console.log(pc.red(" npx @next2d/builder --platform xbox --env prd --v8-root C:\\path\\to\\v8"));
377
+ console.log(pc.red(` See ${XBOX_DIR_NAME}/README.md ("V8 の用意") for the build steps.`));
378
+ return;
379
+ }
380
+ if (!fs.existsSync(`${resolvedV8Root}/include/v8.h`)) {
381
+ console.log(pc.red(`\`include/v8.h\` not found under: ${resolvedV8Root}`));
382
+ console.log(pc.red(`Check the \`--v8-root\` path. See ${XBOX_DIR_NAME}/README.md for how to prepare the prebuilt V8.`));
383
+ return;
384
+ }
385
+ const configure = () => {
386
+ return new Promise((resolve, reject) => {
387
+ const stream = cp.spawn("cmake", [
388
+ "-S", `${process.cwd()}/${XBOX_DIR_NAME}`,
389
+ "-B", cmakeBuildDir,
390
+ "-G", "Visual Studio 17 2022",
391
+ "-A", gdkArch,
392
+ "-D", `V8_ROOT=${resolvedV8Root}`
393
+ ], { "stdio": "inherit" });
394
+ stream.on("close", (code) => {
395
+ if (code !== 0) {
396
+ return reject("Failed to configure the Xbox (CMake/GDK) project.");
397
+ }
398
+ resolve();
399
+ });
400
+ });
401
+ };
402
+ await configure();
403
+ if (ctx.open || ctx.preview) {
404
+ // Visual Studio ソリューションを開く (実機/エミュレータでの実行はVS側で行う)
405
+ cp.spawn("cmake", [
406
+ "--open", cmakeBuildDir
407
+ ], { "stdio": "inherit" });
408
+ return;
409
+ }
410
+ // フルビルド (Release パッケージまで)。失敗時は reject して非ゼロ終了させる
411
+ await new Promise((resolve, reject) => {
412
+ const stream = cp.spawn("cmake", [
413
+ "--build", cmakeBuildDir,
414
+ "--config", "Release"
415
+ ], { "stdio": "inherit" });
416
+ stream.on("close", (code) => {
417
+ if (code !== 0) {
418
+ return reject("Export of the Xbox (GDK) package failed.");
419
+ }
420
+ console.log();
421
+ console.log(pc.green(`Finished building the Xbox (GDK) package for ${gdkArch}.`));
422
+ console.log();
423
+ resolve();
424
+ });
425
+ });
426
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@next2d/builder",
3
- "version": "0.1.8",
3
+ "version": "0.1.11",
4
4
  "description": "Multi-platform builder for Next2d Framework, supporting export to various platforms such as macOS, Windows, iOS, Android and Web(HTML)",
5
5
  "author": "Toshiyuki Ienaga <ienaga@next2d.app>",
6
6
  "license": "MIT",
@@ -21,7 +21,9 @@
21
21
  "Multi-platform builder"
22
22
  ],
23
23
  "scripts": {
24
- "lint": "eslint src/index.ts",
24
+ "lint": "eslint src",
25
+ "build": "tsc",
26
+ "test": "tsc && node --test \"tests/**/*.test.ts\"",
25
27
  "prepare": "tsc",
26
28
  "release": "tsc"
27
29
  },
@@ -38,18 +40,18 @@
38
40
  },
39
41
  "dependencies": {
40
42
  "@electron-forge/core": "^7.11.2",
41
- "@types/node": "^26.1.0",
43
+ "@types/node": "^26.4.0",
42
44
  "picocolors": "^1.1.1",
43
- "vite": "^8.1.3"
45
+ "vite": "^8.2.2"
44
46
  },
45
47
  "devDependencies": {
46
- "@eslint/eslintrc": "^3.3.5",
48
+ "@eslint/eslintrc": "^3.3.7",
47
49
  "@eslint/js": "^10.0.1",
48
- "@typescript-eslint/eslint-plugin": "^8.62.1",
49
- "@typescript-eslint/parser": "^8.62.1",
50
- "eslint": "^10.6.0",
50
+ "@typescript-eslint/eslint-plugin": "^8.69.0",
51
+ "@typescript-eslint/parser": "^8.69.0",
52
+ "eslint": "^10.9.1",
51
53
  "eslint-plugin-unused-imports": "^4.4.1",
52
- "globals": "^17.7.0",
54
+ "globals": "^17.12.0",
53
55
  "typescript": "^6.0.3"
54
56
  }
55
57
  }
@@ -89,10 +89,24 @@ file(GLOB_RECURSE NEXT2D_HOST_SOURCES
89
89
  "${CMAKE_CURRENT_SOURCE_DIR}/src/*.h"
90
90
  )
91
91
 
92
+ # 埋め込みアセット: builder の buildXbox が assets.pak と assets.rc を必ず生成し、
93
+ # RCDATA "N2DASSETS" として exe にリンクする (ゲーム JS/HTML は平文で隣に置かない)。
94
+ # 埋め込みは必須。assets.rc が無いのは builder を経由せず cmake を直接叩いた
95
+ # ホスト単体ビルド (ゲーム資材なし) のみで、その場合はゲームは起動しない。
96
+ set(NEXT2D_ASSETS_RC "${CMAKE_CURRENT_SOURCE_DIR}/assets.rc")
97
+ if(EXISTS "${NEXT2D_ASSETS_RC}")
98
+ enable_language(RC)
99
+ list(APPEND NEXT2D_HOST_SOURCES "${NEXT2D_ASSETS_RC}")
100
+ message(STATUS "Next2D: embedding assets from ${NEXT2D_ASSETS_RC}")
101
+ else()
102
+ message(WARNING "Next2D: assets.rc not found - host-only build (no game assets). Run @next2d/builder to embed.")
103
+ endif()
104
+
92
105
  add_executable(Next2DXboxHost WIN32 ${NEXT2D_HOST_SOURCES})
93
106
 
94
107
  target_include_directories(Next2DXboxHost PRIVATE
95
108
  "${CMAKE_CURRENT_SOURCE_DIR}/src"
109
+ "${CMAKE_CURRENT_SOURCE_DIR}" # third_party/ (stb_image, dr_mp3 等)
96
110
  )
97
111
 
98
112
  # 展開レイアウト (GDK_ROOT) 使用時: include/lib を明示指定し、実行時 DLL を並べる
@@ -124,6 +138,20 @@ if(MSVC)
124
138
  # Release でも PDB を生成する (クラッシュダンプ解析でスタックを名前解決するため)
125
139
  target_compile_options(Next2DXboxHost PRIVATE /Zi)
126
140
  target_link_options(Next2DXboxHost PRIVATE /DEBUG /OPT:REF /OPT:ICF)
141
+
142
+ # Release: リンク時コード生成 (LTCG)。翻訳単位を跨いだインライン化が効き、
143
+ # 毎フレーム通る V8 バインディング層 (小さな関数の呼び出し連鎖) に有効。
144
+ # (VS ジェネレータでは COMPILE_OPTIONS は C++ (ClCompile) にのみ渡り、
145
+ # RC (assets.rc) には影響しない。/Zi と同じ流儀)
146
+ target_compile_options(Next2DXboxHost PRIVATE $<$<CONFIG:Release>:/GL>)
147
+ target_link_options(Next2DXboxHost PRIVATE $<$<CONFIG:Release>:/LTCG>)
148
+
149
+ # /arch:AVX2: Xbox Series X|S (Zen 2) と Haswell (2013) 以降の PC で動作。
150
+ # ソフトラスタ (RasterCore) や pak 解析などホスト C++ の自動ベクトル化が進む。
151
+ # Xbox One (Jaguar) は AVX2 非対応のため除外する。
152
+ if(NOT CMAKE_GENERATOR_PLATFORM MATCHES "XboxOne")
153
+ target_compile_options(Next2DXboxHost PRIVATE /arch:AVX2)
154
+ endif()
127
155
  endif()
128
156
 
129
157
  # webgpu_dawn は SHARED (DLL)。実行に必要なため exe の隣へステージする
@@ -135,14 +163,25 @@ if(TARGET webgpu_dawn)
135
163
  COMMENT "Staging webgpu_dawn.dll next to the executable")
136
164
  endif()
137
165
 
138
- # WebGPU / D3D12 / GameInput / WIC / XAudio2 / GDK
166
+ # WebGPU / D3D12 / GameInput / XAudio2 / GDK
139
167
  target_link_libraries(Next2DXboxHost PRIVATE
140
168
  d3d12
141
169
  dxgi
142
170
  dxguid
143
- windowscodecs # WIC: 画像デコード
144
171
  )
145
172
 
173
+ if(NOT NEXT2D_IS_CONSOLE)
174
+ # デスクトップ専用 (Game Core OS に存在しない):
175
+ # windowscodecs = WIC (stb_image で扱えない形式の画像デコードフォールバック)
176
+ # dbghelp = クラッシュハンドラのスタックトレース (StackWalk64/SymFromAddr)
177
+ # MF (mfplat 等)/d2d1/dwrite/shlwapi/winmm はソース側の #pragma comment(lib) が
178
+ # 同じ NEXT2D_XBOX_CONSOLE ガード内でリンク指示する。
179
+ target_link_libraries(Next2DXboxHost PRIVATE
180
+ windowscodecs
181
+ dbghelp
182
+ )
183
+ endif()
184
+
146
185
  if(NEXT2D_IS_CONSOLE)
147
186
  # コンソール用ライブラリ (GDK が提供)
148
187
  target_link_libraries(Next2DXboxHost PRIVATE
@@ -176,18 +215,15 @@ target_compile_definitions(Next2DXboxHost PRIVATE
176
215
 
177
216
  # -----------------------------------------------------------------------------
178
217
  # ランタイム資材のステージング
179
- # builder が assets/app に JS/HTML/アセットを配置する。
180
- # js/bootstrap.js はブラウザ相当グローバルを整える起動スクリプト。
218
+ # ゲーム JS/HTML/アセット (assets/app) とホストスクリプト (js/bootstrap.js) は
219
+ # builder が assets.pak にまとめて exe 内 RCDATA へ**必ず**埋め込む
220
+ # (非埋め込みの選択肢は無い。平文 JS/HTML を配布物に残さないのが目的)。
221
+ # したがって exe 隣へは assets/ も js/ もコピーしない。
222
+ # MicrosoftGame.config (GDK タイトル設定) だけを exe の隣へステージングする。
181
223
  # -----------------------------------------------------------------------------
182
224
  add_custom_command(TARGET Next2DXboxHost POST_BUILD
183
- COMMAND ${CMAKE_COMMAND} -E copy_directory
184
- "${CMAKE_CURRENT_SOURCE_DIR}/assets"
185
- "$<TARGET_FILE_DIR:Next2DXboxHost>/assets"
186
- COMMAND ${CMAKE_COMMAND} -E copy_directory
187
- "${CMAKE_CURRENT_SOURCE_DIR}/js"
188
- "$<TARGET_FILE_DIR:Next2DXboxHost>/js"
189
225
  COMMAND ${CMAKE_COMMAND} -E copy_if_different
190
226
  "${CMAKE_CURRENT_SOURCE_DIR}/MicrosoftGame.config"
191
227
  "$<TARGET_FILE_DIR:Next2DXboxHost>/MicrosoftGame.config"
192
- COMMENT "Staging Next2D assets, bootstrap JS and MicrosoftGame.config"
228
+ COMMENT "Staging MicrosoftGame.config (assets/JS embedded in exe)"
193
229
  )
@@ -378,3 +378,21 @@ xbox/
378
378
  ├─ Gamepad.cpp DomShims.cpp
379
379
  └─ webgpu/{WebGPU.cpp,WebGPUCommon.h,WebGPUEnums.h}
380
380
  ```
381
+
382
+ ---
383
+
384
+ ## コンソール (Game Core OS) とテキスト描画・フォント
385
+
386
+ コンソールには DirectWrite / システムフォントが存在しないため、`fillText`/`measureText`
387
+ は同梱の stb_truetype 実装 (`platform/StbTextRasterizer`) が担う。フォントは実行時登録:
388
+
389
+ - **ゲーム資材に TTF/OTF を含める**(推奨): Web ビルドの資材 (`assets/app`) に
390
+ `*.ttf` / `*.otf` があれば起動時に自動登録される (vite の `public/` に置く等)。
391
+ 日本語テキストを使う場合は Noto Sans JP (OFL) などの同梱を推奨。
392
+ - 開発ビルド: exe 隣接の `fonts/` ディレクトリからも読み込む。
393
+ - フォント未登録の場合、テキストは近似メトリクスのみ (グリフ描画なし) になる。
394
+
395
+ デスクトップ (PC/GDK) は従来どおり DirectWrite が主経路のため、フォント同梱は不要。
396
+ 同様に、画像は stb_image、音声は dr_mp3/dr_wav/stb_vorbis が全プラットフォーム共通の
397
+ 第一経路で、WIC / Media Foundation はデスクトップ限定のフォールバック
398
+ (AAC/TIFF 等の非標準形式向け)。コンソールでの動画 (`<video>`) は未対応。