⚠️ This project is currently in development. Official release coming soon!
3D Emotion Visualization & Personal Wellness Tracking Platform
- 📖 Overview
- ✨ Key Features
- 🛠 Tech Stack
- 🏗 Architecture
- 🔧 Technical Challenges & Solutions
- 🚀 Getting Started
- 📸 Screenshots
- 🗓 Roadmap
- 🔗 Related
- 👤 Author
ZeroGravity is a personal wellness application that helps users track and visualize their emotions through an immersive 3D experience. The platform transforms emotional data into beautiful, interactive 3D planets that morph and change based on your emotional state.
📌 Rebuilt from an incomplete collaborative Vue project into a full-featured solo full-stack application. Original Vue version | Backend Repository
- 🎨 Visual Emotion Tracking - Transform abstract emotions into tangible 3D visualizations
- 📊 Data-Driven Insights - Analyze emotional patterns over time with interactive charts
- 🤖 AI-Powered Suggestions - Get intelligent emotion predictions from diary entries
- 🧩 Cross-Platform - Seamlessly sync between web app and Chrome extension
| Feature | Description | Tech |
|---|---|---|
| 🌍 3D Emotion Planets | Custom GLSL shaders with simplex noise, smooth lerp transitions | Three.js, R3F, Lamina |
| 📝 3-Step Recording | Emotion Level → Reason → Diary with URL-based navigation | React Context, Next.js |
| 📅 Responsive Calendar | Desktop/mobile calendar with emotion detail drawer | date-fns, Radix UI |
| 📊 Chart Analytics | Time period navigation (week/month/year) with statistics | Chart.js |
| 🤖 AI Prediction | Gemini-powered emotion suggestions from diary entries | Google Gemini API |
| 🧩 Chrome Extension | New tab override synced with web app (auth & theme) | Vite, Manifest V3 |
| 🔐 OAuth Auth | Google & Kakao social login with secure session | NextAuth v5 |
| 🧘 Spaceout Mode | Meditation feature with sequential video playback | Next.js |
| Category | Technologies |
|---|---|
| Frontend | Next.js 15 (App Router), React 19, TypeScript |
| 3D Graphics | Three.js, React Three Fiber, Lamina, Custom GLSL Shaders |
| AI | Google Gemini API |
| Authentication | NextAuth v5 (Google, Kakao OAuth) |
| State Management | TanStack Query, React Context |
| Styling | Tailwind CSS 4, Radix UI Themes |
| Build | pnpm Workspace, Vite (library mode) |
| Deploy | Docker, nginx, OCI (Oracle Cloud), GitHub Actions |
| DevOps | Zero-downtime deployment, Health checks, Auto-rollback |
zerogravity-react/
├── packages/
│ ├── web/ # Next.js 15 Web Application
│ │ ├── src/app/ # App Router with route groups
│ │ │ ├── (public)/ # Login, Home, Terms
│ │ │ └── (protected)/ # Record, Profile, Spaceout
│ │ ├── src/services/ # API service layer (dto/query/service)
│ │ └── src/lib/ # Auth, Axios configuration
│ │
│ ├── extension/ # Chrome Extension (Manifest V3)
│ │ ├── src/lib/ # Chrome Cookies API integration
│ │ └── public/ # Extension manifest & assets
│ │
│ └── shared/ # Shared Library
│ ├── components/ # UI components (Clock, Navigation, etc.)
│ │ └── ui/emotion/ # 3D Planet with GLSL shaders
│ ├── hooks/ # Shared React hooks
│ └── utils/ # Utility functions
│
├── .github/workflows/ # CI/CD (deploy, build-extension)
├── pnpm-workspace.yaml # Monorepo configuration
└── package.json # Root dependencies
The Challenge: I wanted to build a Chrome Extension to improve accessibility - users could see their emotion planet right from their new tab. But Chrome Extensions don't support SSR, making Next.js unusable for the extension.
The Solution: Instead of migrating everything to Vite (losing Next.js benefits), I created a shared package containing the 3D planet and common UI components. The extension displays the same home experience, then links users to the full web app for recording and analytics.
The Result:
packages/web: Full Next.js app with SSR, auth, and all featurespackages/extension: Lightweight Vite build for Chrome new tabpackages/shared: Common components used by both (3D planet, clock, theme)
Problem: Share UI components between Next.js app and Chrome Extension with full type safety
Solution:
- pnpm workspace with 3 packages (web, extension, shared)
- Vite library mode with multiple entry points
- TypeScript declaration generation for shared package
Outcome: Tree-shakeable shared library with full type safety across packages
Problem: Need organic, smooth emotion visualization that morphs based on emotional state
Solution:
- Custom GLSL vertex shader with simplex noise 4D (Ian McEwan's Ashima Arts implementation)
- Smooth lerp transitions (0.03 speed) for colors, frequencies, and material properties
three-custom-shader-materialfor extending MeshPhysicalMaterial
Outcome: Visually engaging 3D planets that smoothly morph based on emotion level
// Wobble effect using simplex noise
float getWobble(vec3 position) {
vec3 warpedPosition = position;
warpedPosition += simplexNoise4d(vec4(
position * uWarpPositionFrequency,
uTime * uWarpTimeFrequency
)) * uWarpStrength;
return simplexNoise4d(vec4(
warpedPosition * uPositionFrequency,
uTime * uTimeFrequency
)) * uStrength;
}Problem: Chrome Extension needs to access NextAuth session from web app without separate login
Solution:
- Chrome Cookies API reads NextAuth session cookies (
authjs.session-token) - HTTP/HTTPS cookie name handling for different environments
- Session validation via
/api/auth/sessionendpoint
Outcome: Seamless authentication - login once on web, automatically authenticated in extension
Problem: 502 errors during failed deployments caused service interruption
Solution:
- Build-first strategy: Build new Docker image BEFORE stopping old container
- Image-based rollback: Backup current image, restore instantly on failure (no rebuild)
- 150-second health check: 30 attempts × 5 seconds with container inspection
Outcome: Old container keeps running if build fails, instant rollback from backup image
# Build new image (old container still running)
docker build -t zerogv-frontend:${ENV}-new .
# Backup current image
docker tag zerogv-frontend:${ENV} zerogv-frontend:${ENV}-backup
# Swap containers only after successful build
docker compose down && docker compose up -d- Node.js >= 18
- pnpm >= 8
# Clone the repository
git clone https://github.com/zerogravity-project/zerogravity-react.git
cd zerogravity-react
# Install dependencies
pnpm install
# Set up environment variables
cp packages/web/.env.example packages/web/.env.local# Start web application
pnpm dev:web # http://localhost:3000
# Start extension development
pnpm dev:extension # Load unpacked from packages/extension/dist
# Build all packages
pnpm build:all
# Type check
pnpm type-check:all
# Lint
pnpm lint:all# NextAuth Configuration
AUTH_SECRET=your-secret
AUTH_URL=http://localhost:3000
AUTH_GOOGLE_ID=your-google-client-id
AUTH_GOOGLE_SECRET=your-google-client-secret
AUTH_KAKAO_ID=your-kakao-client-id
AUTH_KAKAO_SECRET=your-kakao-client-secret
# Backend API
NEXT_PUBLIC_API_BASE_URL=https://api.zerogv.com🚧 Screenshots are being prepared...
- Mobile app (React Native)
- More emotion visualization themes
- Social features (share emotions with friends)
- Advanced AI insights with trend analysis
Minuk Hwang - Fullstack Developer
Made with ❤️ and ☕