@kurot/cli 1.3.0 → 2.0.1
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/CHANGELOG.md +43 -0
- package/README.md +118 -330
- package/dist/core/components/discover-components.d.ts.map +1 -1
- package/dist/core/components/discover-components.js +7 -15
- package/dist/core/components/discover-components.js.map +1 -1
- package/dist/core/config.d.ts +8 -16
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +12 -4
- package/dist/core/config.js.map +1 -1
- package/dist/core/dev-server.d.ts +1 -1
- package/dist/core/dev-server.js +13 -13
- package/dist/core/dev-server.js.map +1 -1
- package/dist/core/diagnostics/codes.d.ts +3 -6
- package/dist/core/diagnostics/codes.d.ts.map +1 -1
- package/dist/core/diagnostics/codes.js +4 -10
- package/dist/core/diagnostics/codes.js.map +1 -1
- package/dist/core/diagnostics/output.d.ts +1 -1
- package/dist/core/diagnostics/output.d.ts.map +1 -1
- package/dist/core/{exml → kui}/ast.d.ts +17 -107
- package/dist/core/kui/ast.d.ts.map +1 -0
- package/dist/core/kui/ast.js +8 -0
- package/dist/core/{exml → kui}/ast.js.map +1 -1
- package/dist/core/kui/codegen.d.ts.map +1 -0
- package/dist/core/{exml → kui}/codegen.js +17 -177
- package/dist/core/kui/codegen.js.map +1 -0
- package/dist/core/kui/index.d.ts +29 -0
- package/dist/core/kui/index.d.ts.map +1 -0
- package/dist/core/kui/index.js +23 -0
- package/dist/core/kui/index.js.map +1 -0
- package/dist/core/{exml/exml-diagnostics.d.ts → kui/kui-diagnostics.d.ts} +2 -2
- package/dist/core/kui/kui-diagnostics.d.ts.map +1 -0
- package/dist/core/{exml/exml-diagnostics.js → kui/kui-diagnostics.js} +4 -4
- package/dist/core/kui/kui-diagnostics.js.map +1 -0
- package/dist/core/kui/kui-parser.d.ts +7 -0
- package/dist/core/kui/kui-parser.d.ts.map +1 -0
- package/dist/core/kui/kui-parser.js +153 -0
- package/dist/core/kui/kui-parser.js.map +1 -0
- package/dist/core/{exml → kui}/registry.d.ts +3 -26
- package/dist/core/kui/registry.d.ts.map +1 -0
- package/dist/core/{exml → kui}/registry.js +12 -43
- package/dist/core/kui/registry.js.map +1 -0
- package/dist/core/{exml → kui}/skin-module-builder.d.ts +6 -6
- package/dist/core/kui/skin-module-builder.d.ts.map +1 -0
- package/dist/core/{exml → kui}/skin-module-builder.js +7 -6
- package/dist/core/kui/skin-module-builder.js.map +1 -0
- package/dist/core/kui/skin-parts-declaration.d.ts.map +1 -0
- package/dist/core/{exml → kui}/skin-parts-declaration.js +2 -2
- package/dist/core/kui/skin-parts-declaration.js.map +1 -0
- package/dist/core/kui/source-location.d.ts.map +1 -0
- package/dist/core/kui/source-location.js.map +1 -0
- package/dist/core/namespace-external-plugin.d.ts +1 -1
- package/dist/core/namespace-external-plugin.js +1 -1
- package/dist/core/plugins/compile-custom-namespaces.d.ts +3 -3
- package/dist/core/plugins/compile-custom-namespaces.js +3 -3
- package/dist/core/plugins/compile-kui.d.ts +6 -0
- package/dist/core/plugins/compile-kui.d.ts.map +1 -0
- package/dist/core/plugins/compile-kui.js +167 -0
- package/dist/core/plugins/compile-kui.js.map +1 -0
- package/dist/core/plugins/copy-assets.d.ts +3 -3
- package/dist/core/plugins/copy-assets.d.ts.map +1 -1
- package/dist/core/plugins/copy-assets.js +7 -6
- package/dist/core/plugins/copy-assets.js.map +1 -1
- package/dist/core/plugins/index.d.ts +1 -1
- package/dist/core/plugins/index.d.ts.map +1 -1
- package/dist/core/plugins/index.js +3 -3
- package/dist/core/plugins/index.js.map +1 -1
- package/dist/core/project.d.ts +14 -10
- package/dist/core/project.d.ts.map +1 -1
- package/dist/core/project.js +11 -7
- package/dist/core/project.js.map +1 -1
- package/dist/core/template.js +1 -1
- package/dist/core/template.js.map +1 -1
- package/dist/define.d.ts +1 -1
- package/dist/define.d.ts.map +1 -1
- package/package.json +5 -3
- package/templates/game/kurot.config.ts +3 -3
- package/templates/game/resource/ui/skins/ButtonSkin.kui.xml +8 -0
- package/templates/game/resource/ui/skins/CheckBoxSkin.kui.xml +12 -0
- package/templates/game/resource/ui/skins/ComboBoxSkin.kui.xml +11 -0
- package/templates/game/resource/ui/skins/GroupSkin.kui.xml +6 -0
- package/templates/game/resource/ui/skins/HScrollBarSkin.kui.xml +6 -0
- package/templates/game/resource/ui/skins/HSliderSkin.kui.xml +7 -0
- package/templates/game/resource/ui/skins/ImageSkin.kui.xml +6 -0
- package/templates/game/resource/ui/skins/ItemRendererSkin.kui.xml +7 -0
- package/templates/game/resource/ui/skins/LabelSkin.kui.xml +6 -0
- package/templates/game/resource/ui/skins/ListSkin.kui.xml +9 -0
- package/templates/game/resource/ui/skins/PanelSkin.kui.xml +11 -0
- package/templates/game/resource/ui/skins/ProgressBarSkin.kui.xml +8 -0
- package/templates/game/resource/ui/skins/RadioButtonSkin.kui.xml +12 -0
- package/templates/game/resource/ui/skins/ScrollerSkin.kui.xml +7 -0
- package/templates/game/resource/ui/skins/TabBarSkin.kui.xml +7 -0
- package/templates/game/resource/ui/skins/TextInputSkin.kui.xml +8 -0
- package/templates/game/resource/ui/skins/ToggleButtonSkin.kui.xml +7 -0
- package/templates/game/resource/ui/skins/ToggleSwitchSkin.kui.xml +7 -0
- package/templates/game/resource/ui/skins/VScrollBarSkin.kui.xml +6 -0
- package/templates/game/resource/ui/skins/VSliderSkin.kui.xml +7 -0
- package/templates/game/resource/ui/skins/ViewStackSkin.kui.xml +6 -0
- package/dist/core/exml/ast.d.ts.map +0 -1
- package/dist/core/exml/ast.js +0 -8
- package/dist/core/exml/codegen.d.ts.map +0 -1
- package/dist/core/exml/codegen.js.map +0 -1
- package/dist/core/exml/exml-diagnostics.d.ts.map +0 -1
- package/dist/core/exml/exml-diagnostics.js.map +0 -1
- package/dist/core/exml/exml-parser.d.ts +0 -27
- package/dist/core/exml/exml-parser.d.ts.map +0 -1
- package/dist/core/exml/exml-parser.js +0 -380
- package/dist/core/exml/exml-parser.js.map +0 -1
- package/dist/core/exml/index.d.ts +0 -54
- package/dist/core/exml/index.d.ts.map +0 -1
- package/dist/core/exml/index.js +0 -51
- package/dist/core/exml/index.js.map +0 -1
- package/dist/core/exml/registry.d.ts.map +0 -1
- package/dist/core/exml/registry.js.map +0 -1
- package/dist/core/exml/skin-module-builder.d.ts.map +0 -1
- package/dist/core/exml/skin-module-builder.js.map +0 -1
- package/dist/core/exml/skin-parts-declaration.d.ts.map +0 -1
- package/dist/core/exml/skin-parts-declaration.js.map +0 -1
- package/dist/core/exml/source-location.d.ts.map +0 -1
- package/dist/core/exml/source-location.js.map +0 -1
- package/dist/core/exml/xml-parser.d.ts +0 -86
- package/dist/core/exml/xml-parser.d.ts.map +0 -1
- package/dist/core/exml/xml-parser.js +0 -196
- package/dist/core/exml/xml-parser.js.map +0 -1
- package/dist/core/plugins/compile-exml.d.ts +0 -14
- package/dist/core/plugins/compile-exml.d.ts.map +0 -1
- package/dist/core/plugins/compile-exml.js +0 -256
- package/dist/core/plugins/compile-exml.js.map +0 -1
- package/templates/game/resource/default.thm.json +0 -19
- package/templates/game/resource/skins/eui/ButtonSkin.exml +0 -16
- package/templates/game/resource/skins/eui/CheckBoxSkin.exml +0 -18
- package/templates/game/resource/skins/eui/ComboBoxSkin.exml +0 -31
- package/templates/game/resource/skins/eui/GroupSkin.exml +0 -4
- package/templates/game/resource/skins/eui/HScrollBarSkin.exml +0 -6
- package/templates/game/resource/skins/eui/HSliderSkin.exml +0 -7
- package/templates/game/resource/skins/eui/ImageSkin.exml +0 -4
- package/templates/game/resource/skins/eui/ItemRendererSkin.exml +0 -15
- package/templates/game/resource/skins/eui/LabelSkin.exml +0 -7
- package/templates/game/resource/skins/eui/ListSkin.exml +0 -11
- package/templates/game/resource/skins/eui/PanelSkin.exml +0 -15
- package/templates/game/resource/skins/eui/ProgressBarSkin.exml +0 -11
- package/templates/game/resource/skins/eui/RadioButtonSkin.exml +0 -18
- package/templates/game/resource/skins/eui/ScrollerSkin.exml +0 -8
- package/templates/game/resource/skins/eui/TabBarSkin.exml +0 -6
- package/templates/game/resource/skins/eui/TextInputSkin.exml +0 -22
- package/templates/game/resource/skins/eui/ToggleButtonSkin.exml +0 -21
- package/templates/game/resource/skins/eui/ToggleSwitchSkin.exml +0 -15
- package/templates/game/resource/skins/eui/VScrollBarSkin.exml +0 -6
- package/templates/game/resource/skins/eui/VSliderSkin.exml +0 -7
- package/templates/game/resource/skins/eui/ViewStackSkin.exml +0 -4
- /package/dist/core/{exml → kui}/codegen.d.ts +0 -0
- /package/dist/core/{exml → kui}/skin-parts-declaration.d.ts +0 -0
- /package/dist/core/{exml → kui}/source-location.d.ts +0 -0
- /package/dist/core/{exml → kui}/source-location.js +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,49 @@ and this project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.ht
|
|
|
7
7
|
|
|
8
8
|
## Unreleased
|
|
9
9
|
|
|
10
|
+
## 2.0.1 — 2026-09-21
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- Raised the `@kurot/ui-document` requirement to `^0.6.1` for canonical Skin
|
|
15
|
+
state and internal-node handling.
|
|
16
|
+
- Simplified the authored Skin root to `class`; storage IDs, format versions,
|
|
17
|
+
runtime targets, and default flags are no longer user-edited XML metadata.
|
|
18
|
+
- Default theme mappings now come from internal built-in conventions and
|
|
19
|
+
configured project component pairs.
|
|
20
|
+
- Skin parts are inferred from identified visual nodes; internal nodes can omit
|
|
21
|
+
IDs. States use the root `states` list and local `property.state` attributes,
|
|
22
|
+
so state-only targets do not require artificial part names.
|
|
23
|
+
- Image `source` values use plain resource keys without an
|
|
24
|
+
`@resource:image:` prefix.
|
|
25
|
+
|
|
26
|
+
## 2.0.0 — 2026-09-21
|
|
27
|
+
|
|
28
|
+
This release is scoped to the Kurot Editor toolchain. Existing EXML game
|
|
29
|
+
projects remain supported by the 1.3.x line and are not expected to upgrade or
|
|
30
|
+
change their project configuration.
|
|
31
|
+
|
|
32
|
+
### Added
|
|
33
|
+
|
|
34
|
+
- Canonical KUI XML Skin compilation through `@kurot/ui-document`.
|
|
35
|
+
- Generated default theme mappings derived from Skin `target` and `default`
|
|
36
|
+
metadata, including duplicate-default diagnostics.
|
|
37
|
+
- KUI XML project templates for all 21 built-in UI skins.
|
|
38
|
+
|
|
39
|
+
### Changed
|
|
40
|
+
|
|
41
|
+
- Replaced the `exml` project configuration with `ui.sourceDir`,
|
|
42
|
+
`ui.namespaces`, and `ui.components`.
|
|
43
|
+
- Simplified SkinIR to the runtime operations produced by semantic KUI
|
|
44
|
+
documents and removed syntax-specific compatibility branches.
|
|
45
|
+
- The theme JSON is generated at the fixed `resource/default.thm.json` output
|
|
46
|
+
path rather than configured or supplied as an authored input.
|
|
47
|
+
|
|
48
|
+
### Removed
|
|
49
|
+
|
|
50
|
+
- EXML parsing, theme-input discovery, `.exml` templates, and compatibility
|
|
51
|
+
diagnostics.
|
|
52
|
+
|
|
10
53
|
## 1.3.0 — 2026-09-20
|
|
11
54
|
|
|
12
55
|
### Added
|
package/README.md
CHANGED
|
@@ -1,399 +1,187 @@
|
|
|
1
1
|
# @kurot/cli
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Build tooling for the Kurot UI Editor workflow. It uses esbuild, emits ES2022
|
|
4
|
+
ESM, and compiles canonical KUI XML skins into runtime theme modules.
|
|
4
5
|
|
|
5
|
-
> **Current release:
|
|
6
|
+
> **Current release: 2.0.1.** Node.js 20 or later is required.
|
|
6
7
|
|
|
7
|
-
>
|
|
8
|
-
>
|
|
9
|
-
>
|
|
8
|
+
> **Release scope:** The 2.0.x line is currently dedicated to Kurot Editor integration.
|
|
9
|
+
> Existing game projects that use EXML, including CrashMaster, should remain on
|
|
10
|
+
> `@kurot/cli@1.3.x`. Version 2.0.x is not an in-place project upgrade and does
|
|
11
|
+
> not require those projects to change their configuration or UI assets.
|
|
10
12
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
`@kurot/cli` does **not** require a global install.
|
|
13
|
+
See [CHANGELOG.md](CHANGELOG.md) for release history.
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
## Usage
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
The CLI does not require a global install.
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
20
|
npx @kurot/cli create my-game
|
|
21
|
-
npx @kurot/cli create my-lib --template empty
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
### In-project commands
|
|
25
|
-
|
|
26
|
-
Scaffolded projects include `@kurot/cli` as a devDependency and expose commands via npm scripts:
|
|
27
|
-
|
|
28
|
-
```bash
|
|
29
21
|
cd my-game
|
|
30
22
|
pnpm install
|
|
31
|
-
pnpm
|
|
32
|
-
pnpm dev # dev server
|
|
33
|
-
pnpm clean # clean output
|
|
23
|
+
pnpm dev
|
|
34
24
|
```
|
|
35
25
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
```
|
|
26
|
+
Scaffolded projects expose `build`, `dev`, and `clean` scripts. For an
|
|
27
|
+
Editor-managed KUI XML project, install the package with
|
|
28
|
+
`pnpm add -D @kurot/cli@2`. Existing EXML projects should keep their current
|
|
29
|
+
1.3.x dependency.
|
|
41
30
|
|
|
42
31
|
## Commands
|
|
43
32
|
|
|
44
33
|
### `kurot create`
|
|
45
34
|
|
|
46
|
-
Scaffold a new project from a template.
|
|
47
|
-
|
|
48
35
|
```bash
|
|
49
|
-
kurot create <name> [
|
|
36
|
+
kurot create <name> [--template game|empty]
|
|
50
37
|
```
|
|
51
38
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
**Templates:**
|
|
57
|
-
|
|
58
|
-
| Template | Extends | Dependencies | Description |
|
|
59
|
-
| -------- | --------- | ------------------------------------------------- | -------------------------------------------------------------------------------- |
|
|
60
|
-
| `game` | `UILayer` | `@kurot/core` + `@kurot/game` + `@kurot/ui` | Full-featured project with resource loading, scene building, and Tween animation |
|
|
61
|
-
| `empty` | `Sprite` | `@kurot/core` | Minimal project — pure Canvas rendering, no extra dependencies |
|
|
62
|
-
|
|
63
|
-
**Lifecycle:**
|
|
64
|
-
|
|
65
|
-
| Template | Entry class | Lifecycle |
|
|
66
|
-
| -------- | ---------------------- | ------------------------------------------------------------------------------------------------- |
|
|
67
|
-
| `game` | `Main extends UILayer` | `createChildren` → `runGame` → `loadResource` → `loadTheme` → `createGameScene` → `startAnimation` |
|
|
68
|
-
| `empty` | `Main extends Sprite` | constructor → `ADDED_TO_STAGE` → `onAddToStage` |
|
|
39
|
+
The `game` template includes `@kurot/core`, `@kurot/game`, `@kurot/ui`, KUI
|
|
40
|
+
skins, resource loading, and an editable HTML template. The `empty` template
|
|
41
|
+
contains a minimal `Sprite` application.
|
|
69
42
|
|
|
70
43
|
### `kurot build`
|
|
71
44
|
|
|
72
|
-
Compile the project into ESM application, engine, namespace, and theme bundles.
|
|
73
|
-
|
|
74
|
-
```bash
|
|
75
|
-
kurot build [options]
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
| Option | Description | Default |
|
|
79
|
-
| ------------------------ | ------------------------------------------------------ | ------- |
|
|
80
|
-
| `-r, --release` | Minified, content-hashed release build (→ bin-release) | `false` |
|
|
81
|
-
| `--sourcemap` | Generate sourcemaps | `false` |
|
|
82
|
-
| `--watch` | Rebuild source on file changes | `false` |
|
|
83
|
-
| `--analyze` | Print bundle size analysis (esbuild metafile) | `false` |
|
|
84
|
-
| `--strict` | Promote supported warnings to build errors | `false` |
|
|
85
|
-
| `--diagnostics <format>` | Diagnostic output: `human` or `json` | `human` |
|
|
86
|
-
|
|
87
|
-
`--diagnostics json` writes exactly one JSON result to stdout. It includes
|
|
88
|
-
`success`, `mode`, `durationMs`, the output directory on success, and all
|
|
89
|
-
structured diagnostics. Release builds use strict diagnostic policy by default.
|
|
90
|
-
|
|
91
45
|
```bash
|
|
92
|
-
kurot build --
|
|
46
|
+
kurot build [--release] [--sourcemap] [--watch] [--analyze]
|
|
47
|
+
[--strict] [--diagnostics human|json]
|
|
93
48
|
```
|
|
94
49
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
| development | `bin-debug/` — per-file `.js` mirroring `src/` (`Main.js`, `com/.../X.js`) + engine chunks in `js/` |
|
|
100
|
-
| release (`-r`) | `bin-release/web/<timestamp>/` — `js/main.min_<hash>.js` + `js/kurot.*.min_<hash>.js` + `manifest.json` |
|
|
50
|
+
Development output is written to `bin-debug/`. Release output is written to
|
|
51
|
+
`bin-release/web/<timestamp>/` with minified, content-hashed files. Engine,
|
|
52
|
+
project namespace, theme, and application code are separate ESM chunks joined
|
|
53
|
+
by the generated HTML import map.
|
|
101
54
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
resolve bare specifiers (`import { Sprite } from '@kurot/core'`) in the browser
|
|
105
|
-
without duplicating engine code. `resource/` (including the compiled
|
|
106
|
-
`default.thm.json`) is copied with fixed names, since user code references those
|
|
107
|
-
paths directly. The entry script bootstraps via your own `createPlayer()` call.
|
|
55
|
+
`--diagnostics json` reserves stdout for one machine-readable build result.
|
|
56
|
+
Release builds apply strict diagnostic policy by default.
|
|
108
57
|
|
|
109
58
|
### `kurot dev`
|
|
110
59
|
|
|
111
|
-
Start a development server with auto-recompilation on file changes (manual browser refresh required).
|
|
112
|
-
|
|
113
|
-
```bash
|
|
114
|
-
kurot dev [options]
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
| Option | Description | Default |
|
|
118
|
-
| ------------------------ | ------------------------------------------ | ------- |
|
|
119
|
-
| `-p, --port <port>` | Port to listen | `3000` |
|
|
120
|
-
| `--sourcemap` | Generate sourcemaps | `false` |
|
|
121
|
-
| `--strict` | Promote supported warnings to build errors | `false` |
|
|
122
|
-
| `--diagnostics <format>` | Diagnostic output: `human` or `jsonl` | `human` |
|
|
123
|
-
|
|
124
|
-
Unlike build's single JSON result, `kurot dev --diagnostics jsonl` writes one
|
|
125
|
-
JSON event per line so an agent can follow initial builds, diagnostics,
|
|
126
|
-
rebuilds, and server readiness incrementally.
|
|
127
|
-
|
|
128
60
|
```bash
|
|
129
|
-
kurot dev --
|
|
61
|
+
kurot dev [--port 3000] [--sourcemap] [--strict]
|
|
62
|
+
[--diagnostics human|jsonl]
|
|
130
63
|
```
|
|
131
64
|
|
|
132
|
-
|
|
133
|
-
|
|
65
|
+
The development server rebuilds TypeScript, KUI XML, custom namespaces, and
|
|
66
|
+
the component catalog as their sources change. Browser refresh is currently
|
|
67
|
+
manual. JSONL mode reserves stdout for incremental build and server events.
|
|
134
68
|
|
|
135
69
|
### `kurot clean`
|
|
136
70
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
```bash
|
|
140
|
-
kurot clean
|
|
141
|
-
```
|
|
71
|
+
Removes `bin-debug` and `bin-release`.
|
|
142
72
|
|
|
143
73
|
## Configuration
|
|
144
74
|
|
|
145
|
-
Create
|
|
75
|
+
Create `kurot.config.ts` in the project root:
|
|
146
76
|
|
|
147
77
|
```ts
|
|
148
78
|
export default {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
},
|
|
169
|
-
},
|
|
79
|
+
target: 'html5',
|
|
80
|
+
entry: 'src/Main.ts',
|
|
81
|
+
output: { dir: 'bin-debug' },
|
|
82
|
+
html: { template: 'template/web/index.html' },
|
|
83
|
+
stage: {
|
|
84
|
+
width: 640,
|
|
85
|
+
height: 1136,
|
|
86
|
+
scaleMode: 'showAll',
|
|
87
|
+
orientation: 'auto',
|
|
88
|
+
frameRate: 60,
|
|
89
|
+
},
|
|
90
|
+
ui: {
|
|
91
|
+
sourceDir: 'resource/ui',
|
|
92
|
+
components: {
|
|
93
|
+
namespace: 'game',
|
|
94
|
+
sourceDir: 'src/components',
|
|
95
|
+
skinDir: 'resource/ui/components',
|
|
96
|
+
},
|
|
97
|
+
},
|
|
170
98
|
};
|
|
171
99
|
```
|
|
172
100
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
| ------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------ |
|
|
177
|
-
| `target` | `string` | Build target — currently only `'html5'` |
|
|
178
|
-
| `entry` | `string` | Entry file path, default `'src/Main.ts'` |
|
|
179
|
-
| `output.dir` | `string` | Output directory, default `'bin-debug'` |
|
|
180
|
-
| `html.template` | `string` | Optional project-owned HTML template; the CLI default page is used when omitted |
|
|
181
|
-
| `stage.width` | `number` | Stage width |
|
|
182
|
-
| `stage.height` | `number` | Stage height |
|
|
183
|
-
| `stage.scaleMode` | `string` | Scale mode: `showAll` / `noScale` / `exactFit` / `noBorder` / `fixedHeight` / `fixedWidth` / `fixedNarrow` / `fixedWide` |
|
|
184
|
-
| `stage.orientation` | `string` | Orientation: `auto` / `portrait` / `landscape` |
|
|
185
|
-
| `stage.frameRate` | `number` | Frame rate — must be a positive integer |
|
|
186
|
-
| `exml.themeFile` | `string` | Theme JSON file path |
|
|
187
|
-
| `exml.components` | `ComponentsConfig` | Optional reusable-component convention: namespace, TypeScript source directory, and Skin directory |
|
|
188
|
-
| `exml.namespaces` | `Record<string, string>` | Optional EXML prefix → source barrel-file mapping |
|
|
189
|
-
|
|
190
|
-
## HTML Template
|
|
191
|
-
|
|
192
|
-
New projects include an editable `template/web/index.html`. The build reads
|
|
193
|
-
this file and writes the rendered page to the active output directory. Existing
|
|
194
|
-
projects that do not configure `html.template` continue to use the CLI's
|
|
195
|
-
built-in default page.
|
|
196
|
-
|
|
197
|
-
The following placeholders are required in a configured project template:
|
|
198
|
-
|
|
199
|
-
| Placeholder | Generated value |
|
|
200
|
-
| --- | --- |
|
|
201
|
-
| `{{KUROT_IMPORT_MAP}}` | Engine and custom namespace import map |
|
|
202
|
-
| `{{KUROT_STAGE_WIDTH}}` | Configured stage width |
|
|
203
|
-
| `{{KUROT_STAGE_HEIGHT}}` | Configured stage height |
|
|
204
|
-
| `{{KUROT_SCALE_MODE}}` | Configured scale mode |
|
|
205
|
-
| `{{KUROT_ORIENTATION}}` | Configured orientation |
|
|
206
|
-
| `{{KUROT_FRAME_RATE}}` | Configured frame rate |
|
|
207
|
-
| `{{KUROT_ENTRY_SCRIPT}}` | Compiled application entry script |
|
|
208
|
-
|
|
209
|
-
The template may otherwise contain any project-specific HTML, styles, loading
|
|
210
|
-
screen, platform SDK, analytics, fonts, or additional containers. A build fails
|
|
211
|
-
with a clear error when a configured template is missing a required placeholder.
|
|
212
|
-
|
|
213
|
-
## EXML Skin Compiler
|
|
214
|
-
|
|
215
|
-
The CLI includes a complete EXML skin parsing and code generation pipeline (XML → SkinIR → ESM JavaScript). `.exml` files placed in the `resource/` directory are compiled automatically during `kurot build`.
|
|
216
|
-
|
|
217
|
-
### Features
|
|
218
|
-
|
|
219
|
-
- **XML Parsing** — lightweight parser with namespace, CDATA, and comment support
|
|
220
|
-
- **AST / IR Generation** — converts to an intermediate representation (SkinIR)
|
|
221
|
-
- **Code Generation** — outputs ESM factory functions
|
|
222
|
-
- **Component Registry** — built-in `eui:*` / `egret:*` namespace mapping to `@kurot/ui` / `@kurot/core`
|
|
223
|
-
- **Reusable Components** — pairs `src/components/<Name>.ts` with `resource/skins/components/<Name>Skin.exml`, then exposes `<game:Name>` without a hand-written barrel
|
|
224
|
-
- **Custom Namespaces** — retains `exml.namespaces` for advanced manually maintained source barrels
|
|
225
|
-
- **View States** — supports `<eui:states>`, shorthand `states="up,down"`, state properties, `includeIn`, and `excludeFrom`
|
|
226
|
-
- **Skin Properties** — preserves root properties such as `minWidth`, `minHeight`, and state-specific values
|
|
227
|
-
- **Percent Layout** — auto-detects `width="100%"` and converts to `percentWidth`
|
|
228
|
-
- **Data Binding** — parses `{expression}` binding syntax and generates `Binding.bindProperty` calls
|
|
229
|
-
- **Structured Diagnostics** — stable codes, source locations, suggestions, and strict warning promotion
|
|
230
|
-
|
|
231
|
-
Unknown tags remain warnings in normal development builds and are omitted from
|
|
232
|
-
the generated visual tree. Under `--strict` (and in release builds), those
|
|
233
|
-
warnings become errors. Syntax errors, invalid theme JSON, and other genuine
|
|
234
|
-
Skin compilation failures always stop the build; the compiler never substitutes
|
|
235
|
-
an empty Skin factory.
|
|
236
|
-
|
|
237
|
-
The standard declarations `xmlns:eui="http://ns.egret.com/eui"` and
|
|
238
|
-
`xmlns:egret="http://ns.egret.com/egret"` are namespace identifiers. The CLI
|
|
239
|
-
resolves their prefixes internally and does not access those URLs over the
|
|
240
|
-
network, so the original Egret namespace pages do not need to be hosted.
|
|
241
|
-
|
|
242
|
-
### Reusable components
|
|
243
|
-
|
|
244
|
-
The game template keeps reusable component logic and white-Egret-compatible
|
|
245
|
-
skins in parallel directories:
|
|
246
|
-
|
|
247
|
-
```text
|
|
248
|
-
src/components/<path>/<Name>.ts
|
|
249
|
-
resource/skins/components/<path>/<Name>Skin.exml
|
|
250
|
-
```
|
|
251
|
-
|
|
252
|
-
The TypeScript file must export a class named `<Name>`, and the paired EXML
|
|
253
|
-
must use a standard `eui:Skin` root with a `class` attribute. The CLI validates
|
|
254
|
-
the pair, generates the shared `#ns/game` entry, adds the default Theme mapping,
|
|
255
|
-
and accepts `<game:Name />` in other skins. Components are globally unique by
|
|
256
|
-
class name within the configured namespace.
|
|
257
|
-
|
|
258
|
-
Development builds also emit `.kurot/component-catalog.json` for editor and
|
|
259
|
-
agent tooling. The catalog is intentionally omitted from release output.
|
|
260
|
-
|
|
261
|
-
Every successful EXML compilation also writes `.kurot/skin-parts.d.ts`. It
|
|
262
|
-
augments `@kurot/ui`'s `SkinPartsMap` with the exact named parts and runtime
|
|
263
|
-
types found in each compiled skin. It also discovers exported project classes
|
|
264
|
-
through a compiled string-literal `this.skinName`, configured reusable-component
|
|
265
|
-
pairs, or a unique `<ClassName>Skin` naming match, then narrows their inherited
|
|
266
|
-
public `skinParts` property automatically. Ambiguous naming matches are left
|
|
267
|
-
untyped instead of being guessed. The generated file is included by the template
|
|
268
|
-
`tsconfig.json`, ignored by git, and never enters browser or release bundles.
|
|
101
|
+
`ui.sourceDir` contains `.kui.xml` documents. The build always generates the
|
|
102
|
+
runtime theme manifest at `resource/default.thm.json`; it is not an authored
|
|
103
|
+
input. `ui.namespaces` can map additional XML prefixes to project barrel files.
|
|
269
104
|
|
|
270
|
-
|
|
271
|
-
its prefix must not conflict with `exml.components.namespace`.
|
|
105
|
+
The HTML template must contain these placeholders:
|
|
272
106
|
|
|
273
|
-
|
|
107
|
+
- `{{KUROT_IMPORT_MAP}}`
|
|
108
|
+
- `{{KUROT_STAGE_WIDTH}}`
|
|
109
|
+
- `{{KUROT_STAGE_HEIGHT}}`
|
|
110
|
+
- `{{KUROT_SCALE_MODE}}`
|
|
111
|
+
- `{{KUROT_ORIENTATION}}`
|
|
112
|
+
- `{{KUROT_FRAME_RATE}}`
|
|
113
|
+
- `{{KUROT_ENTRY_SCRIPT}}`
|
|
274
114
|
|
|
275
|
-
|
|
276
|
-
`onSkinReady()`. The generated declaration derives the `skinParts` type from that
|
|
277
|
-
assignment:
|
|
115
|
+
## KUI XML compilation
|
|
278
116
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
export class BattlePanel extends Component {
|
|
284
|
-
public constructor() {
|
|
285
|
-
super();
|
|
286
|
-
this.skinName = 'game.ui.BattlePanelSkin';
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
protected override onSkinReady(): void {
|
|
290
|
-
super.onSkinReady();
|
|
291
|
-
this.skinParts.groupField.visible = true;
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
```
|
|
295
|
-
|
|
296
|
-
The same declaration narrowing applies when the runtime assigns the skin
|
|
297
|
-
externally. For example, an exported `MultiplierIR` class is matched to a
|
|
298
|
-
unique compiled `ui.MultiplierIRSkin`, so the renderer remains free of a
|
|
299
|
-
repeated generic skin name:
|
|
117
|
+
KUI XML is the authored Skin format. A Skin root declares its generated class
|
|
118
|
+
name and, when needed, its state names:
|
|
300
119
|
|
|
301
|
-
```
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
}
|
|
120
|
+
```xml
|
|
121
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
122
|
+
<Skin xmlns="https://kurot.dev/ui/1" class="skins.ButtonSkin" states="up,down,disabled">
|
|
123
|
+
<Group id="root" minWidth="100" minHeight="50">
|
|
124
|
+
<Rect fillColor="#315A9D" fillColor.down="#244474" alpha.disabled="0.5" />
|
|
125
|
+
<Label id="labelDisplay" horizontalCenter="0" verticalCenter="0" />
|
|
126
|
+
</Group>
|
|
127
|
+
</Skin>
|
|
310
128
|
```
|
|
311
129
|
|
|
312
|
-
|
|
130
|
+
Only nodes exposed as runtime skin parts need an `id`. State-specific values
|
|
131
|
+
use `property.state` on the affected node, so internal graphics remain unnamed.
|
|
132
|
+
Image sources use their resource key directly, for example
|
|
133
|
+
`source="button_up_png"`.
|
|
313
134
|
|
|
314
|
-
|
|
315
|
-
import { UIEvent } from '@kurot/ui';
|
|
135
|
+
The pipeline is:
|
|
316
136
|
|
|
317
|
-
|
|
137
|
+
```text
|
|
138
|
+
.kui.xml → UIDocument → SkinIR → ESM skin factory → theme bundle
|
|
318
139
|
```
|
|
319
140
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
UI 2.0 no longer copies part names onto component instances and no longer
|
|
326
|
-
supports `setSkinPart()`, `partAdded()`, or `partRemoved()`. Read parts through
|
|
327
|
-
`this.skinParts` only while the skin-ready lifecycle is active. Use an explicit
|
|
328
|
-
generic skin type when generated host declarations are unavailable outside a
|
|
329
|
-
CLI project.
|
|
141
|
+
The build derives default skin mappings from built-in component conventions and
|
|
142
|
+
configured project component pairs. The build writes `default.thm.json` with
|
|
143
|
+
those mappings and the generated `skinsJs` module path. Duplicate conventional
|
|
144
|
+
mappings are errors. Unknown tags are warnings in normal development and errors
|
|
145
|
+
under strict or release builds.
|
|
330
146
|
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
does not need to assign `skinName` itself. Hand-written `Skin` subclasses may be
|
|
336
|
-
imported and assigned directly instead of using a string.
|
|
147
|
+
Successful compilation also writes `.kurot/skin-parts.d.ts`. Every identified
|
|
148
|
+
node below the visual root is inferred as a skin part; its `id` is the part
|
|
149
|
+
name. The declaration augments the UI runtime with those exact names and types.
|
|
150
|
+
This file is editor-only, ignored by git, and never enters browser bundles.
|
|
337
151
|
|
|
338
|
-
|
|
152
|
+
## Reusable components
|
|
339
153
|
|
|
340
|
-
|
|
341
|
-
or `js/default.thm.min_<hash>.js` (release) — that registers each skin factory.
|
|
342
|
-
`default.thm.json` keeps only the component→skin mapping plus a `skinsJs`
|
|
343
|
-
pointer to that module, which the runtime `Theme` imports. No `.exml` is shipped.
|
|
154
|
+
Convention-based reusable components pair:
|
|
344
155
|
|
|
345
|
-
```
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
XML Element Tree
|
|
349
|
-
↓ parseEXML()
|
|
350
|
-
SkinIR
|
|
351
|
-
↓ generateCode({ format: 'esm' })
|
|
352
|
-
per-skin ESM factories
|
|
353
|
-
↓ esbuild bundle (+ minify in release)
|
|
354
|
-
js/default.thm[.min_<hash>].js (skins register on globalThis)
|
|
156
|
+
```text
|
|
157
|
+
src/components/<path>/<Name>.ts
|
|
158
|
+
resource/ui/components/<path>/<Name>Skin.kui.xml
|
|
355
159
|
```
|
|
356
160
|
|
|
357
|
-
|
|
161
|
+
The TypeScript module must export `<Name>`. The paired skin must target
|
|
162
|
+
`<namespace>.<Name>`. The CLI exposes the component as `<namespace>:<Name>` in
|
|
163
|
+
KUI XML, refreshes the namespace bundle, and emits development catalog data at
|
|
164
|
+
`.kurot/component-catalog.json`.
|
|
358
165
|
|
|
359
|
-
|
|
166
|
+
Use `onSkinReady()` for logic that needs skin parts and `onSkinRemoved()` for
|
|
167
|
+
cleanup before a skin replacement. Access generated parts through
|
|
168
|
+
`this.skinParts`.
|
|
360
169
|
|
|
361
|
-
|
|
170
|
+
## Generated project shape
|
|
171
|
+
|
|
172
|
+
```text
|
|
362
173
|
my-game/
|
|
363
|
-
├── .kurot/
|
|
364
|
-
|
|
365
|
-
├── .gitignore # Excludes .kurot and build/dependency output
|
|
366
|
-
├── kurot.config.ts # Project config (includes exml options)
|
|
367
|
-
├── package.json # Dependencies & scripts
|
|
368
|
-
├── tsconfig.json # TypeScript config
|
|
369
|
-
├── template/
|
|
370
|
-
│ └── web/
|
|
371
|
-
│ └── index.html # Editable output page template
|
|
174
|
+
├── .kurot/skin-parts.d.ts
|
|
175
|
+
├── kurot.config.ts
|
|
372
176
|
├── resource/
|
|
373
|
-
│ ├── default.res.json
|
|
374
|
-
│ ├──
|
|
375
|
-
│ └──
|
|
376
|
-
│ ├── components/
|
|
377
|
-
│ └──
|
|
378
|
-
|
|
379
|
-
│
|
|
380
|
-
│
|
|
381
|
-
└──
|
|
382
|
-
|
|
383
|
-
├── Main.ts # Entry: class Main extends Sprite
|
|
384
|
-
└── LoadingUI.ts # Loading progress display
|
|
385
|
-
```
|
|
386
|
-
|
|
387
|
-
## Quick Start
|
|
388
|
-
|
|
389
|
-
```bash
|
|
390
|
-
# Full-featured game project (default)
|
|
391
|
-
npx @kurot/cli create my-game
|
|
392
|
-
cd my-game && pnpm install
|
|
393
|
-
pnpm dev
|
|
394
|
-
|
|
395
|
-
# Minimal project
|
|
396
|
-
npx @kurot/cli create my-lib --template empty
|
|
397
|
-
cd my-lib && pnpm install
|
|
398
|
-
pnpm dev
|
|
177
|
+
│ ├── default.res.json
|
|
178
|
+
│ ├── assets/
|
|
179
|
+
│ └── ui/
|
|
180
|
+
│ ├── components/
|
|
181
|
+
│ └── skins/*.kui.xml
|
|
182
|
+
├── src/
|
|
183
|
+
│ ├── components/
|
|
184
|
+
│ ├── LoadingUI.ts
|
|
185
|
+
│ └── Main.ts
|
|
186
|
+
└── template/web/index.html
|
|
399
187
|
```
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discover-components.d.ts","sourceRoot":"","sources":["../../../src/core/components/discover-components.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAE3E;;;GAGG;AACH,wBAAsB,kBAAkB,CACvC,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,mBAAmB,GAAG,SAAS,GACzC,OAAO,CAAC,gBAAgB,EAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"discover-components.d.ts","sourceRoot":"","sources":["../../../src/core/components/discover-components.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAE3E;;;GAGG;AACH,wBAAsB,kBAAkB,CACvC,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,mBAAmB,GAAG,SAAS,GACzC,OAAO,CAAC,gBAAgB,EAAE,CAAC,CA6E7B;AAED;;;GAGG;AACH,wBAAsB,wBAAwB,CAAC,OAAO,EAAE;IACvD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,mBAAmB,CAAC,EAAE,mBAAmB,CAAC;IACnD,QAAQ,CAAC,UAAU,EAAE,gBAAgB,EAAE,CAAC;CACxC,GAAG,OAAO,CAAC,IAAI,CAAC,CAGhB"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as fs from 'node:fs/promises';
|
|
2
2
|
import * as path from 'node:path';
|
|
3
|
+
import { parseUIDocument } from '@kurot/ui-document';
|
|
3
4
|
import { ConfigError } from '../errors.js';
|
|
4
|
-
import { localName, parseXML } from '../exml/index.js';
|
|
5
5
|
/**
|
|
6
6
|
* Discovers reusable component source/skin pairs using the configured
|
|
7
7
|
* directory convention.
|
|
@@ -11,7 +11,7 @@ export async function discoverComponents(root, convention) {
|
|
|
11
11
|
return [];
|
|
12
12
|
const [sourceFiles, skinFiles] = await Promise.all([
|
|
13
13
|
collectFiles(convention.sourceDir, file => file.endsWith('.ts') && !file.endsWith('.d.ts')),
|
|
14
|
-
collectFiles(convention.skinDir, file => file.endsWith('Skin.
|
|
14
|
+
collectFiles(convention.skinDir, file => file.endsWith('Skin.kui.xml')),
|
|
15
15
|
]);
|
|
16
16
|
const sourceByPair = new Map(sourceFiles.map(file => [sourcePairKey(convention.sourceDir, file), file]));
|
|
17
17
|
const skinByPair = new Map(skinFiles.map(file => [skinPairKey(convention.skinDir, file), file]));
|
|
@@ -29,7 +29,7 @@ export async function discoverComponents(root, convention) {
|
|
|
29
29
|
continue;
|
|
30
30
|
}
|
|
31
31
|
if (!skin) {
|
|
32
|
-
errors.push(`Component source '${relative(root, source)}' has no matching skin '${pairKey}Skin.
|
|
32
|
+
errors.push(`Component source '${relative(root, source)}' has no matching skin '${pairKey}Skin.kui.xml'.`);
|
|
33
33
|
continue;
|
|
34
34
|
}
|
|
35
35
|
const name = path.basename(source, '.ts');
|
|
@@ -54,20 +54,12 @@ export async function discoverComponents(root, convention) {
|
|
|
54
54
|
}
|
|
55
55
|
let skinClass;
|
|
56
56
|
try {
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
errors.push(`Component skin '${relative(root, skin)}' must use an eui:Skin root.`);
|
|
60
|
-
continue;
|
|
61
|
-
}
|
|
62
|
-
skinClass = skinRoot.attributes.find(attribute => attribute.name === 'class')?.value ?? '';
|
|
63
|
-
if (!skinClass) {
|
|
64
|
-
errors.push(`Component skin '${relative(root, skin)}' must declare a class attribute.`);
|
|
65
|
-
continue;
|
|
66
|
-
}
|
|
57
|
+
const skinDocument = parseUIDocument(await fs.readFile(skin, 'utf-8'));
|
|
58
|
+
skinClass = skinDocument.id;
|
|
67
59
|
}
|
|
68
60
|
catch (error) {
|
|
69
61
|
const message = error instanceof Error ? error.message : String(error);
|
|
70
|
-
errors.push(`Component skin '${relative(root, skin)}' is invalid
|
|
62
|
+
errors.push(`Component skin '${relative(root, skin)}' is invalid KUI XML: ${message}`);
|
|
71
63
|
continue;
|
|
72
64
|
}
|
|
73
65
|
components.push({
|
|
@@ -124,7 +116,7 @@ function sourcePairKey(sourceDir, file) {
|
|
|
124
116
|
return toPosix(path.relative(sourceDir, file).slice(0, -'.ts'.length));
|
|
125
117
|
}
|
|
126
118
|
function skinPairKey(skinDir, file) {
|
|
127
|
-
return toPosix(path.relative(skinDir, file).slice(0, -'Skin.
|
|
119
|
+
return toPosix(path.relative(skinDir, file).slice(0, -'Skin.kui.xml'.length));
|
|
128
120
|
}
|
|
129
121
|
function hasNamedClassExport(source, name) {
|
|
130
122
|
source = stripComments(source);
|