@kurot/core 2.5.0 → 2.5.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 +42 -2
- package/README.md +25 -10
- package/dist/kurot/text/TextBlockBounds.d.ts +12 -0
- package/dist/kurot/text/TextBlockBounds.d.ts.map +1 -0
- package/dist/kurot/text/TextBlockBounds.js +25 -0
- package/dist/kurot/text/TextBlockBounds.js.map +1 -0
- package/dist/kurot/text/TextRenderBounds.d.ts.map +1 -1
- package/dist/kurot/text/TextRenderBounds.js +5 -2
- package/dist/kurot/text/TextRenderBounds.js.map +1 -1
- package/dist/kurot/text/TextVerticalLayout.d.ts +2 -2
- package/dist/kurot/text/TextVerticalLayout.d.ts.map +1 -1
- package/dist/kurot/text/TextVerticalLayout.js +6 -7
- package/dist/kurot/text/TextVerticalLayout.js.map +1 -1
- package/docs/ai-context.md +17 -12
- package/docs/architecture.md +1 -1
- package/docs/text-layout.md +54 -3
- package/docs/texture-density.md +2 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,10 +4,50 @@ All notable changes to `@kurot/core` are documented here.
|
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
+
## [2.5.1] — 2026-10-10
|
|
8
|
+
|
|
9
|
+
Prepared, not published. The latest verified registry release remains 2.5.0.
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- Decouple dynamic `verticalAlign = "middle"` from `multiline`. Single and
|
|
14
|
+
multiple lines center their complete glyph block, including mixed-size rich
|
|
15
|
+
runs and fallback glyphs. Identical one-line content has the same placement
|
|
16
|
+
in either line mode. Blank rows retain their nominal height and line spacing.
|
|
17
|
+
- Reuse cached block bounds for drawing, link hits and render-only glyph/outline
|
|
18
|
+
padding so nested bitmap caches and WebGL text captures retain centered ink.
|
|
19
|
+
- Preserve stable input row baselines, caret, selection and composition geometry
|
|
20
|
+
in both line modes; preserve top/bottom alignment and nominal measurements.
|
|
21
|
+
|
|
22
|
+
### Compatibility
|
|
23
|
+
|
|
24
|
+
- No new API, dependencies, XML fields or resource format. Existing multiline
|
|
25
|
+
dynamic middle-aligned captions can move to their visual center; changing
|
|
26
|
+
glyphs can translate the block without changing its relative baselines.
|
|
27
|
+
- Unchanged UI, Game, DragonBones, Spine and ui-runtime SDK peers accept this
|
|
28
|
+
patch without version bumps. Applications adopt Core and rebuild explicitly.
|
|
29
|
+
Editor's exact 2.5.0 pin must be changed to adopt it; compatible game ranges
|
|
30
|
+
such as `^2.5.0` need an installation/lock update. CLI and headless packages
|
|
31
|
+
require no release. See [text layout](docs/text-layout.md).
|
|
32
|
+
|
|
33
|
+
### Verification — 2026-10-10
|
|
34
|
+
|
|
35
|
+
- Core 2.5.1 build and all 900 unit tests pass (81 files).
|
|
36
|
+
- All 12 minified browser checks pass in Canvas, WebGL 1/2 at 1×/2×.
|
|
37
|
+
Independent Canvas references verify identical one-row placement in both
|
|
38
|
+
line modes, 24/40/56 px automatic-height captions, multilingual paragraphs,
|
|
39
|
+
wrapping, rich text, blank rows, outlines and nested caches. Input caret,
|
|
40
|
+
selection, composition underline and second-row character hits pass.
|
|
41
|
+
- Package dry-run verifies the 2.5.1 manifest, compiled block-alignment module,
|
|
42
|
+
declarations and updated documentation; `git diff --check` passes.
|
|
43
|
+
No application dependency or SDK peer changes.
|
|
44
|
+
|
|
7
45
|
## [2.5.0] — 2026-10-10
|
|
8
46
|
|
|
9
|
-
|
|
10
|
-
|
|
47
|
+
Published; registry version metadata and latest verified on 2026-10-10.
|
|
48
|
+
CLI 3.6.0 is also published; its game template requires this Core release.
|
|
49
|
+
The published archive downloads through npm pack with matching registry integrity;
|
|
50
|
+
its density API, text baseline module and fractional scissor correction are present.
|
|
11
51
|
|
|
12
52
|
### Added
|
|
13
53
|
|
package/README.md
CHANGED
|
@@ -1,22 +1,38 @@
|
|
|
1
1
|
# @kurot/core
|
|
2
2
|
|
|
3
|
-
**2.5.
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
**2.5.1 is prepared, not published.** It makes dynamic middle alignment
|
|
4
|
+
independent of single/multiline mode. The latest verified registry release is
|
|
5
|
+
2.5.0 (2026-10-10), with source texture density, text baselines, fractional
|
|
6
|
+
viewport fixes and root WebGL target restoration. See [CHANGELOG.md](CHANGELOG.md).
|
|
7
7
|
|
|
8
8
|
A modern rewrite of the Egret game engine. Maintains Egret-compatible display object and event APIs while upgrading the rendering architecture, type safety, and tooling.
|
|
9
9
|
|
|
10
|
-
> **Package version: 2.5.
|
|
10
|
+
> **Package version: 2.5.1 (prepared, not published).** Targets ES2022 and evergreen browsers (Chrome / Edge / Firefox / Safari). No IE / old-Android / pre-2022 Safari support shims.
|
|
11
|
+
|
|
12
|
+
## Unified middle alignment in 2.5.1
|
|
13
|
+
|
|
14
|
+
`multiline` controls hard breaks and wrapping. Dynamic `verticalAlign = "middle"`
|
|
15
|
+
centers the complete glyph block in either line mode, including rich text and
|
|
16
|
+
fallback fonts. Blank rows retain their space; relative baselines and line
|
|
17
|
+
spacing remain unchanged. Identical single-row content centers identically
|
|
18
|
+
with either `multiline` value. Input keeps stable editing rows, including its
|
|
19
|
+
caret, selection and composition underline. Top/bottom alignment and nominal
|
|
20
|
+
measurement sizes retain their contracts.
|
|
21
|
+
|
|
22
|
+
Existing multiline middle-aligned captions may move. After publication,
|
|
23
|
+
adopt Core 2.5.1 and rebuild the application; existing SDK peers accept the patch
|
|
24
|
+
without new releases. This source change does not update installed Editors or
|
|
25
|
+
games. See [text alignment](docs/text-layout.md#middle-alignment-independent-of-line-mode-core-251).
|
|
11
26
|
|
|
12
27
|
## Text alignment correction in 2.5.0
|
|
13
28
|
|
|
14
|
-
|
|
15
|
-
fallback fonts and accents.
|
|
16
|
-
rich runs share an alphabetic baseline.
|
|
29
|
+
Published 2.5.0 centers single-line dynamic middle alignment by measured glyph
|
|
30
|
+
ink, including fallback fonts and accents. Its multiline text and input retain
|
|
31
|
+
font-frame alignment; rich runs share an alphabetic baseline. Version 2.5.1
|
|
32
|
+
extends visual middle alignment to multiline dynamic text. Layout sizes and wrapping stay nominal.
|
|
17
33
|
The existing font-readiness invalidation refreshes these cached metrics.
|
|
18
34
|
See [text alignment](docs/text-layout.md#visual-centering-and-stable-baselines-core-250).
|
|
19
|
-
Install Core 2.5.0
|
|
35
|
+
Install Core 2.5.0 and rebuild to adopt it; published 2.4.0
|
|
20
36
|
does not include the correction. Existing SDK peer ranges require no change.
|
|
21
37
|
|
|
22
38
|
## Bitmap fill correction in 2.3.3
|
|
@@ -123,7 +139,6 @@ matching UI release; Core does not expose `textFit` or `minFontSize`.
|
|
|
123
139
|
## Installation
|
|
124
140
|
|
|
125
141
|
```bash
|
|
126
|
-
# After Core 2.5.0 is published:
|
|
127
142
|
pnpm add @kurot/core@^2.5.0
|
|
128
143
|
```
|
|
129
144
|
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { TextField } from './TextField.js';
|
|
2
|
+
interface TextBlockBounds {
|
|
3
|
+
readonly top: number;
|
|
4
|
+
readonly bottom: number;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Measures the complete glyph block, retaining nominal rows for blank lines.
|
|
8
|
+
* Outlines belong to render padding and do not change alignment.
|
|
9
|
+
*/
|
|
10
|
+
export declare function getTextBlockBounds(field: TextField): TextBlockBounds;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=TextBlockBounds.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TextBlockBounds.d.ts","sourceRoot":"","sources":["../../../src/kurot/text/TextBlockBounds.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAGhD,UAAU,eAAe;IACxB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACxB;AAKD;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,SAAS,GAAG,eAAe,CAkBpE"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// Font, wrapping and line-spacing invalidation replace the field's line array.
|
|
2
|
+
const boundsCache = new WeakMap();
|
|
3
|
+
/**
|
|
4
|
+
* Measures the complete glyph block, retaining nominal rows for blank lines.
|
|
5
|
+
* Outlines belong to render padding and do not change alignment.
|
|
6
|
+
*/
|
|
7
|
+
export function getTextBlockBounds(field) {
|
|
8
|
+
const lines = field.getLinesArr();
|
|
9
|
+
const cached = boundsCache.get(lines);
|
|
10
|
+
if (cached)
|
|
11
|
+
return cached;
|
|
12
|
+
let top = Infinity;
|
|
13
|
+
let bottom = -Infinity;
|
|
14
|
+
let lineTop = 0;
|
|
15
|
+
for (const line of lines) {
|
|
16
|
+
const hasInk = line.inkAscent + line.inkDescent > 0;
|
|
17
|
+
top = Math.min(top, lineTop + (hasInk ? line.baseline - line.inkAscent : 0));
|
|
18
|
+
bottom = Math.max(bottom, lineTop + (hasInk ? line.baseline + line.inkDescent : line.height));
|
|
19
|
+
lineTop += line.height + field.lineSpacing;
|
|
20
|
+
}
|
|
21
|
+
const bounds = { top: top === Infinity ? 0 : top, bottom: bottom === -Infinity ? 0 : bottom };
|
|
22
|
+
boundsCache.set(lines, bounds);
|
|
23
|
+
return bounds;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=TextBlockBounds.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TextBlockBounds.js","sourceRoot":"","sources":["../../../src/kurot/text/TextBlockBounds.ts"],"names":[],"mappings":"AAQA,+EAA+E;AAC/E,MAAM,WAAW,GAAG,IAAI,OAAO,EAAmC,CAAC;AAEnE;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAgB;IAClD,MAAM,KAAK,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;IAClC,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACtC,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAE1B,IAAI,GAAG,GAAG,QAAQ,CAAC;IACnB,IAAI,MAAM,GAAG,CAAC,QAAQ,CAAC;IACvB,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QAC1B,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC;QACpD,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC7E,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;QAC9F,OAAO,IAAI,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,WAAW,CAAC;IAC5C,CAAC;IAED,MAAM,MAAM,GAAG,EAAE,GAAG,EAAE,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IAC9F,WAAW,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAC/B,OAAO,MAAM,CAAC;AACf,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TextRenderBounds.d.ts","sourceRoot":"","sources":["../../../src/kurot/text/TextRenderBounds.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"TextRenderBounds.d.ts","sourceRoot":"","sources":["../../../src/kurot/text/TextRenderBounds.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAKhD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,SAAS,GAAG,MAAM,CAuBjE"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getTextBlockBounds } from './TextBlockBounds.js';
|
|
1
2
|
import { TextFieldType } from './enums/TextFieldType.js';
|
|
2
3
|
import { VerticalAlign } from './enums/VerticalAlign.js';
|
|
3
4
|
/**
|
|
@@ -9,10 +10,12 @@ export function getTextRenderPadding(textField) {
|
|
|
9
10
|
return 0;
|
|
10
11
|
let stroke = 0;
|
|
11
12
|
let overhang = 0;
|
|
13
|
+
const bounds = getTextBlockBounds(textField);
|
|
14
|
+
const baselineShift = textField.verticalAlign === VerticalAlign.MIDDLE
|
|
15
|
+
? (textField.textHeight - bounds.top - bounds.bottom) / 2 : 0;
|
|
12
16
|
for (const line of textField.getLinesArr()) {
|
|
13
17
|
if (line.inkAscent + line.inkDescent > 0) {
|
|
14
|
-
const baseline =
|
|
15
|
-
? (line.height + line.inkAscent - line.inkDescent) / 2 : line.baseline;
|
|
18
|
+
const baseline = line.baseline + baselineShift;
|
|
16
19
|
overhang = Math.max(overhang, line.inkAscent - baseline, baseline + line.inkDescent - line.height);
|
|
17
20
|
}
|
|
18
21
|
for (const element of line.elements) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TextRenderBounds.js","sourceRoot":"","sources":["../../../src/kurot/text/TextRenderBounds.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAEzD;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,SAAoB;IACxD,IAAI,SAAS,CAAC,IAAI,KAAK,aAAa,CAAC,KAAK;QAAE,OAAO,CAAC,CAAC;IAErD,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,
|
|
1
|
+
{"version":3,"file":"TextRenderBounds.js","sourceRoot":"","sources":["../../../src/kurot/text/TextRenderBounds.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAEzD;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,SAAoB;IACxD,IAAI,SAAS,CAAC,IAAI,KAAK,aAAa,CAAC,KAAK;QAAE,OAAO,CAAC,CAAC;IAErD,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,MAAM,MAAM,GAAG,kBAAkB,CAAC,SAAS,CAAC,CAAC;IAC7C,MAAM,aAAa,GAAG,SAAS,CAAC,aAAa,KAAK,aAAa,CAAC,MAAM;QACrE,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,GAAG,MAAM,CAAC,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/D,KAAK,MAAM,IAAI,IAAI,SAAS,CAAC,WAAW,EAAE,EAAE,CAAC;QAC5C,IAAI,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,UAAU,GAAG,CAAC,EAAE,CAAC;YAC1C,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,GAAG,aAAa,CAAC;YAC/C,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,GAAG,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;QACpG,CAAC;QACD,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YACrC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,EAAE,MAAM,IAAI,SAAS,CAAC,MAAM,CAAC;YACxD,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,MAAM,EAAE,CAAC;gBAC9C,MAAM,GAAG,KAAK,CAAC;YAChB,CAAC;QACF,CAAC;IACF,CAAC;IAED,yEAAyE;IACzE,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACpG,CAAC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { TextField } from './TextField.js';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
3
|
+
* Dynamic middle alignment centers the complete glyph block independently of
|
|
4
|
+
* multiline. Input retains nominal rows for stable editing geometry.
|
|
5
5
|
*/
|
|
6
6
|
export declare function getTextVerticalOffset(field: TextField): number;
|
|
7
7
|
//# sourceMappingURL=TextVerticalLayout.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TextVerticalLayout.d.ts","sourceRoot":"","sources":["../../../src/kurot/text/TextVerticalLayout.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"TextVerticalLayout.d.ts","sourceRoot":"","sources":["../../../src/kurot/text/TextVerticalLayout.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAKhD;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,CAa9D"}
|
|
@@ -1,17 +1,16 @@
|
|
|
1
|
+
import { getTextBlockBounds } from './TextBlockBounds.js';
|
|
1
2
|
import { TextFieldType } from './enums/TextFieldType.js';
|
|
2
3
|
import { VerticalAlign } from './enums/VerticalAlign.js';
|
|
3
4
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
5
|
+
* Dynamic middle alignment centers the complete glyph block independently of
|
|
6
|
+
* multiline. Input retains nominal rows for stable editing geometry.
|
|
6
7
|
*/
|
|
7
8
|
export function getTextVerticalOffset(field) {
|
|
8
|
-
const lines = field.getLinesArr();
|
|
9
9
|
const height = !isNaN(field.$explicitHeight) ? field.$explicitHeight : field.textHeight;
|
|
10
|
-
const line = lines[0];
|
|
11
10
|
if (field.verticalAlign === VerticalAlign.MIDDLE) {
|
|
12
|
-
if (field.type === TextFieldType.DYNAMIC
|
|
13
|
-
|
|
14
|
-
return (height -
|
|
11
|
+
if (field.type === TextFieldType.DYNAMIC) {
|
|
12
|
+
const bounds = getTextBlockBounds(field);
|
|
13
|
+
return (height - bounds.top - bounds.bottom) / 2;
|
|
15
14
|
}
|
|
16
15
|
return Math.max(0, (height - field.textHeight) / 2);
|
|
17
16
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TextVerticalLayout.js","sourceRoot":"","sources":["../../../src/kurot/text/TextVerticalLayout.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAEzD;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CAAC,KAAgB;IACrD,MAAM,
|
|
1
|
+
{"version":3,"file":"TextVerticalLayout.js","sourceRoot":"","sources":["../../../src/kurot/text/TextVerticalLayout.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAEzD;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CAAC,KAAgB;IACrD,MAAM,MAAM,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC;IACxF,IAAI,KAAK,CAAC,aAAa,KAAK,aAAa,CAAC,MAAM,EAAE,CAAC;QAClD,IAAI,KAAK,CAAC,IAAI,KAAK,aAAa,CAAC,OAAO,EAAE,CAAC;YAC1C,MAAM,MAAM,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC;YACzC,OAAO,CAAC,MAAM,GAAG,MAAM,CAAC,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAClD,CAAC;QACD,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,MAAM,GAAG,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;IACrD,CAAC;IACD,IAAI,KAAK,CAAC,aAAa,KAAK,aAAa,CAAC,MAAM,EAAE,CAAC;QAClD,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC,UAAU,CAAC,CAAC;IAC/C,CAAC;IACD,OAAO,CAAC,CAAC;AACV,CAAC"}
|
package/docs/ai-context.md
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# @kurot/core — AI context map
|
|
2
2
|
|
|
3
|
-
Core 2.5.
|
|
4
|
-
|
|
3
|
+
Core 2.5.1 is prepared, not published, with dynamic middle alignment independent
|
|
4
|
+
of multiline. Core 2.5.0 remains the latest verified registry release
|
|
5
|
+
(2026-10-10). Read
|
|
5
6
|
[centered flips](../../../docs/centered-flips.md) before changing transforms,
|
|
6
7
|
reflection frames, authored flags or dependency adoption.
|
|
7
8
|
|
|
@@ -15,7 +16,7 @@ agent unfamiliar with Kurot does not need to re-derive the architecture from
|
|
|
15
16
|
scratch on every session. Treat the package source and its `src/index.ts`
|
|
16
17
|
barrel as the authority for current behavior and exports.
|
|
17
18
|
|
|
18
|
-
Package identity: `@kurot/core@2.5.
|
|
19
|
+
Package identity: `@kurot/core@2.5.1`, prepared, not published. It provides Kurot's scene graph,
|
|
19
20
|
events, rendering, text, resource, network and media runtime. Rendering uses a
|
|
20
21
|
flat `InstructionSet + RenderPipe` pipeline. ES2022 / evergreen browsers only
|
|
21
22
|
with `strict: true`. Two
|
|
@@ -53,7 +54,7 @@ src/kurot/
|
|
|
53
54
|
│ push/pop scene integration in player/pipes/.
|
|
54
55
|
├── text/ TextField, BitmapText/BitmapFont, StageText (DOM overlay, INPUT mode only),
|
|
55
56
|
│ HtmlTextParser, InputController, TextMeasurer, TextSegmentation,
|
|
56
|
-
│ LineBreaks, TextLineLayout, WordWrap.
|
|
57
|
+
│ LineBreaks, TextLineLayout, TextBlockBounds, TextVerticalLayout, WordWrap.
|
|
57
58
|
├── resource/ Resource class + `resource` singleton, ResourceLoader, analyzers/
|
|
58
59
|
│ (Image/Json/Text/Sound/Sheet/Font). Async, resource.json-driven (RES-compatible).
|
|
59
60
|
├── net/ HttpRequest, ImageLoader. Low-level; resource/analyzers build on these.
|
|
@@ -227,7 +228,7 @@ Re-export order: `events`, `geom`, `utils`, `display`, `net`, `filters`,
|
|
|
227
228
|
| Change how instructions are built/executed | `player/webgl/WebGLRenderer.ts`, `player/InstructionSet.ts` |
|
|
228
229
|
| Add a new resource type/parser | `resource/analyzers/`, register in `Resource.ts` |
|
|
229
230
|
| Debug a texture-batching issue | `player/webgl/MultiTextureBatcher.ts`, `player/webgl/WebGLDrawCmdManager.ts` |
|
|
230
|
-
| Change text layout/wrapping | `text/LineBreaks.ts`, `text/TextLineLayout.ts`, `text/TextSegmentation.ts`, `text/TextMeasurer.ts`; `docs/text-layout.md` |
|
|
231
|
+
| Change text layout/wrapping | `text/LineBreaks.ts`, `text/TextLineLayout.ts`, `text/TextBlockBounds.ts`, `text/TextVerticalLayout.ts`, `text/TextSegmentation.ts`, `text/TextMeasurer.ts`; `docs/text-layout.md` |
|
|
231
232
|
| Understand dirty-flag propagation | `display/DisplayObject.ts` (`$markDirty`, `$cacheDirtyUp`, `$renderDirtyUp`) |
|
|
232
233
|
| Run perf tests | `examples/benchmark/`, `pnpm benchmark`; automated Kurot/PixiJS/Egret comparison via `pnpm benchmark:compare` |
|
|
233
234
|
|
|
@@ -240,17 +241,21 @@ vertices, UVs, or indices, call updateVertices(). WebGL keeps Mesh indices
|
|
|
240
241
|
separate from quad indices and splits oversized meshes into ordered batches
|
|
241
242
|
with local index remapping (player/webgl/split-mesh.ts).
|
|
242
243
|
|
|
243
|
-
## Text alignment in 2.5.
|
|
244
|
+
## Text alignment in 2.5.1
|
|
244
245
|
|
|
245
246
|
`TextLineLayout.ts` caches alphabetic `baseline` and visible `inkAscent` /
|
|
246
|
-
`inkDescent` per line. `
|
|
247
|
-
|
|
248
|
-
|
|
247
|
+
`inkDescent` per line. `TextBlockBounds.ts` caches the union of row glyph bounds,
|
|
248
|
+
using nominal rows for blank lines. `TextVerticalLayout.ts` centers the entire
|
|
249
|
+
dynamic block in either line mode. Multiline only controls line generation;
|
|
250
|
+
input/top/bottom retain nominal alignment with content-independent font frames.
|
|
251
|
+
Relative row baselines and spacing stay stable, but a dynamic middle block can
|
|
252
|
+
translate when its glyph extents change. Canvas, WebGL
|
|
249
253
|
rasterization and link hit testing share the offset. Render bounds add glyph
|
|
250
254
|
margin without changing measurement, input or external clip boundaries. See
|
|
251
|
-
[text layout](text-layout.md#
|
|
252
|
-
Core 2.
|
|
253
|
-
|
|
255
|
+
[text layout](text-layout.md#middle-alignment-independent-of-line-mode-core-251).
|
|
256
|
+
Published Core 2.5.0 centers only single-line dynamic ink. Version 2.5.1 is
|
|
257
|
+
prepared, not published; existing consumer peers accept it without SDK bumps.
|
|
258
|
+
Adoption requires an explicit installation/lock update and rebuild after release.
|
|
254
259
|
|
|
255
260
|
## Text layout in 2.0.1
|
|
256
261
|
|
package/docs/architecture.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @kurot/core architecture
|
|
2
2
|
|
|
3
|
-
> Package version: 2.5.0 (
|
|
3
|
+
> Package version: 2.5.0 (published; registry version metadata verified on 2026-10-10). See [CHANGELOG.md](../CHANGELOG.md) for release notes.
|
|
4
4
|
> The [AI context map](./ai-context.md) covers directories, non-obvious behavior,
|
|
5
5
|
> terminology and task-to-file references. This document explains design choices
|
|
6
6
|
> and internal mechanisms for contributors; the two documents complement each other.
|
package/docs/text-layout.md
CHANGED
|
@@ -40,8 +40,60 @@ Dictionary and grapheme segmentation follow the browser's `Intl` data. The
|
|
|
40
40
|
pinned Unicode 17.0 tables govern the line-break profile; they do not replace
|
|
41
41
|
the browser's grapheme implementation.
|
|
42
42
|
|
|
43
|
+
## Middle alignment independent of line mode (Core 2.5.1)
|
|
44
|
+
|
|
45
|
+
Core 2.5.1 is prepared, not published. The current verified registry release is
|
|
46
|
+
2.5.0. Its single-line-only visual centering is described in the following section.
|
|
47
|
+
|
|
48
|
+
`multiline` controls hard breaks and width wrapping. Dynamic
|
|
49
|
+
`verticalAlign = "middle"` centers the complete laid-out glyph block in either
|
|
50
|
+
line mode. Identical single-row content, font and bounds produce identical
|
|
51
|
+
placement with `multiline = true` or `false`, including automatic height.
|
|
52
|
+
Multiple rows receive one shared translation; their relative alphabetic baselines
|
|
53
|
+
and line spacing are preserved. Rich runs and fallback glyphs participate in the
|
|
54
|
+
same block bounds. Each blank/whitespace-only row contributes its nominal height,
|
|
55
|
+
including leading and trailing blank rows. An entirely blank block uses those
|
|
56
|
+
nominal rows. Outlines remain render-only and do not affect alignment.
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
textField.multiline = true;
|
|
60
|
+
textField.verticalAlign = 'middle';
|
|
61
|
+
textField.text = 'First line\nSecond line';
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
The visible block is centered within the explicit height, or the nominal content
|
|
65
|
+
height when height is automatic. An overflowing dynamic block remains centered;
|
|
66
|
+
ordinary viewport clipping and scrolling still apply. Changing the outer glyph
|
|
67
|
+
extents can translate the complete block, without changing its row baselines or
|
|
68
|
+
distances. The cache reuses block bounds until font/content/wrapping/spacing
|
|
69
|
+
invalidation replaces the line layout.
|
|
70
|
+
|
|
71
|
+
INPUT continues to align its stable editing rows in either line mode. Caret,
|
|
72
|
+
selection, composition underline and pointer-to-character mapping use those rows,
|
|
73
|
+
so changing glyphs cannot move the editing frame. `top` and `bottom` retain their
|
|
74
|
+
nominal-row semantics. `textHeight`, `measureText()`, automatic dimensions, font
|
|
75
|
+
fitting and wrapping measurements retain their existing contracts.
|
|
76
|
+
|
|
77
|
+
Canvas, WebGL text rasterization, link hit tests and glyph/outline capture margins
|
|
78
|
+
share the block alignment. External masks/scrollRect and input viewports keep
|
|
79
|
+
their authored clip boundaries. No new public property, runtime dependency or
|
|
80
|
+
XML/resource format is introduced. Existing multiline dynamic middle-aligned
|
|
81
|
+
captions can move compared with 2.5.0; adopt the released Core patch and rebuild
|
|
82
|
+
the application to receive the change. Existing SDK peers accept the patch.
|
|
83
|
+
|
|
84
|
+
Unit checks cover both line modes, complete paragraphs, mixed-size rich text,
|
|
85
|
+
blank rows, font/spacing invalidation, top/bottom, short viewports, links and
|
|
86
|
+
single/multiline input caret/selection. The minified browser checks compare
|
|
87
|
+
independent Canvas measurements and actual pixels in Canvas and WebGL 1/2 at
|
|
88
|
+
1×/2×, including multilingual text, wrapping, caches, outlines, caret, selection,
|
|
89
|
+
composition decoration and input character hits.
|
|
90
|
+
|
|
43
91
|
## Visual centering and stable baselines (Core 2.5.0)
|
|
44
92
|
|
|
93
|
+
This section records the published 2.5.0 behavior. Version 2.5.1 extends dynamic
|
|
94
|
+
middle alignment to multiple rows as described above; input and top/bottom retain
|
|
95
|
+
the contracts below.
|
|
96
|
+
|
|
45
97
|
Canvas and WebGL use the same alphabetic baseline and logical-pixel Canvas
|
|
46
98
|
`TextMetrics`. Each cached line records `baseline`, `inkAscent` and `inkDescent`;
|
|
47
99
|
rich runs share that baseline, even when their sizes or font families differ.
|
|
@@ -66,11 +118,10 @@ or operating-system offset table is used.
|
|
|
66
118
|
the actual selected glyphs rather than promising identical pixels.
|
|
67
119
|
|
|
68
120
|
See the [Canvas TextMetrics contract](https://html.spec.whatwg.org/multipage/canvas.html#textmetrics).
|
|
69
|
-
The correction is included in Core 2.5.0
|
|
121
|
+
The correction is included in published Core 2.5.0; it is not in
|
|
70
122
|
published Core 2.4.0. There is no new alignment
|
|
71
123
|
property, runtime dependency or XML format. Default KUI single-line control
|
|
72
|
-
labels use the existing flags with symmetric padding. Adopt Core 2.5.0
|
|
73
|
-
publication and rebuild to receive this behavior; SDK peers need no
|
|
124
|
+
labels use the existing flags with symmetric padding. Adopt Core 2.5.0 and rebuild to receive this behavior; SDK peers need no
|
|
74
125
|
incidental change.
|
|
75
126
|
|
|
76
127
|
`test/TextVerticalLayout.test.ts` covers ink centering, mixed sizes, stable input
|
package/docs/texture-density.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Texture density
|
|
2
2
|
|
|
3
|
-
This API is included in Core 2.5.0,
|
|
4
|
-
|
|
3
|
+
This API is included in published Core 2.5.0, with registry version metadata
|
|
4
|
+
verified on 2026-10-10. Published Core 2.4.0 and earlier do not interpret sheet `resolution`.
|
|
5
5
|
|
|
6
6
|
`new Texture(resolution)` describes source pixels per logical unit. The default
|
|
7
7
|
is 1; the value must be finite and positive, is immutable, and is inherited by
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kurot/core",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.1",
|
|
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",
|