Engine Status
The remaining gaps in Brewser's from scratch HTML, CSS and DOM engine
There is no browser to borrow from on the Switch. Brewser's DOM tree, CSS cascade, and layout engine are reimplemented from scratch in TypeScript (~26K lines) running on top of the nx.js/V8 + Skia foundation (see Architecture). Overall, that from scratch engine (DOM, HTML, CSS) covers roughly 83% of the "real-world app" surface.
This page is the honest list of what's not done yet — the gap lists double as the contribution roadmap. The last two pillars, WebGL and Audio & Video, are bridge-backed rather than reimplemented, so they stand higher and their detail lives on their own pages. If an app or library breaks for you, file an issue with its name — real-world breakage reports directly shape what gets built next.
DOM (~84%)
childrenstill includes text / comment nodes (spec is elements-only); the element-only accessors (firstElementChild/nextElementSibling/childElementCount…) are the correct-behaving alternativeouterHTMLhas no setter; document / window-level capture listeners aren't wireddialog.showModal()has no focus trap or Esc-to-close;setPointerCapturedoesn't reroute events
HTML (~80%)
- No spec tokenizer / insertion modes: no
<template>content model, no implicit<html>/<head>/<body>synthesis, comments and doctype are discarded (the parser is otherwise a tolerant tag-soup subset with error recovery) - No
multipart/form-datarequest bodies (binary file upload); urlencoded GET + POST work. No<datalist>chrome - Inline SVG has no SMIL animation and only a filter subset (
feGaussianBlur/feColorMatrix/feOffset/feDropShadow); filter-graph primitives (feComposite/feMerge/feTurbulence/feImage),gradientTransform/patternTransform, andspreadMethodreflect/repeat aren't modelled (<use>/<image>/ patterns / markers / masks, shapes / paths /<text>/ gradients /transform/viewBoxare covered) <video>has no subtitle (<track>) tracks;posterisn't loaded (a first-frame preview stands in)iframesandbox/ CSP attributes are parsed but not enforced (treated as same-origin)
CSS (~84%)
- Cascade: no
@supports/@import/@layer/@container;::placeholder/::marker/::selectionpseudo-elements unsupported - Layout: vertical margin collapsing is contained — adjacent siblings, and a parent with its first / last in-flow block child through an open edge, collapse correctly (empty blocks self-collapse too), but a collapsed child margin never propagates out to become the parent's own outer margin, and clearance isn't modelled; grid has no
grid-auto-flow: densepacking, named grid lines, or subgrid; tables supportborder-collapse: collapse(shared borders, pixel-exact for uniform widths — full width/style conflict resolution andborder-spacingfor the separate model are approximated / not modelled) but no nested-table promotion;position: stickyis vertical + page-level only (not inside nested scroll containers) - Visual:
transformcovers 2D (translate / rotate / scale),skew/matrix(), and 3D functions flattened to 2D (rotateX/rotateYforeshorten bycos θ,translate3d/scale3duse x,y,matrix3duses its affine slice) — but no true 3D perspective / z-sorting (Canvas2D can't project), andtransform-originis fixed at the box centre.transitiondoesn't cover geometric properties (width / height / offsets) ortransform: translate(those need per-frame relayout), and doesn't interpolate skew / matrix. CSS@keyframesanimation interpolates translate (px + %), rotate / scale, opacity and colours (background / text), withanimation-delay,animation-direction(normal / reverse / alternate) and timing functions — but not geometric box properties,animation-fill-mode, or comma-separated multi-animation lists. Noclip-path. On rounded boxes the 3D border styles (groove / ridge / inset / outset) render as a solid stroke;backdrop-filteron moving (fixed/sticky) elements applies blur only (colour functions are skipped there to hold 60fps) and its backdrop excludes lower fixed / modal / scroll-container layers
WebGL 1 & 2 (~88%)
Bridge-backed, running straight on the Switch's Tegra X1 GPU — not a software reimplementation. WebGL 1 sits ~92% (the safest target), WebGL 2 ~85% and under active conformance hardening. Remaining gaps are exhaustive extension coverage and layered / 3D-texture sampling (GPU-driver-limited). Full extension lists and proof points: Graphics.
Audio & Video (~80%)
Bridge-backed: Web Audio on a hardware-backed graph (~70%), <audio> /
<video> decode in software via FFmpeg (~85%). Remaining gaps are the Web Audio
effect nodes (filter / convolver / delay / compressor), subtitle tracks, and
hardware video decode. Full node list and codec matrix:
Audio & Media.
Summary
| Area | Complete | Biggest missing pieces |
|---|---|---|
| DOM | ~84% | children elements-only, outerHTML setter, document/window capture listeners, dialog focus trap |
| HTML | ~80% | spec parser (insertion modes / <template>), multipart form uploads, advanced SVG (SMIL animation / filter-graph primitives), iframe sandbox enforcement |
| CSS | ~84% | 3D-perspective transforms + transform-origin, geometric transitions / keyframes, clip-path, @supports / @layer |
| WebGL 1 | ~92% | exhaustive extension coverage |
| WebGL 2 | ~85% | layered / 3D-texture sampling (GPU-driver-limited), full conformance hardening |
| Audio & Video | ~80% | Web Audio effect nodes (filter / convolver / delay / compressor), subtitle tracks, hardware video decode |
Related
- Web Platform Support: the JavaScript APIs and standards Brewser implements
- Graphics: Canvas 2D and WebGL, which sit beside this engine
- Audio & Media: the Web Audio graph, media elements and codec matrix in full
- Known Limitations: the shorter list of the biggest current gaps
- Roadmap: where the gaps above are headed next
Last updated for Brewser v0.1.116, September 2026. Percentages are honest estimates of real-world surface coverage, not spec-section counts.

Brewser Docs