-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
428 lines (398 loc) · 28.4 KB
/
Copy pathindex.html
File metadata and controls
428 lines (398 loc) · 28.4 KB
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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>IMex — Pixels in. Prompts out.</title>
<meta name="description" content="IMex reverse-engineers any image into a high-fidelity, model-specific AI prompt. Client-side. Free with Groq. By macchant." />
<meta name="theme-color" content="#0a0a0b" />
<link rel="icon" href="data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'><defs><linearGradient id='g' x1='0' y1='0' x2='1' y2='1'><stop offset='0' stop-color='%237c5cff'/><stop offset='1' stop-color='%23ff5cd0'/></linearGradient></defs><rect width='32' height='32' rx='7' fill='url(%23g)'/><path d='M9 10h3v12H9zM14 10h3l3 5 3-5h3v12h-3v-7l-3 5-3-5v7h-3z' fill='white'/></svg>" />
<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=Inter:wght@300;400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600&family=Instrument+Serif:ital@0;1&display=swap" rel="stylesheet" />
<script src="https://cdn.tailwindcss.com"></script>
<script>
tailwind.config = {
theme: {
extend: {
fontFamily: {
sans: ['Inter', 'system-ui', 'sans-serif'],
mono: ['JetBrains Mono', 'ui-monospace', 'monospace'],
display: ['Instrument Serif', 'Georgia', 'serif'],
},
colors: {
ink: {
950: '#0a0a0b', 900: '#101013', 800: '#17171c', 700: '#22222a',
600: '#2e2e38', 500: '#3a3a47', 400: '#6b6b7a', 300: '#9a9aab',
200: '#c8c8d4', 100: '#e6e6ec',
},
accent: { 700: '#4a2fc4', 600: '#5b3fe0', 500: '#7c5cff', 400: '#9b85ff', 300: '#bba9ff' },
magenta: { 500: '#ff5cd0', 400: '#ff85dd' },
},
},
},
};
</script>
<style>
html { -webkit-text-size-adjust: 100%; }
html, body { background: #0a0a0b; color: #e6e6ec; }
body {
min-height: 100%;
overscroll-behavior-y: none;
}
/* Decorative ambient gradients — fixed via a dedicated layer to avoid the
iOS Safari `background-attachment: fixed` scroll bug. */
.bg-glow {
position: fixed; inset: 0; pointer-events: none; z-index: -2;
background-image:
radial-gradient(1200px 600px at 50% -10%, rgba(124,92,255,0.18), transparent 60%),
radial-gradient(800px 500px at 100% 100%, rgba(255,92,208,0.10), transparent 60%);
}
/* Grid: ::before */
.grid-bg::before {
content: ''; position: fixed; inset: 0; pointer-events: none; z-index: -1;
background-image:
linear-gradient(rgba(124,92,255,0.05) 1px, transparent 1px),
linear-gradient(90deg, rgba(124,92,255,0.05) 1px, transparent 1px);
background-size: 64px 64px;
mask-image: radial-gradient(ellipse 80% 60% at 50% 0%, black, transparent);
-webkit-mask-image: radial-gradient(ellipse 80% 60% at 50% 0%, black, transparent);
}
/* Grain: ::after (so both grain + grid can coexist; previously they were both ::before and only one rendered) */
.grain::after {
content: ''; position: fixed; inset: 0; pointer-events: none; z-index: -1; opacity: .04;
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
}
.scrollbar-thin::-webkit-scrollbar { width: 6px; height: 6px; }
.scrollbar-thin::-webkit-scrollbar-thumb { background: #2e2e38; border-radius: 6px; }
.chip { display: inline-flex; align-items: center; gap: 6px; padding: 4px 10px; border-radius: 999px; background: #17171c; border: 1px solid #22222a; font-size: 12px; }
.chip[data-conf="high"] { border-color: #5b3fe0; color: #e6e6ec; }
.chip[data-conf="mid"] { border-color: #3a3a47; color: #c8c8d4; }
.chip[data-conf="low"] { border-color: #2e2e38; opacity: .65; color: #9a9aab; }
.swatch { width: 22px; height: 22px; border-radius: 6px; border: 1px solid rgba(255,255,255,.06); }
.dropzone.dragover { border-color: #7c5cff; background: #14121f; }
details > summary { list-style: none; cursor: pointer; }
details > summary::-webkit-details-marker { display: none; }
.pulse-dot { width: 8px; height: 8px; border-radius: 50%; background: #7c5cff; box-shadow: 0 0 0 0 rgba(124,92,255,.7); animation: pulse 1.6s infinite; }
@keyframes pulse { 0% { box-shadow: 0 0 0 0 rgba(124,92,255,.5); } 70% { box-shadow: 0 0 0 12px rgba(124,92,255,0); } 100% { box-shadow: 0 0 0 0 rgba(124,92,255,0); } }
.glow { box-shadow: 0 0 0 1px rgba(124,92,255,0.25), 0 18px 60px -20px rgba(124,92,255,0.45); }
.gradient-text { background: linear-gradient(135deg, #ffffff 0%, #bba9ff 60%, #ff85dd 100%); -webkit-background-clip: text; background-clip: text; color: transparent; }
.brand-mark {
background: linear-gradient(135deg, #7c5cff 0%, #ff5cd0 100%);
box-shadow: 0 6px 20px -6px rgba(124,92,255,0.6), inset 0 1px 0 rgba(255,255,255,0.18);
}
.pill { display: inline-flex; align-items: center; gap: 6px; padding: 4px 10px; border-radius: 999px; background: rgba(124,92,255,0.10); border: 1px solid rgba(124,92,255,0.25); font-size: 11px; color: #bba9ff; }
.pill-dot { width: 6px; height: 6px; border-radius: 50%; background: #7c5cff; box-shadow: 0 0 8px #7c5cff; }
.section-num { font-family: 'JetBrains Mono', monospace; font-size: 10px; letter-spacing: 0.12em; color: #6b6b7a; text-transform: uppercase; }
.divider { height: 1px; background: linear-gradient(90deg, transparent, #22222a, transparent); }
kbd { font-family: 'JetBrains Mono', monospace; font-size: 10px; padding: 1px 5px; border-radius: 4px; background: #17171c; border: 1px solid #22222a; color: #c8c8d4; }
</style>
</head>
<body class="font-sans antialiased grid-bg grain">
<div class="bg-glow" aria-hidden="true"></div>
<div class="relative max-w-7xl mx-auto px-6 py-6">
<!-- Header / Brand — editorial masthead -->
<header class="mb-10">
<div class="flex items-center justify-between gap-4 pb-4 border-b border-ink-800">
<!-- left: tiny metadata strip, magazine-style -->
<div class="flex items-center gap-3 text-[10px] font-mono uppercase tracking-[0.18em] text-ink-500">
<span class="hidden sm:inline">Vol. 01</span>
<span class="hidden sm:inline text-ink-700">/</span>
<span class="text-ink-300">Image → Prompt Engine</span>
</div>
<!-- right: nav -->
<nav class="flex items-center gap-2">
<span id="provider-pill" class="pill hidden sm:inline-flex">
<span class="pill-dot"></span>
<span id="provider-pill-label">free mode</span>
</span>
<button id="settings-btn" class="text-xs text-ink-200 hover:text-white border border-ink-800 hover:border-accent-500 rounded-md px-3 py-1.5 transition flex items-center gap-1.5">
<svg viewBox="0 0 24 24" class="w-3.5 h-3.5" fill="none" stroke="currentColor" stroke-width="2"><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-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.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09a1.65 1.65 0 0 0 1.51-1 1.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>
Settings
</button>
<a href="https://github.com/macchant/vectorgen" target="_blank" rel="noopener" class="text-xs text-ink-200 hover:text-white border border-ink-800 hover:border-ink-500 rounded-md px-3 py-1.5 transition hidden md:inline-flex items-center gap-1.5">
<svg viewBox="0 0 24 24" class="w-3.5 h-3.5" fill="currentColor"><path d="M12 .5C5.65.5.5 5.65.5 12c0 5.08 3.29 9.39 7.86 10.91.58.1.79-.25.79-.55v-2.1c-3.2.7-3.87-1.37-3.87-1.37-.52-1.32-1.27-1.67-1.27-1.67-1.04-.71.08-.7.08-.7 1.15.08 1.76 1.18 1.76 1.18 1.02 1.76 2.69 1.25 3.34.95.1-.74.4-1.25.72-1.54-2.55-.29-5.24-1.28-5.24-5.69 0-1.26.45-2.29 1.18-3.1-.12-.29-.51-1.46.11-3.04 0 0 .96-.31 3.15 1.18.91-.25 1.89-.38 2.86-.38.97 0 1.95.13 2.86.38 2.18-1.49 3.14-1.18 3.14-1.18.62 1.58.23 2.75.11 3.04.74.81 1.18 1.84 1.18 3.1 0 4.42-2.69 5.4-5.25 5.68.41.36.78 1.06.78 2.14v3.17c0 .31.21.66.8.55C20.21 21.39 23.5 17.08 23.5 12 23.5 5.65 18.35.5 12 .5z"/></svg>
vectorgen
</a>
</nav>
</div>
<!-- masthead: wordmark + brand mark -->
<div class="pt-5 flex items-center gap-3">
<div class="brand-mark w-10 h-10 rounded-xl grid place-items-center shrink-0">
<svg viewBox="0 0 24 24" class="w-5 h-5 text-white" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round">
<rect x="3" y="3" width="11" height="11" rx="2"/>
<path d="M9 9l4 4M14 14l4 4M16 19h5v-5"/>
</svg>
</div>
<h1 class="font-display gradient-text leading-none tracking-tight text-4xl md:text-5xl">IMex</h1>
<span class="font-display italic text-ink-400 text-sm md:text-base ml-1 hidden sm:inline">— an image-to-prompt reverse engine.</span>
</div>
</header>
<!-- Hero — compact editorial -->
<section id="hero" class="mb-8">
<div class="relative">
<div class="absolute -top-10 -right-10 w-60 h-60 rounded-full bg-accent-500/10 blur-3xl pointer-events-none"></div>
<div class="absolute -bottom-10 left-1/3 w-52 h-52 rounded-full bg-magenta-500/10 blur-3xl pointer-events-none"></div>
<div class="relative grid grid-cols-1 md:grid-cols-12 gap-4 md:gap-8 items-end">
<div class="md:col-span-7">
<div class="text-[10px] font-mono uppercase tracking-[0.22em] text-ink-500 mb-3 flex items-center gap-3">
<span class="w-6 h-px bg-ink-600"></span>
<span>Issue 01 · The Reverse Engine</span>
</div>
<h2 class="font-display tracking-tight leading-[1.0] text-2xl md:text-4xl">
Decode any image into the <span class="italic gradient-text">exact prompt</span> that made it.
</h2>
</div>
<div class="md:col-span-5 md:pb-1">
<p class="text-xs md:text-sm text-ink-300 leading-relaxed border-l border-ink-700 pl-3">
Five-stage pipeline: pixel analysis, frontier VLM, in-browser SigLIP, fusion, model-specific synthesis.
</p>
<div class="mt-3 flex flex-wrap items-center gap-x-3 gap-y-1.5 text-[11px] text-ink-400">
<span class="flex items-center gap-1.5"><span class="w-1 h-1 rounded-full bg-accent-500"></span>client-side</span>
<span class="flex items-center gap-1.5"><span class="w-1 h-1 rounded-full bg-accent-500"></span>private</span>
<span class="flex items-center gap-1.5"><span class="w-1 h-1 rounded-full bg-accent-500"></span>free with Groq</span>
</div>
</div>
</div>
</div>
<!-- Onboarding banner (dismissible) -->
<div id="onboarding" class="hidden mt-5 rounded-xl border border-accent-500/30 bg-accent-500/5 px-4 py-2.5 flex items-center justify-between gap-3">
<div class="flex items-center gap-3 text-xs text-ink-200">
<span class="text-base">✦</span>
<span>Want frontier-quality extraction for free? Add your Groq <code class="font-mono text-accent-300">gsk_…</code> key in <button id="onboarding-open" class="underline decoration-dotted hover:text-white">Settings</button>. ~1.5s, no payment.</span>
</div>
<button id="onboarding-dismiss" class="text-ink-400 hover:text-white text-sm">✕</button>
</div>
</section>
<!-- Main grid -->
<main class="grid grid-cols-1 lg:grid-cols-12 gap-6">
<!-- Left: input -->
<section class="lg:col-span-5 space-y-4">
<div class="flex items-center justify-between mb-1">
<span class="section-num">01 · Input</span>
<span id="stage1-time" class="text-[10px] font-mono text-ink-500"></span>
</div>
<div id="dropzone" class="dropzone relative aspect-square rounded-2xl border-2 border-dashed border-ink-700 hover:border-accent-500 transition bg-ink-900/40 grid place-items-center text-center p-6 cursor-pointer overflow-hidden">
<input id="file-input" type="file" accept="image/*" class="hidden" />
<div id="dropzone-empty" class="space-y-3 relative">
<div class="mx-auto w-14 h-14 rounded-2xl brand-mark grid place-items-center">
<svg viewBox="0 0 24 24" class="w-6 h-6 text-white" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 16V4m0 0l-4 4m4-4l4 4M4 20h16" stroke-linecap="round" stroke-linejoin="round"/></svg>
</div>
<div class="text-sm">Drop an image, <span class="text-accent-400 underline decoration-dotted">browse</span>, or paste from clipboard</div>
<div class="text-xs text-ink-400">PNG · JPG · WEBP · GIF · ≤ 20MB · processed locally</div>
</div>
<img id="preview" alt="" class="hidden max-w-full max-h-full rounded-xl object-contain" />
</div>
<!-- Stage 1 panels -->
<div class="grid grid-cols-2 gap-3 text-xs">
<div class="rounded-xl bg-ink-900/60 border border-ink-700 p-3">
<div class="text-ink-400 mb-1 font-mono text-[10px] uppercase tracking-wider">Aspect</div>
<div id="m-ar" class="font-mono text-ink-100">—</div>
</div>
<div class="rounded-xl bg-ink-900/60 border border-ink-700 p-3">
<div class="text-ink-400 mb-1 font-mono text-[10px] uppercase tracking-wider">Vector-likeness</div>
<div id="m-vector" class="font-mono text-ink-100">—</div>
</div>
<div class="rounded-xl bg-ink-900/60 border border-ink-700 p-3">
<div class="text-ink-400 mb-1 font-mono text-[10px] uppercase tracking-wider">Background</div>
<div id="m-bg" class="font-mono text-ink-100">—</div>
</div>
<div class="rounded-xl bg-ink-900/60 border border-ink-700 p-3">
<div class="text-ink-400 mb-1 font-mono text-[10px] uppercase tracking-wider">Edge density</div>
<div id="m-edge" class="font-mono text-ink-100">—</div>
</div>
</div>
<div class="rounded-xl bg-ink-900/60 border border-ink-700 p-3">
<div class="text-ink-400 mb-2 font-mono text-[10px] uppercase tracking-wider">Palette · LAB k-means</div>
<div id="palette" class="flex flex-wrap gap-2 min-h-[28px]"></div>
</div>
<details class="rounded-xl bg-ink-900/60 border border-ink-700 p-3 text-xs">
<summary class="text-ink-300 hover:text-white flex items-center justify-between font-mono text-[10px] uppercase tracking-wider">
<span>EXIF / metadata</span>
<span class="text-ink-500">▾</span>
</summary>
<pre id="exif" class="mt-2 text-ink-300 font-mono whitespace-pre-wrap text-[11px] max-h-40 overflow-auto scrollbar-thin">—</pre>
</details>
<div class="divider"></div>
<button id="extract-btn" disabled class="w-full rounded-xl brand-mark disabled:bg-none disabled:bg-ink-700 disabled:text-ink-400 disabled:cursor-not-allowed text-white font-medium py-3.5 transition flex items-center justify-center gap-2 glow disabled:!shadow-none">
<span id="extract-label">Extract Prompt</span>
<span id="extract-spinner" class="hidden pulse-dot"></span>
</button>
<p id="status" class="text-xs text-ink-400 text-center min-h-[1em]"></p>
</section>
<!-- Right: schema + prompt output -->
<section class="lg:col-span-7 space-y-4">
<div class="flex items-center justify-between mb-1">
<span class="section-num">02 · Target & Schema</span>
</div>
<!-- Target model selector -->
<div class="rounded-2xl bg-ink-900/60 border border-ink-700 p-4">
<div class="flex items-center justify-between mb-3 flex-wrap gap-2">
<div>
<div class="text-[10px] font-mono uppercase tracking-wider text-ink-400">Target model</div>
<div class="text-sm font-medium">Prompt syntax</div>
</div>
<select id="target-model" class="bg-ink-800 border border-ink-700 rounded-lg px-3 py-1.5 text-sm hover:border-ink-500 focus:border-accent-500 focus:outline-none">
<option value="midjourney">Midjourney v6</option>
<option value="ideogram">Ideogram (typography)</option>
<option value="leonardo">Leonardo.ai</option>
<option value="flux">Flux / Whisk</option>
<option value="kreaflux">Krea Flux</option>
<option value="nanobananapro">Nano Banana Pro (Gemini 3)</option>
<option value="imagen4">Imagen 4 (Google)</option>
<option value="recraftv3">Recraft v3</option>
<option value="sdxl">SDXL / Pony</option>
<option value="dalle3">DALL·E 3</option>
</select>
</div>
<div class="flex flex-wrap gap-3 text-xs">
<label class="flex items-center gap-1.5 cursor-pointer hover:text-white"><input type="checkbox" id="opt-isolated" class="accent-accent-500"/>Isolated subject</label>
<label class="flex items-center gap-1.5 cursor-pointer hover:text-white"><input type="checkbox" id="opt-knolling" class="accent-accent-500"/>Knolling / sticker sheet</label>
<label class="flex items-center gap-1.5 cursor-pointer hover:text-white"><input type="checkbox" id="opt-typography" class="accent-accent-500"/>Preserve typography</label>
<label class="flex items-center gap-1.5 cursor-pointer hover:text-white"><input type="checkbox" id="opt-vector" class="accent-accent-500"/>Force vector mode</label>
</div>
</div>
<!-- Schema chips -->
<div class="rounded-2xl bg-ink-900/60 border border-ink-700 p-4 space-y-3">
<div class="flex items-center justify-between">
<div class="text-sm font-medium">Extracted schema</div>
<div class="text-[11px] text-ink-400 flex items-center gap-2">
<span class="inline-block w-2 h-2 rounded-full bg-accent-500"></span>high
<span class="inline-block w-2 h-2 rounded-full bg-ink-500"></span>mid
<span class="inline-block w-2 h-2 rounded-full bg-ink-700"></span>low
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-3 text-xs">
<div>
<div class="text-ink-400 mb-1 font-mono text-[10px] uppercase tracking-wider">Subject</div>
<div id="s-subject" class="flex flex-wrap gap-1.5 min-h-[28px]"><span class="text-ink-500">—</span></div>
</div>
<div>
<div class="text-ink-400 mb-1 font-mono text-[10px] uppercase tracking-wider">Style</div>
<div id="s-style" class="flex flex-wrap gap-1.5 min-h-[28px]"><span class="text-ink-500">—</span></div>
</div>
<div>
<div class="text-ink-400 mb-1 font-mono text-[10px] uppercase tracking-wider">Linework</div>
<div id="s-linework" class="flex flex-wrap gap-1.5 min-h-[28px]"><span class="text-ink-500">—</span></div>
</div>
<div>
<div class="text-ink-400 mb-1 font-mono text-[10px] uppercase tracking-wider">Medium · technique</div>
<div id="s-medium" class="flex flex-wrap gap-1.5 min-h-[28px]"><span class="text-ink-500">—</span></div>
</div>
<div>
<div class="text-ink-400 mb-1 font-mono text-[10px] uppercase tracking-wider">Lighting</div>
<div id="s-lighting" class="flex flex-wrap gap-1.5 min-h-[28px]"><span class="text-ink-500">—</span></div>
</div>
<div>
<div class="text-ink-400 mb-1 font-mono text-[10px] uppercase tracking-wider">Mood</div>
<div id="s-mood" class="flex flex-wrap gap-1.5 min-h-[28px]"><span class="text-ink-500">—</span></div>
</div>
<div>
<div class="text-ink-400 mb-1 font-mono text-[10px] uppercase tracking-wider">Composition</div>
<div id="s-composition" class="flex flex-wrap gap-1.5 min-h-[28px]"><span class="text-ink-500">—</span></div>
</div>
<div>
<div class="text-ink-400 mb-1 font-mono text-[10px] uppercase tracking-wider">Negatives · avoid</div>
<div id="s-negative" class="flex flex-wrap gap-1.5 min-h-[28px]"><span class="text-ink-500">—</span></div>
</div>
</div>
<details class="text-xs">
<summary class="text-ink-400 hover:text-white font-mono text-[10px] uppercase tracking-wider">Raw narrative caption</summary>
<p id="s-narrative" class="mt-2 text-ink-200 leading-relaxed">—</p>
</details>
</div>
<div class="flex items-center justify-between mb-1 mt-4">
<span class="section-num">03 · Output</span>
</div>
<!-- Final prompt -->
<div class="rounded-2xl bg-ink-900/60 border border-ink-700 p-4">
<div class="flex items-center justify-between mb-2">
<div class="text-sm font-medium">Synthesized prompt</div>
<div class="flex items-center gap-2">
<button id="regenerate-btn" class="text-xs text-ink-300 hover:text-white border border-ink-700 hover:border-accent-500 rounded-md px-2.5 py-1 transition flex items-center gap-1">
<svg viewBox="0 0 24 24" class="w-3 h-3" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M3 12a9 9 0 0 1 15.3-6.4L21 8M21 3v5h-5M21 12a9 9 0 0 1-15.3 6.4L3 16M3 21v-5h5"/></svg>
Regenerate
</button>
<button id="copy-btn" class="text-xs text-ink-300 hover:text-white border border-ink-700 hover:border-accent-500 rounded-md px-2.5 py-1 transition flex items-center gap-1">
<svg viewBox="0 0 24 24" class="w-3 h-3" fill="none" stroke="currentColor" stroke-width="2.5"><rect x="9" y="9" width="11" height="11" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
Copy
</button>
</div>
</div>
<textarea id="final-prompt" rows="6" class="w-full bg-ink-950 border border-ink-700 rounded-lg p-3 font-mono text-xs leading-relaxed text-ink-100 focus:outline-none focus:border-accent-500 resize-y" placeholder="Drop an image and click Extract Prompt…"></textarea>
<div id="prompt-meta" class="text-[11px] text-ink-400 mt-2 font-mono"></div>
</div>
</section>
</main>
<footer class="mt-16 mb-4">
<div class="divider mb-6"></div>
<div class="flex flex-col md:flex-row items-center md:items-end justify-between gap-4 text-[11px] text-ink-500">
<div class="flex items-center gap-2">
<div class="brand-mark w-6 h-6 rounded-md grid place-items-center">
<svg viewBox="0 0 24 24" class="w-3 h-3 text-white" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round">
<rect x="3" y="3" width="11" height="11" rx="2"/>
<path d="M16 19h5v-5"/>
</svg>
</div>
<span><span class="font-display text-ink-300">IMex</span> — part of the <a href="https://github.com/macchant/vectorgen" class="text-ink-300 hover:text-white underline decoration-dotted">vectorgen</a> family · by <a href="https://github.com/macchant" class="text-ink-300 hover:text-white underline decoration-dotted">macchant</a></span>
</div>
<div class="flex items-center gap-3">
<span>all processing client-side</span>
<span>·</span>
<span>API keys never leave your browser</span>
<span>·</span>
<a href="https://github.com/macchant" class="hover:text-ink-300 underline decoration-dotted">GitHub</a>
</div>
</div>
</footer>
</div>
<!-- Settings modal -->
<div id="settings-modal" class="hidden fixed inset-0 z-50 bg-black/70 backdrop-blur-md grid place-items-center p-4">
<div class="bg-ink-900 border border-ink-700 rounded-2xl max-w-lg w-full p-6 space-y-4 glow">
<div class="flex items-center justify-between">
<div class="flex items-center gap-2">
<div class="brand-mark w-7 h-7 rounded-lg grid place-items-center">
<svg viewBox="0 0 24 24" class="w-3.5 h-3.5 text-white" fill="none" stroke="currentColor" stroke-width="2.4"><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-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.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09a1.65 1.65 0 0 0 1.51-1 1.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>
</div>
<h2 class="font-display text-xl">Settings</h2>
</div>
<button id="settings-close" class="text-ink-400 hover:text-white text-lg">✕</button>
</div>
<div class="text-xs text-ink-300 space-y-3">
<div class="rounded-lg bg-accent-500/5 border border-accent-500/20 p-3 text-[11px] text-ink-300 leading-relaxed">
<strong class="text-accent-300">Recommended for free use:</strong> Get a free API key from <a href="https://console.groq.com/keys" target="_blank" class="underline decoration-dotted">console.groq.com</a> (30s, no payment). Pick <em>Groq</em> below and paste your <code class="font-mono text-accent-300">gsk_…</code> key.
</div>
<div>
<label class="block text-ink-400 mb-1 font-mono text-[10px] uppercase tracking-wider">VLM provider</label>
<select id="provider" class="w-full bg-ink-800 border border-ink-700 rounded-lg px-3 py-2 focus:border-accent-500 focus:outline-none">
<option value="none">None — free mode (in-browser models only)</option>
<option value="groq">Groq (Llama 4 Scout / Maverick) — FREE TIER ✨</option>
<option value="openai">OpenAI (gpt-4o / gpt-4o-mini)</option>
<option value="anthropic">Anthropic (claude-sonnet-4-5)</option>
<option value="gemini">Google Gemini (2.5-flash / 2.5-pro)</option>
</select>
</div>
<div>
<label class="block text-ink-400 mb-1 font-mono text-[10px] uppercase tracking-wider">API key <span class="text-ink-500 normal-case">· stored only in your browser</span></label>
<input id="api-key" type="password" placeholder="gsk_… / sk-… / sk-ant-… / AIza…" class="w-full bg-ink-800 border border-ink-700 rounded-lg px-3 py-2 font-mono text-xs focus:border-accent-500 focus:outline-none" />
</div>
<div>
<label class="block text-ink-400 mb-1 font-mono text-[10px] uppercase tracking-wider">Model · optional override</label>
<input id="model-name" type="text" placeholder="e.g. meta-llama/llama-4-scout-17b-16e-instruct" class="w-full bg-ink-800 border border-ink-700 rounded-lg px-3 py-2 font-mono text-xs focus:border-accent-500 focus:outline-none" />
</div>
<div class="border-t border-ink-700 pt-3">
<label class="flex items-center gap-2 cursor-pointer">
<input type="checkbox" id="opt-local-models" class="accent-accent-500" />
<span>Enable in-browser SigLIP tagger (~80MB one-time download)</span>
</label>
<p class="text-ink-500 text-[11px] mt-1 ml-6">Adds grounded tag matching against the IMex / vectorgen vocab. Free, slower first run.</p>
</div>
</div>
<div class="flex justify-end gap-2 pt-2">
<button id="settings-save" class="brand-mark text-white text-sm rounded-lg px-4 py-2 glow">Save</button>
</div>
</div>
</div>
<script type="module" src="./js/main.js"></script>
</body>
</html>