3d-marquee 0.1.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/README.md ADDED
@@ -0,0 +1,80 @@
1
+ # LED Marquee Orb
2
+
3
+ A React + Vite single-page application featuring a 3D rotating orb with a scrolling LED marquee effect. The word scrolls horizontally across the center band of the sphere, creating a seamless ticker display.
4
+
5
+ ## Features
6
+
7
+ - **3D Rotating Orb**: Smoothly rotating sphere with orbit controls
8
+ - **LED Marquee Effect**: Text scrolls horizontally across the center band
9
+ - **Shader-Based Rendering**: High-performance GPU-accelerated LED matrix effect
10
+ - **Bloom Post-Processing**: Glowing LED effect with bloom shader
11
+ - **Responsive Design**: Full viewport canvas that adapts to screen size
12
+
13
+ ## Installation
14
+
15
+ 1. Install dependencies:
16
+ ```bash
17
+ npm install
18
+ ```
19
+
20
+ ## Running the Application
21
+
22
+ Start the development server:
23
+ ```bash
24
+ npm run dev
25
+ ```
26
+
27
+ The application will be available at `http://localhost:5173` (or the port shown in the terminal).
28
+
29
+ ## Building for Production
30
+
31
+ Build the production bundle:
32
+ ```bash
33
+ npm run build
34
+ ```
35
+
36
+ Preview the production build:
37
+ ```bash
38
+ npm run preview
39
+ ```
40
+
41
+ ## Component API
42
+
43
+ The `LedMarqueeOrb` component accepts the following props:
44
+
45
+ - `word` (string, required): The text to display on the marquee
46
+ - `speed` (number, optional, default: 0.25): Scroll speed multiplier
47
+ - `radius` (number, optional, default: 1): Sphere radius
48
+ - `bandHeight` (number, optional, default: 0.2): Height of the LED band (0-1)
49
+ - `ledSpacing` (number, optional, default: 0.05): Spacing between LED dots
50
+
51
+ ## Example Usage
52
+
53
+ ```tsx
54
+ <LedMarqueeOrb word="ROADHERO" speed={0.3} radius={1.2} />
55
+ ```
56
+
57
+ ## Technologies
58
+
59
+ - **React 18**: UI framework
60
+ - **Vite**: Build tool and dev server
61
+ - **TypeScript**: Type safety
62
+ - **Three.js**: 3D graphics library
63
+ - **@react-three/fiber**: React renderer for Three.js
64
+ - **@react-three/drei**: Useful helpers and abstractions
65
+ - **@react-three/postprocessing**: Post-processing effects (bloom)
66
+
67
+ ## Controls
68
+
69
+ - **Mouse Drag**: Rotate the camera around the orb
70
+ - **Scroll**: Zoom in/out (if enabled)
71
+
72
+ ## Implementation Details
73
+
74
+ The LED marquee effect is implemented using a custom shader material that:
75
+ 1. Samples a canvas texture containing the repeated word
76
+ 2. Constrains rendering to a horizontal band around the sphere's equator
77
+ 3. Quantizes UV coordinates into a grid for the LED dot matrix effect
78
+ 4. Applies scrolling offset for the marquee animation
79
+ 5. Uses emissive colors and bloom post-processing for the glow effect
80
+
@@ -0,0 +1,217 @@
1
+ import { jsx as a, jsxs as J } from "react/jsx-runtime";
2
+ import { useFrame as K, Canvas as N } from "@react-three/fiber";
3
+ import { Environment as Z, OrbitControls as $ } from "@react-three/drei";
4
+ import { EffectComposer as ee, Bloom as te } from "@react-three/postprocessing";
5
+ import { useRef as C, useMemo as h, useEffect as oe } from "react";
6
+ import * as c from "three";
7
+ function re({
8
+ word: u = "ROADHERO",
9
+ speed: S = 0.05,
10
+ radius: g = 1,
11
+ ledSpacing: m = 75e-4,
12
+ columnSpacing: M = 5e-3,
13
+ dimColor: E = "#1a261a",
14
+ brightColor: T = "#00ff4d"
15
+ }) {
16
+ const z = C(null), L = C(0), w = C(null), b = C(0), R = C(0), F = h(() => {
17
+ const e = Math.ceil(Math.PI / m), r = Math.ceil(2 * Math.PI / M);
18
+ return { rows: e, cols: r };
19
+ }, [m, M]), q = (e, r) => new Uint8Array(e * r).fill(0), I = (e, r, f, d) => {
20
+ r.fill(0);
21
+ const v = document.createElement("canvas"), t = v.getContext("2d");
22
+ if (!t) return;
23
+ const s = 2048, x = 256;
24
+ v.width = s, v.height = x, t.fillStyle = "#000000", t.fillRect(0, 0, s, x), t.fillStyle = "#ffffff", t.font = "bold 80px monospace", t.textAlign = "center", t.textBaseline = "middle";
25
+ const P = t.measureText(e).width + 200, X = Math.ceil(s / P) + 2;
26
+ for (let l = -1; l < X; l++) {
27
+ const p = s / 2 + l * P;
28
+ t.fillText(e, p, x / 2);
29
+ }
30
+ const j = t.getImageData(0, 0, s, x).data, G = Math.floor(f * 0.4), k = Math.floor(f * 0.6) - G, B = P;
31
+ for (let l = 0; l < x; l++)
32
+ for (let p = 0; p < s; p++) {
33
+ const H = (l * s + p) * 4;
34
+ if (j[H] > 128) {
35
+ const Y = p % B / B, y = Math.floor(Y * d), _ = 1 - l / x, Q = Math.floor(_ * k), U = G + Q;
36
+ U >= 0 && U < f && y >= 0 && y < d && (r[U * d + y] = 1);
37
+ }
38
+ }
39
+ }, O = (e, r, f) => {
40
+ const d = new Uint8Array(r * f);
41
+ for (let t = 0; t < e.length; t++)
42
+ d[t] = e[t] * 255;
43
+ const v = new c.DataTexture(d, f, r, c.RedFormat);
44
+ return v.needsUpdate = !0, v;
45
+ }, { rows: i, cols: n } = F;
46
+ b.current = i, R.current = n;
47
+ const A = h(() => {
48
+ const e = q(i, n);
49
+ return I(u, e, i, n), w.current = e, e;
50
+ }, [u, i, n]), D = h(() => O(A, i, n), [A, i, n]), V = h(() => {
51
+ const e = new c.Color(E);
52
+ return new c.Vector3(e.r, e.g, e.b);
53
+ }, [E]), W = h(() => {
54
+ const e = new c.Color(T);
55
+ return new c.Vector3(e.r, e.g, e.b);
56
+ }, [T]), o = h(() => D ? new c.ShaderMaterial({
57
+ transparent: !0,
58
+ uniforms: {
59
+ uLedMatrix: { value: D },
60
+ uScrollOffset: { value: 0 },
61
+ uLedSpacing: { value: m },
62
+ uColumnSpacing: { value: M },
63
+ uRadius: { value: g },
64
+ uTime: { value: 0 },
65
+ uMatrixRows: { value: i },
66
+ uMatrixCols: { value: n },
67
+ uDimColor: { value: V },
68
+ uBrightColor: { value: W }
69
+ },
70
+ vertexShader: `
71
+ varying vec3 vWorldPosition;
72
+ varying vec2 vUv;
73
+
74
+ void main() {
75
+ vUv = uv;
76
+ vec4 worldPosition = modelMatrix * vec4(position, 1.0);
77
+ vWorldPosition = worldPosition.xyz;
78
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
79
+ }
80
+ `,
81
+ fragmentShader: `
82
+ uniform sampler2D uLedMatrix;
83
+ uniform float uScrollOffset;
84
+ uniform float uLedSpacing;
85
+ uniform float uColumnSpacing;
86
+ uniform float uRadius;
87
+ uniform float uTime;
88
+ uniform float uMatrixRows;
89
+ uniform float uMatrixCols;
90
+ uniform vec3 uDimColor;
91
+ uniform vec3 uBrightColor;
92
+
93
+ varying vec3 vWorldPosition;
94
+ varying vec2 vUv;
95
+
96
+ void main() {
97
+ // Convert world position to spherical coordinates
98
+ vec3 pos = normalize(vWorldPosition);
99
+ float latitude = asin(pos.y); // -PI/2 to PI/2 (south pole to north pole)
100
+ float longitude = atan(pos.z, pos.x); // -PI to PI
101
+
102
+ // Calculate matrix coordinates from latitude/longitude
103
+ // Latitude: -PI/2 to PI/2 -> row 0 to uMatrixRows-1
104
+ float normalizedLat = (latitude + 1.5708) / 3.14159; // 0 to 1
105
+ float row = floor(normalizedLat * uMatrixRows);
106
+ row = clamp(row, 0.0, uMatrixRows - 1.0);
107
+
108
+ // Longitude: -PI to PI -> col 0 to uMatrixCols-1
109
+ // Apply scroll offset for marquee effect
110
+ // Flip longitude direction to fix backwards text
111
+ float normalizedLon = 1.0 - ((longitude + 3.14159) / (2.0 * 3.14159)); // 1 to 0 (flipped)
112
+ float scrolledLon = mod(normalizedLon + uScrollOffset, 1.0);
113
+ float col = floor(scrolledLon * uMatrixCols);
114
+ col = clamp(col, 0.0, uMatrixCols - 1.0);
115
+
116
+ // Sample matrix texture at calculated coordinates
117
+ // Texture coordinates: (col/uMatrixCols, row/uMatrixRows)
118
+ vec2 matrixUv = vec2(col / uMatrixCols, row / uMatrixRows);
119
+ vec4 matrixValue = texture2D(uLedMatrix, matrixUv);
120
+ float ledState = matrixValue.r; // 0.0 (off) or 1.0 (on)
121
+
122
+ // Quantize UVs into LED grid for dot matrix effect
123
+ float columnGridSize = 1.0 / uColumnSpacing;
124
+ float rowGridSize = 1.0 / uLedSpacing;
125
+ vec2 gridUv = vec2(
126
+ floor(vUv.x * columnGridSize) / columnGridSize,
127
+ floor(vUv.y * rowGridSize) / rowGridSize
128
+ );
129
+ vec2 gridCenter = vec2(
130
+ gridUv.x + uColumnSpacing * 0.5,
131
+ gridUv.y + uLedSpacing * 0.5
132
+ );
133
+ vec2 distFromCenter = abs(vUv - gridCenter);
134
+ float maxDist = min(uColumnSpacing, uLedSpacing) * 0.2;
135
+
136
+ // Create circular LED dots
137
+ float dist = length(distFromCenter);
138
+ float ledShape = smoothstep(maxDist, maxDist * 0.7, dist);
139
+
140
+ // Use color uniforms from props
141
+ vec3 dimLedColor = uDimColor;
142
+ vec3 brightLedColor = uBrightColor;
143
+
144
+ // Mix between dim and bright based on matrix state
145
+ vec3 ledColor = mix(dimLedColor, brightLedColor, ledState);
146
+
147
+ // Apply LED shape - this creates the circular bulbs with transparent space between
148
+ vec3 finalColor = mix(
149
+ vec3(0.0, 0.0, 0.0), // Black space between bulbs (will be transparent)
150
+ ledColor, // LED color (dim or bright)
151
+ ledShape
152
+ );
153
+
154
+ // Add emissive glow for bright message LEDs
155
+ float emissive = ledState * ledShape * 1.5;
156
+
157
+ // Calculate alpha: transparent where there are no LEDs, opaque where LEDs are visible
158
+ // Use ledShape directly as alpha so LEDs are visible and space between is transparent
159
+ float alpha = ledShape;
160
+
161
+ gl_FragColor = vec4(finalColor + vec3(emissive * 0.2), alpha);
162
+ }
163
+ `
164
+ }) : null, [D, m, M, g, i, n, V, W]);
165
+ return K((e, r) => {
166
+ z.current && w.current && (L.current += r * S, L.current >= 1 && (L.current -= 1), o && "uniforms" in o && (o.uniforms.uScrollOffset.value = L.current, o.uniforms.uTime.value = e.clock.elapsedTime));
167
+ }), oe(() => {
168
+ if (w.current && (I(
169
+ u,
170
+ w.current,
171
+ b.current,
172
+ R.current
173
+ ), o && "uniforms" in o)) {
174
+ const e = O(
175
+ w.current,
176
+ b.current,
177
+ R.current
178
+ );
179
+ o.uniforms.uLedMatrix.value = e, o.needsUpdate = !0;
180
+ }
181
+ }, [u, o]), o ? /* @__PURE__ */ a("mesh", { ref: z, material: o, children: /* @__PURE__ */ a("sphereGeometry", { args: [g, 64, 64] }) }) : null;
182
+ }
183
+ const ve = ({ word: u, speed: S, dimColor: g, brightColor: m }) => /* @__PURE__ */ J(
184
+ N,
185
+ {
186
+ camera: { position: [0, 0, 5], fov: 50 },
187
+ gl: { antialias: !0, alpha: !0 },
188
+ children: [
189
+ /* @__PURE__ */ a("ambientLight", { intensity: 0.3 }),
190
+ /* @__PURE__ */ a("pointLight", { position: [10, 10, 10], intensity: 0.5 }),
191
+ /* @__PURE__ */ a(Z, { preset: "city" }),
192
+ /* @__PURE__ */ a(
193
+ re,
194
+ {
195
+ word: u,
196
+ speed: S,
197
+ dimColor: g,
198
+ brightColor: m
199
+ }
200
+ ),
201
+ /* @__PURE__ */ a(
202
+ $,
203
+ {
204
+ enablePan: !1,
205
+ minDistance: 3,
206
+ maxDistance: 8,
207
+ minPolarAngle: Math.PI / 3,
208
+ maxPolarAngle: Math.PI - Math.PI / 3
209
+ }
210
+ ),
211
+ /* @__PURE__ */ a(ee, { children: /* @__PURE__ */ a(te, { intensity: 1.5, luminanceThreshold: 0.9, luminanceSmoothing: 0.9 }) })
212
+ ]
213
+ }
214
+ );
215
+ export {
216
+ ve as LedMarqueeOrbContainer
217
+ };
@@ -0,0 +1,93 @@
1
+ (function(r,o){typeof exports=="object"&&typeof module<"u"?o(exports,require("react/jsx-runtime"),require("@react-three/fiber"),require("@react-three/drei"),require("@react-three/postprocessing"),require("react"),require("three")):typeof define=="function"&&define.amd?define(["exports","react/jsx-runtime","@react-three/fiber","@react-three/drei","@react-three/postprocessing","react","three"],o):(r=typeof globalThis<"u"?globalThis:r||self,o(r.ThreeDMarquee={},r.jsxRuntime,r.ReactThreeFiber,r.Drei,r.Postprocessing,r.React,r.THREE))})(this,function(r,o,E,U,z,i,_){"use strict";function k(a){const p=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(a){for(const l in a)if(l!=="default"){const c=Object.getOwnPropertyDescriptor(a,l);Object.defineProperty(p,l,c.get?c:{enumerable:!0,get:()=>a[l]})}}return p.default=a,Object.freeze(p)}const m=k(_);function H({word:a="ROADHERO",speed:p=.05,radius:l=1,ledSpacing:c=.0075,columnSpacing:L=.005,dimColor:O="#1a261a",brightColor:I="#00ff4d"}){const q=i.useRef(null),S=i.useRef(0),C=i.useRef(null),b=i.useRef(0),D=i.useRef(0),Y=i.useMemo(()=>{const e=Math.ceil(Math.PI/c),s=Math.ceil(2*Math.PI/L);return{rows:e,cols:s}},[c,L]),N=(e,s)=>new Uint8Array(e*s).fill(0),j=(e,s,x,h)=>{s.fill(0);const g=document.createElement("canvas"),t=g.getContext("2d");if(!t)return;const v=2048,M=256;g.width=v,g.height=M,t.fillStyle="#000000",t.fillRect(0,0,v,M),t.fillStyle="#ffffff",t.font="bold 80px monospace",t.textAlign="center",t.textBaseline="middle";const P=t.measureText(e).width+200,Q=Math.ceil(v/P)+2;for(let d=-1;d<Q;d++){const w=v/2+d*P;t.fillText(e,w,M/2)}const J=t.getImageData(0,0,v,M).data,G=Math.floor(x*.4),K=Math.floor(x*.6)-G,B=P;for(let d=0;d<M;d++)for(let w=0;w<v;w++){const Z=(d*v+w)*4;if(J[Z]>128){const $=w%B/B,R=Math.floor($*h),ee=1-d/M,te=Math.floor(ee*K),T=G+te;T>=0&&T<x&&R>=0&&R<h&&(s[T*h+R]=1)}}},A=(e,s,x)=>{const h=new Uint8Array(s*x);for(let t=0;t<e.length;t++)h[t]=e[t]*255;const g=new m.DataTexture(h,x,s,m.RedFormat);return g.needsUpdate=!0,g},{rows:u,cols:f}=Y;b.current=u,D.current=f;const V=i.useMemo(()=>{const e=N(u,f);return j(a,e,u,f),C.current=e,e},[a,u,f]),y=i.useMemo(()=>A(V,u,f),[V,u,f]),W=i.useMemo(()=>{const e=new m.Color(O);return new m.Vector3(e.r,e.g,e.b)},[O]),F=i.useMemo(()=>{const e=new m.Color(I);return new m.Vector3(e.r,e.g,e.b)},[I]),n=i.useMemo(()=>y?new m.ShaderMaterial({transparent:!0,uniforms:{uLedMatrix:{value:y},uScrollOffset:{value:0},uLedSpacing:{value:c},uColumnSpacing:{value:L},uRadius:{value:l},uTime:{value:0},uMatrixRows:{value:u},uMatrixCols:{value:f},uDimColor:{value:W},uBrightColor:{value:F}},vertexShader:`
2
+ varying vec3 vWorldPosition;
3
+ varying vec2 vUv;
4
+
5
+ void main() {
6
+ vUv = uv;
7
+ vec4 worldPosition = modelMatrix * vec4(position, 1.0);
8
+ vWorldPosition = worldPosition.xyz;
9
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
10
+ }
11
+ `,fragmentShader:`
12
+ uniform sampler2D uLedMatrix;
13
+ uniform float uScrollOffset;
14
+ uniform float uLedSpacing;
15
+ uniform float uColumnSpacing;
16
+ uniform float uRadius;
17
+ uniform float uTime;
18
+ uniform float uMatrixRows;
19
+ uniform float uMatrixCols;
20
+ uniform vec3 uDimColor;
21
+ uniform vec3 uBrightColor;
22
+
23
+ varying vec3 vWorldPosition;
24
+ varying vec2 vUv;
25
+
26
+ void main() {
27
+ // Convert world position to spherical coordinates
28
+ vec3 pos = normalize(vWorldPosition);
29
+ float latitude = asin(pos.y); // -PI/2 to PI/2 (south pole to north pole)
30
+ float longitude = atan(pos.z, pos.x); // -PI to PI
31
+
32
+ // Calculate matrix coordinates from latitude/longitude
33
+ // Latitude: -PI/2 to PI/2 -> row 0 to uMatrixRows-1
34
+ float normalizedLat = (latitude + 1.5708) / 3.14159; // 0 to 1
35
+ float row = floor(normalizedLat * uMatrixRows);
36
+ row = clamp(row, 0.0, uMatrixRows - 1.0);
37
+
38
+ // Longitude: -PI to PI -> col 0 to uMatrixCols-1
39
+ // Apply scroll offset for marquee effect
40
+ // Flip longitude direction to fix backwards text
41
+ float normalizedLon = 1.0 - ((longitude + 3.14159) / (2.0 * 3.14159)); // 1 to 0 (flipped)
42
+ float scrolledLon = mod(normalizedLon + uScrollOffset, 1.0);
43
+ float col = floor(scrolledLon * uMatrixCols);
44
+ col = clamp(col, 0.0, uMatrixCols - 1.0);
45
+
46
+ // Sample matrix texture at calculated coordinates
47
+ // Texture coordinates: (col/uMatrixCols, row/uMatrixRows)
48
+ vec2 matrixUv = vec2(col / uMatrixCols, row / uMatrixRows);
49
+ vec4 matrixValue = texture2D(uLedMatrix, matrixUv);
50
+ float ledState = matrixValue.r; // 0.0 (off) or 1.0 (on)
51
+
52
+ // Quantize UVs into LED grid for dot matrix effect
53
+ float columnGridSize = 1.0 / uColumnSpacing;
54
+ float rowGridSize = 1.0 / uLedSpacing;
55
+ vec2 gridUv = vec2(
56
+ floor(vUv.x * columnGridSize) / columnGridSize,
57
+ floor(vUv.y * rowGridSize) / rowGridSize
58
+ );
59
+ vec2 gridCenter = vec2(
60
+ gridUv.x + uColumnSpacing * 0.5,
61
+ gridUv.y + uLedSpacing * 0.5
62
+ );
63
+ vec2 distFromCenter = abs(vUv - gridCenter);
64
+ float maxDist = min(uColumnSpacing, uLedSpacing) * 0.2;
65
+
66
+ // Create circular LED dots
67
+ float dist = length(distFromCenter);
68
+ float ledShape = smoothstep(maxDist, maxDist * 0.7, dist);
69
+
70
+ // Use color uniforms from props
71
+ vec3 dimLedColor = uDimColor;
72
+ vec3 brightLedColor = uBrightColor;
73
+
74
+ // Mix between dim and bright based on matrix state
75
+ vec3 ledColor = mix(dimLedColor, brightLedColor, ledState);
76
+
77
+ // Apply LED shape - this creates the circular bulbs with transparent space between
78
+ vec3 finalColor = mix(
79
+ vec3(0.0, 0.0, 0.0), // Black space between bulbs (will be transparent)
80
+ ledColor, // LED color (dim or bright)
81
+ ledShape
82
+ );
83
+
84
+ // Add emissive glow for bright message LEDs
85
+ float emissive = ledState * ledShape * 1.5;
86
+
87
+ // Calculate alpha: transparent where there are no LEDs, opaque where LEDs are visible
88
+ // Use ledShape directly as alpha so LEDs are visible and space between is transparent
89
+ float alpha = ledShape;
90
+
91
+ gl_FragColor = vec4(finalColor + vec3(emissive * 0.2), alpha);
92
+ }
93
+ `}):null,[y,c,L,l,u,f,W,F]);return E.useFrame((e,s)=>{q.current&&C.current&&(S.current+=s*p,S.current>=1&&(S.current-=1),n&&"uniforms"in n&&(n.uniforms.uScrollOffset.value=S.current,n.uniforms.uTime.value=e.clock.elapsedTime))}),i.useEffect(()=>{if(C.current&&(j(a,C.current,b.current,D.current),n&&"uniforms"in n)){const e=A(C.current,b.current,D.current);n.uniforms.uLedMatrix.value=e,n.needsUpdate=!0}},[a,n]),n?o.jsx("mesh",{ref:q,material:n,children:o.jsx("sphereGeometry",{args:[l,64,64]})}):null}const X=({word:a,speed:p,dimColor:l,brightColor:c})=>o.jsxs(E.Canvas,{camera:{position:[0,0,5],fov:50},gl:{antialias:!0,alpha:!0},children:[o.jsx("ambientLight",{intensity:.3}),o.jsx("pointLight",{position:[10,10,10],intensity:.5}),o.jsx(U.Environment,{preset:"city"}),o.jsx(H,{word:a,speed:p,dimColor:l,brightColor:c}),o.jsx(U.OrbitControls,{enablePan:!1,minDistance:3,maxDistance:8,minPolarAngle:Math.PI/3,maxPolarAngle:Math.PI-Math.PI/3}),o.jsx(z.EffectComposer,{children:o.jsx(z.Bloom,{intensity:1.5,luminanceThreshold:.9,luminanceSmoothing:.9})})]});r.LedMarqueeOrbContainer=X,Object.defineProperty(r,Symbol.toStringTag,{value:"Module"})});
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "3d-marquee",
3
+ "version": "0.1.1",
4
+ "type": "module",
5
+ "main": "./dist/3d-marquee.umd.js",
6
+ "module": "./dist/3d-marquee.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/3d-marquee.js",
11
+ "require": "./dist/3d-marquee.umd.js",
12
+ "types": "./dist/index.d.ts"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "scripts": {
19
+ "dev": "vite",
20
+ "build": "tsc && vite build",
21
+ "build:lib": "tsc -p tsconfig.build.json && vite build --mode library",
22
+ "preview": "vite preview"
23
+ },
24
+ "peerDependencies": {
25
+ "@react-three/drei": "^9.92.7",
26
+ "@react-three/fiber": "^8.15.11",
27
+ "@react-three/postprocessing": "^2.15.9",
28
+ "react": "^18.2.0",
29
+ "react-dom": "^18.2.0",
30
+ "three": "^0.158.0"
31
+ },
32
+ "dependencies": {
33
+ "@react-three/drei": "^9.92.7",
34
+ "@react-three/fiber": "^8.15.11",
35
+ "@react-three/postprocessing": "^2.15.9",
36
+ "react": "^18.2.0",
37
+ "react-dom": "^18.2.0",
38
+ "three": "^0.158.0"
39
+ },
40
+ "devDependencies": {
41
+ "@types/node": "^25.0.3",
42
+ "@types/react": "^18.2.43",
43
+ "@types/react-dom": "^18.2.17",
44
+ "@types/three": "^0.158.3",
45
+ "@vitejs/plugin-react": "^4.2.1",
46
+ "typescript": "^5.2.2",
47
+ "vite": "^5.0.8"
48
+ }
49
+ }