Languages: English · 简体中文 · 繁體中文 · 日本語 · 한국어 · Français · Deutsch · Español · Português (Brasil) · Русский · العربية · हिन्दी · ไทย · Tiếng Việt
A hierarchical, infinite-canvas bookmark organizer with beige minimalist design.
Boxing transforms your new tab page into a visual workspace for bookmarks. Instead of flat folders, organize bookmarks into labeled boxes on an infinite canvas — drag, connect, and nest them spatially. Think Obsidian canvas meets bookmarks.
Note
Replace this placeholder with a real screenshot showing the main canvas with boxes and connections.
Infinite Canvas — Pan and zoom freely (Ctrl+scroll). Create unlimited boxes on a single canvas. Connect boxes with lines to show relationships. Set parent-child relationships — move a parent and its children follow.
Two-Level Hierarchy — Large boxes hold small boxes. Small boxes hold bookmarks. Click into a box to enter its sub-canvas. Breadcrumb navigation shows your path. Nest as deep as needed.
Bookmark Management — Each box has its own bookmark collection with list and grid views. Add, edit, delete with a clean dialog. Open in current tab or new tab (configurable). Drag to reorder.
Connectivity — Visual SVG connection lines between boxes. Alt+Click a line to delete it (configurable: single-click or double-click). Parent-child movement propagation with elastic boundary clamping.
Design & Theme — Beige/cream minimalist aesthetic. Light and dark mode with automatic system detection. Adjustable font size and zoom. Square or rounded corners toggle.
14 Languages — en, zh_CN, zh_TW, ja, ko, fr, de, es, pt_BR, ru, ar, hi, th, vi with auto browser-language detection.
Note
Replace this placeholder with a real screenshot showing box hierarchy and bookmark management.
- Download the latest release ZIP
- Unzip to a folder
- Go to
chrome://extensions(oredge://extensions) - Enable Developer mode (top-right toggle)
- Click Load unpacked and select the unzipped folder
- Download the latest release XPI
- Go to
about:addons - Click the gear icon → Install Add-on From File
- Select the downloaded XPI
Tip
End users don't need Node.js or npm. Those are only for development.
- Double-click empty canvas → create a new box
- Drag box title bar → move box
- Ctrl+scroll → zoom canvas (30% to 200%)
- Drag empty canvas → pan
- Right-click → go back to parent canvas level
- Click a box → enter its sub-canvas
- Drag from box edge midpoint → connect to another box
- Alt+Click a connection line → delete it
- Star icon on a box → mark as parent (children move together)
- Pin icon → lock box position
- Canvas top-right circle button → unpin header for fullscreen mode
- All data stored locally in
chrome.storage.local— nothing leaves your device unless you configure optional cloud backup - Optional WebDAV / GitHub Gist backup is the only outbound network usage
- No analytics, no tracking, no third-party services
- 100% open source (Apache-2.0) — audit every line
- Full privacy policy: docs/privacy-policy.md
- Node.js >= 18
- npm
git clone https://github.com/Xxx91n/boxing.git
cd boxing
npm install
npx playwright install firefox chromium
npm run buildnpm run build # Dev build → dist/boxing-chrome + dist/boxing-firefox
npm run dev:chrome # Build + launch Chrome with extension loaded (web-ext)
npm run dev:firefox # Build + launch Firefox with extension loaded (web-ext)
npm run dev:chrome:no-build # Fast reload without rebuilding (requires prior build)
npm run dev:firefox:no-build # Fast reload without rebuilding (requires prior build)
npm test # Playwright tests (Chrome + Firefox)See CONTRIBUTING.md for the full development guide.
Tests tagged @quarantine are excluded from the Firefox lane: native-input dispatch on the
Firefox persistent context hangs (the playwright#16095
class), as tagged in architecture-recovery ticket 01. They keep running in the Chromium lane and in
the dedicated quarantine lane: npm run test:quarantine. Each tag carries a quarantine-ref
comment pointing at the governance ticket
(.scratch/architecture-recovery/issues/14-quarantine-governance.md).
Status below is the quarantine-lane baseline captured 2026-09-02 (ticket 14): 19/19 green on Chromium, 14/19 green on Firefox.
| Test (spec › title) | Chromium | Firefox | Registered | Due (30d) |
|---|---|---|---|---|
| boxing-adr-0007-acceptance › Q3b spatial index threshold 32 | pass | fail | 2026-09-02 | 2026-10-02 |
| boxing-audit › saveLayout localStorage fallback on storage error | pass | fail | 2026-09-02 | 2026-10-02 |
| boxing-debug › open NTP via file:// full workflow | pass | fail | 2026-09-02 | 2026-10-02 |
| boxing-focus-steal › dblclick empty canvas: no selection/focus steal | pass | pass | 2026-09-02 | 2026-10-02 |
| boxing-focus-steal › dblclick canvas-empty title text | pass | pass | 2026-09-02 | 2026-10-02 |
| boxing-focus-steal › selection cleared after renderCanvas | pass | pass | 2026-09-02 | 2026-10-02 |
| boxing-innerclip › small-box at y=0 visible across zoom | pass | fail | 2026-09-02 | 2026-10-02 |
| boxing-innerclip-pan › panned-to-top clip across zoom | pass | pass | 2026-09-02 | 2026-10-02 |
| boxing-onboarding › step navigation and dismiss | pass | pass | 2026-09-02 | 2026-10-02 |
| boxing-popup-dragselect › popup stays open after drag-select | pass | fail | 2026-09-02 | 2026-10-02 |
| boxing-v3 › Chromium load extension + new tab visual check | pass | pass | 2026-09-02 | 2026-10-02 |
| boxing-v3 › Pin header button toggle | pass | pass | 2026-09-02 | 2026-10-02 |
| boxing-v3 › Cross-tab delete guards | pass | pass | 2026-09-02 | 2026-10-02 |
| boxing-webdav › backup saves and restores layout | pass | pass | 2026-09-02 | 2026-10-02 |
| boxing-webdav › sync detects data loss and warns | pass | pass | 2026-09-02 | 2026-10-02 |
| boxing-webdav › empty local pulls from cloud on first sync | pass | pass | 2026-09-02 | 2026-10-02 |
| boxing-webdav › test button shows error on failure | pass | pass | 2026-09-02 | 2026-10-02 |
| data-recovery › export round-trip JSON structure | pass | pass | 2026-09-02 | 2026-10-02 |
| extension-test › NTP HTML rendering | pass | pass | 2026-09-02 | 2026-10-02 |
Expiry rule. Every entry must be resolved by its due date — either repaired (remove the
@quarantine tag + quarantine-ref comment, rejoin the Firefox lane, delete the row) or
retired (delete the test and the row, recording the decision in the governance ticket).
Entries do not auto-extend: at expiry the next governance pass forces the decision, defaulting
to retirement. A newly tagged quarantine must be registered in this table the same day, with
due = registered + 30 days. The quarantine lane is patrolled daily by CI
(.github/workflows/quarantine.yml, continue-on-error).
Contributions are welcome! See CONTRIBUTING.md for setup, workflow, and code style.
Apache-2.0 — see LICENSE
Translations: 简体中文 · 繁體中文 · 日本語 · 한국어 · Français · Deutsch · Español · Português (Brasil) · Русский · العربية · हिन्दी · ไทย · Tiếng Việt — see TRANSLATIONS.md