R

Recall

Build Notes & Change List

A working document for the next few sprints.

Alright, so I went through index.html line by line. It's honestly in good shape — the design tokens hold together, the SM-2 logic is clean, the offline queue actually works, and the command palette is a nice touch. But there's a handful of things that are either broken, missing, or just aren't pulling their weight yet.

This document is my working plan. It's ordered by what I'd actually do first, not by how impressive it sounds on a feature list. Everything here is grounded in the current code — no "rewrite it in React" fantasies.

Part One — Fix What's Broken

These are bugs, not features. Some of them are quiet — you won't notice them until something goes wrong in a way that's hard to trace. Do these before adding anything new.

Bug The card grading race

In answerMc(), you save a reference to the card being answered, then call submitReview() after a 550ms timeout. But submitReview reads state.study.cards[state.study.index] again — it doesn't use the card you passed. If the user taps Next during that half-second, the wrong card gets graded. It's rare, but it's the kind of bug that shows up in a bug report six months from now and takes an hour to find.

Fix: change the signature to submitReview(quality, card) and use the passed card everywhere inside. Small change, removes a whole class of weirdness.

Bug The star button on unsaved notes

When you open the note editor for a new note, the favorite star is still clickable. Clicking it fires toggleFavorite('note', null), which shows "Save this first" — but the star still looks active. Small thing, but it's the kind of tiny friction that makes the app feel less careful than it is.

Fix: disable the star (with a disabled attribute and a subtle opacity change) until state.editingNoteId exists.

Bug The note-to-flashcard parser

This is the weakest part of an otherwise solid feature. Right now it uses:

line.match(/^Q:\s*(.+?)\s*A:\s*(.+)$/i) || line.match(/^(.+?)\s*[-–:]\s+(.+)$/)

The second regex matches timestamps ("12:30"), URLs ("http://..."), hyphenated words ("state-of-the-art"), and any sentence with a colon. It'll silently produce garbage cards. Also, Q: ... A: ... on the same line is rare — most people write them on separate lines.

Replace it with a small state machine that handles:

Q: What is X?
A: It is Y.

Term - Definition
Term: Definition
Term | Definition

Skip any line where the "answer" is under three characters, or where there's no clear delimiter. It's maybe 40 lines of code and it's the difference between a feature people use and one they ignore.

Bug Images in text columns

You're storing base64 images inside notes.img and inside cards.q (via that IMG_MARK trick). It works, but Supabase has a 1MB row limit by default. A single 1200px JPEG at 0.82 quality is 150–400KB. Two images and you're bumping the ceiling. Also, every list query drags those images across the wire even when you're not rendering them.

Fix: move to Supabase Storage. Create two buckets — note-images and card-images, scoped by user ID. Store only the public URL in the row. This is the single most important change for scaling the app past a few hundred notes.

Bug Search doesn't clear when you leave

If you search for something, then click Dashboard in the rail, the search box still has the old query and the library view is still technically populated. It's a small thing, but it makes the app feel sticky in the wrong way.

Fix: clear #searchInput inside showView() whenever the target view isn't library.

Bug Offline conflicts silently overwrite

If you edit a note online in another tab, then come back to this tab which has an offline edit queued, the offline edit wins without any warning. processOfflineQueue() just fires the update.

At minimum, compare updated_at timestamps before applying. If the server row is newer, drop the local edit and notify. It's not a full CRDT — it's just honest.

Part Two — What to Build Next

Ordered by ROI, not by excitement. Each of these is self-contained enough that you can ship it in a weekend.

Feature Pomodoro timer

This is the one I'd build today. It's small, it's visual, and it reinforces the study loop that the rest of the app is already built around.

What it looks like

Why this first

It's item #12 on your own list. It's self-contained. And unlike the more ambitious features, it makes the app feel alive on every screen without requiring the user to do anything.

Feature A real logo, and a copper accent

Right now the logo is a serif italic "R" next to the word "ecall". It's fine, but it doesn't read as a logo — it reads as a heading.

What to do

Two related colors, distinct roles. That's what makes a palette feel intentional instead of decorative.

Feature Color coding for cards and notes

You already have deck colors — gold, sage, brick. Extend the system one level down.

You can store it the same way you store MC data — a hidden suffix in the text field. Or just add a real color column. Either works; the column is cleaner.

Feature A sliding dock

Right now every feature is a full-page swap. You can't check your reminders without leaving the deck you're studying.

Build a persistent dock — vertical on the right edge for desktop, horizontal at the bottom for mobile. Five icons: Dashboard, Cards, Notes, Reminders, Pomodoro. Each one opens a slide-over panel (the same pattern you already use for studyPanel) instead of a full view change.

The active icon gets a copper underline. Everything else stays quiet.

Feature Auto-organizing, starting simple

Your list says "AI or edge functions." Start with the boring version first — it's 80% of the value for 5% of the effort.

Phase one — client-side, no LLM

Phase two — edge functions

Phase one alone will feel magical. Phase two is a nice-to-have.

Feature Snippets — code and file storage

A new view. Title, language, body, tags. Syntax highlighting via Shiki (lighter and prettier than Prism). A copy button, line numbers, and a dark code block that actually matches your paper theme.

Link snippets to notes and cards — "See snippet: binary search" from inside a card. Binary files go to Supabase Storage with metadata in a files table.

This is the feature that turns Recall from a study app into a proper second brain.

Part Three — Small Touches

None of these are features, but all of them are the difference between "nice app" and "app I open every day."

TouchWhy it matters
Italic serif for key wordsYou already use Newsreader for headings. Use italic serif for the user's name in the greeting, deck names in study, and the "due today" label. It becomes your typographic signature.
Subtle paper textureAn SVG noise filter on the --paper background. Makes the app feel physical.
Copper-to-gold gradient on the flameThe streak flame is currently flat gold. A gradient makes it feel earned.
Undo on deleteAdd an Undo button to delete toasts. Queue the delete, apply after 5 seconds. Safety net for misclicks.
View Transitions APIWrap showView() in document.startViewTransition(). One-line change, smooth transitions between views on modern browsers.
Haptic on card flipnavigator.vibrate(10) when flipping on mobile. Tiny, but noticeable.
Confetti on streak milestones7 days, 30 days, 100 days. A one-second canvas burst. Cheap, joyful.
Keyboard shortcut PStart or pause the Pomodoro from anywhere.
Keyboard shortcut FToggle favorite on the current note or deck.
Command palette additions"Start Pomodoro," "Toggle dark mode," "Export all data," "Delete all notes."

Part Four — What Not to Build

This section matters as much as the others. Every feature you add is a feature you have to maintain, and some of them actively dilute the app.

Skip Social features

Sharing decks publicly, following other users, leaderboards. All of it pulls attention away from the actual point, which is your own study loop.

Skip AI chat

You already have a command palette and search. A chat box would be a gimmick. The auto-tagging and "explain this card" features are useful because they're scoped. A general chat interface is not.

Skip Gamification badges

Streaks plus Pomodoro stats are enough. Badges and points feel cheap, and they train users to chase the badge instead of the learning.

Skip A calendar view

Your reminders list plus the activity chart already cover the ground a calendar would. Adding one would just be a second way to see the same data.

Skip Extra themes

One paper theme and one dark theme is plenty. Three themes is a design decision that starts to feel like an escape hatch for not committing to one.

Part Five — Six-Week Plan

Here's how I'd actually sequence this. Roughly a sprint per week, but realistically some weeks will slip and that's fine.

Week 1 — Signature look, plus the timer

Week 2 — Color and the dock

Week 3 — Auto-organize, phase one

Week 4 — Storage and PWA

Week 5 — Snippets

Week 6 — Auto-organize, phase two

If you only do one thing this week: build the Pomodoro timer. It's the smallest change on this list, it's the most visible, and it makes the app feel more finished than any of the bigger features will.

Closing

Recall is closer to being done than it looks. The foundations are solid — the auth flow, the offline queue, the SM-2 logic, the design system. What's missing is mostly the layer between "technically works" and "feels like a product you'd recommend to a friend."

The Pomodoro timer, the copper accent, and the logo monogram alone will shift that feeling more than you'd expect. Everything after that is polish and scale.

Start small. Ship one thing this week. The rest can wait.