Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="utf-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |
| <meta name="theme-color" content="#111319"> | |
| <title>img2threejs — image to procedural Three.js</title> | |
| <meta name="description" content="Turn one reference image into an inspectable procedural Three.js draft, then explore results shared by the community."> | |
| <link rel="icon" href="/static/logo.svg" type="image/svg+xml"> | |
| <link rel="stylesheet" href="/static/styles.css"> | |
| </head> | |
| <body> | |
| <a class="skip-link" href="#main-content">Skip to content</a> | |
| <header class="site-header"> | |
| <a class="brand" href="/" aria-label="img2threejs home"> | |
| <img src="/static/logo.svg" alt="" width="38" height="38"> | |
| <span> | |
| <strong>img2threejs</strong> | |
| <small>Image → procedural Three.js</small> | |
| </span> | |
| </a> | |
| <nav class="site-nav" aria-label="Primary navigation"> | |
| <button id="nav-create" class="nav-link is-active" type="button" aria-current="page">Create</button> | |
| <button id="nav-gallery" class="nav-link" type="button"> | |
| Community gallery | |
| <span class="nav-dot" aria-hidden="true"></span> | |
| </button> | |
| </nav> | |
| <span id="llm-badge" class="badge badge-unknown" title="Checking model configuration" aria-live="polite"> | |
| Checking model | |
| </span> | |
| </header> | |
| <main id="main-content"> | |
| <section id="panel-upload" class="panel upload-panel" aria-labelledby="upload-title"> | |
| <div class="panel-heading"> | |
| <div> | |
| <p class="eyebrow">Create a procedural draft</p> | |
| <h1 id="upload-title">Turn one image into editable Three.js</h1> | |
| <p>Choose a clear, single-object reference. The model writes a structured sculpt spec and a procedural factory you can inspect, run, and refine.</p> | |
| </div> | |
| <span class="step-chip">01 · Reference</span> | |
| </div> | |
| <div id="dropzone" class="dropzone" tabindex="0" role="button" | |
| aria-label="Upload a reference image" aria-describedby="drop-help"> | |
| <span class="upload-mark" aria-hidden="true">↗</span> | |
| <p class="drop-title">Drop a reference image here</p> | |
| <p id="drop-help" class="drop-sub">Click to browse or paste from clipboard · PNG, JPEG, WebP, GIF, BMP · ≤ 10 MiB</p> | |
| <input id="file-input" type="file" accept="image/png,image/jpeg,image/webp,image/gif,image/bmp" hidden> | |
| </div> | |
| <div class="share-control"> | |
| <label class="switch-row" for="share-toggle"> | |
| <input id="share-toggle" type="checkbox" checked> | |
| <span class="switch" aria-hidden="true"><span></span></span> | |
| <span class="switch-copy"> | |
| <strong>Share this result in the public gallery</strong> | |
| <small>On by default. Your uploaded reference, generated preview, title, and downloadable artifacts will be visible to anyone. Turn this off to keep the result out of the gallery; its hard-to-guess job links remain temporarily accessible to anyone who has them.</small> | |
| </span> | |
| </label> | |
| </div> | |
| <div id="preview-row" class="preview-row" hidden> | |
| <div class="preview-image-wrap"> | |
| <img id="preview" alt="Uploaded reference preview"> | |
| <span class="reference-label">Reference</span> | |
| </div> | |
| <div class="preview-meta"> | |
| <div> | |
| <div id="preview-name" class="preview-name"></div> | |
| <div id="palette" class="palette" title="Approximate dominant colours sampled in your browser"></div> | |
| </div> | |
| <label class="hint-label" for="hint">What is the object? <span>Optional, but useful for ambiguous references</span></label> | |
| <input id="hint" type="text" maxlength="80" autocomplete="off" placeholder="e.g. a red diesel locomotive"> | |
| <button id="run-btn" class="primary" type="button"> | |
| <span>Generate Three.js preview</span> | |
| <span aria-hidden="true">→</span> | |
| </button> | |
| </div> | |
| </div> | |
| <p class="honesty-note"> | |
| <strong>What to expect.</strong> This is an approximate, unreviewed procedural reconstruction from one image. | |
| Hidden geometry is inferred—not observed or measured. If the reference cannot support a credible reconstruction, | |
| the pipeline stops with an explanation instead of fabricating confidence. | |
| </p> | |
| </section> | |
| <section id="panel-progress" class="panel progress-panel" aria-labelledby="progress-title" hidden> | |
| <div class="panel-heading compact"> | |
| <div> | |
| <p class="eyebrow">Generation in progress</p> | |
| <h1 id="progress-title">Building your procedural draft</h1> | |
| <p>Provider latency and validator repair rounds can take several minutes. Every update below comes from the running job—there are no estimated percentages.</p> | |
| </div> | |
| <span id="progress-connection" class="status-pill status-working" aria-live="polite">Connecting</span> | |
| </div> | |
| <div class="progress-facts" aria-label="Live generation details"> | |
| <div class="fact-card"> | |
| <span>Elapsed</span> | |
| <strong id="progress-elapsed">0:00</strong> | |
| <small>Since submission</small> | |
| </div> | |
| <div class="fact-card fact-wide"> | |
| <span>Latest activity</span> | |
| <strong id="progress-activity">Uploading your reference…</strong> | |
| <small id="progress-activity-time">Waiting for the first pipeline event</small> | |
| </div> | |
| <div id="progress-attempt-card" class="fact-card" hidden> | |
| <span>Model attempt</span> | |
| <strong id="progress-attempt">—</strong> | |
| <small>Reported by the validator loop</small> | |
| </div> | |
| <div class="fact-card"> | |
| <span>Gallery</span> | |
| <strong id="progress-sharing">Public</strong> | |
| <small>Choice locked for this run</small> | |
| </div> | |
| </div> | |
| <ol id="stages" class="stages" aria-label="Pipeline stages" aria-live="polite"></ol> | |
| <details class="log-drawer"> | |
| <summary> | |
| <span>Live event log</span> | |
| <small>Exact messages from the server</small> | |
| </summary> | |
| <pre id="log" class="log" aria-live="polite"></pre> | |
| </details> | |
| </section> | |
| <section id="panel-result" class="panel result-panel" aria-labelledby="result-title" hidden> | |
| <div class="result-topline"> | |
| <div> | |
| <p class="eyebrow">Generation complete</p> | |
| <h1 id="result-title">Result</h1> | |
| <p id="result-sub" class="result-sub"></p> | |
| </div> | |
| <div class="result-actions"> | |
| <span id="result-share-status" class="status-pill"></span> | |
| <button id="gallery-result-link" class="quiet-button" type="button" hidden>View in gallery →</button> | |
| </div> | |
| </div> | |
| <div class="result-grid"> | |
| <div class="viewer-column"> | |
| <div id="viewer-frame-wrap" class="viewer-frame-wrap" aria-busy="true"> | |
| <iframe id="viewer-frame" title="Generated 3D model viewer" | |
| sandbox="allow-scripts" referrerpolicy="no-referrer"></iframe> | |
| <div id="viewer-overlay" class="viewer-overlay"> | |
| <div> | |
| <span class="spinner" aria-hidden="true"></span> | |
| <p id="viewer-overlay-copy">Starting the secure viewer…</p> | |
| <button id="viewer-retry" class="overlay-action" type="button" hidden>Retry viewer</button> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="viewer-toolbar" aria-label="Preview options"> | |
| <button id="viewer-wireframe" type="button" aria-pressed="false" disabled>Wireframe</button> | |
| <button id="viewer-shadows" type="button" aria-pressed="true" disabled>Shadows</button> | |
| <button id="viewer-reset-camera" type="button" disabled>Reset view</button> | |
| <span id="viewer-control-status" role="status" aria-live="polite"></span> | |
| </div> | |
| <div class="viewer-caption"> | |
| <span>Drag to orbit · scroll to zoom · right-drag to pan</span> | |
| <span id="viewer-stats" aria-live="polite">Preparing model</span> | |
| </div> | |
| </div> | |
| <aside class="result-rail" aria-label="Result details and downloads"> | |
| <div class="rail-section"> | |
| <h2>Keep the useful parts</h2> | |
| <p>The factory and spec are the editable source of truth. The viewer exports are convenient previews.</p> | |
| <div class="downloads"> | |
| <a id="dl-ts" class="button download-button" download> | |
| <span><strong>Factory</strong><small>Editable TypeScript</small></span><b>.ts</b> | |
| </a> | |
| <a id="dl-spec" class="button download-button" download> | |
| <span><strong>Sculpt spec</strong><small>Structured source</small></span><b>.json</b> | |
| </a> | |
| <a id="dl-bundle" class="button download-button" download> | |
| <span><strong>Model bundle</strong><small>Browser-ready module</small></span><b>.js</b> | |
| </a> | |
| <a id="dl-standalone" class="button download-button" download> | |
| <span><strong>Standalone viewer</strong><small>Self-contained preview</small></span><b>.html</b> | |
| </a> | |
| <button id="dl-shot" class="button download-button" type="button" disabled> | |
| <span><strong>Screenshot</strong><small id="shot-status" aria-live="polite">Available when the viewer is ready</small></span><b>.png</b> | |
| </button> | |
| </div> | |
| </div> | |
| <div id="result-publication-warning" class="publication-warning" role="status" hidden> | |
| <strong>Gallery publication warning</strong> | |
| <p id="result-publication-warning-copy"></p> | |
| </div> | |
| <details id="warnings-box" class="warnings-box" hidden> | |
| <summary>Validator notes <span id="warnings-count"></span></summary> | |
| <ul id="warnings-list"></ul> | |
| </details> | |
| <div class="honesty-box"> | |
| <h2>Honesty notes</h2> | |
| <ul id="honesty-list"></ul> | |
| </div> | |
| <button id="again-btn" class="secondary" type="button">Create another model</button> | |
| </aside> | |
| </div> | |
| </section> | |
| <section id="panel-gallery" class="panel gallery-panel" aria-labelledby="gallery-title" hidden> | |
| <div class="panel-heading"> | |
| <div> | |
| <p class="eyebrow">Made by this community</p> | |
| <h1 id="gallery-title">Community gallery</h1> | |
| <p>Browse public results shared by creators. Every card opens the generated model in the same secure, interactive viewer and links to stable artifacts.</p> | |
| </div> | |
| <button id="gallery-refresh" class="quiet-button" type="button">Refresh</button> | |
| </div> | |
| <div class="gallery-disclosure"> | |
| <span aria-hidden="true">◎</span> | |
| <p><strong>Public means public.</strong> Gallery references and generated artifacts can be viewed and downloaded by anyone. Turn sharing off to avoid publication; temporary job links are unlisted, not access-controlled.</p> | |
| </div> | |
| <p id="gallery-status" class="sr-only" role="status" aria-live="polite"></p> | |
| <div id="gallery-loading" class="gallery-loading" aria-hidden="true"> | |
| <span></span><span></span><span></span> | |
| </div> | |
| <div id="gallery-error" class="inline-state inline-error" hidden> | |
| <div> | |
| <strong>Could not load the gallery</strong> | |
| <p id="gallery-error-message"></p> | |
| </div> | |
| <button id="gallery-retry" class="quiet-button" type="button">Try again</button> | |
| </div> | |
| <div id="gallery-empty" class="inline-state gallery-empty" hidden> | |
| <span aria-hidden="true">◇</span> | |
| <div> | |
| <strong>The gallery is ready for its first model</strong> | |
| <p>Generate a result with sharing enabled and it will appear here.</p> | |
| </div> | |
| <button id="gallery-empty-create" class="primary compact-button" type="button">Create one</button> | |
| </div> | |
| <div id="gallery-grid" class="gallery-grid"></div> | |
| <div class="gallery-more"> | |
| <button id="gallery-more" class="secondary inline-button" type="button" hidden>Load more</button> | |
| </div> | |
| </section> | |
| <section id="panel-error" class="panel panel-error" aria-labelledby="error-title" hidden> | |
| <div class="error-mark" aria-hidden="true">!</div> | |
| <div> | |
| <p class="eyebrow">Pipeline stopped</p> | |
| <h1 id="error-title">Something went wrong</h1> | |
| <p id="error-message"></p> | |
| <pre id="error-detail" class="error-detail" hidden></pre> | |
| <button id="error-again-btn" class="secondary inline-button" type="button">Start over</button> | |
| </div> | |
| </section> | |
| </main> | |
| <dialog id="gallery-dialog" class="gallery-dialog" aria-labelledby="gallery-detail-title"> | |
| <div class="dialog-shell"> | |
| <button id="gallery-detail-close" class="dialog-close" type="button" aria-label="Close gallery detail">×</button> | |
| <div id="gallery-detail-loading" class="detail-loading"> | |
| <span class="spinner" aria-hidden="true"></span> | |
| <p>Loading the shared model…</p> | |
| </div> | |
| <div id="gallery-detail-error" class="inline-state inline-error" hidden> | |
| <div> | |
| <strong>Could not open this gallery item</strong> | |
| <p id="gallery-detail-error-message"></p> | |
| </div> | |
| </div> | |
| <div id="gallery-detail-content" hidden> | |
| <div class="detail-heading"> | |
| <div> | |
| <p class="eyebrow">Community result</p> | |
| <h1 id="gallery-detail-title">Shared model</h1> | |
| <p id="gallery-detail-meta"></p> | |
| </div> | |
| <img id="gallery-detail-reference" alt="Shared reference image" loading="lazy"> | |
| </div> | |
| <div class="detail-grid"> | |
| <div> | |
| <div id="gallery-viewer-wrap" class="viewer-frame-wrap gallery-viewer-wrap" aria-busy="true"> | |
| <iframe id="gallery-viewer-frame" title="Shared 3D model viewer" | |
| sandbox="allow-scripts" referrerpolicy="no-referrer"></iframe> | |
| <div id="gallery-viewer-overlay" class="viewer-overlay"> | |
| <div> | |
| <span class="spinner" aria-hidden="true"></span> | |
| <p id="gallery-viewer-overlay-copy">Starting the secure viewer…</p> | |
| <button id="gallery-viewer-retry" class="overlay-action" type="button" hidden>Retry viewer</button> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="viewer-toolbar" aria-label="Shared preview options"> | |
| <button id="gallery-viewer-wireframe" type="button" aria-pressed="false" disabled>Wireframe</button> | |
| <button id="gallery-viewer-shadows" type="button" aria-pressed="true" disabled>Shadows</button> | |
| <button id="gallery-viewer-reset-camera" type="button" disabled>Reset view</button> | |
| <span id="gallery-viewer-control-status" role="status" aria-live="polite"></span> | |
| </div> | |
| <div class="viewer-caption"> | |
| <span>Drag to orbit · scroll to zoom · right-drag to pan</span> | |
| <span id="gallery-viewer-stats" aria-live="polite">Preparing model</span> | |
| </div> | |
| </div> | |
| <aside class="detail-rail"> | |
| <h2>Shared artifacts</h2> | |
| <p>These files are public copies with stable gallery URLs.</p> | |
| <div class="downloads detail-downloads"> | |
| <a id="gallery-dl-reference" class="button">Reference image <b>↗</b></a> | |
| <a id="gallery-dl-ts" class="button" download>Factory <b>.ts</b></a> | |
| <a id="gallery-dl-spec" class="button" download>Sculpt spec <b>.json</b></a> | |
| <a id="gallery-dl-bundle" class="button" download>Model bundle <b>.js</b></a> | |
| <a id="gallery-dl-standalone" class="button" download>Standalone viewer <b>.html</b></a> | |
| <button id="gallery-dl-shot" class="button" type="button" disabled> | |
| Screenshot <b>.png</b> | |
| </button> | |
| </div> | |
| <p id="gallery-shot-status" class="action-status" aria-live="polite">Available when the viewer is ready</p> | |
| <p class="detail-honesty">This is an approximate, unreviewed reconstruction from a single image. Public gallery inclusion is not a visual-quality approval.</p> | |
| </aside> | |
| </div> | |
| </div> | |
| </div> | |
| </dialog> | |
| <footer class="site-footer"> | |
| <p> | |
| Built on | |
| <a href="https://github.com/hoainho/img2threejs" target="_blank" rel="noopener noreferrer">hoainho/img2threejs</a> | |
| (MIT) · reconstruction-by-code, not photogrammetry · | |
| <a href="https://huggingface.co/spaces/Mike0021/img2threejs" target="_blank" rel="noopener noreferrer">Hugging Face Space</a> | |
| </p> | |
| </footer> | |
| <script type="module" src="/static/app.js"></script> | |
| </body> | |
| </html> | |