Digital Garden
Replies, Capsules, and Wrapped: the Planet Learned to Remember
Prologue: after being seen
Last round people moved into the planet’s sky: a real moon, seasonal constellations, each other’s light. The wish wall has been there all along — leave a star, and others can light it up.
But what happens after it’s lit? Across fourteen thousand stars, lighting was the only verb. This round ships three things with a single theme: remembering. A reply remembers one star, a capsule remembers one sentence, and Wrapped remembers a whole year.
One: star replies
Wish-stars now have a voice. From the admin page, any star can be answered — capped at one hundred and forty characters, not one more — and the moment a reply is written, WebSocket broadcasts it to everyone on the planet.
The matching animation on the front end: a violet-pink comet arcs onto that star, its color warms from lit-orange into an even warmer white, and a small ↩ badge appears beside it. Hover, and the full reply floats up.
Debugging uncovered one silent pitfall: Astro’s build doesn’t type-check, so a missing i18n key for sealOff sailed through with a green build — this class of error never cries out, it can only be caught by clicking through every page before launch. The most dangerous thing about silent failure is that it can’t even be bothered to announce itself.
Two: time capsules
Write a sentence and seal it: not sealed, thirty days, or a year. A sealed star glows ice-blue, its content is hidden from everyone, and it can’t be voted on — the backend answers with a 404, because secrecy shouldn’t depend on the front end’s good manners.
When the moment arrives, a Durable Object’s native alarm does the waking: the second it’s due, it broadcasts the reveal to every connected client, with no one polling. The admin can also unseal one early.
Star positions are computed deterministically from the id — refresh as often as you like, it stays put. A star holding a sealed sentence shouldn’t move house on every visit.
Integration testing caught two textbook concurrency bugs:
- The WebSocket broadcast raced ahead of the POST response; the late response triggered another fetch on the front end, and the same capsule was drawn twice. Fixed by deduplicating on id and text.
- A new star’s position was found by a
WHERE ip=?lookup, which on an empty IP grabbed the pinned star’s id. Now it readsMAX(id)right after the INSERT — an inferred id is never trustworthy; take the one you just wrote.
Three: planet Wrapped
/wrapped — the planet’s own year in review. Available in four languages, with real numbers from the backend: how many stars arrived this year, what the most-lit star says, how many countries and regions visited (flags included), total visits, and how many letters are still sealed.
Every number counts up: it starts when scrolled into view, counts from zero to the real value, powered by IntersectionObserver and gsap — it doesn’t count when unseen, and it stops when done. Entries were added to the command palette and the footer.
At launch, /api/wrapped returned: 320 visits, 4 countries. Small numbers — but real ones.
Epilogue
The planet now answers, seals secrets away, and files an annual report. “Remembering” is no longer something a browser refresh wipes out — it lives in the database and in a Durable Object’s alarm.
Next batch: command palette actions and a moon easter egg. The wish wall’s next chapter belongs to time.
Comments