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,376 @@
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>Hands-Free Desktop — 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
+ --desktop-bg: #e2e8f0;
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: 200; 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
+ .desktop { flex: 1; position: relative; overflow: hidden; background: var(--desktop-bg); background-image:
34
+ linear-gradient(rgba(119,234,233,0.03) 1px, transparent 1px),
35
+ linear-gradient(90deg, rgba(119,234,233,0.03) 1px, transparent 1px);
36
+ background-size: 48px 48px; }
37
+
38
+ .icon-grid { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); display: grid; grid-template-columns: repeat(3, 1fr); gap: 28px; }
39
+ .app-icon { width: 96px; height: 96px; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px; border-radius: 16px; background: var(--card); border: 1px solid var(--border); cursor: default; transition: all 200ms; user-select: none; }
40
+ .app-icon.hovered { border-color: var(--primary); background: rgba(119,234,233,0.06); box-shadow: 0 0 20px rgba(119,234,233,0.12); transform: scale(1.06); }
41
+ .app-icon.clicked { animation: iconBounce 0.25s ease; }
42
+ @keyframes iconBounce { 0%{transform:scale(1.06)} 50%{transform:scale(0.94)} 100%{transform:scale(1.06)} }
43
+ .icon-emoji { font-size: 28px; line-height: 1; }
44
+ .icon-label { font-size: 11px; color: var(--text-secondary); font-weight: 500; }
45
+ .app-icon.hovered .icon-label { color: var(--primary); }
46
+
47
+ /* Cursor */
48
+ .cursor { position: absolute; width: 20px; height: 20px; pointer-events: none; z-index: 100; }
49
+ .cursor::before { content: ''; position: absolute; top: 0; left: 0; width: 0; height: 0; border-left: 11px solid var(--primary); border-top: 6px solid transparent; border-bottom: 6px solid transparent; filter: drop-shadow(0 0 4px rgba(119,234,233,0.5)); transform: rotate(-30deg); }
50
+ .cursor.dragging::after { content: ''; position: absolute; top: 14px; left: 2px; width: 6px; height: 6px; border-radius: 50%; background: var(--accent); box-shadow: 0 0 6px var(--accent); }
51
+
52
+ /* Context Menu */
53
+ .ctx-menu { position: absolute; background: var(--card); border: 1px solid var(--border); border-radius: 10px; padding: 4px; z-index: 250; min-width: 140px; opacity: 0; transform: scale(0.95); transition: all 150ms; pointer-events: none; }
54
+ .ctx-menu.visible { opacity: 1; transform: scale(1); pointer-events: auto; }
55
+ .ctx-item { padding: 7px 14px; font-size: 12px; color: var(--text-secondary); border-radius: 6px; cursor: default; }
56
+ .ctx-item:hover { background: var(--surface); color: var(--primary); }
57
+ .ctx-sep { height: 1px; background: var(--border); margin: 2px 0; }
58
+
59
+ /* App Window Modal */
60
+ .app-modal { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%) scale(0.95); width: 340px; background: var(--card); border: 1px solid var(--border); border-radius: 14px; z-index: 180; opacity: 0; pointer-events: none; transition: all 200ms; box-shadow: 0 16px 40px rgba(0,0,0,0.4); }
61
+ .app-modal.visible { opacity: 1; transform: translate(-50%, -50%) scale(1); pointer-events: auto; }
62
+ .modal-header { display: flex; align-items: center; justify-content: space-between; padding: 12px 16px; border-bottom: 1px solid var(--border); }
63
+ .modal-title { font-size: 14px; font-weight: 600; }
64
+ .modal-close { font-size: 16px; color: var(--text-secondary); cursor: pointer; background: none; border: none; line-height: 1; padding: 2px 6px; border-radius: 4px; }
65
+ .modal-close:hover { color: var(--error); }
66
+ .modal-body { padding: 24px 16px; text-align: center; color: var(--text-secondary); font-size: 13px; }
67
+
68
+ /* Taskbar */
69
+ .taskbar { display: flex; align-items: center; justify-content: center; gap: 14px; padding: 8px 16px; background: var(--card); border-top: 1px solid var(--border); z-index: 200; flex-shrink: 0; flex-wrap: wrap; }
70
+ .hint { font-size: 11px; color: var(--text-secondary); opacity: 0.6; }
71
+
72
+ .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: 300; }
73
+
74
+ @media (max-width: 640px) {
75
+ .header { padding: 8px 10px; } .taskbar { gap: 8px; padding: 6px 10px; }
76
+ .icon-grid { gap: 14px; }
77
+ .app-icon { width: 74px; height: 74px; border-radius: 12px; }
78
+ .icon-emoji { font-size: 22px; } .icon-label { font-size: 10px; }
79
+ .hint { display: none; }
80
+ .app-modal { width: 280px; }
81
+ }
82
+ </style>
83
+ </head>
84
+ <body>
85
+
86
+ <div class="header">
87
+ <div class="header-left">
88
+ <div class="brand"><span>Mudra</span> Hands-Free Desktop</div>
89
+ <span class="dot" id="dot"></span>
90
+ <span class="conn-label" id="connLabel">Connecting&hellip;</span>
91
+ </div>
92
+ <div class="header-right">
93
+ <a href="/gallery" class="btn" style="text-decoration:none;">&#8592; Gallery</a>
94
+ <button class="btn" id="simTap">Simulate Tap</button>
95
+ <button class="btn" id="simDTap">Simulate Double-Tap</button>
96
+ <button class="btn" id="simTwist">Simulate Twist</button>
97
+ </div>
98
+ </div>
99
+
100
+ <div class="desktop" id="desktop">
101
+ <div class="icon-grid" id="iconGrid"></div>
102
+ <div class="cursor" id="cursor"></div>
103
+ </div>
104
+
105
+ <div class="ctx-menu" id="ctxMenu">
106
+ <div class="ctx-item" data-action="open">Open</div>
107
+ <div class="ctx-item" data-action="info">Get Info</div>
108
+ <div class="ctx-sep"></div>
109
+ <div class="ctx-item" data-action="remove">Move to Trash</div>
110
+ </div>
111
+
112
+ <div class="app-modal" id="appModal">
113
+ <div class="modal-header">
114
+ <span class="modal-title" id="modalTitle">App</span>
115
+ <button class="modal-close" id="modalClose">&times;</button>
116
+ </div>
117
+ <div class="modal-body" id="modalBody">Content</div>
118
+ </div>
119
+
120
+ <div class="taskbar">
121
+ <button class="btn" id="clickBtn">Click</button>
122
+ <button class="btn" id="dblBtn">Double-Click</button>
123
+ <span class="hint">Arrows move &middot; Space click &middot; D double-click &middot; T twist &middot; Shift drag</span>
124
+ </div>
125
+
126
+ <div class="mudra-badge">Created by Mudra</div>
127
+
128
+ <script>
129
+ /* ── Mudra Protocol Connection (v2) ────────────────────────── */
130
+ const WS_URL = 'ws://127.0.0.1:8766';
131
+ const SIGNALS = ['navigation', 'gesture', 'button'];
132
+
133
+ let ws, reconnectTimer, simTimer;
134
+ let wsOpen = false, deviceReady = false, simulating = true;
135
+ const bus = {};
136
+
137
+ function on(ev, fn) { (bus[ev] ??= []).push(fn); }
138
+ function emit(ev, d) { (bus[ev] || []).forEach(fn => fn(d)); }
139
+ function send(p) { if (ws?.readyState === WebSocket.OPEN) ws.send(JSON.stringify(p)); }
140
+
141
+ function connect() {
142
+ try {
143
+ ws = new WebSocket(WS_URL);
144
+ ws.onopen = () => {
145
+ wsOpen = true; stopSim(); updateStatus();
146
+ SIGNALS.forEach(s => send({ command: 'subscribe', signal: s }));
147
+ };
148
+ ws.onmessage = (e) => {
149
+ try {
150
+ const msg = JSON.parse(e.data);
151
+ if (msg.type === 'connection_status') {
152
+ deviceReady = msg.data?.status === 'connected';
153
+ updateStatus(); return;
154
+ }
155
+ emit(msg.type, msg.data);
156
+ } catch {}
157
+ };
158
+ ws.onclose = () => {
159
+ wsOpen = false; deviceReady = false; updateStatus();
160
+ startSim();
161
+ clearTimeout(reconnectTimer);
162
+ reconnectTimer = setTimeout(connect, 1500);
163
+ };
164
+ ws.onerror = () => ws?.close();
165
+ } catch {
166
+ wsOpen = false; startSim();
167
+ clearTimeout(reconnectTimer);
168
+ reconnectTimer = setTimeout(connect, 1500);
169
+ }
170
+ }
171
+
172
+ function triggerGesture(type) {
173
+ if (wsOpen) send({ command: 'trigger_gesture', data: { type } });
174
+ else emit('gesture', { type, confidence: 0.95, timestamp: Date.now() });
175
+ }
176
+
177
+ /* ── Simulation (when Companion not reachable) ─────────────── */
178
+ function startSim() {
179
+ if (simTimer) return;
180
+ simulating = true;
181
+ let t = 0;
182
+ simTimer = setInterval(() => {
183
+ t += 0.03;
184
+ // Figure-8 pattern
185
+ const dx = Math.cos(t * 0.5) * 3;
186
+ const dy = Math.sin(t * 1.0) * 2.5;
187
+ emit('navigation', { delta_x: dx, delta_y: dy, timestamp: Date.now() });
188
+ if (Math.random() < 0.004) {
189
+ const g = ['tap', 'double_tap', 'twist', 'double_twist'];
190
+ emit('gesture', { type: g[Math.floor(Math.random() * g.length)], confidence: 0.7 + Math.random() * 0.3, timestamp: Date.now() });
191
+ }
192
+ }, 50);
193
+ }
194
+
195
+ function stopSim() { clearInterval(simTimer); simTimer = null; simulating = false; }
196
+
197
+ /* ── Status UI ─────────────────────────────────────────────── */
198
+ const dotEl = document.getElementById('dot');
199
+ const connEl = document.getElementById('connLabel');
200
+
201
+ function updateStatus() {
202
+ if (wsOpen && deviceReady) { dotEl.className = 'dot live'; connEl.textContent = 'Connected'; }
203
+ else if (wsOpen) { dotEl.className = 'dot'; connEl.textContent = 'Waiting for Mudra Band\u2026'; }
204
+ else { dotEl.className = 'dot'; connEl.textContent = simulating ? 'Simulated' : 'Disconnected'; }
205
+ }
206
+
207
+ /* ── Desktop Apps ──────────────────────────────────────────── */
208
+ const apps = [
209
+ { name: 'Browser', emoji: '\u{1F310}', desc: 'Web browser ready. Navigate with gestures.' },
210
+ { name: 'Music', emoji: '\u{1F3B5}', desc: 'Now playing: Ambient Waves. Tap to play/pause.' },
211
+ { name: 'Photos', emoji: '\u{1F4F7}', desc: 'Photo library loaded. 247 items.' },
212
+ { name: 'Terminal', emoji: '\u{1F5A5}', desc: '$ mudra --status\nconnected | signals: 3 active' },
213
+ { name: 'Settings', emoji: '\u2699\uFE0F', desc: 'Mudra Band settings. Gesture sensitivity: High.' },
214
+ { name: 'Files', emoji: '\u{1F4C1}', desc: 'Home directory. 12 items, 3.2 GB free.' },
215
+ ];
216
+
217
+ const desktopEl = document.getElementById('desktop');
218
+ const iconGridEl = document.getElementById('iconGrid');
219
+ const cursorEl = document.getElementById('cursor');
220
+ const ctxMenuEl = document.getElementById('ctxMenu');
221
+ const appModalEl = document.getElementById('appModal');
222
+ const modalTitleEl = document.getElementById('modalTitle');
223
+ const modalBodyEl = document.getElementById('modalBody');
224
+ const modalCloseEl = document.getElementById('modalClose');
225
+
226
+ const iconEls = [];
227
+ apps.forEach(app => {
228
+ const el = document.createElement('div');
229
+ el.className = 'app-icon';
230
+ el.dataset.name = app.name;
231
+ el.dataset.desc = app.desc;
232
+ const emo = document.createElement('span');
233
+ emo.className = 'icon-emoji'; emo.textContent = app.emoji;
234
+ const lab = document.createElement('span');
235
+ lab.className = 'icon-label'; lab.textContent = app.name;
236
+ el.appendChild(emo); el.appendChild(lab);
237
+ iconGridEl.appendChild(el);
238
+ iconEls.push(el);
239
+ });
240
+
241
+ /* ── Cursor State ──────────────────────────────────────────── */
242
+ let cx = 0, cy = 0;
243
+ let dragging = false;
244
+ let hoveredIcon = null;
245
+ let modalOpen = false;
246
+
247
+ function hideCtx() { ctxMenuEl.classList.remove('visible'); }
248
+ function hideModal() { appModalEl.classList.remove('visible'); modalOpen = false; }
249
+
250
+ function openApp(name, desc) {
251
+ modalTitleEl.textContent = name;
252
+ modalBodyEl.textContent = desc;
253
+ appModalEl.classList.add('visible');
254
+ modalOpen = true;
255
+ hideCtx();
256
+ }
257
+
258
+ function clickIcon() {
259
+ hideCtx();
260
+ if (hoveredIcon) {
261
+ hoveredIcon.classList.add('clicked');
262
+ setTimeout(() => hoveredIcon.classList.remove('clicked'), 250);
263
+ }
264
+ }
265
+
266
+ function dblClickIcon() {
267
+ hideCtx();
268
+ if (hoveredIcon) {
269
+ openApp(hoveredIcon.dataset.name, hoveredIcon.dataset.desc);
270
+ }
271
+ }
272
+
273
+ function rightClickIcon() {
274
+ if (hoveredIcon) {
275
+ ctxMenuEl.style.left = Math.min(cx + 10, desktopEl.offsetWidth - 160) + 'px';
276
+ ctxMenuEl.style.top = Math.min(cy + 10, desktopEl.offsetHeight - 100) + 'px';
277
+ ctxMenuEl.classList.add('visible');
278
+ }
279
+ }
280
+
281
+ /* ── Context menu actions ── */
282
+ ctxMenuEl.querySelectorAll('.ctx-item').forEach(item => {
283
+ item.addEventListener('click', () => {
284
+ if (item.dataset.action === 'open' && hoveredIcon) dblClickIcon();
285
+ hideCtx();
286
+ });
287
+ });
288
+
289
+ modalCloseEl.addEventListener('click', hideModal);
290
+
291
+ /* ── Signal Handlers ───────────────────────────────────────── */
292
+ on('navigation', (d) => {
293
+ cx += (d.delta_x || 0) * 2;
294
+ cy += (d.delta_y || 0) * 2;
295
+ cx = Math.max(0, Math.min(desktopEl.offsetWidth - 1, cx));
296
+ cy = Math.max(0, Math.min(desktopEl.offsetHeight - 1, cy));
297
+ });
298
+
299
+ on('gesture', (d) => {
300
+ const t = d.type || '';
301
+ if (modalOpen && t === 'twist') { hideModal(); return; }
302
+ if (t === 'tap') clickIcon();
303
+ if (t === 'double_tap') dblClickIcon();
304
+ if (t === 'twist') rightClickIcon();
305
+ });
306
+
307
+ on('button', (d) => {
308
+ if (d.state === 'pressed') { dragging = true; cursorEl.classList.add('dragging'); }
309
+ if (d.state === 'released') { dragging = false; cursorEl.classList.remove('dragging'); }
310
+ });
311
+
312
+ /* ── Keyboard Fallback ─────────────────────────────────────── */
313
+ const keys = {};
314
+ document.addEventListener('keydown', (e) => {
315
+ keys[e.code] = true;
316
+ if (e.code === 'Space') { e.preventDefault(); clickIcon(); triggerGesture('tap'); }
317
+ if (e.code === 'KeyD') dblClickIcon();
318
+ if (e.code === 'KeyT') rightClickIcon();
319
+ if ((e.code === 'ShiftLeft' || e.code === 'ShiftRight') && !e.repeat) {
320
+ emit('button', { state: 'pressed', timestamp: Date.now() });
321
+ }
322
+ });
323
+ document.addEventListener('keyup', (e) => {
324
+ keys[e.code] = false;
325
+ if (e.code === 'ShiftLeft' || e.code === 'ShiftRight') {
326
+ emit('button', { state: 'released', timestamp: Date.now() });
327
+ }
328
+ });
329
+
330
+ /* ── Buttons ───────────────────────────────────────────────── */
331
+ document.getElementById('simTap').addEventListener('click', () => triggerGesture('tap'));
332
+ document.getElementById('simDTap').addEventListener('click', () => triggerGesture('double_tap'));
333
+ document.getElementById('simTwist').addEventListener('click', () => triggerGesture('twist'));
334
+ document.getElementById('clickBtn').addEventListener('click', clickIcon);
335
+ document.getElementById('dblBtn').addEventListener('click', dblClickIcon);
336
+ desktopEl.addEventListener('click', hideCtx);
337
+
338
+ /* ── Animation Loop ────────────────────────────────────────── */
339
+ function animate() {
340
+ /* Keyboard cursor movement */
341
+ const spd = 5;
342
+ if (keys['ArrowLeft']) cx -= spd;
343
+ if (keys['ArrowRight']) cx += spd;
344
+ if (keys['ArrowUp']) cy -= spd;
345
+ if (keys['ArrowDown']) cy += spd;
346
+ cx = Math.max(0, Math.min(desktopEl.offsetWidth - 1, cx));
347
+ cy = Math.max(0, Math.min(desktopEl.offsetHeight - 1, cy));
348
+
349
+ cursorEl.style.left = cx + 'px';
350
+ cursorEl.style.top = cy + 'px';
351
+
352
+ /* Hit-test icons */
353
+ let newHov = null;
354
+ const dr = desktopEl.getBoundingClientRect();
355
+ iconEls.forEach(icon => {
356
+ const r = icon.getBoundingClientRect();
357
+ const ix = r.left - dr.left, iy = r.top - dr.top;
358
+ if (cx >= ix && cx <= ix + r.width && cy >= iy && cy <= iy + r.height) newHov = icon;
359
+ });
360
+ if (hoveredIcon !== newHov) {
361
+ if (hoveredIcon) hoveredIcon.classList.remove('hovered');
362
+ hoveredIcon = newHov;
363
+ if (hoveredIcon) hoveredIcon.classList.add('hovered');
364
+ }
365
+
366
+ requestAnimationFrame(animate);
367
+ }
368
+
369
+ /* ── Init ──────────────────────────────────────────────────── */
370
+ const dR = desktopEl.getBoundingClientRect();
371
+ cx = dR.width / 2; cy = dR.height / 2;
372
+ connect();
373
+ animate();
374
+ </script>
375
+ </body>
376
+ </html>