Repository navigation
Sashfold 0.2.0 is the release where pages built out of components come apart into what they are: 64 commits since 0.1.5 on 2026-10-01. Shadow trees, Web Animations, the CSS object model and the Streams Standard are written, so the sites that build themselves from web components and style themselves from script render as they are meant to. The script engine has a compiler that writes machine code, and its objects keep their properties in shapes with caches that remember them. Speed work runs through all of it. Still every byte is written in this repository, and still it does not pretend to do what it cannot.
What's New
- Machine code for scripts — a baseline compiler turns a script's hot code into machine code for x86-64 and AArch64, on Linux, Windows and Apple silicon, over a new engine core: eight-byte values, frames on the machine's own stacks, objects that keep their properties in shapes, and property reads and writes that remember what they found.
- Shadow trees —
attachShadow, slots and slot assignment, the standard's event path through them, declarative shadow roots in markup, and styles scoped to each tree with:host,::slotted()and::part(). - Web Animations, CSS animations and CSS transitions —
element.animate(),@keyframes, transitions on style changes, and a real rendering update that runsrequestAnimationFramecallbacks together at one time. - Styles written from script — the CSS object model, so a page that builds its stylesheets with
insertRuleor constructed sheets shows them; and nested rules and cascade layers reach the cascade. - Streams — readable, writable and transform streams, so the frameworks that stream their pages into place load.
- Shadows —
box-shadowandtext-shadow, blurred, inset and animated, drawn with the corners the standard gives them. - Hover, focus and outlines —
:hover,:focus,:active,:focus-visibleand the other state pseudo-classes match, andoutlinedraws. - Import maps, and classes that extend the platform's own interfaces,
blob:URLs that load, and scripts inserted by scripts that wait their turn. - Placeholders that take a page's style —
::placeholder, and fields that keep only the half of their built-in look a page leaves them. - Pages that start loading sooner — the scripts and stylesheets a document names are asked for while the document is still arriving, and the parts of the engine a page never touches are never set up: a new tab's realm costs a fraction of what it did.
What's Fixed
- Pictures that were a web page — every request asked for a document, so a server that answers one address with a picture or with a page to show it in sent the page, and a site's post pictures never drew; each request now asks for what it is for.
- Content shown twice — a component moved from one place in the page to another was never told it had left, so it drew its content a second time; a video site's suggestions came out doubled.
- Carousels and galleries drawn at the picture's full width — a scrolling box in a flex row held its row as wide as its content, a flex row ignored its own maximum height, and a box's own maximum width did not count when its parent measured it.
- A tiny logo — a logo drawn as an SVG with only its proportions given came out square when it sat in a flex row.
- A frame drawn inside a styled search box — a field whose page took its border away still drew the engine's own frame and a second placeholder.
- Slow pages built from components — every style change read every component's stylesheets afresh; on a social site that made a page's busiest moment about ten seconds long, and it is about six now, its restyles three times as fast.
- Pages that use
:has()through:not()— no longer recompute the whole document's styles for a change one element away. - Sign-in buttons that never appeared — the user agent now carries Gecko's compatibility token, as other engines of their own do, and the sign-in services that refused the bare one serve it; and every request carries the Fetch Metadata headers every browser sends, which some sites require of anything that claims to be one.
What's Not Written Yet
- Painting gaps — transforms still translate but do not scale, rotate or skew; filters, clip paths, masks and
text-overfloware not painted. - Slow reactions — when a script reads layout after changing the page, the whole page is laid out again; a page that does that many times in a row stays busy for seconds after it has drawn (the window itself still answers).
- Script speed — the compiler is the first, simple one; a video site's player takes about three seconds to show its first frame where other browsers take one and a half.
- What
getComputedStylesays — flex, grid, gap, border and alignment properties read as empty strings. - The newer edge of scripting — WebAssembly, WebGL, Web Audio, service workers,
WebSocketand the regular-expressionvflag are not written. - Media gaps — video is VP9 in WebM and sound is Opus and WAVE; WebP and AVIF are not read. Windows has no sound and shows no video pictures yet, and on Linux video needs a graphics driver that decodes VP9 through Vulkan Video or VA-API — there is no software path for playback yet.
- macOS — the engine and its command line build and test on macOS in CI, but there is no window there yet.
Measured
- CSS reference tests — 10,272 of 15,682, up from 9,877 of 15,186. The table is at sashfold.com/wpt.html.
- WPT scripted tests — 157,846 of 192,269 subtests over 6,343 files, up from 145,667 of 174,114; the suite grew with the shadow-tree, animation, background and text-decoration directories. The table is at sashfold.com/wpt-harness.html.
- test262 — 41,845 of 45,367, the same count as 0.1.5 with the engine underneath rebuilt; it is run with the compiler off, eager and tiered, and all three agree. The table is at sashfold.com/test262.html.
- At 100% — both html5lib suites, WPT URL parsing, and the Unicode bidirectional and line-breaking conformance suites.
- The Sashfold 100 — 82 of a hundred pages of the live web render on the Windows build and 85 on the Linux build, against 80 and 82 in 0.1.5, with the five deliberately bad certificates refused on both. What each page asks for that is not written yet is listed at sashfold.com/sashfold100.
- Every score is held by CI: a test that stops passing fails the build.
Running It
- The downloads —
sashfold-0.2.0-windows-x64.zip, unzipped withthemeskept besidesashfold.exe, andsashfold-0.2.0-linux-x64.tar.gz, unpacked withthemeskept besidesashfold.sashfold https://en.wikipedia.orgopens the window on a page; with no address it opens its own new-tab page. Downloads go to your Downloads folder. - A Debian package and an AUR package —
sashfold_0.2.0_amd64.debinstalls on Debian 13, Ubuntu 24.04 and their derivatives withsudo apt install ./sashfold_0.2.0_amd64.deb, which putssashfoldon PATH and in the applications menu with its icon; on Arch,sashfold-binon the AUR installs the same build the same way. - Requirements — Windows 10 or 11, 64-bit; the binary is statically linked and imports only the operating system's own libraries, which is checked in CI. Linux needs a 64-bit machine with glibc 2.39 or newer (Ubuntu 24.04, Debian 13, Fedora 40 and their successors, Arch) and a Wayland compositor; video needs a graphics driver that decodes VP9 through Vulkan Video or VA-API, and sound a PulseAudio or PipeWire server, which the Debian package recommends; the binary carries its own C++ runtime and imports only libc and libm, checked the same way.
bash tools/install-desktop-linux.sh ./sashfold --desktopputs it in the applications menu and on the desktop with its icon; that script needs ImageMagick for the icon sizes. - Profiles and headless rendering —
--profile <dir>keeps a browser's cookies, storage and session in that folder between runs.sashfold --render page.html -o out.pngdraws a page to a picture with no window at all.SASHFOLD_USER_AGENTsets the user agent string to anything you like. - Source — macOS builds from source with CMake and Ninja; the window itself is Windows and Linux for now.