@solidrt/core 0.0.40 → 0.0.41
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/AGENTS.md +3 -2
- package/README.md +1 -1
- package/examples/README.md +5 -4
- package/examples/gpu-instancing.tsx +70 -0
- package/examples/gpu-particles.tsx +35 -35
- package/examples/gpu-pipeline.tsx +40 -37
- package/examples/gpu-raw-program.tsx +59 -40
- package/examples/gpu-shader.tsx +48 -41
- package/examples/gpu-texture-blend.tsx +20 -19
- package/examples/inline-image.tsx +1 -1
- package/examples/parse-svg.tsx +94 -0
- package/examples/text-import.tsx +2 -2
- package/examples/wave.glsl +5 -3
- package/examples/window-shader-history.tsx +23 -23
- package/examples/window-shader.tsx +30 -28
- package/jsx-runtime.d.ts +17 -9
- package/package.json +2 -2
- package/src/camera.ts +8 -4
- package/src/color.ts +14 -2
- package/src/gpu.ts +176 -75
- package/src/image.ts +12 -11
- package/src/index.ts +3 -0
- package/src/renderer.ts +9 -8
- package/src/runtime-modules.d.ts +2 -2
- package/src/speech-recognition.ts +2 -1
- package/src/svg.ts +71 -0
- package/src/types.d.ts +72 -36
- package/examples/svg.tsx +0 -49
|
@@ -15,7 +15,7 @@ import bytes from "./logo.png" with { type: "binary" }
|
|
|
15
15
|
|
|
16
16
|
function App() {
|
|
17
17
|
let { data, width, height } = decodeImage(bytes)
|
|
18
|
-
let id = createTexture(data, width, height)
|
|
18
|
+
let id = createTexture(data, width, height, { label: "logo" })
|
|
19
19
|
|
|
20
20
|
return (
|
|
21
21
|
<window alignItems="center" justifyContent="center">
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
// parseSvg turns a whole SVG *document string* into plain draw data. This is
|
|
2
|
+
// not HTML: there are no <rect>/<circle>/<path> JSX children to nest. You hand
|
|
3
|
+
// it the source text (a string you import, fetch, or inline) and get back the
|
|
4
|
+
// document's intrinsic size plus a flat list of draws whose keys match the
|
|
5
|
+
// path element's props - so rendering is a map to <d-path>, wrapped in a view
|
|
6
|
+
// whose `viewBox` fits the document's coordinate space into the box.
|
|
7
|
+
//
|
|
8
|
+
// The point of draws-as-data over an opaque document element: every shape is
|
|
9
|
+
// a real node you own. Below, the house highlights the shape under the
|
|
10
|
+
// pointer - exact-geometry hit testing (the path outline, not its box), with
|
|
11
|
+
// the recolor a per-node prop override that never re-parses the document.
|
|
12
|
+
// The same structure gives per-shape animation (wrap a subset in <d-view>),
|
|
13
|
+
// layer filtering, or interleaving your own JSX between document layers.
|
|
14
|
+
//
|
|
15
|
+
// A multi-color document keeps each shape's own fill; a monochrome icon
|
|
16
|
+
// using stroke/fill "currentColor" is recolored by the `color` option,
|
|
17
|
+
// exactly as `currentColor` would be in a browser. That is how you use an
|
|
18
|
+
// existing icon library (Lucide, Heroicons, Feather, Material, ...): they
|
|
19
|
+
// ship SVG source strings following the currentColor convention. Parse once
|
|
20
|
+
// per document under a memo (or at module scope for a static asset).
|
|
21
|
+
//
|
|
22
|
+
// Being vectors, the draws are resolution-independent: crisp at any drawn
|
|
23
|
+
// size x displayScale(). Prefer them over a raster <texture> (image.tsx)
|
|
24
|
+
// whenever the render size is fluid or the display DPI varies.
|
|
25
|
+
import { render, parseSvg, svg, createMemo, createSignal, For } from "@solidrt/core"
|
|
26
|
+
|
|
27
|
+
// Multi-color document: each shape carries its own fill. The `svg` tag returns
|
|
28
|
+
// the string unchanged; it exists so editors highlight the markup (like `glsl`
|
|
29
|
+
// for shader sources).
|
|
30
|
+
const HOUSE = svg`
|
|
31
|
+
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
|
|
32
|
+
<rect x="20" y="45" width="60" height="45" fill="#457b9d"/>
|
|
33
|
+
<path d="M10 50 L50 15 L90 50 Z" fill="#e63946"/>
|
|
34
|
+
<rect x="42" y="62" width="16" height="28" fill="#f1faee"/>
|
|
35
|
+
<circle cx="50" cy="35" r="6" fill="#ffd166"/>
|
|
36
|
+
</svg>`
|
|
37
|
+
|
|
38
|
+
// Monochrome icon (Lucide arrow-right) drawn with currentColor, recolored below.
|
|
39
|
+
const ARROW = svg`
|
|
40
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
|
|
41
|
+
stroke-linecap="round" stroke-linejoin="round">
|
|
42
|
+
<path d="M5 12h14"/>
|
|
43
|
+
<path d="M12 5l7 7-7 7"/>
|
|
44
|
+
</svg>`
|
|
45
|
+
|
|
46
|
+
// The payoff over the old document-element approach: each draw is its own
|
|
47
|
+
// node, so the shape under the pointer lights up - hit on the true outline
|
|
48
|
+
// (hovering the sky inside the roof triangle's box does nothing), recolor
|
|
49
|
+
// without a re-parse.
|
|
50
|
+
function InteractiveHouse() {
|
|
51
|
+
let doc = createMemo(() => parseSvg(HOUSE))
|
|
52
|
+
let [hot, setHot] = createSignal(-1)
|
|
53
|
+
// repaintBoundary still pays off on an interactive document: the subtree
|
|
54
|
+
// re-records only when a draw inside it changes (hover), never because a
|
|
55
|
+
// sibling elsewhere on the screen did.
|
|
56
|
+
return (
|
|
57
|
+
<view repaintBoundary width={240} height={240} viewBox={[doc().width, doc().height]}>
|
|
58
|
+
<For each={doc().draws}>
|
|
59
|
+
{(draw, i) => (
|
|
60
|
+
<d-path
|
|
61
|
+
{...draw}
|
|
62
|
+
color={hot() === i() ? "#ffd166" : draw.color}
|
|
63
|
+
onPointerEnter={() => setHot(i())}
|
|
64
|
+
onPointerLeave={() => setHot((v) => (v === i() ? -1 : v))}
|
|
65
|
+
/>
|
|
66
|
+
)}
|
|
67
|
+
</For>
|
|
68
|
+
</view>
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// The plain pattern: memoized parse, viewBox-fitted box, draws mapped to
|
|
73
|
+
// <d-path>, and a plain repaintBoundary (the DL-reuse tier, not "snapshot")
|
|
74
|
+
// so the static subtree never re-records alongside animating siblings. The
|
|
75
|
+
// components-package Icon is this plus theming.
|
|
76
|
+
function Svg(props: { src: string; size: number; color?: string }) {
|
|
77
|
+
let doc = createMemo(() => parseSvg(props.src, { color: props.color }))
|
|
78
|
+
return (
|
|
79
|
+
<view repaintBoundary width={props.size} height={props.size} viewBox={[doc().width, doc().height]}>
|
|
80
|
+
<For each={doc().draws}>{(draw) => <d-path {...draw} />}</For>
|
|
81
|
+
</view>
|
|
82
|
+
)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function App() {
|
|
86
|
+
return (
|
|
87
|
+
<window justifyContent="center" alignItems="center" flexDirection="row" gap={32}>
|
|
88
|
+
<InteractiveHouse />
|
|
89
|
+
<Svg size={120} src={ARROW} color="#4f8cff" />
|
|
90
|
+
</window>
|
|
91
|
+
)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
render(() => <App />)
|
package/examples/text-import.tsx
CHANGED
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
//
|
|
8
8
|
// This example shows only the text import itself: it reports the imported
|
|
9
9
|
// file's size and first line. Shader sources are the motivating case - the
|
|
10
|
-
// string is exactly what gpu-shader.tsx passes to
|
|
11
|
-
// the .tsx so it can be edited as GLSL. Inlining trades update granularity for
|
|
10
|
+
// string is exactly what gpu-shader.tsx passes to createShaderTexture, moved
|
|
11
|
+
// out of the .tsx so it can be edited as GLSL. Inlining trades update granularity for
|
|
12
12
|
// zero I/O, so keep big or streamable files in assets/ and read them at
|
|
13
13
|
// runtime instead.
|
|
14
14
|
import { render } from "@solidrt/core"
|
package/examples/wave.glsl
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
// wave.glsl - animated scanline
|
|
2
2
|
//
|
|
3
3
|
// A plain fragment body in the injected-preamble dialect: no #version line, so
|
|
4
|
-
//
|
|
5
|
-
//
|
|
4
|
+
// createShaderTexture prepends vUV / iResolution / fragColor. The time uniform
|
|
5
|
+
// is this file's own declaration, driven by the app through params. Living in
|
|
6
|
+
// its own file it stays editable as GLSL instead of as a template literal.
|
|
7
|
+
uniform float uTime;
|
|
6
8
|
void main() {
|
|
7
9
|
vec2 uv = vUV;
|
|
8
|
-
float wave = sin(uv.x * 12.0 +
|
|
10
|
+
float wave = sin(uv.x * 12.0 + uTime * 2.0) * 0.06;
|
|
9
11
|
float d = abs(uv.y - 0.5 - wave);
|
|
10
12
|
float line = smoothstep(0.05, 0.0, d);
|
|
11
13
|
vec3 col = mix(vec3(0.05, 0.07, 0.12), vec3(0.2, 0.8, 1.0), line);
|
|
@@ -3,37 +3,37 @@
|
|
|
3
3
|
// one-frame history. Here it draws a motion echo behind the orbiting square;
|
|
4
4
|
// click to toggle the echo term off and compare with the plain frame.
|
|
5
5
|
import { render, onFrame, createSignal } from "@solidrt/core"
|
|
6
|
-
import { compileShader, destroyShader, linkProgram } from "@solidrt/core/gpu"
|
|
6
|
+
import { compileShader, destroyShader, glsl, linkProgram } from "@solidrt/core/gpu"
|
|
7
7
|
|
|
8
|
-
let VERTEX = `#version 300 es
|
|
9
|
-
precision highp float;
|
|
10
|
-
out vec2 vUV;
|
|
11
|
-
void main() {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
8
|
+
let VERTEX = glsl`#version 300 es
|
|
9
|
+
precision highp float;
|
|
10
|
+
out vec2 vUV;
|
|
11
|
+
void main() {
|
|
12
|
+
vec2 p = vec2(float((gl_VertexID << 1) & 2), float(gl_VertexID & 2));
|
|
13
|
+
// uSource/uPrevious are top-left origin; flip v so the frame lands upright.
|
|
14
|
+
vUV = vec2(p.x, 1.0 - p.y);
|
|
15
|
+
gl_Position = vec4(p * 2.0 - 1.0, 0.0, 1.0);
|
|
16
|
+
}
|
|
17
17
|
`
|
|
18
18
|
|
|
19
|
-
let ECHO = `
|
|
20
|
-
uniform sampler2D uSource;
|
|
21
|
-
uniform sampler2D uPrevious;
|
|
22
|
-
uniform float uEcho;
|
|
23
|
-
in vec2 vUV;
|
|
24
|
-
void main() {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
19
|
+
let ECHO = glsl`
|
|
20
|
+
uniform sampler2D uSource;
|
|
21
|
+
uniform sampler2D uPrevious;
|
|
22
|
+
uniform float uEcho;
|
|
23
|
+
in vec2 vUV;
|
|
24
|
+
void main() {
|
|
25
|
+
vec4 cur = texture(uSource, vUV);
|
|
26
|
+
vec4 prev = texture(uPrevious, vUV);
|
|
27
|
+
// Brightest of the current frame and the decayed previous one: motion
|
|
28
|
+
// leaves a one-frame ghost trailing it.
|
|
29
|
+
fragColor = max(cur, prev * uEcho);
|
|
30
|
+
}
|
|
31
31
|
`
|
|
32
32
|
|
|
33
33
|
function App() {
|
|
34
34
|
let vs = compileShader("vertex", VERTEX)
|
|
35
35
|
let fs = compileShader("fragment", ECHO, { header: true })
|
|
36
|
-
let echoProgram = linkProgram(vs, fs)
|
|
36
|
+
let echoProgram = linkProgram(vs, fs, { label: "echo" })
|
|
37
37
|
destroyShader(vs)
|
|
38
38
|
destroyShader(fs)
|
|
39
39
|
|
|
@@ -9,38 +9,40 @@
|
|
|
9
9
|
// is an identity pass, which must be indistinguishable from no shader at all
|
|
10
10
|
// (the orientation/half-pixel regression check from the plan).
|
|
11
11
|
import { render, onFrame, createSignal } from "@solidrt/core"
|
|
12
|
-
import { compileShader, destroyShader, linkProgram } from "@solidrt/core/gpu"
|
|
12
|
+
import { compileShader, destroyShader, glsl, linkProgram } from "@solidrt/core/gpu"
|
|
13
13
|
|
|
14
|
-
let VERTEX = `#version 300 es
|
|
15
|
-
precision highp float;
|
|
16
|
-
out vec2 vUV;
|
|
17
|
-
void main() {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
14
|
+
let VERTEX = glsl`#version 300 es
|
|
15
|
+
precision highp float;
|
|
16
|
+
out vec2 vUV;
|
|
17
|
+
void main() {
|
|
18
|
+
vec2 p = vec2(float((gl_VertexID << 1) & 2), float(gl_VertexID & 2));
|
|
19
|
+
// uSource is top-left origin; flip v so the frame lands upright on the
|
|
20
|
+
// window (the one flip of the frame path, done here in the vertex stage).
|
|
21
|
+
vUV = vec2(p.x, 1.0 - p.y);
|
|
22
|
+
gl_Position = vec4(p * 2.0 - 1.0, 0.0, 1.0);
|
|
23
|
+
}
|
|
24
24
|
`
|
|
25
25
|
|
|
26
|
-
// { header: true } declares #version, precision, iResolution
|
|
27
|
-
//
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
uniform
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
vec2
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
26
|
+
// { header: true } declares #version, precision, iResolution and fragColor;
|
|
27
|
+
// uSource, vUV, and the app's own uniforms - the time included - are
|
|
28
|
+
// declared here.
|
|
29
|
+
let WARP = glsl`
|
|
30
|
+
uniform sampler2D uSource;
|
|
31
|
+
uniform float uAmount;
|
|
32
|
+
uniform float uTime;
|
|
33
|
+
in vec2 vUV;
|
|
34
|
+
void main() {
|
|
35
|
+
vec2 uv = vUV;
|
|
36
|
+
uv.x += sin(uv.y * 24.0 + uTime * 3.0) * 0.012 * uAmount;
|
|
37
|
+
uv.y += sin(uv.x * 18.0 - uTime * 2.0) * 0.012 * uAmount;
|
|
38
|
+
fragColor = texture(uSource, uv);
|
|
39
|
+
}
|
|
38
40
|
`
|
|
39
41
|
|
|
40
42
|
function App() {
|
|
41
43
|
let vs = compileShader("vertex", VERTEX)
|
|
42
44
|
let fs = compileShader("fragment", WARP, { header: true })
|
|
43
|
-
let warp = linkProgram(vs, fs)
|
|
45
|
+
let warp = linkProgram(vs, fs, { label: "warp" })
|
|
44
46
|
destroyShader(vs)
|
|
45
47
|
destroyShader(fs)
|
|
46
48
|
|
|
@@ -50,7 +52,7 @@ function App() {
|
|
|
50
52
|
|
|
51
53
|
return (
|
|
52
54
|
<window
|
|
53
|
-
shader={{ program: warp, params: {
|
|
55
|
+
shader={{ program: warp, params: { uTime: time(), uAmount: amount() } }}
|
|
54
56
|
onPointerDown={() => setAmount(a => (a > 0 ? 0 : 1))}
|
|
55
57
|
flexDirection="column"
|
|
56
58
|
gap={12}
|
|
@@ -59,9 +61,9 @@ function App() {
|
|
|
59
61
|
>
|
|
60
62
|
<text fontSize={28} color="#222">Window shader</text>
|
|
61
63
|
<view flexDirection="row" gap={12}>
|
|
62
|
-
<rect
|
|
63
|
-
<rect
|
|
64
|
-
<rect
|
|
64
|
+
<rect width={90} height={90} radius={12} color="#0077ff" />
|
|
65
|
+
<rect width={90} height={90} radius={12} color="#ff6a00" />
|
|
66
|
+
<rect width={90} height={90} radius={12} color="#00c46a" />
|
|
65
67
|
</view>
|
|
66
68
|
<text fontSize={14} color="#666">Click to toggle warp (identity at 0)</text>
|
|
67
69
|
</window>
|
package/jsx-runtime.d.ts
CHANGED
|
@@ -2,12 +2,18 @@ import type {
|
|
|
2
2
|
WindowProps,
|
|
3
3
|
RectProps,
|
|
4
4
|
OvalProps,
|
|
5
|
+
LineProps,
|
|
5
6
|
PathProps,
|
|
6
|
-
SvgProps,
|
|
7
7
|
ViewProps,
|
|
8
|
+
ViewOwnProps,
|
|
8
9
|
TextProps,
|
|
9
10
|
TextureProps,
|
|
10
11
|
LayoutProps,
|
|
12
|
+
PositionProps,
|
|
13
|
+
GeometryProps,
|
|
14
|
+
OvalGeometryProps,
|
|
15
|
+
TextGeometryProps,
|
|
16
|
+
LineGeometryProps,
|
|
11
17
|
Element as CoreElement,
|
|
12
18
|
ElementChildrenAttribute as CoreElementChildrenAttribute
|
|
13
19
|
} from "./src/types"
|
|
@@ -30,21 +36,23 @@ export namespace JSX {
|
|
|
30
36
|
ref?: Ref<{ id: number }> | undefined
|
|
31
37
|
}
|
|
32
38
|
|
|
39
|
+
// Layout forms compose LayoutProps and derive their geometry from the
|
|
40
|
+
// layout box; d-* forms compose the paint-space geometry props instead.
|
|
33
41
|
interface IntrinsicElements {
|
|
34
42
|
window: WindowProps & ElementRef
|
|
35
43
|
view: ViewProps & ElementRef
|
|
36
44
|
text: TextProps & LayoutProps & ElementRef
|
|
37
45
|
rect: RectProps & LayoutProps & ElementRef
|
|
38
46
|
oval: OvalProps & LayoutProps & ElementRef
|
|
47
|
+
line: LineProps & LayoutProps & ElementRef
|
|
39
48
|
path: PathProps & LayoutProps & ElementRef
|
|
40
|
-
svg: SvgProps & LayoutProps & ElementRef
|
|
41
49
|
texture: TextureProps & LayoutProps & ElementRef
|
|
42
|
-
"d-view":
|
|
43
|
-
"d-rect": RectProps & ElementRef
|
|
44
|
-
"d-oval": OvalProps & ElementRef
|
|
45
|
-
"d-
|
|
46
|
-
"d-
|
|
47
|
-
"d-texture": TextureProps & ElementRef
|
|
48
|
-
"d-text": TextProps & ElementRef
|
|
50
|
+
"d-view": ViewOwnProps & ElementRef
|
|
51
|
+
"d-rect": RectProps & GeometryProps & ElementRef
|
|
52
|
+
"d-oval": OvalProps & OvalGeometryProps & ElementRef
|
|
53
|
+
"d-line": LineProps & LineGeometryProps & ElementRef
|
|
54
|
+
"d-path": PathProps & PositionProps & ElementRef
|
|
55
|
+
"d-texture": TextureProps & GeometryProps & ElementRef
|
|
56
|
+
"d-text": TextProps & TextGeometryProps & ElementRef
|
|
49
57
|
}
|
|
50
58
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solidrt/core",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.41",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "Antoine van Wel",
|
|
6
6
|
"type": "module",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"colord": "^2.9.3"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
|
-
"@solidrt/flux-types": "0.0.
|
|
30
|
+
"@solidrt/flux-types": "0.0.41"
|
|
31
31
|
},
|
|
32
32
|
"peerDependencies": {
|
|
33
33
|
"@solidjs/signals": "2.0.0-beta.26",
|
package/src/camera.ts
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
import { createSignal, onCleanup } from "@solidjs/signals"
|
|
10
10
|
import { listCameras, open } from "flux:camera"
|
|
11
|
+
import type { TextureId } from "flux:gpu"
|
|
11
12
|
import { on } from "srt:events"
|
|
12
13
|
|
|
13
14
|
export type CameraFacing = "front" | "back" | "unknown"
|
|
@@ -41,8 +42,11 @@ let devicesAccessor: (() => CameraInfo[]) | undefined
|
|
|
41
42
|
|
|
42
43
|
/**
|
|
43
44
|
* Current camera list as a reactive accessor: re-enumerates on hotplug. Also
|
|
44
|
-
*
|
|
45
|
-
*
|
|
45
|
+
* kicks off the camera subsystem (required before hotplug events fire), which
|
|
46
|
+
* starts asynchronously: the list is empty until the initial device events
|
|
47
|
+
* arrive - moments later normally, never if the platform's capture backend is
|
|
48
|
+
* wedged. App-lifetime: there is one camera subsystem, so no cleanup is
|
|
49
|
+
* needed.
|
|
46
50
|
*
|
|
47
51
|
* Coverage caveat (SDL 3.4.8): only Android delivers both add and remove. On
|
|
48
52
|
* Linux you get add events but not remove (removal is broken upstream); on
|
|
@@ -70,7 +74,7 @@ export function onDeviceChange(callback: (event: { added: boolean }) => void): (
|
|
|
70
74
|
/** A live camera as reactive accessors. */
|
|
71
75
|
export type CameraStream = {
|
|
72
76
|
/** Texture id once the stream is up, undefined while opening; render with <texture src={...}>. */
|
|
73
|
-
texture():
|
|
77
|
+
texture(): TextureId | undefined
|
|
74
78
|
/** Actual stream size, undefined while opening. */
|
|
75
79
|
width(): number | undefined
|
|
76
80
|
height(): number | undefined
|
|
@@ -87,7 +91,7 @@ export type CameraStream = {
|
|
|
87
91
|
* call open() from "flux:camera" directly.
|
|
88
92
|
*/
|
|
89
93
|
export function createCamera(options: CameraOptions = {}): CameraStream {
|
|
90
|
-
let [texture, setTexture] = createSignal<
|
|
94
|
+
let [texture, setTexture] = createSignal<TextureId | undefined>(undefined)
|
|
91
95
|
let [width, setWidth] = createSignal<number | undefined>(undefined)
|
|
92
96
|
let [height, setHeight] = createSignal<number | undefined>(undefined)
|
|
93
97
|
let [barcode, setBarcode] = createSignal<BarcodeResult | undefined>(undefined)
|
package/src/color.ts
CHANGED
|
@@ -48,9 +48,21 @@ type Stop = { offset: number; color: number }
|
|
|
48
48
|
// `pct()` length vocabulary used by layout and transformOrigin: a gradient's
|
|
49
49
|
// position is naturally a fraction (like a stop offset), so 0..1 reads cleaner
|
|
50
50
|
// than pct(0)..pct(100). Do not "unify" them onto pct().
|
|
51
|
+
//
|
|
52
|
+
// The optional absolute-space fields are produced by parseSvg, never by the
|
|
53
|
+
// factories: `units: "absolute"` switches the coordinates to the document's
|
|
54
|
+
// drawing space, `spread` is the SVG spreadMethod (default pad), and
|
|
55
|
+
// `transform` an SVG matrix(a b c d e f) sextet mapping the gradient's
|
|
56
|
+
// coordinates into that space (default identity).
|
|
57
|
+
type AbsoluteSpace = {
|
|
58
|
+
units?: "absolute"
|
|
59
|
+
spread?: "pad" | "reflect" | "repeat"
|
|
60
|
+
transform?: [number, number, number, number, number, number]
|
|
61
|
+
}
|
|
62
|
+
|
|
51
63
|
export type Gradient =
|
|
52
|
-
| { readonly __gradient: "linear"; x0: number; y0: number; x1: number; y1: number; stops: Stop[] }
|
|
53
|
-
| { readonly __gradient: "radial"; cx: number; cy: number; r: number; circle
|
|
64
|
+
| ({ readonly __gradient: "linear"; x0: number; y0: number; x1: number; y1: number; stops: Stop[] } & AbsoluteSpace)
|
|
65
|
+
| ({ readonly __gradient: "radial"; cx: number; cy: number; r: number; circle?: boolean; stops: Stop[] } & AbsoluteSpace)
|
|
54
66
|
|
|
55
67
|
/**
|
|
56
68
|
* A linear gradient between two points, each given in 0..1 of the element's box
|