Chronoframe
Self-hosted personal gallery application with online photo management and albums, supporting Live/Motion Photos, EXIF parsing, geolocation recognition, and an explore map.
Install / Use
/learn @HoshinoSuzumi/ChronoframeREADME
ChronoFrame
<p align="center"> <img src="https://socialify.git.ci/HoshinoSuzumi/chronoframe/image?custom_description=Self-hosted+personal+gallery+application.&description=1&font=KoHo&forks=0&issues=0&logo=https%3A%2F%2Fgithub.com%2FHoshinoSuzumi%2Fchronoframe%2Fraw%2Frefs%2Fheads%2Fmain%2Fpublic%2Ffavicon.svg&name=1&owner=1&pattern=Plus&pulls=0&stargazers=0&theme=Auto" alt="Chronoframe"> </p> <p align="center"> <a href="https://github.com/HoshinoSuzumi/chronoframe/releases/latest"> <img src="https://badgen.net/github/release/HoshinoSuzumi/chronoframe/stable?icon=docker&label=stable" alt="Latest Release"> </a> <a href="https://github.com/HoshinoSuzumi/chronoframe/releases?q=beta&expanded=false"> <img src="https://badgen.net/github/release/HoshinoSuzumi/chronoframe?icon=docker&label=nightly" alt="Latest Nightly Release"> </a> <img src="https://img.shields.io/badge/License-MIT-green.svg" alt="License"> </p> <p align="center"> <a href="https://discord.gg/https://discord.gg/U4vQuydP2m"> <img src="https://dcbadge.limes.pink/api/server/https://discord.gg/U4vQuydP2m" alt="Discord Server" /> </a> </p> <p align="center"> <a href="https://hellogithub.com/repository/HoshinoSuzumi/chronoframe" target="_blank"><img src="https://api.hellogithub.com/v1/widgets/recommend.svg?rid=947d47ffe8404985908b266e187dec99&claim_uid=kLVoiAFPJaBtr1D&theme=neutral" alt="Featured|HelloGitHub" style="width: 250px; height: 54px;" width="250" height="54" /></a> <a href="https://www.producthunt.com/products/chronoframe?embed=true&utm_source=badge-featured&utm_medium=badge&utm_source=badge-chronoframe" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=1029556&theme=neutral&t=1761159404569" alt="ChronoFrame - Self-hosted photo gallery for photographers. | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a> </p>Languages: English | 中文
A smooth photo display and management application, supporting multiple image formats and large-size image rendering.
✨ Features
🖼️ Powerful Photo Management
- Manage photos online - Easily manage and browse photos via the web interface
- Explore map - Browse photo locations on a map
- Smart EXIF parsing - Automatically extracts metadata such as capture time, geolocation, and camera parameters
- Reverse geocoding - Automatically identifies photo shooting locations
- Multi-format support - Supports mainstream formats including JPEG, PNG, HEIC/HEIF
- Smart thumbnails - Efficient thumbnail generation using ThumbHash
🔧 Modern Tech Stack
- Nuxt 4 - Built on the latest Nuxt framework with SSR/SSG support
- TypeScript - Full type safety
- TailwindCSS - Modern CSS framework
- Drizzle ORM - Type-safe database ORM
☁️ Flexible Storage Solutions
- Multiple storage backends - Supports S3-compatible storage, local filesystem
- CDN acceleration - Configurable CDN URL for faster photo delivery
🐳 Deployment
We recommend deploying with the prebuilt Docker image. View the image on ghcr
Create a .env file and configure environment variables.
Below is a minimal configuration example. For complete configuration options, see Configuration Guide:
# Admin email (required)
CFRAME_ADMIN_EMAIL=
# Admin username (optional, default Chronoframe)
CFRAME_ADMIN_NAME=
# Admin password (optional, default CF1234@!)
CFRAME_ADMIN_PASSWORD=
# Site metadata (all optional)
NUXT_PUBLIC_APP_TITLE=
NUXT_PUBLIC_APP_SLOGAN=
NUXT_PUBLIC_APP_AUTHOR=
NUXT_PUBLIC_APP_AVATAR_URL=
# Map provider (maplibre/mapbox)
NUXT_PUBLIC_MAP_PROVIDER=maplibre
# MapTiler access token for MapLibre
NUXT_PUBLIC_MAP_MAPLIBRE_TOKEN=
# Mapbox access token for Mapbox
NUXT_PUBLIC_MAPBOX_ACCESS_TOKEN=
# Mapbox unrestricted token (optional, reverse geocoding)
NUXT_MAPBOX_ACCESS_TOKEN=
# Storage provider (local, s3 or openlist)
NUXT_STORAGE_PROVIDER=local
NUXT_PROVIDER_LOCAL_PATH=/app/data/storage
# Session password (32‑char random string, required)
NUXT_SESSION_PASSWORD=
Pull Image
Use the published image on GitHub Container Registry and Docker Hub. Choose the source that works best for your network:
GitHub Container Registry (GHCR)
docker pull ghcr.io/hoshinosuzumi/chronoframe:latest
Docker Hub
docker pull hoshinosuzumi/chronoframe:latest
Docker
Run with customized environment variables:
docker run -d --name chronoframe -p 3000:3000 -v $(pwd)/data:/app/data --env-file .env ghcr.io/hoshinosuzumi/chronoframe:latest
Docker Compose
Create docker-compose.yml:
services:
chronoframe:
image: ghcr.io/hoshinosuzumi/chronoframe:latest
container_name: chronoframe
restart: unless-stopped
ports:
- '3000:3000'
volumes:
- ./data:/app/data
env_file:
- .env
Start:
docker compose up -d
📖 User Guide
If
CFRAME_ADMIN_EMAILandCFRAME_ADMIN_PASSWORDare not set, the default admin account is:
- Email:
admin@chronoframe.com- Password:
CF1234@!
Logging into the Dashboard
- Click avatar to sign in with GitHub OAuth or use email/password login
Uploading Photos
- Go to the dashboard at /dashboard
- On the Photos page, select and upload images (supports batch & drag-and-drop)
- System will automatically parse EXIF data, generate thumbnails, and perform reverse geocoding
📸 Screenshots

🛠️ Development
Requirements
- Node.js 18+
- pnpm 9.0+
Install dependencies
# With pnpm (recommended)
pnpm install
# Or with other package managers
npm install
yarn install
Configure environment variables
cp .env.example .env
Initialize database
# 2. Generate migration files (optional)
pnpm db:generate
# 3. Run database migrations
pnpm db:migrate
Start development server
pnpm dev
App will start at http://localhost:3000.
Project Structure
chronoframe/
├── app/ # Nuxt app
│ ├── components/ # Components
│ ├── pages/ # Page routes
│ ├── composables/ # Composables
│ └── stores/ # Pinia stores
├── packages/
│ └── webgl-image/ # WebGL image viewer
├── server/
│ ├── api/ # API routes
│ ├── database/ # DB schema & migrations
│ └── services/ # Business logic services
└── shared/ # Shared types & utils
Build commands
# Development (with dependencies build)
pnpm dev
# Build only dependencies
pnpm build:deps
# Production build
pnpm build
# Database operations
pnpm db:generate # Generate migration files
pnpm db:migrate # Run migrations
# Preview production build
pnpm preview
🤝 Contributing
Contributions are welcome! Please:
- Fork the repo
- Create a feature branch (git checkout -b feature/amazing-feature)
- Commit changes (git commit -m 'Add some amazing feature')
- Push to branch (git push origin feature/amazing-feature)
- Open a Pull Request
Coding Guidelines
- Use TypeScript for type safety
- Follow ESLint and Prettier conventions
- Update documentation accordingly
📄 License
This project is licensed under the MIT License.
👤 Author
Timothy Yin
- Email: master@uniiem.com
- GitHub: @HoshinoSuzumi
- Website: bh8.ga
- Gallery: lens.bh8.ga
