Put together an example shadcn/ui carousel component implementation with smooth scroll progress dot indicators.
Notes on engineering, developer experience, design systems, and agentic engineering.
Latest
-
-
Better fluid sizing with round()
ishadeed.com
-
Tint buttons based on their foreground color for
:hoverand:activestates.button { --bg: transparent; --fg: currentColor; --am: 0%; background-color: color-mix(in srgb, var(--bg), var(--fg) var(--am)); color: var(--fg); &:hover { --am: 10%; } &:active { --am: 20%; } } .blue { --bg: oklch(48.8% 0.243 264.376); --fg: oklch(1 0 0); } .neutral { --bg: oklch(92.9% 0.013 255.508); --fg: oklch(27.8% 0.033 256.848); } -
Tree structure using CSS anchor positioning
lab.chsmc.org
One of the coolest uses of CSS anchor positioning I have seen.
-
Nikhil Anand's personal website
nikhil.io
-
Nguyễn Ngọc Ánh's personal website
anh.ng
-
William Jansson's personal website
williamjansson.com
-
Using Container Queries in a CSS Grid to Detect Truncation
v0-css-container-query-test.vercel.app
-
Managing Context Windows with pi /tree: Branches, Summaries, and Subagent-like Workflows
stacktoheap.com
-
Daniel Griesser's PI Config
github.com
-
The Anatomy of an Agent Harness
x.com/Vtrivedy10
-
Agentic Engineering Patterns
simonwillison.net
Patterns for getting the best results out of coding agents like Claude Code and OpenAI Codex.
-
React Grab
www.react-grab.com
-
Smooth Dot Indicators with Embla Carousel and CSS color-mix()
The interview gallery on ibrewmyown.coffee uses image carousels with pagination dots. Standard pagination dots using Embla Carousel toggle between active and inactive, but I wanted them to respond to scroll progress: as you drag, the current indicator fades out while the next one fades in.
Implementation
Embla Carousel exposes scroll progress, making this possible:
const onScroll = (): void => { const snapList = emblaApi.scrollSnapList(); const progress = emblaApi.scrollProgress(); if (snapList.length < 2) return; let lower = snapList.length - 2; for (let i = 0; i < snapList.length - 1; i++) { if (progress >= snapList[i] && progress <= snapList[i + 1]) { lower = i; break; } } const upper = lower + 1; const range = snapList[upper] - snapList[lower]; const t = range === 0 ? 0 : (progress - snapList[lower]) / range; dotNodes.forEach((_, i) => { if (i === lower) setDotProgress(i, 1 - t); else if (i === upper) setDotProgress(i, t); else setDotProgress(i, 0); }); };As
tinterpolates from 0 to 1, a CSS custom property--dot-progressis set for each dot. This single value drives two animations: width expansion and color interpolation.Width and Color
The dot width expands as you approach it:
width: calc(var(--spacing) * 2 + var(--spacing) * 3 * var(--dot-progress, 0));And the color blends between two states using
color-mix():background-color: color-mix( in srgb, var(--color-neutral-600) calc(var(--dot-progress, 0) * 100%), var(--color-neutral-300) );This approach preserves contrast, keeping the active dot darkest and the inactive lightest. The browser handles both interpolations without additional JS overhead.
Hat tip to Derek Briggs for the color fade idea: “What if the current active indicator faded out the primary color during the drag and the next active faded in so that the most active item had the most contrast always?”
-
History of Software Design
historyofsoftware.org
-
How to implement beautiful shadow borders
x.com/PixelJanitor
-
Naz Hamid's personal website
nazhamid.com
-
Anton Repponen's personal website
repponen.com
-
ESLint complexity rule
eslint.org
-
<TextMorph />
torph.lochie.me
Dependency-free animated text component.