The real thing, running here. Hover to scroll it, or click to use it — Escape stops.
The problem with every other version of this
Search for an app that locks something away until a date and you will find dozens. They all work the same way: you give your secret to a server, and the server promises not to hand it back early.
That is a promise, not a lock. It fails if the company is acquired, if the database leaks, if someone talks a support agent into an override, or if the service simply shuts down. And crucially, it fails for exactly the person it is supposed to constrain — because if you can email support, you can get it back.
The actual mechanism
drand is a public randomness beacon run as a distributed network. It publishes a new random value at a fixed interval, forever, and the value for a future round is not computable in advance by anyone.
tlock-js lets you encrypt against a specific future round. The resulting
cipher cannot be decrypted until that round is published — not slowly, not
with effort, but not at all, because the key does not exist.
The consequences are worth stating plainly:
- Changing your system clock does nothing.
- Going offline does nothing. It fails closed — no network, no opening.
- Reading the page source does nothing.
- I cannot open it early. Neither can you. There is no emergency exit.
That last one is the feature, and it is irreversible. An escape hatch you control is not a constraint.
Why I built it
To moderate my own Steam access — not quit, moderate. A fixed weekly slot, reached by a ladder that widens the gap a day at a time. My mother holds the Steam recovery email, which closes the obvious back door of just resetting the password.
It works for any secret. The Steam framing is just what made me write it.
The honest limitation
Everything is local. Ciphers live in localStorage, tied to one browser on
one device. Lose them and the password is gone permanently, because there is
no server holding a copy — that being the entire point.
Export exists for exactly this reason, and the discipline it demands is real: seal something, then immediately email yourself the cipher. The architecture that makes it trustworthy is the same architecture that makes it unforgiving.
The most recent pass softened that without compromising it. Download as an openable file saves a copy of the whole page with your shelf baked into it — not a data export you would have to import somewhere, but a working copy of the app that opens by double-click, offline, with every countdown and Open button intact. Asking someone to keep a JSON file safe is asking them to understand what it is for. Asking them to keep a file that just works is not.
What the last change taught me
The trust-model note — don’t want to type your real password here? Zip it locally and seal the zip’s password instead — was written, correct, and completely invisible. It sat inside a collapsed panel that nobody opens.
Moving it took five minutes and no logic changed. But a safeguard nobody reads is not a safeguard, and “it’s in the documentation” is the weakest defence in software. If it matters, it goes where people are already looking, in the colour you use for everything else that matters.
Refinements
How it changed
Every pass, dated, oldest first — nothing trimmed and nothing tidied out. The version that got rejected is usually more informative than the one that shipped.
5
- Started
Rejected the obvious architecture first
Every app in this category works the same way — a server holds your secret and declines to give it back until a date. That is not a lock, it is a promise, and it breaks the moment the server is compromised, sold or switched off. Started instead from drand, the League of Entropy beacon that publishes a new random round every three seconds. Encrypt against a future round and the decryption key does not exist anywhere on Earth until that round arrives.
Functionality - Changed
One self-contained file, not an app you install
tlock-js bundled with esbuild into a single HTML file. No accounts, no analytics, no server, and no network call at all except to api.drand.sh at the moment of opening. Sealing works fully offline, because tlock-js hardcodes the chain info — you can lock something away with no connection at all.
Functionality - Changed
Dropped the one-month ceiling
The first build capped seals at a month, on the theory that longer was irresponsible. That was me designing around my own nerves. The cap went to 20 years — still a sanity guard, but no longer a policy about how anyone else should use it.
Functionality - Changed
Generate the password in-page, without ambiguous characters
If the point is that you never see the secret again, typing one you already know is the weaker path. A 24-character generator using crypto.getRandomValues, with lookalike characters stripped out so reading one off a screen at 11pm cannot go wrong.
Quality of life - Changed
Named the categories instead of asking "what is this?"
A free-text box makes you invent a label every time. A dropdown grouped by Gaming, Social & media, Money and Other — with the specific services listed under each — turns it into one click, with free text still available for anything unlisted.
Ease of use
12
- Changed
Series — one seal, many ciphers
A single cipher cannot change a habit; it just postpones one evening. Series mints a run of them on a repeating schedule, each opening on its own date and all holding the same password. Open one, log in, burn it, wait for the next.
Functionality - Changed
The ladder, and the arithmetic underneath it
Fixed intervals do not reduce anything. Ladder mode takes free-text day gaps that widen over time. The recommended preset ramps 1+2+3+4+5+6 — which sums to 21, exactly three weeks — so after the ramp every release lands on the same weekday forever. Four presets: Ramp to weekly, Ramp to fortnightly, Gentle ramp, and Full taper for quitting outright.
Functionality - Note
Predictability is the mechanism, not a nicety
An erratic access schedule reproduces the variable-reward pattern that makes gambling compulsive. A schedule you can predict does the opposite. That is why the ladder converges on a fixed weekday rather than simply getting longer, and why "Anchor start" exists to snap the first release to a chosen weekday and time.
Functionality - Changed
The Open button enables itself, with no refresh
The shelf shows live countdowns, and a vault's Open button switches on the moment its round lands. Making someone reload a page to find out whether they are allowed yet adds a small ritual of checking, which is precisely the behaviour the app exists to reduce.
Quality of life - Changed
Decrypt in place, then burn
The password appears in the row it belongs to, with Copy and Burn directly beneath it — not in a modal, not at the top of the page. Burn deletes the cipher and wipes the clipboard, so the intended ritual (open, log in, burn immediately, then play) is the path of least resistance rather than a discipline you have to remember.
Quality of life - Changed
Export and email, because there is no sync
Ciphers live in localStorage, keyed to one browser on one device. Building sync would mean a server, which would undo the entire premise. So: export the whole shelf to JSON, import merges and skips duplicates, and any row can be emailed to yourself — with a one-email-for-the-whole-set option that falls back to the clipboard when the mailto would be too long. A stolen cipher is worthless until its date, so this is safe to do.
Functionality - Changed
An opening log that counts the gap, not the streak
Every opening is recorded with its date, the vault name, and the gap since the previous one, plus a 30-day stat line. Streak counters reward not opening, which turns into a thing to protect and then to break. The gap is the honest measure — and if gaps are widening while sessions get longer, that is bingeing, and the schedule should hold rather than stretch.
Quality of life - Changed
Open a cipher that is not on this shelf
Paste a cipher from a backup email, or load a .txt file. The round is readable from the armor header, so the page can show a real countdown for a cipher it has never seen before, and refuse to open it early. This is what makes the email backup an actual recovery path rather than a comforting-looking string.
Functionality - Fixed
The service worker must never cache drand
The PWA kit caches the app shell so it works offline — but requests to drand.sh are deliberately excluded. A cached beacon response could wrongly unlock a vault, or wrongly refuse to open one that is due. Caching the wrong thing here breaks the only guarantee the app makes.
Functionality - Note
The ratchet only turns one way
Tightening the schedule is one click — delete the remaining ciphers. Loosening it takes five minutes: new password, new ladder, reseal. The asymmetry is deliberate. A system you can relax as easily as you can tighten it is not a constraint, it is a suggestion.
Functionality - Note
Known limit, written down rather than hidden
Sealing 300+ ciphers at once will freeze the tab, because the encryption loop is synchronous. Fine at 50, ugly at 366. The fix is to yield to the event loop between iterations. Recorded in the handoff as a known gap rather than discovered later by whoever hits it.
Quality of life - Shipped
Decided against ads, permanently
An attention-harvesting SDK inside an attention-protection app is a contradiction, and it would break the "nothing leaves your device" claim that is the product's single best argument. Free with a tip jar instead. If it ever monetises properly: a one-time unlock, never a subscription — you do not bill someone monthly for not gaming.
Quality of life
3
- Changed
A way to use it without trusting the page at all
Added a note for people unwilling to type a real password into a web page: protect the secret in a local zip first using a tool you already trust, and seal the zip's password here instead. The page then only ever sees an arbitrary string you invented, never the real secret.
Ease of use - Changed
Download the whole thing as a file that still works
The honest weak point was always that losing every copy of a cipher loses the password permanently, and "export a JSON file" asks someone to understand what a JSON file is for. So: one button that saves a complete copy of the page with the current shelf baked in as a localStorage seed. Double-click it later, in any browser, offline, and it behaves exactly like this page — countdowns, Open, per-cipher delete, all of it, because it literally is this page. The source it copies is captured once at load, before any button can have been pressed, so a downloaded file can never carry a decrypted password in it.
Quality of life - Fixed
Moved it, because nobody was going to read it there
That note was correct and completely invisible — written inside a collapsed "How it works" panel that nobody opens. It became its own box, in the app's existing warning red, placed above "How it works" and open by default. Five minutes, no logic changed. A safeguard nobody reads is not a safeguard, and "it's in the documentation" is the weakest defence in software.
Ease of use
Screens
A look around
Look around — 4 screens

Sealing a vault — enter a secret or generate one, then set the date it becomes openable. 
The trust-model box. Moved out of a collapsed panel and made red, because nobody was reading it where it was. 
Ladder mode — gaps of 1,2,3,4,5,6 days then 7 forever. The sum is exactly three weeks, so every release lands on the same weekday. 
Opening a cipher from a backup email, and the log that tracks the gap between openings rather than a streak.