UNPKG

@razorpay/blade-mcp

Version:

Model Context Protocol server for Blade

340 lines (288 loc) 11 kB
## Component Name RazorSense ## Description RazorSense is a WebGL-powered component that renders an animated glass refraction effect with video/image textures, colorama color grading, displacement, bloom, and light sweep effects. It ships with built-in presets for common use cases such as background waves, success animations, and zoomed-in card treatments. Assets can be preloaded with `preloadRazorSenseAssets()` to avoid frame skipping on mount. ## Important Constraints - `videoSrc` and `imageSrc` are mutually exclusivewhen `imageSrc` is provided, the video is not created. - Changing `gradientMapSrc` or `gradientMap2Src` re-initializes the WebGL context. - `preloadRazorSenseAssets(preset)` should be called and awaited before mounting the component with that preset to avoid visible loading artifacts. - The component only works on **web** (requires WebGL). - `edgeFeather` values range from 0 (no feather) to higher values for more aggressive feathering: `[top, right, bottom, left]`. - `backgroundColor` uses RGB in the `[0-1, 0-1, 0-1]` rangenot hex or CSS colors. - Props always take priority over preset values. ## TypeScript Types The following types represent the props that the RazorSense component accepts. ```typescript type RazorSensePreset = 'default' | 'zoomed' | 'bottomWave' | 'rippleWave' | 'circleSlideUp'; type RazorSenseProps = { /** CSS width (default: '100%') */ width?: string | number; /** CSS height (default: '100%') */ height?: string | number; /** * Named preset that provides a base configuration. * Any explicit props override the preset values. * - 'default' — baseline, same as not passing a preset * - 'zoomed' — tight closeup with high zoom and edge feathering * - 'bottomWave' — static image, bottom wave style * - 'rippleWave' — ray pulse video, ripple effect * - 'circleSlideUp' — success circle animation */ preset?: RazorSensePreset; /** Base CDN path for loading default assets */ assetsPath?: string; // --- Asset Customization --- /** URL to a static image to use as the base texture instead of video */ imageSrc?: string; /** URL to the gradient map image for colorama effect */ gradientMapSrc?: string; /** URL to a second gradient map for cross-fading via gradientMapBlend */ gradientMap2Src?: string; /** Canvas element for runtime gradient map hot-swap without reinitializing WebGL */ gradientMapCanvas?: HTMLCanvasElement | null; // --- Playback --- /** Whether video is paused (default: false) */ paused?: boolean; /** Video start time in seconds (default: 0) */ startTime?: number; /** Video end time in seconds (default: 14) */ endTime?: number; /** Video playback rate multiplier (default: 1.0) */ playbackRate?: number; /** Animate light effect independently of video (default: false) */ animateLightIndependently?: boolean; // --- Effect Toggles --- /** Enable displacement effect (default: true) */ enableDisplacement?: boolean; /** Enable colorama effect (default: true) */ enableColorama?: boolean; /** Enable bloom effect (default: true) */ enableBloom?: boolean; /** Enable light sweep effect (default: true) */ enableLightSweep?: boolean; /** Toggle center element (default: true) */ enableCenterElement?: boolean; // --- Zoom & Pan --- /** Zoom level — 1.0 = normal, 2.0 = 2x zoom (default: 1.0) */ zoom?: number; /** Horizontal pan offset -1 to 1 (default: 0.0) */ panX?: number; /** Vertical pan offset -1 to 1 (default: 0.0) */ panY?: number; /** Per-side edge feathering [top, right, bottom, left] (default: [0,0,0,0]) */ edgeFeather?: [number, number, number, number]; // --- Colorama --- /** Input range min (default: 0.0) */ inputMin?: number; /** Input range max (default: 1.0) */ inputMax?: number; /** Gamma curve: <1 = brights, >1 = darks (default: 1.05) */ modifyGamma?: number; /** 0 = off, >0 = number of discrete posterization steps (default: 0.0) */ posterizeLevels?: number; /** Stretch/compress the gradient index (default: 1.0) */ cycleRepetitions?: number; /** Static phase offset (default: 0.0) */ phaseShift?: number; /** Cycling animation speed (default: 0.0) */ cycleSpeed?: number; /** false = clamp, true = wrap/fract (default: false) */ wrapMode?: boolean; /** false = normal, true = reverse gradient (default: true) */ reverse?: boolean; /** 0 = full effect, 1 = original (default: 0.0) */ blendWithOriginal?: number; /** Cross-fade between gradientMapSrc and gradientMap2Src (default: 0.0) */ gradientMapBlend?: number; /** Duration of gradientMapBlend transition in seconds (default: 0.6) */ gradientMapBlendDuration?: number; // --- Displacement --- /** Number of glass slits (default: 45.0) */ numSegments?: number; /** Angle of slits in radians (default: 0.15) */ slitAngle?: number; /** X displacement in pixels (default: -12.0) */ displacementX?: number; /** Y displacement in pixels (default: -20.0) */ displacementY?: number; // --- Color Correction --- /** Levels black point (default: 0.0) */ ccBlackPoint?: number; /** Levels white point (default: 0.9) */ ccWhitePoint?: number; /** Midtone gamma (default: 1.2) */ ccMidtoneGamma?: number; /** Output gamma (default: 1.2) */ ccGamma?: number; /** Contrast boost (default: 0.0) */ ccContrast?: number; // --- Light Effect --- /** Strength of light sweep effect (default: 0.2) */ lightIntensity?: number; /** Frame when light effect starts (default: 140) */ lightStartFrame?: number; // --- Center Element --- /** Duration of center element animation cycle in seconds (default: 6.0) */ centerAnimDuration?: number; // --- Canvas --- /** Target aspect ratio width/height for cover behavior (default: 3/2) */ aspectRatio?: number; // --- Background --- /** Background color RGB [0-1, 0-1, 0-1] to blend bright areas with */ backgroundColor?: [number, number, number]; // --- Cycle Animation --- /** Whether to animate cycle repetitions (default: true) */ animateCycleReps?: boolean; /** Starting value for cycle repetitions animation (default: 1.0) */ cycleRepetitionsStart?: number; /** Ending value for cycle repetitions animation (default: 1.15) */ cycleRepetitionsEnd?: number; /** Frame when cycle repetitions animation starts (default: 0) */ cycleRepetitionsStartFrame?: number; /** Duration of cycle repetitions animation in frames (default: 140) */ cycleRepetitionsDuration?: number; // --- Callbacks --- /** Called when assets are loaded */ onLoad?: () => void; /** Called on error */ onError?: (error: Error) => void; className?: string; style?: React.CSSProperties; }; ``` ## Example Here are examples demonstrating various ways to use the RazorSense component: ### Basic Usage Renders the default glass refraction animation filling its container. ```jsx import React from 'react'; import { RazorSense, Box } from '@razorpay/blade/components'; const DefaultExample = () => { return ( <Box width="100%" height="100vh"> <RazorSense width="100%" height="100%" /> </Box> ); }; export default DefaultExample; ``` ### Using Presets Presets provide ready-made configurations for common use cases. ```jsx import React from 'react'; import { RazorSense, Box } from '@razorpay/blade/components'; const PresetExamples = () => { return ( <Box display="flex" flexDirection="column" gap="spacing.6"> {/* Zoomed-in closeup — good for card/badge backgrounds */} <Box width="100%" height="400px"> <RazorSense width="100%" height="100%" preset="zoomed" /> </Box> {/* Bottom wave — decorative footer/header strip */} <Box width="100%" height="250px"> <RazorSense width="100%" height="100%" preset="bottomWave" /> </Box> {/* Ripple wave — pulsing ray animation */} <Box width="100%" height="100vh"> <RazorSense width="100%" height="100%" preset="rippleWave" /> </Box> </Box> ); }; export default PresetExamples; ``` ### Paused Video with Independent Light Animation Pauses the video at a specific frame while keeping the light sweep animating. ```jsx import React from 'react'; import { RazorSense, Box } from '@razorpay/blade/components'; const PausedExample = () => { return ( <Box width="100%" height="100vh"> <RazorSense width="100%" height="100%" paused={true} startTime={8} animateLightIndependently={true} lightStartFrame={0} /> </Box> ); }; export default PausedExample; ``` ### Success Animation with Preloading Uses `preloadRazorSenseAssets` to preload assets before mounting, combined with a success UI card and framer-motion animations. ```jsx import React, { useState, useEffect } from 'react'; import { m as motion } from 'framer-motion'; import { RazorSense, preloadRazorSenseAssets, Box, Heading, Text, Button, CheckIcon, } from '@razorpay/blade/components'; const SuccessAnimation = () => { const [isLoaded, setIsLoaded] = useState(false); const [assetsPreloaded, setAssetsPreloaded] = useState(false); useEffect(() => { preloadRazorSenseAssets('circleSlideUp') .then(() => setAssetsPreloaded(true)) .catch((error) => console.error('Failed to preload:', error)); }, []); if (!assetsPreloaded) { return <div>Loading...</div>; } return ( <Box position="relative" display="flex" alignItems="center" justifyContent="center" height="100vh" backgroundColor="surface.background.gray.intense" > {/* Background shader animation */} <motion.div initial={{ opacity: 0 }} animate={{ opacity: isLoaded ? 0 : 1 }} transition={{ delay: isLoaded ? 0.5 : 0, duration: isLoaded ? 1.5 : 0.3 }} style={{ position: 'absolute', top: '50%', left: '50%', transform: 'translate(-50%, -45%)' }} > <RazorSense width="500px" height="800px" preset="circleSlideUp" edgeFeather={[0, 0, 0.2, 0]} onLoad={() => setIsLoaded(true)} /> </motion.div> {/* Success card */} <Box position="relative" zIndex={100} padding="spacing.10" maxWidth="500px"> <Box backgroundColor="feedback.background.positive.subtle" borderRadius="max" width="80px" height="80px" display="flex" alignItems="center" justifyContent="center" > <CheckIcon size="xlarge" color="feedback.icon.positive.intense" /> </Box> <Heading size="large" textAlign="center"> You're officially in! </Heading> <Button variant="primary" size="large" isFullWidth> Get Started </Button> </Box> </Box> ); }; export default SuccessAnimation; ```