@flighthq/shape 0.3.0-next.1220.6982c21 → 0.3.0-next.1248.f867198
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/dist/shapeFill.d.ts.map +1 -1
- package/dist/shapeFill.js +7 -13
- package/dist/shapeFill.js.map +1 -1
- package/dist/shapeStroke.d.ts +2 -2
- package/dist/shapeStroke.d.ts.map +1 -1
- package/dist/shapeStroke.js +12 -76
- package/dist/shapeStroke.js.map +1 -1
- package/package.json +6 -6
- package/src/shapeFill.test.ts +9 -3
- package/src/shapeStroke.test.ts +34 -23
package/dist/shapeFill.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shapeFill.d.ts","sourceRoot":"","sources":["../src/shapeFill.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAe,iBAAiB,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAQtG,wBAAgB,0BAA0B,CACxC,IAAI,EAAE,IAAI,EACV,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,SAAS,iBAAiB,EAAE,EACtC,CAAC,EAAE,MAAM,GACR,IAAI,CAsEN;AAMD,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAc/D;
|
|
1
|
+
{"version":3,"file":"shapeFill.d.ts","sourceRoot":"","sources":["../src/shapeFill.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAe,iBAAiB,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAQtG,wBAAgB,0BAA0B,CACxC,IAAI,EAAE,IAAI,EACV,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,SAAS,iBAAiB,EAAE,EACtC,CAAC,EAAE,MAAM,GACR,IAAI,CAsEN;AAMD,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAc/D;AASD,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,SAAS,iBAAiB,EAAE,GAAG,eAAe,EAAE,GAAG,IAAI,CAuCpG;AAGD,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,SAAS,iBAAiB,EAAE,GAAG,OAAO,CAcpF;AAID,wBAAgB,YAAY,CAAC,QAAQ,EAAE,SAAS,iBAAiB,EAAE,GAAG,OAAO,CAQ5E"}
|
package/dist/shapeFill.js
CHANGED
|
@@ -64,10 +64,9 @@ export function getPathCommandOperandCount(verb) {
|
|
|
64
64
|
// `beginFill … endFill` (or the next fill) span becomes one `ShapeFillRegion` whose `path` carries the
|
|
65
65
|
// geometry (primitives expanded to MOVE/LINE/CURVE verbs, curves kept for the renderer to flatten).
|
|
66
66
|
//
|
|
67
|
-
// Returns `null` when the
|
|
68
|
-
//
|
|
69
|
-
//
|
|
70
|
-
// or strokes.
|
|
67
|
+
// Returns `null` when the fills are not expressible as plain solid regions (gradient/texture fills or
|
|
68
|
+
// textured triangles). Stroke styles are independent: callers that render both layers resolve them
|
|
69
|
+
// through `getShapeStrokeRegions` and fall back when either layer returns `null`.
|
|
71
70
|
export function getShapeFillRegions(commands) {
|
|
72
71
|
if (hasNonSolidShapeFill(commands))
|
|
73
72
|
return null;
|
|
@@ -109,17 +108,13 @@ export function getShapeFillRegions(commands) {
|
|
|
109
108
|
regions.push({ path, color, alpha });
|
|
110
109
|
return regions;
|
|
111
110
|
}
|
|
112
|
-
// True if the command stream uses
|
|
111
|
+
// True if the command stream uses a fill the GPU solid-fill path cannot express.
|
|
113
112
|
export function hasNonSolidShapeFill(commands) {
|
|
114
113
|
let i = 0;
|
|
115
114
|
while (i < commands.length) {
|
|
116
115
|
const name = commands[i];
|
|
117
116
|
const argCount = commands[i + 1];
|
|
118
|
-
if (name === 'beginGradientFill' ||
|
|
119
|
-
name === 'beginTextureFill' ||
|
|
120
|
-
name === 'lineStyle' ||
|
|
121
|
-
name === 'lineGradientStyle' ||
|
|
122
|
-
name === 'lineTextureStyle') {
|
|
117
|
+
if (name === 'beginGradientFill' || name === 'beginTextureFill') {
|
|
123
118
|
return true;
|
|
124
119
|
}
|
|
125
120
|
if (name === 'drawTriangles' && commands[i + 2 + 2] !== null) {
|
|
@@ -129,9 +124,8 @@ export function hasNonSolidShapeFill(commands) {
|
|
|
129
124
|
}
|
|
130
125
|
return false;
|
|
131
126
|
}
|
|
132
|
-
// True if the command stream declares any fill (solid, gradient, or bitmap).
|
|
133
|
-
//
|
|
134
|
-
// needs the raster fallback until the GPU fill + stroke paths compose).
|
|
127
|
+
// True if the command stream declares any fill (solid, gradient, or bitmap). Consumers can distinguish
|
|
128
|
+
// stroke-only Shape streams without rebuilding fill geometry.
|
|
135
129
|
export function hasShapeFill(commands) {
|
|
136
130
|
let i = 0;
|
|
137
131
|
while (i < commands.length) {
|
package/dist/shapeFill.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shapeFill.js","sourceRoot":"","sources":["../src/shapeFill.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"shapeFill.js","sourceRoot":"","sources":["../src/shapeFill.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAEvD,qGAAqG;AACrG,mGAAmG;AACnG,uGAAuG;AACvG,oGAAoG;AACpG,uDAAuD;AACvD,MAAM,UAAU,0BAA0B,CACxC,IAAU,EACV,IAAY,EACZ,QAAsC,EACtC,CAAS;IAET,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,QAAQ;YACX,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAW,EAAE,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAW,CAAC,CAAC;YACtF,MAAM;QACR,KAAK,QAAQ;YACX,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAW,EAAE,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAW,CAAC,CAAC;YACtF,MAAM;QACR,KAAK,SAAS;YACZ,aAAa,CACX,IAAI,EACJ,QAAQ,CAAC,CAAC,CAAW,EACrB,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAW,EACzB,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAW,EACzB,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAW,CAC1B,CAAC;YACF,MAAM;QACR,KAAK,cAAc;YACjB,SAAS,CACP,IAAI,EACJ,QAAQ,CAAC,CAAC,CAAW,EACrB,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAW,EACzB,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAW,EACzB,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAW,EACzB,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAW,EACzB,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAW,CAC1B,CAAC;YACF,MAAM;QACR,KAAK,YAAY;YACf,mBAAmB,CACjB,IAAI,EACJ,QAAQ,CAAC,CAAC,CAAW,EACrB,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAW,EACzB,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAW,EACzB,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAW,CAC1B,CAAC;YACF,MAAM;QACR,KAAK,aAAa,CAAC,CAAC,CAAC;YACnB,MAAM,CAAC,GAAG,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAW,CAAC;YACpC,MAAM,CAAC,GAAG,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAW,CAAC;YACpC,mBAAmB,CAAC,IAAI,EAAG,QAAQ,CAAC,CAAC,CAAY,GAAG,CAAC,GAAG,CAAC,EAAG,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAY,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;YAC9G,MAAM;QACR,CAAC;QACD,KAAK,eAAe;YAClB,qBAAqB,CACnB,IAAI,EACJ,QAAQ,CAAC,CAAC,CAAW,EACrB,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAW,EACzB,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAW,EACzB,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAW,CAC1B,CAAC;YACF,MAAM;QACR,KAAK,oBAAoB;YACvB,0BAA0B,CACxB,IAAI,EACJ,QAAQ,CAAC,CAAC,CAAW,EACrB,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAW,EACzB,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAW,EACzB,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAW,EACxB,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAY,GAAG,CAAC,EAC9B,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAY,GAAG,CAAC,CAChC,CAAC;YACF,MAAM;QACR,KAAK,UAAU;YACb,IAAI,CAAC,OAAO,GAAG,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAgB,CAAC;YAC9C,aAAa,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAsB,EAAE,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAsB,CAAC,CAAC;YAC5F,MAAM;QACR;YACE,MAAM;IACV,CAAC;AACH,CAAC;AAED,sGAAsG;AACtG,wGAAwG;AACxG,2FAA2F;AAC3F,iEAAiE;AACjE,MAAM,UAAU,0BAA0B,CAAC,IAAY;IACrD,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,WAAW,CAAC,OAAO,CAAC;QACzB,KAAK,WAAW,CAAC,OAAO;YACtB,OAAO,CAAC,CAAC;QACX,KAAK,WAAW,CAAC,QAAQ,CAAC;QAC1B,KAAK,WAAW,CAAC,YAAY,CAAC;QAC9B,KAAK,WAAW,CAAC,YAAY;YAC3B,OAAO,CAAC,CAAC;QACX,KAAK,WAAW,CAAC,cAAc;YAC7B,OAAO,CAAC,CAAC;QACX,SAAS,eAAe;YACtB,OAAO,CAAC,CAAC;IACb,CAAC;AACH,CAAC;AAED,gGAAgG;AAChG,uGAAuG;AACvG,oGAAoG;AACpG,EAAE;AACF,sGAAsG;AACtG,mGAAmG;AACnG,kFAAkF;AAClF,MAAM,UAAU,mBAAmB,CAAC,QAAsC;IACxE,IAAI,oBAAoB,CAAC,QAAQ,CAAC;QAAE,OAAO,IAAI,CAAC;IAEhD,MAAM,OAAO,GAAsB,EAAE,CAAC;IACtC,IAAI,IAAI,GAAgB,IAAI,CAAC;IAC7B,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,MAAM,OAAO,GAAgB,SAAS,CAAC;IAEvC,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,OAAO,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC;QAC3B,MAAM,IAAI,GAAG,QAAQ,CAAC,CAAC,CAAW,CAAC;QACnC,MAAM,QAAQ,GAAG,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAW,CAAC;QAC3C,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAChB,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC;QAEjB,QAAQ,IAAI,EAAE,CAAC;YACb,KAAK,WAAW,CAAC,CAAC,CAAC;gBACjB,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC;oBAAE,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;gBACpF,KAAK,GAAG,QAAQ,CAAC,CAAC,CAAW,CAAC;gBAC9B,KAAK,GAAG,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAW,CAAC;gBAClC,IAAI,GAAG,EAAE,QAAQ,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC;gBAC3C,MAAM;YACR,CAAC;YACD,KAAK,SAAS,CAAC,CAAC,CAAC;gBACf,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC;oBAAE,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;gBACpF,IAAI,GAAG,IAAI,CAAC;gBACZ,MAAM;YACR,CAAC;YACD;gBACE,0FAA0F;gBAC1F,sFAAsF;gBACtF,IAAI,IAAI,KAAK,IAAI;oBAAE,0BAA0B,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;gBACvE,MAAM;QACV,CAAC;IACH,CAAC;IAED,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;IACpF,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,oBAAoB,CAAC,QAAsC;IACzE,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,OAAO,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC;QAC3B,MAAM,IAAI,GAAG,QAAQ,CAAC,CAAC,CAAW,CAAC;QACnC,MAAM,QAAQ,GAAG,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAW,CAAC;QAC3C,IAAI,IAAI,KAAK,mBAAmB,IAAI,IAAI,KAAK,kBAAkB,EAAE,CAAC;YAChE,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IAAI,IAAI,KAAK,eAAe,IAAI,QAAQ,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YAC7D,OAAO,IAAI,CAAC;QACd,CAAC;QACD,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC;IACpB,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,uGAAuG;AACvG,8DAA8D;AAC9D,MAAM,UAAU,YAAY,CAAC,QAAsC;IACjE,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,OAAO,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC;QAC3B,MAAM,IAAI,GAAG,QAAQ,CAAC,CAAC,CAAW,CAAC;QACnC,IAAI,IAAI,KAAK,WAAW,IAAI,IAAI,KAAK,mBAAmB,IAAI,IAAI,KAAK,kBAAkB;YAAE,OAAO,IAAI,CAAC;QACrG,CAAC,IAAI,CAAC,GAAI,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAY,CAAC;IACvC,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,KAAK,GAAG,kBAAkB,CAAC;AAEjC,SAAS,mBAAmB,CAAC,IAAU,EAAE,EAAU,EAAE,EAAU,EAAE,EAAU,EAAE,EAAU;IACrF,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,CAAC;IACtB,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC,OAAO,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC;IACjD,SAAS,CAAC,IAAI,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;IACjE,SAAS,CAAC,IAAI,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC;IACjE,SAAS,CAAC,IAAI,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;IACjE,SAAS,CAAC,IAAI,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC;AACnE,CAAC;AAED,yFAAyF;AACzF,SAAS,aAAa,CAAC,IAAU,EAAE,KAAwB,EAAE,IAAuB;IAClF,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACtB,+FAA+F;QAC/F,qGAAqG;QACrG,MAAM,IAAI,GAAG,0BAA0B,CAAC,IAAI,CAAC,CAAC;QAC9C,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACzB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE;YAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAC3D,CAAC,IAAI,IAAI,CAAC;IACZ,CAAC;AACH,CAAC;AAED,SAAS,qBAAqB,CAAC,IAAU,EAAE,CAAS,EAAE,CAAS,EAAE,CAAS,EAAE,CAAS;IACnF,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAC1C,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IAC9C,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAClD,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC9C,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;AAC5C,CAAC;AAED,SAAS,0BAA0B,CACjC,IAAU,EACV,CAAS,EACT,CAAS,EACT,CAAS,EACT,CAAS,EACT,EAAU,EACV,EAAU;IAEV,MAAM,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC;IACpB,MAAM,MAAM,GAAG,CAAC,GAAG,CAAC,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC;IAC/C,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC,OAAO,EAAE,KAAK,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC;IACnD,aAAa,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC;IAC7C,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,EAAE,CAAC,CAAC;IACxD,aAAa,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,GAAG,EAAE,EAAE,MAAM,CAAC,CAAC;IACvD,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE,MAAM,CAAC,CAAC;IACpD,aAAa,CAAC,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,EAAE,CAAC,CAAC;IAC/C,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC;IAC/C,aAAa,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC;AACvC,CAAC;AAED,SAAS,SAAS,CAAC,IAAU,EAAE,GAAW,EAAE,GAAW,EAAE,GAAW,EAAE,GAAW,EAAE,EAAU,EAAE,EAAU;IACvG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC;IAC/C,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;AAC7C,CAAC;AAED,SAAS,aAAa,CAAC,IAAU,EAAE,EAAU,EAAE,EAAU,EAAE,EAAU,EAAE,EAAU;IAC/E,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;IACzC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;AACjC,CAAC;AAED,SAAS,QAAQ,CAAC,IAAU,EAAE,IAAY,EAAE,CAAS,EAAE,CAAS;IAC9D,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACzB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AACvB,CAAC"}
|
package/dist/shapeStroke.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ShapeCommandToken,
|
|
2
|
-
export declare function getShapeStrokeRegions(commands: readonly ShapeCommandToken[]):
|
|
1
|
+
import type { ShapeCommandToken, ShapeStrokeRegion } from '@flighthq/types/contract';
|
|
2
|
+
export declare function getShapeStrokeRegions(commands: readonly ShapeCommandToken[]): ShapeStrokeRegion[] | null;
|
|
3
3
|
export declare function hasNonSolidShapeStroke(commands: readonly ShapeCommandToken[]): boolean;
|
|
4
4
|
//# sourceMappingURL=shapeStroke.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shapeStroke.d.ts","sourceRoot":"","sources":["../src/shapeStroke.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"shapeStroke.d.ts","sourceRoot":"","sources":["../src/shapeStroke.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAQ,iBAAiB,EAAE,iBAAiB,EAAe,MAAM,0BAA0B,CAAC;AAYxG,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,SAAS,iBAAiB,EAAE,GAAG,iBAAiB,EAAE,GAAG,IAAI,CAkExG;AAED,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,SAAS,iBAAiB,EAAE,GAAG,OAAO,CAQtF"}
|
package/dist/shapeStroke.js
CHANGED
|
@@ -1,45 +1,26 @@
|
|
|
1
|
-
import { strokePath } from '@flighthq/path/contract';
|
|
2
1
|
import { PathCommand } from '@flighthq/types/contract';
|
|
3
|
-
import { appendShapeGeometryCommand
|
|
4
|
-
// Resolves
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
// fills use. This replaces the offscreen Canvas-2D raster-to-texture stroke fallback with
|
|
9
|
-
// GPU-tessellated, resolution-independent geometry (sharp when scaled, no per-shape offscreen cost,
|
|
10
|
-
// and no bounds-clipped miter spikes) — and is the first consumer of the otherwise-orphaned strokePath.
|
|
2
|
+
import { appendShapeGeometryCommand } from './shapeFill';
|
|
3
|
+
// Resolves each solid lineStyle span into its authored centerline + stroke style. The backend-neutral
|
|
4
|
+
// tessellateStrokePath consumer turns that pair into non-overlapping triangles for both open strokes and
|
|
5
|
+
// hollow closed rings. Keeping the centerline here also lets a renderer reject pathological geometry
|
|
6
|
+
// with the tessellator's null sentinel and preserve the Shape's Canvas raster fallback.
|
|
11
7
|
//
|
|
12
|
-
// Returns
|
|
13
|
-
//
|
|
14
|
-
// A closed stroke offsets into a hollow RING, and the tessellator fills each contour solid with no hole
|
|
15
|
-
// subtraction, so a ring can't be direct-filled — only an OPEN stroke's outline is a simple fillable
|
|
16
|
-
// polygon. Closure is decided geometrically on the accumulated centerline (a CLOSE verb, or a subpath
|
|
17
|
-
// whose end returns to its start — which covers self-closing rect/ellipse/circle/round-rect primitives,
|
|
18
|
-
// `appendShapePolygon`, a manual return-to-start polyline, and a `drawPath` carrying either), so it is
|
|
19
|
-
// stroke-span-aware: only geometry drawn under an active `lineStyle` reaches a centerline, so an
|
|
20
|
-
// unstroked closed primitive never forces the fallback. Solid open strokes only; ring tessellation (a
|
|
21
|
-
// stroke-strip or stencil-cover route) is a later addition.
|
|
8
|
+
// Returns null only for gradient/bitmap strokes, which the solid mesh path cannot express. Geometry
|
|
9
|
+
// without an active lineStyle never reaches a centerline and cannot force a fallback.
|
|
22
10
|
export function getShapeStrokeRegions(commands) {
|
|
23
11
|
if (hasNonSolidShapeStroke(commands))
|
|
24
12
|
return null;
|
|
25
13
|
const regions = [];
|
|
26
|
-
let centerline = null;
|
|
14
|
+
let centerline = null;
|
|
27
15
|
let style = null;
|
|
28
16
|
let color = 0;
|
|
29
17
|
let alpha = 1;
|
|
30
18
|
let penX = 0;
|
|
31
19
|
let penY = 0;
|
|
32
|
-
let deferred = false; // a stroked span closed into a ring the direct-fill route can't express
|
|
33
20
|
const flush = () => {
|
|
34
21
|
if (style === null || centerline === null || centerline.commands.length === 0)
|
|
35
22
|
return;
|
|
36
|
-
|
|
37
|
-
deferred = true;
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
const outline = strokePath(centerline, style);
|
|
41
|
-
if (outline.commands.length > 0)
|
|
42
|
-
regions.push({ path: outline, color, alpha });
|
|
23
|
+
regions.push({ path: centerline, style, color, alpha });
|
|
43
24
|
};
|
|
44
25
|
let i = 0;
|
|
45
26
|
while (i < commands.length) {
|
|
@@ -48,7 +29,6 @@ export function getShapeStrokeRegions(commands) {
|
|
|
48
29
|
const a = i + 2;
|
|
49
30
|
i = a + argCount;
|
|
50
31
|
if (name === 'lineStyle') {
|
|
51
|
-
// A new stroke style ends the previous span's outline and opens a fresh centerline.
|
|
52
32
|
flush();
|
|
53
33
|
const thickness = commands[a];
|
|
54
34
|
if (thickness > 0) {
|
|
@@ -58,7 +38,7 @@ export function getShapeStrokeRegions(commands) {
|
|
|
58
38
|
const joints = commands[a + 6];
|
|
59
39
|
style = {
|
|
60
40
|
width: thickness,
|
|
61
|
-
// Shape's CapsStyle 'none' is
|
|
41
|
+
// Shape's CapsStyle 'none' is StrokeStyle's butt cap; round/square pass through.
|
|
62
42
|
cap: caps === 'none' ? 'butt' : caps,
|
|
63
43
|
join: joints,
|
|
64
44
|
miterLimit: commands[a + 7],
|
|
@@ -72,15 +52,13 @@ export function getShapeStrokeRegions(commands) {
|
|
|
72
52
|
}
|
|
73
53
|
else if (isShapeGeometryCommand(name)) {
|
|
74
54
|
if (centerline !== null) {
|
|
75
|
-
// A span whose first geometry is a lineTo/curve
|
|
76
|
-
// position, matching Canvas 2D stroking the running path.
|
|
55
|
+
// A span whose first geometry is a lineTo/curve starts from the current pen, matching Canvas.
|
|
77
56
|
if (centerline.commands.length === 0 && name !== 'moveTo') {
|
|
78
57
|
centerline.commands.push(PathCommand.MOVE_TO);
|
|
79
58
|
centerline.data.push(penX, penY);
|
|
80
59
|
}
|
|
81
60
|
appendShapeGeometryCommand(centerline, name, commands, a);
|
|
82
61
|
}
|
|
83
|
-
// Track the pen off the polyline verbs so the next span can seed from it (primitives self-start).
|
|
84
62
|
if (name === 'moveTo' || name === 'lineTo') {
|
|
85
63
|
penX = commands[a];
|
|
86
64
|
penY = commands[a + 1];
|
|
@@ -94,13 +72,10 @@ export function getShapeStrokeRegions(commands) {
|
|
|
94
72
|
penY = commands[a + 5];
|
|
95
73
|
}
|
|
96
74
|
}
|
|
97
|
-
// Fill-style + other non-geometry commands do not affect the stroke centerline.
|
|
98
75
|
}
|
|
99
76
|
flush();
|
|
100
|
-
return
|
|
77
|
+
return regions;
|
|
101
78
|
}
|
|
102
|
-
// True if the stream uses a stroke the GPU outline path cannot express (a gradient or bitmap stroke),
|
|
103
|
-
// so the caller must fall back to the raster path. A solid `lineStyle` is expressible.
|
|
104
79
|
export function hasNonSolidShapeStroke(commands) {
|
|
105
80
|
let i = 0;
|
|
106
81
|
while (i < commands.length) {
|
|
@@ -111,42 +86,6 @@ export function hasNonSolidShapeStroke(commands) {
|
|
|
111
86
|
}
|
|
112
87
|
return false;
|
|
113
88
|
}
|
|
114
|
-
// True if the centerline encloses a region — a CLOSE verb, or any subpath whose end returns to its
|
|
115
|
-
// start (≥2 segments so it bounds area). Such a stroke offsets into a hollow ring the direct-fill
|
|
116
|
-
// tessellator cannot express, so the caller defers the whole shape to raster. Walks the verb/data
|
|
117
|
-
// stream with getPathCommandOperandCount so CLOSE/WIDE verbs keep the data cursor aligned.
|
|
118
|
-
function isCenterlineClosed(path) {
|
|
119
|
-
const { commands, data } = path;
|
|
120
|
-
let d = 0;
|
|
121
|
-
let subStartX = 0;
|
|
122
|
-
let subStartY = 0;
|
|
123
|
-
let lastX = 0;
|
|
124
|
-
let lastY = 0;
|
|
125
|
-
let segments = 0;
|
|
126
|
-
const subpathReturnsToStart = () => segments >= 2 && Math.abs(lastX - subStartX) < CLOSE_EPSILON && Math.abs(lastY - subStartY) < CLOSE_EPSILON;
|
|
127
|
-
for (let c = 0; c < commands.length; c++) {
|
|
128
|
-
const verb = commands[c];
|
|
129
|
-
if (verb === PathCommand.CLOSE)
|
|
130
|
-
return true;
|
|
131
|
-
const n = getPathCommandOperandCount(verb);
|
|
132
|
-
if (verb === PathCommand.MOVE_TO || verb === PathCommand.WIDE_MOVE_TO) {
|
|
133
|
-
if (subpathReturnsToStart())
|
|
134
|
-
return true;
|
|
135
|
-
// A WIDE_MOVE_TO's real endpoint is its trailing (x,y) pair; MOVE_TO's is its only pair.
|
|
136
|
-
lastX = subStartX = data[d + n - 2];
|
|
137
|
-
lastY = subStartY = data[d + n - 1];
|
|
138
|
-
segments = 0;
|
|
139
|
-
}
|
|
140
|
-
else if (n >= 2) {
|
|
141
|
-
// The endpoint of LINE/CURVE/CUBIC/WIDE_LINE is its trailing (x,y) pair.
|
|
142
|
-
lastX = data[d + n - 2];
|
|
143
|
-
lastY = data[d + n - 1];
|
|
144
|
-
segments++;
|
|
145
|
-
}
|
|
146
|
-
d += n;
|
|
147
|
-
}
|
|
148
|
-
return subpathReturnsToStart();
|
|
149
|
-
}
|
|
150
89
|
function isShapeGeometryCommand(name) {
|
|
151
90
|
return (name === 'moveTo' ||
|
|
152
91
|
name === 'lineTo' ||
|
|
@@ -158,7 +97,4 @@ function isShapeGeometryCommand(name) {
|
|
|
158
97
|
name === 'drawRoundRectangle' ||
|
|
159
98
|
name === 'drawPath');
|
|
160
99
|
}
|
|
161
|
-
// Endpoint-coincidence tolerance for return-to-start closure. Authored primitives (rect/ellipse) and
|
|
162
|
-
// polygons re-emit their start coordinate exactly, so this only absorbs trivial float noise.
|
|
163
|
-
const CLOSE_EPSILON = 1e-6;
|
|
164
100
|
//# sourceMappingURL=shapeStroke.js.map
|
package/dist/shapeStroke.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shapeStroke.js","sourceRoot":"","sources":["../src/shapeStroke.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"shapeStroke.js","sourceRoot":"","sources":["../src/shapeStroke.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flighthq/shape",
|
|
3
|
-
"version": "0.3.0-next.
|
|
3
|
+
"version": "0.3.0-next.1248.f867198",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/flighthq/flight.git",
|
|
@@ -36,11 +36,11 @@
|
|
|
36
36
|
"clean:dist": "tsx ../../scripts/clean-package-dist.ts"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@flighthq/scene2d": "0.3.0-next.
|
|
40
|
-
"@flighthq/geometry": "0.3.0-next.
|
|
41
|
-
"@flighthq/node": "0.3.0-next.
|
|
42
|
-
"@flighthq/path": "0.3.0-next.
|
|
43
|
-
"@flighthq/types": "0.3.0-next.
|
|
39
|
+
"@flighthq/scene2d": "0.3.0-next.1248.f867198",
|
|
40
|
+
"@flighthq/geometry": "0.3.0-next.1248.f867198",
|
|
41
|
+
"@flighthq/node": "0.3.0-next.1248.f867198",
|
|
42
|
+
"@flighthq/path": "0.3.0-next.1248.f867198",
|
|
43
|
+
"@flighthq/types": "0.3.0-next.1248.f867198"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"typescript": "^5.3.0"
|
package/src/shapeFill.test.ts
CHANGED
|
@@ -151,14 +151,17 @@ describe('getShapeFillRegions', () => {
|
|
|
151
151
|
expect(getShapeFillRegions(shape.data.commands)).toBeNull();
|
|
152
152
|
});
|
|
153
153
|
|
|
154
|
-
it('
|
|
154
|
+
it('resolves solid fills independently of a solid stroke', () => {
|
|
155
155
|
const shape = createShape();
|
|
156
156
|
appendShapeLineStyle(shape, 2, 0x000000);
|
|
157
157
|
appendShapeBeginFill(shape, 0xff0000);
|
|
158
158
|
appendShapeRectangle(shape, 0, 0, 10, 10);
|
|
159
159
|
appendShapeEndFill(shape);
|
|
160
160
|
|
|
161
|
-
|
|
161
|
+
const regions = getShapeFillRegions(shape.data.commands);
|
|
162
|
+
expect(regions).not.toBeNull();
|
|
163
|
+
expect(regions).toHaveLength(1);
|
|
164
|
+
expect(regions![0].color).toBe(0xff0000);
|
|
162
165
|
});
|
|
163
166
|
});
|
|
164
167
|
|
|
@@ -171,9 +174,12 @@ describe('hasNonSolidShapeFill', () => {
|
|
|
171
174
|
expect(hasNonSolidShapeFill(shape.data.commands)).toBe(false);
|
|
172
175
|
});
|
|
173
176
|
|
|
174
|
-
it('is true
|
|
177
|
+
it('is false for a solid stroke and true for a bitmap or gradient style', () => {
|
|
175
178
|
const shape = createShape();
|
|
176
179
|
appendShapeLineStyle(shape, 1, 0);
|
|
180
|
+
expect(hasNonSolidShapeFill(shape.data.commands)).toBe(false);
|
|
181
|
+
|
|
182
|
+
appendShapeBeginGradientFill(shape, 'linear', [0xff0000, 0x0000ff], [1, 1], [0, 255]);
|
|
177
183
|
expect(hasNonSolidShapeFill(shape.data.commands)).toBe(true);
|
|
178
184
|
});
|
|
179
185
|
});
|
package/src/shapeStroke.test.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { tessellateStrokePath } from '@flighthq/path/contract';
|
|
2
2
|
import type { ShapeCommandToken } from '@flighthq/types/contract';
|
|
3
3
|
import { PathCommand } from '@flighthq/types/contract';
|
|
4
4
|
import { describe, expect, it } from 'vitest';
|
|
@@ -25,25 +25,21 @@ function strokedCorner(join: 'bevel' | 'miter' | 'round', thickness = 20) {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
describe('getShapeStrokeRegions', () => {
|
|
28
|
-
it('
|
|
28
|
+
it('resolves a solid stroke span into one styled centerline carrying its color + alpha', () => {
|
|
29
29
|
const regions = strokedCorner('miter');
|
|
30
30
|
expect(regions).not.toBeNull();
|
|
31
31
|
expect(regions!.length).toBe(1);
|
|
32
32
|
expect(regions![0].color).toBe(0x112233);
|
|
33
33
|
expect(regions![0].alpha).toBe(0.5);
|
|
34
|
-
|
|
34
|
+
expect(regions![0].style).toMatchObject({ width: 20, join: 'miter', cap: 'butt' });
|
|
35
35
|
expect(regions![0].path.commands.length).toBeGreaterThan(0);
|
|
36
36
|
expect(regions![0].path.commands[0]).toBe(PathCommand.MOVE_TO);
|
|
37
37
|
});
|
|
38
38
|
|
|
39
|
-
it('
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
// The corner geometry differs per join: bevel cuts the corner, round arcs it (more points), miter
|
|
44
|
-
// extends it. If joins were ignored (the old raster-clip bug) these would be identical.
|
|
45
|
-
expect(miter).not.toBe(bevel);
|
|
46
|
-
expect(round).toBeGreaterThan(bevel);
|
|
39
|
+
it('preserves miter, bevel, and round styles for the shared stroke tessellator', () => {
|
|
40
|
+
expect(strokedCorner('miter')![0].style.join).toBe('miter');
|
|
41
|
+
expect(strokedCorner('bevel')![0].style.join).toBe('bevel');
|
|
42
|
+
expect(strokedCorner('round')![0].style.join).toBe('round');
|
|
47
43
|
});
|
|
48
44
|
|
|
49
45
|
it('emits no region for a cleared stroke (lineStyle thickness 0) and for a stroke-free shape', () => {
|
|
@@ -73,36 +69,51 @@ describe('getShapeStrokeRegions', () => {
|
|
|
73
69
|
expect(regions![1].color).toBe(0x00ff00);
|
|
74
70
|
});
|
|
75
71
|
|
|
76
|
-
it('tessellates an
|
|
77
|
-
const
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
expect(mesh.indices.length).toBeGreaterThan(0);
|
|
72
|
+
it('tessellates an open styled centerline into a non-empty mesh', () => {
|
|
73
|
+
const region = strokedCorner('miter')![0];
|
|
74
|
+
const mesh = tessellateStrokePath(region.path, region.style);
|
|
75
|
+
expect(mesh).not.toBeNull();
|
|
76
|
+
expect(mesh!.indices.length).toBeGreaterThan(0);
|
|
82
77
|
});
|
|
83
78
|
|
|
84
|
-
it('
|
|
79
|
+
it('resolves and tessellates a closed rectangle as a hollow ring', () => {
|
|
85
80
|
const shape = createShape();
|
|
86
81
|
appendShapeLineStyle(shape, 8, 0xff0000, 1, false, 'normal', 'none', 'miter', 4);
|
|
87
82
|
appendShapeRectangle(shape, 10, 10, 100, 50);
|
|
88
|
-
|
|
83
|
+
const region = getShapeStrokeRegions(shape.data.commands)![0];
|
|
84
|
+
expect(tessellateStrokePath(region.path, region.style)).not.toBeNull();
|
|
89
85
|
});
|
|
90
86
|
|
|
91
|
-
it('
|
|
87
|
+
it('resolves a stroked drawPath carrying a CLOSE verb', () => {
|
|
92
88
|
const shape = createShape();
|
|
93
89
|
appendShapeLineStyle(shape, 6, 0x0000ff, 1, false, 'normal', 'none', 'miter', 4);
|
|
94
90
|
// A triangle subpath closed by an explicit CLOSE verb — a ring, not an open stroke.
|
|
95
91
|
const verbs = [PathCommand.MOVE_TO, PathCommand.LINE_TO, PathCommand.LINE_TO, PathCommand.CLOSE];
|
|
96
92
|
appendShapePath(shape, verbs, [0, 0, 40, 0, 20, 30], 'nonZero');
|
|
97
|
-
|
|
93
|
+
const region = getShapeStrokeRegions(shape.data.commands)![0];
|
|
94
|
+
expect(tessellateStrokePath(region.path, region.style)).not.toBeNull();
|
|
98
95
|
});
|
|
99
96
|
|
|
100
|
-
it('
|
|
97
|
+
it('resolves a stroked return-to-start polygon without a CLOSE verb', () => {
|
|
101
98
|
const shape = createShape();
|
|
102
99
|
appendShapeLineStyle(shape, 6, 0x0000ff, 1, false, 'normal', 'none', 'miter', 4);
|
|
103
100
|
// appendShapePolygon re-emits the first point as a trailing lineTo (return-to-start), no CLOSE verb.
|
|
104
101
|
appendShapePolygon(shape, [0, 0, 50, 0, 25, 40]);
|
|
105
|
-
|
|
102
|
+
const region = getShapeStrokeRegions(shape.data.commands)![0];
|
|
103
|
+
expect(tessellateStrokePath(region.path, region.style)).not.toBeNull();
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('keeps a pathological centerline as a region so the renderer can select raster fallback', () => {
|
|
107
|
+
const shape = createShape();
|
|
108
|
+
appendShapeLineStyle(shape, 6, 0x0000ff, 1, false, 'normal', 'none', 'miter', 4);
|
|
109
|
+
appendShapePath(
|
|
110
|
+
shape,
|
|
111
|
+
[PathCommand.MOVE_TO, PathCommand.LINE_TO, PathCommand.LINE_TO, PathCommand.LINE_TO, PathCommand.CLOSE],
|
|
112
|
+
[0, 0, 40, 40, 0, 40, 40, 0],
|
|
113
|
+
'nonZero',
|
|
114
|
+
);
|
|
115
|
+
const region = getShapeStrokeRegions(shape.data.commands)![0];
|
|
116
|
+
expect(tessellateStrokePath(region.path, region.style)).toBeNull();
|
|
106
117
|
});
|
|
107
118
|
|
|
108
119
|
it('ignores an UNSTROKED closed primitive and still strokes a later open line (span-aware)', () => {
|