Generating…Gate B · Row 12
Poster
React + Tailwind
const css = `
@keyframes card-poster-stripes { to { background-position: 28px 0; } }
.card-poster {
position: relative;
display: flex;
flex-direction: column;
justify-content: space-between;
width: 170px;
height: 200px;
padding: 14px;
border-radius: 6px;
background: light-dark(#373a40, #f1f2f3);
color: light-dark(#fbfcfd, #121417);
overflow: hidden;
cursor: pointer;
perspective: 400px;
}
.card-poster:focus-visible { outline: 2px solid light-dark(#42454c, #e5e6e9); outline-offset: 4px; }
.card-poster__stripes {
position: absolute;
left: 0;
right: 0;
top: 34px;
height: 18px;
background: repeating-linear-gradient(-45deg, light-dark(#fbfcfd, #121417) 0 7px, transparent 7px 14px) 0 0 / 28px 100%;
transform: scaleX(0);
transform-origin: left;
transition: transform 0.5s cubic-bezier(0.65, 0, 0.35, 1);
}
.card-poster:hover .card-poster__stripes, .card-poster:focus-visible .card-poster__stripes {
transform: none;
animation: card-poster-stripes 0.6s linear infinite;
}
.card-poster__top { display: flex; justify-content: space-between; font-size: 9px; font-weight: 600; letter-spacing: 0.12em; text-transform: uppercase; }
.card-poster__word { position: relative; display: flex; font-size: 34px; font-weight: 600; letter-spacing: -0.04em; line-height: 0.9; text-transform: uppercase; }
.card-poster__ch {
display: inline-block;
transform-origin: 50% 100%;
transform: rotateX(-90deg);
opacity: 0;
transition: transform 0.55s cubic-bezier(0.34, 1.5, 0.64, 1) calc(var(--i) * 45ms), opacity 0.2s ease calc(var(--i) * 45ms);
}
.card-poster__ch--rest { transform: none; opacity: 1; }
.card-poster__line { position: relative; height: 34px; }
.card-poster__line > * { position: absolute; left: 0; top: 0; }
.card-poster:hover .card-poster__ch, .card-poster:focus-visible .card-poster__ch { transform: none; opacity: 1; }
.card-poster:hover .card-poster__ch--rest, .card-poster:focus-visible .card-poster__ch--rest { transform: rotateX(90deg); opacity: 0; }
.card-poster__foot { font-size: 10px; line-height: 1.3; font-weight: 600; }
@media (prefers-reduced-motion: reduce) {
.card-poster__ch, .card-poster__stripes { transition-duration: 0.01s; transition-delay: 0s; }
.card-poster:hover .card-poster__stripes { animation: none; }
}
`;
// Each line flips from its resting word to its hover word, letter by letter.
const LINES = [
['MAKE', 'MOVE'],
['IT', 'IT'],
];
export function PosterCard() {
return (
<>
<style>
{css}
</style>
<div className="card-poster" tabIndex={0} role="img" aria-label="Poster: Make it move. Motion week, 2 to 6 November">
<div className="card-poster__top" aria-hidden="true">
<span>Motion week</span>
<span>N°04</span>
</div>
<span className="card-poster__stripes" aria-hidden="true" />
<div aria-hidden="true">
{LINES.map(([rest, hover], li) => (
<div key={li} className="card-poster__line">
<span className="card-poster__word">
{[...rest].map((c, i) => (
<span key={i} className="card-poster__ch card-poster__ch--rest" style={{ '--i': i + li * 4 } as React.CSSProperties}>
{c}
</span>
))}
</span>
<span className="card-poster__word">
{[...hover].map((c, i) => (
<span key={i} className="card-poster__ch" style={{ '--i': i + li * 4 } as React.CSSProperties}>
{c}
</span>
))}
</span>
</div>
))}
</div>
<div className="card-poster__foot" aria-hidden="true">
2 to 6 November
<br />
Talks, workshops, demos
</div>
</div>
</>
);
}Markup where the component goes, CSS in your stylesheet. No JavaScript.
HTML
<div class="card-poster" tabindex="0" role="img" aria-label="Poster: Make it move. Motion week, 2 to 6 November">
<div class="card-poster__top" aria-hidden="true">
<span>Motion week</span>
<span>N°04</span>
</div>
<span class="card-poster__stripes" aria-hidden="true"></span>
<div aria-hidden="true">
<div class="card-poster__line">
<span class="card-poster__word">
<span class="card-poster__ch card-poster__ch--rest" style="--i:0">M</span>
<span class="card-poster__ch card-poster__ch--rest" style="--i:1">A</span>
<span class="card-poster__ch card-poster__ch--rest" style="--i:2">K</span>
<span class="card-poster__ch card-poster__ch--rest" style="--i:3">E</span>
</span>
<span class="card-poster__word">
<span class="card-poster__ch" style="--i:0">M</span>
<span class="card-poster__ch" style="--i:1">O</span>
<span class="card-poster__ch" style="--i:2">V</span>
<span class="card-poster__ch" style="--i:3">E</span>
</span>
</div>
<div class="card-poster__line">
<span class="card-poster__word">
<span class="card-poster__ch card-poster__ch--rest" style="--i:4">I</span>
<span class="card-poster__ch card-poster__ch--rest" style="--i:5">T</span>
</span>
<span class="card-poster__word">
<span class="card-poster__ch" style="--i:4">I</span>
<span class="card-poster__ch" style="--i:5">T</span>
</span>
</div>
</div>
<div class="card-poster__foot" aria-hidden="true">2 to 6 November<br/>Talks, workshops, demos</div>
</div>CSS
@keyframes card-poster-stripes { to { background-position: 28px 0; } }
.card-poster {
position: relative;
display: flex;
flex-direction: column;
justify-content: space-between;
width: 170px;
height: 200px;
padding: 14px;
border-radius: 6px;
background: light-dark(#373a40, #f1f2f3);
color: light-dark(#fbfcfd, #121417);
overflow: hidden;
cursor: pointer;
perspective: 400px;
}
.card-poster:focus-visible { outline: 2px solid light-dark(#42454c, #e5e6e9); outline-offset: 4px; }
.card-poster__stripes {
position: absolute;
left: 0;
right: 0;
top: 34px;
height: 18px;
background: repeating-linear-gradient(-45deg, light-dark(#fbfcfd, #121417) 0 7px, transparent 7px 14px) 0 0 / 28px 100%;
transform: scaleX(0);
transform-origin: left;
transition: transform 0.5s cubic-bezier(0.65, 0, 0.35, 1);
}
.card-poster:hover .card-poster__stripes, .card-poster:focus-visible .card-poster__stripes {
transform: none;
animation: card-poster-stripes 0.6s linear infinite;
}
.card-poster__top { display: flex; justify-content: space-between; font-size: 9px; font-weight: 600; letter-spacing: 0.12em; text-transform: uppercase; }
.card-poster__word { position: relative; display: flex; font-size: 34px; font-weight: 600; letter-spacing: -0.04em; line-height: 0.9; text-transform: uppercase; }
.card-poster__ch {
display: inline-block;
transform-origin: 50% 100%;
transform: rotateX(-90deg);
opacity: 0;
transition: transform 0.55s cubic-bezier(0.34, 1.5, 0.64, 1) calc(var(--i) * 45ms), opacity 0.2s ease calc(var(--i) * 45ms);
}
.card-poster__ch--rest { transform: none; opacity: 1; }
.card-poster__line { position: relative; height: 34px; }
.card-poster__line > * { position: absolute; left: 0; top: 0; }
.card-poster:hover .card-poster__ch, .card-poster:focus-visible .card-poster__ch { transform: none; opacity: 1; }
.card-poster:hover .card-poster__ch--rest, .card-poster:focus-visible .card-poster__ch--rest { transform: rotateX(90deg); opacity: 0; }
.card-poster__foot { font-size: 10px; line-height: 1.3; font-weight: 600; }
@media (prefers-reduced-motion: reduce) {
.card-poster__ch, .card-poster__stripes { transition-duration: 0.01s; transition-delay: 0s; }
.card-poster:hover .card-poster__stripes { animation: none; }
}Goal: Create a "Poster" card.
Visual behavior: A type poster: on hover the headline flips letter by letter from MAKE IT to MOVE IT, each letter swinging on its baseline, while hazard stripes slide in across the top and keep moving.
Technique:
- Each line holds two stacked words; every letter is its own span with transform-origin at its baseline and a delay from its index (--i x 45ms).
- On hover the resting letters rotate up to rotateX(90deg) and fade as the new ones swing down from rotateX(-90deg) on an overshooting curve.
- The stripe band scales in from the left and then scrolls its repeating gradient on a loop.
Accessibility: Focusable with role="img" and an aria-label giving the full poster text; the letters are aria-hidden. Under prefers-reduced-motion the change is instant.
My stack: {{USER_STACK}}
My styling: {{USER_STYLING}}
My constraints: {{USER_CONSTRAINTS}}
My colors: neutral only. Black, white and grays, no hues. Use the color values above as written, or my project's closest neutral tokens.
Return a single self-contained component. No dependencies.Goal: Create a "Poster" card.
Visual behavior: A type poster: on hover the headline flips letter by letter from MAKE IT to MOVE IT, each letter swinging on its baseline, while hazard stripes slide in across the top and keep moving.
Technique:
- Each line holds two stacked words; every letter is its own span with transform-origin at its baseline and a delay from its index (--i x 45ms).
- On hover the resting letters rotate up to rotateX(90deg) and fade as the new ones swing down from rotateX(-90deg) on an overshooting curve.
- The stripe band scales in from the left and then scrolls its repeating gradient on a loop.
Accessibility: Focusable with role="img" and an aria-label giving the full poster text; the letters are aria-hidden. Under prefers-reduced-motion the change is instant.
My stack: {{USER_STACK}}
My styling: {{USER_STYLING}}
My constraints: {{USER_CONSTRAINTS}}
My colors: use my project's existing color tokens. The color values above are grayscale placeholders. Map each one by its role (surface, text, border, accent, glow) to my theme, and keep their relative lightness so contrast and the effect still read.
Return a single self-contained component. No dependencies.Paste into Claude, ChatGPT or Cursor after filling in {{USER_STACK}}, {{USER_STYLING}} and {{USER_CONSTRAINTS}}. Neutral keeps the greys you see here; Match my project asks the model to map them onto your own colour tokens.
Free to use in any project, commercial included. MIT-0, no attribution required. Licence
About this component
A type poster: on hover the headline flips letter by letter from MAKE IT to MOVE IT, each letter swinging on its baseline, while hazard stripes slide in across the top and keep moving.
- Dependencies
- None
- Difficulty
- Intermediate
- Triggers
- hover, delay stagger, card
- Techniques
- 3d transform, transition delay stagger, keyframes, text animation
- Reduced motion
- Respected
- Theme
- Light and dark (follows your page's color-scheme)
Focusable with role="img" and an aria-label giving the full poster text; the letters are aria-hidden. Under prefers-reduced-motion the change is instant.