Exclusifbêta

Exploded View <mv-exploded>

Vue éclatée en 3D de n’importe quelle interface vivante : chaque boîte devient un plan surélevé selon sa profondeur visuelle (les conteneurs invisibles n’ajoutent pas d’étage), l’ensemble s’incline en pose isométrique, pivote au glisser ou au clavier, isole une couche au survol (tag, classes, taille), étiquette les couches avec des lignes de rappel, puis se réassemble sur des ressorts par étage et restaure les styles d’origine à l’octet près.

Catégorie3D
TypeWeb Component (<mv-exploded>)
Statutbêta
Keywordsexclusive, 3d, exploded-view, anatomy, inspector, preserve-3d, layers, landing, devtools, spring

When to use

  • A landing page should reveal the anatomy of a live interface as layered planes in 3D
  • A design system or devtools demo needs to show how a component is built, with labeled layers
  • A scroll-driven section should explode and reassemble a UI as the visitor passes through

Avoid when

  • A flat device frame is enough to present the interface → use Device Mockup instead
  • The wrapped interface must stay usable, since clicks are intercepted while it is exploded
  • The subtree has hundreds of elements; layer caps protect performance but the view gets cluttered

Installation

node scripts/add.mjs exploded --out ./src/marvelous

Agent IA avec le serveur MCP Marvelous UI : install_components({ slugs: ["exploded"], target_dir: "<absolute path>/src/marvelous", framework: "react" }).

Fichiers copiés (dépendances comprises) : tokens/tokens.css, core/base.css, core/dom.js, core/element.js, core/motion.js, core/observe.js, components/exploded/exploded.js, components/exploded/exploded.css.

Utilisation

Balisage de référence : partez de celui-ci et personnalisez-le avec les attributs, data-* et les variables CSS :

<div class="ex-demo">
  <style>
    .ex-demo { display: grid; grid-template-columns: minmax(0, 340px) minmax(0, 1fr); align-items: center; gap: clamp(16px, 4vw, 56px); min-height: 620px; padding: 32px clamp(20px, 4vw, 56px); box-sizing: border-box; }
    @media (max-width: 820px) { .ex-demo { grid-template-columns: 1fr; } }
    .ex-eyebrow { margin: 0 0 10px; font: 600 12px/1 var(--mv-font-mono); letter-spacing: .08em; text-transform: uppercase; color: var(--mv-accent-fg); }
    .ex-copy h2 { margin: 0; font: 750 clamp(1.8rem, 3vw, 2.4rem)/1.05 var(--mv-font-sans); letter-spacing: -.035em; }
    .ex-copy > p:not(.ex-eyebrow) { margin: 14px 0 0; color: var(--mv-fg-muted); font-size: .95rem; line-height: 1.55; }
    .ex-facts { list-style: none; margin: 22px 0 0; padding: 0; display: grid; gap: 10px; font-size: .88rem; }
    .ex-facts li { display: flex; gap: 10px; align-items: baseline; }
    .ex-facts b { font: 700 1rem/1 var(--mv-font-sans); min-width: 2.2em; color: var(--mv-fg); }
    .ex-facts span { color: var(--mv-fg-muted); }
    .ex-keys { margin-top: 22px; font-size: .78rem; color: var(--mv-fg-subtle); }
    .ex-keys kbd { font: 600 11px/1 var(--mv-font-mono); padding: 3px 6px; border-radius: 5px; border: 1px solid var(--mv-border-strong); border-bottom-width: 2px; background: var(--mv-surface); color: var(--mv-fg); }

    .ex-view { min-height: 540px; display: grid; place-items: center; }
    .ex-card { width: min(100%, 340px); border-radius: 22px; background: var(--mv-surface-raised); border: 1px solid var(--mv-border); box-shadow: var(--mv-shadow-xl); overflow: hidden; }
    .ex-media { position: relative; height: 176px; background: linear-gradient(180deg, #8ec5ff 0%, #cfe6ff 55%, #f6e7d4 100%); }
    .ex-media svg { position: absolute; inset: auto 0 0; width: 100%; height: 120px; }
    .ex-badge { position: absolute; top: 14px; left: 14px; padding: 6px 10px; border-radius: 999px; background: oklch(0.99 0 0 / .92); color: oklch(0.25 0.03 270); font: 650 11.5px/1 var(--mv-font-sans); box-shadow: 0 4px 12px oklch(0.2 0.05 260 / .18); }
    .ex-fav { position: absolute; top: 10px; right: 10px; width: 36px; height: 36px; border-radius: 50%; border: 0; display: grid; place-items: center; background: oklch(0.99 0 0 / .92); color: oklch(0.62 0.22 20); box-shadow: 0 4px 12px oklch(0.2 0.05 260 / .18); cursor: pointer; }
    .ex-fav svg { position: static; width: 18px; height: 18px; }
    .ex-body { padding: 16px 18px 18px; display: grid; gap: 10px; }
    .ex-host { position: relative; display: flex; align-items: center; gap: 10px; margin-top: -38px; }
    .ex-avatar { width: 44px; height: 44px; border-radius: 50%; display: grid; place-items: center; background: linear-gradient(135deg, oklch(0.7 0.15 40), oklch(0.6 0.18 350)); color: white; font: 700 14px/1 var(--mv-font-sans); border: 3px solid var(--mv-surface-raised); box-shadow: var(--mv-shadow-md); }
    .ex-host small { margin-top: 30px; font-size: 12px; color: var(--mv-fg-muted); }
    .ex-body h3 { margin: 2px 0 0; font: 700 1.15rem/1.2 var(--mv-font-sans); letter-spacing: -.02em; }
    .ex-meta { margin: -4px 0 0; font-size: .82rem; color: var(--mv-fg-muted); }
    .ex-tags { display: flex; flex-wrap: wrap; gap: 6px; }
    .ex-tags span { padding: 4px 9px; border-radius: 999px; background: var(--mv-bg-muted); border: 1px solid var(--mv-border); font-size: 11.5px; color: var(--mv-fg-muted); }
    .ex-foot { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-top: 4px; padding-top: 12px; border-top: 1px solid var(--mv-border); }
    .ex-price { font-size: .82rem; color: var(--mv-fg-muted); }
    .ex-price b { font: 750 1.25rem/1 var(--mv-font-sans); color: var(--mv-fg); letter-spacing: -.02em; }
  </style>

  <div class="ex-copy">
    <p class="ex-eyebrow">Design system · Refuge</p>
    <h2>How it’s built</h2>
    <p>This booking card isn’t a mockup: it’s the real DOM, exploded by visual depth. Orbit it, hover a layer to isolate it, click to pin it.</p>
    <ul class="ex-facts">
      <li><b>0</b><span>lines of code added to the card</span></li>
      <li><b>1:1</b><span>original styles restored on reassembly</span></li>
      <li><b>3D</b><span>native preserve-3d, no DOM copies</span></li>
    </ul>
    <p class="ex-keys"><kbd>Enter</kbd> explode · <kbd>←</kbd><kbd>→</kbd><kbd>↑</kbd><kbd>↓</kbd> orbit · <kbd>+</kbd><kbd>−</kbd> spacing · <kbd>Esc</kbd></p>
  </div>

  <mv-exploded class="ex-view" controls exploded aria-label="Booking card in exploded view">
    <article class="ex-card" data-mv-layer="Card">
      <div class="ex-media" data-mv-layer="Media">
        <svg viewBox="0 0 340 120" preserveAspectRatio="none" aria-hidden="true">
          <path d="M0 120 L0 70 L60 22 L96 52 L142 8 L204 64 L240 40 L300 86 L340 60 L340 120 Z" fill="#6d86b8"/>
          <path d="M142 8 L128 22 L138 20 L146 30 L154 18 L164 26 Z" fill="#fff"/>
          <path d="M0 120 L0 92 L70 60 L130 96 L190 70 L260 100 L340 80 L340 120 Z" fill="#3f5f8f"/>
          <path d="M0 120 L0 108 L90 92 L180 110 L270 96 L340 106 L340 120 Z" fill="#2b4169"/>
        </svg>
        <span class="ex-badge" data-mv-layer="Badge">Guest favorite</span>
        <button class="ex-fav" type="button" aria-label="Add to favorites" data-mv-layer="Favorite">
          <svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M12 21s-7.5-4.6-9.6-9.2C.9 8.4 3 4.5 6.8 4.5c2.1 0 3.6 1.1 5.2 3 1.6-1.9 3.1-3 5.2-3 3.8 0 5.9 3.9 4.4 7.3C19.5 16.4 12 21 12 21z"/></svg>
        </button>
      </div>
      <div class="ex-body">
        <div class="ex-host"><span class="ex-avatar" data-mv-layer="Host">MC</span><small>Maya, host since 2019</small></div>
        <h3>Arolla Chalet</h3>
        <p class="ex-meta">Zermatt · 6 guests · 3 bedrooms</p>
        <div class="ex-tags" data-mv-layer="Amenities"><span>Sauna</span><span>Matterhorn view</span><span>Ski-in/ski-out</span></div>
        <div class="ex-foot">
          <div class="ex-price"><b>$460</b> / night</div>
          <a class="mv-button" href="#" data-mv-layer="Primary action">Book</a>
        </div>
      </div>
    </article>
  </mv-exploded>
</div>

API

Attributes

NameTypeDefaultDescription
explodedbooleanExploded state (reflected; setting it on load animates the opening).
triggertoggle | hover | scroll | manualtoggletoggle: keyboard, toolbar or API; hover: explodes on hover/focus; scroll: progress tied to scrolling (20 → 50% of the way through the viewport).
gapnumber (px)62Z spacing between two visible floors.
depthvisual | domvisualvisual: only elements that paint (background, border, shadow, text, media) add a floor; dom: one floor per nesting level.
max-depthnumber10Maximum number of floors (deeper elements stay on the last one).
max-layersnumber600Performance safeguard.
tilt / spinnumber (deg)54 / -32Exploded pose: tilt (rotateX) and spin (rotateZ).
scalenumber0.84Scales the assembly down once exploded (so it stays in frame).
labelsauto | authored | noneautoLabels: those from data-mv-layer, otherwise (auto) the largest plane on each floor with its tag.class.
controlsbooleanBuilt-in toolbar (Explode/Assemble, Reset view).
data-mv-layer (descendant)stringLayer name shown in a callout with a leader line.
data-mv-depth (descendant)numberForces how many floors this element adds (0 = stays on its parent’s plane).

Properties

NameTypeDescription
stats{ layers, levels }Number of planes and floors in the current view.

Methods

NameDescription
explode() / assemble() / toggle(force?)Programmatic control.
resetView()Returns to the default pose after orbiting.

Events

NameDescription
mv-explode / mv-assembleState change. detail: { layers, levels }.
mv-layer-hoverA plane is hovered. detail: { element, level }.

CSS classes

NameDescription
mv-exploded-hud / -leaders / -callout / -tipAnnotation layer (aria-hidden): SVG leader lines, callouts, tooltip for the hovered plane.
mv-exploded-toolbar / -btn / -hintToolbar (controls attribute).
[data-mv-exploded-layer|leaf|ghost|clip|hover|pinned]Temporary markers set on planes during the exploded view (removed on reassembly).

CSS variables

NameDefaultDescription
--mv-exploded-colorvar(--mv-accent)Wireframe, hover and leader lines.
--mv-exploded-perspective1800pxScene perspective.
--mv-exploded-progress0 → 1 while exploding (read-only, usable in CSS).

Accessibility

The host is focusable (role=group, aria-roledescription “exploded view”, aria-keyshortcuts): Enter/Space explodes or assembles, arrows orbit (Shift = faster), +/− adjust the spacing, Home resets, Escape unpins then assembles. The state is announced in a live region. While inspecting, clicks inside the interface are intercepted (you inspect, you don’t activate); the content stays readable by screen readers. Annotations are aria-hidden, the toolbar is accessible. Reduced motion: no springs or per-floor offsets, the pose applies instantly.

Cette page a été traduite par IA. Signaler un problème de traduction