Fujimod
Try your camera firmware in the browser and build Fujimod SD boot files.
A paper-craft habit tracker for the eighth try. Fall seven times, rise eight: tick a habit and it becomes a fold; a thousand folds make a wish.
LifestyleGitHub @ozesince02OnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
Repository information has not been collected yet.
No updates detected yet. GitHub releases will appear here.
A paper-craft habit tracker. Fall seven times, rise eight.
Translation pending
Taken from the repository README
Loading the full README.
Read the full README ↗Fall seven times, rise eight. A paper-craft habit tracker for people who have started over more times than they can count. Tick a habit and it becomes a fold; tick a day's habits and a paper crane folds itself; a thousand cranes make a wish.
Live: onemorefold.com · tracker at onemorefold.com/app · what's new: patch notes
One More Fold began as oze's Habit Tracker v2, a Google Sheet held together with COUNTIFs, and was folded into something lighter. It's made by one person, oze, with Claude Code as a pair programmer.
No ads, no analytics, no trackers. See the Privacy page.
| Part | What |
|---|---|
| Front end | Plain ES modules, no framework. Vite builds a multi-page static site. Three.js for the crane, GSAP for motion. Self-hosted fonts. |
| Data | Local first: one object in localStorage (eightfold:v1). When signed in, a sync engine mirrors it to Supabase. |
| Backend | Supabase (Postgres in Mumbai): Auth, row-level security on every table, Realtime for sync, and one Edge Function that sends closed-app reminders every 30 minutes. |
| Hosting | A Cloudflare Worker serving the built files, with strict security headers and a Content-Security-Policy that allows no third-party scripts. |
| Checks | Node scripts with node:assert (no test framework), including the real database schema run on PGlite and Web Push checked against RFC 8291. |
You need Node 24 and npm.
git clone https://github.com/ozesince02/onemorefold.git
cd onemorefold
npm ci
npm run dev
The landing page is at http://localhost:5173 and the tracker at http://localhost:5173/app.html.
Without any settings, the dev server works fully on your device, with no accounts or sync. That's enough for most work.
To try accounts and sync, make your own free Supabase project:
.env.example to .env and fill in your project's URL and publishable key. .env is
ignored by git, and it only ever holds public values.npm run build needs these settings and stops on purpose when they're missing.
| Command | What it does |
|---|---|
npm run dev | Dev server with hot reload |
npm run check | Every check: stats, reminders, seed data, security, themes, backups, schedules, years, the database schema and its row-level security, sync, Web Push |
npm run build | The production site in dist/ |
npm run serve:dist | Serves dist/ with the real security headers, on http://localhost:4173 |
npm audit | Must report 0 vulnerabilities |
npm run shared | Copies the shared reminder logic into the Edge Function, after changing it in src/lib |
npm run vapid | One-time key setup for closed-app reminders (owner only; docs/push-setup.md) |
| Path | What it is |
|---|---|
index.html, src/landing.js | The landing page: the crane you fold by ticking six habits, the story, the feature zine |
app.html, src/app.js | The tracker: Month, Year and Habits views |
privacy.html, terms.html, patch-notes.html, 404.html | The other pages |
src/lib/ | The logic, all plain functions: store.js (data), stats.js (every number), schedule.js, reminders-core.js, sanitize.js (validation and esc()), sync/ (sync engine), auth.js, push.js |
src/ui/ | Paper pieces: torn edges, charts, the account menu, the crane story scroll, crane notes, reminders |
src/three/ | The Three.js crane that folds from a flat square |
src/data/bulletin.js | The noren: the notice under the landing header. Edit it to change or take down the message |
src/data/ | oze's own log for the landing page's story (story.js), an invented year for the checks (sample.js), the demo habits, the patch notes and the crane notes' text |
src/styles/ | CSS, with every colour a role token in tokens.css |
public/ | Static files: the service worker, icons, _headers (security headers and CSP) |
supabase/migrations/ | The database, as SQL, run by hand in order |
supabase/functions/ | The send-reminders Edge Function and its shared code |
scripts/ | Checks, build helpers and setup scripts |
docs/ | Design, decisions, security, plans |
| Read | For |
|---|---|
| CONTRIBUTING.md | How to contribute, and the rules every change follows |
| SECURITY.md | How to report a security problem |
| docs/security.md | Threat model, rules and the audit log |
| docs/design.md | The design system: paper, colour tokens, type, motion, voice |
| docs/decisions.md | Why things are the way they are (D-001 onwards) |
| docs/data-storage.md | Accounts, the database and sync |
| docs/buddies-and-notifications.md | The plan for buddies, challenges and notifications |
| docs/vision.md | Ideas for later |
| CHANGELOG.md | Every change, for people using the app |
| CLAUDE.md | The project's working instructions for Claude Code (the same rules, written for the AI) |
Ideas, bug reports and pull requests are welcome. Please read CONTRIBUTING.md first: One More Fold puts security and people's data ahead of features, and the guide explains the branch flow, the checks and the design rules. For anything bigger than a small fix, open an issue first so we can talk it through.
Found a security problem? Please don't open a public issue; see SECURITY.md.
The code is MIT licensed: use it, change it, build on it.
The name and branding are not part of the licence. "One More Fold" (and its former name,
"Eightfold"), onemorefold.com, the crane
mark and the wordmark (public/favicon.svg, the app icons in public/, and the mark drawn in the
code) belong to the author. If you run your own copy, give it its own name and look, so nobody
mistakes it for this one.
Also not covered by the licence:
src/data/story.js: oze's own habit log from January to October 2026, which the landing
page tells its story with. It's personal data, shared for that page, not something to reuse. The
checks use the invented year in src/data/sample.js instead.