File size: 8,370 Bytes
c5b48f1 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | <!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
<title>PixelLock — AI Pixel-Art Retexturing</title>
<meta name="description" content="Footprint-locked AI pixel-art retexturing — keep the exact silhouette, change the style." />
<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=Space+Grotesk:wght@400;500;700&family=JetBrains+Mono:wght@400;500;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="/static/styles.css" />
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Crect width='16' height='16' rx='3' fill='%230b0b14'/%3E%3Crect x='3' y='3' width='4' height='4' fill='%23a06bff'/%3E%3Crect x='9' y='3' width='4' height='4' fill='%2300e5d4'/%3E%3Crect x='3' y='9' width='4' height='4' fill='%2300e5d4'/%3E%3Crect x='9' y='9' width='4' height='4' fill='%23a06bff'/%3E%3C/svg%3E" />
</head>
<body>
<div class="bg-glow" aria-hidden="true"></div>
<div class="scanlines" aria-hidden="true"></div>
<header class="appbar">
<div class="brand">
<span class="logo" aria-hidden="true"><i></i><i></i><i></i><i></i></span>
<h1 class="wordmark">Pixel<b>Lock</b></h1>
<span class="brand-div">|</span>
<span class="brand-sub">AI Pixel-Art Retexturing Tool</span>
</div>
<div class="fp-pill" title="Every edit keeps your sprite's exact shape, by construction">
<svg viewBox="0 0 24 24" width="14" height="14"><path fill="currentColor" d="M12 1a5 5 0 0 0-5 5v3H6a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-9a2 2 0 0 0-2-2h-1V6a5 5 0 0 0-5-5m0 2a3 3 0 0 1 3 3v3H9V6a3 3 0 0 1 3-3"/></svg>
Footprint-locked retexturing
</div>
<div class="appbar-right">
<span class="server-pill"><span id="server-dot" class="dot down"></span><span id="server-label">connecting…</span></span>
<a class="ghost-btn" href="https://github.com/ggml-org/llama.cpp" target="_blank" rel="noopener">⌁ GBNF · llama.cpp</a>
</div>
</header>
<div class="howbar">
<span class="how-tag">⚡ NOT an image generator</span>
<span class="how-steps">your PNG → a <b>text grid</b> (PALETTE + GRID) → a <b>fine-tuned text LLM</b> rewrites it under a <b>GBNF grammar</b> that locks the exact shape → pixel-perfect PNG. <em>It's language modeling, not diffusion.</em></span>
</div>
<section class="proofbar" aria-label="PixelLock guarantees">
<div class="proof-card">
<span class="proof-k">100%</span>
<span class="proof-v">footprint constrained</span>
</div>
<div class="proof-card">
<span class="proof-k">PNG → TEXT → PNG</span>
<span class="proof-v">palette grid, not diffusion</span>
</div>
<div class="proof-card">
<span class="proof-k">LLAMA.CPP + GBNF</span>
<span class="proof-v">shape locked in the decoder</span>
</div>
</section>
<main class="layout">
<!-- LEFT: controls -->
<aside class="controls">
<section class="step">
<h2><span class="num">01</span> Upload sprite</h2>
<div id="dropzone" class="dropzone" tabindex="0" role="button" aria-label="Upload a sprite PNG">
<input id="file" type="file" accept="image/png,image/*" hidden />
<div id="dz-empty" class="dz-empty">
<div class="dz-ico" aria-hidden="true">⬆</div>
<p class="dz-main">Drop sprite PNG or <span class="link">click to upload</span></p>
<p class="dz-hint">best for 16×16 – 64×64</p>
<span class="dz-tag">PNG</span>
</div>
<div id="dz-loaded" class="dz-loaded" hidden>
<img id="dz-preview" class="pixelated" alt="loaded sprite" />
<div class="dz-meta"><span id="dz-name" class="dz-name">sprite.png</span>
<button id="dz-clear" class="link-btn" type="button">change</button></div>
</div>
</div>
</section>
<section class="step starter-step">
<h2><span class="num">01B</span> Starter sprites <span class="opt">click to load</span></h2>
<div id="asset-strip" class="asset-strip" aria-label="Starter sprites"></div>
</section>
<section class="step">
<h2><span class="num">02</span> Theme / vibe <span class="opt">optional</span></h2>
<div id="chips" class="chips" role="listbox" aria-label="Theme presets"></div>
</section>
<section class="step">
<h2><span class="num">03</span> Prompt <span class="opt">optional</span></h2>
<textarea id="prompt" class="prompt" rows="3" spellcheck="false"
placeholder="Restyle into… (the AI invents the colors; the shape stays locked)"></textarea>
</section>
<section class="step">
<h2><span class="num">04</span> Mode</h2>
<div id="mode-toggle" class="toggle" role="tablist" aria-label="Edit mode">
<span id="toggle-glider" class="toggle-glider" aria-hidden="true"></span>
<button class="toggle-opt active" data-mode="exact" role="tab" aria-selected="true">🎨 Retheme</button>
<button class="toggle-opt" data-mode="upscale2x" role="tab" aria-selected="false">⤢ Upscale 2×</button>
</div>
</section>
<button id="run" class="run-btn" disabled>
<span class="run-label">▶ RUN RETEXTURE</span>
<span class="run-spinner" aria-hidden="true"></span>
</button>
<p id="run-hint" class="hint">load a sprite to begin</p>
</aside>
<!-- CENTER: stage -->
<section class="stage lab">
<div class="compare">
<figure class="frame">
<figcaption>INPUT <span>your sprite</span></figcaption>
<div class="checker canvas"><img id="img-in" class="pixelated" alt="input sprite" /></div>
</figure>
<div class="arrow" aria-hidden="true">▶</div>
<figure class="frame">
<figcaption>OUTPUT <span>AI restyled</span></figcaption>
<div class="checker canvas">
<img id="img-out" class="pixelated" alt="restyled sprite" />
<div id="frame-empty" class="frame-empty"><p>your restyled sprite<br/>appears here</p></div>
<div id="frame-loader" class="frame-loader" hidden>
<div class="loader-grid"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></div>
<p id="loader-text">working…</p>
</div>
</div>
</figure>
<aside class="sil-panel">
<div class="sil-head">
<svg viewBox="0 0 24 24" width="12" height="12"><path fill="currentColor" d="M12 1a5 5 0 0 0-5 5v3H6a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-9a2 2 0 0 0-2-2h-1V6a5 5 0 0 0-5-5m0 2a3 3 0 0 1 3 3v3H9V6a3 3 0 0 1 3-3"/></svg>
SILHOUETTE LOCKED
</div>
<div class="sil-art checker"><canvas id="sil-canvas" width="64" height="64"></canvas></div>
<p class="sil-note">Exact footprint & transparency preserved — guaranteed by the decoding grammar, not hoped for.</p>
</aside>
</div>
<div class="statusbar">
<span id="badge" class="badge ok" hidden>✓ silhouette preserved</span>
<span id="status" class="status">—</span>
<a id="download" class="dl-btn" download hidden>⭳ Download PNG</a>
</div>
<details class="wire-reveal">
<summary>⌖ see what the model actually <b>wrote</b> — it's text, not pixels</summary>
<pre id="wire-out" class="wire">Run an edit, then peek here: the LLM literally writes a PALETTE block and a GRID of cells (K R R K …). The GBNF grammar forces every transparent cell to stay transparent — that's why the shape can't break.</pre>
</details>
<section class="gallery-wrap" aria-label="Before and after examples">
<div class="gallery-head"><h3>Before → After examples</h3><span class="hint-sm">click any card to load it</span></div>
<div id="gallery" class="gallery"></div>
</section>
</section>
</main>
<footer class="site-foot">
<span class="foot-strong">✦ Pixel-precise · AI-powered · your shape, any vibe</span>
<span class="sep">·</span>
<span class="foot-dim">fine-tuned Gemma-4-12B · GBNF footprint grammar · runs on llama.cpp · Build Small Hackathon</span>
</footer>
<script src="/static/app.js" defer></script>
</body>
</html>
|