Skip to content

Commit eeb5460

Browse files
author
Oussama
committed
fix: vary generated quiz artwork cards
1 parent 6b3bda7 commit eeb5460

2 files changed

Lines changed: 135 additions & 18 deletions

File tree

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
<script>
2+
let { artist } = $props();
3+
4+
const palette = ['var(--accent-primary)', 'var(--accent-secondary)', 'var(--seq-2)', 'var(--gender-nonbinary)'];
5+
6+
function hashString(value = '') {
7+
let hash = 2166136261;
8+
for (const char of value) {
9+
hash ^= char.charCodeAt(0);
10+
hash = Math.imul(hash, 16777619);
11+
}
12+
return hash >>> 0;
13+
}
14+
15+
function createRandom(seed) {
16+
let value = seed || 1;
17+
return () => {
18+
value = Math.imul(value, 1664525) + 1013904223;
19+
return (value >>> 0) / 4294967296;
20+
};
21+
}
22+
23+
function buildArtwork(source) {
24+
const seed = hashString(`${source?.artist_id}-${source?.sample_work_title}-${source?.medium_primary}`);
25+
const random = createRandom(seed);
26+
const medium = source?.medium_primary ?? 'Other';
27+
const lineCount = medium === 'Drawing' ? 8 : medium === 'Photography' ? 3 : medium === 'Film/Video' ? 5 : 6;
28+
const circles = Array.from({ length: 2 + (seed % 3) }, () => ({
29+
cx: 64 + random() * 292,
30+
cy: 58 + random() * 126,
31+
r: 12 + random() * 24,
32+
color: palette[Math.floor(random() * palette.length)],
33+
}));
34+
const lines = Array.from({ length: lineCount }, (_, index) => {
35+
const y = 54 + random() * 142;
36+
const wobble = 18 + random() * 42;
37+
return {
38+
d: `M ${44 + random() * 34} ${y.toFixed(1)} C ${(118 + random() * 74).toFixed(1)} ${(y - wobble).toFixed(
39+
1,
40+
)}, ${(214 + random() * 70).toFixed(1)} ${(y + wobble).toFixed(1)}, ${(338 + random() * 36).toFixed(1)} ${(
41+
50 +
42+
random() * 152
43+
).toFixed(1)}`,
44+
width: index % 3 === 0 ? 3 : 2,
45+
};
46+
});
47+
const panels = Array.from({ length: medium === 'Film/Video' ? 5 : medium === 'Design' ? 6 : 0 }, (_, index) => ({
48+
x: 48 + index * 58,
49+
y: 44 + random() * 20,
50+
height: 92 + random() * 52,
51+
}));
52+
return { circles, lines, panels, accent: palette[seed % palette.length], medium };
53+
}
54+
55+
let artwork = $derived(buildArtwork(artist));
56+
</script>
57+
58+
<figure class="work-card generated-work-card" aria-label={`Generated visual proxy for ${artist.sample_work_title}`}>
59+
<svg viewBox="0 0 420 250" aria-hidden="true">
60+
<rect class="outer" x="18" y="18" width="384" height="214"></rect>
61+
{#if artwork.panels.length}
62+
{#each artwork.panels as panel}
63+
<rect class="panel" x={panel.x} y={panel.y} width="42" height={panel.height}></rect>
64+
{/each}
65+
{/if}
66+
{#if artwork.medium === 'Photography'}
67+
<rect class="photo-field" x="72" y="56" width="276" height="138"></rect>
68+
<line class="horizon" x1="72" x2="348" y1="152" y2="152"></line>
69+
{/if}
70+
{#each artwork.lines as line}
71+
<path d={line.d} style:stroke-width={line.width}></path>
72+
{/each}
73+
{#each artwork.circles as circle}
74+
<circle cx={circle.cx} cy={circle.cy} r={circle.r} style:fill={circle.color}></circle>
75+
{/each}
76+
<line class="baseline" x1="48" y1="206" x2="372" y2="206"></line>
77+
<path class="accent" d="M58 34 L362 34" style:stroke={artwork.accent}></path>
78+
</svg>
79+
<figcaption>
80+
<span>Representative artwork</span>
81+
<em>{artist.sample_work_title}</em>
82+
{#if artist.sample_work_year}
83+
<b>{artist.sample_work_year}</b>
84+
{/if}
85+
<b>{artist.medium_primary}</b>
86+
</figcaption>
87+
</figure>
88+
89+
<style>
90+
.generated-work-card svg {
91+
background: var(--bg-paper);
92+
}
93+
94+
.generated-work-card .outer,
95+
.generated-work-card path,
96+
.generated-work-card line,
97+
.generated-work-card .panel {
98+
fill: none;
99+
stroke: var(--fg-on-light-strong);
100+
stroke-linecap: round;
101+
stroke-linejoin: round;
102+
}
103+
104+
.generated-work-card .outer {
105+
stroke-width: 2;
106+
}
107+
108+
.generated-work-card path,
109+
.generated-work-card line {
110+
stroke-width: 2;
111+
}
112+
113+
.generated-work-card circle {
114+
opacity: 0.18;
115+
stroke: var(--fg-on-light-strong);
116+
stroke-width: 1.5;
117+
}
118+
119+
.generated-work-card .panel,
120+
.generated-work-card .photo-field {
121+
fill: color-mix(in srgb, var(--fg-on-light-strong) 6%, transparent);
122+
stroke-width: 1.5;
123+
}
124+
125+
.generated-work-card .horizon,
126+
.generated-work-card .baseline {
127+
stroke-width: 2.5;
128+
}
129+
130+
.generated-work-card .accent {
131+
stroke-width: 3;
132+
}
133+
</style>

website/src/lib/scenes/Scene5Quiz.svelte

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<script>
22
import AnchorBar from '../charts/AnchorBar.svelte';
3+
import GeneratedWorkCard from '../charts/GeneratedWorkCard.svelte';
34
import SceneTitle from '../components/SceneTitle.svelte';
45
import { matchArtist } from '../utils/match.js';
56
import './scene5Quiz.css';
@@ -193,24 +194,7 @@
193194
</p>
194195
</div>
195196
</div>
196-
<figure class="work-card">
197-
<svg viewBox="0 0 420 250" aria-hidden="true">
198-
<rect x="18" y="18" width="384" height="214"></rect>
199-
<path d="M52 184 C102 126 130 156 174 98 S274 78 350 150"></path>
200-
<path d="M58 72 L148 118 L232 62 L356 116"></path>
201-
<circle cx="108" cy="166" r="18"></circle>
202-
<circle cx="302" cy="92" r="26"></circle>
203-
<line x1="42" y1="204" x2="372" y2="204"></line>
204-
</svg>
205-
<figcaption>
206-
<span>Representative artwork</span>
207-
<em>{result.artist.sample_work_title}</em>
208-
{#if result.artist.sample_work_year}
209-
<b>{result.artist.sample_work_year}</b>
210-
{/if}
211-
<b>{result.artist.medium_primary}</b>
212-
</figcaption>
213-
</figure>
197+
<GeneratedWorkCard artist={result.artist} />
214198
<AnchorBar artistName={result.artist.name} artistCount={result.artist.n_works} />
215199
<div class="actions">
216200
<button type="button" onclick={reset}>Try again</button>

0 commit comments

Comments
 (0)