A stunning web application featuring virtual VRM characters with real-time animations, dynamic model/animation management, and interactive UI with Supabase backend.
- πͺ Real-time VRM Rendering - 3D character rendering with Three.js and @pixiv/three-vrm
- π VRMA Animation Queue - Automatic animation playback with lazy loading and shuffling
- π¨ Dynamic Model Switcher - Easy switching between multiple VRM models from database
- π Background Customization - Multiple background options with cookie persistence
- π Admin Panel - Upload and manage VRM models and animations (admin only)
- πΎ Database Integration - Supabase backend for models and animations storage
- πΎ Cookie-based State Persistence - Remembers user's selected model and background
- π± Responsive UI - Modern glassmorphism design with Tailwind CSS
- β‘ Performance Optimized - Lazy loading, smart caching, and efficient animation management
- π Auto-retry System - Automatically retries incompatible animations until finding compatible ones
- Node.js 18+
- npm, yarn, or pnpm
- Supabase account and project
- Clone and install
git clone https://github.com/yourusername/vrm-dance-web.git
cd vrm-dance-web
npm install- Setup Supabase
- Create a Supabase project at https://supabase.com
- Copy
.env.exampleto.env.local - Fill in your Supabase credentials:
NEXT_PUBLIC_SUPABASE_URL=your-project-url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
SUPABASE_SERVICE_ROLE_KEY=your-service-role-key- Run development server
npm run dev- Open in browser
http://localhost:3000
- Next.js 16 - React framework with App Router
- TypeScript 5 - Type-safe development
- Tailwind CSS 4 - Utility-first styling
- Three.js 0.180 - WebGL 3D library
- @pixiv/three-vrm 3.4.3 - VRM model loading and runtime
- @pixiv/three-vrm-animation 3.4.3 - VRMA animation support
- Supabase - Backend as a Service (Database, Storage, Auth)
- PostgreSQL - Database for models and animations metadata
- Supabase Storage - File storage for VRM models, animations, and avatars
- Radix UI - Accessible UI components
- Lucide React - Icon library
- Tailwind CSS - Utility-first styling
vrm-dance-web/
βββ src/
β βββ app/
β β βββ page.tsx # Main application page
β β βββ layout.tsx # Root layout
β β βββ globals.css # Global styles
β β βββ (auth)/ # Auth pages (login, etc.)
β β βββ api/ # API routes
β β βββ models/ # Models CRUD endpoints
β β βββ animations/ # Animations CRUD endpoints
β β βββ auth/ # Authentication endpoints
β βββ components/
β β βββ VRMDancer.tsx # VRM 3D renderer with animation queue
β β βββ LiveHeader.tsx # Header with model/background controls
β β βββ AdminPanel.tsx # Admin panel for uploads
β β βββ ModelCombobox.tsx # Model dropdown selector
β β βββ ModelManagement.tsx # Model upload & management
β β βββ AnimationManagement.tsx # Animation upload & management
β β βββ BackgroundCombobox.tsx # Background selector
β β βββ VRMPreview.tsx # VRM model preview component
β β βββ ui/ # Reusable UI components (shadcn/ui)
β βββ constants/
β β βββ backgrounds.ts # Background image configurations
β βββ lib/
β β βββ auth-context.tsx # Auth context provider
β β βββ supabase.ts # Supabase client
β β βββ utils.ts # Helper utilities
β βββ utils/
β β βββ cookies.ts # Cookie utilities
β β βββ shuffle.ts # Array shuffle utility
β βββ middleware.ts # Next.js middleware for auth
βββ public/
β βββ background/ # Background images
β βββ avatar/ # Default avatars (optional)
βββ supabase/
β βββ migrations/ # Database migration files
βββ .env.example # Environment variables template
βββ package.json
βββ tsconfig.json
βββ tailwind.config.ts
βββ next.config.ts
βββ README.md
- Login to the app with admin credentials
- Click "Admin Panel" button in the header
- In the "Model Management" tab, click "Choose File"
- Select your
.vrmfile and optionally provide:- Custom name (or it will auto-detect from filename)
- Avatar image URL
- Rotation (degrees)
- Scale factor
- Click "Upload Model" and wait for completion
- Model is now available in the Model Combobox for all users
- Login to the app with admin credentials
- Click "Admin Panel" button in the header
- Go to "Animation Management" tab
- Click "Choose File" and select your
.vrmafile - Optionally provide a custom name
- Click "Upload Animation" and wait for completion
- Animation is now in the shuffle queue for all models
- Place image in
public/background/ - Add to
src/constants/backgrounds.ts:
{
id: 'custom-bg',
name: 'Custom Background',
path: '/background/your-bg.png',
description: 'Your description'
}Note: Models and animations are stored in Supabase Storage buckets and metadata in PostgreSQL database. No code changes required for adding new models/animations!
The VRMDancer component implements a sophisticated animation system:
- Database-driven: Animations loaded from Supabase via
/api/animations - Auto-play: Automatically cycles through animations from the queue
- Lazy Loading: Animations load on-demand to optimize performance
- Preloading: First 3 animations preload for smooth playback
- Shuffling: Animation order is randomized each cycle
- Compatibility Validation: Validates animation tracks - skips incompatible animations (0 tracks)
- Auto-retry: If animation fails to load, automatically queues next animation after 500ms
- Error Feedback: Displays error message with retry indication during loading failures
User preferences are saved to cookies:
- Selected VRM model (365 days)
- Selected background (365 days)
- Restored automatically on page refresh
- Proper mixer cleanup on model change (stop actions, uncache root, clear cache)
- Failsafe timeout (10s) prevents stuck loading states
- Animation cache cleared per-VRM to prevent cross-model contamination
- Efficient Supabase SDK upload (10MB in ~2s)
- Smart cleanup on component unmount
- Check Supabase connection (verify env variables in
.env.local) - Ensure VRM file uploaded successfully via Admin Panel
- Check browser console for loader errors
- Verify VRM file is version 1.0+
- Check database has model entry:
/api/modelsshould return the model
- Normal behavior: Some animations are incompatible with certain VRM models (different bone structure)
- Auto-retry: System will automatically skip incompatible animations and try next one
- Check browser DevTools for "Failed to load animation clip" or "Animation has 0 tracks"
- Wait for auto-retry (500ms delay) - compatible animation will load eventually
- If stuck for >10s, refresh page (failsafe timeout resets loading state)
- Check Supabase Storage bucket permissions (RLS policies)
- Verify file size limits (default: 50MB for Supabase free tier)
- Check network connection during upload
- Ensure admin authentication is valid
- Reduce VRM model polygon count before uploading
- Use browser hardware acceleration
- Close other browser tabs
- Check Supabase region latency
- Clear browser cookies and refresh
- Check cookie utility functions in
src/utils/cookies.ts - Verify cookies are enabled in browser settings
interface VRMDancerProps {
vrmUrl: string; // Path to .vrm model file
rotation?: number; // Model rotation in degrees (default: 0)
scale?: number; // Model scale factor (default: 1.5)
}Returns list of all VRM models from database.
[
{
"id": "uuid",
"name": "Model Name",
"file_url": "https://supabase-storage-url/model.vrm",
"avatar_url": "https://...",
"rotation": 0,
"scale": 1.25,
"created_at": "2024-01-01T00:00:00Z"
}
]Upload new VRM model (requires admin auth).
- Body: FormData with
file, optionalname,avatar_url,rotation,scale - Response: Created model object
Delete VRM model (requires admin auth).
Returns list of all animations from database.
Upload new animation (requires admin auth).
Delete animation (requires admin auth).
Contributions are welcome! To get started:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes
- Commit (
git commit -m 'Add amazing feature') - Push (
git push origin feature/amazing-feature) - Open a Pull Request
npm run dev # Start development server
npm run build # Build for production
npm start # Run production server
npm run lint # Run ESLintThis project is open source and available under the MIT License.