Aller au contenu
O-UI

Recherche

Trouvez un composant ou une page de documentation.

Hologram

BêtaComposant

Projette un texte, une icône ou un logo en hologramme crédible, que le pointeur perturbe.

Frameworks
ReactVueVanilla
Technologies
WebGLCanvas 2D
Déclenché par
PointeurApparition à l'écranContinu
Mis à jour le
Paramètres

Hologram projette un texte, une icône ou un logo comme une lumière translucide : lignes de balayage, légère interférence chromatique, scintillement lent, halo, copies fantômes en profondeur et cône de projection. Au survol, la projection se perturbe autour du pointeur puis se résorbe ; au repos, de rares micro-glitchs la gardent vivante. Le contenu HTML reste dans la page, pour les lecteurs d'écran et en repli. Utilisez-le pour un titre court, un statut ou une marque, sur un fond sombre de préférence ; il ne convient pas au texte courant.

Installation

Installez l'élément et ses dépendances en une commande :

pnpm dlx shadcn@latest add https://o-ui.hd987.dev/r/hologram.json

Hologram n'a aucune dépendance : il dessine avec WebGL2, disponible dans tous les navigateurs récents. Sans WebGL2, le contenu HTML s'affiche à la place, dans la couleur de l'hologramme avec un halo CSS. Les prérequis communs à tous les composants (Tailwind CSS v4, React 19 ou Vue 3.5) sont décrits dans Installation.

Utilisation

Placez Hologram dans un titre : le texte vient de la prop text, et le titre garde sa sémantique. Pour une icône ou un logo, donnez-lui un <svg> inline ou une <img> en enfant.

import { Hologram } from "@/components/o-ui/hologram/hologram";

export function Hero() {
  return (
    <h1>
      <Hologram text="NOW ONLINE" fontSize={120} />
    </h1>
  );
}
<Hologram preset="hud">
  <ShieldIcon className="size-16" aria-label="Secured" />
</Hologram>

Hologram est un composant client : ces extraits fonctionnent tels quels dans un Server Component de Next.js. Avec un enfant <svg> ou <img>, text est ignoré : c'est l'enfant qui est projeté. Un texte en enfant (<Hologram>Hello {name}</Hologram>) vaut text ; tout autre HTML en enfant n'est pas projeté et s'affiche tel quel.

Quelques règles font la différence :

  1. Le contenu donne sa taille au composant. En mode texte, la hauteur vient du texte et la largeur du parent ; avec fit (activé par défaut), fontSize est une taille maximale et le texte rétrécit quand la largeur manque, sans jamais être agrandi. Avec un enfant, le composant prend la taille de cet enfant : dimensionnez votre <svg> ou votre <img> en CSS.
  2. Écrivez les retours à la ligne dans text, avec \n. Le texte ne passe jamais à la ligne de lui-même.
  3. Laissez de la place autour. Le halo, les fantômes et les tranches décalées sortent du contenu : environ 50 px autour et jusqu'à 160 px sous le contenu pour le cône de projection. Évitez overflow: hidden sur le composant ou ses ancêtres proches, et gardez de l'espace avec les éléments voisins. Si le composant touche le bord de la page, posez overflow-x: clip sur la section pour éviter un défilement horizontal.
  4. Préférez un fond sombre. L'hologramme est une lumière translucide : il reste visible sur fond clair, mais c'est sur un fond sombre qu'il prend tout son relief. Les exemples de cette page forcent le thème sombre sur leur scène avec la classe dark.
  5. Prévoyez une pause pour toute la page. L'animation est continue : un seul interrupteur suffit à la mettre en pause partout (voir Mettre en pause).

Exemples

Mise en service

Un hero de lancement dans un h1. La séquence d'allumage (intro, 1,2 s par défaut) joue quand le titre entre à l'écran : un balayage révèle le texte, quelques tranches se résolvent, le scintillement se calme. Le bouton appelle replay() par la ref.

Six rendus

Le même mot dans les six presets. cinematic est le rendu par défaut ; les autres changent la couleur, les lignes, le scintillement, l'aberration, le grain, les fantômes et l'instabilité d'un seul coup. Chaque prop fine reste réglable par-dessus.

Statut système

Un statut piloté par l'application, en preset="hud". À chaque étape, la démo change text et appelle disturb() : la projection réagit à la donnée. Le paragraphe porte aria-live="polite" pour annoncer les changements.

Logo et icônes

Un logo multicolore projeté avec ses propres couleurs (colorMode="source") et trois icônes teintées en hud. Un clic ou un tap sur le logo appelle disturb({ x, y }) au point touché ; le bouton lance une salve sur tout.

Personnalisation

Presets et réglages fins

preset choisit un rendu cohérent : cinematic (projection stable, le défaut), hud (interface nette), retro (terminal ambre), broken (signal dégradé), ghost (spectre translucide) et neon (enseigne saturée). Une prop fine donnée explicitement l'emporte sur le preset ; retirez-la pour revenir à la valeur du preset.

<Hologram text="SYSTEM" preset="retro" flicker={0.6} scanlineSize={5} />
  • Lumière. color et colorEnd forment un dégradé vertical, du haut vers le bas ; opacity règle la translucidité et glow le halo.
  • Signal. scanlines et scanlineSize règlent les lignes de balayage et la bande qui descend lentement ; flicker le scintillement ; aberration le désalignement rouge et bleu ; noise le grain.
  • Volume. ghost et depth règlent les copies fantômes et leur décalage ; beam le cône de projection sous le contenu ; parallax leur glissement vers le pointeur.
  • Vie. instability règle la fréquence des micro-glitchs spontanés (0 pour une projection parfaitement stable) ; speed la vitesse de toute l'animation ambiante (0 la fige) ; seed la graine des glitchs et du grain.

Perturbation au pointeur

Sur pointeur fin, une énergie monte quand le pointeur entre dans le composant et avec sa vitesse, puis retombe en returnDuration secondes. Dans le rayon radius, les tranches sautent, des lignes se perdent, l'aberration et le grain se renforcent ; le reste du contenu frissonne légèrement. strength règle la force (0 coupe la perturbation) et parallax incline les fantômes vers le pointeur.

Sur un écran tactile, l'hologramme vit mais ne suit pas le doigt. Appelez disturb() sur un tap, un bouton ou un changement de données pour une salve, globale ou centrée sur un point en pixels CSS depuis le coin supérieur gauche du composant.

Couleurs et thème

Les couleurs par défaut sont celles du preset. Toute couleur CSS convient : une variable du thème (var(--primary)) s'adapte d'elle-même, et currentColor suit la couleur du texte environnant.

<Hologram text="Spectrum" color="var(--primary)" colorEnd="var(--primary-foreground)" />

En colorMode="source", le contenu garde ses couleurs : un logo multicolore reste reconnaissable, et color ne sert plus qu'au halo, au cône et au repli.

Intégration

Next.js et Nuxt

Le rendu serveur produit le contenu HTML, déjà dans la couleur de l'hologramme ; la projection le remplace visuellement au chargement du script.

  • Next.js : Hologram est un composant client, utilisable dans un Server Component. Un fichier qui utilise la ref ou un gestionnaire d'événement doit commencer par "use client".
  • Nuxt : aucun <ClientOnly> n'est nécessaire. Importez Hologram explicitement : l'import automatique de Nuxt préfixe le nom d'un composant par son dossier.
  • Taille au chargement. Avec un rendu serveur, le texte apparaît d'abord à fontSize, puis fit le réduit au chargement du script sur un petit écran. fontSize est un nombre, pas une valeur responsive : choisissez un compromis entre ordinateur et mobile.

Contrôle programmatique

La ref React reçoit l'élément racine augmenté de disturb() et replay(). En Vue, le composant expose el, disturb et replay.

"use client";

import { useRef } from "react";
import { Hologram, type HologramHandle } from "@/components/o-ui/hologram/hologram";

export function Status({ value }: { value: string }) {
  const hologramRef = useRef<HologramHandle>(null);
  return (
    <>
      <Hologram ref={hologramRef} text={value} preset="hud" />
      <button type="button" onClick={() => hologramRef.current?.disturb({ strength: 1.2 })}>
        Ping
      </button>
    </>
  );
}

Mettre en pause toutes les animations

L'hologramme vit sans fin. Pour la WCAG 2.2.2, la page doit permettre de mettre ce mouvement en pause. La pause commune de FrameLoop, installé avec Hologram, fige tous les hologrammes de la page, ceux créés ensuite compris, et les autres animations continues d'O-UI : un seul interrupteur suffit. Placez-le dans l'en-tête, le pied de page ou les réglages du site.

import { setAnimationsPaused } from "@/components/o-ui/frame-loop/frame-loop-core";

setAnimationsPaused(true); // every hologram shows a stable frame

La prop paused fige une seule instance ; la pause commune l'emporte.

États

La racine expose data-state : loading (contenu HTML visible, projection en préparation), active (animée), idle (dessinée, au repos), static (pause ou mouvement réduit), disabled et fallback (sans WebGL, ou contenu qui ne peut pas être projeté). data-source vaut text, svg ou image, et data-disturbed est présent pendant une perturbation : de quoi styler le contenu voisin.

API

PropTypeDéfautDescription
textstring"O-UI"Texte projeté, 240 caractères au plus ; les retours à la ligne explicites sont conservés. Avec un enfant svg ou img, il est ignoré.
fontSizenumber160Taille du texte en pixels CSS, de 12 à 512. Avec fit, c'est la taille maximale.
fontFamilystring"inherit"Famille de police CSS du texte ; « inherit » reprend la police environnante.
fontWeightnumber700Graisse du texte, de 100 à 900.
letterSpacingnumber0Approche du texte en pixels CSS, de −8 à 32.
lineHeightnumber1.1Interligne du texte relatif à la taille, de 0,8 à 2.
alignHologramAlign"center"Alignement horizontal des lignes : « left », « center » ou « right ».
fitbooleantrueRéduit le texte pour tenir dans la largeur disponible, sans jamais l'agrandir.
presetHologramPreset"cinematic"Rendu cohérent de base : « cinematic », « hud », « retro », « broken », « ghost » ou « neon ». Chaque prop fine donnée explicitement l'emporte.
colorModeHologramColorMode"tint"« tint » colore la forme avec color et colorEnd ; « source » conserve les couleurs du contenu.
colorstring"#6ee7ff"Couleur en haut de la forme, toute couleur CSS ; elle teinte aussi le halo, les fantômes et le cône.
colorEndstring"#bff6ff"Couleur en bas de la forme : le dégradé vertical vers l'émetteur.
opacitynumber0.85Translucidité globale, de 0 à 1.
glownumber0.5Halo autour de la forme, de 0 (aucun) à 1 : sa portée et son intensité.
scanlinesnumber0.35Contraste des lignes de balayage et de la bande qui descend, de 0 (aucune) à 1.
scanlineSizenumber3Pas des lignes de balayage en pixels CSS, de 1 à 12.
flickernumber0.25Scintillement lent et irrégulier de la luminosité, de 0 (stable) à 1.
aberrationnumber1Désalignement rouge et bleu au repos en pixels CSS, de 0 à 8 ; une perturbation l'amplifie.
noisenumber0.15Grain de signal, de 0 (aucun) à 1.
ghostnumber0.35Opacité des deux copies fantômes derrière la forme, de 0 (aucune) à 1.
depthnumber10Décalage des copies fantômes en pixels CSS, de 0 à 40 : l'épaisseur perçue.
beamnumber0.25Cône de projection sous la forme, de 0 (aucun) à 1.
speednumber1Vitesse de l'animation ambiante (lignes, scintillement, grain), de 0 (figée) à 3.
seednumber1Graine des glitchs spontanés et du grain, un entier de 0 à 1 000 000 : deux instances diffèrent.
instabilitynumber0.3Fréquence et force des glitchs spontanés au repos, de 0 (jamais) à 1 ; toujours moins de trois par seconde.
intronumber1.2Durée de la séquence d'allumage à la première apparition, en secondes, de 0 (aucune) à 4.
strengthnumber0.6Force de la perturbation autour du pointeur, de 0 (aucune) à 2.
radiusnumber80Rayon de la perturbation autour du pointeur en pixels CSS, de 0 à 500.
returnDurationnumber0.6Temps de résorption d'une perturbation, en secondes, de 0,1 à 3.
parallaxnumber0.15Glissement des fantômes et du halo vers le pointeur, de 0 (aucun) à 1.
pixelRationumber1.5Densité de pixels maximale du canvas, de 0,5 à 2, jamais au-delà de celle de l'écran. Baissez-la sur un très grand titre.
pausedbooleanfalseFige une frame stable, sans scintillement, glitch ni grain, et arrête la boucle.
disabledbooleanfalseAffiche le contenu HTML tel quel et libère le GPU.
reducedMotionReducedMotion"user"« user » suit le réglage du système, « always » fige toujours l'hologramme, « never » garde le mouvement (à réserver à un choix explicite de l'utilisateur).

Les nombres hors plage sont bornés. Une valeur invalide (NaN, mauvais type, mot-clé inconnu) garde la valeur courante. Une couleur est transmise telle quelle au CSS : si le navigateur ne la reconnaît pas, l'hologramme prend currentColor. Une prop retirée revient à la valeur du preset, puis à la valeur par défaut.

Props des adaptateurs. React : className est fusionné avec cn(), les attributs natifs sont transmis à la racine (span), children reçoit le <svg> ou l'<img> à projeter, et ref donne l'élément racine augmenté de disturb() et replay(). Vue : class est fusionné de même, le slot par défaut reçoit le contenu à projeter, et le composant expose el, disturb et replay.

Accessibilité

  • Contenu réel. Le texte, le <svg> ou l'<img> existe dès le rendu serveur et reste dans la page, invisible une fois la projection dessinée. Les lecteurs d'écran le lisent normalement ; donnez à une icône décorative aria-hidden="true" et à une icône porteuse de sens un aria-label, exactement comme sans hologramme.
  • Canvas décoratif. Le canvas est en aria-hidden="true" et pointer-events: none : il ne capte ni clic, ni focus. Placez un lien ou un bouton autour de Hologram, jamais dans le <svg> projeté : le contenu projeté est rendu invisible, anneau de focus compris.
  • Mouvement réduit. Avec prefers-reduced-motion, l'hologramme reste holographique mais figé : couleur, halo, lignes et fantômes fixes, sans scintillement, glitch, grain animé ni réaction au pointeur ; l'allumage devient un fondu et disturb() ne fait rien. La bascule du système est prise en compte en direct.
  • Pas de flash. Au-dessus de 3 Hz, le scintillement reste sous un dixième de la luminance quels que soient les réglages. Les déchirures rapides restent dans un disque de 120 px autour du pointeur ; ailleurs, tranches et lignes perdues changent au plus trois fois par seconde, et les glitchs spontanés aussi (WCAG 2.3.1). Gardez tout de même flicker et instability modérés sur un grand titre.
  • Pause. L'animation continue s'arrête avec la pause commune de la page ou la prop paused (WCAG 2.2.2).
  • Contraste élevé et repli. En forced-colors, sans WebGL2 ou sur un GPU logiciel, le contenu HTML s'affiche dans la couleur de l'hologramme avec un halo CSS.

Performances

  • Dépendances : aucune. Le cœur et ses fichiers pèsent environ 16 kB compressés (40 kB minifiés), primitives comprises.
  • Un rendu par frame. Le contenu est rasterisé une fois par changement (texte, typographie, police, taille affichée, densité de pixels) dans une texture bornée à 2 millions de pixels ; son halo est calculé au même moment. Chaque frame dessine ensuite un seul triangle plein canvas, sans cible intermédiaire.
  • Travail borné. La densité de pixels est plafonnée par pixelRatio (1,5 par défaut) et le canvas à 4 millions de pixels. Les écouteurs du pointeur n'existent que sur pointeur fin et effet actif.
  • Sommeil. Hors écran, dans un onglet masqué, en pause ou sous mouvement réduit, rien ne tourne. Loin de l'écran (360 px), le contexte WebGL est libéré et recréé à l'approche : une page peut aligner de nombreux hologrammes sans dépasser la limite de contextes du navigateur.
  • Plusieurs instances. Chaque hologramme est un membre de la boucle commune de la page : toutes les mesures passent avant tous les rendus, et une page avec plusieurs éléments O-UI ne demande qu'une frame par rafraîchissement.

Problèmes fréquents

  • Le halo ou le cône est coupé. Un ancêtre en overflow: hidden rogne le canvas, qui déborde du composant. Retirez-le ou gardez de l'espace.
  • Le logo est un rectangle plein. En mode tint, seule la couverture compte : une image JPEG sans transparence est un rectangle. Utilisez un SVG ou une image PNG/WebP avec transparence.
  • Le logo SVG perd un détail. Le SVG est sérialisé avec ses styles calculés, mais il est rendu seul : une référence externe (<use href="…"> vers un autre fichier, une image distante, une police web) n'est pas disponible. Gardez le SVG autonome.
  • L'image n'est pas projetée. Une image d'une autre origine sans en-tête CORS ne peut pas être lue : servez-la depuis votre domaine ou avec crossorigin="anonymous". En attendant, le composant affiche l'image telle quelle (data-state="fallback").
  • Les réglages fins semblent sans effet. Vérifiez preset : une prop fine donnée l'emporte toujours, mais une prop à undefined revient à la valeur du preset.

Notes et limites

  • Navigateurs. WebGL2 est nécessaire : Chrome, Edge, Firefox, Safari 15 et plus. Sans lui, le contenu HTML coloré s'affiche.
  • Un contenu par instance. Avec des enfants, seul le premier <svg> ou <img> est projeté ; le reste du HTML s'affiche normalement.
  • Pas de HTML arbitraire. Un bloc de texte mis en forme, un composant ou une vidéo ne peut pas être rasterisé : utilisez text, un SVG ou une image.
  • Changement de contenu. Un nouveau texte remplace l'ancien d'un coup ; appelez disturb() au même moment pour une transition en glitch, comme l'exemple Statut système. Un nouveau logo, ou un SVG modifié sur place, reconstruit l'hologramme sans rejouer l'allumage. Il n'y a pas de transformation progressive entre deux contenus.