@saluzi/saluzi-edu 0.2.34 → 0.2.35

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 (151) hide show
  1. package/dist/cli.js +42 -42
  2. package/dist/guide/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  3. package/dist/guide/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  4. package/dist/guide/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  5. package/dist/guide/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  6. package/dist/guide/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  7. package/dist/guide/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  8. package/dist/guide/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  9. package/dist/guide/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  10. package/dist/guide/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  11. package/dist/guide/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  12. package/dist/guide/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  13. package/dist/guide/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  14. package/dist/guide/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  15. package/dist/guide/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  16. package/dist/guide/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  17. package/dist/guide/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  18. package/dist/guide/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  19. package/dist/guide/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  20. package/dist/guide/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  21. package/dist/guide/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  22. package/dist/guide/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  23. package/dist/guide/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  24. package/dist/guide/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  25. package/dist/guide/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  26. package/dist/guide/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  27. package/dist/guide/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  28. package/dist/guide/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  29. package/dist/guide/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  30. package/dist/guide/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  31. package/dist/guide/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  32. package/dist/guide/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  33. package/dist/guide/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  34. package/dist/guide/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  35. package/dist/guide/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  36. package/dist/guide/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  37. package/dist/guide/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  38. package/dist/guide/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  39. package/dist/guide/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  40. package/dist/guide/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  41. package/dist/guide/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  42. package/dist/guide/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  43. package/dist/guide/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  44. package/dist/guide/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  45. package/dist/guide/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  46. package/dist/guide/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  47. package/dist/guide/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  48. package/dist/guide/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  49. package/dist/guide/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  50. package/dist/guide/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  51. package/dist/guide/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  52. package/dist/guide/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  53. package/dist/guide/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  54. package/dist/guide/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  55. package/dist/guide/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  56. package/dist/guide/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  57. package/dist/guide/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  58. package/dist/guide/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  59. package/dist/guide/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  60. package/dist/guide/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  61. package/dist/guide/assets/arc-BHMVz_y5.js +1 -0
  62. package/dist/guide/assets/architecture-7EHR7CIX-CbSBUcb5.js +1 -0
  63. package/dist/guide/assets/architectureDiagram-3BPJPVTR-wcJB5ouf.js +36 -0
  64. package/dist/guide/assets/array-BrnE8AWd.js +1 -0
  65. package/dist/guide/assets/blockDiagram-GPEHLZMM-CkYrVwzx.js +132 -0
  66. package/dist/guide/assets/c4Diagram-AAUBKEIU-DiD9rsNe.js +10 -0
  67. package/dist/guide/assets/channel-Ci3DSJxv.js +1 -0
  68. package/dist/guide/assets/chunk-2J33WTMH-BtCG5Mgz.js +1 -0
  69. package/dist/guide/assets/chunk-3OPIFGDE-ByO7Sl21.js +62 -0
  70. package/dist/guide/assets/chunk-4BX2VUAB-BSS9lLPG.js +1 -0
  71. package/dist/guide/assets/chunk-55IACEB6-CeGwUs-Y.js +1 -0
  72. package/dist/guide/assets/chunk-5ZQYHXKU-lfQPlpWw.js +2 -0
  73. package/dist/guide/assets/chunk-727SXJPM-Dk7csXo-.js +206 -0
  74. package/dist/guide/assets/chunk-AQP2D5EJ-DxgPzCop.js +231 -0
  75. package/dist/guide/assets/chunk-BSJP7CBP-DkaucuU0.js +1 -0
  76. package/dist/guide/assets/chunk-CSCIHK7Q-CqC2wNLF.js +125 -0
  77. package/dist/guide/assets/chunk-FMBD7UC4-CJdpjMF6.js +15 -0
  78. package/dist/guide/assets/chunk-KSCS5N6A-BzmG2SKB.js +10 -0
  79. package/dist/guide/assets/chunk-L5ZTLDWV-DLULHpQl.js +1 -0
  80. package/dist/guide/assets/chunk-LZXEDZCA-DeAieGL_.js +2 -0
  81. package/dist/guide/assets/chunk-ND2GUHAM-CYoheonW.js +1 -0
  82. package/dist/guide/assets/chunk-NNHCCRGN-CZB-V-Gv.js +159 -0
  83. package/dist/guide/assets/chunk-NZK2D7GU-tj0TiDjG.js +1 -0
  84. package/dist/guide/assets/chunk-O5CBEL6O-XqfyC6rf.js +11 -0
  85. package/dist/guide/assets/chunk-QZHKN3VN-B4pSqT8x.js +1 -0
  86. package/dist/guide/assets/chunk-WU5MYG2G-BTp4jVLR.js +1 -0
  87. package/dist/guide/assets/chunk-XPW4576I-BNAjqPW9.js +32 -0
  88. package/dist/guide/assets/classDiagram-4FO5ZUOK-DvnG1hC8.js +1 -0
  89. package/dist/guide/assets/classDiagram-v2-Q7XG4LA2-CDSfRrXS.js +1 -0
  90. package/dist/guide/assets/cose-bilkent-S5V4N54A-BGtpG2nc.js +1 -0
  91. package/dist/guide/assets/cytoscape.esm-Da9oojO7.js +321 -0
  92. package/dist/guide/assets/dagre-BM42HDAG-CsDPkQZd.js +4 -0
  93. package/dist/guide/assets/dagre-YawDugTX.js +1 -0
  94. package/dist/guide/assets/defaultLocale-CzQOUpbn.js +1 -0
  95. package/dist/guide/assets/diagram-2AECGRRQ-Bi0iesIB.js +43 -0
  96. package/dist/guide/assets/diagram-5GNKFQAL-B0mUsXMY.js +10 -0
  97. package/dist/guide/assets/diagram-KO2AKTUF-gJ2w08DO.js +3 -0
  98. package/dist/guide/assets/diagram-LMA3HP47-Bfz-mntY.js +24 -0
  99. package/dist/guide/assets/diagram-OG6HWLK6-c0LfJUmp.js +24 -0
  100. package/dist/guide/assets/dist-BkwaIA-w.js +1 -0
  101. package/dist/guide/assets/erDiagram-TEJ5UH35-tNIVvJVS.js +85 -0
  102. package/dist/guide/assets/eventmodeling-FCH6USID-Cf2rgrFX.js +1 -0
  103. package/dist/guide/assets/flowDiagram-I6XJVG4X-DZ7ZJ9gs.js +162 -0
  104. package/dist/guide/assets/ganttDiagram-6RSMTGT7-7fvvO2ap.js +292 -0
  105. package/dist/guide/assets/gitGraph-WXDBUCRP-zBiwTp6u.js +1 -0
  106. package/dist/guide/assets/gitGraphDiagram-PVQCEYII-BDpfxO9f.js +106 -0
  107. package/dist/guide/assets/graphlib-D2mVfvC0.js +1 -0
  108. package/dist/guide/assets/info-J43DQDTF-BxLwAY8v.js +1 -0
  109. package/dist/guide/assets/infoDiagram-5YYISTIA-Db_bmyIO.js +2 -0
  110. package/dist/guide/assets/init-BIStumxp.js +1 -0
  111. package/dist/guide/assets/ishikawaDiagram-YF4QCWOH-BwCoYf2Y.js +70 -0
  112. package/dist/guide/assets/journeyDiagram-JHISSGLW-Bou7oOC_.js +139 -0
  113. package/dist/guide/assets/kanban-definition-UN3LZRKU-lAKeBcZd.js +89 -0
  114. package/dist/guide/assets/katex-DEcVZfaU.css +1 -0
  115. package/dist/guide/assets/line-D9OadBQf.js +1 -0
  116. package/dist/guide/assets/linear-Dby1tqT1.js +1 -0
  117. package/dist/guide/assets/main-ByIvcCOw.css +1 -0
  118. package/dist/guide/assets/main-KHtjEkbM.js +166 -0
  119. package/dist/guide/assets/mermaid-parser.core-Bqq5x6kF.js +4 -0
  120. package/dist/guide/assets/mermaid.core-BS0Z4ePg.js +9 -0
  121. package/dist/guide/assets/mindmap-definition-RKZ34NQL-DKTUw-mh.js +96 -0
  122. package/dist/guide/assets/ordinal-D5SYTrjO.js +1 -0
  123. package/dist/guide/assets/packet-YPE3B663-CEHi_Cah.js +1 -0
  124. package/dist/guide/assets/path-CzCUKGLF.js +1 -0
  125. package/dist/guide/assets/pie-LRSECV5Y-CA6TRlP8.js +1 -0
  126. package/dist/guide/assets/pieDiagram-4H26LBE5-C4BywgU2.js +30 -0
  127. package/dist/guide/assets/quadrantDiagram-W4KKPZXB-xXGhs_Tm.js +7 -0
  128. package/dist/guide/assets/radar-GUYGQ44K-pPRQHVkl.js +1 -0
  129. package/dist/guide/assets/requirementDiagram-4Y6WPE33-B6FgrKWS.js +84 -0
  130. package/dist/guide/assets/rolldown-runtime-S-ySWqyJ.js +1 -0
  131. package/dist/guide/assets/rough.esm-l7pwdmc9.js +1 -0
  132. package/dist/guide/assets/sankeyDiagram-5OEKKPKP-BF9GbLlk.js +40 -0
  133. package/dist/guide/assets/sequenceDiagram-3UESZ5HK-C0Fx8lZi.js +162 -0
  134. package/dist/guide/assets/shiki-CMaUdEs0.js +152 -0
  135. package/dist/guide/assets/src-f-bswMtJ.js +1 -0
  136. package/dist/guide/assets/stateDiagram-AJRCARHV-DTwo-pNm.js +1 -0
  137. package/dist/guide/assets/stateDiagram-v2-BHNVJYJU-D7jALaef.js +1 -0
  138. package/dist/guide/assets/streamdown-nMT_aKRc.js +373 -0
  139. package/dist/guide/assets/timeline-definition-PNZ67QCA-C5CSLNZx.js +120 -0
  140. package/dist/guide/assets/treeView-BLDUP644-Dw8zVUOA.js +1 -0
  141. package/dist/guide/assets/treemap-LRROVOQU-DZnNSrx4.js +1 -0
  142. package/dist/guide/assets/vendor-BU1MXatO.js +9 -0
  143. package/dist/guide/assets/vennDiagram-CIIHVFJN-DyvIDEhj.js +34 -0
  144. package/dist/guide/assets/wardley-L42UT6IY-DghZA76R.js +1 -0
  145. package/dist/guide/assets/wardleyDiagram-YWT4CUSO-CtwyUs6q.js +78 -0
  146. package/dist/guide/assets/xychartDiagram-2RQKCTM6-TQgHZmKB.js +7 -0
  147. package/dist/guide/guide-data.json +3237 -0
  148. package/dist/guide/index.html +24 -0
  149. package/dist/parade/web/cube.js +20 -290
  150. package/dist/parade/web/index.html +41 -6
  151. package/package.json +1 -1
@@ -0,0 +1,24 @@
1
+ <!doctype html>
2
+ <html lang="zh-CN" class="light">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Saluzi Guide · 使用指南</title>
7
+ <meta name="description" content="Saluzi CLI 使用指南 — 新手入门、命令字典、环境变量、Saluzi 特色" />
8
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
9
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
10
+ <link
11
+ href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap"
12
+ rel="stylesheet"
13
+ />
14
+ <script type="module" crossorigin src="/assets/main-KHtjEkbM.js"></script>
15
+ <link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-S-ySWqyJ.js">
16
+ <link rel="modulepreload" crossorigin href="/assets/shiki-CMaUdEs0.js">
17
+ <link rel="modulepreload" crossorigin href="/assets/streamdown-nMT_aKRc.js">
18
+ <link rel="modulepreload" crossorigin href="/assets/vendor-BU1MXatO.js">
19
+ <link rel="stylesheet" crossorigin href="/assets/main-ByIvcCOw.css">
20
+ </head>
21
+ <body>
22
+ <div id="root"></div>
23
+ </body>
24
+ </html>
@@ -2,7 +2,7 @@
2
2
  * Parade overlay cube renderer and session info bar controller.
3
3
  *
4
4
  * Responsibilities:
5
- * 1. Render a purple 3D cube via WebGL in the left canvas area.
5
+ * 1. Render a purple 3D cube via CSS 3D transforms in the left stage area.
6
6
  * 2. Animate the cube with gyroscope-style rotation when runningCount > 0.
7
7
  * 3. Update the info bar (right side) with running/waiting counts and
8
8
  * per-session prompt text from WebSocket pushes.
@@ -15,7 +15,6 @@
15
15
  // Configuration
16
16
  // ---------------------------------------------------------------------------
17
17
 
18
- const PURPLE = [0.545, 0.361, 0.965] // #8B5CF6
19
18
  const MAX_PROMPT_LENGTH = 30
20
19
  const MAX_DISPLAYED_SESSIONS = 5
21
20
  const WS_RECONNECT_MS = 2000
@@ -24,7 +23,7 @@ const WS_RECONNECT_MS = 2000
24
23
  // DOM references
25
24
  // ---------------------------------------------------------------------------
26
25
 
27
- const canvas = document.getElementById('cube-canvas')
26
+ const cubeEl = document.getElementById('cube')
28
27
  const runningCountEl = document.getElementById('running-count')
29
28
  const waitingCountEl = document.getElementById('waiting-count')
30
29
  const waitingPillEl = document.getElementById('waiting-pill')
@@ -267,6 +266,7 @@ function updateCounts() {
267
266
  } else {
268
267
  waitingPillEl.classList.add('zero')
269
268
  }
269
+ updateCubeRotation()
270
270
  }
271
271
 
272
272
  function updateSessionRows() {
@@ -473,304 +473,34 @@ ctxMode.addEventListener('click', function () {
473
473
  /* ignore */
474
474
  }
475
475
  updateModeLabel()
476
+ updateCubeRotation()
476
477
  })
477
478
 
478
479
  updateModeLabel()
479
480
 
480
481
  // ---------------------------------------------------------------------------
481
- // WebGL: Purple 3D Cube
482
+ // CSS 3D Cube rotation control
482
483
  // ---------------------------------------------------------------------------
483
-
484
- var gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl')
485
- var cubeProgram = null
486
- var cubeBuffer = null
487
- var cubeIndexBuffer = null
488
-
489
- // Sync the canvas drawing buffer to its CSS display size × devicePixelRatio.
490
- // Without this, the canvas keeps its initial 240×320 buffer regardless of the
491
- // actual display area — if the window's client height isn't exactly 160px
492
- // (e.g. DPI scaling, title bar subtraction, WM overrides), the cube renders
493
- // at the wrong aspect ratio and looks stretched/squished. This makes the
494
- // cube correct at any window size, on any DPI/resolution/scaling setting.
495
- function resizeCanvasToDisplaySize() {
496
- var dpr = window.devicePixelRatio || 1
497
- var rect = canvas.getBoundingClientRect()
498
- var displayW = Math.max(1, Math.floor(rect.width * dpr))
499
- var displayH = Math.max(1, Math.floor(rect.height * dpr))
500
- if (canvas.width !== displayW || canvas.height !== displayH) {
501
- canvas.width = displayW
502
- canvas.height = displayH
503
- }
504
- }
505
- window.addEventListener('resize', function () {
506
- resizeCanvasToDisplaySize()
507
- updateScrollbar()
508
- })
509
- resizeCanvasToDisplaySize()
510
-
511
- if (gl) {
512
- initCube()
513
- }
514
-
515
- function initCube() {
516
- // -- Shaders --
517
- var vsSource = [
518
- 'attribute vec3 aPos;',
519
- 'uniform mat4 uMVP;',
520
- 'void main() {',
521
- ' gl_Position = uMVP * vec4(aPos, 1.0);',
522
- '}',
523
- ].join('\n')
524
-
525
- var fsSource = [
526
- 'precision mediump float;',
527
- 'uniform vec3 uColor;',
528
- 'void main() {',
529
- ' gl_FragColor = vec4(uColor, 1.0);',
530
- '}',
531
- ].join('\n')
532
-
533
- var vs = compileShader(gl.VERTEX_SHADER, vsSource)
534
- var fs = compileShader(gl.FRAGMENT_SHADER, fsSource)
535
- if (!vs || !fs) return
536
-
537
- cubeProgram = gl.createProgram()
538
- gl.attachShader(cubeProgram, vs)
539
- gl.attachShader(cubeProgram, fs)
540
- gl.linkProgram(cubeProgram)
541
-
542
- // -- Cube vertices (8 corners, unit cube centered at origin) --
543
- var vertices = new Float32Array([
544
- -0.5, -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, -0.5, 0.5, -0.5, -0.5,
545
- -0.5, 0.5, 0.5, -0.5, 0.5, 0.5, 0.5, 0.5, -0.5, 0.5, 0.5,
546
- ])
547
-
548
- // -- Index buffer (12 triangles = 6 faces * 2 triangles) --
549
- var indices = new Uint16Array([
550
- // Front face
551
- 0, 1, 2, 0, 2, 3,
552
- // Back face
553
- 5, 4, 7, 5, 7, 6,
554
- // Top face
555
- 3, 2, 6, 3, 6, 7,
556
- // Bottom face
557
- 4, 5, 1, 4, 1, 0,
558
- // Right face
559
- 1, 5, 6, 1, 6, 2,
560
- // Left face
561
- 4, 0, 3, 4, 3, 7,
562
- ])
563
-
564
- cubeBuffer = gl.createBuffer()
565
- gl.bindBuffer(gl.ARRAY_BUFFER, cubeBuffer)
566
- gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW)
567
-
568
- cubeIndexBuffer = gl.createBuffer()
569
- gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeIndexBuffer)
570
- gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW)
571
-
572
- // -- Initial render --
573
- gl.enable(gl.DEPTH_TEST)
574
- gl.clearColor(0.102, 0.102, 0.18, 1.0) // #1a1a2e
575
- renderFrame()
576
- }
577
-
578
- function compileShader(type, source) {
579
- var shader = gl.createShader(type)
580
- gl.shaderSource(shader, source)
581
- gl.compileShader(shader)
582
- if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
583
- gl.deleteShader(shader)
584
- return null
585
- }
586
- return shader
587
- }
588
-
589
- // ---------------------------------------------------------------------------
590
- // Matrix math (minimal 4x4 operations for perspective + model-view)
591
- // ---------------------------------------------------------------------------
592
-
593
- function mat4Identity() {
594
- var m = new Float32Array(16)
595
- m[0] = 1
596
- m[5] = 1
597
- m[10] = 1
598
- m[15] = 1
599
- return m
600
- }
601
-
602
- function mat4Perspective(fovY, aspect, near, far) {
603
- var f = 1.0 / Math.tan(fovY / 2)
604
- var m = new Float32Array(16)
605
- m[0] = f / aspect
606
- m[5] = f
607
- m[10] = (far + near) / (near - far)
608
- m[11] = -1
609
- m[14] = (2 * far * near) / (near - far)
610
- return m
611
- }
612
-
613
- function mat4Translate(m, x, y, z) {
614
- var r = new Float32Array(m)
615
- r[12] = m[0] * x + m[4] * y + m[8] * z + m[12]
616
- r[13] = m[1] * x + m[5] * y + m[9] * z + m[13]
617
- r[14] = m[2] * x + m[6] * y + m[10] * z + m[14]
618
- r[15] = m[3] * x + m[7] * y + m[11] * z + m[15]
619
- return r
620
- }
621
-
622
- function mat4RotateX(m, a) {
623
- var c = Math.cos(a),
624
- s = Math.sin(a)
625
- var r = new Float32Array(m)
626
- var m4 = m[4],
627
- m5 = m[5],
628
- m6 = m[6],
629
- m7 = m[7]
630
- var m8 = m[8],
631
- m9 = m[9],
632
- m10 = m[10],
633
- m11 = m[11]
634
- r[4] = m4 * c + m8 * s
635
- r[5] = m5 * c + m9 * s
636
- r[6] = m6 * c + m10 * s
637
- r[7] = m7 * c + m11 * s
638
- r[8] = m8 * c - m4 * s
639
- r[9] = m9 * c - m5 * s
640
- r[10] = m10 * c - m6 * s
641
- r[11] = m11 * c - m7 * s
642
- return r
643
- }
644
-
645
- function mat4RotateY(m, a) {
646
- var c = Math.cos(a),
647
- s = Math.sin(a)
648
- var r = new Float32Array(m)
649
- var m0 = m[0],
650
- m1 = m[1],
651
- m2 = m[2],
652
- m3 = m[3]
653
- var m8 = m[8],
654
- m9 = m[9],
655
- m10 = m[10],
656
- m11 = m[11]
657
- r[0] = m0 * c - m8 * s
658
- r[1] = m1 * c - m9 * s
659
- r[2] = m2 * c - m10 * s
660
- r[3] = m3 * c - m11 * s
661
- r[8] = m0 * s + m8 * c
662
- r[9] = m1 * s + m9 * c
663
- r[10] = m2 * s + m10 * c
664
- r[11] = m3 * s + m11 * c
665
- return r
666
- }
667
-
668
- function mat4Scale(m, sx, sy, sz) {
669
- var r = new Float32Array(m)
670
- r[0] *= sx
671
- r[1] *= sx
672
- r[2] *= sx
673
- r[3] *= sx
674
- r[4] *= sy
675
- r[5] *= sy
676
- r[6] *= sy
677
- r[7] *= sy
678
- r[8] *= sz
679
- r[9] *= sz
680
- r[10] *= sz
681
- r[11] *= sz
682
- return r
683
- }
684
-
685
- // ---------------------------------------------------------------------------
686
- // Render loop
687
- // ---------------------------------------------------------------------------
688
-
689
- var rotX = 0.4 // Initial tilt for better visual
690
- var rotY = 0
691
-
692
- function renderFrame() {
693
- if (!gl || !cubeProgram) return
694
-
695
- // Re-sync buffer to display size in case the window resized since last frame.
696
- resizeCanvasToDisplaySize()
697
- gl.viewport(0, 0, canvas.width, canvas.height)
698
- gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
699
-
700
- gl.useProgram(cubeProgram)
701
-
702
- // Projection: 45 degree FOV, canvas aspect ratio
703
- var proj = mat4Perspective(
704
- Math.PI / 4,
705
- canvas.width / canvas.height,
706
- 0.1,
707
- 100,
708
- )
709
-
710
- // View: camera pulled back along Z
711
- var view = mat4Translate(proj, 0, 0, -4)
712
-
713
- // Model: rotate then scale
714
- var model = mat4Identity()
715
- model = mat4RotateX(model, rotX)
716
- model = mat4RotateY(model, rotY)
717
- model = mat4Scale(model, 1.2, 1.2, 1.2)
718
-
719
- // MVP = projection * view * model (already combined above)
720
- var mvp = view
721
- // Multiply view * model
722
- var mvpFinal = mat4Multiply(mvp, model)
723
-
724
- // Set uniforms
725
- var uMVP = gl.getUniformLocation(cubeProgram, 'uMVP')
726
- var uColor = gl.getUniformLocation(cubeProgram, 'uColor')
727
- gl.uniformMatrix4fv(uMVP, false, mvpFinal)
728
- gl.uniform3fv(uColor, PURPLE)
729
-
730
- // Bind vertex buffer
731
- var aPos = gl.getAttribLocation(cubeProgram, 'aPos')
732
- gl.bindBuffer(gl.ARRAY_BUFFER, cubeBuffer)
733
- gl.enableVertexAttribArray(aPos)
734
- gl.vertexAttribPointer(aPos, 3, gl.FLOAT, false, 0, 0)
735
-
736
- // Draw indexed triangles
737
- gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeIndexBuffer)
738
- gl.drawElements(gl.TRIANGLES, 36, gl.UNSIGNED_SHORT, 0)
739
- }
740
-
741
- function mat4Multiply(a, b) {
742
- var r = new Float32Array(16)
743
- var i, j
744
- for (i = 0; i < 4; i++) {
745
- for (j = 0; j < 4; j++) {
746
- r[j * 4 + i] =
747
- a[i] * b[j * 4] +
748
- a[4 + i] * b[j * 4 + 1] +
749
- a[8 + i] * b[j * 4 + 2] +
750
- a[12 + i] * b[j * 4 + 3]
751
- }
752
- }
753
- return r
754
- }
755
-
756
- /**
757
- * Animation loop. Rotates the cube on X and Y axes (gyroscope-style)
758
- * based on the current cube mode:
759
- * Dynamic: rotate when runningCount > 0
760
- * Static: rotate when runningCount === 0 (inverse)
761
- */
762
- function animate() {
484
+ // The cube is a CSS 3D transform element (see index.html <style>). Rotation
485
+ // is driven by applying/removing the .rotating class, which toggles the
486
+ // cube-spin @keyframes animation. Logic mirrors the previous WebGL loop:
487
+ // Dynamic: rotate when runningCount > 0
488
+ // Static: rotate when runningCount === 0 (inverse)
489
+
490
+ function updateCubeRotation() {
491
+ if (!cubeEl) return
763
492
  var shouldRotate =
764
493
  cubeMode === 'dynamic' ? runningCount > 0 : runningCount === 0
765
494
  if (shouldRotate) {
766
- rotY += 0.025
767
- rotX += 0.012
495
+ cubeEl.classList.add('rotating')
496
+ } else {
497
+ cubeEl.classList.remove('rotating')
768
498
  }
769
- renderFrame()
770
- requestAnimationFrame(animate)
771
499
  }
772
500
 
773
- // Start the render loop and WebSocket connection
501
+ // Apply initial state — re-evaluated on each WS message via updateCounts
502
+ updateCubeRotation()
503
+
504
+ // Start the WebSocket connection
774
505
  setWsStatus('connecting')
775
- requestAnimationFrame(animate)
776
506
  connectWebSocket()
@@ -34,8 +34,9 @@
34
34
 
35
35
  /* ---- Left: cube stage ----
36
36
  Use flex-basis instead of fixed px so the stage scales with the window.
37
- The cube canvas inside auto-syncs its buffer to the display size, so the
38
- cube renders correctly at any window dimension. */
37
+ The cube is a CSS 3D transform element — three faces (body + ::before
38
+ + ::after) form a visible cube. Rotates when .rotating class is applied
39
+ (driven by runningCount + cubeMode in cube.js). */
39
40
  #cube-stage {
40
41
  flex: 0 0 43%; /* ~95px of 220px, but proportional so it scales */
41
42
  height: 100%;
@@ -47,10 +48,44 @@
47
48
  align-items: center;
48
49
  justify-content: center;
49
50
  border-right: 1px solid var(--border);
51
+ perspective: 200px;
50
52
  }
51
- #cube-canvas {
52
- width: 100%; height: 100%;
53
- display: block;
53
+ /* CSS 3D cube: body is the front face, ::before is the right face,
54
+ ::after is the top face. Half-size translates position them at 90°. */
55
+ .cube {
56
+ width: 22px;
57
+ height: 22px;
58
+ position: relative;
59
+ transform-style: preserve-3d;
60
+ transform: rotateX(-28deg) rotateY(45deg);
61
+ background: rgba(139, 92, 246, 0.45);
62
+ border: 1px solid #8B5CF6;
63
+ }
64
+ .cube.rotating {
65
+ animation: cube-spin 8s linear infinite;
66
+ }
67
+ .cube::before,
68
+ .cube::after {
69
+ content: '';
70
+ position: absolute;
71
+ inset: 0;
72
+ }
73
+ .cube::before {
74
+ transform: rotateY(90deg) translateZ(11px);
75
+ background: rgba(167, 139, 250, 0.55);
76
+ border: 1px solid #a78bfa;
77
+ }
78
+ .cube::after {
79
+ transform: rotateX(90deg) translateZ(11px);
80
+ background: rgba(109, 40, 217, 0.4);
81
+ border: 1px solid #6d28d9;
82
+ }
83
+ @keyframes cube-spin {
84
+ from { transform: rotateX(-28deg) rotateY(0deg); }
85
+ to { transform: rotateX(-28deg) rotateY(360deg); }
86
+ }
87
+ @media (prefers-reduced-motion: reduce) {
88
+ .cube.rotating { animation: none; }
54
89
  }
55
90
  /* Subtle ring frame around the cube */
56
91
  #cube-stage::after {
@@ -355,7 +390,7 @@
355
390
  </head>
356
391
  <body>
357
392
  <div id="cube-stage">
358
- <canvas id="cube-canvas" width="240" height="320"></canvas>
393
+ <div class="cube" id="cube"></div>
359
394
  </div>
360
395
  <div id="panel">
361
396
  <div id="counts-row">
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saluzi/saluzi-edu",
3
- "version": "0.2.34",
3
+ "version": "0.2.35",
4
4
  "description": "Saluzi CLI - interactive AI coding assistant in the terminal",
5
5
  "license": "MIT",
6
6
  "type": "module",