From 77fe55baebee29cedab65b3798d822f5a5d9764f Mon Sep 17 00:00:00 2001 From: Harsh Yadav <127301538+iharshyadav@users.noreply.github.com> Date: Sun, 1 Mar 2026 05:32:48 +0000 Subject: [PATCH 1/3] fix(animated-beam): make default duration deterministic --- apps/www/public/llms-full.txt | 2 +- apps/www/public/r/animated-beam.json | 2 +- apps/www/registry/magicui/animated-beam.tsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/www/public/llms-full.txt b/apps/www/public/llms-full.txt index 0077fd679..63e2a9410 100644 --- a/apps/www/public/llms-full.txt +++ b/apps/www/public/llms-full.txt @@ -198,7 +198,7 @@ export const AnimatedBeam: React.FC = ({ toRef, curvature = 0, reverse = false, // Include the reverse prop - duration = Math.random() * 3 + 4, + duration = 5, delay = 0, pathColor = "gray", pathWidth = 2, diff --git a/apps/www/public/r/animated-beam.json b/apps/www/public/r/animated-beam.json index 8069ff0fb..329eb6073 100644 --- a/apps/www/public/r/animated-beam.json +++ b/apps/www/public/r/animated-beam.json @@ -10,7 +10,7 @@ "files": [ { "path": "registry/magicui/animated-beam.tsx", - "content": "\"use client\"\n\nimport { RefObject, useEffect, useId, useState } from \"react\"\nimport { motion } from \"motion/react\"\n\nimport { cn } from \"@/lib/utils\"\n\nexport interface AnimatedBeamProps {\n className?: string\n containerRef: RefObject // Container ref\n fromRef: RefObject\n toRef: RefObject\n curvature?: number\n reverse?: boolean\n pathColor?: string\n pathWidth?: number\n pathOpacity?: number\n gradientStartColor?: string\n gradientStopColor?: string\n delay?: number\n duration?: number\n startXOffset?: number\n startYOffset?: number\n endXOffset?: number\n endYOffset?: number\n}\n\nexport const AnimatedBeam: React.FC = ({\n className,\n containerRef,\n fromRef,\n toRef,\n curvature = 0,\n reverse = false, // Include the reverse prop\n duration = Math.random() * 3 + 4,\n delay = 0,\n pathColor = \"gray\",\n pathWidth = 2,\n pathOpacity = 0.2,\n gradientStartColor = \"#ffaa40\",\n gradientStopColor = \"#9c40ff\",\n startXOffset = 0,\n startYOffset = 0,\n endXOffset = 0,\n endYOffset = 0,\n}) => {\n const id = useId()\n const [pathD, setPathD] = useState(\"\")\n const [svgDimensions, setSvgDimensions] = useState({ width: 0, height: 0 })\n\n // Calculate the gradient coordinates based on the reverse prop\n const gradientCoordinates = reverse\n ? {\n x1: [\"90%\", \"-10%\"],\n x2: [\"100%\", \"0%\"],\n y1: [\"0%\", \"0%\"],\n y2: [\"0%\", \"0%\"],\n }\n : {\n x1: [\"10%\", \"110%\"],\n x2: [\"0%\", \"100%\"],\n y1: [\"0%\", \"0%\"],\n y2: [\"0%\", \"0%\"],\n }\n\n useEffect(() => {\n const updatePath = () => {\n if (containerRef.current && fromRef.current && toRef.current) {\n const containerRect = containerRef.current.getBoundingClientRect()\n const rectA = fromRef.current.getBoundingClientRect()\n const rectB = toRef.current.getBoundingClientRect()\n\n const svgWidth = containerRect.width\n const svgHeight = containerRect.height\n setSvgDimensions({ width: svgWidth, height: svgHeight })\n\n const startX =\n rectA.left - containerRect.left + rectA.width / 2 + startXOffset\n const startY =\n rectA.top - containerRect.top + rectA.height / 2 + startYOffset\n const endX =\n rectB.left - containerRect.left + rectB.width / 2 + endXOffset\n const endY =\n rectB.top - containerRect.top + rectB.height / 2 + endYOffset\n\n const controlY = startY - curvature\n const d = `M ${startX},${startY} Q ${\n (startX + endX) / 2\n },${controlY} ${endX},${endY}`\n setPathD(d)\n }\n }\n\n // Initialize ResizeObserver\n const resizeObserver = new ResizeObserver(() => {\n updatePath()\n })\n\n // Observe the container element\n if (containerRef.current) {\n resizeObserver.observe(containerRef.current)\n }\n\n // Call the updatePath initially to set the initial path\n updatePath()\n\n // Clean up the observer on component unmount\n return () => {\n resizeObserver.disconnect()\n }\n }, [\n containerRef,\n fromRef,\n toRef,\n curvature,\n startXOffset,\n startYOffset,\n endXOffset,\n endYOffset,\n ])\n\n return (\n \n \n \n \n \n \n \n \n \n \n \n \n )\n}\n", + "content": "\"use client\"\n\nimport { RefObject, useEffect, useId, useState } from \"react\"\nimport { motion } from \"motion/react\"\n\nimport { cn } from \"@/lib/utils\"\n\nexport interface AnimatedBeamProps {\n className?: string\n containerRef: RefObject // Container ref\n fromRef: RefObject\n toRef: RefObject\n curvature?: number\n reverse?: boolean\n pathColor?: string\n pathWidth?: number\n pathOpacity?: number\n gradientStartColor?: string\n gradientStopColor?: string\n delay?: number\n duration?: number\n startXOffset?: number\n startYOffset?: number\n endXOffset?: number\n endYOffset?: number\n}\n\nexport const AnimatedBeam: React.FC = ({\n className,\n containerRef,\n fromRef,\n toRef,\n curvature = 0,\n reverse = false, // Include the reverse prop\n duration = 5,\n delay = 0,\n pathColor = \"gray\",\n pathWidth = 2,\n pathOpacity = 0.2,\n gradientStartColor = \"#ffaa40\",\n gradientStopColor = \"#9c40ff\",\n startXOffset = 0,\n startYOffset = 0,\n endXOffset = 0,\n endYOffset = 0,\n}) => {\n const id = useId()\n const [pathD, setPathD] = useState(\"\")\n const [svgDimensions, setSvgDimensions] = useState({ width: 0, height: 0 })\n\n // Calculate the gradient coordinates based on the reverse prop\n const gradientCoordinates = reverse\n ? {\n x1: [\"90%\", \"-10%\"],\n x2: [\"100%\", \"0%\"],\n y1: [\"0%\", \"0%\"],\n y2: [\"0%\", \"0%\"],\n }\n : {\n x1: [\"10%\", \"110%\"],\n x2: [\"0%\", \"100%\"],\n y1: [\"0%\", \"0%\"],\n y2: [\"0%\", \"0%\"],\n }\n\n useEffect(() => {\n const updatePath = () => {\n if (containerRef.current && fromRef.current && toRef.current) {\n const containerRect = containerRef.current.getBoundingClientRect()\n const rectA = fromRef.current.getBoundingClientRect()\n const rectB = toRef.current.getBoundingClientRect()\n\n const svgWidth = containerRect.width\n const svgHeight = containerRect.height\n setSvgDimensions({ width: svgWidth, height: svgHeight })\n\n const startX =\n rectA.left - containerRect.left + rectA.width / 2 + startXOffset\n const startY =\n rectA.top - containerRect.top + rectA.height / 2 + startYOffset\n const endX =\n rectB.left - containerRect.left + rectB.width / 2 + endXOffset\n const endY =\n rectB.top - containerRect.top + rectB.height / 2 + endYOffset\n\n const controlY = startY - curvature\n const d = `M ${startX},${startY} Q ${\n (startX + endX) / 2\n },${controlY} ${endX},${endY}`\n setPathD(d)\n }\n }\n\n // Initialize ResizeObserver\n const resizeObserver = new ResizeObserver(() => {\n updatePath()\n })\n\n // Observe the container element\n if (containerRef.current) {\n resizeObserver.observe(containerRef.current)\n }\n\n // Call the updatePath initially to set the initial path\n updatePath()\n\n // Clean up the observer on component unmount\n return () => {\n resizeObserver.disconnect()\n }\n }, [\n containerRef,\n fromRef,\n toRef,\n curvature,\n startXOffset,\n startYOffset,\n endXOffset,\n endYOffset,\n ])\n\n return (\n \n \n \n \n \n \n \n \n \n \n \n \n )\n}\n", "type": "registry:ui" } ] diff --git a/apps/www/registry/magicui/animated-beam.tsx b/apps/www/registry/magicui/animated-beam.tsx index 139380bea..1492ecfa2 100644 --- a/apps/www/registry/magicui/animated-beam.tsx +++ b/apps/www/registry/magicui/animated-beam.tsx @@ -32,7 +32,7 @@ export const AnimatedBeam: React.FC = ({ toRef, curvature = 0, reverse = false, // Include the reverse prop - duration = Math.random() * 3 + 4, + duration = 5, delay = 0, pathColor = "gray", pathWidth = 2, From 7d4986ae8d438d026f33f037a5b0309a1d3d82f4 Mon Sep 17 00:00:00 2001 From: Jinho Yeom Date: Thu, 19 Mar 2026 22:48:39 +0900 Subject: [PATCH 2/3] fix(animated-beam): expose repeat timing controls --- apps/www/content/docs/components/animated-beam.mdx | 2 ++ apps/www/public/llms-full.txt | 10 +++++++--- apps/www/public/r/animated-beam.json | 2 +- apps/www/registry/magicui/animated-beam.tsx | 10 +++++++--- 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/apps/www/content/docs/components/animated-beam.mdx b/apps/www/content/docs/components/animated-beam.mdx index 08c98483a..d7fe98603 100644 --- a/apps/www/content/docs/components/animated-beam.mdx +++ b/apps/www/content/docs/components/animated-beam.mdx @@ -83,6 +83,8 @@ import { AnimatedBeam } from "@/components/ui/animated-beam" | `reverse` | `boolean` | `false` | Whether the beam should be reversed. | | `duration` | `number` | `5` | The duration of the beam. | | `delay` | `number` | `0` | The delay of the beam. | +| `repeat` | `number` | `Infinity` | The number of times the beam animation should repeat. | +| `repeatDelay` | `number` | `0` | The delay between repeated beam animation cycles. | | `pathColor` | `string` | `gray` | The color of the beam. | | `pathWidth` | `number` | `2` | The width of the beam. | | `pathOpacity` | `number` | `0.2` | The opacity of the beam. | diff --git a/apps/www/public/llms-full.txt b/apps/www/public/llms-full.txt index 63e2a9410..fa9715cf4 100644 --- a/apps/www/public/llms-full.txt +++ b/apps/www/public/llms-full.txt @@ -166,7 +166,7 @@ Description: An animated beam of light which travels along a path. Useful for sh --- file: magicui/animated-beam.tsx --- "use client" -import { RefObject, useEffect, useId, useState } from "react" +import { useEffect, useId, useState, type RefObject } from "react" import { motion } from "motion/react" import { cn } from "@/lib/utils" @@ -185,6 +185,8 @@ export interface AnimatedBeamProps { gradientStopColor?: string delay?: number duration?: number + repeat?: number + repeatDelay?: number startXOffset?: number startYOffset?: number endXOffset?: number @@ -205,6 +207,8 @@ export const AnimatedBeam: React.FC = ({ pathOpacity = 0.2, gradientStartColor = "#ffaa40", gradientStopColor = "#9c40ff", + repeat = Infinity, + repeatDelay = 0, startXOffset = 0, startYOffset = 0, endXOffset = 0, @@ -332,8 +336,8 @@ export const AnimatedBeam: React.FC = ({ delay, duration, ease: [0.16, 1, 0.3, 1], // https://easings.net/#easeOutExpo - repeat: Infinity, - repeatDelay: 0, + repeat, + repeatDelay, }} > diff --git a/apps/www/public/r/animated-beam.json b/apps/www/public/r/animated-beam.json index 329eb6073..7eb6e2cf2 100644 --- a/apps/www/public/r/animated-beam.json +++ b/apps/www/public/r/animated-beam.json @@ -10,7 +10,7 @@ "files": [ { "path": "registry/magicui/animated-beam.tsx", - "content": "\"use client\"\n\nimport { RefObject, useEffect, useId, useState } from \"react\"\nimport { motion } from \"motion/react\"\n\nimport { cn } from \"@/lib/utils\"\n\nexport interface AnimatedBeamProps {\n className?: string\n containerRef: RefObject // Container ref\n fromRef: RefObject\n toRef: RefObject\n curvature?: number\n reverse?: boolean\n pathColor?: string\n pathWidth?: number\n pathOpacity?: number\n gradientStartColor?: string\n gradientStopColor?: string\n delay?: number\n duration?: number\n startXOffset?: number\n startYOffset?: number\n endXOffset?: number\n endYOffset?: number\n}\n\nexport const AnimatedBeam: React.FC = ({\n className,\n containerRef,\n fromRef,\n toRef,\n curvature = 0,\n reverse = false, // Include the reverse prop\n duration = 5,\n delay = 0,\n pathColor = \"gray\",\n pathWidth = 2,\n pathOpacity = 0.2,\n gradientStartColor = \"#ffaa40\",\n gradientStopColor = \"#9c40ff\",\n startXOffset = 0,\n startYOffset = 0,\n endXOffset = 0,\n endYOffset = 0,\n}) => {\n const id = useId()\n const [pathD, setPathD] = useState(\"\")\n const [svgDimensions, setSvgDimensions] = useState({ width: 0, height: 0 })\n\n // Calculate the gradient coordinates based on the reverse prop\n const gradientCoordinates = reverse\n ? {\n x1: [\"90%\", \"-10%\"],\n x2: [\"100%\", \"0%\"],\n y1: [\"0%\", \"0%\"],\n y2: [\"0%\", \"0%\"],\n }\n : {\n x1: [\"10%\", \"110%\"],\n x2: [\"0%\", \"100%\"],\n y1: [\"0%\", \"0%\"],\n y2: [\"0%\", \"0%\"],\n }\n\n useEffect(() => {\n const updatePath = () => {\n if (containerRef.current && fromRef.current && toRef.current) {\n const containerRect = containerRef.current.getBoundingClientRect()\n const rectA = fromRef.current.getBoundingClientRect()\n const rectB = toRef.current.getBoundingClientRect()\n\n const svgWidth = containerRect.width\n const svgHeight = containerRect.height\n setSvgDimensions({ width: svgWidth, height: svgHeight })\n\n const startX =\n rectA.left - containerRect.left + rectA.width / 2 + startXOffset\n const startY =\n rectA.top - containerRect.top + rectA.height / 2 + startYOffset\n const endX =\n rectB.left - containerRect.left + rectB.width / 2 + endXOffset\n const endY =\n rectB.top - containerRect.top + rectB.height / 2 + endYOffset\n\n const controlY = startY - curvature\n const d = `M ${startX},${startY} Q ${\n (startX + endX) / 2\n },${controlY} ${endX},${endY}`\n setPathD(d)\n }\n }\n\n // Initialize ResizeObserver\n const resizeObserver = new ResizeObserver(() => {\n updatePath()\n })\n\n // Observe the container element\n if (containerRef.current) {\n resizeObserver.observe(containerRef.current)\n }\n\n // Call the updatePath initially to set the initial path\n updatePath()\n\n // Clean up the observer on component unmount\n return () => {\n resizeObserver.disconnect()\n }\n }, [\n containerRef,\n fromRef,\n toRef,\n curvature,\n startXOffset,\n startYOffset,\n endXOffset,\n endYOffset,\n ])\n\n return (\n \n \n \n \n \n \n \n \n \n \n \n \n )\n}\n", + "content": "\"use client\"\n\nimport { useEffect, useId, useState, type RefObject } from \"react\"\nimport { motion } from \"motion/react\"\n\nimport { cn } from \"@/lib/utils\"\n\nexport interface AnimatedBeamProps {\n className?: string\n containerRef: RefObject // Container ref\n fromRef: RefObject\n toRef: RefObject\n curvature?: number\n reverse?: boolean\n pathColor?: string\n pathWidth?: number\n pathOpacity?: number\n gradientStartColor?: string\n gradientStopColor?: string\n delay?: number\n duration?: number\n repeat?: number\n repeatDelay?: number\n startXOffset?: number\n startYOffset?: number\n endXOffset?: number\n endYOffset?: number\n}\n\nexport const AnimatedBeam: React.FC = ({\n className,\n containerRef,\n fromRef,\n toRef,\n curvature = 0,\n reverse = false, // Include the reverse prop\n duration = 5,\n delay = 0,\n pathColor = \"gray\",\n pathWidth = 2,\n pathOpacity = 0.2,\n gradientStartColor = \"#ffaa40\",\n gradientStopColor = \"#9c40ff\",\n repeat = Infinity,\n repeatDelay = 0,\n startXOffset = 0,\n startYOffset = 0,\n endXOffset = 0,\n endYOffset = 0,\n}) => {\n const id = useId()\n const [pathD, setPathD] = useState(\"\")\n const [svgDimensions, setSvgDimensions] = useState({ width: 0, height: 0 })\n\n // Calculate the gradient coordinates based on the reverse prop\n const gradientCoordinates = reverse\n ? {\n x1: [\"90%\", \"-10%\"],\n x2: [\"100%\", \"0%\"],\n y1: [\"0%\", \"0%\"],\n y2: [\"0%\", \"0%\"],\n }\n : {\n x1: [\"10%\", \"110%\"],\n x2: [\"0%\", \"100%\"],\n y1: [\"0%\", \"0%\"],\n y2: [\"0%\", \"0%\"],\n }\n\n useEffect(() => {\n const updatePath = () => {\n if (containerRef.current && fromRef.current && toRef.current) {\n const containerRect = containerRef.current.getBoundingClientRect()\n const rectA = fromRef.current.getBoundingClientRect()\n const rectB = toRef.current.getBoundingClientRect()\n\n const svgWidth = containerRect.width\n const svgHeight = containerRect.height\n setSvgDimensions({ width: svgWidth, height: svgHeight })\n\n const startX =\n rectA.left - containerRect.left + rectA.width / 2 + startXOffset\n const startY =\n rectA.top - containerRect.top + rectA.height / 2 + startYOffset\n const endX =\n rectB.left - containerRect.left + rectB.width / 2 + endXOffset\n const endY =\n rectB.top - containerRect.top + rectB.height / 2 + endYOffset\n\n const controlY = startY - curvature\n const d = `M ${startX},${startY} Q ${\n (startX + endX) / 2\n },${controlY} ${endX},${endY}`\n setPathD(d)\n }\n }\n\n // Initialize ResizeObserver\n const resizeObserver = new ResizeObserver(() => {\n updatePath()\n })\n\n // Observe the container element\n if (containerRef.current) {\n resizeObserver.observe(containerRef.current)\n }\n\n // Call the updatePath initially to set the initial path\n updatePath()\n\n // Clean up the observer on component unmount\n return () => {\n resizeObserver.disconnect()\n }\n }, [\n containerRef,\n fromRef,\n toRef,\n curvature,\n startXOffset,\n startYOffset,\n endXOffset,\n endYOffset,\n ])\n\n return (\n \n \n \n \n \n \n \n \n \n \n \n \n )\n}\n", "type": "registry:ui" } ] diff --git a/apps/www/registry/magicui/animated-beam.tsx b/apps/www/registry/magicui/animated-beam.tsx index 1492ecfa2..3b2e9cb53 100644 --- a/apps/www/registry/magicui/animated-beam.tsx +++ b/apps/www/registry/magicui/animated-beam.tsx @@ -1,6 +1,6 @@ "use client" -import { RefObject, useEffect, useId, useState } from "react" +import { useEffect, useId, useState, type RefObject } from "react" import { motion } from "motion/react" import { cn } from "@/lib/utils" @@ -19,6 +19,8 @@ export interface AnimatedBeamProps { gradientStopColor?: string delay?: number duration?: number + repeat?: number + repeatDelay?: number startXOffset?: number startYOffset?: number endXOffset?: number @@ -39,6 +41,8 @@ export const AnimatedBeam: React.FC = ({ pathOpacity = 0.2, gradientStartColor = "#ffaa40", gradientStopColor = "#9c40ff", + repeat = Infinity, + repeatDelay = 0, startXOffset = 0, startYOffset = 0, endXOffset = 0, @@ -166,8 +170,8 @@ export const AnimatedBeam: React.FC = ({ delay, duration, ease: [0.16, 1, 0.3, 1], // https://easings.net/#easeOutExpo - repeat: Infinity, - repeatDelay: 0, + repeat, + repeatDelay, }} > From 50de62520ba2e8e636d27f6410a7dfcdd1c0adfc Mon Sep 17 00:00:00 2001 From: Jinho Yeom Date: Thu, 19 Mar 2026 22:56:20 +0900 Subject: [PATCH 3/3] chore(animated-beam): format docs table for prettier compliance --- .../content/docs/components/animated-beam.mdx | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/apps/www/content/docs/components/animated-beam.mdx b/apps/www/content/docs/components/animated-beam.mdx index d7fe98603..dfe0fa792 100644 --- a/apps/www/content/docs/components/animated-beam.mdx +++ b/apps/www/content/docs/components/animated-beam.mdx @@ -73,27 +73,27 @@ import { AnimatedBeam } from "@/components/ui/animated-beam" ### Animated Beam -| Prop | Type | Default | Description | -| -------------------- | --------- | --------- | -------------------------------------------------------- | -| `className` | `string` | `-` | The class name for the component. | -| `containerRef` | `ref` | `-` | The container ref. | -| `fromRef` | `ref` | `-` | The ref of the element from which the beam should start. | -| `toRef` | `ref` | `-` | The ref of the element to which the beam should end. | -| `curvature` | `number` | `0` | The curvature of the beam. | -| `reverse` | `boolean` | `false` | Whether the beam should be reversed. | -| `duration` | `number` | `5` | The duration of the beam. | -| `delay` | `number` | `0` | The delay of the beam. | -| `repeat` | `number` | `Infinity` | The number of times the beam animation should repeat. | -| `repeatDelay` | `number` | `0` | The delay between repeated beam animation cycles. | -| `pathColor` | `string` | `gray` | The color of the beam. | -| `pathWidth` | `number` | `2` | The width of the beam. | -| `pathOpacity` | `number` | `0.2` | The opacity of the beam. | -| `gradientStartColor` | `string` | `#ffaa40` | The start color of the gradient. | -| `gradientStopColor` | `string` | `#9c40ff` | The stop color of the gradient. | -| `startXOffset` | `number` | `0` | The start x offset of the beam. | -| `startYOffset` | `number` | `0` | The start y offset of the beam. | -| `endXOffset` | `number` | `0` | The end x offset of the beam. | -| `endYOffset` | `number` | `0` | The end y offset of the beam. | +| Prop | Type | Default | Description | +| -------------------- | --------- | ---------- | -------------------------------------------------------- | +| `className` | `string` | `-` | The class name for the component. | +| `containerRef` | `ref` | `-` | The container ref. | +| `fromRef` | `ref` | `-` | The ref of the element from which the beam should start. | +| `toRef` | `ref` | `-` | The ref of the element to which the beam should end. | +| `curvature` | `number` | `0` | The curvature of the beam. | +| `reverse` | `boolean` | `false` | Whether the beam should be reversed. | +| `duration` | `number` | `5` | The duration of the beam. | +| `delay` | `number` | `0` | The delay of the beam. | +| `repeat` | `number` | `Infinity` | The number of times the beam animation should repeat. | +| `repeatDelay` | `number` | `0` | The delay between repeated beam animation cycles. | +| `pathColor` | `string` | `gray` | The color of the beam. | +| `pathWidth` | `number` | `2` | The width of the beam. | +| `pathOpacity` | `number` | `0.2` | The opacity of the beam. | +| `gradientStartColor` | `string` | `#ffaa40` | The start color of the gradient. | +| `gradientStopColor` | `string` | `#9c40ff` | The stop color of the gradient. | +| `startXOffset` | `number` | `0` | The start x offset of the beam. | +| `startYOffset` | `number` | `0` | The start y offset of the beam. | +| `endXOffset` | `number` | `0` | The end x offset of the beam. | +| `endYOffset` | `number` | `0` | The end y offset of the beam. | ## Credits