npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@s8fy/pptx-viewer

v3.2.0

Published

High-fidelity, framework-agnostic PPTX viewer SDK for browsers

Readme

@s8fy/pptx-viewer

High-fidelity PowerPoint viewing in the browser, with a framework-neutral SDK and native Web Component.

Built on the shared @s8fy parser, model, and DOM/SVG renderer pipeline, with font-driven text layout, vector graphics, charts, and supported DrawingML effects. The package provides the framework-neutral viewer controller, a native custom element, parser/PDF helpers, and the stylesheet required by the default viewer UI.

Install

pnpm add @s8fy/pptx-viewer

Usage

import { createPptxViewer } from '@s8fy/pptx-viewer'
import '@s8fy/pptx-viewer/style.css'

const root = document.querySelector('#viewer')
if (!(root instanceof HTMLElement)) throw new Error('Missing #viewer element')

const viewer = createPptxViewer(root)
try {
  const response = await fetch('/slides.pptx')
  if (!response.ok) throw new Error(`PPTX request failed: ${response.status}`)
  await viewer.load(await response.arrayBuffer(), 'slides.pptx')
  console.log(`Loaded ${viewer.total} slides`)
} catch (error) {
  viewer.destroy()
  throw error
}
// Call viewer.destroy() when your route/component is disposed.

The controller returned by createPptxViewer() owns parsing, slide navigation, rendering, and cleanup for a single mount node.

Add <div id="viewer"></div> to the page and serve a PPTX at the example URL. For a file input, pass await file.arrayBuffer() to load; File, URL strings, and Node Buffer objects are not viewer source values.

Pass one source ({ kind: 'file', file, fileName? } or { kind: 'presentation', presentation }), or omit it for an empty viewer. The retired top-level source fields are rejected. await viewer.load(file) and await viewer.setData(presentation) wait for authorization, font preparation with its existing timeout/fallback, and the first DOM commit. setData removes original-file export capability. File inputs are snapshotted before any asynchronous work. Pending operations reject immediately when superseded or destroyed; ViewerOperationError.code distinguishes invalid_source, missing_document_source, operation_superseded, and viewer_destroyed.

The default configuration uses the WASM parser and unzip engine, a 960 px viewer width, enabled PDF export and presenter mode, and disabled PPTX download. The package ships the parser workers, WASM binaries, viewer CSS, and cacheable KaTeX WOFF2 font assets through its dependency graph; modern bundlers such as Vite preserve them automatically.

The ESM and CJS modules can be imported during SSR without browser globals. Creating a viewer, registering the custom element, or rendering slides still requires a browser DOM; definePptxViewer() is a no-op when customElements is unavailable.

Rendering capabilities

The facade and Web Component share the same Core/Renderer implementation. They display supported native SmartArt layouts, chart/SmartArt animation subtargets, Box animations and dissolve transitions, glyph glow/reflections, shape reflections/inner shadows, solid 3D text, and authored audio posters. SmartArt cached drawings take precedence; native projection covers selected uncached linear-process and organization-hierarchy layouts. Audio controls depend on playable media and browser support, and playback requires user interaction.

Font availability, connected layout, browser capabilities, and effect budgets affect rendering. Unsupported effects/layouts retain their applicable fallback rather than guaranteeing Office pixel parity. PDF export uses a separate static renderer: audio posters do not play audio, and shape-frame reflections require zero blur. See the renderer README for playback and effect details.

Common options

| Option | Default | Usage | | ----------------------- | ----------------------- | ---------------------------------------------------------------------------- | | source | Empty viewer | One explicit file or normalized presentation source | | parser, unzipMode | 'wasm', 'wasm' | Select JS/WASM parsing and the WASM parser's ZIP engine | | wasmUrl | Package-relative | Override the parser WASM URL | | width, initialSlide | 960, 0 | Viewer width in pixels and zero-based starting slide | | hideToolbar | false | Hide the built-in toolbar | | extractFonts | false | Extract embedded fonts for preview; can increase memory use | | enablePdfExport | true | Show PDF export UI; authorization still applies | | enablePptxDownload | false | Show original PPTX download UI | | enablePresenterMode | true | Enable presenter mode | | fonts | Default font resolution | Browser preview font sources; see below | | pdf | Default PDF settings | PDF engine/Worker URLs and font options | | license | No supplied license | { signedLicense, deploymentId?, signedRestrictionPolicies? } | | watermark | Policy-dependent | Additional watermark configuration; cannot remove required policy watermarks |

onLoad({ total }) runs when a document is ready, onSlideChange(index) receives a zero-based index, onLicenseStateChange(state) reports authorization state/reason, and onError(error) reports operation failures once. Explicit asynchronous methods still reject their returned Promise; callers must handle it even when onError is configured. Expected cancellation and calls after destruction do not emit error notifications. Callback throws/rejections cannot change an operation's outcome, and replacing or destroying a document suppresses its remaining callbacks. Initial source loading is asynchronous but creation returns immediately; use onLoad or create an empty viewer and await load() when readiness matters.

Navigation and export

| Controller API | Result | | ---------------------------------------------------------------------- | ------------------------------------------------------------------------------- | | slide, total | Zero-based current index and slide count | | setSlide(index), next(), prev() | Navigate slides; next() first advances a pending click animation when enabled | | load(buffer, fileName?), setData(presentation) | Promise<void> for document replacement | | toPdf(options?) | Promise<Uint8Array>; no download | | downloadPdf({ fileName?, ...options }?) | Promise<void> after conversion and browser download initiation | | downloadPptx(fileName?) | Promise<void> after original-file download initiation | | enterFullscreen() | Promise<void> after the native fullscreen request succeeds | | enterPresenterMode(), exitPresenterMode(), togglePresenterMode() | Presenter controls | | destroy() | Release owned Blob URLs/fonts, listeners, and pending work |

PDF/PPTX export requires a successfully loaded original file. A model-only source cannot reconstruct those bytes. Await load() before exporting and handle promise rejection. A completed download method means the download was initiated, not that the file has finished writing to disk.

Invoke enterFullscreen() directly from a user interaction and handle its rejection. A missing browser API rejects with DOMException name NotSupportedError. Source replacement does not cancel a fullscreen request; destruction rejects it immediately and cleans up only this viewer's fullscreen session, including late native completion.

The top-level pptxToPdf(buffer, options?) and downloadPdf(bytes, fileName) helpers are also exported. They are different from controller methods: the standalone download helper takes existing bytes, and standalone conversion does not accept the controller's fontResolver option.

Animation model in the planned 3.2 release

The facade and framework adapters use Core's animation model. AnimationDegraded is a discriminated union with required kind. In the planned 3.2 release, narrow on text-granularity or timing-fill before reading that variant's fields; the former effect-fallback variant and AnimationEffect.previewFallback are removed. These incompatible type changes intentionally ship in a minor version while the SDK has no external consumers. Add kind: 'text-granularity' to application-created text diagnostics, replace interface extension/declaration merging against the former interface, and reparse original PPTX bytes when migrating persisted models.

Supported dissolve entrance/exit element effects play deterministic particles, preserving authored opacity and timing. They do not use a fade fallback. Repeat, reverse, replay and interrupted-slide snapshots share the object animation lifecycle. PDF export remains static; particle playback does not imply PowerPoint frame equivalence.

Upgrading to 3.0

Replace calls to the removed viewer.fullscreen() alias with viewer.enterFullscreen() and handle its returned Promise<void>. Invoke it in the user interaction handler so the native request retains user activation. The ViewerBinding root re-export has also been removed; create application controllers with createPptxViewer. The /internal lifecycle bridge is for SDK integrations, not a stable application API.

Fonts, deployment, and animation

For self-hosted browser fonts and PDF fallback fonts, pass options such as:

import type { ViewerOptions } from '@s8fy/pptx-viewer'

const options: ViewerOptions = {
  fonts: {
    remoteFonts: false,
    families: { 'Noto Sans SC': '/fonts/NotoSansSC-Regular.ttf' },
  },
  pdf: {
    fontResolver: false,
    unicodeFallbackFont: { url: '/fonts/NotoSansSC-Regular.ttf' },
  },
}

Serve the font at the supplied URL. Preview font resolution may use Google Fonts by default; remoteFonts: false disables that fallback while retaining explicitly configured assets. fonts: false disables remote preview fallback but does not prevent embedded-font injection. PDF fonts require font bytes; preview CSS alone is not sufficient. pdf.fontResolver: false skips automatic PDF font resolution while explicit font options remain usable.

For user-approved local PDF font bytes, use pdf: { fontResolver: { systemFonts: true, remoteFonts: false } }. This is an export-time setting, not a fonts preview option. It requires a supporting browser, a secure context, permission, and supported installed TrueType fonts; provide explicit fallback fonts for unavailable or denied access. Exact fonts are preferred, with compatible Calibri/Carlito and Arial/Arimo fallbacks where available.

The planned 3.2 release replaces createPdfFontOptions / PdfFontOptionsInput with the facade export resolvePdfFonts(input: PdfFontResolutionInput): Promise<PdfFontResolutionResult>, without a compatibility alias or the unused embeddedFonts input. This API change intentionally ships in a minor version while the SDK has no external consumers. It returns { fonts, cjkFallback }. Inspect cjkFallback.status, then pass viewer.downloadPdf({ ...result.fonts, fontResolver: false }); passing the whole result is incorrect. This API is in the source tree and is not available in published 3.1.0.

The report distinguishes not-checked (no model), not-needed (no visible CJK), missing, partial, complete, and unknown coverage. It exposes required, covered, missing and unknown codepoint lists, plus coverageSources: inspected Unicode cmap mappings or declared CSS unicode-range coverage for downloaded faces. Ordinary family fonts and Latin/symbol fonts do not count as CJK fallbacks. Partial Google downloads therefore cannot be mistaken for complete CJK coverage, and symbol-only success remains missing. WOFF2/TTC with no inspectable coverage and unloaded explicit fallback URLs remain unknown.

Automatic Viewer export keeps tolerant resolution; the report does not itself reject downloads. Applications requiring a complete CJK fallback should only accept complete/not-needed, avoid caching rejected results, preserve retry, and check document identity before downloading. Embedded/original fonts are outside this fallback report, so missing does not prove the final PDF lacks glyphs. Even complete is not a font-validity, shaping or fidelity guarantee; CSS coverage is not decoded glyph verification. Prepare the model/imports before requesting local fonts directly in an export click.

Default package assets need no custom URLs in the tested Vite integration. If using copied/CDN assets, wasmUrl selects the parser binary; pdf.wasmUrl selects pdf-converter.wasm, and pdf.workerUrl selects its Worker. Keep asset paths intact, serve WASM rather than HTML fallback content, and allow cross-origin requests when applicable. Browser PDF conversion requires a working Worker and does not retry synchronously after Worker failure.

animationScope defaults to 'fullscreen' (including presenter mode); use 'always' for inline playback or 'never' to disable it. animationMode: 'static' and animate: false disable playback. Reduced-motion preferences are respected unless animate: true is supplied. autoPlayAnimations is off by default and clickToAdvanceAnimation is on. nextAnimation(), completeAnimations(), resetAnimations(), onAnimationStart, and onAnimationEnd control/report supported effects; unsupported PowerPoint effects are not guaranteed to reproduce exactly.

Errors and runtime support

The package declares Node.js 22.12+ and supplies ESM/CJS TypeScript declarations. WASM parsing/export needs WebAssembly GC; choosing parser: 'js' changes parsing only, not the PDF engine. In SSR frameworks, create/mount the viewer in client-side lifecycle code.

Catch ViewerOperationError and inspect code for lifecycle/source failures. AuthorizationDeniedError.reason, PptxFileSizeLimitError.limitBytes, and ResourcePolicyError.details distinguish authorization, file-size, and engineering resource-limit failures. UI flags do not grant an entitlement, and commercial licenses do not disable engineering resource limits.

Custom Element

Register the element once before using <s8fy-pptx-viewer> in markup:

import { definePptxViewer } from '@s8fy/pptx-viewer/web-component'
import '@s8fy/pptx-viewer/style.css'

definePptxViewer()
<s8fy-pptx-viewer id="deck" width="960" enable-pdf-export="false"></s8fy-pptx-viewer>

After the element is connected to the document, load a file through its method or source property:

import { PptxViewerElement } from '@s8fy/pptx-viewer'

const element = document.querySelector('#deck')
if (!(element instanceof PptxViewerElement)) throw new Error('Viewer is not registered')
element.addEventListener('slidechange', (event) => {
  console.log((event as CustomEvent<{ index: number }>).detail.index)
})
const response = await fetch('/slides.pptx')
if (!response.ok) throw new Error(`PPTX request failed: ${response.status}`)
await element.load(await response.arrayBuffer(), 'slides.pptx')

Importing ./web-component alone does not register the element: call definePptxViewer(). There is no file-fetching src attribute. Set structured source, license, fonts, and pdf values as JavaScript properties; the retired file, presentation, and fileName properties and file-name attribute are rejected. Methods such as load, setData, toPdf, and downloads require a connected element. Removing it from the DOM destroys its controller automatically.

Events are load (detail: { total }), slidechange ({ index }), licensestatechange (license state), animationstart/animationend (playback event), and error ({ error }). Listen directly on the element; these events do not bubble. For boolean attributes, only the exact value "false" is false; any other present value is true, and removing an attribute restores its default. Configuration property/attribute changes recreate the controller.

For a connected element, invalid load()/setData() inputs dispatch error and reject the returned Promise; handle the rejection even if an event listener is installed. Assigning source is not awaitable and reports failures through events. Source updates reuse the controller, while clearing the source or changing configuration recreates it.

The element forwards loading, navigation, animation, presenter, and export methods, but does not expose the controller's enterFullscreen() method. Use the SDK controller when that imperative fullscreen API is required.

Package Boundaries

@s8fy/pptx-viewer is intentionally thin:

  • PPTX parsing and PDF helpers come from @s8fy/pptx-core.
  • DOM/SVG rendering and viewer state are handled by @s8fy/pptx-renderer.
  • Framework packages wrap this same controller instead of reimplementing it.

Available framework wrappers:

  • @s8fy/pptx-viewer-react
  • @s8fy/pptx-viewer-vue
  • @s8fy/pptx-viewer-svelte
  • @s8fy/pptx-viewer-solid

Install both a framework adapter and @s8fy/pptx-viewer directly when the application imports @s8fy/pptx-viewer/style.css; the adapter READMEs include the exact commands.

License

The default license is the PolyForm Noncommercial License. Commercial use requires a separate commercial license. See the package LICENSE for terms; runtime license validation is separate from permission to use the software commercially.