Source
This app’s code and revision history are public. Download a copy or explore the files below.
Public
The app’s code and revision history are public.
Run it yourself
Take the whole tree and run it on your own machine. The download needs no account. Cloning needs a sign-in.
Download .zip
bounded clone 7716a56ff3432bc0c1e4837c
A copy you download is not bounded. The guarantees this app runs under - declared egress, proven invariants, writes that fail closed - live in the runtime serving this page, not in the files. What you get is auditable source you can read and run, with no runtime guarantees attached.
AGENTS.md
# PDF PDF is a set of free PDF tools that run entirely in the browser, and a free alternative to Smallpdf, iLovePDF and Adobe Acrobat for everyday page jobs. It is an OpenApp in the OpenApps free apps store (https://free-apps.openapps.xyz/), owned by the OpenApps team. ## What it promises - Files never leave the person's device. Nothing is uploaded, ever: no server step, no analytics on file contents. Never add a feature that sends a file or its contents anywhere. - Free, with no daily limit, no watermark, no account and no paid tier. Never add a cap, an upsell or tracking. - What the person sees is what they download: page order, rotation and page numbers in the result match the workspace. ## What it does Merge PDFs and images into one PDF; reorder files and pages (drag, or the arrow buttons); rotate and delete pages, with Undo (button, toast and Ctrl or Cmd+Z); extract selected pages; split into one PDF per page or by ranges (separate files or one zip); compress (Medium or Strong: photos and scans are redrawn smaller as JPEG, text and drawings untouched); save pages as JPG or PNG at 150 or 300 dpi (files, one zip, or the phone's share sheet); JPG, PNG and other images the browser can open to PDF on A4, US Letter or at image size; page numbers at six positions, as "1" or "1 of N". Job links open the same page ready for one job: /merge, /split (with `?ranges=1-3,4-9`), /compress, /rotate, /organize, /delete-pages, /extract-pages, /jpg-to-pdf, /pdf-to-jpg, /page-numbers (`src/lib/tools.ts`). The host serves index.html for these paths; the canonical stays `/`. It does not edit text, OCR, convert to Word, fill forms, add passwords or sign (Sign does signatures: https://sign-free.openapps.xyz/). Locked (encrypted) PDFs are refused with an explanation. Bookmarks and form fields are not carried into new files. Compress leaves CMYK, spot color and palette images, masks, and images under 30 KB as they are. ## How it is built - `index.html` is the static landing page that search engines and AI crawlers read. Keep its copy, comparison, FAQ and JSON-LD in sync with what the app does. - `src/Workspace.tsx` is the whole tool. It mounts into the landing hero (`#workspace`); once files are added, `body.app-mode` hides the landing sections. Wider than 720px the save panel (tabs PDF, Split, Images) is a sticky sidebar; at 720px and below it opens as a sheet from Options, and the kit `.action-bar` holds the main buttons (Rotate, Delete, Extract while pages are selected). - `src/lib/engine.ts` does all file work and is loaded only when the first file is added: pdf-lib (1.17.1) reads PDFs, writes every result and compresses images (`shrinkImages`); pdf.js (`pdfjs-dist`, legacy build for older phones) draws page previews and page images in one shared worker. pdf.js's WebAssembly decoders and character maps are copied into `dist/pdfjs/` by `vite.config.ts`. - `src/lib/sort.ts` is drag to reorder for mouse and touch (press and hold on touch). `src/lib/flip.ts` makes page and file moves glide. `src/lib/ranges.ts` reads split ranges. `src/ui.tsx` has the toast (with Undo), the kit dialog, the segmented control and saving. - There is no API and no data. `policy.json` has one collection that refuses everything, because the app is a Bounded app only for hosting. A server function could not do this job anyway (no npm packages, 128 KiB request bodies), and files must not leave the device. - `public/llms.txt` and `public/index.md` tell AI assistants that PDF is browser-only, which job links to send and what each job does. Keep them, the landing copy, the comparison and the FAQ (visible and JSON-LD) in sync with what ships. - Keep `dist/` small (about 4.1 MB today): a release uploads all of it in one request, and very large uploads fail. ## Working on it `npm install && npm run build` typechecks and builds `dist/`. Ship changes through previews and releases as your runtime instructions describe; the app is an OpenApp, so nobody deploys it directly. Check a change in a real browser at 390px and 1440px: merge two PDFs, reorder files and pages, rotate, delete and Undo, extract, split every page and by ranges (zip too), compress a scanned PDF at both levels, save pages as JPG and PNG, images to PDF with each page size, page numbers on rotated pages, a job link such as /split?ranges=1-2,3-5, and a locked PDF. Open the downloads and check page counts, order, rotation and that compressed pages still look right. ## Voice Plain words, short sentences, no jargon, no em dashes. Say what happens, not how clever it is.
Change history
Quality pass: compress, PDF to JPG, phone layout, job links, llms.txt and index.md
Bounded source sync
Bounded source sync
Bounded source sync
Bounded source sync