{"id":38305636,"url":"https://github.com/zsh-eng/spaced","last_synced_at":"2026-01-17T02:27:03.132Z","repository":{"id":231976603,"uuid":"782965666","full_name":"zsh-eng/spaced","owner":"zsh-eng","description":"A modern flashcard app.","archived":false,"fork":false,"pushed_at":"2025-02-08T04:51:47.000Z","size":1230,"stargazers_count":30,"open_issues_count":31,"forks_count":5,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-08T05:21:50.417Z","etag":null,"topics":["flashcards","spaced-repetition"],"latest_commit_sha":null,"homepage":"https://spaced.zsheng.app","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zsh-eng.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-04-06T14:57:10.000Z","updated_at":"2025-02-08T04:51:51.000Z","dependencies_parsed_at":"2024-12-10T16:28:41.317Z","dependency_job_id":"8b8da254-f7a0-4ea4-bc26-4c4c3055e4a0","html_url":"https://github.com/zsh-eng/spaced","commit_stats":null,"previous_names":["zsh-eng/spaced"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/zsh-eng/spaced","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zsh-eng%2Fspaced","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zsh-eng%2Fspaced/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zsh-eng%2Fspaced/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zsh-eng%2Fspaced/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zsh-eng","download_url":"https://codeload.github.com/zsh-eng/spaced/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zsh-eng%2Fspaced/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28492288,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-17T00:50:05.742Z","status":"online","status_checked_at":"2026-01-17T02:00:07.808Z","response_time":85,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["flashcards","spaced-repetition"],"created_at":"2026-01-17T02:27:02.353Z","updated_at":"2026-01-17T02:27:03.122Z","avatar_url":"https://github.com/zsh-eng.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 🔭 spaced\n\n[Check out spaced here!](https://spaced.zsheng.app/)\n\n🔭 spaced is a modern flashcard app that helps you learn faster and remember longer.\nIt uses spaced repetition to help you learn more efficiently.\n\nNote: This is project is still in early development.\nIf you have any suggestions or feedback, please feel free to open an issue.\n\n## NOTICE\n\nThe second one is always better.\n\nI've been building a new version of spaced that is local-first, works offline, is much faster, has better UX, and shows you your stats.\n\nCheck it out [here](https://github.com/zsh-eng/spaced2).\n\n![spaced2](./spaced-screenshots.png)\n\n## Motivation\n\nSpaced repetition is proven to be one of the **most effective ways to learn**.\n\nCurrently, there are many great apps out there that use spaced repetition, such as\n[Anki](https://ankiweb.net/), [SuperMemo](https://www.supermemo.com/en/blog/twenty-rules-of-formulating-knowledge),\nand [RemNote](https://www.remnote.com/).\n\nPersonally, I use `obsidian-spaced-repetition`, which I love because of the tight integration with Obsidian.\nI believe that [markdown](https://www.markdownguide.org/) is the best way to store your flashcards.\n\nHowever, one aspect that I dislike about both `obsidian-spaced-repetition`\n(and other tools like ObsidianToAnki)\nis the separator syntax that is used to create flashcards.\nFor my own personal workflow, I use Obsidian to write notes\n, but writing flashcards adds clutter.\nFundamentally, I believe that flashcards should be treated\nas separate entities that are _colocated_ with your notes,\nbut different in the following ways:\n\n1. Flashcards should only be seen during review.\n2. There is no need to search / index / tag flashcards in the same way that notes are searched.\n   The whole point of flashcards is to only appear when they need to be reviewed.\n\nThus, I created **spaced**, which focuses on handling the spaced repetition aspect of learning.\nThis way, I can focus on writing notes that are easy to read and understand (in Obsidian),\nand create flashcards that are effective for spaced repetition (in spaced).\n\n### Example\n\nHere's an example of my existing notes using Obsidian Spaced Repetition:\n\n```markdown\n#### Dynamic and Static Binding\n\nWhat is dynamic binding (aka late binding)?\n?\nA mechanism where _method calls_ in code are resolved at **runtime** rather than at compile time.\n\n\u003c!--SR:!2024-01-02,25,249--\u003e\n\nWhat is static binding?\n?\nWhen a _method call_ is resolved at _compile_ time.\n\n\u003c!--SR:!2024-03-24,94,271--\u003e\n\nOverriden and overloaded methods: static or dynamic binding?\n?\nOverridden methods are resolved using **dynamic binding**, and therefore resolves to the implementation in the actual type of the object.\nIn contrast, overloaded methods are resolved using **static binding**.\n\n\u003c!--SR:!2024-03-12,85,271--\u003e\n```\n\nHere's my ideal syntax:\n\n```markdown\n#### Dynamic and Static Binding\n\n**Dynamic Binding (Late Binding)**: A mechanism where _method calls_ in code are resolved at **runtime** rather than at compile time.\nOverriden methods are resolved using **dynamic binding**.\n\n\u003c!-- id:\u003csome-card-id-here, where flashcards are stored separately\u003e --\u003e\n\n**Static binding**: When a _method call_ is resolved at _compile_ time.\nOverloaded methods are resolved using **static binding**.\n\n\u003c!-- id:\u003csome-card-id-here, where flashcards are stored separately\u003e --\u003e\n```\n\n### Why not just use local storage? Why not keep it all in Obsidian?\n\n1. I don't always have access to my Obsidian vault - I want to be able to review flashcards on the go.\n2. I want to be able to easily share flashcards with others.\n3. I want to create a UI/UX that _I_ personally enjoy using.\n   One of the big criticisms that I have of `obsidian-spaced-repetition` is that it doesn't store the history of your reviews.\n   You also cannot undo a review, which is annoying if you accidentally mark something as \"easy\".\n\n## Self Hosting\n\nIf you want to self-host this project, you can do so by following these steps:\n\n1. Fork the repository.\n2. Generate a new `AUTH_SECRET` with the following command\n\n   ```shell\n   pnpm dlx auth secret\n   ```\n\n3. Create a new [GitHub OAuth App](https://authjs.dev/guides/configuring-github).\n4. Fill in the `.env` file with the `AUTH_GITHUB_ID` and `AUTH_GITHUB_SECRET`.\n5. Create a new database in [Turso](https://turso.dev/).\n6. Fill in the `.env` file with the `TURSO_DATABASE_URL` and `TURSO_AUTH_TOKEN`.\n7. (Optional): To support image uploads, I use a custom\n   [Cloudflare Worker](https://github.com/zsh-eng/image-upload).\n   If you don't want to, just fill in a dummy value for\n   `CLOUDFLARE_IMAGE_UPLOAD_WORKER_TOKEN`.\n8. Run the following command to create the database tables:\n\n   ```shell\n   pnpm db:push\n   ```\n\n9. Deploy the app to [Vercel](https://vercel.com/).\n10. Done! You should now be able to access your own instance of **spaced**.\n\n## Resources\n\n- [SuperMemo's Twenty Rules of Formulating Knowledge](https://www.supermemo.com/en/blog/twenty-rules-of-formulating-knowledge)\n\n## Acknowledgements\n\nThis project was built using the following tech stack:\n\n- Next.js\n- **UI:** TailwindCSS, shadcn/ui\n- **Backend**: tRPC\n- **Database**: Turso\n- **ORM**: Drizzle\n\nGreat Libraries:\n\n- **Spaced Repetition**: [ts-fsrs](https://github.com/open-spaced-repetition/ts-fsrs)\n- **Swipe gestures**: [react-swipeable](https://www.npmjs.com/package/react-swipeable)\n- **Markdown editing**: [Milkdown](https://milkdown.dev/)\n- **Icons**: [Lucide](https://lucide.dev/icons/)\n\nI've also learned a lot from the following resources:\n\n- [Lexical](https://lexical.dev/): referenced their implementation of undo / redo\n- [ts-fsrs-demo](https://github.com/ishiko732/ts-fsrs-demo): structure for a spaced repetition app\n- [Radix UI](https://www.radix-ui.com/primitives/docs/components/toast): building swipe gestures\n- [obsidian-spaced-repetition](https://github.com/st3v3nmw/obsidian-spaced-repetition)\n\nFinally, a special thanks to @ishiko732 for answering questions regarding `ts-fsrs` and spaced repetition.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzsh-eng%2Fspaced","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzsh-eng%2Fspaced","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzsh-eng%2Fspaced/lists"}