Orbit is an analog-future personal operating environment that learns your daily rhythms and figures out what to do next. Traditional to-do apps leave you with overwhelming lists of unranked checkboxes, while digital calendars force you to manually plan every half-hour block. When real life gets messy, those plans fall apart and you spend more time managing tools than doing actual work.

We built Orbit to solve that problem. Instead of asking you to schedule every task by hand, Orbit lets you brain-dump your thoughts through voice or a quick terminal prompt. It checks your personal habits, active commitments, and current time, then surfaces one clear recommendation for what to work on right now.

What makes Orbit different is that it treats your day as a fluid stream of focus rather than a rigid calendar grid. It separates fixed appointments from flexible goals, gives you a distraction-free focus cockpit to get work done, and recalculates your path as your day moves forward.


Inspiration

The idea started from our own frustration during busy college semesters and heavy development sprints. We would find ourselves juggling classes, workouts, team syncs, and project deadlines. We would write down natural thoughts like: "Review chapter 4 after lunch, workout before the 4 PM team sync, prep presentation slides."

Existing tools failed us on this simple way of thinking:

  1. To-do apps stripped away time context. They treated an urgent paper due at 5 PM with the exact same weight as a book we wanted to read someday.
  2. Calendar apps demanded exact start times, end times, and manual block placement before we even knew how long our morning work would take.
  3. Smart schedulers felt sterile and complex, designed for corporate meetings rather than real students and developers balancing energy and habits.

We realized people do not think in calendar grid coordinates. We think in relative anchors and routines: "I want to study after my nap," or "I need to workout before standup."

We designed Orbit around that mental model. Give the user a terminal prompt and an open microphone, capture natural thoughts, resolve relative phrases against personal context, and let deterministic logic guide the day forward.


What it does

When you open Orbit, you are greeted by Today’s Focus, anchored by the "What's Next" Hero Card.

+-------------------------------------------------------------------------+
| [O] ORBIT // ACTIVE OBJECTIVE                            SYS_DATE: TODAY|
|                                                                         |
|  Finish Operating Systems Lab                      [ 45 MIN ] [ 2:00 PM]|
|  "Scheduled for 2:00 PM right after your lecture (1:00 PM - 2:00 PM)."  |
|                                                                         |
|  [ > START MISSION ]     [ MARK DONE ]     [ SKIP ]     [ LOCK TIME ]   |
+-------------------------------------------------------------------------+

Here is how the complete user experience works:

  1. Capturing Intent (Voice or Terminal): At the bottom of the screen sits a terminal input bar (>) and a microphone button. You can type or speak naturally: "I have an OS lab meeting at 2pm, need to review pull requests for an hour after my afternoon workout, and pick up groceries." If you open Listening Mode (/listen), an audio-reactive visualizer pulses to your voice while the browser transcribes your speech in real time.

  2. Context and Constraint Reasoning: Orbit sends your input along with your timezone, wall clock, and stored personal profile to our extraction pipeline. In Personal Orbit (/orbit), you maintain a bento grid of personal context, including workout routines, class times, deep-work habits, and major countdown milestones (like "Moving to Malaysia in 18 days"). Orbit cross-references your input against these directives. If you say "review PRs after my workout", and your context records your workout from 3:00 PM to 4:00 PM, Orbit locks the task to 4:00 PM.

  3. Curating "The Path Ahead": Tasks are grouped into three distinct types:

    • Fixed: Hard commitments with set clock times (classes, meetings, scheduled calls).
    • Flexible: Action items with estimated durations that Orbit fits into open windows between your fixed commitments.
    • Informational: Passive notes and reminders that do not block your calendar.
  4. Executing in Focused Mode (/focus): Clicking START on the Hero Card opens a fullscreen, distraction-free environment with an animated starfield. Orbit tracks your active session with an SVG circular progress ring, keyboard shortcuts (Space to pause and resume, Esc to exit), and accurate timekeeping. When you finish, Orbit logs your session, calculates your efficiency score: $$\text{Efficiency} = \min\left(\text{round}\left(\frac{t_{\text{estimated}}}{t_{\text{actual}}} \times 100\right), 200\right)\%$$ calculates your daily streak based on distinct calendar days, marks the task complete in the database, and recalculates the next mission for your day.

  5. Tracking Cognitive Load in Weekly Flow (/week): The weekly view groups tasks across the current ISO week (Monday through Sunday), totals your daily hours, and renders a color-coded bar chart scaled to your heaviest day. Clicking any day opens an inspection drawer showing the exact task breakdown and completion status for that date.


How we built it

Orbit is built as a fast Next.js application that connects browser interactions, persistent relational storage, and AI reasoning.

graph LR
    subgraph Client ["Client (Next.js 16 + React 19)"]
        UI["Today / Week / Orbit Views"]
        Focus["Focus Mode & Starfield Engine"]
        Listen["Web Speech API & AudioContext"]
        Input["Persistent Terminal Input"]
    end

    subgraph Middleware ["Next.js Proxy Layer"]
        AuthMid["Cookie Auth & Token Refresh"]
        RouteGuard["safeNextPath Guard"]
    end

    subgraph API ["Next.js Route Handlers"]
        AIExtract["/api/ai/extract"]
        WhatsNext["/api/ai/whats-next"]
        TaskRoutes["/api/tasks & /api/tasks/week"]
        CtxRoutes["/api/context"]
        SessRoutes["/api/sessions"]
    end

    subgraph External ["Services & Storage"]
        Gemini["Google Gemini Model Chain"]
        Supabase["Supabase Postgres (ap-south-1)"]
    end

    Input -->|POST text, timeZone| AIExtract
    Listen -->|Audio Stream| Listen
    Listen -->|POST transcript| AIExtract
    UI -->|GET tz=Area/City| WhatsNext
    UI -->|GET / PATCH| TaskRoutes

    AIExtract -->|Fetch Context & Tasks| Supabase
    AIExtract -->|Prompt + Fallback Chain| Gemini
    AIExtract -->|Insert Tasks & Transcripts| Supabase
    WhatsNext -->|Query Pending Tasks| Supabase
    TaskRoutes -->|RLS-Scoped Queries| Supabase
    SessRoutes -->|Log Session & Update Task| Supabase

    AuthMid --> UI

1. Frontend and Custom Design System

  • Framework: Next.js 16.3.1 (App Router) with React 19.2.8 and TypeScript.
  • Styling and Tokens: We built a custom design system using CSS Custom Properties and CSS Modules (globals.css, pixel-effects.css, animations.css). We created 3-layer beveled pixel borders, dithered gradients, inset terminal inputs, CRT scanline overlays, and responsive step-based animations.
  • Typography: Self-hosted via next/font/google for Space Grotesk (headers), Hanken Grotesk (body copy), and JetBrains Mono (labels and telemetry).

2. Speech Processing and Voice Visualization

  • On /listen, we combined the browser Web Speech API (continuous: true, interimResults: true) with the Web Audio API (AudioContext + createAnalyser).
  • We sample frequency data from the microphone, calculate an audio level ($0.0 \dots 1.0$), and dynamically scale the concentric rings of the VoiceCore visualizer (scale(1 + audioLevel * 0.15)) alongside a 12-column pixel audio bar animation.

3. AI Extraction and Model Fallback Chain

  • When text or speech is submitted, /api/ai/extract injects the current wall clock, personal context directives, and existing tasks into a system prompt with a strict JSON schema.
  • We query the Gemini API using native HTTP fetch with an AbortSignal timeout. Rather than relying on a single model, we built a sequential fallback chain: $$\text{gemini-3.6-flash} \longrightarrow \text{gemini-3.7-flash} \longrightarrow \text{gemini-flash-latest} \longrightarrow \text{gemini-pro-latest}$$
  • A 25-second budget ceiling (GEMINI_BUDGET_MS) ensures that slow upstream responses fall back to our local regex parser (localFallback) before the host serverless timeout kills the request.

4. Deterministic "What's Next" Ranking Engine

In /api/ai/whats-next, we evaluate pending tasks for the user's local date using a clock-aware scoring algorithm:

  • Base Score: $\text{Priority} \times 10$ ($10 \dots 100$).
  • Fixed Commitment Urgency: Fixed tasks starting within 1 hour receive a $+50$ boost; within 2 hours, $+25$; already past, $-20$.
  • Flexible Window Optimization: Flexible tasks scheduled in the next 2-hour window receive $+15$; unscheduled flexible tasks receive $+5$.
  • Informational Demotion: Informational items receive $-30$ so they do not take over the hero card.
  • Dynamic Rationale: Generates contextual time-of-day explanations ("Best afternoon task given your current schedule...").

5. Database, Row-Level Security, and Auth

  • Supabase Postgres (ap-south-1): Four core tables: tasks, context_items, sessions, and transcripts.
  • Row Level Security (RLS): Every table has strict policies enforcing auth.uid() = user_id.
  • Cookie-Based SSR Authentication: Handled via @supabase/ssr across Client Components, Route Handlers, and Next.js Middleware, with open-redirect guards (safeNextPath) preventing off-site redirects.

Challenges we ran into

Building Orbit required solving practical problems across timezones, browser quirks, and AI predictability.

1. The UTC Timezone Trap

In early versions, evening tasks kept disappearing from the Today view. This happened because new Date().toISOString().slice(0, 10) generates a UTC date. For users behind GMT (like New York or San Francisco), an evening task created at 8:00 PM local was tagged with tomorrow's UTC date.

  • Our Solution: We built a dedicated timezone module in src/lib/time.ts. The browser sends its IANA timezone (clientTimeZone()), and the server parses dates using Intl.DateTimeFormat("en-CA", { timeZone }). We also standardized day arithmetic around UTC-midnight timestamps to prevent daylight saving changes from skipping dates.

2. The Dangerous GET-Route Data Repair Bug

Early on, our task fetch route attempted to clean up unparseable time strings (like "after my nap") by looping through rows during a GET request and writing scheduled_time: null back to the database. This meant simply visiting the homepage erased the user's original time data.

  • Our Solution: We separated display formatting from data storage. We created withDisplayableTime(), which cleans up objects in memory for the UI while keeping the database records safe.

3. Focus Timer Drift in Background Tabs

Our initial focus timer used a basic setInterval(..., 1000) that incremented a second counter. However, browsers throttle intervals in background tabs to save power. A user who switched tabs during a 25-minute study session would return to find the timer had only counted 14 minutes.

  • Our Solution: We switched from tick counting to true wall-clock tracking. We store a runningSince timestamp (Date.now()) and an accumulated bankedSeconds value. When the timer updates, it computes the exact difference against the system clock. We also saved this state in localStorage under RESUME_KEY, allowing active sessions to survive accidental page refreshes.

4. Microphone Leaks on Route Navigation

While testing /listen, we noticed the browser microphone indicator stayed on even after navigating back to the home page. The component cleanup was stopping the audio visualizer node but leaving the underlying SpeechRecognition session open.

  • Our Solution: We created a centralized stopCapture() cleanup function inside an unmount effect that stops SpeechRecognition, closes the AudioContext, and calls .stop() on every track of the MediaStream.

5. Cross-Component State Sync

When a user added tasks through the bottom InputBar or completed voice input in /listen, navigating to / showed an outdated timeline. Because TodayPage fetched data in a client useEffect, calling router.refresh() did not trigger a refetch.

  • Our Solution: We created a lightweight event bus using native DOM events (src/lib/taskEvents.ts). When tasks are added or updated, notifyTasksChanged() dispatches orbit:tasks-changed, telling all mounted views to refresh immediately without a full page reload.

Accomplishments that we’re proud of

  • Zero-Dependency Native Unit Test Suite: We wrote a test suite in src/lib/*.test.mts using Node 24’s native node:test runner. All 21 tests pass with zero extra test dependencies, verifying time parsers, date calculations, leap years, DST shifts, and security guards.
  • Honest, Cohesive UX Over Feature Bloat: During UI audits, we found placeholder buttons (such as an unbuilt calendar sync button). Instead of keeping non-working controls, we replaced them with an honest status page at /calendar explaining that Orbit currently plans only from direct input.
  • Custom PixelDialog System: Instead of breaking immersion with OS-native window.prompt() and window.confirm() popups, we built a custom, accessible in-app PixelDialog component that matches our retro-futuristic style.
  • Strict API Boundary Validation: In src/lib/apiError.ts, we wrote input validators (str(), int(), readJson()) that verify every payload field, preventing malformed data, prototype pollution, or unvalidated database writes.
  • Motion Accessibility: We built a global prefers-reduced-motion rule in animations.css. It collapses continuous loops (pulsing orbs, drifting starfield, CRT scanlines, blinking cursors) down to $0.01\text{ms}$ transitions so users with motion sensitivities can use Orbit comfortably.

What we learned

  • AI needs deterministic guardrails: Language models are great at understanding human context (like knowing that "sync after lunch" means 1:00 PM), but they are probabilistic and should not manage application state directly. The most reliable pattern is wrapping the model with strict validation: structured context injection before the call, and schema verification after it.
  • Time handling requires real discipline: Time in web development involves timezones, wall-clock perception, ISO calendar standards, and user habits. Getting time calculations right across serverless runtimes, databases, and client browsers took careful engineering.
  • Tactile aesthetics improve daily focus: Building an interface with deliberate pixel borders, audio visualizers, and clear button feedback made planning feel rewarding. When a productivity tool feels responsive and enjoyable, using it stops feeling like a chore.

What’s next for Orbit-AI

Near-term

  • Two-Way Google and Outlook Calendar Sync: Add OAuth2 integrations with Google Calendar and Outlook so Orbit can import external events into the fixed timeline and export finished focus blocks.
  • Server Components Fetch Optimization: Move initial data fetching on /, /orbit, and /week into React Server Components with streaming Suspense boundaries, removing loading skeleton flashes.
  • Interactive Timeline Drag and Lock: Add tactile drag-and-drop handles on the Today timeline to let users manually reorder tasks and lock flexible time slots.

Long-term

  • Multi-Day Cognitive Load Balancing: Expand our ranking algorithms to look across entire weeks, spreading out heavy tasks based on past focus session history to prevent burnout.
  • Passive Context Memory Extraction: Allow the AI pipeline to analyze transcribed voice notes and suggest new personal context items automatically (for example, detecting a recurring weekly tennis class and adding it as a habit).
  • Multi-Device Focus Telemetry: Add synchronized focus rooms so friends or teammates can share focus sessions and daily streaks in real time.
Share this project:

Updates

Submission history