Your notes are your tasks. Your tasks are your calendar.
A productivity app that merges infinite nested bullet-point notes with timeboxing and calendar management. Think Workflowy meets Sunsama — outline your thoughts, plan your day, and track your time in one place.
Most productivity tools force you to choose: you can have great notes (Obsidian, Notion) or you can have great task management (Todoist, Things) or you can have great calendar planning (Sunsama, Motion). But your brain doesn't work in silos. A meeting note becomes a task. A task needs a time slot. A time slot needs context from your notes.
Infinity Bullets treats everything as one thing: a bullet. A bullet can be a note, a task, a project, a kanban card, or a calendar event. It can nest infinitely, get a due date, land on your calendar, or become a board. There's no separate "tasks" tab or "calendar" app — it's all the same tree.
| Feature | Workflowy | Notion | Todoist | Infinity Bullets |
|---|---|---|---|---|
| Infinite nesting | Yes | Limited | No | Yes |
| Zoom into any bullet | Yes | No | No | Yes |
| Kanban from any bullet | No | Separate | Separate | Yes, inline toggle |
| Due dates on bullets | No | Yes | Yes | Yes |
| Timeboxing / calendar | No | No | No | Yes |
| Split view editing | No | No | No | Yes, up to 4 panes |
| Projects / folders | No | Yes | Yes | Yes |
| Offline-first, no account | No | No | No | Yes |
| Open source | No | No | No | Yes |
The core of the app. Every bullet can contain bullets, which can contain bullets, infinitely deep. Click any bullet's dot to zoom in — it becomes your entire view. Breadcrumbs let you navigate back up. This is how your brain organizes information: hierarchically, not in flat lists.
- Create bullets with
Enter, nest withTab, unnest withShift+Tab - Collapse/expand subtrees to manage complexity
- Drag and drop bullets to reorganize, with visual drop indicators
- Complete bullets with
Cmd+Enter(strikethrough)
Organize your bullets into a clean hierarchy:
Folders > Notebooks > Pages
Each Page contains its own infinite bullet tree. The sidebar gives you structure without sacrificing the freeform nature of the bullets inside. Search across all pages from the sidebar search bar. Double-click to rename. Right-click for context menus.
Any bullet with children can be toggled into a kanban board — no separate tool needed. The bullet's direct children become columns, and their children become cards.
- Toggle via the bullet's hover menu: "View as kanban"
- Drag cards between columns
- Drag columns to reorder
- Inline editing on column headers and cards
- Toggle back to list view anytime — same data, different presentation
Any bullet can have a due date. Add an optional time range and it becomes a timebox — a block on your calendar.
- Color-coded date chips on bullets:
- Red — overdue or due today
- Amber — due tomorrow
- Green — future date
- Blue — timeboxed (has a time range)
- Date picker with quick options (Today, Tomorrow, Next Mon, Next Fri)
- Mini calendar for picking specific dates
- Optional start/end time inputs for timeboxing
See your timeboxed bullets on a real calendar. Available as a per-page toggle (Bullets / Calendar) or as a global view showing all pages.
- Day view (default) and week view with toggle
- Time grid from 6am to 10pm with hour markers
- Drag unscheduled tasks from the sidebar onto the calendar to timebox them
- Drag existing blocks to reschedule
- Current time indicator (red line)
- Navigate between days/weeks with arrow buttons
Open up to 4 pages side-by-side in resizable vertical columns. Each pane has independent zoom and scroll. Edit in one pane and see live updates across all panes showing the same content.
- Open via bullet hover menu: "Open in split view"
- Resize panes by dragging the divider
- Close individual panes with the X button
- Breadcrumbs work independently per pane
Star any bullet for quick access. The bookmarks panel shows all starred bullets in tree order. Click to navigate, click again to remove. Bookmarks navigate within whichever split view pane is currently active.
Full dark mode support with a toggle in the header. Persisted to localStorage.
| Shortcut | Action |
|---|---|
Enter |
New bullet below |
Tab |
Indent (nest under previous sibling) |
Shift+Tab |
Outdent (move up a level) |
Backspace (empty bullet) |
Delete bullet, merge with previous |
Cmd+Enter |
Toggle complete (strikethrough) |
Cmd+B |
Toggle sidebar |
Alt+Left |
Zoom out one level |
Arrow Up/Down |
Navigate between visible bullets |
# Clone the repo
git clone https://github.com/chansty/infinity-bullets.git
cd infinity-bullets
# Install dependencies
pnpm install
# Start dev server
pnpm devOpen http://localhost:3000 and start typing. That's it — no accounts, no configuration, no database setup. Everything saves to your browser's IndexedDB.
pnpm build
pnpm start| Layer | Technology | Why |
|---|---|---|
| Framework | Next.js 16 (App Router) | Server components, fast dev experience |
| UI | React 19 | Latest concurrent features |
| Language | TypeScript (strict) | Type safety across the entire codebase |
| Styling | Tailwind CSS v4 | Utility-first, dark mode, fast iteration |
| State | Zustand | Lightweight, no boilerplate, great devtools |
| Storage | IndexedDB (via idb) |
Local-first, offline, large capacity |
| IDs | nanoid | Fast, URL-safe, unique identifiers |
Everything is a BulletNode. Folders, notebooks, pages, and bullets all share the same type with a type discriminator. This means every tree operation (insert, delete, move, indent, outdent, drag-drop) works uniformly across the entire hierarchy.
type BulletNode = {
id: string
content: string
parentId: string | null
children: string[] // ordered child IDs
type: "folder" | "notebook" | "page" | "bullet"
collapsed: boolean
completed: boolean
bookmarked: boolean
viewMode: "list" | "kanban"
dueDate: number | null // epoch ms
timeStart: number | null // timebox start
timeEnd: number | null // timebox end
tags: string[]
metadata: Record<string, unknown>
createdAt: number
updatedAt: number
}A single Zustand store holds all application state. The flat Record<string, BulletNode> structure gives O(1) lookups by ID, while parentId + children[] references encode the tree. All mutations are immutable (spread operator), and saves are debounced to IndexedDB at 300ms intervals.
src/
app/
page.tsx # Root layout with sidebar + main + split panels
layout.tsx # Next.js root layout
globals.css # Tailwind imports + custom styles
components/
BulletTree.tsx # Main panel: dashboard mode + page mode
BulletItem.tsx # Single bullet row with all interactions
BulletMenu.tsx # Hover context menu (zoom, bookmark, kanban, etc.)
Sidebar.tsx # Projects sidebar with search
SidebarItem.tsx # Folder/notebook/page row in sidebar
SidebarContextMenu.tsx # Right-click menu for sidebar items
SplitView.tsx # Split panel container + resize handles
KanbanBoard.tsx # Kanban view (columns + cards)
CalendarView.tsx # Day/week calendar with time grid
DateChip.tsx # Inline color-coded date badge on bullets
DatePicker.tsx # Date/time picker popover
Breadcrumbs.tsx # Zoom navigation path
BookmarksPanel.tsx # Bookmarks modal overlay
BookmarksButton.tsx # Header bookmark toggle
DarkModeToggle.tsx # Theme switcher
PanelContext.tsx # React context for split view identity
lib/
types.ts # BulletNode type, NodeType, ViewMode
store.ts # Zustand store (state + actions)
tree-operations.ts # Pure immutable tree mutation functions
db.ts # IndexedDB persistence layer
date-utils.ts # Date formatting and calendar math
Planned features, roughly in priority order:
- Reminders & notification feed with snooze/reschedule
- Google Calendar integration (read-only overlay of meetings)
- Bidirectional
[[linking]]between bullets - Global search across all content
- Claude "second brain" integration — AI-generated notes that grow over time
- Graph visualization of connected thoughts
- Tags and filtered views
- Mobile responsive layout
- Export/import (OPML, Markdown)
- Collaborative editing (CRDT-based sync)
This is a personal project, but contributions are welcome. Feel free to open issues for bugs or feature ideas.