parti-morph
v0.1.0
Published
React DOM snapshot particle morph transitions.
Maintainers
Readme
Parti Morph
parti-morph is a React package for DOM-captured particle page transitions. It captures a source element with html2canvas, maps the captured pixels into a Three.js particle field, and morphs those particles toward one or more target elements on the next page.
Install
npm install parti-morphPeer dependencies:
npm install react react-domBasic Usage
Define the DOM elements that Parti Morph should capture. Selectors are owned by your app, not the package.
import {
PageParticleMorph,
capturePageParticleSnapshot,
usePageParticleTransition,
type PageParticleTransitionConfig,
} from 'parti-morph'
const particleConfig = {
pageRoot: '#root',
source: {
element: '[data-parti-source]',
mode: 'solid',
},
targets: [
{
element: '[data-parti-dashboard]',
mode: 'solid',
},
{
element: '[data-parti-nav]',
mode: 'difference',
},
],
} satisfies PageParticleTransitionConfigCapture the source before switching pages:
const [isDashboard, setIsDashboard] = useState(false)
const transition = usePageParticleTransition({
active: isDashboard,
particlesEnabled: true,
setActive: setIsDashboard,
})
async function enterDashboard() {
const snapshot = await capturePageParticleSnapshot(particleConfig)
transition.handleEnter(snapshot)
}Render the overlay while the transition is active:
{isDashboard && transition.pagePhase === 'entered' ? (
<PageParticleMorph
config={particleConfig}
phase="enter"
snapshot={transition.pageParticleSnapshot}
/>
) : null}
{transition.leaveMorphVisible ? (
<PageParticleMorph
config={particleConfig}
holdMs={transition.leaveMorphHoldMs}
phase="leave"
snapshot={transition.pageParticleSnapshot}
/>
) : null}API
PageParticleTransitionConfig
type PageParticleTransitionConfig = {
overlayIgnoreClassName?: string
pageRoot?: HTMLElement | string | (() => HTMLElement | null)
source: {
element: HTMLElement | string | (() => HTMLElement | null)
mode?: 'solid' | 'difference'
}
sourceFallbackRect?: RectSpec | ((viewport: { height: number; width: number }) => RectSpec)
targets?: Array<{
element: HTMLElement | string | (() => HTMLElement | null)
mode?: 'solid' | 'difference'
}>
}sourceis the element captured before the route/page changes.targetsare captured after the destination page is mounted.mode: 'solid'keeps visible pixels from the captured element.mode: 'difference'ignores pixels close to the element/page background, useful for headers or transparent panels.pageRoothelps Parti Morph infer the page background color.sourceFallbackRectis used if the source element is unavailable during a leave transition.overlayIgnoreClassNamedefaults toparti-morph-overlay.
capturePageParticleSnapshot(config)
Captures config.source and returns a PageParticleSnapshot | null.
captureTargetParticleSnapshots(config)
Captures config.targets and returns PageParticleCapture[].
PageParticleMorph
<PageParticleMorph
config={particleConfig}
phase="enter" // or "leave"
snapshot={snapshot}
holdMs={340}
/>usePageParticleTransition
A small state helper for active/inactive page transitions:
const transition = usePageParticleTransition({
active,
particlesEnabled: true,
setActive,
persistActiveStateKey: 'optional.localStorage.key',
})It returns:
pagePhase:'idle' | 'entering' | 'leaving' | 'entered'pageParticleSnapshothandleEnter(snapshot?)handleLeave()leaveMorphVisibleleaveMorphHoldMs
Demo
A minimal login-to-dashboard demo lives in demo/.
npm run demoOr run it manually:
cd demo
npm install
npm run devOpen the printed local URL, sign in, then sign out to see both enter and leave particle morphs.
Package Structure
src/contains the TypeScript source.dist/contains the published JavaScript and declaration output.demo/contains a standalone Vite demo app.npm run buildgeneratesdist/.npm publishruns the build automatically throughprepublishOnly.
