@taverse/react-holographic-card
v0.3.3
Published
React components for interactive holographic cards.
Maintainers
Readme
@taverse/react-holographic-card
Interactive holographic finishes for image-based and React-rendered cards.
Visit the live landing page and interactive demo to explore every effect and try the component in the browser. The package is available on npm, and development happens in the GitHub repository.
Install
npm install @taverse/react-holographic-cardImport the component and its stylesheet:
import { HolographicCard } from "@taverse/react-holographic-card";
import "@taverse/react-holographic-card/styles.css";
export function Example() {
return (
<HolographicCard
frontImage="/cards/card.png"
backImage="/cards/back.png"
backAlt="Limited-edition card back"
alt="Limited-edition card"
effect="holo"
foilArea="artwork"
artworkBounds={{ top: 16, right: 5, bottom: 37, left: 5 }}
/>
);
}No card data model or external API is required. Map data from your own API or database directly to component props.
Content modes
Image mode requires frontImage and alt. Use frontImageProps for native image options and events.
React-content mode requires frontContent and ariaLabel:
<HolographicCard
frontContent={
<div className="membership-card">
<strong>Studio Member</strong>
<span>NO. 2048</span>
</div>
}
ariaLabel="Studio membership card 2048"
effect="topography"
/>The two front modes are mutually exclusive in TypeScript. Custom content is presentational and must not contain links, buttons, or form controls.
The back supports either backImage or backContent. When neither is provided, the component renders a brand-neutral CSS back. A failed back image also falls back to the neutral back.
Card face control
Exported HolographicCardFace values are "front" | "back". Add flipOnClick for native mouse, touch, Enter, and Space activation, and use either defaultFace for local state or face with onFaceChange for consumer-owned state:
const [face, setFace] = useState<HolographicCardFace>("front");
<HolographicCard
frontContent={<div>What follows dusk?</div>}
ariaLabel="Dusk prompt"
backContent={<div>Night follows dusk.</div>}
backAriaLabel="Night follows dusk"
face={face}
onFaceChange={setFace}
flipOnClick
/>Direct flipping takes priority over click expansion and never mutates active/group state. Face state is deterministic during SSR, local to each mounted card in groups and carousels, and swaps without interpolation under reduced motion. See docs/card-flip.md for image/content, controlled/uncontrolled, disabled, keyboard, SSR, group, carousel, and styling guidance.
API
| Prop | Default | Purpose |
| --- | --- | --- |
| effect | holo | Selects a built-in visual finish. |
| effectSeed | stable generated seed | Makes texture placement reproducible. |
| foilImage / maskImage | none | Supplies custom foil and mask image URLs. |
| foilArea | auto | Uses artwork, notched-artwork, inset-artwork, or full. |
| artworkBounds | none | Overrides the rectangular artwork clip with percentage { top, right, bottom, left } bounds; Reverse Foil automatically uses the inverse region. |
| accentColor | library default | Changes the active glow color. |
| interaction | pointer | Accepts pointer, orientation, auto, or none. |
| expandOnClick | true | Enables click/keyboard expansion. |
| flipOnClick | false | Requests the opposite face from click, touch, Enter, or Space. |
| face | none | Authoritative controlled face (front or back). |
| defaultFace | front | Seeds uncontrolled face state once. |
| onFaceChange | none | Receives the next face once per accepted direct activation. |
| backAriaLabel | derived | Describes custom back content; falls back to backAlt, then the card label. |
| autoAnimate | false | Plays the one-shot showcase motion. |
| active / defaultActive | false | Controls expanded state. |
| onActiveChange | none | Receives active-state changes. |
| disabled | false | Prevents activation changes and neutralizes interaction motion; an already active controlled card remains active. |
All compatible root <div> attributes, including className, style, data-*, and root event handlers, are forwarded to the root element.
Motion behavior
Motion sources are resolved in this order: pointer interaction, device orientation, then one-shot showcase motion. Pointer interaction retains ownership for 500 ms after leave before handing off to active orientation input or returning to neutral. Direct pointer or orientation input cancels showcase motion for that card instance.
interaction="none" disables pointer and orientation input, but an explicit autoAnimate still allows showcase motion. If orientation permission is denied, click expansion still works when expandOnClick is enabled.
Reduced motion disables pointer, orientation, and showcase motion. Card Activation remains functional and recenters or scales immediately without a spring or initial spin. See docs/card-motion-runtime.md for the internal ownership and environment seam.
Effect catalog
holographicEffects is the source of truth for selection UIs:
Effect IDs describe generic visual finishes. They do not represent Pokemon rarities, subtypes, sets, or card metadata, and the package does not infer an effect from application data.
import { holographicEffects, type HolographicEffect } from "@taverse/react-holographic-card";
holographicEffects.map(({ id, label, description }) => ({ id, label, description }));Use the exported catalog to render choices and the derived HolographicEffect type to validate stored values. This keeps consumer UIs synchronized when the catalog evolves.
The catalog currently includes 30 finishes. Asset-backed additions such as galaxy, angular-maze, spectral-grain, and flowing-lines follow the same interaction, SSR, and foilArea contracts as the original finishes.
Multiple cards
HolographicCardGroup ensures only one descendant card is active:
<HolographicCardGroup>
<HolographicCard id="first" frontImage="/first.png" alt="First card" effect="cosmos" />
<HolographicCard id="second" frontImage="/second.png" alt="Second card" effect="glitter" />
</HolographicCardGroup>Use activeId, defaultActiveId, and onActiveIdChange to control a group. Controlled groups should give every card an explicit id. Do not combine card-level controlled state with group state.
Circular carousel
HolographicCarousel arranges three to eight cards on a responsive 3D orbit. It includes
previous/next controls, thumbnails, horizontal drag, keyboard navigation, an optional ripple
surface, reduced-motion behavior, and a decelerating entrance animation.
import {
HolographicCard,
HolographicCarousel,
HolographicCarouselItem,
} from "@taverse/react-holographic-card";
<HolographicCarousel
defaultSelectedId="first"
onSelectedIdChange={(id) => console.log(id)}
ariaLabel="Featured cards"
>
<HolographicCarouselItem
id="first"
label="First card"
thumbnail={<img src="/first-thumb.png" alt="" />}
>
<HolographicCard frontImage="/first.png" alt="First card" effect="cosmos" />
</HolographicCarouselItem>
<HolographicCarouselItem id="second" label="Second card">
<HolographicCard frontImage="/second.png" alt="Second card" effect="glitter" />
</HolographicCarouselItem>
</HolographicCarousel>;Selection can be uncontrolled with defaultSelectedId or controlled with selectedId and
onSelectedIdChange. animateOnMount, showControls, showThumbnails, showSelectionInfo, and
showWave default to true. Autoplay advances every 6 seconds by default; set
autoAdvanceMs={0} to disable it or provide another duration in milliseconds. The carousel loops
automatically and falls back to the first item when an uncontrolled selection disappears.
The selected card receives a subtle automatic tilt so its foil remains visible. Card click
expansion follows the child HolographicCard configuration; use expandOnClick (the default) to
open it. Autoplay pauses while the carousel is hovered or focused and respects reduced-motion
preferences.
The main theming variables are --rh-carousel-card-width, the unitless stage-relative
--rh-carousel-radius-x and --rh-carousel-radius-y, --rh-carousel-wave-color, and
--rh-carousel-control-color. See docs/holographic-carousel.md
for interaction, accessibility, and responsive details.
Custom styling
Use className, data-effect, and the stable layers .rh-card__front, .rh-card__content, .rh-card__shine, and .rh-card__glare to customize a built-in finish. Supported dynamic variables are:
--rh-pointer-x,--rh-pointer-y,--rh-pointer-from-center--rh-background-x,--rh-background-y,--rh-card-opacity--rh-card-glow,--rh-foil,--rh-mask
Transform and spring variables are internal and may change between releases.
Deterministic rendering and SSR
The default seed is derived from React useId, so server rendering does not rely on Math.random(). Pass a stable effectSeed for snapshots, synchronized collections, or reproducible artwork. Browser APIs are only accessed from effects or user gestures.
See docs/effect-inventory.md for the complete built-in effect catalog.
License
The effect code and bundled bitmap textures are distributed under GPL-3.0-only.
