# CAMPUS: 21st.dev components ported

Both pages are single-file vanilla HTML, so each component below was ported by hand: the
behaviour and structure were kept, the React and Motion dependencies were replaced with CSS
transitions, WAAPI-free requestAnimationFrame loops or plain DOM, and the visuals were
restyled to the TAI tokens (Inter, ember, butter `#F5E76A`, violet `#B8A7F0`). Sources were
read with `mcp__21st__get_component` on 2026-09-13. The install command pulls the real React
component into the tailabsv2 repo when the concept is built for production.

| id | Component | Author | Install | Used in |
|---|---|---|---|---|
| 20033 | Pixelated Image Reveal | soralabs | `npx shadcn@latest add "https://21st.dev/r/soralabs/pixelated-image-reveal?api_key=$API_KEY_21ST"` | landing: case-study cards |
| 21470 | Logo Cloud Marquee | 7ovr | `npx shadcn@latest add "https://21st.dev/r/7ovr/logo-cloud-3?api_key=$API_KEY_21ST"` | landing: both logo rows, testimonials track |
| 18898 | Feature Bento | uilayout | `npx shadcn@latest add "https://21st.dev/r/uilayout.contact/feature-bento?api_key=$API_KEY_21ST"` | landing: "For you today" trio, stats band; dashboard: featured trio |
| 23545 | Presence Avatars | ddoemonn | `npx shadcn@latest add "https://21st.dev/r/ddoemonn/presence-avatars?api_key=$API_KEY_21ST"` | landing: frame bar, live card, feed panel; dashboard: live card |
| 22085 | Testimonials 13 | shadcnui-blocks | `npx shadcn@latest add "https://21st.dev/r/shadcnui-blocks/testimonials-13?api_key=$API_KEY_21ST"` | landing: testimonials |
| 20459 | Number Ticker | danielpetho | `npx shadcn@latest add "https://21st.dev/r/danielpetho/basic-number-ticker?api_key=$API_KEY_21ST"` | landing: headline stats |
| 19070 | Advanced Stats | uilayout | `npx shadcn@latest add "https://21st.dev/r/uilayout.contact/advanced-stats?api_key=$API_KEY_21ST"` | dashboard: team-lead KPI row and answer chart |
| 22247 | Sectors Donut | ssicevs | `npx shadcn@latest add "https://21st.dev/r/ssicevs/sectors-donut?api_key=$API_KEY_21ST"` | dashboard: readiness donuts per team |
| 23552 | Segmented Control | ddoemonn | `npx shadcn@latest add "https://21st.dev/r/ddoemonn/segmented-control?api_key=$API_KEY_21ST"` | landing: audience switch; dashboard: persona switch |

## What changed in each port

### 20033 Pixelated Image Reveal
Kept: the N by N grid of cells, the randomised stagger (`createRandomStaggerDelays`, one
shuffle per run), the two-phase sequence (cells in, swap, cells out), the generation counter
that cancels a stale run, hover on fine pointers and tap-to-toggle on coarse pointers, the
reduced-motion branch that swaps instantly, Enter and Space activation.
Changed: `next/image` layers became the case photo (front) and a colour-block results panel
(back), so the swap reveals the three result tiles rather than a second photo. Cell colour is
ember. `stepDuration` stays 0.3s. Motion's per-cell `transition.delay` became `setTimeout`
per cell on a `will-change: opacity` element.

### 21470 Logo Cloud Marquee
Kept: the CSS keyframe track (`translateX(0)` to `-50%`), the duplicated content for a
seamless loop, the edge mask, pause on hover, `animation: none` under reduced motion.
Changed: the duplicate is created in JS (`cloneNode` and `aria-hidden`) so the markup lists
each logo once. Hover pause is gated behind `(hover:hover) and (pointer:fine)`. All ten
employer logos are the real files; typeb.jpeg has an opaque background so it sits on its own
36px plate with no grayscale filter (the other marks are grayscale until hover).
Under reduced motion the track wraps to a static grid instead of scrolling.

### 18898 Feature Bento
Kept: the hero card with a film background, dark scrim and live pill; the stat tiles with
one big number and a label; the CTA-style colour tiles.
Changed: the blue gradient set became butter, violet, ember and ink blocks; the
`group-hover:scale-105` image zoom was dropped (hover motion on a marketing card the user
sees once is not worth a transform on a video). The trio is the For you today shape,
not the 2 by 3 bento.

### 23545 Presence Avatars
Kept: overlapping tiles ordered by first-seen, `initials()` fallback under the image,
`describe()` sentence for the polite live region, a `+N` overflow chip, the sr-only list of
names, entrance from `scale(.86)` with opacity.
Changed: the Motion spring (`stiffness 520, damping 34, mass .45`) is overdamped, so its CSS
twin is `transform 260ms cubic-bezier(.23,1,.32,1)`; entrance tiles stagger 40ms. The rail
width is set once per render instead of being animated (no `width` transitions). The landing
version rotates one person in or out every 7 seconds to show the join and leave states; the
dashboard version is static. Tile class is `.ptile` to avoid colliding with result tiles.

### 22085 Testimonials 13
Kept: the auto-playing quote marquee that pauses on hover, avatar with initials fallback,
name, role, quote, company mark per card.
Changed: the Marquee helper is the same CSS track as 21470. The X link button was removed
(no source to link). Company marks are the real logo files (Dallas and Brazen have none, so they
stay as text chips), plus a Team or Career label so the two audiences read as mixed on purpose. Every third card is a colour block.

### 20459 Number Ticker
Kept: tween from `from` to `target`, rounding, tabular numerals, trigger on demand when the
card scrolls into view (once, via IntersectionObserver instead of `useInView`).
Changed: Motion's `easeInOut` tween became a 1400ms quartic ease-out in
`requestAnimationFrame`, matching the page's `--ease-out`. Added `data-dec` for 4.8 and
`data-suffix` for the plus sign, and `en-GB` thousands formatting. Under reduced motion the
final value is written immediately.

### 19070 Advanced Stats
Kept: the KPI row (label, value, delta line) and the one-chart-plus-breakdown layout.
Changed: Recharts area chart became a five-bar CSS chart that answers the ask bar, animated
with `transform: scaleY` from the bottom in 300ms (the source animates with a clip path on a
timeline). The scroll-triggered `TimelineAnimation` reveals were dropped: a daily dashboard
should not re-reveal on every visit.

### 22247 Sectors Donut
Kept: SVG ring with `r 52` style geometry (here `r 42`, stroke 12), `strokeDasharray` of
`pct / 100 * C - 2` for a 2px gap, negative `strokeDashoffset` for the start angle, the
centred symbol and caption, legend rows, and the cross-highlight where hovering an arc or a
legend row dims the rest to 0.22 (200ms `ease`), reduced motion respected.
Changed: arcs enter with an 80ms stagger through a `.pre` class instead of Motion; legend
rows are real buttons so keyboard focus highlights too; colours are the five readiness
levels; the centre reads "up to speed" (levels 3 to 5).

### 23552 Segmented Control
Kept: `radiogroup` and `radio` roles, roving `tabindex`, Arrow, Home and End keys, the
clipped duplicate-label trick so the active label is cream on ink without colour tweening,
the sliding thumb as a `translateX` percentage.
Changed: the Motion spring on the thumb was removed on purpose. The brief and the frequency
rule say the audience and persona switches must not animate; the thumb jumps instantly and
only the content cross-fades (under 200ms). Selection fires on `pointerdown` so it responds on
press. Short labels swap in below 640px.

## Not from 21st
The canvas pixelation resolve (coarse blocks to the real frame on scroll-in and hover) is
a canvas mosaic implemented from the sketch in BRIEF section 7. The pill cloud is
a hand-written spring simulation (stiffness 120, damping 14 per second, cursor repulsion
within 150px), a drifting topic cloud. The date-chip rail and workspace switcher are
hand-written; the 21st catalogue had calendar pickers and full sidebars but no light
horizontal day rail or plain workspace menu worth carrying over.
