@solidtv/renderer 1.2.3 → 1.2.5
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/src/common/CommonTypes.d.ts +0 -5
- package/dist/src/core/CoreTextNode.d.ts +0 -17
- package/dist/src/core/CoreTextNode.js +0 -21
- package/dist/src/core/CoreTextNode.js.map +1 -1
- package/dist/src/core/shaders/canvas/RadialProgress.js +9 -1
- package/dist/src/core/shaders/canvas/RadialProgress.js.map +1 -1
- package/dist/src/core/shaders/templates/RadialProgressTemplate.d.ts +16 -0
- package/dist/src/core/shaders/templates/RadialProgressTemplate.js +11 -0
- package/dist/src/core/shaders/templates/RadialProgressTemplate.js.map +1 -1
- package/dist/src/core/shaders/webgl/RadialProgress.js +30 -10
- package/dist/src/core/shaders/webgl/RadialProgress.js.map +1 -1
- package/dist/src/core/text-rendering/CanvasTextRenderer.js +0 -7
- package/dist/src/core/text-rendering/CanvasTextRenderer.js.map +1 -1
- package/dist/src/core/text-rendering/SdfTextRenderer.js +0 -11
- package/dist/src/core/text-rendering/SdfTextRenderer.js.map +1 -1
- package/dist/src/core/text-rendering/TextRenderer.d.ts +0 -20
- package/dist/src/main-api/Inspector.js +20 -4
- package/dist/src/main-api/Inspector.js.map +1 -1
- package/dist/tsconfig.dist.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/common/CommonTypes.ts +0 -5
- package/src/core/CoreTextNode.ts +0 -22
- package/src/core/shaders/canvas/RadialProgress.ts +10 -1
- package/src/core/shaders/templates/RadialProgressTemplate.test.ts +26 -0
- package/src/core/shaders/templates/RadialProgressTemplate.ts +25 -0
- package/src/core/shaders/webgl/RadialProgress.ts +30 -10
- package/src/core/text-rendering/CanvasTextRenderer.ts +0 -9
- package/src/core/text-rendering/SdfTextRenderer.ts +0 -13
- package/src/core/text-rendering/TextRenderer.ts +0 -20
- package/src/main-api/Inspector.ts +23 -6
|
@@ -9,6 +9,7 @@ import type { WebGlRenderer } from '../../renderers/webgl/WebGlRenderer.js';
|
|
|
9
9
|
|
|
10
10
|
export const RadialProgress: WebGlShaderType<RadialProgressProps> = {
|
|
11
11
|
props: RadialProgressTemplate.props,
|
|
12
|
+
time: true,
|
|
12
13
|
update(node: CoreNode) {
|
|
13
14
|
const props = this.props!;
|
|
14
15
|
|
|
@@ -21,6 +22,8 @@ export const RadialProgress: WebGlShaderType<RadialProgressProps> = {
|
|
|
21
22
|
this.uniform1f('u_progress', props.progress);
|
|
22
23
|
this.uniform1f('u_startAngle', props.startAngle);
|
|
23
24
|
this.uniform1f('u_direction', props.direction);
|
|
25
|
+
this.uniform1f('u_duration', props.duration);
|
|
26
|
+
this.uniform1f('u_countdown', props.countdown);
|
|
24
27
|
this.uniform1fv('u_stops', new Float32Array(props.stops));
|
|
25
28
|
|
|
26
29
|
const colors: number[] = [];
|
|
@@ -61,6 +64,7 @@ export const RadialProgress: WebGlShaderType<RadialProgressProps> = {
|
|
|
61
64
|
#define TWO_PI 6.28318530717958647692
|
|
62
65
|
|
|
63
66
|
uniform float u_alpha;
|
|
67
|
+
uniform float u_time;
|
|
64
68
|
uniform vec2 u_dimensions;
|
|
65
69
|
uniform sampler2D u_texture;
|
|
66
70
|
|
|
@@ -70,6 +74,8 @@ export const RadialProgress: WebGlShaderType<RadialProgressProps> = {
|
|
|
70
74
|
uniform float u_progress;
|
|
71
75
|
uniform float u_startAngle;
|
|
72
76
|
uniform float u_direction;
|
|
77
|
+
uniform float u_duration;
|
|
78
|
+
uniform float u_countdown;
|
|
73
79
|
|
|
74
80
|
uniform float u_stops[MAX_STOPS];
|
|
75
81
|
uniform vec4 u_colors[MAX_STOPS];
|
|
@@ -107,6 +113,13 @@ export const RadialProgress: WebGlShaderType<RadialProgressProps> = {
|
|
|
107
113
|
void main() {
|
|
108
114
|
vec4 base = texture2D(u_texture, v_textureCoords) * v_color;
|
|
109
115
|
|
|
116
|
+
// Effective progress: when u_duration > 0 the shader self-animates from
|
|
117
|
+
// u_time, otherwise we use the static u_progress prop. countdown == 1
|
|
118
|
+
// drains (1 -> 0), countdown == 0 fills (0 -> 1).
|
|
119
|
+
float cyclePos = u_duration > 0.0 ? fract(u_time / u_duration) : 0.0;
|
|
120
|
+
float animProgress = u_countdown > 0.5 ? 1.0 - cyclePos : cyclePos;
|
|
121
|
+
float progress = u_duration > 0.0 ? animProgress : u_progress;
|
|
122
|
+
|
|
110
123
|
vec2 p = v_nodeCoords.xy * u_dimensions - u_center;
|
|
111
124
|
float dist = length(p);
|
|
112
125
|
float halfW = u_width * 0.5;
|
|
@@ -122,39 +135,46 @@ export const RadialProgress: WebGlShaderType<RadialProgressProps> = {
|
|
|
122
135
|
|
|
123
136
|
// Filled arc coverage (1 if in filled arc, else 0). When progress >= 1 the
|
|
124
137
|
// whole ring is filled regardless of \`t\` -- guards against the mod() seam.
|
|
125
|
-
float arcCoverage =
|
|
138
|
+
float arcCoverage = progress >= 1.0 ? 1.0 : step(t, progress);
|
|
126
139
|
float fillCoverage = ringCoverage * arcCoverage;
|
|
127
140
|
|
|
128
141
|
#if CAP_ROUND
|
|
129
142
|
// Round caps: discs of radius halfW at the start and head of the arc
|
|
130
143
|
float a0 = u_startAngle;
|
|
131
|
-
float a1 = u_startAngle + u_direction *
|
|
144
|
+
float a1 = u_startAngle + u_direction * progress * TWO_PI;
|
|
132
145
|
vec2 cap0 = vec2(cos(a0), sin(a0)) * u_radius;
|
|
133
146
|
vec2 cap1 = vec2(cos(a1), sin(a1)) * u_radius;
|
|
134
147
|
float capMask = max(discCoverage(p, cap0, halfW), discCoverage(p, cap1, halfW));
|
|
135
148
|
// Caps only visible when there's something to cap (progress > 0 and < 1).
|
|
136
|
-
float capGate = step(0.0001,
|
|
149
|
+
float capGate = step(0.0001, progress) * step(progress, 0.9999);
|
|
137
150
|
fillCoverage = max(fillCoverage, capMask * capGate);
|
|
138
151
|
#endif
|
|
139
152
|
|
|
140
153
|
// Sample gradient. Normalize \`t\` to the *filled* portion so the gradient
|
|
141
154
|
// spans the visible arc end-to-end regardless of progress.
|
|
142
|
-
float gradT =
|
|
155
|
+
float gradT = progress > 0.0 ? clamp(t / progress, 0.0, 1.0) : 0.0;
|
|
143
156
|
vec4 fillCol = getGradientColor(gradT);
|
|
144
157
|
|
|
145
|
-
// Composite: track under fill (if track enabled), both gated by ringCoverage
|
|
158
|
+
// Composite: track under fill (if track enabled), both gated by ringCoverage.
|
|
159
|
+
// We work in PREMULTIPLIED-alpha space here so AA edges composite cleanly
|
|
160
|
+
// against \`base\` -- mix(base.rgb, layer.rgb, la) with a coverage-scaled
|
|
161
|
+
// \`layer\` would multiply layer.rgb by coverage a second time and darken
|
|
162
|
+
// the AA falloff (see issue #36). The renderer's blend func is
|
|
163
|
+
// (ONE, ONE_MINUS_SRC_ALPHA), which expects premultiplied output.
|
|
164
|
+
vec4 fillPM = vec4(fillCol.rgb * fillCol.a, fillCol.a);
|
|
146
165
|
vec4 layer = vec4(0.0);
|
|
147
166
|
#if HAS_TRACK
|
|
167
|
+
vec4 trackPM = vec4(u_trackColor.rgb * u_trackColor.a, u_trackColor.a);
|
|
148
168
|
float trackCoverage = ringCoverage * (1.0 - fillCoverage);
|
|
149
|
-
layer =
|
|
169
|
+
layer = trackPM * trackCoverage + fillPM * fillCoverage;
|
|
150
170
|
#else
|
|
151
|
-
layer =
|
|
171
|
+
layer = fillPM * fillCoverage;
|
|
152
172
|
#endif
|
|
153
173
|
|
|
154
|
-
//
|
|
155
|
-
//
|
|
174
|
+
// Premultiplied "over": out = src + dst*(1 - src.a). The output stays
|
|
175
|
+
// visible on a fully-transparent \`base\` because layer brings its own alpha.
|
|
156
176
|
float la = clamp(layer.a, 0.0, 1.0);
|
|
157
|
-
vec3 blended =
|
|
177
|
+
vec3 blended = base.rgb * (1.0 - la) + layer.rgb;
|
|
158
178
|
float outA = base.a + la * (1.0 - base.a);
|
|
159
179
|
gl_FragColor = vec4(blended, outA);
|
|
160
180
|
}
|
|
@@ -87,7 +87,6 @@ const renderText = (props: CoreTextNodeProps): TextRenderInfo => {
|
|
|
87
87
|
return {
|
|
88
88
|
width: 0,
|
|
89
89
|
height: 0,
|
|
90
|
-
trimmedHeight: 0,
|
|
91
90
|
};
|
|
92
91
|
}
|
|
93
92
|
|
|
@@ -192,18 +191,10 @@ const renderText = (props: CoreTextNodeProps): TextRenderInfo => {
|
|
|
192
191
|
if (canvas.width > 0 && canvas.height > 0) {
|
|
193
192
|
imageData = context.getImageData(0, 0, canvasW, canvasH);
|
|
194
193
|
}
|
|
195
|
-
// Cap-top of first line to descender bottom of last line.
|
|
196
|
-
// descender is negative in NormalizedFontMetrics.
|
|
197
|
-
const trimmedHeight =
|
|
198
|
-
lineAmount > 0
|
|
199
|
-
? metrics.capHeight - metrics.descender + (lineAmount - 1) * lineHeightPx
|
|
200
|
-
: 0;
|
|
201
|
-
|
|
202
194
|
return {
|
|
203
195
|
imageData,
|
|
204
196
|
width: effectiveWidth,
|
|
205
197
|
height: effectiveHeight,
|
|
206
|
-
trimmedHeight,
|
|
207
198
|
remainingLines,
|
|
208
199
|
hasRemainingText,
|
|
209
200
|
};
|
|
@@ -52,7 +52,6 @@ const renderText = (props: CoreTextNodeProps): TextRenderInfo => {
|
|
|
52
52
|
return {
|
|
53
53
|
width: 0,
|
|
54
54
|
height: 0,
|
|
55
|
-
trimmedHeight: 0,
|
|
56
55
|
};
|
|
57
56
|
}
|
|
58
57
|
|
|
@@ -64,7 +63,6 @@ const renderText = (props: CoreTextNodeProps): TextRenderInfo => {
|
|
|
64
63
|
hasRemainingText: false,
|
|
65
64
|
width: layout.width,
|
|
66
65
|
height: layout.height,
|
|
67
|
-
trimmedHeight: layout.trimmedHeight,
|
|
68
66
|
layout,
|
|
69
67
|
};
|
|
70
68
|
}
|
|
@@ -76,7 +74,6 @@ const renderText = (props: CoreTextNodeProps): TextRenderInfo => {
|
|
|
76
74
|
return {
|
|
77
75
|
width: 0,
|
|
78
76
|
height: 0,
|
|
79
|
-
trimmedHeight: 0,
|
|
80
77
|
};
|
|
81
78
|
}
|
|
82
79
|
|
|
@@ -90,7 +87,6 @@ const renderText = (props: CoreTextNodeProps): TextRenderInfo => {
|
|
|
90
87
|
hasRemainingText: false,
|
|
91
88
|
width: layout.width,
|
|
92
89
|
height: layout.height,
|
|
93
|
-
trimmedHeight: layout.trimmedHeight,
|
|
94
90
|
layout,
|
|
95
91
|
};
|
|
96
92
|
};
|
|
@@ -349,21 +345,12 @@ const generateTextLayout = (
|
|
|
349
345
|
}
|
|
350
346
|
}
|
|
351
347
|
|
|
352
|
-
// Cap-top of first line to descender bottom of last line.
|
|
353
|
-
// descender is negative in NormalizedFontMetrics, so subtracting it
|
|
354
|
-
// adds the descender depth. Zero when there are no rendered lines.
|
|
355
|
-
const trimmedHeight =
|
|
356
|
-
lineAmount > 0
|
|
357
|
-
? metrics.capHeight - metrics.descender + (lineAmount - 1) * lineHeightPx
|
|
358
|
-
: 0;
|
|
359
|
-
|
|
360
348
|
// Convert final dimensions to pixel space for the layout
|
|
361
349
|
return {
|
|
362
350
|
glyphs,
|
|
363
351
|
distanceRange: fontScale * fontData.distanceField.distanceRange,
|
|
364
352
|
width: effectiveWidth * fontScale,
|
|
365
353
|
height: effectiveHeight,
|
|
366
|
-
trimmedHeight,
|
|
367
354
|
fontScale: fontScale,
|
|
368
355
|
lineHeight: lineHeightPx,
|
|
369
356
|
fontFamily,
|
|
@@ -320,11 +320,6 @@ export interface TextLayout {
|
|
|
320
320
|
* Total text height
|
|
321
321
|
*/
|
|
322
322
|
height: number;
|
|
323
|
-
/**
|
|
324
|
-
* Trimmed text height — cap-top of the first line to descender bottom
|
|
325
|
-
* of the last line. See `TextRenderInfo.trimmedHeight`.
|
|
326
|
-
*/
|
|
327
|
-
trimmedHeight: number;
|
|
328
323
|
/**
|
|
329
324
|
* Font scale factor
|
|
330
325
|
*/
|
|
@@ -421,21 +416,6 @@ export interface TextRenderProps {
|
|
|
421
416
|
export interface TextRenderInfo {
|
|
422
417
|
width: number;
|
|
423
418
|
height: number;
|
|
424
|
-
/**
|
|
425
|
-
* Height of the visible glyph extent — from the first line's cap-top to
|
|
426
|
-
* the last line's descender bottom. Excludes half-leading and the slack
|
|
427
|
-
* between the font's ascender and cap-top.
|
|
428
|
-
*
|
|
429
|
-
* @remarks
|
|
430
|
-
* Formula: `capHeight − descender + (lines − 1) × lineHeightPx`
|
|
431
|
-
* (descender is negative in font metrics, so subtracting it adds the
|
|
432
|
-
* descender depth). For empty text, this is 0.
|
|
433
|
-
*
|
|
434
|
-
* Use this when you want flex `alignItems: 'center'` (or any layout
|
|
435
|
-
* that aligns by node `h`) to optically center the visible glyphs.
|
|
436
|
-
* Set `node.h = node.trimmedHeight` after the `loaded` event.
|
|
437
|
-
*/
|
|
438
|
-
trimmedHeight: number;
|
|
439
419
|
hasRemainingText?: boolean;
|
|
440
420
|
remainingLines?: number;
|
|
441
421
|
imageData?: ImageData | null; // Image data for Canvas Text Renderer
|
|
@@ -848,10 +848,21 @@ export class Inspector {
|
|
|
848
848
|
}
|
|
849
849
|
|
|
850
850
|
createTextNode(node: CoreTextNode): CoreTextNode {
|
|
851
|
+
// CoreTextNode carries two prop bags:
|
|
852
|
+
// - `node.props` (inherited CoreNodeProps): x, y, w, h, mount*, alpha…
|
|
853
|
+
// - `node.textProps` (private): text, fontSize, fontFamily, lineHeight…
|
|
854
|
+
// The mirror div needs both, so we merge them for the initial paint.
|
|
855
|
+
// Without `node.props` the div would have no left/top and render at (0,0)
|
|
856
|
+
// regardless of where the canvas drew the text.
|
|
851
857
|
// eslint-disable-next-line
|
|
852
858
|
// @ts-ignore - textProps is a private property and keeping it that way
|
|
853
859
|
// but we need it from the inspector to set the initial properties on the div element
|
|
854
|
-
const
|
|
860
|
+
const mergedProps = {
|
|
861
|
+
...node.props,
|
|
862
|
+
|
|
863
|
+
...(node as unknown as { textProps: CoreTextNodeProps }).textProps,
|
|
864
|
+
} as CoreTextNodeProps;
|
|
865
|
+
const div = this.createDiv(node.id, mergedProps);
|
|
855
866
|
(div as HTMLElement & { node: CoreNode }).node = node;
|
|
856
867
|
(node as CoreTextNode & { div: HTMLElement }).div = div;
|
|
857
868
|
|
|
@@ -952,12 +963,18 @@ export class Inspector {
|
|
|
952
963
|
};
|
|
953
964
|
// Define traps for each property in knownProperties
|
|
954
965
|
knownProperties.forEach((property) => {
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
966
|
+
// Walk the entire prototype chain. CoreTextNode extends CoreNode, so
|
|
967
|
+
// properties like x / y / w / h / mountX / mountY are defined on
|
|
968
|
+
// CoreNode.prototype — two hops up from a CoreTextNode instance. A
|
|
969
|
+
// single-level lookup (the previous behavior) returned undefined for
|
|
970
|
+
// those props on text nodes and skipped installing the trap, which
|
|
971
|
+
// meant updates to those props never reached the mirror div.
|
|
972
|
+
let originalProp: PropertyDescriptor | undefined =
|
|
973
|
+
Object.getOwnPropertyDescriptor(node, property);
|
|
974
|
+
let proto: object | null = Object.getPrototypeOf(node) as object | null;
|
|
975
|
+
while (originalProp === undefined && proto !== null) {
|
|
960
976
|
originalProp = Object.getOwnPropertyDescriptor(proto, property);
|
|
977
|
+
proto = Object.getPrototypeOf(proto) as object | null;
|
|
961
978
|
}
|
|
962
979
|
|
|
963
980
|
if (originalProp === undefined) {
|