Spaces:
Running
Running
File size: 9,600 Bytes
62fdf85 39ff632 62fdf85 39ff632 62fdf85 39ff632 37e3d5a 39ff632 62fdf85 39ff632 37e3d5a 39ff632 37e3d5a 39ff632 37e3d5a 39ff632 37e3d5a 39ff632 37e3d5a 39ff632 f074dc6 39ff632 37e3d5a f074dc6 bf1fb5f 39ff632 37e3d5a 39ff632 37e3d5a 39ff632 37e3d5a 39ff632 37e3d5a 39ff632 37e3d5a 39ff632 37e3d5a 39ff632 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 | ---
title: img2threejs
emoji: 🧊
colorFrom: indigo
colorTo: gray
sdk: docker
app_port: 7860
pinned: false
license: mit
short_description: Image to procedural Three.js with community gallery
tags:
- threejs
- image-to-3d
- procedural-generation
- code-generation
- llm
startup_duration_timeout: 30m
---
# img2threejs — image to procedural Three.js
Upload one object reference image. A vision-capable LLM authors an
`ObjectSculptSpec`; deterministic validators enforce the upstream structural
and strict-quality rules; and the vendored generator emits a TypeScript
`THREE.Group` factory. The result renders in a sandboxed browser viewer and is
downloadable as the original spec, TypeScript, an ESM bundle, and standalone
HTML. Successful results are shared to the public community gallery by
default; the clearly labelled upload-page toggle lets each user keep a result
out of the gallery before generation begins.
This Docker Space adapts [hoainho/img2threejs](https://github.com/hoainho/img2threejs)
(MIT), synced to v1.3.0 commit
`2c78038d315ec93086ef308c17ad2f1cd4cca683`. It is reconstruction-by-code,
not photogrammetry, mesh extraction, or a downloaded asset pack.
## What the hosted workflow guarantees
```text
image ──▶ byte/type/decompression guard + deterministic probe
──▶ vision LLM authors schema-2.1 ObjectSculptSpec
──▶ strict validator (errors return to the LLM, up to 3 repair rounds)
──▶ original spec saved locked and unreviewed
──▶ separate hosted-preview compile manifest (all supported parts)
──▶ vendored generator + esbuild ──▶ sandboxed viewer/downloads
──▶ optional persistent community publication (default on)
```
The hosted preview does **not** fabricate upstream review evidence. The
downloaded `spec.json` retains an empty `reviewHistory` and its original locked
pass order. A separate compile copy marks itself
`hosted-unreviewed-preview` and combines the declared components into one
preview pass. It contains no screenshot comparison, AI-vision score, reviewer,
or `continue` decision.
The result is an approximate, stylized procedural reconstruction from a single
image. Hidden sides are inferred rather than observed or measured. Structural
strict validation is not visual approval; production approval requires running
the upstream pass-by-pass render, comparison, and review loop outside this
hosted preview. Unsupported geometry families and parent cycles are rejected
instead of being replaced by placeholder boxes.
## Community gallery and privacy
The upload page starts with **Share this result to the community gallery**
enabled. The disclosure beside it states that publication includes the
uploaded reference image and generated artifacts. Turn it off before choosing
Generate to keep the job out of the gallery; opted-out and failed jobs are
never copied to gallery storage. Opted-out job URLs are unlisted rather than
access-controlled and expire with temporary job storage.
Published entries are written atomically to a private Hugging Face Bucket
mounted at `/data` and are exposed only through the gallery API below. They
survive app restarts, unlike the short-lived per-job files under `/tmp`.
Gallery cards open the real generated bundle in the same sandboxed viewer and
offer the same downloads. The viewer provides orbit, zoom, pan, wireframe,
shadow, camera-reset, and screenshot controls.
## Required Space Secrets
Conversion needs a vision-capable Anthropic Messages or OpenAI-compatible chat
endpoint. Add these under **Settings → Secrets**:
| Secret | Required | Example | Purpose |
| --- | --- | --- | --- |
| `LLM_API_KEY` | yes | provider API key | Credential; never logged or returned to the browser. |
| `LLM_MODEL` | yes | `claude-sonnet-4-5`, `moonshotai/kimi-k3` | Provider model identifier; it must accept images. |
| `LLM_BASE_URL` | no | `https://api.anthropic.com` | Provider base URL; defaults to Anthropic. |
| `LLM_API_STYLE` | no | `auto`, `anthropic`, or `openai` | `auto` tries Messages then falls back on HTTP 404. |
| `LLM_MAX_TOKENS` | no | `32768` | Response budget for reasoning plus the structured spec. |
| `LLM_TIMEOUT_S` | no | `180` | Per-request timeout in seconds. |
| `LLM_MAX_RETRIES` | no | `2` | Transient provider retries. |
| `LLM_REFERER`, `LLM_TITLE` | no | provider-specific | Optional attribution headers. |
Set the public Space variable `GALLERY_DIR=/data/gallery`. The production
Space mounts `hf://buckets/Mike0021/img2threejs-gallery` at `/data`; another
deployment should mount its own Bucket at the same path.
Optional operational variables are `JOB_TIMEOUT_S` (default `1800`, covering
queue time through the completed browser bundle) and
`GALLERY_PUBLISH_TIMEOUT_S` (default `120`, bounding the isolated persistent
Bucket copy). Long opaque stages report elapsed time every 25 seconds; the UI
does not invent completion percentages.
`ANTHROPIC_API_KEY`/`ANTHROPIC_AUTH_TOKEN`, `ANTHROPIC_BASE_URL`, and
`ANTHROPIC_MODEL` are accepted as server-side aliases. Without a key and model,
the app still starts, `/health` reports `llm_configured: false`, and job creation
returns `503 llm_not_configured`; no model or placeholder is emitted.
## HTTP API
```bash
curl https://<space-host>/health
curl -F "file=@object.png" https://<space-host>/api/jobs
curl -N https://<space-host>/api/jobs/<job-id>/events
curl https://<space-host>/api/jobs/<job-id>/artifacts/spec.json
curl https://<space-host>/api/jobs/<job-id>/artifacts/factory.ts
curl https://<space-host>/api/jobs/<job-id>/artifacts/model.bundle.js
curl https://<space-host>/api/jobs/<job-id>/artifacts/standalone.html
curl 'https://<space-host>/api/gallery?offset=0&limit=24'
curl https://<space-host>/api/gallery/<gallery-id>
curl https://<space-host>/api/gallery/<gallery-id>/artifacts/standalone.html
```
Uploads are limited to PNG, JPEG, WebP, GIF, or BMP, 10 MiB, and 40 MP by
default. SVG is rejected. Images are orientation-normalized, metadata-stripped,
and downscaled to at most 1024 px before processing. Defaults permit 10 jobs per
hour per client, 2 active conversions, and 8 queued/running jobs total. In the
multipart job request, `share` defaults to `true`; send `share=false` to opt
out.
## Run and test locally
Python 3.12 and Node 22 are the tested versions.
```bash
python3 -m pip install -r requirements.txt
npm ci
pytest -q
python3 forge/tests/test_pipeline.py
LLM_API_KEY=... LLM_MODEL=... LLM_BASE_URL=... python3 -m app.main
# http://127.0.0.1:7860
```
Build and verify the same target architecture used by Hugging Face:
```bash
docker build --platform=linux/amd64 -t img2threejs .
docker run --rm -p 7860:7860 \
-e LLM_API_KEY -e LLM_MODEL -e LLM_BASE_URL img2threejs
scripts/verify_docker.sh
```
The Docker build regenerates a fixture factory through the real strict gate
and hosted-preview compiler, bundles it with esbuild, and executes the bundle
headlessly in Node. The final runtime image contains only runtime dependencies,
`app/`, the required `forge/` source, and the license—not tests, scripts,
rollouts, virtual environments, caches, or the upstream comparison clone.
## Deploy and verify
The helper uses the currently authenticated local `hf` CLI account; an
`HF_TOKEN` environment variable is not required. `--dry-run` performs no Hub
mutation and prints the exact deterministic upload allowlist.
```bash
hf auth whoami
hf buckets create Mike0021/img2threejs-gallery --private --exist-ok
hf spaces volumes set Mike0021/img2threejs \
--volume hf://buckets/Mike0021/img2threejs-gallery:/data
hf spaces variables add Mike0021/img2threejs --env GALLERY_DIR=/data/gallery
python3 scripts/deploy_space.py --dry-run
python3 scripts/deploy_space.py # sets present LLM_* aliases as Secrets
# or: python3 scripts/deploy_space.py --no-secrets
hf spaces logs Mike0021/img2threejs --build --follow
hf spaces logs Mike0021/img2threejs --follow
python3 scripts/verify_space.py # wait/info/logs + GET-only probes
python3 scripts/verify_space.py \
--e2e tests/fixtures/mug_photo.png # real SSE job + artifact/node smoke
```
The deploy helper stages only its allowlist and issues one sanitized
`hf upload`. Secret values are passed in a temporary mode-0600 secrets file;
only secret names are printed. The live verifier never submits a job unless an
explicit `--e2e IMAGE` is supplied.
## Repository layout
| Path | Purpose |
| --- | --- |
| `app/` | FastAPI service, LLM client, pipeline adapter, SPA, and sandboxed viewer |
| `forge/` | Vendored upstream v1.3 pipeline with targeted runtime generator/safety fixes |
| `grimoire/`, `SKILL.md` | Upstream rubrics and complete agent workflow |
| `UPSTREAM_REVISION` | Exact upstream version and commit provenance |
| `tests/` | Unit, HTTP, pipeline, manifest, and render smoke tests |
| `scripts/` | Fixture builder, Node smoke, Docker verifier, deployer, live verifier |
| `docs/SECURITY.md` | Threat model, controls, and accepted limitations |
The targeted `forge/` changes preserve declared component dimensions without
scaling child pivots, avoid misinterpreting non-axis attachments, detect parent
cycles, and retain explicit hosted-preview honesty labels. The Space supports
the v1.3 advanced primitive set instead of replacing unknown geometry with
boxes. The adapter is therefore intentionally not a byte-for-byte upstream
tree.
## License and attribution
MIT — © 2026 hoainho (upstream) and this Space's contributors. See
`LICENSE`. three.js is MIT © the three.js authors.
|