TreeMap
A free, open-source disk-space visualizer. Squarified treemap, duplicate hunting, disk-full forecasting, and cleanup that only ever moves files to the Trash.
Free PDF tools that work without uploading anything — compress, merge, split, rotate, reorder, convert and OCR. The work happens on your own device.
ProductivityTypeScript · JavaScriptGitHub @billionedges-mkOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
pdf-iq.com — seven PDF tools that run entirely in the browser. No upload, no account, no server-side processing.
Taken from the repository README
Loading the full README. The saved excerpt is shown below.
Seven PDF tools that run inside the browser tab. No upload, no account, no server-side
processing — not as a policy, as an architecture. The file is opened by the browser, changed on
the device, and saved back to disk.
The footer of every page carries a live readout of bytes sent and third-party requests. It is
real instrumentation (src/entries/net.ts), not decoration.Read the full README ↗Seven PDF tools that run inside the browser tab. No upload, no account, no server-side processing — not as a policy, as an architecture. The file is opened by the browser, changed on the device, and saved back to disk.
The footer of every page carries a live readout of bytes sent and third-party requests. It is
real instrumentation (src/entries/net.ts), not decoration.
One page sends something: /for-professionals, which asks firms what to build and stores three
answers and an email. It says so before you press anything, and the counter moving is the point.
Everywhere else, bytes sent should read zero, and third-party requests should read zero on every
page including that one. If either is non-zero anywhere else, that is a bug worth chasing.
npm install
npm run build # -> dist/
npm run dev # build, watch, and serve on http://localhost:4321
Gates, all of which should pass before a deploy:
npm run typecheck # tsc --noEmit
npm run licenses # fails on any AGPL/GPL/SSPL anywhere in the tree
node tools/contrast.mjs # WCAG contrast for every colour pair the design uses
In-browser verification, which is where anything involving canvas, codecs or pdf.js has to be checked, because none of it exists in Node:
node tools/selftest.mjs # then open /selftest.html and /tools-selftest.html
src/pages/*.html page bodies; the shell is added at build time
src/entries/*.ts one bundle per page
src/lib/ the actual work: compress, outline, textlayer, ocr-pool, ...
src/test/ in-browser self-tests
tools/build.mjs the static site generator
tools/site.mjs routes, nav order and page metadata — single source of truth
functions/api/ the one server endpoint: /for-professionals' form, on Cloudflare D1
vendor-tessdata/ OCR language models, committed (~49 MB, see TECH_DEBT.md)
Every route is written to disk as a complete HTML document. There is no client-side router, because a search engine reading these pages is the entire commercial argument.
Measured footprint: 98 MB built, 255 files, largest single file 10.4 MB. Of that, 49 MB is OCR language models and ~24 MB is tesseract wasm core variants (only one of which any given browser fetches). A tool page first-loads in 206 KB transferred — measured against the live site with brotli, counting the page, its entry bundle and every shared chunk the entry imports. Nearly all of it is one 178 KB chunk, which is pdf-lib.
Three reasons Pages wins:
The VPS would win if we needed server-side logic. We do not, and deliberately never will.
Both limits are comfortable: Pages caps at 25 MiB per file (we peak at 10.9 MB) and 20,000 files (we have 245).
| Setting | Value |
|---|---|
| Framework preset | None |
| Build command | npm run build |
| Build output directory | dist |
| Root directory | (repo root, leave blank) |
| Environment variable | NODE_VERSION = 22 |
public/_headers is picked up automatically and carries the CSP, the cache policy, and the
Content-Type: application/gzip rule for the language models. That last one matters: the
models are gzip streams that tesseract.js inflates itself, so if the CDN applied its own
Content-Encoding on top, the browser would silently decode one layer and hand tesseract data it
cannot inflate.
Simplest path is to move pdf-iq.com's nameservers to Cloudflare; Pages then creates the apex
and www records itself when you add the custom domain (CNAME flattening handles the apex).
| Record | Name | Value | Notes |
|---|---|---|---|
| CNAME | pdf-iq.com | <project>.pages.dev | created by Pages |
| CNAME | www | <project>.pages.dev | created by Pages |
| MX | pdf-iq.com | your mail provider's | must be re-created after the nameserver move |
| TXT | pdf-iq.com | SPF | from the mail provider |
| TXT | <selector>._domainkey | DKIM | from the mail provider |
| TXT | _dmarc | DMARC policy | start at p=none |
[email protected] up before moving nameservers, then copy the MX,
SPF and DKIM records into Cloudflare as part of the move. Moving nameservers without carrying
the mail records across silently breaks email — and the address appears 12 times across the
site.pdf-iq.com/privacy returns 200 in a
browser. That URL is registered in Play Console and in the Data Safety declaration. See
TECH_DEBT.md.npm run licenses walks the whole transitive tree and fails on anything copyleft. This is a
build gate, not a courtesy: Ghostscript, MuPDF and CoherentPDF are all AGPL-3.0, and WebAssembly
is conveyed to the visitor's browser, which would put this entire site under source-disclosure
obligations. Compression is therefore an object-level image walk with pdf-lib rather than a port
of any of them.
This project is MIT licensed — see LICENSE. The bundled OCR language models are Apache-2.0
from the Tesseract project and the fonts are OFL-1.1; both carry their own terms.
Current tree: 27 packages, zero copyleft. pdf-lib (MIT), pdfjs-dist (Apache-2.0), tesseract.js (Apache-2.0), fonts OFL-1.1. The bundled OCR language models are Apache-2.0 from the Tesseract project.
The full list is TECH_DEBT.md. These are the ones worth knowing before you trust it with
anything:
Files over 60 MB are refused. The ceiling is measured, not guessed, and it is set from the
point where the work stops being usable rather than where the tab crashes — those are far apart.
On the machine it was measured on, save() went from 4.2s at 80 MB to 163s at 85 MB while the tab
stayed alive and answered nothing; an actual crash is nearer 800 MB, and an iPhone completed 400 MB.
Measuring for the crash would have justified raising the limit to 600 MB. Reproduce it at
/memory-probe/, which refuses to report a figure from a run that cannot be true.
Two caveats on that number, both real: it comes from one desktop, and no valid phone measurement was ever obtained — three attempts produced impossible readings, and the probe now rejects them rather than printing them.
Encrypted PDFs: RC4 40 and 128-bit, AES-128 and AES-256 (R6) are tested against files another
implementation wrote. npm run verify:crypto runs 25 cases through the real open path against
MuPDF-written fixtures and reads every output back with both MuPDF and pypdf. Until 11 September 2026 only RC4 40-bit
had met a real file, and the first run against those found AES-128 output silently corrupt and
AES-256 not working at all — both fixed, see CLAIMS 30. AES-256 R5, the deprecated Adobe
variant, is implemented and has no fixture, so it is untested.
Removing a password follows the rule shared with the Android app: an author's print, copy or edit limits are lifted only by the owner password. A restricted file opened with the password that only opens it — or opening with no password at all — is refused, never silently stripped.
CMYK, JPEG 2000, JBIG2 and CCITT images are detected and skipped, with a specific reason given to the user. That logic is tested; it has never run against a real file of any of those kinds.
OCR accuracy is measured only against clean synthetic type — 95% mean confidence there, which says nothing about a phone photo of a contract. Pages that already carry a text layer are read rather than recognised, which is both faster and exact.
Browsers: everything is exercised in Chrome, and Safari on iPhone has been walked through the four things most likely to break there. Desktop Safari and Firefox have not been tested.
CLAIMS.md holds twenty-one checks, each written after a specific failure and naming it. It is
worth reading before the code: most of the interesting bugs in this project were not crashes but
gaps between what something claimed and what it did — a button that ran and discarded its result,
a comment citing a probe file that did not exist, a measuring tool that reported an impossible
number four times.
The governing rule is that a number which cannot be measured does not ship — cut, not softened.