particle-network-bg 1.0.1 → 1.0.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/README.md +13 -2
- package/dist/{chunk-BMXQY2SK.mjs → chunk-JZTYQ6XI.mjs} +74 -28
- package/dist/index.d.mts +10 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +74 -28
- package/dist/index.mjs +1 -1
- package/dist/react.d.mts +16 -2
- package/dist/react.d.ts +16 -2
- package/dist/react.js +88 -31
- package/dist/react.mjs +14 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -89,6 +89,8 @@ function App() {
|
|
|
89
89
|
```
|
|
90
90
|
|
|
91
91
|
> **Note:** Config is applied on mount. The canvas resizes to the window. When gradients are enabled, a background `<div>` is automatically created behind the canvas for smooth CSS-based gradient rendering.
|
|
92
|
+
>
|
|
93
|
+
> Pulse animations are automatically phase-randomized so particles don't pulse in sync.
|
|
92
94
|
|
|
93
95
|
## Configuration
|
|
94
96
|
|
|
@@ -160,6 +162,7 @@ new ParticleNetwork(canvas, {
|
|
|
160
162
|
secondaryHighlightPosition: "bottom-right",
|
|
161
163
|
minRadius: 20, // min size for liquid glass particles (overrides root minRadius)
|
|
162
164
|
maxRadius: 40, // max size for liquid glass particles (overrides root maxRadius)
|
|
165
|
+
blobSpeed: 1, // blob deformation speed multiplier (0 = frozen, 2 = double speed)
|
|
163
166
|
},
|
|
164
167
|
});
|
|
165
168
|
```
|
|
@@ -344,7 +347,7 @@ function App() {
|
|
|
344
347
|
</ChildParticle>
|
|
345
348
|
|
|
346
349
|
{/* Liquid glass blob particle */}
|
|
347
|
-
<GlassChildParticle id="clock" x={600} y={400} radius={60}>
|
|
350
|
+
<GlassChildParticle id="clock" x={600} y={400} radius={60} glassColor="#ff6600" glassOpacity={0.8}>
|
|
348
351
|
<span>🕐</span>
|
|
349
352
|
</GlassChildParticle>
|
|
350
353
|
|
|
@@ -371,6 +374,9 @@ function App() {
|
|
|
371
374
|
| `overflow` | string | `"hidden"` | CSS overflow for the child content container |
|
|
372
375
|
| `anchorForce` | number | `0.05` | Spring force pulling back to anchor (0–1). Lower = more floaty |
|
|
373
376
|
| `mouseInfluence` | number | `0.1` | Mouse influence multiplier (0–1). 0 = ignores mouse |
|
|
377
|
+
| `glassOpacity` | number | — | Opacity (0–1) for liquid glass. Overrides global `liquidGlass.opacity` |
|
|
378
|
+
| `glassColor` | string | — | Color (hex) for liquid glass. Overrides global `liquidGlass.color` |
|
|
379
|
+
| `liquidGlassConfig` | `Partial<LiquidGlassConfig>` | — | Full liquid glass config override, merged over global `liquidGlass` |
|
|
374
380
|
| `children` | ReactNode | — | Content to render inside the particle |
|
|
375
381
|
| `style` | CSSProperties | — | Style applied to the inner wrapper div |
|
|
376
382
|
| `className` | string | — | Class applied to the inner wrapper div |
|
|
@@ -391,7 +397,9 @@ network.addChildParticle({
|
|
|
391
397
|
radius: 50,
|
|
392
398
|
anchorForce: 0.05,
|
|
393
399
|
mouseInfluence: 0.1,
|
|
394
|
-
liquidGlass:
|
|
400
|
+
liquidGlass: true,
|
|
401
|
+
glassOpacity: 0.7, // override global liquidGlass.opacity
|
|
402
|
+
glassColor: "#ff6600", // override global liquidGlass.color
|
|
395
403
|
});
|
|
396
404
|
|
|
397
405
|
// Update its anchor (e.g. on scroll/resize)
|
|
@@ -436,6 +444,9 @@ interface ChildParticleConfig {
|
|
|
436
444
|
anchorForce?: number;
|
|
437
445
|
mouseInfluence?: number;
|
|
438
446
|
liquidGlass?: boolean;
|
|
447
|
+
glassOpacity?: number; // overrides global liquidGlass.opacity
|
|
448
|
+
glassColor?: string; // overrides global liquidGlass.color
|
|
449
|
+
liquidGlassConfig?: Partial<LiquidGlassConfig>; // merged over global liquidGlass
|
|
439
450
|
}
|
|
440
451
|
|
|
441
452
|
interface ChildParticlePosition {
|
|
@@ -43,6 +43,7 @@ var DEFAULT_LIQUID_GLASS = {
|
|
|
43
43
|
shadowStrength: 0.4,
|
|
44
44
|
secondaryReflection: 0.25,
|
|
45
45
|
secondaryHighlightPosition: "bottom-right",
|
|
46
|
+
blobSpeed: 1,
|
|
46
47
|
minRadius: 20,
|
|
47
48
|
maxRadius: 40
|
|
48
49
|
};
|
|
@@ -158,7 +159,7 @@ var ParticleNetwork = class {
|
|
|
158
159
|
const h = isRect ? particle.height : (particle.currentRadius ?? particle.radius) * 2;
|
|
159
160
|
el.style.width = w + "px";
|
|
160
161
|
el.style.height = h + "px";
|
|
161
|
-
el.style.transform = `
|
|
162
|
+
el.style.transform = `translate3d(${Math.round(px - w / 2)}px, ${Math.round(py - h / 2)}px, 0)`;
|
|
162
163
|
if (isRect) {
|
|
163
164
|
const br = particle.borderRadius ?? Math.min(w, h) / 2;
|
|
164
165
|
el.style.borderRadius = br + "px";
|
|
@@ -314,7 +315,14 @@ var ParticleNetwork = class {
|
|
|
314
315
|
if (!Array.isArray(config.particleTypes)) {
|
|
315
316
|
throw new Error("particleTypes must be an array");
|
|
316
317
|
}
|
|
317
|
-
|
|
318
|
+
let hasAssetEntries = false;
|
|
319
|
+
for (const entry of config.particleTypes) {
|
|
320
|
+
if (entry?.type === "asset") {
|
|
321
|
+
hasAssetEntries = true;
|
|
322
|
+
break;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
if (hasAssetEntries && (!config.assets || typeof config.assets !== "object")) {
|
|
318
326
|
throw new Error("assets map is required when using particleTypes with asset entries");
|
|
319
327
|
}
|
|
320
328
|
for (let i = 0; i < config.particleTypes.length; i++) {
|
|
@@ -334,8 +342,9 @@ var ParticleNetwork = class {
|
|
|
334
342
|
if (typeof pt.asset !== "string" || !pt.asset) {
|
|
335
343
|
throw new Error(`particleTypes[${i}].asset must be a non-empty string`);
|
|
336
344
|
}
|
|
337
|
-
|
|
338
|
-
|
|
345
|
+
const assetKey = pt.asset;
|
|
346
|
+
if (!config.assets?.[assetKey]) {
|
|
347
|
+
throw new Error(`particleTypes[${i}]: asset "${assetKey}" not found in assets`);
|
|
339
348
|
}
|
|
340
349
|
}
|
|
341
350
|
}
|
|
@@ -433,6 +442,7 @@ var ParticleNetwork = class {
|
|
|
433
442
|
delete p.assetId;
|
|
434
443
|
delete p.liquidGlass;
|
|
435
444
|
delete p.typeConfig;
|
|
445
|
+
delete p.pulsePhase;
|
|
436
446
|
});
|
|
437
447
|
if (particleTypes?.length) {
|
|
438
448
|
const counts = [];
|
|
@@ -501,6 +511,14 @@ var ParticleNetwork = class {
|
|
|
501
511
|
if (!particleTypes?.length && (this.config.liquidGlassPercentage != null || this.config.liquidGlassCount != null)) {
|
|
502
512
|
this.assignLiquidGlass();
|
|
503
513
|
}
|
|
514
|
+
this.particles.forEach((p) => {
|
|
515
|
+
if (p.isChild) return;
|
|
516
|
+
const tc = p.typeConfig;
|
|
517
|
+
const doPulse = tc?.pulse ?? this.config.pulseEnabled;
|
|
518
|
+
if (doPulse) {
|
|
519
|
+
p.pulsePhase = Math.random() * Math.PI * 2;
|
|
520
|
+
}
|
|
521
|
+
});
|
|
504
522
|
this.assignMouseBehavior();
|
|
505
523
|
}
|
|
506
524
|
assignLiquidGlass() {
|
|
@@ -606,7 +624,8 @@ var ParticleNetwork = class {
|
|
|
606
624
|
if (doPulse) {
|
|
607
625
|
const speed = tc?.pulseSpeed ?? this.config.pulseSpeed;
|
|
608
626
|
this.pulseAngle += speed;
|
|
609
|
-
const
|
|
627
|
+
const phase = particle.pulsePhase ?? 0;
|
|
628
|
+
const pulseScale = Math.sin(this.pulseAngle + phase) * 0.5 + 1;
|
|
610
629
|
particle.currentRadius = particle.radius * pulseScale;
|
|
611
630
|
} else {
|
|
612
631
|
particle.currentRadius = particle.radius;
|
|
@@ -807,7 +826,20 @@ var ParticleNetwork = class {
|
|
|
807
826
|
}
|
|
808
827
|
draw3DFluidSphere(particle) {
|
|
809
828
|
const tc = particle.typeConfig;
|
|
810
|
-
|
|
829
|
+
let perTypeLg = tc && "liquidGlass" in tc && typeof tc.liquidGlass === "object" ? tc.liquidGlass : void 0;
|
|
830
|
+
if (particle.isChild && particle.childId) {
|
|
831
|
+
const childConfig = this.childParticleConfigs.get(particle.childId);
|
|
832
|
+
if (childConfig) {
|
|
833
|
+
const overrides = {
|
|
834
|
+
...childConfig.liquidGlassConfig ?? {},
|
|
835
|
+
...childConfig.glassOpacity != null && { opacity: childConfig.glassOpacity },
|
|
836
|
+
...childConfig.glassColor != null && { color: childConfig.glassColor }
|
|
837
|
+
};
|
|
838
|
+
if (Object.keys(overrides).length > 0) {
|
|
839
|
+
perTypeLg = { ...perTypeLg ?? {}, ...overrides };
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
}
|
|
811
843
|
const lg = perTypeLg ? { ...this.getLiquidGlassConfig(), ...perTypeLg } : this.getLiquidGlassConfig();
|
|
812
844
|
const r = particle.currentRadius ?? particle.radius;
|
|
813
845
|
if (r <= 0) return;
|
|
@@ -816,46 +848,60 @@ var ParticleNetwork = class {
|
|
|
816
848
|
const cx = particle.x;
|
|
817
849
|
const cy = particle.y;
|
|
818
850
|
const isRect = particle.width != null && particle.height != null;
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
851
|
+
const hasExplicitChildOpacity = particle.isChild && particle.childId && (() => {
|
|
852
|
+
const cfg = this.childParticleConfigs.get(particle.childId);
|
|
853
|
+
return cfg?.glassOpacity != null || cfg?.liquidGlassConfig?.opacity != null;
|
|
854
|
+
})();
|
|
855
|
+
let opacity = lg.opacity ?? DEFAULT_LIQUID_GLASS.opacity;
|
|
856
|
+
if (!hasExplicitChildOpacity) {
|
|
857
|
+
opacity *= this.config.particleOpacity;
|
|
858
|
+
if (this.config.depthEffectEnabled) {
|
|
859
|
+
opacity *= 0.6 + 0.4 * particle.z;
|
|
860
|
+
}
|
|
822
861
|
}
|
|
823
862
|
if (opacity <= 0) return;
|
|
824
|
-
|
|
863
|
+
const blobSpeed = lg.blobSpeed ?? 1;
|
|
864
|
+
blob.rotation += blob.rotSpeed * blobSpeed;
|
|
825
865
|
for (let m = 0; m < blob.phases.length; m++) {
|
|
826
|
-
blob.phases[m] += blob.phaseSpeeds[m];
|
|
866
|
+
blob.phases[m] += blob.phaseSpeeds[m] * blobSpeed;
|
|
827
867
|
}
|
|
828
|
-
blob.hlAngle += blob.hlAngleSpeed;
|
|
868
|
+
blob.hlAngle += blob.hlAngleSpeed * blobSpeed;
|
|
829
869
|
this.updateBlobMouse(particle);
|
|
830
870
|
const color = lg.color ?? DEFAULT_LIQUID_GLASS.color;
|
|
831
871
|
const baseR = parseInt(color.slice(1, 3), 16);
|
|
832
872
|
const baseG = parseInt(color.slice(3, 5), 16);
|
|
833
873
|
const baseB = parseInt(color.slice(5, 7), 16);
|
|
834
874
|
const shadowStr = lg.shadowStrength ?? DEFAULT_LIQUID_GLASS.shadowStrength;
|
|
875
|
+
const refl = (lg.reflectionStrength ?? DEFAULT_LIQUID_GLASS.reflectionStrength) / DEFAULT_LIQUID_GLASS.reflectionStrength;
|
|
835
876
|
const gradR = isRect ? Math.max(particle.width, particle.height) / 2 : r;
|
|
836
877
|
const hlDist = gradR * 0.35;
|
|
837
878
|
const hlX = cx + Math.cos(blob.hlAngle) * hlDist;
|
|
838
879
|
const hlY = cy + Math.sin(blob.hlAngle) * hlDist;
|
|
839
|
-
const lr = Math.min(255, baseR + Math.round((255 - baseR) * 0.55));
|
|
840
|
-
const lgr = Math.min(255, baseG + Math.round((255 - baseG) * 0.55));
|
|
841
|
-
const lb = Math.min(255, baseB + Math.round((255 - baseB) * 0.55));
|
|
880
|
+
const lr = Math.min(255, baseR + Math.round((255 - baseR) * 0.55 * refl));
|
|
881
|
+
const lgr = Math.min(255, baseG + Math.round((255 - baseG) * 0.55 * refl));
|
|
882
|
+
const lb = Math.min(255, baseB + Math.round((255 - baseB) * 0.55 * refl));
|
|
842
883
|
const dr = Math.max(0, Math.round(baseR * (1 - shadowStr * 0.35)));
|
|
843
884
|
const dg = Math.max(0, Math.round(baseG * (1 - shadowStr * 0.35)));
|
|
844
885
|
const db = Math.max(0, Math.round(baseB * (1 - shadowStr * 0.35)));
|
|
845
886
|
this.ctx.save();
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
887
|
+
this.ctx.globalAlpha = 1;
|
|
888
|
+
if (hasExplicitChildOpacity && opacity >= 0.99) {
|
|
889
|
+
this.ctx.fillStyle = `rgba(${baseR},${baseG},${baseB}, ${opacity})`;
|
|
890
|
+
} else {
|
|
891
|
+
const grad = this.ctx.createRadialGradient(
|
|
892
|
+
hlX,
|
|
893
|
+
hlY,
|
|
894
|
+
gradR * 0.05,
|
|
895
|
+
cx,
|
|
896
|
+
cy,
|
|
897
|
+
gradR * 1.05
|
|
898
|
+
);
|
|
899
|
+
grad.addColorStop(0, `rgba(${lr},${lgr},${lb}, ${opacity * 0.95})`);
|
|
900
|
+
grad.addColorStop(0.4, `rgba(${baseR},${baseG},${baseB}, ${opacity * 0.8})`);
|
|
901
|
+
grad.addColorStop(0.8, `rgba(${dr},${dg},${db}, ${opacity * 0.6})`);
|
|
902
|
+
grad.addColorStop(1, `rgba(${dr},${dg},${db}, ${opacity * 0.25})`);
|
|
903
|
+
this.ctx.fillStyle = grad;
|
|
904
|
+
}
|
|
859
905
|
if (isRect) {
|
|
860
906
|
const halfW = particle.width / 2;
|
|
861
907
|
const halfH = particle.height / 2;
|
package/dist/index.d.mts
CHANGED
|
@@ -38,6 +38,8 @@ interface LiquidGlassConfig {
|
|
|
38
38
|
minRadius?: number;
|
|
39
39
|
/** Maximum radius (px) for liquid glass particles (overrides root maxRadius). */
|
|
40
40
|
maxRadius?: number;
|
|
41
|
+
/** Blob deformation speed multiplier (default 1). 0 = frozen, 2 = double speed. */
|
|
42
|
+
blobSpeed?: number;
|
|
41
43
|
}
|
|
42
44
|
interface CircleTypeEntry {
|
|
43
45
|
type: "circle";
|
|
@@ -94,6 +96,12 @@ interface ChildParticleConfig {
|
|
|
94
96
|
mouseInfluence?: number;
|
|
95
97
|
/** Render as liquid glass particle. Default false. */
|
|
96
98
|
liquidGlass?: boolean;
|
|
99
|
+
/** Opacity (0–1) for liquid glass child particles. Overrides global liquidGlass.opacity. */
|
|
100
|
+
glassOpacity?: number;
|
|
101
|
+
/** Color (hex) for liquid glass child particles. Overrides global liquidGlass.color. */
|
|
102
|
+
glassColor?: string;
|
|
103
|
+
/** Full liquid glass config override for child particles. Merged over global liquidGlass. */
|
|
104
|
+
liquidGlassConfig?: Partial<LiquidGlassConfig>;
|
|
97
105
|
}
|
|
98
106
|
/** Emitted position data for a child particle each frame. */
|
|
99
107
|
interface ChildParticlePosition {
|
|
@@ -208,6 +216,8 @@ interface Particle {
|
|
|
208
216
|
overflow?: string;
|
|
209
217
|
/** Per-type config entry (shallow overrides root config). */
|
|
210
218
|
typeConfig?: ParticleTypeEntry;
|
|
219
|
+
/** Random phase offset (0–2π) for pulse animation. Makes particles pulse out of sync. */
|
|
220
|
+
pulsePhase?: number;
|
|
211
221
|
/** Smoothed x for overlay positioning. */
|
|
212
222
|
smoothX?: number;
|
|
213
223
|
/** Smoothed y for overlay positioning. */
|
package/dist/index.d.ts
CHANGED
|
@@ -38,6 +38,8 @@ interface LiquidGlassConfig {
|
|
|
38
38
|
minRadius?: number;
|
|
39
39
|
/** Maximum radius (px) for liquid glass particles (overrides root maxRadius). */
|
|
40
40
|
maxRadius?: number;
|
|
41
|
+
/** Blob deformation speed multiplier (default 1). 0 = frozen, 2 = double speed. */
|
|
42
|
+
blobSpeed?: number;
|
|
41
43
|
}
|
|
42
44
|
interface CircleTypeEntry {
|
|
43
45
|
type: "circle";
|
|
@@ -94,6 +96,12 @@ interface ChildParticleConfig {
|
|
|
94
96
|
mouseInfluence?: number;
|
|
95
97
|
/** Render as liquid glass particle. Default false. */
|
|
96
98
|
liquidGlass?: boolean;
|
|
99
|
+
/** Opacity (0–1) for liquid glass child particles. Overrides global liquidGlass.opacity. */
|
|
100
|
+
glassOpacity?: number;
|
|
101
|
+
/** Color (hex) for liquid glass child particles. Overrides global liquidGlass.color. */
|
|
102
|
+
glassColor?: string;
|
|
103
|
+
/** Full liquid glass config override for child particles. Merged over global liquidGlass. */
|
|
104
|
+
liquidGlassConfig?: Partial<LiquidGlassConfig>;
|
|
97
105
|
}
|
|
98
106
|
/** Emitted position data for a child particle each frame. */
|
|
99
107
|
interface ChildParticlePosition {
|
|
@@ -208,6 +216,8 @@ interface Particle {
|
|
|
208
216
|
overflow?: string;
|
|
209
217
|
/** Per-type config entry (shallow overrides root config). */
|
|
210
218
|
typeConfig?: ParticleTypeEntry;
|
|
219
|
+
/** Random phase offset (0–2π) for pulse animation. Makes particles pulse out of sync. */
|
|
220
|
+
pulsePhase?: number;
|
|
211
221
|
/** Smoothed x for overlay positioning. */
|
|
212
222
|
smoothX?: number;
|
|
213
223
|
/** Smoothed y for overlay positioning. */
|
package/dist/index.js
CHANGED
|
@@ -67,6 +67,7 @@ var DEFAULT_LIQUID_GLASS = {
|
|
|
67
67
|
shadowStrength: 0.4,
|
|
68
68
|
secondaryReflection: 0.25,
|
|
69
69
|
secondaryHighlightPosition: "bottom-right",
|
|
70
|
+
blobSpeed: 1,
|
|
70
71
|
minRadius: 20,
|
|
71
72
|
maxRadius: 40
|
|
72
73
|
};
|
|
@@ -182,7 +183,7 @@ var ParticleNetwork = class {
|
|
|
182
183
|
const h = isRect ? particle.height : (particle.currentRadius ?? particle.radius) * 2;
|
|
183
184
|
el.style.width = w + "px";
|
|
184
185
|
el.style.height = h + "px";
|
|
185
|
-
el.style.transform = `
|
|
186
|
+
el.style.transform = `translate3d(${Math.round(px - w / 2)}px, ${Math.round(py - h / 2)}px, 0)`;
|
|
186
187
|
if (isRect) {
|
|
187
188
|
const br = particle.borderRadius ?? Math.min(w, h) / 2;
|
|
188
189
|
el.style.borderRadius = br + "px";
|
|
@@ -338,7 +339,14 @@ var ParticleNetwork = class {
|
|
|
338
339
|
if (!Array.isArray(config.particleTypes)) {
|
|
339
340
|
throw new Error("particleTypes must be an array");
|
|
340
341
|
}
|
|
341
|
-
|
|
342
|
+
let hasAssetEntries = false;
|
|
343
|
+
for (const entry of config.particleTypes) {
|
|
344
|
+
if (entry?.type === "asset") {
|
|
345
|
+
hasAssetEntries = true;
|
|
346
|
+
break;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
if (hasAssetEntries && (!config.assets || typeof config.assets !== "object")) {
|
|
342
350
|
throw new Error("assets map is required when using particleTypes with asset entries");
|
|
343
351
|
}
|
|
344
352
|
for (let i = 0; i < config.particleTypes.length; i++) {
|
|
@@ -358,8 +366,9 @@ var ParticleNetwork = class {
|
|
|
358
366
|
if (typeof pt.asset !== "string" || !pt.asset) {
|
|
359
367
|
throw new Error(`particleTypes[${i}].asset must be a non-empty string`);
|
|
360
368
|
}
|
|
361
|
-
|
|
362
|
-
|
|
369
|
+
const assetKey = pt.asset;
|
|
370
|
+
if (!config.assets?.[assetKey]) {
|
|
371
|
+
throw new Error(`particleTypes[${i}]: asset "${assetKey}" not found in assets`);
|
|
363
372
|
}
|
|
364
373
|
}
|
|
365
374
|
}
|
|
@@ -457,6 +466,7 @@ var ParticleNetwork = class {
|
|
|
457
466
|
delete p.assetId;
|
|
458
467
|
delete p.liquidGlass;
|
|
459
468
|
delete p.typeConfig;
|
|
469
|
+
delete p.pulsePhase;
|
|
460
470
|
});
|
|
461
471
|
if (particleTypes?.length) {
|
|
462
472
|
const counts = [];
|
|
@@ -525,6 +535,14 @@ var ParticleNetwork = class {
|
|
|
525
535
|
if (!particleTypes?.length && (this.config.liquidGlassPercentage != null || this.config.liquidGlassCount != null)) {
|
|
526
536
|
this.assignLiquidGlass();
|
|
527
537
|
}
|
|
538
|
+
this.particles.forEach((p) => {
|
|
539
|
+
if (p.isChild) return;
|
|
540
|
+
const tc = p.typeConfig;
|
|
541
|
+
const doPulse = tc?.pulse ?? this.config.pulseEnabled;
|
|
542
|
+
if (doPulse) {
|
|
543
|
+
p.pulsePhase = Math.random() * Math.PI * 2;
|
|
544
|
+
}
|
|
545
|
+
});
|
|
528
546
|
this.assignMouseBehavior();
|
|
529
547
|
}
|
|
530
548
|
assignLiquidGlass() {
|
|
@@ -630,7 +648,8 @@ var ParticleNetwork = class {
|
|
|
630
648
|
if (doPulse) {
|
|
631
649
|
const speed = tc?.pulseSpeed ?? this.config.pulseSpeed;
|
|
632
650
|
this.pulseAngle += speed;
|
|
633
|
-
const
|
|
651
|
+
const phase = particle.pulsePhase ?? 0;
|
|
652
|
+
const pulseScale = Math.sin(this.pulseAngle + phase) * 0.5 + 1;
|
|
634
653
|
particle.currentRadius = particle.radius * pulseScale;
|
|
635
654
|
} else {
|
|
636
655
|
particle.currentRadius = particle.radius;
|
|
@@ -831,7 +850,20 @@ var ParticleNetwork = class {
|
|
|
831
850
|
}
|
|
832
851
|
draw3DFluidSphere(particle) {
|
|
833
852
|
const tc = particle.typeConfig;
|
|
834
|
-
|
|
853
|
+
let perTypeLg = tc && "liquidGlass" in tc && typeof tc.liquidGlass === "object" ? tc.liquidGlass : void 0;
|
|
854
|
+
if (particle.isChild && particle.childId) {
|
|
855
|
+
const childConfig = this.childParticleConfigs.get(particle.childId);
|
|
856
|
+
if (childConfig) {
|
|
857
|
+
const overrides = {
|
|
858
|
+
...childConfig.liquidGlassConfig ?? {},
|
|
859
|
+
...childConfig.glassOpacity != null && { opacity: childConfig.glassOpacity },
|
|
860
|
+
...childConfig.glassColor != null && { color: childConfig.glassColor }
|
|
861
|
+
};
|
|
862
|
+
if (Object.keys(overrides).length > 0) {
|
|
863
|
+
perTypeLg = { ...perTypeLg ?? {}, ...overrides };
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
}
|
|
835
867
|
const lg = perTypeLg ? { ...this.getLiquidGlassConfig(), ...perTypeLg } : this.getLiquidGlassConfig();
|
|
836
868
|
const r = particle.currentRadius ?? particle.radius;
|
|
837
869
|
if (r <= 0) return;
|
|
@@ -840,46 +872,60 @@ var ParticleNetwork = class {
|
|
|
840
872
|
const cx = particle.x;
|
|
841
873
|
const cy = particle.y;
|
|
842
874
|
const isRect = particle.width != null && particle.height != null;
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
875
|
+
const hasExplicitChildOpacity = particle.isChild && particle.childId && (() => {
|
|
876
|
+
const cfg = this.childParticleConfigs.get(particle.childId);
|
|
877
|
+
return cfg?.glassOpacity != null || cfg?.liquidGlassConfig?.opacity != null;
|
|
878
|
+
})();
|
|
879
|
+
let opacity = lg.opacity ?? DEFAULT_LIQUID_GLASS.opacity;
|
|
880
|
+
if (!hasExplicitChildOpacity) {
|
|
881
|
+
opacity *= this.config.particleOpacity;
|
|
882
|
+
if (this.config.depthEffectEnabled) {
|
|
883
|
+
opacity *= 0.6 + 0.4 * particle.z;
|
|
884
|
+
}
|
|
846
885
|
}
|
|
847
886
|
if (opacity <= 0) return;
|
|
848
|
-
|
|
887
|
+
const blobSpeed = lg.blobSpeed ?? 1;
|
|
888
|
+
blob.rotation += blob.rotSpeed * blobSpeed;
|
|
849
889
|
for (let m = 0; m < blob.phases.length; m++) {
|
|
850
|
-
blob.phases[m] += blob.phaseSpeeds[m];
|
|
890
|
+
blob.phases[m] += blob.phaseSpeeds[m] * blobSpeed;
|
|
851
891
|
}
|
|
852
|
-
blob.hlAngle += blob.hlAngleSpeed;
|
|
892
|
+
blob.hlAngle += blob.hlAngleSpeed * blobSpeed;
|
|
853
893
|
this.updateBlobMouse(particle);
|
|
854
894
|
const color = lg.color ?? DEFAULT_LIQUID_GLASS.color;
|
|
855
895
|
const baseR = parseInt(color.slice(1, 3), 16);
|
|
856
896
|
const baseG = parseInt(color.slice(3, 5), 16);
|
|
857
897
|
const baseB = parseInt(color.slice(5, 7), 16);
|
|
858
898
|
const shadowStr = lg.shadowStrength ?? DEFAULT_LIQUID_GLASS.shadowStrength;
|
|
899
|
+
const refl = (lg.reflectionStrength ?? DEFAULT_LIQUID_GLASS.reflectionStrength) / DEFAULT_LIQUID_GLASS.reflectionStrength;
|
|
859
900
|
const gradR = isRect ? Math.max(particle.width, particle.height) / 2 : r;
|
|
860
901
|
const hlDist = gradR * 0.35;
|
|
861
902
|
const hlX = cx + Math.cos(blob.hlAngle) * hlDist;
|
|
862
903
|
const hlY = cy + Math.sin(blob.hlAngle) * hlDist;
|
|
863
|
-
const lr = Math.min(255, baseR + Math.round((255 - baseR) * 0.55));
|
|
864
|
-
const lgr = Math.min(255, baseG + Math.round((255 - baseG) * 0.55));
|
|
865
|
-
const lb = Math.min(255, baseB + Math.round((255 - baseB) * 0.55));
|
|
904
|
+
const lr = Math.min(255, baseR + Math.round((255 - baseR) * 0.55 * refl));
|
|
905
|
+
const lgr = Math.min(255, baseG + Math.round((255 - baseG) * 0.55 * refl));
|
|
906
|
+
const lb = Math.min(255, baseB + Math.round((255 - baseB) * 0.55 * refl));
|
|
866
907
|
const dr = Math.max(0, Math.round(baseR * (1 - shadowStr * 0.35)));
|
|
867
908
|
const dg = Math.max(0, Math.round(baseG * (1 - shadowStr * 0.35)));
|
|
868
909
|
const db = Math.max(0, Math.round(baseB * (1 - shadowStr * 0.35)));
|
|
869
910
|
this.ctx.save();
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
911
|
+
this.ctx.globalAlpha = 1;
|
|
912
|
+
if (hasExplicitChildOpacity && opacity >= 0.99) {
|
|
913
|
+
this.ctx.fillStyle = `rgba(${baseR},${baseG},${baseB}, ${opacity})`;
|
|
914
|
+
} else {
|
|
915
|
+
const grad = this.ctx.createRadialGradient(
|
|
916
|
+
hlX,
|
|
917
|
+
hlY,
|
|
918
|
+
gradR * 0.05,
|
|
919
|
+
cx,
|
|
920
|
+
cy,
|
|
921
|
+
gradR * 1.05
|
|
922
|
+
);
|
|
923
|
+
grad.addColorStop(0, `rgba(${lr},${lgr},${lb}, ${opacity * 0.95})`);
|
|
924
|
+
grad.addColorStop(0.4, `rgba(${baseR},${baseG},${baseB}, ${opacity * 0.8})`);
|
|
925
|
+
grad.addColorStop(0.8, `rgba(${dr},${dg},${db}, ${opacity * 0.6})`);
|
|
926
|
+
grad.addColorStop(1, `rgba(${dr},${dg},${db}, ${opacity * 0.25})`);
|
|
927
|
+
this.ctx.fillStyle = grad;
|
|
928
|
+
}
|
|
883
929
|
if (isRect) {
|
|
884
930
|
const halfW = particle.width / 2;
|
|
885
931
|
const halfH = particle.height / 2;
|
package/dist/index.mjs
CHANGED
package/dist/react.d.mts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import * as react from 'react';
|
|
2
3
|
import { ReactNode, CSSProperties, RefObject } from 'react';
|
|
3
|
-
import { ParticleNetworkConfig } from './index.mjs';
|
|
4
|
+
import { LiquidGlassConfig, ParticleNetworkConfig, ParticleNetwork } from './index.mjs';
|
|
4
5
|
|
|
6
|
+
declare const ParticleNetworkContext: react.Context<ParticleNetwork | null>;
|
|
5
7
|
declare function useParticleNetwork(config?: Partial<ParticleNetworkConfig>): RefObject<HTMLCanvasElement | null>;
|
|
6
8
|
interface ParticleNetworkBgProps {
|
|
7
9
|
config?: Partial<ParticleNetworkConfig>;
|
|
@@ -27,6 +29,12 @@ interface ChildParticleProps {
|
|
|
27
29
|
anchorForce?: number;
|
|
28
30
|
/** Mouse influence multiplier (0-1). Default 0.1. */
|
|
29
31
|
mouseInfluence?: number;
|
|
32
|
+
/** Opacity (0-1) for liquid glass. Only applies when liquidGlass is true. */
|
|
33
|
+
glassOpacity?: number;
|
|
34
|
+
/** Color (hex) for liquid glass. Only applies when liquidGlass is true. */
|
|
35
|
+
glassColor?: string;
|
|
36
|
+
/** Full liquid glass config override. Merged over global liquidGlass. */
|
|
37
|
+
liquidGlassConfig?: Partial<LiquidGlassConfig>;
|
|
30
38
|
children?: ReactNode;
|
|
31
39
|
style?: CSSProperties;
|
|
32
40
|
className?: string;
|
|
@@ -49,10 +57,16 @@ interface GlassChildParticleProps {
|
|
|
49
57
|
anchorForce?: number;
|
|
50
58
|
/** Mouse influence multiplier (0-1). Default 0.1. */
|
|
51
59
|
mouseInfluence?: number;
|
|
60
|
+
/** Opacity (0-1) for the glass background. Default uses global liquidGlass.opacity. */
|
|
61
|
+
glassOpacity?: number;
|
|
62
|
+
/** Color (hex) for the glass background. Default uses global liquidGlass.color. */
|
|
63
|
+
glassColor?: string;
|
|
64
|
+
/** Full liquid glass config override. Merged over global liquidGlass. */
|
|
65
|
+
liquidGlassConfig?: Partial<LiquidGlassConfig>;
|
|
52
66
|
children?: ReactNode;
|
|
53
67
|
style?: CSSProperties;
|
|
54
68
|
className?: string;
|
|
55
69
|
}
|
|
56
70
|
declare function GlassChildParticle(props: GlassChildParticleProps): react_jsx_runtime.JSX.Element;
|
|
57
71
|
|
|
58
|
-
export { ChildParticle, type ChildParticleProps, GlassChildParticle, type GlassChildParticleProps, ParticleNetworkBg, type ParticleNetworkBgProps, useParticleNetwork };
|
|
72
|
+
export { ChildParticle, type ChildParticleProps, GlassChildParticle, type GlassChildParticleProps, ParticleNetworkBg, type ParticleNetworkBgProps, ParticleNetworkContext, useParticleNetwork };
|
package/dist/react.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import * as react from 'react';
|
|
2
3
|
import { ReactNode, CSSProperties, RefObject } from 'react';
|
|
3
|
-
import { ParticleNetworkConfig } from './index.js';
|
|
4
|
+
import { LiquidGlassConfig, ParticleNetworkConfig, ParticleNetwork } from './index.js';
|
|
4
5
|
|
|
6
|
+
declare const ParticleNetworkContext: react.Context<ParticleNetwork | null>;
|
|
5
7
|
declare function useParticleNetwork(config?: Partial<ParticleNetworkConfig>): RefObject<HTMLCanvasElement | null>;
|
|
6
8
|
interface ParticleNetworkBgProps {
|
|
7
9
|
config?: Partial<ParticleNetworkConfig>;
|
|
@@ -27,6 +29,12 @@ interface ChildParticleProps {
|
|
|
27
29
|
anchorForce?: number;
|
|
28
30
|
/** Mouse influence multiplier (0-1). Default 0.1. */
|
|
29
31
|
mouseInfluence?: number;
|
|
32
|
+
/** Opacity (0-1) for liquid glass. Only applies when liquidGlass is true. */
|
|
33
|
+
glassOpacity?: number;
|
|
34
|
+
/** Color (hex) for liquid glass. Only applies when liquidGlass is true. */
|
|
35
|
+
glassColor?: string;
|
|
36
|
+
/** Full liquid glass config override. Merged over global liquidGlass. */
|
|
37
|
+
liquidGlassConfig?: Partial<LiquidGlassConfig>;
|
|
30
38
|
children?: ReactNode;
|
|
31
39
|
style?: CSSProperties;
|
|
32
40
|
className?: string;
|
|
@@ -49,10 +57,16 @@ interface GlassChildParticleProps {
|
|
|
49
57
|
anchorForce?: number;
|
|
50
58
|
/** Mouse influence multiplier (0-1). Default 0.1. */
|
|
51
59
|
mouseInfluence?: number;
|
|
60
|
+
/** Opacity (0-1) for the glass background. Default uses global liquidGlass.opacity. */
|
|
61
|
+
glassOpacity?: number;
|
|
62
|
+
/** Color (hex) for the glass background. Default uses global liquidGlass.color. */
|
|
63
|
+
glassColor?: string;
|
|
64
|
+
/** Full liquid glass config override. Merged over global liquidGlass. */
|
|
65
|
+
liquidGlassConfig?: Partial<LiquidGlassConfig>;
|
|
52
66
|
children?: ReactNode;
|
|
53
67
|
style?: CSSProperties;
|
|
54
68
|
className?: string;
|
|
55
69
|
}
|
|
56
70
|
declare function GlassChildParticle(props: GlassChildParticleProps): react_jsx_runtime.JSX.Element;
|
|
57
71
|
|
|
58
|
-
export { ChildParticle, type ChildParticleProps, GlassChildParticle, type GlassChildParticleProps, ParticleNetworkBg, type ParticleNetworkBgProps, useParticleNetwork };
|
|
72
|
+
export { ChildParticle, type ChildParticleProps, GlassChildParticle, type GlassChildParticleProps, ParticleNetworkBg, type ParticleNetworkBgProps, ParticleNetworkContext, useParticleNetwork };
|
package/dist/react.js
CHANGED
|
@@ -23,6 +23,7 @@ __export(react_exports, {
|
|
|
23
23
|
ChildParticle: () => ChildParticle,
|
|
24
24
|
GlassChildParticle: () => GlassChildParticle,
|
|
25
25
|
ParticleNetworkBg: () => ParticleNetworkBg,
|
|
26
|
+
ParticleNetworkContext: () => ParticleNetworkContext,
|
|
26
27
|
useParticleNetwork: () => useParticleNetwork
|
|
27
28
|
});
|
|
28
29
|
module.exports = __toCommonJS(react_exports);
|
|
@@ -74,6 +75,7 @@ var DEFAULT_LIQUID_GLASS = {
|
|
|
74
75
|
shadowStrength: 0.4,
|
|
75
76
|
secondaryReflection: 0.25,
|
|
76
77
|
secondaryHighlightPosition: "bottom-right",
|
|
78
|
+
blobSpeed: 1,
|
|
77
79
|
minRadius: 20,
|
|
78
80
|
maxRadius: 40
|
|
79
81
|
};
|
|
@@ -189,7 +191,7 @@ var ParticleNetwork = class {
|
|
|
189
191
|
const h = isRect ? particle.height : (particle.currentRadius ?? particle.radius) * 2;
|
|
190
192
|
el.style.width = w + "px";
|
|
191
193
|
el.style.height = h + "px";
|
|
192
|
-
el.style.transform = `
|
|
194
|
+
el.style.transform = `translate3d(${Math.round(px - w / 2)}px, ${Math.round(py - h / 2)}px, 0)`;
|
|
193
195
|
if (isRect) {
|
|
194
196
|
const br = particle.borderRadius ?? Math.min(w, h) / 2;
|
|
195
197
|
el.style.borderRadius = br + "px";
|
|
@@ -345,7 +347,14 @@ var ParticleNetwork = class {
|
|
|
345
347
|
if (!Array.isArray(config.particleTypes)) {
|
|
346
348
|
throw new Error("particleTypes must be an array");
|
|
347
349
|
}
|
|
348
|
-
|
|
350
|
+
let hasAssetEntries = false;
|
|
351
|
+
for (const entry of config.particleTypes) {
|
|
352
|
+
if (entry?.type === "asset") {
|
|
353
|
+
hasAssetEntries = true;
|
|
354
|
+
break;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
if (hasAssetEntries && (!config.assets || typeof config.assets !== "object")) {
|
|
349
358
|
throw new Error("assets map is required when using particleTypes with asset entries");
|
|
350
359
|
}
|
|
351
360
|
for (let i = 0; i < config.particleTypes.length; i++) {
|
|
@@ -365,8 +374,9 @@ var ParticleNetwork = class {
|
|
|
365
374
|
if (typeof pt.asset !== "string" || !pt.asset) {
|
|
366
375
|
throw new Error(`particleTypes[${i}].asset must be a non-empty string`);
|
|
367
376
|
}
|
|
368
|
-
|
|
369
|
-
|
|
377
|
+
const assetKey = pt.asset;
|
|
378
|
+
if (!config.assets?.[assetKey]) {
|
|
379
|
+
throw new Error(`particleTypes[${i}]: asset "${assetKey}" not found in assets`);
|
|
370
380
|
}
|
|
371
381
|
}
|
|
372
382
|
}
|
|
@@ -464,6 +474,7 @@ var ParticleNetwork = class {
|
|
|
464
474
|
delete p.assetId;
|
|
465
475
|
delete p.liquidGlass;
|
|
466
476
|
delete p.typeConfig;
|
|
477
|
+
delete p.pulsePhase;
|
|
467
478
|
});
|
|
468
479
|
if (particleTypes?.length) {
|
|
469
480
|
const counts = [];
|
|
@@ -532,6 +543,14 @@ var ParticleNetwork = class {
|
|
|
532
543
|
if (!particleTypes?.length && (this.config.liquidGlassPercentage != null || this.config.liquidGlassCount != null)) {
|
|
533
544
|
this.assignLiquidGlass();
|
|
534
545
|
}
|
|
546
|
+
this.particles.forEach((p) => {
|
|
547
|
+
if (p.isChild) return;
|
|
548
|
+
const tc = p.typeConfig;
|
|
549
|
+
const doPulse = tc?.pulse ?? this.config.pulseEnabled;
|
|
550
|
+
if (doPulse) {
|
|
551
|
+
p.pulsePhase = Math.random() * Math.PI * 2;
|
|
552
|
+
}
|
|
553
|
+
});
|
|
535
554
|
this.assignMouseBehavior();
|
|
536
555
|
}
|
|
537
556
|
assignLiquidGlass() {
|
|
@@ -637,7 +656,8 @@ var ParticleNetwork = class {
|
|
|
637
656
|
if (doPulse) {
|
|
638
657
|
const speed = tc?.pulseSpeed ?? this.config.pulseSpeed;
|
|
639
658
|
this.pulseAngle += speed;
|
|
640
|
-
const
|
|
659
|
+
const phase = particle.pulsePhase ?? 0;
|
|
660
|
+
const pulseScale = Math.sin(this.pulseAngle + phase) * 0.5 + 1;
|
|
641
661
|
particle.currentRadius = particle.radius * pulseScale;
|
|
642
662
|
} else {
|
|
643
663
|
particle.currentRadius = particle.radius;
|
|
@@ -838,7 +858,20 @@ var ParticleNetwork = class {
|
|
|
838
858
|
}
|
|
839
859
|
draw3DFluidSphere(particle) {
|
|
840
860
|
const tc = particle.typeConfig;
|
|
841
|
-
|
|
861
|
+
let perTypeLg = tc && "liquidGlass" in tc && typeof tc.liquidGlass === "object" ? tc.liquidGlass : void 0;
|
|
862
|
+
if (particle.isChild && particle.childId) {
|
|
863
|
+
const childConfig = this.childParticleConfigs.get(particle.childId);
|
|
864
|
+
if (childConfig) {
|
|
865
|
+
const overrides = {
|
|
866
|
+
...childConfig.liquidGlassConfig ?? {},
|
|
867
|
+
...childConfig.glassOpacity != null && { opacity: childConfig.glassOpacity },
|
|
868
|
+
...childConfig.glassColor != null && { color: childConfig.glassColor }
|
|
869
|
+
};
|
|
870
|
+
if (Object.keys(overrides).length > 0) {
|
|
871
|
+
perTypeLg = { ...perTypeLg ?? {}, ...overrides };
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
}
|
|
842
875
|
const lg = perTypeLg ? { ...this.getLiquidGlassConfig(), ...perTypeLg } : this.getLiquidGlassConfig();
|
|
843
876
|
const r = particle.currentRadius ?? particle.radius;
|
|
844
877
|
if (r <= 0) return;
|
|
@@ -847,46 +880,60 @@ var ParticleNetwork = class {
|
|
|
847
880
|
const cx = particle.x;
|
|
848
881
|
const cy = particle.y;
|
|
849
882
|
const isRect = particle.width != null && particle.height != null;
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
883
|
+
const hasExplicitChildOpacity = particle.isChild && particle.childId && (() => {
|
|
884
|
+
const cfg = this.childParticleConfigs.get(particle.childId);
|
|
885
|
+
return cfg?.glassOpacity != null || cfg?.liquidGlassConfig?.opacity != null;
|
|
886
|
+
})();
|
|
887
|
+
let opacity = lg.opacity ?? DEFAULT_LIQUID_GLASS.opacity;
|
|
888
|
+
if (!hasExplicitChildOpacity) {
|
|
889
|
+
opacity *= this.config.particleOpacity;
|
|
890
|
+
if (this.config.depthEffectEnabled) {
|
|
891
|
+
opacity *= 0.6 + 0.4 * particle.z;
|
|
892
|
+
}
|
|
853
893
|
}
|
|
854
894
|
if (opacity <= 0) return;
|
|
855
|
-
|
|
895
|
+
const blobSpeed = lg.blobSpeed ?? 1;
|
|
896
|
+
blob.rotation += blob.rotSpeed * blobSpeed;
|
|
856
897
|
for (let m = 0; m < blob.phases.length; m++) {
|
|
857
|
-
blob.phases[m] += blob.phaseSpeeds[m];
|
|
898
|
+
blob.phases[m] += blob.phaseSpeeds[m] * blobSpeed;
|
|
858
899
|
}
|
|
859
|
-
blob.hlAngle += blob.hlAngleSpeed;
|
|
900
|
+
blob.hlAngle += blob.hlAngleSpeed * blobSpeed;
|
|
860
901
|
this.updateBlobMouse(particle);
|
|
861
902
|
const color = lg.color ?? DEFAULT_LIQUID_GLASS.color;
|
|
862
903
|
const baseR = parseInt(color.slice(1, 3), 16);
|
|
863
904
|
const baseG = parseInt(color.slice(3, 5), 16);
|
|
864
905
|
const baseB = parseInt(color.slice(5, 7), 16);
|
|
865
906
|
const shadowStr = lg.shadowStrength ?? DEFAULT_LIQUID_GLASS.shadowStrength;
|
|
907
|
+
const refl = (lg.reflectionStrength ?? DEFAULT_LIQUID_GLASS.reflectionStrength) / DEFAULT_LIQUID_GLASS.reflectionStrength;
|
|
866
908
|
const gradR = isRect ? Math.max(particle.width, particle.height) / 2 : r;
|
|
867
909
|
const hlDist = gradR * 0.35;
|
|
868
910
|
const hlX = cx + Math.cos(blob.hlAngle) * hlDist;
|
|
869
911
|
const hlY = cy + Math.sin(blob.hlAngle) * hlDist;
|
|
870
|
-
const lr = Math.min(255, baseR + Math.round((255 - baseR) * 0.55));
|
|
871
|
-
const lgr = Math.min(255, baseG + Math.round((255 - baseG) * 0.55));
|
|
872
|
-
const lb = Math.min(255, baseB + Math.round((255 - baseB) * 0.55));
|
|
912
|
+
const lr = Math.min(255, baseR + Math.round((255 - baseR) * 0.55 * refl));
|
|
913
|
+
const lgr = Math.min(255, baseG + Math.round((255 - baseG) * 0.55 * refl));
|
|
914
|
+
const lb = Math.min(255, baseB + Math.round((255 - baseB) * 0.55 * refl));
|
|
873
915
|
const dr = Math.max(0, Math.round(baseR * (1 - shadowStr * 0.35)));
|
|
874
916
|
const dg = Math.max(0, Math.round(baseG * (1 - shadowStr * 0.35)));
|
|
875
917
|
const db = Math.max(0, Math.round(baseB * (1 - shadowStr * 0.35)));
|
|
876
918
|
this.ctx.save();
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
919
|
+
this.ctx.globalAlpha = 1;
|
|
920
|
+
if (hasExplicitChildOpacity && opacity >= 0.99) {
|
|
921
|
+
this.ctx.fillStyle = `rgba(${baseR},${baseG},${baseB}, ${opacity})`;
|
|
922
|
+
} else {
|
|
923
|
+
const grad = this.ctx.createRadialGradient(
|
|
924
|
+
hlX,
|
|
925
|
+
hlY,
|
|
926
|
+
gradR * 0.05,
|
|
927
|
+
cx,
|
|
928
|
+
cy,
|
|
929
|
+
gradR * 1.05
|
|
930
|
+
);
|
|
931
|
+
grad.addColorStop(0, `rgba(${lr},${lgr},${lb}, ${opacity * 0.95})`);
|
|
932
|
+
grad.addColorStop(0.4, `rgba(${baseR},${baseG},${baseB}, ${opacity * 0.8})`);
|
|
933
|
+
grad.addColorStop(0.8, `rgba(${dr},${dg},${db}, ${opacity * 0.6})`);
|
|
934
|
+
grad.addColorStop(1, `rgba(${dr},${dg},${db}, ${opacity * 0.25})`);
|
|
935
|
+
this.ctx.fillStyle = grad;
|
|
936
|
+
}
|
|
890
937
|
if (isRect) {
|
|
891
938
|
const halfW = particle.width / 2;
|
|
892
939
|
const halfH = particle.height / 2;
|
|
@@ -1308,6 +1355,9 @@ function BaseChildParticle({
|
|
|
1308
1355
|
anchorForce,
|
|
1309
1356
|
mouseInfluence,
|
|
1310
1357
|
liquidGlass,
|
|
1358
|
+
glassOpacity,
|
|
1359
|
+
glassColor,
|
|
1360
|
+
liquidGlassConfig,
|
|
1311
1361
|
children,
|
|
1312
1362
|
style,
|
|
1313
1363
|
className
|
|
@@ -1327,7 +1377,10 @@ function BaseChildParticle({
|
|
|
1327
1377
|
overflow,
|
|
1328
1378
|
anchorForce,
|
|
1329
1379
|
mouseInfluence,
|
|
1330
|
-
liquidGlass
|
|
1380
|
+
liquidGlass,
|
|
1381
|
+
glassOpacity,
|
|
1382
|
+
glassColor,
|
|
1383
|
+
liquidGlassConfig
|
|
1331
1384
|
});
|
|
1332
1385
|
setOverlayEl(instance.getChildOverlayElement(id));
|
|
1333
1386
|
return () => {
|
|
@@ -1347,9 +1400,12 @@ function BaseChildParticle({
|
|
|
1347
1400
|
overflow,
|
|
1348
1401
|
anchorForce,
|
|
1349
1402
|
mouseInfluence,
|
|
1350
|
-
liquidGlass
|
|
1403
|
+
liquidGlass,
|
|
1404
|
+
glassOpacity,
|
|
1405
|
+
glassColor,
|
|
1406
|
+
liquidGlassConfig
|
|
1351
1407
|
});
|
|
1352
|
-
}, [instance, id, x, y, radius, width, height, borderRadius, overflow, anchorForce, mouseInfluence, liquidGlass]);
|
|
1408
|
+
}, [instance, id, x, y, radius, width, height, borderRadius, overflow, anchorForce, mouseInfluence, liquidGlass, glassOpacity, glassColor, liquidGlassConfig]);
|
|
1353
1409
|
if (!overlayEl) return null;
|
|
1354
1410
|
const isRect = width != null && height != null;
|
|
1355
1411
|
const portalBorderRadius = isRect ? (borderRadius ?? Math.min(width, height) / 2) + "px" : "50%";
|
|
@@ -1379,5 +1435,6 @@ function BaseChildParticle({
|
|
|
1379
1435
|
ChildParticle,
|
|
1380
1436
|
GlassChildParticle,
|
|
1381
1437
|
ParticleNetworkBg,
|
|
1438
|
+
ParticleNetworkContext,
|
|
1382
1439
|
useParticleNetwork
|
|
1383
1440
|
});
|
package/dist/react.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ParticleNetwork
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-JZTYQ6XI.mjs";
|
|
4
4
|
|
|
5
5
|
// src/react.tsx
|
|
6
6
|
import {
|
|
@@ -78,6 +78,9 @@ function BaseChildParticle({
|
|
|
78
78
|
anchorForce,
|
|
79
79
|
mouseInfluence,
|
|
80
80
|
liquidGlass,
|
|
81
|
+
glassOpacity,
|
|
82
|
+
glassColor,
|
|
83
|
+
liquidGlassConfig,
|
|
81
84
|
children,
|
|
82
85
|
style,
|
|
83
86
|
className
|
|
@@ -97,7 +100,10 @@ function BaseChildParticle({
|
|
|
97
100
|
overflow,
|
|
98
101
|
anchorForce,
|
|
99
102
|
mouseInfluence,
|
|
100
|
-
liquidGlass
|
|
103
|
+
liquidGlass,
|
|
104
|
+
glassOpacity,
|
|
105
|
+
glassColor,
|
|
106
|
+
liquidGlassConfig
|
|
101
107
|
});
|
|
102
108
|
setOverlayEl(instance.getChildOverlayElement(id));
|
|
103
109
|
return () => {
|
|
@@ -117,9 +123,12 @@ function BaseChildParticle({
|
|
|
117
123
|
overflow,
|
|
118
124
|
anchorForce,
|
|
119
125
|
mouseInfluence,
|
|
120
|
-
liquidGlass
|
|
126
|
+
liquidGlass,
|
|
127
|
+
glassOpacity,
|
|
128
|
+
glassColor,
|
|
129
|
+
liquidGlassConfig
|
|
121
130
|
});
|
|
122
|
-
}, [instance, id, x, y, radius, width, height, borderRadius, overflow, anchorForce, mouseInfluence, liquidGlass]);
|
|
131
|
+
}, [instance, id, x, y, radius, width, height, borderRadius, overflow, anchorForce, mouseInfluence, liquidGlass, glassOpacity, glassColor, liquidGlassConfig]);
|
|
123
132
|
if (!overlayEl) return null;
|
|
124
133
|
const isRect = width != null && height != null;
|
|
125
134
|
const portalBorderRadius = isRect ? (borderRadius ?? Math.min(width, height) / 2) + "px" : "50%";
|
|
@@ -148,5 +157,6 @@ export {
|
|
|
148
157
|
ChildParticle,
|
|
149
158
|
GlassChildParticle,
|
|
150
159
|
ParticleNetworkBg,
|
|
160
|
+
ParticleNetworkContext,
|
|
151
161
|
useParticleNetwork
|
|
152
162
|
};
|