This page lists files in the current directory. You can view content, get download/execute commands for Wget, Curl, or PowerShell, or filter the list using wildcards (e.g., `*.sh`).
wget 'https://sme10.lists2.roe3.org/mdrone/animated-hover-disclosures/index.html'
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Animated Hover Disclosures</title>
<link rel="stylesheet" href="./style.css">
</head>
<body>
<h1 class="fluid">the craft of ui</h1>
<p>
Unlock the art and science of interface development. This isn’t just about
pushing pixels or following documentation — it’s about mastering the
tools, understanding the nuances, and shaping experiences with intention.
</p>
<ul>
<li data-active="true">
<article>
<h3>The Craft</h3>
<p>
Gain the confidence to build anything you envision, transforming
motion, interaction, and design principles into second nature.
</p>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M6 3h12l4 6-10 13L2 9Z" />
<path d="M11 3 8 9l4 13 4-13-3-6" />
<path d="M2 9h20" />
</svg>
<a href="#">
<span>Watch now</span>
</a>
<img src="https://picsum.photos/720/720?random=12" alt="" />
</article>
</li>
<li>
<article>
<h3>CSS Animation</h3>
<p>
Master CSS animations from your very first set of @keyframes right
through to things no one else ever teaches you.
</p>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<rect width="18" height="18" x="3" y="3" rx="2" />
<path d="M7 3v18" />
<path d="M3 7.5h4" />
<path d="M3 12h18" />
<path d="M3 16.5h4" />
<path d="M17 3v18" />
<path d="M17 7.5h4" />
<path d="M17 16.5h4" />
</svg>
<a href="#"><span>Watch now</span></a>
<img src="https://picsum.photos/720/720?random=17" alt="" />
</article>
</li>
<li>
<article>
<h3>SVG Filters</h3>
<p>
Shaders on a budget. Learn how to use noise to your advantage whilst
making flames and stickers.
</p>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<polygon points="22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3" />
</svg>
<a href="#"><span>Watch now</span></a>
<img src="https://picsum.photos/720/720?random=19" alt="" />
</article>
</li>
<li>
<article>
<h3>Scroll Animation</h3>
<p>
Take your users on a journey with the joy of tasteful scroll
animation. You might not even need JavaScript.
</p>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M19 17V5a2 2 0 0 0-2-2H4" />
<path
d="M8 21h12a2 2 0 0 0 2-2v-1a1 1 0 0 0-1-1H11a1 1 0 0 0-1 1v1a2 2 0 1 1-4 0V5a2 2 0 1 0-4 0v2a1 1 0 0 0 1 1h3"
/>
</svg>
<a href="#"><span>Watch now</span></a>
<img src="https://picsum.photos/720/720?random=42" alt="" />
</article>
</li>
<li>
<article>
<h3>Taming Canvas</h3>
<p>
Grasp how to tame the pixel playground and when to do so. Whilst
building with "Performance Driven Development".
</p>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<circle cx="13.5" cy="6.5" r=".5" fill="currentColor" />
<circle cx="17.5" cy="10.5" r=".5" fill="currentColor" />
<circle cx="8.5" cy="7.5" r=".5" fill="currentColor" />
<circle cx="6.5" cy="12.5" r=".5" fill="currentColor" />
<path
d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10c.926 0 1.648-.746 1.648-1.688 0-.437-.18-.835-.437-1.125-.29-.289-.438-.652-.438-1.125a1.64 1.64 0 0 1 1.668-1.668h1.996c3.051 0 5.555-2.503 5.555-5.554C21.965 6.012 17.461 2 12 2z"
/>
</svg>
<a href="#"><span>Watch now</span></a>
<img src="https://picsum.photos/720/720?random=128" alt="" />
</article>
</li>
<li>
<article>
<h3>Layout Tricks</h3>
<p>
Do you really need a library for that? Sometimes stepping back and
rethinking the problem yields a nifty solution.
</p>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path
d="m21.64 3.64-1.28-1.28a1.21 1.21 0 0 0-1.72 0L2.36 18.64a1.21 1.21 0 0 0 0 1.72l1.28 1.28a1.2 1.2 0 0 0 1.72 0L21.64 5.36a1.2 1.2 0 0 0 0-1.72"
/>
<path d="m14 7 3 3" />
<path d="M5 6v4" />
<path d="M19 14v4" />
<path d="M10 2v2" />
<path d="M7 8H3" />
<path d="M21 16h-4" />
<path d="M11 3H9" />
</svg>
<a href="#"><span>Watch now</span></a>
<img src="https://picsum.photos/720/720?random=56" alt="" />
</article>
</li>
<li>
<article>
<h3>Mastering Time</h3>
<p>
It's not all just easings and compositions. Time plays a crucial
part in various UI patterns that might not seem obvious at first.
</p>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M5 22h14" />
<path d="M5 2h14" />
<path
d="M17 22v-4.172a2 2 0 0 0-.586-1.414L12 12l-4.414 4.414A2 2 0 0 0 7 17.828V22"
/>
<path
d="M7 2v4.172a2 2 0 0 0 .586 1.414L12 12l4.414-4.414A2 2 0 0 0 17 6.172V2"
/>
</svg>
<a href="#"><span>Watch now</span></a>
<img src="https://picsum.photos/720/720?random=39" alt="" />
</article>
</li>
</ul>
<a
class="bear-link"
href="https://twitter.com/intent/follow?screen_name=jh3yy"
target="_blank"
rel="noreferrer noopener"
>
<svg
class="w-9"
viewBox="0 0 969 955"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<circle
cx="161.191"
cy="320.191"
r="133.191"
stroke="currentColor"
stroke-width="20"
></circle>
<circle
cx="806.809"
cy="320.191"
r="133.191"
stroke="currentColor"
stroke-width="20"
></circle>
<circle
cx="695.019"
cy="587.733"
r="31.4016"
fill="currentColor"
></circle>
<circle
cx="272.981"
cy="587.733"
r="31.4016"
fill="currentColor"
></circle>
<path
d="M564.388 712.083C564.388 743.994 526.035 779.911 483.372 779.911C440.709 779.911 402.356 743.994 402.356 712.083C402.356 680.173 440.709 664.353 483.372 664.353C526.035 664.353 564.388 680.173 564.388 712.083Z"
fill="currentColor"
></path>
<rect
x="310.42"
y="448.31"
width="343.468"
height="51.4986"
fill="#FF1E1E"
></rect>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M745.643 288.24C815.368 344.185 854.539 432.623 854.539 511.741H614.938V454.652C614.938 433.113 597.477 415.652 575.938 415.652H388.37C366.831 415.652 349.37 433.113 349.37 454.652V511.741L110.949 511.741C110.949 432.623 150.12 344.185 219.845 288.24C289.57 232.295 384.138 200.865 482.744 200.865C581.35 200.865 675.918 232.295 745.643 288.24Z"
fill="currentColor"
></path>
</svg>
</a>
<script type="module" src="./script.js"></script>
</body>
</html>
wget 'https://sme10.lists2.roe3.org/mdrone/animated-hover-disclosures/script.js'
import { Pane } from 'https://cdn.skypack.dev/tweakpane@4.0.4';
const config = {
theme: 'system' };
const ctrl = new Pane({
title: 'Config',
expanded: true });
const update = () => {
document.documentElement.dataset.theme = config.theme;
};
const sync = event => {
if (
!document.startViewTransition ||
event.target.controller.view.labelElement.innerText !== 'Theme')
return update();
document.startViewTransition(() => update());
};
ctrl.addBinding(config, 'theme', {
label: 'Theme',
options: {
System: 'system',
Light: 'light',
Dark: 'dark' } });
ctrl.on('change', sync);
update();
// the one piece we need goes here
const list = document.querySelector('ul');
const items = list.querySelectorAll('li');
const setIndex = event => {
// for flex
// if (event.target.closest('li'))
// for (const item of items)
// item.dataset.active =
// item === event.target.closest('li') ? 'true' : 'false'
// for grid
const closest = event.target.closest('li');
if (closest) {
const index = [...items].indexOf(closest);
const cols = new Array(list.children.length).
fill().
map((_, i) => {
items[i].dataset.active = (index === i).toString();
return index === i ? '10fr' : '1fr';
}).
join(' ');
list.style.setProperty('grid-template-columns', cols);
}
};
list.addEventListener('focus', setIndex, true);
list.addEventListener('click', setIndex);
list.addEventListener('pointermove', setIndex);
const resync = () => {
const w = Math.max(
...[...items].map(i => {
return i.offsetWidth;
}));
list.style.setProperty('--article-width', w);
};
window.addEventListener('resize', resync);
resync();
wget 'https://sme10.lists2.roe3.org/mdrone/animated-hover-disclosures/style.css'
@import url('https://unpkg.com/normalize.css') layer(normalize);
@layer normalize, base, demo;
@layer demo {
body {
background: light-dark(#fff, #000);
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
gap: 1rem;
padding-block: 2rem;
}
h1,
p {
margin: 0;
}
h1.fluid {
--font-size-min: 22;
--font-level: 4.25;
}
h3 {
white-space: nowrap;
margin: 0;
}
body > p {
width: 74ch;
max-width: calc(100% - 4rem);
text-wrap: balance;
font-family: monospace;
margin-bottom: 4rem;
line-height: 1.5;
opacity: 0.8;
font-weight: 400;
@media (max-width: 768px) {
text-align: center;
}
}
li :is(svg, h3) {
opacity: 0.6;
transition: opacity calc(var(--speed) * 1.2) var(--easing);
}
li :is(a, p) {
opacity: 0;
transition: opacity calc(var(--speed) * 1.2) var(--easing);
width: -webkit-fit-content;
width: -moz-fit-content;
width: fit-content;
}
li img {
filter: grayscale(1) brightness(1.5);
scale: 1.1;
transition-property: filter, scale;
transition-duration: calc(var(--speed) * 1.2);
transition-timing-function: var(--easing);
}
[data-active='true'] :is(a, p, h3, svg) {
opacity: var(--opacity, 1);
}
[data-active='true'] :is(a, p) {
transition-delay: calc(var(--speed) * 0.25);
}
[data-active='true'] img {
filter: grayscale(0) brightness(1);
scale: 1;
transition-delay: calc(var(--speed) * 0.25);
}
article {
/* outline: 2px dashed canvasText; */
width: calc(var(--article-width) * 1px);
height: 100%;
position: absolute;
font-family: monospace;
top: 0;
left: 0;
display: flex;
flex-direction: column;
justify-content: flex-end;
gap: 1rem;
padding-inline: calc(var(--base) * 0.5 - 9px);
padding-bottom: 1rem;
overflow: hidden;
h3 {
position: absolute;
top: 1rem;
left: calc(var(--base) * 0.5);
transform-origin: 0 50%;
rotate: 90deg;
font-size: 1rem;
font-weight: 300;
text-transform: uppercase;
font-family: monospace;
}
svg {
width: 18px;
fill: none;
}
p {
font-size: 13px;
text-wrap: balance;
line-height: 1.25;
--opacity: 0.8;
}
a {
position: absolute;
bottom: 1rem;
height: 18px;
line-height: 1;
color: inherit;
&:is(:focus-visible, :hover) {
outline: none;
span {
text-decoration: underline;
text-underline-offset: 4px;
}
}
span {
display: inline-block;
line-height: 18px;
translate: calc(var(--base) * 0.5);
font-weight: 500;
}
}
img {
position: absolute;
pointer-events: none;
inset: 0;
width: 100%;
height: 100%;
-o-object-fit: cover;
object-fit: cover;
-webkit-mask: radial-gradient(100% 100% at 100% 0, #fff, #0000);
mask: radial-gradient(100% 100% at 100% 0, #fff, #0000);
}
}
/* gotta use some Math on the container really */
/* width is "ideal" 7 * 80px + 6 * gap + say 300px or whatever the ideal width is */
:root {
--gap: 8px;
--base: clamp(2rem, 8cqi, 80px);
--easing: linear(
0 0%,
0.1538 4.09%,
0.2926 8.29%,
0.4173 12.63%,
0.5282 17.12%,
0.6255 21.77%,
0.7099 26.61%,
0.782 31.67%,
0.8425 37%,
0.8887 42.23%,
0.9257 47.79%,
0.9543 53.78%,
0.9752 60.32%,
0.9883 67.11%,
0.9961 75%,
1 100%
);
--speed: 0.6s;
}
ul {
display: grid;
container-type: inline-size;
grid-template-columns: 10fr 1fr 1fr 1fr 1fr 1fr 1fr;
gap: var(--gap);
list-style-type: none;
justify-content: center;
padding: 0;
height: clamp(300px, 40dvh, 474px);
margin: 0;
width: calc(
((var(--items) - 1) * var(--base)) + ((var(--items) - 1) * var(--gap)) +
var(--ideal)
);
width: 820px;
max-width: calc(100% - 4rem);
transition: grid-template-columns var(--speed) var(--easing);
transition: grid-template-columns var(--speed) var(--easing), -ms-grid-columns var(--speed) var(--easing);
}
li {
/* outline: 4px dashed canvasText; */
background: light-dark(#fff, #000);
position: relative;
overflow: hidden;
min-width: var(--base);
border-radius: 8px;
border: 1px solid color-mix(in hsl, canvas, canvasText 50%);
}
}
@layer base {
:root {
--font-size-min: 16;
--font-size-max: 20;
--font-ratio-min: 1.2;
--font-ratio-max: 1.33;
--font-width-min: 375;
--font-width-max: 1500;
}
html {
color-scheme: light dark;
}
[data-theme='light'] {
color-scheme: light only;
}
[data-theme='dark'] {
color-scheme: dark only;
}
:where(.fluid) {
--fluid-min: calc(
var(--font-size-min) * pow(var(--font-ratio-min), var(--font-level, 0))
);
--fluid-max: calc(
var(--font-size-max) * pow(var(--font-ratio-max), var(--font-level, 0))
);
--fluid-preferred: calc(
(var(--fluid-max) - var(--fluid-min)) /
(var(--font-width-max) - var(--font-width-min))
);
--fluid-type: clamp(
(var(--fluid-min) / 16) * 1rem,
((var(--fluid-min) / 16) * 1rem) -
(((var(--fluid-preferred) * var(--font-width-min)) / 16) * 1rem) +
(var(--fluid-preferred) * var(--variable-unit, 100vi)),
(var(--fluid-max) / 16) * 1rem
);
font-size: var(--fluid-type);
}
*,
*:after,
*:before {
box-sizing: border-box;
}
body {
display: grid;
place-items: center;
min-height: 100vh;
font-family: 'SF Pro Text', 'SF Pro Icons', 'AOS Icons', 'Helvetica Neue',
Helvetica, Arial, sans-serif, system-ui;
}
body::before {
--size: 45px;
--line: color-mix(in hsl, canvasText, transparent 70%);
content: '';
height: 100vh;
width: 100vw;
position: fixed;
background: linear-gradient(
90deg,
var(--line) 1px,
transparent 1px var(--size)
)
50% 50% / var(--size) var(--size),
linear-gradient(var(--line) 1px, transparent 1px var(--size)) 50% 50% /
var(--size) var(--size);
-webkit-mask: linear-gradient(-20deg, transparent 50%, white);
mask: linear-gradient(-20deg, transparent 50%, white);
top: 0;
transform-style: flat;
pointer-events: none;
z-index: -1;
}
.bear-link {
color: canvasText;
position: fixed;
top: 1rem;
left: 1rem;
width: 48px;
aspect-ratio: 1;
display: grid;
place-items: center;
opacity: 0.8;
}
:where(.x-link, .bear-link):is(:hover, :focus-visible) {
opacity: 1;
}
.bear-link svg {
width: 75%;
}
/* Utilities */
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border-width: 0;
}
}