jsgui3-server 0.0.140 → 0.0.142

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 (32) hide show
  1. package/.github/agents/jsgui3-server.agent.md +699 -0
  2. package/.github/instructions/copilot.instructions.md +180 -0
  3. package/.playwright-mcp/page-2025-11-29T23-39-18-629Z.png +0 -0
  4. package/.playwright-mcp/page-2025-11-29T23-39-31-903Z.png +0 -0
  5. package/.playwright-mcp/page-2025-11-30T00-33-56-265Z.png +0 -0
  6. package/.playwright-mcp/page-2025-11-30T00-34-06-619Z.png +0 -0
  7. package/docs/agent-development-guide.md +108 -4
  8. package/docs/api-reference.md +116 -0
  9. package/docs/controls-development.md +127 -0
  10. package/docs/css/luxuryObsidianCss.js +1203 -0
  11. package/docs/css/obsidian-scrollbars.css +370 -0
  12. package/docs/diagrams/jsgui3-stack.svg +568 -0
  13. package/docs/guides/JSGUI3_UI_ARCHITECTURE_GUIDE.md +2527 -0
  14. package/docs/guides/OBSIDIAN_LUXURY_DESIGN_GUIDE.md +847 -0
  15. package/docs/jsgui3-vs-express-comparison.svg +542 -0
  16. package/docs/jsgui3-vs-nestjs-comparison.svg +550 -0
  17. package/docs/publishers-guide.md +76 -0
  18. package/docs/troubleshooting.md +51 -0
  19. package/examples/controls/15) window, observable SSE/README.md +125 -0
  20. package/examples/controls/15) window, observable SSE/check.js +144 -0
  21. package/examples/controls/15) window, observable SSE/client.js +395 -0
  22. package/examples/controls/15) window, observable SSE/server.js +111 -0
  23. package/http/responders/static/Static_Route_HTTP_Responder.js +16 -16
  24. package/module.js +7 -0
  25. package/package.json +9 -8
  26. package/port-utils.js +112 -0
  27. package/serve-factory.js +27 -5
  28. package/tests/README.md +40 -26
  29. package/tests/examples-controls.e2e.test.js +164 -0
  30. package/tests/observable-sse.test.js +363 -0
  31. package/tests/port-utils.test.js +114 -0
  32. package/tests/test-runner.js +13 -12
@@ -0,0 +1,847 @@
1
+ # Obsidian Luxury Design Guide
2
+
3
+ ## Architecture Diagrams for Software Stack Visualization
4
+
5
+ This guide establishes the visual language for creating premium architectural diagrams that illustrate software stacks, platform compositions, and system hierarchies. The "Obsidian Luxury" aesthetic combines dark sophistication with jewel-toned accents to create diagrams that are both beautiful and technically precise.
6
+
7
+ ---
8
+
9
+ ## Design Philosophy
10
+
11
+ ### Core Principles
12
+
13
+ 1. **Layered Clarity** - Software stacks should read like geological cross-sections, with clear stratification showing how platforms build upon each other
14
+ 2. **Jeweled Hierarchy** - Use gemstone colors to encode architectural significance and data flow direction
15
+ 3. **Dimensional Depth** - Employ gradients, shadows, and perspective to convey the "weight" of foundational layers
16
+ 4. **Elegant Density** - Pack information richly while maintaining visual breathing room
17
+
18
+ ### When to Use This Style
19
+
20
+ - System architecture overviews
21
+ - Platform composition diagrams
22
+ - Technology stack illustrations
23
+ - Infrastructure layer visualizations
24
+ - Service mesh and microservice topologies
25
+ - Data flow through multi-tier systems
26
+
27
+ ---
28
+
29
+ ## Color Palette
30
+
31
+ ### Foundation Colors (Dark Theme Base)
32
+
33
+ ```
34
+ Obsidian Background
35
+ ├── Deep Black: #0d1117 (primary background)
36
+ ├── Slate Dark: #161b22 (card backgrounds)
37
+ ├── Slate Medium: #21262d (elevated surfaces)
38
+ └── Slate Light: #30363d (borders, dividers)
39
+ ```
40
+
41
+ ### Jewel Accent Colors (Architectural Significance)
42
+
43
+ Each gemstone color encodes a specific architectural role:
44
+
45
+ | Gem | Hex | RGB | Architectural Meaning |
46
+ |-----|-----|-----|----------------------|
47
+ | **Gold** | `#c9a227` | 201, 162, 39 | Core/Foundation, APIs, Primary Data Flow |
48
+ | **Sapphire** | `#3b82f6` | 59, 130, 246 | Services, Business Logic, Processing |
49
+ | **Emerald** | `#10b981` | 16, 185, 129 | Success States, Health, Active Connections |
50
+ | **Ruby** | `#ef4444` | 239, 68, 68 | Errors, Critical Paths, Breaking Changes |
51
+ | **Amethyst** | `#a855f7` | 168, 85, 247 | External Systems, Integrations, Plugins |
52
+ | **Topaz** | `#f59e0b` | 245, 158, 11 | Warnings, Pending States, Async Operations |
53
+ | **Pearl** | `#e2e8f0` | 226, 232, 240 | Text, Labels, Secondary Information |
54
+
55
+ ### Gradient Definitions
56
+
57
+ ```xml
58
+ <!-- Gold Accent (horizontal) - for headers, key elements -->
59
+ <linearGradient id="goldAccent" x1="0%" y1="0%" x2="100%" y2="100%">
60
+ <stop offset="0%" stop-color="#d4af37"/>
61
+ <stop offset="25%" stop-color="#c9a227"/>
62
+ <stop offset="50%" stop-color="#b8960f"/>
63
+ <stop offset="75%" stop-color="#c9a227"/>
64
+ <stop offset="100%" stop-color="#d4af37"/>
65
+ </linearGradient>
66
+
67
+ <!-- Gold Shine (text effect) -->
68
+ <linearGradient id="goldShine" x1="0%" y1="0%" x2="100%" y2="0%">
69
+ <stop offset="0%" stop-color="#f4e4bc"/>
70
+ <stop offset="50%" stop-color="#c9a227"/>
71
+ <stop offset="100%" stop-color="#f4e4bc"/>
72
+ </linearGradient>
73
+
74
+ <!-- Obsidian Background (vertical depth) -->
75
+ <linearGradient id="obsidianBg" x1="0%" y1="0%" x2="0%" y2="100%">
76
+ <stop offset="0%" stop-color="#1a1f2e"/>
77
+ <stop offset="50%" stop-color="#0d1117"/>
78
+ <stop offset="100%" stop-color="#080b10"/>
79
+ </linearGradient>
80
+
81
+ <!-- Sapphire Glow (services) -->
82
+ <radialGradient id="sapphireGlow" cx="50%" cy="50%" r="50%">
83
+ <stop offset="0%" stop-color="#60a5fa"/>
84
+ <stop offset="100%" stop-color="#3b82f6"/>
85
+ </radialGradient>
86
+
87
+ <!-- Emerald Glow (success/active) -->
88
+ <radialGradient id="emeraldGlow" cx="50%" cy="50%" r="50%">
89
+ <stop offset="0%" stop-color="#34d399"/>
90
+ <stop offset="100%" stop-color="#10b981"/>
91
+ </radialGradient>
92
+
93
+ <!-- Ruby Glow (errors/critical) -->
94
+ <radialGradient id="rubyGlow" cx="50%" cy="50%" r="50%">
95
+ <stop offset="0%" stop-color="#f87171"/>
96
+ <stop offset="100%" stop-color="#ef4444"/>
97
+ </radialGradient>
98
+
99
+ <!-- Amethyst Glow (external/integrations) -->
100
+ <radialGradient id="amethystGlow" cx="50%" cy="50%" r="50%">
101
+ <stop offset="0%" stop-color="#c084fc"/>
102
+ <stop offset="100%" stop-color="#a855f7"/>
103
+ </radialGradient>
104
+ ```
105
+
106
+ ---
107
+
108
+ ## Architecture Diagram Patterns
109
+
110
+ ### Pattern 1: Vertical Stack (Platform Layers)
111
+
112
+ Use for showing how technologies build upon each other:
113
+
114
+ ```
115
+ ┌─────────────────────────────────────────────────────────┐
116
+ │ APPLICATION LAYER │ ← Gold border
117
+ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
118
+ │ │ Web UI │ │ API │ │ Admin │ │ CLI │ │
119
+ │ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ │
120
+ ├───────┼────────────┼────────────┼────────────┼──────────┤
121
+ │ └────────────┴─────┬──────┴────────────┘ │
122
+ │ SERVICE LAYER │ ← Sapphire
123
+ │ ┌──────────────────────────────────────────────────┐ │
124
+ │ │ Business Logic Services │ │
125
+ │ └──────────────────────┬───────────────────────────┘ │
126
+ ├─────────────────────────┼───────────────────────────────┤
127
+ │ DATA LAYER │ ← Emerald
128
+ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
129
+ │ │ SQLite │ │ Cache │ │ Files │ │
130
+ │ └─────────┘ └─────────┘ └─────────┘ │
131
+ ├─────────────────────────────────────────────────────────┤
132
+ │ INFRASTRUCTURE LAYER │ ← Slate
133
+ │ ┌─────────────────────────────────────────────────┐ │
134
+ │ │ Node.js │ │
135
+ │ └─────────────────────────────────────────────────┘ │
136
+ └─────────────────────────────────────────────────────────┘
137
+ ```
138
+
139
+ **SVG Implementation Notes:**
140
+ - Each layer is a `<g>` group with consistent padding
141
+ - Layer backgrounds use subtle gradients (darker at bottom = "heavier")
142
+ - Gold accent on top layer indicates entry points
143
+ - Connector lines use `stroke-dasharray` for optional paths
144
+
145
+ ### Pattern 2: Horizontal Flow (Data Pipeline)
146
+
147
+ Use for showing data transformation through stages:
148
+
149
+ ```
150
+ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
151
+ │ INGEST │───▶│ PROCESS │───▶│ STORE │───▶│ SERVE │
152
+ │ │ │ │ │ │ │ │
153
+ │ ┌──────┐ │ │ ┌──────┐ │ │ ┌──────┐ │ │ ┌──────┐ │
154
+ │ │Source│ │ │ │Parse │ │ │ │ DB │ │ │ │ API │ │
155
+ │ │ URLs │ │ │ │& Norm│ │ │ │Write │ │ │ │Query │ │
156
+ │ └──────┘ │ │ └──────┘ │ │ └──────┘ │ │ └──────┘ │
157
+ └──────────┘ └──────────┘ └──────────┘ └──────────┘
158
+ Topaz Sapphire Emerald Gold
159
+ (pending) (process) (storage) (output)
160
+ ```
161
+
162
+ **SVG Implementation Notes:**
163
+ - Arrows use `<marker>` elements with gold fill
164
+ - Stage boxes have rounded corners (`rx="8"`)
165
+ - Inner boxes show specific operations
166
+ - Color encodes stage type, not status
167
+
168
+ ### Pattern 3: Nested Composition (System of Systems)
169
+
170
+ Use for showing how subsystems compose into larger wholes:
171
+
172
+ ```
173
+ ┌─────────────────────────────────────────────────────────────────┐
174
+ │ NEWS AGGREGATOR │
175
+ │ ┌───────────────────────────┐ ┌───────────────────────────┐ │
176
+ │ │ CRAWLER SYSTEM │ │ ANALYSIS SYSTEM │ │
177
+ │ │ ┌─────┐ ┌─────┐ ┌─────┐ │ │ ┌─────┐ ┌─────┐ ┌─────┐ │ │
178
+ │ │ │Queue│ │Fetch│ │Parse│ │ │ │ NLP │ │ Geo │ │Score│ │ │
179
+ │ │ └──┬──┘ └──┬──┘ └──┬──┘ │ │ └──┬──┘ └──┬──┘ └──┬──┘ │ │
180
+ │ │ └───────┴───────┘ │ │ └───────┴───────┘ │ │
181
+ │ │ Orchestrator │ │ Orchestrator │ │
182
+ │ └─────────────┬─────────────┘ └─────────────┬─────────────┘ │
183
+ │ │ │ │
184
+ │ └──────────────┬───────────────┘ │
185
+ │ │ │
186
+ │ ┌────────────────────────────┴─────────────────────────────┐ │
187
+ │ │ SHARED DATA LAYER │ │
188
+ │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
189
+ │ │ │ URLs │ │ Articles │ │ Places │ │ Scores │ │ │
190
+ │ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ │
191
+ │ └───────────────────────────────────────────────────────────┘ │
192
+ └─────────────────────────────────────────────────────────────────┘
193
+ ```
194
+
195
+ **SVG Implementation Notes:**
196
+ - Outer container has gold accent border
197
+ - Subsystems use sapphire tint backgrounds
198
+ - Shared layer uses emerald to show connectivity
199
+ - Depth conveyed through nested rounded rectangles
200
+
201
+ ### Pattern 4: Radial Architecture (Hub and Spoke)
202
+
203
+ Use for showing central services with satellite dependencies:
204
+
205
+ ```
206
+ ┌─────────┐
207
+ │ External│
208
+ │ API │
209
+ └────┬────┘
210
+
211
+ ┌────────┐ ┌────┴────┐ ┌────────┐
212
+ │ Cache │──│ CORE │──│ Search │
213
+ │ Layer │ │ SERVICE │ │ Index │
214
+ └────────┘ └────┬────┘ └────────┘
215
+
216
+ ┌────────┐ ┌────┴────┐ ┌────────┐
217
+ │ Queue │──│Database │──│ Files │
218
+ │Service │ │ Cluster │ │ Store │
219
+ └────────┘ └─────────┘ └────────┘
220
+ ```
221
+
222
+ **SVG Implementation Notes:**
223
+ - Central node uses radial gradient with gold center
224
+ - Spokes use straight lines with subtle glow
225
+ - Satellite nodes sized by importance
226
+ - Optional: animate pulse on central node
227
+
228
+ ---
229
+
230
+ ## Visual Elements
231
+
232
+ ### Box Styles
233
+
234
+ #### Primary Container (System Boundary)
235
+ ```xml
236
+ <rect x="0" y="0" width="400" height="300"
237
+ rx="12" ry="12"
238
+ fill="url(#obsidianBg)"
239
+ stroke="url(#goldAccent)"
240
+ stroke-width="2"
241
+ filter="url(#dropShadow)"/>
242
+ ```
243
+
244
+ #### Secondary Container (Subsystem)
245
+ ```xml
246
+ <rect x="20" y="20" width="360" height="260"
247
+ rx="8" ry="8"
248
+ fill="#161b22"
249
+ stroke="#30363d"
250
+ stroke-width="1"/>
251
+ ```
252
+
253
+ #### Component Box (Individual Service)
254
+ ```xml
255
+ <rect x="40" y="40" width="120" height="80"
256
+ rx="6" ry="6"
257
+ fill="#21262d"
258
+ stroke="#3b82f6"
259
+ stroke-width="1.5"
260
+ opacity="0.9"/>
261
+ ```
262
+
263
+ ### Connector Styles
264
+
265
+ #### Primary Data Flow
266
+ ```xml
267
+ <line x1="100" y1="100" x2="200" y2="100"
268
+ stroke="url(#goldAccent)"
269
+ stroke-width="2"
270
+ marker-end="url(#arrowGold)"/>
271
+ ```
272
+
273
+ #### Secondary/Optional Flow
274
+ ```xml
275
+ <line x1="100" y1="120" x2="200" y2="120"
276
+ stroke="#64748b"
277
+ stroke-width="1"
278
+ stroke-dasharray="4 2"
279
+ marker-end="url(#arrowGray)"/>
280
+ ```
281
+
282
+ #### Bidirectional Flow
283
+ ```xml
284
+ <line x1="100" y1="140" x2="200" y2="140"
285
+ stroke="#3b82f6"
286
+ stroke-width="1.5"
287
+ marker-start="url(#arrowBlue)"
288
+ marker-end="url(#arrowBlue)"/>
289
+ ```
290
+
291
+ ### Arrow Markers
292
+
293
+ ```xml
294
+ <defs>
295
+ <!-- Gold arrow for primary flows -->
296
+ <marker id="arrowGold" viewBox="0 0 10 10" refX="9" refY="5"
297
+ markerWidth="6" markerHeight="6" orient="auto-start-reverse">
298
+ <path d="M 0 0 L 10 5 L 0 10 z" fill="#c9a227"/>
299
+ </marker>
300
+
301
+ <!-- Blue arrow for service connections -->
302
+ <marker id="arrowBlue" viewBox="0 0 10 10" refX="9" refY="5"
303
+ markerWidth="5" markerHeight="5" orient="auto-start-reverse">
304
+ <path d="M 0 0 L 10 5 L 0 10 z" fill="#3b82f6"/>
305
+ </marker>
306
+
307
+ <!-- Gray arrow for optional paths -->
308
+ <marker id="arrowGray" viewBox="0 0 10 10" refX="9" refY="5"
309
+ markerWidth="4" markerHeight="4" orient="auto-start-reverse">
310
+ <path d="M 0 0 L 10 5 L 0 10 z" fill="#64748b"/>
311
+ </marker>
312
+ </defs>
313
+ ```
314
+
315
+ ### Filter Effects
316
+
317
+ ```xml
318
+ <defs>
319
+ <!-- Drop shadow for elevated elements -->
320
+ <filter id="dropShadow" x="-20%" y="-20%" width="140%" height="140%">
321
+ <feDropShadow dx="0" dy="4" stdDeviation="8" flood-color="#000" flood-opacity="0.5"/>
322
+ </filter>
323
+
324
+ <!-- Glow effect for active/highlighted elements -->
325
+ <filter id="glow" x="-50%" y="-50%" width="200%" height="200%">
326
+ <feGaussianBlur stdDeviation="4" result="coloredBlur"/>
327
+ <feMerge>
328
+ <feMergeNode in="coloredBlur"/>
329
+ <feMergeNode in="SourceGraphic"/>
330
+ </feMerge>
331
+ </filter>
332
+
333
+ <!-- Text glow for titles -->
334
+ <filter id="textGlow" x="-20%" y="-20%" width="140%" height="140%">
335
+ <feGaussianBlur in="SourceAlpha" stdDeviation="2" result="blur"/>
336
+ <feFlood flood-color="#c9a227" flood-opacity="0.5"/>
337
+ <feComposite in2="blur" operator="in"/>
338
+ <feMerge>
339
+ <feMergeNode/>
340
+ <feMergeNode in="SourceGraphic"/>
341
+ </feMerge>
342
+ </filter>
343
+ </defs>
344
+ ```
345
+
346
+ ---
347
+
348
+ ## Typography
349
+
350
+ ### Font Stack
351
+ ```css
352
+ /* Primary: Technical content */
353
+ font-family: 'JetBrains Mono', 'Fira Code', 'Consolas', monospace;
354
+
355
+ /* Display: Titles and headers */
356
+ font-family: 'Georgia', 'Times New Roman', serif;
357
+
358
+ /* UI: Labels and annotations */
359
+ font-family: 'Inter', 'SF Pro Display', 'Segoe UI', sans-serif;
360
+ ```
361
+
362
+ ### Text Hierarchy
363
+
364
+ | Level | Font | Size | Color | Usage |
365
+ |-------|------|------|-------|-------|
366
+ | **Title** | Georgia Bold | 32-48px | `url(#goldShine)` | Diagram title |
367
+ | **Section** | Inter SemiBold | 18-24px | `#e2e8f0` | Layer/section names |
368
+ | **Label** | Inter Medium | 12-14px | `#94a3b8` | Component labels |
369
+ | **Code** | JetBrains Mono | 11-13px | `#a5b4fc` | Technical names |
370
+ | **Annotation** | Inter Regular | 10-11px | `#64748b` | Explanatory notes |
371
+
372
+ ### Text Examples
373
+
374
+ ```xml
375
+ <!-- Diagram Title -->
376
+ <text x="700" y="50" text-anchor="middle"
377
+ font-family="Georgia, serif" font-size="38" font-weight="bold"
378
+ fill="url(#goldShine)" filter="url(#textGlow)">
379
+ System Architecture
380
+ </text>
381
+
382
+ <!-- Section Header -->
383
+ <text x="100" y="120"
384
+ font-family="Inter, sans-serif" font-size="20" font-weight="600"
385
+ fill="#e2e8f0" letter-spacing="2">
386
+ APPLICATION LAYER
387
+ </text>
388
+
389
+ <!-- Component Label -->
390
+ <text x="150" y="180" text-anchor="middle"
391
+ font-family="Inter, sans-serif" font-size="13" font-weight="500"
392
+ fill="#94a3b8">
393
+ API Gateway
394
+ </text>
395
+
396
+ <!-- Technical Name -->
397
+ <text x="150" y="200" text-anchor="middle"
398
+ font-family="JetBrains Mono, monospace" font-size="11"
399
+ fill="#a5b4fc">
400
+ express.Router()
401
+ </text>
402
+ ```
403
+
404
+ ---
405
+
406
+ ## Layout Guidelines
407
+
408
+ ### Spacing Scale
409
+
410
+ ```
411
+ 4px - Minimal gap (text kerning adjustments)
412
+ 8px - Tight spacing (inline elements)
413
+ 16px - Standard padding (component internals)
414
+ 24px - Comfortable margin (between components)
415
+ 32px - Section spacing (between logical groups)
416
+ 48px - Layer separation (major architectural boundaries)
417
+ 64px - Canvas margins (diagram edges)
418
+ ```
419
+
420
+ ### Alignment Rules
421
+
422
+ 1. **Vertical stacks**: Align centers, maintain consistent width
423
+ 2. **Horizontal flows**: Align baselines, maintain consistent height
424
+ 3. **Nested containers**: Indent by 24px per nesting level
425
+ 4. **Connectors**: Use orthogonal routing (90° angles only)
426
+
427
+ ### Responsive Considerations
428
+
429
+ For large diagrams (>1200px wide):
430
+ - Use `viewBox` for scalability
431
+ - Minimum text size: 10px at 100% zoom
432
+ - Ensure 4:3 or 16:9 aspect ratios for presentation compatibility
433
+
434
+ ---
435
+
436
+ ## Icon Vocabulary
437
+
438
+ ### Standard Symbols
439
+
440
+ ```xml
441
+ <!-- Database (cylinder) -->
442
+ <symbol id="iconDatabase" viewBox="0 0 32 32">
443
+ <ellipse cx="16" cy="6" rx="12" ry="4" fill="none" stroke="currentColor" stroke-width="2"/>
444
+ <path d="M4 6 v20 a12,4 0 0,0 24,0 v-20" fill="none" stroke="currentColor" stroke-width="2"/>
445
+ <ellipse cx="16" cy="26" rx="12" ry="4" fill="none" stroke="currentColor" stroke-width="2"/>
446
+ </symbol>
447
+
448
+ <!-- Server/Service (rectangle with status) -->
449
+ <symbol id="iconServer" viewBox="0 0 32 32">
450
+ <rect x="2" y="4" width="28" height="24" rx="3" fill="none" stroke="currentColor" stroke-width="2"/>
451
+ <line x1="2" y1="12" x2="30" y2="12" stroke="currentColor" stroke-width="2"/>
452
+ <circle cx="8" cy="8" r="2" fill="currentColor"/>
453
+ <line x1="8" y1="18" x2="24" y2="18" stroke="currentColor" stroke-width="2"/>
454
+ <line x1="8" y1="22" x2="20" y2="22" stroke="currentColor" stroke-width="2"/>
455
+ </symbol>
456
+
457
+ <!-- API (connected nodes) -->
458
+ <symbol id="iconAPI" viewBox="0 0 32 32">
459
+ <circle cx="8" cy="16" r="5" fill="none" stroke="currentColor" stroke-width="2"/>
460
+ <circle cx="24" cy="16" r="5" fill="none" stroke="currentColor" stroke-width="2"/>
461
+ <line x1="13" y1="16" x2="19" y2="16" stroke="currentColor" stroke-width="2"/>
462
+ <circle cx="16" cy="6" r="4" fill="none" stroke="currentColor" stroke-width="2"/>
463
+ <line x1="16" y1="10" x2="16" y2="14" stroke="currentColor" stroke-width="2"/>
464
+ </symbol>
465
+
466
+ <!-- Queue (stacked items) -->
467
+ <symbol id="iconQueue" viewBox="0 0 32 32">
468
+ <rect x="4" y="4" width="24" height="6" rx="2" fill="none" stroke="currentColor" stroke-width="2"/>
469
+ <rect x="4" y="13" width="24" height="6" rx="2" fill="none" stroke="currentColor" stroke-width="2"/>
470
+ <rect x="4" y="22" width="24" height="6" rx="2" fill="none" stroke="currentColor" stroke-width="2"/>
471
+ </symbol>
472
+
473
+ <!-- External System (cloud) -->
474
+ <symbol id="iconCloud" viewBox="0 0 32 32">
475
+ <path d="M8 24 a6,6 0 0,1 0-12 a8,8 0 0,1 16,0 a5,5 0 0,1 0,12 z"
476
+ fill="none" stroke="currentColor" stroke-width="2"/>
477
+ </symbol>
478
+
479
+ <!-- Gem/Accent (decorative) -->
480
+ <symbol id="iconGem" viewBox="0 0 32 32">
481
+ <polygon points="16,2 28,12 16,30 4,12"
482
+ fill="none" stroke="currentColor" stroke-width="2"/>
483
+ <line x1="4" y1="12" x2="28" y2="12" stroke="currentColor" stroke-width="1"/>
484
+ <line x1="16" y1="2" x2="10" y2="12" stroke="currentColor" stroke-width="1"/>
485
+ <line x1="16" y1="2" x2="22" y2="12" stroke="currentColor" stroke-width="1"/>
486
+ <line x1="10" y1="12" x2="16" y2="30" stroke="currentColor" stroke-width="1"/>
487
+ <line x1="22" y1="12" x2="16" y2="30" stroke="currentColor" stroke-width="1"/>
488
+ </symbol>
489
+ ```
490
+
491
+ ### Icon Usage
492
+
493
+ ```xml
494
+ <!-- Place icon with color -->
495
+ <use href="#iconDatabase" x="100" y="100" width="32" height="32"
496
+ style="color: #10b981"/>
497
+
498
+ <!-- Icon with label -->
499
+ <g transform="translate(200, 150)">
500
+ <use href="#iconServer" x="0" y="0" width="32" height="32" style="color: #3b82f6"/>
501
+ <text x="16" y="45" text-anchor="middle"
502
+ font-family="Inter, sans-serif" font-size="11" fill="#94a3b8">
503
+ API Server
504
+ </text>
505
+ </g>
506
+ ```
507
+
508
+ ---
509
+
510
+ ## Complete Example: Three-Tier Architecture
511
+
512
+ ```xml
513
+ <?xml version="1.0" encoding="UTF-8"?>
514
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 600">
515
+ <defs>
516
+ <!-- Include all gradients, markers, filters from above -->
517
+ <linearGradient id="obsidianBg" x1="0%" y1="0%" x2="0%" y2="100%">
518
+ <stop offset="0%" stop-color="#1a1f2e"/>
519
+ <stop offset="100%" stop-color="#0d1117"/>
520
+ </linearGradient>
521
+ <linearGradient id="goldAccent" x1="0%" y1="0%" x2="100%" y2="0%">
522
+ <stop offset="0%" stop-color="#d4af37"/>
523
+ <stop offset="50%" stop-color="#c9a227"/>
524
+ <stop offset="100%" stop-color="#d4af37"/>
525
+ </linearGradient>
526
+ <filter id="dropShadow">
527
+ <feDropShadow dx="0" dy="4" stdDeviation="8" flood-opacity="0.4"/>
528
+ </filter>
529
+ </defs>
530
+
531
+ <!-- Background -->
532
+ <rect width="800" height="600" fill="url(#obsidianBg)"/>
533
+
534
+ <!-- Title -->
535
+ <text x="400" y="45" text-anchor="middle"
536
+ font-family="Georgia, serif" font-size="28" font-weight="bold"
537
+ fill="url(#goldAccent)">
538
+ Three-Tier Architecture
539
+ </text>
540
+
541
+ <!-- Presentation Layer -->
542
+ <g transform="translate(50, 80)">
543
+ <rect width="700" height="120" rx="8" fill="#161b22"
544
+ stroke="#c9a227" stroke-width="2" filter="url(#dropShadow)"/>
545
+ <text x="20" y="25" font-family="Inter, sans-serif" font-size="14"
546
+ fill="#c9a227" font-weight="600">PRESENTATION LAYER</text>
547
+
548
+ <g transform="translate(50, 45)">
549
+ <rect width="140" height="60" rx="6" fill="#21262d" stroke="#64748b"/>
550
+ <text x="70" y="35" text-anchor="middle" font-family="Inter"
551
+ font-size="13" fill="#e2e8f0">Web Browser</text>
552
+ </g>
553
+ <g transform="translate(230, 45)">
554
+ <rect width="140" height="60" rx="6" fill="#21262d" stroke="#64748b"/>
555
+ <text x="70" y="35" text-anchor="middle" font-family="Inter"
556
+ font-size="13" fill="#e2e8f0">Mobile App</text>
557
+ </g>
558
+ <g transform="translate(410, 45)">
559
+ <rect width="140" height="60" rx="6" fill="#21262d" stroke="#64748b"/>
560
+ <text x="70" y="35" text-anchor="middle" font-family="Inter"
561
+ font-size="13" fill="#e2e8f0">CLI Tool</text>
562
+ </g>
563
+ </g>
564
+
565
+ <!-- Connectors: Presentation → Business -->
566
+ <g stroke="#c9a227" stroke-width="2">
567
+ <line x1="400" y1="200" x2="400" y2="230"/>
568
+ <polygon points="395,225 400,235 405,225" fill="#c9a227"/>
569
+ </g>
570
+
571
+ <!-- Business Layer -->
572
+ <g transform="translate(50, 240)">
573
+ <rect width="700" height="120" rx="8" fill="#161b22"
574
+ stroke="#3b82f6" stroke-width="2" filter="url(#dropShadow)"/>
575
+ <text x="20" y="25" font-family="Inter, sans-serif" font-size="14"
576
+ fill="#3b82f6" font-weight="600">BUSINESS LAYER</text>
577
+
578
+ <g transform="translate(50, 45)">
579
+ <rect width="180" height="60" rx="6" fill="#21262d" stroke="#3b82f6"/>
580
+ <text x="90" y="35" text-anchor="middle" font-family="Inter"
581
+ font-size="13" fill="#e2e8f0">API Gateway</text>
582
+ </g>
583
+ <g transform="translate(260, 45)">
584
+ <rect width="180" height="60" rx="6" fill="#21262d" stroke="#3b82f6"/>
585
+ <text x="90" y="35" text-anchor="middle" font-family="Inter"
586
+ font-size="13" fill="#e2e8f0">Service Layer</text>
587
+ </g>
588
+ <g transform="translate(470, 45)">
589
+ <rect width="180" height="60" rx="6" fill="#21262d" stroke="#3b82f6"/>
590
+ <text x="90" y="35" text-anchor="middle" font-family="Inter"
591
+ font-size="13" fill="#e2e8f0">Auth Service</text>
592
+ </g>
593
+ </g>
594
+
595
+ <!-- Connectors: Business → Data -->
596
+ <g stroke="#3b82f6" stroke-width="2">
597
+ <line x1="400" y1="360" x2="400" y2="390"/>
598
+ <polygon points="395,385 400,395 405,385" fill="#3b82f6"/>
599
+ </g>
600
+
601
+ <!-- Data Layer -->
602
+ <g transform="translate(50, 400)">
603
+ <rect width="700" height="120" rx="8" fill="#161b22"
604
+ stroke="#10b981" stroke-width="2" filter="url(#dropShadow)"/>
605
+ <text x="20" y="25" font-family="Inter, sans-serif" font-size="14"
606
+ fill="#10b981" font-weight="600">DATA LAYER</text>
607
+
608
+ <g transform="translate(50, 45)">
609
+ <rect width="180" height="60" rx="6" fill="#21262d" stroke="#10b981"/>
610
+ <text x="90" y="35" text-anchor="middle" font-family="Inter"
611
+ font-size="13" fill="#e2e8f0">Primary Database</text>
612
+ </g>
613
+ <g transform="translate(260, 45)">
614
+ <rect width="180" height="60" rx="6" fill="#21262d" stroke="#10b981"/>
615
+ <text x="90" y="35" text-anchor="middle" font-family="Inter"
616
+ font-size="13" fill="#e2e8f0">Cache Layer</text>
617
+ </g>
618
+ <g transform="translate(470, 45)">
619
+ <rect width="180" height="60" rx="6" fill="#21262d" stroke="#10b981"/>
620
+ <text x="90" y="35" text-anchor="middle" font-family="Inter"
621
+ font-size="13" fill="#e2e8f0">File Storage</text>
622
+ </g>
623
+ </g>
624
+
625
+ <!-- Legend -->
626
+ <g transform="translate(50, 550)">
627
+ <text x="0" y="0" font-family="Inter" font-size="10" fill="#64748b">
628
+ <tspan fill="#c9a227">■</tspan> Entry Points
629
+ <tspan dx="20" fill="#3b82f6">■</tspan> Services
630
+ <tspan dx="20" fill="#10b981">■</tspan> Storage
631
+ </text>
632
+ </g>
633
+ </svg>
634
+ ```
635
+
636
+ ---
637
+
638
+ ## Validation & Tooling
639
+
640
+ Use the SVG validation tools to ensure diagram quality:
641
+
642
+ ```bash
643
+ # Validate XML and check for issues
644
+ node tools/dev/svg-validate.js docs/diagrams/my-architecture.svg
645
+
646
+ # Check for visual overlaps
647
+ node tools/dev/svg-collisions.js docs/diagrams/my-architecture.svg
648
+
649
+ # Index elements for reference
650
+ node tools/dev/svg-validate.js docs/diagrams/my-architecture.svg --index
651
+
652
+ # Find specific elements
653
+ node tools/dev/svg-validate.js docs/diagrams/my-architecture.svg --find "@rect"
654
+ node tools/dev/svg-validate.js docs/diagrams/my-architecture.svg --find "L:50-100"
655
+ ```
656
+
657
+ ---
658
+
659
+ ## Checklist for Architecture Diagrams
660
+
661
+ - [ ] **Clear hierarchy**: Layers read top-to-bottom or left-to-right
662
+ - [ ] **Consistent colors**: Each color encodes the same meaning throughout
663
+ - [ ] **Readable text**: Minimum 10px at 100% zoom
664
+ - [ ] **Labeled connections**: Data flows have directional arrows
665
+ - [ ] **Legend included**: Color/symbol meanings explained
666
+ - [ ] **Valid SVG**: Passes `svg-validate.js` checks
667
+ - [ ] **No overlaps**: Passes `svg-collisions.js` checks
668
+ - [ ] **Proper viewBox**: Scalable without distortion
669
+ - [ ] **Accessible names**: Groups have meaningful structure
670
+
671
+ ---
672
+
673
+ ## Scrollbar Styling (Obsidian Theme)
674
+
675
+ Custom scrollbars are essential for maintaining visual consistency in dark-themed dashboards. The Obsidian theme uses subtle, elegant scrollbars that complement the jewel-toned aesthetic.
676
+
677
+ ### ⚠️ CRITICAL: Preventing Layout Jiggle
678
+
679
+ **Layout jiggle** occurs when scrollbar appearance/disappearance causes content to shift horizontally. This is the most common scrollbar UX problem and MUST be addressed.
680
+
681
+ **Solution: Use Overlay Scrollbars**
682
+
683
+ ```css
684
+ /* RECOMMENDED: Overlay scrollbars - no layout jiggle */
685
+ .my-scrollable-container {
686
+ /* Primary: overlay scrollbars (Chromium-based browsers) */
687
+ overflow-y: overlay;
688
+ /* Reserve space on browsers that support it */
689
+ scrollbar-gutter: stable;
690
+ /* Firefox styling */
691
+ scrollbar-width: thin;
692
+ scrollbar-color: var(--obsidian-border) transparent;
693
+ }
694
+
695
+ /* Fallback for browsers without overlay support */
696
+ @supports not (overflow: overlay) {
697
+ .my-scrollable-container {
698
+ overflow-y: auto;
699
+ /* scrollbar-gutter: stable still helps in modern Firefox */
700
+ }
701
+ }
702
+ ```
703
+
704
+ **Key CSS Properties:**
705
+
706
+ | Property | Purpose |
707
+ |----------|---------|
708
+ | `overflow: overlay` | Scrollbar floats over content (Chromium) |
709
+ | `scrollbar-gutter: stable` | Reserves scrollbar space to prevent jiggle |
710
+ | `background: transparent` on track | Makes overlay scrollbar less intrusive |
711
+
712
+ **Available Utility Classes** (from `src/ui/css/obsidian-scrollbars.css`):
713
+
714
+ | Class | Description |
715
+ |-------|-------------|
716
+ | `.obsidian-scroll-overlay` | **RECOMMENDED** - No layout jiggle, gold theme |
717
+ | `.obsidian-scroll-overlay-glow` | Overlay + gold glow on hover |
718
+ | `.obsidian-scroll` | Standard scrollbar (may jiggle) |
719
+ | `.obsidian-scroll-thin` | 6px width scrollbar |
720
+ | `.obsidian-scroll-hidden` | Hidden scrollbar (still scrollable) |
721
+
722
+ ### CSS Variables for Scrollbars
723
+
724
+ Use these CSS variables (defined in `:root`) for consistent scrollbar theming:
725
+
726
+ ```css
727
+ :root {
728
+ /* Core backgrounds */
729
+ --obsidian-bg-deep: rgba(10, 13, 20, 0.99);
730
+ --obsidian-bg-surface: rgba(20, 24, 36, 0.98);
731
+ --obsidian-bg-elevated: rgba(30, 35, 50, 0.95);
732
+
733
+ /* Gold accents */
734
+ --obsidian-gold: #c9a227;
735
+ --obsidian-gold-dim: rgba(201, 162, 39, 0.6);
736
+ --obsidian-gold-glow: rgba(201, 162, 39, 0.4);
737
+
738
+ /* Borders */
739
+ --obsidian-border: rgba(201, 162, 39, 0.3);
740
+ --obsidian-border-dim: rgba(201, 162, 39, 0.15);
741
+ }
742
+ ```
743
+
744
+ ### Standard Scrollbar Implementation
745
+
746
+ Apply to any scrollable container:
747
+
748
+ ```css
749
+ /* Scrollbar - Obsidian Luxury */
750
+ .your-scrollable-container {
751
+ overflow-y: auto;
752
+ scrollbar-width: thin; /* Firefox */
753
+ scrollbar-color: var(--obsidian-border) var(--obsidian-bg-deep); /* Firefox */
754
+ }
755
+
756
+ /* WebKit Browsers (Chrome, Safari, Edge) */
757
+ .your-scrollable-container::-webkit-scrollbar {
758
+ width: 8px;
759
+ height: 8px;
760
+ }
761
+
762
+ .your-scrollable-container::-webkit-scrollbar-track {
763
+ background: var(--obsidian-bg-deep);
764
+ border-radius: 4px;
765
+ }
766
+
767
+ .your-scrollable-container::-webkit-scrollbar-thumb {
768
+ background: var(--obsidian-border);
769
+ border-radius: 4px;
770
+ border: 1px solid transparent;
771
+ background-clip: content-box;
772
+ }
773
+
774
+ .your-scrollable-container::-webkit-scrollbar-thumb:hover {
775
+ background: var(--obsidian-gold-dim);
776
+ }
777
+
778
+ .your-scrollable-container::-webkit-scrollbar-corner {
779
+ background: var(--obsidian-bg-deep);
780
+ }
781
+ ```
782
+
783
+ ### Size Variants
784
+
785
+ | Variant | Width | Use Case |
786
+ |---------|-------|----------|
787
+ | **Thin** | 6px | Compact lists, sidebars |
788
+ | **Standard** | 8px | Default for most containers |
789
+ | **Wide** | 12px | Main content areas, data tables |
790
+
791
+ ```css
792
+ /* Thin variant */
793
+ .scrollbar-thin::-webkit-scrollbar { width: 6px; }
794
+
795
+ /* Wide variant */
796
+ .scrollbar-wide::-webkit-scrollbar { width: 12px; }
797
+ ```
798
+
799
+ ### Scrollbar Hover Glow Effect
800
+
801
+ For premium interactive feel, add a gold glow on hover:
802
+
803
+ ```css
804
+ .premium-scrollbar::-webkit-scrollbar-thumb:hover {
805
+ background: var(--obsidian-gold-dim);
806
+ box-shadow:
807
+ 0 0 4px var(--obsidian-gold-glow),
808
+ inset 0 0 2px var(--obsidian-gold-glow);
809
+ }
810
+ ```
811
+
812
+ ### jsgui3 Integration
813
+
814
+ When building jsgui3 controls with scrollable areas, add scrollbar CSS in the control's factory:
815
+
816
+ ```javascript
817
+ // In your control factory
818
+ class ScrollableListControl extends jsgui.Control {
819
+ constructor(spec = {}) {
820
+ super({ ...spec, tagName: 'div' });
821
+ this.dom.attributes.set('class', 'scrollable-list obsidian-scroll');
822
+ // ...
823
+ }
824
+ }
825
+ ```
826
+
827
+ Reference CSS file:
828
+ - `src/ui/controls/DatabaseSelector.css` - Full implementation example
829
+ - `src/ui/css/obsidian-scrollbars.css` - Shared scrollbar utilities (create if needed)
830
+
831
+ ### Best Practices
832
+
833
+ 1. **Always include Firefox fallback** - `scrollbar-width: thin; scrollbar-color: ...`
834
+ 2. **Use CSS variables** - Never hardcode colors
835
+ 3. **Respect container borders** - Add `padding-right` to prevent content touching scrollbar
836
+ 4. **Test dark mode** - Scrollbars should be subtle but visible
837
+ 5. **Consider touch devices** - Scrollbar styles may be ignored on mobile
838
+
839
+ ---
840
+
841
+ ## Related Resources
842
+
843
+ - `docs/diagrams/decision-tree-engine-deep-dive.svg` - Reference implementation
844
+ - `tools/dev/svg-validate.js` - Validation tool with hash indexing
845
+ - `tools/dev/svg-collisions.js` - Visual collision detection
846
+ - `tools/dev/svg-shared/hashUtils.js` - Element referencing utilities
847
+ - `src/ui/controls/DatabaseSelector.css` - Scrollbar implementation reference