markgraphy 0.1.1
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/LICENSE.txt +21 -0
- package/README.md +154 -0
- package/dist/animated/GraphAgni.svelte +430 -0
- package/dist/animated/GraphAgni.svelte.d.ts +22 -0
- package/dist/animated/GraphAum.svelte +294 -0
- package/dist/animated/GraphAum.svelte.d.ts +20 -0
- package/dist/animated/GraphBoot.svelte +325 -0
- package/dist/animated/GraphBoot.svelte.d.ts +28 -0
- package/dist/animated/GraphCron.svelte +476 -0
- package/dist/animated/GraphCron.svelte.d.ts +42 -0
- package/dist/animated/GraphDamru.svelte +341 -0
- package/dist/animated/GraphDamru.svelte.d.ts +18 -0
- package/dist/animated/GraphDeps.svelte +245 -0
- package/dist/animated/GraphDeps.svelte.d.ts +29 -0
- package/dist/animated/GraphDiya.svelte +330 -0
- package/dist/animated/GraphDiya.svelte.d.ts +22 -0
- package/dist/animated/GraphFire.svelte +246 -0
- package/dist/animated/GraphFire.svelte.d.ts +22 -0
- package/dist/animated/GraphFlame.svelte +258 -0
- package/dist/animated/GraphFlame.svelte.d.ts +14 -0
- package/dist/animated/GraphFlowPlayer.svelte +346 -0
- package/dist/animated/GraphFlowPlayer.svelte.d.ts +27 -0
- package/dist/animated/GraphGanga.svelte +305 -0
- package/dist/animated/GraphGanga.svelte.d.ts +20 -0
- package/dist/animated/GraphHash.svelte +251 -0
- package/dist/animated/GraphHash.svelte.d.ts +20 -0
- package/dist/animated/GraphJapa.svelte +253 -0
- package/dist/animated/GraphJapa.svelte.d.ts +20 -0
- package/dist/animated/GraphLife.svelte +312 -0
- package/dist/animated/GraphLife.svelte.d.ts +27 -0
- package/dist/animated/GraphMandala.svelte +262 -0
- package/dist/animated/GraphMandala.svelte.d.ts +24 -0
- package/dist/animated/GraphMandel.svelte +290 -0
- package/dist/animated/GraphMandel.svelte.d.ts +27 -0
- package/dist/animated/GraphPulse.svelte +248 -0
- package/dist/animated/GraphPulse.svelte.d.ts +24 -0
- package/dist/animated/GraphRain.svelte +280 -0
- package/dist/animated/GraphRain.svelte.d.ts +22 -0
- package/dist/animated/GraphScatter.svelte +395 -0
- package/dist/animated/GraphScatter.svelte.d.ts +31 -0
- package/dist/animated/GraphScope.svelte +197 -0
- package/dist/animated/GraphScope.svelte.d.ts +22 -0
- package/dist/animated/GraphSequence.svelte +247 -0
- package/dist/animated/GraphSequence.svelte.d.ts +18 -0
- package/dist/animated/GraphSpinners.svelte +109 -0
- package/dist/animated/GraphSpinners.svelte.d.ts +22 -0
- package/dist/animated/GraphState.svelte +270 -0
- package/dist/animated/GraphState.svelte.d.ts +14 -0
- package/dist/animated/GraphStream.svelte +223 -0
- package/dist/animated/GraphStream.svelte.d.ts +24 -0
- package/dist/animated/GraphSurya.svelte +268 -0
- package/dist/animated/GraphSurya.svelte.d.ts +22 -0
- package/dist/animated/GraphTerminal.svelte +238 -0
- package/dist/animated/GraphTerminal.svelte.d.ts +28 -0
- package/dist/animated/GraphTicker.svelte +163 -0
- package/dist/animated/GraphTicker.svelte.d.ts +21 -0
- package/dist/animated/GraphTypewriter.svelte +130 -0
- package/dist/animated/GraphTypewriter.svelte.d.ts +22 -0
- package/dist/animated/GraphWorkflow.svelte +570 -0
- package/dist/animated/GraphWorkflow.svelte.d.ts +29 -0
- package/dist/assets/favicon.svg +21 -0
- package/dist/diagram/AmplifierDiagram.svelte +206 -0
- package/dist/diagram/AmplifierDiagram.svelte.d.ts +12 -0
- package/dist/diagram/AsciiDiagram.svelte +212 -0
- package/dist/diagram/AsciiDiagram.svelte.d.ts +24 -0
- package/dist/diagram/DiagramEditor.svelte +414 -0
- package/dist/diagram/DiagramEditor.svelte.d.ts +3 -0
- package/dist/diagram/MetricsTableDiagram.svelte +125 -0
- package/dist/diagram/MetricsTableDiagram.svelte.d.ts +18 -0
- package/dist/diagram/NestedRadiiDiagram.svelte +218 -0
- package/dist/diagram/NestedRadiiDiagram.svelte.d.ts +12 -0
- package/dist/diagram/PromptLoopDiagram.svelte +331 -0
- package/dist/diagram/PromptLoopDiagram.svelte.d.ts +12 -0
- package/dist/diagram/ascii.d.ts +35 -0
- package/dist/diagram/ascii.js +83 -0
- package/dist/diagram/parser.d.ts +16 -0
- package/dist/diagram/parser.js +71 -0
- package/dist/frame/Graph.svelte +141 -0
- package/dist/frame/Graph.svelte.d.ts +14 -0
- package/dist/frame/GraphArrow.svelte +49 -0
- package/dist/frame/GraphArrow.svelte.d.ts +9 -0
- package/dist/frame/GraphBody.svelte +39 -0
- package/dist/frame/GraphBody.svelte.d.ts +10 -0
- package/dist/frame/GraphRule.svelte +21 -0
- package/dist/frame/GraphRule.svelte.d.ts +6 -0
- package/dist/frame/GraphTick.svelte +23 -0
- package/dist/frame/GraphTick.svelte.d.ts +9 -0
- package/dist/frame/GraphTrack.svelte +29 -0
- package/dist/frame/GraphTrack.svelte.d.ts +14 -0
- package/dist/frame/clock.d.ts +10 -0
- package/dist/frame/clock.js +62 -0
- package/dist/frame/glyphs.d.ts +22 -0
- package/dist/frame/glyphs.js +53 -0
- package/dist/frame/motion.css +27 -0
- package/dist/frame/motion.d.ts +24 -0
- package/dist/frame/motion.js +47 -0
- package/dist/frame/tone.d.ts +11 -0
- package/dist/frame/tone.js +64 -0
- package/dist/graphs/GraphActivity.svelte +387 -0
- package/dist/graphs/GraphActivity.svelte.d.ts +22 -0
- package/dist/graphs/GraphBars.svelte +194 -0
- package/dist/graphs/GraphBars.svelte.d.ts +20 -0
- package/dist/graphs/GraphBullet.svelte +208 -0
- package/dist/graphs/GraphBullet.svelte.d.ts +22 -0
- package/dist/graphs/GraphCalendar.svelte +203 -0
- package/dist/graphs/GraphCalendar.svelte.d.ts +20 -0
- package/dist/graphs/GraphCells.svelte +181 -0
- package/dist/graphs/GraphCells.svelte.d.ts +18 -0
- package/dist/graphs/GraphCompare.svelte +192 -0
- package/dist/graphs/GraphCompare.svelte.d.ts +18 -0
- package/dist/graphs/GraphCountdown.svelte +96 -0
- package/dist/graphs/GraphCountdown.svelte.d.ts +14 -0
- package/dist/graphs/GraphDiff.svelte +181 -0
- package/dist/graphs/GraphDiff.svelte.d.ts +18 -0
- package/dist/graphs/GraphFlow.svelte +137 -0
- package/dist/graphs/GraphFlow.svelte.d.ts +21 -0
- package/dist/graphs/GraphFunnel.svelte +190 -0
- package/dist/graphs/GraphFunnel.svelte.d.ts +21 -0
- package/dist/graphs/GraphGantt.svelte +258 -0
- package/dist/graphs/GraphGantt.svelte.d.ts +25 -0
- package/dist/graphs/GraphHeatmap.svelte +287 -0
- package/dist/graphs/GraphHeatmap.svelte.d.ts +22 -0
- package/dist/graphs/GraphInvoice.svelte +294 -0
- package/dist/graphs/GraphInvoice.svelte.d.ts +34 -0
- package/dist/graphs/GraphKpi.svelte +166 -0
- package/dist/graphs/GraphKpi.svelte.d.ts +17 -0
- package/dist/graphs/GraphLatency.svelte +340 -0
- package/dist/graphs/GraphLatency.svelte.d.ts +28 -0
- package/dist/graphs/GraphMeter.svelte +121 -0
- package/dist/graphs/GraphMeter.svelte.d.ts +16 -0
- package/dist/graphs/GraphPlot.svelte +226 -0
- package/dist/graphs/GraphPlot.svelte.d.ts +18 -0
- package/dist/graphs/GraphQuota.svelte +303 -0
- package/dist/graphs/GraphQuota.svelte.d.ts +27 -0
- package/dist/graphs/GraphRank.svelte +141 -0
- package/dist/graphs/GraphRank.svelte.d.ts +21 -0
- package/dist/graphs/GraphSlo.svelte +325 -0
- package/dist/graphs/GraphSlo.svelte.d.ts +31 -0
- package/dist/graphs/GraphSlope.svelte +197 -0
- package/dist/graphs/GraphSlope.svelte.d.ts +19 -0
- package/dist/graphs/GraphSpark.svelte +125 -0
- package/dist/graphs/GraphSpark.svelte.d.ts +15 -0
- package/dist/graphs/GraphSpec.svelte +69 -0
- package/dist/graphs/GraphSpec.svelte.d.ts +14 -0
- package/dist/graphs/GraphStack.svelte +266 -0
- package/dist/graphs/GraphStack.svelte.d.ts +25 -0
- package/dist/graphs/GraphStat.svelte +103 -0
- package/dist/graphs/GraphStat.svelte.d.ts +16 -0
- package/dist/graphs/GraphTable.svelte +133 -0
- package/dist/graphs/GraphTable.svelte.d.ts +15 -0
- package/dist/graphs/GraphTimeline.svelte +164 -0
- package/dist/graphs/GraphTimeline.svelte.d.ts +18 -0
- package/dist/graphs/GraphTimer.svelte +117 -0
- package/dist/graphs/GraphTimer.svelte.d.ts +15 -0
- package/dist/graphs/GraphTree.svelte +147 -0
- package/dist/graphs/GraphTree.svelte.d.ts +16 -0
- package/dist/graphs/GraphUptime.svelte +210 -0
- package/dist/graphs/GraphUptime.svelte.d.ts +18 -0
- package/dist/graphs/GraphWaffle.svelte +131 -0
- package/dist/graphs/GraphWaffle.svelte.d.ts +17 -0
- package/dist/graphs/GraphWaterfall.svelte +258 -0
- package/dist/graphs/GraphWaterfall.svelte.d.ts +22 -0
- package/dist/index.d.ts +147 -0
- package/dist/index.js +87 -0
- package/dist/themes.css +54 -0
- package/package.json +67 -0
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
<script module lang="ts">
|
|
2
|
+
export interface GraphAumProps {
|
|
3
|
+
/** Caption drawn on the top edge as `[ TITLE ]`. Uppercase, 1–2 words. */
|
|
4
|
+
title: string;
|
|
5
|
+
/** Animate the ink-in and resonance. Default true. Reduced motion freezes a settled frame. */
|
|
6
|
+
animated?: boolean;
|
|
7
|
+
/** Width of the scene in characters; at least 46 so the figure fits. Default 56. */
|
|
8
|
+
cols?: number;
|
|
9
|
+
/** Height of the scene in rows. Default 22. */
|
|
10
|
+
rows?: number;
|
|
11
|
+
/** Milliseconds per tick. Default 110. */
|
|
12
|
+
speedMs?: number;
|
|
13
|
+
/** Seed offsets the resonance wave along the stroke. Default 7. */
|
|
14
|
+
seedNum?: number;
|
|
15
|
+
/** Short caption under the art; the art itself is decorative. */
|
|
16
|
+
label?: string;
|
|
17
|
+
class?: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// The figure is drawn from five stroke polylines in paint order: bindu,
|
|
21
|
+
// crescent, the two humps with the tail, and the om loop. It is rasterized
|
|
22
|
+
// once at module load; every instance shares the same cell order.
|
|
23
|
+
// The art box is pre-widened (~1.8x) because terminal cells are ~2x taller
|
|
24
|
+
// than wide; on screen the figure reads round.
|
|
25
|
+
const ART_W = 44;
|
|
26
|
+
const ART_H = 22;
|
|
27
|
+
|
|
28
|
+
const STROKES: number[][][] = [
|
|
29
|
+
// bindu — the dot above
|
|
30
|
+
[[32, 0]],
|
|
31
|
+
// crescent (chandra) — shallow cup opening up
|
|
32
|
+
[
|
|
33
|
+
[25, 2],
|
|
34
|
+
[30, 3],
|
|
35
|
+
[36, 3],
|
|
36
|
+
[41, 2]
|
|
37
|
+
],
|
|
38
|
+
// upper hump: tip at upper-left, arc right, return to the cusp
|
|
39
|
+
[
|
|
40
|
+
[7, 8],
|
|
41
|
+
[14, 5],
|
|
42
|
+
[23, 5],
|
|
43
|
+
[31, 7],
|
|
44
|
+
[29, 10],
|
|
45
|
+
[22, 12],
|
|
46
|
+
[13, 12]
|
|
47
|
+
],
|
|
48
|
+
// lower hump + tail: bulge right, descend, curl left along the bottom
|
|
49
|
+
[
|
|
50
|
+
[13, 12],
|
|
51
|
+
[23, 12],
|
|
52
|
+
[32, 14],
|
|
53
|
+
[36, 17],
|
|
54
|
+
[34, 19],
|
|
55
|
+
[27, 21],
|
|
56
|
+
[14, 21],
|
|
57
|
+
[5, 20]
|
|
58
|
+
],
|
|
59
|
+
// the om loop — small circle hanging at the left, painted last
|
|
60
|
+
[
|
|
61
|
+
[9, 13],
|
|
62
|
+
[4, 12],
|
|
63
|
+
[0, 14],
|
|
64
|
+
[2, 17],
|
|
65
|
+
[5, 18],
|
|
66
|
+
[9, 16],
|
|
67
|
+
[9, 14],
|
|
68
|
+
[7, 13]
|
|
69
|
+
]
|
|
70
|
+
];
|
|
71
|
+
|
|
72
|
+
interface InkCell {
|
|
73
|
+
x: number;
|
|
74
|
+
y: number;
|
|
75
|
+
/** Paint order along the strokes; drives the ink-in and the wave. */
|
|
76
|
+
s: number;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function rasterizeStrokes(): InkCell[] {
|
|
80
|
+
const seen = new Set<number>();
|
|
81
|
+
const cells: InkCell[] = [];
|
|
82
|
+
let s = 0;
|
|
83
|
+
|
|
84
|
+
for (const pts of STROKES) {
|
|
85
|
+
for (let i = 0; i < pts.length - 1; i++) {
|
|
86
|
+
const [x0, y0] = pts[i] as [number, number];
|
|
87
|
+
const [x1, y1] = pts[i + 1] as [number, number];
|
|
88
|
+
const steps = Math.max(Math.abs(x1 - x0), Math.abs(y1 - y0)) * 4;
|
|
89
|
+
|
|
90
|
+
for (let t = 0; t <= steps; t++) {
|
|
91
|
+
const x = Math.round(x0 + ((x1 - x0) * t) / steps);
|
|
92
|
+
const y = Math.round(y0 + ((y1 - y0) * t) / steps);
|
|
93
|
+
const key = y * ART_W + x;
|
|
94
|
+
|
|
95
|
+
if (x >= 0 && x < ART_W && y >= 0 && y < ART_H && !seen.has(key)) {
|
|
96
|
+
seen.add(key);
|
|
97
|
+
cells.push({ x, y, s });
|
|
98
|
+
s += 1;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return cells;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const INK_CELLS = rasterizeStrokes();
|
|
108
|
+
const INK_MAP = new Map<number, number>(
|
|
109
|
+
INK_CELLS.map((cell) => [cell.y * ART_W + cell.x, cell.s])
|
|
110
|
+
);
|
|
111
|
+
const INK_TOTAL = INK_CELLS.length;
|
|
112
|
+
|
|
113
|
+
interface Seg {
|
|
114
|
+
text: string;
|
|
115
|
+
cls?: string;
|
|
116
|
+
}
|
|
117
|
+
</script>
|
|
118
|
+
|
|
119
|
+
<script lang="ts">
|
|
120
|
+
import Graph from '../frame/Graph.svelte';
|
|
121
|
+
import GraphBody from '../frame/GraphBody.svelte';
|
|
122
|
+
|
|
123
|
+
let {
|
|
124
|
+
title,
|
|
125
|
+
animated = true,
|
|
126
|
+
cols = 56,
|
|
127
|
+
rows = 22,
|
|
128
|
+
speedMs = 110,
|
|
129
|
+
seedNum = 7,
|
|
130
|
+
label = 'the primordial vibration',
|
|
131
|
+
class: className = ''
|
|
132
|
+
}: GraphAumProps = $props();
|
|
133
|
+
|
|
134
|
+
// svelte-ignore state_referenced_locally
|
|
135
|
+
const width = Math.max(46, cols);
|
|
136
|
+
// svelte-ignore state_referenced_locally
|
|
137
|
+
const height = Math.max(ART_H, rows);
|
|
138
|
+
const offsetX = Math.floor((width - ART_W) / 2);
|
|
139
|
+
const offsetY = Math.floor((height - ART_H) / 2);
|
|
140
|
+
|
|
141
|
+
const inkTicks = 46;
|
|
142
|
+
const waveSpeed = 2;
|
|
143
|
+
const waveGap = 44;
|
|
144
|
+
const waveLength = INK_TOTAL + waveGap;
|
|
145
|
+
|
|
146
|
+
// svelte-ignore state_referenced_locally
|
|
147
|
+
const seedPhase = (((seedNum * 7) % waveLength) + waveLength) % waveLength;
|
|
148
|
+
|
|
149
|
+
// svelte-ignore state_referenced_locally
|
|
150
|
+
const initialTick = animated
|
|
151
|
+
? inkTicks + Math.floor((waveLength * 0.4) / waveSpeed)
|
|
152
|
+
: inkTicks;
|
|
153
|
+
|
|
154
|
+
// svelte-ignore state_referenced_locally
|
|
155
|
+
let tick = $state(initialTick);
|
|
156
|
+
|
|
157
|
+
const moving = $derived(
|
|
158
|
+
animated &&
|
|
159
|
+
(typeof window === 'undefined' ||
|
|
160
|
+
!window.matchMedia('(prefers-reduced-motion: reduce)').matches)
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
$effect(() => {
|
|
164
|
+
if (!moving) {
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const timer = window.setInterval(() => {
|
|
169
|
+
tick += 1;
|
|
170
|
+
}, speedMs);
|
|
171
|
+
|
|
172
|
+
return () => window.clearInterval(timer);
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
const view = $derived.by((): Seg[][] => {
|
|
176
|
+
const reveal = Math.min(INK_TOTAL, Math.floor((tick / inkTicks) * INK_TOTAL));
|
|
177
|
+
const wavePos =
|
|
178
|
+
reveal >= INK_TOTAL
|
|
179
|
+
? (seedPhase + (tick - inkTicks) * waveSpeed) % waveLength
|
|
180
|
+
: -1;
|
|
181
|
+
const out: Seg[][] = [];
|
|
182
|
+
|
|
183
|
+
for (let y = 0; y < height; y++) {
|
|
184
|
+
const segs: Seg[] = [];
|
|
185
|
+
let buf = '';
|
|
186
|
+
let cls: string | undefined;
|
|
187
|
+
|
|
188
|
+
const flush = () => {
|
|
189
|
+
if (buf.length > 0) {
|
|
190
|
+
segs.push({ text: buf, cls });
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
buf = '';
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
for (let x = 0; x < width; x++) {
|
|
197
|
+
const ax = x - offsetX;
|
|
198
|
+
const ay = y - offsetY;
|
|
199
|
+
const s = ax >= 0 && ax < ART_W && ay >= 0 && ay < ART_H
|
|
200
|
+
? INK_MAP.get(ay * ART_W + ax)
|
|
201
|
+
: undefined;
|
|
202
|
+
let ch = ' ';
|
|
203
|
+
let next: string | undefined;
|
|
204
|
+
|
|
205
|
+
if (s !== undefined) {
|
|
206
|
+
if (reveal < INK_TOTAL) {
|
|
207
|
+
// Wet ink: freshly drawn cells glow, then settle to the foreground.
|
|
208
|
+
if (s < reveal) {
|
|
209
|
+
ch = '█';
|
|
210
|
+
|
|
211
|
+
if (reveal - s <= 6) {
|
|
212
|
+
next = 'hot';
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
} else {
|
|
216
|
+
// Resonance: one crest travels the stroke order and rests.
|
|
217
|
+
const d = (wavePos - s + waveLength) % waveLength;
|
|
218
|
+
|
|
219
|
+
ch = '█';
|
|
220
|
+
|
|
221
|
+
if (d <= 3) {
|
|
222
|
+
next = 'hot';
|
|
223
|
+
} else if (d <= 12) {
|
|
224
|
+
next = 'mid';
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (next === cls) {
|
|
230
|
+
buf += ch;
|
|
231
|
+
} else {
|
|
232
|
+
flush();
|
|
233
|
+
cls = next;
|
|
234
|
+
buf = ch;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
flush();
|
|
239
|
+
out.push(segs);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
return out;
|
|
243
|
+
});
|
|
244
|
+
</script>
|
|
245
|
+
|
|
246
|
+
<Graph {title} class={className}>
|
|
247
|
+
<GraphBody>
|
|
248
|
+
<div class="aum">
|
|
249
|
+
<div class="viewport">
|
|
250
|
+
<pre class="art" aria-hidden="true"><code>{#each view as line, i (i)}{#each line as seg, j (j)}{#if seg.cls}<span class={seg.cls}>{seg.text}</span>{:else}{seg.text}{/if}{/each}{#if i < view.length - 1}{'\n'}{/if}{/each}</code></pre>
|
|
251
|
+
</div>
|
|
252
|
+
{#if label}
|
|
253
|
+
<p class="caption">{label}</p>
|
|
254
|
+
{/if}
|
|
255
|
+
</div>
|
|
256
|
+
</GraphBody>
|
|
257
|
+
</Graph>
|
|
258
|
+
|
|
259
|
+
<style>
|
|
260
|
+
.aum {
|
|
261
|
+
display: flex;
|
|
262
|
+
flex-direction: column;
|
|
263
|
+
gap: 1rem;
|
|
264
|
+
min-width: 0;
|
|
265
|
+
font-size: 0.875rem;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
.viewport {
|
|
269
|
+
overflow-x: auto;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
.art {
|
|
273
|
+
margin: 0;
|
|
274
|
+
font-size: 0.85rem;
|
|
275
|
+
line-height: 1.15;
|
|
276
|
+
color: var(--graph-foreground, oklch(0.93 0 0));
|
|
277
|
+
white-space: pre;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
.hot {
|
|
281
|
+
color: var(--graph-accent, oklch(0.78 0.17 155));
|
|
282
|
+
font-weight: 600;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
.mid {
|
|
286
|
+
color: var(--graph-muted, oklch(0.62 0 0));
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
.caption {
|
|
290
|
+
margin: 0;
|
|
291
|
+
font-size: 0.8rem;
|
|
292
|
+
color: var(--graph-muted, oklch(0.62 0 0));
|
|
293
|
+
}
|
|
294
|
+
</style>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface GraphAumProps {
|
|
2
|
+
/** Caption drawn on the top edge as `[ TITLE ]`. Uppercase, 1–2 words. */
|
|
3
|
+
title: string;
|
|
4
|
+
/** Animate the ink-in and resonance. Default true. Reduced motion freezes a settled frame. */
|
|
5
|
+
animated?: boolean;
|
|
6
|
+
/** Width of the scene in characters; at least 46 so the figure fits. Default 56. */
|
|
7
|
+
cols?: number;
|
|
8
|
+
/** Height of the scene in rows. Default 22. */
|
|
9
|
+
rows?: number;
|
|
10
|
+
/** Milliseconds per tick. Default 110. */
|
|
11
|
+
speedMs?: number;
|
|
12
|
+
/** Seed offsets the resonance wave along the stroke. Default 7. */
|
|
13
|
+
seedNum?: number;
|
|
14
|
+
/** Short caption under the art; the art itself is decorative. */
|
|
15
|
+
label?: string;
|
|
16
|
+
class?: string;
|
|
17
|
+
}
|
|
18
|
+
declare const GraphAum: import("svelte").Component<GraphAumProps, {}, "">;
|
|
19
|
+
type GraphAum = ReturnType<typeof GraphAum>;
|
|
20
|
+
export default GraphAum;
|
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
<script module lang="ts">
|
|
2
|
+
export interface GraphBootStep {
|
|
3
|
+
/** Short label, e.g. 'compose up', 'migrate', 'seed'. */
|
|
4
|
+
label: string;
|
|
5
|
+
/** Optional ETA in 'ms' to surface in the per-step tag, e.g. '~1.4s'. */
|
|
6
|
+
eta?: string;
|
|
7
|
+
/** If true, this step fails; the final summary shows ✗ and stops. Default false. */
|
|
8
|
+
fail?: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface GraphBootProps {
|
|
12
|
+
/** Caption on the frame's top edge as `[ TITLE ]`. Uppercase, 1–2 words. */
|
|
13
|
+
title: string;
|
|
14
|
+
/** Ordered list of deploy/boot steps to show. */
|
|
15
|
+
steps: GraphBootStep[];
|
|
16
|
+
/** Milliseconds per tick of the boot animation. Default 90. */
|
|
17
|
+
speedMs?: number;
|
|
18
|
+
/** Total ticks each step is "in progress" before flipping to ✓/✗. Default 14. */
|
|
19
|
+
stepTicks?: number;
|
|
20
|
+
/** Seed for any stochastic timing jitter per step. Default 5. */
|
|
21
|
+
seedNum?: number;
|
|
22
|
+
/** Animate the boot. Default true. Reduced motion freezes a mid-run frame. */
|
|
23
|
+
animated?: boolean;
|
|
24
|
+
/** Short caption under the art. */
|
|
25
|
+
label?: string;
|
|
26
|
+
class?: string;
|
|
27
|
+
}
|
|
28
|
+
</script>
|
|
29
|
+
|
|
30
|
+
<script lang="ts">
|
|
31
|
+
import Graph from '../frame/Graph.svelte';
|
|
32
|
+
import GraphBody from '../frame/GraphBody.svelte';
|
|
33
|
+
|
|
34
|
+
let {
|
|
35
|
+
title,
|
|
36
|
+
steps,
|
|
37
|
+
speedMs = 90,
|
|
38
|
+
stepTicks = 14,
|
|
39
|
+
seedNum = 5,
|
|
40
|
+
animated = true,
|
|
41
|
+
label = 'from cold to live',
|
|
42
|
+
class: className = ''
|
|
43
|
+
}: GraphBootProps = $props();
|
|
44
|
+
|
|
45
|
+
interface Seg {
|
|
46
|
+
text: string;
|
|
47
|
+
cls?: string;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// svelte-ignore state_referenced_locally
|
|
51
|
+
const list: GraphBootStep[] = steps.length > 0 ? steps : [{ label: 'idle' }];
|
|
52
|
+
|
|
53
|
+
// svelte-ignore state_referenced_locally
|
|
54
|
+
const stepDur = Math.max(2, Math.round(stepTicks));
|
|
55
|
+
|
|
56
|
+
// Seeded per-step duration jitter so a step takes 70%..130% of the default.
|
|
57
|
+
function mulberry32(seed: number): () => number {
|
|
58
|
+
let a = seed >>> 0;
|
|
59
|
+
return () => {
|
|
60
|
+
a = (a + 0x6d2b79f5) | 0;
|
|
61
|
+
let t = Math.imul(a ^ (a >>> 15), 1 | a);
|
|
62
|
+
t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
|
|
63
|
+
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// svelte-ignore state_referenced_locally
|
|
68
|
+
const rand = mulberry32(seedNum);
|
|
69
|
+
// svelte-ignore state_referenced_locally
|
|
70
|
+
const jitter: number[] = list.map(() => 0.7 + rand() * 0.6);
|
|
71
|
+
|
|
72
|
+
// Per-step tick length = stepDur * jitter (rounded, >= 3).
|
|
73
|
+
// svelte-ignore state_referenced_locally
|
|
74
|
+
const stepLens: number[] = list.map((_, i) =>
|
|
75
|
+
Math.max(3, Math.round(stepDur * (jitter[i] ?? 1)))
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
// Total ticks to complete the whole boot (sum of all step lengths) plus 6 ticks of post-summary.
|
|
79
|
+
const totalTicks = stepLens.reduce((a, b) => a + b, 0) + 6;
|
|
80
|
+
// svelte-ignore state_referenced_locally
|
|
81
|
+
const initialTick = animated ? Math.min(totalTicks, Math.floor(totalTicks * 0.6)) : totalTicks;
|
|
82
|
+
|
|
83
|
+
// svelte-ignore state_referenced_locally
|
|
84
|
+
let tick = $state(initialTick);
|
|
85
|
+
|
|
86
|
+
const moving = $derived(
|
|
87
|
+
animated &&
|
|
88
|
+
(typeof window === 'undefined' ||
|
|
89
|
+
!window.matchMedia('(prefers-reduced-motion: reduce)').matches)
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
$effect(() => {
|
|
93
|
+
if (!moving) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const timer = window.setInterval(() => {
|
|
98
|
+
if (tick < totalTicks) {
|
|
99
|
+
tick += 1;
|
|
100
|
+
} else {
|
|
101
|
+
tick = 0;
|
|
102
|
+
}
|
|
103
|
+
}, speedMs);
|
|
104
|
+
|
|
105
|
+
return () => window.clearInterval(timer);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
// For each step, derive: status, fill (0..1), and tickSinceEnd.
|
|
109
|
+
// status: 'pending' | 'running' | 'ok' | 'fail'
|
|
110
|
+
const stepState = $derived.by(() => {
|
|
111
|
+
const out: { status: 'pending' | 'running' | 'ok' | 'fail'; fill: number }[] = [];
|
|
112
|
+
let acc = 0;
|
|
113
|
+
|
|
114
|
+
for (let i = 0; i < list.length; i++) {
|
|
115
|
+
const len = stepLens[i] ?? stepDur;
|
|
116
|
+
const start = acc;
|
|
117
|
+
const end = acc + len;
|
|
118
|
+
acc = end;
|
|
119
|
+
|
|
120
|
+
if (tick < start) {
|
|
121
|
+
out.push({ status: 'pending', fill: 0 });
|
|
122
|
+
} else if (tick < end) {
|
|
123
|
+
const fill = (tick - start) / Math.max(1, len - 1);
|
|
124
|
+
out.push({ status: 'running', fill: Math.min(1, fill) });
|
|
125
|
+
} else {
|
|
126
|
+
// A failing step fails on its final tick and everything after.
|
|
127
|
+
const failed = !!list[i]?.fail && tick >= end;
|
|
128
|
+
out.push({ status: failed ? 'fail' : 'ok', fill: 1 });
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return out;
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
// A failing step halts later steps — if any prior step is 'fail', all subsequent
|
|
136
|
+
// are marked skipped (kept pending) so the summary makes sense.
|
|
137
|
+
const haltedAt = $derived.by(() => {
|
|
138
|
+
for (let i = 0; i < stepState.length; i++) {
|
|
139
|
+
if (stepState[i]!.status === 'fail') {
|
|
140
|
+
return i;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return -1;
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
// For rendering, an effective state honors the halt.
|
|
147
|
+
const effectiveState = $derived(
|
|
148
|
+
stepState.map((s, i) => {
|
|
149
|
+
if (haltedAt >= 0 && i > haltedAt) {
|
|
150
|
+
return { status: 'pending' as const, fill: 0 };
|
|
151
|
+
}
|
|
152
|
+
return s;
|
|
153
|
+
})
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
// Total elapsed time: a synthetic ETA in seconds. Each step = 0.6s base.
|
|
157
|
+
// svelte-ignore state_referenced_locally
|
|
158
|
+
const totalEta = $derived(
|
|
159
|
+
(stepLens.reduce((a, b) => a + b, 0) * (speedMs / 1000)).toFixed(1)
|
|
160
|
+
);
|
|
161
|
+
// svelte-ignore state_referenced_locally
|
|
162
|
+
const elapsedS = $derived(
|
|
163
|
+
Math.min(parseFloat(totalEta), (tick * speedMs) / 1000).toFixed(1)
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
// Pass / fail summary
|
|
167
|
+
const summary = $derived.by(() => {
|
|
168
|
+
const anyFail = haltedAt >= 0;
|
|
169
|
+
const okCount = effectiveState.filter((s) => s.status === 'ok').length;
|
|
170
|
+
const failCount = effectiveState.filter((s) => s.status === 'fail').length;
|
|
171
|
+
const total = list.length;
|
|
172
|
+
|
|
173
|
+
if (anyFail) {
|
|
174
|
+
return { kind: 'fail' as const, ok: okCount, fail: failCount, total };
|
|
175
|
+
}
|
|
176
|
+
return { kind: 'ok' as const, ok: total, fail: 0, total };
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
// RLE view of the per-step rows
|
|
180
|
+
const view = $derived.by((): Seg[] => {
|
|
181
|
+
const out: Seg[] = [];
|
|
182
|
+
// Find the longest label, cap at 18 chars to keep rows tidy
|
|
183
|
+
const labelWidth = Math.min(18, Math.max(8, ...list.map((s) => s.label.length + 2)));
|
|
184
|
+
|
|
185
|
+
for (let i = 0; i < list.length; i++) {
|
|
186
|
+
const step = list[i]!;
|
|
187
|
+
const state = effectiveState[i]!;
|
|
188
|
+
|
|
189
|
+
// "[ label ] [▰▰▰▱▱▱▱▱▱▱] ·1.2s ✓"
|
|
190
|
+
const pad = labelWidth - step.label.length;
|
|
191
|
+
const paddedLabel = step.label + ' '.repeat(Math.max(0, pad));
|
|
192
|
+
|
|
193
|
+
out.push({ text: ' ' });
|
|
194
|
+
out.push({ text: paddedLabel, cls: 'mid' });
|
|
195
|
+
|
|
196
|
+
// bar — 10 cells wide
|
|
197
|
+
const barWidth = 10;
|
|
198
|
+
const filled = Math.round(state.fill * barWidth);
|
|
199
|
+
|
|
200
|
+
if (state.status === 'pending') {
|
|
201
|
+
out.push({ text: '[' });
|
|
202
|
+
out.push({ text: '·'.repeat(barWidth), cls: 'faint' });
|
|
203
|
+
out.push({ text: ']' });
|
|
204
|
+
out.push({ text: ' ' });
|
|
205
|
+
out.push({ text: '…', cls: 'faint' });
|
|
206
|
+
} else if (state.status === 'running') {
|
|
207
|
+
out.push({ text: '[' });
|
|
208
|
+
out.push({ text: '▰'.repeat(filled), cls: 'hot' });
|
|
209
|
+
out.push({ text: '▱'.repeat(barWidth - filled), cls: 'faint' });
|
|
210
|
+
out.push({ text: ']' });
|
|
211
|
+
out.push({ text: ' ' });
|
|
212
|
+
if (step.eta) {
|
|
213
|
+
out.push({ text: step.eta, cls: 'mid' });
|
|
214
|
+
} else {
|
|
215
|
+
out.push({ text: '…', cls: 'faint' });
|
|
216
|
+
}
|
|
217
|
+
} else if (state.status === 'ok') {
|
|
218
|
+
out.push({ text: '[' });
|
|
219
|
+
out.push({ text: '▰'.repeat(barWidth), cls: 'mid' });
|
|
220
|
+
out.push({ text: ']' });
|
|
221
|
+
out.push({ text: ' ' });
|
|
222
|
+
if (step.eta) {
|
|
223
|
+
out.push({ text: step.eta, cls: 'mid' });
|
|
224
|
+
} else {
|
|
225
|
+
out.push({ text: 'ok', cls: 'mid' });
|
|
226
|
+
}
|
|
227
|
+
out.push({ text: ' ' });
|
|
228
|
+
out.push({ text: '✓', cls: 'hot' });
|
|
229
|
+
} else {
|
|
230
|
+
out.push({ text: '[' });
|
|
231
|
+
out.push({ text: '▰'.repeat(filled) + '▱'.repeat(barWidth - filled), cls: 'faint' });
|
|
232
|
+
out.push({ text: ']' });
|
|
233
|
+
out.push({ text: ' ' });
|
|
234
|
+
if (step.eta) {
|
|
235
|
+
out.push({ text: step.eta, cls: 'mid' });
|
|
236
|
+
} else {
|
|
237
|
+
out.push({ text: '—', cls: 'faint' });
|
|
238
|
+
}
|
|
239
|
+
out.push({ text: ' ' });
|
|
240
|
+
out.push({ text: '✗', cls: 'fail' });
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
out.push({ text: '\n' });
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Summary row
|
|
247
|
+
out.push({ text: ' ' });
|
|
248
|
+
out.push({ text: '─'.repeat(labelWidth), cls: 'faint' });
|
|
249
|
+
out.push({ text: '\n' });
|
|
250
|
+
|
|
251
|
+
out.push({ text: ' ' });
|
|
252
|
+
out.push({ text: 'total', cls: 'mid' });
|
|
253
|
+
out.push({ text: ' '.repeat(Math.max(0, labelWidth - 5)) });
|
|
254
|
+
|
|
255
|
+
const mark = summary.kind === 'ok' ? '✓' : '✗';
|
|
256
|
+
const markCls = summary.kind === 'ok' ? 'hot' : 'fail';
|
|
257
|
+
const passedText = `${summary.ok}/${summary.total} passed`;
|
|
258
|
+
const space = ' ';
|
|
259
|
+
|
|
260
|
+
out.push({ text: passedText, cls: 'mid' });
|
|
261
|
+
out.push({ text: space });
|
|
262
|
+
out.push({ text: `${elapsedS}s / ${totalEta}s`, cls: 'mid' });
|
|
263
|
+
out.push({ text: ' ' });
|
|
264
|
+
out.push({ text: mark, cls: markCls });
|
|
265
|
+
|
|
266
|
+
return out;
|
|
267
|
+
});
|
|
268
|
+
</script>
|
|
269
|
+
|
|
270
|
+
<Graph {title} class={className}>
|
|
271
|
+
<GraphBody>
|
|
272
|
+
<div class="boot">
|
|
273
|
+
<div class="viewport">
|
|
274
|
+
<pre class="art" aria-hidden="true"><code>{#each view as seg, i (i)}{#if seg.cls}<span class={seg.cls}>{seg.text}</span>{:else}{seg.text}{/if}{/each}</code></pre>
|
|
275
|
+
</div>
|
|
276
|
+
<p class="caption">{label}</p>
|
|
277
|
+
</div>
|
|
278
|
+
</GraphBody>
|
|
279
|
+
</Graph>
|
|
280
|
+
|
|
281
|
+
<style>
|
|
282
|
+
.boot {
|
|
283
|
+
display: flex;
|
|
284
|
+
flex-direction: column;
|
|
285
|
+
gap: 0.75rem;
|
|
286
|
+
min-width: 0;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
.viewport {
|
|
290
|
+
overflow-x: auto;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
.art {
|
|
294
|
+
margin: 0;
|
|
295
|
+
font-size: 0.85rem;
|
|
296
|
+
line-height: 1.5;
|
|
297
|
+
color: var(--graph-foreground, oklch(0.93 0 0));
|
|
298
|
+
white-space: pre;
|
|
299
|
+
font-variant-numeric: tabular-nums;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
.hot {
|
|
303
|
+
color: var(--graph-accent, oklch(0.78 0.17 155));
|
|
304
|
+
font-weight: 600;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
.mid {
|
|
308
|
+
color: var(--graph-muted, oklch(0.62 0 0));
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
.faint {
|
|
312
|
+
color: var(--graph-faint, oklch(0.3 0 0));
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
.fail {
|
|
316
|
+
color: var(--graph-fail, oklch(0.7 0.18 25));
|
|
317
|
+
font-weight: 600;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
.caption {
|
|
321
|
+
margin: 0;
|
|
322
|
+
font-size: 0.8rem;
|
|
323
|
+
color: var(--graph-muted, oklch(0.62 0 0));
|
|
324
|
+
}
|
|
325
|
+
</style>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export interface GraphBootStep {
|
|
2
|
+
/** Short label, e.g. 'compose up', 'migrate', 'seed'. */
|
|
3
|
+
label: string;
|
|
4
|
+
/** Optional ETA in 'ms' to surface in the per-step tag, e.g. '~1.4s'. */
|
|
5
|
+
eta?: string;
|
|
6
|
+
/** If true, this step fails; the final summary shows ✗ and stops. Default false. */
|
|
7
|
+
fail?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export interface GraphBootProps {
|
|
10
|
+
/** Caption on the frame's top edge as `[ TITLE ]`. Uppercase, 1–2 words. */
|
|
11
|
+
title: string;
|
|
12
|
+
/** Ordered list of deploy/boot steps to show. */
|
|
13
|
+
steps: GraphBootStep[];
|
|
14
|
+
/** Milliseconds per tick of the boot animation. Default 90. */
|
|
15
|
+
speedMs?: number;
|
|
16
|
+
/** Total ticks each step is "in progress" before flipping to ✓/✗. Default 14. */
|
|
17
|
+
stepTicks?: number;
|
|
18
|
+
/** Seed for any stochastic timing jitter per step. Default 5. */
|
|
19
|
+
seedNum?: number;
|
|
20
|
+
/** Animate the boot. Default true. Reduced motion freezes a mid-run frame. */
|
|
21
|
+
animated?: boolean;
|
|
22
|
+
/** Short caption under the art. */
|
|
23
|
+
label?: string;
|
|
24
|
+
class?: string;
|
|
25
|
+
}
|
|
26
|
+
declare const GraphBoot: import("svelte").Component<GraphBootProps, {}, "">;
|
|
27
|
+
type GraphBoot = ReturnType<typeof GraphBoot>;
|
|
28
|
+
export default GraphBoot;
|