godlights 0.1.0
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 +198 -0
- package/dist/godlights.js +8 -0
- package/dist/godlights.mjs +435 -0
- package/dist/index.d.ts +181 -0
- package/package.json +54 -0
package/README.md
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
# godlights
|
|
2
|
+
|
|
3
|
+
Animated god-ray / light-beam effects for React. Render stunning volumetric light scenes on a `<canvas>`, fully configurable and animatable.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install godlights
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick start
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
import { GodLights } from "godlights";
|
|
15
|
+
import type { SceneConfig } from "godlights";
|
|
16
|
+
|
|
17
|
+
const scene: SceneConfig = {
|
|
18
|
+
width: 1920,
|
|
19
|
+
height: 1080,
|
|
20
|
+
noise: 8,
|
|
21
|
+
grainSize: 1,
|
|
22
|
+
layers: [
|
|
23
|
+
{
|
|
24
|
+
id: "bg",
|
|
25
|
+
type: "background",
|
|
26
|
+
bgType: "solid",
|
|
27
|
+
bgColor: "#000000",
|
|
28
|
+
bgColor2: "#000000",
|
|
29
|
+
bgGradientAngle: 180,
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
id: "rays-1",
|
|
33
|
+
name: "Rays 1",
|
|
34
|
+
type: "rays",
|
|
35
|
+
direction: 180,
|
|
36
|
+
spread: 120,
|
|
37
|
+
originX: 50,
|
|
38
|
+
originY: -20,
|
|
39
|
+
rayCount: 40,
|
|
40
|
+
rayWidth: 87,
|
|
41
|
+
divergence: 0.4,
|
|
42
|
+
rayLength: 0.55,
|
|
43
|
+
colorStart: "#ffffff",
|
|
44
|
+
colorEnd: "#ffffff",
|
|
45
|
+
opacity: 0.42,
|
|
46
|
+
blendMode: "screen",
|
|
47
|
+
fadeToTransparent: true,
|
|
48
|
+
blur: 17.5,
|
|
49
|
+
randomnessWidth: 100,
|
|
50
|
+
randomnessLength: 24,
|
|
51
|
+
randomnessAngle: 0,
|
|
52
|
+
seed: 1337,
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
id: "halo-1",
|
|
56
|
+
name: "Halo 1",
|
|
57
|
+
type: "halo",
|
|
58
|
+
originX: 50,
|
|
59
|
+
originY: 0,
|
|
60
|
+
color: "#ffffff",
|
|
61
|
+
intensity: 0.25,
|
|
62
|
+
size: 0.5,
|
|
63
|
+
blendMode: "lighter",
|
|
64
|
+
},
|
|
65
|
+
],
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export default function App() {
|
|
69
|
+
return (
|
|
70
|
+
<GodLights
|
|
71
|
+
scene={scene}
|
|
72
|
+
animate
|
|
73
|
+
className="absolute inset-0 w-full h-full"
|
|
74
|
+
/>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## `<GodLights>` props
|
|
80
|
+
|
|
81
|
+
| Prop | Type | Default | Description |
|
|
82
|
+
|------|------|---------|-------------|
|
|
83
|
+
| `scene` | `SceneConfig` | required | Full scene configuration |
|
|
84
|
+
| `animate` | `boolean` | `false` | Enable animation loop |
|
|
85
|
+
| `animParams` | `AnimParams` | `DEFAULT_ANIM_PARAMS` | Animation parameters (speed, amplitudes) |
|
|
86
|
+
| `showFps` | `boolean` | `false` | Show FPS counter overlay |
|
|
87
|
+
| `className` | `string` | — | CSS class for the wrapper `<div>` |
|
|
88
|
+
| `style` | `CSSProperties` | — | Inline style for the wrapper `<div>` |
|
|
89
|
+
|
|
90
|
+
## `SceneConfig`
|
|
91
|
+
|
|
92
|
+
```ts
|
|
93
|
+
interface SceneConfig {
|
|
94
|
+
width: number; // Canvas width in px (used for aspect ratio)
|
|
95
|
+
height: number; // Canvas height in px
|
|
96
|
+
noise: number; // Film grain intensity (0–100)
|
|
97
|
+
grainSize: number; // Film grain pixel size (1–4)
|
|
98
|
+
layers: Layer[]; // Ordered list of layers (bottom to top)
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Layer types
|
|
103
|
+
|
|
104
|
+
### `BackgroundLayer`
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
{
|
|
108
|
+
id: string;
|
|
109
|
+
type: "background";
|
|
110
|
+
bgType: "solid" | "linear" | "radial";
|
|
111
|
+
bgColor: string; // Hex color (primary)
|
|
112
|
+
bgColor2: string; // Hex color (secondary, for gradients)
|
|
113
|
+
bgGradientAngle: number; // Gradient angle in degrees
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### `RayLayer`
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
{
|
|
121
|
+
id: string;
|
|
122
|
+
name: string;
|
|
123
|
+
type: "rays";
|
|
124
|
+
direction: number; // Angle the rays point (degrees)
|
|
125
|
+
spread: number; // Angular spread of ray fan (degrees)
|
|
126
|
+
originX: number; // Origin X (% of canvas width, can be < 0 or > 100)
|
|
127
|
+
originY: number; // Origin Y (% of canvas height, can be < 0 or > 100)
|
|
128
|
+
rayCount: number; // Number of rays
|
|
129
|
+
rayWidth: number; // Ray width (1–200)
|
|
130
|
+
divergence: number; // How much rays splay out (0.1–5)
|
|
131
|
+
rayLength: number; // Ray length as fraction of canvas diagonal (0.1–3)
|
|
132
|
+
colorStart: string; // Hex color at origin
|
|
133
|
+
colorEnd: string; // Hex color at tip
|
|
134
|
+
opacity: number; // Overall opacity (0–1)
|
|
135
|
+
blendMode: BlendMode; // CSS blend mode
|
|
136
|
+
fadeToTransparent: boolean; // Fade tips to transparent
|
|
137
|
+
blur: number; // Gaussian blur in px (0–100)
|
|
138
|
+
randomnessWidth: number; // Width randomness (0–100)
|
|
139
|
+
randomnessLength: number; // Length randomness (0–100)
|
|
140
|
+
randomnessAngle: number; // Angle randomness (0–100)
|
|
141
|
+
seed: number; // RNG seed for reproducible randomness
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### `HaloLayer`
|
|
146
|
+
|
|
147
|
+
```ts
|
|
148
|
+
{
|
|
149
|
+
id: string;
|
|
150
|
+
name: string;
|
|
151
|
+
type: "halo";
|
|
152
|
+
originX: number; // Center X (% of canvas width)
|
|
153
|
+
originY: number; // Center Y (% of canvas height)
|
|
154
|
+
color: string; // Hex color
|
|
155
|
+
intensity: number; // Brightness (0–1)
|
|
156
|
+
size: number; // Radius as fraction of canvas diagonal (0.01–2)
|
|
157
|
+
blendMode: BlendMode;
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## `AnimParams`
|
|
162
|
+
|
|
163
|
+
```ts
|
|
164
|
+
interface AnimParams {
|
|
165
|
+
speed: number; // Animation speed (0–10)
|
|
166
|
+
angleAmp: number; // Ray angle oscillation amplitude (0–100)
|
|
167
|
+
lengthAmp: number; // Ray length oscillation amplitude (0–100)
|
|
168
|
+
widthAmp: number; // Ray width oscillation amplitude (0–100)
|
|
169
|
+
haloAmp: number; // Halo intensity oscillation amplitude (0–100)
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## Default values
|
|
174
|
+
|
|
175
|
+
```ts
|
|
176
|
+
import {
|
|
177
|
+
DEFAULT_SCENE,
|
|
178
|
+
DEFAULT_RAY_LAYER,
|
|
179
|
+
DEFAULT_HALO_LAYER,
|
|
180
|
+
DEFAULT_BACKGROUND_LAYER,
|
|
181
|
+
DEFAULT_ANIM_PARAMS,
|
|
182
|
+
} from "godlights";
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## Utility exports
|
|
186
|
+
|
|
187
|
+
```ts
|
|
188
|
+
import {
|
|
189
|
+
drawScene, // (canvas, scene, t?) => void — draw one frame
|
|
190
|
+
exportScene, // (scene) => Promise<Blob> — export PNG blob
|
|
191
|
+
exportDataURL, // (scene) => Promise<string> — export PNG data URL
|
|
192
|
+
BLEND_MODES, // { value, label }[] — available blend modes
|
|
193
|
+
} from "godlights";
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## License
|
|
197
|
+
|
|
198
|
+
MIT
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const G=require("react/jsx-runtime"),E=require("react"),K=[{label:"Normal",value:"source-over"},{label:"Lighter (additive)",value:"lighter"},{label:"Screen",value:"screen"},{label:"Overlay",value:"overlay"},{label:"Soft light",value:"soft-light"},{label:"Hard light",value:"hard-light"}],J={speed:1,angleAmp:50,lengthAmp:50,widthAmp:50,haloAmp:50},j={type:"rays",direction:200,spread:60,originX:50,originY:0,rayCount:24,rayWidth:60,divergence:1.6,rayLength:1.4,opacity:.6,blendMode:"lighter",colorStart:"#ffffff",colorEnd:"#ffffff",fadeToTransparent:!0,blur:8,randomnessWidth:30,randomnessLength:18,randomnessAngle:30,seed:1337},x={type:"halo",originX:50,originY:0,intensity:.5,size:.25,color:"#ffffff",blendMode:"lighter"},H={id:"background",type:"background",bgType:"solid",bgColor:"#000000",bgColor2:"#000000",bgGradientAngle:180},Q={width:1920,height:1080,noise:8,grainSize:1,layers:[{...H},{id:"halo-1",name:"Halo",...x},{id:"rays-1",name:"Rays",...j}]},Z={width:1920,height:1080,rayCount:24,rayWidth:60,divergence:1.6,rayLength:1.4,opacity:.6,blendMode:"lighter",haloBlendMode:"lighter",direction:200,spread:60,originX:50,originY:0,haloOriginX:50,haloOriginY:0,colorStart:"#ffd28a",colorEnd:"#ffd28a",fadeToTransparent:!0,bgType:"gradient",bgColor:"#0b1024",bgColor2:"#1a1340",bgGradientAngle:180,halo:.5,haloSize:.25,haloColor:"#ffd28a",blur:8,noise:8,grainSize:1,randomness:30,randomnessWidth:30,randomnessLength:18,randomnessAngle:30,seed:1337};function $(e){let t=e>>>0;return function(){t=t+1831565813|0;let o=t;return o=Math.imul(o^o>>>15,o|1),o^=o+Math.imul(o^o>>>7,o|61),((o^o>>>14)>>>0)/4294967296}}function Y(e){const t=e.replace("#","").trim(),o=t.length===3?t.split("").map(i=>i+i).join(""):t.padEnd(6,"0"),n=parseInt(o.substring(0,6),16);return{r:n>>16&255,g:n>>8&255,b:n&255}}function k(e,t){return`rgba(${e.r},${e.g},${e.b},${t})`}function ee(e){return(e-90)*Math.PI/180}function te(e,t,o,n){if(e.save(),e.globalCompositeOperation="source-over",n.bgType==="solid")e.fillStyle=n.bgColor,e.fillRect(0,0,t,o);else if(n.bgType==="gradient"){const i=n.bgGradientAngle*Math.PI/180,a=t/2,s=o/2,r=Math.hypot(t,o)/2,l=Math.cos(i)*r,d=Math.sin(i)*r,c=e.createLinearGradient(a-l,s-d,a+l,s+d);c.addColorStop(0,n.bgColor),c.addColorStop(1,n.bgColor2),e.fillStyle=c,e.fillRect(0,0,t,o)}e.restore()}function ne(e,t,o,n,i=0,a){if(n.intensity<=0)return;e.save(),e.globalCompositeOperation=n.blendMode;const s=n.originX/100*t,r=n.originY/100*o,l=a?a.haloAmp/50:1,d=i!==0?1+Math.sin(i*.4)*.04*l:1,c=Math.hypot(t,o)*n.size*d,m=e.createRadialGradient(s,r,0,s,r,c),f=Y(n.color);m.addColorStop(0,k(f,n.intensity)),m.addColorStop(.5,k(f,n.intensity*.4)),m.addColorStop(1,k(f,0)),e.fillStyle=m,e.beginPath(),e.arc(s,r,c,0,Math.PI*2),e.fill(),e.restore()}function P(e,t,o,n,i=0,a){const s=n.originX/100*t,r=n.originY/100*o,l=ee(n.direction),d=n.spread*Math.PI/180,c=Y(n.colorStart),m=Y(n.colorEnd),y=Math.hypot(t,o)*n.rayLength,b=$(n.seed),R=n.randomnessWidth??n.randomness??0,T=n.randomnessLength??n.randomness??0,O=n.randomnessAngle??n.randomness??0;for(let h=0;h<n.rayCount;h++){const C=n.rayCount===1?.5:h/(n.rayCount-1),M=1-b()*(R/100),L=1-b()*(T/100)*.6,v=n.rayCount>1?d/(n.rayCount-1):d,u=(b()-.5)*(O/100)*v,p=h*2.399,g=a?a.angleAmp/50:1,A=a?a.lengthAmp/50:1,_=a?a.widthAmp/50:1,S=i!==0?Math.sin(i*.6+p)*(Math.max(O,12)/100)*v*.55*g:0,w=i!==0?1+Math.sin(i*.45+p+1.2)*(R/400)*_:1,D=i!==0?1+Math.sin(i*.35+p+2.5)*(T/400)*A:1,V=l-d/2+d*C+u+S,I=Math.max(1,n.rayWidth*M*w),N=Math.max(1,I*n.divergence),z=Math.max(50,y*L*D);e.save(),e.translate(s,r),e.rotate(V);const W=e.createLinearGradient(0,0,z,0);W.addColorStop(0,k(c,n.opacity)),W.addColorStop(1,k(m,n.fadeToTransparent?0:n.opacity)),e.fillStyle=W,e.beginPath(),e.moveTo(0,-I/2),e.lineTo(z,-N/2),e.lineTo(z,N/2),e.lineTo(0,I/2),e.closePath(),e.fill(),e.restore()}}function oe(e,t,o,n,i=0,a){if(n.blur>0){const s=new OffscreenCanvas(t,o),r=s.getContext("2d");if(!r)return;P(r,t,o,n,i,a),e.save(),e.globalCompositeOperation=n.blendMode,e.filter=`blur(${n.blur}px)`,e.drawImage(s,0,0),e.restore()}else e.save(),e.globalCompositeOperation=n.blendMode,P(e,t,o,n,i,a),e.restore()}function U(e,t,o=0,n,i=!1){const a=e.getContext("2d");if(!a)return;const{width:s,height:r}=e;a.clearRect(0,0,s,r);for(const l of t.layers)l.type==="background"?te(a,s,r,l):l.type==="halo"?ne(a,s,r,l,o,n):l.type==="rays"&&oe(a,s,r,l,o,n);!i&&t.noise>0&&re(a,s,r,t.noise,t.grainSize)}function B(e,t){U(e,{width:t.width,height:t.height,noise:t.noise,grainSize:t.grainSize,layers:[{id:"background",type:"background",bgType:t.bgType,bgColor:t.bgColor,bgColor2:t.bgColor2,bgGradientAngle:t.bgGradientAngle},{id:"halo-legacy",type:"halo",name:"Halo",originX:t.haloOriginX,originY:t.haloOriginY,intensity:t.halo,size:t.haloSize,color:t.haloColor,blendMode:t.haloBlendMode},{id:"rays-legacy",type:"rays",name:"Rays",direction:t.direction,spread:t.spread,originX:t.originX,originY:t.originY,rayCount:t.rayCount,rayWidth:t.rayWidth,divergence:t.divergence,rayLength:t.rayLength,opacity:t.opacity,blendMode:t.blendMode,colorStart:t.colorStart,colorEnd:t.colorEnd,fadeToTransparent:t.fadeToTransparent,blur:t.blur,randomness:t.randomness,randomnessWidth:t.randomnessWidth,randomnessLength:t.randomnessLength,randomnessAngle:t.randomnessAngle,seed:t.seed}]})}function re(e,t,o,n,i){const a=Math.max(1,Math.floor(i)),s=e.getImageData(0,0,t,o),r=s.data,l=n/100*60;if(a===1)for(let d=0;d<r.length;d+=4){if(r[d+3]===0)continue;const c=(Math.random()-.5)*2*l;r[d]=F(r[d]+c),r[d+1]=F(r[d+1]+c),r[d+2]=F(r[d+2]+c)}else for(let d=0;d<o;d+=a)for(let c=0;c<t;c+=a){const m=(Math.random()-.5)*2*l;for(let f=0;f<a&&d+f<o;f++)for(let y=0;y<a&&c+y<t;y++){const b=((d+f)*t+(c+y))*4;r[b+3]!==0&&(r[b]=F(r[b]+m),r[b+1]=F(r[b+1]+m),r[b+2]=F(r[b+2]+m))}}e.putImageData(s,0,0)}function F(e){return e<0?0:e>255?255:e}async function ae(e,t,o=.95){const n=document.createElement("canvas");return n.width=e.width,n.height=e.height,U(n,e),new Promise((i,a)=>{n.toBlob(s=>{s?i(s):a(new Error("Failed to generate image"))},t,o)})}async function se(e){const t=document.createElement("canvas");return t.width=e.width,t.height=e.height,U(t,e),`background-image: url("${t.toDataURL("image/png")}");
|
|
2
|
+
background-size: cover;
|
|
3
|
+
background-position: center;
|
|
4
|
+
background-repeat: no-repeat;`}async function ie(e,t,o=.95){const n=document.createElement("canvas");return n.width=e.width,n.height=e.height,B(n,e),new Promise((i,a)=>{n.toBlob(s=>{s?i(s):a(new Error("Failed to generate image"))},t,o)})}async function q(e,t,o=.95){const n=document.createElement("canvas");return n.width=e.width,n.height=e.height,B(n,e),n.toDataURL(t,o)}async function de(e){return`background-image: url("${await q(e,"image/png")}");
|
|
5
|
+
background-size: cover;
|
|
6
|
+
background-position: center;
|
|
7
|
+
background-repeat: no-repeat;`}const X={position:"absolute",top:0,right:0,bottom:0,left:0,width:"100%",height:"100%",display:"block"};function le({scene:e,animate:t=!1,animParams:o,showFps:n=!1,className:i,style:a}){const s=E.useRef(null),r=E.useRef(null),l=E.useRef(e),d=E.useRef(o),[c,m]=E.useState(0),f=E.useRef([]);E.useEffect(()=>{l.current=e},[e]),E.useEffect(()=>{d.current=o},[o]),E.useEffect(()=>{if(t)return;const h=s.current;if(!h)return;const C=requestAnimationFrame(()=>{h.width=e.width,h.height=e.height,U(h,e)});return()=>cancelAnimationFrame(C)},[e,t]);const{noise:y,grainSize:b,width:R,height:T}=e;E.useEffect(()=>{if(!t)return;const h=r.current;if(!h||y<=0)return;const C=h.getContext("2d");if(!C)return;const M=R,L=T,v=C.createImageData(M,L),u=v.data,p=Math.max(1,Math.floor(b));if(p===1)for(let g=0;g<u.length;g+=4){const A=Math.random()*255|0;u[g]=u[g+1]=u[g+2]=A,u[g+3]=255}else for(let g=0;g<L;g+=p)for(let A=0;A<M;A+=p){const _=Math.random()*255|0;for(let S=0;S<p&&g+S<L;S++)for(let w=0;w<p&&A+w<M;w++){const D=((g+S)*M+(A+w))*4;u[D]=u[D+1]=u[D+2]=_,u[D+3]=255}}C.putImageData(v,0,0)},[t,y,b,R,T]),E.useEffect(()=>{if(!t){f.current=[],m(0);return}const h=s.current;if(!h)return;let C,M=0,L=null;const v=u=>{var g;if(L!==null&&(M+=(u-L)/1e3*(((g=d.current)==null?void 0:g.speed)??1)),L=u,n){const A=f.current;A.push(u);const _=u-1e3;let S=0;for(;S<A.length&&A[S]<_;)S++;f.current=A.slice(S),m(f.current.length)}const p=l.current;(h.width!==p.width||h.height!==p.height)&&(h.width=p.width,h.height=p.height),U(h,p,M,d.current,!0),C=requestAnimationFrame(v)};return C=requestAnimationFrame(v),()=>cancelAnimationFrame(C)},[t,n]);const O=t&&y>0?y/100*.35:0;return G.jsxs("div",{className:i,style:{position:"relative",overflow:"hidden",...a},children:[G.jsx("canvas",{ref:s,width:R,height:T,style:X}),t&&G.jsx("canvas",{ref:r,width:R,height:T,style:{...X,pointerEvents:"none",mixBlendMode:"overlay",opacity:O,display:y>0?"block":"none"}}),n&&t&&G.jsxs("span",{style:{position:"absolute",top:12,right:12,borderRadius:6,background:"rgba(0,0,0,0.6)",padding:"2px 8px",fontFamily:"monospace",fontSize:12,color:"rgba(255,255,255,0.7)",pointerEvents:"none",backdropFilter:"blur(4px)",WebkitBackdropFilter:"blur(4px)"},children:[c," fps"]})]})}exports.BLEND_MODES=K;exports.DEFAULT_ANIM_PARAMS=J;exports.DEFAULT_BACKGROUND_LAYER=H;exports.DEFAULT_CONFIG=Z;exports.DEFAULT_HALO_LAYER=x;exports.DEFAULT_RAY_LAYER=j;exports.DEFAULT_SCENE=Q;exports.GodLights=le;exports.buildCssSnippet=de;exports.buildSceneCssSnippet=se;exports.drawGodRays=B;exports.drawScene=U;exports.exportDataURL=q;exports.exportImage=ie;exports.exportScene=ae;exports.hexToRgb=Y;exports.mulberry32=$;
|
|
8
|
+
//# sourceMappingURL=godlights.js.map
|
|
@@ -0,0 +1,435 @@
|
|
|
1
|
+
import { jsxs as X, jsx as B } from "react/jsx-runtime";
|
|
2
|
+
import M from "react";
|
|
3
|
+
const re = [
|
|
4
|
+
{ label: "Normal", value: "source-over" },
|
|
5
|
+
{ label: "Lighter (additive)", value: "lighter" },
|
|
6
|
+
{ label: "Screen", value: "screen" },
|
|
7
|
+
{ label: "Overlay", value: "overlay" },
|
|
8
|
+
{ label: "Soft light", value: "soft-light" },
|
|
9
|
+
{ label: "Hard light", value: "hard-light" }
|
|
10
|
+
], ae = {
|
|
11
|
+
speed: 1,
|
|
12
|
+
angleAmp: 50,
|
|
13
|
+
lengthAmp: 50,
|
|
14
|
+
widthAmp: 50,
|
|
15
|
+
haloAmp: 50
|
|
16
|
+
}, j = {
|
|
17
|
+
type: "rays",
|
|
18
|
+
direction: 200,
|
|
19
|
+
spread: 60,
|
|
20
|
+
originX: 50,
|
|
21
|
+
originY: 0,
|
|
22
|
+
rayCount: 24,
|
|
23
|
+
rayWidth: 60,
|
|
24
|
+
divergence: 1.6,
|
|
25
|
+
rayLength: 1.4,
|
|
26
|
+
opacity: 0.6,
|
|
27
|
+
blendMode: "lighter",
|
|
28
|
+
colorStart: "#ffffff",
|
|
29
|
+
colorEnd: "#ffffff",
|
|
30
|
+
fadeToTransparent: !0,
|
|
31
|
+
blur: 8,
|
|
32
|
+
randomnessWidth: 30,
|
|
33
|
+
randomnessLength: 18,
|
|
34
|
+
randomnessAngle: 30,
|
|
35
|
+
seed: 1337
|
|
36
|
+
}, V = {
|
|
37
|
+
type: "halo",
|
|
38
|
+
originX: 50,
|
|
39
|
+
originY: 0,
|
|
40
|
+
intensity: 0.5,
|
|
41
|
+
size: 0.25,
|
|
42
|
+
color: "#ffffff",
|
|
43
|
+
blendMode: "lighter"
|
|
44
|
+
}, q = {
|
|
45
|
+
id: "background",
|
|
46
|
+
type: "background",
|
|
47
|
+
bgType: "solid",
|
|
48
|
+
bgColor: "#000000",
|
|
49
|
+
bgColor2: "#000000",
|
|
50
|
+
bgGradientAngle: 180
|
|
51
|
+
}, se = {
|
|
52
|
+
width: 1920,
|
|
53
|
+
height: 1080,
|
|
54
|
+
noise: 8,
|
|
55
|
+
grainSize: 1,
|
|
56
|
+
layers: [
|
|
57
|
+
{ ...q },
|
|
58
|
+
{ id: "halo-1", name: "Halo", ...V },
|
|
59
|
+
{ id: "rays-1", name: "Rays", ...j }
|
|
60
|
+
]
|
|
61
|
+
}, ie = {
|
|
62
|
+
width: 1920,
|
|
63
|
+
height: 1080,
|
|
64
|
+
rayCount: 24,
|
|
65
|
+
rayWidth: 60,
|
|
66
|
+
divergence: 1.6,
|
|
67
|
+
rayLength: 1.4,
|
|
68
|
+
opacity: 0.6,
|
|
69
|
+
blendMode: "lighter",
|
|
70
|
+
haloBlendMode: "lighter",
|
|
71
|
+
direction: 200,
|
|
72
|
+
spread: 60,
|
|
73
|
+
originX: 50,
|
|
74
|
+
originY: 0,
|
|
75
|
+
haloOriginX: 50,
|
|
76
|
+
haloOriginY: 0,
|
|
77
|
+
colorStart: "#ffd28a",
|
|
78
|
+
colorEnd: "#ffd28a",
|
|
79
|
+
fadeToTransparent: !0,
|
|
80
|
+
bgType: "gradient",
|
|
81
|
+
bgColor: "#0b1024",
|
|
82
|
+
bgColor2: "#1a1340",
|
|
83
|
+
bgGradientAngle: 180,
|
|
84
|
+
halo: 0.5,
|
|
85
|
+
haloSize: 0.25,
|
|
86
|
+
haloColor: "#ffd28a",
|
|
87
|
+
blur: 8,
|
|
88
|
+
noise: 8,
|
|
89
|
+
grainSize: 1,
|
|
90
|
+
randomness: 30,
|
|
91
|
+
randomnessWidth: 30,
|
|
92
|
+
randomnessLength: 18,
|
|
93
|
+
randomnessAngle: 30,
|
|
94
|
+
seed: 1337
|
|
95
|
+
};
|
|
96
|
+
function x(e) {
|
|
97
|
+
let t = e >>> 0;
|
|
98
|
+
return function() {
|
|
99
|
+
t = t + 1831565813 | 0;
|
|
100
|
+
let o = t;
|
|
101
|
+
return o = Math.imul(o ^ o >>> 15, o | 1), o ^= o + Math.imul(o ^ o >>> 7, o | 61), ((o ^ o >>> 14) >>> 0) / 4294967296;
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
function Y(e) {
|
|
105
|
+
const t = e.replace("#", "").trim(), o = t.length === 3 ? t.split("").map((i) => i + i).join("") : t.padEnd(6, "0"), n = parseInt(o.substring(0, 6), 16);
|
|
106
|
+
return {
|
|
107
|
+
r: n >> 16 & 255,
|
|
108
|
+
g: n >> 8 & 255,
|
|
109
|
+
b: n & 255
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
function O(e, t) {
|
|
113
|
+
return `rgba(${e.r},${e.g},${e.b},${t})`;
|
|
114
|
+
}
|
|
115
|
+
function K(e) {
|
|
116
|
+
return (e - 90) * Math.PI / 180;
|
|
117
|
+
}
|
|
118
|
+
function J(e, t, o, n) {
|
|
119
|
+
if (e.save(), e.globalCompositeOperation = "source-over", n.bgType === "solid")
|
|
120
|
+
e.fillStyle = n.bgColor, e.fillRect(0, 0, t, o);
|
|
121
|
+
else if (n.bgType === "gradient") {
|
|
122
|
+
const i = n.bgGradientAngle * Math.PI / 180, a = t / 2, s = o / 2, r = Math.hypot(t, o) / 2, d = Math.cos(i) * r, l = Math.sin(i) * r, c = e.createLinearGradient(a - d, s - l, a + d, s + l);
|
|
123
|
+
c.addColorStop(0, n.bgColor), c.addColorStop(1, n.bgColor2), e.fillStyle = c, e.fillRect(0, 0, t, o);
|
|
124
|
+
}
|
|
125
|
+
e.restore();
|
|
126
|
+
}
|
|
127
|
+
function Q(e, t, o, n, i = 0, a) {
|
|
128
|
+
if (n.intensity <= 0) return;
|
|
129
|
+
e.save(), e.globalCompositeOperation = n.blendMode;
|
|
130
|
+
const s = n.originX / 100 * t, r = n.originY / 100 * o, d = a ? a.haloAmp / 50 : 1, l = i !== 0 ? 1 + Math.sin(i * 0.4) * 0.04 * d : 1, c = Math.hypot(t, o) * n.size * l, m = e.createRadialGradient(s, r, 0, s, r, c), p = Y(n.color);
|
|
131
|
+
m.addColorStop(0, O(p, n.intensity)), m.addColorStop(0.5, O(p, n.intensity * 0.4)), m.addColorStop(1, O(p, 0)), e.fillStyle = m, e.beginPath(), e.arc(s, r, c, 0, Math.PI * 2), e.fill(), e.restore();
|
|
132
|
+
}
|
|
133
|
+
function P(e, t, o, n, i = 0, a) {
|
|
134
|
+
const s = n.originX / 100 * t, r = n.originY / 100 * o, d = K(n.direction), l = n.spread * Math.PI / 180, c = Y(n.colorStart), m = Y(n.colorEnd), A = Math.hypot(t, o) * n.rayLength, b = x(n.seed), L = n.randomnessWidth ?? n.randomness ?? 0, w = n.randomnessLength ?? n.randomness ?? 0, G = n.randomnessAngle ?? n.randomness ?? 0;
|
|
135
|
+
for (let h = 0; h < n.rayCount; h++) {
|
|
136
|
+
const C = n.rayCount === 1 ? 0.5 : h / (n.rayCount - 1), S = 1 - b() * (L / 100), E = 1 - b() * (w / 100) * 0.6, R = n.rayCount > 1 ? l / (n.rayCount - 1) : l, g = (b() - 0.5) * (G / 100) * R, f = h * 2.399, u = a ? a.angleAmp / 50 : 1, y = a ? a.lengthAmp / 50 : 1, D = a ? a.widthAmp / 50 : 1, v = i !== 0 ? Math.sin(i * 0.6 + f) * (Math.max(G, 12) / 100) * R * 0.55 * u : 0, T = i !== 0 ? 1 + Math.sin(i * 0.45 + f + 1.2) * (L / 400) * D : 1, k = i !== 0 ? 1 + Math.sin(i * 0.35 + f + 2.5) * (w / 400) * y : 1, N = d - l / 2 + l * C + g + v, I = Math.max(1, n.rayWidth * S * T), _ = Math.max(1, I * n.divergence), U = Math.max(50, A * E * k);
|
|
137
|
+
e.save(), e.translate(s, r), e.rotate(N);
|
|
138
|
+
const W = e.createLinearGradient(0, 0, U, 0);
|
|
139
|
+
W.addColorStop(0, O(c, n.opacity)), W.addColorStop(
|
|
140
|
+
1,
|
|
141
|
+
O(m, n.fadeToTransparent ? 0 : n.opacity)
|
|
142
|
+
), e.fillStyle = W, e.beginPath(), e.moveTo(0, -I / 2), e.lineTo(U, -_ / 2), e.lineTo(U, _ / 2), e.lineTo(0, I / 2), e.closePath(), e.fill(), e.restore();
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
function Z(e, t, o, n, i = 0, a) {
|
|
146
|
+
if (n.blur > 0) {
|
|
147
|
+
const s = new OffscreenCanvas(t, o), r = s.getContext("2d");
|
|
148
|
+
if (!r) return;
|
|
149
|
+
P(r, t, o, n, i, a), e.save(), e.globalCompositeOperation = n.blendMode, e.filter = `blur(${n.blur}px)`, e.drawImage(s, 0, 0), e.restore();
|
|
150
|
+
} else
|
|
151
|
+
e.save(), e.globalCompositeOperation = n.blendMode, P(e, t, o, n, i, a), e.restore();
|
|
152
|
+
}
|
|
153
|
+
function z(e, t, o = 0, n, i = !1) {
|
|
154
|
+
const a = e.getContext("2d");
|
|
155
|
+
if (!a) return;
|
|
156
|
+
const { width: s, height: r } = e;
|
|
157
|
+
a.clearRect(0, 0, s, r);
|
|
158
|
+
for (const d of t.layers)
|
|
159
|
+
d.type === "background" ? J(a, s, r, d) : d.type === "halo" ? Q(a, s, r, d, o, n) : d.type === "rays" && Z(a, s, r, d, o, n);
|
|
160
|
+
!i && t.noise > 0 && ee(a, s, r, t.noise, t.grainSize);
|
|
161
|
+
}
|
|
162
|
+
function H(e, t) {
|
|
163
|
+
z(e, {
|
|
164
|
+
width: t.width,
|
|
165
|
+
height: t.height,
|
|
166
|
+
noise: t.noise,
|
|
167
|
+
grainSize: t.grainSize,
|
|
168
|
+
layers: [
|
|
169
|
+
{
|
|
170
|
+
id: "background",
|
|
171
|
+
type: "background",
|
|
172
|
+
bgType: t.bgType,
|
|
173
|
+
bgColor: t.bgColor,
|
|
174
|
+
bgColor2: t.bgColor2,
|
|
175
|
+
bgGradientAngle: t.bgGradientAngle
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
id: "halo-legacy",
|
|
179
|
+
type: "halo",
|
|
180
|
+
name: "Halo",
|
|
181
|
+
originX: t.haloOriginX,
|
|
182
|
+
originY: t.haloOriginY,
|
|
183
|
+
intensity: t.halo,
|
|
184
|
+
size: t.haloSize,
|
|
185
|
+
color: t.haloColor,
|
|
186
|
+
blendMode: t.haloBlendMode
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
id: "rays-legacy",
|
|
190
|
+
type: "rays",
|
|
191
|
+
name: "Rays",
|
|
192
|
+
direction: t.direction,
|
|
193
|
+
spread: t.spread,
|
|
194
|
+
originX: t.originX,
|
|
195
|
+
originY: t.originY,
|
|
196
|
+
rayCount: t.rayCount,
|
|
197
|
+
rayWidth: t.rayWidth,
|
|
198
|
+
divergence: t.divergence,
|
|
199
|
+
rayLength: t.rayLength,
|
|
200
|
+
opacity: t.opacity,
|
|
201
|
+
blendMode: t.blendMode,
|
|
202
|
+
colorStart: t.colorStart,
|
|
203
|
+
colorEnd: t.colorEnd,
|
|
204
|
+
fadeToTransparent: t.fadeToTransparent,
|
|
205
|
+
blur: t.blur,
|
|
206
|
+
randomness: t.randomness,
|
|
207
|
+
randomnessWidth: t.randomnessWidth,
|
|
208
|
+
randomnessLength: t.randomnessLength,
|
|
209
|
+
randomnessAngle: t.randomnessAngle,
|
|
210
|
+
seed: t.seed
|
|
211
|
+
}
|
|
212
|
+
]
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
function ee(e, t, o, n, i) {
|
|
216
|
+
const a = Math.max(1, Math.floor(i)), s = e.getImageData(0, 0, t, o), r = s.data, d = n / 100 * 60;
|
|
217
|
+
if (a === 1)
|
|
218
|
+
for (let l = 0; l < r.length; l += 4) {
|
|
219
|
+
if (r[l + 3] === 0) continue;
|
|
220
|
+
const c = (Math.random() - 0.5) * 2 * d;
|
|
221
|
+
r[l] = F(r[l] + c), r[l + 1] = F(r[l + 1] + c), r[l + 2] = F(r[l + 2] + c);
|
|
222
|
+
}
|
|
223
|
+
else
|
|
224
|
+
for (let l = 0; l < o; l += a)
|
|
225
|
+
for (let c = 0; c < t; c += a) {
|
|
226
|
+
const m = (Math.random() - 0.5) * 2 * d;
|
|
227
|
+
for (let p = 0; p < a && l + p < o; p++)
|
|
228
|
+
for (let A = 0; A < a && c + A < t; A++) {
|
|
229
|
+
const b = ((l + p) * t + (c + A)) * 4;
|
|
230
|
+
r[b + 3] !== 0 && (r[b] = F(r[b] + m), r[b + 1] = F(r[b + 1] + m), r[b + 2] = F(r[b + 2] + m));
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
e.putImageData(s, 0, 0);
|
|
234
|
+
}
|
|
235
|
+
function F(e) {
|
|
236
|
+
return e < 0 ? 0 : e > 255 ? 255 : e;
|
|
237
|
+
}
|
|
238
|
+
async function le(e, t, o = 0.95) {
|
|
239
|
+
const n = document.createElement("canvas");
|
|
240
|
+
return n.width = e.width, n.height = e.height, z(n, e), new Promise((i, a) => {
|
|
241
|
+
n.toBlob(
|
|
242
|
+
(s) => {
|
|
243
|
+
s ? i(s) : a(new Error("Failed to generate image"));
|
|
244
|
+
},
|
|
245
|
+
t,
|
|
246
|
+
o
|
|
247
|
+
);
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
async function de(e) {
|
|
251
|
+
const t = document.createElement("canvas");
|
|
252
|
+
return t.width = e.width, t.height = e.height, z(t, e), `background-image: url("${t.toDataURL("image/png")}");
|
|
253
|
+
background-size: cover;
|
|
254
|
+
background-position: center;
|
|
255
|
+
background-repeat: no-repeat;`;
|
|
256
|
+
}
|
|
257
|
+
async function ce(e, t, o = 0.95) {
|
|
258
|
+
const n = document.createElement("canvas");
|
|
259
|
+
return n.width = e.width, n.height = e.height, H(n, e), new Promise((i, a) => {
|
|
260
|
+
n.toBlob(
|
|
261
|
+
(s) => {
|
|
262
|
+
s ? i(s) : a(new Error("Failed to generate image"));
|
|
263
|
+
},
|
|
264
|
+
t,
|
|
265
|
+
o
|
|
266
|
+
);
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
async function te(e, t, o = 0.95) {
|
|
270
|
+
const n = document.createElement("canvas");
|
|
271
|
+
return n.width = e.width, n.height = e.height, H(n, e), n.toDataURL(t, o);
|
|
272
|
+
}
|
|
273
|
+
async function he(e) {
|
|
274
|
+
return `background-image: url("${await te(e, "image/png")}");
|
|
275
|
+
background-size: cover;
|
|
276
|
+
background-position: center;
|
|
277
|
+
background-repeat: no-repeat;`;
|
|
278
|
+
}
|
|
279
|
+
const $ = {
|
|
280
|
+
position: "absolute",
|
|
281
|
+
top: 0,
|
|
282
|
+
right: 0,
|
|
283
|
+
bottom: 0,
|
|
284
|
+
left: 0,
|
|
285
|
+
width: "100%",
|
|
286
|
+
height: "100%",
|
|
287
|
+
display: "block"
|
|
288
|
+
};
|
|
289
|
+
function ge({
|
|
290
|
+
scene: e,
|
|
291
|
+
animate: t = !1,
|
|
292
|
+
animParams: o,
|
|
293
|
+
showFps: n = !1,
|
|
294
|
+
className: i,
|
|
295
|
+
style: a
|
|
296
|
+
}) {
|
|
297
|
+
const s = M.useRef(null), r = M.useRef(null), d = M.useRef(e), l = M.useRef(o), [c, m] = M.useState(0), p = M.useRef([]);
|
|
298
|
+
M.useEffect(() => {
|
|
299
|
+
d.current = e;
|
|
300
|
+
}, [e]), M.useEffect(() => {
|
|
301
|
+
l.current = o;
|
|
302
|
+
}, [o]), M.useEffect(() => {
|
|
303
|
+
if (t) return;
|
|
304
|
+
const h = s.current;
|
|
305
|
+
if (!h) return;
|
|
306
|
+
const C = requestAnimationFrame(() => {
|
|
307
|
+
h.width = e.width, h.height = e.height, z(h, e);
|
|
308
|
+
});
|
|
309
|
+
return () => cancelAnimationFrame(C);
|
|
310
|
+
}, [e, t]);
|
|
311
|
+
const { noise: A, grainSize: b, width: L, height: w } = e;
|
|
312
|
+
M.useEffect(() => {
|
|
313
|
+
if (!t) return;
|
|
314
|
+
const h = r.current;
|
|
315
|
+
if (!h || A <= 0) return;
|
|
316
|
+
const C = h.getContext("2d");
|
|
317
|
+
if (!C) return;
|
|
318
|
+
const S = L, E = w, R = C.createImageData(S, E), g = R.data, f = Math.max(1, Math.floor(b));
|
|
319
|
+
if (f === 1)
|
|
320
|
+
for (let u = 0; u < g.length; u += 4) {
|
|
321
|
+
const y = Math.random() * 255 | 0;
|
|
322
|
+
g[u] = g[u + 1] = g[u + 2] = y, g[u + 3] = 255;
|
|
323
|
+
}
|
|
324
|
+
else
|
|
325
|
+
for (let u = 0; u < E; u += f)
|
|
326
|
+
for (let y = 0; y < S; y += f) {
|
|
327
|
+
const D = Math.random() * 255 | 0;
|
|
328
|
+
for (let v = 0; v < f && u + v < E; v++)
|
|
329
|
+
for (let T = 0; T < f && y + T < S; T++) {
|
|
330
|
+
const k = ((u + v) * S + (y + T)) * 4;
|
|
331
|
+
g[k] = g[k + 1] = g[k + 2] = D, g[k + 3] = 255;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
C.putImageData(R, 0, 0);
|
|
335
|
+
}, [t, A, b, L, w]), M.useEffect(() => {
|
|
336
|
+
if (!t) {
|
|
337
|
+
p.current = [], m(0);
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
const h = s.current;
|
|
341
|
+
if (!h) return;
|
|
342
|
+
let C, S = 0, E = null;
|
|
343
|
+
const R = (g) => {
|
|
344
|
+
var u;
|
|
345
|
+
if (E !== null && (S += (g - E) / 1e3 * (((u = l.current) == null ? void 0 : u.speed) ?? 1)), E = g, n) {
|
|
346
|
+
const y = p.current;
|
|
347
|
+
y.push(g);
|
|
348
|
+
const D = g - 1e3;
|
|
349
|
+
let v = 0;
|
|
350
|
+
for (; v < y.length && y[v] < D; ) v++;
|
|
351
|
+
p.current = y.slice(v), m(p.current.length);
|
|
352
|
+
}
|
|
353
|
+
const f = d.current;
|
|
354
|
+
(h.width !== f.width || h.height !== f.height) && (h.width = f.width, h.height = f.height), z(h, f, S, l.current, !0), C = requestAnimationFrame(R);
|
|
355
|
+
};
|
|
356
|
+
return C = requestAnimationFrame(R), () => cancelAnimationFrame(C);
|
|
357
|
+
}, [t, n]);
|
|
358
|
+
const G = t && A > 0 ? A / 100 * 0.35 : 0;
|
|
359
|
+
return /* @__PURE__ */ X(
|
|
360
|
+
"div",
|
|
361
|
+
{
|
|
362
|
+
className: i,
|
|
363
|
+
style: { position: "relative", overflow: "hidden", ...a },
|
|
364
|
+
children: [
|
|
365
|
+
/* @__PURE__ */ B(
|
|
366
|
+
"canvas",
|
|
367
|
+
{
|
|
368
|
+
ref: s,
|
|
369
|
+
width: L,
|
|
370
|
+
height: w,
|
|
371
|
+
style: $
|
|
372
|
+
}
|
|
373
|
+
),
|
|
374
|
+
t && /* @__PURE__ */ B(
|
|
375
|
+
"canvas",
|
|
376
|
+
{
|
|
377
|
+
ref: r,
|
|
378
|
+
width: L,
|
|
379
|
+
height: w,
|
|
380
|
+
style: {
|
|
381
|
+
...$,
|
|
382
|
+
pointerEvents: "none",
|
|
383
|
+
mixBlendMode: "overlay",
|
|
384
|
+
opacity: G,
|
|
385
|
+
display: A > 0 ? "block" : "none"
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
),
|
|
389
|
+
n && t && /* @__PURE__ */ X(
|
|
390
|
+
"span",
|
|
391
|
+
{
|
|
392
|
+
style: {
|
|
393
|
+
position: "absolute",
|
|
394
|
+
top: 12,
|
|
395
|
+
right: 12,
|
|
396
|
+
borderRadius: 6,
|
|
397
|
+
background: "rgba(0,0,0,0.6)",
|
|
398
|
+
padding: "2px 8px",
|
|
399
|
+
fontFamily: "monospace",
|
|
400
|
+
fontSize: 12,
|
|
401
|
+
color: "rgba(255,255,255,0.7)",
|
|
402
|
+
pointerEvents: "none",
|
|
403
|
+
backdropFilter: "blur(4px)",
|
|
404
|
+
WebkitBackdropFilter: "blur(4px)"
|
|
405
|
+
},
|
|
406
|
+
children: [
|
|
407
|
+
c,
|
|
408
|
+
" fps"
|
|
409
|
+
]
|
|
410
|
+
}
|
|
411
|
+
)
|
|
412
|
+
]
|
|
413
|
+
}
|
|
414
|
+
);
|
|
415
|
+
}
|
|
416
|
+
export {
|
|
417
|
+
re as BLEND_MODES,
|
|
418
|
+
ae as DEFAULT_ANIM_PARAMS,
|
|
419
|
+
q as DEFAULT_BACKGROUND_LAYER,
|
|
420
|
+
ie as DEFAULT_CONFIG,
|
|
421
|
+
V as DEFAULT_HALO_LAYER,
|
|
422
|
+
j as DEFAULT_RAY_LAYER,
|
|
423
|
+
se as DEFAULT_SCENE,
|
|
424
|
+
ge as GodLights,
|
|
425
|
+
he as buildCssSnippet,
|
|
426
|
+
de as buildSceneCssSnippet,
|
|
427
|
+
H as drawGodRays,
|
|
428
|
+
z as drawScene,
|
|
429
|
+
te as exportDataURL,
|
|
430
|
+
ce as exportImage,
|
|
431
|
+
le as exportScene,
|
|
432
|
+
Y as hexToRgb,
|
|
433
|
+
x as mulberry32
|
|
434
|
+
};
|
|
435
|
+
//# sourceMappingURL=godlights.mjs.map
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { default as default_2 } from 'react';
|
|
2
|
+
import { JSX as JSX_2 } from 'react/jsx-runtime';
|
|
3
|
+
|
|
4
|
+
/** Parameters that control the animation loop — not persisted in scene. */
|
|
5
|
+
export declare interface AnimParams {
|
|
6
|
+
/** Time multiplier — higher = faster (default 1). */
|
|
7
|
+
speed: number;
|
|
8
|
+
/** Angle swing intensity 0–100 (default 50). */
|
|
9
|
+
angleAmp: number;
|
|
10
|
+
/** Ray length oscillation intensity 0–100 (default 50). */
|
|
11
|
+
lengthAmp: number;
|
|
12
|
+
/** Ray width oscillation intensity 0–100 (default 50). */
|
|
13
|
+
widthAmp: number;
|
|
14
|
+
/** Halo pulse intensity 0–100 (default 50). */
|
|
15
|
+
haloAmp: number;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export declare interface BackgroundLayer {
|
|
19
|
+
id: "background";
|
|
20
|
+
type: "background";
|
|
21
|
+
bgType: BackgroundType;
|
|
22
|
+
bgColor: string;
|
|
23
|
+
bgColor2: string;
|
|
24
|
+
bgGradientAngle: number;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export declare type BackgroundType = "transparent" | "solid" | "gradient";
|
|
28
|
+
|
|
29
|
+
export declare const BLEND_MODES: {
|
|
30
|
+
label: string;
|
|
31
|
+
value: BlendMode;
|
|
32
|
+
}[];
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* God Rays / Light Rays rendering engine
|
|
36
|
+
* Supports multiple independent ray and halo layers per scene.
|
|
37
|
+
*/
|
|
38
|
+
export declare type BlendMode = "source-over" | "lighter" | "screen" | "overlay" | "soft-light" | "hard-light";
|
|
39
|
+
|
|
40
|
+
export declare function buildCssSnippet(config: GodRaysConfig): Promise<string>;
|
|
41
|
+
|
|
42
|
+
export declare function buildSceneCssSnippet(scene: SceneConfig): Promise<string>;
|
|
43
|
+
|
|
44
|
+
export declare const DEFAULT_ANIM_PARAMS: AnimParams;
|
|
45
|
+
|
|
46
|
+
export declare const DEFAULT_BACKGROUND_LAYER: BackgroundLayer;
|
|
47
|
+
|
|
48
|
+
export declare const DEFAULT_CONFIG: GodRaysConfig;
|
|
49
|
+
|
|
50
|
+
export declare const DEFAULT_HALO_LAYER: Omit<HaloLayer, "id" | "name">;
|
|
51
|
+
|
|
52
|
+
export declare const DEFAULT_RAY_LAYER: Omit<RayLayer, "id" | "name">;
|
|
53
|
+
|
|
54
|
+
export declare const DEFAULT_SCENE: SceneConfig;
|
|
55
|
+
|
|
56
|
+
export declare function drawGodRays(canvas: HTMLCanvasElement, config: GodRaysConfig): void;
|
|
57
|
+
|
|
58
|
+
export declare function drawScene(canvas: HTMLCanvasElement, scene: SceneConfig, time?: number, anim?: AnimParams, skipGrain?: boolean): void;
|
|
59
|
+
|
|
60
|
+
export declare function exportDataURL(config: GodRaysConfig, type: "image/png" | "image/jpeg", quality?: number): Promise<string>;
|
|
61
|
+
|
|
62
|
+
export declare function exportImage(config: GodRaysConfig, type: "image/png" | "image/jpeg", quality?: number): Promise<Blob>;
|
|
63
|
+
|
|
64
|
+
export declare function exportScene(scene: SceneConfig, type: "image/png" | "image/jpeg", quality?: number): Promise<Blob>;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Standalone Godlights canvas component.
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* <GodLights scene={myScene} className="w-full h-full" />
|
|
71
|
+
* <GodLights scene={myScene} animate animParams={{ speed: 1, angleAmp: 50, lengthAmp: 50, widthAmp: 50, haloAmp: 50 }} />
|
|
72
|
+
*/
|
|
73
|
+
export declare function GodLights({ scene, animate, animParams, showFps, className, style, }: GodLightsProps): JSX_2.Element;
|
|
74
|
+
|
|
75
|
+
export declare interface GodLightsProps {
|
|
76
|
+
/** Full scene configuration — use the Godlights editor to build this. */
|
|
77
|
+
scene: SceneConfig;
|
|
78
|
+
/** Enable animation loop. */
|
|
79
|
+
animate?: boolean;
|
|
80
|
+
/** Animation parameters (speed, amplitudes). Only used when animate=true. */
|
|
81
|
+
animParams?: AnimParams;
|
|
82
|
+
/** Show FPS counter overlay. Only visible when animate=true. */
|
|
83
|
+
showFps?: boolean;
|
|
84
|
+
className?: string;
|
|
85
|
+
style?: default_2.CSSProperties;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export declare interface GodRaysConfig {
|
|
89
|
+
width: number;
|
|
90
|
+
height: number;
|
|
91
|
+
rayCount: number;
|
|
92
|
+
rayWidth: number;
|
|
93
|
+
divergence: number;
|
|
94
|
+
rayLength: number;
|
|
95
|
+
opacity: number;
|
|
96
|
+
blendMode: BlendMode;
|
|
97
|
+
haloBlendMode: BlendMode;
|
|
98
|
+
direction: number;
|
|
99
|
+
spread: number;
|
|
100
|
+
originX: number;
|
|
101
|
+
originY: number;
|
|
102
|
+
haloOriginX: number;
|
|
103
|
+
haloOriginY: number;
|
|
104
|
+
colorStart: string;
|
|
105
|
+
colorEnd: string;
|
|
106
|
+
fadeToTransparent: boolean;
|
|
107
|
+
bgType: BackgroundType;
|
|
108
|
+
bgColor: string;
|
|
109
|
+
bgColor2: string;
|
|
110
|
+
bgGradientAngle: number;
|
|
111
|
+
halo: number;
|
|
112
|
+
haloSize: number;
|
|
113
|
+
haloColor: string;
|
|
114
|
+
blur: number;
|
|
115
|
+
noise: number;
|
|
116
|
+
grainSize: number;
|
|
117
|
+
randomness: number;
|
|
118
|
+
randomnessWidth: number;
|
|
119
|
+
randomnessLength: number;
|
|
120
|
+
randomnessAngle: number;
|
|
121
|
+
seed: number;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export declare interface HaloLayer {
|
|
125
|
+
id: string;
|
|
126
|
+
type: "halo";
|
|
127
|
+
name: string;
|
|
128
|
+
originX: number;
|
|
129
|
+
originY: number;
|
|
130
|
+
intensity: number;
|
|
131
|
+
size: number;
|
|
132
|
+
color: string;
|
|
133
|
+
blendMode: BlendMode;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export declare function hexToRgb(hex: string): {
|
|
137
|
+
r: number;
|
|
138
|
+
g: number;
|
|
139
|
+
b: number;
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
export declare type Layer = RayLayer | HaloLayer | BackgroundLayer;
|
|
143
|
+
|
|
144
|
+
export declare function mulberry32(seed: number): () => number;
|
|
145
|
+
|
|
146
|
+
export declare interface RayLayer {
|
|
147
|
+
id: string;
|
|
148
|
+
type: "rays";
|
|
149
|
+
name: string;
|
|
150
|
+
direction: number;
|
|
151
|
+
spread: number;
|
|
152
|
+
originX: number;
|
|
153
|
+
originY: number;
|
|
154
|
+
rayCount: number;
|
|
155
|
+
rayWidth: number;
|
|
156
|
+
divergence: number;
|
|
157
|
+
rayLength: number;
|
|
158
|
+
opacity: number;
|
|
159
|
+
blendMode: BlendMode;
|
|
160
|
+
colorStart: string;
|
|
161
|
+
colorEnd: string;
|
|
162
|
+
fadeToTransparent: boolean;
|
|
163
|
+
blur: number;
|
|
164
|
+
/** @deprecated use randomnessWidth/Length/Angle */
|
|
165
|
+
randomness?: number;
|
|
166
|
+
randomnessWidth: number;
|
|
167
|
+
randomnessLength: number;
|
|
168
|
+
randomnessAngle: number;
|
|
169
|
+
seed: number;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export declare interface SceneConfig {
|
|
173
|
+
width: number;
|
|
174
|
+
height: number;
|
|
175
|
+
noise: number;
|
|
176
|
+
grainSize: number;
|
|
177
|
+
/** Ordered back-to-front. BackgroundLayer is always at index 0. */
|
|
178
|
+
layers: Layer[];
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export { }
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "godlights",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Animated god ray / light beam effects for React — zero dependencies beyond React itself.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/godlights.js",
|
|
7
|
+
"module": "./dist/godlights.mjs",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": "./dist/godlights.mjs",
|
|
12
|
+
"require": "./dist/godlights.js",
|
|
13
|
+
"types": "./dist/index.d.ts"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist/*.js",
|
|
18
|
+
"dist/*.mjs",
|
|
19
|
+
"dist/*.d.ts",
|
|
20
|
+
"README.md"
|
|
21
|
+
],
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "https://github.com/gustavoquinalha/rays-generator.git",
|
|
25
|
+
"directory": "packages/godlights"
|
|
26
|
+
},
|
|
27
|
+
"homepage": "https://github.com/gustavoquinalha/rays-generator/tree/main/packages/godlights#readme",
|
|
28
|
+
"sideEffects": false,
|
|
29
|
+
"scripts": {
|
|
30
|
+
"build": "vite build && tsc --emitDeclarationOnly --declaration --outDir dist",
|
|
31
|
+
"dev": "vite build --watch"
|
|
32
|
+
},
|
|
33
|
+
"peerDependencies": {
|
|
34
|
+
"react": ">=18",
|
|
35
|
+
"react-dom": ">=18"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@types/react": "^18.3.12",
|
|
39
|
+
"@types/react-dom": "^18.3.1",
|
|
40
|
+
"@vitejs/plugin-react": "^4.3.3",
|
|
41
|
+
"typescript": "^5.6.3",
|
|
42
|
+
"vite": "^5.4.10",
|
|
43
|
+
"vite-plugin-dts": "^4.5.4"
|
|
44
|
+
},
|
|
45
|
+
"keywords": [
|
|
46
|
+
"god-rays",
|
|
47
|
+
"light-rays",
|
|
48
|
+
"canvas",
|
|
49
|
+
"react",
|
|
50
|
+
"animation",
|
|
51
|
+
"visual-effects"
|
|
52
|
+
],
|
|
53
|
+
"license": "MIT"
|
|
54
|
+
}
|