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:
blitsen doctor distErrors 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:
blitsen doctor dist --json
blitsen doctor dist --target win32-x64Supported areas#
This is a practical summary. The generated compatibility matrix lists individual globals, classes and members.
| Area | Current support |
|---|---|
| DOM | Documents, elements, text, fragments, templates, attributes, selectors, mutation observers and common traversal/mutation APIs |
| Events | Event 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 modes | Pointer-lock methods on every platform and root-element fullscreen on desktop, with standard promises, state properties and change/error events; unsupported platforms reject |
| Forms | Basic input, textarea, select, option, button and form state; keyboard editing and selection |
| Layout reads | Bounding rectangles, client/offset geometry, computed style, scrolling, ranges, carets and selection |
| Scheduling | requestAnimationFrame, timeouts and intervals |
| Networking | Buffered fetch, request/response/headers/blob, abort signals, WebSocket and EventSource |
| Workers | Dedicated workers, message channels, structured clone and transferable buffers |
| Routing | location, history, hash changes and popstate within the application; document navigation is absent |
| Styling | Stylesheets, rule source, media queries, CSS support checks and resize observers |
| Audio | <audio> and a focused Web Audio subset |
| Storage | synchronous durable localStorage and realm-scoped sessionStorage |
| Canvas | <canvas> with a broad 2D context: paths, text, images, gradients, patterns, compositing, getImageData and toDataURL |
| Gamepads | Per-frame navigator.getGamepads() snapshots and connection events on Linux, macOS and Windows, with standard mapping and dual-rumble where the device reports it |
| Notifications | Standard Notification construction, permission, close, and lifecycle events on Linux, Windows, eligible packaged macOS apps; see platform limits below |
Important absences#
| Feature | What to use or expect |
|---|---|
| WebGL and WebGPU | Not implemented; getContext("webgl") answers null. Use the 2D context, or <blitsen-view> for GPU output |
Canvas shadows and ctx.filter | Absent, so a feature test selects a fallback; both need a blur the renderer has none of |
| Advanced canvas text controls | letterSpacing, wordSpacing, fontKerning, fontStretch, fontVariantCaps and textRendering are absent |
OffscreenCanvas and ImageBitmap | Absent; a <canvas> that is never in the document draws, reads back and encodes |
| WebAssembly | Provided by Bun |
| XHR | Use fetch |
| Streams | Responses are buffered; streaming body APIs are absent |
| FileReader | Absent; Bun supplies File, FormData and streaming bodies |
| Form reset and constraint validation | HTMLFormElement.reset() and submit(), reset controls, validity, checkValidity, labels and file inputs are absent; submit with requestSubmit() and validate in application code |
DataTransfer.files and .items | Absent; a drop reports absolute filesystem paths in dataTransfer.paths |
| Starting a drag | draggable, dragstart, dragend and dragging out to the desktop are absent; dropping into the window works |
| IndexedDB | Absent; use application-owned durable storage |
| Object URLs and browser caches | URL.createObjectURL, URL.revokeObjectURL, caches and cookieStore are absent |
| Broadcast and observer APIs | BroadcastChannel, IntersectionObserver, PerformanceObserver and idle callbacks are absent; ResizeObserver is supported |
| SharedWorker and ServiceWorker | Absent; dedicated Worker is supported |
| Browser modal dialogs | alert, confirm, prompt and print are absent; use blitsen/dialog where available |
| Cookies | No cookie jar; document.cookie is absent |
| Custom elements and shadow DOM | Absent; DOMParser is supported |
| Constructible stylesheets | adoptedStyleSheets, CSSStyleSheet.replace()/replaceSync() and mutable rule/style objects are absent; linked and inline stylesheets are supported |
| Document navigation | Hash 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 tracks | Absent; audio is supported |
| Accessibility tree | Deliberately 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 layer | document.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:
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:
if ("Notification" in globalThis) {
new Notification("Finished");
}The same rule applies to optional native members:
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.