| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>FormaAi Studio</title> |
| |
| <link rel="preconnect" href="https://fonts.googleapis.com"> |
| <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> |
| <link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;600;800;900&family=Inter:wght@300;400;500;700&display=swap" rel="stylesheet"> |
| |
| <link rel="stylesheet" href="/static/style.css"> |
| |
| <script type="module" src="https://ajax.googleapis.com/ajax/libs/model-viewer/3.5.0/model-viewer.min.js"></script> |
| </head> |
| <body> |
| <div class="glow-bg"></div> |
| |
| <div class="container"> |
| |
| <div class="top-bar"> |
| <div class="lang-switcher"> |
| <button class="lang-btn active" id="lang-en-btn" aria-label="Switch to English"> |
| <svg viewBox="0 0 36 36" width="16" height="16" xmlns="http://www.w3.org/2000/svg" style="vertical-align: middle;"><clipPath id="circle-clip"><circle cx="18" cy="18" r="18"/></clipPath><g clip-path="url(#circle-clip)"><rect width="36" height="36" fill="#fff"/><path d="M0 0h36v2.77H0zm0 5.54h36v2.77H0zm0 11.08h36v2.77H0zm0 5.54h36v2.77H0zm0 5.54h36v2.77H0zm0 5.54h36v2.77H0zm0 11.08h36v2.77H0zm0 5.54h36v2.77H0z" fill="#B22234"/><rect width="16" height="19.38" fill="#3C3B6E"/><g fill="#fff"><circle cx="3" cy="3" r="0.8"/><circle cx="7" cy="3" r="0.8"/><circle cx="11" cy="3" r="0.8"/><circle cx="15" cy="3" r="0.8"/><circle cx="5" cy="7" r="0.8"/><circle cx="9" cy="7" r="0.8"/><circle cx="13" cy="7" r="0.8"/><circle cx="3" cy="11" r="0.8"/><circle cx="7" cy="11" r="0.8"/><circle cx="11" cy="11" r="0.8"/><circle cx="15" cy="11" r="0.8"/><circle cx="5" cy="15" r="0.8"/><circle cx="9" cy="15" r="0.8"/><circle cx="13" cy="15" r="0.8"/></g></g></svg> |
| <span>EN</span> |
| </button> |
| <button class="lang-btn" id="lang-ru-btn" aria-label="Переключить на русский"> |
| <svg viewBox="0 0 36 36" width="16" height="16" xmlns="http://www.w3.org/2000/svg" style="vertical-align: middle;"><clipPath id="russia-clip"><circle cx="18" cy="18" r="18"/></clipPath><g clip-path="url(#russia-clip)"><rect width="36" height="12" fill="#fff"/><rect y="12" width="36" height="12" fill="#0039A6"/><rect y="24" width="36" height="12" fill="#D52B1E"/></g></svg> |
| <span>RU</span> |
| </button> |
| </div> |
| </div> |
|
|
| |
| <header class="header"> |
| <h1 class="header-title" data-i18n="header_title">FormaAi Studio</h1> |
| <p class="header-subtitle" data-i18n="header_subtitle">Unified Hybrid 3D Generation Pipeline (Mesh + Gaussians)</p> |
| </header> |
|
|
| |
| <div class="workspace"> |
| |
| <div class="controls-panel glass-panel"> |
| |
| <div class="panel-section"> |
| <h2 class="section-title"> |
| <span class="icon"> |
| <svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg> |
| </span> |
| <span data-i18n="input_image">1. Input Image</span> |
| </h2> |
| <div class="dropzone" id="dropzone"> |
| <input type="file" id="file-input" accept="image/*" style="display: none;"> |
| <div class="dropzone-empty" id="dropzone-empty"> |
| <svg class="upload-icon" viewBox="0 0 24 24" width="48" height="48"> |
| <path fill="currentColor" d="M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96zM14 13v4h-4v-4H7l5-5 5 5h-3z"/> |
| </svg> |
| <p class="upload-text"> |
| <span data-i18n="upload_text">Drag & drop image here or </span> |
| <span data-i18n="upload_browse" style="color: var(--neon-indigo); font-weight: 600;">choose file</span> |
| </p> |
| <p class="upload-hint" data-i18n="upload_hint">Supports PNG, JPG, JPEG</p> |
| </div> |
| <div class="dropzone-preview" id="dropzone-preview" style="display: none;"> |
| <img id="image-preview" src="" alt="Preview"> |
| <button class="remove-btn" id="remove-img-btn" type="button"> |
| <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" style="margin-right: 4px; vertical-align: middle;"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg> |
| <span data-i18n="remove_btn">Delete</span> |
| </button> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div class="panel-section"> |
| <div class="accordion"> |
| <div class="accordion-header" id="accordion-basic-btn"> |
| <h2 class="section-title"> |
| <span class="icon"> |
| <svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83 2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg> |
| </span> |
| <span data-i18n="gen_params">2. Generation Settings</span> |
| </h2> |
| <span class="arrow">▼</span> |
| </div> |
| <div class="accordion-content" id="accordion-basic-content"> |
| |
| <div class="form-group"> |
| <label for="seed-input" data-i18n="seed_label">Random Seed</label> |
| <input type="number" id="seed-input" value="42" min="0"> |
| </div> |
| |
| <div class="form-group"> |
| <label><span data-i18n="stage1_steps">Sparse Structure Steps (Stage 1):</span> <span id="ss-steps-val" class="badge">12</span></label> |
| <input type="range" id="ss-steps-input" min="4" max="30" step="1" value="12"> |
| </div> |
|
|
| <div class="form-group"> |
| <label><span data-i18n="stage1_cfg">Sparse Structure CFG (Guidance):</span> <span id="ss-cfg-val" class="badge">7.5</span></label> |
| <input type="range" id="ss-cfg-input" min="1" max="15" step="0.5" value="7.5"> |
| </div> |
|
|
| <div class="form-group"> |
| <label><span data-i18n="stage2_steps">Structured Latent Steps (Stage 2):</span> <span id="slat-steps-val" class="badge">12</span></label> |
| <input type="range" id="slat-steps-input" min="4" max="30" step="1" value="12"> |
| </div> |
|
|
| <div class="form-group"> |
| <label><span data-i18n="stage2_cfg">Structured Latent CFG (Guidance):</span> <span id="slat-cfg-val" class="badge">3.0</span></label> |
| <input type="range" id="slat-cfg-input" min="1" max="10" step="0.5" value="3.0"> |
| </div> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div class="panel-section"> |
| <div class="accordion"> |
| <div class="accordion-header" id="accordion-post-btn"> |
| <h2 class="section-title"> |
| <span class="icon"> |
| <svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg> |
| </span> |
| <span data-i18n="postprocess_title">3. Postprocessing & AI Upscaling</span> |
| </h2> |
| <span class="arrow">▼</span> |
| </div> |
| <div class="accordion-content" id="accordion-post-content"> |
| |
| <div class="form-group checkbox-group"> |
| <input type="checkbox" id="refine-gs-input"> |
| <label for="refine-gs-input" data-i18n="refine_gs_label">Refine 3D Gaussians (Differentiable Refinement)</label> |
| </div> |
|
|
| <div class="form-group" id="refine-steps-group"> |
| <label><span data-i18n="refine_steps_label">Optimization Steps:</span> <span id="refine-steps-val" class="badge">100</span></label> |
| <input type="range" id="refine-steps-input" min="20" max="300" step="10" value="100"> |
| </div> |
|
|
| <div class="form-group"> |
| <label data-i18n="mesh_upscaling">Mesh Texture Scaling (AI Super Resolution)</label> |
| <div class="radio-group"> |
| <label class="radio-label"> |
| <input type="radio" name="upscale-factor" value="1"> |
| <span data-i18n="upscale_off">Off</span> |
| </label> |
| <label class="radio-label"> |
| <input type="radio" name="upscale-factor" value="2" checked> |
| <span>2K (Swin2SR x2)</span> |
| </label> |
| <label class="radio-label"> |
| <input type="radio" name="upscale-factor" value="4"> |
| <span>4K (Swin2SR x4)</span> |
| </label> |
| </div> |
| </div> |
|
|
| <div class="form-group"> |
| <label data-i18n="upscale_device">Upscaling Device</label> |
| <div class="radio-group device-radio"> |
| <label class="radio-label"> |
| <input type="radio" name="upscale-device" value="GPU"> |
| <span data-i18n="device_gpu">GPU (Fast)</span> |
| </label> |
| <label class="radio-label"> |
| <input type="radio" name="upscale-device" value="CPU"> |
| <span data-i18n="device_cpu">CPU (No OOM)</span> |
| </label> |
| <label class="radio-label"> |
| <input type="radio" name="upscale-device" value="Auto-Fallback" checked> |
| <span data-i18n="device_auto">Auto-Fallback</span> |
| </label> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <button class="btn-primary" id="generate-btn" data-i18n="generate_btn">Generate 3D Object</button> |
| |
| |
| <div class="status-box" id="status-box" style="display: none;"> |
| <div class="status-header"> |
| <span class="status-label"><span data-i18n="status_label">Status:</span> <strong id="status-text">Pending...</strong></span> |
| <span class="status-percent" id="status-percent">0%</span> |
| </div> |
| <div class="progress-bar-container"> |
| <div class="progress-bar" id="progress-bar"></div> |
| </div> |
| <div class="log-output" id="log-output"> |
| <div class="log-line text-cyan">> Initializing interface...</div> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div class="preview-panel glass-panel"> |
| <h2 class="section-title"> |
| <span class="icon"> |
| <svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg> |
| </span> |
| <span data-i18n="result_title">4. Generation Result</span> |
| </h2> |
| |
| |
| <div class="viewport-container"> |
| <div class="viewport-placeholder" id="viewport-placeholder"> |
| <svg class="placeholder-icon" viewBox="0 0 24 24" width="64" height="64"> |
| <path fill="currentColor" d="M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5"/> |
| </svg> |
| <p data-i18n="viewport_placeholder">GLB 3D model will appear here after generation completes</p> |
| </div> |
| |
| <model-viewer id="model-viewer" |
| src="" |
| alt="FormaAi Generated 3D Model" |
| auto-rotate |
| camera-controls |
| shadow-intensity="1" |
| exposure="1" |
| style="display: none; width: 100%; height: 100%;"> |
| </model-viewer> |
| </div> |
|
|
| |
| <div class="tabs-container"> |
| <div class="tabs-header"> |
| <button class="tab-btn active" data-tab="images-tab" data-i18n="tab_preview">Add. Preview</button> |
| <button class="tab-btn" data-tab="files-tab" id="downloads-tab-btn" data-i18n="tab_downloads" disabled>Downloads</button> |
| </div> |
| |
| <div class="tabs-content"> |
| |
| <div class="tab-pane active" id="images-tab"> |
| <div class="gallery"> |
| <div class="gallery-item"> |
| <h3 data-i18n="mask_title">Image Mask (Rembg)</h3> |
| <div class="gallery-image-box"> |
| <div class="img-placeholder" id="mask-placeholder" data-i18n="mask_placeholder">Waiting for generation...</div> |
| <img id="mask-preview" src="" alt="Mask Preview" style="display: none;"> |
| </div> |
| </div> |
| <div class="gallery-item"> |
| <h3 data-i18n="render_title">3D Gaussians Render (Front View)</h3> |
| <div class="gallery-image-box"> |
| <div class="img-placeholder" id="render-placeholder" data-i18n="render_placeholder">Waiting for generation...</div> |
| <img id="render-preview" src="" alt="Gaussian Preview" style="display: none;"> |
| </div> |
| </div> |
| </div> |
| </div> |
| |
| |
| <div class="tab-pane" id="files-tab"> |
| <div class="files-list" id="files-list"> |
| <p class="text-gray" id="downloads-empty-text" data-i18n="downloads_empty">Result files not generated.</p> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <script src="/static/app.js"></script> |
| </body> |
| </html> |
|
|