Hub by Arif Aslam 2 min read

Engineering

These are write-ups from the codebase rather than about it. Every constant quoted is a constant in the source, every code block is copied from a real file, and the bugs are left in, including the ones that were mine and embarrassing.

The through-line, if there is one: this is a data application with no server, so every decision that a backend would normally absorb has to be made in a browser tab, in front of the user, with their file. That constraint produces more interesting problems than it has any right to.

Subscribe by Atom feed.

12 min read
How a detached ArrayBuffer rewrote our file loader
Registering a buffer with DuckDB-WASM transfers it to the worker, which detaches it, so every read after that line throws. Fixing one line of ordering exposed three other things the loader has to do before it crosses that point: normalize the encoding strictly, find the real table under a bank statement's letterhead, and keep a decoded sample for the check that catches a parse which reported success and returned nonsense.
12 min read
A rebuildable pipeline: every step is SQL
Forty operations, none of which touch a row: each emits SQL, and the chain is dropped and rebuilt from scratch on every change. Why views become tables past a depth of five, why the stored SQL is a cache rather than the source of truth, and what a cross-view join has to do so that a change in one file reaches the other.
13 min read
Finding tables in PDFs without a server
A PDF contains glyphs at coordinates and lines drawn on a page, and no tables at all. Three passes reconstruct one anyway: lattice from the drawing operations, stream from text alignment, OCR for scans. The tolerances are the interesting part, and so is the rule that appears twice in the pipeline: always prefer the reversible error.
11 min read
A chart palette you can validate by machine
Eight hues in a fixed order, two modes, and a perceptual separation floor that a script checks rather than an eye. Why the order of the array is itself the safety mechanism, why hues are never cycled, and why a series keeps its color when a filter removes the series next to it.
12 min read
Converting 100 MB in a static page without a server
Thirty-nine converter pages, no framework, and nothing heavy loaded until a file is in hand. Where the size cap comes from, how a file crosses to the workbench through a single-slot IndexedDB record, and the bundling bug that worked perfectly in development and crashed every converter in production.

What you will not find here

No benchmarks against competitors, no numbers I cannot point at in a file, and no claims about performance that were not measured. Where something is a judgment call rather than a measurement, the post says so. Where something is still broken, the post says that too.

The stack, for context: React 19 and TypeScript for the workbench at /app, plain TypeScript for everything else, Vite as a multi-page build, DuckDB compiled to WebAssembly as the query engine, ECharts for charts, ag-grid for the data grid, and Cloudflare Pages serving static files. No backend, no accounts, no database of yours anywhere but your own machine.

AA

Arif Aslam

Staff engineer in Bangalore. By day at Mammoth Analytics; building ExploreMyData on the side. More on my author page or LinkedIn.

The thing all of this runs

Every constant, every rescue path and every palette slot above is live in the workbench.

Open the workbench