@vib3code/sdk 2.0.3-canary.45332e3 → 2.0.3-canary.4874bcf

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/DOCS/AGENT_HARNESS_ARCHITECTURE.md +2 -0
  2. package/DOCS/ANDROID_DEPLOYMENT.md +59 -0
  3. package/DOCS/ARCHITECTURE.md +1 -0
  4. package/DOCS/CI_TESTING.md +2 -0
  5. package/DOCS/CLI_ONBOARDING.md +2 -0
  6. package/DOCS/CONTROL_REFERENCE.md +2 -0
  7. package/DOCS/CROSS_SITE_DESIGN_PATTERNS.md +2 -0
  8. package/DOCS/ENV_SETUP.md +2 -0
  9. package/DOCS/EPIC_SCROLL_EVENTS.md +2 -0
  10. package/DOCS/EXPANSION_DESIGN.md +979 -0
  11. package/DOCS/EXPANSION_DESIGN_ULTRA.md +389 -0
  12. package/DOCS/EXPORT_FORMATS.md +2 -0
  13. package/DOCS/GPU_DISPOSAL_GUIDE.md +2 -0
  14. package/DOCS/HANDOFF_LANDING_PAGE.md +2 -0
  15. package/DOCS/HANDOFF_SDK_DEVELOPMENT.md +2 -0
  16. package/DOCS/LICENSING_TIERS.md +2 -0
  17. package/DOCS/MASTER_PLAN_2026-01-31.md +2 -0
  18. package/DOCS/MULTIVIZ_CHOREOGRAPHY_PATTERNS.md +3 -1
  19. package/DOCS/OBS_SETUP_GUIDE.md +2 -0
  20. package/DOCS/OPTIMIZATION_PLAN_MATH.md +119 -0
  21. package/DOCS/PRODUCT_STRATEGY.md +2 -0
  22. package/DOCS/PROJECT_SETUP.md +2 -0
  23. package/DOCS/README.md +5 -3
  24. package/DOCS/REFERENCE_SCROLL_ANALYSIS.md +2 -0
  25. package/DOCS/RENDERER_LIFECYCLE.md +2 -0
  26. package/DOCS/REPO_MANIFEST.md +2 -0
  27. package/DOCS/ROADMAP.md +2 -0
  28. package/DOCS/SCROLL_TIMELINE_v3.md +2 -0
  29. package/DOCS/SITE_REFACTOR_PLAN.md +2 -0
  30. package/DOCS/STATUS.md +2 -0
  31. package/DOCS/SYSTEM_INVENTORY.md +2 -0
  32. package/DOCS/TELEMETRY_EXPORTS.md +2 -0
  33. package/DOCS/VISUAL_ANALYSIS_CLICKERSS.md +2 -0
  34. package/DOCS/VISUAL_ANALYSIS_FACETAD.md +2 -0
  35. package/DOCS/VISUAL_ANALYSIS_SIMONE.md +2 -0
  36. package/DOCS/VISUAL_ANALYSIS_TABLESIDE.md +2 -0
  37. package/DOCS/WEBGPU_STATUS.md +2 -0
  38. package/DOCS/XR_BENCHMARKS.md +2 -0
  39. package/DOCS/archive/BLUEPRINT_EXECUTION_PLAN_2026-01-07.md +1 -34
  40. package/DOCS/archive/DEV_TRACK_ANALYSIS.md +1 -80
  41. package/DOCS/archive/DEV_TRACK_PLAN_2026-01-07.md +1 -42
  42. package/DOCS/archive/SESSION_014_PLAN.md +1 -195
  43. package/DOCS/archive/SESSION_LOG_2026-01-07.md +1 -56
  44. package/DOCS/archive/STRATEGIC_BLUEPRINT_2026-01-07.md +1 -72
  45. package/DOCS/archive/SYSTEM_AUDIT_2026-01-30.md +1 -741
  46. package/DOCS/archive/WEBGPU_STATUS_2026-02-15_STALE.md +1 -38
  47. package/DOCS/dev-tracks/DEV_TRACK_SESSION_2026-01-31.md +2 -0
  48. package/DOCS/dev-tracks/DEV_TRACK_SESSION_2026-02-06.md +2 -0
  49. package/DOCS/dev-tracks/DEV_TRACK_SESSION_2026-02-13.md +2 -0
  50. package/DOCS/dev-tracks/DEV_TRACK_SESSION_2026-02-15.md +2 -0
  51. package/DOCS/dev-tracks/DEV_TRACK_SESSION_2026-02-16.md +2 -0
  52. package/DOCS/dev-tracks/PERF_UPGRADE_2026-02-16.md +310 -0
  53. package/DOCS/dev-tracks/README.md +2 -0
  54. package/package.json +2 -4
  55. package/src/cli/index.js +59 -5
  56. package/src/experimental/GameLoop.js +72 -0
  57. package/src/experimental/LatticePhysics.js +100 -0
  58. package/src/experimental/LiveDirector.js +143 -0
  59. package/src/experimental/PlayerController4D.js +154 -0
  60. package/src/experimental/VIB3Actor.js +138 -0
  61. package/src/experimental/VIB3Compositor.js +117 -0
  62. package/src/experimental/VIB3Link.js +122 -0
  63. package/src/experimental/VIB3Orchestrator.js +146 -0
  64. package/src/experimental/VIB3Universe.js +109 -0
  65. package/src/experimental/demos/CrystalLabyrinth.js +202 -0
  66. package/src/export/SVGExporter.js +9 -5
  67. package/src/features/CollectionManager.js +27 -9
  68. package/src/gallery/CollectionManager.js +27 -9
  69. package/src/geometry/generators/Crystal.js +2 -2
  70. package/src/geometry/warp/HypersphereCore.js +53 -24
  71. package/src/math/Mat4x4.js +418 -142
  72. package/src/math/Projection.js +57 -7
  73. package/src/math/Rotor4D.js +102 -73
  74. package/src/math/Vec4.js +265 -111
  75. package/src/quantum/QuantumVisualizer.js +28 -0
  76. package/src/scene/Node4D.js +74 -24
  77. package/src/testing/ProjectionClass.test.js +38 -0
  78. package/src/variations/VariationManager.js +6 -1
  79. package/src/wasm/WasmLoader.js +11 -6
  80. package/tools/update_projection.py +109 -0
@@ -0,0 +1,122 @@
1
+ /**
2
+ * VIB3Link - Multi-User Synchronization
3
+ *
4
+ * Provides a networking layer (mocked for now) to sync VIB3Universe state
5
+ * between multiple clients. Handles entity updates, parameter deltas, and events.
6
+ *
7
+ * @experimental
8
+ */
9
+ export class VIB3Link {
10
+ constructor() {
11
+ this.connected = false;
12
+ this.roomId = null;
13
+ this.isHost = false;
14
+ this.peers = new Set();
15
+ this.eventBus = new EventTarget();
16
+
17
+ // Bind methods
18
+ this.handleMessage = this.handleMessage.bind(this);
19
+ }
20
+
21
+ /**
22
+ * Connect to a shared room.
23
+ * @param {string} roomId
24
+ */
25
+ async connect(roomId) {
26
+ this.roomId = roomId;
27
+ this.connected = true;
28
+
29
+ // Mock connection logic
30
+ console.log(`VIB3Link: Connected to room ${roomId}`);
31
+
32
+ // In a real implementation, we would establish WebRTC/WebSocket here
33
+ // and negotiate host status. For now, assume single-player or host.
34
+ this.isHost = true;
35
+
36
+ this.emit('connected', { roomId, isHost: this.isHost });
37
+ }
38
+
39
+ /**
40
+ * Disconnect from the room.
41
+ */
42
+ disconnect() {
43
+ this.connected = false;
44
+ this.peers.clear();
45
+ console.log(`VIB3Link: Disconnected.`);
46
+ this.emit('disconnected', {});
47
+ }
48
+
49
+ /**
50
+ * Broadcast an event to all peers.
51
+ * @param {string} type - Message type (upd, prm, evt)
52
+ * @param {object} payload
53
+ */
54
+ broadcast(type, payload) {
55
+ if (!this.connected) return;
56
+
57
+ const message = {
58
+ t: type,
59
+ s: Date.now(), // simple sequence
60
+ p: payload
61
+ };
62
+
63
+ // In real impl: webrtcChannel.send(JSON.stringify(message));
64
+
65
+ // Mock loopback for local testing (optional)
66
+ // this.handleMessage(message);
67
+ }
68
+
69
+ /**
70
+ * Handle an incoming message from the network.
71
+ * @param {object} message
72
+ */
73
+ handleMessage(message) {
74
+ const { t, p } = message;
75
+
76
+ switch (t) {
77
+ case 'upd':
78
+ this.emit('entityUpdate', p);
79
+ break;
80
+ case 'prm':
81
+ this.emit('parameterDelta', p);
82
+ break;
83
+ case 'evt':
84
+ this.emit('universeEvent', p);
85
+ break;
86
+ default:
87
+ console.warn(`VIB3Link: Unknown message type ${t}`);
88
+ }
89
+ }
90
+
91
+ /**
92
+ * Sync the state of all entities. Called by Orchestrator tick.
93
+ * @param {Map<string, object>} entities
94
+ */
95
+ sync(entities) {
96
+ if (!this.connected || !this.isHost) return;
97
+
98
+ // Collect dirty state
99
+ // In a real optimized system, we'd diff state or only send moved entities
100
+ // For now, let's just log that we would sync
101
+ // console.log(`VIB3Link: Syncing ${entities.size} entities`);
102
+ }
103
+
104
+ /**
105
+ * Emit a local event for system consumption.
106
+ * @param {string} name
107
+ * @param {object} detail
108
+ */
109
+ emit(name, detail) {
110
+ const event = new CustomEvent(name, { detail });
111
+ this.eventBus.dispatchEvent(event);
112
+ }
113
+
114
+ /**
115
+ * Listen for network events.
116
+ * @param {string} name
117
+ * @param {function} callback
118
+ */
119
+ on(name, callback) {
120
+ this.eventBus.addEventListener(name, (e) => callback(e.detail));
121
+ }
122
+ }
@@ -0,0 +1,146 @@
1
+ /**
2
+ * VIB3Orchestrator - The Core of the VIB3 Universe
3
+ *
4
+ * Manages the lifecycle and coordination of multiple VIB3+ entities (visualizers).
5
+ * Implements the "Universe" concept where multiple instances share a clock,
6
+ * physics, and event bus.
7
+ *
8
+ * @experimental
9
+ */
10
+ export class VIB3Orchestrator {
11
+ constructor() {
12
+ this.entities = new Map(); // id -> Entity
13
+ this.nextEntityId = 1;
14
+
15
+ // Master Clock
16
+ this.time = 0;
17
+ this.lastFrameTime = 0;
18
+ this.paused = false;
19
+
20
+ // Systems
21
+ this.eventBus = new EventTarget();
22
+
23
+ // Bind loop
24
+ this.tick = this.tick.bind(this);
25
+ }
26
+
27
+ /**
28
+ * Start the universe simulation loop.
29
+ */
30
+ start() {
31
+ if (this.running) return;
32
+ this.running = true;
33
+ this.lastFrameTime = performance.now();
34
+ requestAnimationFrame(this.tick);
35
+ console.log('VIB3Orchestrator: Universe started.');
36
+ }
37
+
38
+ /**
39
+ * Stop the universe simulation loop.
40
+ */
41
+ stop() {
42
+ this.running = false;
43
+ console.log('VIB3Orchestrator: Universe stopped.');
44
+ }
45
+
46
+ /**
47
+ * Spawn a new VIB3 entity.
48
+ * @param {string} type - 'actor', 'prop', 'environment'
49
+ * @param {object} config - Configuration for the entity
50
+ * @returns {string} Entity ID
51
+ */
52
+ spawn(type, config = {}) {
53
+ const id = `vib3_entity_${this.nextEntityId++}`;
54
+
55
+ // In a real implementation, this would instantiate VIB3Actor or VIB3Prop
56
+ // For now, we store a mock object representing the entity state
57
+ const entity = {
58
+ id,
59
+ type,
60
+ config,
61
+ position: config.position || { x: 0, y: 0, z: 0 },
62
+ rotation: config.rotation || { x: 0, y: 0, z: 0, w: 0 }, // 4D rotation
63
+ active: true,
64
+
65
+ // Mock VIB3Engine interface
66
+ engine: {
67
+ setParameter: (k, v) => console.log(`[${id}] set ${k}=${v}`),
68
+ getParameter: (k) => 0
69
+ },
70
+
71
+ update: (dt) => {
72
+ // Default update logic
73
+ // e.g., apply basic physics or script behavior
74
+ }
75
+ };
76
+
77
+ this.entities.set(id, entity);
78
+ this.emit('entitySpawned', { id, type });
79
+ console.log(`VIB3Orchestrator: Spawned ${type} (${id})`);
80
+
81
+ return id;
82
+ }
83
+
84
+ /**
85
+ * Remove an entity from the universe.
86
+ * @param {string} id
87
+ */
88
+ kill(id) {
89
+ if (this.entities.has(id)) {
90
+ const entity = this.entities.get(id);
91
+ // Cleanup logic (e.g., destroy VIB3Engine instance)
92
+ if (entity.destroy) entity.destroy();
93
+
94
+ this.entities.delete(id);
95
+ this.emit('entityDespawned', { id });
96
+ console.log(`VIB3Orchestrator: Killed entity ${id}`);
97
+ }
98
+ }
99
+
100
+ /**
101
+ * The main simulation loop.
102
+ * Prioritizes Physics -> Narrative -> Visuals.
103
+ * @param {number} timestamp
104
+ */
105
+ tick(timestamp) {
106
+ if (!this.running) return;
107
+
108
+ const dt = (timestamp - this.lastFrameTime) / 1000;
109
+ this.lastFrameTime = timestamp;
110
+ this.time += dt;
111
+
112
+ // 1. Physics / Logic Update
113
+ this.entities.forEach(entity => {
114
+ if (entity.active && entity.update) {
115
+ entity.update(this.time, dt);
116
+ }
117
+ });
118
+
119
+ // 2. Event Processing (Mock)
120
+ // Check for collisions, triggers, etc.
121
+
122
+ // 3. Visual Sync (Mock)
123
+ // Ensure all entities are rendering the current frame
124
+
125
+ requestAnimationFrame(this.tick);
126
+ }
127
+
128
+ /**
129
+ * Emit a global universe event.
130
+ * @param {string} name
131
+ * @param {object} detail
132
+ */
133
+ emit(name, detail) {
134
+ const event = new CustomEvent(name, { detail });
135
+ this.eventBus.dispatchEvent(event);
136
+ }
137
+
138
+ /**
139
+ * Listen for global universe events.
140
+ * @param {string} name
141
+ * @param {function} callback
142
+ */
143
+ on(name, callback) {
144
+ this.eventBus.addEventListener(name, (e) => callback(e.detail));
145
+ }
146
+ }
@@ -0,0 +1,109 @@
1
+ /**
2
+ * VIB3Universe - High-Level Entry Point for VIB3+ Ultra
3
+ *
4
+ * Combines Orchestrator (Logic) and Compositor (Visuals) into a single API.
5
+ * Manages the "World" where multiple VIB3+ instances coexist.
6
+ *
7
+ * @experimental
8
+ */
9
+ import { VIB3Orchestrator } from './VIB3Orchestrator.js';
10
+ import { VIB3Compositor } from './VIB3Compositor.js';
11
+ import { VIB3Actor } from './VIB3Actor.js';
12
+ import { VIB3Engine } from '../core/VIB3Engine.js';
13
+
14
+ export class VIB3Universe {
15
+ /**
16
+ * @param {string} containerId - DOM ID for the universe container
17
+ */
18
+ constructor(containerId = 'vib3-universe') {
19
+ this.orchestrator = new VIB3Orchestrator();
20
+ this.compositor = new VIB3Compositor(containerId);
21
+ this.actors = new Map(); // id -> VIB3Actor
22
+ }
23
+
24
+ /**
25
+ * Start the universe simulation.
26
+ */
27
+ start() {
28
+ this.orchestrator.start();
29
+ }
30
+
31
+ /**
32
+ * Stop the universe simulation.
33
+ */
34
+ stop() {
35
+ this.orchestrator.stop();
36
+ }
37
+
38
+ /**
39
+ * Spawn a new actor into the universe.
40
+ * @param {object} config
41
+ * @param {string} config.personality - Actor personality profile
42
+ * @param {string} config.system - Visualization system ('quantum', 'faceted', 'holographic')
43
+ * @param {number} config.geometry - Initial geometry index
44
+ * @param {object} config.layer - Layer options { zIndex, blendMode, opacity, position }
45
+ * @returns {Promise<VIB3Actor>} The spawned actor
46
+ */
47
+ async spawnActor(config = {}) {
48
+ const actorId = `actor_${Date.now()}_${Math.floor(Math.random() * 1000)}`;
49
+
50
+ // 1. Create a container for this actor's engine
51
+ const container = document.createElement('div');
52
+ container.id = `container_${actorId}`;
53
+ container.style.width = '100%';
54
+ container.style.height = '100%';
55
+ container.style.pointerEvents = 'none'; // Default to pass-through events
56
+
57
+ // 2. Add to compositor (visual layer)
58
+ this.compositor.addInstance(actorId, container, config.layer || {});
59
+
60
+ // 3. Initialize VIB3 Engine
61
+ const engine = new VIB3Engine({
62
+ system: config.system || 'holographic',
63
+ preferWebGPU: true // Ultra tier defaults to high perf
64
+ });
65
+
66
+ // Initialize engine within the container
67
+ // Note: VIB3Engine.initialize expects a container ID
68
+ await engine.initialize(container.id);
69
+
70
+ // Set initial state
71
+ if (config.geometry !== undefined) {
72
+ engine.setParameter('geometry', config.geometry);
73
+ }
74
+
75
+ // 4. Wrap in Actor (logic layer)
76
+ const actor = new VIB3Actor(engine, config.personality || 'neutral');
77
+ actor.id = actorId;
78
+
79
+ // 5. Register with Orchestrator (simulation loop)
80
+ this.orchestrator.entities.set(actorId, actor);
81
+ this.actors.set(actorId, actor);
82
+
83
+ console.log(`VIB3Universe: Spawned actor ${actorId}`);
84
+ return actor;
85
+ }
86
+
87
+ /**
88
+ * Remove an actor from the universe.
89
+ * @param {string} actorId
90
+ */
91
+ despawnActor(actorId) {
92
+ const actor = this.actors.get(actorId);
93
+ if (actor) {
94
+ // Remove from logic
95
+ this.orchestrator.kill(actorId);
96
+
97
+ // Cleanup engine
98
+ if (actor.engine && actor.engine.destroy) {
99
+ actor.engine.destroy();
100
+ }
101
+
102
+ // Remove from visuals
103
+ this.compositor.removeInstance(actorId);
104
+ this.actors.delete(actorId);
105
+
106
+ console.log(`VIB3Universe: Despawned actor ${actorId}`);
107
+ }
108
+ }
109
+ }
@@ -0,0 +1,202 @@
1
+ /**
2
+ * CrystalLabyrinth.js - Vertical Slice Demo
3
+ *
4
+ * Implements the full "Ultra" stack:
5
+ * - VIB3Universe (Multi-instance)
6
+ * - VIB3Orchestrator (Game Loop)
7
+ * - VIB3Compositor (Visuals)
8
+ * - LatticePhysics (4D Collision)
9
+ * - PlayerController4D (Input)
10
+ * - LiveDirector (AI Pacing)
11
+ *
12
+ * @experimental
13
+ */
14
+ import { VIB3Universe } from '../VIB3Universe.js';
15
+ import { GameLoop } from '../GameLoop.js';
16
+ import { LatticePhysics } from '../LatticePhysics.js';
17
+ import { PlayerController4D } from '../PlayerController4D.js';
18
+ import { LiveDirector } from '../LiveDirector.js';
19
+
20
+ class CrystalLabyrinthGame {
21
+ constructor() {
22
+ this.universe = new VIB3Universe('vib3-universe');
23
+ this.physics = new LatticePhysics();
24
+ this.director = new LiveDirector(this.universe);
25
+
26
+ // Game State
27
+ this.score = 0;
28
+ this.health = 100;
29
+ this.isPlaying = false;
30
+
31
+ // Entities
32
+ this.player = null; // The "Camera"
33
+ this.crystals = [];
34
+ this.shadows = [];
35
+
36
+ // UI
37
+ this.ui = {
38
+ score: document.getElementById('score'),
39
+ health: document.getElementById('health'),
40
+ overlay: document.getElementById('overlay'),
41
+ startBtn: document.getElementById('start-btn')
42
+ };
43
+
44
+ // Bind input
45
+ this.controller = new PlayerController4D(document.body, {
46
+ setParameter: (k, v) => this.updatePlayerView(k, v)
47
+ });
48
+
49
+ // Setup Loop
50
+ this.loop = new GameLoop(
51
+ (dt) => this.update(dt),
52
+ (alpha) => this.render(alpha)
53
+ );
54
+
55
+ this.init();
56
+ }
57
+
58
+ async init() {
59
+ // Create the "World" (Background Layer)
60
+ // A deep, slow-moving Holographic system representing the void
61
+ const world = await this.universe.spawnActor({
62
+ personality: 'neutral',
63
+ system: 'holographic',
64
+ geometry: 11, // Hypersphere
65
+ layer: { zIndex: 0, opacity: 0.4 }
66
+ });
67
+
68
+ // Setup UI listeners
69
+ this.ui.startBtn.addEventListener('click', () => this.start());
70
+ }
71
+
72
+ start() {
73
+ this.isPlaying = true;
74
+ this.ui.overlay.classList.add('hidden');
75
+
76
+ // Start Systems
77
+ this.universe.start();
78
+ this.loop.start();
79
+ this.director.start();
80
+
81
+ // Spawn Level
82
+ this.spawnLevel();
83
+ }
84
+
85
+ async spawnLevel() {
86
+ // Spawn 5 Crystals (Pickups)
87
+ for (let i = 0; i < 5; i++) {
88
+ const crystal = await this.universe.spawnActor({
89
+ personality: 'heroic', // Bright, positive
90
+ system: 'faceted',
91
+ geometry: 7, // Crystal
92
+ layer: { zIndex: 10, blendMode: 'screen', opacity: 0.9 }
93
+ });
94
+
95
+ // Random position in 4D space (mock)
96
+ crystal.physics = {
97
+ pos: {
98
+ x: (Math.random() - 0.5) * 20,
99
+ y: (Math.random() - 0.5) * 5,
100
+ z: (Math.random() - 0.5) * 20
101
+ },
102
+ vel: { x: 0, y: 0, z: 0 },
103
+ acc: { x: 0, y: 0, z: 0 }
104
+ };
105
+
106
+ this.crystals.push(crystal);
107
+ }
108
+
109
+ // Spawn 3 Shadows (Enemies)
110
+ for (let i = 0; i < 3; i++) {
111
+ const shadow = await this.universe.spawnActor({
112
+ personality: 'glitch', // Chaotic, negative
113
+ system: 'quantum',
114
+ geometry: 16, // Spiky
115
+ layer: { zIndex: 5, blendMode: 'multiply', opacity: 0.7 }
116
+ });
117
+
118
+ shadow.physics = {
119
+ pos: { x: 0, y: 0, z: -30 }, // Start far away
120
+ vel: { x: 0, y: 0, z: 0 },
121
+ acc: { x: 0, y: 0, z: 0 }
122
+ };
123
+
124
+ this.shadows.push(shadow);
125
+ }
126
+ }
127
+
128
+ /**
129
+ * Physics Update (Fixed Timestep)
130
+ */
131
+ update(dt) {
132
+ if (!this.isPlaying) return;
133
+
134
+ // 1. Update Player Controls
135
+ this.controller.update(dt);
136
+
137
+ // 2. Update Physics World
138
+ // Sync player controller state to physics engine?
139
+ // For now, controller handles movement directly.
140
+
141
+ // 3. AI Logic (Shadows hunt player)
142
+ this.shadows.forEach(shadow => {
143
+ // Move towards player (0,0,0 relative to camera)
144
+ // In a real engine, we'd have absolute coordinates.
145
+ // Here, we simulate relative motion by updating parameters
146
+
147
+ // Mock: Oscillate shadow intensity based on "proximity"
148
+ shadow.emote('panic', 0.5);
149
+ });
150
+
151
+ // 4. Check Collisions (Mock)
152
+ // If player is close to a crystal -> Collect
153
+ if (Math.random() < 0.005 && this.crystals.length > 0) {
154
+ this.collectCrystal(this.crystals.pop());
155
+ }
156
+ }
157
+
158
+ /**
159
+ * Render Update (Variable Timestep)
160
+ */
161
+ render(alpha) {
162
+ // Visual interpolation could happen here
163
+ }
164
+
165
+ updatePlayerView(key, value) {
166
+ // Broadcast player view changes to the World actor
167
+ // This makes the world rotate around the player
168
+ const world = this.universe.actors.get(this.universe.orchestrator.entities.keys().next().value);
169
+ if (world && world.engine) {
170
+ world.engine.setParameter(key, value);
171
+ }
172
+ }
173
+
174
+ collectCrystal(actor) {
175
+ this.score++;
176
+ this.ui.score.innerText = this.score;
177
+
178
+ // FX
179
+ actor.emote('joy', 1.0, 500);
180
+ setTimeout(() => {
181
+ this.universe.despawnActor(actor.id);
182
+ }, 500);
183
+
184
+ if (this.score >= 5) {
185
+ this.win();
186
+ }
187
+ }
188
+
189
+ win() {
190
+ this.isPlaying = false;
191
+ this.ui.overlay.innerHTML = `
192
+ <h1 style="color: #0f0; text-shadow: 0 0 20px #0f0;">SECTOR STABILIZED</h1>
193
+ <p>The lattice is secure.</p>
194
+ <button onclick="location.reload()">Re-enter</button>
195
+ `;
196
+ this.ui.overlay.classList.remove('hidden');
197
+ this.loop.stop();
198
+ }
199
+ }
200
+
201
+ // Start Game
202
+ new CrystalLabyrinthGame();
@@ -355,17 +355,21 @@ function projectPoints(points, rotor, dimension, width, height) {
355
355
  const centerY = height / 2;
356
356
  const scale = Math.min(width, height) * 0.4;
357
357
 
358
+ // Reuse vectors to minimize allocation
359
+ const rotatedBuffer = new Vec4();
360
+ const projectedBuffer = new Vec4();
361
+
358
362
  for (const point of points) {
359
363
  // Apply 4D rotation
360
- const rotated = rotor.rotate(point);
364
+ rotor.rotate(point, rotatedBuffer);
361
365
 
362
366
  // Project to 3D (perspective from W)
363
- const proj3d = rotated.projectPerspective(dimension);
367
+ rotatedBuffer.projectPerspective(dimension, projectedBuffer);
364
368
 
365
369
  // Project to 2D (simple orthographic for clean SVG)
366
- const x = centerX + proj3d.x * scale;
367
- const y = centerY - proj3d.y * scale; // Flip Y for SVG coordinates
368
- const depth = proj3d.z; // Keep depth for styling
370
+ const x = centerX + projectedBuffer.x * scale;
371
+ const y = centerY - projectedBuffer.y * scale; // Flip Y for SVG coordinates
372
+ const depth = projectedBuffer.z; // Keep depth for styling
369
373
 
370
374
  projected.push({ x, y, depth, original: point });
371
375
  }
@@ -415,19 +415,37 @@ export class CollectionManager {
415
415
  */
416
416
  getStatistics() {
417
417
  const collections = Array.from(this.collections.values());
418
- const stats = {
419
- totalCollections: collections.length,
420
- totalVariations: collections.reduce((sum, c) => sum + c.variations.length, 0),
421
- customCollections: collections.filter(c => c.name.includes('User') || c.name.includes('Custom')).length,
422
- baseCollections: collections.filter(c => c.name.includes('Base')).length,
423
- collections: collections.map(c => ({
418
+ let totalVariations = 0;
419
+ let customCollections = 0;
420
+ let baseCollections = 0;
421
+ const collectionList = new Array(collections.length);
422
+
423
+ for (let i = 0; i < collections.length; i++) {
424
+ const c = collections[i];
425
+ totalVariations += c.variations.length;
426
+
427
+ const name = c.name || '';
428
+ if (name.includes('User') || name.includes('Custom')) {
429
+ customCollections++;
430
+ }
431
+ if (name.includes('Base')) {
432
+ baseCollections++;
433
+ }
434
+
435
+ collectionList[i] = {
424
436
  name: c.name,
425
437
  filename: c.filename,
426
438
  variationCount: c.variations.length,
427
439
  created: c.created
428
- }))
440
+ };
441
+ }
442
+
443
+ return {
444
+ totalCollections: collections.length,
445
+ totalVariations,
446
+ customCollections,
447
+ baseCollections,
448
+ collections: collectionList
429
449
  };
430
-
431
- return stats;
432
450
  }
433
451
  }
@@ -222,19 +222,37 @@ export class CollectionManager {
222
222
  */
223
223
  getStatistics() {
224
224
  const collections = Array.from(this.collections.values());
225
- const stats = {
226
- totalCollections: collections.length,
227
- totalVariations: collections.reduce((sum, c) => sum + c.variations.length, 0),
228
- customCollections: collections.filter(c => c.name.includes('Custom')).length,
229
- baseCollections: collections.filter(c => c.name.includes('Base')).length,
230
- collections: collections.map(c => ({
225
+ let totalVariations = 0;
226
+ let customCollections = 0;
227
+ let baseCollections = 0;
228
+ const collectionList = new Array(collections.length);
229
+
230
+ for (let i = 0; i < collections.length; i++) {
231
+ const c = collections[i];
232
+ totalVariations += c.variations.length;
233
+
234
+ const name = c.name || '';
235
+ if (name.includes('Custom')) {
236
+ customCollections++;
237
+ }
238
+ if (name.includes('Base')) {
239
+ baseCollections++;
240
+ }
241
+
242
+ collectionList[i] = {
231
243
  name: c.name,
232
244
  filename: c.filename,
233
245
  variationCount: c.variations.length,
234
246
  created: c.created
235
- }))
247
+ };
248
+ }
249
+
250
+ return {
251
+ totalCollections: collections.length,
252
+ totalVariations,
253
+ customCollections,
254
+ baseCollections,
255
+ collections: collectionList
236
256
  };
237
-
238
- return stats;
239
257
  }
240
258
  }