#OPFS
Is that a rail system linking the OPFs and VAB?
For Sci-Fi Cutaway Saturday: This uncredited cross section of the Vehicle Assembly Building at the Kennedy Space Center on Merritt Island, Florida, January 10, 1974.
November 7, 2026 at 7:43 PM
OPFS is proud to be a Living Wage Employer. This Living Wage Week, we are celebrating 25 years of the Living Wage movement!

#LivingWage #LivingWageWeek #SingleParentSupport #Scotland
November 10, 2026 at 12:25 PM
Today, One Parent Families Scotland gave evidence as part of the inquiry on Universal Credit held by the APPG on Ending the Need for Food Banks at Westminster, represented by OPFS Head of Policy, Strategy and Comms, Charis Chittick. We are proud to support the Essentials Guarantee.
November 10, 2026 at 3:07 PM
also, rendering is done using ThreeJS. I'm very happy with how well the API is designed, even things like copying one texture to another is very straightforward.
(I've also used fast-png for PNG decoding & fflate for accessing files from the client JAR, which is cached in OPFS)
November 8, 2026 at 3:26 AM
“I don’t know enough about OPFS to take part.”

You don’t need to. Your first impressions are useful too. 💬

Our survey asks what you think of OPFS and how we communicate. There are no right or wrong answers; we’d like your honest views.

Have your say by Mon 16 Nov: docs.google.com/forms/d/e/1F...
November 9, 2026 at 12:02 PM
Running GTFS archives client-side in Wasm keeps server costs near zero once the static bundle loads. Streaming chunks into IndexedDB or OPFS as they arrive can also soften the initial wait when someone pulls several days of feed history.
November 10, 2026 at 3:07 PM
useful for collaborative apps, mobile tools, and anything where multiple people might edit the same data. it supports TypeScript and Rust, works across web and mobile platforms, and is open source. www.everydev.ai/tools/syncular
Syncular - SQL Sync Engine for Local First | EveryDev.ai
Syncular is an open-source, offline-first SQL sync engine licensed under Apache-2.0. It gives every client a real local SQLite database — OPFS in the…
www.everydev.ai
November 9, 2026 at 1:24 AM
OPFS welcomes the Scottish Government’s plans to reform council tax debt recovery for survivors of domestic abuse in Scotland, including proposals to reduce or remove council tax liabilities and increase the time given to pay before debt recovery action is taken.

#CouncilTaxReform #CouncilTax
November 5, 2026 at 11:10 AM
cloning a #radicle repo in #grove as a sequence diagram painted with Pele inside Grove itself (preview of a mermaid containing markdown)
November 6, 2026 at 10:32 AM
What comes to mind when you think of OPFS? 💬

We’re reviewing how we look, sound and tell our story, and we’d love your input.

Take our 15 minute survey and enter to win a £30 gift card: docs.google.com/forms/d/e/1F...

Closes Monday 16 November
November 3, 2026 at 9:00 AM
Worried about money but unsure where to start? That’s enough to begin a conversation with OPFS.

This Talk Money Week, asking for support counts. It all counts.

Call 0808 801 0323.
opfs.org.uk/support-and-...

#TalkMoney #TalkMoneyWeek #ItAllCounts
November 3, 2026 at 4:03 PM
Zero-Backend Client-Side RAG in the Browser with WebGPU, Transformers.js, MediaPipe, and OPFS
Original: https://codingcat.dev/post/client-side-webgpu-rag-transformers-js-mediapipe-opfs Most teams building semantic search or Retrieval-Augmented Generation (RAG) for documentation portals reach straight for a cloud vector database and an external embedding API. That works fine until you need instant sub-10ms keystroke search, offline availability, or strict zero-egress privacy for user documents. With WebGPU compute shaders, **Transformers.js v3** , **Google MediaPipe** , and the `Origin Private File System (OPFS)`, you can run the entire embedding, vector indexing, and synthesis pipeline directly inside the user's browser tab. ## The Mental Model: Local WebGPU Shaders + OPFS Binary Vector Cache Why did client-side embeddings feel sluggish three years ago? Because running matrix multiplication on a single JavaScript main thread blocks UI rendering, and WebGL was designed for rasterizing triangles rather than general-purpose tensor math. **WebGPU** gives browser Web Workers direct access to GPU compute pipelines (`GPUBuffer` and WGSL compute shaders), while `OPFS` provides high-throughput binary file storage so quantized ONNX models and pre-computed `Float32Array` vector indexes load from disk in milliseconds on repeat visits. ## Browser Compute Runtimes Comparison: WebAssembly vs. WebGL vs. WebGPU vs. WebNN { "_key": "wai_tbl_29271a6d2d", "_type": "table", "rows": [ { "_key": "wai_row0_a596e93a89", "_type": "row", "cells": [ "Browser Compute Backend", "Hardware Target", "384-d Embedding Latency (Batch=1)", "Quantization Support & Best Use Case" ] }, { "_key": "wai_row1_2cfb35df7c", "_type": "row", "cells": [ "WASM SIMD (Threads)", "Multi-core CPU", "18ms to 45ms", "q8 / int8 universal fallback for devices without discrete or integrated WebGPU." ] }, { "_key": "wai_row2_2aa93fccc9", "_type": "row", "cells": [ "WebGL 2.0", "Legacy GPU Fragment Shaders", "12ms to 30ms", "fp16 / fp32 texture hacks; lacks native storage buffers and compute workgroups." ] }, { "_key": "wai_row3_223837fae9", "_type": "row", "cells": [ "WebGPU (navigator.gpu)", "Modern GPU Compute Units", "1.8ms to 5.5ms", "q4f16 / fp16 / int8 via WGSL compute shaders; ideal for Transformers.js v3 and MediaPipe." ] }, { "_key": "wai_row4_7a8da24412", "_type": "row", "cells": [ "WebNN (navigator.ml)", "Dedicated NPU / OS ML Accelerator", "1.2ms to 4.0ms", "Direct OS-level graph compilation (DirectML, CoreML, NNAPI) for ultra-low battery drain." ] } ] } ## Step 1: Generating 384-Dimensional Embeddings on WebGPU in a Web Worker To keep Main Thread Interaction to Next Paint (INP) under 16ms, always initialize your embedding pipeline inside a dedicated Web Worker and probe `navigator.gpu.requestAdapter()` to select `device: 'webgpu'` with graceful fallback to `'wasm'`: // src/workers/embedding-worker.ts import { pipeline, env, type FeatureExtractionPipeline } from "@huggingface/transformers"; // Cache quantized ONNX weights in the browser Cache API / OPFS env.allowLocalModels = false; env.useBrowserCache = true; let extractorPromise: Promise<FeatureExtractionPipeline> | null = null; async function detectOptimalDevice(): Promise<"webgpu" | "wasm"> { if (typeof navigator !== "undefined" && "gpu" in navigator) { try { const adapter = await (navigator as unknown as { gpu: GPU }).gpu.requestAdapter(); if (adapter) return "webgpu"; } catch (_) { // Fallback to WASM SIMD } } return "wasm"; } export async function getEmbeddingExtractor(): Promise<FeatureExtractionPipeline> { if (!extractorPromise) { const device = await detectOptimalDevice(); extractorPromise = pipeline( "feature-extraction", "Snowflake/snowflake-arctic-embed-xs", { device, dtype: device === "webgpu" ? "fp16" : "q8", } ); } return extractorPromise; } export async function embedTextToFloat32(text: string): Promise<Float32Array> { const extractor = await getEmbeddingExtractor(); const output = await extractor(text, { pooling: "cls", normalize: true, }); return new Float32Array(output.data as Float32Array); } ## Step 2: Persisting Binary Vector Indexes in Origin Private File System (OPFS) Storing thousands of JSON-serialized float arrays in `localStorage` or naive IndexedDB object stores creates massive serialization overhead. Instead, pack your normalized `Float32Array` embeddings contiguously into a binary file inside `navigator.storage.getDirectory()` (OPFS) and run a single-pass dot-product scan: // src/lib/vector/opfs-vector-index.ts export interface VectorMetadata { id: string; title: string; slug: string; excerpt: string; } export class OpfsFlatVectorIndex { private readonly dim: number; private vectors: Float32Array = new Float32Array(0); private docs: VectorMetadata[] = []; constructor(dimensions = 384) { this.dim = dimensions; } async saveToOpfs(filename = "codingcat-vectors-384d.bin"): Promise<void> { const root = await navigator.storage.getDirectory(); const fileHandle = await root.getFileHandle(filename, { create: true }); const writable = await fileHandle.createWritable(); await writable.write(this.vectors.buffer); await writable.close(); const metaHandle = await root.getFileHandle(`${filename}.meta.json`, { create: true }); const metaWritable = await metaHandle.createWritable(); await metaWritable.write(JSON.stringify(this.docs)); await metaWritable.close(); } async loadFromOpfs(filename = "codingcat-vectors-384d.bin"): Promise<boolean> { try { const root = await navigator.storage.getDirectory(); const fileHandle = await root.getFileHandle(filename); const file = await fileHandle.getFile(); const arrayBuffer = await file.arrayBuffer(); this.vectors = new Float32Array(arrayBuffer); const metaHandle = await root.getFileHandle(`${filename}.meta.json`); const metaFile = await metaHandle.getFile(); this.docs = JSON.parse(await metaFile.text()) as VectorMetadata[]; return true; } catch { return false; } } /** * Since embeddings are L2-normalized at extraction time, * Cosine Similarity equals the raw dot product. */ searchTopK(queryVec: Float32Array, k = 5): Array<VectorMetadata & { score: number }> { const count = this.docs.length; const dim = this.dim; const scores: Array<{ idx: number; score: number }> = []; for (let i = 0; i < count; i++) { const offset = i * dim; let dot = 0; for (let d = 0; d < dim; d++) { dot += queryVec[d] * this.vectors[offset + d]; } scores.push({ idx: i, score: dot }); } scores.sort((a, b) => b.score - a.score); return scores.slice(0, k).map(({ idx, score }) => ({ ...this.docs[idx], score, })); } } ## AJ Pro-Tip: Ship Pre-Computed Binary Embeddings from Your Astro Build > **AJ Pro-Tip: Pre-Compute Corpus Embeddings at Build Time, Embed Only the Query in the Browser. **Do not force every visitor's GPU to embed your entire 500-article blog archive on first page load. Generate your `codingcat-vectors-384d.bin` binary artifact once during your Astro static/SSR build (less than 750KB for 500 articles at `Float32` or 375KB at `Float16`), cache it in OPFS, and only run the WebGPU embedding pipeline on the user's 10-word search query. ## **Try the Live Browser AI & WebMCP Playground** You can test every pattern from this article live right now in our interactive Web AI & WebMCP Playground on CodingCat.dev, or inspect our production discovery manifests on the Developers & Agent APIs page. If you are organizing a developer conference or engineering summit, check out my Web AI talk abstracts on alexpatterson.dev and explore more hands-on Courses, Podcasts, and Blog Posts right here on CodingCat.dev.
dev.to
October 31, 2026 at 2:26 PM
Making a map like this would have been much harder just a couple of years ago. We now have address data in Canada that is good enough for this. DuckDB-WASM allows for fast database operations in the browser. OPFS is just a couple of years old now. And WebGL can offload computation to the GPU.
October 30, 2026 at 3:29 AM
Our annual report is here!

👩‍👦‍👦 This year, we supported 3,963 families across Scotland, providing one-to-one support to 2,401 parents.

👉 Read the report here: opfs.org.uk/who-we-are/a...

#SingleParentSupport #OPFS #Scotland #SingleParents #AnnualReport
October 30, 2026 at 2:57 PM
i was looking at it but i decided to try indexedDB first. what are your thoughts on OPFS?
October 26, 2026 at 5:57 PM
Did you give OPFS a try yet? It’s rather new, but I’m still using it as a relatively easy localstorage replacement. developer.mozilla.org/en-US/docs/W...

It’s no more permanent than localstorage or indexeddb though, which is a bummer.
Origin private file system - Web APIs | MDN
The origin private file system (OPFS) is a storage endpoint provided as part of the File System API, which is private to the origin of the page and not visible to the user like the regular file system...
developer.mozilla.org
October 26, 2026 at 7:43 AM
Yep OPFS is sandboxed too. I don’t think there’s any significant difference there.
October 19, 2026 at 6:33 PM
one concern i have for saved game data is persistence. i basically just want a file on disk. i don't want the browser chucking it for arcane reasons.

thoughts:

(1) indexedDB with manual backups.

(2) something new turned up in my research: OPFS. worth checking out?
today i'm prototyping some save system funcitionality for [the coiled sun]!

my testbed is using localstorage, which is fine for testing. i have a fair amount of world state to store, and i want to find ways to get around volatility issues (it's for metaprogression!). currently looking at indexedDB.
October 19, 2026 at 6:03 PM
I use IDB with Dexie. If you want SQL, there is a port of SQLite to WASM running on OPFS.
October 19, 2026 at 6:21 PM
The OPFS sandbox isn’t accessible to the user in the regular file browser, it’s also intended for application state, just like IDB, so it won’t really help with the backup problem.
October 19, 2026 at 6:38 PM
doing a bit more research, it looks like OPFS might be a more modern alternative for saved game data with better persistence? do you have thoughts on if that might be more appropriate?
October 19, 2026 at 5:57 PM
ah, does that apply to OPFS too?

yeah i was considering manual backup + indexedDB, but i'd prefer more seamless for the user! hence considering the file system API or the OPFS part of that specifically.
October 19, 2026 at 6:31 PM
I haven't used opfs myself. persistence level looks about the same as IDB. I think it comes down to whether your data really is best handled as bytes or records. with IDB you get indexing which may or may not be helpful. json is a trivial ingestion or export format for IDB.
October 19, 2026 at 6:01 PM