Inspiration

I've tried getting into journaling like five separate times and always give up in like three days, because most journaling apps ask you to sit down and write a whole page about your feelings, and that's just never going to happen on a random Tuesday. But streak-based apps like Duolingo actually work on me — I've got a 200+ day streak on stuff way less important than my own life. So I wanted to steal that mechanic and point it at something that actually matters: noticing your days instead of letting them all blur together.

What it does

Ember asks for two things a day: one good thing that happened, and one thing you're still working through. That's the whole entry — no prompts, no blank page. It tracks how many days in a row you've shown up, and once you log a day you can turn it into a shareable "day card" image, kind of like a mini Spotify Wrapped but for a single day instead of a whole year.

How I built it

React + TypeScript + Vite, no backend — everything is saved with localStorage in the browser, so there's no account system to build or maintain. The streak logic walks backward day by day from today (or yesterday, if today hasn't been logged yet) checking for consecutive dates, and the share card is drawn on an HTML <canvas> and exported as a PNG.

I used AI (Claude) — for scaffolding the project, writing the streak and canvas logic. I disclosed that in the README along with everything it touched, since I wanted to actually understand what got built instead of just shipping a black box.

Challenges I ran into

The streak logic was more annoying than it should've been — figuring out whether "today" counts toward a streak if you haven't logged yet, and making sure it doesn't break at midnight or across time zones, took a few tries to get right. Getting the share card to look decent with variable-length text was another one — long entries would overflow the canvas until I added text wrapping. And since this is a single-page app, wiring up per-page SEO metadata (titles, descriptions, canonical tags) took more setup than a normal multi-page site would.

Git was its own adventure — I originally committed the whole project in one shot and had to rebuild the history into smaller, logical commits afterward, which taught me more about git reset and staging than I expected to learn this weekend.

What I learned

How streak logic actually works under the hood, how to draw and export images with the Canvas API, and what actually goes into a "production-ready" static site beyond just the app itself — sitemaps, structured data, social share images, a real 404 page, none of which I'd set up from scratch before. Also, apparently, several ways why a commit might break halfway

Built With

Share this project:

Updates

Submission history