Skip to content

Sashfold 0.1.0

Choose a tag to compare

@codingncaffeine codingncaffeine released this 16 Sep 22:42
· 439 commits to main since this release

Sashfold 0.1.0 is the first release that is not a pre-release, and the largest by far: 142 commits since 0.0.7 on 2026-09-04. Its theme is that pages now run their scripts, the window came to Linux, and the network stack is entirely the engine's own. A JavaScript engine written in this repository runs a page's scripts against its DOM, with events, timers, promises, modules and the rest of the language behind them, and reaches out over fetch and XMLHttpRequest with the cross-origin rules a browser is supposed to keep. The window is now a Wayland client of its own on Linux, and HTTPS there runs over a TLS 1.3 and 1.2 client written here too, with no operating system TLS stack behind it at all. Frames, iframes and framesets carry real windows now, each running its own scripts and taking its own scrolling, typing and clicks. The CSS reference tests went from 8345 of 14,616 to 9427; the scripted tests are a yardstick of their own now, at 65,822 of 74,294 subtests, and so is test262, the ECMAScript conformance suite, at 40,358 of 41,791. Still every byte is written in this repository, and still it does not pretend to do what it cannot.

What's New

  • A JavaScript engine of its own — lexer, parser, an object model, and an interpreter that runs on a bytecode machine of its own devising: ES5 with let/const, arrows, template literals, destructuring, classes with private fields, generators, async functions and async generators, Map and Set, Promise, typed arrays and ArrayBuffer, BigInt, Proxy and Reflect, and ES modules with import(), import.meta and top-level await. It is scored against test262, the ECMAScript conformance suite, below.
  • Pages run their own scripts — a realm gives each document's scripts the DOM: elements, attributes, innerHTML, events with capture and bubbling, setTimeout, setInterval, requestAnimationFrame, queueMicrotask, location, history, localStorage and the rest, wired into the shell, the headless renderer and the test runner alike. A page that builds its own menus and banners with a script now shows them.
  • fetch and XMLHttpRequest, with CORS — Headers, Request, Response, FormData and AbortController, and the rules above them a browser is supposed to keep: a preflight before a request that needs one, an opaque response for no-cors, and a cross-origin response read only when its own header allows it.
  • A window for Linux — the browser's window is a Wayland client of its own now, spoken over the compositor's socket with no toolkit underneath it. It draws at the display's scale, fractions included, takes a touchscreen's taps and drags, composes with an input method at the caret, and draws its own frame — minimize, maximize, close, a drag handle and a resize band — where the compositor draws none.
  • HTTPS on Linux, homemade down to the primitives — a TLS 1.3 and TLS 1.2 client written in this repository, over cryptographic primitives also written here, checks a server's certificate against a trust store and its issuer's revocation list, and resumes a second connection to the same host from the first one's session ticket.
  • iframes, frames and framesets — each shows its document in a real window of its own, running its own scripts, held to the page's framing rules, and taking the wheel, the keyboard, typing, selection and links exactly as the page itself does; a frameset is laid out as the grid its rows and columns name, with a frame drawn in each cell.
  • object and embed elements — each shows a fetched document in a window of its own, a picture, or its fallback content, decided the way HTML asks and drawn live from whichever it turns out to be.
  • window.open — a script opens a named frame, or a new tab in the page's own container, gated on the reader's own click or keypress so a page cannot pop one open unasked.
  • Content Security Policy — a page's own headers and <meta> policies judge every fetch and every redirect hop it makes, every inline script and style by nonce or hash, and every string a script would compile, with each refusal on the page's console.
  • Content blocking and cosmetic filtering — Adblock-syntax filter lists judge every request before it leaves the machine, local phishing and malware lists keep the browser off a nefarious site with no lookup sent anywhere, and a list's element-hiding rules become a stylesheet added to the page.
  • Profiles and containers — a profile keeps its cookies and its session between runs, and containers keep a window's tabs apart from one another, each with a cookie jar of its own and a colour of its own along its tab's edge.
  • Storage — localStorage is the shell's now, one area per container and origin, kept for as long as the browser runs and written to the profile as it changes, so a page's storage outlives the page and comes back on the next start.
  • Session restore — every tab, its history and where it was scrolled comes back on the next start, written to the profile as they change.
  • The command palette and four theme presets — Ctrl+Shift+P opens a list over every command the shell has, narrowed by typing: a new tab in any container, switching to an open tab, or choosing a theme by name. Nord, Solarized Dark, High Contrast and Sashfold Light ship beside the default theme.
  • The new-tab page — a clock and a greeting over the theme's colors, or over the theme's own pictures, crossfading from one to the next.
  • An HTTP cache that matures — a stale copy with an ETag or a Last-Modified is revalidated rather than refetched, a response with no explicit freshness gets a sensible guess from its own age, and every entry is kept on disk in the profile between runs.
  • document.write — a script that writes its own markup as the parser reaches it lands in order, at the point the specification puts it.
  • SVG, drawn by a rasterizer of its own — paths, shapes, groups and transforms, linear and radial gradients, clip paths and a first cut of text, inline in a page or decoded as a picture's source.
  • CFF fonts — a Type 2 charstring interpreter reads CFF and CFF-flavored OpenType outlines, which is how most CJK faces and many web fonts are actually drawn.
  • Web fonts in WOFF and WOFF2 — the second unwrapped through a brotli decoder written in this repository, with font matching by stretch, style, weight and unicode-range for a family declared in pieces.
  • Kerning and Unicode line breaking — pairs are kerned from a font's own tables, and the complete UAX #14 line-breaking algorithm sits behind word-break, line-break and overflow-wrap.
  • Colour emoji — pictures from a font's own CBDT and sbix tables, and layered glyphs from COLR and CPAL.
  • Favicons — a page's own icon, decoded from BMP, ICO or PNG, drawn in its tab.
  • Ranges — Range and StaticRange, and a live range that every mutation moves along with the text it spans.
  • blob: URLs, structured clone and postMessage — URL.createObjectURL and a store of its own; a value posted between windows, sent through a MessagePort, or pushed into history, is cloned properly in the realm that receives it, cycles, typed arrays, dates and all.

What's Fixed

  • Minified CSS combinators failed to parse — a selector written as a>b, a+b or a~b with no spaces around the combinator was dropped whole, which cost 70 of the Sashfold 100 their rules; a script calling querySelector, matches or closest with the same kind of selector threw instead of answering.
  • Fixed and sticky boxes did not track the page's scroll — a position: fixed box drifted along with the page instead of staying at the viewport, and a position: sticky box did not re-stick as the page scrolled past it.
  • Content painted in the wrong order — floats, block backgrounds and inline text now paint in the order CSS 2.1 Appendix E gives them, so a float sits over the blocks it overlaps and under their own words, where before the layering could go either way.
  • A float's percentage height did not resolve, and an out-of-flow box's margin collapsed where it should not — a floated box's percentage height now resolves against a containing block whose height is written, as it does for any other block child, and an absolutely positioned box's top margin no longer collapses into its parent's, which used to push the parent down by a margin the positioned box does not even occupy space for.
  • A hostile JPEG could overflow the decoder's arithmetic — a stream whose dequantized coefficients reached the edge of what the format allows overflowed the inverse transform's math; the transform now runs with room to spare, and every well-formed picture still decodes to the same byte as before.

What's Not Written Yet

  • The newer edge of scripting — regular-expression lookbehind, property escapes and the v flag are not written, so a script built by a bundle that needs them fails at parse time with a syntax error that names it, and the page arrives as its markup alone; import maps, WebSocket, streams, shadow trees and MutationObserver records are not written either.
  • Layout gaps — subgrid and masonry are passed over; margin-trim, multi-column layout and several table behaviors are not read. A word in a language a dictionary segments — Thai, Lao, Khmer, Myanmar — breaks between clusters rather than at its own boundaries, and hyphenation only ever breaks at a soft hyphen already written into the text.
  • Painting gaps — shadows, outlines, filters, clip paths, masks and border-image; a transform can translate but not rotate or scale; a page fetches at most sixty-four of its pictures, so a gallery longer than that shows blank boxes past the sixty-fourth.
  • No complex-script shaping — Arabic letters do not join, a combining mark inside a right-to-left run can land on the wrong side of its base, and font hinting is not applied.
  • Media gaps — WebP, AVIF, animated GIF beyond its first frame, audio and video.
  • macOS — the engine and its command line build and test on macOS in CI, but there is no window there yet, and no TLS client of its own either.

Measured

  • CSS reference tests — 9427 of 14,616 over CSS 2 and sixteen CSS module directories, up from 8345. The table is at sashfold.com/wpt.html.
  • WPT scripted tests — a yardstick of its own now: 65,822 of 74,294 subtests over 1,260 files under seventeen dom/ and html/ directories. The table is at sashfold.com/wpt-harness.html.
  • test262 — the ECMAScript conformance suite, also new since 0.0.7: 40,358 of 41,791. The table is at sashfold.com/test262.html.
  • At 100% — both html5lib suites (7032 and 1784), WPT URL parsing (893), the Unicode bidirectional conformance suites (861,948 cases), and Unicode line breaking (16,672 of 16,672).
  • The Sashfold 100 — 83 of a hundred pages of the live web render on the Windows build and 81 on the Linux build, each rendered nightly and published, 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.1.0-windows-x64.zip, unzipped with themes kept beside sashfold.exe, and sashfold-0.1.0-linux-x64.tar.gz, unpacked with themes kept beside sashfold. sashfold https://en.wikipedia.org opens 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.1.0_amd64.deb installs on Debian 13, Ubuntu 24.04 and their derivatives with sudo apt install ./sashfold_0.1.0_amd64.deb, which puts sashfold on PATH and in the applications menu with its icon; on Arch, sashfold-bin on 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; the binary carries its own C++ runtime and imports only libc and libm, checked the same way, and the window is a Wayland client of its own with no toolkit underneath it. bash tools/install-desktop-linux.sh ./sashfold --desktop puts 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.png draws a page to a picture with no window at all.
  • Source — macOS builds from source with CMake and Ninja; the window itself is Windows and Linux for now.