@kurot/core 2.2.0 → 2.2.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 CHANGED
@@ -4,6 +4,37 @@ All notable changes to `@kurot/core` are documented here.
4
4
 
5
5
  ---
6
6
 
7
+ ## [2.2.1] — 2026-10-08
8
+
9
+ ### Fixed
10
+
11
+ - Keep Thai/Lao/Khmer dictionary wrapping and alphabetic overflow wrapping
12
+ functional in minified bundles that rename rule functions. Customize LB28 by
13
+ its imported function identity instead of its name.
14
+ - Protect grapheme clusters in normal word wrapping, emergency word wrapping
15
+ and `wordWrap = false`. Family emoji, flags, skin-tone modifiers, combining
16
+ marks and conjuncts stay intact. An oversized cluster can overflow the field
17
+ width rather than being split.
18
+
19
+ ### Internal
20
+
21
+ - Share cached word/grapheme `Intl.Segmenter` instances with the public
22
+ segmentation utilities. Reuse each paragraph's grapheme end offsets between
23
+ ordinary and emergency layout; do not retain text or segment results globally.
24
+ - Keep `@cto.af/linebreak` pinned to 4.0.3 and the default Unicode 17.0 profile
25
+ unchanged. No public API, runtime dependency, resource or KUI format change.
26
+
27
+ ### Tests
28
+
29
+ - Add a minified browser-bundle regression with `keepNames: false`, using
30
+ esbuild as a development dependency only.
31
+ - Cover complete-character wrapping, oversized clusters, rich-text boundaries,
32
+ CRLF source lengths, input hit testing and existing soft-wrap caret affinity.
33
+ - Retain all 19,338 official Unicode 17.0 line-break conformance cases.
34
+ - Verify a packed consumer with published UI 3.2.0 and DragonBones 0.1.0:
35
+ strict declaration checking and a complete minified bundle render correctly
36
+ through Canvas 2D, WebGL 1 and WebGL 2 with `keepNames: false`.
37
+
7
38
  ## [2.2.0] — 2026-10-08
8
39
 
9
40
  ### Added
package/README.md CHANGED
@@ -2,7 +2,21 @@
2
2
 
3
3
  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.
4
4
 
5
- > **Package version: 2.2.0.** Targets ES2022 and evergreen browsers (Chrome / Edge / Firefox / Safari). No IE / old-Android / pre-2022 Safari support shims.
5
+ > **Package version: 2.2.1.** Targets ES2022 and evergreen browsers (Chrome / Edge / Firefox / Safari). No IE / old-Android / pre-2022 Safari support shims.
6
+
7
+ ## Text wrapping fixes in 2.2.1
8
+
9
+ TextField wrapping remains functional when a bundler renames functions.
10
+ Dictionary wrapping and alphabetic overflow no longer depend on Unicode rule
11
+ function names. Both word wrapping and `wordWrap = false` keep grapheme
12
+ clusters intact, including family emoji, flags, skin-tone modifiers and combining
13
+ marks. A cluster wider than the field can overflow intact. Source and input
14
+ indices continue to use UTF-16 offsets.
15
+
16
+ The patch adds no public API, runtime dependency or resource/KUI format change.
17
+ The existing UI 3.2.0, Game 2.0.0, ui-runtime 0.8.2 and DragonBones 0.1.0 peer
18
+ ranges accept it. Update the installed Core version and lockfile to receive
19
+ the fixes; see [text layout](docs/text-layout.md).
6
20
 
7
21
  ## Scroll clipping in 2.1.1
8
22
 
@@ -34,15 +48,14 @@ matching UI release; Core does not expose `textFit` or `minFontSize`.
34
48
  ## Installation
35
49
 
36
50
  ```bash
37
- pnpm add @kurot/core@^2.2.0
51
+ pnpm add @kurot/core@^2.2.1
38
52
  ```
39
53
 
40
- Core 2.2.0 depends on `@kurot/bitmap-font ^0.1.0` for bitmap-font data and shared
41
- layout. Package installation resolves this dependency from npm. UI 3.1.0,
42
- Game 2.0.0 and ui-runtime 0.8.2 accept Core 2.2.0 through their existing peer
43
- ranges. Install those packages separately when the application needs their
44
- capabilities. The new UI BitmapLabel component follows in a separate UI release;
45
- it is absent from UI 3.1.0.
54
+ Core depends on `@kurot/bitmap-font ^0.1.0` for bitmap-font data and shared
55
+ layout. Package installation resolves this dependency from npm. Install other
56
+ Kurot packages separately when the application needs their capabilities.
57
+ Published UI 3.2.0 provides BitmapLabel and requires Core `^2.2.0`;
58
+ UI 3.1.0 does not contain this component.
46
59
 
47
60
  ## Features
48
61
 
@@ -12,6 +12,7 @@ export declare function getDefaultLineBreaks(text: string): LineBreakOpportunity
12
12
  * Dictionary boundaries tailor complex-context scripts (Thai, Lao, Khmer).
13
13
  * Emergency wrapping relaxes alphabetic word protection only; punctuation,
14
14
  * non-breaking spaces and word joiners retain their Unicode constraints.
15
+ * Layout may reuse a paragraph's UTF-16 grapheme ends across both profiles.
15
16
  */
16
- export declare function getWordLineBreaks(text: string, emergency?: boolean): LineBreakOpportunity[];
17
+ export declare function getWordLineBreaks(text: string, emergency?: boolean, graphemeEnds?: readonly number[]): LineBreakOpportunity[];
17
18
  //# sourceMappingURL=LineBreaks.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"LineBreaks.d.ts","sourceRoot":"","sources":["../../../src/kurot/text/LineBreaks.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,oBAAoB;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;CAClB;AAQD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,oBAAoB,EAAE,CAEzE;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,UAAQ,GAAG,oBAAoB,EAAE,CAezF"}
1
+ {"version":3,"file":"LineBreaks.d.ts","sourceRoot":"","sources":["../../../src/kurot/text/LineBreaks.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,oBAAoB;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;CAClB;AAMD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,oBAAoB,EAAE,CAEzE;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAChC,IAAI,EAAE,MAAM,EACZ,SAAS,UAAQ,EACjB,YAAY,GAAE,SAAS,MAAM,EAAkC,GAC7D,oBAAoB,EAAE,CAcxB"}
@@ -1,8 +1,8 @@
1
- import { LineBreak, LineBreakClasses, MAY_BREAK, PASS, Rules } from '@cto.af/linebreak';
1
+ import { LB28, LineBreak, LineBreakClasses, MAY_BREAK, PASS, Rules } from '@cto.af/linebreak';
2
+ import { getGraphemeEndPositions, getWordSegments } from './TextSegmentation.js';
2
3
  const defaultRules = new Rules();
3
4
  const emergencyRules = new Rules();
4
- emergencyRules.removeRule('LB28');
5
- let wordSegmenter;
5
+ emergencyRules.rules = emergencyRules.rules.filter(rule => rule !== LB28);
6
6
  /**
7
7
  * Unicode 17.0 UAX #14 boundaries, expressed as UTF-16 offsets.
8
8
  * The default profile is kept separate from dictionary and overflow tailoring
@@ -15,21 +15,25 @@ export function getDefaultLineBreaks(text) {
15
15
  * Dictionary boundaries tailor complex-context scripts (Thai, Lao, Khmer).
16
16
  * Emergency wrapping relaxes alphabetic word protection only; punctuation,
17
17
  * non-breaking spaces and word joiners retain their Unicode constraints.
18
+ * Layout may reuse a paragraph's UTF-16 grapheme ends across both profiles.
18
19
  */
19
- export function getWordLineBreaks(text, emergency = false) {
20
+ export function getWordLineBreaks(text, emergency = false, graphemeEnds = getGraphemeEndPositions(text)) {
20
21
  const base = emergency ? emergencyRules : defaultRules;
21
22
  if (emergency || !Array.from(text).some(character => isComplexContext(character.codePointAt(0)))) {
22
- return Array.from(base.breaks(text), ({ position, required }) => ({ position, required }));
23
+ return collectProtectedBreaks(base, text, graphemeEnds);
23
24
  }
24
- wordSegmenter ??= new Intl.Segmenter(undefined, { granularity: 'word' });
25
- const boundaries = new Set(Array.from(wordSegmenter.segment(text), segment => segment.index));
25
+ const boundaries = new Set(Array.from(getWordSegments(text), segment => segment.index));
26
26
  const rules = new Rules();
27
- rules.addRuleBefore('LB28', state => {
27
+ rules.rules.splice(rules.rules.indexOf(LB28), 0, state => {
28
28
  return boundaries.has(state.cur.len) && isComplexContext(state.cur.cp) && isComplexContext(state.next.cp)
29
29
  ? MAY_BREAK
30
30
  : PASS;
31
31
  });
32
- return Array.from(rules.breaks(text), ({ position, required }) => ({ position, required }));
32
+ return collectProtectedBreaks(rules, text, graphemeEnds);
33
+ }
34
+ function collectProtectedBreaks(rules, text, graphemeEnds) {
35
+ const boundaries = new Set(graphemeEnds);
36
+ return Array.from(rules.breaks(text), ({ position, required }) => ({ position, required })).filter(point => point.required || boundaries.has(point.position));
33
37
  }
34
38
  function isComplexContext(codePoint) {
35
39
  return codePoint >= 0 && LineBreak.get(codePoint) === LineBreakClasses.SA;
@@ -1 +1 @@
1
- {"version":3,"file":"LineBreaks.js","sourceRoot":"","sources":["../../../src/kurot/text/LineBreaks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAOxF,MAAM,YAAY,GAAG,IAAI,KAAK,EAAE,CAAC;AACjC,MAAM,cAAc,GAAG,IAAI,KAAK,EAAE,CAAC;AACnC,cAAc,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;AAElC,IAAI,aAAyC,CAAC;AAE9C;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAAY;IAChD,OAAO,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;AACpG,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAY,EAAE,SAAS,GAAG,KAAK;IAChE,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,YAAY,CAAC;IACvD,IAAI,SAAS,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,gBAAgB,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAE,CAAC,CAAC,EAAE,CAAC;QACnG,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;IAC5F,CAAC;IAED,aAAa,KAAK,IAAI,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC,CAAC;IACzE,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;IAC9F,MAAM,KAAK,GAAG,IAAI,KAAK,EAAE,CAAC;IAC1B,KAAK,CAAC,aAAa,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE;QACnC,OAAO,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,gBAAgB,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,gBAAgB,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YACxG,CAAC,CAAC,SAAS;YACX,CAAC,CAAC,IAAI,CAAC;IACT,CAAC,CAAC,CAAC;IACH,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;AAC7F,CAAC;AAED,SAAS,gBAAgB,CAAC,SAAiB;IAC1C,OAAO,SAAS,IAAI,CAAC,IAAI,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,gBAAgB,CAAC,EAAE,CAAC;AAC3E,CAAC"}
1
+ {"version":3,"file":"LineBreaks.js","sourceRoot":"","sources":["../../../src/kurot/text/LineBreaks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,gBAAgB,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC9F,OAAO,EAAE,uBAAuB,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAOjF,MAAM,YAAY,GAAG,IAAI,KAAK,EAAE,CAAC;AACjC,MAAM,cAAc,GAAG,IAAI,KAAK,EAAE,CAAC;AACnC,cAAc,CAAC,KAAK,GAAG,cAAc,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;AAE1E;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAAY;IAChD,OAAO,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;AACpG,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAChC,IAAY,EACZ,SAAS,GAAG,KAAK,EACjB,eAAkC,uBAAuB,CAAC,IAAI,CAAC;IAE/D,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,YAAY,CAAC;IACvD,IAAI,SAAS,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,gBAAgB,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAE,CAAC,CAAC,EAAE,CAAC;QACnG,OAAO,sBAAsB,CAAC,IAAI,EAAE,IAAI,EAAE,YAAY,CAAC,CAAC;IACzD,CAAC;IAED,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;IACxF,MAAM,KAAK,GAAG,IAAI,KAAK,EAAE,CAAC;IAC1B,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,EAAE;QACxD,OAAO,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,gBAAgB,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,gBAAgB,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YACxG,CAAC,CAAC,SAAS;YACX,CAAC,CAAC,IAAI,CAAC;IACT,CAAC,CAAC,CAAC;IACH,OAAO,sBAAsB,CAAC,KAAK,EAAE,IAAI,EAAE,YAAY,CAAC,CAAC;AAC1D,CAAC;AAED,SAAS,sBAAsB,CAAC,KAAY,EAAE,IAAY,EAAE,YAA+B;IAC1F,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,YAAY,CAAC,CAAC;IACzC,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,MAAM,CACjG,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,IAAI,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,CACzD,CAAC;AACH,CAAC;AAED,SAAS,gBAAgB,CAAC,SAAiB;IAC1C,OAAO,SAAS,IAAI,CAAC,IAAI,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,gBAAgB,CAAC,EAAE,CAAC;AAC3E,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"TextLineLayout.d.ts","sourceRoot":"","sources":["../../../src/kurot/text/TextLineLayout.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAA6B,MAAM,yBAAyB,CAAC;AAErG,MAAM,WAAW,qBAAqB;IACrC,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;CACjB;AAQD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,YAAY,EAAE,EAAE,OAAO,EAAE,qBAAqB,GAAG,YAAY,EAAE,CAoJxG"}
1
+ {"version":3,"file":"TextLineLayout.d.ts","sourceRoot":"","sources":["../../../src/kurot/text/TextLineLayout.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAA6B,MAAM,yBAAyB,CAAC;AAErG,MAAM,WAAW,qBAAqB;IACrC,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;CACjB;AAQD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,YAAY,EAAE,EAAE,OAAO,EAAE,qBAAqB,GAAG,YAAY,EAAE,CAuJxG"}
@@ -1,5 +1,6 @@
1
1
  import { getWordLineBreaks } from './LineBreaks.js';
2
2
  import { measureText } from './TextMeasurer.js';
3
+ import { getGraphemeEndPositions } from './TextSegmentation.js';
3
4
  /**
4
5
  * Layout uses the complete text so style boundaries cannot create line breaks.
5
6
  * Soft-wrap separator spaces are omitted from painting and measured width,
@@ -39,9 +40,10 @@ export function layoutTextLines(elements, options) {
39
40
  lines.push(line);
40
41
  return;
41
42
  }
43
+ const graphemeEnds = getGraphemeEndPositions(paragraph);
42
44
  const positions = options.wordWrap
43
- ? getWordLineBreaks(paragraph).map(point => start + point.position)
44
- : characterPositions(paragraph).map(position => start + position);
45
+ ? getWordLineBreaks(paragraph, false, graphemeEnds).map(point => start + point.position)
46
+ : graphemeEnds.map(position => start + position);
45
47
  let emergencyPositions;
46
48
  let emergencyIndex = 0;
47
49
  let oversizedBoundary = -1;
@@ -71,7 +73,7 @@ export function layoutTextLines(elements, options) {
71
73
  candidateIndex++;
72
74
  }
73
75
  if (chosen === lineStart) {
74
- emergencyPositions ??= getWordLineBreaks(paragraph, true).map(point => start + point.position);
76
+ emergencyPositions ??= getWordLineBreaks(paragraph, true, graphemeEnds).map(point => start + point.position);
75
77
  const firstBoundary = positions[positionIndex];
76
78
  oversizedBoundary = firstBoundary;
77
79
  while (emergencyPositions[emergencyIndex] <= lineStart) {
@@ -139,13 +141,4 @@ export function layoutTextLines(elements, options) {
139
141
  return { width, height, charNum: end - start, hasNextLine: false, elements: lineElements };
140
142
  }
141
143
  }
142
- function characterPositions(text) {
143
- const positions = [];
144
- let position = 0;
145
- for (const character of text) {
146
- position += character.length;
147
- positions.push(position);
148
- }
149
- return positions;
150
- }
151
144
  //# sourceMappingURL=TextLineLayout.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"TextLineLayout.js","sourceRoot":"","sources":["../../../src/kurot/text/TextLineLayout.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"TextLineLayout.js","sourceRoot":"","sources":["../../../src/kurot/text/TextLineLayout.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export declare function getWordSegments(text: string): Intl.Segments;
2
+ export declare function getGraphemeSegments(text: string): Intl.Segments;
3
+ /**
4
+ * End offsets use UTF-16 units, matching TextField's source and caret indices.
5
+ */
6
+ export declare function getGraphemeEndPositions(text: string): number[];
7
+ //# sourceMappingURL=TextSegmentation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TextSegmentation.d.ts","sourceRoot":"","sources":["../../../src/kurot/text/TextSegmentation.ts"],"names":[],"mappings":"AAGA,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC,QAAQ,CAG3D;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC,QAAQ,CAG/D;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAE9D"}
@@ -0,0 +1,17 @@
1
+ let wordSegmenter;
2
+ let graphemeSegmenter;
3
+ export function getWordSegments(text) {
4
+ wordSegmenter ??= new Intl.Segmenter(undefined, { granularity: 'word' });
5
+ return wordSegmenter.segment(text);
6
+ }
7
+ export function getGraphemeSegments(text) {
8
+ graphemeSegmenter ??= new Intl.Segmenter(undefined, { granularity: 'grapheme' });
9
+ return graphemeSegmenter.segment(text);
10
+ }
11
+ /**
12
+ * End offsets use UTF-16 units, matching TextField's source and caret indices.
13
+ */
14
+ export function getGraphemeEndPositions(text) {
15
+ return Array.from(getGraphemeSegments(text), segment => segment.index + segment.segment.length);
16
+ }
17
+ //# sourceMappingURL=TextSegmentation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TextSegmentation.js","sourceRoot":"","sources":["../../../src/kurot/text/TextSegmentation.ts"],"names":[],"mappings":"AAAA,IAAI,aAAyC,CAAC;AAC9C,IAAI,iBAA6C,CAAC;AAElD,MAAM,UAAU,eAAe,CAAC,IAAY;IAC3C,aAAa,KAAK,IAAI,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC,CAAC;IACzE,OAAO,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC/C,iBAAiB,KAAK,IAAI,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,EAAE,WAAW,EAAE,UAAU,EAAE,CAAC,CAAC;IACjF,OAAO,iBAAiB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AACxC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,uBAAuB,CAAC,IAAY;IACnD,OAAO,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;AACjG,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"WordWrap.d.ts","sourceRoot":"","sources":["../../../src/kurot/text/WordWrap.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAsCH;;;;;;;;GAQG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAsC/C;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAUrD"}
1
+ {"version":3,"file":"WordWrap.d.ts","sourceRoot":"","sources":["../../../src/kurot/text/WordWrap.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AA6BH;;;;;;;;GAQG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAsC/C;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CASrD"}
@@ -8,15 +8,8 @@
8
8
  * Falls back to character-by-character splitting when `Intl.Segmenter` is
9
9
  * unavailable.
10
10
  */
11
- // ── Segmenter (lazy, cached) ────────────────────────────────────────────────
12
- let _segmenter;
11
+ import { getGraphemeSegments, getWordSegments } from './TextSegmentation.js';
13
12
  const hasSegmenter = typeof Intl !== 'undefined' && typeof Intl.Segmenter === 'function';
14
- function getSegmenter() {
15
- if (!_segmenter) {
16
- _segmenter = new Intl.Segmenter(undefined, { granularity: 'word' });
17
- }
18
- return _segmenter;
19
- }
20
13
  // ── Breaking space / newline tables ─────────────────────────────────────────
21
14
  const BREAKING_SPACES = new Set([
22
15
  0x0009, // tab
@@ -50,7 +43,7 @@ export function tokenize(text) {
50
43
  return [];
51
44
  if (hasSegmenter) {
52
45
  const result = [];
53
- for (const seg of getSegmenter().segment(text)) {
46
+ for (const seg of getWordSegments(text)) {
54
47
  const s = seg.segment;
55
48
  if (!s)
56
49
  continue;
@@ -93,9 +86,8 @@ export function tokenize(text) {
93
86
  */
94
87
  export function splitGraphemes(text) {
95
88
  if (hasSegmenter) {
96
- const seg = new Intl.Segmenter(undefined, { granularity: 'grapheme' });
97
89
  const result = [];
98
- for (const s of seg.segment(text)) {
90
+ for (const s of getGraphemeSegments(text)) {
99
91
  result.push(s.segment);
100
92
  }
101
93
  return result;
@@ -1 +1 @@
1
- {"version":3,"file":"WordWrap.js","sourceRoot":"","sources":["../../../src/kurot/text/WordWrap.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"WordWrap.js","sourceRoot":"","sources":["../../../src/kurot/text/WordWrap.ts"],"names":[],"mappings":"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"}
@@ -5,7 +5,8 @@ agent unfamiliar with Kurot does not need to re-derive the architecture from
5
5
  scratch on every session. Treat the package source and its `src/index.ts`
6
6
  barrel as the authority for current behavior and exports.
7
7
 
8
- Package identity: `@kurot/core@2.2.0`. It provides Kurot's scene graph,
8
+ Package identity: `@kurot/core@2.2.1`. This patch is prepared for publication;
9
+ Core 2.2.0 is published. It provides Kurot's scene graph,
9
10
  events, rendering, text, resource, network and media runtime. Rendering uses a
10
11
  flat `InstructionSet + RenderPipe` pipeline. ES2022 / evergreen browsers only
11
12
  with `strict: true`. Two
@@ -42,7 +43,8 @@ src/kurot/
42
43
  │ CustomFilter, MultiPassFilter, BloomFilter. GPU execution in player/webgl/;
43
44
  │ push/pop scene integration in player/pipes/.
44
45
  ├── text/ TextField, BitmapText/BitmapFont, StageText (DOM overlay, INPUT mode only),
45
- │ HtmlTextParser, InputController, TextMeasurer, LineBreaks, TextLineLayout, WordWrap.
46
+ │ HtmlTextParser, InputController, TextMeasurer, TextSegmentation,
47
+ │ LineBreaks, TextLineLayout, WordWrap.
46
48
  ├── resource/ Resource class + `resource` singleton, ResourceLoader, analyzers/
47
49
  │ (Image/Json/Text/Sound/Sheet/Font). Async, resource.json-driven (RES-compatible).
48
50
  ├── net/ HttpRequest, ImageLoader. Low-level; resource/analyzers build on these.
@@ -203,7 +205,7 @@ Re-export order: `events`, `geom`, `utils`, `display`, `net`, `filters`,
203
205
  | Change how instructions are built/executed | `player/webgl/WebGLRenderer.ts`, `player/InstructionSet.ts` |
204
206
  | Add a new resource type/parser | `resource/analyzers/`, register in `Resource.ts` |
205
207
  | Debug a texture-batching issue | `player/webgl/MultiTextureBatcher.ts`, `player/webgl/WebGLDrawCmdManager.ts` |
206
- | Change text layout/wrapping | `text/LineBreaks.ts`, `text/TextLineLayout.ts`, `text/TextMeasurer.ts`; `docs/text-layout.md` |
208
+ | Change text layout/wrapping | `text/LineBreaks.ts`, `text/TextLineLayout.ts`, `text/TextSegmentation.ts`, `text/TextMeasurer.ts`; `docs/text-layout.md` |
207
209
  | Understand dirty-flag propagation | `display/DisplayObject.ts` (`$markDirty`, `$cacheDirtyUp`, `$renderDirtyUp`) |
208
210
  | Run perf tests | `examples/benchmark/`, `pnpm benchmark`; automated Kurot/PixiJS/Egret comparison via `pnpm benchmark:compare` |
209
211
 
@@ -220,6 +222,13 @@ with local index remapping (player/webgl/split-mesh.ts).
220
222
 
221
223
  Word-wrapped text uses Unicode 17.0 UAX #14, dictionary tailoring for SA scripts
222
224
  and alphabetic overflow tailoring. Style runs never introduce break positions.
225
+ Core 2.2.1 tailors rules by imported function identity and filters optional
226
+ breaks through grapheme boundaries. Character wrapping also uses complete
227
+ graphemes. Never introduce a break inside a cluster; an oversized cluster
228
+ overflows intact. The untailored default profile stays unchanged for Unicode
229
+ conformance. `TextSegmentation.ts` shares cached word/grapheme segmenters;
230
+ ordinary and emergency layout reuse a paragraph's UTF-16 grapheme end offsets.
231
+ No text or segmentation results are retained globally. See [text layout](text-layout.md).
223
232
  Automatic-wrap spaces count in source offsets but not painted width. Core's
224
233
  Canvas renderer advances input indices by line.charNum, including hidden spaces
225
234
  and CRLF; do not derive the next line's source offset from painted text lengths.
@@ -254,4 +263,4 @@ The dependency is published @kurot/bitmap-font ^0.1.0, with no local override.
254
263
  BitmapText.measureText() leaves rendered constraints and layout caches unchanged;
255
264
  text borrows the font and the resource/caller retains ownership. Font pages are
256
265
  full, unrotated textures at scale factor 1. Core 2.1.1 does not include these
257
- changes. Source versions alone do not confirm Core publication.
266
+ changes. Core 2.2.0 is published with its registry bitmap-font dependency.
@@ -1,6 +1,6 @@
1
1
  # @kurot/core architecture
2
2
 
3
- > Package version: 2.2.0. See [CHANGELOG.md](../CHANGELOG.md) for release notes.
3
+ > Package version: 2.2.1. 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.
@@ -14,10 +14,16 @@ resources, networking and media runtime. Public APIs follow Egret's
14
14
  `DisplayObject` and event model, while rendering uses a flat
15
15
  `InstructionSet + RenderPipe` pipeline inspired by Pixi.js 8.
16
16
 
17
- Version 2.2.0 uses published `@kurot/bitmap-font ^0.1.0` as the headless font-data
17
+ Since 2.2.0, Core uses published `@kurot/bitmap-font ^0.1.0` as the headless font-data
18
18
  and layout kernel. Core manages font resources, image-page ownership and glyph
19
19
  drawing in both backends. UI components belong to the UI package.
20
20
 
21
+ TextField uses Unicode 17.0 line-break rules with dictionary and overflow
22
+ tailoring. Since 2.2.1, tailoring uses imported rule identities, and layout
23
+ filters optional break positions through `Intl.Segmenter` grapheme boundaries.
24
+ Word and grapheme segmenters are cached; paragraph results remain local to
25
+ each layout. See [text layout](text-layout.md).
26
+
21
27
  | Aspect | Description |
22
28
  | ------------------ | ---------------------------------------------------------- |
23
29
  | Modules | ES modules (`@kurot/core` npm package) |
@@ -96,6 +102,7 @@ packages/core/src/kurot/
96
102
  │ ├── HtmlTextParser.ts # HTML text parsing
97
103
  │ ├── InputController.ts # selection, caret and keyboard input
98
104
  │ ├── TextMeasurer.ts # measureText and getFontString
105
+ │ ├── TextSegmentation.ts # shared cached word/grapheme segmenters and UTF-16 boundaries
99
106
  │ ├── LineBreaks.ts # Unicode 17.0 UAX #14 boundaries and dictionary segmentation
100
107
  │ ├── TextLineLayout.ts # rich-text wrapping, width fitting and UTF-16 source offsets
101
108
  │ ├── WordWrap.ts # independent token and grapheme utilities
@@ -10,6 +10,10 @@ additional wrap opportunities.
10
10
  and closing punctuation rules rather than treating dictionary words as units.
11
11
  - Thai, Lao and Khmer add dictionary boundaries through the browser's
12
12
  `Intl.Segmenter`. The default Unicode rules remain independently testable.
13
+ - Since Core 2.2.1, optional word and emergency break opportunities are filtered
14
+ through `Intl.Segmenter` grapheme boundaries. Emoji ZWJ sequences, flags,
15
+ skin-tone modifiers, combining marks and conjuncts stay intact. A grapheme
16
+ wider than the field overflows intact rather than being split.
13
17
  - When an alphabetic word is wider than the entire line, emergency wrapping
14
18
  relaxes UAX #14's alphabetic rule LB28. Non-breaking spaces, narrow
15
19
  non-breaking spaces, word joiners and punctuation protection remain in force.
@@ -24,13 +28,18 @@ additional wrap opportunities.
24
28
  - In multiline mode, CRLF, CR, LF, VT, FF, NEL, line separator and paragraph
25
29
  separator force line breaks. A trailing hard separator retains a final empty line.
26
30
 
27
- `wordWrap = false` retains character-based wrapping in multiline mode. Since
31
+ `wordWrap = false` wraps between grapheme clusters in multiline mode since
32
+ Core 2.2.1; earlier releases wrapped between code points. Since
28
33
  Core 2.1.0, explicit `multiline = false` renders only the first
29
34
  hard-separated line without width wrapping. Dynamic text defaults to multiline;
30
35
  INPUT defaults to single-line until the flag is assigned. An unconstrained
31
36
  multiline field measures its hard-separated lines without automatic wrapping.
32
37
  Fixed height clips drawing rather than changing those measured lines.
33
38
 
39
+ Dictionary and grapheme segmentation follow the browser's `Intl` data. The
40
+ pinned Unicode 17.0 tables govern the line-break profile; they do not replace
41
+ the browser's grapheme implementation.
42
+
34
43
  ## Font readiness
35
44
 
36
45
  Load fonts before constructing or measuring text where possible. After a font
@@ -48,7 +57,11 @@ string is retained, including later hard-separated lines hidden in single-line
48
57
  mode. Existing files are not rewritten automatically.
49
58
 
50
59
  `WordWrap.tokenize()` remains a public word-segmentation utility; it is not the
51
- TextField line-break algorithm. `splitGraphemes()` is likewise independent.
60
+ TextField line-break algorithm. `splitGraphemes()` returns complete grapheme
61
+ clusters. These utilities and TextField share cached word/grapheme segmenters.
62
+ Layout computes grapheme end offsets once per constrained paragraph and reuses
63
+ them for ordinary and emergency wrapping. Text and segmentation results are
64
+ not cached globally.
52
65
 
53
66
  ## Validation
54
67
 
@@ -57,6 +70,18 @@ cases against the untailored profile. The compressed fixture includes its
57
70
  source URL, SHA-256 and Unicode license. Dictionary and emergency tailoring,
58
71
  multilingual width fitting, rich text, input offsets and rendering are tested
59
72
  separately in `test/TextWrapping.test.ts`.
73
+ `test/TextGraphemes.test.ts` covers complete-character wrapping, oversized
74
+ clusters, rich-text boundaries, hard separators and UTF-16 input offsets.
75
+ `test/LineBreaks.test.ts` also builds and executes a minified browser bundle
76
+ with `keepNames: false` to verify dictionary, alphabetic, grapheme and
77
+ non-breaking protection. The test environment provides browser APIs without
78
+ Node's `Buffer` global.
79
+
80
+ The 2.2.1 release check installs the packed Core with published UI 3.2.0 and
81
+ DragonBones 0.1.0, checks their declarations together, and renders a complete
82
+ minified browser bundle with `keepNames: false` in Canvas 2D, WebGL 1 and
83
+ WebGL 2. It verifies real-font grapheme layout, dictionary/emergency wrapping,
84
+ BitmapLabel glyphs and an animated native DragonBones mesh.
60
85
 
61
86
  The dependency bundles its Unicode property tables and uses no network or Node
62
87
  runtime APIs. Both WebGL text rasterization and Canvas rendering share this
@@ -65,15 +90,51 @@ regressions. No resource-manifest or CLI XML-format change is involved.
65
90
 
66
91
  ## Package dependencies
67
92
 
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`.
93
+ Published UI 3.2.0 requires Core `^2.2.0` for BitmapLabel. Older UI 3.1.0 and
94
+ ui-runtime 0.8.2 declare Core `^2.1.0`; game 2.0.0 declares `^2.0.0`.
95
+ Existing example lockfiles still resolve Core 2.1.1 and UI 3.1.0; accepting a
96
+ version in a dependency range does not update an installed package.
97
+ DragonBones 0.1.0 declares Core `^2.1.1` and develops against published Core
98
+ 2.2.0. Its animation adapter does not depend on TextField wrapping changes.
99
+ CLI templates use `latest`.
72
100
  Label font shrinking calls `invalidateTextMetrics()` and requires Core 2.1.0
73
- or later. Core 2.2.0 preserves that TextField contract and remains accepted by
101
+ or later. Core 2.2.1 preserves that TextField contract and remains accepted by
74
102
  these existing peer ranges. Bitmap-font rendering is separate from TextField;
75
103
  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.
104
+ and published UI 3.2.0; published UI 3.1.0 does not contain it.
105
+
106
+ Current consumers still need an installed-version update after 2.2.1 is published:
107
+
108
+ | Consumer | Current Core declaration | Locked or pinned Core | Required update |
109
+ | --- | --- | --- | --- |
110
+ | UI development | `^2.2.0` | 2.2.0 | Refresh the lockfile. |
111
+ | DragonBones development | `2.2.0`; peer `^2.1.1` | 2.2.0 | Update the development pin and lockfile. The peer already accepts 2.2.1. |
112
+ | Game / ui-runtime development | `^2.1.1` | 2.1.1 | Refresh the lockfiles. Their peers already accept 2.2.1. |
113
+ | Engine examples / tentax / copied Reskin project | `^2.1.1` | 2.1.1 | Refresh application lockfiles. |
114
+ | Editor | `2.1.1` | Exact pin 2.1.1 | Update the dependency and rebuild to deliver the fix. |
115
+ | Reskin application / milf-master template | `^2.1.1` | No pnpm lockfile | Update the installation; the declared range accepts 2.2.1. |
116
+
117
+ These consumer packages and applications are not changed by the Core patch.
118
+
119
+ ## Updating from Core 2.2.0 to 2.2.1
120
+
121
+ The 2.2.0 wrapper customizes rules by function name. Minifiers that rename
122
+ functions can silently disable alphabetic overflow tailoring and cause SA-script
123
+ dictionary wrapping to throw `Rule not found: "LB28"`. Core 2.2.1 customizes
124
+ the pinned dependency's rules by imported function identity, so this text path
125
+ no longer requires preserved function names. Kurot CLI's existing
126
+ `keepNames: true` setting remains useful for other name-based consumer APIs;
127
+ this patch does not change the CLI build contract.
128
+
129
+ Passing the official default corpus does not cover every real-text sequence.
130
+ The dependency exposes internal break opportunities for some composed emoji,
131
+ including family ZWJ sequences. Core 2.2.1 filters optional layout opportunities
132
+ through grapheme boundaries and uses those boundaries for character wrapping.
133
+ The untailored default Unicode profile remains unchanged. This affects
134
+ TextField layout without changing DragonBones playback or the separate
135
+ bitmap-font layout contract. No asset or project migration is required; update
136
+ the installed package and lockfile after publication. Source 2.2.1 is prepared
137
+ for publication; Core 2.2.0 is the published release.
77
138
 
78
139
  References: [UAX #14 revision 55](https://www.unicode.org/reports/tr14/tr14-55.html),
79
140
  [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.2.0",
3
+ "version": "2.2.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",
@@ -44,6 +44,7 @@
44
44
  "devDependencies": {
45
45
  "@playwright/test": "1.62.1",
46
46
  "@types/node": "^22.0.0",
47
+ "esbuild": "^0.28.2",
47
48
  "fast-check": "^4.6.0",
48
49
  "happy-dom": "^20.8.9",
49
50
  "pixi.js": "8.20.0",