sketchmark 2.1.9 → 2.1.10
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 +1 -0
- package/dist/src/render/embed.js +26 -16
- package/dist/tests/run.js +3 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -246,6 +246,7 @@ const html = renderToEmbedHtml(doc, {
|
|
|
246
246
|
|
|
247
247
|
`renderToEmbedHtml()` inlines sampled SVG frames so the preview can play without a server route. Use `maxFrames` to trade file size for smoother motion.
|
|
248
248
|
The embed chrome defaults to a transparent outer background and uses light/dark-aware translucent controls so it can sit inside either theme more naturally.
|
|
249
|
+
For broad embed-host compatibility, prefer self-contained HTML with inline scripts/styles, avoid CDN dependencies, avoid dynamic module imports from blob/object URLs, and avoid using blob URLs for runtime-loaded assets when a `data:` URL or other inline form will work.
|
|
249
250
|
The embed export menu includes MP4 when the browser supports WebCodecs, so Chrome and Edge are the safest targets for video export.
|
|
250
251
|
|
|
251
252
|
The root package intentionally exports no builders, player, project loader, deck/sequence helpers, 3D renderer, or preset compiler.
|
package/dist/src/render/embed.js
CHANGED
|
@@ -19,6 +19,7 @@ function renderToEmbedHtml(document, options = {}) {
|
|
|
19
19
|
const initialFrameIndex = frameIndexForTime(initialTime, frameTimes);
|
|
20
20
|
const initialFrame = frames[initialFrameIndex] ?? frames[0] ?? (0, svg_1.renderToSvg)(document, options);
|
|
21
21
|
const chromeBackground = escapeHtml(String(options.chromeBackground ?? "transparent"));
|
|
22
|
+
const mp4MuxerRuntimeSource = inlineMp4MuxerRuntime(mp4_muxer_source_1.MP4_MUXER_SOURCE);
|
|
22
23
|
const statusLabel = escapeHtml(title || "Sketchmark embed");
|
|
23
24
|
const payload = {
|
|
24
25
|
title,
|
|
@@ -225,9 +226,11 @@ function renderToEmbedHtml(document, options = {}) {
|
|
|
225
226
|
</details>` : ""}
|
|
226
227
|
<div id="meta">${statusLabel}</div>
|
|
227
228
|
</div>
|
|
229
|
+
<script>
|
|
230
|
+
${mp4MuxerRuntimeSource}
|
|
231
|
+
</script>
|
|
228
232
|
<script>
|
|
229
233
|
const payload = ${serializeForScript(payload)};
|
|
230
|
-
const mp4MuxerSource = ${serializeForScript(mp4_muxer_source_1.MP4_MUXER_SOURCE)};
|
|
231
234
|
const stage = document.getElementById("stage");
|
|
232
235
|
const playButton = document.getElementById("play");
|
|
233
236
|
const slider = document.getElementById("time");
|
|
@@ -244,7 +247,6 @@ function renderToEmbedHtml(document, options = {}) {
|
|
|
244
247
|
};
|
|
245
248
|
let metaTimer = 0;
|
|
246
249
|
let exportBusy = false;
|
|
247
|
-
let mp4MuxerModulePromise = null;
|
|
248
250
|
|
|
249
251
|
function clampTime(value) {
|
|
250
252
|
if (!payload.duration) return 0;
|
|
@@ -372,9 +374,7 @@ function renderToEmbedHtml(document, options = {}) {
|
|
|
372
374
|
}
|
|
373
375
|
|
|
374
376
|
function loadSvgImage(svg) {
|
|
375
|
-
|
|
376
|
-
const url = URL.createObjectURL(blob);
|
|
377
|
-
return loadImage(url).finally(() => URL.revokeObjectURL(url));
|
|
377
|
+
return loadImage(svgDataUrl(svg));
|
|
378
378
|
}
|
|
379
379
|
|
|
380
380
|
function loadImage(url) {
|
|
@@ -386,6 +386,10 @@ function renderToEmbedHtml(document, options = {}) {
|
|
|
386
386
|
});
|
|
387
387
|
}
|
|
388
388
|
|
|
389
|
+
function svgDataUrl(svg) {
|
|
390
|
+
return "data:image/svg+xml;charset=utf-8," + encodeURIComponent(svg);
|
|
391
|
+
}
|
|
392
|
+
|
|
389
393
|
function canvasToBlob(canvas, type, quality) {
|
|
390
394
|
return new Promise((resolve, reject) => {
|
|
391
395
|
canvas.toBlob((blob) => {
|
|
@@ -431,17 +435,9 @@ function renderToEmbedHtml(document, options = {}) {
|
|
|
431
435
|
}
|
|
432
436
|
|
|
433
437
|
async function loadMp4Muxer() {
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
mp4MuxerModulePromise = import(url)
|
|
438
|
-
.catch((error) => {
|
|
439
|
-
mp4MuxerModulePromise = null;
|
|
440
|
-
throw error;
|
|
441
|
-
})
|
|
442
|
-
.finally(() => URL.revokeObjectURL(url));
|
|
443
|
-
}
|
|
444
|
-
return mp4MuxerModulePromise;
|
|
438
|
+
const module = globalThis.__SKETCHMARK_MP4_MUXER__;
|
|
439
|
+
if (module && module.Muxer && module.ArrayBufferTarget) return module;
|
|
440
|
+
throw new Error("MP4 runtime could not be initialized in this host.");
|
|
445
441
|
}
|
|
446
442
|
|
|
447
443
|
async function rasterBlob(format) {
|
|
@@ -686,3 +682,17 @@ function serializeForScript(value) {
|
|
|
686
682
|
.replace(/\u2028/g, "\\u2028")
|
|
687
683
|
.replace(/\u2029/g, "\\u2029");
|
|
688
684
|
}
|
|
685
|
+
function inlineMp4MuxerRuntime(source) {
|
|
686
|
+
const withoutExportBlock = source.replace(/\s*export\s*\{[\s\S]*?\}\s*;?\s*$/, "");
|
|
687
|
+
const runtime = `${withoutExportBlock}
|
|
688
|
+
globalThis.__SKETCHMARK_MP4_MUXER__ = {
|
|
689
|
+
ArrayBufferTarget,
|
|
690
|
+
FileSystemWritableFileStreamTarget,
|
|
691
|
+
Muxer,
|
|
692
|
+
StreamTarget
|
|
693
|
+
};`;
|
|
694
|
+
return escapeInlineScript(runtime);
|
|
695
|
+
}
|
|
696
|
+
function escapeInlineScript(value) {
|
|
697
|
+
return value.replace(/<\/script/gi, "<\\/script").replace(/<!--/g, "<\\!--");
|
|
698
|
+
}
|
package/dist/tests/run.js
CHANGED
|
@@ -137,7 +137,9 @@ test("renders a self-contained interactive embed HTML shell", () => {
|
|
|
137
137
|
assert(html.includes('data-export-format="svg"'), "should include export controls");
|
|
138
138
|
assert(html.includes('data-export-format="mp4"'), "should include mp4 export");
|
|
139
139
|
assert(html.includes("__SKETCHMARK_EMBED__"), "should expose a runtime controller");
|
|
140
|
-
assert(html.includes("
|
|
140
|
+
assert(html.includes("__SKETCHMARK_MP4_MUXER__"), "should inline the mp4 muxer runtime");
|
|
141
|
+
assert(!html.includes("import(url)"), "should avoid blob-based dynamic module imports");
|
|
142
|
+
assert(html.includes("data:image/svg+xml;charset=utf-8,"), "should use data URLs for SVG rasterization inside embed hosts");
|
|
141
143
|
assert(html.includes("sketchmark-rendered"), "should notify host frames when ready");
|
|
142
144
|
});
|
|
143
145
|
test("resolves element-local timeline tracks", () => {
|