Lofty Morning Handoff ✦
Built at GlobeHack S1 · 36 hours · Solo
## 💡 Inspiration
Real estate is a game of timing — and most agents are losing it every night.
Leads don't browse listings at 9 AM. They browse at 2 AM. They submit pre-approval letters before dawn. They compare agents by the time the sun rises. And by the time a real estate agent opens their laptop
with their morning coffee, the window has already closed.
I kept thinking: what if the agent's AI never slept?
Lofty's AOS (Agent Operating System) already handles overnight automation — follow-ups, showing requests, buyer matching. But there was a missing layer: the intelligent morning handoff. A system that takes
everything AOS did overnight, synthesizes it, and hands it to the agent in a way they can act on in seconds — not minutes.
That became the obsession. Not just a dashboard. A morning briefing system — narrated, ranked, and approval-ready before the agent finishes their first cup of coffee.
## 🏗️ What We Built
### The Flow
Agent wakes up
↓
Opens Lofty Morning Handoff
↓
🎬 Narrated video briefing plays automatically
↓
📋 Transcript reveals all overnight action items
↓
⚡ Priority queue — ranked by AI confidence score
↓
One-tap: Approve · Delegate · Edit · Snooze
↓
Ask Lofty anything in plain English (⌘K)
### Key Features
🎬 Morning Briefing Video
- Animated particle canvas with nebula glow backgrounds
- Web Speech API narration — each slide advances only when speech completes
- Per-lead slides with buyer/seller indicators, character avatars, score rings, and signal timelines
- Cinematic reveal animations: clip-path scans, expanding rings, staggered signal entries, glowing confidence bars
- Keyboard controls:
Spacepause ·←→navigate ·Mmute ·Escskip
⚡ Priority Queue
- AI-ranked leads with confidence scores and signal-driven explanations
- Drag-to-reorder with custom priority saved to
sessionStorage - Action modes per card: Approve & Execute · Edit recommendation · Delegate to team · Snooze
- All actions logged to InsForge audit trail in real time
🧠 Confidence Score Engine
- 5-factor weighted model:
$$\text{Confidence} = \frac{\sum_{i} w_i \cdot f_i}{\sum_{i} w_i}$$
| Factor | What it measures |
|---|---|
| 📊 Signal Volume | How many overnight signals the lead generated |
| ⏱ Recency | How fresh the most recent signal is |
| 🎯 Lead Score | The CRM base score (0–100) |
| 🔀 Signal Diversity | Variety of signal types (visit, email, showing…) |
| ⚡ Urgency | Deadline pressure or missed response time |
- All weights are live-adjustable via the ⚙ Tune Model drawer — changes apply instantly across every card
- Weights persist to
localStorageacross sessions - Per-factor breakdown visible in the Why This Matters drawer
🤖 Ask Lofty (⌘K)
- Natural language AI assistant powered by Llama 3.3-70B via HuggingFace
- Passes live queue context into the system prompt — answers are lead-specific
- Detects email drafts and renders them in monospace with a Copy button
- Suggestion chips on focus · instant fallback if LLM is unavailable
## 🔧 How We Built It
### Architecture
┌─────────────────────────────────────────────────┐
│ Frontend │
│ Next.js 16 App Router · React 19 · TypeScript │
│ Tailwind v4 · Framer Motion · shadcn/ui │
└─────────────────┬───────────────────────────────┘
│
┌─────────┴─────────┐
▼ ▼
┌──────────────┐ ┌─────────────────┐
│ InsForge │ │ HuggingFace │
│ (Postgres + │ │ Llama 3.3-70B │
│ Auth + Edge │ │ Together Router│
│ Functions) │ └─────────────────┘
└──────────────┘
│
priority_queue · leads · lead_signals
approvals · audit_log
### Build Order
- → Scaffolded Next.js with Tailwind and shadcn/ui
- → Seeded
lib/mock-data.tswith 5 realistic leads + overnight signals - → Built the video player with particle canvas and Web Speech API narration
- → Built action cards with all 4 action modes and drag-to-reorder
- → Wired InsForge backend (
priority_queue,leads,lead_signalstables) - → Added HuggingFace Llama 3.3-70B for Ask Lofty and Why This Matters
- → Built the 5-factor confidence engine with adjustable weights
- → Animated all video slides into cinematic reveals
- → Dockerized and deployed
## 🚧 Challenges
→ Speech-driven slide timing
Browser speechSynthesis fires onend unreliably — sometimes never. The naive approach (fixed 6s timer) cut audio off mid-sentence. The fix: decouple visual progress (fills to 95% via interval) from
advancement (triggered only by onend), with a 20s safety timeout as fallback and a advancedRef mutex to prevent double-advance.
→ Canvas sizing at mount
canvas.offsetWidth returns 0 before layout completes. Every particle animation started at 0×0. Fix: defer initialization one frame with requestAnimationFrame, use parentElement.clientWidth as the size
source, and apply HiDPI scaling via ctx.setTransform(dpr, 0, 0, dpr, 0, 0).
→ Pause re-triggering speech
Adding paused to the speech useEffect dependency array caused the utterance to restart on every pause/resume — the opposite of pausing. Fix: remove paused from deps, use speechSynthesis.pause() /
speechSynthesis.resume() in a separate effect, and read pause state through a pausedRef in callbacks.
→ Framer Motion + HTML drag events
motion.div's onDragStart has a different type signature than the HTML5 drag API. Wrapping motion.div in a plain <div> for drag events and keeping motion.div for animation only resolved the TypeScript
conflict cleanly.
→ Confidence model UX
The model needs to feel controllable, not like a black box. The solution: a live-preview tuner where every slider change immediately re-renders all queue cards with the new weights, showing the before/after
delta inline. Judges and agents can see exactly what's driving each score.
## 📚 What We Learned
- Speech APIs are deceptively fragile — browser TTS has significant cross-platform inconsistencies that require layered fallbacks
- Canvas timing requires patience — React's render cycle and browser layout don't align;
requestAnimationFrameis the bridge - InsForge is genuinely fast to wire — Postgres + SDK took under 2 hours end-to-end including schema design and seeding
- Explainability matters in AI UX — showing why a score is what it is (and letting users change it) builds far more trust than just showing a number
- Hackathon shipping is about the demo moment — every technical decision was filtered through "will this look right at 2 AM with 5 minutes left?"
## 🛠️ Tech Stack
| Layer | Technology |
|---|---|
| Frontend | Next.js 16 (App Router), React 19, TypeScript |
| Styling | Tailwind CSS v4, Framer Motion, shadcn/ui |
| AI / LLM | Llama 3.3-70B via HuggingFace Together Router |
| Backend | InsForge (Postgres + Auth + Edge Functions) |
| Audio | Web Speech API (speechSynthesis) |
| Deploy | Docker + docker-compose |
Built With
- audit-log)-apis-&-browser-apis-web-speech-api-(speechsynthesis)
- auth
- css-frameworks-&-libraries-next.js-16-(app-router)
- docker-compose-dev-tools-claude-code-(ai-pair-programming)
- edge-functions
- framer-motion
- git
- github
- html5-canvas-api
- html5-drag-and-drop-api-infrastructure-&-devops-docker
- huggingface-inference-api
- javascript
- languages-typescript
- node.js
- react-19
- shadcn/ui-ai-/-llm-llama-3.3-70b-instruct-turbo-(via-huggingface-together-router)-backend-&-database-insforge-(postgres
- tailwind-css-v4
Log in or sign up for Devpost to join the conversation.