Modern photo gallery for photographers, with S3/GitHub sync, EXIF details, maps, and a WebGL viewer. https://afilmory.art
Find a file
Innei 4e888c789b
feat(share): port SSR three-mode iframe renderer into be
Cloud deploys go through be, which had a legacy /share/iframe wired
to dist/static/web/share.html and a single-id schema — both removed
by the SSR rewrite in 229b3368. Reimplement the renderer in be using
hono/jsx, supporting id / ids (multi) / tag (+limit) modes with the
same Collection/PhotoItem layout, badge, and resize bridge as SSR.
Drop the stale StaticShareService and its share.html lookup.
2026-06-17 00:51:32 +08:00
.cursor/rules refactor: update color documentation and enhance ErrorElement component 2025-07-15 00:19:46 +08:00
.github chore: update build workflow to generate routes using Vite 2026-01-11 22:47:39 +08:00
.specstory Afilmory Docs (#66) 2025-09-11 18:42:47 +08:00
.vscode feat: enhance storage provider management and settings 2025-10-28 23:49:16 +08:00
apps fix(share): serve embed.js from be to fix cloud 404 2026-06-16 23:38:27 +08:00
be feat(share): port SSR three-mode iframe renderer into be 2026-06-17 00:51:32 +08:00
docs feat(builder): add variant cluster report pipeline with CLIP embedding spikes 2026-06-11 19:36:46 +08:00
locales feat(web): add date-range filter to gallery 2026-06-03 14:11:41 +09:00
packages fix(share): serve embed.js from be to fix cloud 404 2026-06-16 23:38:27 +08:00
patches chore: add placeholder file to patches directory 2025-11-27 01:25:28 +08:00
photos@906be11f8e refactor(oauth): remove redirect URI settings from system configuration 2025-11-12 17:56:22 +08:00
plugins chore: update package dependencies and configurations across the monorepo 2026-01-10 23:35:37 +08:00
scripts chore(deps): bump idna to 3.18 in clip-embedder uv.lock 2026-06-16 15:53:18 +08:00
.dockerignore chore(dockerignore): update .dockerignore to exclude environment files and adjust paths for SSR assets 2025-06-11 00:08:09 +08:00
.env.template feat: add GIT_TOKEN and PG_CONNECTION_STRING to environment configuration 2025-06-28 14:19:42 +08:00
.gitignore feat(share): redesign iframe embed as script widget with three modes 2026-06-16 22:00:42 +08:00
.prettierrc.mjs feat: revamp dashboard photo management (#136) 2025-10-31 02:07:13 +08:00
AGENTS.md feat: implement ShareModal and related components for enhanced photo sharing 2025-11-30 22:50:33 +08:00
builder.config.default.ts feat(builder): integrate GitHub repository synchronization plugin and update configuration 2025-11-14 00:23:26 +08:00
bump.config.ts chore: add bump config 2026-04-26 01:32:36 +08:00
CLAUDE.md docs: add CLAUDE.md 2026-06-11 19:38:09 +08:00
config.example.json feat: Add configurable ICP beian footer for China mainland (#228) 2026-03-16 17:56:31 +08:00
DEVELOPMENT.md refactor: remove RSS support from social configuration 2025-11-30 01:27:48 +08:00
docker-compose.yml feat(docker): add Docker Compose configuration for database and caching services 2025-11-13 23:43:22 +08:00
Dockerfile chore(docker): use node:lts-alpine instead of pinning to 24 2026-06-02 19:53:24 +09:00
Dockerfile.core chore(docker): use node:lts-alpine instead of pinning to 24 2026-06-02 19:53:24 +09:00
Dockerfile.oauth feat(oauth-gateway): implement multi-tenant OAuth gateway service 2025-11-12 16:33:24 +08:00
env.ts feat: implement remote repository support for manifest updates 2025-06-28 13:34:35 +08:00
eslint.config.mjs chore(deps): bump patch deps; migrate from @iconify-json/lucide to lucide-react 2026-05-21 15:15:49 +08:00
LICENSE feat(server): onboarding and login layout design 2025-10-27 01:18:06 +08:00
logo.jpg chore: update favicon images and enhance favicon generation script 2025-06-24 12:41:46 +08:00
package.json fix(deps): pin vite-plugin-checker to 0.14.1 to fix CI build 2026-06-16 23:19:32 +08:00
pnpm-lock.yaml fix(deps): pin vite-plugin-checker to 0.14.1 to fix CI build 2026-06-16 23:19:32 +08:00
pnpm-workspace.yaml chore(deps): override vulnerable vite, esbuild, @babel/core transitives 2026-06-16 15:52:02 +08:00
README.md refactor: remove landing page components and configurations 2026-01-14 23:21:18 +08:00
renovate.json feat: init 2025-06-05 13:27:09 +08:00
rss-spec.md feat: implement email notification system for comments 2025-12-03 20:57:26 +08:00
site.config.ts feat: Add configurable ICP beian footer for China mainland (#228) 2026-03-16 17:56:31 +08:00
tsconfig.json chore(deps): upgrade pnpm to 11.1.2 and bump all dependencies (#242) 2026-05-16 15:14:12 +08:00

Afilmory

Afilmory

A modern, high-performance photo gallery platform for photographers

Official SaaSDocumentationLive ExamplesSelf-Hosting


Afilmory (/əˈfɪlməri/, "uh-FIL-muh-ree") is a comprehensive photo gallery solution that combines Auto Focus (AF), Aperture (light control), Film (vintage medium), and Memory (captured moments). Built with React + TypeScript, it offers automatic photo synchronization from multiple storage sources, high-performance WebGL rendering, and professional EXIF metadata display.

🚀 Quick Start

👉 Get Started at afilmory.art - Zero setup, live in minutes!

The easiest way to create your photo gallery. No deployment, no servers, no maintenance required.

Why Choose SaaS?

  • Zero Configuration - Sign up and go live immediately
  • Live CMS - Edit photos, titles, and metadata in real-time
  • Custom Domains - Bind your own domain with DNS verification
  • Auto Updates - Always running the latest features
  • Managed Infrastructure - We handle scaling, backups, and maintenance

Start Your Gallery Now →

Option 2: Self-Hosting

For developers who need full control over their deployment:

Docker (Recommended)

# See our Docker deployment guide
https://github.com/Afilmory/docker

Manual Installation

# 1. Clone and install
git clone https://github.com/Afilmory/Afilmory.git
cd Afilmory
pnpm install

# 2. Configure
cp config.example.json config.json
cp builder.config.default.ts builder.config.ts
# Edit both files with your settings

# 3. Build manifest and thumbnails
pnpm run build:manifest

# 4. Start the application
pnpm dev

For detailed self-hosting instructions, see DEVELOPMENT.md and Documentation.

📸 Live Galleries

See Afilmory in action:

Features

Core Capabilities

  • 🖼️ High-Performance WebGL Renderer - Custom WebGL image viewer with smooth zoom, pan, and gesture support
  • 📱 Responsive Masonry Layout - Powered by Masonic, adapts seamlessly to any screen size
  • 🎨 Modern UI/UX - Built with Tailwind CSS and Radix UI for accessibility and aesthetics
  • Incremental Sync - Smart change detection processes only new or modified photos
  • 🌐 Internationalization - Multi-language support with i18next
  • 🔗 Social Sharing - OpenGraph metadata for rich social media previews

Image Processing

  • 🔄 Format Support - Automatic conversion of HEIC/HEIF and TIFF formats
  • 🖼️ Smart Thumbnails - Multi-size thumbnail generation for optimized loading
  • 📊 Complete EXIF Display - Camera model, focal length, aperture, ISO, and more
  • 🌈 Blurhash Placeholders - Elegant progressive loading experience
  • 📱 Live Photos - Detection and display of iPhone Live Photos
  • ☀️ HDR Images - Full HDR image support
  • 🎛️ Fujifilm Recipes - Display Fujifilm film simulation settings

Advanced Features

  • 🗂️ Multi-Storage Support - S3-compatible storage, GitHub, Eagle, and local file system
  • 🏷️ File System Tags - Auto-generated tags based on directory structure
  • Concurrent Processing - Multi-process/multi-thread support for fast builds
  • 🗺️ Interactive Map - Geographic visualization with GPS coordinates using MapLibre
  • 🔍 Fullscreen Viewer - Immersive image viewing with gesture controls
  • 📷 Share & Embed - Share images to social media or embed in your website

🏗️ Architecture

Monorepo Structure

afilmory/
├── apps/
│   ├── web/              # React SPA (Vite + React Router 7)
│   ├── ssr/              # Next.js SSR wrapper for SEO/OG
│   ├── docs/             # Documentation site (VitePress)
├── be/                   # Backend services (Hono-based)
│   ├── apps/
│   │   ├── core/         # Core API server
│   │   ├── dashboard/    # Admin dashboard backend
│   │   └── oauth-gateway/# OAuth authentication gateway
│   └── packages/
│       ├── framework/    # Hono enterprise framework
│       ├── db/           # Database schemas (Drizzle ORM)
│       ├── redis/        # Redis client
│       └── websocket/    # WebSocket gateway
├── packages/
│   ├── builder/          # Photo processing pipeline
│   ├── webgl-viewer/     # WebGL image viewer component
│   ├── ui/               # Shared UI components
│   ├── hooks/            # React hooks library
│   ├── sdk/              # API client SDK
│   ├── utils/            # Utility functions
│   └── data/             # Shared data types
└── plugins/              # Builder plugins

Frontend Stack

  • React 19 - Latest React with Compiler
  • TypeScript - Full type safety
  • Vite - Lightning-fast build tool
  • React Router 7 - Modern routing
  • Tailwind CSS - Utility-first CSS framework
  • Radix UI - Accessible component primitives
  • Jotai - Atomic state management
  • TanStack Query - Data fetching and caching
  • i18next - Internationalization

Backend Stack

  • Hono - Ultra-fast web framework
  • Drizzle ORM - Type-safe database toolkit
  • PostgreSQL - Primary database
  • Redis - Caching and pub/sub
  • WebSocket - Real-time communication

Build Pipeline

  • Node.js - Server-side runtime
  • Sharp - High-performance image processing
  • AWS SDK - S3 storage operations
  • Worker Threads/Cluster - Parallel processing
  • EXIF-Reader - Metadata extraction

Storage Adapters

Designed with adapter pattern for flexibility:

  • S3-Compatible - AWS S3, MinIO, Backblaze B2, Alibaba Cloud OSS
  • GitHub - Use GitHub repository as storage
  • Eagle - Import from Eagle app library
  • Local File System - For development and testing

🛠️ Development

Prerequisites

  • Node.js 18+
  • pnpm 10+
  • TypeScript 5.9+

Project Setup

# Install dependencies
pnpm install

# Copy configuration files
cp config.example.json config.json
cp builder.config.default.ts builder.config.ts

# Set up environment variables
cp .env.template .env
# Edit .env with your credentials

Common Commands

# Development
pnpm dev                    # Start web + SSR
pnpm dev:be                 # Start backend services
pnpm --filter web dev       # Web app only
pnpm --filter @afilmory/ssr dev  # SSR only

# Build
pnpm build                  # Build production web app
pnpm build:manifest         # Generate photo manifest (incremental)
pnpm build:manifest -- --force  # Full rebuild

# Documentation
pnpm docs:dev               # Start docs dev server
pnpm docs:build             # Build documentation

# Code Quality
pnpm lint                   # Lint and fix
pnpm format                 # Format code
pnpm type-check             # Type checking

Configuration Files

config.json - Site presentation config:

{
  "name": "My Gallery",
  "title": "My Photography",
  "description": "Capturing beautiful moments",
  "url": "https://gallery.example.com",
  "accentColor": "#007bff",
  "author": {
    "name": "Your Name",
    "url": "https://example.com",
    "avatar": "https://example.com/avatar.jpg"
  },
  "social": {
    "github": "username",
    "twitter": "username"
  },
  "map": ["maplibre"],
  "mapStyle": "builtin",
  "mapProjection": "mercator"
}

builder.config.ts - Photo processing config:

import { defineBuilderConfig } from '@afilmory/builder'

export default defineBuilderConfig(() => ({
  storage: {
    provider: 's3',
    bucket: 'my-photos',
    region: 'us-east-1',
    // ... other S3 settings
  },
  system: {
    processing: {
      defaultConcurrency: 10,
      enableLivePhotoDetection: true,
    },
    observability: {
      showProgress: true,
      showDetailedStats: true,
    },
  },
}))

🔌 Extending Afilmory

Custom Storage Provider

Implement the StorageProvider interface:

import { StorageProvider } from '@afilmory/builder'

class MyStorageProvider implements StorageProvider {
  async getFile(key: string): Promise<Buffer | null> {
    // Your implementation
  }

  async listImages(): Promise<StorageObject[]> {
    // Your implementation
  }

  // ... other required methods
}

Custom Builder Plugin

Create a plugin for the build pipeline:

import { BuilderPlugin } from '@afilmory/builder'

export const myPlugin = (): BuilderPlugin => ({
  name: 'my-plugin',
  async onBeforeBuild(context) {
    // Pre-build hook
  },
  async onAfterBuild(context) {
    // Post-build hook
  },
})

📚 Documentation

🤝 Contributing

We welcome contributions! Please see our Contributing Guide for details.

Development Workflow

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Make your changes
  4. Run tests and linting (pnpm test && pnpm lint)
  5. Commit your changes (git commit -m 'Add amazing feature')
  6. Push to the branch (git push origin feature/amazing-feature)
  7. Open a Pull Request

📄 License

Attribution Network License (ANL) v1.0 © 2025 Afilmory Team

See LICENSE for more details.

🙏 Acknowledgments

Built with love by the Afilmory team and contributors. Special thanks to all photographers using Afilmory to share their work with the world.


If this project helps you, please give it a Star!