These 48 bugs were found by reading registry source (fetched 2026-09-16) and in shipped apps. They are grouped by pattern: when you audit any registry component, scan for each pattern's signature, not just for the named components. Lint ids are void lint rules that catch the pattern statically.
Format: Library / component: the bug → the impact. The fix pattern closes each group.
1. Dead on Tailwind v4 (silent: no error, the effect never shows)
Signature: animate- classes with no css/cssVars in the registry item; keyframes in tailwind.config.* or in comments; v3 utility names; undefined theme classes.
- Aceternity
spotlight:animate-spotlightships with no CSS, and the base class isopacity-0→ invisible forever. - Aceternity
meteors,moving-border(and other customanimate-*items): no CSS in the registry item → no animation. - React Bits
StarBorder: keyframes exist only as a commentedtailwind.config.jsblock → static. - Registries generally:
bg-gradient-to-*,flex-shrink-0, bareshadow/rounded,outline-none, config keyframes → gradients missing, sizes one step off. - Cult
direction-aware-tabs: undefinedshadow-inner-shadow→ silent style loss. - kibo
gantt: undefined--color-backdrop→ silent style loss. - ReUI
frame: served JSON lost variant prefixes → dead variants.
Fix pattern: put @keyframes + a class in @layer components, or --animate-x + @keyframes in @theme. Rename v3 utilities (bg-linear-to-*, shrink-0, shadow-xs, outline-hidden). Run next build and confirm the class exists in the compiled CSS. Lint: lint/tw-unknown-class, lint/tw-js-config-ignored, lint/tw-v3-renamed, lint/tw-v3-arbitrary-var.
2. Hidden or placeholder server HTML (SEO, no-JS, LCP)
Signature: opacity-0, initial={{ opacity: 0 }} or initial="hidden" on text; a number component rendering 0/""/startValue; GSAP set after hydration.
- Magic UI
number-ticker: SSR rendersstartValue(0), and a width change from0to12,400causes CLS → crawlers and link previews see 0. - React Bits
CountUp: SSR renders an empty→ no number without JS. - Aceternity
text-generate-effect: every word SSRs atopacity-0+blur(10px)→ invisible without JS; LCP delayed to the end of a 0.2s × N stagger. - Magic UI
text-animate:initial="hidden"→ text at opacity 0 before hydration. - React Bits
SplitText: full text on the server, then GSAP setsopacity:0; y:40afterfonts.ready→ flash, hide, reveal; LCP moves. - React Bits
SplitText:willChange: "transform, opacity"left on the parent after completion; pulls gsap + ScrollTrigger + SplitText (~45–70 KB) for one headline → a permanent layer; weight. Lint:lint/will-change-static.
Fix pattern: SSR the final value and visible text. Animate position, not visibility, on LCP text (RevealText). Numbers animate only if they start offscreen (NumberTicker, or @number-flow/react).
3. SSR crashes and hydration mismatches
Signature: window/document/navigator/matchMedia/localStorage at module scope or in render; Math.random()/Date.now() in render; createPortal(document.body) in render.
- Skiper106:
navigator.userAgentat module scope → SSR crash. - Aceternity
background-beams:Math.random()in render for duration, delay andy2→ hydration mismatch, and values re-randomise each render. - Aceternity (26 of 118 free items):
Math.random()in render → hydration risk. - Magic UI
globe:setTimeout(() => style.opacity = "1", 0)→ a hydration-timing hack. - React Bits (all 171 files): no
'use client'→ RSC import errors.
Fix pattern: browser globals only inside effects or useSyncExternalStore (server snapshot). Seeded or precomputed values instead of Math.random() in render. 'use client' only on the interactive leaf. Lint: lint/browser-global-in-render.
4. Leaks: subscriptions and loops without cleanup
Signature: .on('change' or addEventListener outside useEffect; requestAnimationFrame without cancelAnimationFrame; new Lenis without destroy; api.on without off; setInterval per instance.
- Skiper34, Skiper37:
scrollY.on('change')in the render body → a new listener every render. - Skiper30 (+16/17/28/31/34): the Lenis rAF loop is never cancelled and
lenis.destroy()is missing → a permanent rAF after unmount. - Skiper54:
api.on('select')is never removed → listener leak. - kibo
relative-time: asetIntervalper instance, never paused → N timers.
Fix pattern: useMotionValueEvent or an effect with an unsubscribe. Match every add, observe, rAF, interval or create with its remove, disconnect, cancel, clear or destroy. One shared ticker for lists. No Lenis. Lint: lint/motionvalue-subscribe-in-render, lint/raf-without-cancel, lint/listener-without-cleanup, lint/timer-in-render.
5. Hooks misuse
Signature: use[A-Z]…( inside &&, ternaries, JSX or style={{}}; m.create() or component definitions in render; ref.current in deps; props already read from refs listed in effect deps.
- Magic UI
magic-card:useMotionTemplateinside{mode === "gradient" && …}→ React throws whenmodechanges. - Skiper19:
useTransforminside astyle={{}}literal → rules-of-hooks violation. - tailark
animated-group:m.create()in render → remount and replay every render. - Aceternity
text-generate-effect:[scope.current]as an effect dep → a stale or ineffective effect. - React Bits
Aurora: deps[amplitude]although the value is read from a ref → destroys and rebuilds the WebGL context on prop change. - Magic UI
globe:configobject in effect deps → inlineconfig={{…}}recreates the globe every render. - Cult
direction-aware-tabs: hardcodedlayoutId="bubble"→ two instances fight.
Fix pattern: hooks at the top level; useMemo for created components; useId()-scoped layoutId; stable primitives in deps; update uniforms instead of rebuilding.
6. Per-frame React work and allocation
Signature: setState inside mousemove/pointermove/scroll/rAF/useAnimationFrame; new Intl.NumberFormat, new Color or getBoundingClientRect inside loops; window listeners per instance.
- React Bits
Magnet: a windowmousemoveper instance +getBoundingClientRect+setStateon every move → N listeners, layout reads and re-renders per event. - React Bits
SpotlightCard:setStateper move and a repainted full-cardradial-gradient→ re-renders children every frame. - Magic UI
number-ticker, React BitsCountUp: a newIntl.NumberFormatper frame, locale hardcoded toen-US→ GC churn; wrong locale. - React Bits
Aurora:new Color()×3 per frame → ~420 allocations/s. - Aceternity
dotted-glow-background:getBoundingClientRectinside draw +shadowBlurper dot → forced layout at 60fps. - ReUI
scrollspy: capture-phase scroll + a forced layout loop; itsthrottleTimeprop is unused → scroll jank. - Magic UI
number-ticker:useSpringwith damping 60 → slow settle (the top idle cost in a shipped app).
Fix pattern: refs + one rAF writing el.style.translate (SpotlightCard, Magnetic); measure once on enter or in a ResizeObserver; hoist formatters; IntersectionObserver instead of scroll listeners; near-critical springs.
7. Never stops: offscreen spin and no visibility pause
Signature: repeat: Infinity, infinite, useAnimationFrame or a rAF loop with no IntersectionObserver, useInView or data-fx; WebGL libraries' internal loops.
- Magic UI
border-beam: motion animatesoffset-distanceon the main thread forever → idle CPU. - motion-primitives
border-trail, tailarkinfinite-slider:repeat: Infinity, never paused → idle main thread. - React Bits
ShinyText: a perpetualuseAnimationFramewritingbackground-position(still ticking whendisabled) → a paint every frame per instance. - Magic UI
globe: cobe's rAF runs until unmount; no IntersectionObserver or visibility pause → GPU burn. - Magic UI
animated-beam:repeat = InfinityJS gradient animation → a repaint every frame. - Magic UI
animated-beam: its ResizeObserver watches only the container; endpoints that move (font swap, image load, accordion) leave the beam pointing at stale coordinates. - React Bits backgrounds: 35/56 have no offscreen pause, 53/56 no reduced motion, 23/56 no DPR cap → GPU burn; WCAG 2.3.3.
- Aceternity
spotlight-new: infinite motion +z-40→ covers content and never rests.
Fix pattern: CSS animation + data-fx + FxGate (recipes §0). JS loops cancel (not skip) on IntersectionObserver and visibilitychange. Lint: smooth/raf-loop-idle.
8. Paint-bound or layout-bound animation
Signature: animating background, background-position, filter, box-shadow, SVG gradient attributes, width/height/top/left; many stacked backdrop-filters; mask-image over animated children.
- RareUI
HookSidebar: springstop/height→ layout every frame. - Magic UI
animated-beam: animatesx1/x2/y1/y2of alinearGradient→ path repaint per frame. - Aceternity
background-beams: 50 SVG paths × animated gradients, no IntersectionObserver or RM → CPU raster. - Magic UI
magic-card(orb mode):filter: blur(60px)on a 420px element moving with the pointer → a huge blurred layer per frame. - Aceternity
text-generate-effect:filter: bluranimated per word → rasterisation per word per frame. - tailark
progressive-blur: 8 stackedbackdrop-filterlayers → 8–15ms per frame. - kibo
gantt: 5×backdrop-bluron sticky elements → scroll jank. - void measurement (recipes §8–9): a
mask-imagefade over animated blobs → 10% dropped frames; a paint animation over an animated backdrop without its own layer → 14–46%.
Fix pattern: move pre-rasterised layers with translate/rotate (BeamBorder, AuroraBackdrop, SpotlightCard); one blur + one mask; a static overlay instead of a mask over animation; will-change: transform on a single small paint-animated element. Lint: lint/animate-layout-prop, lint/transition-all, smooth/animate-layout-property.
9. DOM and node explosions
Signature: Array(n).fill().map of animated nodes; per-character motion spans; SVG grids.
- Magic UI
dot-pattern(glow): ~5,130s, each with an infinite spring → DOM and animation explosion. - Magic UI
animated-grid-pattern: the same node explosion. - motion-primitives
text-effect: per-character motion nodes by default → ~60 nodes per headline.
Fix pattern: CSS gradients (PatternBackdrop); per="word" or CSS per-word (RevealText).
10. WebGL, canvas and expensive dependencies
Signature: a getContext('webgl')//createGlobe per instance or in .map(); DPR 2 hardcoded; three/R3F for a 2D quad; heavy or stale dependencies.
- RareUI
FluidOrb: one WebGL context per instance, uncapped rAF, DPR 2 → the 9th context evicts the 1st in lists. - React Bits
Silk: three + R3F (~150 KB) for one quad,frameloop="always"→ the worst cost/benefit. - React Bits
GridScan: importsface-api.js(~700 KB + weights) → a bundle bomb. - Aceternity
globe/3d-globe/canvas-reveal-effect/vortex: three-globe or R3F, one context each → 600 KB+. - Magic UI
globe: pinscobe@^0.6.4(current 2.0.1);devicePixelRatio: 2andwidth * 2hardcoded;mapSamples: 16000→ a stale major; 4× pixels on DPR-1 screens. - Magic UI
globe: drag usesonPointerOutwith nosetPointerCapture→ the drag drops at the canvas edge. - Animate UI (17 items): depends on
@base-ui-components/react(renamed to@base-ui/react) → a duplicate, older Base UI. - shadcnblocks:
import { cn } from "cn"+ a"cn"dependency → phantom dependency. - ReUI
tree/rating: site-internal@/app/(create)/…imports → build break.
Fix pattern: ≤1 context per page, never in lists (static seeded frame for many instances); DPR ≤1.5; ≤30fps; ogl or raw WebGL2 per speed → references/rendering-smoothness.md §8; cobe 2.x for globes; diff registry dependencies against package.json. Lint: lint/webgl-in-map, lint/heavy-import, smooth/multiple-webgl-contexts.
11. Accessibility
Signature: duplicated content without Fix pattern: duplicates get Signature: hex/rgb/hsl literals, Fix pattern: the token mapping table in SKILL.md; one hue via Sources: registry JSON under aria-hidden/inert; aria-label on generic elements; clickable / without type; hover-only behaviour; decorative SVG without aria-hidden; global SVG ids.
marquee: 3 duplicate copies without aria-hidden/inert; hover-only pause → links read and tabbed 4×; WCAG 2.2.2.TextRoll: two copies of every letter with no aria-hidden → "H o m e H o m e".TextRoll: nav items with href data render with no → not focusable, not crawlable.TextRoll: hover-only, ease: "easeInOut" on enter, key={index}, framer-motion import → no focus parity.text-animate: aria-label on a generic div/p + sr-only duplicate + aria-hidden segments → double announcement; label ignored.StarBorder: as defaults to 'button' with no type → submits enclosing forms.animated-beam: decorative SVG without aria-hidden → noise for screen readers.spotlight: hardcoded id="filter" + a 151px feGaussianBlur + z-[1] over content → cross-instance filter collisions; expensive raster.tree: zero ARIA while the docs claim keyboard support → inaccessible.HookSidebar: exact href === pathname → nested routes highlight nothing.Skiper102 → name collision.aria-hidden="true" inert; decorative layers get aria-hidden; real /; :focus-visible/:focus-within parity; a pause control for >5s motion; useId() for SVG ids; @headless-tree/react for trees; longest-prefix route matching. Lint: lint/div-button.12. Off-token styling (every library)
neutral-*/zinc-*/purple-* classes, dark:text-white text-black, purple→pink gradient pairs, next-themes just to pick a blend mode.
border-beam: #ffaa40 → #9c40ff → off-brand; design/purple-gradient.magic-card: #9E7AFF → #FE8BBB, #ee4f27 → #6b21ef; next-themes dependency → second accent; extra dependency.background-beams: #18CCFC → #6344F5 → #AE48FF → the purple→pink trope.SpotlightCard, StarBorder: neutral-800/900, #000/#fff/#222 → breaks light mode and directions.--brand + color-mix(in oklab, …). Lint: lint/hardcoded-colors, design/multiple-accents, design/gradient-text.
magicui.design/r, reactbits.dev/r, ui.aceternity.com/registry, skiper-ui.com/registry, coss.com/ui/r, animate-ui.com/r; repos listed in catalogue.md; owner research ~/code/sandbox/void/ui/v3/component-libs.md §3 and local-digest.md §4.