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.
- package/CHANGELOG.md +665 -0
- package/LICENSE +191 -0
- package/README.md +853 -0
- package/hooks/claude-code/post-plan.mjs +391 -0
- package/hooks/claude-code/post-remember.mjs +239 -0
- package/hooks/claude-code/pre-compact.mjs +241 -0
- package/hooks/claude-code/pre-websearch.mjs +90 -0
- package/hooks/claude-code/prompt-submit.mjs +861 -0
- package/hooks/claude-code/session-start.mjs +494 -0
- package/hooks/claude-code/shared.mjs +368 -0
- package/hooks/claude-code/stop.mjs +646 -0
- package/hooks/claude-code/test-user-learning.mjs +531 -0
- package/mcp-server/package.json +38 -0
- package/mcp-server/run.mjs +10 -0
- package/mcp-server/src/config.ts +70 -0
- package/mcp-server/src/http.ts +93 -0
- package/mcp-server/src/index.ts +203 -0
- package/mcp-server/src/preload-http.ts +25 -0
- package/mcp-server/src/preload.ts +29 -0
- package/mcp-server/src/scripts/migrate-qdrant-to-sqlite.ts +506 -0
- package/mcp-server/src/services/categories.ts +429 -0
- package/mcp-server/src/services/discord.ts +702 -0
- package/mcp-server/src/services/file-checksums.ts +33 -0
- package/mcp-server/src/services/local-embeddings.ts +77 -0
- package/mcp-server/src/services/neural-interface.ts +344 -0
- package/mcp-server/src/services/sqlite.ts +823 -0
- package/mcp-server/src/tools/browser-advanced.ts +123 -0
- package/mcp-server/src/tools/browser-interact.ts +255 -0
- package/mcp-server/src/tools/browser-navigate.ts +77 -0
- package/mcp-server/src/tools/browser-observe.ts +1330 -0
- package/mcp-server/src/tools/browser.ts +107 -0
- package/mcp-server/src/tools/card-tools.ts +193 -0
- package/mcp-server/src/tools/card.ts +22 -0
- package/mcp-server/src/tools/category.ts +379 -0
- package/mcp-server/src/tools/discord-channel.ts +274 -0
- package/mcp-server/src/tools/discord-guild.ts +188 -0
- package/mcp-server/src/tools/discord-member.ts +158 -0
- package/mcp-server/src/tools/discord-message.ts +231 -0
- package/mcp-server/src/tools/discord-onboarding.ts +228 -0
- package/mcp-server/src/tools/discord-role.ts +209 -0
- package/mcp-server/src/tools/discord-thread.ts +110 -0
- package/mcp-server/src/tools/discord-webhook.ts +176 -0
- package/mcp-server/src/tools/discord.ts +40 -0
- package/mcp-server/src/tools/forget.ts +38 -0
- package/mcp-server/src/tools/git-tools.ts +141 -0
- package/mcp-server/src/tools/git.ts +13 -0
- package/mcp-server/src/tools/image-tools.ts +98 -0
- package/mcp-server/src/tools/image.ts +17 -0
- package/mcp-server/src/tools/leonardo-browser-tools.ts +281 -0
- package/mcp-server/src/tools/leonardo.ts +28 -0
- package/mcp-server/src/tools/loop.ts +348 -0
- package/mcp-server/src/tools/memories.ts +118 -0
- package/mcp-server/src/tools/recall.ts +323 -0
- package/mcp-server/src/tools/reflect.ts +145 -0
- package/mcp-server/src/tools/remember.ts +115 -0
- package/mcp-server/src/tools/response.ts +26 -0
- package/mcp-server/src/tools/restore.ts +34 -0
- package/mcp-server/src/tools/sync.ts +114 -0
- package/mcp-server/src/tools/tictactoe-tools.ts +98 -0
- package/mcp-server/src/tools/tictactoe.ts +13 -0
- package/mcp-server/src/tools/utils.ts +25 -0
- package/mcp-server/src/tools/whiteboard-tools.ts +260 -0
- package/mcp-server/src/tools/whiteboard.ts +22 -0
- package/mcp-server/src/tui.ts +940 -0
- package/mcp-server/src/types.ts +85 -0
- package/mcp-server/tsconfig.json +19 -0
- package/neural-interface/package.json +27 -0
- package/neural-interface/public/apple-touch-icon.png +0 -0
- package/neural-interface/public/category-logos/claude.svg +1 -0
- package/neural-interface/public/category-logos/gemini-color.svg +1 -0
- package/neural-interface/public/category-logos/openai.svg +1 -0
- package/neural-interface/public/category-logos/synabun.png +0 -0
- package/neural-interface/public/claude-chat.css +878 -0
- package/neural-interface/public/claude-chat.html +92 -0
- package/neural-interface/public/claude-chat.js +1168 -0
- package/neural-interface/public/favicon-16x16.png +0 -0
- package/neural-interface/public/favicon-32x32.png +0 -0
- package/neural-interface/public/gallery.svg +6 -0
- package/neural-interface/public/icon-192.png +0 -0
- package/neural-interface/public/icon-512.png +0 -0
- package/neural-interface/public/index-legacy.html +14677 -0
- package/neural-interface/public/index.html +212 -0
- package/neural-interface/public/index2d-legacy.html +8193 -0
- package/neural-interface/public/index2d.html +127 -0
- package/neural-interface/public/invite.html +351 -0
- package/neural-interface/public/leonardoai.svg +1 -0
- package/neural-interface/public/logo-synabun.png +0 -0
- package/neural-interface/public/logoHD.png +0 -0
- package/neural-interface/public/manifest.json +14 -0
- package/neural-interface/public/offline.html +299 -0
- package/neural-interface/public/onboarding.html +2335 -0
- package/neural-interface/public/openclaw-logo-text.png +0 -0
- package/neural-interface/public/pin-svgrepo-com.svg +25 -0
- package/neural-interface/public/sessionicon.svg +8 -0
- package/neural-interface/public/shared/ansi-parser.js +305 -0
- package/neural-interface/public/shared/api.js +1043 -0
- package/neural-interface/public/shared/colors.js +153 -0
- package/neural-interface/public/shared/constants.js +141 -0
- package/neural-interface/public/shared/html-shell.js +777 -0
- package/neural-interface/public/shared/html-term-renderer.js +1022 -0
- package/neural-interface/public/shared/i18n.js +147 -0
- package/neural-interface/public/shared/registry.js +82 -0
- package/neural-interface/public/shared/state.js +86 -0
- package/neural-interface/public/shared/storage.js +150 -0
- package/neural-interface/public/shared/styles.css +21212 -0
- package/neural-interface/public/shared/ui-automation-studio.js +3573 -0
- package/neural-interface/public/shared/ui-bookmarks.js +231 -0
- package/neural-interface/public/shared/ui-claude-panel.js +6333 -0
- package/neural-interface/public/shared/ui-command-runner.js +534 -0
- package/neural-interface/public/shared/ui-cost-widget.js +602 -0
- package/neural-interface/public/shared/ui-detail.js +1454 -0
- package/neural-interface/public/shared/ui-explorer.js +1356 -0
- package/neural-interface/public/shared/ui-file-explorer.js +2750 -0
- package/neural-interface/public/shared/ui-games.js +411 -0
- package/neural-interface/public/shared/ui-help.js +107 -0
- package/neural-interface/public/shared/ui-image-gallery.js +461 -0
- package/neural-interface/public/shared/ui-invite.js +519 -0
- package/neural-interface/public/shared/ui-keybinds.js +452 -0
- package/neural-interface/public/shared/ui-layouts.js +297 -0
- package/neural-interface/public/shared/ui-link.js +731 -0
- package/neural-interface/public/shared/ui-loading.js +255 -0
- package/neural-interface/public/shared/ui-menubar.js +499 -0
- package/neural-interface/public/shared/ui-multiselect.js +93 -0
- package/neural-interface/public/shared/ui-navbar.js +222 -0
- package/neural-interface/public/shared/ui-notifications.js +287 -0
- package/neural-interface/public/shared/ui-panels.js +309 -0
- package/neural-interface/public/shared/ui-resume.js +653 -0
- package/neural-interface/public/shared/ui-search.js +145 -0
- package/neural-interface/public/shared/ui-sessions.js +531 -0
- package/neural-interface/public/shared/ui-settings.js +5987 -0
- package/neural-interface/public/shared/ui-sidebar.js +1905 -0
- package/neural-interface/public/shared/ui-skills.js +2805 -0
- package/neural-interface/public/shared/ui-stats.js +38 -0
- package/neural-interface/public/shared/ui-sync.js +201 -0
- package/neural-interface/public/shared/ui-terminal.js +6385 -0
- package/neural-interface/public/shared/ui-tooltip.js +123 -0
- package/neural-interface/public/shared/ui-trash.js +439 -0
- package/neural-interface/public/shared/ui-tutorial-draw.js +875 -0
- package/neural-interface/public/shared/ui-tutorial-steps.js +2276 -0
- package/neural-interface/public/shared/ui-tutorial.js +1117 -0
- package/neural-interface/public/shared/ui-update.js +244 -0
- package/neural-interface/public/shared/ui-whiteboard.js +3262 -0
- package/neural-interface/public/shared/ui-workspaces.js +722 -0
- package/neural-interface/public/shared/utils.js +360 -0
- package/neural-interface/public/shared/vterm-buffer.js +1102 -0
- package/neural-interface/public/sw.js +52 -0
- package/neural-interface/public/synabun.png +0 -0
- package/neural-interface/public/toolbar-album.svg +8 -0
- package/neural-interface/public/toolbar-question.svg +6 -0
- package/neural-interface/public/toolbar-sessions.svg +6 -0
- package/neural-interface/public/variant/2d/background.js +113 -0
- package/neural-interface/public/variant/2d/context-menu.js +133 -0
- package/neural-interface/public/variant/2d/gfx.js +45 -0
- package/neural-interface/public/variant/2d/graph.js +1635 -0
- package/neural-interface/public/variant/2d/hulls.js +207 -0
- package/neural-interface/public/variant/2d/lasso.js +135 -0
- package/neural-interface/public/variant/2d/layout.js +594 -0
- package/neural-interface/public/variant/2d/main.js +521 -0
- package/neural-interface/public/variant/2d/minimap.js +312 -0
- package/neural-interface/public/variant/2d/settings-gfx.js +98 -0
- package/neural-interface/public/variant/3d/background.js +884 -0
- package/neural-interface/public/variant/3d/camera.js +661 -0
- package/neural-interface/public/variant/3d/gfx.js +116 -0
- package/neural-interface/public/variant/3d/graph.js +2399 -0
- package/neural-interface/public/variant/3d/main.js +500 -0
- package/neural-interface/public/variant/3d/settings-gfx.js +228 -0
- package/neural-interface/scripts/rebuild-pty.js +100 -0
- package/neural-interface/server.js +15000 -0
- package/neural-interface/templates/CLAUDE-template.md +211 -0
- package/package.json +53 -0
- package/postinstall.js +135 -0
- package/setup.js +260 -0
- package/skills/leonardo/SKILL.md +159 -0
- package/skills/leonardo/icon.svg +1 -0
- package/skills/leonardo/modules/browser-guide.md +378 -0
- package/skills/leonardo/modules/image-prompter.md +277 -0
- package/skills/leonardo/modules/model-advisor.md +100 -0
- package/skills/leonardo/modules/prompt-library.md +110 -0
- package/skills/leonardo/modules/style-guide.md +186 -0
- package/skills/leonardo/modules/video-prompter.md +311 -0
- package/skills/synabun/SKILL.md +185 -0
- package/skills/synabun/icon.png +0 -0
- package/skills/synabun/modules/audit.md +374 -0
- package/skills/synabun/modules/changelog.md +194 -0
- package/skills/synabun/modules/idea.md +144 -0
- package/skills/synabun/modules/memorize.md +188 -0
- 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
|
+
});
|