@gem-org/gemffects
v1.1.0
Published
Gemffects — librería React de efectos visuales
Maintainers
Readme
📑 Contents
- Installation
- Basic usage
- As child
- Headless hooks
- Optimized imports
- Effect catalog
- Particles
- Motion tokens
- Scripts
- Development
- License
📦 Installation
npm install @gem-org/gemffectsThe consuming application must use react and react-dom ^19.
@gem-org/gem-system is an optional peer. Gemffects reads --gem-* tokens from the host when they exist, and falls back to neutral values otherwise. It does not reimplement Button, inputs, Modal, Shine, Transition, Skeleton, Spinner, or Indicator.
🚀 Basic usage
Import the complete stylesheet once in your application entry point, then wrap UI with an effect:
import "@gem-org/gemffects/styles.css";
import { Glow, Ripple } from "@gem-org/gemffects";
export function SaveAction() {
return (
<Glow>
<Ripple>
<button type="button">Save</button>
</Ripple>
</Glow>
);
}The main package import is convenient for prototypes or applications that use most of the library.
🧩 As child
By default each effect renders a wrapping div. Pass asChild to merge classes, CSS variables, and listeners onto the single child — useful in Flex/Grid or on a real button:
import "@gem-org/gemffects/ripple.css";
import { Ripple } from "@gem-org/gemffects/ripple";
export function SaveRipple() {
return (
<Ripple asChild>
<button type="button">Save</button>
</Ripple>
);
}asChild requires exactly one React element child. Overlay layers (ripples, particles, halos) are injected inside that element.
🪝 Headless hooks
Pointer effects also ship as hooks so you can attach motion to an existing node without the wrapper. Tilt3D, Magnetic, and Spotlight call the same hook internally.
import "@gem-org/gemffects/tokens.css";
import "@gem-org/gemffects/tilt-3d.css";
import { useTilt3D } from "@gem-org/gemffects/tilt-3d";
export function TiltButton() {
const { ref, style, pointerProps, isTracking, motionClassName } = useTilt3D({
intensity: "md",
});
return (
<button
type="button"
ref={ref}
className={[
"gemfx-tilt3d",
isTracking && "gemfx-tilt3d--tracking",
motionClassName,
].filter(Boolean).join(" ")}
style={style}
{...pointerProps}
>
<span className="gemfx-tilt3d__surface">Save</span>
</button>
);
}useMagnetic returns { ref, style, transform, pose }. useSpotlight returns overlay coords on pose (x / y percentages) and the same --gemfx-spotlight-* variables on style; you render the beam layer. Add the returned motionClassName to a headless host when using ignoreReducedMotion.
⚡ Optimized imports
To load only what your application uses, import the motion tokens, the effect stylesheet, and the effect subpath:
import "@gem-org/gemffects/tokens.css";
import "@gem-org/gemffects/ripple.css";
import { Ripple } from "@gem-org/gemffects/ripple";
export function SaveRipple() {
return (
<Ripple>
<button type="button">Save</button>
</Ripple>
);
}Import tokens.css only once. Some effects also require stylesheets from shared modules:
ParticleBurst,ParticleRain, andRipuseparticles.css.- CSS aliases:
@gem-org/gemffects/holo-foil.css→holofoil.css,@gem-org/gemffects/tilt-3d.css→tilt3d.css.
If you prefer not to manage these style dependencies, use styles.css. JavaScript helpers are available from @gem-org/gemffects/utils, motion tokens from @gem-org/gemffects/tokens, and the particle runtime from @gem-org/gemffects/particles.
🧩 Effect catalog
Gemffects includes 27 effects, organized by purpose. Public classes use the .gemfx-* prefix (BEM). Effect parameters use --gemfx-* custom properties.
🌟 Aura, light, and neon
- Glow (
/glow) — rear neon glow with a breathing pulse. - Spotlight (
/spotlight) — circular light that follows the pointer. - BorderBeam (
/border-beam) — neon beam that travels the container edge. - Flash (
/flash) — brief white or gold burst over the child.
🌀 3D and motion
- Tilt3D (
/tilt-3d) — interactive 3D tilt from the pointer. - Float (
/float) — continuous vertical levitation. - Magnetic (
/magnetic) — subtle attraction toward the cursor. - Zoom (
/zoom) — scale the child (in, out, pulse, or lens at the pointer). - PulseScale (
/pulse-scale) — attention beat for CTAs. - Vortex (
/vortex) — spatial swirl on hover (cards).
🎨 Style, filters, and retro
- HoloFoil (
/holo-foil) — multicolor holographic sheen. - Flicker (
/flicker) — retro neon flicker. - Glitch (
/glitch) — RGB split distortion. - Glassmorphism (
/glassmorphism) — frosted glass with backdrop blur. - BlurUnveil (
/blur-unveil) — blur-to-sharp reveal (typically images). - Marquee (
/marquee) — infinite looping marquee. - ScrambleText (
/scramble-text) — matrix-style decode for titles. - Noise (
/noise) — photographic grain overlay.
🎨 Gradients and meshes
- GradientText (
/gradient-text) — text filled with a sliding, pulsing, or static color gradient (from/via/to). - GradientMesh (
/gradient-mesh) — liquid moving mesh of soft color blobs behind the child. - GradientBorder (
/gradient-border) — dynamic gradient stroke around the container edge. - GradientGlossy (
/gradient-glossy) — zenith glossy lighting: 3-stop gradient from any basecolorplus inset sheen;directionisto-bottom/to-top/to-right/to-left.
🎆 Particles and interactions
- ParticleBurst (
/particle-burst) — confetti or sparks on click. Needsparticles.css. - ParticleRain (
/particle-rain) — falling confetti, stars, or lights. Needsparticles.css. - Ripple (
/ripple) — expanding wave from the pointer. - Rip (
/rip) — scratch or tear trail with optional debris. Needsparticles.css. - RipZone (
/rip-zone) — scratch-off cover that reveals the child (lottery-card scrape). - Meteors (
/meteors) — shooting-star field in a container. - Unlock (
/unlock) — door-style cover that opens from the center (horizontal/vertical) or slides away (left/right/up/down);variantisunlockorlock. Door face viacoverSrc(image URL) orcover(node or(slot) => nodefactory for splits), else solidcolor.
Shared wrapper API
Effects wrap children. Typical props: asChild, trigger, isActive, isPaused, duration, delay, intensity, className, classNames. Pointer effects also export headless hooks (useTilt3D, useMagnetic, useSpotlight). Lifecycle callbacks follow onGlow / outGlow (and the matching name per effect). Overlays are aria-hidden. Pointer events on the child stay enabled unless the effect itself is the control (Rip, RipZone).
Every effect respects prefers-reduced-motion: reduce by default. Set ignoreReducedMotion only when motion is essential to the intended experience; the same option is available in the headless hooks.
Pointer-tracking effects (Tilt3D, Magnetic, Spotlight, HoloFoil, and Zoom) accept disabledOnTouch, defaulting to true: touch-origin tracking is skipped while mouse and pen keep working. Set it to false only when following a finger is intentional.
Gesture and tap effects (RipZone, Rip, Ripple, Flash, ParticleBurst, and ParticleRain) expose the same prop but default it to false, so scratch, drag, tap, press, and hold remain usable on touch. Set it to true to ignore touch-origin gestures without disabling mouse or pen input. trigger="always" is unaffected. Gyroscope input is outside the v1 scope.
🎆 Particles
The shared particle field lives at @gem-org/gemffects/particles:
import "@gem-org/gemffects/tokens.css";
import "@gem-org/gemffects/particles.css";
import "@gem-org/gemffects/particle-burst.css";
import { ParticleBurst } from "@gem-org/gemffects/particle-burst";ParticleLayer, useParticleField, and spawn helpers are public if you need a custom burst. Kinds include spark, star, confetti, and light.
🎨 Motion tokens
Duration, easing, and intensity are Gemffects-owned. They ship as TypeScript maps and as --gemfx-* CSS variables generated from those maps. Palette, type, space, and radius stay on the host (--gem-*).
import {
duration,
easing,
intensity,
mixIntensity,
} from "@gem-org/gemffects/tokens";Load the CSS variables once:
import "@gem-org/gemffects/tokens.css";Helpers such as cx and useEffectPhase are available from @gem-org/gemffects/utils.
🛠️ Scripts
npm run dev— starts Storybook athttp://localhost:6006.npm run build— builds the library, subpaths, and CSS files intodist/.npm run build-storybook— builds the static documentation.npm run bundle— measures dist module and stylesheet sizes.npm run typecheck— checks TypeScript types.npm run lint— runs ESLint.
🧑💻 Development
- Effects live in
src/effects/<Name>/. - Motion tokens live in
src/tokens/(duration,easing,intensity). - Generated CSS variables live in
src/styles/tokens.scss. Storybook loadssrc/styles/effects.scss. - Particle runtime lives in
src/particles/. - SCSS is colocated with each effect. Published TSX does not import SCSS; consumers load
./name.css. - Public classes use the
.gemfx-*prefix and BEM naming. - TypeScript is strict and
anyis not allowed. - Storybook is the development and documentation environment.
