← All projects

tools

Free file conversion tools that run entirely in your browser. No uploads, no accounts, no ads.

Stack
  • TypeScript
  • Astro
  • Preact
Links

tools

CI codecov

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.

Why

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.

Tools

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.

Stack

  • Astro 6 — multi-page output, islands architecture
  • Preact (compat) — interactive widgets (~10 KB instead of React's ~45 KB)
  • Tailwind v4 — via the @tailwindcss/vite plugin

Per-area workhorses:

Area Library
PDF 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:

Native browser APIs are preferred over libraries wherever possible: crypto.randomUUID, SubtleCrypto, CompressionStream, OffscreenCanvas, createImageBitmap, WebCodecs. Heavy work runs in Web Workers.

Local development

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 viewer

Testing

End-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.

Deploy

Deploys automatically to Cloudflare Workers Static Assets via Workers Builds on push to main. Manual deploy:

npm run build
npx wrangler deploy

wrangler.toml configures the asset directory and the not_found_handling strategy.

Adding a new mode to an existing tool

Modes share a hub (PdfHub.tsx, ImageHub.tsx, …). To add one:

  1. Library at src/lib/<area>/<op>.ts — framework-agnostic, unit-testable.
  2. Worker at src/lib/<area>/<op>.worker.ts if the work is heavier than ~50 ms — wraps the lib in a postMessage interface.
  3. Panel at src/components/tools/<PanelName>.tsx — Preact, manages its own state. Use the shared widgets:
  4. Register in hub — add a Mode literal and a ModeSpec blurb to the hub component, plus a conditional render block. Use the generic Hub wrapper.
  5. E2E — extend the relevant e2e/<hub>.spec.ts with a tab-click + real-fixture round-trip test.

Adding a new product family

  1. Catalog entry in src/lib/tools.ts — slug, name, blurbs. This drives the homepage, 404, and sitemap automatically.

  2. Hub at src/components/tools/<Family>Hub.tsx modelled on an existing hub.

  3. Page at src/pages/<family>.astro — uses HubPageLayout which assembles the visible markup + HowTo + FAQPage + BreadcrumbList JSON-LD from a single data block.

  4. E2E at e2e/<family>.spec.ts — add a real-fixture spec block. If the new family needs new fixture types, extend scripts/build-fixtures.mjs and e2e/fixtures.ts.

  5. 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

Non-negotiables for every tool

  • 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.

Commit convention

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.

License

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.