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,341 @@
|
|
|
1
|
+
<script module lang="ts">
|
|
2
|
+
export interface GraphDamruProps {
|
|
3
|
+
/** Caption drawn on the top edge as `[ TITLE ]`. Uppercase, 1–2 words. */
|
|
4
|
+
title: string;
|
|
5
|
+
/** Animate the tala. Default true. Reduced motion freezes a clap beat. */
|
|
6
|
+
animated?: boolean;
|
|
7
|
+
/** Width of the scene in characters. Default 60. */
|
|
8
|
+
cols?: number;
|
|
9
|
+
/** Height of the scene in rows. Default 16. */
|
|
10
|
+
rows?: number;
|
|
11
|
+
/** Milliseconds per beat. Default 220. */
|
|
12
|
+
speedMs?: number;
|
|
13
|
+
/** Short caption under the art; the art itself is decorative. */
|
|
14
|
+
label?: string;
|
|
15
|
+
class?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface Seg {
|
|
19
|
+
text: string;
|
|
20
|
+
cls?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Adi tala: 8 beats, structure 4+2+2 (laghu 4, drutam 2, drutam 2).
|
|
24
|
+
// Beats 1, 5, 7 are claps (both hands); the rest are waves alternating.
|
|
25
|
+
const BEAT_KIND: ('clap' | 'wave-up' | 'wave-down')[] = [
|
|
26
|
+
'clap',
|
|
27
|
+
'wave-up',
|
|
28
|
+
'wave-down',
|
|
29
|
+
'wave-up',
|
|
30
|
+
'clap',
|
|
31
|
+
'wave-up',
|
|
32
|
+
'clap',
|
|
33
|
+
'wave-down'
|
|
34
|
+
];
|
|
35
|
+
</script>
|
|
36
|
+
|
|
37
|
+
<script lang="ts">
|
|
38
|
+
import Graph from '../frame/Graph.svelte';
|
|
39
|
+
import GraphBody from '../frame/GraphBody.svelte';
|
|
40
|
+
|
|
41
|
+
let {
|
|
42
|
+
title,
|
|
43
|
+
animated = true,
|
|
44
|
+
cols = 60,
|
|
45
|
+
rows = 16,
|
|
46
|
+
speedMs = 220,
|
|
47
|
+
label = 'the first sound',
|
|
48
|
+
class: className = ''
|
|
49
|
+
}: GraphDamruProps = $props();
|
|
50
|
+
|
|
51
|
+
// svelte-ignore state_referenced_locally
|
|
52
|
+
const width = Math.max(28, cols);
|
|
53
|
+
// svelte-ignore state_referenced_locally
|
|
54
|
+
const height = Math.max(10, rows);
|
|
55
|
+
const beatTicks = 10; // ticks per beat; one tala = 80 ticks
|
|
56
|
+
const RIPPLE_TICKS = 12; // ripple lifetime
|
|
57
|
+
|
|
58
|
+
// svelte-ignore state_referenced_locally
|
|
59
|
+
const cx = Math.floor(width / 2);
|
|
60
|
+
// Damru binding line (where the two triangles meet).
|
|
61
|
+
// svelte-ignore state_referenced_locally
|
|
62
|
+
const lineY = Math.floor(height / 2) - 1;
|
|
63
|
+
// Triangle half-base (cells each side of center).
|
|
64
|
+
const baseHalf = 4;
|
|
65
|
+
// Height of each triangle in rows.
|
|
66
|
+
const triH = 5;
|
|
67
|
+
|
|
68
|
+
// Up triangle cells: rows lineY-1 (apex) down to lineY-triH (base), centered on cx.
|
|
69
|
+
// Apex is 1 cell wide, base is (2*baseHalf+1)=9 cells wide.
|
|
70
|
+
interface Triangle {
|
|
71
|
+
cells: { x: number; y: number; relX: number; relY: number }[];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// svelte-ignore state_referenced_locally
|
|
75
|
+
const upTri: Triangle = (() => {
|
|
76
|
+
const cells: Triangle['cells'] = [];
|
|
77
|
+
|
|
78
|
+
for (let row = 0; row < triH; row++) {
|
|
79
|
+
// row 0 = top (apex), row triH-1 = bottom (base)
|
|
80
|
+
const w = 1 + 2 * row; // 1, 3, 5, 7, 9
|
|
81
|
+
const halfW = (w - 1) / 2;
|
|
82
|
+
const y = lineY - triH + row;
|
|
83
|
+
for (let dx = -halfW; dx <= halfW; dx++) {
|
|
84
|
+
cells.push({ x: cx + dx, y, relX: dx, relY: row });
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return { cells };
|
|
89
|
+
})();
|
|
90
|
+
|
|
91
|
+
// Down triangle: mirror below the binding line.
|
|
92
|
+
// svelte-ignore state_referenced_locally
|
|
93
|
+
const downTri: Triangle = (() => {
|
|
94
|
+
const cells: Triangle['cells'] = [];
|
|
95
|
+
|
|
96
|
+
for (let row = 0; row < triH; row++) {
|
|
97
|
+
const w = 1 + 2 * row;
|
|
98
|
+
const halfW = (w - 1) / 2;
|
|
99
|
+
const y = lineY + 1 + row;
|
|
100
|
+
for (let dx = -halfW; dx <= halfW; dx++) {
|
|
101
|
+
cells.push({ x: cx + dx, y, relX: dx, relY: row });
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return { cells };
|
|
106
|
+
})();
|
|
107
|
+
|
|
108
|
+
// svelte-ignore state_referenced_locally
|
|
109
|
+
const initialTick = animated ? 0 : 0;
|
|
110
|
+
|
|
111
|
+
// svelte-ignore state_referenced_locally
|
|
112
|
+
let tick = $state(initialTick);
|
|
113
|
+
|
|
114
|
+
const moving = $derived(
|
|
115
|
+
animated &&
|
|
116
|
+
(typeof window === 'undefined' ||
|
|
117
|
+
!window.matchMedia('(prefers-reduced-motion: reduce)').matches)
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
$effect(() => {
|
|
121
|
+
if (!moving) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const timer = window.setInterval(() => {
|
|
126
|
+
tick += 1;
|
|
127
|
+
}, speedMs);
|
|
128
|
+
|
|
129
|
+
return () => window.clearInterval(timer);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
// Pulse intensity for a triangle, given the age of the last beat and whether
|
|
133
|
+
// this triangle is the active one for that beat.
|
|
134
|
+
function pulse(age: number, active: boolean): number {
|
|
135
|
+
if (!active) {
|
|
136
|
+
return 0.18;
|
|
137
|
+
}
|
|
138
|
+
// Decay from 1.0 at age 0 to ~0.25 by age = beatTicks*2
|
|
139
|
+
return Math.max(0.25, 1 - age / (beatTicks * 2));
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const view = $derived.by((): Seg[][] => {
|
|
143
|
+
const beatIdx = Math.floor(tick / beatTicks) % 8;
|
|
144
|
+
const age = tick % beatTicks;
|
|
145
|
+
const kind = BEAT_KIND[beatIdx]!;
|
|
146
|
+
|
|
147
|
+
const upActive = kind === 'clap' || kind === 'wave-up';
|
|
148
|
+
const downActive = kind === 'clap' || kind === 'wave-down';
|
|
149
|
+
const upI = pulse(age, upActive);
|
|
150
|
+
const downI = pulse(age, downActive);
|
|
151
|
+
|
|
152
|
+
// Glyph by pulse intensity.
|
|
153
|
+
function triGlyph(i: number): { ch: string; cls: string | undefined } {
|
|
154
|
+
if (i >= 0.8) {
|
|
155
|
+
return { ch: '█', cls: 'hot' };
|
|
156
|
+
}
|
|
157
|
+
if (i >= 0.55) {
|
|
158
|
+
return { ch: '▓', cls: 'mid' };
|
|
159
|
+
}
|
|
160
|
+
if (i >= 0.3) {
|
|
161
|
+
return { ch: '▒', cls: 'faint' };
|
|
162
|
+
}
|
|
163
|
+
return { ch: '░', cls: 'faint' };
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Ripples: ages 0..RIPPLE_TICKS-1 in the recent past, drawn as a ring of `▒`.
|
|
167
|
+
// Newest first so young ripples override older ones at the same cell.
|
|
168
|
+
const rippleAges: number[] = [];
|
|
169
|
+
|
|
170
|
+
for (let a = 0; a < RIPPLE_TICKS; a++) {
|
|
171
|
+
if (tick - a >= 0 && (tick - a) % beatTicks === 0) {
|
|
172
|
+
rippleAges.push(a);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Map of cell -> {ch, cls} for ripples (drawn UNDER the triangles).
|
|
177
|
+
const rippleMap = new Map<number, { ch: string; cls: string | undefined }>();
|
|
178
|
+
|
|
179
|
+
for (const a of rippleAges) {
|
|
180
|
+
const r = (a + 1) * 1.4;
|
|
181
|
+
const lifeLeft = 1 - a / RIPPLE_TICKS;
|
|
182
|
+
if (lifeLeft < 0.25) {
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
const cls = lifeLeft > 0.6 ? 'mid' : 'faint';
|
|
186
|
+
// Approximate the ring by sampling the grid perimeter at distance r.
|
|
187
|
+
// We step around the circle in angle increments and project to cells.
|
|
188
|
+
const steps = Math.max(20, Math.ceil(r * 8));
|
|
189
|
+
|
|
190
|
+
for (let s = 0; s < steps; s++) {
|
|
191
|
+
const ang = (s / steps) * Math.PI * 2;
|
|
192
|
+
const px = cx + r * Math.cos(ang);
|
|
193
|
+
const py = lineY + (r * Math.sin(ang)) / 2.1;
|
|
194
|
+
const ix = Math.round(px);
|
|
195
|
+
const iy = Math.round(py);
|
|
196
|
+
if (ix < 0 || ix >= width || iy < 0 || iy >= height) {
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
199
|
+
const key = iy * width + ix;
|
|
200
|
+
|
|
201
|
+
if (!rippleMap.has(key)) {
|
|
202
|
+
rippleMap.set(key, { ch: '▒', cls });
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Pre-fill cells: start blank.
|
|
208
|
+
const out: Seg[][] = [];
|
|
209
|
+
|
|
210
|
+
for (let y = 0; y < height; y++) {
|
|
211
|
+
const segs: Seg[] = [];
|
|
212
|
+
let buf = '';
|
|
213
|
+
let cls: string | undefined;
|
|
214
|
+
|
|
215
|
+
const flush = () => {
|
|
216
|
+
if (buf.length > 0) {
|
|
217
|
+
segs.push({ text: buf, cls });
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
buf = '';
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
for (let x = 0; x < width; x++) {
|
|
224
|
+
let ch = ' ';
|
|
225
|
+
let next: string | undefined;
|
|
226
|
+
|
|
227
|
+
// Binding line at lineY: a row of `─` across the width.
|
|
228
|
+
if (y === lineY) {
|
|
229
|
+
ch = '─';
|
|
230
|
+
} else {
|
|
231
|
+
// Ripples go first (lowest priority).
|
|
232
|
+
const r = rippleMap.get(y * width + x);
|
|
233
|
+
if (r) {
|
|
234
|
+
ch = r.ch;
|
|
235
|
+
next = r.cls;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Triangles override ripples where they overlap.
|
|
240
|
+
if (y >= lineY - triH && y < lineY) {
|
|
241
|
+
// Up triangle region
|
|
242
|
+
const cell = upTri.cells.find((c) => c.x === x && c.y === y);
|
|
243
|
+
if (cell) {
|
|
244
|
+
const g = triGlyph(upI);
|
|
245
|
+
ch = g.ch;
|
|
246
|
+
next = g.cls;
|
|
247
|
+
}
|
|
248
|
+
} else if (y > lineY && y <= lineY + triH) {
|
|
249
|
+
// Down triangle region
|
|
250
|
+
const cell = downTri.cells.find((c) => c.x === x && c.y === y);
|
|
251
|
+
if (cell) {
|
|
252
|
+
const g = triGlyph(downI);
|
|
253
|
+
ch = g.ch;
|
|
254
|
+
next = g.cls;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Bottom-row counter: "tala X · beat Y · CLAP/WAVE"
|
|
259
|
+
if (y === height - 1) {
|
|
260
|
+
const beatNo = beatIdx + 1;
|
|
261
|
+
const talaNo = Math.floor(tick / (beatTicks * 8)) + 1;
|
|
262
|
+
const kindShort = kind === 'clap' ? 'CLAP' : kind === 'wave-up' ? 'WAVE↑' : 'WAVE↓';
|
|
263
|
+
const text = `tala ${talaNo} · beat ${beatNo}/8 · ${kindShort}`;
|
|
264
|
+
// Right-align the text in the row.
|
|
265
|
+
const start = Math.max(0, width - text.length);
|
|
266
|
+
if (x >= start) {
|
|
267
|
+
ch = text[x - start]!;
|
|
268
|
+
next = undefined;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
if (next === cls) {
|
|
273
|
+
buf += ch;
|
|
274
|
+
} else {
|
|
275
|
+
flush();
|
|
276
|
+
cls = next;
|
|
277
|
+
buf = ch;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
flush();
|
|
282
|
+
out.push(segs);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
return out;
|
|
286
|
+
});
|
|
287
|
+
</script>
|
|
288
|
+
|
|
289
|
+
<Graph {title} class={className}>
|
|
290
|
+
<GraphBody>
|
|
291
|
+
<div class="damru">
|
|
292
|
+
<div class="viewport">
|
|
293
|
+
<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>
|
|
294
|
+
</div>
|
|
295
|
+
{#if label}
|
|
296
|
+
<p class="caption">{label}</p>
|
|
297
|
+
{/if}
|
|
298
|
+
</div>
|
|
299
|
+
</GraphBody>
|
|
300
|
+
</Graph>
|
|
301
|
+
|
|
302
|
+
<style>
|
|
303
|
+
.damru {
|
|
304
|
+
display: flex;
|
|
305
|
+
flex-direction: column;
|
|
306
|
+
gap: 1rem;
|
|
307
|
+
min-width: 0;
|
|
308
|
+
font-size: 0.875rem;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
.viewport {
|
|
312
|
+
overflow-x: auto;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
.art {
|
|
316
|
+
margin: 0;
|
|
317
|
+
font-size: 0.85rem;
|
|
318
|
+
line-height: 1.15;
|
|
319
|
+
color: var(--graph-foreground, oklch(0.93 0 0));
|
|
320
|
+
white-space: pre;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
.hot {
|
|
324
|
+
color: var(--graph-accent, oklch(0.78 0.17 155));
|
|
325
|
+
font-weight: 600;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
.mid {
|
|
329
|
+
color: var(--graph-muted, oklch(0.62 0 0));
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
.faint {
|
|
333
|
+
color: var(--graph-faint, oklch(0.3 0 0));
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
.caption {
|
|
337
|
+
margin: 0;
|
|
338
|
+
font-size: 0.8rem;
|
|
339
|
+
color: var(--graph-muted, oklch(0.62 0 0));
|
|
340
|
+
}
|
|
341
|
+
</style>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface GraphDamruProps {
|
|
2
|
+
/** Caption drawn on the top edge as `[ TITLE ]`. Uppercase, 1–2 words. */
|
|
3
|
+
title: string;
|
|
4
|
+
/** Animate the tala. Default true. Reduced motion freezes a clap beat. */
|
|
5
|
+
animated?: boolean;
|
|
6
|
+
/** Width of the scene in characters. Default 60. */
|
|
7
|
+
cols?: number;
|
|
8
|
+
/** Height of the scene in rows. Default 16. */
|
|
9
|
+
rows?: number;
|
|
10
|
+
/** Milliseconds per beat. Default 220. */
|
|
11
|
+
speedMs?: number;
|
|
12
|
+
/** Short caption under the art; the art itself is decorative. */
|
|
13
|
+
label?: string;
|
|
14
|
+
class?: string;
|
|
15
|
+
}
|
|
16
|
+
declare const GraphDamru: import("svelte").Component<GraphDamruProps, {}, "">;
|
|
17
|
+
type GraphDamru = ReturnType<typeof GraphDamru>;
|
|
18
|
+
export default GraphDamru;
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
<script module lang="ts">
|
|
2
|
+
/** A node in a dependency tree. */
|
|
3
|
+
export interface DepNode {
|
|
4
|
+
/** Package or module name. */
|
|
5
|
+
name: string;
|
|
6
|
+
/** Semver or tag string — rendered as a muted tag next to the name. */
|
|
7
|
+
version: string;
|
|
8
|
+
/** Direct dependencies of this package. */
|
|
9
|
+
children?: DepNode[];
|
|
10
|
+
/** Accent the row (e.g. mark the root or a pinned package). */
|
|
11
|
+
accent?: boolean;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface GraphDepsProps {
|
|
15
|
+
/** Caption drawn on the top edge as `[ TITLE ]`. */
|
|
16
|
+
title: string;
|
|
17
|
+
/** Root-level dependencies, each with a name and version. */
|
|
18
|
+
deps: DepNode[];
|
|
19
|
+
/** Maximum depth to render. Default 6. Clamped 1..16. */
|
|
20
|
+
depth?: number;
|
|
21
|
+
/** Animate the cascade. Default true. Reduced motion shows the full tree. */
|
|
22
|
+
animated?: boolean;
|
|
23
|
+
/** Milliseconds between cascading reveals. Default 80. */
|
|
24
|
+
speedMs?: number;
|
|
25
|
+
/** Caption rendered muted under the tree. */
|
|
26
|
+
label?: string;
|
|
27
|
+
class?: string;
|
|
28
|
+
}
|
|
29
|
+
</script>
|
|
30
|
+
|
|
31
|
+
<script lang="ts">
|
|
32
|
+
import Graph from '../frame/Graph.svelte';
|
|
33
|
+
import GraphBody from '../frame/GraphBody.svelte';
|
|
34
|
+
|
|
35
|
+
let {
|
|
36
|
+
title,
|
|
37
|
+
deps,
|
|
38
|
+
depth = 6,
|
|
39
|
+
animated = true,
|
|
40
|
+
speedMs = 80,
|
|
41
|
+
label = '',
|
|
42
|
+
class: className = ''
|
|
43
|
+
}: GraphDepsProps = $props();
|
|
44
|
+
|
|
45
|
+
// svelte-ignore state_referenced_locally
|
|
46
|
+
const maxDepth = Math.max(1, Math.min(16, depth));
|
|
47
|
+
|
|
48
|
+
interface FlatRow {
|
|
49
|
+
key: string;
|
|
50
|
+
branch: string;
|
|
51
|
+
depthMark: string;
|
|
52
|
+
name: string;
|
|
53
|
+
version: string;
|
|
54
|
+
accent?: boolean;
|
|
55
|
+
depth: number;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function flatten(
|
|
59
|
+
nodes: DepNode[],
|
|
60
|
+
prefix = '',
|
|
61
|
+
trail = 'root',
|
|
62
|
+
isRoot = true,
|
|
63
|
+
currentDepth = 0
|
|
64
|
+
): FlatRow[] {
|
|
65
|
+
const singleRoot = isRoot && nodes.length === 1;
|
|
66
|
+
return nodes.flatMap((node, index) => {
|
|
67
|
+
const last = index === nodes.length - 1;
|
|
68
|
+
const branch = singleRoot ? '' : prefix + (last ? '└─ ' : '├─ ');
|
|
69
|
+
const childPrefix = singleRoot ? '' : prefix + (last ? ' ' : '│ ');
|
|
70
|
+
const row: FlatRow = {
|
|
71
|
+
key: `${trail}/${node.name}@${node.version}-${index}`,
|
|
72
|
+
branch,
|
|
73
|
+
depthMark: '·'.repeat(Math.max(0, currentDepth + (singleRoot ? 0 : 1))),
|
|
74
|
+
name: node.name,
|
|
75
|
+
version: node.version,
|
|
76
|
+
accent: node.accent,
|
|
77
|
+
depth: currentDepth
|
|
78
|
+
};
|
|
79
|
+
const kids =
|
|
80
|
+
node.children && currentDepth < maxDepth
|
|
81
|
+
? flatten(node.children, childPrefix, row.key, false, currentDepth + 1)
|
|
82
|
+
: [];
|
|
83
|
+
return [row, ...kids];
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const rows = $derived(flatten(deps));
|
|
88
|
+
const hasAccent = $derived(rows.some((r) => r.accent));
|
|
89
|
+
|
|
90
|
+
const moving = $derived(
|
|
91
|
+
animated &&
|
|
92
|
+
(typeof window === 'undefined' ||
|
|
93
|
+
!window.matchMedia('(prefers-reduced-motion: reduce)').matches)
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
let revealed = $state(0);
|
|
97
|
+
// svelte-ignore state_referenced_locally
|
|
98
|
+
const preRevealed = moving ? 0 : rows.length;
|
|
99
|
+
|
|
100
|
+
$effect(() => {
|
|
101
|
+
revealed = preRevealed;
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
$effect(() => {
|
|
105
|
+
if (!moving || rows.length < 2) return;
|
|
106
|
+
const timer = window.setInterval(() => {
|
|
107
|
+
if (revealed >= rows.length) {
|
|
108
|
+
revealed = 0;
|
|
109
|
+
} else {
|
|
110
|
+
revealed = revealed + 1;
|
|
111
|
+
}
|
|
112
|
+
}, Math.max(40, speedMs));
|
|
113
|
+
return () => window.clearInterval(timer);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
const visible = $derived(moving ? revealed : rows.length);
|
|
117
|
+
|
|
118
|
+
// Counts for the bottom caption: how many packages and how many roots.
|
|
119
|
+
const totalCount = $derived(rows.length);
|
|
120
|
+
const rootCount = $derived(deps.length);
|
|
121
|
+
</script>
|
|
122
|
+
|
|
123
|
+
<Graph {title} class={className}>
|
|
124
|
+
<GraphBody>
|
|
125
|
+
<div class="scroll">
|
|
126
|
+
<ul class="tree" role="list">
|
|
127
|
+
{#each rows as row, i (row.key)}
|
|
128
|
+
{#if i < visible}
|
|
129
|
+
<li
|
|
130
|
+
class="row"
|
|
131
|
+
class:dim={hasAccent && !row.accent}
|
|
132
|
+
style="--d: {row.depth}"
|
|
133
|
+
>
|
|
134
|
+
<span class="depth" aria-hidden="true">{row.depthMark}</span>
|
|
135
|
+
<span class="branch" aria-hidden="true">{row.branch}</span>
|
|
136
|
+
<span class="name" class:c-accent={row.accent}>{row.name}</span>
|
|
137
|
+
<span class="at" aria-hidden="true">@</span>
|
|
138
|
+
<span class="version">{row.version}</span>
|
|
139
|
+
</li>
|
|
140
|
+
{/if}
|
|
141
|
+
{/each}
|
|
142
|
+
</ul>
|
|
143
|
+
<span class="sr-only">Dependency tree with {totalCount} packages under {rootCount} roots.</span>
|
|
144
|
+
</div>
|
|
145
|
+
{#if label}
|
|
146
|
+
<p class="caption">{label}</p>
|
|
147
|
+
{/if}
|
|
148
|
+
</GraphBody>
|
|
149
|
+
</Graph>
|
|
150
|
+
|
|
151
|
+
<style>
|
|
152
|
+
.scroll {
|
|
153
|
+
overflow-x: auto;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.tree {
|
|
157
|
+
display: flex;
|
|
158
|
+
min-width: max-content;
|
|
159
|
+
flex-direction: column;
|
|
160
|
+
gap: 0.22rem;
|
|
161
|
+
margin: 0;
|
|
162
|
+
padding: 0;
|
|
163
|
+
list-style: none;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.row {
|
|
167
|
+
display: inline-flex;
|
|
168
|
+
align-items: baseline;
|
|
169
|
+
gap: 0.35rem;
|
|
170
|
+
font-size: 0.82rem;
|
|
171
|
+
white-space: nowrap;
|
|
172
|
+
animation: dep-fade 0.32s ease-out;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
@keyframes dep-fade {
|
|
176
|
+
from {
|
|
177
|
+
opacity: 0;
|
|
178
|
+
transform: translateX(0.2rem);
|
|
179
|
+
}
|
|
180
|
+
to {
|
|
181
|
+
opacity: 1;
|
|
182
|
+
transform: translateX(0);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
@media (prefers-reduced-motion: reduce) {
|
|
187
|
+
.row {
|
|
188
|
+
animation: none;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
.depth {
|
|
193
|
+
color: var(--graph-faint, oklch(0.3 0 0));
|
|
194
|
+
font-size: 0.7rem;
|
|
195
|
+
letter-spacing: 0.2em;
|
|
196
|
+
user-select: none;
|
|
197
|
+
min-width: 0;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
.branch {
|
|
201
|
+
color: var(--graph-frame, oklch(0.6 0 0 / 0.5));
|
|
202
|
+
user-select: none;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
.name {
|
|
206
|
+
color: var(--graph-foreground, oklch(0.93 0 0));
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
.c-accent {
|
|
210
|
+
color: var(--graph-accent, oklch(0.78 0.17 155));
|
|
211
|
+
font-weight: 600;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
.at {
|
|
215
|
+
color: var(--graph-faint, oklch(0.3 0 0));
|
|
216
|
+
user-select: none;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
.version {
|
|
220
|
+
color: var(--graph-muted, oklch(0.62 0 0));
|
|
221
|
+
font-size: 0.78rem;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
.dim {
|
|
225
|
+
opacity: 0.55;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
.caption {
|
|
229
|
+
margin: 0.6rem 0 0;
|
|
230
|
+
font-size: 0.78rem;
|
|
231
|
+
color: var(--graph-muted, oklch(0.62 0 0));
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
.sr-only {
|
|
235
|
+
position: absolute;
|
|
236
|
+
width: 1px;
|
|
237
|
+
height: 1px;
|
|
238
|
+
padding: 0;
|
|
239
|
+
margin: -1px;
|
|
240
|
+
overflow: hidden;
|
|
241
|
+
clip-path: inset(50%);
|
|
242
|
+
white-space: nowrap;
|
|
243
|
+
border-width: 0;
|
|
244
|
+
}
|
|
245
|
+
</style>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/** A node in a dependency tree. */
|
|
2
|
+
export interface DepNode {
|
|
3
|
+
/** Package or module name. */
|
|
4
|
+
name: string;
|
|
5
|
+
/** Semver or tag string — rendered as a muted tag next to the name. */
|
|
6
|
+
version: string;
|
|
7
|
+
/** Direct dependencies of this package. */
|
|
8
|
+
children?: DepNode[];
|
|
9
|
+
/** Accent the row (e.g. mark the root or a pinned package). */
|
|
10
|
+
accent?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export interface GraphDepsProps {
|
|
13
|
+
/** Caption drawn on the top edge as `[ TITLE ]`. */
|
|
14
|
+
title: string;
|
|
15
|
+
/** Root-level dependencies, each with a name and version. */
|
|
16
|
+
deps: DepNode[];
|
|
17
|
+
/** Maximum depth to render. Default 6. Clamped 1..16. */
|
|
18
|
+
depth?: number;
|
|
19
|
+
/** Animate the cascade. Default true. Reduced motion shows the full tree. */
|
|
20
|
+
animated?: boolean;
|
|
21
|
+
/** Milliseconds between cascading reveals. Default 80. */
|
|
22
|
+
speedMs?: number;
|
|
23
|
+
/** Caption rendered muted under the tree. */
|
|
24
|
+
label?: string;
|
|
25
|
+
class?: string;
|
|
26
|
+
}
|
|
27
|
+
declare const GraphDeps: import("svelte").Component<GraphDepsProps, {}, "">;
|
|
28
|
+
type GraphDeps = ReturnType<typeof GraphDeps>;
|
|
29
|
+
export default GraphDeps;
|