From 3ae3a4861bcb0b0fae2c1f41312de51ba8152cc3 Mon Sep 17 00:00:00 2001 From: Alexander Whitestone Date: Wed, 25 Mar 2026 14:06:38 -0400 Subject: [PATCH] feat: Implement ArchonAssembler with primitive shapes (Refs #530) --- app.js | 19 ++++ archon_assembler.js | 213 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 232 insertions(+) create mode 100644 archon_assembler.js diff --git a/app.js b/app.js index 4334d49..080d628 100644 --- a/app.js +++ b/app.js @@ -3,6 +3,7 @@ import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js'; import { RenderPass } from 'three/addons/postprocessing/RenderPass.js'; import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js'; import { SMAAPass } from 'three/addons/postprocessing/SMAAPass.js'; +import { ArchonAssembler } from './archon_assembler.js'; // ═══════════════════════════════════════════ // NEXUS v2.0 — WebSocket Bridge to Timmy @@ -47,6 +48,7 @@ let frameCount = 0, lastFPSTime = 0, fps = 0; let chatOpen = true; let loadProgress = 0; let performanceTier = 'high'; +let archonAssembler; // ═══ COMMIT HEATMAP ═══ let heatmapMesh = null, heatmapMat = null, heatmapTexture = null; @@ -210,6 +212,23 @@ async function init() { createDualBrainPanel(); updateLoad(90); + // Test Archon Assembler + const testManifest = { + head: true, + torso: true, + arms: true, + legs: true, + hands: true, + eyes: true, + mouth: true, + wings: true, + aura: true, + crown: true, + }; + archonAssembler = new ArchonAssembler(scene, testManifest); + archonAssembler.assemble(); + archonAssembler.spawn(new THREE.Vector3(0, 0, -15)); + composer = new EffectComposer(renderer); composer.addPass(new RenderPass(scene, camera)); composer.addPass(new UnrealBloomPass(new THREE.Vector2(window.innerWidth, window.innerHeight), 0.6, 0.4, 0.85)); diff --git a/archon_assembler.js b/archon_assembler.js new file mode 100644 index 0000000..efad4fb --- /dev/null +++ b/archon_assembler.js @@ -0,0 +1,213 @@ +import * as THREE from 'three'; +import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js'; +import { RenderPass } from 'three/addons/postprocessing/RenderPass.js'; +import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js'; +import { SMAAPass } from 'three/addons/postprocessing/SMAAPass.js'; + +// Assuming NEXUS colors are available or passed in +const NEXUS = { + colors: { + primary: 0x4af0c0, + secondary: 0x7b5cff, + bg: 0x050510, + panelBg: 0x0a0f28, + nebula1: 0x1a0a3e, + nebula2: 0x0a1a3e, + gold: 0xffd700, + danger: 0xff4466, + gridLine: 0x1a2a4a, + } + }; + +class ArchonAssembler { + constructor(scene, manifest) { + this.scene = scene; + this.manifest = manifest; + this.avatarGroup = new THREE.Group(); + this.scene.add(this.avatarGroup); + this.parts = {}; // To store references to individual parts + } + + _createMaterial(color) { + // Use a material consistent with the wireframe_glow aesthetic + // This will likely be a basic material or shader material that interacts with UnrealBloomPass + return new THREE.MeshBasicMaterial({ + color: color, + wireframe: true, + transparent: true, + opacity: 0.8, + // These properties might be needed if not handled by post-processing + // blending: THREE.AdditiveBlending, + // emissive: color, + // emissiveIntensity: 1.5, + }); + } + + assemble() { + // Clear existing parts if any + while(this.avatarGroup.children.length > 0){ + this.avatarGroup.remove(this.avatarGroup.children[0]); + } + this.parts = {}; + + // Head (SphereGeometry) + if (this.manifest.head) { + const headGeometry = new THREE.SphereGeometry(0.5, 32, 32); + const headMaterial = this._createMaterial(NEXUS.colors.primary); + const head = new THREE.Mesh(headGeometry, headMaterial); + head.position.y = 2; // Example position + this.avatarGroup.add(head); + this.parts.head = head; + } + + // Torso (BoxGeometry) + if (this.manifest.torso) { + const torsoGeometry = new THREE.BoxGeometry(1, 1.5, 0.75); + const torsoMaterial = this._createMaterial(NEXUS.colors.secondary); + const torso = new THREE.Mesh(torsoGeometry, torsoMaterial); + torso.position.y = 1; // Example position + this.avatarGroup.add(torso); + this.parts.torso = torso; + } + + // Arms (CylinderGeometry) - simple example, will need left/right + if (this.manifest.arms) { + const armGeometry = new THREE.CylinderGeometry(0.15, 0.15, 1, 16); + const armMaterial = this._createMaterial(NEXUS.colors.gold); + + const armLeft = new THREE.Mesh(armGeometry, armMaterial); + armLeft.position.set(-0.6, 1.5, 0); // Left arm + armLeft.rotation.z = Math.PI / 2; // Horizontal + this.avatarGroup.add(armLeft); + this.parts.armLeft = armLeft; + + const armRight = new THREE.Mesh(armGeometry, armMaterial); + armRight.position.set(0.6, 1.5, 0); // Right arm + armRight.rotation.z = -Math.PI / 2; // Horizontal + this.avatarGroup.add(armRight); + this.parts.armRight = armRight; + } + + // Legs (CylinderGeometry) - simple example, will need left/right + if (this.manifest.legs) { + const legGeometry = new THREE.CylinderGeometry(0.2, 0.2, 1.2, 16); + const legMaterial = this._createMaterial(NEXUS.colors.nebula1); + + const legLeft = new THREE.Mesh(legGeometry, legMaterial); + legLeft.position.set(-0.3, 0.5, 0); // Left leg + this.avatarGroup.add(legLeft); + this.parts.legLeft = legLeft; + + const legRight = new THREE.Mesh(legGeometry, legMaterial); + legRight.position.set(0.3, 0.5, 0); // Right leg + this.avatarGroup.add(legRight); + this.parts.legRight = legRight; + } + + // Hands/Fingers (small SphereGeometry clusters) - Placeholder + if (this.manifest.hands) { + const handGeometry = new THREE.SphereGeometry(0.2, 16, 16); + const handMaterial = this._createMaterial(NEXUS.colors.gold); + + const handLeft = new THREE.Mesh(handGeometry, handMaterial); + handLeft.position.set(-1.1, 1.5, 0); + this.avatarGroup.add(handLeft); + this.parts.handLeft = handLeft; + + const handRight = new THREE.Mesh(handGeometry, handMaterial); + handRight.position.set(1.1, 1.5, 0); + this.avatarGroup.add(handRight); + this.parts.handRight = handRight; + } + + // Eyes (emissive small spheres on head) - Placeholder + if (this.manifest.eyes) { + const eyeGeometry = new THREE.SphereGeometry(0.08, 16, 16); + const eyeMaterial = new THREE.MeshBasicMaterial({ color: 0xffffff, emissive: 0xffffff, emissiveIntensity: 2 }); // Emissive for glow + const eyeLeft = new THREE.Mesh(eyeGeometry, eyeMaterial); + eyeLeft.position.set(-0.2, 2.1, 0.45); // Adjust position relative to head + this.avatarGroup.add(eyeLeft); + this.parts.eyeLeft = eyeLeft; + + const eyeRight = new THREE.Mesh(eyeGeometry, eyeMaterial); + eyeRight.position.set(0.2, 2.1, 0.45); // Adjust position relative to head + this.avatarGroup.add(eyeRight); + this.parts.eyeRight = eyeRight; + } + + // Mouth (torus segment on head) - Placeholder + if (this.manifest.mouth) { + const mouthGeometry = new THREE.TorusGeometry(0.15, 0.03, 8, 16, Math.PI); // Half torus + const mouthMaterial = this._createMaterial(NEXUS.colors.primary); + const mouth = new THREE.Mesh(mouthGeometry, mouthMaterial); + mouth.position.set(0, 1.8, 0.5); // Adjust position relative to head + mouth.rotation.x = Math.PI / 2; + this.avatarGroup.add(mouth); + this.parts.mouth = mouth; + } + + // Wings (PlaneGeometry with wireframe) - Placeholder + if (this.manifest.wings) { + const wingGeometry = new THREE.PlaneGeometry(2, 1.5); + const wingMaterial = this._createMaterial(NEXUS.colors.nebula2); + const wingLeft = new THREE.Mesh(wingGeometry, wingMaterial); + wingLeft.position.set(-1.2, 2, -0.2); + wingLeft.rotation.y = Math.PI / 2; + this.avatarGroup.add(wingLeft); + this.parts.wingLeft = wingLeft; + + const wingRight = new THREE.Mesh(wingGeometry, wingMaterial); + wingRight.position.set(1.2, 2, -0.2); + wingRight.rotation.y = -Math.PI / 2; + this.avatarGroup.add(wingRight); + this.parts.wingRight = wingRight; + } + + // Aura (transparent SphereGeometry around body) - Placeholder + if (this.manifest.aura) { + const auraGeometry = new THREE.SphereGeometry(2, 32, 32); + const auraMaterial = new THREE.MeshBasicMaterial({ + color: NEXUS.colors.primary, + transparent: true, + opacity: 0.1, + side: THREE.BackSide, // Render inside out + blending: THREE.AdditiveBlending, + }); + const aura = new THREE.Mesh(auraGeometry, auraMaterial); + aura.position.y = 1.5; + this.avatarGroup.add(aura); + this.parts.aura = aura; + } + + // Crown (TorusGeometry above head) - Placeholder + if (this.manifest.crown) { + const crownGeometry = new THREE.TorusGeometry(0.6, 0.05, 8, 32); + const crownMaterial = this._createMaterial(NEXUS.colors.gold); + const crown = new THREE.Mesh(crownGeometry, crownMaterial); + crown.position.y = 2.6; + this.avatarGroup.add(crown); + this.parts.crown = crown; + } + } + + spawn(position) { + this.avatarGroup.position.copy(position); + this.avatarGroup.visible = true; // Make the group visible + // TODO: Implement materialization animation + console.log("Archon spawned at", position); + } + + remove() { + this.avatarGroup.visible = false; // Hide the group + // TODO: Implement de-materialization animation + console.log("Archon removed"); + } + + updateManifest(newManifest) { + this.manifest = newManifest; + this.assemble(); // Re-assemble with new parts + console.log("Archon manifest updated"); + } +} + +export { ArchonAssembler }; -- 2.43.0