Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="utf-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |
| <title>html studio — harvis</title> | |
| <meta name="description" content="Describe a site, let any open-weights model write it, and deploy it to harvis.dev in about two seconds."> | |
| <link rel="stylesheet" href="styles.css"> | |
| <link rel="stylesheet" href="app.css"> | |
| </head> | |
| <body> | |
| <header class="nav"> | |
| <a class="lockup" href="https://harvis.dev" target="_blank" rel="noopener"> | |
| <span class="mark">[#]</span> | |
| <span class="wordmark">harvis</span> | |
| </a> | |
| <span class="nav-div" aria-hidden="true"></span> | |
| <span class="nav-title">html studio</span> | |
| <div class="nav-spacer"></div> | |
| <div class="auth"> | |
| <button id="signin" class="btn btn-outline btn-sm" type="button"> | |
| <i class="ri-user-line" aria-hidden="true"></i>Sign in with Hugging Face | |
| </button> | |
| <button id="tokentoggle" class="btn btn-ghost btn-sm" type="button"> | |
| <i class="ri-key-2-line" aria-hidden="true"></i>Use a token | |
| </button> | |
| <div id="whoami" class="whoami" hidden> | |
| <img id="avatar" alt="" width="22" height="22"> | |
| <span id="username" class="mono"></span> | |
| <button id="signout" class="btn btn-ghost btn-sm" type="button">Sign out</button> | |
| </div> | |
| <button id="theme" class="btn btn-ghost btn-sm btn-icon" type="button" title="Toggle ink / paper theme" aria-label="Toggle theme"> | |
| <i class="ri-contrast-2-line" aria-hidden="true"></i> | |
| </button> | |
| </div> | |
| </header> | |
| <div id="tokenrow" class="tokenrow" hidden> | |
| <label for="token">access token</label> | |
| <span class="inputwrap"> | |
| <i class="ri-key-2-line" aria-hidden="true"></i> | |
| <input id="token" type="password" autocomplete="off" spellcheck="false" | |
| placeholder="hf_… — huggingface.co/settings/tokens"> | |
| </span> | |
| <button id="tokensave" class="btn btn-secondary btn-sm" type="button">Save</button> | |
| <span class="hint">Stored in this browser. Sent only to the Hugging Face router.</span> | |
| </div> | |
| <main class="layout"> | |
| <!-- ── controls ───────────────────────────────────────────────── --> | |
| <aside class="rail"> | |
| <div class="field"> | |
| <label for="model">model</label> | |
| <span class="selectwrap"> | |
| <select id="model"><option value="">loading…</option></select> | |
| <span class="caret" aria-hidden="true">▾</span> | |
| </span> | |
| <p class="hint" id="modelhint">Open-weights chat models on the Hugging Face router.</p> | |
| </div> | |
| <div class="field field-grow"> | |
| <label for="prompt">describe the site</label> | |
| <textarea id="prompt" spellcheck="false" | |
| placeholder="A landing page for a coffee subscription called Ember. Hero with a tagline, three plan cards with prices, an FAQ, and a footer. Warm, generous whitespace, restrained motion."></textarea> | |
| </div> | |
| <details class="advanced"> | |
| <summary>advanced</summary> | |
| <div class="field"> | |
| <label for="system">system prompt</label> | |
| <textarea id="system" rows="5" spellcheck="false"></textarea> | |
| </div> | |
| <div class="field-row"> | |
| <div class="field"> | |
| <label for="temp">temperature <span id="tempval" class="mono-val">0.70</span></label> | |
| <input id="temp" type="range" min="0" max="1.5" step="0.05" value="0.7"> | |
| </div> | |
| <div class="field"> | |
| <label for="maxtok">max tokens</label> | |
| <input id="maxtok" type="number" min="1000" max="128000" step="1000" value="16000"> | |
| </div> | |
| </div> | |
| </details> | |
| <div class="actions"> | |
| <button id="generate" class="btn btn-primary btn-lg btn-full" type="button"> | |
| <i class="ri-terminal-line" aria-hidden="true"></i>Generate | |
| </button> | |
| <button id="stop" class="btn btn-secondary btn-lg" type="button" hidden>Stop</button> | |
| </div> | |
| <div class="examples"> | |
| <span class="examples-label">try</span> | |
| <button class="tag" type="button" data-example="A one-page portfolio for a landscape photographer named Ilse Moreau. Full-bleed hero image from picsum.photos, a masonry gallery of 9 photos with a lightbox, a short about section, and a contact form. Minimal, thin serif headings.">portfolio</button> | |
| <button class="tag" type="button" data-example="A playable Snake game. Canvas-based, arrow keys and swipe support, score and high score persisted, a start overlay, and a monochrome terminal aesthetic.">snake</button> | |
| <button class="tag" type="button" data-example="A pricing page for a developer tool called Relay. Three tiers with a monthly/annual toggle that recalculates prices, a feature comparison table, and an FAQ. Square corners, one accent colour, mono for every number.">pricing</button> | |
| <button class="tag" type="button" data-example="A deployment dashboard: four KPI tiles, a line chart of requests over 12 months, and a table of recent deploys with status dots and mono timestamps. Draw charts with inline SVG, no libraries.">dashboard</button> | |
| </div> | |
| </aside> | |
| <!-- ── output ─────────────────────────────────────────────────── --> | |
| <section class="output"> | |
| <div class="tabs" role="tablist"> | |
| <button class="tab is-active" id="tab-preview" role="tab" aria-selected="true" type="button">preview</button> | |
| <button class="tab" id="tab-code" role="tab" aria-selected="false" type="button"> | |
| code <span id="bytes" class="meta"></span> | |
| </button> | |
| <div class="tabs-spacer"></div> | |
| <span id="status" class="status"></span> | |
| <button id="reload" class="btn btn-ghost btn-sm" type="button"> | |
| <i class="ri-refresh-line" aria-hidden="true"></i>Re-render | |
| </button> | |
| <button id="download" class="btn btn-ghost btn-sm" type="button"> | |
| <i class="ri-download-2-line" aria-hidden="true"></i>Download | |
| </button> | |
| </div> | |
| <div class="pane pane-preview" id="pane-preview"> | |
| <div class="empty" id="empty"> | |
| <span class="corners" aria-hidden="true"><i></i><i></i><i></i><i></i></span> | |
| <i class="ri-code-s-slash-line empty-mark" aria-hidden="true"></i> | |
| <p class="empty-title">Nothing rendered yet.</p> | |
| <p class="hint">Pick a model, describe the site, then generate.</p> | |
| </div> | |
| <iframe id="preview" title="Live preview of the generated site" | |
| sandbox="allow-scripts allow-modals allow-popups allow-forms allow-pointer-lock allow-downloads" | |
| hidden></iframe> | |
| </div> | |
| <div class="pane pane-code" id="pane-code" hidden> | |
| <textarea id="code" spellcheck="false" autocomplete="off" | |
| placeholder="The generated document lands here, and it is editable. Edits re-render and are what gets deployed."></textarea> | |
| </div> | |
| <!-- ── deploy ───────────────────────────────────────────────── --> | |
| <div class="deploybar"> | |
| <button id="deploy" class="btn btn-primary" type="button" disabled> | |
| <i class="ri-rocket-line" aria-hidden="true"></i><span id="deploylabel">Deploy to harvis.dev</span> | |
| </button> | |
| <button id="newsite" class="btn btn-ghost btn-sm" type="button" hidden | |
| title="Create a new site instead of updating this one">New site</button> | |
| <div class="deployresult" id="deployresult"></div> | |
| </div> | |
| </section> | |
| </main> | |
| <div id="toast" class="toast" role="status" aria-live="polite" hidden> | |
| <span class="corners" aria-hidden="true"><i></i><i></i><i></i><i></i></span> | |
| <span id="toastdot" class="dot"></span> | |
| <span id="toastmsg"></span> | |
| </div> | |
| <script type="module" src="app.js"></script> | |
| </body> | |
| </html> | |