Skip to content

Commit 1747d6c

Browse files
committed
Themes: animate the five theme illustrations in the style of the home figure (5 s loops: packets, nodes lighting up, pulse rings); still art under reduced motion
1 parent 6b9cc94 commit 1747d6c

3 files changed

Lines changed: 102 additions & 3 deletions

File tree

‎_includes/theme_art.html‎

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,41 @@
1-
{%- comment -%} Per-theme line illustration (same art as research.md). Usage: include theme_art.html slug=... class=... {%- endcomment -%}
1+
{%- comment -%} Per-theme line illustration (same art as research.md). Usage: include theme_art.html slug=... class=...
2+
Elements with class "ta" are animation overlays, invisible unless motion is allowed (_sass/_theme_art.scss). {%- endcomment -%}
23
<svg class="{{ include.class }}" viewBox="0 0 240 160" aria-hidden="true" focusable="false">
34
{%- case include.slug %}
45
{%- when 'swarm' %}
56
<g stroke="currentColor" stroke-width="1" opacity=".35"><path d="M30 120 70 60M70 60 130 80M70 60 110 20M130 80 110 20M130 80 170 130M30 120 130 80M170 130 215 70M130 80 215 70M110 20 190 35M190 35 215 70"/></g>
67
<g fill="currentColor" opacity=".55"><circle cx="30" cy="120" r="4"/><circle cx="130" cy="80" r="4"/><circle cx="170" cy="130" r="4"/><circle cx="215" cy="70" r="4"/><circle cx="110" cy="20" r="4"/><circle cx="190" cy="35" r="4"/></g>
8+
<g fill="none" stroke="var(--accent)" stroke-width="2.5" stroke-linecap="round" stroke-dasharray="14 100"><path class="ta ta-sw-p1" pathLength="100" d="M70 60 30 120"/><path class="ta ta-sw-p1" pathLength="100" d="M70 60 130 80"/><path class="ta ta-sw-p1" pathLength="100" d="M70 60 110 20"/><path class="ta ta-sw-p2" pathLength="100" d="M130 80 170 130"/><path class="ta ta-sw-p2" pathLength="100" d="M130 80 215 70"/><path class="ta ta-sw-p2" pathLength="100" d="M110 20 190 35"/></g>
9+
<g fill="var(--accent)"><circle class="ta ta-sw-n1" cx="30" cy="120" r="4"/><circle class="ta ta-sw-n1" cx="130" cy="80" r="4"/><circle class="ta ta-sw-n1" cx="110" cy="20" r="4"/><circle class="ta ta-sw-n2" cx="170" cy="130" r="4"/><circle class="ta ta-sw-n2" cx="215" cy="70" r="4"/><circle class="ta ta-sw-n2" cx="190" cy="35" r="4"/></g>
710
<circle cx="70" cy="60" r="7" fill="var(--accent)"/><circle cx="70" cy="60" r="14" fill="none" stroke="var(--accent)" opacity=".3"/>
11+
<circle class="ta ta-sw-ring" cx="70" cy="60" r="14" fill="none" stroke="var(--accent)" stroke-width="1.5"/>
812
{%- when 'edge' %}
913
<g fill="none" stroke="currentColor" stroke-width="1" opacity=".4"><path d="M120 30V70M120 70 60 110M120 70 180 110M120 70V120M60 110 30 140M60 110 90 140M180 110 150 140M180 110 210 140"/></g>
1014
<g fill="currentColor" opacity=".55"><circle cx="60" cy="110" r="4"/><circle cx="180" cy="110" r="4"/><circle cx="120" cy="120" r="4"/><circle cx="30" cy="140" r="3"/><circle cx="90" cy="140" r="3"/><circle cx="150" cy="140" r="3"/><circle cx="210" cy="140" r="3"/></g>
15+
<g fill="none" stroke="var(--accent)" stroke-width="2.5" stroke-linecap="round" stroke-dasharray="14 100"><path class="ta ta-ed-p0" pathLength="100" d="M120 40V70"/><path class="ta ta-ed-p1" pathLength="100" d="M120 70 60 110"/><path class="ta ta-ed-p1" pathLength="100" d="M120 70 180 110"/><path class="ta ta-ed-p1" pathLength="100" d="M120 70V120"/><path class="ta ta-ed-p2" pathLength="100" d="M60 110 30 140"/><path class="ta ta-ed-p2" pathLength="100" d="M60 110 90 140"/><path class="ta ta-ed-p2" pathLength="100" d="M180 110 150 140"/><path class="ta ta-ed-p2" pathLength="100" d="M180 110 210 140"/><path class="ta ta-ed-up" pathLength="100" d="M210 140 180 110 120 70V40"/></g>
16+
<g fill="var(--accent)"><circle class="ta ta-ed-n1" cx="60" cy="110" r="4"/><circle class="ta ta-ed-n1" cx="180" cy="110" r="4"/><circle class="ta ta-ed-n1" cx="120" cy="120" r="4"/><circle class="ta ta-ed-n2" cx="30" cy="140" r="3"/><circle class="ta ta-ed-n2" cx="90" cy="140" r="3"/><circle class="ta ta-ed-n2" cx="150" cy="140" r="3"/><circle class="ta ta-ed-n2" cx="210" cy="140" r="3"/></g>
1117
<rect x="96" y="14" width="48" height="26" rx="13" fill="none" stroke="var(--accent)" stroke-width="1.5"/><circle cx="120" cy="70" r="7" fill="var(--accent)"/>
18+
<rect class="ta ta-ed-cloud" x="96" y="14" width="48" height="26" rx="13" fill="var(--accent)" fill-opacity=".2" stroke="var(--accent)" stroke-width="2.5"/>
19+
<circle class="ta ta-ed-ring" cx="120" cy="70" r="12" fill="none" stroke="var(--accent)" stroke-width="1.5"/>
1220
{%- when 'neurosymbolic' %}
1321
<g fill="none" stroke="currentColor" stroke-width="1" opacity=".4"><rect x="20" y="95" width="50" height="38" rx="4"/><rect x="82" y="95" width="50" height="38" rx="4"/><rect x="144" y="95" width="50" height="38" rx="4"/><path d="M45 95V70M107 95V70M169 95V70M45 70H169M107 70V40"/></g>
1422
<g fill="currentColor" opacity=".55"><circle cx="45" cy="70" r="3.5"/><circle cx="107" cy="70" r="3.5"/><circle cx="169" cy="70" r="3.5"/></g>
23+
<g fill="var(--accent)" fill-opacity=".12" stroke="var(--accent)" stroke-width="1.5"><rect class="ta ta-ns-f1" x="20" y="95" width="50" height="38" rx="4"/><rect class="ta ta-ns-f2" x="82" y="95" width="50" height="38" rx="4"/><rect class="ta ta-ns-f3" x="144" y="95" width="50" height="38" rx="4"/></g>
24+
<g fill="none" stroke="var(--accent)" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="14 100"><path class="ta ta-ns-p" pathLength="100" d="M45 95V70H107V41"/><path class="ta ta-ns-p" pathLength="100" d="M107 95V41"/><path class="ta ta-ns-p" pathLength="100" d="M169 95V70H107V41"/></g>
1525
<circle cx="107" cy="34" r="7" fill="var(--accent)"/><circle cx="107" cy="34" r="14" fill="none" stroke="var(--accent)" opacity=".3"/>
26+
<circle class="ta ta-ns-ring" cx="107" cy="34" r="14" fill="none" stroke="var(--accent)" stroke-width="1.5"/>
1627
{%- when 'trust' %}
1728
<path d="M120 16 188 40V82C188 114 158 138 120 148 82 138 52 114 52 82V40Z" fill="none" stroke="currentColor" stroke-width="1.2" opacity=".4"/>
1829
<path d="M120 36 170 54V82C170 104 148 122 120 130 92 122 70 104 70 82V54Z" fill="none" stroke="currentColor" stroke-width="1" opacity=".25"/>
19-
<path d="M98 82 114 98 145 64" fill="none" stroke="var(--accent)" stroke-width="3.5" stroke-linecap="round" stroke-linejoin="round"/>
30+
<path class="ta ta-tr-trace" pathLength="100" d="M120 16 188 40V82C188 114 158 138 120 148 82 138 52 114 52 82V40Z" fill="none" stroke="var(--accent)" stroke-width="2.5" stroke-linecap="round" stroke-dasharray="14 100"/>
31+
<path class="ta ta-tr-ring" d="M120 36 170 54V82C170 104 148 122 120 130 92 122 70 104 70 82V54Z" fill="none" stroke="var(--accent)" stroke-width="1.5"/>
32+
<path class="ta-tr-check" pathLength="100" d="M98 82 114 98 145 64" fill="none" stroke="var(--accent)" stroke-width="3.5" stroke-linecap="round" stroke-linejoin="round"/>
2033
{%- when 'timeseries' %}
2134
<g stroke="currentColor" stroke-width="1" opacity=".3"><path d="M20 130H220M20 130V20"/></g>
2235
<path d="M20 100C40 100 45 60 65 60S85 108 105 108 125 48 145 48 165 92 185 92 205 70 220 70" fill="none" stroke="currentColor" stroke-width="1.4" opacity=".5"/>
23-
<path d="M145 48C165 48 165 92 185 92S205 70 220 70" fill="none" stroke="var(--accent)" stroke-width="2.4" stroke-dasharray="1 5" stroke-linecap="round"/>
36+
<path class="ta ta-ts-trace" pathLength="100" d="M20 100C40 100 45 60 65 60S85 108 105 108 125 48 145 48" fill="none" stroke="var(--accent)" stroke-width="2.5" stroke-linecap="round" stroke-dasharray="8 100"/>
37+
<path class="ta-ts-fc" d="M145 48C165 48 165 92 185 92S205 70 220 70" fill="none" stroke="var(--accent)" stroke-width="2.4" stroke-dasharray="1 5" stroke-linecap="round"/>
2438
<circle cx="145" cy="48" r="5" fill="var(--accent)"/>
39+
<circle class="ta ta-ts-ring" cx="145" cy="48" r="10" fill="none" stroke="var(--accent)" stroke-width="1.5"/>
2540
{%- endcase %}
2641
</svg>

‎_sass/_theme_art.scss‎

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
// _theme_art.scss — motion for the theme illustrations (_includes/theme_art.html), on Home and /research/.
2+
// Same vocabulary as the animated home figure: one 5 s loop per theme, travelling packets, nodes lighting up,
3+
// pulse rings. Overlays (.ta) stay invisible unless motion is allowed, so reduced motion shows the still art.
4+
5+
$loop: 5s;
6+
7+
// A dash runs the length of a path (pathLength="100") between two points of the loop.
8+
@mixin packet($name, $from, $to) {
9+
@keyframes #{$name} {
10+
0%, #{$from} { opacity: 0; stroke-dashoffset: 14; }
11+
#{$from + 1%} { opacity: 1; }
12+
#{$to - 1%} { opacity: 1; }
13+
#{$to}, 100% { opacity: 0; stroke-dashoffset: -100; }
14+
}
15+
}
16+
// A node lights up briefly.
17+
@mixin flash($name, $at, $peak: 1) {
18+
@keyframes #{$name} {
19+
0%, #{$at} { opacity: 0; }
20+
#{$at + 3%} { opacity: $peak; }
21+
#{$at + 14%}, 100% { opacity: 0; }
22+
}
23+
}
24+
// A ring expands and fades.
25+
@mixin pulse($name, $at, $scale: 1.9) {
26+
@keyframes #{$name} {
27+
0%, #{$at} { opacity: 0; transform: scale(1); }
28+
#{$at + 1.2%} { opacity: 0.8; transform: scale(1.04); }
29+
#{$at + 12%} { opacity: 0; transform: scale($scale); }
30+
100% { opacity: 0; transform: scale(1); }
31+
}
32+
}
33+
34+
.ta { opacity: 0; }
35+
36+
// Swarm: the leader pulses, then messages hop to its neighbours and on to theirs.
37+
@include pulse(ta-sw-ring, 0%);
38+
@include packet(ta-sw-p1, 4%, 26%);
39+
@include flash(ta-sw-n1, 24%);
40+
@include packet(ta-sw-p2, 32%, 54%);
41+
@include flash(ta-sw-n2, 52%);
42+
// Edge–cloud: the cloud sends down through the hub to the devices, then one device reports back up.
43+
@include packet(ta-ed-p0, 0%, 12%);
44+
@include pulse(ta-ed-ring, 11%);
45+
@include packet(ta-ed-p1, 14%, 30%);
46+
@include flash(ta-ed-n1, 28%);
47+
@include packet(ta-ed-p2, 32%, 46%);
48+
@include flash(ta-ed-n2, 44%);
49+
@include packet(ta-ed-up, 58%, 86%);
50+
@include flash(ta-ed-cloud, 84%, 0.9);
51+
// Neuro-symbolic: frames are read left to right, evidence climbs the logic tree, the verdict pulses.
52+
@include flash(ta-ns-f1, 0%);
53+
@include flash(ta-ns-f2, 7%);
54+
@include flash(ta-ns-f3, 14%);
55+
@include packet(ta-ns-p, 24%, 46%);
56+
@include pulse(ta-ns-ring, 45%);
57+
// Trust: a check runs around the shield, then the tick is drawn and the shield pulses.
58+
@include packet(ta-tr-trace, 0%, 40%);
59+
@include pulse(ta-tr-ring, 52%, 1.3);
60+
@keyframes ta-tr-check {
61+
0%, 40% { stroke-dashoffset: 100; opacity: 1; }
62+
52% { stroke-dashoffset: 0; }
63+
90% { opacity: 1; }
64+
98%, 100% { stroke-dashoffset: 0; opacity: 0; }
65+
}
66+
// Time series: a cursor reads the history, the present point pulses, the forecast unrolls.
67+
@include packet(ta-ts-trace, 0%, 40%);
68+
@include pulse(ta-ts-ring, 40%);
69+
@keyframes ta-ts-fc {
70+
0%, 42% { clip-path: inset(0 100% 0 0); opacity: 1; }
71+
70% { clip-path: inset(0 0 0 0); }
72+
92% { opacity: 1; }
73+
100% { clip-path: inset(0 0 0 0); opacity: 0; }
74+
}
75+
76+
@media (prefers-reduced-motion: no-preference) {
77+
@each $n in sw-ring, sw-p1, sw-n1, sw-p2, sw-n2, ed-p0, ed-ring, ed-p1, ed-n1, ed-p2, ed-n2, ed-up, ed-cloud,
78+
ns-f1, ns-f2, ns-f3, ns-p, ns-ring, tr-trace, tr-ring, tr-check, ts-trace, ts-ring, ts-fc {
79+
.ta-#{$n} { animation: ta-#{$n} $loop linear infinite; }
80+
}
81+
.ta-sw-ring, .ta-ed-ring, .ta-ns-ring, .ta-tr-ring, .ta-ts-ring { transform-box: fill-box; transform-origin: center; }
82+
.ta-tr-check { stroke-dasharray: 100; }
83+
}

‎style.scss‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,6 @@
1212
@use "publications";
1313
@use "people";
1414
@use "research";
15+
@use "theme_art";
1516
@use "news";
1617
@use "pages";

0 commit comments

Comments
 (0)