The SDK is free to try. Production use, or shipping on any origin other than your development one, needs a commercial license with an unlocked, origin-bound build.

Live examples

A complete WebDocs editor built entirely on @squareys/webdecks-sdk — every button is one SDK call, and the page is presented live through WebGPU. It proves the bar the SDK is held to: a third party can build a real editor on the public API alone.

The reference editor

Open a .docx, format text, change paragraph styles, undo/redo, copy/cut/paste, and export — with the page rendered live by the SDK's WebGPU viewport and the caret and selection read back through wrapper getters. There is no pixel-readback preview: the canvasis the render. Needs a WebGPU browser; on Linux/Wayland run Chrome under XWayland (see Troubleshooting).

Not loading? The demo is deployed separately from these docs. Build it withbun run build in examples/sdk-react-editor (Bun bundles it to a static dist/) and deploy that, plus the engine assets at./engine/, to /sdk-demo/. The full, commented source is in that folder.

Wiring the live viewport in React

The demo's useWebdocs hook returns [state, actions] and keeps the module, document and viewport in refs. A single <canvas> gets the live view once the device is ready:

// One <canvas ref> gets the live viewport in an effect; the canvas IS the render.
useEffect(() => {
  if (state.status === "ready" && canvasRef.current)
    actions.attachCanvas(canvasRef.current);
}, [state.status, actions]);

return <canvas ref={canvasRef} className="live-view" />;

// Inside the hook, attachCanvas is one line:
//   const viewport = (await engine.createViewport(canvas)).start();

Format the selection

// Select a range and bold it — mutators chain and repaint the live viewport.
doc.selection.selectRange(paragraph, start, end);
doc.toggleFormat(TextFormat.bold);

// Reflect the toolbar's active state from the run under the caret.
const run = doc.paragraph(paragraph)?.runAt(start);
const isBold = run ? (run.format & TextFormat.bold) !== 0 : false;

Read the caret & selection

// Positions are (paragraph, byteOffset) pairs; getters read live off the engine.
const { caretParagraph, caretByteOffset, hasSelection } = doc.selection;
console.log(`caret at paragraph ${caretParagraph}, byte ${caretByteOffset}`);
if (hasSelection)
  console.log(doc.selection.anchorParagraph, doc.selection.anchorByteOffset);

// Named motions fold in the direction; pass true to extend the selection.
doc.selection.wordRight(true);   // Shift+Ctrl+Right

Undo & redo

if (doc.undo()) refreshToolbar();   // returns false when the history is empty
if (doc.redo()) refreshToolbar();

Edit a spreadsheet cell

The same shape, a different engine: attach a SpreadsheetModule, reach the active sheet, and set values, numbers, formulas and formatting with chained cell setters.

import { SpreadsheetModule } from "@squareys/webdecks-sdk";

const engine = await SpreadsheetModule.attach(wasm);
const book = await engine.spreadsheets.create();
const sheet = book.activeSheet;

sheet.cell(0, 0).setText("Revenue");
sheet.cell(0, 1).setNumber(1250).setBold(true);     // chained, colour-preserving
sheet.cell(1, 0).setText("Projected");
sheet.cell(1, 1).setFormula("=B1 * 1.2");
book.recalculate();

console.log(sheet.cell(1, 1).number);   // 1500

Add a shape to a slide

And again for presentations: attach a PresentationModule, take a slide, and author a text box and a shape. Authoring mutators return the new shape's wrapper, so they chain.

import { PresentationModule, ShapeKind } from "@squareys/webdecks-sdk";

const engine = await PresentationModule.attach(wasm);
const deck = await engine.presentations.create();
const slide = deck.slide(0)!;

// x, y, width, height in design px; font size in px; colour packed 0xRRGGBBAA.
slide.addTextBox(120, 90, 1200, 200, "Quarterly review", 96, 0xffffffff);

// A rounded rectangle behind the title, sent to the back.
slide
  .addShape(ShapeKind.roundedRectangle, 100, 60, 1240, 260, 0x2b6cb0ff)
  .sendToBack();

Export

// Every engine exports the same way; the bytes come from the real serializer.
const pptx = await deck.export("pptx");            // "pptx" | "odp" | "webdeck"
saveBlob(new Blob([pptx]), "deck.pptx");

// PNG is a thumbnail off the export path — never the live viewport.
const poster = await deck.exportThumbnail(0, 1280, 720);

Build your own

The demo's useWebdocs hook is a compact model for wiring the SDK into any framework: it owns the module session and the viewport, and exposes the operations as plain callbacks. Pair it with the API reference and the getting-started guide.

The SDK is free to try. Production use, or shipping on any origin other than your development one, needs a commercial license with an unlocked, origin-bound build.