152 lines
5.4 KiB
Markdown
152 lines
5.4 KiB
Markdown
# upload-GLTF
|
|
|
|
A secure web interface for uploading 3D assets (GLTF/GLB + textures) with automatic Draco compression and GitHub push. Built for La Fabrik Durable.
|
|
|
|
## Stack
|
|
|
|
- **Next.js 16** (App Router) + React 19 + TypeScript
|
|
- **Three.js** (@react-three/fiber + @react-three/drei) for 3D preview
|
|
- **Tailwind CSS** for styling
|
|
- **Octokit** for pushing via the GitHub API
|
|
- **Blender** (headless) for Draco mesh compression
|
|
- **Coolify** (Docker) for hosting
|
|
|
|
## Installation
|
|
|
|
```bash
|
|
git clone https://github.com/La-Fabrik-Durable/upload-GLTF.git
|
|
cd upload-GLTF
|
|
npm install
|
|
```
|
|
|
|
## Configuration
|
|
|
|
Copy `.env.example` to `.env.local` and fill in the values:
|
|
|
|
```env
|
|
UPLOAD_SECRET_KEY=your-secret-key-here
|
|
GITHUB_TOKEN=ghp_your-github-personal-access-token
|
|
GIT_BRANCH=main
|
|
GIT_REPO_URL=https://github.com/your-org/your-repo.git
|
|
BLENDER_PATH=/Applications/Blender.app/Contents/MacOS/Blender
|
|
```
|
|
|
|
| Variable | Description | Required |
|
|
|----------|-------------|----------|
|
|
| `UPLOAD_SECRET_KEY` | Secret key for upload authentication | Yes |
|
|
| `GITHUB_TOKEN` | GitHub Personal Access Token (fine-grained, `Contents: Read and write`) | Yes |
|
|
| `GIT_BRANCH` | Target branch (default: main) | No |
|
|
| `GIT_REPO_URL` | Target GitHub repository URL | Yes |
|
|
| `BLENDER_PATH` | Path to Blender binary (default: `blender`) | No |
|
|
|
|
> To create a token: GitHub > Settings > Developer settings > Fine-grained personal access tokens > select the target repo > Permissions > Contents: Read and write.
|
|
|
|
## Usage
|
|
|
|
### Development
|
|
|
|
```bash
|
|
npm run dev
|
|
```
|
|
|
|
Access the app at `http://localhost:3000`
|
|
|
|
> **Note:** Draco compression requires Blender installed locally. On macOS, Blender is typically at `/Applications/Blender.app/Contents/MacOS/Blender`. Set `BLENDER_PATH` in `.env.local` accordingly. If Blender is not available, models are pushed to GitHub without compression.
|
|
|
|
### Production (Coolify / Docker)
|
|
|
|
```bash
|
|
docker build -t upload-gltf .
|
|
docker run -p 3000:3000 \
|
|
-e UPLOAD_SECRET_KEY=your-key \
|
|
-e GITHUB_TOKEN=ghp_xxx \
|
|
-e GIT_REPO_URL=https://github.com/org/repo.git \
|
|
upload-gltf
|
|
```
|
|
|
|
The Docker image includes Blender headless (installed once at build time). On startup, the entrypoint checks if Blender is available and logs its version. No extra configuration is needed in production — `BLENDER_PATH` defaults to `blender` which is in the container's PATH.
|
|
|
|
## How it works
|
|
|
|
1. The user enters their access key
|
|
2. They pick a **destination** (`farm`, `map`, `powergrid`, `workshop`, `general`, `environment`)
|
|
3. They select a folder containing:
|
|
- `model.glb` or `model.gltf` (**required**)
|
|
- Textures: `roughness`, `normal`, `metalness`, `color`, `displace` (`.png/.jpg/.webp`, **optional** — missing textures show a warning but don't block the upload)
|
|
4. The model is displayed in a 3D preview
|
|
5. On clicking "Envoyer sur GitHub":
|
|
- The app computes the git SHA of each local file and compares with the remote repo
|
|
- If the folder doesn't exist, upload proceeds directly
|
|
- If the folder exists and files differ, a confirmation dialog shows **only the actual changes** (modified, new, or deleted files)
|
|
- If the folder exists and nothing changed, the upload is skipped entirely ("Aucun fichier modifie")
|
|
6. For models: the file is written to `/tmp`, compressed with Blender Draco, then the compressed version is pushed
|
|
7. For textures: pushed directly without compression
|
|
8. **Only changed and new files are pushed** — unchanged files are skipped to save bandwidth and API calls
|
|
9. All changes are pushed in a **single commit** with a formatted message that only lists what changed:
|
|
|
|
**New folder:**
|
|
```
|
|
update: upload-gltf add a new model -> farm/my-model
|
|
|
|
📦 Model
|
|
✅ model.gltf (compressed)
|
|
🎨 Textures
|
|
✅ color.jpg
|
|
❌ metalness (manquant)
|
|
```
|
|
|
|
**Update (only metalness changed):**
|
|
```
|
|
update: upload-gltf update -> general/coffeetest
|
|
|
|
🎨 Textures
|
|
🔄 metalness.jpg
|
|
```
|
|
|
|
Symbols: `✅` new — `🔄` modified — `❌` missing or deleted
|
|
|
|
10. Orphan files (present on remote but not in the new upload) are deleted in the same commit
|
|
11. If Blender is unavailable, the original model is pushed as-is (graceful fallback)
|
|
|
|
## Destinations
|
|
|
|
Uploaded models are pushed to `public/models/<destination>/<folderName>/` in the target repo:
|
|
|
|
| Destination | Path |
|
|
|-------------|------|
|
|
| Farm | `public/models/farm/` |
|
|
| Map | `public/models/map/` |
|
|
| Powergrid | `public/models/powergrid/` |
|
|
| Workshop | `public/models/workshop/` |
|
|
| General | `public/models/general/` |
|
|
| Environment | `public/models/environment/` |
|
|
|
|
## Project Structure
|
|
|
|
```
|
|
app/
|
|
├── api/upload/route.ts # API: GET (check + SHA diff) + POST (compress + smart push)
|
|
├── globals.css # Tailwind + Google Fonts
|
|
├── layout.tsx # Root layout
|
|
└── page.tsx # Home page
|
|
components/
|
|
├── UploadZone.tsx # UI: key input, destination picker, folder picker, SHA diff, overwrite confirmation, upload
|
|
├── ModelViewer.tsx # Lazy wrapper for the 3D viewer
|
|
└── SceneViewer.tsx # Three.js Canvas
|
|
scripts/
|
|
└── compress.py # Blender Draco compression script
|
|
Dockerfile # Multi-stage build: Node 20 slim + Blender headless + tini
|
|
docker-entrypoint.sh # Startup: Blender check + launch
|
|
```
|
|
|
|
## Supported Formats
|
|
|
|
| Type | Extensions |
|
|
|------|------------|
|
|
| 3D Models | `.glb`, `.gltf` |
|
|
| Textures | `.png`, `.jpg`, `.jpeg`, `.webp` |
|
|
|
|
## License
|
|
|
|
MIT
|