Spaces:
Running
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
(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
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
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.
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:
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.
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.