@retro-antlitz-kartei/react-editor 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs ADDED
@@ -0,0 +1,750 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+ var generator = require('@retro-antlitz-kartei/generator');
5
+ var jsxRuntime = require('react/jsx-runtime');
6
+ var animate = require('@retro-antlitz-kartei/animate');
7
+
8
+ // src/AvatarEditor.tsx
9
+ function AvatarPreview({
10
+ config,
11
+ width = 320,
12
+ height = 400,
13
+ background = true,
14
+ floor = true,
15
+ className,
16
+ style,
17
+ onClick
18
+ }) {
19
+ const ref = react.useRef(null);
20
+ react.useEffect(() => {
21
+ const canvas = ref.current;
22
+ if (!canvas) return;
23
+ generator.renderAvatar(canvas, config, { background, floor });
24
+ }, [config, background, floor, width, height]);
25
+ return /* @__PURE__ */ jsxRuntime.jsx(
26
+ "canvas",
27
+ {
28
+ ref,
29
+ width,
30
+ height,
31
+ className,
32
+ style: { imageRendering: "pixelated", display: "block", ...style },
33
+ onClick
34
+ }
35
+ );
36
+ }
37
+ function CombatModal({ config, theme: t, onClose }) {
38
+ const canvasRef = react.useRef(null);
39
+ const arenaRef = react.useRef(null);
40
+ const [pose, setPose] = react.useState("idle");
41
+ react.useEffect(() => {
42
+ const canvas = canvasRef.current;
43
+ if (!canvas) return;
44
+ const arena = new animate.AvatarArena(canvas, { pose: "idle" });
45
+ arena.setConfig(config);
46
+ arenaRef.current = arena;
47
+ return () => arena.destroy();
48
+ }, []);
49
+ react.useEffect(() => {
50
+ arenaRef.current?.setConfig(config);
51
+ }, [config]);
52
+ react.useEffect(() => {
53
+ arenaRef.current?.setPose(pose);
54
+ }, [pose]);
55
+ return /* @__PURE__ */ jsxRuntime.jsx(
56
+ "div",
57
+ {
58
+ onClick: onClose,
59
+ style: {
60
+ position: "fixed",
61
+ inset: 0,
62
+ zIndex: 60,
63
+ background: "rgba(8,4,16,0.82)",
64
+ display: "flex",
65
+ alignItems: "center",
66
+ justifyContent: "center",
67
+ padding: "20px",
68
+ backdropFilter: "blur(3px)"
69
+ },
70
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
71
+ "div",
72
+ {
73
+ onClick: (e) => e.stopPropagation(),
74
+ style: {
75
+ background: t.cabinet,
76
+ border: "4px solid " + t.cabinetBorder,
77
+ borderRadius: t.paper ? "6px" : "14px",
78
+ padding: "18px",
79
+ display: "flex",
80
+ flexDirection: "column",
81
+ gap: "14px",
82
+ width: "100%",
83
+ maxWidth: "420px",
84
+ boxShadow: "0 20px 60px rgba(0,0,0,.6)"
85
+ },
86
+ children: [
87
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", gap: "10px" }, children: [
88
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontFamily: t.mono, fontSize: "10px", color: t.title, letterSpacing: "1px" }, children: "\u2694 COMBAT MODE" }),
89
+ /* @__PURE__ */ jsxRuntime.jsx(
90
+ "button",
91
+ {
92
+ onClick: onClose,
93
+ style: {
94
+ fontFamily: t.mono,
95
+ fontSize: "11px",
96
+ cursor: "pointer",
97
+ width: "30px",
98
+ height: "30px",
99
+ borderRadius: "7px",
100
+ border: "2px solid " + t.panelBorder,
101
+ background: "#ffffff10",
102
+ color: "#fff",
103
+ flex: "0 0 auto"
104
+ },
105
+ children: "\u2715"
106
+ }
107
+ )
108
+ ] }),
109
+ /* @__PURE__ */ jsxRuntime.jsx(
110
+ "canvas",
111
+ {
112
+ ref: canvasRef,
113
+ width: 360,
114
+ height: 380,
115
+ style: {
116
+ width: "100%",
117
+ maxWidth: "360px",
118
+ aspectRatio: "360 / 380",
119
+ imageRendering: "pixelated",
120
+ display: "block",
121
+ margin: "0 auto",
122
+ borderRadius: "8px",
123
+ border: "3px solid " + t.cabinetBorder,
124
+ background: "#0c0618"
125
+ }
126
+ }
127
+ ),
128
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "grid", gridTemplateColumns: "repeat(3,1fr)", gap: "7px" }, children: animate.POSES.map((p) => /* @__PURE__ */ jsxRuntime.jsx(
129
+ "button",
130
+ {
131
+ onClick: () => setPose(p),
132
+ style: {
133
+ fontFamily: t.mono,
134
+ fontSize: "7px",
135
+ letterSpacing: ".5px",
136
+ cursor: "pointer",
137
+ padding: "10px 4px",
138
+ borderRadius: "6px",
139
+ border: "2px solid " + (pose === p ? "#00f0ff" : "#3a2f55"),
140
+ background: pose === p ? "#00f0ff" : "#1c0d33",
141
+ color: pose === p ? "#10131c" : "#cdbcff"
142
+ },
143
+ children: animate.POSE_NAMES[p].toUpperCase()
144
+ },
145
+ p
146
+ )) })
147
+ ]
148
+ }
149
+ )
150
+ }
151
+ );
152
+ }
153
+
154
+ // src/theme.ts
155
+ var LAYOUTS = [
156
+ { key: "arcade", name: "ARCADE" },
157
+ { key: "kompakt", name: "COMPACT" },
158
+ { key: "steckbrief", name: "WANTED" }
159
+ ];
160
+ var MONO = "'Press Start 2P',monospace";
161
+ var BODY = "'VT323',monospace";
162
+ function theme(layout) {
163
+ if (layout === "kompakt") {
164
+ return {
165
+ stageBg: "#10131c",
166
+ cabinet: "#1a1f2e",
167
+ cabinetBorder: "#2a3145",
168
+ marqueeBg: "#232a3d",
169
+ title: "#7df9ff",
170
+ accent: "#ff5d8f",
171
+ screenBg: "#0b0e16",
172
+ panel: "#222a3d",
173
+ panelBorder: "#323b54",
174
+ rowBg: "#1a2032",
175
+ text: "#cdd6f4",
176
+ sub: "#8a93b2",
177
+ mainDir: "row",
178
+ mono: MONO,
179
+ body: BODY,
180
+ radius: "14px",
181
+ titleText: "AVATAR EDITOR",
182
+ glow: false,
183
+ paper: false
184
+ };
185
+ }
186
+ if (layout === "steckbrief") {
187
+ return {
188
+ stageBg: "#3a2a18",
189
+ cabinet: "#efe2c4",
190
+ cabinetBorder: "#7a5a32",
191
+ marqueeBg: "#c0392b",
192
+ title: "#fff4dc",
193
+ accent: "#c0392b",
194
+ screenBg: "#d8c9a6",
195
+ panel: "#e6d8ba",
196
+ panelBorder: "#b89a64",
197
+ rowBg: "#f3ead2",
198
+ text: "#4a3520",
199
+ sub: "#8a6e44",
200
+ mainDir: "row",
201
+ mono: MONO,
202
+ body: BODY,
203
+ radius: "4px",
204
+ titleText: "WANTED",
205
+ glow: false,
206
+ paper: true
207
+ };
208
+ }
209
+ return {
210
+ // arcade
211
+ stageBg: "#1a0b2e",
212
+ cabinet: "#3a1d5c",
213
+ cabinetBorder: "#ff2e88",
214
+ marqueeBg: "#120726",
215
+ title: "#ffe600",
216
+ accent: "#00f0ff",
217
+ screenBg: "#06010f",
218
+ panel: "#2a1248",
219
+ panelBorder: "#7b2ff7",
220
+ rowBg: "#1c0d33",
221
+ text: "#ffe600",
222
+ sub: "#b48cff",
223
+ mainDir: "column",
224
+ mono: MONO,
225
+ body: BODY,
226
+ radius: "10px",
227
+ titleText: "AVATAR-O-MAT",
228
+ glow: true,
229
+ paper: false
230
+ };
231
+ }
232
+ var FONT_HREFS = [
233
+ "https://fonts.googleapis.com/css2?family=Press+Start+2P&family=VT323&display=swap"
234
+ ];
235
+ var PART_CONTROLS = [
236
+ { key: "gender", label: "BUILD" },
237
+ { key: "hut", label: "HAT" },
238
+ { key: "haare", label: "HAIR" },
239
+ { key: "ohren", label: "EARS" },
240
+ { key: "nase", label: "NOSE" },
241
+ { key: "acc", label: "ACCESSORY" },
242
+ { key: "torso", label: "TOP" },
243
+ { key: "hose", label: "TROUSERS" }
244
+ ];
245
+ var VIEW_OPTIONS = [
246
+ { key: "left", name: "LEFT" },
247
+ { key: "front", name: "FRONT" },
248
+ { key: "right", name: "RIGHT" }
249
+ ];
250
+ function useControllable(controlled, initial, onChange) {
251
+ const [internal, setInternal] = react.useState(initial);
252
+ const value = controlled !== void 0 ? controlled : internal;
253
+ const set = react.useCallback(
254
+ (v) => {
255
+ if (controlled === void 0) setInternal(v);
256
+ onChange?.(v);
257
+ },
258
+ [controlled, onChange]
259
+ );
260
+ return [value, set];
261
+ }
262
+ function AvatarEditor(props) {
263
+ const {
264
+ value,
265
+ defaultValue,
266
+ seed,
267
+ onChange,
268
+ layout: layoutProp,
269
+ defaultLayout = "arcade",
270
+ onLayoutChange,
271
+ showLayoutPicker = true,
272
+ showCombat = true,
273
+ showCode = true,
274
+ showSeed = true,
275
+ loadFonts = true,
276
+ className,
277
+ style
278
+ } = props;
279
+ const initialConfig = react.useMemo(
280
+ () => generator.normalizeConfig(value ?? defaultValue ?? (seed ? generator.configFromSeed(seed) : generator.DEFAULT_CONFIG)),
281
+ // initial only
282
+ // eslint-disable-next-line react-hooks/exhaustive-deps
283
+ []
284
+ );
285
+ const [config, setConfig] = useControllable(value, initialConfig, onChange);
286
+ const [layout, setLayout] = useControllable(layoutProp, defaultLayout, onLayoutChange);
287
+ const [modalOpen, setModalOpen] = react.useState(false);
288
+ const [codeInput, setCodeInput] = react.useState("");
289
+ const [codeMsg, setCodeMsg] = react.useState("");
290
+ const [seedInput, setSeedInput] = react.useState(seed ?? "");
291
+ const t = theme(layout);
292
+ react.useEffect(() => {
293
+ if (!loadFonts || typeof document === "undefined") return;
294
+ for (const href of FONT_HREFS) {
295
+ if (document.querySelector(`link[href="${href}"]`)) continue;
296
+ const link = document.createElement("link");
297
+ link.rel = "stylesheet";
298
+ link.href = href;
299
+ document.head.appendChild(link);
300
+ }
301
+ if (!document.getElementById("rak-keyframes")) {
302
+ const s = document.createElement("style");
303
+ s.id = "rak-keyframes";
304
+ s.textContent = "@keyframes rak-coinpulse{0%,100%{transform:translateY(0)}50%{transform:translateY(-2px)}}";
305
+ document.head.appendChild(s);
306
+ }
307
+ }, [loadFonts]);
308
+ const patch = react.useCallback((p) => setConfig({ ...config, ...p }), [config, setConfig]);
309
+ const cycle = react.useCallback(
310
+ (key, dir) => {
311
+ const len = generator.PART_NAMES[key].length;
312
+ patch({ [key]: (config[key] + dir + len) % len });
313
+ },
314
+ [config, patch]
315
+ );
316
+ const onRandom = () => setConfig({ ...generator.randomConfig(), view: config.view });
317
+ const onCopyCode = () => {
318
+ const code = generator.encodeConfig(config);
319
+ try {
320
+ navigator.clipboard.writeText(code);
321
+ setCodeMsg("Copied!");
322
+ } catch {
323
+ setCodeInput(code);
324
+ setCodeMsg("Selected");
325
+ }
326
+ };
327
+ const onLoadCode = () => {
328
+ if (!codeInput.trim()) return;
329
+ const next = generator.decodeConfig(codeInput, config);
330
+ setConfig(next);
331
+ setCodeMsg("Loaded!");
332
+ };
333
+ const onGenerateSeed = () => {
334
+ if (!seedInput.trim()) return;
335
+ setConfig({ ...generator.configFromSeed(seedInput), view: config.view });
336
+ };
337
+ const arrowStyle = {
338
+ fontFamily: t.mono,
339
+ fontSize: "10px",
340
+ cursor: "pointer",
341
+ flex: "0 0 auto",
342
+ width: "32px",
343
+ height: "32px",
344
+ borderRadius: t.paper ? "3px" : "7px",
345
+ border: "2px solid " + t.accent,
346
+ background: t.glow ? t.accent : t.accent + "22",
347
+ color: t.glow ? "#10131c" : t.accent,
348
+ lineHeight: 1
349
+ };
350
+ const rowStyle = {
351
+ display: "flex",
352
+ alignItems: "center",
353
+ gap: "8px",
354
+ background: t.rowBg,
355
+ borderRadius: t.paper ? "3px" : "8px",
356
+ padding: "6px 8px",
357
+ border: "1px solid " + t.panelBorder
358
+ };
359
+ const partLabelStyle = { fontFamily: t.mono, fontSize: "7px", color: t.sub, letterSpacing: "1px" };
360
+ const partValueStyle = { fontFamily: t.body, fontSize: "19px", color: t.text, lineHeight: 1.1, marginTop: "2px" };
361
+ const dividerStyle = { height: "2px", background: t.panelBorder, opacity: 0.6, margin: "2px 0" };
362
+ const swatchRowStyle = { display: "flex", alignItems: "center", gap: "10px", flexWrap: "wrap" };
363
+ const swatchLabelStyle = { fontFamily: t.mono, fontSize: "7px", color: t.sub, letterSpacing: "1px", width: "78px", flex: "0 0 auto" };
364
+ const codeFieldStyle = {
365
+ flex: "1 1 auto",
366
+ minWidth: 0,
367
+ fontFamily: "monospace",
368
+ fontSize: "11px",
369
+ padding: "7px 8px",
370
+ borderRadius: t.paper ? "3px" : "6px",
371
+ border: "2px solid " + t.panelBorder,
372
+ background: t.paper ? "#fff" : "#0c111c",
373
+ color: t.text,
374
+ outline: "none",
375
+ whiteSpace: "nowrap",
376
+ overflow: "hidden",
377
+ textOverflow: "ellipsis",
378
+ boxSizing: "border-box"
379
+ };
380
+ const smallBtnStyle = {
381
+ fontFamily: t.mono,
382
+ fontSize: "7px",
383
+ letterSpacing: ".5px",
384
+ cursor: "pointer",
385
+ padding: "8px 9px",
386
+ borderRadius: t.paper ? "3px" : "6px",
387
+ border: "2px solid " + t.accent,
388
+ background: t.glow ? t.accent : t.accent + "22",
389
+ color: t.glow ? "#10131c" : t.accent,
390
+ flex: "0 0 auto"
391
+ };
392
+ const codeLabelStyle = { fontFamily: t.mono, fontSize: "7px", color: t.sub, letterSpacing: "1px" };
393
+ const swatchBtn = (col, active) => ({
394
+ background: col,
395
+ width: "22px",
396
+ height: "22px",
397
+ cursor: "pointer",
398
+ padding: 0,
399
+ borderRadius: t.paper ? "2px" : "5px",
400
+ border: "2px solid " + (active ? t.accent : t.paper ? "#00000033" : "#ffffff44"),
401
+ boxShadow: active ? "0 0 0 2px " + t.accent + "66" : "none"
402
+ });
403
+ const nameDisplay = generator.PART_NAMES.torso[config.torso].toUpperCase();
404
+ const partRow = (key, label) => /* @__PURE__ */ jsxRuntime.jsxs("div", { style: rowStyle, children: [
405
+ /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: () => cycle(key, -1), style: arrowStyle, children: "\u25C0" }),
406
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { flex: 1, minWidth: 0, textAlign: "center" }, children: [
407
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: partLabelStyle, children: label }),
408
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: partValueStyle, children: generator.PART_NAMES[key][config[key]] })
409
+ ] }),
410
+ /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: () => cycle(key, 1), style: arrowStyle, children: "\u25B6" })
411
+ ] }, key);
412
+ return /* @__PURE__ */ jsxRuntime.jsxs(
413
+ "div",
414
+ {
415
+ className,
416
+ style: {
417
+ minHeight: "100%",
418
+ width: "100%",
419
+ background: t.stageBg,
420
+ padding: "24px",
421
+ display: "flex",
422
+ flexDirection: "column",
423
+ alignItems: "center",
424
+ fontFamily: t.body,
425
+ backgroundImage: "radial-gradient(circle at 50% 0%, " + t.accent + "22, transparent 60%)",
426
+ boxSizing: "border-box",
427
+ ...style
428
+ },
429
+ children: [
430
+ showLayoutPicker && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: "10px", alignItems: "center", flexWrap: "wrap", marginBottom: "14px" }, children: [
431
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontFamily: t.mono, fontSize: "9px", color: "#fff", opacity: 0.55, letterSpacing: "1px" }, children: "LAYOUT" }),
432
+ LAYOUTS.map((l) => /* @__PURE__ */ jsxRuntime.jsx(
433
+ "button",
434
+ {
435
+ onClick: () => setLayout(l.key),
436
+ style: {
437
+ fontFamily: t.mono,
438
+ fontSize: "8px",
439
+ letterSpacing: "1px",
440
+ cursor: "pointer",
441
+ padding: "7px 9px",
442
+ borderRadius: "6px",
443
+ border: "2px solid " + (layout === l.key ? t.accent : "#ffffff22"),
444
+ background: layout === l.key ? t.accent : "#ffffff10",
445
+ color: layout === l.key ? "#10131c" : "#fff"
446
+ },
447
+ children: l.name
448
+ },
449
+ l.key
450
+ ))
451
+ ] }),
452
+ /* @__PURE__ */ jsxRuntime.jsxs(
453
+ "div",
454
+ {
455
+ style: {
456
+ width: "100%",
457
+ maxWidth: t.mainDir === "row" ? "860px" : "540px",
458
+ background: t.cabinet,
459
+ border: "4px solid " + t.cabinetBorder,
460
+ borderRadius: t.radius,
461
+ boxShadow: "0 18px 50px rgba(0,0,0,.5)" + (t.glow ? ", 0 0 30px " + t.accent + "33" : ""),
462
+ overflow: "hidden"
463
+ },
464
+ children: [
465
+ /* @__PURE__ */ jsxRuntime.jsxs(
466
+ "div",
467
+ {
468
+ style: {
469
+ background: t.marqueeBg,
470
+ padding: "14px",
471
+ display: "flex",
472
+ gap: "12px",
473
+ alignItems: "center",
474
+ justifyContent: "center",
475
+ borderBottom: "3px solid " + t.cabinetBorder
476
+ },
477
+ children: [
478
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { width: "10px", height: "10px", borderRadius: "50%", background: t.accent, boxShadow: "0 0 8px " + t.accent } }),
479
+ /* @__PURE__ */ jsxRuntime.jsx(
480
+ "span",
481
+ {
482
+ style: {
483
+ fontFamily: t.mono,
484
+ fontSize: t.titleText === "WANTED" ? "20px" : "15px",
485
+ color: t.title,
486
+ letterSpacing: "2px",
487
+ textShadow: t.glow ? "0 0 10px " + t.accent : "2px 2px 0 #00000044"
488
+ },
489
+ children: t.titleText
490
+ }
491
+ ),
492
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { width: "10px", height: "10px", borderRadius: "50%", background: t.accent, boxShadow: "0 0 8px " + t.accent } })
493
+ ]
494
+ }
495
+ ),
496
+ /* @__PURE__ */ jsxRuntime.jsxs(
497
+ "div",
498
+ {
499
+ style: {
500
+ display: "flex",
501
+ flexDirection: t.mainDir,
502
+ gap: "16px",
503
+ padding: "18px",
504
+ alignItems: t.mainDir === "row" ? "stretch" : "center"
505
+ },
506
+ children: [
507
+ /* @__PURE__ */ jsxRuntime.jsxs(
508
+ "div",
509
+ {
510
+ style: {
511
+ flex: t.mainDir === "row" ? "0 0 300px" : "0 0 auto",
512
+ display: "flex",
513
+ flexDirection: "column",
514
+ gap: "8px",
515
+ alignItems: "center"
516
+ },
517
+ children: [
518
+ /* @__PURE__ */ jsxRuntime.jsxs(
519
+ "div",
520
+ {
521
+ style: {
522
+ position: "relative",
523
+ padding: "10px",
524
+ background: t.screenBg,
525
+ borderRadius: t.paper ? "4px" : "10px",
526
+ border: "4px solid " + t.cabinetBorder,
527
+ boxShadow: "inset 0 0 20px rgba(0,0,0,.6)",
528
+ cursor: showCombat ? "pointer" : "default"
529
+ },
530
+ onClick: showCombat ? () => setModalOpen(true) : void 0,
531
+ children: [
532
+ /* @__PURE__ */ jsxRuntime.jsx(AvatarPreview, { config, width: 320, height: 400, style: { width: "264px", height: "330px", borderRadius: "3px" } }),
533
+ /* @__PURE__ */ jsxRuntime.jsx(
534
+ "div",
535
+ {
536
+ style: {
537
+ position: "absolute",
538
+ inset: "10px",
539
+ pointerEvents: "none",
540
+ borderRadius: "3px",
541
+ backgroundImage: "repeating-linear-gradient(0deg, rgba(0,0,0,.16) 0 2px, transparent 2px 4px)",
542
+ mixBlendMode: "multiply"
543
+ }
544
+ }
545
+ ),
546
+ showCombat && /* @__PURE__ */ jsxRuntime.jsx(
547
+ "div",
548
+ {
549
+ style: {
550
+ position: "absolute",
551
+ right: "14px",
552
+ bottom: "14px",
553
+ fontFamily: t.mono,
554
+ fontSize: "7px",
555
+ letterSpacing: "1px",
556
+ color: t.title,
557
+ background: t.marqueeBg,
558
+ border: "2px solid " + t.cabinetBorder,
559
+ borderRadius: "6px",
560
+ padding: "5px 7px",
561
+ pointerEvents: "none"
562
+ },
563
+ children: "\u2694 FIGHT"
564
+ }
565
+ )
566
+ ]
567
+ }
568
+ ),
569
+ /* @__PURE__ */ jsxRuntime.jsx(
570
+ "div",
571
+ {
572
+ style: {
573
+ fontFamily: t.mono,
574
+ fontSize: "9px",
575
+ color: t.title,
576
+ letterSpacing: "1px",
577
+ padding: "6px 10px",
578
+ background: t.marqueeBg,
579
+ borderRadius: "5px",
580
+ textAlign: "center",
581
+ border: "2px solid " + t.cabinetBorder
582
+ },
583
+ children: "THE " + nameDisplay + " WEARER"
584
+ }
585
+ ),
586
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { width: "264px", maxWidth: "100%", display: "flex", flexDirection: "column", gap: "8px", marginTop: "2px" }, children: [
587
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", gap: "6px", width: "100%" }, children: VIEW_OPTIONS.map((o) => /* @__PURE__ */ jsxRuntime.jsx(
588
+ "button",
589
+ {
590
+ onClick: () => patch({ view: o.key }),
591
+ style: {
592
+ fontFamily: t.mono,
593
+ fontSize: "7px",
594
+ letterSpacing: ".5px",
595
+ cursor: "pointer",
596
+ flex: 1,
597
+ padding: "8px 4px",
598
+ borderRadius: t.paper ? "3px" : "6px",
599
+ border: "2px solid " + (config.view === o.key ? t.accent : t.panelBorder),
600
+ background: config.view === o.key ? t.accent : t.paper ? "#ffffff55" : "#ffffff10",
601
+ color: config.view === o.key ? "#10131c" : t.text
602
+ },
603
+ children: o.name
604
+ },
605
+ o.key
606
+ )) }),
607
+ partRow("mund", "MOUTH"),
608
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: swatchRowStyle, children: [
609
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: swatchLabelStyle, children: "BACKGROUND" }),
610
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", gap: "6px", flexWrap: "wrap" }, children: generator.BG.map((c, i) => /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: () => patch({ bg: i }), style: swatchBtn(c, config.bg === i) }, c)) })
611
+ ] }),
612
+ showCode && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
613
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: dividerStyle }),
614
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "6px" }, children: [
615
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: codeLabelStyle, children: "CODE" }),
616
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: "6px" }, children: [
617
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: codeFieldStyle, children: generator.encodeConfig(config) }),
618
+ /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: onCopyCode, style: smallBtnStyle, children: "COPY" })
619
+ ] }),
620
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: "6px" }, children: [
621
+ /* @__PURE__ */ jsxRuntime.jsx(
622
+ "input",
623
+ {
624
+ value: codeInput,
625
+ onChange: (e) => {
626
+ setCodeInput(e.target.value);
627
+ setCodeMsg("");
628
+ },
629
+ placeholder: "Paste code\u2026",
630
+ style: codeFieldStyle
631
+ }
632
+ ),
633
+ /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: onLoadCode, style: smallBtnStyle, children: "LOAD" })
634
+ ] }),
635
+ codeMsg && /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontFamily: t.mono, fontSize: "7px", color: t.accent }, children: codeMsg })
636
+ ] })
637
+ ] }),
638
+ showSeed && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
639
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: dividerStyle }),
640
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "6px" }, children: [
641
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: codeLabelStyle, children: "SEED" }),
642
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: "6px" }, children: [
643
+ /* @__PURE__ */ jsxRuntime.jsx(
644
+ "input",
645
+ {
646
+ value: seedInput,
647
+ onChange: (e) => setSeedInput(e.target.value),
648
+ onKeyDown: (e) => {
649
+ if (e.key === "Enter") onGenerateSeed();
650
+ },
651
+ placeholder: "e.g. your name\u2026",
652
+ style: codeFieldStyle
653
+ }
654
+ ),
655
+ /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: onGenerateSeed, style: smallBtnStyle, children: "GENERATE" })
656
+ ] })
657
+ ] })
658
+ ] })
659
+ ] })
660
+ ]
661
+ }
662
+ ),
663
+ /* @__PURE__ */ jsxRuntime.jsxs(
664
+ "div",
665
+ {
666
+ style: {
667
+ flex: 1,
668
+ minWidth: 0,
669
+ width: t.mainDir === "column" ? "100%" : "auto",
670
+ display: "flex",
671
+ flexDirection: "column",
672
+ gap: "9px",
673
+ background: t.panel,
674
+ border: "3px solid " + t.panelBorder,
675
+ borderRadius: t.paper ? "4px" : "10px",
676
+ padding: "14px"
677
+ },
678
+ children: [
679
+ PART_CONTROLS.map((c) => partRow(c.key, c.label)),
680
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: dividerStyle }),
681
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: swatchRowStyle, children: [
682
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: swatchLabelStyle, children: "SKIN" }),
683
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", gap: "6px", flexWrap: "wrap" }, children: generator.SKIN.map((c, i) => /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: () => patch({ skin: i }), style: swatchBtn(c, config.skin === i) }, c)) })
684
+ ] }),
685
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: swatchRowStyle, children: [
686
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: swatchLabelStyle, children: "CLOTHING" }),
687
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", gap: "6px", flexWrap: "wrap" }, children: generator.CLOTH.map((c, i) => /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: () => patch({ cloth: i }), style: swatchBtn(c, config.cloth === i) }, c)) })
688
+ ] }),
689
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: dividerStyle }),
690
+ /* @__PURE__ */ jsxRuntime.jsx(
691
+ "button",
692
+ {
693
+ onClick: onRandom,
694
+ style: {
695
+ fontFamily: t.mono,
696
+ fontSize: "10px",
697
+ letterSpacing: "1px",
698
+ cursor: "pointer",
699
+ padding: "12px",
700
+ borderRadius: t.paper ? "3px" : "9px",
701
+ marginTop: "2px",
702
+ border: "3px solid " + t.title,
703
+ background: t.accent,
704
+ color: "#10131c"
705
+ },
706
+ children: "\u{1F3B2} RANDOM"
707
+ }
708
+ )
709
+ ]
710
+ }
711
+ )
712
+ ]
713
+ }
714
+ ),
715
+ /* @__PURE__ */ jsxRuntime.jsxs(
716
+ "div",
717
+ {
718
+ style: {
719
+ background: t.marqueeBg,
720
+ padding: "10px",
721
+ display: "flex",
722
+ gap: "10px",
723
+ alignItems: "center",
724
+ justifyContent: "center",
725
+ color: t.title,
726
+ borderTop: "3px solid " + t.cabinetBorder
727
+ },
728
+ children: [
729
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: t.accent, fontSize: "14px", animation: "rak-coinpulse 1.2s ease-in-out infinite" }, children: "\u25CF" }),
730
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontFamily: t.mono, fontSize: "8px", letterSpacing: "1px" }, children: "INSERT COIN \xB7 SATIRE EDITION" })
731
+ ]
732
+ }
733
+ )
734
+ ]
735
+ }
736
+ ),
737
+ showCombat && modalOpen && /* @__PURE__ */ jsxRuntime.jsx(CombatModal, { config, theme: t, onClose: () => setModalOpen(false) })
738
+ ]
739
+ }
740
+ );
741
+ }
742
+
743
+ exports.AvatarEditor = AvatarEditor;
744
+ exports.AvatarPreview = AvatarPreview;
745
+ exports.CombatModal = CombatModal;
746
+ exports.FONT_HREFS = FONT_HREFS;
747
+ exports.LAYOUTS = LAYOUTS;
748
+ exports.theme = theme;
749
+ //# sourceMappingURL=index.cjs.map
750
+ //# sourceMappingURL=index.cjs.map