@brett_lamy/docstream 1.9.1 → 1.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/README.md +30 -0
  2. package/dist/docs/DocsRenderer.d.ts.map +1 -1
  3. package/dist/docs/DocsRenderer.js +12 -1
  4. package/dist/docs/DocsRenderer.js.map +1 -1
  5. package/dist/index.d.ts +4 -0
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +2 -0
  8. package/dist/index.js.map +1 -1
  9. package/dist/stl/StlViewer.d.ts +13 -0
  10. package/dist/stl/StlViewer.d.ts.map +1 -0
  11. package/dist/stl/StlViewer.js +277 -0
  12. package/dist/stl/StlViewer.js.map +1 -0
  13. package/dist/stl/index.d.ts +5 -0
  14. package/dist/stl/index.d.ts.map +1 -0
  15. package/dist/stl/index.js +3 -0
  16. package/dist/stl/index.js.map +1 -0
  17. package/dist/stl/parse.d.ts +13 -0
  18. package/dist/stl/parse.d.ts.map +1 -0
  19. package/dist/stl/parse.js +69 -0
  20. package/dist/stl/parse.js.map +1 -0
  21. package/dist/strudel/StrudelPlayer.d.ts +15 -0
  22. package/dist/strudel/StrudelPlayer.d.ts.map +1 -0
  23. package/dist/strudel/StrudelPlayer.js +178 -0
  24. package/dist/strudel/StrudelPlayer.js.map +1 -0
  25. package/dist/strudel/engine.d.ts +38 -0
  26. package/dist/strudel/engine.d.ts.map +1 -0
  27. package/dist/strudel/engine.js +65 -0
  28. package/dist/strudel/engine.js.map +1 -0
  29. package/dist/strudel/index.d.ts +5 -0
  30. package/dist/strudel/index.d.ts.map +1 -0
  31. package/dist/strudel/index.js +4 -0
  32. package/dist/strudel/index.js.map +1 -0
  33. package/dist/strudel/url.d.ts +5 -0
  34. package/dist/strudel/url.d.ts.map +1 -0
  35. package/dist/strudel/url.js +9 -0
  36. package/dist/strudel/url.js.map +1 -0
  37. package/dist/styles.css +194 -0
  38. package/package.json +14 -1
  39. package/src/docs/DocsRenderer.tsx +12 -1
  40. package/src/env.d.ts +3 -0
  41. package/src/index.ts +4 -0
  42. package/src/stl/StlViewer.tsx +334 -0
  43. package/src/stl/index.ts +4 -0
  44. package/src/stl/parse.ts +72 -0
  45. package/src/strudel/StrudelPlayer.tsx +246 -0
  46. package/src/strudel/engine.ts +98 -0
  47. package/src/strudel/index.ts +4 -0
  48. package/src/strudel/url.ts +9 -0
  49. package/src/styles.css +194 -0
@@ -0,0 +1,69 @@
1
+ /** True for a URL whose path ends in `.stl` (query string and hash ignored). */
2
+ export function isStlUrl(url) {
3
+ return /\.stl(?:[?#]|$)/i.test(url.trim());
4
+ }
5
+ // A binary STL is an 80-byte header, a uint32 triangle count, then 50 bytes per triangle. ASCII
6
+ // files start with "solid", but so do some binary headers, so the byte length decides.
7
+ function isBinary(view) {
8
+ if (view.byteLength < 84)
9
+ return false;
10
+ return 84 + view.getUint32(80, true) * 50 === view.byteLength;
11
+ }
12
+ function faceNormal(p, o, out) {
13
+ const ux = p[o + 3] - p[o], uy = p[o + 4] - p[o + 1], uz = p[o + 5] - p[o + 2];
14
+ const vx = p[o + 6] - p[o], vy = p[o + 7] - p[o + 1], vz = p[o + 8] - p[o + 2];
15
+ let nx = uy * vz - uz * vy, ny = uz * vx - ux * vz, nz = ux * vy - uy * vx;
16
+ const len = Math.hypot(nx, ny, nz) || 1;
17
+ nx /= len, ny /= len, nz /= len;
18
+ for (let k = 0; k < 3; k++) {
19
+ out[o + k * 3] = nx;
20
+ out[o + k * 3 + 1] = ny;
21
+ out[o + k * 3 + 2] = nz;
22
+ }
23
+ }
24
+ function finish(positions, triangles) {
25
+ // Stored normals are often zero or wrong; the winding is what slicers trust, so recompute.
26
+ const normals = new Float32Array(positions.length);
27
+ for (let t = 0; t < triangles; t++)
28
+ faceNormal(positions, t * 9, normals);
29
+ const min = [Infinity, Infinity, Infinity];
30
+ const max = [-Infinity, -Infinity, -Infinity];
31
+ for (let i = 0; i < positions.length; i += 3) {
32
+ for (let k = 0; k < 3; k++) {
33
+ const v = positions[i + k];
34
+ if (v < min[k])
35
+ min[k] = v;
36
+ if (v > max[k])
37
+ max[k] = v;
38
+ }
39
+ }
40
+ if (!triangles)
41
+ min.fill(0), max.fill(0);
42
+ return { positions, normals, triangles, min, max };
43
+ }
44
+ /** Parse a binary or ASCII STL file. Throws when the data is neither. */
45
+ export function parseStl(data) {
46
+ const view = new DataView(data);
47
+ if (isBinary(view)) {
48
+ const triangles = view.getUint32(80, true);
49
+ const positions = new Float32Array(triangles * 9);
50
+ for (let t = 0; t < triangles; t++) {
51
+ const base = 84 + t * 50 + 12; // skip the stored normal
52
+ for (let k = 0; k < 9; k++)
53
+ positions[t * 9 + k] = view.getFloat32(base + k * 4, true);
54
+ }
55
+ return finish(positions, triangles);
56
+ }
57
+ const text = new TextDecoder().decode(data);
58
+ if (!/^\s*solid\b/i.test(text))
59
+ throw new Error("Not an STL file");
60
+ const values = [];
61
+ const vertex = /vertex\s+(\S+)\s+(\S+)\s+(\S+)/gi;
62
+ for (let m = vertex.exec(text); m; m = vertex.exec(text))
63
+ values.push(+m[1], +m[2], +m[3]);
64
+ const triangles = Math.floor(values.length / 9);
65
+ if (!triangles && /facet/i.test(text))
66
+ throw new Error("Malformed ASCII STL");
67
+ return finish(Float32Array.from(values.slice(0, triangles * 9)), triangles);
68
+ }
69
+ //# sourceMappingURL=parse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.js","sourceRoot":"","sources":["../../src/stl/parse.ts"],"names":[],"mappings":"AASA,gFAAgF;AAChF,MAAM,UAAU,QAAQ,CAAC,GAAW;IAClC,OAAO,kBAAkB,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAA;AAC5C,CAAC;AAED,gGAAgG;AAChG,uFAAuF;AACvF,SAAS,QAAQ,CAAC,IAAc;IAC9B,IAAI,IAAI,CAAC,UAAU,GAAG,EAAE;QAAE,OAAO,KAAK,CAAA;IACtC,OAAO,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,KAAK,IAAI,CAAC,UAAU,CAAA;AAC/D,CAAC;AAED,SAAS,UAAU,CAAC,CAAe,EAAE,CAAS,EAAE,GAAiB;IAC/D,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAE,GAAG,CAAC,CAAC,CAAC,CAAE,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAE,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAE,CAAA;IACpF,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAE,GAAG,CAAC,CAAC,CAAC,CAAE,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAE,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAE,CAAA;IACpF,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAA;IAC1E,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,CAAA;IACvC,EAAE,IAAI,GAAG,EAAE,EAAE,IAAI,GAAG,EAAE,EAAE,IAAI,GAAG,CAAA;IAC/B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3B,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAA;QACnB,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAA;QACvB,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAA;IACzB,CAAC;AACH,CAAC;AAED,SAAS,MAAM,CAAC,SAAuB,EAAE,SAAiB;IACxD,2FAA2F;IAC3F,MAAM,OAAO,GAAG,IAAI,YAAY,CAAC,SAAS,CAAC,MAAM,CAAC,CAAA;IAClD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,EAAE,CAAC,EAAE;QAAE,UAAU,CAAC,SAAS,EAAE,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC,CAAA;IACzE,MAAM,GAAG,GAA6B,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAA;IACpE,MAAM,GAAG,GAA6B,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAA;IACvE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QAC7C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC3B,MAAM,CAAC,GAAG,SAAS,CAAC,CAAC,GAAG,CAAC,CAAE,CAAA;YAC3B,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,CAAE;gBAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;YAC3B,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,CAAE;gBAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;QAC7B,CAAC;IACH,CAAC;IACD,IAAI,CAAC,SAAS;QAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACxC,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,EAAE,GAAG,EAAE,CAAA;AACpD,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,QAAQ,CAAC,IAAiB;IACxC,MAAM,IAAI,GAAG,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAA;IAC/B,IAAI,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACnB,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,IAAI,CAAC,CAAA;QAC1C,MAAM,SAAS,GAAG,IAAI,YAAY,CAAC,SAAS,GAAG,CAAC,CAAC,CAAA;QACjD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,EAAE,CAAC,EAAE,EAAE,CAAC;YACnC,MAAM,IAAI,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,CAAA,CAAC,yBAAyB;YACvD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE;gBAAE,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,CAAA;QACxF,CAAC;QACD,OAAO,MAAM,CAAC,SAAS,EAAE,SAAS,CAAC,CAAA;IACrC,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;IAC3C,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAA;IAClE,MAAM,MAAM,GAAa,EAAE,CAAA;IAC3B,MAAM,MAAM,GAAG,kCAAkC,CAAA;IACjD,KAAK,IAAI,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAE,CAAC,CAAA;IAC7F,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;IAC/C,IAAI,CAAC,SAAS,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAA;IAC7E,OAAO,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,GAAG,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,CAAA;AAC7E,CAAC"}
@@ -0,0 +1,15 @@
1
+ export interface StrudelPlayerProps {
2
+ /** Strudel pattern code (what you would type at strudel.cc). */
3
+ code?: string;
4
+ /** URL of a `.strudel` file to load when `code` is absent. */
5
+ src?: string;
6
+ title?: string;
7
+ className?: string;
8
+ /** Show the code under the player from the start. Defaults to false. */
9
+ showCode?: boolean;
10
+ /** Sample banks to load before the first play. Defaults to the Tidal dirt-samples. */
11
+ samples?: readonly string[];
12
+ }
13
+ /** A live-coded music player: Strudel (strudel.cc) runs the pattern in this page, no iframe. */
14
+ export declare function StrudelPlayer({ code, src, title, className, showCode, samples }: StrudelPlayerProps): import("react").JSX.Element;
15
+ //# sourceMappingURL=StrudelPlayer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StrudelPlayer.d.ts","sourceRoot":"","sources":["../../src/strudel/StrudelPlayer.tsx"],"names":[],"mappings":"AAcA,MAAM,WAAW,kBAAkB;IACjC,gEAAgE;IAChE,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,8DAA8D;IAC9D,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,wEAAwE;IACxE,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,sFAAsF;IACtF,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAC5B;AAkFD,gGAAgG;AAChG,wBAAgB,aAAa,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,SAAS,EAAE,QAAgB,EAAE,OAAyB,EAAE,EAAE,kBAAkB,+BAyI7H"}
@@ -0,0 +1,178 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useId, useRef, useState, useSyncExternalStore } from "react";
3
+ import { Code2, Loader2, Pause, Play } from "lucide-react";
4
+ import { HighlightedCode } from "../docs/HighlightedCode.js";
5
+ import { DEFAULT_SAMPLES, getStrudelSnapshot, playStrudel, stopStrudel, strudelNow, subscribeStrudel, } from "./engine.js";
6
+ const NOTE = /^([a-g])([#bs]*)(-?\d+)?$/i;
7
+ const STEPS = { c: 0, d: 2, e: 4, f: 5, g: 7, a: 9, b: 11 };
8
+ // A vertical position for an event: its pitch when it has one, else a stable lane per sample name.
9
+ function pitch(value) {
10
+ if (typeof value === "number")
11
+ return value;
12
+ if (!value || typeof value !== "object")
13
+ return null;
14
+ const v = value;
15
+ if (typeof v.note === "number")
16
+ return v.note;
17
+ if (typeof v.note === "string") {
18
+ const m = NOTE.exec(v.note);
19
+ if (m) {
20
+ const accidental = [...m[2]].reduce((n, c) => n + (c === "b" ? -1 : 1), 0);
21
+ return STEPS[m[1].toLowerCase()] + accidental + (Number(m[3] ?? 3) + 1) * 12;
22
+ }
23
+ }
24
+ if (typeof v.freq === "number")
25
+ return 69 + 12 * Math.log2(v.freq / 440);
26
+ if (typeof v.n === "number" && typeof v.s !== "string")
27
+ return v.n;
28
+ if (typeof v.s === "string") {
29
+ let h = 0;
30
+ for (const c of v.s)
31
+ h = (h * 31 + c.charCodeAt(0)) | 0;
32
+ return (Math.abs(h) % 24) + (typeof v.n === "number" ? v.n : 0);
33
+ }
34
+ return null;
35
+ }
36
+ const num = (t) => Number(t.valueOf());
37
+ // Scrolling piano roll: two cycles centered on the playhead, onsets only. Idle: quiet bars.
38
+ function drawRoll(canvas, pattern, now) {
39
+ const ctx = canvas.getContext("2d");
40
+ if (!ctx)
41
+ return;
42
+ const dpr = Math.min(window.devicePixelRatio || 1, 2);
43
+ const w = Math.max(1, Math.round(canvas.clientWidth * dpr));
44
+ const h = Math.max(1, Math.round(canvas.clientHeight * dpr));
45
+ if (canvas.width !== w || canvas.height !== h) {
46
+ canvas.width = w;
47
+ canvas.height = h;
48
+ }
49
+ ctx.clearRect(0, 0, w, h);
50
+ ctx.fillStyle = getComputedStyle(canvas).color;
51
+ if (!pattern || now === null) {
52
+ ctx.globalAlpha = 0.18;
53
+ const bars = 48;
54
+ for (let i = 0; i < bars; i++) {
55
+ const bh = (0.2 + 0.6 * Math.abs(Math.sin(i * 1.7) * Math.cos(i * 0.6))) * h;
56
+ ctx.fillRect((i / bars) * w + 1, (h - bh) / 2, w / bars - 3 * dpr, bh);
57
+ }
58
+ ctx.globalAlpha = 1;
59
+ return;
60
+ }
61
+ const begin = now - 1, end = now + 1;
62
+ let haps;
63
+ try {
64
+ haps = pattern.queryArc(begin, end).filter((hap) => hap.whole && num(hap.whole.begin) === num(hap.part.begin));
65
+ }
66
+ catch {
67
+ return;
68
+ }
69
+ const pitches = haps.map((hap) => pitch(hap.value));
70
+ const known = pitches.filter((p) => p !== null);
71
+ const lo = known.length ? Math.min(...known) : 0;
72
+ const hi = known.length ? Math.max(...known) : 1;
73
+ const range = Math.max(hi - lo, 11);
74
+ const pad = 4 * dpr;
75
+ const lane = Math.max(3 * dpr, Math.min(10 * dpr, (h - 2 * pad) / (range + 1)));
76
+ const x = (t) => ((t - begin) / (end - begin)) * w;
77
+ haps.forEach((hap, i) => {
78
+ const p = pitches[i] ?? lo;
79
+ const s = num(hap.whole.begin), e = num(hap.whole.end);
80
+ const y = h - pad - lane - ((p - lo + (range - (hi - lo)) / 2) / range) * (h - 2 * pad - lane);
81
+ ctx.globalAlpha = s <= now && now < e ? 1 : s > now ? 0.45 : 0.25;
82
+ ctx.fillRect(x(s), y, Math.max(2 * dpr, x(e) - x(s) - 1.5 * dpr), lane);
83
+ });
84
+ ctx.globalAlpha = 0.6;
85
+ ctx.fillRect(w / 2 - dpr / 2, 0, dpr, h);
86
+ ctx.globalAlpha = 1;
87
+ }
88
+ /** A live-coded music player: Strudel (strudel.cc) runs the pattern in this page, no iframe. */
89
+ export function StrudelPlayer({ code, src, title, className, showCode = false, samples = DEFAULT_SAMPLES }) {
90
+ const id = useId();
91
+ const [source, setSource] = useState(() => (code !== undefined ? { kind: "ready", code } : { kind: "loading" }));
92
+ const [codeOpen, setCodeOpen] = useState(showCode);
93
+ const [error, setError] = useState(null);
94
+ const [cycle, setCycle] = useState(0);
95
+ const pattern = useRef(null);
96
+ const canvasRef = useRef(null);
97
+ const snapshot = useSyncExternalStore(subscribeStrudel, getStrudelSnapshot, getStrudelSnapshot);
98
+ const status = snapshot.owner === id ? snapshot.status : "idle";
99
+ useEffect(() => {
100
+ if (code !== undefined) {
101
+ setSource({ kind: "ready", code });
102
+ return;
103
+ }
104
+ if (!src) {
105
+ setSource({ kind: "error", message: "no pattern" });
106
+ return;
107
+ }
108
+ let live = true;
109
+ setSource({ kind: "loading" });
110
+ fetch(src)
111
+ .then((res) => {
112
+ if (!res.ok)
113
+ throw new Error(`${res.status} ${res.statusText}`.trim());
114
+ return res.text();
115
+ })
116
+ .then((text) => live && setSource({ kind: "ready", code: text }))
117
+ .catch((err) => live && setSource({ kind: "error", message: err instanceof Error ? err.message : String(err) }));
118
+ return () => {
119
+ live = false;
120
+ };
121
+ }, [code, src]);
122
+ // Stop our pattern when the player unmounts or its code changes underneath it.
123
+ const ready = source.kind === "ready" ? source.code : null;
124
+ useEffect(() => () => void stopStrudel(id), [id, ready]);
125
+ useEffect(() => {
126
+ const canvas = canvasRef.current;
127
+ if (!canvas)
128
+ return;
129
+ if (status !== "playing") {
130
+ drawRoll(canvas, null, null);
131
+ const resize = new ResizeObserver(() => drawRoll(canvas, null, null));
132
+ resize.observe(canvas);
133
+ return () => resize.disconnect();
134
+ }
135
+ let frame = 0;
136
+ let shown = -1;
137
+ const tick = () => {
138
+ const now = strudelNow();
139
+ drawRoll(canvas, pattern.current, now);
140
+ const whole = now === null ? 0 : Math.floor(now) + 1;
141
+ if (whole !== shown)
142
+ setCycle((shown = whole));
143
+ frame = requestAnimationFrame(tick);
144
+ };
145
+ tick();
146
+ return () => cancelAnimationFrame(frame);
147
+ }, [status]);
148
+ const toggle = async () => {
149
+ if (source.kind !== "ready")
150
+ return;
151
+ if (status !== "idle") {
152
+ await stopStrudel(id);
153
+ return;
154
+ }
155
+ setError(null);
156
+ try {
157
+ pattern.current = await playStrudel(id, source.code, samples);
158
+ }
159
+ catch (err) {
160
+ if (err instanceof Error && err.message === "superseded")
161
+ return;
162
+ setError(err instanceof Error ? err.message : String(err));
163
+ }
164
+ };
165
+ const label = title ?? (src ? src.split(/[?#]/)[0].split("/").pop() : "Strudel pattern");
166
+ const codeId = `${id}-code`;
167
+ const sub = source.kind === "error"
168
+ ? `Couldn't load: ${source.message}`
169
+ : source.kind === "loading"
170
+ ? "Loading…"
171
+ : status === "loading"
172
+ ? "Loading sounds…"
173
+ : status === "playing"
174
+ ? `Cycle ${cycle}`
175
+ : "Strudel";
176
+ return (_jsxs("figure", { className: `docstream-strudel ${className ?? ""}`.trim(), "data-state": status, children: [_jsxs("div", { className: "docstream-strudel__bar", children: [_jsx("button", { type: "button", className: "docstream-strudel__play", onClick: toggle, disabled: source.kind !== "ready", "aria-label": status === "idle" ? `Play ${label}` : `Stop ${label}`, children: status === "loading" ? (_jsx(Loader2, { className: "docstream-strudel__spin", size: 18 })) : status === "playing" ? (_jsx(Pause, { size: 18 })) : (_jsx(Play, { size: 18 })) }), _jsxs("div", { className: "docstream-strudel__meta", children: [_jsx("span", { className: "docstream-strudel__title", children: label }), _jsx("span", { className: "docstream-strudel__sub", "aria-live": "polite", children: sub })] }), _jsx("canvas", { ref: canvasRef, className: "docstream-strudel__roll", "aria-hidden": "true" }), source.kind === "ready" && (_jsx("button", { type: "button", className: "docstream-strudel__toggle", "aria-expanded": codeOpen, "aria-controls": codeId, "aria-label": codeOpen ? "Hide code" : "Show code", onClick: () => setCodeOpen((open) => !open), children: _jsx(Code2, { size: 16 }) }))] }), error && (_jsx("div", { className: "docstream-strudel__error", role: "alert", children: error })), source.kind === "ready" && codeOpen && (_jsx("div", { id: codeId, className: "docstream-strudel__code", children: _jsx(HighlightedCode, { code: source.code.trim(), language: "javascript" }) }))] }));
177
+ }
178
+ //# sourceMappingURL=StrudelPlayer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StrudelPlayer.js","sourceRoot":"","sources":["../../src/strudel/StrudelPlayer.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ /** A scheduled event, as `Pattern.queryArc` returns it. */
2
+ export interface StrudelHap {
3
+ whole?: {
4
+ begin: number | {
5
+ valueOf(): number;
6
+ };
7
+ end: number | {
8
+ valueOf(): number;
9
+ };
10
+ } | null;
11
+ part: {
12
+ begin: number | {
13
+ valueOf(): number;
14
+ };
15
+ end: number | {
16
+ valueOf(): number;
17
+ };
18
+ };
19
+ value: unknown;
20
+ }
21
+ export interface StrudelPattern {
22
+ queryArc(begin: number, end: number): StrudelHap[];
23
+ }
24
+ /** Sample banks loaded before the first pattern, matching what strudel.cc code expects (`s("bd sd")`). */
25
+ export declare const DEFAULT_SAMPLES: string[];
26
+ export interface StrudelSnapshot {
27
+ /** The player id that owns the runtime right now, or null. */
28
+ owner: string | null;
29
+ status: "idle" | "loading" | "playing";
30
+ }
31
+ export declare function subscribeStrudel(fn: () => void): () => void;
32
+ export declare function getStrudelSnapshot(): StrudelSnapshot;
33
+ /** Evaluate `code` and start it, taking the runtime from any other player. Must run from a user gesture. */
34
+ export declare function playStrudel(owner: string, code: string, samples?: readonly string[]): Promise<StrudelPattern>;
35
+ export declare function stopStrudel(owner: string): Promise<void>;
36
+ /** The scheduler's position in cycles, for animation frames; null while stopped or not loaded. */
37
+ export declare function strudelNow(): number | null;
38
+ //# sourceMappingURL=engine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/strudel/engine.ts"],"names":[],"mappings":"AAGA,2DAA2D;AAC3D,MAAM,WAAW,UAAU;IACzB,KAAK,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,GAAG;YAAE,OAAO,IAAI,MAAM,CAAA;SAAE,CAAC;QAAC,GAAG,EAAE,MAAM,GAAG;YAAE,OAAO,IAAI,MAAM,CAAA;SAAE,CAAA;KAAE,GAAG,IAAI,CAAA;IAC7F,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,GAAG;YAAE,OAAO,IAAI,MAAM,CAAA;SAAE,CAAC;QAAC,GAAG,EAAE,MAAM,GAAG;YAAE,OAAO,IAAI,MAAM,CAAA;SAAE,CAAA;KAAE,CAAA;IACpF,KAAK,EAAE,OAAO,CAAA;CACf;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,UAAU,EAAE,CAAA;CACnD;AAcD,0GAA0G;AAC1G,eAAO,MAAM,eAAe,UAAsC,CAAA;AAElE,MAAM,WAAW,eAAe;IAC9B,8DAA8D;IAC9D,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAAA;CACvC;AAYD,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAG3D;AAED,wBAAgB,kBAAkB,IAAI,eAAe,CAEpD;AAiBD,4GAA4G;AAC5G,wBAAsB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,SAAS,MAAM,EAAoB,GAAG,OAAO,CAAC,cAAc,CAAC,CAgBpI;AAED,wBAAsB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAI9D;AAED,kGAAkG;AAClG,wBAAgB,UAAU,IAAI,MAAM,GAAG,IAAI,CAE1C"}
@@ -0,0 +1,65 @@
1
+ // One Strudel runtime per page, loaded on the first play (@strudel/web is ~850 KB and touches
2
+ // `window` at import). Players share it, so starting one stops whichever was playing.
3
+ /** Sample banks loaded before the first pattern, matching what strudel.cc code expects (`s("bd sd")`). */
4
+ export const DEFAULT_SAMPLES = ["github:tidalcycles/dirt-samples"];
5
+ let runtime = null;
6
+ let loaded = null;
7
+ let snapshot = { owner: null, status: "idle" };
8
+ const listeners = new Set();
9
+ function set(next) {
10
+ snapshot = next;
11
+ listeners.forEach((fn) => fn());
12
+ }
13
+ export function subscribeStrudel(fn) {
14
+ listeners.add(fn);
15
+ return () => listeners.delete(fn);
16
+ }
17
+ export function getStrudelSnapshot() {
18
+ return snapshot;
19
+ }
20
+ function load(samples) {
21
+ runtime ??= import("@strudel/web").then((mod) => mod.initStrudel({
22
+ prebake: () => Promise.all(samples.map((s) => mod.samples(s))),
23
+ onToggle: (started) => {
24
+ if (!started && snapshot.status === "playing")
25
+ set({ owner: null, status: "idle" });
26
+ },
27
+ })).then((repl) => (loaded = repl));
28
+ runtime.catch(() => {
29
+ runtime = null;
30
+ });
31
+ return runtime;
32
+ }
33
+ /** Evaluate `code` and start it, taking the runtime from any other player. Must run from a user gesture. */
34
+ export async function playStrudel(owner, code, samples = DEFAULT_SAMPLES) {
35
+ set({ owner, status: "loading" });
36
+ try {
37
+ const repl = await load(samples);
38
+ if (snapshot.owner !== owner)
39
+ throw new Error("superseded");
40
+ const pattern = await repl.evaluate(code, true);
41
+ if (!pattern || repl.state.evalError) {
42
+ const err = repl.state.evalError;
43
+ throw err instanceof Error ? err : new Error(String(err ?? "Strudel could not evaluate this pattern"));
44
+ }
45
+ if (snapshot.owner === owner)
46
+ set({ owner, status: "playing" });
47
+ return pattern;
48
+ }
49
+ catch (err) {
50
+ if (snapshot.owner === owner)
51
+ set({ owner: null, status: "idle" });
52
+ throw err;
53
+ }
54
+ }
55
+ export async function stopStrudel(owner) {
56
+ if (snapshot.owner !== owner)
57
+ return;
58
+ set({ owner: null, status: "idle" });
59
+ (await runtime)?.stop();
60
+ }
61
+ /** The scheduler's position in cycles, for animation frames; null while stopped or not loaded. */
62
+ export function strudelNow() {
63
+ return loaded?.scheduler.started ? loaded.scheduler.now() : null;
64
+ }
65
+ //# sourceMappingURL=engine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine.js","sourceRoot":"","sources":["../../src/strudel/engine.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export { StrudelPlayer } from "./StrudelPlayer.js";
2
+ export type { StrudelPlayerProps } from "./StrudelPlayer.js";
3
+ export { DEFAULT_SAMPLES, playStrudel, stopStrudel } from "./engine.js";
4
+ export { isStrudelFile, isStrudelLanguage } from "./url.js";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/strudel/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAC/C,YAAY,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AACzD,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AACpE,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,OAAO,CAAA"}
@@ -0,0 +1,4 @@
1
+ export { StrudelPlayer } from "./StrudelPlayer.js";
2
+ export { DEFAULT_SAMPLES, playStrudel, stopStrudel } from "./engine.js";
3
+ export { isStrudelFile, isStrudelLanguage } from "./url.js";
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/strudel/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAE/C,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AACpE,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,OAAO,CAAA"}
@@ -0,0 +1,5 @@
1
+ /** True for a URL whose path ends in `.strudel` (query string and hash ignored). */
2
+ export declare function isStrudelFile(url: string): boolean;
3
+ /** Fence languages that render as a Strudel player. */
4
+ export declare function isStrudelLanguage(language: string | null | undefined): boolean;
5
+ //# sourceMappingURL=url.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"url.d.ts","sourceRoot":"","sources":["../../src/strudel/url.ts"],"names":[],"mappings":"AAAA,oFAAoF;AACpF,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAElD;AAED,uDAAuD;AACvD,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAE9E"}
@@ -0,0 +1,9 @@
1
+ /** True for a URL whose path ends in `.strudel` (query string and hash ignored). */
2
+ export function isStrudelFile(url) {
3
+ return /\.strudel(?:[?#]|$)/i.test(url.trim());
4
+ }
5
+ /** Fence languages that render as a Strudel player. */
6
+ export function isStrudelLanguage(language) {
7
+ return !!language && /^strudel$/i.test(language);
8
+ }
9
+ //# sourceMappingURL=url.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"url.js","sourceRoot":"","sources":["../../src/strudel/url.ts"],"names":[],"mappings":"AAAA,oFAAoF;AACpF,MAAM,UAAU,aAAa,CAAC,GAAW;IACvC,OAAO,sBAAsB,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAA;AAChD,CAAC;AAED,uDAAuD;AACvD,MAAM,UAAU,iBAAiB,CAAC,QAAmC;IACnE,OAAO,CAAC,CAAC,QAAQ,IAAI,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;AAClD,CAAC"}
package/dist/styles.css CHANGED
@@ -450,6 +450,200 @@
450
450
  border-radius: 12px;
451
451
  }
452
452
 
453
+ /* StlViewer: a WebGL preview of an .stl model ({% embed url="part.stl" %}). The model takes
454
+ its color from `color`, so it follows the theme's primary. */
455
+ .docstream-stl,
456
+ .docstream-strudel {
457
+ margin: 0;
458
+ display: flex;
459
+ flex-direction: column;
460
+ gap: 6px;
461
+ }
462
+
463
+ .docstream-stl__stage {
464
+ position: relative;
465
+ aspect-ratio: 16 / 9;
466
+ border: 1px solid var(--gb-border);
467
+ border-radius: 12px;
468
+ overflow: hidden;
469
+ color: var(--gb-primary, #6366f1);
470
+ background:
471
+ radial-gradient(circle at 50% 40%, color-mix(in srgb, var(--gb-muted, #f4f4f5) 40%, transparent), transparent 70%),
472
+ var(--gb-muted, #f4f4f5);
473
+ }
474
+
475
+ .docstream-stl__canvas {
476
+ display: block;
477
+ width: 100%;
478
+ height: 100%;
479
+ cursor: grab;
480
+ touch-action: none;
481
+ }
482
+
483
+ .docstream-stl__canvas:active {
484
+ cursor: grabbing;
485
+ }
486
+
487
+ .docstream-stl__canvas:focus-visible {
488
+ outline: 2px solid var(--gb-primary, #6366f1);
489
+ outline-offset: -2px;
490
+ border-radius: 12px;
491
+ }
492
+
493
+ .docstream-stl__status {
494
+ display: grid;
495
+ place-items: center;
496
+ height: 100%;
497
+ padding: 16px;
498
+ text-align: center;
499
+ font-size: 13px;
500
+ color: var(--gb-muted-foreground);
501
+ }
502
+
503
+ .docstream-stl__reset {
504
+ position: absolute;
505
+ top: 8px;
506
+ right: 8px;
507
+ padding: 3px 10px;
508
+ border: 1px solid var(--gb-border);
509
+ border-radius: 999px;
510
+ background: var(--gb-panel, #fff);
511
+ color: var(--gb-panel-foreground, inherit);
512
+ font: inherit;
513
+ font-size: 12px;
514
+ cursor: pointer;
515
+ opacity: 0.85;
516
+ }
517
+
518
+ .docstream-stl__reset:hover {
519
+ opacity: 1;
520
+ background: var(--gb-hover, var(--gb-accent));
521
+ }
522
+
523
+ .docstream-stl__caption {
524
+ display: flex;
525
+ flex-wrap: wrap;
526
+ justify-content: space-between;
527
+ gap: 4px 12px;
528
+ font-size: 12px;
529
+ color: var(--gb-muted-foreground);
530
+ }
531
+
532
+ .docstream-stl__caption a {
533
+ color: inherit;
534
+ font-weight: 500;
535
+ }
536
+
537
+ /* StrudelPlayer: a Strudel pattern as an audio player (```strudel fences, .strudel embeds). */
538
+ .docstream-strudel__bar {
539
+ display: flex;
540
+ align-items: center;
541
+ gap: 12px;
542
+ padding: 10px 12px;
543
+ border: 1px solid var(--gb-border);
544
+ border-radius: 12px;
545
+ background: var(--gb-panel, #fff);
546
+ color: var(--gb-panel-foreground, inherit);
547
+ }
548
+
549
+ .docstream-strudel__play {
550
+ flex: none;
551
+ display: grid;
552
+ place-items: center;
553
+ width: 40px;
554
+ height: 40px;
555
+ border: 0;
556
+ border-radius: 999px;
557
+ background: var(--gb-primary, #6366f1);
558
+ color: var(--gb-primary-foreground, #fff);
559
+ cursor: pointer;
560
+ }
561
+
562
+ .docstream-strudel__play:disabled {
563
+ opacity: 0.5;
564
+ cursor: default;
565
+ }
566
+
567
+ .docstream-strudel__play:focus-visible,
568
+ .docstream-strudel__toggle:focus-visible {
569
+ outline: 2px solid var(--gb-primary, #6366f1);
570
+ outline-offset: 2px;
571
+ }
572
+
573
+ .docstream-strudel__spin {
574
+ animation: docstream-strudel-spin 0.9s linear infinite;
575
+ }
576
+
577
+ @keyframes docstream-strudel-spin {
578
+ to {
579
+ transform: rotate(360deg);
580
+ }
581
+ }
582
+
583
+ .docstream-strudel__meta {
584
+ display: flex;
585
+ flex-direction: column;
586
+ min-width: 0;
587
+ flex: 0 1 auto;
588
+ max-width: 40%;
589
+ }
590
+
591
+ .docstream-strudel__title {
592
+ font-weight: 600;
593
+ font-size: 14px;
594
+ overflow: hidden;
595
+ text-overflow: ellipsis;
596
+ white-space: nowrap;
597
+ }
598
+
599
+ .docstream-strudel__sub {
600
+ font-size: 12px;
601
+ color: var(--gb-muted-foreground);
602
+ font-variant-numeric: tabular-nums;
603
+ }
604
+
605
+ .docstream-strudel__roll {
606
+ flex: 1 1 auto;
607
+ min-width: 60px;
608
+ height: 40px;
609
+ color: var(--gb-primary, #6366f1);
610
+ }
611
+
612
+ .docstream-strudel__toggle {
613
+ flex: none;
614
+ display: grid;
615
+ place-items: center;
616
+ width: 32px;
617
+ height: 32px;
618
+ border: 1px solid var(--gb-border);
619
+ border-radius: 8px;
620
+ background: transparent;
621
+ color: var(--gb-muted-foreground);
622
+ cursor: pointer;
623
+ }
624
+
625
+ .docstream-strudel__toggle[aria-expanded="true"],
626
+ .docstream-strudel__toggle:hover {
627
+ background: var(--gb-hover, var(--gb-accent));
628
+ color: inherit;
629
+ }
630
+
631
+ .docstream-strudel__error {
632
+ font-size: 12px;
633
+ color: var(--gb-danger, #dc2626);
634
+ white-space: pre-wrap;
635
+ }
636
+
637
+ .docstream-strudel__code {
638
+ border: 1px solid var(--gb-border);
639
+ border-radius: 12px;
640
+ background: var(--gb-code-bg);
641
+ color: var(--gb-code-fg);
642
+ padding: 12px 14px;
643
+ overflow-x: auto;
644
+ font-size: 13px;
645
+ }
646
+
453
647
  .docs-content-ref {
454
648
  display: flex !important;
455
649
  align-items: center;