Free file tools that run entirely in your browser. Live at tools.dcln.me.
No uploads. No accounts. No ads. No cookies. Open source under MIT.
Most online file tools upload your file to a server, process it there, and offer you the result. The privacy promises are typically "we delete it after an hour" — not "we never had it."
Modern browsers can do this work locally. So that's what these tools do.
All nine product families are live. Each lives at a single URL with operations exposed as tabs — no per-operation URLs.
| Slug | Modes |
|---|---|
pdf |
Merge, split, rotate, organize, images → PDF, PDF → images |
image |
Convert, resize, compress, favicon bundle, SVG → raster, strip EXIF |
audio-video |
Convert, trim, compress, extract audio, frames, video → GIF, merge — via WebCodecs |
data |
JSON / YAML / XML / TOML / CSV / TSV: convert, format, validate, generate TS types |
color |
HEX / RGB / HSL / OKLCH / CMYK conversion, harmony palettes, WCAG contrast checker |
encode |
Base64, URL encoding, JWT decoder, SHA-1 / 256 / 384 / 512 via WebCrypto |
document |
Markdown ↔ HTML, DOCX → HTML/Markdown/text, PDF → text, browser-native print to PDF |
archive |
Create ZIP / TAR / TAR.GZ / GZIP; extract those plus RAR. Auto-detect on read |
code |
Beautify + minify JS, TS, CSS, HTML, JSON, SCSS, Markdown, YAML, GraphQL, Vue, SQL |
The canonical catalog lives in src/lib/tools.ts and feeds
the homepage, 404 page, and sitemap.
- Astro 6 — multi-page output, islands architecture
- Preact (compat) — interactive widgets (~10 KB instead of React's ~45 KB)
- Tailwind v4 — via the
@tailwindcss/viteplugin
Per-area workhorses:
| Area | Library |
|---|---|
| pdf-lib (write) + pdfjs-dist (read) | |
| Image | native createImageBitmap / OffscreenCanvas + libheif-js, @jsquash/avif, utif2 for codecs the browser lacks; exifr + piexifjs for EXIF |
| Audio/Video | mediabunny (WebCodecs convert / trim / compress / extract / frame / merge) + gifenc for video → GIF |
| Data | js-yaml, fast-xml-parser, fast-xml-builder, smol-toml, papaparse |
| Document | marked (MD → HTML), turndown (HTML → MD), mammoth (DOCX → HTML), browser-native print for PDF export |
| Archive | fflate (ZIP/GZIP) + a small custom ustar TAR reader/writer + node-unrar-js for RAR extract |
| Code | prettier standalone with lazy-loaded parser plugins, sql-formatter, terser for JS/TS minify, csso for CSS minify |
| Encode | WebCrypto SubtleCrypto for hashing; native btoa/atob for Base64 |
| DnD | @dnd-kit for the PDF organizer thumbnail reorder |
Infrastructure:
- Cloudflare Workers Static Assets — hosting
- Cloudflare R2 at
cdn.dcln.me— for WASM blobs that exceed the 25 MiB per-asset cap - Cloudflare Web Analytics — no cookies, no fingerprinting
Native browser APIs are preferred over libraries wherever possible:
crypto.randomUUID, SubtleCrypto, CompressionStream, OffscreenCanvas,
createImageBitmap, WebCodecs. Heavy work runs in Web Workers.
Node 22+ required.
npm install
npm run dev # local dev server at http://localhost:4321
npm run build # production build → dist/
npm run preview # serve the production build locally
npm run check # astro check (type + Astro template diagnostics)
npm run lint # eslint
npm run test:e2e # Playwright suite (102 tests)
npm run test:fixtures # rebuild e2e/fixtures/* from source (needs ffmpeg + network)
npm run test:report # build test-artifacts/index.html — visual before/after viewerEnd-to-end tests live in e2e/*.spec.ts and exercise every hub against real
fixtures committed under e2e/fixtures/ — small but authentic
files (Big Buck Bunny clip @ CC-BY 3.0, real DOCX, multi-page PDF with embedded
images, JPEG with real EXIF tags, ZIP/TAR/TAR.GZ archives, etc.).
Fixtures are produced deterministically by
scripts/build-fixtures.mjs; regenerate with
npm run test:fixtures. Provenance and licenses are documented in
e2e/fixtures/README.md.
The Playwright config retries failed tests once locally (twice on CI) to absorb the occasional WebCodecs race under parallel load. The Audio/Video real-fixture suite runs in serial mode for the same reason.
Deploys automatically to Cloudflare Workers Static Assets via Workers Builds on
push to main. Manual deploy:
npm run build
npx wrangler deploywrangler.toml configures the asset directory and the not_found_handling
strategy.
Modes share a hub (PdfHub.tsx, ImageHub.tsx, …). To add one:
- Library at
src/lib/<area>/<op>.ts— framework-agnostic, unit-testable. - Worker at
src/lib/<area>/<op>.worker.tsif the work is heavier than ~50 ms — wraps the lib in apostMessageinterface. - Panel at
src/components/tools/<PanelName>.tsx— Preact, manages its own state. Use the shared widgets:FileDropZonefor inputOutputPanelfor text outputs with copy/download- Unified
Statusdiscriminated union (idle | loading | working | done | error) Fieldset+Pillsfor option groups
- Register in hub — add a
Modeliteral and aModeSpecblurb to the hub component, plus a conditional render block. Use the genericHubwrapper. - E2E — extend the relevant
e2e/<hub>.spec.tswith a tab-click + real-fixture round-trip test.
-
Catalog entry in
src/lib/tools.ts— slug, name, blurbs. This drives the homepage, 404, and sitemap automatically. -
Hub at
src/components/tools/<Family>Hub.tsxmodelled on an existing hub. -
Page at
src/pages/<family>.astro— usesHubPageLayoutwhich assembles the visible markup +HowTo+FAQPage+BreadcrumbListJSON-LD from a single data block. -
E2E at
e2e/<family>.spec.ts— add a real-fixture spec block. If the new family needs new fixture types, extendscripts/build-fixtures.mjsande2e/fixtures.ts. -
WASM > 1 MB — upload to R2 at
cdn.dcln.me/<lib-name>/<version>/<file>and load from there. Pin the version.wrangler r2 object put dcln-assets/libheif/1.19.8/libheif.wasm --file=./libheif.wasm
- Lighthouse ≥95 across Performance, Accessibility, Best Practices, SEO. Release blocker.
- Drag-and-drop must have a keyboard-accessible fallback (visible click-to-select button, arrow buttons for reordering).
- ARIA live region for progress and completion.
- "Files never leave your browser" copy visible above the fold.
- No third-party scripts beyond Cloudflare Web Analytics. No cookie banner.
This project uses Conventional Commits. Every commit and PR title must follow the pattern:
type(optional-scope): short description
Types: feat, fix, docs, style, refactor, perf, ci, chore, test, build, revert.
For new modes, use the family slug as the scope:
feat(image): add SVG → raster mode
fix(pdf): handle password-protected PDFs gracefully
ci: bump lighthouse threshold to error-level 0.95
commitlint validates commits on every PR via the Commit Messages job in .github/workflows/ci.yml. Past commits made before this convention was added are not retroactively validated.
MIT. See LICENSE.
Test fixtures under e2e/fixtures/ include video frames
derived from Blender Foundation's Big Buck Bunny (CC-BY 3.0); see the
fixtures README for full per-file provenance.