Project Info
Inspiration
Memories as a whole are spatial, and one of the most powerful and nostalgic ways of capturing these memories is through photographs. They are the closest humans get to reliving their experiences, but we wondered if it was possible to get one step closer.
What it does
We came up with a way to relive your memories using Gaussian Splatting to reconstruct a 3D scene from natural language description of the memory, photos of the memory, or a video of the memory. Rem enables you to move inside the 3D space, which is customized by a creative agent to feel as closely as possible to how it felt in the moment.
How we built it
๐จ Frontend: Next.js 16 (App Router) + React 19 + Tailwind, with a three-screen flow (ingest โ loading โ 3D viewer) ๐๏ธ Voice input: intuitive browser-native Web Speech API for live transcription โ no audio leaves the device ๐ง Agent-based personalization system: Gemini + Pika MCP power a lightweight agent pipeline that transforms raw inputs into a consistent memory representation and guided reconstruction. We use two main components: Structured memory agents (Gemini sub-agents) vision: extracts structured understanding from uploaded photos analyzer: combines past memories + current input into a recurring โworld summaryโ extractor: isolates the relevant slice of that world for the new memory persona: builds a persistent, evolving visual identity across memories These help maintain consistency across reconstructions. Creative + tool-agent layer (Pika MCP) The system also includes a creative agent that generates the cinematic direction for each memory reconstruction. It takes the scene context and persona and translates them into a coherent visual style for the output. Supporting tools include: fix_look: re-grades video (lighting, palette, mood, clothing, accessories) while preserving geometry and identity music: selects or generates audio to maintain emotional continuity ๐ 3D rendering: Three.js + gsplat for real-time Gaussian Splat rendering, with a key points extracted from SfM using COLMAP โ gaussian initialization โ rasterization and gradient descent โ gaussian densification and pruning. ๐ Pipeline: user input โ personalization โ 3D memory reconstruction ๐พ Storage: Redis-backed job/scene store with an in-memory fallback, so the whole app degrades gracefully without infra ๐ Observability: OpenTelemetry tracing into Arize AX, plus an LLM-as-judge evaluator with a feedback loop for grading hotspot quality
Challenges we ran into
๐ฅ Consistent scene generation for 3D Gaussian Splatting (3DGS): Our initial approach relied on fully generated videos from Midjourney. However, 3DGS depends on Structure-from-Motion, which requires smooth camera motion and consistent scene geometry across frames. Generated videos frequently introduced temporal inconsistencies that degraded reconstruction quality. To address this, we shifted toward real photos and videos while using Pika MCP to apply controlled personalization. This preserved the consistency required for reconstruction while still allowing creative modifications. ๐ธ Tool costs: We also experimented with Veo3-generated videos, which produced significantly better temporal consistency. Unfortunately, the cost of generating sufficient video data quickly exhausted our available credits. With greater resources, we believe a fully generative memory reconstruction pipeline could become feasible. โณ Training times: Training each splat took a significant amount of time (at least 30 minutes), and would sometimes hang for very long if the input had many photos or frames. The led us to spend a lot of effort trying different training inputs, from generated videos to generative mesh view points. In the end, we realized that sampling every other frame in a video could significantly speed up the process with minimal impact on visual quality.
Accomplishments we're proud of
๐ฎ UI: We built a Three.js-powered viewer that successfully captures the feeling of stepping back into a memory rather than simply viewing media. โจ 3DGS Quality: Despite having only a single day to develop and iterate, we achieved surprisingly strong reconstruction quality. We were especially excited to reconstruct a live human subject with limited distortion, since dynamic people are traditionally challenging for Gaussian Splatting yet are central to many memories.
What we learned
We learned how to design systems with long-latency AI pipelines involving video generation, scene reconstruction, and personalization. We also gained a much deeper understanding of 3D Gaussian Splatting, particularly the importance of input consistency and data quality. Most importantly, we explored how creative agents can personalize experiences rather than simply generate content.
What's next
We plan on expanding Rem to be able to traverse multiple memories as once by grouping them. For example, if someone went to Florida for vacation, they can upload their photos of the beach, the southernmost point of the continental US, and Disney World separately and then group them to be able to navigate from one scene to another. Another large area we could go into is increasing shareability of memories. We will likely make Rem a platform where users can share their memories and information hotspots with other users. These other users can add their own memories to make more hotspots, turning it into a multi-layered reconstruction of one scene. It's like Harry Potter's Pensieve, where multiple memories are being layered and pulled out of one's brain. Like Dumbledore said, "I sometimes find, and I am sure you know the feeling, that I simply have too many thoughts and memories crammed into my mind." Rem gives those memories a place to live.
Rem โ walk through your memories in 3D
Write down a moment (and drop a photo or video), and Rem turns it into a 3D Gaussian-splat scene you can walk through. Built at the Berkeley AI Hackathon.
Two input modalities, same 3D output:
- Text / photo โ creative vision (Pika) โ AI video (Veo 3) โ
- Video โ re-graded to the memory's look (Pika fix-my-look; palette/lighting/mood changed, original geometry + camera motion preserved, so it stays COLMAP-friendly) โ
โฆthen โ frames โ COLMAP โ gaussian-splat training โ a scene.ply you explore in the browser.
Architecture โ 4 components, 2 deployments, 1 hosted DB
| Component | Runs on | Does | Code |
| ---------------- | ---------------------- | ------------------------------------------- | --------------------------------------------------- | ----------- |
| Frontend | the user's browser | input UI, progress bar, 3D viewer | src/app/**/page.tsx, src/components/ |
| Backend | Vercel (Next API) | create memory, start pipeline, serve status | src/app/api/, src/lib/ |
| DB + Storage | Supabase | the memory row (status + splat URL) + files | schema.sql, accessed via src/lib/ & pipeline/ |
| GPU pipeline | Modal | the heavy ML: (video | images)โframesโCOLMAPโgsplatโscene.ply | pipeline/ |
Frontend + Backend are one Next.js app (one deploy). The pipeline is a separate Python deploy on Modal. Supabase is a hosted service.
๐ฆ BROWSER โโHTTPโโโบ ๐ฉ VERCEL (Next API) โโtriggerโโโบ ๐ฅ MODAL (GPU pipeline)
โฒ โ โ
โ poll status โ create / read row โ write status + splat
โ download scene.ply โผ โผ
โโโโโโโโโโโโโโโโโ ๐ฆ SUPABASE (Postgres + Storage) โโโโโโโโโ
The browser and the GPU never talk directly โ the DB is the shared whiteboard.
End-to-end flow
1. ๐ฆ Browser user submits a journal entry + photo(s) and/or a video
2. ๐ฉ Backend POST /api/memories โ insert row (PENDING) โ upload files โ trigger Modal โ return { id }
3. ๐ฅ GPU run_pipeline:
agent layer โ persona-coherent prompt / creative look (Gemini + Pika MCP)
generate โ Veo 3 video (photo/text) OR fix-my-look re-grade (video)
score โ scene-appropriate music (Pika MCP, optional)
reconstruct โ frames โ COLMAP โ gaussian-splat training โ scene.ply
(writes status GENERATINGโRECONSTRUCTINGโTRAINING to the DB as it goes)
4. ๐ฅ GPU upload scene.ply to Storage โ update row (status=READY, splat_url=...)
5. ๐ฆ Browser polls GET /api/memories/:id every 2s โ sees READY โ loads splat_url into the viewer
POSTโModal is async (fire-and-forget). The pipeline runs its steps
in order (sync). The browser polls to learn when it's done. The big
scene.ply is downloaded directly from Storage โ it never passes through the backend.
Memories are also embedded (Voyage AI) and indexed in Redis for
"find memories like this one" similarity search (/api/memories/:id/similar).
The agent layer (how a memory becomes a coherent scene)
The pipeline is a plain script, but the GENERATE half is driven by a small set of
agents in pipeline/agents/ so each new memory stays visually consistent with the
person's past memories. Two patterns:
A. Prompted Gemini sub-agents โ one shared multimodal client, each agent is a focused system prompt:
visionโ reads the uploaded photos once โ a cached structuredPhotoAnalysis.analyzerโ past memories + this memory's vision โ the recurring "world summary."extractorโ pulls the slice of that world relevant to the new entry.personaโ merges it into a persistent, evolving persona spec (the visual identity).
B. Pika MCP tool-agents โ Gemini connected to the Pika MCP server as an MCP
client (OAuth via agents/pika_auth.py), using automatic tool-calling:
creativeโ authors the creative vision for the shot from the scene + persona.fix_lookโ runs Pika's fix-my-look skill to re-grade an input video to the memory's look (palette/lighting/mood) while preserving geometry, motion and identity.musicโ picks scene-appropriate music (search_music/generate_music) and mixes it under the clip (edit_audio_mix).
steps/compose_scene.py orchestrates them: vision โ analyzer โ extractor โ persona โ creative vision โ final prompt. Every Pika MCP agent is gated (PIKA_MCP_ENABLED)
and fail-safe โ if disabled or erroring it returns nothing and the pipeline falls
back (persona-only prompt, raw clip, no music), so reconstruction always runs.
Repo structure
hack-berkeley/
โโโ src/ โโ THE NEXT.JS APP (browser + backend) โโ
โ โโโ app/
โ โ โโโ page.tsx ๐ฆ ingest screen
โ โ โโโ memories/[id]/page.tsx ๐ฆ progress โ 3D viewer (polls status)
โ โ โโโ api/
โ โ โโโ memories/route.ts ๐ฉ POST create + start pipeline, GET list
โ โ โโโ memories/[id]/route.ts ๐ฉ GET status (the poll endpoint)
โ โ โโโ memories/[id]/similar/route.ts ๐ฉ semantic "similar memories" search
โ โ โโโ redis-health/route.ts ๐ฉ Redis connectivity check
โ โโโ components/ ๐ฆ ingest-screen, loading-screen, memory-viewer
โ โโโ lib/
โ โ โโโ supabase.ts ๐ฉ server-only Supabase client
โ โ โโโ db.ts ๐ฉ create/read the memories row
โ โ โโโ storage.ts ๐ฉ upload inputs / public URLs
โ โ โโโ modal.ts ๐ฉ trigger the GPU pipeline
โ โ โโโ embeddings.ts ๐ฉ text embeddings (Voyage AI)
โ โ โโโ memory-search.ts ๐ฉ Redis vector index + KNN search
โ โ โโโ redis.ts ๐ฉ Redis client
โ โโโ types/memory.ts ๐ shared types = Contract A + C
โ
โโโ pipeline/ โโ THE GPU SERVICE (Modal) โโ
โ โโโ app.py ๐ฅ Modal app + trigger endpoint
โ โโโ run_pipeline.py ๐ฅ the recipe (generate โ reconstruct)
โ โโโ db.py / storage.py ๐ฅ Supabase status writes / file I/O
โ โโโ media.py ๐ฅ photo-vs-video detection + first-frame grab
โ โโโ veo.py ๐ฅ Veo 3 video generation (gated)
โ โโโ persona_store.py ๐ฅ the evolving persona spec (singleton)
โ โโโ smoke_test.py / full_test.py ๐ฅ local GENERATE tests (no GPU/Supabase)
โ โโโ agents/ โโ the coherence agent layer โโ
โ โ โโโ client.py ๐ฅ shared multimodal Gemini client
โ โ โโโ vision.py ๐ฅ one-time photo read (cached)
โ โ โโโ analyzer.py ๐ฅ past memories โ world summary
โ โ โโโ extractor.py ๐ฅ relevant slice for this entry
โ โ โโโ persona.py ๐ฅ merge slice โ persona spec
โ โ โโโ creative.py ๐ฅ creative vision (Pika MCP)
โ โ โโโ fix_look.py ๐ฅ video re-grade (Pika fix-my-look)
โ โ โโโ music.py ๐ฅ scene-aware music (Pika MCP)
โ โ โโโ pika_auth.py ๐ฅ Pika MCP OAuth (authorize + refresh)
โ โโโ steps/
โ โโโ compose_scene.py ๐ฅ orchestrates the agents โ prompt + analysis
โ โโโ generate_video.py ๐ฅ Veo 3: creative prompt โ video
โ โโโ make_prompt.py ๐ฅ legacy one-shot prompt (superseded)
โ โโโ extract_frames.py ๐ฅ ffmpeg: video โ frames
โ โโโ colmap.py ๐ฅ frames โ camera poses
โ โโโ train_gsplat.py ๐ฅ poses โ trained gaussians
โ โโโ export.py ๐ฅ โ scene.ply
โ
โโโ schema.sql ๐ the memories table = Contract C
โโโ .env.local.example ๐ Next.js env keys
โโโ .agents/skills/ ๐ฆ vendored Pika skills (fix-my-look, persona-builder, โฆ)
API & status
POST /api/memories create a memory + start the pipeline
multipart: { description, photo? } (the file may be a video)
โ 201 { id }
GET /api/memories list memories
GET /api/memories/:id one memory (the browser polls this for status)
GET /api/memories/:id/similar semantically similar memories
Each memory moves through these states, which the UI renders:
PENDING โ GENERATING โ RECONSTRUCTING โ TRAINING โ READY | FAILED
Files live in the public memories Storage bucket: โฆ/inputs/<file> (the upload),
โฆ/frames/โฆ (for COLMAP), and โฆ/scene.ply (the splat the viewer loads).
Local setup
Prereqs
- Node 20+, Python 3.11+, a Supabase project, a Modal account.
1. Add the missing deps
npm i @supabase/supabase-js # backend talks to Supabase
(pipeline/requirements.txt is installed inside the Modal image, not locally.)
2. Supabase
- Run
schema.sqlin the SQL editor. - Create a public Storage bucket named
memories.
3. Env
cp .env.local.example .env.local # fill in the NEXT.JS section (Supabase, Voyage, Redis)
# set the PIPELINE values as a Modal secret:
modal secret create rem-secrets \
SUPABASE_URL=... SUPABASE_SERVICE_ROLE_KEY=... \
GEMINI_API_KEY=... MODAL_SECRET=...
# creative vision (Pika MCP, OAuth-only):
# 1) once, locally: cd pipeline && python -m agents.pika_auth authorize (browser)
# 2) ship the token file to Modal (PIKA_MCP_TOKEN_PATH) or set PIKA_MCP_REFRESH_TOKEN,
# then enable with PIKA_MCP_ENABLED=1 (silent refresh thereafter)
# video generation (Veo 3): add VEO_ENABLED=1 (reuses GEMINI_API_KEY)
4. Run
npm run dev # frontend + backend โ http://localhost:3000
modal serve pipeline/app.py # GPU pipeline (dev URL) โ put it in MODAL_URL
Conventions & notes
- Next.js 16 (App Router, Turbopack). โ ๏ธ
paramsin route handlers and server pages is aPromiseโawaitit (seeapi/memories/[id]/route.ts). PerAGENTS.md, this Next version has breaking changes: afternpm install, verify specifics againstnode_modules/next/dist/docs/before relying on any API.node_modulesis not committed, so those docs aren't on disk yet. - Server vs client:
src/lib/*is server-only (holds the service-role key) โ never import it from a"use client"component. The browser only talks to the backend viafetch. - Big files โ Storage, never the DB. The DB stores the
splat_urlstring; the browser downloads the file straight from Storage. - AI architecture: the pipeline recipe is a plain sequential script, but the
GENERATE half is driven by the agent layer (
pipeline/agents/, see the section above). Models in play: Gemini (persona/coherence sub-agents + photo vision), Pika MCP (creative vision, fix-my-look video re-grade, music), Veo 3 (video), and Voyage AI embeddings for similarity search. All Pika MCP calls are gated and fail-safe, so the splat still builds with them off. Backend calls are traced with Arize Phoenix.
Analysis
View
Metric
- 28
- 26
- 19
- 10
- 10
Figures cover GitHub contributors during the hackathon window. A co-authored commit counts in full for each author, so per-member totals add up to more than the whole-team figures.
Technology
- CSSIn code
- FastAPIIn code
- Next.jsIn code
- PythonIn code
- ReactIn code
- RedisIn code
- SQLIn code
- SupabaseIn code
- Tailwind CSSIn code
- TypeScriptIn code
- AnthropicClaimed
- Google GeminiClaimed
- JavaScriptClaimed
- Node.jsClaimed
10 of 14 appear in the indexed code. 4 claimed on Devpost could not be matched to code, which may simply mean the tool leaves no trace in the repository.
AI coding agents
- Claude CodeConfig ยท Commits
- CodexConfig
Detected from committed agent config files and commit authorship. Absence of a signal is not proof an agent was unused.
Codebase size
Source size
252 KB
Source files
66
Counts recognized source files only; vendored directories, binaries and lockfiles are excluded, so this is smaller than the repository on disk.
Repository
haileyl6171/rem
85 files ยท 37.2 MB ยท @ cda833c
Structure
Interface
9 files ยท 11%Screens, components and styles rendered to the user.
API & routing
6 files ยท 7%Request entry points: routes, handlers and controllers.
Application logic
44 files ยท 52%Domain rules, services and shared utilities.
Data & schema
1 file ยท 1%Schema definitions, migrations and data access.
Supporting
Layers are inferred from where files sit in the tree, not from reading the code. A project that names its directories unconventionally will read oddly here โ open the file browser to check anything the diagram implies.
Languages
- TypeScript45%
- Python40%
- Markdown10%
- CSS2%
- SQL2%
- Shell1%
Share of indexed source by file size. Binary and vendored files are excluded.
Dependencies
package.json
npm ยท 20- @arizeai/phoenix-otel
- @mkkellogg/gaussian-splats-3d
- @react-three/drei
- @react-three/fiber
- @react-three/postprocessing
- @supabase/supabase-js
- @types/three
- next
- react
- react-dom
- redis
- three
- +8 more
pipeline/requirements.txt
pypi ยท 9- fastapi
- google-genai
- gsplat
- mcp
- modal
- numpy
- plyfile
- requests
- supabase
Declared in the repositoryโs manifests at the indexed commit. A declared package is not proof it is used, and runtime dependencies are listed first.
This projectโs features have not been analysed yet.
Export this project's context (description, README, evidence, key source files) to chat with an AI agent elsewhere.