55 SECONDARY = '#8BA6FF' ,
66 HIGHLIGHT = '#40C4FF' ,
77 NODE_COUNT = 150 ,
8- NODE_STRIDE = 8 , // x, y, vx, vy, radius, layer, parentId, phase
8+ NODE_STRIDE = 9 , // x, y, vx, vy, radius, layer, parentId, phase, energy
99 AGENT_COUNT = 20 ,
1010 AGENT_STRIDE = 6 , // x, y, vx, vy, targetIdx, state
1111 PACKET_COUNT = 20 ,
1818 * Uses a Zero-Allocation strategy (pre-allocated buffers) for high performance.
1919 *
2020 * **Node Buffer Layout (Float32Array):**
21- * [x, y, vx, vy, radius, layer, parentId, phase]
21+ * [x, y, vx, vy, radius, layer, parentId, phase, energy ]
2222 *
2323 * **Agent Buffer Layout (Float32Array):**
2424 * [x, y, vx, vy, targetIdx, state, ...]
@@ -274,14 +274,15 @@ class HomeCanvas extends Base {
274274 layer = buffer [ idx + 5 ] ,
275275 parentId = buffer [ idx + 6 ] ,
276276 phase = buffer [ idx + 7 ] ,
277+ energy = buffer [ idx + 8 ] ,
277278 pos = getPos ( idx , layer ) ;
278279
279280 let dx = pos . x - mx ,
280281 dy = pos . y - my ,
281282 dist = Math . sqrt ( dx * dx + dy * dy ) ,
282283 isHover = dist < 50 ;
283284
284- // Shockwave Interaction (Nodes Pulse)
285+ // Shockwave Interaction
285286 if ( me . shockwaves . length > 0 ) {
286287 me . shockwaves . forEach ( wave => {
287288 let wDist = Math . sqrt ( ( pos . x - wave . x ) ** 2 + ( pos . y - wave . y ) ** 2 ) ,
@@ -293,20 +294,23 @@ class HomeCanvas extends Base {
293294 ctx . beginPath ( ) ;
294295 let r = parentId === - 1 ? radius * 1.5 : radius ;
295296
296- // Breathing Effect
297- r *= 1 + Math . sin ( me . time * 2 + phase ) * 0.15 ;
297+ // Breathing + Energy
298+ r *= 1 + Math . sin ( me . time * 2 + phase ) * 0.15 + energy ;
298299
299300 if ( isHover ) r *= 1.5 ;
300301
301302 ctx . arc ( pos . x , pos . y , r , 0 , Math . PI * 2 ) ;
302303
303- if ( layer === 2 ) {
304+ if ( energy > 0.1 ) {
305+ // Energetic Node (Agent Scanned)
306+ ctx . fillStyle = HIGHLIGHT ;
307+ ctx . globalAlpha = Math . min ( 1 , 0.5 + energy ) ;
308+ } else if ( layer === 2 ) {
304309 ctx . fillStyle = isHover ? '#FFFFFF' : PRIMARY ;
305310 ctx . globalAlpha = isHover ? 1 : 0.8 ;
306311 } else if ( parentId === - 2 ) {
307312 // Drifting Node Visual
308313 ctx . fillStyle = HIGHLIGHT ;
309- // Phase-based pulse for drifters
310314 ctx . globalAlpha = 0.6 + Math . sin ( me . time * 10 + phase ) * 0.3 ;
311315 } else if ( layer === 1 ) {
312316 ctx . fillStyle = isHover ? HIGHLIGHT : SECONDARY ;
@@ -494,6 +498,9 @@ class HomeCanvas extends Base {
494498
495499 // Phase (Breathing offset)
496500 buffer [ idx + 7 ] = Math . random ( ) * Math . PI * 2 ;
501+
502+ // Energy
503+ buffer [ idx + 8 ] = 0 ;
497504 }
498505
499506 // 2. Assign Children to nearest Parent
@@ -720,14 +727,16 @@ class HomeCanvas extends Base {
720727 dist = Math . sqrt ( dx * dx + dy * dy ) ;
721728
722729 if ( dist < 10 ) {
723- agents [ idx + 5 ] = 1 ; // Scan
724- agents [ idx + 2 ] *= 0.1 ;
730+ // Arrived! Scan.
731+ agents [ idx + 5 ] = 1 ; // Scan state
732+ agents [ idx + 2 ] *= 0.1 ; // Slow down
725733 agents [ idx + 3 ] *= 0.1 ;
734+
735+ // Transfer Energy to Node
736+ nodes [ nIdx + 8 ] = 1.0 ;
726737 } else {
727- let force = 0.05 ;
728- agents [ idx + 2 ] += ( dx / dist ) * force ;
729- agents [ idx + 3 ] += ( dy / dist ) * force ;
730- }
738+ // Steer towards target
739+
731740 } else if ( state === 1 ) {
732741 if ( Math . random ( ) < 0.02 ) {
733742 agents [ idx + 4 ] = - 1 ;
@@ -871,6 +880,11 @@ class HomeCanvas extends Base {
871880 // 4. Physics
872881 buffer [ idx + 2 ] *= 0.95 ; // Friction
873882 buffer [ idx + 3 ] *= 0.95 ;
883+
884+ // Energy Decay
885+ buffer [ idx + 8 ] *= 0.99 ;
886+
887+ let drift = isParent ? 0.02 : 0.01 ;
874888
875889 // 4. Ambient Drift / Flow Field
876890 if ( isParent ) {
0 commit comments