Repository navigation
Releases: OpenPresentation/opf-render
Release list
@openpresentation/opf-render 0.24.1
- RR-96: the example baseline follows core 0.24.0 (gallery 4 theme records with
variants; no slide changes). 0.24.0 was tagged but never published, because its publish run still checked the core 0.23 corpus; 0.24.1 is the first 0.24 release of the renderer.
@openpresentation/opf-render 0.23.0
- RR-95: README note on the chart preview and an opf-pptx 0.22.0 export: since 0.22.2 they draw the same series colors (the deck color scheme and
chart.colors), the same value axis for column, bar, line and area charts (core's composed axis) and the same 20 px chart text. - RR-96 (output-changing for decks and slides that set
design.variantor a picture or gradienttone; borders, gridlines, axis lines, chart text and the code panel change for every deck): every slide is drawn from core's resolved roles for its variant, as PowerPoint does with its colour map.design.variant(deck and slide, the"dark1"shorthand, the accent order) sets the background (bg1), text (tx1), surface (bg2), the series colour order and the neutrals; a variant hides the background of a less specific level. Table and chart frames, gridlines (tx1 at 15%), axis lines (25%), chart text (65%), the pie and treemap outlines, the video play icon, the code panel and its text, the metric neutral trend and the table header text come from the scheme-derived neutrals, so no fixed grey or white is left in the drawing code. A picture background that names itstonetakes that tone's variant and a 40% scrim of the slide background (the renderer's own, core exposes none). Needs@openpresentation/opf0.23.0. - RR-96 (adopts core RR-96, opf#732; test and baseline changes only, no renderer code): core derives borders, chart gridlines and axis lines from the color scheme (the text color mixed into the background,
roles.neutrals) instead of a fixed slate, so every card, table rule and chart changes color, not geometry, and the example corpus gains the color-variants deck. The tests that encoded the old colors expect the new ones (neutral-scaffolding, and the traced SVG digests ofchart-table-dataandchart-finite-statistics). The example and template baselines select new ones,rr96-scheme-neutrals, whenever core derives the neutrals (schemeNeutralsDerived());golden-gatecompares the selected baseline with every slide of the installed examples instead of a fixed 807. Requires the unreleased core 0.23.0.
@openpresentation/opf-render 0.22.2
- RR-89 (output-changing for every chart without highlight): chart series are drawn in core's
chartSeriesPaletteof the deck's resolved colour scheme (accent1toaccent6, then the same six accents tinted 40% toward white), sodesign.colorSchemerecolours the series instead of every deck drawing the cool-horizon blues; a deck without a colour scheme of its own keeps the engine default's accents. The palette still goes through core'schartPaletteForFill(contrast against the chart panel), andchart.highlightcolours are unchanged.chart.colorsentries (hex, scheme slot, role orvar:reference) replace the palette colour at their position, before the same adjustment;chart.highlightstill wins. The renderer's ownCHART_SERIES_COLORScopy is deleted. Needs@openpresentation/opf0.22.0. - RR-90 (output-changing for every chart): chart axis, legend, category and data-label text is core's
chartTextSizeinstead of 14 px floored to the 16 px (12 pt) minimum: 20 px (15 pt) in a roomy chart box, shrunk (at most a 1/18 of the box height and 1/30 of its width, whole pixels) only when the box is small, and never belowcomposition.minFontSize. A chart no longer renders at 12 pt beside 24 pt bullets. Needs@openpresentation/opf0.22.0. - RR-92 (no pixel change for the usual chart): a column, bar, line or area chart draws the value axis core composes for its box (
item.chart.valueAxis:min,max,majorUnit), the same axis the PPTX export writes, so the preview and PowerPoint or Keynote show the same gridlines. In a short box core estimates the plot from the box rather than from the laid-out plot, so the major unit can differ by one 1/2/5 step from before; every other chart type keeps its renderer-side scale. The renderer's localniceScale,maxIntervalsForandstackCategoryValuesare replaced by core's. Needs@openpresentation/opf0.22.0.
@openpresentation/opf-render 0.22.1
- RR-90: 0.22.1 is the first published 0.22 renderer. The 0.22.0 tag exists but was never published: its publish run found the example baseline stale against core 0.22. 0.22.1 carries the refreshed baseline (#260) and the same code as 0.22.0, which requires core ^0.22.0.
@openpresentation/opf-render 0.20.4
- RR-87: establish Git trust only for the exact checked-out workspace in the publishing job before verifying its merged release identity. Preserve the full source, tag and manifest checks; no runtime or export behavior changes.
@openpresentation/opf-render 0.20.2
- RR-85: Select the reviewed metric-centering example baseline for ordinary checks and trusted publication when the installed core defaults metrics to center. Preserve historical baseline bytes, explicit reviewed overrides and exact raster checks.
@openpresentation/opf-render 0.20.0
Renderer 0.20.0 requires published core 0.20.1 and supports Gallery 3 nested-array layout records, neutral structural defaults, typed numeric alignment and zero-based magnitude axes. The temporary unreleased-core declaration has been removed for this release.
- Layout templates now author
areasas nested arrays of region-name cells. String rows are outside the contract; grid geometry and explicit region pins retain their existing meaning. - Adopt the published Gallery 3 catalog contract for renderer development fixtures with an authentic registry lock. Engine versions and existing core/renderer contracts remain unchanged until the coordinated 0.20 release preparation.
Declare the matching unreleased core 0.20 requirement so the established RR-55 gate waits for genuine registry core before standalone packed checks; coordinated source and packed/browser qualification remains required. Release preparation removes this declaration and release checks refuse it.
- Structural card, table and chart rules use quiet neutral defaults instead of the scheme’s fifth brand accent. Authored border colors remain unchanged. Tables align typed numeric values and numeric-column headers to the right by default, retaining explicit cell and design alignment and original cell values. Preview and native export share the same resolved defaults.
Bar, column and filled-area magnitude axes include zero by default, including near-equal positive or negative values; line/scatter automatic domains remain unchanged.
@openpresentation/opf-render 0.19.1
The 0.19 renderer train uses 0.19.1 after the 0.19.0 publisher stopped before npm publication. It includes the adaptive v2 layout renderer and the corrected ordinary release checks.
- Ordinary renderer release tests select the existing reviewed v2 example baseline, matching installed core 0.19 examples. Explicit historical baseline overrides and all source, raster, missing-baseline and empty-corpus guards remain strict; no golden bytes or tolerances change.
@openpresentation/opf-render 0.18.2
- FF-46 (opf#362; tests only): per-name host fixtures for the 22 proprietary script, emoji, math and code-table names that pass the native visual comparison.
test/script-name-hosts.mjs(Node) andtest/script-name-hosts-browser.mjs(Chromium, offline) take each name oftest/fixtures/script-name-families.json(Aparajita, Arabic Typesetting, Cambria Math, David, FangSong, Gautami, Gisha, Kalinga, Microsoft JhengHei, Microsoft YaHei, MingLiU, Miriam, Nyala, PMingLiU, Segoe UI Emoji, SimHei, SimSun, Sylfaen, Symbol, Tunga, Webdings, Wingdings) and check that it resolves to its policy route with the policysizeAdjust, that every script sample draws in its route face with no other fallback (Sylfaen's Armenian and Georgian in their designated Noto faces; every mapped symbol code in the chain face that has it) at the route file's own advances, and that the drawn face is the pinned file. Both writeartifacts/script-name-hosts/*.json, the evidence the core font tracker reads. - opf#361 (output changes only for size-adjusted families): the renderer applies
font-policy.json'ssizeAdjustandlineAscentrows wherever they are, so with core's opf#361 rows the previews of Angsana New (0.75, line ascent 0.83 / 0.86), DilleniaUPC (0.68, 0.82 / 0.85), Sakkal Majalla (0.89, 0.76 / 0.81), Malgun Gothic (1.07) and Nirmala UI (1.07, 0.97 / 0.94) draw and measure their script text at the size PowerPoint draws it, and Arabic Typesetting lines move down 0.04 em (0.02 em on a line with a Latin run) for its corrected line ascent 0.74 / 0.80.- White space that follows a size-adjusted run now stays in that run (
createScriptFonts().plan), as PowerPoint keeps it in the script font: the space between two Hangul words of a Malgun Gothic title is measured and drawn at the run's adjusted size instead of a separate run at the composed size, which a browser drew wider than its measured advance (the FF-19 browser check caught it once Malgun Gothic carried a multiplier). test/arabic-size-adjust.mjs,test/script-fonts-browser.mjsandtest/script-corpora-slides-browser.mjsread the multipliers and title sizes from the installed core's policy instead of hard-coding Arabic Typesetting's, and the first checks the five new rows exactly when they are present.- No golden moves: the 807 example slides render identical SVG on the golden path with core's current policy and with the opf#361 rows.
- White space that follows a size-adjusted run now stays in that run (
- opf-render#189 changes the default output of PNG and raster PDF for Indic, Thai, Lao, Khmer and Myanmar text. The raster path now places each complex-script cluster at HarfBuzz's pen position (
fonts.outlines.shape, the shaper browsers use) instead of fontkit's.- Who it affects: conversions that have HarfBuzz, which the Node fonts handle and the bundled faces always have. The default
toPngand raster PDF therefore change for this text. - Fallback to fontkit's pens: without a shaper, output stays byte-identical. A run HarfBuzz cannot map back to its characters also falls back.
- Why: fontkit kerns after a decomposed Thai sara am differently from HarfBuzz, so a cluster after it (ใจ after น้ำ) was about 0.7 px off at 25 px.
- Script corpora: six samples change, measured as mean pixel difference against HarfBuzz's own outlines, before → after. All six now draw exactly like HarfBuzz's outlines, and no other sample changes:
thai-title: 0.46 → 0thai-sara-am: 1.48 → 0thai-no-spaces: 0.47 → 0taml-title: 5.7 → 0telu-title: 2.79 → 0mymr-medials: 12.96 → 0
- Against Chromium: seven of eight Thai checks (three lines and the issue's own line, at 25 and 60 px) come closer. For example,
thai-sara-amat 60 px drops from 266 channel values off by more than 64 to 43. What remains is the anti-aliasing difference that HarfBuzz's own outlines show too. - One regression:
thai-no-spacesat 25 px moves slightly away from Chromium (mean difference 1.298 → 1.329). The output there is exactly HarfBuzz's; fontkit's old offset happened to land nearer Chromium's pixels. - Raster goldens: unchanged, because no golden deck has complex-script text.
- Who it affects: conversions that have HarfBuzz, which the Node fonts handle and the bundled faces always have. The default
- Preserve named reference glyphs when subsetting embedded fonts so small text in macOS browser SVG previews draws like the whole face, while retaining compact, deterministic subsets.
- RR-81: regenerate explicitly pinned v2 example and template candidates in the prescribed Playwright image, with separate read-only generation and guarded baseline-only writes.
- Preserve the host color scheme across the slideshow player's CSS reset and use system Highlight for forced-colors focus outlines, so dark and light embeds retain the correct accessible system palette.
@openpresentation/opf-render 0.18.1
- render#171 (tooling and docs only, no change to the package):
npm run bench:soak(scripts/soak.mjs) is a repeatable sustained-load benchmark for long-lived render and export workers. Each worker process holds one fonts handle (loadFontswith the office pack andscripts: 'auto'), blocks the network and repeatsensure,toSvg,toPngand, when@openpresentation/opf-pptxis installed,toPptxover core's example decks and a script-corpora deck, at concurrency 1 and 4 for 500 or more jobs per worker. It samples RSS and retained heap after a forced GC, reports p50 and p95 latency per operation, tests the steady-state window for monotonic memory growth (Mann-Kendall plus Theil-Sen, criterion in the script header), and compares the SVG, PNG and PPTX hashes of every repeat of a deck; the JSON report and Markdown summary go to the git-ignoredartifacts/soak/. It is not part ofnpm test. The README section "Long-lived workers: measured memory and latency" publishes the first measurement with its hardware and Node version. - render#123: the vector PDF writer moves to
pako3.0.2 (from 1.0.11), whose exports are named only (import { deflate } from "pako"). Output is byte-identical:flatepasseslegacyHash: true, so pako 3 keeps writing canonical zlib streams as pako 1 did (its new default, the hash of Chromium zlib, writes about 1% larger streams with the same inflated content and would change every PDF's bytes and/ID). The/export-browserbundle tree-shakes pako's inflate side away: 20 KB smaller minified (6 KB gzipped). - render#191: dependency refresh. Upgrade the font packages with the renderer: install
@expo-google-fonts/noto-sans-jp,-kr,-scand-tc0.4.4,noto-color-emoji0.4.7 andnoto-emoji0.4.8 in the same step. They are exact-pinned optional peers: npm with an exact older pin refuses the upgrade (ERESOLVE), and pnpm ornpm --legacy-peer-depsinstalls it with a peer warning, after whichloadFontsrejects the old files withfont-integrity-mismatch. With npm, a caret pin (^0.4.3) moves with the renderer; other package managers can keep the locked older version, so bump the six packages explicitly (-sc,-tcandnoto-emojichange only metadata, but their exact peer pins moved too). The script and emoji font pins move to@expo-google-fonts/noto-sans-jp,-kr,-scand-tc0.4.4,noto-color-emoji0.4.7 andnoto-emoji0.4.8 (optional peers;src/font-manifest.jsre-pinned, licenses unchanged and verified OFL-1.1). The Noto Sans JP and KR faces are rebuilt files of the same 2.004 release with the same outlines and advances and renumbered glyph ids, so over the core examples and the script corpora SVG with embedded fonts and the raster goldens are unchanged; text-as-paths glyph ids (opf-g-<face hash>-<glyph id>) and the vector PDF's six-letter subset tags change for Japanese and Korean text. Noto Color Emoji moves from 2.051 to 2.057 (nine new emoji, redrawn glyphs), so a slide that embeds or exports it changes bytes.<opf-deck>thumbnails: the slide drawing is no longer inside the thumbnail button but under it, so the button's name ("Go to Slide 2 of 5: Agenda") is not contradicted by the slide's own text (WCAG 2.5.3, axe-core 4.14label-content-name-mismatch); the strip looks and behaves the same (a host that paints a background on::part(thumbnail)now paints it over the drawing).harfbuzzjs1.6.3 (HarfBuzz 14.6.0): shaping is unchanged (text-as-paths byte-identical over the examples and script corpora); hb-subset writes somecmapsubtables differently, so 70 of the 807 example SVGs with embedded subsets change by a few bytes (same glyph mapping, same pixels). Development dependencies:axe-core4.14.0,@napi-rs/canvas1.0.10,pdfjs-dist6.4.299. - opf#364 (docs): the README now says to pass the same
fontshandle (fromloadFonts()) to preview, validation, pagination and export so they agree with the drawn faces, and that a call without it uses core's built-in estimate (0.54 em per character, 0.62 em for capitals and digits, 0.32 em for a space, 1 em for CJK, zero for combining marks), which is too narrow for some scripts (opf#566). - RR-20 (release workflow only): publishing opf-render to npm now creates its GitHub Release. A
releasejob innpm-publish.ymlruns after the npm publish on a tag push, takes the notes from the version's## X.Y.Zsection ofCHANGELOG.md(the job fails if the section is missing), and creates the releaseopf-render-vX.Y.Ztitled@openpresentation/opf-render X.Y.Z, marked as the latest release. Only that job holdscontents: write; the publish job keepsid-token: write. GitHub Releases start at 0.18; older versions get none. - opf-render#125 (output-changing only where earlier measurement had left a stale glyph): a text measurement no longer depends on what the same process measured or drew before. fontkit caches one glyph object per glyph id with the code points of the call that created it, and its layout read a character's code points back from that cache. Bounding the outline of Bengali ra (U+09B0, a composite drawn with the nukta glyph as a component) cached the nukta (U+09BC) with no code points, so every later Bengali run with a nukta was shaped as a broken cluster with a dotted circle:
আয় বেড়েছে কিন্তু খরচ অপরিবর্তিতin Noto Sans Bengali at 25 px measured 380.4 or 367.65 px instead of 354.9 (the width HarfBuzz gives, and a fresh process's), and the font-switch matrix drew deck pairwise-50 differently by run order. The registry's faces now give every glyph request exactly the code points it asked for, as the PDF writer's faces already did, so a measurement and the SVG drawn from it are a function of the document and the registry alone. A fresh process measured the right width before and after; only renders that followed an affected outline change. - opf-render#188 (output-changing for complex-script and combining-mark PDFs only): the vector PDF is shaped by HarfBuzz, the browser's shaper, as
text: "paths"outlines are (RR-64 phase 2), instead of fontkit: with a fonts handle that carries the shaper (the NodeloadFontshandle always, a browser handle givenshapeWasm; exposed asfonts.outlines.shape) and, in Node without a handle, with the bundled one the conversion loads. Over the 30 script corpora every glyph the PDF shows now has HarfBuzz's id and position, where fontkit drew other glyphs on 10 samples (Bengali conjuncts, Thai and Lao tone marks, Khmer coeng, Myanmar medials, Syriac marks, Japanese combining sound marks) and put Telugu conjuncts 0.8 px off at 25 px. The PDF still draws the SVG's lines and pinned widths; the layout's measurement stays fontkit. Each character stays with the glyph it became (HarfBuzz cluster level 2), so the glyph-to-Unicode map and/ActualTextspans read back as before. The writer also draws a glyph's small horizontal GPOS placement (up to 0.025 em, it was dropped: Arabic, Hebrew, Devanagari, Tibetan and combining Latin and Cyrillic marks up to 0.6 px off at 25 px) and continues the line after a glyph it shows alone with that glyph's shaped advance (a zero-width joiner after a mark put the rest of a run its nominal width off). Latin text without combining marks is byte-identical. - opf-render#189 (output-changing for PNG and raster PDF of Indic, Thai, Lao, Khmer and Myanmar text only): the raster path pins each complex-script cluster at the fontkit pen of its first character in the run shaped as a whole, not at the advance of the run's prefix shaped alone, which ended without the context of the next character. A Thai leading vowel kerned to its consonant (ไ ด, เ ต) put the consonant with its tone and vowel marks 0.25 px right of the browser's place at 25 px (รายได้เติบโตในทุกภูมิภาค at 60 px: 1,329 channel values off by more than 64 from HarfBuzz's outlines drawn by the same resvg, none now; against Chromium 1,554, now 210, the anti-aliasing difference HarfBuzz's own outlines show too). The script corpora's
thai-digits,laoo-words,taml-pulliandtelu-zwnjnow draw exactly as HarfBuzz's outlines; the approved raster goldens do not change. The raster path's own fontkit faces also pin each glyph's code points (pinGlyphCodePoints, opf-render#125): after an outlined Devanagari letter with a nukta component (ऱ, क़), a later decomposed nukta no longer shapes with a dotted circle. - render#199: a Next.js app that imports
@openpresentation/opf-renderand/fonts-nodebuilds with Turbopack and nonext.config. Since RR-64 and RR-65,next buildfailed because Turbopack compiledharfbuzzjs/dist/harfbuzz.wasm(located withrequire.resolve) as a WebAssembly module; and in a server bundle, the font packages (require.resolveof a computed name, which a bundler turns into a stub that always throws) and the vendoredfonts/directory (new URLwith a computed path) were not found. The Node entries (/fonts-node,/preview-fonts-node) now locate these files at run time through Node's own resolution, in a form bundlers leave alone, so a Next.js server (Turbopack or webpack, route handler or server component) renders the same bytes as plain Node: subset faces, HarfBuzz-shaped outlines and the office pack. Plain Node output is unchanged.loadFontsnow reportsharfbuzz-unavailablethroughonDiagnosticwhen a harfbuzzjs.wasmcannot be loaded (a deployment that did not ship the package) and still loads the fonts, with whole faces and fontkit shaping; a missing file used to rejectloadFonts.npm run test:next-bundlebuilds and serves such an app against the packed package. - render#220: a symbol-encoded family (Wingdings, Symbol, Webdings) named as a font-scheme role also maps its codes in list bodies (
text: [{ text }]ortext: ["..."]), under heading/body and major/minor roles, as #207 made it do for string bodies. Core composes each list paragraph from its block's resolved style, and resolving that open symbo...