@openpresentation/opf-render 0.24.1 → 0.25.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.
- package/README.md +3 -3
- package/dist/svg.js +12 -2
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -212,11 +212,11 @@ console.log(fonts.substitutions);
|
|
|
212
212
|
|
|
213
213
|
Set `trace: true` to stamp rendered SVG elements with `data-opf-path` values such as `slides.0.title`; omit it for smaller production SVG.
|
|
214
214
|
|
|
215
|
-
Layout templates (OPF 0.19, core `opf-layout/v2`:
|
|
215
|
+
Layout templates (OPF 0.19, core `opf-layout/v2`: a `direction` and one ordered `regions` list, nested for two dimensions) draw from core's composed geometry, as every slide does: the renderer adds no arrangement of its own. Core places each block in its region (`geometry.regions`, `item.region`); a card is the `item.frameBox` core composed in the block's cell (`design.contentBox`), and a region with `bleed` arrives with its outer edges on the slide edge and no card. A list core laid out in columns (`item.listColumns`: a lone list in a region with `listColumns: "auto"`, or a list payload with `columns`) draws each column's own fit in its own box, at one shared size, with numbering continuing across the columns; `item.text` (the whole list) is not drawn then. With `trace: true` everything an item of a region draws (card, payload, caption) is grouped in `<g data-opf-region="<name>">`, and each list column is a group with `data-opf-list-column` (its index), `data-opf-list-start` and `data-opf-list-end` (the half-open range of the payload's items it holds) and its `data-opf-box-*`. OPF 0.19 removes `opf-layout/v1` records with no alias or migration shim. Slides without a layout use core's automatic composition; only items bound to template regions carry these region attributes. `test/layout-template-goldens.mjs` pins the SVG and PNG of the 28 built-in templates with 1 to 6 short and long blocks, and of the pages core's `paginate` makes of the ones that overflow.
|
|
216
216
|
|
|
217
217
|
The installed open font pack works offline. The Aptos family previews with the metric-compatible Intos even under the default metric policy; this example additionally permits visual-only look-alikes for families with no metric replacement yet (a documented fallback), and the substitution report identifies requested and resolved faces. A visual substitute is not a claim of metric or pixel equivalence, and it is a known layout-fidelity gap rather than the end state. Replacements apply to rendering only; the document keeps the selected font name. Omit `substitutionPolicy` to restrict the Office pack to its metric mappings, or supply your own licensed faces (`faces`). Missing fonts/glyphs fail explicitly. Without `fonts`, synchronous SVG APIs use estimated widths; named fonts alone do not make rich-run spacing reliable. Browser hosts should load the same bytes using the loader below.
|
|
218
218
|
|
|
219
|
-
Unresolved images produce an `unresolved-asset` diagnostic through `onDiagnostic`, including the OPF path, reason and complete description. The fallback shows a bounded status label when it fits above the selected readability floor, otherwise an icon with the full accessible description. The label is `Image unavailable` over the description (alt, else title, else `Image`) in semibold at 20 px on a 1280 x 720 canvas, and opf-pptx exports the same placeholder as native shapes. It preserves authored opacity, including faint decorative watermarks; a missing image is still missing even when its fallback fits. Use `strictAssets: true` to reject unresolved images. Supply embedded raster data URIs or a synchronous host `imageResolver` to resolve them; the renderer does not fetch URLs or read local paths. Caller descriptions and other metadata override referenced asset metadata through alias chains. These diagnostics identify unresolved sources, not malformed image bytes or native PowerPoint compatibility.
|
|
219
|
+
Unresolved images produce an `unresolved-asset` diagnostic through `onDiagnostic` (a warning in the CLI report, `render/unresolved-asset`, which `--fail-on warning` turns into a failure), including the OPF path, the `source` the author wrote, the reason and the complete description; the `message` names that source, and the image is skipped, not the render. It covers every place a deck spells an image: slide backgrounds (also tiled), image blocks, header/footer and organization logos, picture watermarks, picture bullets, and `asset:` references. The fallback shows a bounded status label when it fits above the selected readability floor, otherwise an icon with the full accessible description. The label is `Image unavailable` over the description (alt, else title, else `Image`) in semibold at 20 px on a 1280 x 720 canvas, and opf-pptx exports the same placeholder as native shapes. It preserves authored opacity, including faint decorative watermarks; a missing image is still missing even when its fallback fits. Use `strictAssets: true` to reject unresolved images. Supply embedded raster data URIs or a synchronous host `imageResolver` to resolve them; the renderer does not fetch URLs or read local paths. Caller descriptions and other metadata override referenced asset metadata through alias chains. These diagnostics identify unresolved sources, not malformed image bytes or native PowerPoint compatibility.
|
|
220
220
|
|
|
221
221
|
Header/footer images and watermarks fit their complete artwork within their allocated regions. Image blocks use their own `fit`, else `design.imageFit` (default `cover`), as core resolves it into `item.image.fit`.
|
|
222
222
|
|
|
@@ -674,7 +674,7 @@ npm run golden:update
|
|
|
674
674
|
Public npm package publication is handled by `.github/workflows/npm-publish.yml` through npm Trusted Publishing (GitHub Actions OIDC) with npm provenance; no npm token is stored. The owner authorized agents to prepare and publish npm releases whenever a release is required (2026-09-29). This authorization does not waive any gate.
|
|
675
675
|
|
|
676
676
|
1. Open a release-prep PR containing only the version bump, `CHANGELOG.md` (assembled from `changes/` with `node scripts/changelog-fragments.mjs assemble --version X.Y.Z`), dependency ranges, lockfile and current-instruction docs. Publish in dependency order (core, then renderer and PPTX, then editor): refresh this repo's lockfile only after the required `@openpresentation/opf` version is on the registry (`npm install --package-lock-only`), then run `npm run test:packed` against it.
|
|
677
|
-
2. Merge after CI is green, then publish by pushing the git tag `opf-render-v<version>` (or `@openpresentation/opf-render@v<version>`) at the merge commit. The workflow verifies that the tag matches `package.json` and
|
|
677
|
+
2. Merge after CI is green, then publish by pushing the git tag `opf-render-v<version>` (or `@openpresentation/opf-render@v<version>`) at the merge commit. The workflow verifies that the tag matches `package.json`, that the push-to-`main` run of `ci.yml` on exactly the tagged commit succeeded (`scripts/ci-evidence.mjs`; it fails closed and re-runs no test, RR-100), and the artifact itself (audit, the packed install, `npm pack --dry-run`) before `npm publish --access public --provenance`. A tag pushed while CI still runs fails at the evidence step; re-run the failed job once CI is green. A manual `workflow_dispatch` runs the same job without the tag check and is a fallback only.
|
|
678
678
|
3. Verify with `npm view @openpresentation/opf-render@<version> version gitHead dist.attestations` and, from the core repo, `node scripts/test-renderer-publication.mjs <version> <release-commit> <this-checkout>`. Never republish an existing version.
|
|
679
679
|
|
|
680
680
|
## Shared dynamic composition (local development)
|
package/dist/svg.js
CHANGED
|
@@ -1186,12 +1186,22 @@ function svgHasIntrinsicSize(attributes) {
|
|
|
1186
1186
|
return Boolean((length(attributes.width) && length(attributes.height)) || view);
|
|
1187
1187
|
}
|
|
1188
1188
|
|
|
1189
|
+
// RR-97: the message of an `unresolved-asset` diagnostic names the source the author wrote, so a report says which image to fix
|
|
1190
|
+
// (the diagnostic's `path` says where). The renderer fetches no URL and reads no path: a host resolves a local file to a data URI
|
|
1191
|
+
// (`imageResolver`, or the CLI's `--asset-dir`), and one that cannot says why in its own finding.
|
|
1192
|
+
function unresolvedImageMessage(kind, src, missingReference, outcome) {
|
|
1193
|
+
if (missingReference) return `${kind} asset "${missingReference}" is not declared in the deck's assets, so ${outcome}. Declare the asset or resolve it in the host.`;
|
|
1194
|
+
if (typeof src !== "string" || src === "") return `${kind} has no src, so ${outcome}.`;
|
|
1195
|
+
const shown = src.startsWith("data:") ? `${src.slice(0, Math.min(src.indexOf(",") + 1 || 40, 60))}...` : src.length > 120 ? `${src.slice(0, 117)}...` : src;
|
|
1196
|
+
return `${kind} "${shown}" was not resolved to an embedded PNG, JPEG, GIF, WebP or SVG data URI, so ${outcome}. Fix the path, embed the image as a data URI, or resolve it in the host (imageResolver, or --asset-dir in the CLI).`;
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1189
1199
|
// The drawable data URI of a picture bullet, or undefined (after reporting unresolved-asset once) so the glyph marker stays.
|
|
1190
1200
|
function resolveBulletImage(bulletImage, bound, options) {
|
|
1191
1201
|
const { drawable, source, asset, missingReference } = resolveImageSource({ value: bulletImage.source, path: bulletImage.path }, bound, options);
|
|
1192
1202
|
if (drawable) return source;
|
|
1193
1203
|
const reason=missingReference?'missing-reference':!asset.src?'missing-source':'unsupported-source';
|
|
1194
|
-
const message=
|
|
1204
|
+
const message=unresolvedImageMessage('Bullet image',asset.src,missingReference,'the preview draws the character bullet');
|
|
1195
1205
|
if (options.strictAssets) throw new OPFRenderError("unresolved-asset", message, { path: bulletImage.path,reason });
|
|
1196
1206
|
reportDiagnostic({code:'unresolved-asset',path:bulletImage.path,message,reason,source:asset.src,assetId:missingReference,description:asset.alt??asset.title??'Bullet image',placeholder:'glyph'},options);
|
|
1197
1207
|
return undefined;
|
|
@@ -1222,7 +1232,7 @@ function renderImage(item, box, bound, options) {
|
|
|
1222
1232
|
...attrs });
|
|
1223
1233
|
}
|
|
1224
1234
|
const reason=missingReference?'missing-reference':!asset.src?'missing-source':'unsupported-source';
|
|
1225
|
-
const message=
|
|
1235
|
+
const message=unresolvedImageMessage('Image',asset.src,missingReference,'the preview draws the unavailable-image placeholder');
|
|
1226
1236
|
if (options.strictAssets) throw new OPFRenderError("unresolved-asset", message, { path: item.path,reason });
|
|
1227
1237
|
const fill = bound.design.colors.surface;
|
|
1228
1238
|
const scale=Math.min(bound.design.dimensions.width,bound.design.dimensions.height)/720;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openpresentation/opf-render",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.25.0",
|
|
4
4
|
"description": "Deterministic local OPF renderer for SVG, PNG, and PDF output.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -142,7 +142,7 @@
|
|
|
142
142
|
"test:forced-colors-browser": "node test/forced-colors-browser.mjs artifacts/forced-colors"
|
|
143
143
|
},
|
|
144
144
|
"dependencies": {
|
|
145
|
-
"@openpresentation/opf": "^0.
|
|
145
|
+
"@openpresentation/opf": "^0.25.0",
|
|
146
146
|
"bidi-js": "1.1.0",
|
|
147
147
|
"fontkit": "^2.0.4",
|
|
148
148
|
"harfbuzzjs": "1.6.3",
|
|
@@ -341,7 +341,7 @@
|
|
|
341
341
|
}
|
|
342
342
|
},
|
|
343
343
|
"devDependencies": {
|
|
344
|
-
"@openpresentation/gallery": "^
|
|
344
|
+
"@openpresentation/gallery": "^5.0.0",
|
|
345
345
|
"@expo-google-fonts/arimo": "0.4.3",
|
|
346
346
|
"@expo-google-fonts/caladea": "0.4.2",
|
|
347
347
|
"@expo-google-fonts/cousine": "0.4.3",
|