@amg555/frameforge-mcp 2.4.8 → 2.4.9

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.
@@ -326,7 +326,7 @@ function detectComponentTheme({ visualDescription = '', visual_description = '',
326
326
  }
327
327
 
328
328
  // 7. Shame / Mirror / Reflection / Water / Self Awareness / Theory of Mind (Scene 3, 9)
329
- if (/(?:^|[^\w])(shame|blush|embarrass|mirror|reflection|water pool|theory of mind|how others see|self-aware|identity|looking at me|psychology|mind-shift)(?:[^\w]|$)/i.test(text)
329
+ if (/(?:^|[^\w])(shame|blush|embarrass|mirror|reflection|water pool|theory of mind|how others see|self-aware|identity|looking at me|shame psychology|mind-shift)(?:[^\w]|$)/i.test(text)
330
330
  || /കണ്ണാടി|പ്രതിഫലനം|മറ്റുള്ളവർ എന്നെ|തിയറി ഓഫ് മൈൻഡ്|സ്വന്തം ശരീരം മറച്ചു|വ്യക്തിത്വം|ശ്രദ്ധിക്കുന്നുണ്ട്|യഥാർത്ഥ രഹസ്യം|നാണം മറയ്ക്കാൻ/.test(text)) {
331
331
  return 'doodle_shame_reflection';
332
332
  }
@@ -392,7 +392,7 @@ function detectComponentTheme({ visualDescription = '', visual_description = '',
392
392
  }
393
393
 
394
394
  // High Velocity Speed Action
395
- if (/(?:^|[^\w])(sports|workout|gym|athlete|speed|streaks|race|championship|extreme|versus|vs|hype|adrenaline|power|velocity|fast)(?:[^\w]|$)/.test(text)
395
+ if (/(?:^|[^\w])(sports|workout|gym|athlete|speed|streaks|race|championship|extreme|hype|adrenaline|velocity|sprint|fast motion)(?:[^\w]|$)/.test(text)
396
396
  || /കായിക|മത്സര|വേഗത|വ്യായാമം|खेल|दौड़/.test(text)) {
397
397
  return 'speed_action';
398
398
  }
@@ -421,9 +421,9 @@ function detectComponentTheme({ visualDescription = '', visual_description = '',
421
421
  return 'chart';
422
422
  }
423
423
 
424
- // Neural Network Nodes
425
- if (/(?:^|[^\w])(network|node|nodes|ai|model|neural|pipeline|architecture|server|system|mesh|connect|synapse|deep learning)(?:[^\w]|$)/.test(text)
426
- || /നെറ്റ്‌വർക്ക്|സിനാപ്സ്|ശൃംഖല|नेटवर्क/.test(text)) {
424
+ // Neural Network Nodes / AI Topology
425
+ if (/(?:^|[^\w])(network|nodes|neural network|neural net|distributed system|server mesh|deep learning)(?:[^\w]|$)/.test(text)
426
+ || /നെറ്റ്‌വർക്ക്|ശൃംഖല|नेटवर्क/.test(text)) {
427
427
  return 'nodes';
428
428
  }
429
429
 
@@ -433,16 +433,59 @@ function detectComponentTheme({ visualDescription = '', visual_description = '',
433
433
  return 'isometric_geometry';
434
434
  }
435
435
 
436
- // Fallbacks matched to aesthetic
436
+ // ── Universal Semantic Visual Archetypes (General Content & Education) ──
437
+ // 1. Versus / Comparison / Split Screen
438
+ if (/(?:^|[^\w])(versus|vs|comparison|compare|pros and cons|pros vs cons|difference between|dichotomy|contrast|side-by-side|before and after|before vs after)(?:[^\w]|$)/i.test(text)
439
+ || /വ്യത്യാസം|താരതമ്യം|എതിര്|പോരാട്ടം|തമ്മിൽ|തുലനം|താരതമ്യപ്പെടുത്തൽ/.test(text)) {
440
+ return 'versus_comparison';
441
+ }
442
+
443
+ // 2. Mechanism / Physics / Machinery / Engine / Aerodynamics
444
+ if (/(?:^|[^\w])(engine|gear|gears|motor|physics|aerodynamics|thrust|turbine|propulsion|piston|hydraulic|kinetic|machine|machinery|circuit|mechanics|thermodynamics|levers|pulley|internal combustion|mechanical|cutaway|airflow|lift|rotor|dynamo)(?:[^\w]|$)/i.test(text)
445
+ || /യന്ത്രം|എഞ്ചിൻ|ഭൗതികശാസ്ത്രം|പ്രവർത്തനം|ചലനം|മെക്കാനിസം|ഭൗതികം/.test(text)) {
446
+ return 'mechanism_physics';
447
+ }
448
+
449
+ // 3. Process / Pipeline / Workflow / Stages / Assembly / Lifecycle
450
+ if (/(?:^|[^\w])(pipeline|workflow|step by step|steps|stages|phase|phases|production line|assembly|manufacturing|lifecycle|funnel|conveyor|sequence|how it works|how it is made|procedure)(?:[^\w]|$)/i.test(text)
451
+ || /ഘട്ടങ്ങൾ|പ്രക്രിയ|ഘട്ടം|ഉൽപ്പാദനം|വഴികൾ|പ്രവർത്തനരീതി/.test(text)) {
452
+ return 'process_pipeline';
453
+ }
454
+
455
+ // 4. Cognitive Insight / Psychology / Brain / Eureka / Revelation / Mind
456
+ if (/(?:^|[^\w])(mind|psychology|cognitive|brain|insight|revelation|eureka|intuition|subconscious|thinking|thought|contemplation|intelligence|mental|awareness|neuroscience|concept|idea|epiphany)(?:[^\w]|$)/i.test(text)
457
+ || /മനസ്സ്|ബുദ്ധി|ചിന്ത|മനഃശാസ്ത്രം|ജ്ഞാനം|മസ്തിഷ്കം|ബോധം/.test(text)) {
458
+ return 'cognitive_insight';
459
+ }
460
+
461
+ // 5. Magnification / Loupe / Macro Zoom / Scrutiny / Detailed Inspection
462
+ if (/(?:^|[^\w])(magnify|magnification|zoom|microscopic|macro|close up|closeup|inspection|loupe|examine|scrutiny|detail|focal point|focus in|specimen)(?:[^\w]|$)/i.test(text)
463
+ || /സൂക്ഷ്മ|പരിശോധന|വലുതാക്കി കാണുക|സൂക്ഷ്മമായി|നിരീക്ഷണം/.test(text)) {
464
+ return 'magnification_focus';
465
+ }
466
+
467
+ // 6. Explainer / Presentation / Tutorial / Masterclass Whiteboard / Breakdown
468
+ if (/(?:^|[^\w])(explain|explainer|presentation|lecture|teach|tutorial|whiteboard|blackboard|breakdown|guide|overview|theory|principles|fundamentals|introduction|summary|lesson|masterclass)(?:[^\w]|$)/i.test(text)
469
+ || /വിവരണം|പഠിപ്പിക്കുക|ക്ലാസ്|പാഠം|തത്വം|വിവരിക്കുക/.test(text)) {
470
+ return 'explainer_presentation';
471
+ }
472
+
473
+ // 7. Waveform / Audio / Sound / Acoustics / Equalizer
474
+ if (/(?:^|[^\w])(waveform|audio|sound|equalizer|frequency|acoustics|hz|decibel|music spectrum|voice waveform)(?:[^\w]|$)/i.test(text)
475
+ || /ശബ്ദതരംഗം|തരംഗം|സംഗീതം|ധ്വനി/.test(text)) {
476
+ return 'waveform';
477
+ }
478
+
479
+ // Fallbacks matched to aesthetic (rich semantic defaults, never sterile)
437
480
  if (aesthetic === 'cosmic_space') return 'celestial_orbit';
438
481
  if (aesthetic === 'cinematic_documentary') return 'doodle_general_human';
439
482
  if (aesthetic === 'finance_executive') return 'chart';
440
483
  if (aesthetic === 'nature_organic') return 'dna_helix';
441
484
  if (aesthetic === 'breaking_news') return 'radar_globe';
442
485
  if (aesthetic === 'cyber_tech') return 'nodes';
443
- if (aesthetic === 'minimal_luxury') return 'isometric_geometry';
486
+ if (aesthetic === 'minimal_luxury') return 'explainer_presentation';
444
487
  if (aesthetic === 'hype_sports') return 'speed_action';
445
- return 'waveform';
488
+ return 'explainer_presentation';
446
489
  }
447
490
 
448
491
  // ── Harness HTML Wrapper for User / Agent Code ────────────────────────────────
@@ -712,6 +755,8 @@ const IS_LIGHT = ${Boolean(pal.isLight)};
712
755
  const STROKE_COLOR = ${JSON.stringify(pal.isLight ? (pal.stroke || '#1c1917') : '#f8fafc')};
713
756
  const STROKE_ALT = ${JSON.stringify(pal.isLight ? (pal.strokeAlt || '#44403c') : 'rgba(255, 255, 255, 0.7)')};
714
757
  const AMBIENT_LINE = ${JSON.stringify(pal.isLight ? 'rgba(28, 25, 23, 0.22)' : 'rgba(255, 255, 255, 0.25)')};
758
+ const TEXT_MAIN = ${JSON.stringify(pal.isLight ? '#1c1917' : '#f8fafc')};
759
+ const TEXT_MUTED = ${JSON.stringify(pal.isLight ? '#78716c' : '#94a3b8')};
715
760
 
716
761
  let cachedImage = null;
717
762
  if (IMAGE_SRC) {
@@ -3313,7 +3358,679 @@ function drawMainScene(t) {
3313
3358
  ctx.drawImage(cachedImage, cx - imgW / 2, cy - imgH / 2, imgW, imgH);
3314
3359
  ctx.restore();
3315
3360
 
3316
- } else {
3361
+ } else if (COMP_THEME === 'versus_comparison') {
3362
+ // Universal Archetype: Split-Screen Versus / Comparison
3363
+ const splitSpring = spring(t, 0.05, 180, 14);
3364
+ const cardLeftSpring = spring(t, 0.15, 190, 15);
3365
+ const cardRightSpring = spring(t, 0.28, 190, 15);
3366
+ const badgeSpring = spring(t, 0.42, 220, 13);
3367
+
3368
+ // Center divider beam
3369
+ const divAlpha = Math.min(1, Math.max(0, splitSpring));
3370
+ ctx.save();
3371
+ ctx.globalAlpha = divAlpha;
3372
+ const seamGrad = ctx.createLinearGradient(0, cy - H * 0.42, 0, cy + H * 0.42);
3373
+ seamGrad.addColorStop(0, 'rgba(255,255,255,0)');
3374
+ seamGrad.addColorStop(0.5, ACCENT);
3375
+ seamGrad.addColorStop(1, 'rgba(255,255,255,0)');
3376
+ ctx.strokeStyle = seamGrad;
3377
+ ctx.lineWidth = 3;
3378
+ ctx.beginPath();
3379
+ ctx.moveTo(cx, cy - H * 0.42);
3380
+ ctx.lineTo(cx, cy + H * 0.42);
3381
+ ctx.stroke();
3382
+
3383
+ // Seam energy sparks
3384
+ for (let sp = 0; sp < 8; sp++) {
3385
+ const spY = cy - H * 0.35 + ((sp * 95 + t * 240) % (H * 0.7));
3386
+ const spR = 3 + Math.sin(t * 8 + sp) * 2;
3387
+ ctx.fillStyle = ACCENT;
3388
+ ctx.beginPath();
3389
+ ctx.arc(cx, spY, spR, 0, Math.PI * 2);
3390
+ ctx.fill();
3391
+ }
3392
+ ctx.restore();
3393
+
3394
+ // Left Card (Side A)
3395
+ const cardW = Math.min(W * 0.38, 520);
3396
+ const cardH = Math.min(H * 0.62, 540);
3397
+ const leftX = cx - cardW - 35;
3398
+ const cardY = cy - cardH / 2;
3399
+
3400
+ ctx.save();
3401
+ ctx.globalAlpha = Math.min(1, Math.max(0, cardLeftSpring));
3402
+ ctx.translate(leftX + (1 - cardLeftSpring) * -60, cardY);
3403
+ ctx.fillStyle = CARD_BG;
3404
+ ctx.strokeStyle = CARD_BORDER;
3405
+ ctx.lineWidth = 2;
3406
+ ctx.beginPath();
3407
+ ctx.roundRect(0, 0, cardW, cardH, 20);
3408
+ ctx.fill();
3409
+ ctx.stroke();
3410
+
3411
+ // Left Card Header & Accent Pill
3412
+ ctx.fillStyle = 'rgba(56, 189, 248, 0.15)';
3413
+ ctx.beginPath();
3414
+ ctx.roundRect(24, 24, 110, 32, 16);
3415
+ ctx.fill();
3416
+ ctx.fillStyle = '#38bdf8';
3417
+ ctx.font = 'bold 16px ' + FONT_DISPLAY;
3418
+ ctx.fillText('OPTION A', 42, 45);
3419
+
3420
+ // Left Metrics / Feature Bars
3421
+ for (let b = 0; b < 4; b++) {
3422
+ const barY = 90 + b * 75;
3423
+ const bProgress = Math.min(1, Math.max(0, spring(t, 0.3 + b * 0.1, 160, 14)));
3424
+ ctx.fillStyle = IS_LIGHT ? 'rgba(0,0,0,0.06)' : 'rgba(255,255,255,0.06)';
3425
+ ctx.beginPath();
3426
+ ctx.roundRect(24, barY + 22, cardW - 48, 14, 7);
3427
+ ctx.fill();
3428
+
3429
+ ctx.fillStyle = '#38bdf8';
3430
+ ctx.beginPath();
3431
+ const fillW = (cardW - 48) * (0.45 + 0.15 * Math.sin(b * 1.5 + 2)) * bProgress;
3432
+ ctx.roundRect(24, barY + 22, fillW, 14, 7);
3433
+ ctx.fill();
3434
+
3435
+ // Feature icon / indicator
3436
+ sCircle(36, barY + 8, 6, 100 + b, '#38bdf8', 2, '#38bdf8');
3437
+ ctx.fillStyle = TEXT_MAIN;
3438
+ ctx.font = '600 18px ' + FONT_DISPLAY;
3439
+ ctx.fillText('ATTRIBUTE 0' + (b + 1), 54, barY + 14);
3440
+ }
3441
+ ctx.restore();
3442
+
3443
+ // Right Card (Side B)
3444
+ const rightX = cx + 35;
3445
+ ctx.save();
3446
+ ctx.globalAlpha = Math.min(1, Math.max(0, cardRightSpring));
3447
+ ctx.translate(rightX + (1 - cardRightSpring) * 60, cardY);
3448
+ ctx.fillStyle = CARD_BG;
3449
+ ctx.strokeStyle = CARD_BORDER;
3450
+ ctx.lineWidth = 2;
3451
+ ctx.beginPath();
3452
+ ctx.roundRect(0, 0, cardW, cardH, 20);
3453
+ ctx.fill();
3454
+ ctx.stroke();
3455
+
3456
+ // Right Card Header & Accent Pill
3457
+ ctx.fillStyle = 'rgba(244, 63, 94, 0.15)';
3458
+ ctx.beginPath();
3459
+ ctx.roundRect(24, 24, 110, 32, 16);
3460
+ ctx.fill();
3461
+ ctx.fillStyle = '#f43f5e';
3462
+ ctx.font = 'bold 16px ' + FONT_DISPLAY;
3463
+ ctx.fillText('OPTION B', 42, 45);
3464
+
3465
+ // Right Metrics / Feature Bars
3466
+ for (let b = 0; b < 4; b++) {
3467
+ const barY = 90 + b * 75;
3468
+ const bProgress = Math.min(1, Math.max(0, spring(t, 0.35 + b * 0.1, 160, 14)));
3469
+ ctx.fillStyle = IS_LIGHT ? 'rgba(0,0,0,0.06)' : 'rgba(255,255,255,0.06)';
3470
+ ctx.beginPath();
3471
+ ctx.roundRect(24, barY + 22, cardW - 48, 14, 7);
3472
+ ctx.fill();
3473
+
3474
+ ctx.fillStyle = '#f43f5e';
3475
+ ctx.beginPath();
3476
+ const fillW = (cardW - 48) * (0.55 + 0.12 * Math.cos(b * 1.8 + 1)) * bProgress;
3477
+ ctx.roundRect(24, barY + 22, fillW, 14, 7);
3478
+ ctx.fill();
3479
+
3480
+ sCircle(36, barY + 8, 6, 200 + b, '#f43f5e', 2, '#f43f5e');
3481
+ ctx.fillStyle = TEXT_MAIN;
3482
+ ctx.font = '600 18px ' + FONT_DISPLAY;
3483
+ ctx.fillText('ATTRIBUTE 0' + (b + 1), 54, barY + 14);
3484
+ }
3485
+ ctx.restore();
3486
+
3487
+ // Center VS Emblem Badge
3488
+ ctx.save();
3489
+ ctx.translate(cx, cy);
3490
+ const bScale = Math.max(0, badgeSpring);
3491
+ ctx.scale(bScale, bScale);
3492
+ ctx.fillStyle = IS_LIGHT ? '#ffffff' : '#0f172a';
3493
+ ctx.strokeStyle = ACCENT;
3494
+ ctx.lineWidth = 4;
3495
+ ctx.beginPath();
3496
+ ctx.arc(0, 0, 48, 0, Math.PI * 2);
3497
+ ctx.fill();
3498
+ ctx.stroke();
3499
+
3500
+ ctx.strokeStyle = 'rgba(255, 255, 255, 0.4)';
3501
+ ctx.lineWidth = 1.5;
3502
+ ctx.beginPath();
3503
+ ctx.arc(0, 0, 42, 0, Math.PI * 2);
3504
+ ctx.stroke();
3505
+
3506
+ ctx.font = '900 28px ' + FONT_DISPLAY;
3507
+ ctx.fillStyle = ACCENT;
3508
+ ctx.textAlign = 'center';
3509
+ ctx.textBaseline = 'middle';
3510
+ ctx.fillText('VS', 0, 2);
3511
+ ctx.restore();
3512
+
3513
+ } else if (COMP_THEME === 'mechanism_physics') {
3514
+ // Universal Archetype: Mechanical Engineering, Cutaway Gears, Forces & Kinematics
3515
+ const engSpring = spring(t, 0.05, 170, 14);
3516
+ const vectorSpring = spring(t, 0.45, 180, 15);
3517
+
3518
+ // Background schematic blueprint grid lines
3519
+ ctx.save();
3520
+ ctx.strokeStyle = IS_LIGHT ? 'rgba(0,0,0,0.07)' : 'rgba(56, 189, 248, 0.12)';
3521
+ ctx.lineWidth = 1;
3522
+ for (let gx = cx - 450; gx <= cx + 450; gx += 60) {
3523
+ ctx.beginPath(); ctx.moveTo(gx, cy - 320); ctx.lineTo(gx, cy + 320); ctx.stroke();
3524
+ }
3525
+ for (let gy = cy - 300; gy <= cy + 300; gy += 60) {
3526
+ ctx.beginPath(); ctx.moveTo(cx - 480, gy); ctx.lineTo(cx + 480, gy); ctx.stroke();
3527
+ }
3528
+ ctx.strokeStyle = IS_LIGHT ? 'rgba(0,0,0,0.1)' : 'rgba(56, 189, 248, 0.2)';
3529
+ ctx.lineWidth = 1.5;
3530
+ ctx.beginPath(); ctx.arc(cx, cy, 340, 0, Math.PI * 2); ctx.stroke();
3531
+ ctx.restore();
3532
+
3533
+ // Helper: Draw precision technical gear with teeth
3534
+ function drawGear(gx, gy, radius, teeth, rotAngle, color, axleColor) {
3535
+ ctx.save();
3536
+ ctx.translate(gx, gy);
3537
+ ctx.rotate(rotAngle);
3538
+ ctx.fillStyle = color;
3539
+ ctx.strokeStyle = STROKE_COLOR;
3540
+ ctx.lineWidth = 2.5;
3541
+
3542
+ ctx.beginPath();
3543
+ const toothDepth = radius * 0.14;
3544
+ for (let i = 0; i < teeth; i++) {
3545
+ const a0 = (i * 2 * Math.PI) / teeth;
3546
+ const a1 = a0 + (Math.PI / teeth) * 0.35;
3547
+ const a2 = a0 + (Math.PI / teeth) * 0.65;
3548
+ const a3 = a0 + (Math.PI / teeth);
3549
+
3550
+ const rIn = radius - toothDepth;
3551
+ const rOut = radius + toothDepth;
3552
+
3553
+ if (i === 0) ctx.moveTo(rIn * Math.cos(a0), rIn * Math.sin(a0));
3554
+ else ctx.lineTo(rIn * Math.cos(a0), rIn * Math.sin(a0));
3555
+ ctx.lineTo(rOut * Math.cos(a1), rOut * Math.sin(a1));
3556
+ ctx.lineTo(rOut * Math.cos(a2), rOut * Math.sin(a2));
3557
+ ctx.lineTo(rIn * Math.cos(a3), rIn * Math.sin(a3));
3558
+ }
3559
+ ctx.closePath();
3560
+ ctx.fill();
3561
+ ctx.stroke();
3562
+
3563
+ // Hollow interior & spokes
3564
+ ctx.beginPath();
3565
+ ctx.arc(0, 0, radius * 0.62, 0, Math.PI * 2);
3566
+ ctx.fillStyle = IS_LIGHT ? '#ffffff' : '#080d1a';
3567
+ ctx.fill();
3568
+ ctx.stroke();
3569
+
3570
+ // 4 Precision Spokes
3571
+ for (let sp = 0; sp < 4; sp++) {
3572
+ ctx.save();
3573
+ ctx.rotate((sp * Math.PI) / 2);
3574
+ ctx.fillStyle = color;
3575
+ ctx.fillRect(-6, -radius * 0.58, 12, radius * 0.58 * 2);
3576
+ ctx.restore();
3577
+ }
3578
+
3579
+ // Center Axle Hub
3580
+ ctx.beginPath();
3581
+ ctx.arc(0, 0, radius * 0.25, 0, Math.PI * 2);
3582
+ ctx.fillStyle = axleColor;
3583
+ ctx.fill();
3584
+ ctx.stroke();
3585
+ sCircle(0, 0, radius * 0.1, 50, '#ffffff', 2, '#ffffff');
3586
+
3587
+ ctx.restore();
3588
+ }
3589
+
3590
+ ctx.save();
3591
+ const gScale = Math.min(1, Math.max(0, engSpring));
3592
+ ctx.translate(cx, cy);
3593
+ ctx.scale(gScale, gScale);
3594
+ ctx.translate(-cx, -cy);
3595
+
3596
+ // Primary Gear Train (Interlocking 3 gears)
3597
+ const gearSpeed = t * 1.4;
3598
+ drawGear(cx - 150, cy, 140, 24, gearSpeed, IS_LIGHT ? '#e2e8f0' : '#1e293b', ACCENT);
3599
+ drawGear(cx + 90, cy - 80, 105, 18, -gearSpeed * (24 / 18) + 0.17, IS_LIGHT ? '#cbd5e1' : '#334155', ACCENT2);
3600
+ drawGear(cx + 175, cy + 95, 70, 12, gearSpeed * (24 / 12) + 0.25, IS_LIGHT ? '#94a3b8' : '#475569', '#10b981');
3601
+
3602
+ // Dynamic Kinematic Linkage / Piston
3603
+ const pistonCycle = t * 3.5;
3604
+ const crankR = 60;
3605
+ const crankX = cx - 150 + Math.cos(gearSpeed) * crankR;
3606
+ const crankY = cy + Math.sin(gearSpeed) * crankR;
3607
+ const pistonY = cy + 180 + Math.sin(pistonCycle) * 35;
3608
+ const pistonX = cx - 150;
3609
+
3610
+ sLine(crankX, crankY, pistonX, pistonY, 301, ACCENT, 5);
3611
+ sCircle(crankX, crankY, 8, 302, '#ffffff', 2, ACCENT);
3612
+ sCircle(pistonX, pistonY, 8, 303, '#ffffff', 2, ACCENT);
3613
+
3614
+ // Piston Head in Cylinder
3615
+ ctx.fillStyle = IS_LIGHT ? '#64748b' : '#38bdf8';
3616
+ ctx.fillRect(pistonX - 35, pistonY - 15, 70, 30);
3617
+ ctx.strokeStyle = STROKE_COLOR;
3618
+ ctx.lineWidth = 2.5;
3619
+ ctx.strokeRect(pistonX - 35, pistonY - 15, 70, 30);
3620
+
3621
+ // Dynamic Force Vectors & Aerodynamic Flow Arrows
3622
+ if (vectorSpring > 0.05) {
3623
+ ctx.save();
3624
+ ctx.globalAlpha = Math.min(1, Math.max(0, vectorSpring));
3625
+
3626
+ const vX = cx + 290;
3627
+ const vY = cy - 140;
3628
+ sLine(vX, vY, vX + 110, vY, 401, '#10b981', 4);
3629
+ ctx.fillStyle = '#10b981';
3630
+ ctx.beginPath();
3631
+ ctx.moveTo(vX + 125, vY);
3632
+ ctx.lineTo(vX + 105, vY - 8);
3633
+ ctx.lineTo(vX + 105, vY + 8);
3634
+ ctx.closePath();
3635
+ ctx.fill();
3636
+ ctx.font = 'bold 15px ' + FONT_DISPLAY;
3637
+ ctx.fillText('F_THRUST = 4.8 kN', vX, vY - 16);
3638
+
3639
+ ctx.strokeStyle = '#f59e0b';
3640
+ ctx.lineWidth = 3;
3641
+ ctx.beginPath();
3642
+ ctx.arc(cx - 150, cy, 185, -0.6, 0.6);
3643
+ ctx.stroke();
3644
+ ctx.fillStyle = '#f59e0b';
3645
+ ctx.font = 'bold 15px ' + FONT_DISPLAY;
3646
+ ctx.fillText('TORQUE = 320 Nm', cx - 210, cy - 195);
3647
+ ctx.restore();
3648
+ }
3649
+
3650
+ ctx.restore();
3651
+
3652
+ } else if (COMP_THEME === 'process_pipeline') {
3653
+ // Universal Archetype: Multi-Stage Process / Pipeline / Supply Chain / Lifecycle
3654
+ const pipeSpring = spring(t, 0.05, 170, 14);
3655
+ const stages = [
3656
+ { name: 'INGEST', label: '01 / SOURCE', desc: 'Raw Signals' },
3657
+ { name: 'SYNTHESIS', label: '02 / TRANSFORM', desc: 'Active Process' },
3658
+ { name: 'VALIDATION', label: '03 / VERIFY', desc: 'Quality Gate' },
3659
+ { name: 'DEPLOYMENT', label: '04 / OUTPUT', desc: 'Master Release' },
3660
+ ];
3661
+
3662
+ const pipeY = cy;
3663
+ const startX = cx - 450;
3664
+ const totalW = 900;
3665
+ const segW = totalW / (stages.length - 1);
3666
+
3667
+ ctx.save();
3668
+ const pScale = Math.min(1, Math.max(0, pipeSpring));
3669
+ ctx.translate(cx, cy);
3670
+ ctx.scale(pScale, pScale);
3671
+ ctx.translate(-cx, -cy);
3672
+
3673
+ // Main Conduit Pipeline Track
3674
+ const conduitG = ctx.createLinearGradient(startX, 0, startX + totalW, 0);
3675
+ conduitG.addColorStop(0, ACCENT);
3676
+ conduitG.addColorStop(0.5, '#38bdf8');
3677
+ conduitG.addColorStop(1, '#10b981');
3678
+
3679
+ ctx.strokeStyle = IS_LIGHT ? 'rgba(0,0,0,0.1)' : 'rgba(255,255,255,0.15)';
3680
+ ctx.lineWidth = 14;
3681
+ ctx.lineCap = 'round';
3682
+ ctx.beginPath();
3683
+ ctx.moveTo(startX, pipeY);
3684
+ ctx.lineTo(startX + totalW, pipeY);
3685
+ ctx.stroke();
3686
+
3687
+ ctx.strokeStyle = conduitG;
3688
+ ctx.lineWidth = 6;
3689
+ ctx.stroke();
3690
+
3691
+ // Flowing Data Packet Orbs along the conduit
3692
+ for (let pk = 0; pk < 5; pk++) {
3693
+ const pkProgress = ((t * 0.45 + pk * 0.22) % 1.0);
3694
+ const pkX = startX + pkProgress * totalW;
3695
+ ctx.fillStyle = '#ffffff';
3696
+ ctx.beginPath();
3697
+ ctx.arc(pkX, pipeY, 6, 0, Math.PI * 2);
3698
+ ctx.fill();
3699
+
3700
+ ctx.fillStyle = ACCENT;
3701
+ ctx.globalAlpha = 0.4;
3702
+ ctx.beginPath();
3703
+ ctx.arc(pkX, pipeY, 14, 0, Math.PI * 2);
3704
+ ctx.fill();
3705
+ ctx.globalAlpha = 1.0;
3706
+ }
3707
+
3708
+ // Stage Nodes & Info Cards
3709
+ for (let s = 0; s < stages.length; s++) {
3710
+ const st = stages[s];
3711
+ const nodeX = startX + s * segW;
3712
+ const nodeSpring = spring(t, 0.15 + s * 0.16, 180, 14);
3713
+ const nodeAlpha = Math.min(1, Math.max(0, nodeSpring));
3714
+
3715
+ const activeStage = Math.min(stages.length - 1, Math.floor((t / window.DURATION) * stages.length));
3716
+ const isActive = s === activeStage;
3717
+
3718
+ ctx.save();
3719
+ ctx.globalAlpha = nodeAlpha;
3720
+ ctx.translate(nodeX, pipeY);
3721
+
3722
+ const isTop = s % 2 === 0;
3723
+ const cardOffsetY = isTop ? -180 : 70;
3724
+ const cardW = 190;
3725
+ const cardH = 95;
3726
+
3727
+ sLine(0, 0, 0, isTop ? -50 : 50, 500 + s, isActive ? ACCENT : STROKE_ALT, 2.5);
3728
+
3729
+ ctx.fillStyle = CARD_BG;
3730
+ ctx.strokeStyle = isActive ? ACCENT : CARD_BORDER;
3731
+ ctx.lineWidth = isActive ? 3 : 1.5;
3732
+ ctx.beginPath();
3733
+ ctx.roundRect(-cardW / 2, cardOffsetY, cardW, cardH, 14);
3734
+ ctx.fill();
3735
+ ctx.stroke();
3736
+
3737
+ if (isActive) {
3738
+ ctx.strokeStyle = 'rgba(255, 255, 255, 0.3)';
3739
+ ctx.lineWidth = 1;
3740
+ ctx.beginPath();
3741
+ ctx.roundRect(-cardW / 2 + 4, cardOffsetY + 4, cardW - 8, cardH - 8, 10);
3742
+ ctx.stroke();
3743
+ }
3744
+
3745
+ ctx.textAlign = 'center';
3746
+ ctx.font = 'bold 12px ' + FONT_DISPLAY;
3747
+ ctx.fillStyle = isActive ? ACCENT : '#94a3b8';
3748
+ ctx.fillText(st.label, 0, cardOffsetY + 26);
3749
+
3750
+ ctx.font = '800 16px ' + FONT_DISPLAY;
3751
+ ctx.fillStyle = TEXT_MAIN;
3752
+ ctx.fillText(st.name, 0, cardOffsetY + 52);
3753
+
3754
+ ctx.font = '500 13px ' + FONT_BODY;
3755
+ ctx.fillStyle = TEXT_MUTED;
3756
+ ctx.fillText(st.desc, 0, cardOffsetY + 76);
3757
+
3758
+ const nodeR = isActive ? 22 : 16;
3759
+ ctx.fillStyle = IS_LIGHT ? '#ffffff' : '#0f172a';
3760
+ ctx.beginPath();
3761
+ ctx.arc(0, 0, nodeR, 0, Math.PI * 2);
3762
+ ctx.fill();
3763
+
3764
+ ctx.strokeStyle = isActive ? ACCENT : '#64748b';
3765
+ ctx.lineWidth = isActive ? 4 : 3;
3766
+ ctx.beginPath();
3767
+ ctx.arc(0, 0, nodeR, 0, Math.PI * 2);
3768
+ ctx.stroke();
3769
+
3770
+ sCircle(0, 0, isActive ? 8 : 5, 520 + s, isActive ? '#ffffff' : '#94a3b8', 2, isActive ? ACCENT : '#64748b');
3771
+
3772
+ ctx.restore();
3773
+ }
3774
+
3775
+ ctx.restore();
3776
+
3777
+ } else if (COMP_THEME === 'cognitive_insight') {
3778
+ // Universal Archetype: Cognitive Psychology, Neural Eureka, Theory of Mind & Idea Spark
3779
+ const brainSpring = spring(t, 0.05, 170, 14);
3780
+ const eurekaSpring = spring(t, window.DURATION * 0.35, 160, 12);
3781
+ const orbitSpring = spring(t, 0.40, 180, 15);
3782
+
3783
+ ctx.save();
3784
+ const cScale = Math.min(1, Math.max(0, brainSpring));
3785
+ ctx.translate(cx, cy);
3786
+ ctx.scale(cScale, cScale);
3787
+
3788
+ // Concentric Thought Wave Ripples
3789
+ for (let r = 0; r < 4; r++) {
3790
+ const ripPhase = (t * 0.8 + r * 0.25) % 1.0;
3791
+ const ripR = 90 + ripPhase * 240;
3792
+ ctx.strokeStyle = ACCENT;
3793
+ ctx.globalAlpha = Math.max(0, (1 - ripPhase) * 0.35);
3794
+ ctx.lineWidth = 2.5;
3795
+ ctx.beginPath();
3796
+ ctx.arc(0, 0, ripR, 0, Math.PI * 2);
3797
+ ctx.stroke();
3798
+ }
3799
+ ctx.globalAlpha = 1.0;
3800
+
3801
+ // Cerebral Neural Core / Brain Silhouette
3802
+ const brainR = 120;
3803
+ const coreGrad = ctx.createRadialGradient(0, -20, 20, 0, 0, brainR * 1.5);
3804
+ coreGrad.addColorStop(0, '#fef08a');
3805
+ coreGrad.addColorStop(0.3, ACCENT);
3806
+ coreGrad.addColorStop(0.8, '#6366f1');
3807
+ coreGrad.addColorStop(1, 'rgba(15, 23, 42, 0)');
3808
+
3809
+ ctx.fillStyle = coreGrad;
3810
+ ctx.beginPath();
3811
+ ctx.arc(0, 0, brainR * 1.4, 0, Math.PI * 2);
3812
+ ctx.fill();
3813
+
3814
+ // Neural Synapses
3815
+ const synNodes = [
3816
+ { x: -50, y: -60 }, { x: 0, y: -80 }, { x: 50, y: -60 },
3817
+ { x: -80, y: -20 }, { x: -30, y: -20 }, { x: 30, y: -20 }, { x: 80, y: -20 },
3818
+ { x: -60, y: 30 }, { x: 0, y: 25 }, { x: 60, y: 30 },
3819
+ { x: -25, y: 70 }, { x: 25, y: 70 },
3820
+ ];
3821
+
3822
+ ctx.strokeStyle = 'rgba(255, 255, 255, 0.35)';
3823
+ ctx.lineWidth = 2;
3824
+ for (let i = 0; i < synNodes.length; i++) {
3825
+ for (let j = i + 1; j < synNodes.length; j++) {
3826
+ const dx = synNodes[i].x - synNodes[j].x;
3827
+ const dy = synNodes[i].y - synNodes[j].y;
3828
+ const dist = Math.hypot(dx, dy);
3829
+ if (dist < 75) {
3830
+ ctx.beginPath();
3831
+ ctx.moveTo(synNodes[i].x, synNodes[i].y);
3832
+ ctx.lineTo(synNodes[j].x, synNodes[j].y);
3833
+ ctx.stroke();
3834
+
3835
+ const pulse = (t * 2.5 + i * 0.3 + j * 0.2) % 1.0;
3836
+ const px = synNodes[i].x + (synNodes[j].x - synNodes[i].x) * pulse;
3837
+ const py = synNodes[i].y + (synNodes[j].y - synNodes[i].y) * pulse;
3838
+ ctx.fillStyle = '#ffffff';
3839
+ ctx.beginPath();
3840
+ ctx.arc(px, py, 2.5, 0, Math.PI * 2);
3841
+ ctx.fill();
3842
+ }
3843
+ }
3844
+ }
3845
+
3846
+ for (let n = 0; n < synNodes.length; n++) {
3847
+ const sn = synNodes[n];
3848
+ const fire = Math.sin(t * 8 + n * 1.3);
3849
+ const dotR = 5 + (fire > 0.5 ? 2.5 : 0);
3850
+ sCircle(sn.x, sn.y, dotR, 600 + n, '#ffffff', 2, fire > 0.3 ? '#fef08a' : ACCENT);
3851
+ }
3852
+
3853
+ // Eureka Idea Spark Burst
3854
+ if (eurekaSpring > 0.05) {
3855
+ const eProgress = Math.min(1, Math.max(0, eurekaSpring));
3856
+ ctx.save();
3857
+ ctx.scale(eProgress, eProgress);
3858
+
3859
+ const rays = 12;
3860
+ for (let ry = 0; ry < rays; ry++) {
3861
+ const ang = (ry * Math.PI * 2) / rays + t * 0.4;
3862
+ const len = 140 + Math.sin(t * 6 + ry) * 25;
3863
+ ctx.strokeStyle = ry % 2 === 0 ? '#fef08a' : '#ffffff';
3864
+ ctx.lineWidth = ry % 2 === 0 ? 3 : 1.5;
3865
+ ctx.beginPath();
3866
+ ctx.moveTo(Math.cos(ang) * 50, Math.sin(ang) * 50);
3867
+ ctx.lineTo(Math.cos(ang) * len, Math.sin(ang) * len);
3868
+ ctx.stroke();
3869
+ }
3870
+
3871
+ sCircle(0, 0, 18, 650, '#ffffff', 3, '#f59e0b');
3872
+ sCircle(0, 0, 8, 651, '#ffffff', 2, '#ffffff');
3873
+ ctx.restore();
3874
+ }
3875
+
3876
+ // Orbiting Insight Badges
3877
+ if (orbitSpring > 0.05) {
3878
+ const badges = ['PERCEPTION', 'COGNITION', 'INTUITION', 'INSIGHT'];
3879
+ ctx.save();
3880
+ ctx.globalAlpha = Math.min(1, Math.max(0, orbitSpring));
3881
+
3882
+ for (let bg = 0; bg < badges.length; bg++) {
3883
+ const bgAngle = (bg * Math.PI * 2) / badges.length + t * 0.35;
3884
+ const bgX = Math.cos(bgAngle) * 310;
3885
+ const bgY = Math.sin(bgAngle) * 190;
3886
+
3887
+ ctx.fillStyle = CARD_BG;
3888
+ ctx.strokeStyle = CARD_BORDER;
3889
+ ctx.lineWidth = 1.5;
3890
+ ctx.beginPath();
3891
+ ctx.roundRect(bgX - 65, bgY - 18, 130, 36, 18);
3892
+ ctx.fill();
3893
+ ctx.stroke();
3894
+
3895
+ ctx.font = 'bold 13px ' + FONT_DISPLAY;
3896
+ ctx.fillStyle = TEXT_MAIN;
3897
+ ctx.textAlign = 'center';
3898
+ ctx.fillText(badges[bg], bgX, bgY + 5);
3899
+
3900
+ ctx.strokeStyle = 'rgba(255, 255, 255, 0.12)';
3901
+ ctx.beginPath();
3902
+ ctx.moveTo(0, 0);
3903
+ ctx.lineTo(bgX, bgY);
3904
+ ctx.stroke();
3905
+ }
3906
+ ctx.restore();
3907
+ }
3908
+
3909
+ ctx.restore();
3910
+
3911
+ } else if (COMP_THEME === 'magnification_focus') {
3912
+ // Universal Archetype: Optical Loupe, Precision Macro Zoom & Scrutiny Reticle
3913
+ const focusSpring = spring(t, 0.05, 170, 14);
3914
+ const loupeSpring = spring(t, 0.25, 180, 14);
3915
+
3916
+ // Deep research background grid & underlying specimen traces
3917
+ ctx.save();
3918
+ ctx.strokeStyle = IS_LIGHT ? 'rgba(0,0,0,0.06)' : 'rgba(255,255,255,0.08)';
3919
+ ctx.lineWidth = 1;
3920
+ for (let gx = 0; gx < W; gx += 40) {
3921
+ ctx.beginPath(); ctx.moveTo(gx, 0); ctx.lineTo(gx, H); ctx.stroke();
3922
+ }
3923
+ for (let gy = 0; gy < H; gy += 40) {
3924
+ ctx.beginPath(); ctx.moveTo(0, gy); ctx.lineTo(W, gy); ctx.stroke();
3925
+ }
3926
+
3927
+ for (let tr = 0; tr < 16; tr++) {
3928
+ const trX = cx - 350 + tr * 48;
3929
+ const trY = cy - 200 + ((tr * 73) % 400);
3930
+ sLine(trX, trY, trX + 80, trY + 40, 700 + tr, IS_LIGHT ? 'rgba(0,0,0,0.15)' : 'rgba(56, 189, 248, 0.2)', 2);
3931
+ }
3932
+ ctx.restore();
3933
+
3934
+ // Floating Optical Loupe (Lissajous gentle inspection movement)
3935
+ const loupeR = Math.min(W, H) * 0.26;
3936
+ const lissX = cx + Math.sin(t * 1.1) * 70;
3937
+ const lissY = cy + Math.cos(t * 0.85) * 45;
3938
+
3939
+ ctx.save();
3940
+ const lScale = Math.min(1, Math.max(0, loupeSpring));
3941
+ ctx.translate(lissX, lissY);
3942
+ ctx.scale(lScale, lScale);
3943
+
3944
+ ctx.fillStyle = 'rgba(0, 0, 0, 0.45)';
3945
+ ctx.beginPath();
3946
+ ctx.arc(15, 20, loupeR, 0, Math.PI * 2);
3947
+ ctx.fill();
3948
+
3949
+ // Inside Magnified Specimen (Clipped Circle)
3950
+ ctx.save();
3951
+ ctx.beginPath();
3952
+ ctx.arc(0, 0, loupeR - 8, 0, Math.PI * 2);
3953
+ ctx.clip();
3954
+
3955
+ ctx.fillStyle = IS_LIGHT ? '#ffffff' : '#070f1e';
3956
+ ctx.fillRect(-loupeR, -loupeR, loupeR * 2, loupeR * 2);
3957
+
3958
+ ctx.save();
3959
+ ctx.scale(2.4, 2.4);
3960
+ for (let m = -8; m <= 8; m++) {
3961
+ sLine(m * 22, -loupeR, m * 22, loupeR, 720 + m, 'rgba(56, 189, 248, 0.3)', 1.5);
3962
+ sLine(-loupeR, m * 22, loupeR, m * 22, 740 + m, 'rgba(56, 189, 248, 0.3)', 1.5);
3963
+ }
3964
+ sCircle(0, 0, 36, 760, '#f59e0b', 3, 'rgba(245, 158, 11, 0.2)');
3965
+ sCircle(0, 0, 16, 761, '#ef4444', 2.5, '#ef4444');
3966
+ for (let br = 0; br < 6; br++) {
3967
+ const brA = (br * Math.PI * 2) / 6 + t * 0.5;
3968
+ sLine(0, 0, Math.cos(brA) * 55, Math.sin(brA) * 55, 770 + br, ACCENT, 2.5);
3969
+ sCircle(Math.cos(brA) * 55, Math.sin(brA) * 55, 5, 780 + br, '#ffffff', 1.5, ACCENT);
3970
+ }
3971
+ ctx.restore();
3972
+
3973
+ // Precision Crosshairs & Calibrated Reticle
3974
+ ctx.strokeStyle = '#38bdf8';
3975
+ ctx.lineWidth = 1.5;
3976
+ ctx.beginPath();
3977
+ ctx.moveTo(-loupeR + 15, 0); ctx.lineTo(-25, 0);
3978
+ ctx.moveTo(25, 0); ctx.lineTo(loupeR - 15, 0);
3979
+ ctx.moveTo(0, -loupeR + 15); ctx.lineTo(0, -25);
3980
+ ctx.moveTo(0, 25); ctx.lineTo(0, loupeR - 15);
3981
+ ctx.stroke();
3982
+
3983
+ for (let deg = 0; deg < 36; deg++) {
3984
+ const dRad = (deg * Math.PI * 2) / 36;
3985
+ const isMajor = deg % 9 === 0;
3986
+ const tLen = isMajor ? 16 : 8;
3987
+ const rOut = loupeR - 12;
3988
+ const rIn = rOut - tLen;
3989
+ ctx.strokeStyle = isMajor ? ACCENT : 'rgba(255,255,255,0.4)';
3990
+ ctx.lineWidth = isMajor ? 2 : 1;
3991
+ ctx.beginPath();
3992
+ ctx.moveTo(Math.cos(dRad) * rIn, Math.sin(dRad) * rIn);
3993
+ ctx.lineTo(Math.cos(dRad) * rOut, Math.sin(dRad) * rOut);
3994
+ ctx.stroke();
3995
+ }
3996
+ ctx.restore(); // End clipping
3997
+
3998
+ // Bezel
3999
+ ctx.strokeStyle = '#d4af37';
4000
+ ctx.lineWidth = 14;
4001
+ ctx.beginPath();
4002
+ ctx.arc(0, 0, loupeR, 0, Math.PI * 2);
4003
+ ctx.stroke();
4004
+
4005
+ ctx.strokeStyle = '#fef08a';
4006
+ ctx.lineWidth = 2.5;
4007
+ ctx.beginPath();
4008
+ ctx.arc(0, 0, loupeR - 6, 0, Math.PI * 2);
4009
+ ctx.stroke();
4010
+
4011
+ ctx.strokeStyle = 'rgba(255, 255, 255, 0.4)';
4012
+ ctx.lineWidth = 4;
4013
+ ctx.beginPath();
4014
+ ctx.arc(0, 0, loupeR - 24, -1.8, -0.6);
4015
+ ctx.stroke();
4016
+
4017
+ ctx.fillStyle = CARD_BG;
4018
+ ctx.strokeStyle = ACCENT;
4019
+ ctx.lineWidth = 1.5;
4020
+ ctx.beginPath();
4021
+ ctx.roundRect(loupeR - 40, -loupeR - 10, 160, 48, 10);
4022
+ ctx.fill();
4023
+ ctx.stroke();
4024
+
4025
+ ctx.font = 'bold 12px monospace';
4026
+ ctx.fillStyle = ACCENT;
4027
+ ctx.fillText('MAGNIFY: 250%', loupeR - 26, -loupeR + 12);
4028
+ ctx.fillStyle = TEXT_MAIN;
4029
+ ctx.fillText('POS: ' + Math.round(lissX) + ', ' + Math.round(lissY), loupeR - 26, -loupeR + 28);
4030
+
4031
+ ctx.restore();
4032
+
4033
+ } else if (COMP_THEME === 'waveform') {
3317
4034
  // Kinetic Frequency Equalizer Waveform
3318
4035
  const bars = 36;
3319
4036
  const barW = (W * 0.7) / bars;
@@ -3330,6 +4047,153 @@ function drawMainScene(t) {
3330
4047
  ctx.fillStyle = barGrad;
3331
4048
  ctx.beginPath(); ctx.roundRect(bx, by, barW - 6, hVal, 4); ctx.fill();
3332
4049
  }
4050
+
4051
+ } else {
4052
+ // Universal Semantic Default & Explainer Presentation (Whiteboard Masterclass & Concept Pillars)
4053
+ const boardSpring = spring(t, 0.05, 170, 14);
4054
+ const p1Spring = spring(t, 0.18, 190, 15);
4055
+ const p2Spring = spring(t, 0.32, 190, 15);
4056
+ const p3Spring = spring(t, 0.46, 190, 15);
4057
+
4058
+ const boardW = Math.min(W * 0.88, 1100);
4059
+ const boardH = Math.min(H * 0.68, 620);
4060
+ const boardX = cx - boardW / 2;
4061
+ const boardY = cy - boardH / 2;
4062
+
4063
+ ctx.save();
4064
+ const bScale = Math.min(1, Math.max(0, boardSpring));
4065
+ ctx.translate(cx, cy);
4066
+ ctx.scale(bScale, bScale);
4067
+ ctx.translate(-cx, -cy);
4068
+
4069
+ // Architectural Frosted Glass Presentation Board
4070
+ ctx.fillStyle = CARD_BG;
4071
+ ctx.strokeStyle = CARD_BORDER;
4072
+ ctx.lineWidth = 2.5;
4073
+ ctx.beginPath();
4074
+ ctx.roundRect(boardX, boardY, boardW, boardH, 24);
4075
+ ctx.fill();
4076
+ ctx.stroke();
4077
+
4078
+ // Board Header Accent Bar
4079
+ ctx.fillStyle = ACCENT;
4080
+ ctx.beginPath();
4081
+ ctx.roundRect(boardX + 32, boardY + 28, 6, 32, 3);
4082
+ ctx.fill();
4083
+
4084
+ ctx.font = '800 22px ' + FONT_DISPLAY;
4085
+ ctx.fillStyle = TEXT_MAIN;
4086
+ ctx.textAlign = 'left';
4087
+ ctx.fillText('CORE PRINCIPLES & ARCHITECTURE', boardX + 48, boardY + 50);
4088
+
4089
+ // Live Status Badge
4090
+ ctx.fillStyle = 'rgba(16, 185, 129, 0.15)';
4091
+ ctx.beginPath();
4092
+ ctx.roundRect(boardX + boardW - 160, boardY + 28, 128, 30, 15);
4093
+ ctx.fill();
4094
+ ctx.fillStyle = '#10b981';
4095
+ ctx.font = 'bold 13px ' + FONT_DISPLAY;
4096
+ ctx.fillText('● SYSTEM ACTIVE', boardX + boardW - 146, boardY + 48);
4097
+
4098
+ // 3 Structured Concept Pillars
4099
+ const pillarData = [
4100
+ { num: '01', title: 'FOUNDATION', desc: 'Core axioms & structure', icon: 'diamond', spr: p1Spring },
4101
+ { num: '02', title: 'DYNAMICS', desc: 'Kinetic transformation', icon: 'gear', spr: p2Spring },
4102
+ { num: '03', title: 'IMPACT', desc: 'Synthesized outcome', icon: 'star', spr: p3Spring },
4103
+ ];
4104
+
4105
+ const pillarW = (boardW - 128) / 3;
4106
+ const pillarH = boardH - 140;
4107
+ const pillarY = boardY + 95;
4108
+
4109
+ for (let p = 0; p < 3; p++) {
4110
+ const pd = pillarData[p];
4111
+ const pilX = boardX + 32 + p * (pillarW + 32);
4112
+ const pAlpha = Math.min(1, Math.max(0, pd.spr));
4113
+
4114
+ ctx.save();
4115
+ ctx.globalAlpha = pAlpha;
4116
+ ctx.translate(pilX, pillarY + (1 - pd.spr) * 40);
4117
+
4118
+ // Pillar Card
4119
+ ctx.fillStyle = IS_LIGHT ? 'rgba(255,255,255,0.7)' : 'rgba(255,255,255,0.04)';
4120
+ ctx.strokeStyle = p === 1 ? ACCENT : 'rgba(255,255,255,0.1)';
4121
+ ctx.lineWidth = p === 1 ? 2.5 : 1.5;
4122
+ ctx.beginPath();
4123
+ ctx.roundRect(0, 0, pillarW, pillarH, 16);
4124
+ ctx.fill();
4125
+ ctx.stroke();
4126
+
4127
+ // Number Tag
4128
+ ctx.font = '900 48px ' + FONT_DISPLAY;
4129
+ ctx.fillStyle = p === 1 ? ACCENT : (IS_LIGHT ? 'rgba(0,0,0,0.1)' : 'rgba(255,255,255,0.12)');
4130
+ ctx.fillText(pd.num, 24, 60);
4131
+
4132
+ // Pillar Title
4133
+ ctx.font = '700 20px ' + FONT_DISPLAY;
4134
+ ctx.fillStyle = TEXT_MAIN;
4135
+ ctx.fillText(pd.title, 24, 110);
4136
+
4137
+ // Pillar Description
4138
+ ctx.font = '500 15px ' + FONT_BODY;
4139
+ ctx.fillStyle = TEXT_MUTED;
4140
+ ctx.fillText(pd.desc, 24, 138);
4141
+
4142
+ // Dynamic Animated Diagram Graphic inside Pillar
4143
+ const gfxY = pillarH * 0.65;
4144
+ const gfxX = pillarW / 2;
4145
+
4146
+ if (pd.icon === 'diamond') {
4147
+ ctx.save();
4148
+ ctx.translate(gfxX, gfxY);
4149
+ ctx.rotate(t * 1.2);
4150
+ ctx.strokeStyle = ACCENT;
4151
+ ctx.lineWidth = 3;
4152
+ ctx.strokeRect(-28, -28, 56, 56);
4153
+ sCircle(0, 0, 10, 800, '#ffffff', 2, ACCENT);
4154
+ ctx.restore();
4155
+ } else if (pd.icon === 'gear') {
4156
+ sCircle(gfxX, gfxY, 36, 810, ACCENT, 3);
4157
+ const pulseR = 20 + Math.sin(t * 5) * 8;
4158
+ sCircle(gfxX, gfxY, pulseR, 811, '#ffffff', 2, '#38bdf8');
4159
+ } else {
4160
+ for (let st = 0; st < 4; st++) {
4161
+ const ang = (st * Math.PI) / 2 + t * 0.8;
4162
+ sLine(gfxX, gfxY, gfxX + Math.cos(ang) * 36, gfxY + Math.sin(ang) * 36, 820 + st, '#f59e0b', 3);
4163
+ }
4164
+ sCircle(gfxX, gfxY, 8, 825, '#ffffff', 2, '#f59e0b');
4165
+ }
4166
+
4167
+ // Feature Check items
4168
+ for (let ch = 0; ch < 3; ch++) {
4169
+ const itemY = pillarH - 85 + ch * 24;
4170
+ sCircle(28, itemY, 4, 830 + ch, ACCENT, 2, ACCENT);
4171
+ ctx.fillStyle = TEXT_MAIN;
4172
+ ctx.font = '500 13px ' + FONT_BODY;
4173
+ ctx.fillText('Verification Key 0' + (ch + 1), 42, itemY + 4);
4174
+ }
4175
+
4176
+ ctx.restore();
4177
+ }
4178
+
4179
+ // Inter-Pillar Energy Connectors
4180
+ ctx.strokeStyle = ACCENT;
4181
+ ctx.lineWidth = 2.5;
4182
+ for (let c = 0; c < 2; c++) {
4183
+ const connX1 = boardX + 32 + (c + 1) * pillarW + c * 32 - 16;
4184
+ const connX2 = connX1 + 32;
4185
+ const connY = pillarY + 80;
4186
+ sLine(connX1, connY, connX2, connY, 850 + c, ACCENT, 3);
4187
+ ctx.fillStyle = ACCENT;
4188
+ ctx.beginPath();
4189
+ ctx.moveTo(connX2 + 4, connY);
4190
+ ctx.lineTo(connX2 - 4, connY - 5);
4191
+ ctx.lineTo(connX2 - 4, connY + 5);
4192
+ ctx.closePath();
4193
+ ctx.fill();
4194
+ }
4195
+
4196
+ ctx.restore();
3333
4197
  }
3334
4198
 
3335
4199
  ctx.restore();