--- 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:///health curl -F "file=@object.png" https:///api/jobs curl -N https:///api/jobs//events curl https:///api/jobs//artifacts/spec.json curl https:///api/jobs//artifacts/factory.ts curl https:///api/jobs//artifacts/model.bundle.js curl https:///api/jobs//artifacts/standalone.html curl 'https:///api/gallery?offset=0&limit=24' curl https:///api/gallery/ curl https:///api/gallery//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.