@markdy/renderer-dom 0.8.14 → 0.8.16
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/README.md +4 -2
- package/dist/index.d.ts +3 -1
- package/dist/index.js +96 -7
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -11,7 +11,8 @@ Web Animations API renderer for [MarkdyScript](../../docs/SYNTAX.md) scenes. Tra
|
|
|
11
11
|
- **Focused diagram visuals** — flowchart shapes, tree buses, state self-loops, sequence lifelines/messages, constellation orbits, group zones, and annotations
|
|
12
12
|
- **Semantic node cards** — compact SVG glyphs for browsers, services, gateways, queues, workers, databases, storage, CDN, security, platform, and more
|
|
13
13
|
- **Seek-safe** — manual `currentTime` control enables reliable `seek()` in any direction
|
|
14
|
-
- **Playback-rate controls** — set timeline speed to slow down or speed up diagrams without rebuilding animations
|
|
14
|
+
- **Playback-rate controls** — set normalized timeline speed to slow down or speed up diagrams without rebuilding animations
|
|
15
|
+
- **Interactive viewport** — opt into wheel zoom and drag pan while click-to-pause stays available
|
|
15
16
|
- **Semantic themes** — `paper`, `editorial`, `nebula`, `midnight`, `blueprint`, and `graphite`, with per-role node and edge colors
|
|
16
17
|
- **Single dependency** — only `@markdy/core`
|
|
17
18
|
|
|
@@ -73,7 +74,8 @@ diagram.destroy(); // clean up DOM + cancel animations
|
|
|
73
74
|
| `copyright` | `boolean` | `true` | Show a small "Powered by Markdy" badge below the animation |
|
|
74
75
|
| `progressBar` | `boolean` | `true` | Deprecated compatibility flag for the rainbow scene-boundary progress bar |
|
|
75
76
|
| `sceneBoundaryProgress` | `boolean` | `progressBar ?? true` | Preferred flag for the rainbow scene-boundary progress bar |
|
|
76
|
-
| `playbackRate` | `number` | `1` |
|
|
77
|
+
| `playbackRate` | `number` | `1` | Normalized timeline speed multiplier; `1` is Markdy's normal pace |
|
|
78
|
+
| `interactiveViewport` | `boolean` | `false` | Enable wheel zoom and drag pan on the rendered viewport |
|
|
77
79
|
| `onWarning` | `(warning: Diagnostic) => void` | `console.warn` | Called for each soft parse warning |
|
|
78
80
|
| `onTimeUpdate` | `(seconds: number, durationSeconds: number) => void` | — | Called whenever playback or seek changes the current time |
|
|
79
81
|
| `onPlayStateChange` | `(playing: boolean) => void` | — | Called when playback starts or pauses |
|
package/dist/index.d.ts
CHANGED
|
@@ -20,8 +20,10 @@ interface DiagramOptions {
|
|
|
20
20
|
progressBar?: boolean;
|
|
21
21
|
/** Show rainbow progress around scene boundary. Defaults to true. */
|
|
22
22
|
sceneBoundaryProgress?: boolean;
|
|
23
|
-
/** Playback speed multiplier. Defaults to 1. */
|
|
23
|
+
/** Playback speed multiplier. Defaults to 1, where 1 is Markdy's normal pace. */
|
|
24
24
|
playbackRate?: number;
|
|
25
|
+
/** Enable wheel zoom and drag pan on the rendered viewport. Defaults to false. */
|
|
26
|
+
interactiveViewport?: boolean;
|
|
25
27
|
onWarning?: (warning: Diagnostic) => void;
|
|
26
28
|
onTimeUpdate?: (seconds: number, durationSeconds: number) => void;
|
|
27
29
|
onPlayStateChange?: (playing: boolean) => void;
|
package/dist/index.js
CHANGED
|
@@ -1810,6 +1810,12 @@ function applyThemeToScene(scene, theme) {
|
|
|
1810
1810
|
}
|
|
1811
1811
|
|
|
1812
1812
|
// src/diagram.ts
|
|
1813
|
+
var NORMAL_PLAYBACK_RATE = 4 / 5;
|
|
1814
|
+
var DEFAULT_PLAYBACK_RATE = 1;
|
|
1815
|
+
var MIN_VIEWPORT_ZOOM = 0.5;
|
|
1816
|
+
var MAX_VIEWPORT_ZOOM = 3;
|
|
1817
|
+
var VIEWPORT_ZOOM_STEP = 15e-4;
|
|
1818
|
+
var DRAG_CLICK_THRESHOLD_PX = 4;
|
|
1813
1819
|
function createBeatCaptionLayer(doc, beats) {
|
|
1814
1820
|
const layer = doc.createElement("div");
|
|
1815
1821
|
layer.className = "markdy-beat-caption-layer";
|
|
@@ -1856,7 +1862,8 @@ function createDiagram(opts) {
|
|
|
1856
1862
|
assets,
|
|
1857
1863
|
progressBar,
|
|
1858
1864
|
sceneBoundaryProgress,
|
|
1859
|
-
playbackRate: initialPlaybackRate =
|
|
1865
|
+
playbackRate: initialPlaybackRate = DEFAULT_PLAYBACK_RATE,
|
|
1866
|
+
interactiveViewport = false,
|
|
1860
1867
|
onWarning = (w) => console.warn(`[markdy] line ${w.line}: ${w.message}`),
|
|
1861
1868
|
onTimeUpdate,
|
|
1862
1869
|
onPlayStateChange
|
|
@@ -1937,10 +1944,19 @@ function createDiagram(opts) {
|
|
|
1937
1944
|
});
|
|
1938
1945
|
applyThemeToScene(scene, plan.theme);
|
|
1939
1946
|
viewport.appendChild(scene);
|
|
1947
|
+
const viewportTransform = document.createElement("div");
|
|
1948
|
+
viewportTransform.className = "markdy-viewport-transform";
|
|
1949
|
+
Object.assign(viewportTransform.style, {
|
|
1950
|
+
position: "absolute",
|
|
1951
|
+
inset: "0",
|
|
1952
|
+
transformOrigin: "0 0",
|
|
1953
|
+
willChange: interactiveViewport ? "transform" : "auto"
|
|
1954
|
+
});
|
|
1955
|
+
scene.appendChild(viewportTransform);
|
|
1940
1956
|
const sceneContent = document.createElement("div");
|
|
1941
1957
|
sceneContent.className = "markdy-scene-content";
|
|
1942
1958
|
Object.assign(sceneContent.style, { position: "absolute", inset: "0" });
|
|
1943
|
-
|
|
1959
|
+
viewportTransform.appendChild(sceneContent);
|
|
1944
1960
|
const titleEl = createTitleEl(plan.title);
|
|
1945
1961
|
sceneContent.appendChild(titleEl);
|
|
1946
1962
|
const cameraLayer = document.createElement("div");
|
|
@@ -1998,9 +2014,11 @@ function createDiagram(opts) {
|
|
|
1998
2014
|
nodeLayer.appendChild(el);
|
|
1999
2015
|
nodeEls.set(node.id, el);
|
|
2000
2016
|
}
|
|
2017
|
+
let fitScale = 1;
|
|
2001
2018
|
function scaleScene() {
|
|
2002
|
-
const
|
|
2003
|
-
|
|
2019
|
+
const width = viewport.clientWidth || plan.meta.width;
|
|
2020
|
+
fitScale = width / plan.meta.width;
|
|
2021
|
+
scene.style.transform = `scale(${fitScale})`;
|
|
2004
2022
|
}
|
|
2005
2023
|
scaleScene();
|
|
2006
2024
|
const resizeObserver = new ResizeObserver(scaleScene);
|
|
@@ -2042,16 +2060,75 @@ function createDiagram(opts) {
|
|
|
2042
2060
|
anim.currentTime = 0;
|
|
2043
2061
|
}
|
|
2044
2062
|
let sceneMs = 0;
|
|
2045
|
-
let playbackRate = Number.isFinite(initialPlaybackRate) && initialPlaybackRate > 0 ? initialPlaybackRate :
|
|
2063
|
+
let playbackRate = Number.isFinite(initialPlaybackRate) && initialPlaybackRate > 0 ? initialPlaybackRate : DEFAULT_PLAYBACK_RATE;
|
|
2046
2064
|
let lastRafTs = null;
|
|
2047
2065
|
let isPlaying = false;
|
|
2048
2066
|
let rafId = null;
|
|
2067
|
+
let viewportScale = 1;
|
|
2068
|
+
let viewportPanX = 0;
|
|
2069
|
+
let viewportPanY = 0;
|
|
2070
|
+
let activePointerId = null;
|
|
2071
|
+
let dragStartX = 0;
|
|
2072
|
+
let dragStartY = 0;
|
|
2073
|
+
let dragLastX = 0;
|
|
2074
|
+
let dragLastY = 0;
|
|
2075
|
+
let dragMoved = false;
|
|
2076
|
+
let suppressNextClick = false;
|
|
2077
|
+
function applyViewportTransform() {
|
|
2078
|
+
viewportTransform.style.transform = `translate(${viewportPanX}px, ${viewportPanY}px) scale(${viewportScale})`;
|
|
2079
|
+
}
|
|
2080
|
+
function handleViewportWheel(event) {
|
|
2081
|
+
event.preventDefault();
|
|
2082
|
+
const rect = viewport.getBoundingClientRect();
|
|
2083
|
+
const pointerX = (event.clientX - rect.left) / fitScale;
|
|
2084
|
+
const pointerY = (event.clientY - rect.top) / fitScale;
|
|
2085
|
+
const nextScale = Math.min(MAX_VIEWPORT_ZOOM, Math.max(MIN_VIEWPORT_ZOOM, viewportScale * Math.exp(-event.deltaY * VIEWPORT_ZOOM_STEP)));
|
|
2086
|
+
if (nextScale === viewportScale) return;
|
|
2087
|
+
const sceneX = (pointerX - viewportPanX) / viewportScale;
|
|
2088
|
+
const sceneY = (pointerY - viewportPanY) / viewportScale;
|
|
2089
|
+
viewportScale = nextScale;
|
|
2090
|
+
viewportPanX = pointerX - sceneX * viewportScale;
|
|
2091
|
+
viewportPanY = pointerY - sceneY * viewportScale;
|
|
2092
|
+
applyViewportTransform();
|
|
2093
|
+
}
|
|
2094
|
+
function handleViewportPointerDown(event) {
|
|
2095
|
+
if (event.button !== 0 || activePointerId !== null) return;
|
|
2096
|
+
activePointerId = event.pointerId;
|
|
2097
|
+
dragStartX = event.clientX;
|
|
2098
|
+
dragStartY = event.clientY;
|
|
2099
|
+
dragLastX = event.clientX;
|
|
2100
|
+
dragLastY = event.clientY;
|
|
2101
|
+
dragMoved = false;
|
|
2102
|
+
viewport.setPointerCapture(event.pointerId);
|
|
2103
|
+
viewport.style.cursor = "grabbing";
|
|
2104
|
+
}
|
|
2105
|
+
function handleViewportPointerMove(event) {
|
|
2106
|
+
if (event.pointerId !== activePointerId) return;
|
|
2107
|
+
const deltaX = (event.clientX - dragLastX) / fitScale;
|
|
2108
|
+
const deltaY = (event.clientY - dragLastY) / fitScale;
|
|
2109
|
+
const totalX = event.clientX - dragStartX;
|
|
2110
|
+
const totalY = event.clientY - dragStartY;
|
|
2111
|
+
if (!dragMoved && Math.hypot(totalX, totalY) >= DRAG_CLICK_THRESHOLD_PX) dragMoved = true;
|
|
2112
|
+
dragLastX = event.clientX;
|
|
2113
|
+
dragLastY = event.clientY;
|
|
2114
|
+
viewportPanX += deltaX;
|
|
2115
|
+
viewportPanY += deltaY;
|
|
2116
|
+
applyViewportTransform();
|
|
2117
|
+
}
|
|
2118
|
+
function handleViewportPointerEnd(event) {
|
|
2119
|
+
if (event.pointerId !== activePointerId) return;
|
|
2120
|
+
if (dragMoved) suppressNextClick = true;
|
|
2121
|
+
if (viewport.hasPointerCapture(event.pointerId)) viewport.releasePointerCapture(event.pointerId);
|
|
2122
|
+
activePointerId = null;
|
|
2123
|
+
dragMoved = false;
|
|
2124
|
+
viewport.style.cursor = interactiveViewport ? "grab" : "pointer";
|
|
2125
|
+
}
|
|
2049
2126
|
function applyCurrentTime() {
|
|
2050
2127
|
for (const anim of allAnims) anim.currentTime = sceneMs;
|
|
2051
2128
|
onTimeUpdate?.(sceneMs / 1e3, durationSeconds);
|
|
2052
2129
|
}
|
|
2053
2130
|
function rafTick(timestamp) {
|
|
2054
|
-
if (lastRafTs !== null) sceneMs += (timestamp - lastRafTs) * playbackRate;
|
|
2131
|
+
if (lastRafTs !== null) sceneMs += (timestamp - lastRafTs) * playbackRate * NORMAL_PLAYBACK_RATE;
|
|
2055
2132
|
lastRafTs = timestamp;
|
|
2056
2133
|
if (totalDurationMs > 0 && sceneMs >= totalDurationMs) {
|
|
2057
2134
|
if (loop) sceneMs = sceneMs % totalDurationMs;
|
|
@@ -2122,8 +2199,20 @@ function createDiagram(opts) {
|
|
|
2122
2199
|
if (viewport.parentNode === container) container.removeChild(viewport);
|
|
2123
2200
|
}
|
|
2124
2201
|
};
|
|
2125
|
-
viewport.style.cursor = "pointer";
|
|
2202
|
+
viewport.style.cursor = interactiveViewport ? "grab" : "pointer";
|
|
2203
|
+
if (interactiveViewport) {
|
|
2204
|
+
viewport.style.touchAction = "none";
|
|
2205
|
+
viewport.addEventListener("wheel", handleViewportWheel, { passive: false });
|
|
2206
|
+
viewport.addEventListener("pointerdown", handleViewportPointerDown);
|
|
2207
|
+
viewport.addEventListener("pointermove", handleViewportPointerMove);
|
|
2208
|
+
viewport.addEventListener("pointerup", handleViewportPointerEnd);
|
|
2209
|
+
viewport.addEventListener("pointercancel", handleViewportPointerEnd);
|
|
2210
|
+
}
|
|
2126
2211
|
viewport.addEventListener("click", () => {
|
|
2212
|
+
if (suppressNextClick) {
|
|
2213
|
+
suppressNextClick = false;
|
|
2214
|
+
return;
|
|
2215
|
+
}
|
|
2127
2216
|
if (isPlaying) diagram.pause();
|
|
2128
2217
|
else {
|
|
2129
2218
|
if (!loop && sceneMs >= totalDurationMs) sceneMs = 0;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@markdy/renderer-dom",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.16",
|
|
4
4
|
"description": "Browser renderer for diagram-native animated MarkdyScript architecture diagrams, built on the Web Animations API.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -44,14 +44,14 @@
|
|
|
44
44
|
"access": "public"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@markdy/core": "0.8.
|
|
47
|
+
"@markdy/core": "0.8.16"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
50
|
"jsdom": "^29.1.1",
|
|
51
51
|
"tsup": "^8.5.1",
|
|
52
52
|
"typescript": "^5.9.3",
|
|
53
53
|
"vitest": "^4.1.7",
|
|
54
|
-
"@markdy/stdlib-systems": "0.8.
|
|
54
|
+
"@markdy/stdlib-systems": "0.8.16"
|
|
55
55
|
},
|
|
56
56
|
"scripts": {
|
|
57
57
|
"build": "tsup",
|