Scramble and unscramble QR code tile puzzles — 3×3, 4×4, or 5×5 grids.
QReorder is a web tool with two modes: Scramble a working QR code into a shuffled tile puzzle and share it as a challenge, or Unscramble a scrambled QR puzzle back into a scannable QR code using an intelligent multi-phase solver — all running in the browser with no uploads to any server.
Turn any working QR code into a tile puzzle.
-
Upload — click the upload area or drag and drop a QR code image (PNG, JPG, or WebP). The QR code should be scannable before you scramble it.
-
Crop (optional) — clean up borders before scrambling using the crop tools:
- Tight Crop — automatically removes quiet-zone padding by detecting the background color from the image corners
- Manual Crop — opens a canvas crop editor with 8 drag handles; a zoom panel appears while dragging for pixel-precise alignment
- Undo Crop — restores the pre-crop image if needed
-
Choose a grid size — select how many tiles to cut the image into:
Grid Tiles Difficulty 3×3 9 Easy 4×4 16 Moderate 5×5 25 Hard -
Scramble — click Scramble QR Code. Tile positions are randomly shuffled (tiles are never rotated, only repositioned).
-
Download and share — click Download Scrambled QR to save the puzzle as a PNG and share it as a challenge.
Best practices: Use a clean black-and-white QR code. Remove all white padding (quiet zone) — extra space shifts tile boundaries and makes auto-solving harder. A square source image gives the cleanest tile cuts. QR codes with error correction level Q or H are much more likely to be solvable after scrambling.
Reconstruct a scrambled QR puzzle back into a scannable QR code.
-
Upload — click the upload area or drag and drop a scrambled QR code image (PNG, JPG, or WebP).
-
Verify the grid size — the app auto-detects the grid (3×3, 4×4, or 5×5). If detection looks wrong, use the Override Grid Size dropdown to set it manually.
-
Rotate tiles if needed — click any tile to rotate it 90° clockwise. Repeat to cycle through 180° and 270°. The scrambler never rotates tiles, so only do this if the source image was already rotated.
-
Rearrange tiles manually (optional) — drag tiles to swap positions. Placing tiles you already recognize can speed up the solve.
-
Lock tiles in place (optional) — click the lock icon on a tile to pin it. Locked tiles are skipped by the solver, which can dramatically reduce solve time.
-
Choose decoder mode (optional) — use the decoder switch in the Unscramble action bar to choose the decode backend:
- jsQR (default) — lightweight and stable for general use
- ZXing-WASM — usually faster on difficult 5×5 puzzles and often better on noisy inputs
-
Inspect tiles (optional) — two zoom tools are available in the tile grid header:
- Tile zoom — hover a tile and click the expand button to view it full-size. Click anywhere or press
Escto return to the grid. - Magnifying glass — click the Zoom toggle to activate a circular 3.5× lens that follows your cursor. The lens extends beyond the grid so you can see corners and edges clearly. Use the color swatches to change the gap fill color between tiles.
- Tile zoom — hover a tile and click the expand button to view it full-size. Click anywhere or press
-
Solve — click Solve QR Code in the same action bar. On desktop/tablet this action bar appears above the tile grid; on mobile it appears as a sticky bottom row. The solver runs in the background and shows live progress. When a valid QR is found, the solution is displayed with the decoded message.
Best practices: Use a high-contrast, clean black-and-white QR code. Ensure no extra padding around the image (tiles must align exactly to grid boundaries), no visible seams or gaps between tiles, and a square aspect ratio. Higher error correction levels (Q or H) significantly improve solver success.
- Node.js ≥ 20
- pnpm ≥ 9 — install via
corepack enableornpm install -g pnpm
git clone https://github.com/ThingEngineer/QReorder.git
cd QReorder
pnpm install| Command | Description |
|---|---|
pnpm dev |
Start the Vite dev server at http://localhost:5173 |
pnpm build |
Production build → apps/web-app/dist/ |
pnpm turbo check-types |
Strict TypeScript check — run before committing |
pnpm lint |
ESLint across all packages |
pnpm test |
Run all tests (Vitest) |
pnpm test:coverage |
Run tests with coverage report |
cd apps/web-app && pnpm preview |
Preview the production build at http://localhost:4173 |
pnpm buildskips type-checking (--noCheck). Always runpnpm turbo check-typesseparately before committing.
# Add a runtime dependency to the web app
pnpm add <package> --filter @qreorder/web-app
# Add a dev dependency
pnpm add -D <package> --filter @qreorder/web-app| Package | Role |
|---|---|
apps/web-app (@qreorder/web-app) |
Vite + React 19 app |
packages/types (@qreorder/types) |
Shared TypeScript types — no build step, workspace:* dep |
apps/mobile-app |
Expo React Native (placeholder) |
See docs/DEVELOPMENT.md for the full development guide, including Turborepo caching, environment variables, Tailwind setup, and shared types.
