Skip to content

feat(registry): add SVG Morph component#80

Open
alejopequeno wants to merge 8 commits intomainfrom
alejo/svg-morph
Open

feat(registry): add SVG Morph component#80
alejopequeno wants to merge 8 commits intomainfrom
alejo/svg-morph

Conversation

@alejopequeno
Copy link
Copy Markdown
Contributor

@alejopequeno alejopequeno commented Feb 13, 2026

Result

New svg-morph registry component that morphs SVG path d attributes with auto-looping. Supports multiple morph slots (each cycling through its own path states), static paths for compound shapes, and a transform prop for coordinate system conversion.

  • Component: registry/joyco/blocks/svg-morph.tsx — uses flubber for path interpolation + Motion for animation
  • Demo: Animated face with morphing eyes and mouth (3 expression states)
  • Docs: Full props table, usage example, auto-looping explanation, and limitations section

Install via:

npx shadcn@latest add @joyco/svg-morph

Dependencies added automatically: flubber, motion.

Media

Screen.Recording.2026-02-12.at.11.24.49.PM.mov

Greptile Summary

This PR adds a new svg-morph registry component that smoothly morphs SVG path d attributes using flubber for interpolation and motion for animation. The implementation is split cleanly into an AutoMorphPath (self-looping) and a ControlledMorphPath (externally driven by a step prop), along with a companion useSvgMorph hook. The mid-animation interruption handling in ControlledMorphPath is a thoughtful touch. Documentation is thorough.

Two bugs were found in the component:

  • Runtime crash on out-of-bounds step: In ControlledMorphPath, if step >= paths.length, paths[step] resolves to undefined. Both the useRef initialization and the useEffect can then pass undefined into flubber.interpolate, throwing a runtime error. The useSvgMorph hook guards against this internally, but users in controlled mode who pass step directly are exposed.
  • Infinite re-render loop on empty paths: In AutoMorphPath, passing an empty paths array causes loopedPaths = [undefined]. The onComplete callback always satisfies pathIndex === loopedPaths.length - 1, so setPathIndex increments unboundedly, freezing the UI. A simple if (paths.length === 0) return null guard resolves this.

Confidence Score: 3/5

  • Safe to merge after addressing the two runtime crash/infinite-loop edge cases in the main component.
  • The happy path (valid paths arrays, clamped step values) works correctly and the implementation is well-structured. However, two bugs can cause hard crashes or infinite re-renders under common misuse conditions: passing an out-of-bounds step to ControlledMorphPath throws immediately via flubber, and passing an empty paths array to AutoMorphPath produces an unbounded re-render loop. Both are straightforward to fix with short guard clauses.
  • Pay close attention to registry/joyco/blocks/svg-morph.tsx — specifically the AutoMorphPath empty-array edge case (line 31) and the ControlledMorphPath out-of-bounds step handling (lines 70 and 79).

Important Files Changed

Filename Overview
registry/joyco/blocks/svg-morph.tsx Main SVG morph component with AutoMorphPath and ControlledMorphPath sub-components. Has a potential runtime crash when step is out of bounds and when paths is an empty array.
hooks/use-svg-morph.ts Well-implemented hook for controlled mode; correctly clamps step values within valid range using useCallback and useState.
demos/svg-morph-demo.tsx Clean auto-looping demo with a face expression animation using three morph slots.
demos/svg-morph-controlled-demo.tsx Controlled step demo with prev/next/direct navigation buttons; correctly uses useSvgMorph hook for clamped step management.
content/components/svg-morph.mdx Comprehensive docs covering props, auto-loop behavior, controlled mode, useSvgMorph API, and limitations (fill-only, no compound paths, synchronized timing).

Last reviewed commit: 3d93fba

@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented Feb 13, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
joyco-hub Ready Ready Preview, Comment Apr 21, 2026 3:17pm

Copy link
Copy Markdown
Contributor

@greptile-apps greptile-apps Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

13 files reviewed, 4 comments

Edit Code Review Agent Settings | Greptile

Comment thread registry/joyco/blocks/svg-morph.tsx Outdated
Comment thread registry/joyco/blocks/svg-morph.tsx Outdated
Import useMemo and cache loopedPaths and indices to avoid recreating
arrays on every render. Update the effect to depend on the memoized
loopedPaths so animations update reliably when paths change.
Implement a step prop that switches the component to controlled
mode and animates directly to the target step (preserving mid-
animation state). Add a useSvgMorph hook to manage step state
(setStep/next/prev/isFirst/isLast), include a controlled demo, and
update docs and registry metadata to advertise the new mode and hook.
@matiasperz
Copy link
Copy Markdown
Contributor

@greptileai

Copy link
Copy Markdown
Contributor

@matiasperz matiasperz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this api should be controlled by default instead of including code on it's core to auto-reproduce.

Comment thread registry/joyco/blocks/svg-morph.tsx Outdated
Comment thread registry/joyco/blocks/svg-morph.tsx Outdated
Remove auto-loop logic from the core component and hook. SvgMorph now
only responds to step changes; users compose auto-play in userland.
Adds guards for empty paths and out-of-bounds step.
…alejo/svg-morph

# Conflicts:
#	pnpm-lock.yaml
#	public/r/registry.json
#	registry.json
#	registry/components/games/svg-morph.tsx
The merge commit accidentally shipped main's lockfile without re-running
pnpm install. Also clean up the stale hooks/use-svg-morph.ts path.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants