### Get started with craftsmith CLI (bash)
Source: https://docs.logisheets.com/craft/craft.html
Scaffold, install, and validate a new craft using the `craftsmith` CLI. Run these commands in order: create the craft, install dependencies, validate the contract, and then build to compile to `dist/`.
```bash
npx craftsmith new my-craft
cd my-craft && npm install
npx craftsmith check . # validate the contract
npx craftsmith build . # compile → dist/
```
--------------------------------
### Install craftsmith and scaffold a project
Source: https://docs.logisheets.com/craft/writing-a-craft.html
Install the craftsmith CLI and scaffold a new craft project. Run these commands in order from your terminal.
```bash
npm i -D logisheets-craftsmith # the CLI
npx craftsmith new my-craft # scaffold a project
cd my-craft && npm install
```
--------------------------------
### WorkbookWatcher usage with start() and get()
Source: https://docs.logisheets.com/runtime.html
Creates a WorkbookWatcher that polls './watch' every 10 seconds, logs each loaded id, and starts polling. After starting, the current workbook for 'sales-2026' can be retrieved with get().
```ts
const runtime = new SpreadsheetRuntime()
const watcher = new WorkbookWatcher(runtime, './watch', {
intervalMs: 10_000,
onLoad: (id) => console.log('loaded', id),
})
watcher.start()
// ... elsewhere, serve the current revision:
const wb = watcher.get('sales-2026')
```
--------------------------------
### Install logisheets-formula-editor
Source: https://docs.logisheets.com/engine.html
Install the companion package that provides the formula bar and in-cell editor. The engine itself does not ship these UI components.
```bash
npm install logisheets-formula-editor
```
--------------------------------
### Install logisheets-runtime with npm
Source: https://docs.logisheets.com/runtime.html
Install the logisheets-runtime package from npm to use the headless LogiSheets engine on Node.
```bash
npm install logisheets-runtime
```
--------------------------------
### Register methods with RpcServer
Source: https://docs.logisheets.com/runtime.html
Shows how to create a runtime and server, register methods that create workbooks and read cell values, and start listening on an ephemeral port. Handlers receive an RpcContext and can throw RpcError for structured errors.
```typescript
const runtime = new SpreadsheetRuntime()
const server = new RpcServer(runtime)
server
.register('newWorkbook', (_p, {runtime}) => ({id: runtime.createWorkbook().id}))
.register('getCell', (p, {runtime}) => {
const wb = runtime.workbooks.find((w) => w.id === p.id)
if (!wb) throw new RpcError(RPC_INVALID_PARAMS, `no workbook ${p.id}`)
return wb.getValue(0, p.row, p.col)
})
const addr = await server.listen(0)
// POST JSON-RPC 2.0 to http://127.0.0.1:${addr.port}
```
--------------------------------
### Craft manifest example (schemaVersion, craftId, tools)
Source: https://docs.logisheets.com/craft/writing-a-craft.html
The manifest is a generated build artifact that the host reads to discover and drive your craft. Run `craftsmith check` in CI to guarantee it matches your code. The `url`, `rtJs`, and `tools` fields are present only when you have a UI, runtime, or tools respectively.
```jsonc
{
"schemaVersion": 1,
"craftId": "my-craft",
"version": "0.1.0",
"label": "My Craft",
"url": "index.html", // present iff you have a UI
"rtJs": "runtime.js", // present iff you have a runtime
"skill": { "description": "…", "guidance": "…" },
"tools": [
{ "name": "write_cell", "description": "…",
"inputSchema": { /* from your types */ },
"paramOrder": ["row","col","text"],
"entry": "tools.js", "export": "writeCell",
"mutates": true, "confirmation": "always" }
]
}
```
--------------------------------
### WorkbookWatcher descriptor files (wb_*.json)
Source: https://docs.logisheets.com/runtime.html
Two example descriptor files for the WorkbookWatcher. Each must include an id, version, and at least one of path or url; when both are present, path wins. Relative paths resolve against the watched directory.
```json
{"id": "sales-2026", "version": 7, "path": "books/sales.xlsx"}
{"id": "sales-2026", "version": 7, "url": "https://host/books/sales.xlsx"}
```
--------------------------------
### Zoom control example using engine zoom API
Source: https://docs.logisheets.com/engine.html
Example of a zoom control in a toolbar: listens to 'zoomChange' to update a label, then calls zoomIn, setZoom(1.5), and resetZoom.
```typescript
// A zoom control in your toolbar.
engine.on('zoomChange', (z) => setLabel(`${Math.round(z * 100)}%`))
await engine.zoomIn()
await engine.setZoom(1.5)
await engine.resetZoom()
```
--------------------------------
### Install logisheets-engine and logisheets-web via npm
Source: https://docs.logisheets.com/introduction.html
Install the required packages for embedding the LogiSheets spreadsheet UI in a web page.
```bash
npm install logisheets-engine logisheets-web
```
--------------------------------
### Subscribe to engine events (selectionChange, gridChange, startEdit, contextMenu)
Source: https://docs.logisheets.com/engine.html
Shows how to subscribe to engine events using on(). The payload types are determined by the event; for example, selectionChange provides SelectedData, gridChange provides Grid | null, startEdit provides {row, col, initialText}, and contextMenu provides {context, x, y}.
```TypeScript
engine.on('selectionChange', (data) => setSelection(data))
engine.on('gridChange', (grid) => setGrid(grid))
engine.on('startEdit', ({row, col, initialText}) => openEditor(row, col, initialText))
engine.on('contextMenu', ({context, x, y}) => openMyMenu(context, x, y))
```
--------------------------------
### Quick start: create workbook, input cells, read evaluated values
Source: https://docs.logisheets.com/runtime.html
Create a runtime, create a workbook, input a value and a formula, read the evaluated result, change the input, and confirm the formula recalculates. Cells are 0-indexed as (sheetIdx, row, col): A1 = (0,0,0), B1 = (0,0,1).
```ts
import {SpreadsheetRuntime} from 'logisheets-runtime'
const runtime = new SpreadsheetRuntime()
const wb = runtime.createWorkbook()
await wb.ops.inputCell(0, 0, 0, '10') // A1 = 10 (value)
await wb.ops.inputCell(0, 0, 1, '=A1*2') // B1 = =A1*2 (formula)
wb.getValue(0, 0, 1) // → { type: 'number', value: 20 }
await wb.ops.inputCell(0, 0, 0, '21') // change A1
wb.getValue(0, 0, 1) // → { type: 'number', value: 42 } (recalculated)
runtime.closeAll()
```
--------------------------------
### Insert rows and set column width (Rust and TypeScript)
Source: https://docs.logisheets.com/usage.html
Shows how to build a payload action in Rust and the equivalent transaction object in TypeScript for inserting rows and setting column width. The Rust example uses `PayloadsAction::new()` with `add_payload` calls; the TypeScript example sets `undoable: true` and `temp: false`.
```rust
use logisheets_rs::{InsertRows, SetColWidth};
PayloadsAction::new()
.add_payload(InsertRows { sheet_idx: 0, start: 2, count: 3 })
.add_payload(SetColWidth { sheet_idx: 0, col: 0, width: 120.0 });
```
```ts
const tx = {
payloads: [
{type: 'insertRows', value: {sheetIdx: 0, start: 2, count: 3}},
{type: 'setColWidth', value: {sheetIdx: 0, col: 0, width: 120}},
],
undoable: true,
temp: false,
}
```
--------------------------------
### Initialize via UMD build without a bundler
Source: https://docs.logisheets.com/engine.html
Loads the style and UMD script from a script tag, wiring up a new engine from the LogiSheetsEngine global. Requires a container element; otherwise nothing is rendered.
```html
```
--------------------------------
### Import Engine and mount as ES module (with bundler)
Source: https://docs.logisheets.com/engine.html
Creates an Engine instance, mounts it when ready. Must be used with a bundler that resolves imports and processes the CSS import.
```typescript
import {Engine} from 'logisheets-engine'
import 'logisheets-engine/style.css'
const engine = new Engine()
engine.on('ready', () => engine.mount(document.getElementById('app')!))
```
--------------------------------
### Create cellStyleUpdate payload with StyleUpdateType
Source: https://docs.logisheets.com/usage.html
Create a cellStyleUpdate payload. The Rust example uses StyleUpdateType::default() and sets optional fields; the TypeScript example uses StyleUpdateTypeBuilder and CellStyleUpdateBuilder. The resulting payload is a cellStyleUpdate when placed in a transaction.
```rust
use logisheets_rs::{CellStyleUpdate};
// StyleUpdateType has the same optional fields as the TS shape above.
let mut ty = logisheets_rs::StyleUpdateType::default();
ty.set_font_bold = Some(true);
ty.set_font_color = Some("FFFF0000".to_string());
PayloadsAction::new()
.add_payload(CellStyleUpdate { sheet_idx: 0, row: 0, col: 0, ty });
```
```ts
import {CellStyleUpdateBuilder, StyleUpdateTypeBuilder} from 'logisheets-web'
const ty = new StyleUpdateTypeBuilder()
.setFontBold(true)
.setFontColor('FFFF0000')
.build()
const payload = new CellStyleUpdateBuilder()
.sheetIdx(0).row(0).col(0).ty(ty)
.build()
// -> { type: 'cellStyleUpdate', value: ... } when placed in a transaction
```
--------------------------------
### new Engine(config?: Partial)
Source: https://docs.logisheets.com/engine.html
Creates the engine and its own Web Worker. Worker + WASM initialization happens asynchronously; wait for the `ready` event before use.
```APIDOC
## new Engine(config?: Partial)
### Description
Creates the engine and its own Web Worker. Worker + WASM initialization happens asynchronously; wait for the `ready` event before use.
### Method
constructor
### Endpoint
new Engine(config?: Partial)
### Parameters
#### Request Body
- **config** (Partial) - Optional - Configuration object for the engine. All fields are optional; defaults come from `DEFAULT_ENGINE_CONFIG`.
### Response
#### Success Response
- **engine** (Engine) - The constructed Engine instance.
### Response Example
```ts
const engine = new Engine()
```
```
--------------------------------
### Create transaction with cellInput and cellClear payloads
Source: https://docs.logisheets.com/usage.html
Create a transaction with cellInput and cellClear payloads. The Rust example uses PayloadsAction::new().add_payload; the TypeScript example shows the transaction object with payloads, undoable, and temp fields. content is always a string, even for numbers.
```rust
use logisheets_rs::{CellInput, CellClear};
PayloadsAction::new()
.add_payload(CellInput { sheet_idx: 0, row: 0, col: 0, content: "=SUM(B1:B9)".into() })
.add_payload(CellClear { sheet_idx: 0, row: 5, col: 0 });
```
```ts
const tx = {
payloads: [
{type: 'cellInput', value: {sheetIdx: 0, row: 0, col: 0, content: '=SUM(B1:B9)'}},
{type: 'cellClear', value: {sheetIdx: 0, row: 5, col: 0}},
],
undoable: true,
temp: false,
}
```
--------------------------------
### Svelte integration with logisheets-engine
Source: https://docs.logisheets.com/engine.html
Svelte component that mounts the engine on mount and destroys it on unmount. Uses bind:this to get the host element and creates the engine once in the script.
```svelte
```
--------------------------------
### Vue 3 integration with logisheets-engine
Source: https://docs.logisheets.com/engine.html
Vue 3 component that mounts the engine on mount and destroys it on unmount. Uses a template ref for the host element and creates the engine once in the setup scope.
```vue
```
--------------------------------
### isReady(): boolean
Source: https://docs.logisheets.com/engine.html
Returns whether the worker + WASM finished initializing.
```APIDOC
## isReady(): boolean
### Description
Returns whether the worker + WASM finished initializing.
### Method
isReady
### Endpoint
isReady(): boolean
### Parameters
None
### Response
#### Success Response
- **boolean** (boolean) - `true` if the worker + WASM finished initializing, `false` otherwise.
### Response Example
```ts
const ready = engine.isReady()
```
```
--------------------------------
### Inspecting sheets (Rust and TypeScript)
Source: https://docs.logisheets.com/usage.html
Inspect workbook sheets: get the sheet count, all sheet info, a sheet name by index, and retrieve a worksheet by index or by name (Rust) or by stable id (TypeScript).
```rust
let count = wb.get_sheet_count();
let info = wb.get_all_sheet_info(); // Vec { id, idx, name, ... }
let name = wb.get_sheet_name_by_idx(0)?;
let ws = wb.get_sheet_by_idx(0)?; // by index
let ws = wb.get_sheet_by_name("Sheet1")?; // by name
```
```typescript
const count = wb.getSheetCount()
const info = wb.getAllSheetInfo() // SheetInfo[] { id, idx, name, ... }
const name = wb.getSheetNameByIdx(0)
const ws = wb.getWorksheet(0) // by index
const ws = wb.getWorksheetById(sheetId) // by stable id
```
--------------------------------
### Creating or loading a workbook (Rust and TypeScript)
Source: https://docs.logisheets.com/usage.html
Create an empty workbook or load one from .xlsx bytes. In Rust, use Workbook::new() or Workbook::from_file(&bytes, "example.xlsx"). In TypeScript, construction is synchronous because WASM is bundled; use wb.load(new Uint8Array(bytes), 'example.xlsx') after fetching the file.
```rust
use logisheets_rs::Workbook;
// Empty workbook (starts with one sheet)
let mut wb = Workbook::new();
// Or load from .xlsx bytes
let bytes = std::fs::read("example.xlsx")?;
let mut wb = Workbook::from_file(&bytes, "example.xlsx".to_string())?;
```
```typescript
import {Workbook} from 'logisheets-web' // or 'logisheets' in Node
// Empty workbook — WASM is bundled, so construction is synchronous
const wb = new Workbook()
// Or load from .xlsx bytes (Uint8Array)
const bytes = await fetch('/example.xlsx').then(r => r.arrayBuffer())
wb.load(new Uint8Array(bytes), 'example.xlsx')
```
--------------------------------
### package.json identity fields
Source: https://docs.logisheets.com/craft/writing-a-craft.html
The three identity fields in `package.json` that the host needs. `craftId` is stable and kebab-case; `label` is the human name; `version` is the package version. When published, the host installs by `craftId` and reads the generated `manifest.json`.
```json
{
"craftId": "my-craft", // stable, kebab-case — the id the host installs under
"label": "My Craft", // human name shown in the craft picker
"version": "0.1.0"
}
```
--------------------------------
### Create block with description and per-operation permissions
Source: https://docs.logisheets.com/craft/writing-a-craft.html
Creates a block with a description and per-operation permissions. The description is saved and reported by getBlockInfo, so write it for a stranger. Set owner to 'my-craft' (required for any policy to bite) and use modifyPolicy as the fallback; operations left out follow modifyPolicy. The operations are insertDeleteLines, removeBlock, modifySchema, cellInput, sortByField, modifyDescription, and overrideValidation, each taking all, ownerAndUser, or ownerOnly.
```ts
await ctx.workbook.handleTransaction({
transaction: {
payloads: [
{
type: 'createBlock',
value: {
sheetIdx, id: blockId,
masterRow: 0, masterCol: 0, rowCnt: 8, colCnt: 3,
owner: 'my-craft', // required for any policy to bite
description:
'One row per run. `score` is computed by my-craft; ' +
'edit `input`, never `score`.',
modifyPolicy: 'ownerAndUser', // the fallback
permissions: {
cellInput: 'all', // let anyone type
insertDeleteLines: 'ownerOnly',
removeBlock: 'ownerOnly',
modifySchema: 'ownerOnly',
// sortByField left out → follows modifyPolicy
},
},
},
],
undoable: true, temp: false,
},
})
```
--------------------------------
### Insert rows via context menu transaction
Source: https://docs.logisheets.com/engine.html
Branches on context.target to build different menus and runs the chosen action as a transaction. Uses getSelectedLines to compute the start row and calls engine.getDataService().handleTransaction with an insertRows payload, marking it undoable.
```typescript
async function insertRows(context, count) {
const lines = getSelectedLines(context.selectedData) // {start, end, type}
const start = lines ? Math.min(lines.start, lines.end) : (context.row ?? 0)
await engine.getDataService().handleTransaction({
payloads: [{type: 'insertRows', value: {sheetIdx: engine.getCurrentSheetIndex(), start, count}}],
undoable: true,
temp: false,
})
}
```
--------------------------------
### runtime.createWorkbook()
Source: https://docs.logisheets.com/runtime.html
Creates a new, empty workbook in the runtime.
```APIDOC
## [SDK] runtime.createWorkbook()
### Description
Creates a new, empty workbook in the runtime.
### Method
createWorkbook
### Signature
`(): Workbook`
### Parameters
None
### Returns
A new Workbook instance.
### Example
```ts
const wb = runtime.createWorkbook()
```
```
--------------------------------
### Project structure after scaffolding
Source: https://docs.logisheets.com/craft/writing-a-craft.html
Shows the project structure created by `craftsmith new`. The `tools.ts` file is the core logic; `index.html` is optional; `runtime.ts` is not scaffolded and must be added manually for the runtime face.
```text
my-craft/
├── package.json # identity: craftId, label, version (+ check/build scripts)
├── tools.ts # YOUR LOGIC — pure functions (the core)
├── index.html # a browser UI (optional)
└── tsconfig.json
```
--------------------------------
### loadFile
Source: https://docs.logisheets.com/engine.html
Loads a `.xlsx` file into the engine and refreshes the mounted grid.
```APIDOC
## loadFile
### Description
Load `.xlsx` bytes and refresh the mounted grid. Prefer this over `DataService.loadWorkbook` when the UI is mounted — it also updates the Svelte component's dimensions/anchors.
### Method
loadFile
### Endpoint
`loadFile(buffer: Uint8Array, filename: string): Promise`
### Parameters
- **buffer** (Uint8Array) - Required - The `.xlsx` file bytes.
- **filename** (string) - Required - The name of the file being loaded.
### Request Example
```ts
const buf = await fetch('workbook.xlsx').then((r) => r.arrayBuffer())
const grid = await engine.loadFile(new Uint8Array(buf), 'workbook.xlsx')
```
### Response
#### Success Response
- **Grid | null** - The loaded grid, or `null` if loading failed.
#### Response Example
```ts
const grid = await engine.loadFile(new Uint8Array(buf), 'workbook.xlsx')
```
```
--------------------------------
### Import Engine and required CSS
Source: https://docs.logisheets.com/engine.html
Import the Engine class and the required style.css to ship the grid styles. The CSS import is mandatory.
```ts
import {Engine} from 'logisheets-engine'
import 'logisheets-engine/style.css' // required — ships the grid styles
```
--------------------------------
### mount(container: HTMLElement, options?: EngineMountOptions): void
Source: https://docs.logisheets.com/engine.html
Mounts the grid UI into the given container on the default session. Options are all optional.
```APIDOC
## mount(container: HTMLElement, options?: EngineMountOptions): void
### Description
Mounts the grid UI into the given container on the default session. Options are all optional.
### Method
mount
### Endpoint
mount(container: HTMLElement, options?: EngineMountOptions): void
### Parameters
#### Path Parameters
- **container** (HTMLElement) - Required - The DOM element to mount the grid UI into.
#### Request Body
- **options** (EngineMountOptions) - Optional - Mount options. All fields optional.
- **showSheetTabs** (boolean) - Optional - Render the sheet-tab bar at the bottom. Set `false` if you provide your own tabs.
- **showScrollbars** (boolean) - Optional - Render scrollbars.
- **cellLayouts** (CellLayout[]) - Optional - Per-cell visual overrides (background, tooltip). See CellLayout.
- **getIsEditingFormula** (() => boolean) - Optional - Return `true` while the user is editing a formula in your own input, so the canvas doesn't steal focus.
- **onInvalidFormula** (() => void) - Optional - Called when the user commits an invalid formula.
### Request Example
```ts
engine.mount(container, {
showSheetTabs: false, // app renders its own tabs
showScrollbars: true,
cellLayouts,
getIsEditingFormula: () => isEditingFormulaRef.current(),
})
```
### Response
#### Success Response
- **void** - No return value.
### Response Example
```ts
engine.mount(document.getElementById('spreadsheet')!)
```
```
--------------------------------
### Import SpreadsheetRuntime and RpcServer from logisheets-runtime
Source: https://docs.logisheets.com/runtime.html
Import the SpreadsheetRuntime and RpcServer classes from the logisheets-runtime package to create and host workbooks.
```ts
import {SpreadsheetRuntime, RpcServer} from 'logisheets-runtime'
```
--------------------------------
### initOffscreen(canvas: HTMLCanvasElement): Promise
Source: https://docs.logisheets.com/engine.html
Headless rendering into your own canvas, without mounting the interactive UI. Advanced; only needed for custom render pipelines.
```APIDOC
## initOffscreen(canvas: HTMLCanvasElement): Promise
### Description
Headless rendering into your own canvas, without mounting the interactive UI. Advanced; only needed for custom render pipelines.
### Method
initOffscreen
### Endpoint
initOffscreen(canvas: HTMLCanvasElement): Promise
### Parameters
#### Path Parameters
- **canvas** (HTMLCanvasElement) - Required - The canvas element to render into.
### Response
#### Success Response
- **Promise** (Promise) - Resolves when offscreen rendering is initialized.
### Response Example
```ts
await engine.initOffscreen(canvas)
```
```
--------------------------------
### craftsmith CLI: check, build, pack
Source: https://docs.logisheets.com/craft/writing-a-craft.html
Commands to check, build, and pack a craft. `check` validates the tool contract and purity without writing; `build` compiles tools.ts/runtime.ts into dist/ and manifest.json; `pack` tars dist/ into a shippable -.tgz.
```bash
npx craftsmith check . # validate the tool contract + purity — no writes
npx craftsmith build . # compile tools.ts/runtime.ts → dist/ + manifest.json
npx craftsmith pack . # tar dist/ into a shippable -.tgz
```
--------------------------------
### mountWhenReady helper for logisheets-engine
Source: https://docs.logisheets.com/engine.html
Helper that mounts the engine once it is ready, handling the case where the engine is already ready (since 'ready' won't fire again). Use it in any framework to encapsulate the mount-on-ready logic.
```ts
import type {Engine} from 'logisheets-engine'
export function mountWhenReady(engine: Engine, el: HTMLElement) {
const run = () => engine.mount(el, {showSheetTabs: true, showScrollbars: true})
engine.isReady() ? run() : engine.on('ready', run)
}
```
--------------------------------
### Engine initialization and ready event
Source: https://docs.logisheets.com/engine.html
Constructs an Engine and waits for the 'ready' event before mounting into a DOM element. The engine creates its own Web Worker; worker and WASM initialization are asynchronous.
```TypeScript
const engine = new Engine(/* config? */)
engine.on('ready', () => {
engine.mount(document.getElementById('spreadsheet')!)
})
```
--------------------------------
### Create formula bar with createFormulaEditor and createEngineFormulaSource
Source: https://docs.logisheets.com/engine.html
Wire a vanilla formula bar to the engine using createEngineFormulaSource and createFormulaEditor. The onSubmit handler commits a cellInput transaction, and the selectionChange listener keeps the bar in sync with the selected cell.
```ts
import {createFormulaEditor} from 'logisheets-formula-editor/core'
import {createEngineFormulaSource} from 'logisheets-formula-editor/engine'
const source = createEngineFormulaSource(engine.getDataService())
const bar = createFormulaEditor(document.getElementById('formula-bar')!, {
...source,
onSubmit: (value) => {
const sel = engine.getSelection()
if (sel.data?.ty !== 'cellRange') return
const {startRow, startCol} = sel.data.d
// commit — see "Editing data" above
engine.getWorkbook().handleTransaction({
transaction: {
payloads: [{type: 'cellInput', value: {sheetIdx: engine.getCurrentSheetIndex(), row: startRow, col: startCol, content: value}}],
undoable: true,
temp: false,
},
temp: false,
})
},
})
// keep the bar showing the selected cell
engine.on('selectionChange', async (sel) => {
if (sel.data?.ty !== 'cellRange') return
const {startRow, startCol} = sel.data.d
const cell = await engine.getDataService().getCellInfo(engine.getCurrentSheetIndex(), startRow, startCol)
if (!isErrorMessage(cell)) bar.setValue(cell.getFormula() ? `=${cell.getFormula()}` : cell.getText())
})
```
--------------------------------
### runtime.loadWorkbookFromBytes(content, name, path?)
Source: https://docs.logisheets.com/runtime.html
Loads a workbook from .xlsx bytes already in memory.
```APIDOC
## [SDK] runtime.loadWorkbookFromBytes(content, name, path?)
### Description
Loads a workbook from .xlsx bytes already in memory.
### Method
loadWorkbookFromBytes
### Signature
`(content: Uint8Array, name: string, path?: string): Workbook`
### Parameters
- **content** (Uint8Array) - Required - The .xlsx file bytes.
- **name** (string) - Required - The name of the workbook.
- **path** (string) - Optional - The file path associated with the workbook.
### Returns
A Workbook instance.
### Example
```ts
const bytes = new Uint8Array(...)
const wb = runtime.loadWorkbookFromBytes(bytes, 'book.xlsx')
```
```
--------------------------------
### Create multiple sessions for split views
Source: https://docs.logisheets.com/engine.html
Creates two sessions on the same engine to display the same workbook in multiple views. Loads the file once, mounts each session to its own container, sets an independent active sheet, listens for selection changes, and destroys the second session when its window closes.
```typescript
const engine = new Engine()
engine.on('ready', async () => {
await engine.loadFile(bytes, 'book.xlsx') // load once, on the engine
// First view.
const main = engine.createSession()
main.mount(document.getElementById('view-main')!)
// Second view of the SAME workbook — edits sync both ways.
const second = engine.createSession()
second.mount(document.getElementById('view-second')!)
second.setCurrentSheetIndex(1) // independent active sheet
second.on('selectionChange', (sel) => console.log('view 2', sel))
// When the second window closes:
second.destroy() // unmounts and frees its canvas in the worker
})
```
--------------------------------
### Create in-cell editor with createInlineCellEditor
Source: https://docs.logisheets.com/engine.html
Create an in-cell editor controller that listens for the engine's startEdit event, positions an editor over the target cell, commits edits, and paints reference highlights. Keep it in sync with gridChange events.
```ts
import {createInlineCellEditor} from 'logisheets-formula-editor/inline'
const inline = createInlineCellEditor({
container: gridEl, // the same element you mounted the engine into
eventSource: engine, // the Engine (or a Session) emitting startEdit
dataService: engine.getDataService(),
sheetIdx: engine.getCurrentSheetIndex(),
getSheetName: () => engine.getSheets()[engine.getCurrentSheetIndex()]?.name ?? '',
inputCell: (sheetIdx, row, col, text) => engine.getWorkbook().handleTransaction({
transaction: {payloads: [{type: 'cellInput', value: {sheetIdx, row, col, content: text}}], undoable: true, temp: false},
temp: false,
}),
setSelection: (sel) => engine.setSelection(sel),
grid: engine.getGrid(),
})
engine.on('gridChange', (g) => inline.setGrid(g))
```
--------------------------------
### runtime.loadWorkbook(path)
Source: https://docs.logisheets.com/runtime.html
Loads a .xlsx workbook from disk. Loading the same path twice returns the already-open workbook until it is closed.
```APIDOC
## [SDK] runtime.loadWorkbook(path)
### Description
Loads a .xlsx workbook from disk. Loading the same path twice returns the already-open workbook until it is closed.
### Method
loadWorkbook
### Signature
`(path: string): Promise`
### Parameters
- **path** (string) - Required - The file path to the .xlsx file.
### Returns
A Promise that resolves to a Workbook instance.
### Example
```ts
const wb = await runtime.loadWorkbook('./book.xlsx')
```
```
--------------------------------
### initOffscreen
Source: https://docs.logisheets.com/engine.html
Binds an offscreen canvas for rendering.
```APIDOC
## [POST] /dataService/initOffscreen
### Description
Binds an offscreen canvas for rendering.
### Method
POST
### Endpoint
/dataService/initOffscreen
### Parameters
#### Request Body
- **canvas** (OffscreenCanvas) - Required - The offscreen canvas to bind.
### Request Example
```json
{
"canvas": {}
}
```
### Response
#### Success Response (200)
- **void** - No content on success.
#### Error Response
- **ErrorMessage** - An error message if binding fails.
### Response Example
```json
{}
```
```