mudra-skills 1.0.0

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 (149) hide show
  1. package/.claude-plugin/plugin.json +19 -0
  2. package/CLAUDE.md +35 -0
  3. package/bin/install.js +25 -0
  4. package/package.json +28 -0
  5. package/skills/mudra-master/SKILL.md +202 -0
  6. package/skills/mudra-master/mudra-preview/SKILL.md +151 -0
  7. package/skills/mudra-master/mudra-preview/assets/ar-menu.html +382 -0
  8. package/skills/mudra-master/mudra-preview/assets/document-scroller.html +468 -0
  9. package/skills/mudra-master/mudra-preview/assets/drum-machine.html +788 -0
  10. package/skills/mudra-master/mudra-preview/assets/emg-visualizer.html +390 -0
  11. package/skills/mudra-master/mudra-preview/assets/generative-art.html +408 -0
  12. package/skills/mudra-master/mudra-preview/assets/gesture-assistant.html +342 -0
  13. package/skills/mudra-master/mudra-preview/assets/gesture-speech.html +444 -0
  14. package/skills/mudra-master/mudra-preview/assets/hands-free-desktop.html +376 -0
  15. package/skills/mudra-master/mudra-preview/assets/model-rotator.html +365 -0
  16. package/skills/mudra-master/mudra-preview/assets/mudra-duel.html +3200 -0
  17. package/skills/mudra-master/mudra-preview/assets/mudra-monitor.html +1451 -0
  18. package/skills/mudra-master/mudra-preview/assets/mudra-ultimate-template.html +891 -0
  19. package/skills/mudra-master/mudra-preview/assets/music-sequencer.html +455 -0
  20. package/skills/mudra-master/mudra-preview/assets/neural-pong.html +380 -0
  21. package/skills/mudra-master/mudra-preview/assets/neural-snake.html +364 -0
  22. package/skills/mudra-master/mudra-preview/assets/presentation-controller.html +345 -0
  23. package/skills/mudra-master/mudra-preview/assets/pressure-painter.html +285 -0
  24. package/skills/mudra-master/mudra-preview/assets/runner.html +1812 -0
  25. package/skills/mudra-master/mudra-preview/assets/smart-home.html +461 -0
  26. package/skills/mudra-master/mudra-preview/assets/space-invaders.html +1154 -0
  27. package/skills/mudra-master/mudra-preview/assets/waterful-ring-toss.html +1624 -0
  28. package/skills/mudra-master/mudra-preview/references/agent_protocol.json +646 -0
  29. package/skills/mudra-master/mudra-preview/references/promt.md +16829 -0
  30. package/skills/mudra-master/mudra-xr/SKILL.md +245 -0
  31. package/skills/mudra-master/mudra-xr/assets/demos/3dgs-walkthrough.html +242 -0
  32. package/skills/mudra-master/mudra-xr/assets/demos/aisimulator.html +792 -0
  33. package/skills/mudra-master/mudra-xr/assets/demos/balloonpop.html +422 -0
  34. package/skills/mudra-master/mudra-xr/assets/demos/ballpit.html +284 -0
  35. package/skills/mudra-master/mudra-xr/assets/demos/drone.html +41 -0
  36. package/skills/mudra-master/mudra-xr/assets/demos/gemini-icebreakers.html +338 -0
  37. package/skills/mudra-master/mudra-xr/assets/demos/gemini-xrobject.html +302 -0
  38. package/skills/mudra-master/mudra-xr/assets/demos/math3d.html +188 -0
  39. package/skills/mudra-master/mudra-xr/assets/demos/measure.html +247 -0
  40. package/skills/mudra-master/mudra-xr/assets/demos/occlusion.html +251 -0
  41. package/skills/mudra-master/mudra-xr/assets/demos/rain.html +498 -0
  42. package/skills/mudra-master/mudra-xr/assets/demos/screenwiper.html +432 -0
  43. package/skills/mudra-master/mudra-xr/assets/demos/splash.html +519 -0
  44. package/skills/mudra-master/mudra-xr/assets/demos/webcam_gestures.html +253 -0
  45. package/skills/mudra-master/mudra-xr/assets/demos/xremoji.html +833 -0
  46. package/skills/mudra-master/mudra-xr/assets/demos/xrpoet.html +151 -0
  47. package/skills/mudra-master/mudra-xr/assets/samples/depthmap.html +266 -0
  48. package/skills/mudra-master/mudra-xr/assets/samples/depthmesh.html +100 -0
  49. package/skills/mudra-master/mudra-xr/assets/samples/game_rps.html +1099 -0
  50. package/skills/mudra-master/mudra-xr/assets/samples/gestures_custom.html +467 -0
  51. package/skills/mudra-master/mudra-xr/assets/samples/gestures_heuristic.html +256 -0
  52. package/skills/mudra-master/mudra-xr/assets/samples/lighting.html +163 -0
  53. package/skills/mudra-master/mudra-xr/assets/samples/mesh_detection.html +46 -0
  54. package/skills/mudra-master/mudra-xr/assets/samples/modelviewer.html +183 -0
  55. package/skills/mudra-master/mudra-xr/assets/samples/paint.html +133 -0
  56. package/skills/mudra-master/mudra-xr/assets/samples/planar-vst.html +45 -0
  57. package/skills/mudra-master/mudra-xr/assets/samples/reticle.html +95 -0
  58. package/skills/mudra-master/mudra-xr/assets/samples/skybox_agent.html +384 -0
  59. package/skills/mudra-master/mudra-xr/assets/samples/sound.html +390 -0
  60. package/skills/mudra-master/mudra-xr/assets/samples/ui.html +496 -0
  61. package/skills/mudra-master/mudra-xr/assets/samples/virtual-screens.html +808 -0
  62. package/skills/mudra-master/mudra-xr/assets/templates/0_basic.html +64 -0
  63. package/skills/mudra-master/mudra-xr/assets/templates/1_ui.html +107 -0
  64. package/skills/mudra-master/mudra-xr/assets/templates/2_hands.html +183 -0
  65. package/skills/mudra-master/mudra-xr/assets/templates/3_depth.html +89 -0
  66. package/skills/mudra-master/mudra-xr/assets/templates/4_stereo.html +84 -0
  67. package/skills/mudra-master/mudra-xr/assets/templates/5_camera.html +117 -0
  68. package/skills/mudra-master/mudra-xr/assets/templates/6_ai.html +154 -0
  69. package/skills/mudra-master/mudra-xr/assets/templates/7_ai_live.html +253 -0
  70. package/skills/mudra-master/mudra-xr/assets/templates/8_objects.html +95 -0
  71. package/skills/mudra-master/mudra-xr/assets/templates/9_xr-toggle.html +90 -0
  72. package/skills/mudra-master/mudra-xr/assets/templates/heuristic_hand_gestures.html +102 -0
  73. package/skills/mudra-master/mudra-xr/assets/templates/meshes.html +47 -0
  74. package/skills/mudra-master/mudra-xr/assets/templates/planes.html +47 -0
  75. package/skills/mudra-master/mudra-xr/assets/templates/uikit.html +187 -0
  76. package/skills/mudra-master/mudra-xr/references/agent_protocol.json +878 -0
  77. package/skills/mudra-master/mudra-xr/references/promt.md +1516 -0
  78. package/skills/mudra-preview/SKILL.md +151 -0
  79. package/skills/mudra-preview/assets/ar-menu.html +382 -0
  80. package/skills/mudra-preview/assets/document-scroller.html +468 -0
  81. package/skills/mudra-preview/assets/drum-machine.html +788 -0
  82. package/skills/mudra-preview/assets/emg-visualizer.html +390 -0
  83. package/skills/mudra-preview/assets/generative-art.html +408 -0
  84. package/skills/mudra-preview/assets/gesture-assistant.html +342 -0
  85. package/skills/mudra-preview/assets/gesture-speech.html +444 -0
  86. package/skills/mudra-preview/assets/hands-free-desktop.html +376 -0
  87. package/skills/mudra-preview/assets/model-rotator.html +365 -0
  88. package/skills/mudra-preview/assets/mudra-duel.html +3200 -0
  89. package/skills/mudra-preview/assets/mudra-monitor.html +1451 -0
  90. package/skills/mudra-preview/assets/mudra-ultimate-template.html +891 -0
  91. package/skills/mudra-preview/assets/music-sequencer.html +455 -0
  92. package/skills/mudra-preview/assets/neural-pong.html +380 -0
  93. package/skills/mudra-preview/assets/neural-snake.html +364 -0
  94. package/skills/mudra-preview/assets/presentation-controller.html +345 -0
  95. package/skills/mudra-preview/assets/pressure-painter.html +285 -0
  96. package/skills/mudra-preview/assets/runner.html +1812 -0
  97. package/skills/mudra-preview/assets/smart-home.html +461 -0
  98. package/skills/mudra-preview/assets/space-invaders.html +1154 -0
  99. package/skills/mudra-preview/assets/waterful-ring-toss.html +1624 -0
  100. package/skills/mudra-preview/references/agent_protocol.json +646 -0
  101. package/skills/mudra-preview/references/promt.md +16829 -0
  102. package/skills/mudra-xr/SKILL.md +245 -0
  103. package/skills/mudra-xr/assets/demos/3dgs-walkthrough.html +242 -0
  104. package/skills/mudra-xr/assets/demos/aisimulator.html +792 -0
  105. package/skills/mudra-xr/assets/demos/balloonpop.html +422 -0
  106. package/skills/mudra-xr/assets/demos/ballpit.html +284 -0
  107. package/skills/mudra-xr/assets/demos/drone.html +41 -0
  108. package/skills/mudra-xr/assets/demos/gemini-icebreakers.html +338 -0
  109. package/skills/mudra-xr/assets/demos/gemini-xrobject.html +302 -0
  110. package/skills/mudra-xr/assets/demos/math3d.html +188 -0
  111. package/skills/mudra-xr/assets/demos/measure.html +247 -0
  112. package/skills/mudra-xr/assets/demos/occlusion.html +251 -0
  113. package/skills/mudra-xr/assets/demos/rain.html +498 -0
  114. package/skills/mudra-xr/assets/demos/screenwiper.html +432 -0
  115. package/skills/mudra-xr/assets/demos/splash.html +519 -0
  116. package/skills/mudra-xr/assets/demos/webcam_gestures.html +253 -0
  117. package/skills/mudra-xr/assets/demos/xremoji.html +833 -0
  118. package/skills/mudra-xr/assets/demos/xrpoet.html +151 -0
  119. package/skills/mudra-xr/assets/samples/depthmap.html +266 -0
  120. package/skills/mudra-xr/assets/samples/depthmesh.html +100 -0
  121. package/skills/mudra-xr/assets/samples/game_rps.html +1099 -0
  122. package/skills/mudra-xr/assets/samples/gestures_custom.html +467 -0
  123. package/skills/mudra-xr/assets/samples/gestures_heuristic.html +256 -0
  124. package/skills/mudra-xr/assets/samples/lighting.html +163 -0
  125. package/skills/mudra-xr/assets/samples/mesh_detection.html +46 -0
  126. package/skills/mudra-xr/assets/samples/modelviewer.html +183 -0
  127. package/skills/mudra-xr/assets/samples/paint.html +133 -0
  128. package/skills/mudra-xr/assets/samples/planar-vst.html +45 -0
  129. package/skills/mudra-xr/assets/samples/reticle.html +95 -0
  130. package/skills/mudra-xr/assets/samples/skybox_agent.html +384 -0
  131. package/skills/mudra-xr/assets/samples/sound.html +390 -0
  132. package/skills/mudra-xr/assets/samples/ui.html +496 -0
  133. package/skills/mudra-xr/assets/samples/virtual-screens.html +808 -0
  134. package/skills/mudra-xr/assets/templates/0_basic.html +64 -0
  135. package/skills/mudra-xr/assets/templates/1_ui.html +107 -0
  136. package/skills/mudra-xr/assets/templates/2_hands.html +183 -0
  137. package/skills/mudra-xr/assets/templates/3_depth.html +89 -0
  138. package/skills/mudra-xr/assets/templates/4_stereo.html +84 -0
  139. package/skills/mudra-xr/assets/templates/5_camera.html +117 -0
  140. package/skills/mudra-xr/assets/templates/6_ai.html +154 -0
  141. package/skills/mudra-xr/assets/templates/7_ai_live.html +253 -0
  142. package/skills/mudra-xr/assets/templates/8_objects.html +95 -0
  143. package/skills/mudra-xr/assets/templates/9_xr-toggle.html +90 -0
  144. package/skills/mudra-xr/assets/templates/heuristic_hand_gestures.html +102 -0
  145. package/skills/mudra-xr/assets/templates/meshes.html +47 -0
  146. package/skills/mudra-xr/assets/templates/planes.html +47 -0
  147. package/skills/mudra-xr/assets/templates/uikit.html +187 -0
  148. package/skills/mudra-xr/references/agent_protocol.json +878 -0
  149. package/skills/mudra-xr/references/promt.md +1516 -0
@@ -0,0 +1,364 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <title>Neural Snake — Mudra Studio</title>
7
+ <style>
8
+ @media (prefers-reduced-motion: reduce) {
9
+ *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
10
+ }
11
+
12
+ :root {
13
+ --bg: #ffffff; --card: #f1f5f9; --primary: #0d9488; --accent: #14b8a6;
14
+ --text: #0f172a; --text-secondary: #475569; --success: #16a34a;
15
+ --warning: #ca8a04; --error: #dc2626;
16
+ --border: rgba(15,23,42,0.12); --surface: rgba(0,0,0,0.04);
17
+ --grid-line: rgba(13,148,136,0.08); --game-bg: #f0fdfa;
18
+ }
19
+
20
+ * { margin: 0; padding: 0; box-sizing: border-box; }
21
+ body { background: var(--bg); color: var(--text); font-family: 'Poppins', system-ui, sans-serif; overflow: hidden; height: 100vh; display: flex; flex-direction: column; }
22
+
23
+ .header { display: flex; align-items: center; justify-content: space-between; padding: 10px 16px; background: var(--card); border-bottom: 1px solid var(--border); z-index: 100; flex-shrink: 0; gap: 8px; flex-wrap: wrap; }
24
+ .header-left, .header-right { display: flex; align-items: center; gap: 10px; }
25
+ .brand { font-weight: 700; font-size: 14px; } .brand span { color: var(--primary); }
26
+ .dot { width: 9px; height: 9px; border-radius: 50%; background: var(--warning); box-shadow: 0 0 0 3px rgba(234,179,8,0.15); transition: all 150ms; }
27
+ .dot.live { background: var(--success); box-shadow: 0 0 0 3px rgba(34,197,94,0.18); }
28
+ .conn-label { font-size: 12px; color: var(--text-secondary); }
29
+
30
+ .btn { background: var(--surface); border: 1px solid var(--border); color: var(--text-secondary); padding: 5px 12px; border-radius: 8px; font-size: 12px; cursor: pointer; font-family: inherit; transition: border-color 150ms, color 150ms; white-space: nowrap; }
31
+ .btn:hover { border-color: var(--primary); color: var(--primary); }
32
+
33
+ .score-bar { display: flex; align-items: center; justify-content: center; gap: 32px; padding: 8px 16px; flex-shrink: 0; }
34
+ .score-item { text-align: center; }
35
+ .score-label { font-size: 10px; color: var(--text-secondary); text-transform: uppercase; letter-spacing: 1px; }
36
+ .score-value { font-size: 24px; font-weight: 800; color: var(--primary); font-variant-numeric: tabular-nums; }
37
+
38
+ .game-wrap { flex: 1; display: flex; justify-content: center; align-items: center; padding: 0 12px 12px; position: relative; }
39
+ canvas { background: var(--game-bg); border: 1px solid var(--border); border-radius: 12px; max-width: 100%; max-height: 100%; }
40
+
41
+ .boost-indicator { position: absolute; top: 16px; right: 24px; background: rgba(119,234,233,0.12); border: 1px solid var(--primary); color: var(--primary); padding: 5px 14px; border-radius: 8px; font-size: 12px; font-weight: 700; letter-spacing: 1px; opacity: 0; transition: opacity 200ms; z-index: 15; }
42
+ .boost-indicator.show { opacity: 1; }
43
+
44
+ .overlay { position: fixed; inset: 0; display: flex; flex-direction: column; justify-content: center; align-items: center; background: rgba(0,0,0,0.8); z-index: 90; opacity: 0; pointer-events: none; transition: opacity 300ms; }
45
+ .overlay.show { opacity: 1; pointer-events: auto; }
46
+ .overlay h2 { font-size: 36px; font-weight: 800; margin-bottom: 8px; }
47
+ .overlay h2 em { font-style: normal; color: var(--primary); }
48
+ .overlay p { color: var(--text-secondary); font-size: 16px; }
49
+
50
+ .toolbar { display: flex; align-items: center; justify-content: space-between; gap: 14px; padding: 10px 16px; background: var(--card); border-top: 1px solid var(--border); z-index: 100; flex-shrink: 0; flex-wrap: wrap; }
51
+ .sig-row { display: flex; gap: 14px; }
52
+ .sig { font-size: 11px; color: var(--text-secondary); font-variant-numeric: tabular-nums; }
53
+ .sig b { color: var(--primary); font-weight: 600; }
54
+ .hint { font-size: 11px; color: var(--text-secondary); opacity: 0.6; }
55
+
56
+ .mudra-badge { position: fixed; bottom: 12px; right: 12px; font-size: 11px; color: var(--text-secondary); opacity: 0.7; letter-spacing: 0.02em; pointer-events: none; z-index: 200; }
57
+
58
+ @media (max-width: 640px) {
59
+ .header { padding: 8px 10px; } .toolbar { gap: 8px; padding: 8px 10px; }
60
+ .hint { display: none; } .score-bar { gap: 20px; padding: 6px 12px; }
61
+ }
62
+ </style>
63
+ </head>
64
+ <body>
65
+
66
+ <div class="header">
67
+ <div class="header-left">
68
+ <div class="brand"><span>Mudra</span> Neural Snake</div>
69
+ <span class="dot" id="dot"></span>
70
+ <span class="conn-label" id="connLabel">Connecting&hellip;</span>
71
+ </div>
72
+ <div class="header-right">
73
+ <a href="/gallery" class="btn" style="text-decoration:none;">&#8592; Gallery</a>
74
+ <button class="btn" id="simTap">Simulate Tap</button>
75
+ <button class="btn" id="simRestart">Restart</button>
76
+ </div>
77
+ </div>
78
+
79
+ <div class="score-bar">
80
+ <div class="score-item"><div class="score-label">Score</div><div class="score-value" id="score">0</div></div>
81
+ <div class="score-item"><div class="score-label">Speed</div><div class="score-value" id="speed">1x</div></div>
82
+ <div class="score-item"><div class="score-label">High Score</div><div class="score-value" id="highScore">0</div></div>
83
+ </div>
84
+
85
+ <div class="game-wrap">
86
+ <canvas id="canvas" width="400" height="400"></canvas>
87
+ <div class="boost-indicator" id="boostInd">BOOST</div>
88
+ </div>
89
+
90
+ <div class="overlay" id="overlay">
91
+ <h2>Game <em>Over</em></h2>
92
+ <p id="overMsg">Score: 0 — Restarting in 3s...</p>
93
+ </div>
94
+
95
+ <div class="toolbar">
96
+ <span class="hint">Arrows steer &middot; Space boost &middot; R restart &middot; G toggle grid</span>
97
+ <div class="sig-row">
98
+ <div class="sig">dX: <b id="vDx">0</b></div>
99
+ <div class="sig">dY: <b id="vDy">0</b></div>
100
+ <div class="sig">Dir: <b id="vDir">RIGHT</b></div>
101
+ </div>
102
+ </div>
103
+
104
+ <div class="mudra-badge">Created by Mudra</div>
105
+
106
+ <script>
107
+ /* ── Mudra Protocol Connection (v2) ────────────────────────── */
108
+ const WS_URL = 'ws://127.0.0.1:8766';
109
+ const SIGNALS = ['navigation', 'gesture'];
110
+
111
+ let ws, reconnectTimer, simTimer;
112
+ let wsOpen = false, deviceReady = false, simulating = true;
113
+ const bus = {};
114
+
115
+ function on(ev, fn) { (bus[ev] ??= []).push(fn); }
116
+ function emit(ev, d) { (bus[ev] || []).forEach(fn => fn(d)); }
117
+ function send(p) { if (ws?.readyState === WebSocket.OPEN) ws.send(JSON.stringify(p)); }
118
+
119
+ function connect() {
120
+ try {
121
+ ws = new WebSocket(WS_URL);
122
+ ws.onopen = () => {
123
+ wsOpen = true; stopSim(); updateStatus();
124
+ SIGNALS.forEach(s => send({ command: 'subscribe', signal: s }));
125
+ };
126
+ ws.onmessage = (e) => {
127
+ try {
128
+ const msg = JSON.parse(e.data);
129
+ if (msg.type === 'connection_status') {
130
+ deviceReady = msg.data?.status === 'connected';
131
+ updateStatus(); return;
132
+ }
133
+ emit(msg.type, msg.data);
134
+ } catch {}
135
+ };
136
+ ws.onclose = () => {
137
+ wsOpen = false; deviceReady = false; updateStatus();
138
+ startSim();
139
+ clearTimeout(reconnectTimer);
140
+ reconnectTimer = setTimeout(connect, 1500);
141
+ };
142
+ ws.onerror = () => ws?.close();
143
+ } catch {
144
+ wsOpen = false; startSim();
145
+ clearTimeout(reconnectTimer);
146
+ reconnectTimer = setTimeout(connect, 1500);
147
+ }
148
+ }
149
+
150
+ function triggerGesture(type) {
151
+ if (wsOpen) send({ command: 'trigger_gesture', data: { type } });
152
+ else emit('gesture', { type, confidence: 0.95, timestamp: Date.now() });
153
+ }
154
+
155
+ /* ── Simulation (when Companion not reachable) ─────────────── */
156
+ function startSim() {
157
+ if (simTimer) return;
158
+ simulating = true;
159
+ let t = 0;
160
+ simTimer = setInterval(() => {
161
+ t += 0.05;
162
+ // Navigate toward food
163
+ if (!gameOver && food) {
164
+ const head = snake[0];
165
+ let dx = food.x - head.x;
166
+ let dy = food.y - head.y;
167
+ // Add occasional random deviation
168
+ if (Math.random() < 0.15) {
169
+ dx += (Math.random() - 0.5) * 8;
170
+ dy += (Math.random() - 0.5) * 8;
171
+ }
172
+ emit('navigation', { delta_x: dx * 0.8, delta_y: dy * 0.8, timestamp: Date.now() });
173
+ }
174
+ // Occasional gestures
175
+ if (Math.random() < 0.003) {
176
+ const g = ['tap', 'double_tap', 'twist', 'double_twist'];
177
+ emit('gesture', { type: g[Math.floor(Math.random() * g.length)], confidence: 0.7 + Math.random() * 0.3, timestamp: Date.now() });
178
+ }
179
+ }, 60);
180
+ }
181
+
182
+ function stopSim() { clearInterval(simTimer); simTimer = null; simulating = false; }
183
+
184
+ /* ── Status UI ─────────────────────────────────────────────── */
185
+ const dotEl = document.getElementById('dot');
186
+ const connEl = document.getElementById('connLabel');
187
+
188
+ function updateStatus() {
189
+ if (wsOpen && deviceReady) { dotEl.className = 'dot live'; connEl.textContent = 'Connected'; }
190
+ else if (wsOpen) { dotEl.className = 'dot'; connEl.textContent = 'Waiting for Mudra Band\u2026'; }
191
+ else { dotEl.className = 'dot'; connEl.textContent = simulating ? 'Simulated' : 'Disconnected'; }
192
+ }
193
+
194
+ /* ── Game Setup ────────────────────────────────────────────── */
195
+ const canvas = document.getElementById('canvas');
196
+ const ctx = canvas.getContext('2d');
197
+ const GRID = 20;
198
+ const CELL = canvas.width / GRID;
199
+
200
+ let snake, dir, nextDir, food, score, highScore = 0, gameOver, boosted, boostEnd;
201
+ let showGrid = true;
202
+ const baseInterval = 150;
203
+ let lastTick = 0;
204
+
205
+ // Accumulate navigation deltas to determine direction
206
+ let navAccX = 0, navAccY = 0;
207
+ const NAV_THRESHOLD = 3;
208
+
209
+ function init() {
210
+ snake = [{ x: 10, y: 10 }, { x: 9, y: 10 }, { x: 8, y: 10 }];
211
+ dir = { x: 1, y: 0 }; nextDir = { x: 1, y: 0 };
212
+ score = 0; gameOver = false; boosted = false; boostEnd = 0;
213
+ navAccX = 0; navAccY = 0;
214
+ placeFood();
215
+ document.getElementById('score').textContent = '0';
216
+ document.getElementById('speed').textContent = '1x';
217
+ document.getElementById('overlay').classList.remove('show');
218
+ }
219
+
220
+ function placeFood() {
221
+ let attempts = 0;
222
+ do {
223
+ food = { x: Math.floor(Math.random() * GRID), y: Math.floor(Math.random() * GRID) };
224
+ attempts++;
225
+ } while (snake.some(s => s.x === food.x && s.y === food.y) && attempts < 200);
226
+ }
227
+
228
+ function tick(now) {
229
+ requestAnimationFrame(tick);
230
+ if (gameOver) { draw(); return; }
231
+ const interval = boosted && now < boostEnd ? baseInterval / 2 : baseInterval;
232
+ if (now - lastTick < interval) { draw(); return; }
233
+ lastTick = now;
234
+
235
+ if (boosted && now >= boostEnd) { boosted = false; document.getElementById('boostInd').classList.remove('show'); document.getElementById('speed').textContent = '1x'; }
236
+
237
+ dir = nextDir;
238
+ const head = { x: snake[0].x + dir.x, y: snake[0].y + dir.y };
239
+
240
+ if (head.x < 0 || head.x >= GRID || head.y < 0 || head.y >= GRID || snake.some(s => s.x === head.x && s.y === head.y)) {
241
+ gameOver = true;
242
+ if (score > highScore) { highScore = score; document.getElementById('highScore').textContent = String(highScore); }
243
+ document.getElementById('overlay').classList.add('show');
244
+ document.getElementById('overMsg').textContent = 'Score: ' + score + ' \u2014 Restarting in 3s...';
245
+ setTimeout(init, 3000);
246
+ return;
247
+ }
248
+
249
+ snake.unshift(head);
250
+ if (head.x === food.x && head.y === food.y) {
251
+ score++;
252
+ document.getElementById('score').textContent = String(score);
253
+ placeFood();
254
+ } else {
255
+ snake.pop();
256
+ }
257
+ draw();
258
+ }
259
+
260
+ function draw() {
261
+ const w = canvas.width, h = canvas.height;
262
+ // Background
263
+ const cs = getComputedStyle(document.documentElement);
264
+ ctx.fillStyle = cs.getPropertyValue('--game-bg').trim() || '#0a0f12';
265
+ ctx.fillRect(0, 0, w, h);
266
+
267
+ // Grid lines
268
+ if (showGrid) {
269
+ ctx.strokeStyle = cs.getPropertyValue('--grid-line').trim() || 'rgba(119,234,233,0.06)';
270
+ ctx.lineWidth = 0.5;
271
+ for (let i = 0; i <= GRID; i++) {
272
+ ctx.beginPath(); ctx.moveTo(i * CELL, 0); ctx.lineTo(i * CELL, h); ctx.stroke();
273
+ ctx.beginPath(); ctx.moveTo(0, i * CELL); ctx.lineTo(w, i * CELL); ctx.stroke();
274
+ }
275
+ }
276
+
277
+ // Food
278
+ const primary = cs.getPropertyValue('--accent').trim() || '#2dd4bf';
279
+ ctx.fillStyle = primary;
280
+ ctx.beginPath();
281
+ ctx.arc(food.x * CELL + CELL / 2, food.y * CELL + CELL / 2, CELL / 2.5, 0, Math.PI * 2);
282
+ ctx.fill();
283
+
284
+ // Snake
285
+ const headColor = cs.getPropertyValue('--primary').trim() || '#77EAE9';
286
+ snake.forEach((s, i) => {
287
+ const alpha = 1 - (i / snake.length) * 0.5;
288
+ if (i === 0) {
289
+ ctx.fillStyle = headColor;
290
+ } else {
291
+ ctx.fillStyle = `rgba(119,234,233,${alpha})`;
292
+ }
293
+ const pad = i === 0 ? 1 : 2;
294
+ ctx.beginPath();
295
+ ctx.roundRect(s.x * CELL + pad, s.y * CELL + pad, CELL - pad * 2, CELL - pad * 2, 4);
296
+ ctx.fill();
297
+ });
298
+ }
299
+
300
+ /* ── Signal Handlers ───────────────────────────────────────── */
301
+ on('navigation', (d) => {
302
+ const dx = d.delta_x || 0;
303
+ const dy = d.delta_y || 0;
304
+ document.getElementById('vDx').textContent = dx.toFixed(1);
305
+ document.getElementById('vDy').textContent = dy.toFixed(1);
306
+
307
+ navAccX += dx;
308
+ navAccY += dy;
309
+
310
+ // Determine direction from accumulated deltas
311
+ if (Math.abs(navAccX) > NAV_THRESHOLD || Math.abs(navAccY) > NAV_THRESHOLD) {
312
+ let nd = null;
313
+ if (Math.abs(navAccX) > Math.abs(navAccY)) {
314
+ nd = navAccX > 0 ? { x: 1, y: 0 } : { x: -1, y: 0 };
315
+ } else {
316
+ nd = navAccY > 0 ? { x: 0, y: 1 } : { x: 0, y: -1 };
317
+ }
318
+ // Prevent 180-degree reversal
319
+ if (nd && !(nd.x === -dir.x && nd.y === -dir.y)) {
320
+ nextDir = nd;
321
+ const names = { '1,0': 'RIGHT', '-1,0': 'LEFT', '0,1': 'DOWN', '0,-1': 'UP' };
322
+ document.getElementById('vDir').textContent = names[nd.x + ',' + nd.y] || '';
323
+ }
324
+ navAccX = 0;
325
+ navAccY = 0;
326
+ }
327
+ });
328
+
329
+ on('gesture', (d) => {
330
+ const type = d.type || 'unknown';
331
+ if (type === 'tap') {
332
+ boosted = true;
333
+ boostEnd = performance.now() + 2000;
334
+ document.getElementById('boostInd').classList.add('show');
335
+ document.getElementById('speed').textContent = '2x';
336
+ }
337
+ if (type === 'double_tap') init();
338
+ if (type === 'twist') {
339
+ showGrid = !showGrid;
340
+ }
341
+ });
342
+
343
+ /* ── Keyboard Fallback ─────────────────────────────────────── */
344
+ document.addEventListener('keydown', (e) => {
345
+ if (e.code === 'ArrowRight') { e.preventDefault(); emit('navigation', { delta_x: 10, delta_y: 0, timestamp: Date.now() }); }
346
+ if (e.code === 'ArrowLeft') { e.preventDefault(); emit('navigation', { delta_x: -10, delta_y: 0, timestamp: Date.now() }); }
347
+ if (e.code === 'ArrowDown') { e.preventDefault(); emit('navigation', { delta_x: 0, delta_y: 10, timestamp: Date.now() }); }
348
+ if (e.code === 'ArrowUp') { e.preventDefault(); emit('navigation', { delta_x: 0, delta_y: -10, timestamp: Date.now() }); }
349
+ if (e.code === 'Space') { e.preventDefault(); triggerGesture('tap'); }
350
+ if (e.code === 'KeyR') triggerGesture('double_tap');
351
+ if (e.code === 'KeyG') triggerGesture('twist');
352
+ });
353
+
354
+ /* ── Buttons ───────────────────────────────────────────────── */
355
+ document.getElementById('simTap').addEventListener('click', () => triggerGesture('tap'));
356
+ document.getElementById('simRestart').addEventListener('click', () => triggerGesture('double_tap'));
357
+
358
+ /* ── Init ──────────────────────────────────────────────────── */
359
+ init();
360
+ connect();
361
+ requestAnimationFrame(tick);
362
+ </script>
363
+ </body>
364
+ </html>