@moku-labs/game 0.11.0 → 0.12.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.
- package/README.md +1 -0
- package/dist/app/page.d.mts +1 -1
- package/dist/app/system.d.mts +2 -2
- package/dist/app.d.mts +1 -1
- package/dist/app.mjs +1 -1
- package/dist/{assets-BHwTLVta.mjs → assets-DYiKxPBX.mjs} +27 -63
- package/dist/assets.mjs +1 -1
- package/dist/cli.d.mts +3 -2
- package/dist/cli.mjs +324 -43
- package/dist/{commands-C4QlqijJ.d.mts → commands-DvFr8Uwp.d.mts} +2 -2
- package/dist/control.d.mts +1 -1
- package/dist/{index-8TiJQjQA.d.mts → index-rnOYAriI.d.mts} +44 -4
- package/dist/index.d.mts +5 -5
- package/dist/index.mjs +2 -2
- package/dist/inspect.d.mts +3 -3
- package/dist/jsx-dev-runtime.d.mts +1 -1
- package/dist/jsx-runtime.d.mts +1 -1
- package/dist/lint.mjs +3 -1
- package/dist/{runtime-DOBYM6g4.d.mts → runtime-B276Gg0s.d.mts} +1 -1
- package/dist/{src-BSbtHZWk.mjs → src-SmT-XxVf.mjs} +56 -6
- package/dist/testing.d.mts +1 -1
- package/dist/testing.mjs +1 -1
- package/dist/{types-CefgYzFt.d.mts → types-Bcdo5-2w.d.mts} +1 -1
- package/dist/{types-BUwDHKXm.d.mts → types-BrTpz9oL.d.mts} +1 -1
- package/dist/{types-Ca_z_4tQ.d.mts → types-DLghaGEy.d.mts} +2 -2
- package/dist/{types-BM4shh8K.d.mts → types-D_2G6Q68.d.mts} +1 -1
- package/dist/visual.d.mts +9 -6
- package/dist/visual.mjs +7 -3
- package/llms.txt +6 -5
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -167,6 +167,7 @@ The engine bin `moku-game` serves, builds and packs a game folder. A game writes
|
|
|
167
167
|
| `moku-game native doctor`, `native clean` | Checks or removes the native project |
|
|
168
168
|
| `moku-game keys [--check]` | Writes `generated/assets.ts`, the strings and `manifest.json` |
|
|
169
169
|
| `moku-game pack [--no-cache]` | Packs the assets into `dist/assets` |
|
|
170
|
+
| `moku-game visual [--update] [--only <name>] [--no-pixels]` | Runs the visual tests of `tests/visual/index.ts` against `tests/visual/baselines/`. The pixel leg runs on a Mac, on a page served for the run. Exit 1 when a checkpoint differs |
|
|
170
171
|
|
|
171
172
|
Every command takes `--root <dir>`, `--preload <path>` and `--serve-plugin <path>`.
|
|
172
173
|
|
package/dist/app/page.d.mts
CHANGED
package/dist/app/system.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { tn as PlayerStateProvider } from "../types-ZQLYXo5X.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import { _ as SystemShellFactory, g as SystemName, h as SystemModules } from "../types-
|
|
2
|
+
import { ct as PlatformProvider } from "../index-rnOYAriI.mjs";
|
|
3
|
+
import { _ as SystemShellFactory, g as SystemName, h as SystemModules } from "../types-DLghaGEy.mjs";
|
|
4
4
|
import { Back, Haptics, KeepAwake, Lifecycle, Store } from "@moku-labs/system";
|
|
5
5
|
|
|
6
6
|
//#region src/app/system.d.ts
|
package/dist/app.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Xt as Json } from "./types-ZQLYXo5X.mjs";
|
|
2
|
-
import { a as GameHandle, c as MemoryProvider, d as SaveKind, f as Scenario, g as SystemName, i as GameDefinition, l as PageAgent, n as GameApp, o as GamePluginConfigs, p as ScreenSeams, r as GameConfig, s as HeadlessSeams } from "./types-
|
|
2
|
+
import { a as GameHandle, c as MemoryProvider, d as SaveKind, f as Scenario, g as SystemName, i as GameDefinition, l as PageAgent, n as GameApp, o as GamePluginConfigs, p as ScreenSeams, r as GameConfig, s as HeadlessSeams } from "./types-DLghaGEy.mjs";
|
|
3
3
|
import { AnyPluginInstance } from "@moku-labs/core";
|
|
4
4
|
|
|
5
5
|
//#region src/app/define.d.ts
|
package/dist/app.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Ct as effectsPlugin, H as platformPlugin, Nt as audioPlugin, i as screen, t as createApp } from "./src-SmT-XxVf.mjs";
|
|
2
2
|
import { t as memory } from "./memory-CWlqhS7l.mjs";
|
|
3
3
|
import { t as fakeClock } from "./fake-MpzwZhIZ.mjs";
|
|
4
4
|
//#region src/app/define.ts
|
|
@@ -1059,21 +1059,30 @@ function copyLoose(bundle, file, bytes) {
|
|
|
1059
1059
|
const LOOSE_SIDE = 512;
|
|
1060
1060
|
/** The last segment of a key that names a particle texture starts with this. */
|
|
1061
1061
|
const FX_PREFIX = "fx-";
|
|
1062
|
+
/** A folder of particle textures: every texture below it is one. */
|
|
1063
|
+
const FX_FOLDER = "fx";
|
|
1062
1064
|
/** The groups in the order a bundle packs them. */
|
|
1063
1065
|
const GROUP_ORDER = ["fx", "main"];
|
|
1064
1066
|
/**
|
|
1065
|
-
* Picks the atlas group of one texture. A key whose last segment starts with `fx
|
|
1066
|
-
*
|
|
1067
|
+
* Picks the atlas group of one texture. A key whose last segment starts with `fx-`, or with a
|
|
1068
|
+
* folder segment `fx` between the bundle name and the stem, goes to `fx` whatever its size: the
|
|
1069
|
+
* frames of an animation in `fx/` too. Any other texture goes to `main` when no side is above
|
|
1070
|
+
* 512 px.
|
|
1067
1071
|
*
|
|
1068
1072
|
* @param texture - The key and the size of the texture.
|
|
1069
1073
|
* @returns The group, or `undefined` when the texture stays loose by its size.
|
|
1070
1074
|
* @example
|
|
1071
1075
|
* ```ts
|
|
1072
1076
|
* groupOf({ key: "ui.fx-rays", width: 504, height: 512 }); // "fx"
|
|
1077
|
+
* groupOf({ key: "ui.fx.leaf", width: 64, height: 64 }); // "fx", from assets/fx/leaf.webp of ui
|
|
1078
|
+
* groupOf({ key: "ui.fx", width: 64, height: 64 }); // "main": a stem, no folder
|
|
1073
1079
|
* ```
|
|
1074
1080
|
*/
|
|
1075
1081
|
function groupOf(texture) {
|
|
1076
|
-
|
|
1082
|
+
const segments = texture.key.split(".");
|
|
1083
|
+
const name = segments.at(-1) ?? "";
|
|
1084
|
+
const folders = segments.slice(1, -1);
|
|
1085
|
+
if (name.startsWith(FX_PREFIX) || folders.includes(FX_FOLDER)) return "fx";
|
|
1077
1086
|
return texture.width <= LOOSE_SIDE && texture.height <= LOOSE_SIDE ? "main" : void 0;
|
|
1078
1087
|
}
|
|
1079
1088
|
/**
|
|
@@ -3080,65 +3089,23 @@ async function runCli(argv, strings, ui = createBrandConsole()) {
|
|
|
3080
3089
|
*/
|
|
3081
3090
|
/** How every generated file starts. */
|
|
3082
3091
|
const HEADER = "// generated by @moku-labs/game/assets, do not edit";
|
|
3083
|
-
/** The
|
|
3084
|
-
const
|
|
3092
|
+
/** The engine root a generated module imports its types and helpers from, quoted. */
|
|
3093
|
+
const ENGINE = "\"@moku-labs/game\"";
|
|
3085
3094
|
/** How a key with no parameters is typed, so `tr` takes it with no second argument. */
|
|
3086
3095
|
const NO_PARAMS = "Record<string, never>";
|
|
3087
3096
|
/** The name of the union a plain argument is typed by. */
|
|
3088
3097
|
const ARGUMENT = "Argument";
|
|
3089
3098
|
/**
|
|
3090
|
-
* The
|
|
3091
|
-
*
|
|
3099
|
+
* The import of the helpers the messages of a module call, by the names the message bodies use:
|
|
3100
|
+
* `messageArgument` as `argument` for a plain argument, `messageDuration` as `duration` for a
|
|
3101
|
+
* duration. None when no message calls one.
|
|
3092
3102
|
*
|
|
3093
|
-
* @
|
|
3103
|
+
* @param entries - The keys of the locale.
|
|
3104
|
+
* @returns The import line, or `undefined`.
|
|
3094
3105
|
*/
|
|
3095
|
-
function
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
"function argument(value: unknown, intl: I18n.IntlKit): I18n.Part {",
|
|
3099
|
-
" if (Array.isArray(value)) {",
|
|
3100
|
-
` return { kind: "text", text: intl.list().format(value ${CAST$1} readonly string[]) };`,
|
|
3101
|
-
" }",
|
|
3102
|
-
"",
|
|
3103
|
-
" if (typeof value === \"number\") return { kind: \"text\", text: intl.number().format(value) };",
|
|
3104
|
-
"",
|
|
3105
|
-
" if (",
|
|
3106
|
-
" typeof value === \"object\" &&",
|
|
3107
|
-
" value !== null &&",
|
|
3108
|
-
" \"type\" in value &&",
|
|
3109
|
-
" \"props\" in value &&",
|
|
3110
|
-
" \"children\" in value",
|
|
3111
|
-
" ) {",
|
|
3112
|
-
` return { kind: "element", node: value ${CAST$1} I18n.ElementNode };`,
|
|
3113
|
-
" }",
|
|
3114
|
-
"",
|
|
3115
|
-
" return { kind: \"text\", text: String(value) };",
|
|
3116
|
-
"}"
|
|
3117
|
-
].join("\n");
|
|
3118
|
-
}
|
|
3119
|
-
/**
|
|
3120
|
-
* The helper a compiled `duration` calls: milliseconds into the record `Intl.DurationFormat`
|
|
3121
|
-
* reads. The same split as `durationInput` of the plugin: whole seconds rounded up, a negative or
|
|
3122
|
-
* non-finite value as zero, hours and minutes when above zero, seconds always.
|
|
3123
|
-
*
|
|
3124
|
-
* @returns The helper as source.
|
|
3125
|
-
*/
|
|
3126
|
-
function durationHelper() {
|
|
3127
|
-
return [
|
|
3128
|
-
"/** Milliseconds as Intl.DurationFormat reads them: whole seconds rounded up, seconds always. */",
|
|
3129
|
-
"function duration(ms: number): Partial<Record<Intl.DurationFormatUnit, number>> {",
|
|
3130
|
-
" const total = Number.isFinite(ms) ? Math.max(0, Math.ceil(ms / 1000)) : 0;",
|
|
3131
|
-
" const hours = Math.floor(total / 3600);",
|
|
3132
|
-
" const minutes = Math.floor((total % 3600) / 60);",
|
|
3133
|
-
" const input: Partial<Record<Intl.DurationFormatUnit, number>> = {};",
|
|
3134
|
-
"",
|
|
3135
|
-
" if (hours > 0) input.hours = hours;",
|
|
3136
|
-
" if (minutes > 0) input.minutes = minutes;",
|
|
3137
|
-
" input.seconds = total % 60;",
|
|
3138
|
-
"",
|
|
3139
|
-
" return input;",
|
|
3140
|
-
"}"
|
|
3141
|
-
].join("\n");
|
|
3106
|
+
function helperImport(entries) {
|
|
3107
|
+
const helpers = [...entries.some((entry) => entry.compiled.usesArgument) ? ["messageArgument as argument"] : [], ...entries.some((entry) => entry.compiled.usesDuration) ? ["messageDuration as duration"] : []];
|
|
3108
|
+
return helpers.length === 0 ? void 0 : `import { ${helpers.join(", ")} } from ${ENGINE};`;
|
|
3142
3109
|
}
|
|
3143
3110
|
/**
|
|
3144
3111
|
* Compares two keys, so every list the compiler writes has one order.
|
|
@@ -3152,8 +3119,8 @@ function byName(left, right) {
|
|
|
3152
3119
|
return left < right ? -1 : 1;
|
|
3153
3120
|
}
|
|
3154
3121
|
/**
|
|
3155
|
-
* Writes `generated/strings.<locale>.ts`: one arrow per key, keys sorted,
|
|
3156
|
-
* message
|
|
3122
|
+
* Writes `generated/strings.<locale>.ts`: one arrow per key, keys sorted, and the import of each
|
|
3123
|
+
* engine helper only when a message calls it.
|
|
3157
3124
|
*
|
|
3158
3125
|
* @param entries - The keys of the locale, in any order.
|
|
3159
3126
|
* @returns The text of the module.
|
|
@@ -3166,11 +3133,8 @@ function byName(left, right) {
|
|
|
3166
3133
|
function emitLocale(entries) {
|
|
3167
3134
|
const sorted = [...entries].toSorted((left, right) => byName(left.key, right.key));
|
|
3168
3135
|
const rows = sorted.map((entry) => ` ${JSON.stringify(entry.key)}: ${entry.compiled.source}`);
|
|
3169
|
-
const
|
|
3170
|
-
|
|
3171
|
-
if (sorted.some((entry) => entry.compiled.usesDuration)) blocks.push(durationHelper());
|
|
3172
|
-
blocks.push(`export default {\n${rows.join(",\n")}\n} satisfies I18n.CompiledMessages;`);
|
|
3173
|
-
return `${blocks.join("\n\n")}\n`;
|
|
3136
|
+
const imports = [`import type { I18n } from ${ENGINE};`, helperImport(sorted)].filter((line) => line !== void 0);
|
|
3137
|
+
return [`${HEADER}\n${imports.join("\n")}`, `export default {\n${rows.join(",\n")}\n} satisfies I18n.CompiledMessages;\n`].join("\n\n");
|
|
3174
3138
|
}
|
|
3175
3139
|
/**
|
|
3176
3140
|
* Writes the type of one parameter.
|
|
@@ -3230,7 +3194,7 @@ function paramsOf(params) {
|
|
|
3230
3194
|
function emitTypes(entries) {
|
|
3231
3195
|
const sorted = [...entries].toSorted((left, right) => byName(left.key, right.key));
|
|
3232
3196
|
const rows = sorted.map((entry) => ` ${JSON.stringify(entry.key)}: ${paramsOf(entry.params)};`);
|
|
3233
|
-
const blocks = sorted.some((entry) => Object.values(entry.params).some((entry) => entry.kind === "argument")) ? [`${HEADER}\nimport type { DescriptionNode } from
|
|
3197
|
+
const blocks = sorted.some((entry) => Object.values(entry.params).some((entry) => entry.kind === "argument")) ? [`${HEADER}\nimport type { DescriptionNode } from ${ENGINE};`, `type ${ARGUMENT} = string | number | readonly string[] | DescriptionNode;`] : [HEADER];
|
|
3234
3198
|
blocks.push(`export type Strings = {\n${rows.join("\n")}\n};`, "export type StringKey = keyof Strings;");
|
|
3235
3199
|
return `${blocks.join("\n\n")}\n`;
|
|
3236
3200
|
}
|
package/dist/assets.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as runCli, c as emitKeys, i as compileStrings, l as emitManifest, n as importStrings, o as scanAssets, r as checkStrings, s as packAssets, t as exportStrings } from "./assets-
|
|
1
|
+
import { a as runCli, c as emitKeys, i as compileStrings, l as emitManifest, n as importStrings, o as scanAssets, r as checkStrings, s as packAssets, t as exportStrings } from "./assets-DYiKxPBX.mjs";
|
|
2
2
|
export { checkStrings, compileStrings, emitKeys, emitManifest, exportStrings, importStrings, packAssets, runCli, scanAssets };
|
package/dist/cli.d.mts
CHANGED
|
@@ -33,8 +33,8 @@ type PreparedPage = {
|
|
|
33
33
|
};
|
|
34
34
|
/**
|
|
35
35
|
* Runs one `moku-game` command line in this process: `dev`, `build`, `native <verb>`, `keys`,
|
|
36
|
-
* `pack` or `help`, with `--root`, `--preload` and `--serve-plugin` before or after the
|
|
37
|
-
* word. Every line goes through the branded console; nothing exits the process.
|
|
36
|
+
* `pack`, `visual` or `help`, with `--root`, `--preload` and `--serve-plugin` before or after the
|
|
37
|
+
* command word. Every line goes through the branded console; nothing exits the process.
|
|
38
38
|
*
|
|
39
39
|
* @param argv - The arguments after the bin.
|
|
40
40
|
* @returns The exit code.
|
|
@@ -42,6 +42,7 @@ type PreparedPage = {
|
|
|
42
42
|
* ```ts
|
|
43
43
|
* // bin/moku-game.mjs in a game folder:
|
|
44
44
|
* await runCli(["dev", "--port", "0"]); // 0 after Ctrl+C; stdout had "http://localhost:<port>/"
|
|
45
|
+
* await runCli(["visual", "--no-pixels"]); // 0 when every checkpoint of tests/visual/index.ts is the same
|
|
45
46
|
* await runCli(["help"]); // 0
|
|
46
47
|
* ```
|
|
47
48
|
*/
|