Blitsen

Documentation Web API support

Web API support#

Blitsen implements the browser APIs needed by its supported application profile, not a complete browser. Build-time checks and runtime feature detection are both part of using it safely.

Check an application#

Run doctor against built output:

sh
blitsen doctor dist

Errors block export because the scanner found either a server-root fetch whose resource is not shipped or an untranspiled source entry. Web-API absences and narrower behavior are warnings: they may be guarded by a fallback—or may fail when the path executes. Review every warning and test the result in Blitsen.

For a machine-readable report or a different target:

sh
blitsen doctor dist --json
blitsen doctor dist --target win32-x64

Supported areas#

This is a practical summary. The generated compatibility matrix lists individual globals, classes and members.

AreaCurrent support
DOMDocuments, elements, text, fragments, templates, attributes, selectors, mutation observers and common traversal/mutation APIs
EventsEvent targets, custom, mouse, keyboard, focus, input, pointer, wheel, error, submit, clipboard and drag events; pointer lock with relative mouse movement where the platform accepts it
Window modesPointer-lock methods on every platform and root-element fullscreen on desktop, with standard promises, state properties and change/error events; unsupported platforms reject
FormsBasic input, textarea, select, option, button and form state; keyboard editing and selection
Layout readsBounding rectangles, client/offset geometry, computed style, scrolling, ranges, carets and selection
SchedulingrequestAnimationFrame, timeouts and intervals
NetworkingBuffered fetch, request/response/headers/blob, abort signals, WebSocket and EventSource
WorkersDedicated workers, message channels, structured clone and transferable buffers
Routinglocation, history, hash changes and popstate within the application; document navigation is absent
StylingStylesheets, rule source, media queries, CSS support checks and resize observers
Audio<audio> and a focused Web Audio subset
Storagesynchronous durable localStorage and realm-scoped sessionStorage
Canvas<canvas> with a broad 2D context: paths, text, images, gradients, patterns, compositing, getImageData and toDataURL
GamepadsPer-frame navigator.getGamepads() snapshots and connection events on Linux, macOS and Windows, with standard mapping and dual-rumble where the device reports it
NotificationsStandard Notification construction, permission, close, and lifecycle events on Linux, Windows, eligible packaged macOS apps; see platform limits below

Important absences#

FeatureWhat to use or expect
WebGL and WebGPUNot implemented; getContext("webgl") answers null. Use the 2D context, or <blitsen-view> for GPU output
Canvas shadows and ctx.filterAbsent, so a feature test selects a fallback; both need a blur the renderer has none of
Advanced canvas text controlsletterSpacing, wordSpacing, fontKerning, fontStretch, fontVariantCaps and textRendering are absent
OffscreenCanvas and ImageBitmapAbsent; a <canvas> that is never in the document draws, reads back and encodes
WebAssemblyProvided by Bun
XHRUse fetch
StreamsResponses are buffered; streaming body APIs are absent
FileReaderAbsent; Bun supplies File, FormData and streaming bodies
Form reset and constraint validationHTMLFormElement.reset() and submit(), reset controls, validity, checkValidity, labels and file inputs are absent; submit with requestSubmit() and validate in application code
DataTransfer.files and .itemsAbsent; a drop reports absolute filesystem paths in dataTransfer.paths
Starting a dragdraggable, dragstart, dragend and dragging out to the desktop are absent; dropping into the window works
IndexedDBAbsent; use application-owned durable storage
Object URLs and browser cachesURL.createObjectURL, URL.revokeObjectURL, caches and cookieStore are absent
Broadcast and observer APIsBroadcastChannel, IntersectionObserver, PerformanceObserver and idle callbacks are absent; ResizeObserver is supported
SharedWorker and ServiceWorkerAbsent; dedicated Worker is supported
Browser modal dialogsalert, confirm, prompt and print are absent; use blitsen/dialog where available
CookiesNo cookie jar; document.cookie is absent
Custom elements and shadow DOMAbsent; DOMParser is supported
Constructible stylesheetsadoptedStyleSheets, CSSStyleSheet.replace()/replaceSync() and mutable rule/style objects are absent; linked and inline stylesheets are supported
Document navigationHash changes work; assigning location.href, pathname or search throws NotSupportedError. location.assign, replace and reload, window.open/close, and document.write are absent
Video and text tracksAbsent; audio is supported
Accessibility treeDeliberately not exported: screen readers receive no roles, names, focus state or live regions; DOM keyboard focus remains separate and supported
Full IME and complex text editing<input>/<textarea> preedit, commit and bounded undo/redo are implemented; contenteditable, surrounding-text deletion and native CJK/RTL workflows remain unverified
Fullscreen top layerdocument.documentElement.requestFullscreen() is supported on desktop. Arbitrary-element fullscreen is rejected because Blitsen does not yet promote a subtree into a Fullscreen top layer

Dropped files are paths#

A file dragged in from the desktop arrives as the standard dragenter/dragover/dragleave/drop sequence, and — as in a browser — the drop is only dispatched where the preceding dragover was cancelled. What it carries is not:

js
zone.addEventListener("dragover", event => event.preventDefault());
zone.addEventListener("drop", event => {
  event.preventDefault();
  for (const path of event.dataTransfer.paths) console.log(path);
});

dataTransfer.paths is a frozen array of absolute filesystem paths, which your filesystem library opens directly — there is no File to read back asynchronously, and dataTransfer.files and .items are absent rather than empty. types still contains "Files", and getData("text/uri-list") returns the same files as file: URLs, so the code that decides whether to accept a drop does not change.

copy, cut and paste are dispatched with a clipboardData DataTransfer when Ctrl/Cmd is held with C, X or V, over the same platform clipboard blitsen/clipboard uses. Cancel a copy or a cut to replace what is written; cancel a paste to insert it yourself.

Feature detection#

Missing APIs are absent rather than installed as no-op stubs:

js
if ("Notification" in globalThis) {
  new Notification("Finished");
}

The same rule applies to optional native members:

js
import dialog from "blitsen/dialog";

if (dialog.openFile) {
  const path = await dialog.openFile();
}

Do not infer support from TypeScript's browser library. A package can add Blitsen declarations but cannot remove unsupported names from lib.dom.d.ts; doctor checks the built application instead.

Pointer lock and fullscreen#

Element.requestPointerLock() is installed on every platform; root-element fullscreen is available on every desktop. Both it and document.documentElement.requestFullscreen() require a native pointer or keyboard activation. They return promises, update document.pointerLockElement or document.fullscreenElement, and raise the corresponding pointerlockchange/pointerlockerror or fullscreenchange/fullscreenerror events. Losing window focus, losing the render surface, or suspending the application, pressing Escape, or disconnecting the target releases the affected mode. While locked, absolute cursor hit testing stops and winit device deltas arrive as mousemove.movementX/movementY on the locked element. The unadjustedMovement: true option is rejected with NotSupportedError: winit exposes relative device deltas, but does not provide the cross-platform acceleration-control guarantee that option promises.

The standard fullscreen path is always borderless fullscreen on the monitor containing the window at request time, falling back to the primary monitor when the platform cannot identify a current one. It never selects exclusive fullscreen: the Web API provides no video-mode, resolution, or refresh-rate selector, so choosing an exclusive mode would be arbitrary and could reconfigure the display. Use the native window API for application-controlled window state, but it also intentionally exposes borderless rather than exclusive fullscreen.

Linux rejects pointer-lock requests with NotSupportedError and dispatch pointerlockerror; the method's presence is therefore not a platform-support test. Pinned winit cannot provide Locked cursor grab on X11. Physical multi-monitor placement and compositor-specific grab behavior still need acceptance on the supported backends; a refused cursor grab rejects rather than pretending the lock succeeded. DOM modes temporarily override blitsen/window fullscreen, cursor visibility and cursor-grab settings; changes made through the native API while a DOM mode is active become the state restored when that DOM mode exits or a document reloads.

Gamepads#

Linux, macOS and Windows install the standard navigator.getGamepads() surface. It returns a frozen array whose indices are stable while devices connect and disconnect; a disconnected slot is null, and a device that returns reuses its old slot when that slot is still free. Two controllers with the same public id remain distinct because the native backend identity, not the label, owns the slot. gamepadconnected and gamepaddisconnected are delivered in backend order at the top of the next application frame. Applications that need hot-plug while otherwise idle should keep a requestAnimationFrame loop active; Blitsen starts no controller-only polling loop.

Known mappings expose the standard four axes and seventeen buttons. Axes are clamped to [-1, 1], button values to [0, 1], and the backend's default dead-zone and jitter filters apply. A device whose layout cannot be mapped honestly has mapping === "" and empty axes/buttons rather than a guessed ordering. timestamp changes only when that slot's state or connection changes.

vibrationActuator is a dual-rumble actuator only when the backend reports force-feedback support; otherwise it is null. playEffect() supports only "dual-rumble", with magnitudes in [0, 1] and a duration/start delay of at most 60 seconds. Motor availability and strength remain device and driver properties. Delay and duration are quantized by the backend's 50 ms force- feedback clock; the returned promise settles from its completion event, and a replacement settles the preceding effect as "preempted".

Notifications#

The standard Notification global and blitsen/notify share one backend, identifier registry, and frame-turn event queue. The constructor maps body, icon, actions, and requireInteraction; data, dir, lang, and timestamp remain readable on the object. Tag replacement, image/badge, vibration, renotify, silent delivery, and per-action icons throw NotSupportedError instead of being silently accepted.

The global exists on Linux, on Windows, in macOS application bundles with the identity required by UNUserNotificationCenter. It is absent in an unbundled macOS development host. Windows reports the notifier's own setting, so Notification.permission is "granted" or "denied" there and requestPermission() reads rather than prompts. Test "Notification" in globalThis; use blitsen/notify when the richer native event/action identity is required.

Cold-start activation is blitsen/notify only. A click on a notification whose process has exited is delivered as an activation event on notify.onEvent (Native APIs); it cannot become a click on a Notification object, because the object it would belong to was created by a session that has ended.

Internationalisation#

Bun supplies full Intl, including range/parts formatting, Segmenter, DisplayNames and DurationFormat. Blitsen uses the same implementation in documents and workers.

Renderer differences#

HTML and CSS are rendered by Blitz rather than a browser engine. Some valid browser styles render differently or are ignored. Current high-impact areas include transitions, fixed/sticky positioning, paint effects, form-control styling, host-dependent font metrics, colour emoji and complex text input. Static complex text uses Parley/HarfRust shaping; ship @font-face files when coverage and metrics must be portable.

SVG paints — inline <svg>, <img src="icon.svg"> and CSS background-image, as vectors rather than as rasterised images. Focused tests cover basic shapes and paths, sizing, viewBox, currentColor, subtree mutation, subresources and <text>; a <pattern> fill fails and leaves a red mark in the frame's corner. Blitz/usvg accepts further features such as gradients, dashed strokes, opacity and clipping, but they do not yet have individual compatibility oracles. doctor warns on the unsupported constructs it can recognize rather than every <svg>. SVG <text> resolves fonts through a different database from HTML text and can silently find none — see COMPATIBILITY.md before putting chart labels inside an <svg>.

Doctor reports patterns it can recognize, but it cannot prove visual equivalence. Keep screenshot or interaction tests for important layouts and verify them on each target operating system.

Local and remote resources#

An export has no web server. Local HTML, CSS, modules and assets are loaded from the application bundle. Remote fetch and WebSocket are supported; remote script/module loading and remote subresources are deliberately narrower or refused. Prefer a self-contained application and use relative local URLs.

Security model#

A Blitsen application is trusted native software. There is no same-origin policy, browser sandbox, permission prompt or safe boundary for untrusted third-party pages. Validate remote data as you would in any native application and never use the runtime as a general web-content viewer.