textReveal
Character by character
504 components · 0 dependencies · MIT
Not a folder of fades. Variable-font axes that bend to the pointer, words that morph letter by letter, carousels built on the browser's own scrolling, menus that actually trap focus.
01Everything, listed
Every component and the attribute that drives it. Most of the kit needs no JavaScript at the call site at all.
data-rm-revealdata-rm-textdata-rm-decryptdata-rm-glitchdata-rm-shinydata-rm-countdata-rm-pressuredata-rm-morphdata-rm-curvedata-rm-odometerdata-rm-highlightdata-rm-outlinedata-rm-rolldata-rm-countdowndata-rm-typedata-rm-wavejsjsjsjsdata-rm-magneticjsjsjsdata-rm-sayjsjsjsdata-rm-spotlightdata-rm-tiltdata-rm-borderdata-rm-card-kitdata-rm-layersdata-rm-edgedata-rm-fandata-rm-card-parallaxdata-rm-beamdata-rm-traildata-rm-glaredata-rm-electricdata-rm-blur-edgedata-rm-cornersjsjsjsjsdata-rm-meteorsdata-rm-sparklesdata-rm-lampdata-rm-beamsdata-rm-dotsdata-rm-stripesdata-rm-scanlinedata-rm-meshdata-rm-starsdata-rm-ringsdata-rm-hexdata-rm-plusdata-rm-diagonalsdata-rm-topographydata-rm-circuitdata-rm-vignettedata-rm-halftonedata-rm-parallaxdata-rm-progressdata-rm-horizontaldata-rm-stackdata-rm-scrubdata-rm-tracingdata-rm-flattendata-rm-stickydata-rm-skewdata-rm-mosaicdata-rm-zoom-outdata-rm-lines-indata-rm-text-maskdata-rm-timelinedata-rm-split-scrolldata-rm-reveal-griddata-rm-pinneddata-rm-scroll-countdata-rm-scroll-rotatedata-rm-scroll-scaledata-rm-scroll-blurdata-rm-scroll-colourdata-rm-pin-stepsdata-rm-scroll-drawdata-rm-scroll-depthdata-rm-snap-sectionsdata-rm-scroll-maskdata-rm-scroll-marqueedata-rm-scroll-gradientdata-rm-scroll-splitdata-rm-scroll-zoomdata-rm-scroll-typedata-rm-image-revealdata-rm-pixeldata-rm-previewdata-rm-marqueedata-rm-carouseldata-rm-ringdata-rm-deckdata-rm-image-traildata-rm-scratchdata-rm-dockdata-rm-comparedata-rm-panelsdata-rm-orbitdata-rm-rippledata-rm-linesdata-rm-dragdata-rm-shuffledata-rm-coverflowdata-rm-thumbsdata-rm-autoplaydata-rm-wheeldata-rm-peekdata-rm-tickerdata-rm-slideshowdata-rm-masonrydata-rm-swipe-stackdata-rm-filmstripdata-rm-hover-peekdata-rm-polaroidsdata-rm-folddata-rm-grid-zoomdata-rm-crossfadedata-rm-parallax-griddata-rm-tilt-griddata-rm-mask-revealdata-rm-slatsdata-rm-zoom-stripdata-rm-spiraldata-rm-image-walldata-rm-flip-griddata-rm-peeldata-rm-focus-griddata-rm-ribbondata-rm-contact-sheetdata-rm-filldata-rm-shimmerdata-rm-sparkdata-rm-swapjsdata-rm-underlinedata-rm-pressdata-rm-halodata-rm-strokedata-rm-btndata-rm-pilldata-rm-gooeydata-rm-condensedata-rm-overlaydata-rm-tabsdata-rm-spydata-rm-ring-progressdata-rm-commanddata-rm-sidebardata-rm-raildata-rm-bottomdata-rm-megadata-rm-circle-navdata-rm-curtain-navdata-rm-hover-spreaddata-rm-breadcrumbsdata-rm-treedata-rm-split-navdata-rm-stack-navdata-rm-dot-navdata-rm-accordiondata-rm-flipdata-rm-expanddata-rm-lightboxdata-rm-scrollbardata-rm-dropdowndata-rm-tooltipdata-rm-toggledata-rm-islanddata-rm-sheetdata-rm-segmenteddata-rm-frosteddata-rm-modaldata-rm-actionsjsdata-rm-contextdata-rm-floatdata-rm-growdata-rm-count-charsdata-rm-passworddata-rm-validatedata-rm-rangedata-rm-dropdata-rm-stepsdata-rm-field-focusdata-rm-submitdata-rm-mascotdata-rm-successdata-rm-otpdata-rm-lockdata-rm-inputdata-rm-searchdata-rm-tagsdata-rm-selectdata-rm-clearabledata-rm-maskdata-rm-inline-editdata-rm-strength-meterdata-rm-slider-pairdata-rm-rating-sliderdata-rm-colourdata-rm-date-fielddata-rm-signaturedata-rm-switch-rowdata-rm-quantitydata-rm-consentdata-rm-form-progressdata-rm-error-summarydata-rm-skeletondata-rm-spinnerdata-rm-progress-bardata-rm-dots-loaderdata-rm-statusdata-rm-badgedata-rm-emptydata-rm-toast-stackdata-rm-snackbardata-rm-bannerdata-rm-inline-alertdata-rm-push-carddata-rm-belldata-rm-counterdata-rm-presencedata-rm-ribbon-alertdata-rm-status-bardata-rm-progress-toastdata-rm-undo-bardata-rm-confirm-sheetdata-rm-countdown-notedata-rm-stacked-avatarsdata-rm-typingdata-rm-live-tickerdata-rm-pill-alertdata-rm-corner-toastdata-rm-sound-badgedata-rm-sparklinedata-rm-barsdata-rm-donutdata-rm-gaugedata-rm-statdata-rm-ratingdata-rm-area-chartdata-rm-step-chartdata-rm-candlesdata-rm-waterfalldata-rm-radardata-rm-heat-calendardata-rm-bulletdata-rm-funneldata-rm-treemapdata-rm-activity-ringsdata-rm-compare-barsdata-rm-spark-barsdata-rm-delta-badgedata-rm-big-numberdata-rm-range-bardata-rm-piedata-rm-scatterdata-rm-timeline-chartdata-rm-metersdata-rm-number-tickerdata-rm-task-listdata-rm-task-checkdata-rm-task-reorderdata-rm-task-groupdata-rm-kanbandata-rm-task-progressdata-rm-task-filterdata-rm-subtasksdata-rm-task-duedata-rm-task-prioritydata-rm-task-assigneedata-rm-task-swipedata-rm-task-undodata-rm-task-countdata-rm-task-emptydata-rm-task-searchdata-rm-task-bulkdata-rm-task-timerdata-rm-task-streakdata-rm-task-notedata-rm-avatardata-rm-avatar-uploaddata-rm-profile-carddata-rm-profile-headerdata-rm-user-menudata-rm-account-switcherdata-rm-presence-ringdata-rm-followdata-rm-biodata-rm-socialdata-rm-statsdata-rm-badgesdata-rm-profile-tabsdata-rm-coverdata-rm-identitydata-rm-editor-toolbardata-rm-bubble-menudata-rm-slash-menudata-rm-mention-pickerdata-rm-block-handledata-rm-code-blockdata-rm-markdown-previewdata-rm-find-replacedata-rm-comment-threaddata-rm-suggestiondata-rm-version-chipdata-rm-outline-panedata-rm-word-countdata-rm-autosave-badgedata-rm-selection-toolbardata-rm-typewriterdata-rm-month-griddata-rm-week-griddata-rm-day-timelinedata-rm-now-linedata-rm-mini-calendardata-rm-date-rangedata-rm-time-pickerdata-rm-duration-fielddata-rm-timezone-pilldata-rm-availability-griddata-rm-booking-slotsdata-rm-recurrencedata-rm-agenda-listdata-rm-deadline-pilldata-rm-event-chipdata-rm-week-stripdata-rm-data-griddata-rm-column-pickerdata-rm-bulk-bardata-rm-saved-viewsdata-rm-query-bardata-rm-keyboard-mapdata-rm-log-streamdata-rm-metric-tiledata-rm-health-griddata-rm-audit-rowdata-rm-env-switchdata-rm-role-badgedata-rm-quota-meterdata-rm-job-queuedata-rm-diff-tabledata-rm-export-menudata-rm-player-bardata-rm-scrubberdata-rm-waveformdata-rm-chapter-listdata-rm-caption-toggledata-rm-rate-menudata-rm-volume-dialdata-rm-pip-toggledata-rm-queue-listdata-rm-now-playingdata-rm-transcript-syncdata-rm-thumb-stripdata-rm-live-badgedata-rm-buffer-ringdata-rm-mini-playerdata-rm-keyboard-hintsdata-rm-product-carddata-rm-product-gallerydata-rm-product-zoomdata-rm-swatchesdata-rm-size-pickerdata-rm-price-tagdata-rm-discount-badgedata-rm-stock-meterdata-rm-rating-starsdata-rm-review-summarydata-rm-add-to-cartdata-rm-wishlistdata-rm-compare-traydata-rm-quick-viewdata-rm-product-tabsdata-rm-variant-pickerdata-rm-breadcrumb-traildata-rm-sort-bardata-rm-filter-paneldata-rm-result-countdata-rm-cart-drawerdata-rm-cart-linedata-rm-cart-totalsdata-rm-cart-emptydata-rm-cart-badgedata-rm-mini-cartdata-rm-free-shippingdata-rm-coupondata-rm-checkout-stepsdata-rm-order-summarydata-rm-payment-methodsdata-rm-address-formdata-rm-delivery-optionsdata-rm-gift-notedata-rm-order-confirmdata-rm-order-trackingdata-rm-return-requestdata-rm-invoice-rowdata-rm-save-for-laterdata-rm-recently-vieweddata-rm-hero-bannerdata-rm-collection-griddata-rm-lookbookdata-rm-category-tilesdata-rm-sale-countdowndata-rm-bundle-builderdata-rm-size-guidedata-rm-stock-notifydata-rm-product-videodata-rm-swatch-gallerydata-rm-badge-stackdata-rm-trust-rowdata-rm-shipping-estimatedata-rm-recently-boughtdata-rm-cross-selldata-rm-upsell-rowdata-rm-gift-carddata-rm-loyalty-pointsdata-rm-referral-boxdata-rm-subscribe-boxdata-rm-order-listdata-rm-order-carddata-rm-order-statusdata-rm-tracking-mapdata-rm-delivery-slotdata-rm-address-bookdata-rm-address-carddata-rm-payment-cardsdata-rm-subscription-carddata-rm-pause-subscriptiondata-rm-invoice-listdata-rm-download-rowdata-rm-wishlist-griddata-rm-review-formdata-rm-review-carddata-rm-question-answerdata-rm-support-ticketdata-rm-chat-bubbledata-rm-refund-statusdata-rm-account-navdata-rm-bubble-fielddata-rm-fireworksdata-rm-gravity-starsdata-rm-hole-tunneldata-rm-radial-introdata-rm-light-raysdata-rm-prism-splitdata-rm-drift-shapesdata-rm-noise-wavedata-rm-link-webdata-rm-ripple-pooldata-rm-glow-orbsdata-rm-liquid-buttondata-rm-flip-buttondata-rm-copy-buttondata-rm-theme-toggledata-rm-count-buttondata-rm-flip-carddata-rm-management-bardata-rm-pin-listdata-rm-preview-linkdata-rm-file-treedata-rm-presence-rowdata-rm-morph-icondata-rm-pricingdata-rm-plan-toggledata-rm-feature-matrixdata-rm-savingsdata-rm-quotedata-rm-logo-walldata-rm-rating-rowdata-rm-faqdata-rm-help-tipdata-rm-shortcutsdata-rm-tourdata-rm-checklistdata-rm-welcomedata-rm-footer-columnsdata-rm-announcementdata-rm-mega-footerdata-rm-sortabledata-rm-sticky-headdata-rm-row-expanddata-rm-table-emptydata-rm-codedata-rm-diffdata-rm-api-rowdata-rm-uptimedata-rm-changelogdata-rm-bentodata-rm-split-paneldata-rm-sticky-asidedata-rm-dividerdata-rm-section-markjs02Everything, running
Nothing here is a recording. Hover, press, drag. The ones that normally play once are set to repeat so you can actually see them.
textReveal
Character by character
decrypt
SOYRAGE AGENCY
glitch
404
shiny
Available for work
countUp
1,250
typewriter
waveText hover
Run the pointer over
morph
pressure hover
Pressure
odometer
128,400
curve
marquee drag any row · scroll the page · one runs upward
spotlight hover
tilt hover
border
glare hover
trail
electric
beam
blurEdge
Focus falls off gradually, the way a lens does it — stacked layers, each blurred harder and masked to a narrower band.
One backdrop-filter with a mask blurs everything equally and reads as a smear.
waves hover
retroGrid
dotGrid hover
fill · shimmer · spark · swap · ripple · magnetic hover every one
Six effects on one surface, so you can tell them apart. Black on cream here and cream on black everywhere else — the same components, no second code path.
cursor · target · crosshair · splash
A custom cursor is a page-level decision, so init() leaves it alone. Switch this page's:
carousel drag · arrow keys
pressure · morph · curve · odometer · highlight
beam · trail · glare · electric · blurEdge
waves · retroGrid · dotGrid · grain
carousel · ring · deck · dock · scratch · imageTrail
pill · gooey · condense · overlay · tabs
fill · shimmer · spark · swap · ripple
ring drag · arrow keys
deck
panels hover · tab
orbit
magnetLines hover
dock hover
imageReveal
pixelate hover
scratch drag
hoverPreview hover the rows
imageTrail sweep the pointer
meteors
sparkles
Launch day
lamp
beams
outline scroll
Fills as you scroll
countdown
flip hover · enter
expand click a card
accordion
The height animates from 0fr to 1fr on a grid row, so nothing is measured and nothing is hardcoded.
An image that loads late, a font that swaps, text that rewraps — every version built on scrollHeight breaks on all three.
aria-expanded, aria-controls, and a labelled region.
lightbox click
drag throw it · arrows
confetti press
shuffle filter it
rollText hover the links
scrollbar five looks · scroll them
dropdown arrow keys
tooltip · toggle
underline · press · halo · strokeDraw
corners hover
mesh
starfield scroll
dots
stripes
scanline
Every named start state, on the same component. Scroll them into view — each plays as it arrives, and each runs backwards if you scroll away and come back.
One component, fifty-two named looks. Hover them, reach them with Tab, press them. None replaces the element underneath.
command press ⌘K or ctrl-K
sidebar escape closes
rail follows the page
bottomNav tap one
mega hover intent
mascot · passwordToggle · floatLabel type in it
successButton press it
padlock type 1234
otp type · paste a code
rangeFill
toggle · charCount
autoGrow · validate leave it empty and blur
masonry resize the window
swipeStack drag · arrow keys
filmstrip drag it
hoverPeek hover the titles
polaroids hover · tab
foldGallery hover a panel
gridZoom click a tile
crossfade arrow keys
parallaxGrid scroll
tiltGrid move the pointer
maskReveal scroll
slats scroll
zoomStrip scroll it sideways
spiralGallery scroll
imageWall drag · arrow keys
flipGrid scroll into view
peelStack press the button
focusGrid hover · tab
ribbon scroll
contactSheet click a frame
searchField press the icon
tagsField Enter · Backspace
selectField · clearable
maskField edit the middle
inlineEdit click the title
inputKit three of twenty-four
One component, twenty-four named looks. Type in them, reach them with Tab. Every one keeps the real input underneath, so autofill, paste, undo and your password manager all still work.
One component, twenty-four named looks. None of them animates a width or a height, so a grid of cards never reflows while you move across it.
mosaic assembles from the middle out
lineByLine
Prose arrives a line at a time, because a paragraph read one word at a time is a reading test rather than an effect. The lines are re-split when the width changes, since a line is a fact about the layout and not a property of the text.
timeline
revealGrid a wave from the corner
coverflow scroll it sideways
thumbs pick one, or scroll the frame
wheel hover · arrows
slideshow real controls
ticker opposing rows
autoplay it stops when you touch it
peek the next one shows
island press to change it
sheet drag the grip down
segmented arrow keys
springModal · actionSheet
toast hover the stack to hold it
contextMenu right-click · menu key
spinner six shapes
skeleton
progressBar · dotsLoader
pulseDot · badgeCount
emptyState
An empty state is the moment a product either explains itself or looks broken.
Add the first onesparkline drawn, not scaled
bars
donut · gauge
stat · stars
pill hover · tab
gooey hover · tab
overlay keyboard safe
tabs arrow keys
Move right and the panel arrives from the right; move back and it comes from the left. One comparison, and the difference between tabs that feel spatial and tabs that blink.
A real tablist: arrow keys, Home and End, roving tabindex, and panels genuinely hidden when inactive rather than parked off screen.
Under reduced motion the slide is dropped and the switch is instant. The content was the point; the direction was the flourish.
circleNav arrow keys
curtainNav Escape closes
hoverSpread hover · tab
breadcrumbs open the middle
treeNav arrows · Right opens
splitNav parts open
stackNav deals out
dotNav follows the page
toastStack
snackbar
banner
inlineAlert
The content this wraps around.
pushCard
The content this wraps around.
bell
counter
presenceDot
ribbonAlert
The content this wraps around.
statusBar
progressToast
undoBar
confirmSheet
The content this wraps around.
countdownNote
stackedAvatars
typingDots
Ana is typing
liveTicker
pillAlert
cornerToast
soundBadge
taskList
taskCheck
taskReorder
taskGroup
kanban
taskProgress
taskFilter
subtasks
taskDue
taskPriority
taskAssignee
taskSwipe
taskUndo
The content this wraps around.
taskCount
taskEmpty
Nothing left today.
taskSearch
taskBulk
taskTimer
taskStreak
taskNote
Client wants the blue version by Friday.
areaChart
stepChart
candlestick
| Mon |
waterfall
radar
heatCalendar
bulletChart
funnel
treemap
progressRings
comparisonBars
sparkBars
deltaBadge
bigNumber
rangeBar
pieSlices
scatterPlot
timelineChart
meterRow
numberTicker
strengthMeter
sliderPair
ratingSlider
colourField
dateField
signaturePad
switchRow
quantityStepper
consentBox
The content this wraps around.
the termsThe content this wraps around.
formProgress
errorSummary
avatar
avatarUpload
profileCard
profileHeader
userMenu
accountSwitcher
presenceRing
followButton
bioReveal
Nora Vale has been recording rivers since 2016. Mostly at dawn.
socialRow
statsRow
badgeRow
profileTabs
The content this wraps around.
The content this wraps around.
coverParallax
identityChip
scrollCounter
scrollRotate
The content this wraps around.
scrollScale
The content this wraps around.
scrollBlur
scrollColour
The content this wraps around.
pinSteps
The content this wraps around.
The content this wraps around.
scrollDraw
depthLayers
scrollSnapSections
revealMaskScroll
The content this wraps around.
marqueeScroll
scrollGradient
The content this wraps around.
scrollSplit
Behind
scrollZoomPin
scrollTypeScale
productCard
productGallery
productZoom
colourSwatches
sizePicker
priceTag
discountBadge
stockMeter
ratingStars
reviewSummary
addToCart
wishlistHeart
compareTray
quickView
Heavyweight, garment dyed.
productTabs
variantPicker
breadcrumbTrail
sortBar
filterPanel
resultCount
cartDrawer
cartLine
cartTotals
cartEmpty
The content this wraps around.
Everything in this demo shop is invented.
cartBadge
miniCart
Two invented items.
freeShippingBar
couponField
checkoutSteps
orderSummary
paymentMethods
addressForm
deliveryOptions
giftNote
orderConfirm
A demonstration confirmation for an invented shop.
orderTracking
returnRequest
invoiceRow
| INV-DEMO-004 | £48.00 |
| Two invented items, delivered. | |
saveForLater
recentlyViewed
pricingTable
£0
£24
£78
planToggle
featureMatrix
| Feature | Starter | Studio |
|---|---|---|
| Custom domain | — | ✓ |
savingsBadge
quoteCard
They rebuilt our checkout in a fortnight.
logoWall
ratingRow
faqList
helpTip
shortcutSheet
tourStep
checklistCard
welcomeCard
Three things worth doing first.
footerColumns
announcementRow
Free shipping this week
New: dark mode is live
megaFooter
sortableTable
| Client | MRR |
|---|---|
| Acme | £2,400 |
stickyHeaderTable
| Invoice | Amount |
|---|
rowExpand
| INV-0042 | £1,200 |
| Paid 3 September by card ending 4242. | |
tableEmpty
| Invoice | Amount |
|---|
codeBlock
import { codeBlock } from "@soyrageagency/rage-motion";
diffView
apiRow
Creates a charge.
uptimeDots
changelogFeed
Sortable tables.
bentoGrid
splitPanel
stickyAside
dividerMark
sectionMark
heroBanner
Stoneware thrown in small batches at the Cloudberry Studio, a shop that does not exist.
See the collectioncollectionGrid
€24
€24
€38
lookbook
categoryTiles
saleCountdown
Winter sale ends in
bundleBuilder
sizeGuide
| Size | Chest | Length |
|---|---|---|
| S | 96 | 70 |
| M | 104 | 72 |
| S | 38 | 27.5 |
| M | 41 | 28.5 |
stockNotify
productVideo
swatchGallery
badgeStack
trustRow
shippingEstimate
recentlyBought
crossSell
upsellRow
giftCard
loyaltyPoints
referralBox
subscribeBox
orderList
orderCard
Placed 4 April 2031 · £48.00
orderStatusPill
Order RM-0032
trackingMap
deliverySlot
addressBook
addressCard
paymentCards
subscriptionCard
£14.00 a month, cancel whenever you like.
pauseSubscription
Kelp coffee, every month (invented)
invoiceList
downloadRow
wishlistGrid
reviewForm
reviewCard
Bought this for the studio and it has survived a winter of being knocked off the bench. The glaze has one chip and that was entirely my fault.
questionAnswer
supportTicket
Thanks for getting in touch — we have asked the courier for the drop-off photograph.
chatBubble
Thanks for the photograph.
No problem — the box was empty when it arrived.
refundStatus
accountNav
editorToolbar
bubbleMenu
Select any part of this sentence and the formatting bar appears above it.
slashMenu
mentionPicker
blockHandle
Three quarters of the people we interviewed had already built the thing by hand.
Nobody could name the person who owned the spreadsheet.
“We send it out on Fridays and hope.”
The handover step is where the week is lost.
fencedCode
import { editorToolbar, slashMenu } from "@soyrageagency/rage-motion";
const stop = editorToolbar();
slashMenu("[data-rm-slash-menu]", { trigger: "/" });
window.addEventListener("beforeunload", stop);
markdownPreview
We shipped the importer on the 14th.
findReplace
The brief went out on Monday. The brief came back on Thursday with the brief attached twice.
Every brief since has been sent as a link.
commentThread
The handover step is where the week is lost, according to four of the six teams we spoke to.
suggestion
We shipped the importer in the
second
final week of March, ahead of
the agreed date.
versionChip
outlinePane
Four of six teams lose a day a week to the handover.
Eighteen interviews across three markets.
Forty minutes each, unstructured after the first ten.
Weighted towards teams of under twenty.
The spreadsheet is the product.
Nobody owns the Friday send.
Name an owner before buying a tool.
wordCount
autosaveBadge
selectionToolbar
Select a sentence in this paragraph and the action bar docks to the bottom of the window.
It stays in one place whether you selected with a mouse, a thumb, or Shift and the arrow keys.
typewriterMode
The caret line holds its height while the text scrolls beneath it.
Paragraphs away from the caret dim by opacity alone, so nothing moves and everything is still selectable and still read aloud in full.
Keep typing and this paragraph rises to meet the same line.
monthGrid
| Mon | Tue | Wed | Thu | Fri | Sat | Sun |
|---|---|---|---|---|---|---|
weekGrid
|
|
|
|
dayTimeline
nowLine
miniCalendar
| M | T | W | T | F | S | S |
|---|---|---|---|---|---|---|
dateRange
timePicker
durationField
timezonePill
Kick-off is at and and .
availabilityGrid
bookingSlots
recurrenceBuilder
agendaList
deadlinePill
eventChip
weekStrip
dataGrid
| Order | Customer | Status | Total |
|---|---|---|---|
| #4821 | Marta Ibáñez | Packing | €248.00 |
| #4822 | Hendrik Voss | Awaiting payment | €1,940.50 |
| #4823 | Aoife Brennan | Shipped | €76.20 |
| #4824 | Rui Cardoso | Packing | €512.00 |
| #4825 | Lena Ostrowska | Refunded | €96.99 |
columnPicker
| Order | Customer | Region | Total |
|---|---|---|---|
| #4821 | Marta Ibáñez | Iberia | €248.00 |
| #4822 | Hendrik Voss | DACH | €1,940.50 |
| #4823 | Aoife Brennan | Ireland | €76.20 |
bulkBar
| Order | Customer | Total |
|---|---|---|
| #4821 | Marta Ibáñez | €248.00 |
| #4822 | Hendrik Voss | €1,940.50 |
| #4823 | Aoife Brennan | €76.20 |
savedViews
queryBar
keyboardMap
logStream
metricTile
healthGrid
auditRow
envSwitch
roleBadge
| Person | Role |
|---|---|
| marta@northwind.co | Owner |
| alex@northwind.co | Admin |
| rui@northwind.co | Editor |
| aoife@northwind.co | Viewer |
quotaMeter
jobQueue
diffTable
| Field | Before | After |
|---|---|---|
| Plan | Team | Business |
| Seats | 12 | 40 |
| SSO domain | northwind.co | |
| Trial ends | 2026-03-18 | |
| Billing email | billing@northwind.co | billing@northwind.co |
| Region | eu-west-1 | eu-west-1 |
exportMenu
playerBar
Opening the kiln after a thirty-hour firing.
scrubber
waveform
chapterList
captionToggle
rateMenu
volumeDial
pipToggle
queueList
nowPlaying
Marta Ruiz
transcriptSync
We start at the clay pit, which is four fields behind the workshop.
It has to be wedged before anything else happens to it.
Most people wedge to mix. You wedge to get the air out.
A single bubble will take the pot apart in the kiln.
Sixty turns, and then you stop, because over-wedging stiffens it.
thumbStrip
liveBadge
bufferRing
miniPlayer
keyboardHints
bubbleField
Eighteen days in open cedar, then six weeks cold.
Read the processfireworks
New year, new kiln
gravityStars
Wood-fired reduction, twenty-two hours, three of us awake.
holeTunnel
A century of pipework under the Ebro, mapped in eleven days.
radialIntro
Applications for the spring intake close on the 30th.
ApplylightRays
Open studio
Come and put your hands in something.
prismSplit
Tenmoku over a thin slip, cone 10 reduction. Broke to rust on the rim.
Open the logdriftShapes
Small runs, honest materials, and a kiln we know the moods of.
noiseWave
Four days walking, one notebook, no signal after the second morning.
linkWeb
Eleven people, four workshops, one glaze that came from a neighbour.
ripplePool
Move across this and it moves back.
Book a tasterglowOrbs
Cone 10 by midnight if the wind holds.
liquidButton
flipButton
copyButton
npm i @soyrageagency/rage-motion
themeToggle
countButton
flipCard
Identity and site, 2025.
managementBar
Select photos to get started
pinList
previewLinkCard
fileTree
presenceRow
morphIcon
rings
hexGrid hover
plusGrid
diagonals
topography
circuit
vignette scroll
halftone hover
03Made of scrolling
Which means every one of these runs backwards too. An animation that only plays forwards feels broken the instant somebody scrolls the other way — and most of them do.
tracing
A line drawn down the article as you read it: a real path revealed with
stroke-dashoffset, which is why it can curve and why the
glowing head sits exactly on it.
And here is highlight — the paragraph fills word by word as it crosses the viewport. The unlit state is a muted colour, never an opacity of zero, because prose you cannot read until you have scrolled far enough is a reading tax.
parallax
scrub
--rm-progress runs 0 → 1 as this block crosses the
viewport, and the stylesheet decides what that means. Anything
expressible in CSS becomes scroll-driven without another component.
flatten
stack
Cards pile up and shrink as you pass them. The sticking is position: sticky; only the scale and the brightness are computed.
Every card sticks a little further down than the last, so the pile stays readable at the top rather than disappearing behind the front one.
Under reduced motion the whole effect is dropped and they are simply three cards, in order, at full size.
sticky
The pin is CSS. The only JavaScript decides which panel is in the reading position and swaps the image to match.
The panels are ordinary stacked content, so on a narrow screen you drop the sticky rule in a media query and it degrades to a normal article.
No JavaScript branch for mobile, no separate template. The same markup, one rule lighter.
horizontal
Vertical scroll distance is mapped to horizontal travel by giving the wrapper height.
It never hijacks the wheel, so the trackpad, the keyboard and the scrollbar all keep working.
Which is exactly what the transform-and-wheel-listener version breaks, every time.
And under reduced motion it becomes a plain horizontally scrollable strip.
04Two states, one handle
Almost every before/after slider on the web is pointer-only, which
leaves it unusable on a keyboard and invisible to a screen reader. This
is a real role="slider": arrows, Home, End and an announced
value. Dragging is the enhancement, not the only door.
Drag it, or focus the handle and use ← →
05Hand it to your assistant
Ask any assistant for a scroll reveal and it writes the same snippet it has written ten thousand times. It is not careless — it has no idea what is already in your project, so it writes the most average thing that could possibly work.
Without MCP
window.addEventListener("scroll", () => {
document.querySelectorAll(".fade").forEach((el) => {
if (el.getBoundingClientRect().top < innerHeight)
el.classList.add("show");
});
});
A layout read per element per event. And a .fade { opacity: 0 } waiting for the day the script does not load.
With MCP
<div data-rm-reveal="up" data-rm-delay="120">…</div>
It looks before it writes, finds the component you already have, and tells you why it chose it — because the reasoning travels with the component.
No key, no account, no network. The server only reads files from the installed package.
06Take it with you
Every component depends only on core/motion.js. Take the two and go — that is how most people will use this, and it is designed for exactly that.
npm i @soyrageagency/rage-motion
import { init } from "@soyrageagency/rage-motion";
import "@soyrageagency/rage-motion/css";
init();
<link rel="stylesheet" href="…/rage-motion.css">
<script type="module">
import { init } from "…/index.js";
init();
</script>
The sheet follows your pointer while you hold the grip, and on release it decides from the distance and the speed of the throw. A short fast flick dismisses; a slow drag that stopped halfway springs back.