@glowbox/react 1.0.0-rc.2

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Eetu Sutinen
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,93 @@
1
+ # @glowbox/react
2
+
3
+ glowbox components for **React**: `<LedGrid>` — the 3D WebGL LED-grid display (over
4
+ **[@glowbox/led-grid](../led-grid)**) — and `<NixieTube>` — a glowing nixie-tube numeral (over
5
+ **[@glowbox/nixie](../nixie)**).
6
+
7
+ ```sh
8
+ yarn add @glowbox/react
9
+ # peer: react ^18 || ^19 (@glowbox/led-grid + @glowbox/nixie come along as dependencies)
10
+ ```
11
+
12
+ ## `<LedGrid>`
13
+
14
+ ```tsx
15
+ import { LedGrid, type LedDisplay } from '@glowbox/react';
16
+
17
+ const draw = (d: LedDisplay, dt: number) => {
18
+ d.clear();
19
+ d.sphere([4, 4, 4], 3, '#00aaff');
20
+ };
21
+
22
+ export default function App() {
23
+ return (
24
+ <div style={{ width: 480, height: 480 }}>
25
+ <LedGrid
26
+ size={[8, 8, 8]}
27
+ draw={draw}
28
+ led={{ glow: 3, offColor: '#0a0a12' }}
29
+ camera={{ autoOrbit: true, projection: 'perspective' }}
30
+ color={{ background: '#000', gain: 1.1 }}
31
+ interaction={{ zoom: true }}
32
+ />
33
+ </div>
34
+ );
35
+ }
36
+ ```
37
+
38
+ | prop | type | notes |
39
+ | --------------------- | ----------------------------------- | -------------------------------------------------------------------------------------- |
40
+ | `size` | `[number, number, number]` | grid dims `[nx, ny, nz]` (changing it resizes in place — no remount) |
41
+ | `draw` | `(d: LedDisplay, dt: number)=>void` | called every frame; write voxels here |
42
+ | `led` | `LedOptions` | `style` `shape` `stagger` `rgb` `rgbLayout` `vivid` `outline` `size` `glow` `offColor` |
43
+ | `color` | `ColorOptions` | `background` `gain` `tint` |
44
+ | `camera` | `CameraOptions` | `yaw` `pitch` `distance` `fov` `projection` `autoOrbit` `orbitSpeed` `pitchLimits` |
45
+ | `interaction` | `InteractionOptions` | `drag` `dragSpeed` `zoom` `zoomLimits` |
46
+ | `quality` | `QualityOptions` | `pixelRatio` `antialias` `paused` `fps` (frame-rate cap) |
47
+ | `className` / `style` | — | forwarded to the `<canvas>` |
48
+
49
+ Forward a `ref` to reach the imperative `LedDisplay` handle (`snapshot()`, `stats`,
50
+ `setCamera`, …):
51
+
52
+ ```tsx
53
+ const grid = useRef<LedDisplay | null>(null);
54
+ <LedGrid ref={grid} size={[8, 8, 8]} />;
55
+ // grid.current?.snapshot()
56
+ ```
57
+
58
+ The grouped props mirror `@glowbox/led-grid`'s options 1:1 and update **live** — even `size`
59
+ resizes the grid in place. See **@glowbox/led-grid** for defaults, the voxel API, and colour
60
+ semantics.
61
+
62
+ ## `<NixieTube>`
63
+
64
+ ```tsx
65
+ import { NixieTube } from '@glowbox/react';
66
+
67
+ <div style={{ width: 80, height: 150 }}>
68
+ <NixieTube value="7" tubeStyle="classic" color="#ff6a12" />
69
+ </div>;
70
+ ```
71
+
72
+ | prop | type | notes |
73
+ | --------------------- | ------------------------------- | ---------------------------------------------------------- |
74
+ | `value` | `string \| number \| null` | the lit symbol: `0`–`9`, `:`, `-`, or `null`/`''` for dark |
75
+ | `tubeStyle` | `'classic' \| 'slim' \| 'tall'` | physical tube style (maps to the core `style` option) |
76
+ | `color` | `Color` | glow colour (default warm nixie orange) |
77
+ | `glow` | `number` | glow strength 0..1 |
78
+ | `background` | `Color` | tube glass colour |
79
+ | `mesh` | `boolean` | draw the honeycomb anode mesh (default `true`) |
80
+ | `ghost` | `boolean` | show the unlit cathode stack (default `true`) |
81
+ | `pixelRatio` | `number` | cap on `devicePixelRatio` |
82
+ | `className` / `style` | — | forwarded to the `<canvas>` (CSS) |
83
+
84
+ Props update **live**; forward a `ref` for the imperative `NixieTube` handle (`setValue`,
85
+ `setOptions`, `resize`, `snapshot`). See **@glowbox/nixie** for defaults + the
86
+ size-adaptive rendering.
87
+
88
+ ---
89
+
90
+ Sibling packages with the same components: **[@glowbox/svelte](../svelte)** and
91
+ **[@glowbox/vue](../vue)**; content helpers in **[@glowbox/extras](../extras)**. Each
92
+ component fills its parent; give the parent a size. Live demos:
93
+ <https://eetu.github.io/glowbox/>.
@@ -0,0 +1,21 @@
1
+ import { CameraOptions, ColorOptions, InteractionOptions, LedDisplay, LedOptions, QualityOptions } from '@glowbox/led-grid';
2
+ import { CSSProperties } from 'react';
3
+ export interface LedGridProps {
4
+ /** Grid size [nx, ny, nz]. Changing it resizes in place (no remount). */
5
+ size: [number, number, number];
6
+ /** Called every frame; write voxels here. */
7
+ draw?: (d: LedDisplay, dt: number) => void;
8
+ led?: LedOptions;
9
+ color?: ColorOptions;
10
+ camera?: CameraOptions;
11
+ interaction?: InteractionOptions;
12
+ quality?: QualityOptions;
13
+ className?: string;
14
+ style?: CSSProperties;
15
+ }
16
+ /**
17
+ * `<LedGrid>` mounts a 3D WebGL LED-grid display and runs your per-frame draw
18
+ * callback. Forward a ref to reach the imperative `LedDisplay` handle
19
+ * (`snapshot()`, `stats`, `setCamera`, …).
20
+ */
21
+ export declare const LedGrid: import('react').ForwardRefExoticComponent<LedGridProps & import('react').RefAttributes<LedDisplay | null>>;
@@ -0,0 +1,21 @@
1
+ import { NixieOptions, NixieStyle, NixieTube as NixieTubeHandle } from '@glowbox/nixie';
2
+ import { CSSProperties } from 'react';
3
+ export interface NixieTubeProps {
4
+ /** The lit symbol: a char `0`–`9`, `:`, `-`, or null/'' for all-cathodes-dark. */
5
+ value?: string | number | null;
6
+ /** Physical tube style — maps to the core `style` option (renamed to avoid the DOM `style`). */
7
+ tubeStyle?: NixieStyle;
8
+ color?: NixieOptions['color'];
9
+ glow?: number;
10
+ background?: NixieOptions['background'];
11
+ mesh?: boolean;
12
+ ghost?: boolean;
13
+ pixelRatio?: number;
14
+ className?: string;
15
+ style?: CSSProperties;
16
+ }
17
+ /**
18
+ * `<NixieTube>` mounts a single glowing nixie-tube numeral. Forward a ref to reach the
19
+ * imperative `NixieTube` handle (`setValue`, `setOptions`, `resize`, `snapshot`, …).
20
+ */
21
+ export declare const NixieTube: import('react').ForwardRefExoticComponent<NixieTubeProps & import('react').RefAttributes<NixieTubeHandle | null>>;
@@ -0,0 +1,4 @@
1
+ export { LedGrid, type LedGridProps } from './LedGrid';
2
+ export { NixieTube, type NixieTubeProps } from './NixieTube';
3
+ export type * from '@glowbox/led-grid';
4
+ export type { NixieOptions, NixieStyle, NixieTube as NixieTubeHandle } from '@glowbox/nixie';
package/dist/index.js ADDED
@@ -0,0 +1,123 @@
1
+ import { createLedDisplay as e } from "@glowbox/led-grid";
2
+ import { forwardRef as t, useEffect as n, useImperativeHandle as r, useRef as i, useState as a } from "react";
3
+ import { jsx as o } from "react/jsx-runtime";
4
+ import { createNixieTube as s } from "@glowbox/nixie";
5
+ //#region src/LedGrid.tsx
6
+ var c = {
7
+ display: "block",
8
+ width: "100%",
9
+ height: "100%",
10
+ touchAction: "none"
11
+ }, l = t(function(t, s) {
12
+ let { size: l, draw: u, led: d, color: f, camera: p, interaction: m, quality: h, className: g, style: _ } = t, v = i(null), [y, b] = a(null), x = i(t);
13
+ x.current = t, n(() => {
14
+ let t = v.current;
15
+ if (!t) return;
16
+ let n = x.current, r = e(t, {
17
+ size: n.size,
18
+ led: n.led,
19
+ color: n.color,
20
+ camera: n.camera,
21
+ interaction: n.interaction,
22
+ quality: n.quality
23
+ });
24
+ if (!r) {
25
+ console.warn("LedGrid: WebGL unavailable");
26
+ return;
27
+ }
28
+ return b(r), () => {
29
+ r.dispose(), b(null);
30
+ };
31
+ }, []), r(s, () => y, [y]);
32
+ let [S, C, w] = l;
33
+ return n(() => {
34
+ y?.resize([
35
+ S,
36
+ C,
37
+ w
38
+ ]);
39
+ }, [
40
+ y,
41
+ S,
42
+ C,
43
+ w
44
+ ]), n(() => {
45
+ y?.setOptions({ led: d });
46
+ }, [y, d]), n(() => {
47
+ y?.setOptions({ color: f });
48
+ }, [y, f]), n(() => {
49
+ y?.setOptions({ camera: p });
50
+ }, [y, p]), n(() => {
51
+ y?.setOptions({ interaction: m });
52
+ }, [y, m]), n(() => {
53
+ y?.setOptions({ quality: h });
54
+ }, [y, h]), n(() => {
55
+ if (!(!y || !u)) return y.onFrame(u);
56
+ }, [y, u]), /* @__PURE__ */ o("canvas", {
57
+ ref: v,
58
+ className: g,
59
+ style: {
60
+ ...c,
61
+ ..._
62
+ }
63
+ });
64
+ }), u = {
65
+ display: "block",
66
+ width: "100%",
67
+ height: "100%"
68
+ }, d = t(function(e, t) {
69
+ let { value: c = null, tubeStyle: l = "classic", color: d, glow: f, background: p, mesh: m, ghost: h, pixelRatio: g, className: _, style: v } = e, y = i(null), [b, x] = a(null), S = i(e);
70
+ return S.current = e, n(() => {
71
+ let e = y.current;
72
+ if (!e) return;
73
+ let t = S.current, n = s(e, {
74
+ value: t.value ?? null,
75
+ style: t.tubeStyle,
76
+ color: t.color,
77
+ glow: t.glow,
78
+ background: t.background,
79
+ mesh: t.mesh,
80
+ ghost: t.ghost,
81
+ pixelRatio: t.pixelRatio
82
+ });
83
+ if (!n) {
84
+ console.warn("NixieTube: 2D canvas unavailable");
85
+ return;
86
+ }
87
+ return x(n), () => {
88
+ n.dispose(), x(null);
89
+ };
90
+ }, []), r(t, () => b, [b]), n(() => {
91
+ b?.setValue(c ?? null);
92
+ }, [b, c]), n(() => {
93
+ b?.setOptions({
94
+ style: l,
95
+ color: d,
96
+ glow: f,
97
+ background: p,
98
+ mesh: m,
99
+ ghost: h,
100
+ pixelRatio: g
101
+ });
102
+ }, [
103
+ b,
104
+ l,
105
+ d,
106
+ f,
107
+ p,
108
+ m,
109
+ h,
110
+ g
111
+ ]), /* @__PURE__ */ o("canvas", {
112
+ ref: y,
113
+ className: _,
114
+ style: {
115
+ ...u,
116
+ ...v
117
+ }
118
+ });
119
+ });
120
+ //#endregion
121
+ export { l as LedGrid, d as NixieTube };
122
+
123
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/LedGrid.tsx","../src/NixieTube.tsx"],"sourcesContent":["// React wrapper around the plain-JS LED display. Give it a `size` and an optional\n// `draw(d, dt)` callback; the grouped option props (led/color/camera/interaction/\n// quality) mirror @glowbox/led-grid's options 1:1 and update live. All content is the\n// client's — this ships no programs. Mirrors @glowbox/svelte over the same core.\nimport {\n\ttype CameraOptions,\n\ttype ColorOptions,\n\tcreateLedDisplay,\n\ttype InteractionOptions,\n\ttype LedDisplay,\n\ttype LedOptions,\n\ttype QualityOptions\n} from '@glowbox/led-grid';\nimport {\n\ttype CSSProperties,\n\tforwardRef,\n\tuseEffect,\n\tuseImperativeHandle,\n\tuseRef,\n\tuseState\n} from 'react';\n\nexport interface LedGridProps {\n\t/** Grid size [nx, ny, nz]. Changing it resizes in place (no remount). */\n\tsize: [number, number, number];\n\t/** Called every frame; write voxels here. */\n\tdraw?: (d: LedDisplay, dt: number) => void;\n\tled?: LedOptions;\n\tcolor?: ColorOptions;\n\tcamera?: CameraOptions;\n\tinteraction?: InteractionOptions;\n\tquality?: QualityOptions;\n\tclassName?: string;\n\tstyle?: CSSProperties;\n}\n\n// The canvas fills its parent by default; give the parent a size.\nconst baseStyle: CSSProperties = {\n\tdisplay: 'block',\n\twidth: '100%',\n\theight: '100%',\n\ttouchAction: 'none' // let drag-orbit work without the page panning\n};\n\n/**\n * `<LedGrid>` mounts a 3D WebGL LED-grid display and runs your per-frame draw\n * callback. Forward a ref to reach the imperative `LedDisplay` handle\n * (`snapshot()`, `stats`, `setCamera`, …).\n */\n// forwardRef (not the React-19 ref-as-prop) so the same build works against the\n// React 18 peer too.\n// eslint-disable-next-line @eslint-react/no-forward-ref\nexport const LedGrid = forwardRef<LedDisplay | null, LedGridProps>(function LedGrid(props, ref) {\n\tconst { size, draw, led, color, camera, interaction, quality, className, style } = props;\n\tconst canvasRef = useRef<HTMLCanvasElement>(null);\n\tconst [display, setDisplay] = useState<LedDisplay | null>(null);\n\n\t// Latest props, read once at creation (so the create effect can run mount-only\n\t// while later effects keep everything in sync).\n\tconst latestRef = useRef(props);\n\tlatestRef.current = props;\n\n\t// Create the display once for the canvas; dispose on unmount.\n\tuseEffect(() => {\n\t\tconst canvas = canvasRef.current;\n\t\tif (!canvas) return;\n\t\tconst p = latestRef.current;\n\t\tconst d = createLedDisplay(canvas, {\n\t\t\tsize: p.size,\n\t\t\tled: p.led,\n\t\t\tcolor: p.color,\n\t\t\tcamera: p.camera,\n\t\t\tinteraction: p.interaction,\n\t\t\tquality: p.quality\n\t\t});\n\t\tif (!d) {\n\t\t\tconsole.warn('LedGrid: WebGL unavailable');\n\t\t\treturn;\n\t\t}\n\t\tsetDisplay(d);\n\t\treturn () => {\n\t\t\td.dispose();\n\t\t\tsetDisplay(null);\n\t\t};\n\t}, []);\n\n\t// Expose the display via the forwarded ref (null until it exists).\n\tuseImperativeHandle<LedDisplay | null, LedDisplay | null>(ref, () => display, [display]);\n\n\t// Resize the grid in place when the dimensions change (no remount / context loss).\n\tconst [sx, sy, sz] = size;\n\tuseEffect(() => {\n\t\tdisplay?.resize([sx, sy, sz]);\n\t}, [display, sx, sy, sz]);\n\n\t// Live-update each option group *independently*. Patching all groups on any one change\n\t// would re-send `camera` (yaw/pitch/distance) on, say, a colour tweak — snapping the\n\t// view back and fighting drag / auto-orbit. One effect per group patches only what changed.\n\tuseEffect(() => {\n\t\tdisplay?.setOptions({ led });\n\t}, [display, led]);\n\tuseEffect(() => {\n\t\tdisplay?.setOptions({ color });\n\t}, [display, color]);\n\tuseEffect(() => {\n\t\tdisplay?.setOptions({ camera });\n\t}, [display, camera]);\n\tuseEffect(() => {\n\t\tdisplay?.setOptions({ interaction });\n\t}, [display, interaction]);\n\tuseEffect(() => {\n\t\tdisplay?.setOptions({ quality });\n\t}, [display, quality]);\n\n\t// (Re)bind the per-frame draw callback.\n\tuseEffect(() => {\n\t\tif (!display || !draw) return;\n\t\treturn display.onFrame(draw);\n\t}, [display, draw]);\n\n\treturn <canvas ref={canvasRef} className={className} style={{ ...baseStyle, ...style }} />;\n});\n","// React wrapper around @glowbox/nixie's canvas tube. Give it a `value` (the lit symbol)\n// plus optional appearance props that mirror the core NixieOptions and update live. The\n// canvas fills its parent — size the parent to size the tube. Ships in @glowbox/react\n// alongside <LedGrid>, over the sibling @glowbox/nixie core.\nimport {\n\tcreateNixieTube,\n\ttype NixieOptions,\n\ttype NixieStyle,\n\ttype NixieTube as NixieTubeHandle\n} from '@glowbox/nixie';\nimport {\n\ttype CSSProperties,\n\tforwardRef,\n\tuseEffect,\n\tuseImperativeHandle,\n\tuseRef,\n\tuseState\n} from 'react';\n\nexport interface NixieTubeProps {\n\t/** The lit symbol: a char `0`–`9`, `:`, `-`, or null/'' for all-cathodes-dark. */\n\tvalue?: string | number | null;\n\t/** Physical tube style — maps to the core `style` option (renamed to avoid the DOM `style`). */\n\ttubeStyle?: NixieStyle;\n\tcolor?: NixieOptions['color'];\n\tglow?: number;\n\tbackground?: NixieOptions['background'];\n\tmesh?: boolean;\n\tghost?: boolean;\n\tpixelRatio?: number;\n\tclassName?: string;\n\tstyle?: CSSProperties;\n}\n\n// The canvas fills its parent by default; give the parent a size.\nconst baseStyle: CSSProperties = { display: 'block', width: '100%', height: '100%' };\n\n/**\n * `<NixieTube>` mounts a single glowing nixie-tube numeral. Forward a ref to reach the\n * imperative `NixieTube` handle (`setValue`, `setOptions`, `resize`, `snapshot`, …).\n */\n// forwardRef (not the React-19 ref-as-prop) so the same build works against the React 18 peer.\n// eslint-disable-next-line @eslint-react/no-forward-ref\nexport const NixieTube = forwardRef<NixieTubeHandle | null, NixieTubeProps>(\n\tfunction NixieTube(props, ref) {\n\t\tconst {\n\t\t\tvalue = null,\n\t\t\ttubeStyle = 'classic',\n\t\t\tcolor,\n\t\t\tglow,\n\t\t\tbackground,\n\t\t\tmesh,\n\t\t\tghost,\n\t\t\tpixelRatio,\n\t\t\tclassName,\n\t\t\tstyle\n\t\t} = props;\n\t\tconst canvasRef = useRef<HTMLCanvasElement>(null);\n\t\tconst [tube, setTube] = useState<NixieTubeHandle | null>(null);\n\n\t\t// Latest props, read once at creation (create mount-only; later effects sync).\n\t\tconst latestRef = useRef(props);\n\t\tlatestRef.current = props;\n\n\t\t// Create the tube once for the canvas; dispose on unmount.\n\t\tuseEffect(() => {\n\t\t\tconst canvas = canvasRef.current;\n\t\t\tif (!canvas) return;\n\t\t\tconst p = latestRef.current;\n\t\t\tconst t = createNixieTube(canvas, {\n\t\t\t\tvalue: p.value ?? null,\n\t\t\t\tstyle: p.tubeStyle,\n\t\t\t\tcolor: p.color,\n\t\t\t\tglow: p.glow,\n\t\t\t\tbackground: p.background,\n\t\t\t\tmesh: p.mesh,\n\t\t\t\tghost: p.ghost,\n\t\t\t\tpixelRatio: p.pixelRatio\n\t\t\t});\n\t\t\tif (!t) {\n\t\t\t\tconsole.warn('NixieTube: 2D canvas unavailable');\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsetTube(t);\n\t\t\treturn () => {\n\t\t\t\tt.dispose();\n\t\t\t\tsetTube(null);\n\t\t\t};\n\t\t}, []);\n\n\t\tuseImperativeHandle<NixieTubeHandle | null, NixieTubeHandle | null>(ref, () => tube, [tube]);\n\n\t\t// Live-update the lit symbol.\n\t\tuseEffect(() => {\n\t\t\ttube?.setValue(value ?? null);\n\t\t}, [tube, value]);\n\n\t\t// Live-update appearance when any option changes.\n\t\tuseEffect(() => {\n\t\t\ttube?.setOptions({ style: tubeStyle, color, glow, background, mesh, ghost, pixelRatio });\n\t\t}, [tube, tubeStyle, color, glow, background, mesh, ghost, pixelRatio]);\n\n\t\treturn <canvas ref={canvasRef} className={className} style={{ ...baseStyle, ...style }} />;\n\t}\n);\n"],"mappings":";;;;;AAqCA,IAAM,IAA2B;CAChC,SAAS;CACT,OAAO;CACP,QAAQ;CACR,aAAa;AACd,GAUa,IAAU,EAA4C,SAAiB,GAAO,GAAK;CAC/F,IAAM,EAAE,SAAM,SAAM,QAAK,UAAO,WAAQ,gBAAa,YAAS,cAAW,aAAU,GAC7E,IAAY,EAA0B,IAAI,GAC1C,CAAC,GAAS,KAAc,EAA4B,IAAI,GAIxD,IAAY,EAAO,CAAK;CA4B9B,AA3BA,EAAU,UAAU,GAGpB,QAAgB;EACf,IAAM,IAAS,EAAU;EACzB,IAAI,CAAC,GAAQ;EACb,IAAM,IAAI,EAAU,SACd,IAAI,EAAiB,GAAQ;GAClC,MAAM,EAAE;GACR,KAAK,EAAE;GACP,OAAO,EAAE;GACT,QAAQ,EAAE;GACV,aAAa,EAAE;GACf,SAAS,EAAE;EACZ,CAAC;EACD,IAAI,CAAC,GAAG;GACP,QAAQ,KAAK,4BAA4B;GACzC;EACD;EAEA,OADA,EAAW,CAAC,SACC;GAEZ,AADA,EAAE,QAAQ,GACV,EAAW,IAAI;EAChB;CACD,GAAG,CAAC,CAAC,GAGL,EAA0D,SAAW,GAAS,CAAC,CAAO,CAAC;CAGvF,IAAM,CAAC,GAAI,GAAI,KAAM;CA8BrB,OA7BA,QAAgB;EACf,GAAS,OAAO;GAAC;GAAI;GAAI;EAAE,CAAC;CAC7B,GAAG;EAAC;EAAS;EAAI;EAAI;CAAE,CAAC,GAKxB,QAAgB;EACf,GAAS,WAAW,EAAE,OAAI,CAAC;CAC5B,GAAG,CAAC,GAAS,CAAG,CAAC,GACjB,QAAgB;EACf,GAAS,WAAW,EAAE,SAAM,CAAC;CAC9B,GAAG,CAAC,GAAS,CAAK,CAAC,GACnB,QAAgB;EACf,GAAS,WAAW,EAAE,UAAO,CAAC;CAC/B,GAAG,CAAC,GAAS,CAAM,CAAC,GACpB,QAAgB;EACf,GAAS,WAAW,EAAE,eAAY,CAAC;CACpC,GAAG,CAAC,GAAS,CAAW,CAAC,GACzB,QAAgB;EACf,GAAS,WAAW,EAAE,WAAQ,CAAC;CAChC,GAAG,CAAC,GAAS,CAAO,CAAC,GAGrB,QAAgB;EACX,OAAC,KAAW,CAAC,IACjB,OAAO,EAAQ,QAAQ,CAAI;CAC5B,GAAG,CAAC,GAAS,CAAI,CAAC,GAEX,kBAAC,UAAD;EAAQ,KAAK;EAAsB;EAAW,OAAO;GAAE,GAAG;GAAW,GAAG;EAAM;CAAI,CAAA;AAC1F,CAAC,GCtFK,IAA2B;CAAE,SAAS;CAAS,OAAO;CAAQ,QAAQ;AAAO,GAQtE,IAAY,EACxB,SAAmB,GAAO,GAAK;CAC9B,IAAM,EACL,WAAQ,MACR,eAAY,WACZ,UACA,SACA,eACA,SACA,UACA,eACA,cACA,aACG,GACE,IAAY,EAA0B,IAAI,GAC1C,CAAC,GAAM,KAAW,EAAiC,IAAI,GAGvD,IAAY,EAAO,CAAK;CAyC9B,OAxCA,EAAU,UAAU,GAGpB,QAAgB;EACf,IAAM,IAAS,EAAU;EACzB,IAAI,CAAC,GAAQ;EACb,IAAM,IAAI,EAAU,SACd,IAAI,EAAgB,GAAQ;GACjC,OAAO,EAAE,SAAS;GAClB,OAAO,EAAE;GACT,OAAO,EAAE;GACT,MAAM,EAAE;GACR,YAAY,EAAE;GACd,MAAM,EAAE;GACR,OAAO,EAAE;GACT,YAAY,EAAE;EACf,CAAC;EACD,IAAI,CAAC,GAAG;GACP,QAAQ,KAAK,kCAAkC;GAC/C;EACD;EAEA,OADA,EAAQ,CAAC,SACI;GAEZ,AADA,EAAE,QAAQ,GACV,EAAQ,IAAI;EACb;CACD,GAAG,CAAC,CAAC,GAEL,EAAoE,SAAW,GAAM,CAAC,CAAI,CAAC,GAG3F,QAAgB;EACf,GAAM,SAAS,KAAS,IAAI;CAC7B,GAAG,CAAC,GAAM,CAAK,CAAC,GAGhB,QAAgB;EACf,GAAM,WAAW;GAAE,OAAO;GAAW;GAAO;GAAM;GAAY;GAAM;GAAO;EAAW,CAAC;CACxF,GAAG;EAAC;EAAM;EAAW;EAAO;EAAM;EAAY;EAAM;EAAO;CAAU,CAAC,GAE/D,kBAAC,UAAD;EAAQ,KAAK;EAAsB;EAAW,OAAO;GAAE,GAAG;GAAW,GAAG;EAAM;CAAI,CAAA;AAC1F,CACD"}
package/package.json ADDED
@@ -0,0 +1,85 @@
1
+ {
2
+ "name": "@glowbox/react",
3
+ "version": "1.0.0-rc.2",
4
+ "description": "glowbox components for React — <LedGrid> (3D WebGL LED grid) + <NixieTube> (nixie-tube display).",
5
+ "keywords": [
6
+ "react",
7
+ "led",
8
+ "led-cube",
9
+ "webgl",
10
+ "voxel",
11
+ "3d",
12
+ "nixie",
13
+ "component"
14
+ ],
15
+ "license": "MIT",
16
+ "type": "module",
17
+ "sideEffects": false,
18
+ "files": [
19
+ "dist"
20
+ ],
21
+ "types": "./dist/index.d.ts",
22
+ "module": "./dist/index.js",
23
+ "exports": {
24
+ ".": {
25
+ "types": "./dist/index.d.ts",
26
+ "import": "./dist/index.js"
27
+ }
28
+ },
29
+ "publishConfig": {
30
+ "access": "public"
31
+ },
32
+ "repository": {
33
+ "type": "git",
34
+ "url": "git+https://github.com/eetu/glowbox.git",
35
+ "directory": "packages/react"
36
+ },
37
+ "homepage": "https://eetu.github.io/glowbox/",
38
+ "scripts": {
39
+ "build": "vite build",
40
+ "prepack": "vite build",
41
+ "test": "vitest run",
42
+ "lint": "eslint .",
43
+ "lint:fix": "eslint . --fix",
44
+ "typecheck": "tsc --noEmit",
45
+ "size": "size-limit"
46
+ },
47
+ "size-limit": [
48
+ {
49
+ "name": "esm (own code; react + core external)",
50
+ "path": "dist/index.js",
51
+ "ignore": [
52
+ "react",
53
+ "react-dom",
54
+ "react/jsx-runtime",
55
+ "@glowbox/led-grid",
56
+ "@glowbox/nixie"
57
+ ],
58
+ "limit": "1.5 kB"
59
+ }
60
+ ],
61
+ "peerDependencies": {
62
+ "react": "^18 || ^19"
63
+ },
64
+ "dependencies": {
65
+ "@glowbox/led-grid": "^1.0.0-rc.2",
66
+ "@glowbox/nixie": "^1.0.0-rc.2"
67
+ },
68
+ "devDependencies": {
69
+ "@anarkisti/eslint-config": "^1",
70
+ "@types/react": "^19",
71
+ "@types/react-dom": "^19",
72
+ "@vitejs/plugin-react": "^5",
73
+ "@vitest/browser": "^4.1",
74
+ "@vitest/browser-playwright": "^4.1",
75
+ "eslint": "^10",
76
+ "playwright": "^1.61",
77
+ "react": "^19",
78
+ "react-dom": "^19",
79
+ "typescript": "^6",
80
+ "vite": "^8.1",
81
+ "vite-plugin-dts": "^5",
82
+ "vitest": "^4.1",
83
+ "vitest-browser-react": "^1"
84
+ }
85
+ }