seedmarkfile
seedmark/demo/demo.js/

demo/demo.js raw
1import { avatar, recipe, FAMILIES, VERSION } from '../src/index.js';
2
3const $ = selector => document.querySelector(selector);
4const params = new URL(location.href).searchParams;
5let seed = params.get('seed') ?? 'seedmark';
6let selected = params.get('selected') ?? seed;
7let batch = 0, samples = [], view = 'gallery';
8$('#seed').value = seed;
9for (const family of FAMILIES) {
10 const option = document.createElement('option'); option.value = family; option.textContent = family; $('#family').append(option);
11}
12function image(text, size) {
13 const el = document.createElement('span'); el.className = 'avatar';
14 el.style.width = `${size}px`; el.style.height = `${size}px`;
15 el.innerHTML = avatar(text, { size, version: VERSION });
16 el.setAttribute('aria-hidden', 'true'); return el;
17}
18function syncURL() {
19 const url = new URL(location.href); url.searchParams.set('seed', seed);
20 if (selected !== seed) url.searchParams.set('selected', selected); else url.searchParams.delete('selected');
21 try { history.replaceState(null, '', url); } catch {}
22}
23function colors(value) {
24 if (typeof value === 'string') return /^#[0-9a-f]{3,8}$/i.test(value) ? [value] : [];
25 if (!value || typeof value !== 'object') return [];
26 return Object.values(value).flatMap(colors);
27}
28function select(text) {
29 selected = text; const r = recipe(text, { version: VERSION });
30 $('#selected').innerHTML = avatar(text, { size: 164, version: VERSION });
31 $('#selected-seed').textContent = text === '' ? '(empty string)' : text;
32 $('#selected-family').textContent = r.family; $('#selected-version').textContent = String(r.version);
33 $('#recipe').textContent = JSON.stringify(r, null, 2);
34 $('#scale-preview').replaceChildren(...[24, 32, 48, 64].map(size => {
35 const item = document.createElement('div'); item.className = 'scale-item';
36 const label = document.createElement('small'); label.textContent = `${size}`;
37 item.append(image(text, size), label); return item;
38 }));
39 $('#palette').replaceChildren(...[...new Set(colors(r.palette))].map(color => {
40 const swatch = document.createElement('span'); swatch.style.backgroundColor = color; swatch.title = color; return swatch;
41 }));
42 for (const button of document.querySelectorAll('.tile')) button.setAttribute('aria-pressed', button.dataset.seed === selected);
43 $('#status').textContent = ''; syncURL();
44}
45function makeSamples() {
46 samples = Array.from({ length: 128 }, (_, i) => {
47 const text = i === 0 && batch === 0 ? seed : `${seed}/${batch}:${i}`;
48 return { seed: text, family: recipe(text, { version: VERSION }).family };
49 });
50}
51function drawGallery() {
52 const family = $('#family').value, size = Number($('#size').value);
53 const filtered = samples.filter(s => family === 'all' || s.family === family);
54 $('#gallery').style.setProperty('--size', `${size}px`);
55 $('#gallery').replaceChildren(...filtered.map(s => {
56 const button = document.createElement('button'); button.className = 'tile'; button.dataset.seed = s.seed;
57 button.title = `${s.family}: ${s.seed}`; button.setAttribute('aria-label', `Select ${s.family} avatar for ${s.seed || 'empty seed'}`);
58 button.setAttribute('aria-pressed', s.seed === selected);
59 const code = document.createElement('code'); code.textContent = s.seed || '(empty)';
60 button.append(image(s.seed, size), code); button.onclick = () => select(s.seed); return button;
61 }));
62 $('#batch-note').textContent = `${filtered.length} avatars / batch ${batch + 1}`;
63}
64const lines = [
65 [0, 'Anyone tried the new avatar module yet?'],
66 [1, 'This is me. Apparently I’m a very specific arrangement of shapes.'],
67 [2, 'I found you in the gallery before I read your name.'],
68 [0, 'That’s the test. Same person, every time.'],
69 [3, 'Checking how these hold up at chat size.'],
70 [1, 'Try the circle crop too.'],
71 [2, 'And light mode against dark mode.'],
72 [3, 'The actual seed can be any text.'],
73 [0, 'No initials required.']
74];
75function drawChat() {
76 const names = ['Rowan', 'Alex', 'Kit', 'Sol'];
77 const label = document.createElement('p'); label.className = 'chat-label'; label.textContent = 'Example conversation';
78 $('#chat').replaceChildren(label, ...lines.map(([person, text], index) => {
79 const identity = samples[person]; const row = document.createElement('article'); row.className = 'message';
80 const button = document.createElement('button'); button.setAttribute('aria-label', `Inspect ${names[person]}'s avatar`);
81 button.append(image(identity.seed, 40)); button.onclick = () => select(identity.seed);
82 const body = document.createElement('div'), name = document.createElement('h3'), time = document.createElement('time'), p = document.createElement('p');
83 name.textContent = names[person]; time.textContent = `12:${String(index + 10).padStart(2, '0')}`; name.append(time); p.textContent = text;
84 body.append(name, p); row.append(button, body); return row;
85 }));
86}
87function setView(next) {
88 view = next; $('#gallery').hidden = next !== 'gallery'; $('#chat').hidden = next !== 'chat';
89 $('#grid-tab').setAttribute('aria-pressed', next === 'gallery'); $('#chat-tab').setAttribute('aria-pressed', next === 'chat');
90 $('#family').disabled = next === 'chat'; $('#size').disabled = next === 'chat';
91}
92$('#seed-form').onsubmit = event => { event.preventDefault(); seed = $('#seed').value; batch = 0; makeSamples(); drawGallery(); drawChat(); select(seed); };
93$('#shuffle').onclick = () => {
94 const bytes = crypto.getRandomValues(new Uint8Array(12));
95 $('#seed').value = [...bytes].map(n => n.toString(16).padStart(2, '0')).join('');
96 $('#seed-form').requestSubmit();
97};
98$('#family').onchange = drawGallery; $('#size').onchange = drawGallery;
99$('#crop').onchange = () => document.body.classList.toggle('circle', $('#crop').value === 'circle');
100$('#more').onclick = () => { batch++; makeSamples(); drawGallery(); drawChat(); };
101$('#grid-tab').onclick = () => setView('gallery'); $('#chat-tab').onclick = () => setView('chat');
102$('#theme').onclick = () => document.body.classList.toggle('dark');
103async function copy(text, success) {
104 try { await navigator.clipboard.writeText(text); $('#status').textContent = success; }
105 catch { $('#status').textContent = 'Clipboard unavailable. Download the SVG, or copy the seed from above.'; }
106}
107$('#copy-svg').onclick = () => copy(avatar(selected, { size: 256, version: VERSION }), 'SVG copied.');
108$('#copy-link').onclick = () => { syncURL(); copy(location.href, 'Seed link copied.'); };
109$('#download-svg').onclick = () => {
110 const url = URL.createObjectURL(new Blob([avatar(selected, { size: 256, version: VERSION })], { type: 'image/svg+xml' }));
111 const a = document.createElement('a'); a.href = url; a.download = 'seedmark.svg'; a.click();
112 setTimeout(() => URL.revokeObjectURL(url), 1000); $('#status').textContent = 'SVG downloaded.';
113};
114makeSamples(); drawGallery(); drawChat(); select(selected);
115Object.defineProperty(window, '__seedmark', { value: Object.freeze({ snapshot: () => Object.freeze({ seed, selected, batch, view, family: recipe(selected).family, count: document.querySelectorAll('.tile').length, version: VERSION }) }) });

About

ownerba1b5beed5b5
visibilitypublic
headc808a940bc19

Maintainers

  • ba1b5beed5b5 owner

Clone

  • https://012.run/npub1hgd4hmk4kkukjx7yf402adl7msw0ssnmqmt0y6sgz0j8yjjcj9nqh9znde/seedmark.git

Refs