synabun 1.3.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 (187) hide show
  1. package/CHANGELOG.md +665 -0
  2. package/LICENSE +191 -0
  3. package/README.md +853 -0
  4. package/hooks/claude-code/post-plan.mjs +391 -0
  5. package/hooks/claude-code/post-remember.mjs +239 -0
  6. package/hooks/claude-code/pre-compact.mjs +241 -0
  7. package/hooks/claude-code/pre-websearch.mjs +90 -0
  8. package/hooks/claude-code/prompt-submit.mjs +861 -0
  9. package/hooks/claude-code/session-start.mjs +494 -0
  10. package/hooks/claude-code/shared.mjs +368 -0
  11. package/hooks/claude-code/stop.mjs +646 -0
  12. package/hooks/claude-code/test-user-learning.mjs +531 -0
  13. package/mcp-server/package.json +38 -0
  14. package/mcp-server/run.mjs +10 -0
  15. package/mcp-server/src/config.ts +70 -0
  16. package/mcp-server/src/http.ts +93 -0
  17. package/mcp-server/src/index.ts +203 -0
  18. package/mcp-server/src/preload-http.ts +25 -0
  19. package/mcp-server/src/preload.ts +29 -0
  20. package/mcp-server/src/scripts/migrate-qdrant-to-sqlite.ts +506 -0
  21. package/mcp-server/src/services/categories.ts +429 -0
  22. package/mcp-server/src/services/discord.ts +702 -0
  23. package/mcp-server/src/services/file-checksums.ts +33 -0
  24. package/mcp-server/src/services/local-embeddings.ts +77 -0
  25. package/mcp-server/src/services/neural-interface.ts +344 -0
  26. package/mcp-server/src/services/sqlite.ts +823 -0
  27. package/mcp-server/src/tools/browser-advanced.ts +123 -0
  28. package/mcp-server/src/tools/browser-interact.ts +255 -0
  29. package/mcp-server/src/tools/browser-navigate.ts +77 -0
  30. package/mcp-server/src/tools/browser-observe.ts +1330 -0
  31. package/mcp-server/src/tools/browser.ts +107 -0
  32. package/mcp-server/src/tools/card-tools.ts +193 -0
  33. package/mcp-server/src/tools/card.ts +22 -0
  34. package/mcp-server/src/tools/category.ts +379 -0
  35. package/mcp-server/src/tools/discord-channel.ts +274 -0
  36. package/mcp-server/src/tools/discord-guild.ts +188 -0
  37. package/mcp-server/src/tools/discord-member.ts +158 -0
  38. package/mcp-server/src/tools/discord-message.ts +231 -0
  39. package/mcp-server/src/tools/discord-onboarding.ts +228 -0
  40. package/mcp-server/src/tools/discord-role.ts +209 -0
  41. package/mcp-server/src/tools/discord-thread.ts +110 -0
  42. package/mcp-server/src/tools/discord-webhook.ts +176 -0
  43. package/mcp-server/src/tools/discord.ts +40 -0
  44. package/mcp-server/src/tools/forget.ts +38 -0
  45. package/mcp-server/src/tools/git-tools.ts +141 -0
  46. package/mcp-server/src/tools/git.ts +13 -0
  47. package/mcp-server/src/tools/image-tools.ts +98 -0
  48. package/mcp-server/src/tools/image.ts +17 -0
  49. package/mcp-server/src/tools/leonardo-browser-tools.ts +281 -0
  50. package/mcp-server/src/tools/leonardo.ts +28 -0
  51. package/mcp-server/src/tools/loop.ts +348 -0
  52. package/mcp-server/src/tools/memories.ts +118 -0
  53. package/mcp-server/src/tools/recall.ts +323 -0
  54. package/mcp-server/src/tools/reflect.ts +145 -0
  55. package/mcp-server/src/tools/remember.ts +115 -0
  56. package/mcp-server/src/tools/response.ts +26 -0
  57. package/mcp-server/src/tools/restore.ts +34 -0
  58. package/mcp-server/src/tools/sync.ts +114 -0
  59. package/mcp-server/src/tools/tictactoe-tools.ts +98 -0
  60. package/mcp-server/src/tools/tictactoe.ts +13 -0
  61. package/mcp-server/src/tools/utils.ts +25 -0
  62. package/mcp-server/src/tools/whiteboard-tools.ts +260 -0
  63. package/mcp-server/src/tools/whiteboard.ts +22 -0
  64. package/mcp-server/src/tui.ts +940 -0
  65. package/mcp-server/src/types.ts +85 -0
  66. package/mcp-server/tsconfig.json +19 -0
  67. package/neural-interface/package.json +27 -0
  68. package/neural-interface/public/apple-touch-icon.png +0 -0
  69. package/neural-interface/public/category-logos/claude.svg +1 -0
  70. package/neural-interface/public/category-logos/gemini-color.svg +1 -0
  71. package/neural-interface/public/category-logos/openai.svg +1 -0
  72. package/neural-interface/public/category-logos/synabun.png +0 -0
  73. package/neural-interface/public/claude-chat.css +878 -0
  74. package/neural-interface/public/claude-chat.html +92 -0
  75. package/neural-interface/public/claude-chat.js +1168 -0
  76. package/neural-interface/public/favicon-16x16.png +0 -0
  77. package/neural-interface/public/favicon-32x32.png +0 -0
  78. package/neural-interface/public/gallery.svg +6 -0
  79. package/neural-interface/public/icon-192.png +0 -0
  80. package/neural-interface/public/icon-512.png +0 -0
  81. package/neural-interface/public/index-legacy.html +14677 -0
  82. package/neural-interface/public/index.html +212 -0
  83. package/neural-interface/public/index2d-legacy.html +8193 -0
  84. package/neural-interface/public/index2d.html +127 -0
  85. package/neural-interface/public/invite.html +351 -0
  86. package/neural-interface/public/leonardoai.svg +1 -0
  87. package/neural-interface/public/logo-synabun.png +0 -0
  88. package/neural-interface/public/logoHD.png +0 -0
  89. package/neural-interface/public/manifest.json +14 -0
  90. package/neural-interface/public/offline.html +299 -0
  91. package/neural-interface/public/onboarding.html +2335 -0
  92. package/neural-interface/public/openclaw-logo-text.png +0 -0
  93. package/neural-interface/public/pin-svgrepo-com.svg +25 -0
  94. package/neural-interface/public/sessionicon.svg +8 -0
  95. package/neural-interface/public/shared/ansi-parser.js +305 -0
  96. package/neural-interface/public/shared/api.js +1043 -0
  97. package/neural-interface/public/shared/colors.js +153 -0
  98. package/neural-interface/public/shared/constants.js +141 -0
  99. package/neural-interface/public/shared/html-shell.js +777 -0
  100. package/neural-interface/public/shared/html-term-renderer.js +1022 -0
  101. package/neural-interface/public/shared/i18n.js +147 -0
  102. package/neural-interface/public/shared/registry.js +82 -0
  103. package/neural-interface/public/shared/state.js +86 -0
  104. package/neural-interface/public/shared/storage.js +150 -0
  105. package/neural-interface/public/shared/styles.css +21212 -0
  106. package/neural-interface/public/shared/ui-automation-studio.js +3573 -0
  107. package/neural-interface/public/shared/ui-bookmarks.js +231 -0
  108. package/neural-interface/public/shared/ui-claude-panel.js +6333 -0
  109. package/neural-interface/public/shared/ui-command-runner.js +534 -0
  110. package/neural-interface/public/shared/ui-cost-widget.js +602 -0
  111. package/neural-interface/public/shared/ui-detail.js +1454 -0
  112. package/neural-interface/public/shared/ui-explorer.js +1356 -0
  113. package/neural-interface/public/shared/ui-file-explorer.js +2750 -0
  114. package/neural-interface/public/shared/ui-games.js +411 -0
  115. package/neural-interface/public/shared/ui-help.js +107 -0
  116. package/neural-interface/public/shared/ui-image-gallery.js +461 -0
  117. package/neural-interface/public/shared/ui-invite.js +519 -0
  118. package/neural-interface/public/shared/ui-keybinds.js +452 -0
  119. package/neural-interface/public/shared/ui-layouts.js +297 -0
  120. package/neural-interface/public/shared/ui-link.js +731 -0
  121. package/neural-interface/public/shared/ui-loading.js +255 -0
  122. package/neural-interface/public/shared/ui-menubar.js +499 -0
  123. package/neural-interface/public/shared/ui-multiselect.js +93 -0
  124. package/neural-interface/public/shared/ui-navbar.js +222 -0
  125. package/neural-interface/public/shared/ui-notifications.js +287 -0
  126. package/neural-interface/public/shared/ui-panels.js +309 -0
  127. package/neural-interface/public/shared/ui-resume.js +653 -0
  128. package/neural-interface/public/shared/ui-search.js +145 -0
  129. package/neural-interface/public/shared/ui-sessions.js +531 -0
  130. package/neural-interface/public/shared/ui-settings.js +5987 -0
  131. package/neural-interface/public/shared/ui-sidebar.js +1905 -0
  132. package/neural-interface/public/shared/ui-skills.js +2805 -0
  133. package/neural-interface/public/shared/ui-stats.js +38 -0
  134. package/neural-interface/public/shared/ui-sync.js +201 -0
  135. package/neural-interface/public/shared/ui-terminal.js +6385 -0
  136. package/neural-interface/public/shared/ui-tooltip.js +123 -0
  137. package/neural-interface/public/shared/ui-trash.js +439 -0
  138. package/neural-interface/public/shared/ui-tutorial-draw.js +875 -0
  139. package/neural-interface/public/shared/ui-tutorial-steps.js +2276 -0
  140. package/neural-interface/public/shared/ui-tutorial.js +1117 -0
  141. package/neural-interface/public/shared/ui-update.js +244 -0
  142. package/neural-interface/public/shared/ui-whiteboard.js +3262 -0
  143. package/neural-interface/public/shared/ui-workspaces.js +722 -0
  144. package/neural-interface/public/shared/utils.js +360 -0
  145. package/neural-interface/public/shared/vterm-buffer.js +1102 -0
  146. package/neural-interface/public/sw.js +52 -0
  147. package/neural-interface/public/synabun.png +0 -0
  148. package/neural-interface/public/toolbar-album.svg +8 -0
  149. package/neural-interface/public/toolbar-question.svg +6 -0
  150. package/neural-interface/public/toolbar-sessions.svg +6 -0
  151. package/neural-interface/public/variant/2d/background.js +113 -0
  152. package/neural-interface/public/variant/2d/context-menu.js +133 -0
  153. package/neural-interface/public/variant/2d/gfx.js +45 -0
  154. package/neural-interface/public/variant/2d/graph.js +1635 -0
  155. package/neural-interface/public/variant/2d/hulls.js +207 -0
  156. package/neural-interface/public/variant/2d/lasso.js +135 -0
  157. package/neural-interface/public/variant/2d/layout.js +594 -0
  158. package/neural-interface/public/variant/2d/main.js +521 -0
  159. package/neural-interface/public/variant/2d/minimap.js +312 -0
  160. package/neural-interface/public/variant/2d/settings-gfx.js +98 -0
  161. package/neural-interface/public/variant/3d/background.js +884 -0
  162. package/neural-interface/public/variant/3d/camera.js +661 -0
  163. package/neural-interface/public/variant/3d/gfx.js +116 -0
  164. package/neural-interface/public/variant/3d/graph.js +2399 -0
  165. package/neural-interface/public/variant/3d/main.js +500 -0
  166. package/neural-interface/public/variant/3d/settings-gfx.js +228 -0
  167. package/neural-interface/scripts/rebuild-pty.js +100 -0
  168. package/neural-interface/server.js +15000 -0
  169. package/neural-interface/templates/CLAUDE-template.md +211 -0
  170. package/package.json +53 -0
  171. package/postinstall.js +135 -0
  172. package/setup.js +260 -0
  173. package/skills/leonardo/SKILL.md +159 -0
  174. package/skills/leonardo/icon.svg +1 -0
  175. package/skills/leonardo/modules/browser-guide.md +378 -0
  176. package/skills/leonardo/modules/image-prompter.md +277 -0
  177. package/skills/leonardo/modules/model-advisor.md +100 -0
  178. package/skills/leonardo/modules/prompt-library.md +110 -0
  179. package/skills/leonardo/modules/style-guide.md +186 -0
  180. package/skills/leonardo/modules/video-prompter.md +311 -0
  181. package/skills/synabun/SKILL.md +185 -0
  182. package/skills/synabun/icon.png +0 -0
  183. package/skills/synabun/modules/audit.md +374 -0
  184. package/skills/synabun/modules/changelog.md +194 -0
  185. package/skills/synabun/modules/idea.md +144 -0
  186. package/skills/synabun/modules/memorize.md +188 -0
  187. package/skills/synabun/synabunicon.png +0 -0
@@ -0,0 +1,312 @@
1
+ // ═══════════════════════════════════════════
2
+ // SynaBun Neural Interface — 2D Minimap
3
+ // Small overview canvas with click-to-navigate
4
+ // Reads from graph.js viewport/card data
5
+ // Canvas: #minimap-canvas, container: #minimap
6
+ // ═══════════════════════════════════════════
7
+
8
+ import { state } from '../../shared/state.js';
9
+ import { storage } from '../../shared/storage.js';
10
+ import { catColor } from '../../shared/colors.js';
11
+ import { getViewport, getAllCards, getGraph } from './graph.js';
12
+ import { CARD_W, CARD_H } from './layout.js';
13
+
14
+ const $ = (id) => document.getElementById(id);
15
+
16
+ // ── Private state ──
17
+ let _minimapVisible = true;
18
+ let _minimapThrottle = 0;
19
+ let _minimapEl = null;
20
+ let _minimapCanvas = null;
21
+ let _minimapCtx = null;
22
+
23
+ // ── Drag state ──
24
+ let _dragging = false;
25
+ let _dragStartX = 0;
26
+ let _dragStartY = 0;
27
+ let _dragStartLeft = 0;
28
+ let _dragStartTop = 0;
29
+ let _dragMoved = false;
30
+
31
+ const MINIMAP_POS_KEY = 'synabun-2d-minimap-pos';
32
+
33
+ // ═══════════════════════════════════════════
34
+ // INIT
35
+ // ═══════════════════════════════════════════
36
+
37
+ /**
38
+ * Initialize the minimap canvas, click-to-navigate handler, and toggle button.
39
+ * @param {object} _graphInstance Unused — kept for API compatibility with main.js
40
+ */
41
+ export function initMinimap(_graphInstance) {
42
+ _minimapEl = $('minimap');
43
+ _minimapCanvas = $('minimap-canvas');
44
+ if (!_minimapCanvas) return;
45
+ _minimapCtx = _minimapCanvas.getContext('2d');
46
+
47
+ // Show minimap initially (starts visible)
48
+ if (_minimapEl) {
49
+ _minimapEl.classList.add('visible');
50
+ _restorePosition();
51
+ }
52
+
53
+ // Click-to-navigate (only if user didn't drag)
54
+ _minimapCanvas.addEventListener('click', (e) => {
55
+ if (_dragMoved) return; // was a drag, not a click
56
+ _onMinimapClick(e);
57
+ });
58
+
59
+ // Drag-to-reposition on the container
60
+ if (_minimapEl) {
61
+ _minimapEl.addEventListener('mousedown', _onDragStart);
62
+ window.addEventListener('mousemove', _onDragMove);
63
+ window.addEventListener('mouseup', _onDragEnd);
64
+ }
65
+
66
+ // Toggle button
67
+ const toggleBtn = $('minimap-toggle-btn');
68
+ if (toggleBtn) {
69
+ toggleBtn.addEventListener('click', () => {
70
+ toggleMinimap();
71
+ });
72
+ }
73
+ }
74
+
75
+ // ═══════════════════════════════════════════
76
+ // DRAW
77
+ // ═══════════════════════════════════════════
78
+
79
+ /**
80
+ * Draw the minimap showing all cards and the current viewport rectangle.
81
+ * Throttled to max ~10fps (100ms interval).
82
+ */
83
+ export function drawMinimap() {
84
+ if (!_minimapVisible || _forcedHidden) return;
85
+ const now = performance.now();
86
+ if (now - _minimapThrottle < 100) return;
87
+ _minimapThrottle = now;
88
+
89
+ if (!_minimapCanvas || !_minimapCtx) return;
90
+ const canvas = _minimapCanvas;
91
+ const ctx = _minimapCtx;
92
+ const w = canvas.width;
93
+ const h = canvas.height;
94
+ ctx.clearRect(0, 0, w, h);
95
+
96
+ const cards = getAllCards();
97
+ if (!cards.length) return;
98
+
99
+ // Find bounds
100
+ let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;
101
+ for (const card of cards) {
102
+ if (card.x < minX) minX = card.x;
103
+ if (card.x > maxX) maxX = card.x;
104
+ if (card.y < minY) minY = card.y;
105
+ if (card.y > maxY) maxY = card.y;
106
+ }
107
+
108
+ const pad = 20;
109
+ const rangeX = (maxX - minX) || 1;
110
+ const rangeY = (maxY - minY) || 1;
111
+ const scale = Math.min((w - pad * 2) / rangeX, (h - pad * 2) / rangeY);
112
+
113
+ const offsetX = (w - rangeX * scale) / 2;
114
+ const offsetY = (h - rangeY * scale) / 2;
115
+
116
+ // Draw cards as dots
117
+ const selectedId = state.selectedNodeId;
118
+ for (const card of cards) {
119
+ const mx = (card.x - minX) * scale + offsetX;
120
+ const my = (card.y - minY) * scale + offsetY;
121
+ const color = catColor(card.node.payload?.category);
122
+ ctx.fillStyle = card.node.id === selectedId ? '#fff' : color;
123
+ ctx.beginPath();
124
+ ctx.arc(mx, my, 1.5, 0, Math.PI * 2);
125
+ ctx.fill();
126
+ }
127
+
128
+ // Draw viewport rectangle (offset is in buffer coords, convert CSS to buffer)
129
+ const vp = getViewport();
130
+ const dpr = vp.dpr || 1;
131
+ const vpWorldCenterX = (window.innerWidth * dpr / 2 - vp.offsetX) / vp.scale;
132
+ const vpWorldCenterY = (window.innerHeight * dpr / 2 - vp.offsetY) / vp.scale;
133
+ const vpW = window.innerWidth * dpr / vp.scale;
134
+ const vpH = window.innerHeight * dpr / vp.scale;
135
+ const vpX = (vpWorldCenterX - vpW / 2 - minX) * scale + offsetX;
136
+ const vpY = (vpWorldCenterY - vpH / 2 - minY) * scale + offsetY;
137
+ ctx.strokeStyle = 'rgba(255,255,255,0.5)';
138
+ ctx.lineWidth = 1;
139
+ ctx.strokeRect(vpX, vpY, vpW * scale, vpH * scale);
140
+ }
141
+
142
+ // ═══════════════════════════════════════════
143
+ // CLICK-TO-NAVIGATE
144
+ // ═══════════════════════════════════════════
145
+
146
+ function _onMinimapClick(e) {
147
+ if (!_minimapCanvas) return;
148
+ const rect = _minimapCanvas.getBoundingClientRect();
149
+ const clickX = e.clientX - rect.left;
150
+ const clickY = e.clientY - rect.top;
151
+
152
+ const cards = getAllCards();
153
+ if (!cards.length) return;
154
+
155
+ let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;
156
+ for (const card of cards) {
157
+ if (card.x < minX) minX = card.x;
158
+ if (card.x > maxX) maxX = card.x;
159
+ if (card.y < minY) minY = card.y;
160
+ if (card.y > maxY) maxY = card.y;
161
+ }
162
+
163
+ const w = _minimapCanvas.width, h = _minimapCanvas.height;
164
+ const pad = 20;
165
+ const rangeX = (maxX - minX) || 1;
166
+ const rangeY = (maxY - minY) || 1;
167
+ const scale = Math.min((w - pad * 2) / rangeX, (h - pad * 2) / rangeY);
168
+ const offsetX = (w - rangeX * scale) / 2;
169
+ const offsetY = (h - rangeY * scale) / 2;
170
+
171
+ const worldX = (clickX - offsetX) / scale + minX;
172
+ const worldY = (clickY - offsetY) / scale + minY;
173
+
174
+ const g = getGraph();
175
+ if (g) g.centerAt(worldX, worldY, 500);
176
+ }
177
+
178
+ // ═══════════════════════════════════════════
179
+ // DRAG-TO-REPOSITION
180
+ // ═══════════════════════════════════════════
181
+
182
+ function _onDragStart(e) {
183
+ // Only drag from the minimap border area or with middle mouse
184
+ // Left-click inside canvas navigates, so drag from edges or holding Ctrl
185
+ if (e.button !== 0) return;
186
+
187
+ _dragging = true;
188
+ _dragMoved = false;
189
+ _dragStartX = e.clientX;
190
+ _dragStartY = e.clientY;
191
+
192
+ // Get current computed position
193
+ const rect = _minimapEl.getBoundingClientRect();
194
+ _dragStartLeft = rect.left;
195
+ _dragStartTop = rect.top;
196
+
197
+ e.preventDefault();
198
+ }
199
+
200
+ function _onDragMove(e) {
201
+ if (!_dragging) return;
202
+
203
+ const dx = e.clientX - _dragStartX;
204
+ const dy = e.clientY - _dragStartY;
205
+
206
+ // Only count as a drag if moved more than 4px (prevents accidental drag on click)
207
+ if (!_dragMoved && Math.abs(dx) + Math.abs(dy) < 4) return;
208
+ _dragMoved = true;
209
+
210
+ const newLeft = _dragStartLeft + dx;
211
+ const newTop = _dragStartTop + dy;
212
+
213
+ // Clamp to viewport
214
+ const vw = window.innerWidth;
215
+ const vh = window.innerHeight;
216
+ const mw = _minimapEl.offsetWidth;
217
+ const mh = _minimapEl.offsetHeight;
218
+
219
+ const clampedLeft = Math.max(0, Math.min(newLeft, vw - mw));
220
+ const clampedTop = Math.max(0, Math.min(newTop, vh - mh));
221
+
222
+ // Switch from right/bottom positioning to left/top for drag
223
+ _minimapEl.style.right = 'auto';
224
+ _minimapEl.style.bottom = 'auto';
225
+ _minimapEl.style.left = clampedLeft + 'px';
226
+ _minimapEl.style.top = clampedTop + 'px';
227
+ }
228
+
229
+ function _onDragEnd() {
230
+ if (!_dragging) return;
231
+ _dragging = false;
232
+ if (_dragMoved) _savePosition();
233
+ // _dragMoved stays true so the click handler can check it
234
+ // Reset after a tick so the click event that follows mouseup sees it
235
+ setTimeout(() => { _dragMoved = false; }, 0);
236
+ }
237
+
238
+ // ═══════════════════════════════════════════
239
+ // POSITION PERSISTENCE
240
+ // ═══════════════════════════════════════════
241
+
242
+ function _savePosition() {
243
+ if (!_minimapEl) return;
244
+ try {
245
+ storage.setItem(MINIMAP_POS_KEY, JSON.stringify({
246
+ left: _minimapEl.style.left,
247
+ top: _minimapEl.style.top,
248
+ }));
249
+ } catch (_) { /* storage full or disabled */ }
250
+ }
251
+
252
+ function _restorePosition() {
253
+ if (!_minimapEl) return;
254
+ try {
255
+ const raw = storage.getItem(MINIMAP_POS_KEY);
256
+ if (!raw) return;
257
+ const pos = JSON.parse(raw);
258
+ if (!pos.left || !pos.top) return;
259
+
260
+ // Validate the stored position is still within viewport
261
+ const left = parseInt(pos.left, 10);
262
+ const top = parseInt(pos.top, 10);
263
+ if (isNaN(left) || isNaN(top)) return;
264
+
265
+ const mw = _minimapEl.offsetWidth;
266
+ const mh = _minimapEl.offsetHeight;
267
+ const clampedLeft = Math.max(0, Math.min(left, window.innerWidth - mw));
268
+ const clampedTop = Math.max(0, Math.min(top, window.innerHeight - mh));
269
+
270
+ _minimapEl.style.right = 'auto';
271
+ _minimapEl.style.bottom = 'auto';
272
+ _minimapEl.style.left = clampedLeft + 'px';
273
+ _minimapEl.style.top = clampedTop + 'px';
274
+ } catch (_) { /* corrupted or missing */ }
275
+ }
276
+
277
+ // ═══════════════════════════════════════════
278
+ // TOGGLE
279
+ // ═══════════════════════════════════════════
280
+
281
+ export function toggleMinimap() {
282
+ _minimapVisible = !_minimapVisible;
283
+ if (_minimapEl) _minimapEl.classList.toggle('visible', _minimapVisible && !_forcedHidden);
284
+ const btn = $('minimap-toggle-btn');
285
+ if (btn) btn.classList.toggle('active', _minimapVisible);
286
+ }
287
+
288
+ export function isMinimapVisible() {
289
+ return _minimapVisible;
290
+ }
291
+
292
+ // ── Force hide/show (focus mode) ──
293
+ // Hides the minimap DOM without changing the user's toggle preference.
294
+ // When focus mode exits, the minimap restores to its previous state.
295
+ let _forcedHidden = false;
296
+
297
+ export function forceHideMinimap() {
298
+ _forcedHidden = true;
299
+ if (_minimapEl) _minimapEl.classList.remove('visible');
300
+ }
301
+
302
+ export function restoreMinimap() {
303
+ _forcedHidden = false;
304
+ if (_minimapEl && _minimapVisible) _minimapEl.classList.add('visible');
305
+ }
306
+
307
+ /**
308
+ * Update the graph instance reference (compatibility — no-op in new renderer).
309
+ */
310
+ export function setGraph(_graphInstance) {
311
+ // No-op — minimap reads from graph.js exports directly
312
+ }
@@ -0,0 +1,98 @@
1
+ // ═══════════════════════════════════════════
2
+ // SynaBun Neural Interface — 2D Graphics Settings Tab
3
+ // Self-registers a "Graphics" tab in the settings panel
4
+ // via the shared registry. No explicit exports — side-effect module.
5
+ // ═══════════════════════════════════════════
6
+
7
+ import { registerSettingsTab } from '../../shared/registry.js';
8
+ import { gfx, saveGfxConfig } from './gfx.js';
9
+ import { emit } from '../../shared/state.js';
10
+
11
+ // ═══════════════════════════════════════════
12
+ // SLIDER DEFINITIONS
13
+ // ═══════════════════════════════════════════
14
+
15
+ const SLIDERS = [
16
+ { key: 'parentOrbitRadius', label: 'Parent Orbit Radius', min: 300, max: 1200, step: 50, format: v => String(v) },
17
+ { key: 'childOrbitGap', label: 'Child Orbit Gap', min: 100, max: 500, step: 25, format: v => String(v) },
18
+ { key: 'cardGap', label: 'Card Spacing', min: 5, max: 40, step: 5, format: v => String(v) },
19
+ { key: 'cardOpacity', label: 'Card Opacity', min: 0.3, max: 1, step: 0.05, format: v => v.toFixed(2) },
20
+ { key: 'regionGlowOpacity', label: 'Region Glow', min: 0, max: 0.2, step: 0.01, format: v => v.toFixed(2) },
21
+ { key: 'linkOpacity', label: 'Link Opacity', min: 0, max: 1, step: 0.01, format: v => v.toFixed(2) },
22
+ ];
23
+
24
+ const CHECKBOXES = [
25
+ { key: 'bgBreathingEnabled', label: 'Breathing animation' },
26
+ { key: 'bgLogoVisible', label: 'Logo watermark' },
27
+ ];
28
+
29
+ // ═══════════════════════════════════════════
30
+ // BUILD TAB HTML
31
+ // ═══════════════════════════════════════════
32
+
33
+ function buildGraphicsTab() {
34
+ // Range sliders
35
+ const sliderRows = SLIDERS.map(s => `
36
+ <div class="gfx-row">
37
+ <span class="gfx-label">${s.label}</span>
38
+ <input type="range" data-key="${s.key}" min="${s.min}" max="${s.max}" step="${s.step}" value="${gfx[s.key]}">
39
+ <span class="gfx-val" data-val="${s.key}">${s.format(gfx[s.key])}</span>
40
+ </div>`).join('');
41
+
42
+ // Checkboxes
43
+ const checkboxRows = CHECKBOXES.map(cb => `
44
+ <div class="gfx-row">
45
+ <label class="gfx-label" style="min-width:0;display:flex;align-items:center;gap:6px;cursor:pointer">
46
+ <input type="checkbox" data-key="${cb.key}" ${gfx[cb.key] ? 'checked' : ''}> ${cb.label}
47
+ </label>
48
+ </div>`).join('');
49
+
50
+ return `
51
+ <div class="iface-section">
52
+ ${sliderRows}
53
+ </div>
54
+ <div class="iface-section">
55
+ ${checkboxRows}
56
+ </div>
57
+ `;
58
+ }
59
+
60
+ // ═══════════════════════════════════════════
61
+ // WIRE UP AFTER RENDER
62
+ // ═══════════════════════════════════════════
63
+
64
+ function initGraphicsTab(container) {
65
+ // Range sliders
66
+ container.querySelectorAll('input[type="range"]').forEach(input => {
67
+ input.addEventListener('input', () => {
68
+ const key = input.dataset.key;
69
+ gfx[key] = parseFloat(input.value);
70
+ const valSpan = container.querySelector(`[data-val="${key}"]`);
71
+ if (valSpan) valSpan.textContent = parseFloat(input.step) < 1 ? gfx[key].toFixed(2) : gfx[key];
72
+ saveGfxConfig(gfx);
73
+ emit('graph:refresh');
74
+ });
75
+ });
76
+
77
+ // Checkboxes
78
+ container.querySelectorAll('input[type="checkbox"]').forEach(input => {
79
+ input.addEventListener('change', () => {
80
+ gfx[input.dataset.key] = input.checked;
81
+ saveGfxConfig(gfx);
82
+ emit('graph:refresh');
83
+ });
84
+ });
85
+ }
86
+
87
+ // ═══════════════════════════════════════════
88
+ // SELF-REGISTER
89
+ // ═══════════════════════════════════════════
90
+
91
+ registerSettingsTab({
92
+ id: 'graphics',
93
+ label: 'Graphics',
94
+ icon: '\uD83C\uDFA8',
95
+ order: 70,
96
+ build: buildGraphicsTab,
97
+ afterRender: initGraphicsTab,
98
+ });