@kurot/core 2.1.1 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/README.md +37 -2
  3. package/dist/kurot/display/DisplayObject.d.ts +2 -1
  4. package/dist/kurot/display/DisplayObject.d.ts.map +1 -1
  5. package/dist/kurot/display/DisplayObject.js.map +1 -1
  6. package/dist/kurot/player/canvas/CanvasRenderer.d.ts +2 -0
  7. package/dist/kurot/player/canvas/CanvasRenderer.d.ts.map +1 -1
  8. package/dist/kurot/player/canvas/CanvasRenderer.js +37 -1
  9. package/dist/kurot/player/canvas/CanvasRenderer.js.map +1 -1
  10. package/dist/kurot/player/pipes/BitmapTextPipe.d.ts +20 -0
  11. package/dist/kurot/player/pipes/BitmapTextPipe.d.ts.map +1 -0
  12. package/dist/kurot/player/pipes/BitmapTextPipe.js +27 -0
  13. package/dist/kurot/player/pipes/BitmapTextPipe.js.map +1 -0
  14. package/dist/kurot/player/pipes/index.d.ts +2 -0
  15. package/dist/kurot/player/pipes/index.d.ts.map +1 -1
  16. package/dist/kurot/player/pipes/index.js +1 -0
  17. package/dist/kurot/player/pipes/index.js.map +1 -1
  18. package/dist/kurot/player/webgl/WebGLRenderer.d.ts +1 -0
  19. package/dist/kurot/player/webgl/WebGLRenderer.d.ts.map +1 -1
  20. package/dist/kurot/player/webgl/WebGLRenderer.js +8 -0
  21. package/dist/kurot/player/webgl/WebGLRenderer.js.map +1 -1
  22. package/dist/kurot/resource/Resource.d.ts.map +1 -1
  23. package/dist/kurot/resource/Resource.js +4 -0
  24. package/dist/kurot/resource/Resource.js.map +1 -1
  25. package/dist/kurot/resource/ResourceItem.d.ts +1 -0
  26. package/dist/kurot/resource/ResourceItem.d.ts.map +1 -1
  27. package/dist/kurot/resource/ResourceItem.js +1 -0
  28. package/dist/kurot/resource/ResourceItem.js.map +1 -1
  29. package/dist/kurot/resource/analyzers/FontAnalyzer.d.ts +16 -0
  30. package/dist/kurot/resource/analyzers/FontAnalyzer.d.ts.map +1 -0
  31. package/dist/kurot/resource/analyzers/FontAnalyzer.js +75 -0
  32. package/dist/kurot/resource/analyzers/FontAnalyzer.js.map +1 -0
  33. package/dist/kurot/resource/analyzers/index.d.ts +1 -0
  34. package/dist/kurot/resource/analyzers/index.d.ts.map +1 -1
  35. package/dist/kurot/resource/analyzers/index.js +1 -0
  36. package/dist/kurot/resource/analyzers/index.js.map +1 -1
  37. package/dist/kurot/resource/index.d.ts +1 -0
  38. package/dist/kurot/resource/index.d.ts.map +1 -1
  39. package/dist/kurot/resource/index.js +1 -0
  40. package/dist/kurot/resource/index.js.map +1 -1
  41. package/dist/kurot/text/BitmapFont.d.ts +15 -21
  42. package/dist/kurot/text/BitmapFont.d.ts.map +1 -1
  43. package/dist/kurot/text/BitmapFont.js +59 -66
  44. package/dist/kurot/text/BitmapFont.js.map +1 -1
  45. package/dist/kurot/text/BitmapText.d.ts +29 -19
  46. package/dist/kurot/text/BitmapText.d.ts.map +1 -1
  47. package/dist/kurot/text/BitmapText.js +93 -141
  48. package/dist/kurot/text/BitmapText.js.map +1 -1
  49. package/dist/kurot/text/index.d.ts +1 -0
  50. package/dist/kurot/text/index.d.ts.map +1 -1
  51. package/dist/kurot/text/index.js.map +1 -1
  52. package/docs/ai-context.md +22 -7
  53. package/docs/architecture.md +322 -276
  54. package/docs/bitmap-fonts.md +85 -0
  55. package/docs/resource.md +185 -156
  56. package/docs/text-layout.md +8 -6
  57. package/package.json +3 -2
@@ -0,0 +1,85 @@
1
+ # Bitmap fonts
2
+
3
+ Available in Core 2.2.0 with the published `@kurot/bitmap-font ^0.1.0` dependency.
4
+ Package installs and local builds resolve the font kernel from npm. Installed
5
+ Core 2.1.1 does not include FontAnalyzer or BitmapText rendering; update Core and
6
+ the lockfile to receive them. Source versions alone do not confirm publication.
7
+
8
+ A bitmap font is a descriptor plus a full image page. Core owns image loading and
9
+ rendering; @kurot/bitmap-font owns validation, parsing, serialization and layout.
10
+ See [the shared format](../../bitmap-font/docs/format.md).
11
+
12
+ ```ts
13
+ import { BitmapFont, BitmapText, resource } from '@kurot/core';
14
+
15
+ resource.addResource({
16
+ name: 'number_font_fnt',
17
+ type: 'font',
18
+ url: 'resource/assets/font/number_font.fnt',
19
+ });
20
+ const font = await resource.load<BitmapFont>('number_font_fnt');
21
+ const text = new BitmapText();
22
+ text.font = font;
23
+ text.multiline = false;
24
+ text.text = '1,234.56';
25
+ stage.addChild(text);
26
+ ```
27
+
28
+ `font` is a built-in ResourceType and FontAnalyzer. The descriptor's file is
29
+ resolved relative to the descriptor URL, including URLs with queries. Loading
30
+ resolves only after both descriptor and page are ready. Concurrent requests for
31
+ one font share the pending load. A separately configured PNG resource has
32
+ independent ownership; loading it is not required for the font.
33
+
34
+ Supported descriptors: native version-1 JSON, Egret frames JSON, single-page
35
+ unpacked BMFont text. XML/binary/multi-page/channel-packed fonts are unsupported.
36
+ Glyph coordinates must fit a complete, unrotated page texture.
37
+
38
+ ## Direct texture injection and ownership
39
+
40
+ ```ts
41
+ const font = new BitmapFont(pageTexture, descriptor, { ownsTexture: false });
42
+ ```
43
+
44
+ Direct construction owns the page by default, retaining the SpriteSheet lifecycle
45
+ contract. Set ownsTexture=false for a page owned by a project asset cache. Font
46
+ dispose is idempotent, invalidates subsequent getTexture calls, and disposes only
47
+ owned page data. BitmapText borrows the font; removing text never disposes it.
48
+ FontAnalyzer owns its internal page cache and frees it on resource.destroy(name).
49
+ Do not destroy a font while text using it remains displayed.
50
+
51
+ Parsed `font.data` is a deeply frozen snapshot. Changes require a new font; render
52
+ layout caches assume data does not mutate. Glyph subtextures are borrowed views.
53
+
54
+ ## Text metrics and rendering
55
+
56
+ BitmapText has text/font, lineSpacing/letterSpacing, smoothing, multiline,
57
+ left/center/right textAlign and top/middle/bottom verticalAlign. The default is
58
+ multiline=true. Font metrics, fallback spaces, kerning, wrapping and bounds come
59
+ from layoutBitmapText. `getLayout()` and `getGlyphs()` expose borrowed readonly
60
+ layout data, while textWidth/textHeight report admitted line metrics.
61
+ measureText(width?, height?) measures independently without mutating rendered
62
+ constraints or invalidating its cached layout. UI uses it for measurement.
63
+
64
+ Width and height are constraints, not scales; set scaleX/scaleY to resize font
65
+ art. NaN removes a dimension constraint. Height admits complete line boxes;
66
+ multiline=false draws the first hard-separated line without width wrapping.
67
+ Explicit zero height draws nothing. Default textureScaleFactor=1 is required for
68
+ font assets in this initial implementation.
69
+
70
+ WebGL's BitmapTextPipe submits cropped glyph quads to ordinary texture batching,
71
+ with current transforms, alpha, tint, blend, clipping and filters. Canvas uses the
72
+ same layout and glyph geometry, including tint; cacheAsTexture and RenderTexture
73
+ use that Canvas path. Both honor font offsets without allocating child nodes.
74
+ Changing text/font/metrics invalidates layout and rendering, including an
75
+ existing WebGL instruction without a scene rebuild.
76
+
77
+ Core 2.2.0 fixes BitmapText's previous setter-only width/height accessors.
78
+ BitmapText.EMPTY_FACTOR is retained as a deprecated field; per-font spaceAdvance
79
+ now controls fallback spaces. Line-height, trailing-advance and complete-line
80
+ clipping follow the shared
81
+ format contract rather than the old unrendered class's approximate measurements.
82
+
83
+ The matching UI release provides BitmapLabel for native/programmatic skins;
84
+ published UI 3.1.0 does not include it. KUI catalog/CLI adoption is separate;
85
+ existing installed compilers do not gain a new tag automatically.
package/docs/resource.md CHANGED
@@ -1,39 +1,43 @@
1
- # 资源管理器 (Resource Manager)
1
+ # Resource Manager
2
2
 
3
- ## 概述
3
+ ## Overview
4
4
 
5
- Kurot 资源管理器是从 Egret RES 模块现代化迁移而来的异步资源加载与缓存系统。它提供:
5
+ Kurot's resource manager is an asynchronous loading and caching system adapted
6
+ from Egret RES. It provides:
6
7
 
7
- - **async/await API** — 所有加载操作返回 Promise
8
- - **类型安全** — `ResourceType` 枚举 + 泛型 `get<T>()`
9
- - **配置驱动** — 兼容 Egret `resource.json` 格式
10
- - **按组加载** — 并发控制(默认 2 线程)、自动重试(默认 3 次)
11
- - **可扩展** — 自定义 Analyzer 支持新资源类型
12
- - **零外部依赖** — 仅依赖 core 内部的 `net/` 和 `events/`
8
+ - **async/await API** — loading operations return promises.
9
+ - **Type safety** — the `ResourceType` enum and generic `get<T>()` API.
10
+ - **Configuration-driven loading** — support for Egret `resource.json` files.
11
+ - **Group loading** — concurrency control (2 concurrent loads by default) and
12
+ automatic retries (3 retries by default).
13
+ - **Extensibility** — custom analyzers for additional resource types.
14
+ - **Shared font kernel** — FontAnalyzer parses descriptors through
15
+ `@kurot/bitmap-font`; loading uses Core's `net/` and `events/` modules.
13
16
 
14
- ## 目录结构
17
+ ## Directory structure
15
18
 
16
19
  ```
17
20
  packages/core/src/kurot/resource/
18
- ├── index.ts — 统一导出
19
- ├── Resource.ts — 资源管理器主类(单例 + 便捷实例)
20
- ├── ResourceConfig.ts — 配置文件解析
21
- ├── ResourceLoader.ts — 队列加载器(并发 + 重试)
22
- ├── ResourceItem.ts — 资源项定义 + ResourceType 枚举
23
- ├── ResourceEvent.ts — 事件类型定义
21
+ ├── index.ts — public exports
22
+ ├── Resource.ts — resource manager and shared instance
23
+ ├── ResourceConfig.ts — resource configuration parsing
24
+ ├── ResourceLoader.ts — queued loading, concurrency and retries
25
+ ├── ResourceItem.ts — resource items and the ResourceType enum
26
+ ├── ResourceEvent.ts — resource event types
24
27
  └── analyzers/
25
28
  ├── index.ts
26
- ├── AnalyzerBase.ts — 解析器抽象基类
27
- ├── ImageAnalyzer.ts — 图片 → Texture
28
- ├── JsonAnalyzer.ts — JSON 文件 → object
29
- ├── TextAnalyzer.ts — 纯文本 → string
30
- ├── SoundAnalyzer.ts — 音频 → HTMLAudioElement
31
- └── SheetAnalyzer.ts — 精灵表 JSON + 图片 → SpriteSheet
29
+ ├── AnalyzerBase.ts — analyzer base class
30
+ ├── ImageAnalyzer.ts — image → Texture
31
+ ├── JsonAnalyzer.ts — JSON file → object
32
+ ├── TextAnalyzer.ts — plain text → string
33
+ ├── SoundAnalyzer.ts — audio → HTMLAudioElement
34
+ ├── FontAnalyzer.ts — font descriptor + image → BitmapFont
35
+ └── SheetAnalyzer.ts — sprite-sheet JSON + image → SpriteSheet
32
36
  ```
33
37
 
34
- ## 快速开始
38
+ ## Quick start
35
39
 
36
- ### 1. 准备配置文件
40
+ ### 1. Prepare a configuration file
37
41
 
38
42
  ```json
39
43
  // resource.json
@@ -50,100 +54,101 @@ packages/core/src/kurot/resource/
50
54
  }
51
55
  ```
52
56
 
53
- ### 2. 加载与使用
57
+ ### 2. Load and use resources
54
58
 
55
59
  ```typescript
56
60
  import { resource, ResourceType } from '@kurot/core';
57
61
 
58
- // 加载配置
62
+ // Load the configuration.
59
63
  await resource.loadConfig('resource.json', 'assets/');
60
64
 
61
- // 按组加载
65
+ // Load a resource group.
62
66
  await resource.loadGroup('preload');
63
67
 
64
- // 获取缓存的资源(泛型)
68
+ // Read a cached resource with a generic result type.
65
69
  const texture = resource.get<Texture>('bg');
66
70
 
67
- // 异步加载单个资源
71
+ // Load a single resource asynchronously.
68
72
  const data = await resource.load<object>('config');
69
73
 
70
- // 监听加载进度
74
+ // Track this group's loading progress.
71
75
  await resource.loadGroup('game', 0, (loaded, total) => {
72
- console.log(`进度: ${loaded}/${total}`);
76
+ console.log(`Progress: ${loaded}/${total}`);
73
77
  });
74
78
  ```
75
79
 
76
- ## API 参考
80
+ ## API reference
77
81
 
78
- ### Resource 主类
82
+ ### Resource
79
83
 
80
- #### 配置
84
+ #### Configuration
81
85
 
82
- | 方法 | 说明 |
83
- | -------------------------- | -------------------------------------------------- |
84
- | `loadConfig(url, folder?)` | 加载并解析 resource.json,`folder` 为资源 URL 前缀 |
85
- | `addResource(def)` | 动态添加资源定义 `{ name, url, type }` |
86
+ | Method | Description |
87
+ | -------------------------- | -------------------------------------------------------------- |
88
+ | `loadConfig(url, folder?)` | Load and parse resource.json; `folder` prefixes resource URLs. |
89
+ | `addResource(def)` | Add a resource definition `{ name, url, type }` dynamically. |
86
90
 
87
- #### 加载
91
+ #### Loading
88
92
 
89
- | 方法 | 说明 |
90
- | ----------------------------------------- | -------------------------------------------- |
91
- | `loadGroup(name, priority?, onProgress?)` | 按组加载,返回 Promise。已加载的资源自动跳过 |
92
- | `load<T>(name)` | 异步加载单个资源,返回缓存数据 |
93
+ | Method | Description |
94
+ | ----------------------------------------- | ----------------------------------------------------------------- |
95
+ | `loadGroup(name, priority?, onProgress?)` | Load a group and return a promise; skip resources already loaded. |
96
+ | `load<T>(name)` | Load a single resource and return its cached data. |
93
97
 
94
- #### 缓存
98
+ #### Cache and lookup
95
99
 
96
- | 方法 | 说明 |
97
- | ----------------- | ---------------------------------------- |
98
- | `get<T>(name)` | 同步获取缓存资源,未加载返回 `undefined` |
99
- | `hasRes(name)` | 检查资源是否已缓存 |
100
- | `hasGroup(name)` | 检查组是否存在 |
101
- | `getGroupNames()` | 获取所有组名 |
100
+ | Method | Description |
101
+ | ----------------- | ------------------------------------------------------------------------ |
102
+ | `get<T>(name)` | Read a cached resource synchronously; return `undefined` if unavailable. |
103
+ | `hasRes(name)` | Check whether a resource is cached by an analyzer. |
104
+ | `hasGroup(name)` | Check whether a group exists. |
105
+ | `getGroupNames()` | Return all group names. |
102
106
 
103
- #### 销毁
107
+ #### Destruction
104
108
 
105
- | 方法 | 说明 |
106
- | -------------------- | ---------------------- |
107
- | `destroy(name)` | 销毁单个资源,释放缓存 |
108
- | `destroyGroup(name)` | 销毁整组资源 |
109
- | `destroyAll()` | 销毁所有已加载资源 |
109
+ | Method | Description |
110
+ | -------------------- | ----------------------------------------------- |
111
+ | `destroy(name)` | Destroy a resource and release its cached data. |
112
+ | `destroyGroup(name)` | Destroy all resources in a group. |
113
+ | `destroyAll()` | Destroy all loaded resources. |
110
114
 
111
- #### 事件
115
+ #### Events
112
116
 
113
- | 方法 | 说明 |
114
- | ---------------------- | -------------------------------------- |
115
- | `on(type, listener)` | 监听资源事件 |
116
- | `off(type, listener)` | 移除事件监听 |
117
- | `onProgress(callback)` | 便捷进度监听 `(loaded, total) => void` |
117
+ | Method | Description |
118
+ | ---------------------- | ------------------------------------------------------- |
119
+ | `on(type, listener)` | Listen for a resource event. |
120
+ | `off(type, listener)` | Remove an event listener. |
121
+ | `onProgress(callback)` | Register a progress listener `(loaded, total) => void`. |
118
122
 
119
- #### 扩展
123
+ #### Extension
120
124
 
121
- | 方法 | 说明 |
122
- | ---------------------------------- | ------------------------ |
123
- | `registerAnalyzer(type, analyzer)` | 注册自定义资源类型解析器 |
125
+ | Method | Description |
126
+ | ---------------------------------- | ------------------------------------------------ |
127
+ | `registerAnalyzer(type, analyzer)` | Register an analyzer for a custom resource type. |
124
128
 
125
- ### ResourceType 枚举
129
+ ### ResourceType
126
130
 
127
- | 值 | 说明 |
128
- | --------- | --------------------------------- |
129
- | `'image'` | 图片资源,生成 `Texture` |
130
- | `'json'` | JSON 文件,解析为 `object` |
131
- | `'text'` | 纯文本文件,返回 `string` |
132
- | `'sound'` | 音频文件,返回 `HTMLAudioElement` |
133
- | `'sheet'` | 精灵表,返回 `SpriteSheet` |
131
+ | Value | Description |
132
+ | --------- | --------------------------------------------- |
133
+ | `'image'` | Image resource producing a `Texture`. |
134
+ | `'json'` | JSON file parsed as an `object`. |
135
+ | `'text'` | Plain-text file returned as a `string`. |
136
+ | `'sound'` | Audio file returned as an `HTMLAudioElement`. |
137
+ | `'sheet'` | Sprite sheet returned as a `SpriteSheet`. |
138
+ | `'font'` | Bitmap font returned as a `BitmapFont`. |
134
139
 
135
- ### ResourceEventType 事件类型
140
+ ### ResourceEventType
136
141
 
137
- | 事件 | 触发时机 |
138
- | ------------------- | ------------------------ |
139
- | `CONFIG_COMPLETE` | 配置文件加载完成 |
140
- | `CONFIG_LOAD_ERROR` | 配置文件加载失败 |
141
- | `GROUP_COMPLETE` | 资源组全部加载完成 |
142
- | `GROUP_PROGRESS` | 资源组中单个资源加载完成 |
143
- | `GROUP_LOAD_ERROR` | 资源组中有资源加载失败 |
144
- | `ITEM_LOAD_ERROR` | 单个资源加载失败 |
142
+ | Event | Trigger |
143
+ | ------------------- | ----------------------------------------- |
144
+ | `CONFIG_COMPLETE` | Configuration loading completes. |
145
+ | `CONFIG_LOAD_ERROR` | Configuration loading fails. |
146
+ | `GROUP_COMPLETE` | All resources in a group finish loading. |
147
+ | `GROUP_PROGRESS` | A resource in the group finishes loading. |
148
+ | `GROUP_LOAD_ERROR` | A resource in the group fails to load. |
149
+ | `ITEM_LOAD_ERROR` | A single resource fails to load. |
145
150
 
146
- ### ResourceEvent 接口
151
+ ### ResourceEvent
147
152
 
148
153
  ```typescript
149
154
  interface ResourceEvent {
@@ -155,20 +160,20 @@ interface ResourceEvent {
155
160
  }
156
161
  ```
157
162
 
158
- ## 内置解析器
163
+ ## Built-in analyzers
159
164
 
160
165
  ### ImageAnalyzer
161
166
 
162
- 加载图片并创建 `Texture` 对象。销毁时自动调用 `texture.dispose()`。
167
+ Load an image and create a `Texture`. Destruction calls `texture.dispose()`.
163
168
 
164
169
  ```typescript
165
170
  const texture = resource.get<Texture>('bg');
166
- // texture 可直接用于 Bitmap 显示对象
171
+ // Use the texture with a Bitmap display object.
167
172
  ```
168
173
 
169
174
  ### JsonAnalyzer
170
175
 
171
- 通过 `HttpRequest` 加载 JSON 文件并解析为对象。
176
+ Load a JSON file through `HttpRequest` and parse it into an object.
172
177
 
173
178
  ```typescript
174
179
  const config = resource.get<Record<string, unknown>>('config');
@@ -176,15 +181,33 @@ const config = resource.get<Record<string, unknown>>('config');
176
181
 
177
182
  ### TextAnalyzer
178
183
 
179
- 通过 `HttpRequest` 加载纯文本文件。
184
+ Load a plain-text file through `HttpRequest`.
180
185
 
181
186
  ```typescript
182
187
  const text = resource.get<string>('readme');
183
188
  ```
184
189
 
190
+ ### FontAnalyzer (2.2.0)
191
+
192
+ Load a font descriptor and its image page, resolved relative to the descriptor,
193
+ and return a `BitmapFont`. Supported formats are Egret JSON `.fnt`, native JSON
194
+ and single-page, unpacked BMFont text. Concurrent requests for the same font share
195
+ one load. Destroying the font releases its internal page; a separately configured
196
+ PNG resource retains independent ownership. Display objects borrow the font, so
197
+ removing text does not destroy it. See [bitmap fonts](bitmap-fonts.md) for formats,
198
+ texture restrictions and lifecycle contracts.
199
+
200
+ ```typescript
201
+ import { BitmapFont, resource } from '@kurot/core';
202
+
203
+ resource.addResource({ name: 'numbers', type: 'font', url: 'assets/number_font.fnt' });
204
+ const font = await resource.load<BitmapFont>('numbers');
205
+ ```
206
+
185
207
  ### SoundAnalyzer
186
208
 
187
- 加载音频文件,返回 `HTMLAudioElement`。销毁时自动 `pause()` 并释放 `src`。
209
+ Load an audio file and return an `HTMLAudioElement`. Destruction calls `pause()`
210
+ and releases `src`.
188
211
 
189
212
  ```typescript
190
213
  const audio = resource.get<HTMLAudioElement>('bgm');
@@ -193,27 +216,27 @@ audio.play();
193
216
 
194
217
  ### SheetAnalyzer
195
218
 
196
- 加载精灵表(TexturePacker JSON 格式),两步加载:
219
+ Load a sprite sheet in TexturePacker JSON format in two steps:
197
220
 
198
- 1. 加载 JSON 配置获取帧信息和图片路径
199
- 2. 加载关联图片,切割为子纹理
221
+ 1. Load the JSON descriptor to obtain frame data and the image path.
222
+ 2. Load the image and create subtextures.
200
223
 
201
- 支持三种获取方式:
224
+ Resources can be retrieved in three ways:
202
225
 
203
226
  ```typescript
204
- // 获取整个 SpriteSheet
227
+ // Retrieve the complete SpriteSheet.
205
228
  const sheet = resource.get<SpriteSheet>('hero');
206
229
 
207
- // 通过子键名直接获取子纹理
230
+ // Retrieve a subtexture directly by its subkey name.
208
231
  const frame = resource.get<Texture>('hero_idle_01');
209
232
 
210
- // 通过点号语法获取
233
+ // Retrieve a subtexture with dot notation.
211
234
  const frame2 = resource.get<Texture>('hero.idle_01');
212
235
  ```
213
236
 
214
- ## 自定义解析器
237
+ ## Custom analyzers
215
238
 
216
- 继承 `AnalyzerBase` 实现自定义资源类型:
239
+ Extend `AnalyzerBase` to implement a custom resource type:
217
240
 
218
241
  ```typescript
219
242
  import { AnalyzerBase } from '@kurot/core';
@@ -242,92 +265,98 @@ class XmlAnalyzer extends AnalyzerBase {
242
265
  }
243
266
  }
244
267
 
245
- // 注册
268
+ // Register the analyzer.
246
269
  resource.registerAnalyzer('xml', new XmlAnalyzer());
247
270
  ```
248
271
 
249
- ## 队列加载器 (ResourceLoader)
272
+ ## Queued loading (ResourceLoader)
250
273
 
251
- `ResourceLoader` 是内部使用的队列加载器,支持:
274
+ `ResourceLoader` is the internal queue loader. It supports:
252
275
 
253
- - **并发控制** — `threadCount`(默认 2)限制同时加载数
254
- - **自动重试** — `retryCount`(默认 3)次重试后报告失败
255
- - **回调通知** — `onComplete` / `onError` / `onProgress`
276
+ - **Concurrency control** — `threadCount` limits simultaneous loads (default 2).
277
+ - **Automatic retries** — `retryCount` controls retries before reporting failure
278
+ (default 3).
279
+ - **Notifications** — `onComplete`, `onError` and `onProgress` callbacks.
256
280
 
257
- 通常不需要直接使用 `ResourceLoader`,通过 `Resource.loadGroup()` 即可间接使用。
281
+ Applications normally use `Resource.loadGroup()` instead of accessing
282
+ `ResourceLoader` directly.
258
283
 
259
- ## 配置文件格式
284
+ ## Configuration format
260
285
 
261
- ### 标准格式(2.0.0)
286
+ ### Standard format (2.0.0)
262
287
 
263
288
  ```json
264
289
  {
265
290
  "resources": [
266
291
  {
267
- "name": "资源唯一标识",
268
- "type": "image|json|text|sound|sheet",
269
- "url": "相对或绝对路径",
292
+ "name": "uniqueResourceName",
293
+ "type": "image|json|text|sound|sheet|font",
294
+ "url": "relative-or-absolute-path",
270
295
  "subkeys": { "frameName": { "scale9grid": "1,1,2,2" }, "ordinaryFrame": {} }
271
296
  }
272
297
  ],
273
298
  "groups": [
274
299
  {
275
- "name": "组名",
276
- "keys": "逗号分隔的资源名称"
300
+ "name": "groupName",
301
+ "keys": "resource1,resource2"
277
302
  }
278
303
  ]
279
304
  }
280
305
  ```
281
306
 
282
- 当前源码的 `subkeys` 为对象,旧字符串需要在 Editor 中显式刷新图集后再使用。
283
- `scale9grid` 是 Image 编译默认值,Core 不会自动把它应用到任意 Bitmap。
284
- 参见 [资源默认九宫格契约](../../ui-document/docs/resource-nine-slice.md)。
307
+ `subkeys` is an object map. Refresh legacy sheets explicitly in the Editor before
308
+ using old string-based manifests. `scale9grid` supplies Image compilation defaults;
309
+ Core does not apply it automatically to arbitrary Bitmap objects. See the
310
+ [resource nine-slice defaults contract](../../ui-document/docs/resource-nine-slice.md).
285
311
 
286
- ### URL 解析规则
312
+ ### URL resolution
287
313
 
288
- - 包含 `://` 的 URL 视为绝对路径,不做处理
289
- - 其他 URL 会在前面拼接 `loadConfig()` 的 `folder` 参数
314
+ - URLs containing `://` are treated as absolute and left unchanged.
315
+ - Other URLs receive the `folder` prefix passed to `loadConfig()`.
290
316
 
291
- ### 动态创建组
317
+ ### Creating groups dynamically
292
318
 
293
319
  ```typescript
294
320
  import { resource, ResourceConfig } from '@kurot/core';
295
321
 
296
- // 通过 ResourceConfig 的 createGroup 方法
297
- // 注意:这是底层 API,通常通过配置文件定义组
322
+ // Use ResourceConfig.createGroup for low-level group creation.
323
+ // Applications usually define groups in configuration files.
298
324
  ```
299
325
 
300
- ## 与 Egret RES 的对比
301
-
302
- | 维度 | Egret RES | Kurot Resource |
303
- | ---------- | ----------------------- | ----------------------------------- |
304
- | API 风格 | 回调 `compFunc(data)` | `async/await` + Promise |
305
- | 模块化 | 全局 `RES.xxx` | ES Module 导入 |
306
- | 事件系统 | `egret.EventDispatcher` | 轻量 `on/off` 模式 |
307
- | 类型安全 | 大量 `any` | 泛型 `get<T>()` |
308
- | 版本控制 | `VersionController` | 剔除(构建工具处理) |
309
- | XML 解析 | 内置 | 剔除(KUI XML compiler 处理) |
310
- | 国际化 | 内置 | 剔除(不属于资源加载器职责) |
311
- | 解析器类型 | 8 种 | 5 种(Image/Json/Text/Sound/Sheet) |
312
- | 代码量 | ~3,000 行 | ~1,400 行 |
313
-
314
- ### 剔除的功能
315
-
316
- 以下旧版功能被有意剔除:
317
-
318
- - **VersionController** — CDN 版本控制由现代构建工具(Vite/Webpack)处理
319
- - **i18n 国际化** — 不属于资源加载器的职责
320
- - **XML/Bin 分析器** — KUI XML 由 compiler 预处理,Binary 格式初期不需要
321
- - **AnimationAnalyzer** — 初期不需要,后续按需添加
322
- - **FontAnalyzer** — 初期不需要,后续按需添加
323
- - **同步 getRes() 的复杂 sheet 子键查找** — 简化为点号语法
324
-
325
- ## 注意事项
326
-
327
- 1. **并发 `loadGroup` 调用会排队串行执行** — 内部共享一个 `ResourceLoader` 实例,同时调用多个 `loadGroup`(同组或不同组)不会互相覆盖回调或丢失进度;每次调用仍各自独立 resolve/reject,只是底层批次按调用顺序依次执行,不会真正并行加载。
328
-
329
- 2. **`onProgress` 监听器不会自动移除** — 每次 `onProgress()` 调用会添加一个永久监听器。如需一次性监听,请使用 `loadGroup` 的 `onProgress` 参数。
330
-
331
- 3. **Sheet 子键冲突** — 不同精灵表的子纹理名称不应重复,后加载的不会覆盖先加载的同名子键。
332
-
333
- 4. **资源 URL 需要同源或 CORS** — 图片和音频加载受浏览器同源策略限制。
326
+ ## Comparison with Egret RES
327
+
328
+ | Aspect | Egret RES | Kurot Resource |
329
+ | -------------------- | ------------------------- | ------------------------------------ |
330
+ | API style | Callback `compFunc(data)` | `async/await` and promises |
331
+ | Modules | Global `RES.xxx` | ES module imports |
332
+ | Events | `egret.EventDispatcher` | Lightweight `on/off` API |
333
+ | Type safety | Extensive `any` | Generic `get<T>()` |
334
+ | Versioning | `VersionController` | Handled by build tools |
335
+ | XML parsing | Built in | Handled by the KUI XML compiler |
336
+ | Internationalization | Built in | Outside the resource loader's scope |
337
+ | Analyzer types | 8 | 6 (Image/Json/Text/Sound/Sheet/Font) |
338
+ | Code size | Approximately 3,000 lines | Approximately 1,400 lines |
339
+
340
+ ### Omitted features
341
+
342
+ The following legacy features are intentionally omitted:
343
+
344
+ - **VersionController** — modern build tools such as Vite/Webpack handle CDN
345
+ versioning.
346
+ - **i18n** — internationalization is outside the resource loader's scope.
347
+ - **XML/Bin analyzers** — the compiler preprocesses KUI XML; a built-in binary
348
+ analyzer is not included.
349
+ - **AnimationAnalyzer** — not included; a custom analyzer can provide it if needed.
350
+ - **Complex synchronous getRes() sheet-subkey lookup** — replaced by dot notation.
351
+
352
+ ## Usage notes
353
+
354
+ 1. **Concurrent `loadGroup` calls are queued serially.** They share one internal
355
+ `ResourceLoader`. Calls for the same or different groups retain their own
356
+ callbacks and promise results, but the underlying batches run sequentially.
357
+ 2. **`onProgress` listeners are permanent.** For tracking a single load operation,
358
+ use the callback parameter of `loadGroup`.
359
+ 3. **Sheet subkey collisions.** Avoid duplicate subtexture names across sheets;
360
+ later sheets do not replace an earlier sheet's subkey registration.
361
+ 4. **Resource URLs require same-origin access or CORS.** Browser access rules
362
+ apply to images and audio.
@@ -65,13 +65,15 @@ regressions. No resource-manifest or CLI XML-format change is involved.
65
65
 
66
66
  ## Package dependencies
67
67
 
68
- UI 3.1.0 and ui-runtime 0.8.0 declare Core `^2.1.0` in their peer/development
69
- ranges; game 2.0.0 declares `^2.0.0`. Repository examples require Core `^2.1.0`.
70
- These ranges all accept 2.1.1, but installed lockfiles need updating to receive
71
- its nested scroll-clipping fix. CLI templates use `latest`.
68
+ UI 3.1.0 and ui-runtime 0.8.2 declare Core `^2.1.0` in their peer ranges;
69
+ game 2.0.0 declares `^2.0.0`. Their development dependencies and repository
70
+ examples use Core `^2.1.1`, with lockfiles resolving 2.1.1 for its nested
71
+ scroll-clipping fix. CLI templates use `latest`.
72
72
  Label font shrinking calls `invalidateTextMetrics()` and requires Core 2.1.0
73
- or later. Core 2.1.1 preserves that text contract and does not require another
74
- UI, game or ui-runtime release.
73
+ or later. Core 2.2.0 preserves that TextField contract and remains accepted by
74
+ these existing peer ranges. Bitmap-font rendering is separate from TextField;
75
+ see [bitmap fonts](bitmap-fonts.md). The new UI BitmapLabel requires Core 2.2.0
76
+ and its own UI release; published UI 3.1.0 does not contain it.
75
77
 
76
78
  References: [UAX #14 revision 55](https://www.unicode.org/reports/tr14/tr14-55.html),
77
79
  [official corpus](https://www.unicode.org/Public/17.0.0/ucd/auxiliary/LineBreakTest.txt),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kurot/core",
3
- "version": "2.1.1",
3
+ "version": "2.2.0",
4
4
  "description": "Modern rewrite of the Egret game engine — WebGL multi-texture batching, instruction-driven render pipeline, strict TypeScript, Egret-compatible API",
5
5
  "author": "Kelvin <kyia.x52@gmail.com>",
6
6
  "license": "MIT",
@@ -68,6 +68,7 @@
68
68
  "access": "public"
69
69
  },
70
70
  "dependencies": {
71
- "@cto.af/linebreak": "4.0.3"
71
+ "@cto.af/linebreak": "4.0.3",
72
+ "@kurot/bitmap-font": "^0.1.0"
72
73
  }
73
74
  }