@plannotator/pi-extension 0.19.13 → 0.19.14

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.
@@ -0,0 +1,368 @@
1
+ # SVG Diagram Patterns
2
+
3
+ Building blocks for creating diagrams in implementation plans. All SVGs are inline — no external dependencies. Compose these patterns to build architecture diagrams, data flow visualizations, flowcharts, and charts.
4
+
5
+ All colors reference Plannotator theme tokens. In SVG, use the CSS custom property values directly via `style` attributes or the corresponding CSS classes.
6
+
7
+ ## Table of Contents
8
+ 1. [Arrow Markers](#arrow-markers)
9
+ 2. [Architecture Diagrams](#architecture-diagrams)
10
+ 3. [Flowcharts](#flowcharts)
11
+ 4. [Data Flow](#data-flow)
12
+ 5. [Bar Charts](#bar-charts)
13
+ 6. [Positioning & Layout](#positioning--layout)
14
+
15
+ ## Arrow markers
16
+
17
+ Define reusable markers in `<defs>`. Reference them via `marker-end="url(#arrow)"`.
18
+
19
+ ```svg
20
+ <defs>
21
+ <marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5"
22
+ markerWidth="7" markerHeight="7" orient="auto-start-reverse">
23
+ <path d="M0,0 L10,5 L0,10 z" fill="var(--muted-foreground)"/>
24
+ </marker>
25
+
26
+ <marker id="arrow-primary" viewBox="0 0 10 10" refX="9" refY="5"
27
+ markerWidth="7" markerHeight="7" orient="auto-start-reverse">
28
+ <path d="M0,0 L10,5 L0,10 z" fill="var(--primary)"/>
29
+ </marker>
30
+
31
+ <marker id="arrow-success" viewBox="0 0 10 10" refX="9" refY="5"
32
+ markerWidth="7" markerHeight="7" orient="auto-start-reverse">
33
+ <path d="M0,0 L10,5 L0,10 z" fill="var(--success)"/>
34
+ </marker>
35
+
36
+ <marker id="arrow-destructive" viewBox="0 0 10 10" refX="9" refY="5"
37
+ markerWidth="7" markerHeight="7" orient="auto-start-reverse">
38
+ <path d="M0,0 L10,5 L0,10 z" fill="var(--destructive)"/>
39
+ </marker>
40
+ </defs>
41
+ ```
42
+
43
+ **Note on CSS vars in SVG:** `fill="var(--primary)"` works in inline SVG within an HTML document. For broader compatibility, you can also style via CSS classes instead of inline attributes.
44
+
45
+ ## Architecture diagrams
46
+
47
+ Box-and-arrow diagrams showing how components connect.
48
+
49
+ ### Box node
50
+
51
+ ```svg
52
+ <g transform="translate(100, 80)">
53
+ <rect width="140" height="56" rx="10" fill="var(--card)"
54
+ stroke="var(--border)" stroke-width="1.5"/>
55
+ <text x="70" y="24" text-anchor="middle"
56
+ font-family="var(--font-sans)" font-size="13" font-weight="600"
57
+ fill="var(--foreground)">API Server</text>
58
+ <text x="70" y="40" text-anchor="middle"
59
+ font-family="var(--font-mono)" font-size="10.5"
60
+ fill="var(--muted-foreground)">Express + middleware</text>
61
+ </g>
62
+ ```
63
+
64
+ ### Highlighted box (new or hot-path component)
65
+
66
+ ```svg
67
+ <g transform="translate(100, 80)">
68
+ <rect width="140" height="56" rx="10"
69
+ fill="color-mix(in oklab, var(--primary) 8%, transparent)"
70
+ stroke="var(--primary)" stroke-width="1.5"/>
71
+ <text x="70" y="24" text-anchor="middle"
72
+ font-family="var(--font-sans)" font-size="13" font-weight="600"
73
+ fill="var(--foreground)">New Service</text>
74
+ <text x="70" y="40" text-anchor="middle"
75
+ font-family="var(--font-mono)" font-size="10.5"
76
+ fill="var(--primary)">to be created</text>
77
+ </g>
78
+ ```
79
+
80
+ ### Connecting arrows
81
+
82
+ ```svg
83
+ <!-- Horizontal -->
84
+ <line x1="240" y1="108" x2="320" y2="108"
85
+ stroke="var(--muted-foreground)" stroke-width="1.5"
86
+ marker-end="url(#arrow)"/>
87
+
88
+ <!-- Vertical -->
89
+ <line x1="170" y1="136" x2="170" y2="200"
90
+ stroke="var(--muted-foreground)" stroke-width="1.5"
91
+ marker-end="url(#arrow)"/>
92
+
93
+ <!-- Dashed (async, optional, or secondary) -->
94
+ <line x1="240" y1="108" x2="320" y2="108"
95
+ stroke="var(--primary)" stroke-width="1.5"
96
+ stroke-dasharray="5 4"
97
+ marker-end="url(#arrow-primary)"/>
98
+ ```
99
+
100
+ ### Edge labels
101
+
102
+ Place at the midpoint of an arrow, offset above:
103
+
104
+ ```svg
105
+ <text x="280" y="100" text-anchor="middle"
106
+ font-family="var(--font-mono)" font-size="9.5"
107
+ fill="var(--muted-foreground)">REST</text>
108
+ ```
109
+
110
+ ### Full architecture example
111
+
112
+ ```svg
113
+ <svg viewBox="0 0 720 280" xmlns="http://www.w3.org/2000/svg"
114
+ style="width:100%;max-width:720px">
115
+ <style>
116
+ .box { fill: var(--card); stroke: var(--border); stroke-width: 1.5; }
117
+ .box-new { fill: color-mix(in oklab, var(--primary) 8%, transparent);
118
+ stroke: var(--primary); stroke-width: 1.5; }
119
+ .label { font-family: var(--font-sans); font-size: 13px;
120
+ font-weight: 600; fill: var(--foreground); }
121
+ .sublabel { font-family: var(--font-mono); font-size: 10.5px;
122
+ fill: var(--muted-foreground); }
123
+ .edge { stroke: var(--muted-foreground); stroke-width: 1.5; }
124
+ .edge-label { font-family: var(--font-mono); font-size: 9.5px;
125
+ fill: var(--muted-foreground); }
126
+ </style>
127
+ <defs>
128
+ <marker id="a" viewBox="0 0 10 10" refX="9" refY="5"
129
+ markerWidth="7" markerHeight="7" orient="auto-start-reverse">
130
+ <path d="M0,0 L10,5 L0,10 z" fill="var(--muted-foreground)"/>
131
+ </marker>
132
+ </defs>
133
+
134
+ <!-- Browser -->
135
+ <rect x="20" y="100" width="120" height="56" rx="10" class="box"/>
136
+ <text x="80" y="124" text-anchor="middle" class="label">Browser</text>
137
+ <text x="80" y="140" text-anchor="middle" class="sublabel">React SPA</text>
138
+
139
+ <!-- Arrow: Browser → API -->
140
+ <line x1="140" y1="128" x2="220" y2="128" class="edge" marker-end="url(#a)"/>
141
+ <text x="180" y="120" text-anchor="middle" class="edge-label">HTTPS</text>
142
+
143
+ <!-- API Gateway (new) -->
144
+ <rect x="220" y="100" width="140" height="56" rx="10" class="box-new"/>
145
+ <text x="290" y="124" text-anchor="middle" class="label">API Gateway</text>
146
+ <text x="290" y="140" text-anchor="middle" class="sublabel"
147
+ fill="var(--primary)">new</text>
148
+
149
+ <!-- Arrow: API → DB -->
150
+ <line x1="360" y1="128" x2="440" y2="128" class="edge" marker-end="url(#a)"/>
151
+
152
+ <!-- Postgres -->
153
+ <rect x="440" y="100" width="120" height="56" rx="10" class="box"/>
154
+ <text x="500" y="124" text-anchor="middle" class="label">Postgres</text>
155
+ <text x="500" y="140" text-anchor="middle" class="sublabel">existing</text>
156
+
157
+ <!-- Arrow: API → Cache (vertical) -->
158
+ <line x1="290" y1="156" x2="290" y2="210" class="edge" marker-end="url(#a)"/>
159
+
160
+ <!-- Redis -->
161
+ <rect x="220" y="210" width="140" height="48" rx="10" class="box"/>
162
+ <text x="290" y="240" text-anchor="middle" class="label">Redis Cache</text>
163
+ </svg>
164
+ ```
165
+
166
+ ## Flowcharts
167
+
168
+ ### Process box
169
+
170
+ ```svg
171
+ <rect x="250" y="80" width="120" height="40" rx="8"
172
+ fill="var(--card)" stroke="var(--border)" stroke-width="1.5"/>
173
+ <text x="310" y="105" text-anchor="middle"
174
+ font-family="var(--font-sans)" font-size="12" font-weight="500"
175
+ fill="var(--foreground)">Parse input</text>
176
+ ```
177
+
178
+ ### Decision diamond
179
+
180
+ ```svg
181
+ <path d="M310,262 L352,294 L310,326 L268,294 Z"
182
+ fill="var(--card)" stroke="var(--border)" stroke-width="1.5"/>
183
+ <text x="310" y="298" text-anchor="middle"
184
+ font-family="var(--font-sans)" font-size="11" font-weight="500"
185
+ fill="var(--foreground)">Valid?</text>
186
+ ```
187
+
188
+ ### Terminal / pill node
189
+
190
+ ```svg
191
+ <rect x="260" y="20" width="100" height="36" rx="18"
192
+ fill="var(--card)" stroke="var(--border)" stroke-width="1.5"/>
193
+ <text x="310" y="43" text-anchor="middle"
194
+ font-family="var(--font-sans)" font-size="12" font-weight="500"
195
+ fill="var(--foreground)">Start</text>
196
+ ```
197
+
198
+ ### Success / failure endpoints
199
+
200
+ ```svg
201
+ <!-- Success -->
202
+ <rect x="260" y="400" width="100" height="36" rx="18"
203
+ fill="color-mix(in oklab, var(--success) 12%, transparent)"
204
+ stroke="var(--success)" stroke-width="1.5"/>
205
+ <text x="310" y="423" text-anchor="middle"
206
+ font-family="var(--font-sans)" font-size="12" font-weight="600"
207
+ fill="var(--success)">Done</text>
208
+
209
+ <!-- Failure -->
210
+ <rect x="100" y="400" width="100" height="36" rx="18"
211
+ fill="color-mix(in oklab, var(--destructive) 12%, transparent)"
212
+ stroke="var(--destructive)" stroke-width="1.5"/>
213
+ <text x="150" y="423" text-anchor="middle"
214
+ font-family="var(--font-sans)" font-size="12" font-weight="600"
215
+ fill="var(--destructive)">Error</text>
216
+ ```
217
+
218
+ ### Curved branch path
219
+
220
+ For routing flow from a decision to a side branch:
221
+
222
+ ```svg
223
+ <path d="M268,294 C200,294 160,294 160,240"
224
+ fill="none" stroke="var(--destructive)" stroke-width="1.5"
225
+ marker-end="url(#arrow-destructive)"/>
226
+ ```
227
+
228
+ ## Data flow
229
+
230
+ ### Request / response pair
231
+
232
+ ```svg
233
+ <!-- Request (solid) -->
234
+ <line x1="140" y1="100" x2="280" y2="100"
235
+ stroke="var(--muted-foreground)" stroke-width="1.5"
236
+ marker-end="url(#arrow)"/>
237
+ <text x="210" y="92" text-anchor="middle"
238
+ font-family="var(--font-mono)" font-size="9.5"
239
+ fill="var(--muted-foreground)">POST /api/plan</text>
240
+
241
+ <!-- Response (dashed) -->
242
+ <line x1="280" y1="116" x2="140" y2="116"
243
+ stroke="var(--primary)" stroke-width="1.5" stroke-dasharray="5 4"
244
+ marker-end="url(#arrow-primary)"/>
245
+ <text x="210" y="132" text-anchor="middle"
246
+ font-family="var(--font-mono)" font-size="9.5"
247
+ fill="var(--primary)">{ plan, status }</text>
248
+ ```
249
+
250
+ ### Fan-out pattern
251
+
252
+ ```svg
253
+ <!-- Source box radiating to multiple targets -->
254
+ <line x1="200" y1="100" x2="340" y2="60"
255
+ stroke="var(--muted-foreground)" stroke-width="1.5" marker-end="url(#arrow)"/>
256
+ <line x1="200" y1="100" x2="340" y2="100"
257
+ stroke="var(--muted-foreground)" stroke-width="1.5" marker-end="url(#arrow)"/>
258
+ <line x1="200" y1="100" x2="340" y2="140"
259
+ stroke="var(--muted-foreground)" stroke-width="1.5" marker-end="url(#arrow)"/>
260
+ ```
261
+
262
+ ## Bar charts
263
+
264
+ ```svg
265
+ <svg viewBox="0 0 400 180" xmlns="http://www.w3.org/2000/svg"
266
+ style="width:100%;max-width:400px">
267
+ <!-- Gridlines -->
268
+ <line x1="40" y1="20" x2="380" y2="20"
269
+ stroke="var(--border)" stroke-width="1" opacity="0.5"/>
270
+ <line x1="40" y1="60" x2="380" y2="60"
271
+ stroke="var(--border)" stroke-width="1" opacity="0.5"/>
272
+ <line x1="40" y1="100" x2="380" y2="100"
273
+ stroke="var(--border)" stroke-width="1" opacity="0.5"/>
274
+ <line x1="40" y1="140" x2="380" y2="140"
275
+ stroke="var(--border)" stroke-width="1"/>
276
+
277
+ <!-- Y-axis labels -->
278
+ <text x="35" y="24" text-anchor="end"
279
+ font-family="var(--font-mono)" font-size="9"
280
+ fill="var(--muted-foreground)">30</text>
281
+ <text x="35" y="64" text-anchor="end"
282
+ font-family="var(--font-mono)" font-size="9"
283
+ fill="var(--muted-foreground)">20</text>
284
+ <text x="35" y="104" text-anchor="end"
285
+ font-family="var(--font-mono)" font-size="9"
286
+ fill="var(--muted-foreground)">10</text>
287
+
288
+ <!-- Bars (muted default, primary for peak) -->
289
+ <rect x="60" y="60" width="40" height="80" rx="4"
290
+ fill="var(--muted)"/>
291
+ <rect x="120" y="40" width="40" height="100" rx="4"
292
+ fill="var(--primary)"/>
293
+ <rect x="180" y="80" width="40" height="60" rx="4"
294
+ fill="var(--muted)"/>
295
+ <rect x="240" y="100" width="40" height="40" rx="4"
296
+ fill="var(--muted)"/>
297
+
298
+ <!-- Value labels -->
299
+ <text x="80" y="55" text-anchor="middle"
300
+ font-family="var(--font-mono)" font-size="10" font-weight="600"
301
+ fill="var(--foreground)">20</text>
302
+ <text x="140" y="35" text-anchor="middle"
303
+ font-family="var(--font-mono)" font-size="10" font-weight="600"
304
+ fill="var(--primary)">25</text>
305
+
306
+ <!-- X-axis labels -->
307
+ <text x="80" y="158" text-anchor="middle"
308
+ font-family="var(--font-mono)" font-size="9"
309
+ fill="var(--muted-foreground)">Q1</text>
310
+ <text x="140" y="158" text-anchor="middle"
311
+ font-family="var(--font-mono)" font-size="9"
312
+ fill="var(--muted-foreground)">Q2</text>
313
+ <text x="200" y="158" text-anchor="middle"
314
+ font-family="var(--font-mono)" font-size="9"
315
+ fill="var(--muted-foreground)">Q3</text>
316
+ <text x="260" y="158" text-anchor="middle"
317
+ font-family="var(--font-mono)" font-size="9"
318
+ fill="var(--muted-foreground)">Q4</text>
319
+ </svg>
320
+ ```
321
+
322
+ ## Positioning & layout
323
+
324
+ ### SVG container sizing
325
+ - Use `viewBox` with fixed coordinates; set `style="width:100%;max-width:NNNpx"` for responsive scaling
326
+ - Standard widths: `720px` full-width, `480px` half-width, `360px` sidebar
327
+ - Standard heights: `180–320px` for most diagrams
328
+
329
+ ### Box sizing
330
+ - Standard node: `120–160px` wide, `48–56px` tall
331
+ - Minimum gap between nodes: `60px` horizontal, `40px` vertical
332
+ - Arrow label offset: `8–12px` above the line
333
+ - Diagram padding: `20px` inside the viewBox edges
334
+
335
+ ### Color roles in diagrams
336
+
337
+ | Element | Fill / stroke | Token |
338
+ |---------|---------------|-------|
339
+ | Box background | fill | `var(--card)` |
340
+ | Box stroke | stroke | `var(--border)` |
341
+ | Highlighted box bg | fill | `color-mix(in oklab, var(--primary) 8%, transparent)` |
342
+ | Highlighted box stroke | stroke | `var(--primary)` |
343
+ | Arrow / connector | stroke | `var(--muted-foreground)` |
344
+ | Title text | fill | `var(--foreground)` |
345
+ | Subtitle / label text | fill | `var(--muted-foreground)` |
346
+ | Success path | stroke | `var(--success)` |
347
+ | Error path | stroke | `var(--destructive)` |
348
+ | Warning | fill | `var(--warning)` |
349
+
350
+ ### Using CSS classes in SVG
351
+
352
+ For cleaner markup, define reusable classes in a `<style>` block inside the SVG:
353
+
354
+ ```svg
355
+ <svg viewBox="0 0 720 280" xmlns="http://www.w3.org/2000/svg">
356
+ <style>
357
+ .box { fill: var(--card); stroke: var(--border); stroke-width: 1.5; }
358
+ .new { fill: color-mix(in oklab, var(--primary) 8%, transparent);
359
+ stroke: var(--primary); stroke-width: 1.5; }
360
+ .title { font-family: var(--font-sans); font-size: 13px;
361
+ font-weight: 600; fill: var(--foreground); }
362
+ .sub { font-family: var(--font-mono); font-size: 10.5px;
363
+ fill: var(--muted-foreground); }
364
+ .conn { stroke: var(--muted-foreground); stroke-width: 1.5; }
365
+ </style>
366
+ <!-- nodes and connectors use class="box", class="title", etc. -->
367
+ </svg>
368
+ ```