bookcover-3d-web 0.17.0 → 0.19.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 (2) hide show
  1. package/dist/svg.js +26 -4
  2. package/package.json +1 -1
package/dist/svg.js CHANGED
@@ -1,4 +1,20 @@
1
1
  // SVG parsing and rasterisation utilities
2
+ // Grace period before snapshotting an SVG that embeds other documents — a pragmatic
3
+ // workaround for a Safari rasterisation quirk (see svg_to_bitmap), not a guarantee. Raise it
4
+ // if a cover ever renders in the 3D view without its background again.
5
+ const NESTED_RASTER_SETTLE_MS = 250;
6
+ // Feature detection is no help here (decode()/createImageBitmap exist everywhere) — this is
7
+ // a behavioural quirk specific to WebKit's renderer, so UA/platform sniffing is the only
8
+ // option. WebKit means desktop Safari, or ANY browser on iOS/iPadOS — Apple requires every
9
+ // iOS browser (Chrome, Firefox, Edge included) to run on WebKit under the hood, so those UAs
10
+ // need the same workaround despite naming another browser. Android and desktop Chrome/
11
+ // Firefox/Edge are the real Blink/Gecko engines this doesn't apply to.
12
+ const is_ios = typeof navigator !== 'undefined' && (/iPad|iPhone|iPod/.test(navigator.userAgent)
13
+ // iPadOS reports as "Macintosh" in its UA but is touch-capable, unlike a real Mac
14
+ || (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1));
15
+ const is_safari_desktop = typeof navigator !== 'undefined'
16
+ && /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
17
+ const is_webkit = is_ios || is_safari_desktop;
2
18
  /** Parse dimensions from the root SVG element's width/height attributes.
3
19
  * Values are in pt (Typst's SVG renderer uses pt as its coordinate system).
4
20
  * Accepts both "Xpt" (node backend) and bare "X" (web backend) forms. */
@@ -31,11 +47,17 @@ export async function svg_to_bitmap(svg, w_pt, h_pt) {
31
47
  img.onerror = () => reject(new Error('[cover-3d] SVG failed to load as image'));
32
48
  img.src = url;
33
49
  });
34
- // onload alone doesn't guarantee nested embedded rasters (e.g. a user's
35
- // background photo embedded in the panel SVG) have finished decoding —
36
- // notably on Safari, this can race and snapshot a blank background.
37
- // decode() is spec-guaranteed to wait until the image is fully paintable.
50
+ // onload alone doesn't guarantee the image is actually paintable yet; decode() is
51
+ // spec-guaranteed to wait until it is.
38
52
  await img.decode();
53
+ // WebKit can resolve decode() before it has finished rasterising documents nested
54
+ // inside this one, snapshotting a cover whose background is missing while its text
55
+ // (native to the outer document) is fine. Everything is inline, so this is decode
56
+ // time only, with nothing to wait on over the network. Only covers with something
57
+ // embedded are affected, so plain ones skip the wait entirely, and only WebKit needs
58
+ // the wait at all.
59
+ if (is_webkit && cleaned_svg.includes('data:image/'))
60
+ await new Promise(resolve => setTimeout(resolve, NESTED_RASTER_SETTLE_MS));
39
61
  // Must be awaited here (not returned directly) — the blob URL is revoked in
40
62
  // `finally` right after this call returns, and on Safari that can race ahead of
41
63
  // createImageBitmap still reading from the img element, capturing a blank bitmap.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bookcover-3d-web",
3
- "version": "0.17.0",
3
+ "version": "0.19.0",
4
4
  "license": "MIT-0",
5
5
  "repository": {
6
6
  "type": "git",