Skip to content

Add a pluggable Rust/WASM font source for browser embeds #399

Description

@kostyafarber

Problem

The browser SDK can run Shift's real editor over a host-provided MemoryFontSource, but browser embeds currently need snapshots prepared ahead of time. They cannot opt into Shift's Rust import pipeline to open arbitrary font bytes or source bundles locally in the browser.

The existing shift-bridge entry point is N-API and desktop-owned. Importing it into @shift/editor would break the browser boundary established by #398, while reimplementing parsing and variation construction in TypeScript would create a second source of truth.

Expected outcome

Browser consumers can optionally load fonts through a Rust/WebAssembly backend that satisfies the existing MemoryFontSource contract. Static fixtures, WASM-backed sources, and other host adapters remain interchangeable without changing the editor, renderer, tools, or shared UI.

The WASM backend is opt-in and separately packaged. The browser-safe editor and core SDK do not import it. A browser host owns the backend lifetime and can dispose it independently from an editor session.

Use cases

  • A website lets someone select a local OpenType font and inspect or edit it without uploading the file.
  • An embedded editor opens a host-provided source bundle while keeping parsing and variation construction consistent with desktop Shift.
  • Offline and privacy-sensitive web applications use Shift's Rust font model without Electron or a server-backed workspace.
  • Documentation, playgrounds, and integration environments create real font sources at runtime instead of shipping a prepared snapshot for every example.
  • Multiple editor instances share the same SDK while each uses an independent WASM-backed font source.
  • Expensive parsing runs outside the browser's UI thread so loading a font does not freeze the host application.
  • Future native, WASM, or remote read adapters can target one source contract rather than introducing host-specific editor implementations.

Acceptance criteria

  • An optional browser package exposes an asynchronous way to create a ready font source from browser-owned bytes or a source bundle.
  • The resulting source implements MemoryFontSource and supplies the existing FontSnapshot, GlyphRecord, GlyphSnapshot, and preview contracts.
  • The implementation reuses the canonical Rust font/import crates; it does not reconstruct variation models in TypeScript.
  • Parsing and lazy glyph reads work without Electron, Node runtime APIs, N-API, native filesystem access, persistence, or a server round trip.
  • Parsing and glyph reads execute off the browser UI thread.
  • Two independently created sources can back two live editor sessions without sharing font, selection, camera, or tool state.
  • Disposing a source releases its worker and WASM resources, and does not implicitly dispose other sources or sessions.
  • The existing static in-memory source remains supported without loading the WASM package.
  • A packaged browser consumer demonstrates loading a real font through the WASM source and opening it in createMemoryFontSession.
  • Documentation explains supported inputs, lifecycle ownership, CSP/worker requirements, expected payload size, and browser compatibility.

Boundaries

  • This is a read-source backend, not a browser workspace or persistence implementation.
  • Structural mutation, undo/redo persistence, save/export, and a writable Rust workspace protocol are separate follow-up work.
  • The desktop N-API bridge remains supported and is not replaced by this backend.
  • The core SDK must not bundle or initialize WebAssembly unless the consumer explicitly installs and uses the backend.

Related work

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions