fix: support gltf uploads with local preview
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
# upload-GLTF
|
||||
|
||||
A secure web interface for uploading `model.glb` and its associated textures with two outputs:
|
||||
A secure web interface for uploading `model.gltf` with its associated `.bin` file and textures with two outputs:
|
||||
|
||||
- **Nextcloud Drive** — Archives the original files with automatic versioning (VF/V1/V2...), so artists always have a history of past versions.
|
||||
- **GitHub** — Delivers compressed models (Draco via Blender) and compressed textures to the dev team's repository, ready for integration.
|
||||
- **GitHub** — Delivers GLTF assets and compressed textures to the dev team's repository, ready for integration.
|
||||
|
||||
Built for La Fabrik Durable.
|
||||
|
||||
@@ -14,7 +14,7 @@ Built for La Fabrik Durable.
|
||||
- **Tailwind CSS** for styling
|
||||
- **Octokit** for pushing via the GitHub API
|
||||
- **Nextcloud WebDAV** for Drive archiving with automatic versioning
|
||||
- **Blender** (headless) for Draco mesh compression
|
||||
- **Sharp** for server-side texture compression
|
||||
- **Coolify** (Docker) for hosting
|
||||
|
||||
## Installation
|
||||
@@ -34,7 +34,6 @@ 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
|
||||
|
||||
# Nextcloud Drive (public share WebDAV)
|
||||
NEXTCLOUD_URL=https://cloud.example.com
|
||||
@@ -49,7 +48,6 @@ NEXTCLOUD_BASE_PATH=Models
|
||||
| `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 |
|
||||
| `NEXTCLOUD_URL` | Nextcloud instance URL | Yes |
|
||||
| `NEXTCLOUD_SHARE_TOKEN` | Public share token (the part after `/s/` in the share link) | Yes |
|
||||
| `NEXTCLOUD_SHARE_PASSWORD` | Public share password (empty if none) | No |
|
||||
@@ -67,9 +65,9 @@ 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.
|
||||
> **Note:** The current upload contract accepts `model.gltf` and preserves it as GLTF. `.glb` uploads are rejected by validation.
|
||||
>
|
||||
> Local 3D preview is currently supported for `.glb` files only.
|
||||
> Local 3D preview supports `model.gltf` folders by resolving dropped companion files such as `model.bin` and textures through local object URLs.
|
||||
|
||||
### Production (Coolify / Docker)
|
||||
|
||||
@@ -84,16 +82,17 @@ docker run -p 3000:3000 \
|
||||
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.
|
||||
The Docker image runs the Next.js app and server-side asset preparation in a single container.
|
||||
|
||||
## How it works
|
||||
|
||||
1. The user enters their access key
|
||||
2. They select a folder containing:
|
||||
- `model.glb` (**required**)
|
||||
- `model.gltf` (**required**)
|
||||
- Any associated binary buffer (`.bin`, for example `model.bin`)
|
||||
- Any associated textures (`.png/.jpg/.jpeg/.webp`)
|
||||
3. The `.glb` model is displayed in a local 3D preview
|
||||
5. On clicking "Envoyer":
|
||||
3. The folder is validated locally. `.glb` files are not accepted.
|
||||
4. On clicking "Envoyer":
|
||||
- The app uploads the folder once to a temporary server-side staging area
|
||||
- The app prepares the final Git payload from this staging area
|
||||
- The app checks the remote Git repo for existing files and computes diffs
|
||||
@@ -103,8 +102,8 @@ The Docker image includes Blender headless (installed once at build time). On st
|
||||
|
||||
### Upload flow: Drive first, then Git
|
||||
|
||||
6. **Drive upload (archiving)** — Original files from the staging area are uploaded to the Nextcloud Drive with automatic versioning (see below). This serves as the artists' source of truth and version history. If the Drive upload fails, a modal asks the user whether to send to Git only or cancel entirely.
|
||||
7. **Git upload (delivery to devs)** — The prepared Git payload is reused from staging: models are compressed with Blender Draco, textures are compressed server-side, then all changed files are pushed to GitHub in a single commit. This is what the dev team consumes in the application.
|
||||
5. **Drive upload (archiving)** — Original files from the staging area are uploaded to the Nextcloud Drive with automatic versioning (see below). This serves as the artists' source of truth and version history. If the Drive upload fails, a modal asks the user whether to send to Git only or cancel entirely.
|
||||
6. **Git upload (delivery to devs)** — The prepared Git payload is reused from staging: `model.gltf` and `.bin` files are preserved, textures are compressed server-side, then all changed files are pushed to GitHub in a single commit. This is what the dev team consumes in the application.
|
||||
|
||||
### Drive versioning (Nextcloud WebDAV)
|
||||
|
||||
@@ -114,7 +113,8 @@ The Drive uses a `VF` (version finale) / `Vx` (archived versions) structure:
|
||||
Models/
|
||||
VF/ ← latest version
|
||||
coffeetest/
|
||||
model.glb
|
||||
model.gltf
|
||||
model.bin
|
||||
color.jpg
|
||||
V1/ ← first archive
|
||||
coffeetest/
|
||||
@@ -143,7 +143,7 @@ All changes are pushed in a **single commit** with a grouped formatted message:
|
||||
update: upload-gltf add a new model -> my-model
|
||||
|
||||
📦 Model
|
||||
✅ model.glb (compressed)
|
||||
✅ model.gltf
|
||||
🎨 Textures (color)
|
||||
✅ color_porte.jpg (compressed)
|
||||
|
||||
@@ -151,6 +151,7 @@ update: upload-gltf add a new model -> my-model
|
||||
✅ roughness_tuyaux.png (compressed)
|
||||
|
||||
🧩 Assets
|
||||
✅ model.bin
|
||||
✅ opacity_fenetre.png (compressed)
|
||||
```
|
||||
|
||||
@@ -159,7 +160,7 @@ update: upload-gltf add a new model -> my-model
|
||||
update: upload-gltf update -> coffeetest
|
||||
|
||||
📦 Model
|
||||
↔️ model.glb (compressed)
|
||||
↔️ model.gltf
|
||||
|
||||
🎨 Textures (color)
|
||||
🔄 color_tuyaux.jpg (compressed)
|
||||
@@ -177,8 +178,8 @@ Sections currently used:
|
||||
|
||||
Symbols: `✅` new — `🔄` modified — `↔️` unchanged (model always re-pushed) — `❌` deleted
|
||||
|
||||
8. Orphan files (present on remote but not in the new upload) are deleted in the same commit
|
||||
9. If Blender is unavailable, the original model is pushed as-is (graceful fallback)
|
||||
7. Orphan files (present on remote but not in the new upload) are deleted in the same commit
|
||||
8. `model.gltf` is pushed as-is so companion files like `model.bin` remain valid
|
||||
|
||||
Uploaded models are pushed to `public/models/<folderName>/` in the target repo.
|
||||
|
||||
@@ -186,7 +187,7 @@ Uploaded models are pushed to `public/models/<folderName>/` in the target repo.
|
||||
|
||||
- Large uploads are faster than before because the folder is staged only once, but the Drive upload remains sequential.
|
||||
- Git LFS uploads are still sequential.
|
||||
- The current upload contract still expects a single `model.glb` file and a flat texture set.
|
||||
- The current upload contract expects a single `model.gltf` file plus optional flat support files (`.bin`, `.png`, `.jpg`, `.jpeg`, `.webp`).
|
||||
|
||||
## Project Structure
|
||||
|
||||
@@ -234,22 +235,23 @@ lib/
|
||||
├── upload-staging.ts # Temporary server-side staging and prepared asset reuse
|
||||
├── upload-lock.ts # Lightweight in-memory per-folder upload lock
|
||||
├── asset-classification.ts # Group assets by family for commit messages
|
||||
├── blender.ts # Blender Draco compression
|
||||
├── blender.ts # Legacy Blender compression helper
|
||||
├── commit-message.ts # Commit message builder
|
||||
├── parse-upload.ts # FormData parser + validation
|
||||
├── validate-folder.ts # Client-side folder validation (discriminated union)
|
||||
└── format-bytes.ts # Byte formatting utility
|
||||
scripts/
|
||||
└── compress.py # Blender Draco compression script
|
||||
Dockerfile # Multi-stage build: Node 20 slim + Blender headless + tini
|
||||
docker-entrypoint.sh # Startup: Blender check + launch
|
||||
└── compress.py # Legacy Blender compression script
|
||||
Dockerfile # Multi-stage build: Node 20 slim + tini
|
||||
docker-entrypoint.sh # Startup check + launch
|
||||
```
|
||||
|
||||
## Supported Formats
|
||||
|
||||
| Type | Extensions |
|
||||
|------|------------|
|
||||
| 3D Models | `.glb` |
|
||||
| 3D Models | `.gltf` |
|
||||
| Binary buffers | `.bin` |
|
||||
| Textures | `.png`, `.jpg`, `.jpeg`, `.webp` |
|
||||
|
||||
## License
|
||||
|
||||
Reference in New Issue
Block a user