@3driseai/3drise-viewer 0.1.16 → 0.1.18

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.
Files changed (145) hide show
  1. package/README.md +4 -3
  2. package/dist/components/ChladniGrid.d.ts +15 -0
  3. package/dist/components/ChladniGrid.d.ts.map +1 -0
  4. package/dist/components/ChladniGrid.js +62 -0
  5. package/dist/components/CustomPrimitive.d.ts +2 -0
  6. package/dist/components/CustomPrimitive.d.ts.map +1 -1
  7. package/dist/components/CustomPrimitive.js +2 -2
  8. package/dist/components/EffectsGenerator.d.ts.map +1 -1
  9. package/dist/components/EffectsGenerator.js +26 -2
  10. package/dist/components/FlowNetGrid.d.ts +15 -0
  11. package/dist/components/FlowNetGrid.d.ts.map +1 -0
  12. package/dist/components/FlowNetGrid.js +61 -0
  13. package/dist/components/Galaxy.d.ts.map +1 -1
  14. package/dist/components/Galaxy.js +2 -0
  15. package/dist/components/GirihGrid.d.ts +15 -0
  16. package/dist/components/GirihGrid.d.ts.map +1 -0
  17. package/dist/components/GirihGrid.js +62 -0
  18. package/dist/components/GravWaveGrid.d.ts +15 -0
  19. package/dist/components/GravWaveGrid.d.ts.map +1 -0
  20. package/dist/components/GravWaveGrid.js +62 -0
  21. package/dist/components/GridsGenerator.d.ts +2 -2
  22. package/dist/components/GridsGenerator.d.ts.map +1 -1
  23. package/dist/components/GridsGenerator.js +21 -0
  24. package/dist/components/HyperbolicGrid.d.ts +15 -0
  25. package/dist/components/HyperbolicGrid.d.ts.map +1 -0
  26. package/dist/components/HyperbolicGrid.js +61 -0
  27. package/dist/components/LayoutInstances.d.ts +13 -0
  28. package/dist/components/LayoutInstances.d.ts.map +1 -0
  29. package/dist/components/LayoutInstances.js +39 -0
  30. package/dist/components/ModelPrimitive.d.ts +2 -0
  31. package/dist/components/ModelPrimitive.d.ts.map +1 -1
  32. package/dist/components/ModelPrimitive.js +3 -3
  33. package/dist/components/ObjectNode.d.ts.map +1 -1
  34. package/dist/components/ObjectNode.js +44 -9
  35. package/dist/components/ParticlesGenerator.d.ts +10 -0
  36. package/dist/components/ParticlesGenerator.d.ts.map +1 -0
  37. package/dist/components/ParticlesGenerator.js +23 -0
  38. package/dist/components/ReactionDiffusionGrid.d.ts +15 -0
  39. package/dist/components/ReactionDiffusionGrid.d.ts.map +1 -0
  40. package/dist/components/ReactionDiffusionGrid.js +376 -0
  41. package/dist/components/WallpaperGrid.d.ts +15 -0
  42. package/dist/components/WallpaperGrid.d.ts.map +1 -0
  43. package/dist/components/WallpaperGrid.js +555 -0
  44. package/dist/components/cursor/CursorController.d.ts.map +1 -1
  45. package/dist/components/effects/BlackHoleEffect.d.ts +3 -3
  46. package/dist/components/effects/BlackHoleEffect.d.ts.map +1 -1
  47. package/dist/components/effects/BlackHoleEffect.js +293 -163
  48. package/dist/components/effects/DandelionSeedsEffect.d.ts +13 -0
  49. package/dist/components/effects/DandelionSeedsEffect.d.ts.map +1 -0
  50. package/dist/components/effects/DandelionSeedsEffect.js +510 -0
  51. package/dist/components/effects/FallingLeavesEffect.d.ts +13 -0
  52. package/dist/components/effects/FallingLeavesEffect.d.ts.map +1 -0
  53. package/dist/components/effects/FallingLeavesEffect.js +446 -0
  54. package/dist/components/effects/FieldLinesEffect.d.ts +11 -0
  55. package/dist/components/effects/FieldLinesEffect.d.ts.map +1 -0
  56. package/dist/components/effects/FieldLinesEffect.js +260 -0
  57. package/dist/components/effects/FireflySwarmEffect.d.ts +13 -0
  58. package/dist/components/effects/FireflySwarmEffect.d.ts.map +1 -0
  59. package/dist/components/effects/FireflySwarmEffect.js +408 -0
  60. package/dist/components/effects/GalaxyEffect.d.ts +13 -0
  61. package/dist/components/effects/GalaxyEffect.d.ts.map +1 -0
  62. package/dist/components/effects/GalaxyEffect.js +374 -0
  63. package/dist/components/effects/HarmonicShellEffect.d.ts +11 -0
  64. package/dist/components/effects/HarmonicShellEffect.d.ts.map +1 -0
  65. package/dist/components/effects/HarmonicShellEffect.js +209 -0
  66. package/dist/components/effects/IceCrystalsEffect.d.ts +3 -3
  67. package/dist/components/effects/IceCrystalsEffect.d.ts.map +1 -1
  68. package/dist/components/effects/IceCrystalsEffect.js +286 -166
  69. package/dist/components/effects/IceHaloEffect.d.ts +13 -0
  70. package/dist/components/effects/IceHaloEffect.d.ts.map +1 -0
  71. package/dist/components/effects/IceHaloEffect.js +306 -0
  72. package/dist/components/effects/LichtenbergEffect.d.ts +13 -0
  73. package/dist/components/effects/LichtenbergEffect.d.ts.map +1 -0
  74. package/dist/components/effects/LichtenbergEffect.js +517 -0
  75. package/dist/components/effects/MoleculesEffect.d.ts +3 -3
  76. package/dist/components/effects/MoleculesEffect.d.ts.map +1 -1
  77. package/dist/components/effects/MoleculesEffect.js +322 -164
  78. package/dist/components/effects/MurmurationEffect.d.ts +13 -0
  79. package/dist/components/effects/MurmurationEffect.d.ts.map +1 -0
  80. package/dist/components/effects/MurmurationEffect.js +539 -0
  81. package/dist/components/effects/PlanetaryRingsEffect.d.ts +13 -0
  82. package/dist/components/effects/PlanetaryRingsEffect.d.ts.map +1 -0
  83. package/dist/components/effects/PlanetaryRingsEffect.js +458 -0
  84. package/dist/components/effects/PortalEffect.d.ts +3 -3
  85. package/dist/components/effects/PortalEffect.d.ts.map +1 -1
  86. package/dist/components/effects/PortalEffect.js +240 -163
  87. package/dist/components/effects/ShockwaveEffect.d.ts +5 -3
  88. package/dist/components/effects/ShockwaveEffect.d.ts.map +1 -1
  89. package/dist/components/effects/ShockwaveEffect.js +538 -142
  90. package/dist/components/effects/SmokePlumeEffect.d.ts +3 -3
  91. package/dist/components/effects/SmokePlumeEffect.d.ts.map +1 -1
  92. package/dist/components/effects/SmokePlumeEffect.js +180 -116
  93. package/dist/components/effects/SmokeRingEffect.d.ts +3 -3
  94. package/dist/components/effects/SmokeRingEffect.d.ts.map +1 -1
  95. package/dist/components/effects/SmokeRingEffect.js +260 -135
  96. package/dist/components/effects/StrangeAttractorEffect.d.ts +11 -0
  97. package/dist/components/effects/StrangeAttractorEffect.d.ts.map +1 -0
  98. package/dist/components/effects/StrangeAttractorEffect.js +229 -0
  99. package/dist/components/effects/VolumetricFogEffect.d.ts +5 -3
  100. package/dist/components/effects/VolumetricFogEffect.d.ts.map +1 -1
  101. package/dist/components/effects/VolumetricFogEffect.js +211 -93
  102. package/dist/components/effects/WaterCausticsEffect.d.ts +13 -0
  103. package/dist/components/effects/WaterCausticsEffect.d.ts.map +1 -0
  104. package/dist/components/effects/WaterCausticsEffect.js +308 -0
  105. package/dist/components/effects/index.d.ts +9 -0
  106. package/dist/components/effects/index.d.ts.map +1 -1
  107. package/dist/components/effects/index.js +9 -0
  108. package/dist/components/index.d.ts +19 -0
  109. package/dist/components/index.d.ts.map +1 -1
  110. package/dist/components/index.js +10 -0
  111. package/dist/components/particles/BioluminescentWakeParticles.d.ts +12 -0
  112. package/dist/components/particles/BioluminescentWakeParticles.d.ts.map +1 -0
  113. package/dist/components/particles/BioluminescentWakeParticles.js +1123 -0
  114. package/dist/components/particles/BrownianDustParticles.d.ts +12 -0
  115. package/dist/components/particles/BrownianDustParticles.d.ts.map +1 -0
  116. package/dist/components/particles/BrownianDustParticles.js +757 -0
  117. package/dist/components/particles/ElectronOrbitalsParticles.d.ts +12 -0
  118. package/dist/components/particles/ElectronOrbitalsParticles.d.ts.map +1 -0
  119. package/dist/components/particles/ElectronOrbitalsParticles.js +944 -0
  120. package/dist/components/particles/GrinderSparksParticles.d.ts +12 -0
  121. package/dist/components/particles/GrinderSparksParticles.d.ts.map +1 -0
  122. package/dist/components/particles/GrinderSparksParticles.js +744 -0
  123. package/dist/components/particles/TidalStreamParticles.d.ts +12 -0
  124. package/dist/components/particles/TidalStreamParticles.d.ts.map +1 -0
  125. package/dist/components/particles/TidalStreamParticles.js +788 -0
  126. package/dist/components/particles/index.d.ts +11 -0
  127. package/dist/components/particles/index.d.ts.map +1 -0
  128. package/dist/components/particles/index.js +6 -0
  129. package/dist/constants.d.ts +1 -1
  130. package/dist/constants.d.ts.map +1 -1
  131. package/dist/constants.js +1 -1
  132. package/dist/hooks/useModelObject.d.ts +6 -1
  133. package/dist/hooks/useModelObject.d.ts.map +1 -1
  134. package/dist/hooks/useModelObject.js +19 -6
  135. package/dist/types/gridConfigs.d.ts +98 -0
  136. package/dist/types/gridConfigs.d.ts.map +1 -1
  137. package/dist/types/index.d.ts +1 -1
  138. package/dist/types/index.d.ts.map +1 -1
  139. package/dist/utils/particleTrails.d.ts +70 -0
  140. package/dist/utils/particleTrails.d.ts.map +1 -0
  141. package/dist/utils/particleTrails.js +369 -0
  142. package/dist/utils/pointerField.d.ts +28 -0
  143. package/dist/utils/pointerField.d.ts.map +1 -0
  144. package/dist/utils/pointerField.js +103 -0
  145. package/package.json +2 -2
@@ -1,194 +1,271 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useRef, useMemo } from 'react';
3
- import { useFrame } from '@react-three/fiber';
2
+ import { useEffect, useLayoutEffect, useMemo, useRef } from 'react';
4
3
  import * as THREE from 'three';
4
+ import { useFrame } from '@react-three/fiber';
5
5
  import { applyGenerativeAnimations } from '../../utils/handleGenerativeEffectsAnimations.js';
6
6
  import { useObjectReady } from '../../hooks/useObjectReady.js';
7
- // Multi-layer vortex disc
8
- const discVertShader = /* glsl */ `
9
- varying vec2 vUv;
10
- void main() {
11
- vUv = uv;
12
- gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
7
+ /**
8
+ * A wormhole portal lying under the host.
9
+ *
10
+ * The disc is bent into Flamm's paraboloid (depth ~ sqrt(r - r_t)) so it
11
+ * funnels down to a throat. Through the throat you see another universe,
12
+ * lensed into an Einstein ring at its edge. The funnel swirls with Keplerian
13
+ * shear (omega ~ r^-1.5), using a two-phase flow map so the spiral never winds
14
+ * up, and matter falls in along log spirals, heating and blueshifting.
15
+ */
16
+ const PRE_NORMAL = { transparent: true, depthWrite: false, blending: THREE.NormalBlending, premultipliedAlpha: true };
17
+ const PRE_ADD = { transparent: true, depthWrite: false, blending: THREE.AdditiveBlending, premultipliedAlpha: true };
18
+ function mulberry32(seed) {
19
+ return () => {
20
+ seed |= 0;
21
+ seed = (seed + 0x6d2b79f5) | 0;
22
+ let r = Math.imul(seed ^ (seed >>> 15), 1 | seed);
23
+ r = (r + Math.imul(r ^ (r >>> 7), 61 | r)) ^ r;
24
+ return ((r ^ (r >>> 14)) >>> 0) / 4294967296;
25
+ };
26
+ }
27
+ function seedTriples(count, seed) {
28
+ const rand = mulberry32(seed);
29
+ const out = new Float32Array(count * 3);
30
+ for (let i = 0; i < out.length; i++)
31
+ out[i] = rand();
32
+ return out;
33
+ }
34
+ function buildInfall(count) {
35
+ const n = Math.round(Math.min(Math.max(count, 0), 400));
36
+ return { count: n, aSeed: seedTriples(n, 31) };
37
+ }
38
+ const portalVert = /* glsl */ `
39
+ uniform float uThroatSize;
40
+ uniform float uFunnelDepth;
41
+ uniform float uRadius;
42
+ uniform float uBound;
43
+ varying vec2 vP;
44
+ void main(){
45
+ // Normalised disc coordinates; the geometry is a unit disc scaled by uRadius.
46
+ vP = position.xy;
47
+ float r = length(position.xy);
48
+ // Flamm's paraboloid, the embedding of a Schwarzschild throat:
49
+ // depth falls as sqrt(r - r_throat), flat inside the throat.
50
+ float rt = uThroatSize;
51
+ float s = clamp((r - rt) / max(1.0 - rt, 1e-3), 0.0, 1.0);
52
+ float depth = uFunnelDepth * (1.0 - sqrt(s));
53
+ float Rw = uRadius * uBound;
54
+ vec3 pos = vec3(position.xy * Rw, -depth * Rw);
55
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
13
56
  }
14
57
  `;
15
- const discFragShader = /* glsl */ `
16
- uniform float u_time;
17
- uniform float uSpiralTurns;
58
+ const portalFrag = /* glsl */ `
59
+ uniform float uTime;
18
60
  uniform float uRotationSpeed;
19
- uniform vec3 uInnerColor;
20
- uniform vec3 uOuterColor;
61
+ uniform float uSpiralTurns;
62
+ uniform float uThroatSize;
63
+ uniform vec3 uInnerGlowColor;
64
+ uniform vec3 uOuterGlowColor;
65
+ uniform vec3 uOtherSideColor;
21
66
  uniform float uOpacity;
22
67
  uniform float uIntensity;
68
+ varying vec2 vP;
23
69
 
24
- varying vec2 vUv;
70
+
71
+ float hash13(vec3 p3){
72
+ p3 = fract(p3 * 0.1031);
73
+ p3 += dot(p3, p3.zyx + 31.32);
74
+ return fract((p3.x + p3.y) * p3.z);
75
+ }
76
+ float vnoise(vec3 p){
77
+ vec3 i = floor(p);
78
+ vec3 f = fract(p);
79
+ f = f * f * f * (f * (f * 6.0 - 15.0) + 10.0);
80
+ float n000 = hash13(i);
81
+ float n100 = hash13(i + vec3(1.0, 0.0, 0.0));
82
+ float n010 = hash13(i + vec3(0.0, 1.0, 0.0));
83
+ float n110 = hash13(i + vec3(1.0, 1.0, 0.0));
84
+ float n001 = hash13(i + vec3(0.0, 0.0, 1.0));
85
+ float n101 = hash13(i + vec3(1.0, 0.0, 1.0));
86
+ float n011 = hash13(i + vec3(0.0, 1.0, 1.0));
87
+ float n111 = hash13(i + vec3(1.0, 1.0, 1.0));
88
+ return mix(mix(mix(n000, n100, f.x), mix(n010, n110, f.x), f.y),
89
+ mix(mix(n001, n101, f.x), mix(n011, n111, f.x), f.y), f.z);
90
+ }
91
+ // low-frequency fBm; the rotation between octaves hides the lattice
92
+ const mat3 FBM_ROT = mat3(0.00, 0.80, 0.60, -0.80, 0.36, -0.48, -0.60, -0.48, 0.64);
93
+ float fbm3(vec3 p, int octaves){
94
+ float a = 0.5, s = 0.0;
95
+ for (int i = 0; i < 5; i++){
96
+ if (i >= octaves) break;
97
+ s += a * vnoise(p);
98
+ p = FBM_ROT * p * 2.02;
99
+ a *= 0.5;
100
+ }
101
+ return s;
102
+ }
25
103
 
26
- float hash(vec2 p){ return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453); }
27
104
 
28
- void main() {
29
- vec2 centered = vUv * 2.0 - 1.0;
30
- float dist = length(centered);
31
- if (dist > 1.0) discard;
105
+ vec3 otherSide(vec3 dir, float t){
106
+ // the far universe: a slow nebula and a static star field
107
+ float c = cos(t * 0.02), s = sin(t * 0.02);
108
+ dir.xz = mat2(c, -s, s, c) * dir.xz;
109
+ vec3 w = vec3(fbm3(dir * 1.8, 3), fbm3(dir * 1.8 + 7.1, 3), 0.0);
110
+ float neb = fbm3(dir * 2.6 + w * 1.5, 4);
111
+ vec3 col = uOtherSideColor * smoothstep(0.35, 0.8, neb) * 1.2
112
+ + uInnerGlowColor * smoothstep(0.55, 0.9, fbm3(dir * 4.0 + 3.0, 3)) * 0.35;
113
+ vec3 sp = dir * 42.0;
114
+ vec3 id = floor(sp);
115
+ vec3 f = fract(sp) - 0.5;
116
+ float hs = hash13(id);
117
+ vec3 o = (vec3(hash13(id + 1.7), hash13(id + 3.1), hash13(id + 5.3)) - 0.5) * 0.5;
118
+ float star = step(0.94, hs) * smoothstep(0.1, 0.0, length(f - o)) * (hs - 0.94) * 16.0;
119
+ return col + vec3(star);
120
+ }
32
121
 
33
- float angle = atan(centered.y, centered.x);
122
+ void main(){
34
123
  const float TAU = 6.28318530718;
35
- float t = u_time * uRotationSpeed;
36
-
37
- // Three counter-rotating spiral layers
38
- float s1 = fract(dist * uSpiralTurns - angle / TAU + t);
39
- float s2 = fract(dist * uSpiralTurns * 0.6 + angle / TAU - t * 1.4);
40
- float s3 = fract(dist * uSpiralTurns * 2.2 - angle / TAU * 1.5 + t * 2.1);
41
-
42
- float w3 = pow(1.0 - dist, 2.0);
43
- float vortex = s1 * 0.45 + s2 * 0.30 * (1.0 - w3) + s3 * 0.60 * w3;
44
-
45
- // Gravitational lensing rim
46
- float rimRing = exp(-pow((dist - 0.92) / 0.04, 2.0)) * 3.0;
47
- float rim = pow(smoothstep(0.85, 1.0, dist), 0.7) * 1.5;
124
+ float r = length(vP);
125
+ if (r > 1.0) discard;
126
+ float theta = atan(vP.y, vP.x);
127
+ float rt = uThroatSize;
128
+ float t = uTime * uRotationSpeed;
129
+ float aa = fwidth(r) * 1.5;
48
130
 
49
- // Singularity core
50
- float core = exp(-dist * dist * 22.0) * 4.0;
51
- float singularity = exp(-dist * dist * 90.0) * 8.0;
131
+ // ---- throat: the other side, compressed toward the rim like a fisheye.
132
+ // Near the throat edge light is bent hardest, so the view squeezes into
133
+ // a thin bright Einstein ring.
134
+ float s = clamp(r / rt, 0.0, 1.0);
135
+ float psi = pow(s, 0.55) * 1.45;
136
+ vec3 dir = normalize(vec3(vP / max(r, 1e-4) * sin(psi), cos(psi)));
137
+ vec3 inside = otherSide(dir, t) * (0.5 + 0.5 * (1.0 - s * s));
138
+ float throat = 1.0 - smoothstep(rt - aa, rt + aa, r);
139
+ float einstein = exp(-pow((r - rt) / (0.018 + aa), 2.0));
52
140
 
53
- float edgeFade = 1.0 - smoothstep(0.72, 1.0, dist);
54
- float noise = hash(vec2(dist * 8.0 + t * 0.3, angle));
55
- float flux = 0.85 + 0.15 * noise;
141
+ // ---- funnel: swirling matter on logarithmic spiral arms with Keplerian
142
+ // shear (Omega ~ r^-1.5), crossfaded between two phases so it never winds tight.
143
+ float x = (r - rt) / max(1.0 - rt, 1e-3);
144
+ float omega = pow(max(r, 0.05) / 0.5, -1.5);
145
+ float ph = t / 6.0;
146
+ float f0 = fract(ph), f1 = fract(ph + 0.5);
147
+ float wgt = 1.0 - abs(2.0 * f0 - 1.0);
148
+ float th0 = theta + omega * f0 * 6.0 * 0.8;
149
+ float th1 = theta + omega * f1 * 6.0 * 0.8;
150
+ float n0 = fbm3(vec3(cos(th0) * r * 3.0, sin(th0) * r * 3.0, floor(ph) * 3.1), 4);
151
+ float n1 = fbm3(vec3(cos(th1) * r * 3.0, sin(th1) * r * 3.0, floor(ph + 0.5) * 3.1 + 9.0), 4);
152
+ float n = n0 * wgt + n1 * (1.0 - wgt);
153
+ float arms = 0.5 + 0.5 * sin(uSpiralTurns * log(max(r, 0.02)) * 2.2 - 2.0 * (theta + omega * t * 0.12) + n * 3.0);
154
+ float swirl = (smoothstep(0.25, 1.0, arms) * 0.7 + n * 0.8);
155
+ float bright = pow(1.0 - x, 2.2) * 1.6 + 0.08;
156
+ vec3 grad = mix(uOuterGlowColor, uInnerGlowColor, pow(1.0 - x, 1.8));
157
+ float outer = (1.0 - throat) * (1.0 - smoothstep(0.82, 1.0, r));
158
+ vec3 funnel = grad * swirl * bright * outer;
56
159
 
57
- vec3 rimLight = mix(uOuterColor * 2.0, vec3(1.0, 0.9, 0.7), rimRing * 0.5);
58
- vec3 col = mix(rimLight, uInnerColor, vortex * 0.7 + core * 0.3) * flux;
59
- col += vec3(1.0, 0.95, 0.85) * (singularity + core * 0.4);
60
- col += uOuterColor * rim * 0.8;
61
-
62
- float alpha = (vortex * 0.5 + edgeFade * 0.25 + core * 0.5 + rim * 0.4 + singularity * 0.3)
63
- * uOpacity * uIntensity;
64
- if (alpha < 0.008) discard;
65
- gl_FragColor = vec4(col, alpha);
160
+ vec3 col = inside * throat + funnel + mix(uInnerGlowColor, vec3(1.0), 0.6) * einstein * 1.4;
161
+ float alpha = clamp(throat + (swirl * bright * 0.8) * outer + einstein, 0.0, 1.0) * uOpacity;
162
+ gl_FragColor = vec4(col * uIntensity * uOpacity, alpha);
66
163
  }
67
164
  `;
68
- // ── Event-horizon dust — GPU animated, all motion in vertex shader ────────────
69
- // Each particle orbits independently at a slightly perturbed radius, height, and speed.
70
- const dustVertShader = /* glsl */ `
71
- attribute float aAngle; // initial angle 0..TAU
72
- attribute float aRadiusOff; // -0.12..+0.12 (fractional deviation from rim radius)
73
- attribute float aHeightOff; // -0.08..+0.08 relative height deviation
74
- attribute float aSpeed; // orbit speed multiplier 0.3..1.7
75
- attribute float aPhase; // twinkle phase
76
-
77
- uniform float u_time;
165
+ const infallVert = /* glsl */ `
166
+ attribute vec3 aSeed; // x: start angle, y: phase, z: random
167
+ uniform float uTime;
168
+ uniform float uRotationSpeed;
169
+ uniform float uThroatSize;
170
+ uniform float uFunnelDepth;
78
171
  uniform float uRadius;
79
- uniform float uPointSize;
80
- uniform float u_speed;
81
-
82
- varying float vAlpha;
83
-
84
- void main() {
85
- const float TAU = 6.28318530718;
86
-
87
- float angle = aAngle + u_time * u_speed * aSpeed;
88
- float r = uRadius * (1.0 + aRadiusOff);
89
- float y = uRadius * aHeightOff * sin(angle * 2.3 + aPhase + u_time * 0.7);
90
-
91
- vec3 pos = vec3(cos(angle) * r, y, sin(angle) * r);
92
-
93
- // Subtle twinkle — most dust is nearly invisible, occasionally flickers bright
94
- float twinkle = pow(max(0.0, sin(u_time * 1.8 + aPhase)), 6.0); // sharp spikes
95
- float base = 0.08 + 0.12 * (0.5 + 0.5 * sin(aPhase + u_time * 0.4));
96
- vAlpha = base + twinkle * 0.7;
97
-
98
- vec4 mv = modelViewMatrix * vec4(pos, 1.0);
99
- gl_PointSize = uPointSize * (0.4 + twinkle * 1.6) * (180.0 / -mv.z);
100
- gl_Position = projectionMatrix * mv;
172
+ uniform float uBound;
173
+ uniform float uIntensity;
174
+ varying float vHeat;
175
+ varying float vFade;
176
+ void main(){
177
+ // Matter spirals in on r = r0 exp(-k tau) with Keplerian angular speed;
178
+ // the angle is the closed-form integral of Omega = Omega0 r^-1.5.
179
+ float life = fract(aSeed.y + uTime * uRotationSpeed * 0.05 * (0.7 + 0.6 * aSeed.z));
180
+ float r0 = 0.95;
181
+ float rt = uThroatSize;
182
+ float k = log(r0 / rt);
183
+ float r = r0 * exp(-k * life);
184
+ float om0 = 0.35;
185
+ float phi = aSeed.x * 6.2832 + om0 / (1.5 * k) * (pow(r / 0.5, -1.5) - pow(r0 / 0.5, -1.5)) * 3.0;
186
+ float s = clamp((r - rt) / max(1.0 - rt, 1e-3), 0.0, 1.0);
187
+ float depth = uFunnelDepth * (1.0 - sqrt(s));
188
+ vec3 pos = vec3(cos(phi) * r, sin(phi) * r, -depth + 0.01) * (uRadius * uBound);
189
+ vHeat = pow(1.0 - s, 1.5);
190
+ vFade = smoothstep(0.0, 0.1, life) * (1.0 - smoothstep(0.85, 1.0, life));
191
+ vec4 mv = modelViewMatrix * vec4(pos, 1.0);
192
+ gl_PointSize = (1.2 + 3.5 * vHeat) * uIntensity * (4.0 * uRadius * uBound / max(-mv.z, 1e-3));
193
+ gl_Position = projectionMatrix * mv;
101
194
  }
102
195
  `;
103
- const dustFragShader = /* glsl */ `
104
- uniform vec3 uColor;
196
+ const infallFrag = /* glsl */ `
197
+ uniform vec3 uInnerGlowColor;
198
+ uniform vec3 uOuterGlowColor;
105
199
  uniform float uOpacity;
106
- varying float vAlpha;
107
-
108
- void main() {
109
- vec2 coord = gl_PointCoord - 0.5;
110
- float dist = length(coord);
111
- if (dist > 0.5) discard;
112
- float glow = exp(-dist * dist * 9.0);
113
- gl_FragColor = vec4(uColor, vAlpha * uOpacity * glow);
200
+ varying float vHeat;
201
+ varying float vFade;
202
+ void main(){
203
+ float d = length(gl_PointCoord - 0.5);
204
+ if (d > 0.5) discard;
205
+ float core = smoothstep(0.5, 0.0, d);
206
+ // infalling matter heats up and blueshifts toward the throat
207
+ vec3 col = mix(uOuterGlowColor, mix(uInnerGlowColor, vec3(0.85, 0.92, 1.0), vHeat), vHeat);
208
+ float a = core * core * vFade * (0.3 + 0.9 * vHeat) * uOpacity;
209
+ gl_FragColor = vec4(col * a, a);
114
210
  }
115
211
  `;
116
212
  const PortalEffect = ({ boundingRadius, config, animations, onObjectReady, onObjectDispose }) => {
117
- const { radius, spiralTurns, innerGlowColor, outerGlowColor, rotationSpeed, particleRingEnabled, particleCount, opacity, speed, intensity } = config;
118
- const startValuesCacheRef = useRef({});
213
+ const { intensity = 1, speed = 1, opacity = 0.95, radius = 1.5, spiralTurns = 6, innerGlowColor = '#e9e4ff', outerGlowColor = '#8800ff', rotationSpeed = 1.2, particleRingEnabled = true, particleCount = 160, throatSize = 0.38, funnelDepth = 0.6, otherSideColor = '#2a6bff', } = config;
119
214
  const rootRef = useRef(null);
215
+ const animCache = useRef({});
120
216
  useObjectReady(rootRef, config, onObjectReady, onObjectDispose);
121
- const r = boundingRadius * radius;
122
- const innerColorVec = useMemo(() => { const c = new THREE.Color(innerGlowColor); return new THREE.Vector3(c.r, c.g, c.b); }, [innerGlowColor]);
123
- const outerColorVec = useMemo(() => { const c = new THREE.Color(outerGlowColor); return new THREE.Vector3(c.r, c.g, c.b); }, [outerGlowColor]);
124
- const discMaterial = useMemo(() => new THREE.ShaderMaterial({
125
- vertexShader: discVertShader,
126
- fragmentShader: discFragShader,
127
- uniforms: {
128
- u_time: { value: 0 },
129
- uSpiralTurns: { value: spiralTurns },
130
- uRotationSpeed: { value: rotationSpeed * speed },
131
- uInnerColor: { value: innerColorVec },
132
- uOuterColor: { value: outerColorVec },
133
- uOpacity: { value: opacity },
134
- uIntensity: { value: intensity },
135
- },
136
- transparent: true,
137
- depthWrite: false,
138
- blending: THREE.AdditiveBlending,
139
- side: THREE.DoubleSide,
140
- }), [spiralTurns, rotationSpeed, speed, innerColorVec, outerColorVec, opacity, intensity]);
141
- // ── Event-horizon dust ──────────────────────────────────────────────────────
142
- const { dustGeo, dustMat } = useMemo(() => {
143
- const count = particleCount;
144
- const angles = new Float32Array(count);
145
- const radOffsets = new Float32Array(count);
146
- const heightOffs = new Float32Array(count);
147
- const speeds = new Float32Array(count);
148
- const phases = new Float32Array(count);
149
- for (let i = 0; i < count; i++) {
150
- angles[i] = (i / count) * Math.PI * 2 + Math.random() * 0.2;
151
- radOffsets[i] = (Math.random() - 0.5) * 0.24;
152
- heightOffs[i] = (Math.random() - 0.5) * 0.16;
153
- speeds[i] = 0.3 + Math.random() * 1.4; // wide speed spread
154
- phases[i] = Math.random() * Math.PI * 2;
155
- }
156
- const geo = new THREE.BufferGeometry();
157
- // Positions are computed entirely in vertex shader; use dummy zero positions
158
- geo.setAttribute('position', new THREE.BufferAttribute(new Float32Array(count * 3), 3));
159
- geo.setAttribute('aAngle', new THREE.BufferAttribute(angles, 1));
160
- geo.setAttribute('aRadiusOff', new THREE.BufferAttribute(radOffsets, 1));
161
- geo.setAttribute('aHeightOff', new THREE.BufferAttribute(heightOffs, 1));
162
- geo.setAttribute('aSpeed', new THREE.BufferAttribute(speeds, 1));
163
- geo.setAttribute('aPhase', new THREE.BufferAttribute(phases, 1));
164
- // Dust color: mostly white, very slightly tinted toward innerGlowColor
165
- const dustCol = new THREE.Color(innerGlowColor).lerp(new THREE.Color('#ffffff'), 0.75);
166
- const dustColVec = new THREE.Vector3(dustCol.r, dustCol.g, dustCol.b);
167
- const mat = new THREE.ShaderMaterial({
168
- vertexShader: dustVertShader,
169
- fragmentShader: dustFragShader,
170
- uniforms: {
171
- u_time: { value: 0 },
172
- uRadius: { value: r },
173
- uPointSize: { value: 5 * intensity },
174
- u_speed: { value: speed * 0.5 },
175
- uColor: { value: dustColVec },
176
- uOpacity: { value: opacity * 0.6 },
177
- },
178
- transparent: true,
179
- depthWrite: false,
180
- blending: THREE.AdditiveBlending,
181
- });
182
- return { dustGeo: geo, dustMat: mat };
183
- }, [particleCount, r, innerGlowColor, intensity, speed, opacity]);
184
- useFrame((state) => {
185
- const t = state.clock.getElapsedTime();
186
- discMaterial.uniforms.u_time.value = t;
187
- dustMat.uniforms.u_time.value = t;
188
- if (animations?.length) {
189
- applyGenerativeAnimations([discMaterial, dustMat], animations, startValuesCacheRef.current, Date.now(), false);
190
- }
217
+ // a standalone effect gets boundingRadius 1; guard against an empty host
218
+ const b = boundingRadius > 0 ? boundingRadius : 1;
219
+ const uniforms = useMemo(() => ({
220
+ uTime: { value: 0 },
221
+ uSpeed: { value: 1 },
222
+ uBound: { value: 1 },
223
+ uIntensity: { value: 1 },
224
+ uOpacity: { value: 1 },
225
+ uRadius: { value: 1.5 },
226
+ uSpiralTurns: { value: 6 },
227
+ uRotationSpeed: { value: 1.2 },
228
+ uThroatSize: { value: 0.38 },
229
+ uFunnelDepth: { value: 0.6 },
230
+ uInnerGlowColor: { value: new THREE.Color() },
231
+ uOuterGlowColor: { value: new THREE.Color() },
232
+ uOtherSideColor: { value: new THREE.Color() },
233
+ }), []);
234
+ const materials = useMemo(() => [
235
+ new THREE.ShaderMaterial({ vertexShader: portalVert, fragmentShader: portalFrag, uniforms, ...PRE_NORMAL, side: THREE.DoubleSide }),
236
+ new THREE.ShaderMaterial({ vertexShader: infallVert, fragmentShader: infallFrag, uniforms, ...PRE_ADD }),
237
+ ], [uniforms]);
238
+ useEffect(() => () => materials.forEach((m) => m.dispose()), [materials]);
239
+ // a unit disc; the vertex shader scales it and bends it into the funnel
240
+ const discGeometry = useMemo(() => new THREE.RingGeometry(0.0005, 1, 128, 64), []);
241
+ useEffect(() => () => discGeometry.dispose(), [discGeometry]);
242
+ const infallGeometry = useMemo(() => {
243
+ const inf = buildInfall(particleCount);
244
+ const g = new THREE.BufferGeometry();
245
+ g.setAttribute('position', new THREE.BufferAttribute(new Float32Array(inf.count * 3), 3));
246
+ g.setAttribute('aSeed', new THREE.BufferAttribute(inf.aSeed, 3));
247
+ return g;
248
+ }, [particleCount]);
249
+ useEffect(() => () => infallGeometry.dispose(), [infallGeometry]);
250
+ useLayoutEffect(() => {
251
+ uniforms.uSpeed.value = speed;
252
+ uniforms.uBound.value = b;
253
+ uniforms.uIntensity.value = intensity;
254
+ uniforms.uOpacity.value = opacity;
255
+ uniforms.uRadius.value = radius;
256
+ uniforms.uSpiralTurns.value = spiralTurns;
257
+ uniforms.uRotationSpeed.value = rotationSpeed;
258
+ uniforms.uThroatSize.value = throatSize;
259
+ uniforms.uFunnelDepth.value = funnelDepth;
260
+ uniforms.uInnerGlowColor.value.set(innerGlowColor);
261
+ uniforms.uOuterGlowColor.value.set(outerGlowColor);
262
+ uniforms.uOtherSideColor.value.set(otherSideColor);
263
+ }, [uniforms, speed, b, intensity, opacity, radius, spiralTurns, rotationSpeed, throatSize, funnelDepth, innerGlowColor, outerGlowColor, otherSideColor]);
264
+ useFrame((_, delta) => {
265
+ uniforms.uTime.value += delta * uniforms.uSpeed.value;
266
+ if (animations?.length)
267
+ applyGenerativeAnimations(materials, animations, animCache.current, Date.now(), false);
191
268
  });
192
- return (_jsxs("group", { ref: rootRef, rotation: [-Math.PI / 2, 0, 0], position: [0, -boundingRadius * 0.75, 0], children: [_jsx("mesh", { material: discMaterial, children: _jsx("circleGeometry", { args: [r, 80] }) }), particleRingEnabled && (_jsx("points", { geometry: dustGeo, material: dustMat }))] }));
269
+ return (_jsx("group", { ref: rootRef, children: _jsxs("group", { rotation: [-Math.PI / 2, 0, 0], position: [0, -b * 0.75, 0], children: [_jsx("mesh", { geometry: discGeometry, material: materials[0], frustumCulled: false }), _jsx("points", { geometry: infallGeometry, material: materials[1], visible: particleRingEnabled, frustumCulled: false })] }) }));
193
270
  };
194
271
  export default PortalEffect;
@@ -1,10 +1,12 @@
1
- import React from "react";
2
- import type { ShockwaveConfig, AnimationOptions } from "@3driseai/3drise-core";
1
+ import React from 'react';
2
+ import type { AnimationOptions, ShockwaveConfig } from '@3driseai/3drise-core';
3
3
  import type { ObjectReadyProps } from '../../types/objectReady';
4
- interface ShockwaveEffectProps extends ObjectReadyProps {
4
+ export interface ShockwaveEffectProps extends ObjectReadyProps {
5
5
  boundingRadius: number;
6
6
  config: ShockwaveConfig;
7
7
  animations?: AnimationOptions[];
8
+ /** True when the effect is attached to an object, so it can react to the host. */
9
+ hasHost?: boolean;
8
10
  }
9
11
  declare const ShockwaveEffect: React.FC<ShockwaveEffectProps>;
10
12
  export default ShockwaveEffect;
@@ -1 +1 @@
1
- {"version":3,"file":"ShockwaveEffect.d.ts","sourceRoot":"","sources":["../../../src/components/effects/ShockwaveEffect.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAE/E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAChE,UAAU,oBAAqB,SAAQ,gBAAgB;IACnD,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,eAAe,CAAC;IACxB,UAAU,CAAC,EAAE,gBAAgB,EAAE,CAAC;CACnC;AAkFD,QAAA,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CA2EnD,CAAC;AACF,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"ShockwaveEffect.d.ts","sourceRoot":"","sources":["../../../src/components/effects/ShockwaveEffect.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAsD,MAAM,OAAO,CAAC;AAG3E,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAG/E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAEhE,MAAM,WAAW,oBAAqB,SAAQ,gBAAgB;IAC1D,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,eAAe,CAAC;IACxB,UAAU,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAChC,kFAAkF;IAClF,OAAO,CAAC,EAAE,OAAO,CAAC;CACrB;AA4hBD,QAAA,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CA+BnD,CAAC;AAEF,eAAe,eAAe,CAAC"}