Pixel Transition <mv-pixel-transition>
픽셀 그리드를 통해 두 면 사이를 전환합니다. 정사각형 픽셀이 무작위, 방사형(포인터에서 시작), 대각선 또는 행 순서로 첫 번째 면을 덮으며 자라나고, 완전히 덮인 상태에서 면이 바뀐 뒤 픽셀이 줄어들며 사라집니다.
작동 방식
픽셀 그리드를 통해 두 면 사이를 전환합니다. 정사각형 픽셀이 무작위, 방사형(포인터에서 시작), 대각선 또는 행 순서로 첫 번째 면을 덮으며 자라나고, 완전히 덮인 상태에서 면이 바뀐 뒤 픽셀이 줄어들며 사라집니다. 진행값 하나가 모든 프레임을 구동하므로, 호버가 중간에 끊겨도 부드럽게 되감깁니다.
| 카테고리 | 트랜지션 |
|---|---|
| 유형 | Web Component (<mv-pixel-transition>) |
| 상태 | 안정 |
| Keywords | safe-rewrite, pixel, transition, reveal, hover, card, swap, canvas, retro |
When to use
- A card should swap to a second face through a retro pixel dissolve on hover or focus
- A team or product tile should reveal hidden details with a radial pixel effect from the pointer
- Two images or states should toggle manually with a playful, interruptible pixel transition
Avoid when
- A two-sided card should flip in 3D rather than dissolve → use Flip Card instead
- Users should compare two images side by side with a draggable divider → use Image Compare instead
- The hidden face holds essential information on touch-first pages; hover reveals are easy to miss
설치
node scripts/add.mjs pixel-transition --out ./src/marvelousMarvelous UI MCP 서버를 사용하는 AI 에이전트: install_components({ slugs: ["pixel-transition"], target_dir: "<absolute path>/src/marvelous", framework: "react" }).
복사되는 파일(의존성 포함): tokens/tokens.css, core/base.css, core/canvas.js, core/dom.js, core/element.js, core/focus.js, core/motion.js, components/pixel-transition/pixel-transition.js, components/pixel-transition/pixel-transition.css.
사용법
기본 마크업입니다. 여기서 시작해 속성, data-*, CSS 변수로 커스터마이즈하세요:
<div style="display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:1rem;width:100%;max-width:820px">
<mv-pixel-transition grid="10" colors="oklch(0.97 0.02 85), oklch(0.88 0.08 70), oklch(0.8 0.12 55)" style="aspect-ratio:3/4">
<div style="display:grid;place-items:center;background:linear-gradient(160deg,oklch(0.62 0.19 285),oklch(0.45 0.17 300));color:white;text-align:center;padding:1rem">
<div><p style="margin:0;font:800 3rem/1 var(--mv-font-display)">?</p><p style="margin:.5rem 0 0;font-size:.85rem;opacity:.85">Hover the card</p></div>
</div>
<div style="display:grid;align-content:end;gap:.35rem;padding:1.1rem;background:linear-gradient(180deg,transparent 30%,oklch(0 0 none / .55)),radial-gradient(circle at 30% 30%,oklch(0.85 0.12 80),oklch(0.55 0.16 40));color:white">
<strong style="font-size:1.05rem">Maya Chen</strong>
<span style="font-size:.8rem;opacity:.9">Art Director · Tokyo</span>
</div>
</mv-pixel-transition>
<mv-pixel-transition trigger="click" pattern="radial" grid="14" duration="800" colors="oklch(0.72 0.15 160), oklch(0.62 0.14 175), oklch(0.8 0.12 140)" style="aspect-ratio:3/4">
<div style="display:grid;place-items:center;background:var(--mv-bg-muted);border:1px solid var(--mv-border);border-radius:inherit;text-align:center;padding:1rem">
<div><p style="margin:0;font-weight:600">Pro plan</p><p style="margin:.35rem 0 0;font-size:.8rem;color:var(--mv-fg-muted)">Click to see the price</p></div>
</div>
<div style="display:grid;place-items:center;background:oklch(0.3 0.06 170);color:white;text-align:center;padding:1rem">
<div><p style="margin:0;font:800 2.4rem/1 var(--mv-font-display)">$19</p><p style="margin:.35rem 0 0;font-size:.8rem;opacity:.8">per month, cancel anytime</p></div>
</div>
</mv-pixel-transition>
<mv-pixel-transition pattern="diagonal" grid="16" duration="600" colors="#0f172a, #1e293b, #334155" style="aspect-ratio:3/4">
<div style="display:grid;place-items:center;background:oklch(0.95 0.03 90);color:oklch(0.3 0.05 60);padding:1rem;text-align:center">
<p style="margin:0;font:700 1.35rem/1.2 var(--mv-font-display)">Day</p>
</div>
<div style="display:grid;place-items:center;background:oklch(0.2 0.04 265);color:oklch(0.9 0.05 265);padding:1rem;text-align:center">
<p style="margin:0;font:700 1.35rem/1.2 var(--mv-font-display)">Night ✦</p>
</div>
</mv-pixel-transition>
</div>API
Attributes
| Name | 유형 | Default | Description |
|---|---|---|---|
trigger | hover | click | manual | hover | Trigger (hover: also keyboard focus, and a tap on touch screens; click: click, Enter or Space; manual: toggle()/show() or the flipped attribute). |
pattern | random | radial | diagonal | rows | random | Order in which pixels appear (radial starts from where the pointer entered or clicked, the center otherwise). |
grid | number | 12 | Number of pixel columns, 2 to 60 (square pixels, rows follow). |
duration | number | 700 | Total duration of one switch (ms). |
colors | list of CSS colors | var(--mv-pixel-transition-color) | One or more colors (tokens accepted, they follow the theme), spread across the pixels. |
flipped | boolean | Back face shown (reflected by the component, writable). | |
data-state | front | back | Set by the component. |
Methods
| Name | Description |
|---|---|
toggle() | Switches to the other face. |
show(face) | Shows “front” or “back”. |
Events
| Name | Description |
|---|---|
mv-change | detail: { face, flipped }. At the moment the faces swap. |
Content structure
| Name | Description |
|---|---|
(child 1 / child 2) | Front face, then back face; the element takes the size of the larger one. |
CSS variables
| Name | Default | Description |
|---|---|---|
--mv-pixel-transition-color | var(--mv-fg) | Default pixel color. |
Accessibility
The hidden face is inert and aria-hidden. Without focusable content, the element becomes focusable and acts as a toggle button (role=button, aria-pressed, Enter/Space), named by the face on show; an author role is kept. In hover mode, keyboard focus also reveals the back face and a tap toggles. Reduced motion: instant swap, no pixels. Forced colors: no painted pixels, the faces swap half-way. The frame loop only runs during a switch.