claude-live 2.0.8 → 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -41
- package/bin/claude-live +0 -0
- package/client/dist/assets/AgentDemoScene-CXlvncAb.js +147 -0
- package/client/dist/assets/ColonizationDemoScene-Cils_y13.js +1 -0
- package/client/dist/assets/EffectDemoScene-BXqCMwER.js +138 -0
- package/client/dist/assets/SakuraPage-BfD0y3D9.js +518 -0
- package/client/dist/assets/index-nnbWctP_.css +1 -0
- package/client/dist/assets/index-zmiMo1Db.js +4430 -0
- package/client/dist/index.html +2 -2
- package/package.json +14 -8
- package/server/history-reader.js +68 -0
- package/server/index.js +115 -7
- package/server/project-tree.js +178 -0
- package/server/session-scanner.js +150 -0
- package/server/transcript-parser.js +177 -0
- package/client/dist/assets/BufferResource-B3YcFk1L.js +0 -185
- package/client/dist/assets/CanvasRenderer-B7cP3KcG.js +0 -1
- package/client/dist/assets/Filter-BXkJkOCD.js +0 -1
- package/client/dist/assets/RenderTargetSystem-DkV5EZ2H.js +0 -172
- package/client/dist/assets/WebGLRenderer-Cgmusykq.js +0 -156
- package/client/dist/assets/WebGPURenderer-B_Gw9-ml.js +0 -41
- package/client/dist/assets/browserAll-wXmCMyRg.js +0 -14
- package/client/dist/assets/index-BGs_09Jl.js +0 -318
- package/client/dist/assets/index-DjcKbX6b.css +0 -1
- package/client/dist/assets/webworkerAll-Hyzs6HuJ.js +0 -83
- package/hooks/hooks.json +0 -161
- package/hooks/run-hook.cmd +0 -38
- package/hooks/send-event +0 -5
- package/hooks/session-start +0 -40
package/README.md
CHANGED
|
@@ -1,85 +1,68 @@
|
|
|
1
1
|
# claude-live
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**[Try the live demo](https://marisancans.github.io/claude-live/)** — no install needed
|
|
4
4
|
|
|
5
5
|

|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Real-time visualization of Claude Code activity as a 3D orbital system.
|
|
8
8
|
|
|
9
9
|
## Install
|
|
10
10
|
|
|
11
|
-
###
|
|
11
|
+
### Claude Code Marketplace (recommended)
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
Search for **claude-live** in the Claude Code marketplace, or run inside Claude Code:
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
/plugins install marisancans/claude-live
|
|
15
17
|
```
|
|
16
18
|
|
|
17
|
-
|
|
19
|
+
This gives you the `/claude-live:server` slash command to manage the server from within Claude Code.
|
|
18
20
|
|
|
19
|
-
###
|
|
21
|
+
### npm (standalone)
|
|
20
22
|
|
|
21
23
|
```bash
|
|
22
24
|
npm install -g claude-live
|
|
23
25
|
```
|
|
24
26
|
|
|
25
|
-
|
|
27
|
+
## Use
|
|
26
28
|
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
"PreToolUse": [{ "hooks": [{ "type": "command", "command": "node $(npm root -g)/claude-live/bin/hook.js", "async": true }] }],
|
|
31
|
-
"PostToolUse": [{ "hooks": [{ "type": "command", "command": "node $(npm root -g)/claude-live/bin/hook.js", "async": true }] }]
|
|
32
|
-
}
|
|
33
|
-
}
|
|
29
|
+
```bash
|
|
30
|
+
claude-live # Start server (foreground)
|
|
31
|
+
claude-live start # Start server in background
|
|
34
32
|
```
|
|
35
33
|
|
|
36
|
-
|
|
34
|
+
Open http://localhost:43451 in your browser. Sessions appear automatically as you use Claude Code.
|
|
37
35
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
Once installed, use the `/claude-live:server` slash command in Claude Code:
|
|
36
|
+
With the plugin installed, manage the server from inside Claude Code:
|
|
41
37
|
|
|
42
38
|
```
|
|
43
39
|
/claude-live:server # Check status, auto-start if needed
|
|
44
40
|
/claude-live:server stop # Stop the server
|
|
45
41
|
/claude-live:server restart # Restart the server
|
|
46
42
|
/claude-live:server logs # Show last 30 log lines
|
|
47
|
-
/claude-live:server config # Show current endpoint URL
|
|
48
|
-
/claude-live:server config http://192.168.1.50:43451 # Set remote endpoint
|
|
49
|
-
/claude-live:server config reset # Reset to localhost default
|
|
50
43
|
```
|
|
51
44
|
|
|
52
|
-
Then open http://localhost:43451 in your browser.
|
|
53
|
-
|
|
54
45
|
## How It Works
|
|
55
46
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
- **Read / Grep / Glob** -- scanner at the file, data streams back to core
|
|
59
|
-
- **Edit / Write** -- ink beam fires from core to file
|
|
60
|
-
- **Bash** -- terminal window appears at the node
|
|
61
|
-
- **Subagents** -- satellite systems tethered to their parent
|
|
47
|
+
The server watches Claude Code's session transcript files (`~/.claude/projects/`) and tails them in real time. No hooks or additional configuration required.
|
|
62
48
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
Under the hood: the plugin sends every event to a lightweight Node.js server (pure passthrough, no persistence). The server broadcasts events to a PixiJS frontend via Server-Sent Events (SSE).
|
|
49
|
+
Each Claude Code session appears as an orbiting star system. Every tool call creates a node — the more events a session generates, the larger it grows. Multiple sessions show as separate star systems. Prompts pulse outward, context compaction triggers an implosion/rebirth effect.
|
|
66
50
|
|
|
67
51
|
## Server Endpoints
|
|
68
52
|
|
|
69
53
|
| Endpoint | Method | Description |
|
|
70
54
|
|---|---|---|
|
|
71
|
-
| `/hook` | POST | Receive hook events, broadcast to SSE clients |
|
|
55
|
+
| `/hook` | POST | Receive hook events (legacy/plugin), broadcast to SSE clients |
|
|
72
56
|
| `/events` | GET | SSE stream for the frontend |
|
|
73
|
-
| `/health` | GET | Health check — returns `{"ok":true,"clients":<N>,"port":43451}` |
|
|
57
|
+
| `/health` | GET | Health check — returns `{"ok":true,"version":"X.Y.Z","clients":<N>,"port":43451}` |
|
|
74
58
|
|
|
75
59
|
## Troubleshooting
|
|
76
60
|
|
|
77
|
-
| Symptom |
|
|
78
|
-
|
|
79
|
-
| No activity in browser |
|
|
80
|
-
| Server not reachable |
|
|
81
|
-
| `clients: 0` in `/health` |
|
|
82
|
-
| Hook logs location | Debug delivery failures | `~/.config/claude-live/logs/YYYY-MM-DD.jsonl` |
|
|
61
|
+
| Symptom | Fix |
|
|
62
|
+
|---|---|
|
|
63
|
+
| No activity in browser | Make sure Claude Code is running, check `~/.claude/projects/` has `.jsonl` files |
|
|
64
|
+
| Server not reachable | Run `claude-live` to start it |
|
|
65
|
+
| `clients: 0` in `/health` | Open http://localhost:43451 in your browser |
|
|
83
66
|
|
|
84
67
|
## Development
|
|
85
68
|
|
|
@@ -91,6 +74,7 @@ npm install
|
|
|
91
74
|
node server/index.js # Node.js server on :43451
|
|
92
75
|
cd client && npm run dev # Vite hot-reload on :7979
|
|
93
76
|
cd client && npx tsc --noEmit # Type check frontend
|
|
77
|
+
npm run test:server # Run server tests
|
|
94
78
|
```
|
|
95
79
|
|
|
96
80
|
## License
|
package/bin/claude-live
ADDED
|
Binary file
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import{C as W,G as p,a as b,W as z,S as M,P as A,O as S,B as k,b as C,M as F,A as u,d as h,E as j,R,U as L,V,g as E,L as _,h as G,Q as I,k as g,D as f,I as P,r as v,l as o}from"./index-zmiMo1Db.js";class D{constructor(e){this.clock=new W,this.elapsed=0,this.agentGroup=new p,this.currentVisual=null,this.currentVariation=null,this.agentTetherLine=null,this.wanderOffsets=new b(Math.random()*100,Math.random()*100,Math.random()*100),this.pulseTimer=0,this.pulseInterval=2,this._onResize=()=>{const d=this.renderer.domElement.parentElement;if(!d)return;const y=Math.max(1,d.clientWidth),l=Math.max(1,d.clientHeight);this.camera.aspect=y/l,this.camera.updateProjectionMatrix(),this.renderer.setSize(y,l),this.composer.setSize(y,l)},this.renderer=new z({antialias:!0}),this.renderer.setPixelRatio(Math.min(window.devicePixelRatio,2)),this.renderer.setSize(e.clientWidth,e.clientHeight),this.renderer.setClearColor(197384),e.appendChild(this.renderer.domElement),this.scene=new M;const t=Math.max(1,e.clientWidth),r=Math.max(1,e.clientHeight);this.camera=new A(55,t/r,1,2e3),this.camera.position.set(0,30,110),this.controls=new S(this.camera,this.renderer.domElement),this.controls.enableDamping=!0,this.controls.dampingFactor=.06,this.controls.autoRotate=!0,this.controls.autoRotateSpeed=.5,this.controls.target.set(0,15,0),this.controls.minDistance=20,this.controls.maxDistance=300,this.background=new k,this.scene.add(this.background.group);const n=new C(3,16,16),a=new F({color:4491519,transparent:!0,opacity:.5,blending:u}),i=new h(n,a);this.scene.add(i),this.scene.add(this.agentGroup),this.composer=new j(this.renderer),this.composer.addPass(new R(this.scene,this.camera));const c=new L(new V(e.clientWidth,e.clientHeight),1.2,.4,.15);this.composer.addPass(c),this.scene.updateMatrixWorld(!0),this.resizeObserver=new ResizeObserver(this._onResize),this.resizeObserver.observe(e),window.addEventListener("resize",this._onResize),this._onResize()}setVariation(e){if(this.currentVariation=e,this._clearVisual(),this.currentVisual=e.build(this.agentGroup),!this.agentTetherLine){const t=new E().setFromPoints(new Array(21).fill(new b)),r=new _({color:4500223,transparent:!0,opacity:.2,blending:u});this.agentTetherLine=new G(t,r),this.scene.add(this.agentTetherLine)}this.pulseTimer=0}triggerPulse(){var e,t;(t=(e=this.currentVisual)==null?void 0:e.pulse)==null||t.call(e)}_clearVisual(){this.currentVisual&&(this.currentVisual.dispose(),this.currentVisual=null)}tick(){const e=Math.min(this.clock.getDelta(),.05);if(this.elapsed+=e,this.controls.update(),this.background.tick(e),this.currentVisual){this.currentVisual.tick(e,this.elapsed);const t=.25;this.wanderOffsets.x+=e*t*.8,this.wanderOffsets.y+=e*t*1.1,this.wanderOffsets.z+=e*t*.9;const r=50;if(this.agentGroup.position.set(Math.sin(this.wanderOffsets.x)*r,25+Math.sin(this.wanderOffsets.y)*15,Math.cos(this.wanderOffsets.z)*r*Math.cos(this.wanderOffsets.x*.5)),this.agentTetherLine){const n=new b(0,0,0),a=this.agentGroup.position.clone(),i=n.clone().lerp(a,.5);i.y-=10+Math.sin(this.elapsed*2)*4;const c=new I(n,i,a);this.agentTetherLine.geometry.setFromPoints(c.getPoints(20))}this.pulseTimer+=e,this.pulseTimer>=this.pulseInterval&&(this.pulseTimer=0,this.pulseInterval=1.5+Math.random()*3)}try{this.composer.render()}catch{}}destroy(){this.resizeObserver.disconnect(),window.removeEventListener("resize",this._onResize),this.renderer.dispose(),this.renderer.domElement.remove(),this._clearVisual(),this.agentTetherLine&&(this.scene.remove(this.agentTetherLine),this.agentTetherLine.geometry.dispose(),this.agentTetherLine.material.dispose())}}const w=new P(3.5,128),T=new P(3.5,32).toNonIndexed();function O(s){const e=new p;s.add(e);const t=new g({uniforms:{uTime:{value:0},uActivity:{value:0}},vertexShader:`
|
|
2
|
+
uniform float uTime; uniform float uActivity;
|
|
3
|
+
varying vec3 vWorldPos;
|
|
4
|
+
|
|
5
|
+
float getWarp(vec3 p) {
|
|
6
|
+
// Classic smooth, large rolling waves
|
|
7
|
+
return sin(p.x*2.0 - uTime) * sin(p.y*3.0 - uTime*0.8) * cos(p.z*2.0 + uTime) * 1.5;
|
|
8
|
+
}
|
|
9
|
+
void main() {
|
|
10
|
+
vec3 pos = position + normal * getWarp(position) * (0.6 + uActivity);
|
|
11
|
+
vec4 wPos = modelMatrix * vec4(pos, 1.0);
|
|
12
|
+
vWorldPos = wPos.xyz;
|
|
13
|
+
gl_Position = projectionMatrix * viewMatrix * wPos;
|
|
14
|
+
}
|
|
15
|
+
`,fragmentShader:`
|
|
16
|
+
uniform float uActivity;
|
|
17
|
+
varying vec3 vWorldPos;
|
|
18
|
+
void main() {
|
|
19
|
+
vec3 n = normalize(cross(dFdx(vWorldPos), dFdy(vWorldPos)));
|
|
20
|
+
vec3 v = normalize(cameraPosition - vWorldPos);
|
|
21
|
+
float fresnel = 1.0 - max(dot(v, n), 0.0);
|
|
22
|
+
|
|
23
|
+
vec3 base = mix(vec3(0.01, 0.02, 0.05), vec3(0.05, 0.01, 0.05), fract(vWorldPos.y * 0.15));
|
|
24
|
+
vec3 col = base + pow(fresnel, 4.0) * vec3(0.1, 0.4, 0.8) * (1.0 + uActivity);
|
|
25
|
+
|
|
26
|
+
gl_FragColor = vec4(col, min(1.0, 0.3 + pow(fresnel, 4.0) * 0.5));
|
|
27
|
+
}
|
|
28
|
+
`,transparent:!0,depthWrite:!1,blending:u,side:f});e.add(new h(w,t));let r=0;return{tick(n,a){r=Math.max(0,r-n*2),t.uniforms.uTime.value=a,t.uniforms.uActivity.value=r},pulse(){r=1},dispose(){s.remove(e),t.dispose()}}}function B(s){const e=new p;s.add(e);const t=new g({uniforms:{uTime:{value:0},uActivity:{value:0}},vertexShader:`
|
|
29
|
+
uniform float uTime; uniform float uActivity;
|
|
30
|
+
varying vec3 vWorldPos;
|
|
31
|
+
|
|
32
|
+
float getWarp(vec3 p) {
|
|
33
|
+
// Absolute sine waves create sharp folds and spikes instead of smooth curves
|
|
34
|
+
float n1 = 1.0 - abs(sin(p.x * 3.0 + uTime));
|
|
35
|
+
float n2 = 1.0 - abs(cos(p.y * 4.0 - uTime * 1.5));
|
|
36
|
+
float n3 = 1.0 - abs(sin(p.z * 5.0 + uTime * 0.5));
|
|
37
|
+
return pow(n1 * n2 * n3, 2.0) * 3.0; // Pushed out aggressively
|
|
38
|
+
}
|
|
39
|
+
void main() {
|
|
40
|
+
vec3 pos = position + normal * getWarp(position) * (0.8 + uActivity);
|
|
41
|
+
vec4 wPos = modelMatrix * vec4(pos, 1.0);
|
|
42
|
+
vWorldPos = wPos.xyz;
|
|
43
|
+
gl_Position = projectionMatrix * viewMatrix * wPos;
|
|
44
|
+
}
|
|
45
|
+
`,fragmentShader:`
|
|
46
|
+
uniform float uActivity;
|
|
47
|
+
varying vec3 vWorldPos;
|
|
48
|
+
void main() {
|
|
49
|
+
// Flat shading calculation (inherent to dFdx/dFdy on non-indexed geometry)
|
|
50
|
+
vec3 n = normalize(cross(dFdx(vWorldPos), dFdy(vWorldPos)));
|
|
51
|
+
vec3 v = normalize(cameraPosition - vWorldPos);
|
|
52
|
+
float fresnel = 1.0 - max(dot(v, n), 0.0);
|
|
53
|
+
|
|
54
|
+
vec3 col = vec3(0.01, 0.05, 0.05); // Deep green/cyan base
|
|
55
|
+
col += pow(fresnel, 2.0) * vec3(0.1, 0.8, 0.4) * (1.0 + uActivity); // Harsher glow on flat edges
|
|
56
|
+
|
|
57
|
+
gl_FragColor = vec4(col, min(1.0, 0.4 + pow(fresnel, 2.0) * 0.6));
|
|
58
|
+
}
|
|
59
|
+
`,transparent:!0,depthWrite:!1,blending:u,side:f});e.add(new h(T,t));let r=0;return{tick(n,a){r=Math.max(0,r-n*2),t.uniforms.uTime.value=a,t.uniforms.uActivity.value=r},pulse(){r=1},dispose(){s.remove(e),t.dispose()}}}function $(s){const e=new p;s.add(e);const t=new g({uniforms:{uTime:{value:0},uActivity:{value:0}},vertexShader:`
|
|
60
|
+
uniform float uTime; uniform float uActivity;
|
|
61
|
+
varying vec3 vWorldPos;
|
|
62
|
+
|
|
63
|
+
float getWarp(vec3 p) {
|
|
64
|
+
// Ripple strictly outward from the center poles based on Y
|
|
65
|
+
float radius = length(p.xz);
|
|
66
|
+
// Add a vertical sweeping element so it looks like a drop hitting water
|
|
67
|
+
return sin(radius * 15.0 - uTime * 6.0) * cos(p.y * 3.0 + uTime) * 0.5;
|
|
68
|
+
}
|
|
69
|
+
void main() {
|
|
70
|
+
// Displace the sphere entirely radially
|
|
71
|
+
vec3 pos = position + normal * getWarp(position) * (1.0 + uActivity * 2.0);
|
|
72
|
+
vec4 wPos = modelMatrix * vec4(pos, 1.0);
|
|
73
|
+
vWorldPos = wPos.xyz;
|
|
74
|
+
gl_Position = projectionMatrix * viewMatrix * wPos;
|
|
75
|
+
}
|
|
76
|
+
`,fragmentShader:`
|
|
77
|
+
uniform float uActivity;
|
|
78
|
+
varying vec3 vWorldPos;
|
|
79
|
+
void main() {
|
|
80
|
+
vec3 n = normalize(cross(dFdx(vWorldPos), dFdy(vWorldPos)));
|
|
81
|
+
vec3 v = normalize(cameraPosition - vWorldPos);
|
|
82
|
+
float fresnel = 1.0 - max(dot(v, n), 0.0);
|
|
83
|
+
|
|
84
|
+
vec3 col = vec3(0.01, 0.01, 0.08); // Indigo
|
|
85
|
+
col += pow(fresnel, 5.0) * vec3(0.5, 0.1, 1.0) * (1.0 + uActivity);
|
|
86
|
+
|
|
87
|
+
gl_FragColor = vec4(col, min(1.0, 0.2 + pow(fresnel, 5.0) * 0.8));
|
|
88
|
+
}
|
|
89
|
+
`,transparent:!0,depthWrite:!1,blending:u,side:f});e.add(new h(w,t));let r=0;return{tick(n,a){r=Math.max(0,r-n*2),t.uniforms.uTime.value=a,t.uniforms.uActivity.value=r},pulse(){r=1},dispose(){s.remove(e),t.dispose()}}}function H(s){const e=new p;s.add(e);const t=new g({uniforms:{uTime:{value:0},uActivity:{value:0}},vertexShader:`
|
|
90
|
+
uniform float uTime; uniform float uActivity;
|
|
91
|
+
varying vec3 vWorldPos;
|
|
92
|
+
|
|
93
|
+
float getWarp(vec3 p) {
|
|
94
|
+
// Floor the position to calculate the wave, tearing the geometry into blocks
|
|
95
|
+
vec3 stepP = floor(p * 3.0) / 3.0; // Quantize the space
|
|
96
|
+
float n = sin(stepP.x*5.0 - uTime) * cos(stepP.y*5.0) * sin(stepP.z*5.0 + uTime);
|
|
97
|
+
return n * 1.5;
|
|
98
|
+
}
|
|
99
|
+
void main() {
|
|
100
|
+
vec3 pos = position + normal * getWarp(position) * (0.8 + uActivity * 2.0);
|
|
101
|
+
vec4 wPos = modelMatrix * vec4(pos, 1.0);
|
|
102
|
+
vWorldPos = wPos.xyz;
|
|
103
|
+
gl_Position = projectionMatrix * viewMatrix * wPos;
|
|
104
|
+
}
|
|
105
|
+
`,fragmentShader:`
|
|
106
|
+
uniform float uActivity;
|
|
107
|
+
varying vec3 vWorldPos;
|
|
108
|
+
void main() {
|
|
109
|
+
vec3 n = normalize(cross(dFdx(vWorldPos), dFdy(vWorldPos)));
|
|
110
|
+
vec3 v = normalize(cameraPosition - vWorldPos);
|
|
111
|
+
float fresnel = 1.0 - max(dot(v, n), 0.0);
|
|
112
|
+
|
|
113
|
+
vec3 col = vec3(0.05, 0.01, 0.01); // Deep crimson base
|
|
114
|
+
col += pow(fresnel, 2.0) * vec3(1.0, 0.2, 0.2) * (1.0 + uActivity);
|
|
115
|
+
|
|
116
|
+
gl_FragColor = vec4(col, min(1.0, 0.5 + pow(fresnel, 2.0) * 0.5));
|
|
117
|
+
}
|
|
118
|
+
`,transparent:!0,depthWrite:!1,blending:u,side:f}),r=new h(T,t);e.add(r);let n=0;return{tick(a,i){n=Math.max(0,n-a*2),t.uniforms.uTime.value=i,t.uniforms.uActivity.value=n},pulse(){n=1},dispose(){s.remove(e),t.dispose()}}}function q(s){const e=new p;s.add(e);const t=new g({uniforms:{uTime:{value:0},uActivity:{value:0}},vertexShader:`
|
|
119
|
+
uniform float uTime; uniform float uActivity;
|
|
120
|
+
varying vec3 vWorldPos;
|
|
121
|
+
|
|
122
|
+
float getWarp(vec3 p) {
|
|
123
|
+
// Obscenely high frequency sine waves create mathematical noise, vibrating the mesh
|
|
124
|
+
float n = sin(p.x * 40.0 + uTime * 10.0) * sin(p.y * 40.0 - uTime * 5.0) * sin(p.z * 40.0 + uTime * 8.0);
|
|
125
|
+
return n * 0.25; // Keep amplitude low so it looks like fuzz, not explosions
|
|
126
|
+
}
|
|
127
|
+
void main() {
|
|
128
|
+
vec3 pos = position + normal * getWarp(position) * (1.0 + uActivity * 3.0);
|
|
129
|
+
vec4 wPos = modelMatrix * vec4(pos, 1.0);
|
|
130
|
+
vWorldPos = wPos.xyz;
|
|
131
|
+
gl_Position = projectionMatrix * viewMatrix * wPos;
|
|
132
|
+
}
|
|
133
|
+
`,fragmentShader:`
|
|
134
|
+
uniform float uActivity;
|
|
135
|
+
varying vec3 vWorldPos;
|
|
136
|
+
void main() {
|
|
137
|
+
vec3 n = normalize(cross(dFdx(vWorldPos), dFdy(vWorldPos)));
|
|
138
|
+
vec3 v = normalize(cameraPosition - vWorldPos);
|
|
139
|
+
float fresnel = 1.0 - max(dot(v, n), 0.0);
|
|
140
|
+
|
|
141
|
+
vec3 col = vec3(0.01, 0.01, 0.01); // Basically black hole
|
|
142
|
+
// The high frequency normals make the fresnel scatter like crazy!
|
|
143
|
+
col += pow(fresnel, 3.0) * vec3(0.8, 0.8, 1.0) * (1.0 + uActivity);
|
|
144
|
+
|
|
145
|
+
gl_FragColor = vec4(col, min(1.0, 0.6 + pow(fresnel, 3.0) * 0.4));
|
|
146
|
+
}
|
|
147
|
+
`,transparent:!0,depthWrite:!1,blending:u,side:f});e.add(new h(w,t));let r=0;return{tick(n,a){r=Math.max(0,r-n*2),t.uniforms.uTime.value=a,t.uniforms.uActivity.value=r},pulse(){r=1},dispose(){s.remove(e),t.dispose()}}}const x=[{name:"Smooth Void",description:"Deep dark rolling liquid displacement (The tuned baseline model).",build:O},{name:"Jagged Crystal",description:"Changes displacement to absolute mathematics and uses flat-shading to create sharp, tearing crystal spikes.",build:B},{name:"Concentric Droplet",description:"Symmetrical ripples flow outward radially from the center like a drop of liquid suspended in time.",build:$},{name:"Voxel Glitch Glass",description:"Forces the displacement math to snap to blocks (quantization), tearing the glass into digital cubes.",build:H},{name:"Micro-Fuzz",description:"Uses an obscenely high frequency wave to vibrate the vertices microscopically, causing intense light scattering.",build:q}];function U(){const s=v.useRef(null),e=v.useRef(null),t=v.useRef(0),[r,n]=v.useState(0);v.useEffect(()=>{if(!s.current)return;const i=new D(s.current);e.current=i,i.setVariation(x[0]);function c(){i.tick(),t.current=requestAnimationFrame(c)}return t.current=requestAnimationFrame(c),()=>{cancelAnimationFrame(t.current),i.destroy(),e.current=null}},[]);function a(i){var c;n(i),(c=e.current)==null||c.setVariation(x[i])}return o.jsxs("div",{style:{width:"100vw",height:"100vh",background:"#030308",position:"relative",overflow:"hidden"},children:[o.jsx("div",{ref:s,style:{position:"absolute",top:0,left:0,right:0,bottom:0}}),o.jsxs("div",{style:{position:"absolute",top:0,right:0,width:320,height:"100%",background:"rgba(3,3,14,0.92)",borderLeft:"1px solid rgba(255,255,255,0.06)",display:"flex",flexDirection:"column",fontFamily:"'Inter', 'SF Pro Display', system-ui, sans-serif",color:"#aaa",overflowY:"auto"},children:[o.jsxs("div",{style:{padding:"20px 20px 16px",borderBottom:"1px solid rgba(255,255,255,0.06)",background:"linear-gradient(180deg, rgba(100,120,255,0.06) 0%, transparent 100%)"},children:[o.jsx("div",{style:{fontSize:10,letterSpacing:"0.18em",color:"#555",marginBottom:6,textTransform:"uppercase"},children:"SUBAGENT VISUALIZATIONS"}),o.jsx("div",{style:{fontSize:16,color:"#e8ecf4",fontWeight:600,letterSpacing:"-0.01em"},children:"Agent Node Concepts"}),o.jsx("div",{style:{fontSize:11,color:"#556",marginTop:4,lineHeight:1.5},children:"Each concept is a completely different visual direction for representing a subagent in the Three.js scene."})]}),o.jsx("div",{style:{padding:12,display:"flex",flexDirection:"column",gap:8,flex:1},children:x.map((i,c)=>{const d=r===c,l=["#66aaff","#aa66ff","#8833cc","#4488ff","#44ddff"][c];return o.jsxs("button",{onClick:()=>a(c),style:{textAlign:"left",padding:"14px 16px",borderRadius:8,border:`1px solid ${d?l:"rgba(255,255,255,0.06)"}`,background:d?`linear-gradient(135deg, ${l}15 0%, ${l}08 100%)`:"rgba(255,255,255,0.02)",cursor:"pointer",color:"inherit",transition:"all 0.2s ease",position:"relative",overflow:"hidden"},onMouseEnter:m=>{d||(m.currentTarget.style.borderColor=`${l}66`,m.currentTarget.style.background=`${l}08`)},onMouseLeave:m=>{d||(m.currentTarget.style.borderColor="rgba(255,255,255,0.06)",m.currentTarget.style.background="rgba(255,255,255,0.02)")},children:[d&&o.jsx("div",{style:{position:"absolute",left:0,top:0,bottom:0,width:3,background:`linear-gradient(180deg, ${l}, ${l}44)`,borderRadius:"0 2px 2px 0"}}),o.jsxs("div",{style:{display:"flex",alignItems:"center",gap:10,marginBottom:6},children:[o.jsx("div",{style:{width:28,height:28,borderRadius:6,background:d?`linear-gradient(135deg, ${l}44, ${l}22)`:"rgba(255,255,255,0.04)",display:"flex",alignItems:"center",justifyContent:"center",fontSize:13,fontWeight:700,color:d?l:"#555",border:`1px solid ${d?`${l}33`:"rgba(255,255,255,0.06)"}`,flexShrink:0},children:c+1}),o.jsx("span",{style:{fontSize:13,fontWeight:600,letterSpacing:"-0.01em",color:d?"#eef2ff":"#bbb"},children:i.name})]}),o.jsx("div",{style:{fontSize:11,color:d?"#8899bb":"#556",lineHeight:1.6,paddingLeft:38},children:i.description})]},i.name)})}),o.jsx("div",{style:{padding:"12px 16px",borderTop:"1px solid rgba(255,255,255,0.06)"},children:o.jsx("button",{onClick:()=>{var i;return(i=e.current)==null?void 0:i.triggerPulse()},style:{width:"100%",padding:"10px 0",background:"linear-gradient(135deg, rgba(100,120,255,0.15), rgba(100,120,255,0.08))",border:"1px solid rgba(100,120,255,0.2)",borderRadius:6,cursor:"pointer",color:"#8899cc",fontSize:12,fontWeight:600,letterSpacing:"0.05em",transition:"all 0.2s ease"},onMouseEnter:i=>{i.currentTarget.style.background="linear-gradient(135deg, rgba(100,120,255,0.25), rgba(100,120,255,0.15))",i.currentTarget.style.borderColor="rgba(100,120,255,0.4)"},onMouseLeave:i=>{i.currentTarget.style.background="linear-gradient(135deg, rgba(100,120,255,0.15), rgba(100,120,255,0.08))",i.currentTarget.style.borderColor="rgba(100,120,255,0.2)"},children:"⚡ TRIGGER PULSE"})}),o.jsxs("div",{style:{padding:"10px 16px",borderTop:"1px solid rgba(255,255,255,0.04)",fontSize:10,color:"#334",display:"flex",justifyContent:"space-between"},children:[o.jsx("span",{children:"drag to orbit · scroll to zoom"}),o.jsx("span",{children:"auto-pulse active"})]})]}),o.jsx("a",{href:"#/three",style:{position:"absolute",top:16,left:16,fontSize:11,color:"#556",textDecoration:"none",fontFamily:"'Inter', system-ui, sans-serif",letterSpacing:"0.05em",padding:"6px 12px",background:"rgba(255,255,255,0.03)",border:"1px solid rgba(255,255,255,0.06)",borderRadius:5,transition:"all 0.2s ease"},onMouseEnter:i=>{i.currentTarget.style.borderColor="rgba(255,255,255,0.15)",i.currentTarget.style.color="#aab"},onMouseLeave:i=>{i.currentTarget.style.borderColor="rgba(255,255,255,0.06)",i.currentTarget.style.color="#556"},children:"← back"})]})}export{U as AgentDemoScene};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{C as U,G as O,c as x,W as $,a6 as _,aj as Y,S as X,P as Z,O as J,B as K,a9 as Q,ab as B,d as N,I as W,ak as ee,al as q,M as T,ac as te,E as se,R as ne,U as ie,V as oe,a as p,am as re,A as j,an as ae,ao as ce,Y as G,X as E,v as le,$ as he,a5 as de,_ as pe,r as w,l as h}from"./index-zmiMo1Db.js";class ue{constructor(e){this.clock=new U,this.elapsed=0,this.visualGroup=new O,this.currentVisual=null,this.pulseTimer=0,this.pulseInterval=2.6,this.coreActivity=0,this.accent=new x("#7ec8ff"),this.coreGroup=new O,this.onResize=()=>{const a=this.renderer.domElement.parentElement;if(!a)return;const l=Math.max(1,a.clientWidth),c=Math.max(1,a.clientHeight);this.camera.aspect=l/c,this.camera.updateProjectionMatrix(),this.renderer.setSize(l,c),this.composer.setSize(l,c)},this.renderer=new $({antialias:!0}),this.renderer.setPixelRatio(Math.min(window.devicePixelRatio,2)),this.renderer.setSize(e.clientWidth,e.clientHeight),this.renderer.setClearColor(263435),this.renderer.outputColorSpace=_,this.renderer.toneMapping=Y,this.renderer.toneMappingExposure=1.08,e.appendChild(this.renderer.domElement),this.scene=new X;const t=Math.max(1,e.clientWidth),s=Math.max(1,e.clientHeight);this.camera=new Z(44,t/s,1,3e3),this.camera.position.set(0,60,164),this.controls=new J(this.camera,this.renderer.domElement),this.controls.enableDamping=!0,this.controls.dampingFactor=.06,this.controls.autoRotate=!0,this.controls.autoRotateSpeed=.18,this.controls.target.set(0,18,0),this.controls.minDistance=58,this.controls.maxDistance=320,this.background=new K,this.scene.add(this.background.group),this.scene.add(new Q(13424639,1.2));const n=new B(16777215,.75);n.position.set(90,120,100),this.scene.add(n);const i=new B(8959999,.42);i.position.set(-100,40,-80),this.scene.add(i),this.coreShell=new N(new W(6.4,1),new ee({color:new x("#0b1120"),emissive:this.accent.clone().multiplyScalar(.28),emissiveIntensity:1,specular:new x("#ffffff"),shininess:90,transparent:!0,opacity:.94})),this.coreRing=new N(new q(11.5,.18,12,80),new T({color:this.accent,transparent:!0,opacity:.24})),this.coreRing.rotation.x=Math.PI*.5,this.coreOuterRing=new N(new q(16.5,.12,12,96),new T({color:this.accent.clone().lerp(new x("#ffffff"),.2),transparent:!0,opacity:.12})),this.coreOuterRing.rotation.set(Math.PI*.5,.24,0),this.coreLight=new te(this.accent.getHex(),18,260,2),this.coreGroup.add(this.coreShell,this.coreRing,this.coreOuterRing,this.coreLight),this.coreGroup.position.set(0,12,0),this.scene.add(this.coreGroup),this.scene.add(this.visualGroup),this.composer=new se(this.renderer),this.composer.addPass(new ne(this.scene,this.camera)),this.composer.addPass(new ie(new oe(t,s),.48,.24,.4)),this.resizeObserver=new ResizeObserver(this.onResize),this.resizeObserver.observe(e),window.addEventListener("resize",this.onResize),this.onResize()}setVariation(e){this.clearVisual(),this.applyAccent(e.accent),this.currentVisual=e.build(this.visualGroup,this.camera),this.triggerPulse()}triggerPulse(){var e;this.coreActivity=1,(e=this.currentVisual)==null||e.pulse()}tick(){var t;const e=Math.min(this.clock.getDelta(),.05);this.elapsed+=e,this.pulseTimer+=e,this.coreActivity=Math.max(0,this.coreActivity-e*.62),this.pulseTimer>=this.pulseInterval&&(this.pulseTimer=0,this.pulseInterval=2.3+Math.random()*1.5,this.triggerPulse()),this.controls.update(),this.background.tick(e),(t=this.currentVisual)==null||t.tick(e,this.elapsed),this.tickCore();try{this.composer.render()}catch{}}destroy(){this.resizeObserver.disconnect(),window.removeEventListener("resize",this.onResize),this.clearVisual(),this.background.dispose(),this.controls.dispose(),this.renderer.dispose(),this.renderer.domElement.remove(),this.coreShell.geometry.dispose(),this.coreShell.material.dispose(),this.coreRing.geometry.dispose(),this.coreRing.material.dispose(),this.coreOuterRing.geometry.dispose(),this.coreOuterRing.material.dispose()}applyAccent(e){this.accent.set(e);const t=this.coreShell.material,s=this.coreRing.material,n=this.coreOuterRing.material;t.emissive.copy(this.accent).multiplyScalar(.28),s.color.copy(this.accent),n.color.copy(this.accent).lerp(new x("#ffffff"),.2),this.coreLight.color.copy(this.accent)}tickCore(){const e=1+Math.sin(this.elapsed*.7)*.03,t=1+this.coreActivity*.18,s=this.coreShell.material,n=this.coreRing.material,i=this.coreOuterRing.material;this.coreShell.rotation.y+=.0024,this.coreShell.rotation.x=Math.sin(this.elapsed*.18)*.08,this.coreShell.scale.setScalar(e*t),this.coreRing.rotation.z+=.003+this.coreActivity*.01,this.coreRing.scale.setScalar(1+this.coreActivity*.1),this.coreOuterRing.rotation.y-=.0022,this.coreOuterRing.rotation.z=Math.sin(this.elapsed*.42)*.18,this.coreOuterRing.scale.setScalar(1+this.coreActivity*.16),s.emissiveIntensity=.96+this.coreActivity*.36,n.opacity=.18+this.coreActivity*.14,i.opacity=.08+this.coreActivity*.1,this.coreLight.intensity=14+this.coreActivity*12+Math.sin(this.elapsed*.55)*2}clearVisual(){this.currentVisual&&(this.currentVisual.dispose(),this.currentVisual=null)}}const d=new p(0,12,0),ge=new p(0,1,0),P=new x("#ffffff"),me=new x("#121a2d"),b=new he,f=new p,L=new p,I=new p,M=new x;function fe(o){return o-Math.floor(o)}function g(o){return fe(Math.sin(o*127.1+311.7)*43758.5453123)}function y(o){return g(o)*2-1}function H(o,e){const t=Math.atan2(Math.sin(o-e),Math.cos(o-e));return Math.abs(t)}function D(o,e,t=0,s=Math.PI*2){const n=[],i=o>1?s/(o-1):0,a=t-s*.5;for(let l=0;l<o;l++){const c=s>=Math.PI*2?t+l/o*Math.PI*2:a+i*l;n.push(new p(Math.cos(c),e,Math.sin(c)).normalize())}return n}function A(o,e,t,s=1){const n=o.clone().sub(d);return n.lengthSq()<1e-4?n.set(0,1,0):n.normalize(),{home:o.clone(),position:o.clone(),normal:n,state:"dormant",energy:0,carrierNode:null,meta:e,phase:g(t*3+1)*Math.PI*2,driftAmplitude:s*(.45+g(t*3+2)*.55),driftFrequency:.6+g(t*3+3)*.8}}function S(o,e,t){const s=[];for(let n=0;n<o.length;n++){const i=o[n];i.state==="dormant"&&s.push({index:n,score:t(i)})}return s.sort((n,i)=>n.score-i.score),s.slice(0,e).map(n=>n.index)}function v(o,e){return S(o,e,t=>t.home.distanceToSquared(d))}function ye(){const o=[];for(let e=0;e<84;e++){const t=g(e*13+1)*Math.PI*2,s=16+g(e*13+2)*18,n=.7+g(e*13+3)*.35,i=Math.cos(t)*s*n,a=6+Math.pow(g(e*13+4),.72)*22,l=Math.sin(t)*s*n;o.push(A(new p(d.x+i,d.y+a,d.z+l),{angle:t},e,1))}return o}function be(){const o=[];for(let e=0;e<76;e++){const t=-1+e/75*2+y(e*17+1)*.04,s=14+g(e*17+2)*26,n=t*38,i=6+(1-Math.abs(t)*.7)*14+y(e*17+3)*5,a=y(e*17+4)*(4+s*.12);o.push(A(new p(d.x+n,d.y+i,d.z+a),{sweep:t},e+100,.85))}return o}function xe(){const o=[];for(let e=0;e<82;e++){const t=e%2,s=t===0?-26:26,n=t===0?-7:7,i=s+y(e*19+1)*14,a=7+g(e*19+2)*20,l=n+y(e*19+3)*12;o.push(A(new p(d.x+i,d.y+a,d.z+l),{lobe:t},e+200,.95))}return o}function we(){const o=[];for(let e=0;e<88;e++){const t=e/88*Math.PI*2+y(e*23+1)*.08,s=28+y(e*23+2)*4.8,n=Math.cos(t)*s,i=10+Math.sin(t*2.2)*4+y(e*23+3)*2.4,a=Math.sin(t)*s;o.push(A(new p(d.x+n,d.y+i,d.z+a),{angle:t},e+300,.9))}return o}function Me(){const o=[];for(let t=0;t<80;t++){const s=t%4,n=g(t*29+1)*Math.PI*2,i=8+s*3.8+g(t*29+2)*6,a=Math.cos(n)*i,l=6+s*8.5+y(t*29+3)*2.4,c=Math.sin(n)*i*.82;o.push(A(new p(d.x+a,d.y+l,d.z+c),{angle:n,layer:s},t+400,1.05))}return o}function Se(o,e){const t=g(e*31+1)*Math.PI*2,s=18+g(e*31+2)*10,n=10+g(e*31+3)*18;I.set(d.x+Math.cos(t)*s,d.y+n,d.z+Math.sin(t)*s);const i=S(o,12,a=>a.home.distanceToSquared(I));return i.length?i:v(o,12)}function ve(o,e){const t=-1+e%7/6*2,s=S(o,11,n=>Math.abs((n.meta.sweep??0)-t)*100+Math.abs(n.home.y-(d.y+16)));return s.length?s:v(o,11)}function Pe(o,e){const t=e%2;I.set(d.x+(t===0?-28:28)+y(e*37+1)*6,d.y+10+g(e*37+2)*18,d.z+(t===0?-7:7)+y(e*37+3)*4);const s=S(o,12,n=>((n.meta.lobe??-1)===t?0:1e4)+n.home.distanceToSquared(I));return s.length?s:v(o,12)}function Re(o,e){const t=e*.72,s=S(o,14,n=>H(n.meta.angle??0,t)*180);return s.length?s:v(o,14)}function Ae(o,e){const t=e%4,s=g(e*41+1)*Math.PI*2,n=S(o,10,i=>{const a=(i.meta.layer??-1)===t?0:1e4,l=H(i.meta.angle??0,s)*90;return a+l});return n.length?n:v(o,10)}class ke{constructor(e,t){this.blueprint=t,this.group=new O,this.branchGeometry=new re(1,1,1,6,1,!0),this.branchMaterial=new T({transparent:!0,opacity:.88,depthWrite:!1,blending:j}),this.nodeGeometry=new W(1,1),this.nodeMaterial=new T({transparent:!0,opacity:.96,depthWrite:!1,blending:j}),this.nodes=[],this.segments=[],this.segmentIndexByNode=[],this.pulses=[],this.pulseIndex=0,this.activity=0,this.pendingSteps=0,this.stepAccumulator=0,this.completionDelay=0,this.pulse=()=>{(!this.hasDormantAttractors()&&!this.hasArmedAttractors()||this.segments.length>=this.blueprint.maxSegments-this.blueprint.maxNewPerStep)&&this.reset();const a=this.blueprint.selectTargets(this.attractors,this.pulseIndex).filter(c=>{var r;return((r=this.attractors[c])==null?void 0:r.state)==="dormant"}),l=a.length?a:v(this.attractors,8);for(const c of l){const r=this.attractors[c];r.state==="dormant"&&(r.state="armed",r.energy=1.2)}this.pendingSteps=Math.min(this.pendingSteps+this.blueprint.stepsPerPulse,this.blueprint.stepsPerPulse*4),this.activity=1,this.completionDelay=0,this.pulseIndex+=1,this.spawnPulseBursts(Math.min(3,1+Math.floor(l.length/4)))},this.tick=(a,l)=>{this.activity=Math.max(0,this.activity-a*.46),this.updateAttractors(l,a),this.advanceGrowth(a),this.updatePulses(a,l),this.updateBranchInstances(),this.updateNodeInstances(l),!this.hasDormantAttractors()&&!this.hasArmedAttractors()?(this.completionDelay+=a,this.completionDelay>2.6&&(this.reset(),this.pulse())):this.completionDelay=0},this.dispose=()=>{this.clearPulses(),this.group.removeFromParent(),this.branchGeometry.dispose(),this.branchMaterial.dispose(),this.nodeGeometry.dispose(),this.nodeMaterial.dispose(),this.glowTexture.dispose()},this.accentColor=new x(t.accent),this.branchBaseColor=this.accentColor.clone().lerp(P,.14),this.dormantColor=this.accentColor.clone().lerp(me,.78);const[s,n,i]=ae(t.accent);this.glowTexture=ce(s,n,i,96),this.branchMesh=new G(this.branchGeometry,this.branchMaterial,t.maxSegments),this.branchMesh.instanceMatrix.setUsage(E),this.branchMesh.frustumCulled=!1,this.branchMesh.count=0,this.attractors=t.createAttractors(),this.nodeMesh=new G(this.nodeGeometry,this.nodeMaterial,this.attractors.length),this.nodeMesh.instanceMatrix.setUsage(E),this.nodeMesh.frustumCulled=!1,this.group.add(this.branchMesh,this.nodeMesh),e.add(this.group),this.reset()}reset(){this.clearPulses(),this.nodes=[],this.segments=[],this.segmentIndexByNode=[],this.activity=0,this.pendingSteps=0,this.stepAccumulator=0,this.completionDelay=0,this.pulseIndex=0;for(const e of this.attractors)e.position.copy(e.home),e.state="dormant",e.energy=0,e.carrierNode=null;this.nodes.push({position:d.clone(),parent:null,depth:0,radius:this.blueprint.rootRadius}),this.segmentIndexByNode[0]=-1;for(const e of this.blueprint.seedDirections){f.copy(e).normalize();const t=this.blueprint.stepLength*1.05,s=d.clone().addScaledVector(f,t);this.addNode(0,s,1)}this.updateBranchInstances(),this.updateNodeInstances(0)}updateAttractors(e,t){for(const s of this.attractors){s.energy=Math.max(0,s.energy-t*.72);const n=s.state==="captured"?.18:s.state==="armed"?.42:.1,i=Math.sin(e*s.driftFrequency+s.phase)*s.driftAmplitude*this.blueprint.drift*(n+s.energy*.3);s.position.copy(s.home).addScaledVector(s.normal,i)}}advanceGrowth(e){const s=this.hasArmedAttractors()?3.2:0,n=this.pendingSteps>0?18:s;if(!(n<=0))for(this.stepAccumulator+=e*n;this.stepAccumulator>=1;){this.stepAccumulator-=1;const i=this.growOneStep();if(this.pendingSteps>0&&(this.pendingSteps-=1),!i){this.pendingSteps=0,this.stepAccumulator=0;break}}}growOneStep(){const e=this.blueprint.influenceDistance*this.blueprint.influenceDistance,t=this.blueprint.killDistance*this.blueprint.killDistance,s=new Map,n=new Map;for(const c of this.attractors){if(c.state!=="armed")continue;let r=-1,u=e;for(let z=0;z<this.nodes.length;z++){const V=this.nodes[z].position.distanceToSquared(c.position);V<u&&(u=V,r=z)}if(r<0)continue;const m=this.nodes[r];if(f.copy(c.position).sub(m.position),f.lengthSq()<1e-4)continue;f.normalize();let k=s.get(r);k||(k=new p,s.set(r,k)),k.add(f),n.set(r,(n.get(r)??0)+1)}if(!s.size)return!1;const i=[...s.keys()].sort((c,r)=>(n.get(r)??0)-(n.get(c)??0)),a=[];for(const c of i.slice(0,this.blueprint.maxNewPerStep)){if(this.segments.length>=this.blueprint.maxSegments)break;const r=this.nodes[c],u=s.get(c);if(!u||(f.copy(u).add(this.blueprint.bias),f.lengthSq()<1e-4)||(f.normalize(),L.copy(r.position).addScaledVector(f,this.blueprint.stepLength),!this.isPositionAvailable(L)))continue;const m=this.addNode(c,L,r.depth+1);a.push(m)}if(!a.length)return!1;const l=[];for(const c of this.attractors)if(c.state==="armed"){for(const r of a)if(!(this.nodes[r].position.distanceToSquared(c.position)>t)){c.state="captured",c.energy=1.35,c.carrierNode=r,l.push(r);break}}return l.length&&this.spawnPulseTo(l[l.length-1]),!0}isPositionAvailable(e){const t=this.blueprint.stepLength*.58*(this.blueprint.stepLength*.58);for(const s of this.nodes)if(s.position.distanceToSquared(e)<t)return!1;return!0}addNode(e,t,s){const n=this.nodes[e],i=this.nodes.length,a=Math.max(this.blueprint.tipRadius,n.radius*.9);return this.nodes.push({position:t.clone(),parent:e,depth:s,radius:a}),this.segments.push({startNode:e,endNode:i,radius:Math.max(this.blueprint.tipRadius,a*.92),glow:1.18}),this.segmentIndexByNode[i]=this.segments.length-1,i}updatePulses(e,t){for(const s of this.segments)s.glow=Math.max(0,s.glow-e*.82);for(let s=this.pulses.length-1;s>=0;s--){const n=this.pulses[s];if(n.distance+=e*n.speed,n.distance>=n.totalDistance){this.removePulse(s);continue}let i=0;for(;i<n.distances.length-1&&n.distances[i+1]<n.distance;)i+=1;const a=n.distances[i],l=n.distances[i+1],c=le.clamp((n.distance-a)/Math.max(1e-4,l-a),0,1),r=this.nodes[n.path[i]],u=this.nodes[n.path[i+1]];n.sprite.position.lerpVectors(r.position,u.position,c),n.sprite.scale.setScalar(2.2+Math.sin(t*8+i)*.25+this.activity*.4),n.material.opacity=.8+this.activity*.18;const m=this.segmentIndexByNode[n.path[i+1]];m>=0&&(this.segments[m].glow=Math.max(this.segments[m].glow,1.25))}}updateBranchInstances(){this.branchMesh.count=this.segments.length;for(let e=0;e<this.segments.length;e++){const t=this.segments[e],s=this.nodes[t.startNode].position,n=this.nodes[t.endNode].position;f.copy(n).sub(s);const i=f.length();if(i<1e-4)continue;f.normalize(),b.position.copy(s).lerp(n,.5),b.quaternion.setFromUnitVectors(ge,f);const a=t.radius*(1+t.glow*.3);b.scale.set(a,i,a),b.updateMatrix(),this.branchMesh.setMatrixAt(e,b.matrix),M.copy(this.branchBaseColor).lerp(P,.08+Math.min(t.glow,1.4)*.34),this.branchMesh.setColorAt(e,M)}this.branchMesh.instanceMatrix.needsUpdate=!0,this.branchMesh.instanceColor&&(this.branchMesh.instanceColor.needsUpdate=!0)}updateNodeInstances(e){for(let t=0;t<this.attractors.length;t++){const s=this.attractors[t],n=s.state==="captured"?1.12:s.state==="armed"?.96:.72,i=1+s.energy*.4+Math.sin(e*s.driftFrequency+s.phase)*.04,a=this.blueprint.nodeScale*n*i;b.position.copy(s.position),b.quaternion.identity(),b.scale.setScalar(a),b.updateMatrix(),this.nodeMesh.setMatrixAt(t,b.matrix),s.state==="captured"?M.copy(this.accentColor).lerp(P,.32+s.energy*.14):s.state==="armed"?M.copy(this.accentColor).lerp(P,.16+s.energy*.1):M.copy(this.dormantColor).lerp(this.accentColor,.08),this.nodeMesh.setColorAt(t,M)}this.nodeMesh.instanceMatrix.needsUpdate=!0,this.nodeMesh.instanceColor&&(this.nodeMesh.instanceColor.needsUpdate=!0)}spawnPulseBursts(e){const t=this.attractors.filter(s=>s.state==="captured"&&s.carrierNode!==null);if(t.length)for(let s=0;s<e;s++){const n=t[Math.floor(Math.random()*t.length)];n.carrierNode!==null&&this.spawnPulseTo(n.carrierNode)}}spawnPulseTo(e){if(e<=0||this.pulses.length>=8)return;const t=[];let s=e;for(;s!==null;)t.unshift(s),s=this.nodes[s].parent;if(t.length<2)return;const n=[0];let i=0;for(let c=1;c<t.length;c++){const r=this.nodes[t[c-1]].position,u=this.nodes[t[c]].position;i+=r.distanceTo(u),n.push(i)}const a=new de({map:this.glowTexture,color:P,transparent:!0,opacity:.92,depthWrite:!1,blending:j}),l=new pe(a);l.frustumCulled=!1,l.position.copy(this.nodes[t[0]].position),l.scale.setScalar(2.4),this.group.add(l),this.pulses.push({path:t,distances:n,totalDistance:i,distance:0,speed:24+Math.random()*10,sprite:l,material:a})}removePulse(e){const t=this.pulses[e];t&&(t.sprite.removeFromParent(),t.material.dispose(),this.pulses.splice(e,1))}clearPulses(){for(let e=this.pulses.length-1;e>=0;e--)this.removePulse(e)}hasDormantAttractors(){return this.attractors.some(e=>e.state==="dormant")}hasArmedAttractors(){return this.attractors.some(e=>e.state==="armed")}}function R(o){return{name:o.name,accent:o.accent,layout:o.layout,eventModel:o.eventModel,useCase:o.useCase,description:o.description,build(e){return new ke(e,o)}}}const C=[R({name:"Pocket Canopy",accent:"#7ec8ff",layout:"dome cluster",eventModel:"arm a local neighborhood per event",useCase:"compact session burst around a selected cluster",description:"Closest to the live-node use case: each event wakes a nearby pocket of nodes, and the scaffold grows the smallest readable canopy that still feels organic.",influenceDistance:24,killDistance:4.8,stepLength:3.3,stepsPerPulse:12,maxNewPerStep:5,maxSegments:320,rootRadius:1.18,tipRadius:.22,nodeScale:.92,drift:1.05,bias:new p(0,.18,0),seedDirections:D(5,.9,.15),createAttractors:ye,selectTargets:Se}),R({name:"Ribbon Fan",accent:"#67ddff",layout:"flattened 2.5D fan",eventModel:"events paint narrow sweep bands",useCase:"sidebar card, minimap, or inspector-scale activity view",description:"Same SCA core, but flattened into a shallow fan so you get branching legibility without spending much screen depth.",influenceDistance:22,killDistance:4.4,stepLength:3.2,stepsPerPulse:11,maxNewPerStep:4,maxSegments:280,rootRadius:1.08,tipRadius:.2,nodeScale:.84,drift:.82,bias:new p(0,.1,0),seedDirections:D(5,.55,0,Math.PI*1.05),createAttractors:be,selectTargets:ve}),R({name:"Split Relay",accent:"#a9a0ff",layout:"dual semantic lobes",eventModel:"alternate between left and right node groups",useCase:"tool-vs-agent, request-vs-response, or two-channel routing",description:"Useful when your node field already has two semantic camps. Each event pulls the scaffold into one side, so the branching itself explains the grouping.",influenceDistance:25,killDistance:4.7,stepLength:3.4,stepsPerPulse:12,maxNewPerStep:5,maxSegments:320,rootRadius:1.14,tipRadius:.22,nodeScale:.88,drift:.95,bias:new p(0,.14,0),seedDirections:D(6,.5,Math.PI*.2),createAttractors:xe,selectTargets:Pe}),R({name:"Halo Wreath",accent:"#7cf3e2",layout:"orbital ring",eventModel:"wake a moving arc around a focus target",useCase:"selection halo, focus ring, or surround-state animation",description:"A good fit when the animation should stay compact around one node or cluster. Events wake only one arc, so the ring reads like intent instead of noise.",influenceDistance:27,killDistance:4.5,stepLength:3.25,stepsPerPulse:13,maxNewPerStep:5,maxSegments:340,rootRadius:1.12,tipRadius:.2,nodeScale:.86,drift:.9,bias:new p(0,.04,0),seedDirections:D(7,.22),createAttractors:we,selectTargets:Re}),R({name:"Signal Stack",accent:"#ffb48e",layout:"layered vertical tiers",eventModel:"events climb through stacked bands",useCase:"compact timeline or event ladder with branching memory",description:"This keeps the same attractor logic but turns it into a vertical meter. The result reads more like a time stack than a cloud, while still branching naturally.",influenceDistance:21,killDistance:4.2,stepLength:3.15,stepsPerPulse:10,maxNewPerStep:4,maxSegments:280,rootRadius:1.12,tipRadius:.2,nodeScale:.82,drift:1.08,bias:new p(0,.26,0),seedDirections:[new p(0,1,0).normalize(),new p(.28,.96,.08).normalize(),new p(-.28,.96,-.08).normalize(),new p(.18,.92,-.22).normalize()],createAttractors:Me,selectTargets:Ae})];function F(){return window.innerWidth<920}function Ce(){const o=w.useRef(null),e=w.useRef(null),t=w.useRef(0),[s,n]=w.useState(0),[i,a]=w.useState(()=>F());w.useEffect(()=>{const r=()=>a(F());return window.addEventListener("resize",r),()=>window.removeEventListener("resize",r)},[]),w.useEffect(()=>{if(!o.current)return;const r=new ue(o.current);e.current=r,r.setVariation(C[0]);function u(){r.tick(),t.current=requestAnimationFrame(u)}return t.current=requestAnimationFrame(u),()=>{cancelAnimationFrame(t.current),r.destroy(),e.current=null}},[]);function l(r){var u;n(r),(u=e.current)==null||u.setVariation(C[r])}const c=C[s];return h.jsxs("div",{style:{width:"100vw",height:"100vh",background:"#04050b",position:"relative",overflow:"hidden"},children:[h.jsx("div",{ref:o,style:{position:"absolute",inset:0}}),h.jsxs("div",{style:{position:"absolute",top:i?"auto":0,right:0,bottom:0,width:i?"100%":392,height:i?"48vh":"100%",maxHeight:i?420:"100%",background:"linear-gradient(180deg, rgba(6,8,18,0.97) 0%, rgba(5,7,16,0.9) 100%)",borderLeft:i?"none":"1px solid rgba(255,255,255,0.07)",borderTop:i?"1px solid rgba(255,255,255,0.07)":"none",display:"flex",flexDirection:"column",fontFamily:"'Inter', 'SF Pro Display', system-ui, sans-serif",color:"#c8d1df",overflowY:"auto",backdropFilter:"blur(20px)"},children:[h.jsxs("div",{style:{padding:"20px 20px 16px",borderBottom:"1px solid rgba(255,255,255,0.06)",background:`linear-gradient(180deg, ${c.accent}18 0%, rgba(255,255,255,0) 100%)`},children:[h.jsx("div",{style:{fontSize:10,letterSpacing:"0.18em",color:"#6f7b90",textTransform:"uppercase",marginBottom:8},children:"Space Colonization Lab"}),h.jsx("div",{style:{fontSize:22,fontWeight:680,letterSpacing:"-0.03em",color:"#eef4ff"},children:"5 compact event-animation mappings"}),h.jsx("div",{style:{fontSize:12,lineHeight:1.65,color:"#96a4bc",marginTop:10},children:"Treat nodes as attractors. Each event arms a small pocket of them, the scaffold grows from the core, and pulses travel back through the new branch path."}),h.jsxs("div",{style:{display:"flex",gap:8,flexWrap:"wrap",marginTop:14},children:[h.jsx("span",{style:{padding:"4px 8px",borderRadius:999,fontSize:10,letterSpacing:"0.08em",textTransform:"uppercase",color:c.accent,border:`1px solid ${c.accent}44`,background:`${c.accent}16`},children:c.layout}),h.jsx("span",{style:{fontSize:11,color:"#7f8ca4",alignSelf:"center"},children:c.eventModel})]})]}),h.jsx("div",{style:{padding:"14px 14px 8px",display:"flex",flexDirection:"column",gap:10,flex:1},children:C.map((r,u)=>{const m=u===s;return h.jsxs("button",{onClick:()=>l(u),style:{textAlign:"left",borderRadius:12,border:`1px solid ${m?r.accent:"rgba(255,255,255,0.07)"}`,background:m?`linear-gradient(135deg, ${r.accent}18 0%, rgba(255,255,255,0.03) 100%)`:"rgba(255,255,255,0.025)",padding:"14px 15px",color:"inherit",cursor:"pointer",transition:"border-color 0.2s ease, background 0.2s ease"},children:[h.jsx("div",{style:{display:"flex",alignItems:"flex-start",justifyContent:"space-between",gap:12},children:h.jsxs("div",{style:{display:"flex",alignItems:"flex-start",gap:10},children:[h.jsx("div",{style:{width:28,height:28,borderRadius:8,display:"grid",placeItems:"center",fontSize:12,fontWeight:700,color:m?r.accent:"#7d889d",background:m?`${r.accent}18`:"rgba(255,255,255,0.03)",border:`1px solid ${m?`${r.accent}33`:"rgba(255,255,255,0.06)"}`,flexShrink:0},children:u+1}),h.jsxs("div",{children:[h.jsx("div",{style:{fontSize:14,fontWeight:650,color:m?"#eff4ff":"#cbd5e5"},children:r.name}),h.jsx("div",{style:{fontSize:10,letterSpacing:"0.08em",textTransform:"uppercase",color:m?r.accent:"#6d7890",marginTop:4},children:r.useCase})]})]})}),h.jsx("div",{style:{fontSize:11,color:"#7f8aa0",lineHeight:1.55,marginTop:10},children:r.description})]},r.name)})}),h.jsxs("div",{style:{padding:"14px 18px 16px",borderTop:"1px solid rgba(255,255,255,0.06)"},children:[h.jsx("button",{onClick:()=>{var r;return(r=e.current)==null?void 0:r.triggerPulse()},style:{width:"100%",padding:"11px 0",borderRadius:10,border:`1px solid ${c.accent}44`,background:`linear-gradient(135deg, ${c.accent}22 0%, rgba(255,255,255,0.03) 100%)`,color:"#eef4ff",fontSize:12,fontWeight:650,letterSpacing:"0.08em",textTransform:"uppercase",cursor:"pointer"},children:"Trigger event pulse"}),h.jsxs("div",{style:{display:"grid",gap:6,marginTop:12},children:[h.jsxs("div",{style:{fontSize:10,color:"#5f6980",lineHeight:1.5},children:["Drag to orbit, scroll to zoom. Route: ",h.jsx("code",{children:"#/colonization-demo"})]}),h.jsx("div",{style:{fontSize:10,color:"#5f6980",lineHeight:1.5},children:"Suggested product mapping: keep the node field fixed, arm only event-relevant attractors, and let the scaffold persist as a compact memory of recent flow."})]})]})]}),h.jsx("a",{href:"#/three",style:{position:"absolute",top:16,left:16,padding:"7px 12px",borderRadius:999,border:"1px solid rgba(255,255,255,0.08)",background:"rgba(8,10,18,0.55)",color:"#a8b3c8",textDecoration:"none",fontFamily:"'Inter', system-ui, sans-serif",fontSize:11,letterSpacing:"0.04em",backdropFilter:"blur(12px)"},children:"← back to live view"})]})}export{Ce as ColonizationDemoScene};
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import{C as K,G as L,W as X,S as Y,P as J,O as Q,B as Z,E as ee,R as te,U as oe,V as ae,L as W,a as u,b as H,M as F,A as M,c as S,d as B,e as re,D as ne,T as ie,f as U,g as N,h as E,i as z,j as se,s as le,k as R,r as _,l as g}from"./index-zmiMo1Db.js";const j=new Map;let $=U;function ce(r,t){j.set(r,t),$=(o,i,s)=>{const d=j.get(o);return d?d(i,s):U(o,i,s)}}class ue{constructor(t){this.clock=new K,this.nodeGroup=new L,this.currentNode=null,this.respawnTimer=0,this.currentVariation=null,this.axisGroup=new L,this._onResize=()=>{const i=this.renderer.domElement.parentElement;if(!i)return;const s=i.clientWidth,d=i.clientHeight;this.camera.aspect=s/d,this.camera.updateProjectionMatrix(),this.renderer.setSize(s,d),this.composer.setSize(s,d)},this.renderer=new X({antialias:!0}),this.renderer.setPixelRatio(Math.min(window.devicePixelRatio,2)),this.renderer.setSize(t.clientWidth,t.clientHeight),this.renderer.setClearColor(197384),t.appendChild(this.renderer.domElement),this.scene=new Y,this.camera=new J(55,t.clientWidth/t.clientHeight,1,2e3),this.camera.position.set(0,60,200),this.controls=new Q(this.camera,this.renderer.domElement),this.controls.enableDamping=!0,this.controls.dampingFactor=.06,this.controls.autoRotate=!1,this.controls.target.set(-40,5,-15),this.controls.minDistance=50,this.controls.maxDistance=600,this.background=new Z,this.scene.add(this.background.group),this.scene.add(this.nodeGroup),this.scene.add(this.axisGroup),this._buildAxis(),this._buildCoreGlow(),this.composer=new ee(this.renderer),this.composer.addPass(new te(this.scene,this.camera));const o=new oe(new ae(t.clientWidth,t.clientHeight),.7,.4,.75);this.composer.addPass(o),window.addEventListener("resize",this._onResize),this._onResize()}_buildAxis(){const t=new W({color:2236996,transparent:!0,opacity:.4}),o=(i,s)=>{const d=new N().setFromPoints([i,s]);return new E(d,t)};this.axisGroup.add(o(new u(-120,0,0),new u(20,0,0))),this.axisGroup.add(o(new u(0,-20,0),new u(0,30,0))),this.axisGroup.add(o(new u(0,0,-60),new u(0,0,20)))}_buildCoreGlow(){const t=new H(3,16,16),o=new F({color:new S("#22ff88"),transparent:!0,opacity:.15,blending:M});this.scene.add(new B(t,o));const i=new re(5,6,32),s=new F({color:new S("#4ade80"),transparent:!0,opacity:.2,blending:M,side:ne});this.scene.add(new B(i,s));const d=new u(-80,10,-30),v=new H(2,12,12),h=new F({color:new S("#4ade80"),transparent:!0,opacity:.3,blending:M}),m=new B(v,h);m.position.copy(d),this.scene.add(m)}setVariation(t){if(this.currentVariation=t,t.buildCustomEffect){const o=t.spawnParams()._tool??"";ce(o,t.buildCustomEffect)}this._clearNode(),this._spawnNode()}_clearNode(){this.currentNode&&(this.nodeGroup.remove(this.currentNode.group),this.currentNode.dispose(),this.currentNode=null)}_spawnNode(){if(!this.currentVariation)return;const t=this.currentVariation.spawnParams(this.camera.position),o=new ie(t,$);this.nodeGroup.add(o.group),this.currentNode=o,this.respawnTimer=0}tick(){const t=Math.min(this.clock.getDelta(),.05);this.controls.update(),this.background.tick(t),this.currentNode?(this.currentNode.tick(t),this.currentNode.done&&(this._clearNode(),this.respawnTimer=0)):(this.respawnTimer+=t,this.respawnTimer>1&&this.currentVariation&&this._spawnNode()),this.composer.render()}destroy(){window.removeEventListener("resize",this._onResize),this.renderer.dispose(),this._clearNode(),j.clear()}}const q=new u(0,0,0);function x(r,t){return Math.random()*(t-r)+r}function de(){return{origin:new u(-120,15,-60),target:q.clone().add(new u(x(-2,2),x(-2,2),x(-2,2))),color:new S("#b0c8f0"),colorEnd:new S("#ffffff"),travelTime:3,trailLength:0,trailBrightness:0,trailFadeTime:4,headSize:0,pathConfig:{type:"linear",easing:"easeInCubic"},_tool:"prompt:custom"}}function pe(){const r=Math.random()*Math.PI*2,t=Math.acos(x(-1,1)),o=x(250,400);return new u(Math.sin(t)*Math.cos(r)*o,Math.sin(t)*Math.sin(r)*o,Math.cos(t)*o)}function O(r){const t=de();t._tool=r,t.origin=pe(),t.travelTime=x(4,5.5),t.trailFadeTime=1.8;const o=t.origin.clone().add(q).multiplyScalar(.5);return t.pathConfig={type:"quadratic",easing:"easeInOut",c1:new u(o.x+x(-40,40),o.y+x(20,60),o.z+x(-30,30))},t}function he(r,t){return{f1:1.2+Math.random()*1.5,f2:3.5+Math.random()*3,ph1:Math.random()*Math.PI*2,ph2:Math.random()*Math.PI*2,amp:4+Math.random()*6,perp:new u(Math.random()-.5,Math.random()-.5,Math.random()-.5).normalize(),scatter:new u((Math.random()-.5)*400,(Math.random()-.5)*400,(Math.random()-.5)*400),windowStart:-(r/t)*3.5-Math.random()*.2,rollSpeed:.8+Math.random()*.6}}function fe(r,t,o,i,s){const d=se(t.pathConfig.easing,o),v=le(t.pathConfig,t.origin,t.target,d),h=Math.max(0,1-o/.5),m=Math.min(1,o/.5),l=1-Math.pow(o,8),e=(Math.sin(o*r.f1*Math.PI*2+r.ph1+i*s)*r.amp+Math.sin(o*r.f2*Math.PI*2+r.ph2+i*s*1.4)*r.amp*.3)*m*l;return new u(v.x+r.scatter.x*h+r.perp.x*e,v.y+r.scatter.y*h+r.perp.y*e,v.z+r.scatter.z*h+r.perp.z*e)}function P(r,t,o,i,s){const d=Array.from({length:i},(h,m)=>{const l=he(m,i),e=new Float32Array(o*3),n=new N;n.setAttribute("position",new z(e,3));const c=new Float32Array(o);for(let T=0;T<o;T++)c[T]=T/(o-1);n.setAttribute("aT",new z(c,1));const{mat:a,setOpacity:p,setTime:w}=s(m,n);return r.add(new E(n,a)),{...l,posArr:e,geo:n,mat:a,window:l.windowStart,setOpacity:p,setTime:w}}),v={entries:d.map(h=>({obj:new E(h.geo,h.mat),mat:h.mat,meta:{}})),suppressDefaultTrail:!0,trailTick(h,m,l){var c;const e=2.5+l*.1;let n=!0;for(const a of d){const p=a.window>=1?1/(1.5*a.rollSpeed):(1-a.windowStart)/t.travelTime;a.window=Math.min(2,a.window+m*p);const w=a.window;if(w<=0){a.geo.setDrawRange(0,0),n=!1;continue}if(w>=2){a.setOpacity(0),a.geo.setDrawRange(0,0);continue}n=!1;const T=Math.round(Math.min(1,w)*(o-1)),y=Math.round(Math.max(0,w-1)*(o-1)),A=T-y;if(A<1){a.geo.setDrawRange(0,0);continue}for(let b=y;b<=T;b++){const C=fe(a,t,b/(o-1),l,e);a.posArr[b*3]=C.x,a.posArr[b*3+1]=C.y,a.posArr[b*3+2]=C.z}a.geo.attributes.position.needsUpdate=!0,a.geo.setDrawRange(y,A),a.setOpacity(.7),(c=a.setTime)==null||c.call(a,l)}n&&(v.shouldMarkDone=!0)},tick(){},onLand(){},applyFade(h){},shouldMarkDone:!1};return v}function ge(r,t){return P(r,t,120,8,o=>{const i=new W({color:new S().setHSL(.55+o/8*.15,.9,.6+o%2*.2),transparent:!0,opacity:0,blending:M,depthWrite:!1});return{mat:i,setOpacity:s=>{i.opacity=s}}})}const me=`
|
|
2
|
+
attribute float aT;
|
|
3
|
+
varying float vT;
|
|
4
|
+
void main() { vT = aT; gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0); }
|
|
5
|
+
`,ve=`
|
|
6
|
+
uniform float uTime;
|
|
7
|
+
uniform float uOpacity;
|
|
8
|
+
uniform float uHueBase;
|
|
9
|
+
varying float vT;
|
|
10
|
+
vec3 hsl2rgb(float h, float s, float l) {
|
|
11
|
+
h = mod(h, 1.0);
|
|
12
|
+
vec3 rgb = clamp(abs(mod(h*6.0+vec3(0,4,2),6.0)-3.0)-1.0, 0.0, 1.0);
|
|
13
|
+
return l + s*(rgb-0.5)*(1.0-abs(2.0*l-1.0));
|
|
14
|
+
}
|
|
15
|
+
void main() {
|
|
16
|
+
// Hue drifts along length + time
|
|
17
|
+
float hue = mod(uHueBase + vT * 0.3 + uTime * 0.12, 1.0);
|
|
18
|
+
float core = pow(1.0 - vT, 0.3); // bright at head (t=1 is target)
|
|
19
|
+
float bloom = pow(vT, 0.5) * 0.6;
|
|
20
|
+
vec3 col = hsl2rgb(hue, 1.0, 0.55 + bloom * 0.3);
|
|
21
|
+
// White-hot center
|
|
22
|
+
col = mix(col, vec3(1.0), core * 0.4);
|
|
23
|
+
float alpha = (bloom + core * 0.5) * uOpacity;
|
|
24
|
+
gl_FragColor = vec4(col * (bloom + core * 0.5 + 0.05), alpha);
|
|
25
|
+
}
|
|
26
|
+
`;function we(r,t){return P(r,t,120,8,o=>{const i=new R({vertexShader:me,fragmentShader:ve,uniforms:{uTime:{value:0},uOpacity:{value:0},uHueBase:{value:o/8}},blending:M,transparent:!0,depthWrite:!1});return{mat:i,setOpacity:s=>{i.uniforms.uOpacity.value=s},setTime:s=>{i.uniforms.uTime.value=s}}})}const be=`
|
|
27
|
+
attribute float aT;
|
|
28
|
+
varying float vT;
|
|
29
|
+
void main() { vT = aT; gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0); }
|
|
30
|
+
`,Te=`
|
|
31
|
+
uniform float uTime;
|
|
32
|
+
uniform float uOpacity;
|
|
33
|
+
uniform float uPhase;
|
|
34
|
+
varying float vT;
|
|
35
|
+
float hash(float n) { return fract(sin(n)*43758.5453); }
|
|
36
|
+
void main() {
|
|
37
|
+
// High-freq flicker noise
|
|
38
|
+
float noise = hash(floor(vT * 80.0 + uTime * 30.0));
|
|
39
|
+
float flicker = 0.7 + 0.3 * noise;
|
|
40
|
+
// Traveling pulse toward core (vT=1)
|
|
41
|
+
float pulsePos = mod(uPhase + uTime * 0.6, 1.0);
|
|
42
|
+
float pulse = exp(-pow((vT - pulsePos) / 0.05, 2.0)) * 2.5;
|
|
43
|
+
// Base glow — brighter near core
|
|
44
|
+
float base = pow(vT, 0.4) * 0.5;
|
|
45
|
+
float b = (base + pulse) * flicker;
|
|
46
|
+
// Color: deep blue → cyan → white at pulse peak
|
|
47
|
+
vec3 blue = vec3(0.05, 0.2, 1.0);
|
|
48
|
+
vec3 cyan = vec3(0.2, 0.9, 1.0);
|
|
49
|
+
vec3 white = vec3(1.0, 1.0, 1.0);
|
|
50
|
+
vec3 col = mix(blue, cyan, vT);
|
|
51
|
+
col = mix(col, white, clamp(pulse / 2.5, 0.0, 1.0));
|
|
52
|
+
gl_FragColor = vec4(col * b, b * uOpacity);
|
|
53
|
+
}
|
|
54
|
+
`;function ye(r,t){return P(r,t,120,8,o=>{const i=new R({vertexShader:be,fragmentShader:Te,uniforms:{uTime:{value:0},uOpacity:{value:0},uPhase:{value:o/8}},blending:M,transparent:!0,depthWrite:!1});return{mat:i,setOpacity:s=>{i.uniforms.uOpacity.value=s},setTime:s=>{i.uniforms.uTime.value=s}}})}const xe=`
|
|
55
|
+
attribute float aT;
|
|
56
|
+
varying float vT;
|
|
57
|
+
void main() { vT = aT; gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0); }
|
|
58
|
+
`,Me=`
|
|
59
|
+
uniform float uTime;
|
|
60
|
+
uniform float uOpacity;
|
|
61
|
+
uniform float uOffset;
|
|
62
|
+
varying float vT;
|
|
63
|
+
vec3 hsl2rgb(float h, float s, float l) {
|
|
64
|
+
h = mod(h, 1.0);
|
|
65
|
+
vec3 rgb = clamp(abs(mod(h*6.0+vec3(0,4,2),6.0)-3.0)-1.0, 0.0, 1.0);
|
|
66
|
+
return l + s*(rgb-0.5)*(1.0-abs(2.0*l-1.0));
|
|
67
|
+
}
|
|
68
|
+
void main() {
|
|
69
|
+
// Slow drifting color bands along the strand
|
|
70
|
+
float hue = mod(uOffset + vT * 0.5 + uTime * 0.04, 1.0);
|
|
71
|
+
float bright = 0.5 + 0.5 * sin(vT * 3.0 + uTime * 0.8 + uOffset * 6.28);
|
|
72
|
+
// Soft curtain falloff — bright in the middle of length
|
|
73
|
+
float curtain = sin(vT * 3.14159) * 0.8 + 0.2;
|
|
74
|
+
// Very soft, high luminance pastels
|
|
75
|
+
vec3 col = hsl2rgb(hue, 0.6, 0.6 + bright * 0.25);
|
|
76
|
+
float alpha = curtain * bright * 0.5 * uOpacity;
|
|
77
|
+
gl_FragColor = vec4(col * curtain * bright, alpha);
|
|
78
|
+
}
|
|
79
|
+
`;function Se(r,t){return P(r,t,120,10,o=>{const i=new R({vertexShader:xe,fragmentShader:Me,uniforms:{uTime:{value:0},uOpacity:{value:0},uOffset:{value:o/10}},blending:M,transparent:!0,depthWrite:!1});return{mat:i,setOpacity:s=>{i.uniforms.uOpacity.value=s},setTime:s=>{i.uniforms.uTime.value=s}}})}const Ae=`
|
|
80
|
+
attribute float aT;
|
|
81
|
+
varying float vT;
|
|
82
|
+
void main() { vT = aT; gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0); }
|
|
83
|
+
`,Ce=`
|
|
84
|
+
uniform float uTime;
|
|
85
|
+
uniform float uOpacity;
|
|
86
|
+
uniform float uHue;
|
|
87
|
+
varying float vT;
|
|
88
|
+
vec3 hsl2rgb(float h, float s, float l) {
|
|
89
|
+
h = mod(h, 1.0);
|
|
90
|
+
vec3 rgb = clamp(abs(mod(h*6.0+vec3(0,4,2),6.0)-3.0)-1.0, 0.0, 1.0);
|
|
91
|
+
return l + s*(rgb-0.5)*(1.0-abs(2.0*l-1.0));
|
|
92
|
+
}
|
|
93
|
+
void main() {
|
|
94
|
+
// Traveling energy packets
|
|
95
|
+
float packet1 = exp(-pow(mod(vT - uTime * 0.5, 1.0) / 0.08, 2.0));
|
|
96
|
+
float packet2 = exp(-pow(mod(vT - uTime * 0.5 + 0.4, 1.0) / 0.08, 2.0));
|
|
97
|
+
float energy = packet1 + packet2 * 0.6;
|
|
98
|
+
// White-hot spine at high energy, colored bleed otherwise
|
|
99
|
+
vec3 fiberCol = hsl2rgb(uHue, 1.0, 0.5);
|
|
100
|
+
vec3 col = mix(fiberCol, vec3(1.0), clamp(energy, 0.0, 1.0));
|
|
101
|
+
// Base thread glow — constant soft light
|
|
102
|
+
float base = 0.2 + 0.1 * sin(vT * 20.0 - uTime * 3.0);
|
|
103
|
+
float alpha = (base + energy * 0.8) * uOpacity;
|
|
104
|
+
gl_FragColor = vec4(col * (base + energy * 0.8), alpha);
|
|
105
|
+
}
|
|
106
|
+
`;function _e(r,t){return P(r,t,120,8,o=>{const i=new R({vertexShader:Ae,fragmentShader:Ce,uniforms:{uTime:{value:0},uOpacity:{value:0},uHue:{value:.55+o/8*.35}},blending:M,transparent:!0,depthWrite:!1});return{mat:i,setOpacity:s=>{i.uniforms.uOpacity.value=s},setTime:s=>{i.uniforms.uTime.value=s}}})}const ke=[{name:"Writhing",description:"Baseline — colored strands scatter, converge, weave into core",spawnParams:()=>O("prompt:writhing"),buildCustomEffect:ge},{name:"Neon Iridescent",description:"Hue shifts along length and over time — white-hot core bloom",spawnParams:()=>O("prompt:neon"),buildCustomEffect:we},{name:"Plasma",description:"Electric blue-white with noisy flicker and traveling pulses",spawnParams:()=>O("prompt:plasma"),buildCustomEffect:ye},{name:"Aurora",description:"Soft pastel curtains drifting with slow color bands",spawnParams:()=>O("prompt:aurora"),buildCustomEffect:Se},{name:"Fiber Light",description:"White-hot spine with colored energy packets traveling to core",spawnParams:()=>O("prompt:fiber"),buildCustomEffect:_e}];function f(r,t){return Math.random()*(t-r)+r}const Oe=new u(0,0,0);function Re(){const r=Math.random()*Math.PI*2,t=f(60,110),o=new u(Math.cos(r)*t,f(-8,15),Math.sin(r)*t*.5),i=o.clone().multiplyScalar(.5);return{origin:Oe.clone(),target:o,color:new S("#a78bfa"),colorEnd:new S("#e9d5ff"),travelTime:f(2.5,3.5),trailLength:0,trailBrightness:0,trailFadeTime:30,headSize:0,pathConfig:{type:"quadratic",easing:"easeInOut",c1:new u(i.x+f(-25,25),i.y+f(10,35),i.z+f(-20,20))},_tool:"Glob:demo"}}const V=80,I=10,Pe=.35,Ee=`
|
|
107
|
+
attribute float aT;
|
|
108
|
+
varying float vT;
|
|
109
|
+
void main() {
|
|
110
|
+
vT = aT;
|
|
111
|
+
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
|
112
|
+
}
|
|
113
|
+
`,ze=`
|
|
114
|
+
uniform float uTime;
|
|
115
|
+
uniform float uOpacity;
|
|
116
|
+
uniform vec3 uBaseColor;
|
|
117
|
+
uniform vec3 uTipColor;
|
|
118
|
+
uniform float uPhase;
|
|
119
|
+
varying float vT;
|
|
120
|
+
|
|
121
|
+
void main() {
|
|
122
|
+
vec3 col = mix(uBaseColor, uTipColor, vT);
|
|
123
|
+
|
|
124
|
+
// energy flow racing toward tip
|
|
125
|
+
float flow = sin((vT * 8.0 - uTime * 2.0 + uPhase) * 3.14159);
|
|
126
|
+
flow = pow(max(0.0, flow), 3.0) * 0.3;
|
|
127
|
+
col += uTipColor * flow;
|
|
128
|
+
|
|
129
|
+
// hot head: last 10% glows bright
|
|
130
|
+
float head = smoothstep(0.9, 1.0, vT);
|
|
131
|
+
col = mix(col, uTipColor * 1.5, head * 0.7);
|
|
132
|
+
|
|
133
|
+
float bright = 0.4 + vT * 0.3 + flow * 0.3 + head * 0.8;
|
|
134
|
+
float alpha = uOpacity * (0.3 + vT * 0.3 + flow * 0.15 + head * 0.4);
|
|
135
|
+
|
|
136
|
+
gl_FragColor = vec4(min(col * bright, 1.0), min(alpha, 1.0));
|
|
137
|
+
}
|
|
138
|
+
`;function De(r,t){const o=[];function i(e,n){const c=f(0,Math.PI*2),a=f(-.6,.6),p=new u(Math.cos(c)*Math.cos(a),Math.sin(a),Math.sin(c)*Math.cos(a)).normalize(),w=f(14,22),T=p.clone().multiplyScalar(w),y=new Float32Array(V*3),A=new Float32Array(V),b=new N;b.setAttribute("position",new z(y,3)),b.setAttribute("aT",new z(A,1)),b.setDrawRange(0,0);const C=new R({vertexShader:Ee,fragmentShader:ze,uniforms:{uTime:{value:0},uOpacity:{value:.85},uBaseColor:{value:new u(.2,.12,.4)},uTipColor:{value:new u(.5,.35,.9)},uPhase:{value:f(0,6.28)}},blending:M,transparent:!0,depthWrite:!1}),D=new E(b,C);D.visible=!1,r.add(D),y[0]=t.target.x,y[1]=t.target.y,y[2]=t.target.z,A[0]=0;const G={origin:t.target.clone(),isHit:n,fireDelay:e,pos:t.target.clone(),vel:T,searchDist:f(20,45),gravity:new u(f(-1.5,1.5),f(-3,-1),f(-1.5,1.5)),drift:new u(f(-2,2),f(-.5,.5),f(-2,2)),returnStart:new u,returnArc:new u,returnT:0,returnDur:f(1.2,2),points:[t.target.clone()],posArr:y,tArr:A,geo:b,mat:C,line:D,ptCount:1,state:"waiting",elapsed:0,stateTime:0,tailIdx:0};return o.push(G),G}const s=[],d=Array.from({length:I},(e,n)=>n);for(let e=d.length-1;e>0;e--){const n=Math.floor(Math.random()*(e+1));[d[e],d[n]]=[d[n],d[e]]}for(let e=0;e<I;e++){const n=d[e]<I*Pe;s.push(i(f(.1,3),n))}function v(e){const n=Math.min(e.points.length,V),c=e.points.length-n;for(let a=0;a<n;a++){const p=e.points[c+a];e.posArr[a*3]=p.x,e.posArr[a*3+1]=p.y,e.posArr[a*3+2]=p.z,e.tArr[a]=a/(n-1||1)}e.ptCount=n,e.geo.attributes.position.needsUpdate=!0,e.geo.attributes.aT.needsUpdate=!0}function h(e,n,c,a){const p=1-a;return new u(p*p*e.x+2*p*a*n.x+a*a*c.x,p*p*e.y+2*p*a*n.y+a*a*c.y,p*p*e.z+2*p*a*n.z+a*a*c.z)}function m(e,n){if(e.elapsed+=n,e.mat.uniforms.uTime.value=e.elapsed,e.state==="waiting"){e.elapsed>=e.fireDelay&&(e.state="seeking",e.stateTime=0,e.line.visible=!0);return}if(e.stateTime+=n,e.state==="seeking"){if(e.vel.addScaledVector(e.gravity,n),e.vel.addScaledVector(e.drift,n),e.vel.multiplyScalar(1-n*.3),e.pos.addScaledVector(e.vel,n),e.points.push(e.pos.clone()),v(e),e.geo.setDrawRange(0,e.ptCount),e.pos.distanceTo(e.origin)>=e.searchDist)if(e.isHit){e.state="hit_returning",e.stateTime=0,e.returnStart.copy(e.pos);const c=e.pos.clone().add(e.origin).multiplyScalar(.5);e.returnArc.set(c.x+f(-18,18),c.y+f(8,25),c.z+f(-18,18)),e.returnT=0,e.mat.uniforms.uBaseColor.value.set(.05,.35,.15),e.mat.uniforms.uTipColor.value.set(.3,1,.5)}else e.state="miss_dying",e.stateTime=0,e.tailIdx=0,e.mat.uniforms.uBaseColor.value.set(.3,.05,.05),e.mat.uniforms.uTipColor.value.set(.5,.1,.08)}else if(e.state==="hit_returning"){e.returnT=Math.min(1,e.returnT+n/e.returnDur);const c=e.returnT<.5?2*e.returnT*e.returnT:1-Math.pow(-2*e.returnT+2,2)/2;e.pos.copy(h(e.returnStart,e.returnArc,e.origin,c)),e.points.push(e.pos.clone()),v(e),e.geo.setDrawRange(0,e.ptCount),e.returnT>=1&&(e.state="miss_dying",e.stateTime=0,e.tailIdx=0)}else if(e.state==="miss_dying"){const c=e.isHit?25:15;e.tailIdx=Math.min(e.ptCount-1,e.tailIdx+n*c);const a=Math.round(e.tailIdx),p=e.ptCount-a;if(p<=1){e.state="done",e.geo.setDrawRange(0,0),e.line.visible=!1;return}e.geo.setDrawRange(a,p);for(let w=a;w<e.ptCount;w++)e.tArr[w]=(w-a)/(p-1);e.geo.attributes.aT.needsUpdate=!0,e.isHit||(e.mat.uniforms.uOpacity.value=Math.max(0,.85-e.stateTime*.4))}}const l={entries:[],suppressDefaultTrail:!0,trailTick(e,n){for(const c of s)m(c,n);o.every(c=>c.state==="done")&&(l.shouldMarkDone=!0)},tick(){},onLand(){},applyFade(e){},shouldMarkDone:!1,dispose(){for(const e of o)e.geo.dispose(),e.mat.dispose()}};return l}const Fe=[{name:"Seeker Missiles",description:"Missiles launch staggered, seek outward; hits glow green and arc back, misses turn red and dissolve",spawnParams:Re,buildCustomEffect:De}],k=[{label:"Prompt",color:"#93c5fd",variations:ke},{label:"Glob",color:"#a78bfa",variations:Fe}];function Ve(){const r=_.useRef(null),t=_.useRef(null),o=_.useRef(0),[i,s]=_.useState(0),[d,v]=_.useState(0),h=k[i];_.useEffect(()=>{if(!r.current)return;const l=new ue(r.current);t.current=l;const e=k[0].variations[0];l.setVariation(e);function n(){l.tick(),o.current=requestAnimationFrame(n)}return o.current=requestAnimationFrame(n),()=>{cancelAnimationFrame(o.current),l.destroy(),t.current=null}},[]);function m(l,e){var c;s(l),v(e);const n=k[l].variations[e];(c=t.current)==null||c.setVariation(n)}return g.jsxs("div",{style:{width:"100vw",height:"100vh",background:"#030308",display:"flex",position:"relative"},children:[g.jsx("div",{ref:r,style:{flex:1,height:"100%"}}),g.jsxs("div",{style:{position:"absolute",top:0,right:0,width:280,height:"100%",background:"rgba(3,3,14,0.88)",borderLeft:"1px solid rgba(255,255,255,0.06)",display:"flex",flexDirection:"column",fontFamily:"monospace",color:"#aaa",overflowY:"auto"},children:[g.jsxs("div",{style:{padding:"16px 16px 10px",borderBottom:"1px solid rgba(255,255,255,0.06)"},children:[g.jsx("div",{style:{fontSize:11,letterSpacing:"0.1em",color:"#555",marginBottom:4},children:"EFFECT DEMO"}),g.jsx("div",{style:{fontSize:13,color:"#eee"},children:"trail variations"})]}),g.jsx("div",{style:{display:"flex",padding:"10px 10px 0",gap:6,flexWrap:"wrap"},children:k.map((l,e)=>g.jsx("button",{onClick:()=>m(e,0),style:{padding:"4px 10px",fontSize:11,borderRadius:3,border:`1px solid ${i===e?l.color:"rgba(255,255,255,0.1)"}`,background:i===e?`${l.color}18`:"transparent",color:i===e?l.color:"#666",cursor:"pointer",letterSpacing:"0.05em"},children:l.label},l.label))}),g.jsx("div",{style:{padding:10,display:"flex",flexDirection:"column",gap:8,flex:1},children:h.variations.map((l,e)=>{const n=i===k.indexOf(h)&&d===e;return g.jsxs("button",{onClick:()=>m(k.indexOf(h),e),style:{textAlign:"left",padding:"10px 12px",borderRadius:5,border:`1px solid ${n?h.color:"rgba(255,255,255,0.07)"}`,background:n?`${h.color}12`:"rgba(255,255,255,0.02)",cursor:"pointer",color:"inherit",transition:"border-color 0.15s"},children:[g.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8,marginBottom:4},children:[g.jsx("span",{style:{display:"inline-block",width:8,height:8,borderRadius:"50%",background:n?h.color:"#444",flexShrink:0}}),g.jsxs("span",{style:{fontSize:12,color:n?h.color:"#ccc",fontWeight:600},children:[e+1,". ",l.name]})]}),g.jsx("div",{style:{fontSize:11,color:"#666",lineHeight:1.5,paddingLeft:16},children:l.description})]},l.name)})}),g.jsx("div",{style:{padding:"10px 16px",borderTop:"1px solid rgba(255,255,255,0.05)",fontSize:10,color:"#444"},children:"drag to orbit · scroll to zoom · node loops automatically"})]}),g.jsx("a",{href:"#/three",style:{position:"absolute",top:14,left:14,fontSize:11,color:"#444",textDecoration:"none",fontFamily:"monospace",letterSpacing:"0.05em"},children:"← back"})]})}export{Ve as EffectDemoScene};
|