reflexive 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +77 -0
- package/FAILURES.md +245 -0
- package/README.md +264 -0
- package/Screenshot 2026-01-22 at 6.31.27/342/200/257AM.png +0 -0
- package/dashboard.html +620 -0
- package/demo-ai-features.js +571 -0
- package/demo-app.js +210 -0
- package/demo-inject.js +212 -0
- package/demo-instrumented.js +272 -0
- package/docs/BREAKPOINT-AUDIT.md +293 -0
- package/docs/GENESIS.md +110 -0
- package/docs/HN-LAUNCH-PLAN-V2.md +631 -0
- package/docs/HN-LAUNCH-PLAN.md +492 -0
- package/docs/TODO.md +69 -0
- package/docs/V8-INSPECTOR-RESEARCH.md +1231 -0
- package/logo-carbon.png +0 -0
- package/logo0.jpg +0 -0
- package/logo1.jpg +0 -0
- package/logo2.jpg +0 -0
- package/new-ui-template.html +435 -0
- package/one-shot.js +1109 -0
- package/package.json +47 -0
- package/play-story.sh +10 -0
- package/src/demo-inject.js +3 -0
- package/src/inject.cjs +474 -0
- package/src/reflexive.js +6214 -0
- package/story-game-reflexive.js +1246 -0
- package/story-game-web.js +1030 -0
- package/story-mystery-1769171430377.js +162 -0
package/dashboard.html
ADDED
|
@@ -0,0 +1,620 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Reflexive Nexus - Story Dashboard</title>
|
|
7
|
+
<style>
|
|
8
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
9
|
+
body {
|
|
10
|
+
font-family: 'Courier New', monospace;
|
|
11
|
+
background: #000;
|
|
12
|
+
overflow: hidden;
|
|
13
|
+
color: #fff;
|
|
14
|
+
}
|
|
15
|
+
#three-canvas {
|
|
16
|
+
position: fixed;
|
|
17
|
+
top: 0;
|
|
18
|
+
left: 0;
|
|
19
|
+
width: 100%;
|
|
20
|
+
height: 100%;
|
|
21
|
+
z-index: 0;
|
|
22
|
+
}
|
|
23
|
+
.overlay {
|
|
24
|
+
position: fixed;
|
|
25
|
+
top: 0;
|
|
26
|
+
left: 0;
|
|
27
|
+
width: 100%;
|
|
28
|
+
height: 100%;
|
|
29
|
+
z-index: 1;
|
|
30
|
+
pointer-events: none;
|
|
31
|
+
}
|
|
32
|
+
.ui-container {
|
|
33
|
+
position: relative;
|
|
34
|
+
z-index: 2;
|
|
35
|
+
padding: 40px;
|
|
36
|
+
display: flex;
|
|
37
|
+
flex-direction: column;
|
|
38
|
+
height: 100vh;
|
|
39
|
+
pointer-events: none;
|
|
40
|
+
}
|
|
41
|
+
.ui-container > * {
|
|
42
|
+
pointer-events: auto;
|
|
43
|
+
}
|
|
44
|
+
.header {
|
|
45
|
+
text-align: center;
|
|
46
|
+
margin-bottom: 30px;
|
|
47
|
+
}
|
|
48
|
+
h1 {
|
|
49
|
+
font-size: 4em;
|
|
50
|
+
text-shadow:
|
|
51
|
+
0 0 10px rgba(0, 255, 255, 0.8),
|
|
52
|
+
0 0 20px rgba(0, 255, 255, 0.6),
|
|
53
|
+
0 0 30px rgba(0, 255, 255, 0.4),
|
|
54
|
+
0 0 40px rgba(0, 200, 255, 0.3);
|
|
55
|
+
animation: pulse 3s ease-in-out infinite;
|
|
56
|
+
letter-spacing: 0.1em;
|
|
57
|
+
}
|
|
58
|
+
@keyframes pulse {
|
|
59
|
+
0%, 100% { text-shadow: 0 0 10px rgba(0, 255, 255, 0.8), 0 0 20px rgba(0, 255, 255, 0.6); }
|
|
60
|
+
50% { text-shadow: 0 0 20px rgba(0, 255, 255, 1), 0 0 40px rgba(0, 255, 255, 0.8); }
|
|
61
|
+
}
|
|
62
|
+
.content {
|
|
63
|
+
display: grid;
|
|
64
|
+
grid-template-columns: 1fr 1fr;
|
|
65
|
+
gap: 30px;
|
|
66
|
+
flex: 1;
|
|
67
|
+
}
|
|
68
|
+
.panel {
|
|
69
|
+
background: rgba(0, 20, 40, 0.7);
|
|
70
|
+
border: 2px solid rgba(0, 255, 255, 0.4);
|
|
71
|
+
border-radius: 20px;
|
|
72
|
+
padding: 30px;
|
|
73
|
+
backdrop-filter: blur(10px);
|
|
74
|
+
box-shadow:
|
|
75
|
+
0 0 20px rgba(0, 255, 255, 0.2),
|
|
76
|
+
inset 0 0 20px rgba(0, 255, 255, 0.05);
|
|
77
|
+
}
|
|
78
|
+
.panel h2 {
|
|
79
|
+
color: #00ffff;
|
|
80
|
+
margin-bottom: 20px;
|
|
81
|
+
font-size: 1.8em;
|
|
82
|
+
text-shadow: 0 0 10px rgba(0, 255, 255, 0.5);
|
|
83
|
+
}
|
|
84
|
+
.story-text {
|
|
85
|
+
font-size: 1.2em;
|
|
86
|
+
line-height: 1.8;
|
|
87
|
+
color: #a0d8ff;
|
|
88
|
+
margin-bottom: 20px;
|
|
89
|
+
}
|
|
90
|
+
.metrics {
|
|
91
|
+
display: flex;
|
|
92
|
+
flex-direction: column;
|
|
93
|
+
gap: 20px;
|
|
94
|
+
}
|
|
95
|
+
.metric {
|
|
96
|
+
background: rgba(0, 0, 0, 0.5);
|
|
97
|
+
padding: 15px;
|
|
98
|
+
border-radius: 10px;
|
|
99
|
+
border-left: 4px solid #00ffff;
|
|
100
|
+
}
|
|
101
|
+
.metric-label {
|
|
102
|
+
color: #00ffff;
|
|
103
|
+
font-size: 0.9em;
|
|
104
|
+
margin-bottom: 8px;
|
|
105
|
+
}
|
|
106
|
+
.metric-bar {
|
|
107
|
+
height: 30px;
|
|
108
|
+
background: rgba(0, 0, 0, 0.6);
|
|
109
|
+
border-radius: 15px;
|
|
110
|
+
overflow: hidden;
|
|
111
|
+
position: relative;
|
|
112
|
+
}
|
|
113
|
+
.metric-fill {
|
|
114
|
+
height: 100%;
|
|
115
|
+
background: linear-gradient(90deg, #00ff88, #00ffff, #0088ff);
|
|
116
|
+
transition: width 1s ease;
|
|
117
|
+
box-shadow: 0 0 20px rgba(0, 255, 200, 0.6);
|
|
118
|
+
display: flex;
|
|
119
|
+
align-items: center;
|
|
120
|
+
justify-content: center;
|
|
121
|
+
font-weight: bold;
|
|
122
|
+
color: #000;
|
|
123
|
+
}
|
|
124
|
+
.choices {
|
|
125
|
+
display: flex;
|
|
126
|
+
flex-direction: column;
|
|
127
|
+
gap: 15px;
|
|
128
|
+
}
|
|
129
|
+
.choice-btn {
|
|
130
|
+
padding: 20px;
|
|
131
|
+
background: linear-gradient(135deg, rgba(0, 255, 136, 0.15), rgba(0, 200, 255, 0.15));
|
|
132
|
+
border: 2px solid rgba(0, 255, 200, 0.5);
|
|
133
|
+
border-radius: 12px;
|
|
134
|
+
color: #fff;
|
|
135
|
+
font-size: 1.2em;
|
|
136
|
+
cursor: pointer;
|
|
137
|
+
transition: all 0.3s ease;
|
|
138
|
+
text-align: left;
|
|
139
|
+
font-family: 'Courier New', monospace;
|
|
140
|
+
}
|
|
141
|
+
.choice-btn:hover {
|
|
142
|
+
background: linear-gradient(135deg, rgba(0, 255, 136, 0.3), rgba(0, 200, 255, 0.3));
|
|
143
|
+
transform: translateX(10px);
|
|
144
|
+
box-shadow: 0 0 30px rgba(0, 255, 200, 0.5);
|
|
145
|
+
border-color: #00ffff;
|
|
146
|
+
}
|
|
147
|
+
.chat-panel {
|
|
148
|
+
grid-column: 1 / -1;
|
|
149
|
+
max-height: 200px;
|
|
150
|
+
}
|
|
151
|
+
.chat-input {
|
|
152
|
+
width: 100%;
|
|
153
|
+
padding: 15px;
|
|
154
|
+
background: rgba(0, 0, 0, 0.6);
|
|
155
|
+
border: 2px solid rgba(0, 255, 255, 0.4);
|
|
156
|
+
border-radius: 10px;
|
|
157
|
+
color: #fff;
|
|
158
|
+
font-size: 1.1em;
|
|
159
|
+
font-family: 'Courier New', monospace;
|
|
160
|
+
transition: all 0.1s ease-out, transform 0.1s cubic-bezier(0.68, -0.55, 0.265, 1.55);
|
|
161
|
+
}
|
|
162
|
+
.chat-input:focus {
|
|
163
|
+
outline: none;
|
|
164
|
+
border-color: #00ffff;
|
|
165
|
+
box-shadow: 0 0 20px rgba(0, 255, 255, 0.4);
|
|
166
|
+
}
|
|
167
|
+
.chat-send {
|
|
168
|
+
margin-top: 10px;
|
|
169
|
+
padding: 15px 30px;
|
|
170
|
+
background: linear-gradient(135deg, #00ff88, #00ffff);
|
|
171
|
+
border: none;
|
|
172
|
+
border-radius: 10px;
|
|
173
|
+
color: #000;
|
|
174
|
+
font-weight: bold;
|
|
175
|
+
cursor: pointer;
|
|
176
|
+
font-size: 1.1em;
|
|
177
|
+
font-family: 'Courier New', monospace;
|
|
178
|
+
}
|
|
179
|
+
.chat-send:hover {
|
|
180
|
+
box-shadow: 0 0 30px rgba(0, 255, 200, 0.8);
|
|
181
|
+
transform: translateY(-2px);
|
|
182
|
+
}
|
|
183
|
+
.start-screen {
|
|
184
|
+
position: relative;
|
|
185
|
+
z-index: 10;
|
|
186
|
+
display: flex;
|
|
187
|
+
flex-direction: column;
|
|
188
|
+
justify-content: center;
|
|
189
|
+
align-items: center;
|
|
190
|
+
height: 100vh;
|
|
191
|
+
}
|
|
192
|
+
.start-btn {
|
|
193
|
+
padding: 30px 60px;
|
|
194
|
+
background: linear-gradient(135deg, #00ff88, #00ffff);
|
|
195
|
+
border: none;
|
|
196
|
+
border-radius: 20px;
|
|
197
|
+
color: #000;
|
|
198
|
+
font-size: 2em;
|
|
199
|
+
font-weight: bold;
|
|
200
|
+
cursor: pointer;
|
|
201
|
+
font-family: 'Courier New', monospace;
|
|
202
|
+
box-shadow: 0 0 40px rgba(0, 255, 200, 0.6);
|
|
203
|
+
}
|
|
204
|
+
.start-btn:hover {
|
|
205
|
+
box-shadow: 0 0 60px rgba(0, 255, 200, 1);
|
|
206
|
+
transform: scale(1.05);
|
|
207
|
+
}
|
|
208
|
+
.hidden { display: none; }
|
|
209
|
+
</style>
|
|
210
|
+
</head>
|
|
211
|
+
<body>
|
|
212
|
+
<canvas id="three-canvas"></canvas>
|
|
213
|
+
|
|
214
|
+
<div id="start-screen" class="start-screen">
|
|
215
|
+
<h1>⚡ REFLEXIVE NEXUS ⚡</h1>
|
|
216
|
+
<p style="font-size: 1.5em; margin: 20px 0; color: #00ffff;">AI-POWERED STORY ENGINE</p>
|
|
217
|
+
<button class="start-btn" onclick="startGame()">► INITIALIZE</button>
|
|
218
|
+
</div>
|
|
219
|
+
|
|
220
|
+
<div id="game-screen" class="ui-container hidden">
|
|
221
|
+
<div class="header">
|
|
222
|
+
<h1>⚡ NEXUS ACTIVE ⚡</h1>
|
|
223
|
+
</div>
|
|
224
|
+
|
|
225
|
+
<div class="content">
|
|
226
|
+
<div class="panel">
|
|
227
|
+
<h2>◉ NARRATIVE STREAM</h2>
|
|
228
|
+
<div class="story-text" id="story-text">Initializing story engine...</div>
|
|
229
|
+
|
|
230
|
+
<div class="chat-panel">
|
|
231
|
+
<input type="text" id="chat-input" class="chat-input" placeholder="► Enter command..." />
|
|
232
|
+
<button class="chat-send" onclick="sendCommand()">⚡ EXECUTE</button>
|
|
233
|
+
</div>
|
|
234
|
+
</div>
|
|
235
|
+
|
|
236
|
+
<div class="panel">
|
|
237
|
+
<h2>◉ SYSTEM METRICS</h2>
|
|
238
|
+
<div class="metrics">
|
|
239
|
+
<div class="metric">
|
|
240
|
+
<div class="metric-label">⚡ QUALITY INDEX</div>
|
|
241
|
+
<div class="metric-bar">
|
|
242
|
+
<div class="metric-fill" id="quality-bar" style="width: 50%">50%</div>
|
|
243
|
+
</div>
|
|
244
|
+
</div>
|
|
245
|
+
<div class="metric">
|
|
246
|
+
<div class="metric-label">📍 SCENE PROGRESSION</div>
|
|
247
|
+
<div class="metric-bar">
|
|
248
|
+
<div class="metric-fill" id="scene-bar" style="width: 10%"><span id="scene-count">0</span></div>
|
|
249
|
+
</div>
|
|
250
|
+
</div>
|
|
251
|
+
<div class="metric">
|
|
252
|
+
<div class="metric-label">💫 ENGAGEMENT FLOW</div>
|
|
253
|
+
<div class="metric-bar">
|
|
254
|
+
<div class="metric-fill" id="engagement-bar" style="width: 50%">50%</div>
|
|
255
|
+
</div>
|
|
256
|
+
</div>
|
|
257
|
+
</div>
|
|
258
|
+
|
|
259
|
+
<h2 style="margin-top: 30px;">◉ ACTION VECTORS</h2>
|
|
260
|
+
<div class="choices" id="choices"></div>
|
|
261
|
+
</div>
|
|
262
|
+
</div>
|
|
263
|
+
</div>
|
|
264
|
+
|
|
265
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
|
|
266
|
+
<script>
|
|
267
|
+
// Three.js setup
|
|
268
|
+
let scene, camera, renderer;
|
|
269
|
+
let particleSystem, galaxySystem;
|
|
270
|
+
let time = 0;
|
|
271
|
+
|
|
272
|
+
function initThreeJS() {
|
|
273
|
+
scene = new THREE.Scene();
|
|
274
|
+
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
|
|
275
|
+
camera.position.z = 30;
|
|
276
|
+
|
|
277
|
+
renderer = new THREE.WebGLRenderer({
|
|
278
|
+
canvas: document.getElementById('three-canvas'),
|
|
279
|
+
antialias: true,
|
|
280
|
+
alpha: true
|
|
281
|
+
});
|
|
282
|
+
renderer.setSize(window.innerWidth, window.innerHeight);
|
|
283
|
+
renderer.setClearColor(0x000000, 1);
|
|
284
|
+
|
|
285
|
+
// Create main particle system with custom shader
|
|
286
|
+
createParticleSystem();
|
|
287
|
+
|
|
288
|
+
// Create rotating galaxy
|
|
289
|
+
createGalaxy();
|
|
290
|
+
|
|
291
|
+
// Animation loop
|
|
292
|
+
animate();
|
|
293
|
+
|
|
294
|
+
window.addEventListener('resize', onWindowResize);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
function createParticleSystem() {
|
|
298
|
+
const particleCount = 5000;
|
|
299
|
+
const geometry = new THREE.BufferGeometry();
|
|
300
|
+
const positions = new Float32Array(particleCount * 3);
|
|
301
|
+
const colors = new Float32Array(particleCount * 3);
|
|
302
|
+
const sizes = new Float32Array(particleCount);
|
|
303
|
+
|
|
304
|
+
for (let i = 0; i < particleCount; i++) {
|
|
305
|
+
positions[i * 3] = (Math.random() - 0.5) * 100;
|
|
306
|
+
positions[i * 3 + 1] = (Math.random() - 0.5) * 100;
|
|
307
|
+
positions[i * 3 + 2] = (Math.random() - 0.5) * 100;
|
|
308
|
+
|
|
309
|
+
const color = new THREE.Color();
|
|
310
|
+
color.setHSL(0.5 + Math.random() * 0.2, 1.0, 0.5 + Math.random() * 0.3);
|
|
311
|
+
colors[i * 3] = color.r;
|
|
312
|
+
colors[i * 3 + 1] = color.g;
|
|
313
|
+
colors[i * 3 + 2] = color.b;
|
|
314
|
+
|
|
315
|
+
sizes[i] = Math.random() * 3 + 1;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
|
|
319
|
+
geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3));
|
|
320
|
+
geometry.setAttribute('size', new THREE.BufferAttribute(sizes, 1));
|
|
321
|
+
|
|
322
|
+
const material = new THREE.ShaderMaterial({
|
|
323
|
+
uniforms: {
|
|
324
|
+
time: { value: 0 },
|
|
325
|
+
mood: { value: 0.5 },
|
|
326
|
+
quality: { value: 0.5 }
|
|
327
|
+
},
|
|
328
|
+
vertexShader: `
|
|
329
|
+
attribute float size;
|
|
330
|
+
varying vec3 vColor;
|
|
331
|
+
uniform float time;
|
|
332
|
+
uniform float mood;
|
|
333
|
+
uniform float quality;
|
|
334
|
+
|
|
335
|
+
void main() {
|
|
336
|
+
vColor = color;
|
|
337
|
+
vec3 pos = position;
|
|
338
|
+
|
|
339
|
+
// Swirling motion based on mood
|
|
340
|
+
float angle = time * 0.2 + length(pos.xy) * 0.02;
|
|
341
|
+
float radius = length(pos.xy);
|
|
342
|
+
pos.x += sin(angle + pos.z * 0.01) * mood * 5.0;
|
|
343
|
+
pos.y += cos(angle + pos.z * 0.01) * mood * 5.0;
|
|
344
|
+
pos.z += sin(time * 0.5 + radius * 0.05) * quality * 3.0;
|
|
345
|
+
|
|
346
|
+
vec4 mvPosition = modelViewMatrix * vec4(pos, 1.0);
|
|
347
|
+
gl_PointSize = size * (300.0 / -mvPosition.z) * (0.5 + mood + quality * 0.5);
|
|
348
|
+
gl_Position = projectionMatrix * mvPosition;
|
|
349
|
+
}
|
|
350
|
+
`,
|
|
351
|
+
fragmentShader: `
|
|
352
|
+
varying vec3 vColor;
|
|
353
|
+
uniform float mood;
|
|
354
|
+
uniform float quality;
|
|
355
|
+
|
|
356
|
+
void main() {
|
|
357
|
+
vec2 center = gl_PointCoord - vec2(0.5);
|
|
358
|
+
float dist = length(center);
|
|
359
|
+
|
|
360
|
+
if (dist > 0.5) discard;
|
|
361
|
+
|
|
362
|
+
float alpha = 1.0 - (dist * 2.0);
|
|
363
|
+
alpha = pow(alpha, 2.0);
|
|
364
|
+
alpha *= (0.4 + mood * 0.3 + quality * 0.3);
|
|
365
|
+
|
|
366
|
+
// Glow effect
|
|
367
|
+
vec3 glowColor = vColor * (1.0 + mood * 0.5);
|
|
368
|
+
|
|
369
|
+
gl_FragColor = vec4(glowColor, alpha);
|
|
370
|
+
}
|
|
371
|
+
`,
|
|
372
|
+
transparent: true,
|
|
373
|
+
vertexColors: true,
|
|
374
|
+
blending: THREE.AdditiveBlending,
|
|
375
|
+
depthTest: false
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
particleSystem = new THREE.Points(geometry, material);
|
|
379
|
+
scene.add(particleSystem);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
function createGalaxy() {
|
|
383
|
+
const galaxyCount = 3000;
|
|
384
|
+
const geometry = new THREE.BufferGeometry();
|
|
385
|
+
const positions = new Float32Array(galaxyCount * 3);
|
|
386
|
+
const colors = new Float32Array(galaxyCount * 3);
|
|
387
|
+
|
|
388
|
+
for (let i = 0; i < galaxyCount; i++) {
|
|
389
|
+
const radius = Math.random() * 50 + 10;
|
|
390
|
+
const spinAngle = radius * 0.3;
|
|
391
|
+
const branchAngle = (i % 3) * (Math.PI * 2 / 3);
|
|
392
|
+
|
|
393
|
+
positions[i * 3] = Math.cos(branchAngle + spinAngle) * radius;
|
|
394
|
+
positions[i * 3 + 1] = (Math.random() - 0.5) * 5;
|
|
395
|
+
positions[i * 3 + 2] = Math.sin(branchAngle + spinAngle) * radius;
|
|
396
|
+
|
|
397
|
+
const color = new THREE.Color();
|
|
398
|
+
color.setHSL(0.5 + Math.random() * 0.3, 0.8, 0.6);
|
|
399
|
+
colors[i * 3] = color.r;
|
|
400
|
+
colors[i * 3 + 1] = color.g;
|
|
401
|
+
colors[i * 3 + 2] = color.b;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
|
|
405
|
+
geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3));
|
|
406
|
+
|
|
407
|
+
const material = new THREE.PointsMaterial({
|
|
408
|
+
size: 2,
|
|
409
|
+
vertexColors: true,
|
|
410
|
+
transparent: true,
|
|
411
|
+
opacity: 0.6,
|
|
412
|
+
blending: THREE.AdditiveBlending
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
galaxySystem = new THREE.Points(geometry, material);
|
|
416
|
+
galaxySystem.position.z = -20;
|
|
417
|
+
scene.add(galaxySystem);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
function animate() {
|
|
421
|
+
requestAnimationFrame(animate);
|
|
422
|
+
time += 0.016;
|
|
423
|
+
|
|
424
|
+
// Apply screen shake to camera
|
|
425
|
+
applyShakeToCamera();
|
|
426
|
+
|
|
427
|
+
if (particleSystem) {
|
|
428
|
+
particleSystem.material.uniforms.time.value = time;
|
|
429
|
+
particleSystem.rotation.y += 0.0005;
|
|
430
|
+
particleSystem.rotation.x += 0.0002;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
if (galaxySystem) {
|
|
434
|
+
galaxySystem.rotation.y += 0.002;
|
|
435
|
+
galaxySystem.rotation.z += 0.001;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
renderer.render(scene, camera);
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
function onWindowResize() {
|
|
442
|
+
camera.aspect = window.innerWidth / window.innerHeight;
|
|
443
|
+
camera.updateProjectionMatrix();
|
|
444
|
+
renderer.setSize(window.innerWidth, window.innerHeight);
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
function updateParticleMood(quality, engagement) {
|
|
448
|
+
if (particleSystem) {
|
|
449
|
+
particleSystem.material.uniforms.mood.value = engagement;
|
|
450
|
+
particleSystem.material.uniforms.quality.value = quality;
|
|
451
|
+
|
|
452
|
+
// Update particle colors based on quality
|
|
453
|
+
const colors = particleSystem.geometry.attributes.color;
|
|
454
|
+
for (let i = 0; i < colors.count; i++) {
|
|
455
|
+
const color = new THREE.Color();
|
|
456
|
+
if (quality > 0.7) {
|
|
457
|
+
color.setHSL(0.3 + Math.random() * 0.15, 1.0, 0.5);
|
|
458
|
+
} else if (quality < 0.3) {
|
|
459
|
+
color.setHSL(0.0 + Math.random() * 0.1, 1.0, 0.5);
|
|
460
|
+
} else {
|
|
461
|
+
color.setHSL(0.5 + Math.random() * 0.2, 1.0, 0.5);
|
|
462
|
+
}
|
|
463
|
+
colors.array[i * 3] = color.r;
|
|
464
|
+
colors.array[i * 3 + 1] = color.g;
|
|
465
|
+
colors.array[i * 3 + 2] = color.b;
|
|
466
|
+
}
|
|
467
|
+
colors.needsUpdate = true;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// Game logic
|
|
472
|
+
let sessionId = null;
|
|
473
|
+
|
|
474
|
+
function startGame() {
|
|
475
|
+
console.log('Starting game...');
|
|
476
|
+
fetch('/api/start', { method: 'POST' })
|
|
477
|
+
.then(res => {
|
|
478
|
+
console.log('Got response:', res.status);
|
|
479
|
+
return res.json();
|
|
480
|
+
})
|
|
481
|
+
.then(data => {
|
|
482
|
+
console.log('Game data:', data);
|
|
483
|
+
sessionId = data.sessionId;
|
|
484
|
+
document.getElementById('start-screen').classList.add('hidden');
|
|
485
|
+
document.getElementById('game-screen').classList.remove('hidden');
|
|
486
|
+
displayGameState(data.state);
|
|
487
|
+
})
|
|
488
|
+
.catch(err => {
|
|
489
|
+
console.error('Error starting game:', err);
|
|
490
|
+
alert('Error starting game: ' + err.message);
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
function makeChoice(index) {
|
|
495
|
+
fetch('/api/choice', {
|
|
496
|
+
method: 'POST',
|
|
497
|
+
headers: { 'Content-Type': 'application/json' },
|
|
498
|
+
body: JSON.stringify({ sessionId, choiceIndex: index })
|
|
499
|
+
})
|
|
500
|
+
.then(res => res.json())
|
|
501
|
+
.then(data => displayGameState(data.state));
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
function sendCommand() {
|
|
505
|
+
const input = document.getElementById('chat-input');
|
|
506
|
+
const prompt = input.value.trim();
|
|
507
|
+
if (!prompt) return;
|
|
508
|
+
|
|
509
|
+
fetch('/api/prompt', {
|
|
510
|
+
method: 'POST',
|
|
511
|
+
headers: { 'Content-Type': 'application/json' },
|
|
512
|
+
body: JSON.stringify({ sessionId, prompt })
|
|
513
|
+
})
|
|
514
|
+
.then(res => res.json())
|
|
515
|
+
.then(data => {
|
|
516
|
+
displayGameState(data.state);
|
|
517
|
+
input.value = '';
|
|
518
|
+
});
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
// Screen shake and input effects
|
|
522
|
+
let shakeIntensity = 0;
|
|
523
|
+
let shakeDecay = 0.95;
|
|
524
|
+
|
|
525
|
+
function triggerShake(intensity = 0.5) {
|
|
526
|
+
shakeIntensity = intensity;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
function applyShakeToCamera() {
|
|
530
|
+
if (shakeIntensity > 0.01) {
|
|
531
|
+
camera.position.x += (Math.random() - 0.5) * shakeIntensity * 2;
|
|
532
|
+
camera.position.y += (Math.random() - 0.5) * shakeIntensity * 2;
|
|
533
|
+
camera.rotation.z += (Math.random() - 0.5) * shakeIntensity * 0.02;
|
|
534
|
+
shakeIntensity *= shakeDecay;
|
|
535
|
+
} else {
|
|
536
|
+
// Reset to original position smoothly
|
|
537
|
+
camera.position.x *= 0.9;
|
|
538
|
+
camera.position.y *= 0.9;
|
|
539
|
+
camera.rotation.z *= 0.9;
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
544
|
+
const chatInput = document.getElementById('chat-input');
|
|
545
|
+
|
|
546
|
+
// Vibrate and shake on keypress
|
|
547
|
+
chatInput.addEventListener('keydown', (e) => {
|
|
548
|
+
if (e.key === 'Enter') {
|
|
549
|
+
sendCommand();
|
|
550
|
+
return;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
// Trigger screen shake
|
|
554
|
+
triggerShake(0.3);
|
|
555
|
+
|
|
556
|
+
// Particle burst effect
|
|
557
|
+
if (particleSystem) {
|
|
558
|
+
particleSystem.material.uniforms.mood.value = Math.min(1.0, particleSystem.material.uniforms.mood.value + 0.1);
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
// Input vibration effect
|
|
562
|
+
chatInput.style.transform = 'scale(1.02)';
|
|
563
|
+
setTimeout(() => {
|
|
564
|
+
chatInput.style.transform = 'scale(1)';
|
|
565
|
+
}, 100);
|
|
566
|
+
|
|
567
|
+
// Visual flash
|
|
568
|
+
chatInput.style.borderColor = 'rgba(0, 255, 255, 1)';
|
|
569
|
+
chatInput.style.boxShadow = '0 0 30px rgba(0, 255, 255, 0.8)';
|
|
570
|
+
setTimeout(() => {
|
|
571
|
+
chatInput.style.borderColor = 'rgba(0, 255, 255, 0.4)';
|
|
572
|
+
chatInput.style.boxShadow = '0 0 20px rgba(0, 255, 255, 0.4)';
|
|
573
|
+
}, 150);
|
|
574
|
+
});
|
|
575
|
+
|
|
576
|
+
chatInput.addEventListener('keypress', (e) => {
|
|
577
|
+
if (e.key === 'Enter') sendCommand();
|
|
578
|
+
});
|
|
579
|
+
});
|
|
580
|
+
|
|
581
|
+
function displayGameState(state) {
|
|
582
|
+
document.getElementById('story-text').textContent = state.text;
|
|
583
|
+
|
|
584
|
+
const choicesEl = document.getElementById('choices');
|
|
585
|
+
choicesEl.innerHTML = '';
|
|
586
|
+
|
|
587
|
+
if (state.choices && state.choices.length > 0) {
|
|
588
|
+
state.choices.forEach((choice, index) => {
|
|
589
|
+
const btn = document.createElement('button');
|
|
590
|
+
btn.className = 'choice-btn';
|
|
591
|
+
btn.textContent = '▸ ' + choice.text;
|
|
592
|
+
btn.onclick = () => makeChoice(index);
|
|
593
|
+
choicesEl.appendChild(btn);
|
|
594
|
+
});
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
if (state.quality !== undefined) {
|
|
598
|
+
const qualityPct = Math.round(state.quality * 100);
|
|
599
|
+
const engagementPct = Math.round((state.engagement || 0.5) * 100);
|
|
600
|
+
const sceneCount = state.sceneCount || 0;
|
|
601
|
+
|
|
602
|
+
document.getElementById('quality-bar').style.width = qualityPct + '%';
|
|
603
|
+
document.getElementById('quality-bar').textContent = qualityPct + '%';
|
|
604
|
+
|
|
605
|
+
document.getElementById('engagement-bar').style.width = engagementPct + '%';
|
|
606
|
+
document.getElementById('engagement-bar').textContent = engagementPct + '%';
|
|
607
|
+
|
|
608
|
+
document.getElementById('scene-count').textContent = sceneCount;
|
|
609
|
+
document.getElementById('scene-bar').style.width = Math.min(sceneCount * 10, 100) + '%';
|
|
610
|
+
|
|
611
|
+
// Update Three.js particles
|
|
612
|
+
updateParticleMood(state.quality, state.engagement || 0.5);
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
// Initialize Three.js on load
|
|
617
|
+
initThreeJS();
|
|
618
|
+
</script>
|
|
619
|
+
</body>
|
|
620
|
+
</html>
|