@neveranyart/weaver 1.0.3 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # Weaver
2
2
 
3
+ (WIP DOCS
4
+
3
5
  ## What is this?
4
6
  This is `@neveranyart/weaver`, an in-house package for making interactive React CSR.
5
7
 
package/dist/scene.d.mts CHANGED
@@ -21,7 +21,7 @@ import 'lenis';
21
21
  declare function BakeScene(props: {
22
22
  children?: ReactNode;
23
23
  sceneReady: boolean;
24
- tunnelIn: BasicTunnelIn;
24
+ tunnelIn?: BasicTunnelIn;
25
25
  loadTaskDelay?: number;
26
26
  setSceneReady: Dispatch<SetStateAction<boolean>>;
27
27
  onReady?: () => void;
package/dist/scene.d.ts CHANGED
@@ -21,7 +21,7 @@ import 'lenis';
21
21
  declare function BakeScene(props: {
22
22
  children?: ReactNode;
23
23
  sceneReady: boolean;
24
- tunnelIn: BasicTunnelIn;
24
+ tunnelIn?: BasicTunnelIn;
25
25
  loadTaskDelay?: number;
26
26
  setSceneReady: Dispatch<SetStateAction<boolean>>;
27
27
  onReady?: () => void;
package/dist/scene.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/scene/index.ts","../src/scene/BakeScene.tsx","../src/setup.ts","../src/scene/SceneSync.tsx","../src/hooks/effectOnce.ts","../src/hooks/lenisCallback.ts","../src/hooks/orbit.ts"],"sourcesContent":["import BakeScene from './BakeScene';\nimport SceneSync from './SceneSync';\n\nexport { BakeScene, SceneSync };\n","import { useFrame } from '@react-three/fiber';\nimport React, {\n type Dispatch,\n Fragment,\n type ReactNode,\n type SetStateAction,\n useId,\n useRef,\n} from 'react';\nimport { BasicTunnelIn, Default3DTunnelIn } from '../setup';\n\n/**\n * A core part of an in-house tool called `weaver`.\n *\n * `BakeScene`: This component will notifiy when the global 3D scene is ready.\n *\n * It works by tune in the `useFrame` from `@react-three/fiber`. When the scene is loaded, `useFreame` will fire\n * with ease, the component takes advantage of that, and because `useLoader` is unreliable.\n *\n * This component also accepts 3D elements `children` to be rendered directly to the canvas with some camera options.\n * But you don't have to put every 3D components inside the baker, for example, `SceneSync`s in the page are also\n * being watched by this component.\n *\n * The route renderer **CAN'T** detect if the page has 3D elements or not, so if a page uses any sort of 3D rendering,\n * this component **MUST** be a children iniside `Pipeline` (`index.tsx`), then pass the state value that bake changes\n * to `Pipeline`'s `contentReady` in order for the `BakeScene` to work behind loading fallback screen.\n */\nexport default function BakeScene(props: {\n children?: ReactNode;\n sceneReady: boolean;\n tunnelIn: BasicTunnelIn;\n loadTaskDelay?: number;\n setSceneReady: Dispatch<SetStateAction<boolean>>;\n onReady?: () => void;\n}) {\n const unique = useId();\n const pipeObjects = useId();\n\n const TunnelIn = props.tunnelIn ?? Default3DTunnelIn;\n\n if (!TunnelIn) {\n throw Error(\n 'Failed to find a tunnel to use. Consider setting a default tunnel.'\n );\n }\n\n return (\n <TunnelIn>\n <Fragment key={pipeObjects}>{props.children}</Fragment>\n <NotificationHandler\n key={unique}\n callback={props.onReady}\n sceneReady={props.sceneReady}\n setSceneReady={props.setSceneReady}\n />\n </TunnelIn>\n );\n}\n\nfunction NotificationHandler(props: {\n callback?: (isSceneReady: boolean) => void;\n sceneReady: boolean;\n setSceneReady: (value: boolean) => void;\n}) {\n /**\n * `useFrame` is expensive for something that only triggers once, so yea,\n * we'll remove the notification as soon as the job is done.\n */\n return !props.sceneReady && <RenderNotification {...props} />;\n}\n\nfunction RenderNotification(props: {\n callback?: (isSceneReady: boolean) => void;\n sceneReady: boolean;\n loadTaskDelay?: number;\n setSceneReady: (value: boolean) => void;\n}) {\n const scheduledForCallback = useRef(false);\n\n useFrame(() => {\n if (!props.sceneReady && !scheduledForCallback.current) {\n scheduledForCallback.current = true;\n setTimeout(() => {\n if (props.callback) {\n props.callback(true);\n }\n props.setSceneReady(true);\n }, props.loadTaskDelay ?? 50);\n }\n });\n\n return null;\n}\n","import Lenis from 'lenis';\nimport { ReactNode } from 'react';\n\nexport let lenisInstance: Lenis | undefined = undefined;\n\nexport type BasicTunnelIn = ({ children }: { children: ReactNode }) => null;\nexport let Default3DTunnelIn: BasicTunnelIn | undefined = undefined;\n\nexport const weaverSetup = {\n setLenisInstance(instance: Lenis) {\n lenisInstance = instance;\n },\n set3DTunnel(tunnelIn: BasicTunnelIn) {\n Default3DTunnelIn = tunnelIn;\n },\n};\n","import { Hud } from '@react-three/drei';\nimport { useThree, type Viewport } from '@react-three/fiber';\nimport { cancelFrame, frame } from 'motion/react';\nimport React, {\n type ReactNode,\n type RefObject,\n useCallback,\n useId,\n useLayoutEffect,\n useRef,\n useState,\n} from 'react';\nimport { Group } from 'three';\nimport { useLayoutEffectOnce } from '../hooks/effectOnce';\nimport { useLenisCallback } from '../hooks/lenisCallback';\nimport { useOrbit } from '../hooks/orbit';\nimport { BasicTunnelIn, Default3DTunnelIn, lenisInstance } from '../setup';\n\nexport type Basic3DTransforms = {\n scale: {\n set: (x: number, y: number, z: number) => void;\n };\n position: {\n x: number;\n y: number;\n };\n};\n\ninterface SyncProps {\n /**\n * HTML element ref that `<SceneSync />` will use to sync with the scene.\n *\n * ```tsx\n * <div ref={container} />\n * <SceneSync attach={container}>\n * <group />\n * </SceneSync>\n * ```\n */\n attach: RefObject<HTMLElement | null>;\n\n /**\n * This variable allows fine-grain control over your scene when passed to `<SceneSync />`.\n *\n * `<SceneSync />` will use its own ref and group when creating your scene to control its scale and position.\n * Setting this variable will disable the internal ref, and you can decide on which object gets controlled.\n *\n * This variable is needed for `hud` if you wanted to add a custom camera.\n *\n * For listening to change details, use `onLayoutChange` instead.\n */\n control?: RefObject<Basic3DTransforms | null>;\n\n /**\n * When this variable is set, `<SceneSync />` will send updates when the scene update its positions.\n *\n * The function return the calculated DOM rect, with dimension and position in 3D measurements.\n */\n onLayoutUpdate?: (\n rect: DOMRect,\n dimension: { w: number; h: number },\n position: { x: number; y: number }\n ) => void;\n\n /**\n * Use `Hud` for this scene or not.\n *\n * This is useful when you want to apply custom camera for this scene, or renders multiple scenes on each other.\n *\n * NOTE: When setting a custom camera, the `control` variable must also be set and mount to your scene, not related to the camera\n * to avoid unwanted behavior.\n *\n * `<SceneSync />` groups children passed to it by default, so the camera is also in the group, when syncer updates the group,\n * the camera is also change, ruining the effect.\n */\n hud?: boolean;\n\n /**\n * Control the scene's scaling when positioning.\n */\n scaleFactor?: number;\n\n /**\n * `<SceneSync />` avoid stretching the object by default by using the smallest dimension of the DOM element.\n *\n * This variable will tell `<SceneSync />` to stretch it anyways.\n */\n stretch?: boolean;\n\n /**\n * Disable automatic scaling on the object.\n *\n * This variable will also disable any scaling settings like `stretch` and `scaleFactor`.\n */\n disableScaling?: boolean;\n\n /**\n * `<SceneSync />` will depend on this variable to adjust how it should update.\n *\n * There are 3 modes: `relaxed`, `balanced` and `aggressive`.\n *\n * For each mode, there will be some very distinct trade-offs\n *\n * - `relaxed`: Uses IntersectionObserver paired with a scroll hook, together with ResizeObserver.\n * - (+): Minimal update calls, best performance.\n * - (-): The scene get desynced the moment DOM element moves without changing its sizes.\n * When the scene bleeds out of the DOM element too much, if IntersectionObserver reported that the DOM element\n * is out of view, the scene that did not fully moved out of view will stay there, as scroll hook will be disabled.\n * - `balanced`: Uses IntersectionObserver paired with frame-based update, together with ResizeObserver.\n * - (+): Just enough update calls to allow the DOM element to move freely while maintain aceptable performance.\n * - (-): It will update on every frame when the object gets into view as reported by IntersectionObserver. And the same\n * problem with `relaxed` mode when the scene bleeds out too much.\n * - `aggressive`: Frame-based update only. This mode is like how `<View />` from `@react-three/drei` kepts track of DOM elements.\n * - (+): Designed for precise element <-> scene updates. Can't be desynced, if desynced, that's a bug.\n * - (-): This is frame-based. It will fire updates as long as the scene is still mounted. Too many scenes with this\n * mode enabled is not a good idea. Acceptable amount would be 3 scenes with this mode.\n *\n * Best of both worlds is `balanced` mode, for simpler scenes that doesn't change its position, `relaxed` should be used.\n */\n trackingMode: 'relaxed' | 'balanced' | 'aggressive';\n\n /**\n * Set a custom tunnel for `<SceneSync />` send the components to for this scene only.\n *\n * Which is useful for example, put the objects inside a container in the scene.\n *\n * To set a default tunnel, pass it to `setDefaulTunnel` before use.\n */\n tunnelIn?: BasicTunnelIn;\n\n children: ReactNode;\n}\n\ninterface HudProps extends SyncProps {\n hud: true;\n /**\n * Set the `renderPriority` to render things for `Hud`.\n *\n * This variable is ignored when `hud` is not `true`.\n */\n hudRenderPriority: number;\n}\n\ninterface NormalProps extends SyncProps {\n hud?: false;\n}\n\n/**\n * A core part of an in-house tool called `weaver`.\n *\n * A component to allow three objects to track and sync with DOM element.\n *\n * The component uses `<Hud />` under the \"hud\", so if you want to use more than one `<SceneSync />`,\n * you must set `renderPriority`. If not, the component will render the last scene pushed through React.\n */\nexport default function SceneSync(props: NormalProps | HudProps) {\n const unique = useId();\n\n const TunnelIn = props.tunnelIn ?? Default3DTunnelIn;\n\n if (!TunnelIn) {\n throw Error(\n 'Failed to find a tunnel to use. Consider setting a default tunnel.'\n );\n }\n\n if (props.hud) {\n return (\n <TunnelIn>\n <Hud key={unique} renderPriority={props.hudRenderPriority}>\n <SyncInternal {...props} />\n </Hud>\n </TunnelIn>\n );\n }\n\n return (\n <TunnelIn>\n <SyncInternal key={unique} {...props} />\n </TunnelIn>\n );\n}\n\nfunction SyncInternal(props: SyncProps) {\n const { viewport, camera } = useThree();\n\n const defaultControl = useRef<Group>(null);\n const {\n attach,\n control,\n scaleFactor,\n stretch,\n disableScaling,\n onLayoutUpdate,\n } = props;\n\n const properties: RefObject<{\n viewport?: Omit<Viewport, 'dpr' | 'initialDpr'>;\n }> = useRef({\n viewport: undefined,\n });\n\n const updatePosition = useCallback(() => {\n const activeControl = control ?? defaultControl;\n\n const vp = properties.current.viewport;\n if (!vp) return;\n\n const domRect = attach.current!.getBoundingClientRect();\n const screenH = document.documentElement.clientHeight;\n const screenW = document.body.clientWidth;\n\n const vpWidthRatio = vp.width / screenW;\n const vpHeightRatio = vp.height / screenH;\n\n const scrollOffset = (lenisInstance!.actualScroll / screenH) * vp.height;\n\n const w = domRect.width * vpWidthRatio;\n const h = domRect.height * vpHeightRatio;\n\n const x = domRect.x * vpWidthRatio + w * 0.5 - vp.width * 0.5;\n const y =\n vp.height * 0.5 -\n (domRect.y + lenisInstance!.actualScroll) * vpHeightRatio -\n h * 0.5 +\n scrollOffset;\n\n if (onLayoutUpdate) {\n onLayoutUpdate(domRect, { w, h }, { x, y });\n }\n\n const unwrapedScaleFactor = scaleFactor ?? 1;\n\n if (!disableScaling) {\n if (!stretch) {\n const minScale = Math.min(w, h) * unwrapedScaleFactor;\n activeControl.current!.scale.set(minScale, minScale, minScale);\n } else {\n activeControl.current!.scale.set(\n w * unwrapedScaleFactor,\n h * unwrapedScaleFactor,\n Math.min(w, h) * unwrapedScaleFactor\n );\n }\n }\n\n // eslint-disable-next-line react-hooks/immutability\n activeControl.current!.position.x = x;\n activeControl.current!.position.y = y;\n }, [attach, onLayoutUpdate, control, scaleFactor, disableScaling, stretch]);\n\n /**\n * Update position when `camera` changes.\n */\n useLayoutEffect(() => {\n properties.current.viewport = viewport.getCurrentViewport(camera);\n updatePosition();\n }, [camera, updatePosition, viewport]);\n\n const graceUpdate = useCallback(() => {\n try {\n updatePosition();\n } catch {\n /* empty */\n }\n }, [updatePosition]);\n\n const mode = {\n relaxed: (\n <RelaxedUpdate attach={props.attach} updatePosition={graceUpdate} />\n ),\n balanced: (\n <BalancedUpdate attach={props.attach} updatePosition={graceUpdate} />\n ),\n aggressive: <AggressiveUpdate updatePosition={graceUpdate} />,\n };\n\n if (props.control) {\n return (\n <>\n {props.children}\n {mode[props.trackingMode]}\n </>\n );\n }\n\n return (\n <group ref={defaultControl}>\n {props.children}\n {mode[props.trackingMode]}\n </group>\n );\n}\n\nfunction RelaxedUpdate(props: {\n attach: RefObject<HTMLElement | null>;\n updatePosition: () => void;\n}) {\n const { updatePosition } = props;\n\n /**\n * Scroll hook to update object correctly to the current HTML scroll position.\n */\n useLenisCallback(updatePosition, {\n initialCall: true,\n intersectOn: props.attach,\n });\n\n /**\n * Allows the element to resize too.\n */\n useOrbit({\n target: props.attach,\n events: {\n onIntersect: updatePosition,\n onResize: updatePosition,\n },\n });\n\n useLayoutEffectOnce(updatePosition);\n return null;\n}\n\nfunction BalancedUpdate(props: {\n attach: RefObject<HTMLElement | null>;\n updatePosition: () => void;\n}) {\n const { updatePosition } = props;\n\n const [shouldUpdate, setShouldUpdate] = useState(false);\n\n useOrbit({\n target: props.attach,\n events: {\n onIntersect(entry) {\n setShouldUpdate(entry.isIntersecting);\n },\n onResize: updatePosition,\n },\n rootMargin: '50% 0px 50% 0px',\n });\n\n useLayoutEffect(() => {\n if (shouldUpdate) {\n frame.read(updatePosition, true);\n } else {\n cancelFrame(updatePosition);\n }\n\n return () => {\n cancelFrame(updatePosition);\n };\n }, [updatePosition, shouldUpdate]);\n\n useLayoutEffectOnce(updatePosition);\n return null;\n}\n\nfunction AggressiveUpdate(props: { updatePosition: () => void }) {\n const { updatePosition } = props;\n\n useLayoutEffect(() => {\n frame.read(updatePosition, true);\n\n return () => {\n cancelFrame(updatePosition);\n };\n }, [updatePosition]);\n\n return null;\n}\n","import { useEffect, useLayoutEffect } from 'react';\n\nexport function useEffectOnce(callback: React.EffectCallback) {\n // eslint-disable-next-line react-hooks/exhaustive-deps\n useEffect(callback, []);\n}\n\nexport function useLayoutEffectOnce(callback: React.EffectCallback) {\n // eslint-disable-next-line react-hooks/exhaustive-deps\n useLayoutEffect(callback, []);\n}\n","import { type RefObject, useCallback, useLayoutEffect, useMemo } from 'react';\nimport { lenisInstance } from '../setup';\nimport { useOrbit } from './orbit';\n\ninterface HookOptions {\n /**\n * Hook will report when first initialized without waiting for scroll event to actually happens.\n */\n initialCall?: boolean;\n /**\n * Set an element to only call when the element is actually entering the viewport (with 25% `rootMargin`).\n */\n intersectOn?: RefObject<HTMLOrSVGElement | null>;\n}\n\nexport const scrollCallbackReason = {\n Resize: 'resize',\n Scroll: 'scroll',\n Initialize: 'initialize',\n} as const;\nexport type ScrollCallbackReason =\n (typeof scrollCallbackReason)[keyof typeof scrollCallbackReason];\n\ntype Callback = (latest: number, reason: ScrollCallbackReason) => void;\n\nexport function useLenisCallback(callback: Callback, options?: HookOptions) {\n const callbackWrapScroll = useCallback(\n () => callback(lenisInstance!.actualScroll, scrollCallbackReason.Scroll),\n [callback]\n );\n const callbackWrapResize = useCallback(\n () => callback(lenisInstance!.actualScroll, scrollCallbackReason.Resize),\n [callback]\n );\n\n const intersectOn = useMemo(\n () => options?.intersectOn,\n [options?.intersectOn]\n );\n const initialCall = useMemo(\n () => options?.initialCall,\n [options?.initialCall]\n );\n\n useOrbit({\n target: intersectOn as RefObject<HTMLElement | null> | undefined,\n events: {\n onIntersect(entry) {\n if (entry.isIntersecting) {\n lenisInstance!.on('scroll', callbackWrapScroll);\n window.addEventListener('resize', callbackWrapResize);\n } else {\n lenisInstance!.off('scroll', callbackWrapScroll);\n window.removeEventListener('resize', callbackWrapResize);\n }\n },\n },\n rootMargin: '50% 0px 50% 0px',\n });\n\n useLayoutEffect(() => {\n if (!intersectOn) {\n lenisInstance!.on('scroll', callbackWrapScroll);\n window.addEventListener('resize', callbackWrapResize);\n }\n\n if (initialCall) {\n callback(lenisInstance!.actualScroll, scrollCallbackReason.Initialize);\n }\n\n return () => {\n lenisInstance!.off('scroll', callbackWrapScroll);\n window.removeEventListener('resize', callbackWrapResize);\n };\n }, [\n callback,\n callbackWrapResize,\n callbackWrapScroll,\n initialCall,\n intersectOn,\n ]);\n}\n","import { type RefObject, useLayoutEffect } from 'react';\n\n/**\n * A simple Orbit hook.\n *\n * @param target HTML element ref to attach to.\n * @param events Specify which events should the orbit tracks.\n */\nexport function useOrbit(options: {\n target?: RefObject<HTMLElement | null>;\n events: {\n onResize?: (entry: ResizeObserverEntry) => void;\n onIntersect?: (entry: IntersectionObserverEntry) => void;\n };\n rootMargin?: string;\n}) {\n const { onResize, onIntersect } = options.events;\n const { rootMargin = '25% 0px 25% 0px' } = options;\n\n useLayoutEffect(() => {\n if (!options.target) return;\n if (!options.target.current) return;\n\n let orbitResize = undefined;\n if (onResize) {\n orbitResize = new ResizeObserver((entries) => onResize(entries[0]));\n orbitResize.observe(options.target.current);\n }\n let orbitIntersect = undefined;\n if (onIntersect) {\n orbitIntersect = new IntersectionObserver(\n (entries) => onIntersect(entries[0]),\n { rootMargin }\n );\n orbitIntersect.observe(options.target.current);\n }\n\n return () => {\n orbitResize?.disconnect();\n orbitIntersect?.disconnect();\n };\n }, [onIntersect, onResize, rootMargin, options.target]);\n}\n"],"mappings":"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","names":["React","import_fiber","import_react","import_react","import_react","import_react","React"]}
1
+ {"version":3,"sources":["../src/scene/index.ts","../src/scene/BakeScene.tsx","../src/setup.ts","../src/scene/SceneSync.tsx","../src/hooks/effectOnce.ts","../src/hooks/lenisCallback.ts","../src/hooks/orbit.ts"],"sourcesContent":["import BakeScene from './BakeScene';\nimport SceneSync from './SceneSync';\n\nexport { BakeScene, SceneSync };\n","import { useFrame } from '@react-three/fiber';\nimport React, {\n type Dispatch,\n Fragment,\n type ReactNode,\n type SetStateAction,\n useId,\n useRef,\n} from 'react';\nimport { BasicTunnelIn, Default3DTunnelIn } from '../setup';\n\n/**\n * A core part of an in-house tool called `weaver`.\n *\n * `BakeScene`: This component will notifiy when the global 3D scene is ready.\n *\n * It works by tune in the `useFrame` from `@react-three/fiber`. When the scene is loaded, `useFreame` will fire\n * with ease, the component takes advantage of that, and because `useLoader` is unreliable.\n *\n * This component also accepts 3D elements `children` to be rendered directly to the canvas with some camera options.\n * But you don't have to put every 3D components inside the baker, for example, `SceneSync`s in the page are also\n * being watched by this component.\n *\n * The route renderer **CAN'T** detect if the page has 3D elements or not, so if a page uses any sort of 3D rendering,\n * this component **MUST** be a children iniside `Pipeline` (`index.tsx`), then pass the state value that bake changes\n * to `Pipeline`'s `contentReady` in order for the `BakeScene` to work behind loading fallback screen.\n */\nexport default function BakeScene(props: {\n children?: ReactNode;\n sceneReady: boolean;\n tunnelIn?: BasicTunnelIn;\n loadTaskDelay?: number;\n setSceneReady: Dispatch<SetStateAction<boolean>>;\n onReady?: () => void;\n}) {\n const unique = useId();\n const pipeObjects = useId();\n\n const TunnelIn = props.tunnelIn ?? Default3DTunnelIn;\n\n if (!TunnelIn) {\n throw Error(\n 'Failed to find a tunnel to use. Consider setting a default tunnel.'\n );\n }\n\n return (\n <TunnelIn>\n <Fragment key={pipeObjects}>{props.children}</Fragment>\n <NotificationHandler\n key={unique}\n callback={props.onReady}\n sceneReady={props.sceneReady}\n setSceneReady={props.setSceneReady}\n />\n </TunnelIn>\n );\n}\n\nfunction NotificationHandler(props: {\n callback?: (isSceneReady: boolean) => void;\n sceneReady: boolean;\n setSceneReady: (value: boolean) => void;\n}) {\n /**\n * `useFrame` is expensive for something that only triggers once, so yea,\n * we'll remove the notification as soon as the job is done.\n */\n return !props.sceneReady && <RenderNotification {...props} />;\n}\n\nfunction RenderNotification(props: {\n callback?: (isSceneReady: boolean) => void;\n sceneReady: boolean;\n loadTaskDelay?: number;\n setSceneReady: (value: boolean) => void;\n}) {\n const scheduledForCallback = useRef(false);\n\n useFrame(() => {\n if (!props.sceneReady && !scheduledForCallback.current) {\n scheduledForCallback.current = true;\n setTimeout(() => {\n if (props.callback) {\n props.callback(true);\n }\n props.setSceneReady(true);\n }, props.loadTaskDelay ?? 50);\n }\n });\n\n return null;\n}\n","import Lenis from 'lenis';\nimport { ReactNode } from 'react';\n\nexport let lenisInstance: Lenis | undefined = undefined;\n\nexport type BasicTunnelIn = ({ children }: { children: ReactNode }) => null;\nexport let Default3DTunnelIn: BasicTunnelIn | undefined = undefined;\n\nexport const weaverSetup = {\n setLenisInstance(instance: Lenis) {\n lenisInstance = instance;\n },\n set3DTunnel(tunnelIn: BasicTunnelIn) {\n Default3DTunnelIn = tunnelIn;\n },\n};\n","import { Hud } from '@react-three/drei';\nimport { useThree, type Viewport } from '@react-three/fiber';\nimport { cancelFrame, frame } from 'motion/react';\nimport React, {\n type ReactNode,\n type RefObject,\n useCallback,\n useId,\n useLayoutEffect,\n useRef,\n useState,\n} from 'react';\nimport { Group } from 'three';\nimport { useLayoutEffectOnce } from '../hooks/effectOnce';\nimport { useLenisCallback } from '../hooks/lenisCallback';\nimport { useOrbit } from '../hooks/orbit';\nimport { BasicTunnelIn, Default3DTunnelIn, lenisInstance } from '../setup';\n\nexport type Basic3DTransforms = {\n scale: {\n set: (x: number, y: number, z: number) => void;\n };\n position: {\n x: number;\n y: number;\n };\n};\n\ninterface SyncProps {\n /**\n * HTML element ref that `<SceneSync />` will use to sync with the scene.\n *\n * ```tsx\n * <div ref={container} />\n * <SceneSync attach={container}>\n * <group />\n * </SceneSync>\n * ```\n */\n attach: RefObject<HTMLElement | null>;\n\n /**\n * This variable allows fine-grain control over your scene when passed to `<SceneSync />`.\n *\n * `<SceneSync />` will use its own ref and group when creating your scene to control its scale and position.\n * Setting this variable will disable the internal ref, and you can decide on which object gets controlled.\n *\n * This variable is needed for `hud` if you wanted to add a custom camera.\n *\n * For listening to change details, use `onLayoutChange` instead.\n */\n control?: RefObject<Basic3DTransforms | null>;\n\n /**\n * When this variable is set, `<SceneSync />` will send updates when the scene update its positions.\n *\n * The function return the calculated DOM rect, with dimension and position in 3D measurements.\n */\n onLayoutUpdate?: (\n rect: DOMRect,\n dimension: { w: number; h: number },\n position: { x: number; y: number }\n ) => void;\n\n /**\n * Use `Hud` for this scene or not.\n *\n * This is useful when you want to apply custom camera for this scene, or renders multiple scenes on each other.\n *\n * NOTE: When setting a custom camera, the `control` variable must also be set and mount to your scene, not related to the camera\n * to avoid unwanted behavior.\n *\n * `<SceneSync />` groups children passed to it by default, so the camera is also in the group, when syncer updates the group,\n * the camera is also change, ruining the effect.\n */\n hud?: boolean;\n\n /**\n * Control the scene's scaling when positioning.\n */\n scaleFactor?: number;\n\n /**\n * `<SceneSync />` avoid stretching the object by default by using the smallest dimension of the DOM element.\n *\n * This variable will tell `<SceneSync />` to stretch it anyways.\n */\n stretch?: boolean;\n\n /**\n * Disable automatic scaling on the object.\n *\n * This variable will also disable any scaling settings like `stretch` and `scaleFactor`.\n */\n disableScaling?: boolean;\n\n /**\n * `<SceneSync />` will depend on this variable to adjust how it should update.\n *\n * There are 3 modes: `relaxed`, `balanced` and `aggressive`.\n *\n * For each mode, there will be some very distinct trade-offs\n *\n * - `relaxed`: Uses IntersectionObserver paired with a scroll hook, together with ResizeObserver.\n * - (+): Minimal update calls, best performance.\n * - (-): The scene get desynced the moment DOM element moves without changing its sizes.\n * When the scene bleeds out of the DOM element too much, if IntersectionObserver reported that the DOM element\n * is out of view, the scene that did not fully moved out of view will stay there, as scroll hook will be disabled.\n * - `balanced`: Uses IntersectionObserver paired with frame-based update, together with ResizeObserver.\n * - (+): Just enough update calls to allow the DOM element to move freely while maintain aceptable performance.\n * - (-): It will update on every frame when the object gets into view as reported by IntersectionObserver. And the same\n * problem with `relaxed` mode when the scene bleeds out too much.\n * - `aggressive`: Frame-based update only. This mode is like how `<View />` from `@react-three/drei` kepts track of DOM elements.\n * - (+): Designed for precise element <-> scene updates. Can't be desynced, if desynced, that's a bug.\n * - (-): This is frame-based. It will fire updates as long as the scene is still mounted. Too many scenes with this\n * mode enabled is not a good idea. Acceptable amount would be 3 scenes with this mode.\n *\n * Best of both worlds is `balanced` mode, for simpler scenes that doesn't change its position, `relaxed` should be used.\n */\n trackingMode: 'relaxed' | 'balanced' | 'aggressive';\n\n /**\n * Set a custom tunnel for `<SceneSync />` send the components to for this scene only.\n *\n * Which is useful for example, put the objects inside a container in the scene.\n *\n * To set a default tunnel, pass it to `setDefaulTunnel` before use.\n */\n tunnelIn?: BasicTunnelIn;\n\n children: ReactNode;\n}\n\ninterface HudProps extends SyncProps {\n hud: true;\n /**\n * Set the `renderPriority` to render things for `Hud`.\n *\n * This variable is ignored when `hud` is not `true`.\n */\n hudRenderPriority: number;\n}\n\ninterface NormalProps extends SyncProps {\n hud?: false;\n}\n\n/**\n * A core part of an in-house tool called `weaver`.\n *\n * A component to allow three objects to track and sync with DOM element.\n *\n * The component uses `<Hud />` under the \"hud\", so if you want to use more than one `<SceneSync />`,\n * you must set `renderPriority`. If not, the component will render the last scene pushed through React.\n */\nexport default function SceneSync(props: NormalProps | HudProps) {\n const unique = useId();\n\n const TunnelIn = props.tunnelIn ?? Default3DTunnelIn;\n\n if (!TunnelIn) {\n throw Error(\n 'Failed to find a tunnel to use. Consider setting a default tunnel.'\n );\n }\n\n if (props.hud) {\n return (\n <TunnelIn>\n <Hud key={unique} renderPriority={props.hudRenderPriority}>\n <SyncInternal {...props} />\n </Hud>\n </TunnelIn>\n );\n }\n\n return (\n <TunnelIn>\n <SyncInternal key={unique} {...props} />\n </TunnelIn>\n );\n}\n\nfunction SyncInternal(props: SyncProps) {\n const { viewport, camera } = useThree();\n\n const defaultControl = useRef<Group>(null);\n const {\n attach,\n control,\n scaleFactor,\n stretch,\n disableScaling,\n onLayoutUpdate,\n } = props;\n\n const properties: RefObject<{\n viewport?: Omit<Viewport, 'dpr' | 'initialDpr'>;\n }> = useRef({\n viewport: undefined,\n });\n\n const updatePosition = useCallback(() => {\n const activeControl = control ?? defaultControl;\n\n const vp = properties.current.viewport;\n if (!vp) return;\n\n const domRect = attach.current!.getBoundingClientRect();\n const screenH = document.documentElement.clientHeight;\n const screenW = document.body.clientWidth;\n\n const vpWidthRatio = vp.width / screenW;\n const vpHeightRatio = vp.height / screenH;\n\n const scrollOffset = (lenisInstance!.actualScroll / screenH) * vp.height;\n\n const w = domRect.width * vpWidthRatio;\n const h = domRect.height * vpHeightRatio;\n\n const x = domRect.x * vpWidthRatio + w * 0.5 - vp.width * 0.5;\n const y =\n vp.height * 0.5 -\n (domRect.y + lenisInstance!.actualScroll) * vpHeightRatio -\n h * 0.5 +\n scrollOffset;\n\n if (onLayoutUpdate) {\n onLayoutUpdate(domRect, { w, h }, { x, y });\n }\n\n const unwrapedScaleFactor = scaleFactor ?? 1;\n\n if (!disableScaling) {\n if (!stretch) {\n const minScale = Math.min(w, h) * unwrapedScaleFactor;\n activeControl.current!.scale.set(minScale, minScale, minScale);\n } else {\n activeControl.current!.scale.set(\n w * unwrapedScaleFactor,\n h * unwrapedScaleFactor,\n Math.min(w, h) * unwrapedScaleFactor\n );\n }\n }\n\n // eslint-disable-next-line react-hooks/immutability\n activeControl.current!.position.x = x;\n activeControl.current!.position.y = y;\n }, [attach, onLayoutUpdate, control, scaleFactor, disableScaling, stretch]);\n\n /**\n * Update position when `camera` changes.\n */\n useLayoutEffect(() => {\n properties.current.viewport = viewport.getCurrentViewport(camera);\n updatePosition();\n }, [camera, updatePosition, viewport]);\n\n const graceUpdate = useCallback(() => {\n try {\n updatePosition();\n } catch {\n /* empty */\n }\n }, [updatePosition]);\n\n const mode = {\n relaxed: (\n <RelaxedUpdate attach={props.attach} updatePosition={graceUpdate} />\n ),\n balanced: (\n <BalancedUpdate attach={props.attach} updatePosition={graceUpdate} />\n ),\n aggressive: <AggressiveUpdate updatePosition={graceUpdate} />,\n };\n\n if (props.control) {\n return (\n <>\n {props.children}\n {mode[props.trackingMode]}\n </>\n );\n }\n\n return (\n <group ref={defaultControl}>\n {props.children}\n {mode[props.trackingMode]}\n </group>\n );\n}\n\nfunction RelaxedUpdate(props: {\n attach: RefObject<HTMLElement | null>;\n updatePosition: () => void;\n}) {\n const { updatePosition } = props;\n\n /**\n * Scroll hook to update object correctly to the current HTML scroll position.\n */\n useLenisCallback(updatePosition, {\n initialCall: true,\n intersectOn: props.attach,\n });\n\n /**\n * Allows the element to resize too.\n */\n useOrbit({\n target: props.attach,\n events: {\n onIntersect: updatePosition,\n onResize: updatePosition,\n },\n });\n\n useLayoutEffectOnce(updatePosition);\n return null;\n}\n\nfunction BalancedUpdate(props: {\n attach: RefObject<HTMLElement | null>;\n updatePosition: () => void;\n}) {\n const { updatePosition } = props;\n\n const [shouldUpdate, setShouldUpdate] = useState(false);\n\n useOrbit({\n target: props.attach,\n events: {\n onIntersect(entry) {\n setShouldUpdate(entry.isIntersecting);\n },\n onResize: updatePosition,\n },\n rootMargin: '50% 0px 50% 0px',\n });\n\n useLayoutEffect(() => {\n if (shouldUpdate) {\n frame.read(updatePosition, true);\n } else {\n cancelFrame(updatePosition);\n }\n\n return () => {\n cancelFrame(updatePosition);\n };\n }, [updatePosition, shouldUpdate]);\n\n useLayoutEffectOnce(updatePosition);\n return null;\n}\n\nfunction AggressiveUpdate(props: { updatePosition: () => void }) {\n const { updatePosition } = props;\n\n useLayoutEffect(() => {\n frame.read(updatePosition, true);\n\n return () => {\n cancelFrame(updatePosition);\n };\n }, [updatePosition]);\n\n return null;\n}\n","import { useEffect, useLayoutEffect } from 'react';\n\nexport function useEffectOnce(callback: React.EffectCallback) {\n // eslint-disable-next-line react-hooks/exhaustive-deps\n useEffect(callback, []);\n}\n\nexport function useLayoutEffectOnce(callback: React.EffectCallback) {\n // eslint-disable-next-line react-hooks/exhaustive-deps\n useLayoutEffect(callback, []);\n}\n","import { type RefObject, useCallback, useLayoutEffect, useMemo } from 'react';\nimport { lenisInstance } from '../setup';\nimport { useOrbit } from './orbit';\n\ninterface HookOptions {\n /**\n * Hook will report when first initialized without waiting for scroll event to actually happens.\n */\n initialCall?: boolean;\n /**\n * Set an element to only call when the element is actually entering the viewport (with 25% `rootMargin`).\n */\n intersectOn?: RefObject<HTMLOrSVGElement | null>;\n}\n\nexport const scrollCallbackReason = {\n Resize: 'resize',\n Scroll: 'scroll',\n Initialize: 'initialize',\n} as const;\nexport type ScrollCallbackReason =\n (typeof scrollCallbackReason)[keyof typeof scrollCallbackReason];\n\ntype Callback = (latest: number, reason: ScrollCallbackReason) => void;\n\nexport function useLenisCallback(callback: Callback, options?: HookOptions) {\n const callbackWrapScroll = useCallback(\n () => callback(lenisInstance!.actualScroll, scrollCallbackReason.Scroll),\n [callback]\n );\n const callbackWrapResize = useCallback(\n () => callback(lenisInstance!.actualScroll, scrollCallbackReason.Resize),\n [callback]\n );\n\n const intersectOn = useMemo(\n () => options?.intersectOn,\n [options?.intersectOn]\n );\n const initialCall = useMemo(\n () => options?.initialCall,\n [options?.initialCall]\n );\n\n useOrbit({\n target: intersectOn as RefObject<HTMLElement | null> | undefined,\n events: {\n onIntersect(entry) {\n if (entry.isIntersecting) {\n lenisInstance!.on('scroll', callbackWrapScroll);\n window.addEventListener('resize', callbackWrapResize);\n } else {\n lenisInstance!.off('scroll', callbackWrapScroll);\n window.removeEventListener('resize', callbackWrapResize);\n }\n },\n },\n rootMargin: '50% 0px 50% 0px',\n });\n\n useLayoutEffect(() => {\n if (!intersectOn) {\n lenisInstance!.on('scroll', callbackWrapScroll);\n window.addEventListener('resize', callbackWrapResize);\n }\n\n if (initialCall) {\n callback(lenisInstance!.actualScroll, scrollCallbackReason.Initialize);\n }\n\n return () => {\n lenisInstance!.off('scroll', callbackWrapScroll);\n window.removeEventListener('resize', callbackWrapResize);\n };\n }, [\n callback,\n callbackWrapResize,\n callbackWrapScroll,\n initialCall,\n intersectOn,\n ]);\n}\n","import { type RefObject, useLayoutEffect } from 'react';\n\n/**\n * A simple Orbit hook.\n *\n * @param target HTML element ref to attach to.\n * @param events Specify which events should the orbit tracks.\n */\nexport function useOrbit(options: {\n target?: RefObject<HTMLElement | null>;\n events: {\n onResize?: (entry: ResizeObserverEntry) => void;\n onIntersect?: (entry: IntersectionObserverEntry) => void;\n };\n rootMargin?: string;\n}) {\n const { onResize, onIntersect } = options.events;\n const { rootMargin = '25% 0px 25% 0px' } = options;\n\n useLayoutEffect(() => {\n if (!options.target) return;\n if (!options.target.current) return;\n\n let orbitResize = undefined;\n if (onResize) {\n orbitResize = new ResizeObserver((entries) => onResize(entries[0]));\n orbitResize.observe(options.target.current);\n }\n let orbitIntersect = undefined;\n if (onIntersect) {\n orbitIntersect = new IntersectionObserver(\n (entries) => onIntersect(entries[0]),\n { rootMargin }\n );\n orbitIntersect.observe(options.target.current);\n }\n\n return () => {\n orbitResize?.disconnect();\n orbitIntersect?.disconnect();\n };\n }, [onIntersect, onResize, rootMargin, options.target]);\n}\n"],"mappings":"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","names":["React","import_fiber","import_react","import_react","import_react","import_react","React"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/scene/BakeScene.tsx","../src/setup.ts","../src/scene/SceneSync.tsx","../src/hooks/effectOnce.ts","../src/hooks/lenisCallback.ts","../src/hooks/orbit.ts"],"sourcesContent":["import { useFrame } from '@react-three/fiber';\nimport React, {\n type Dispatch,\n Fragment,\n type ReactNode,\n type SetStateAction,\n useId,\n useRef,\n} from 'react';\nimport { BasicTunnelIn, Default3DTunnelIn } from '../setup';\n\n/**\n * A core part of an in-house tool called `weaver`.\n *\n * `BakeScene`: This component will notifiy when the global 3D scene is ready.\n *\n * It works by tune in the `useFrame` from `@react-three/fiber`. When the scene is loaded, `useFreame` will fire\n * with ease, the component takes advantage of that, and because `useLoader` is unreliable.\n *\n * This component also accepts 3D elements `children` to be rendered directly to the canvas with some camera options.\n * But you don't have to put every 3D components inside the baker, for example, `SceneSync`s in the page are also\n * being watched by this component.\n *\n * The route renderer **CAN'T** detect if the page has 3D elements or not, so if a page uses any sort of 3D rendering,\n * this component **MUST** be a children iniside `Pipeline` (`index.tsx`), then pass the state value that bake changes\n * to `Pipeline`'s `contentReady` in order for the `BakeScene` to work behind loading fallback screen.\n */\nexport default function BakeScene(props: {\n children?: ReactNode;\n sceneReady: boolean;\n tunnelIn: BasicTunnelIn;\n loadTaskDelay?: number;\n setSceneReady: Dispatch<SetStateAction<boolean>>;\n onReady?: () => void;\n}) {\n const unique = useId();\n const pipeObjects = useId();\n\n const TunnelIn = props.tunnelIn ?? Default3DTunnelIn;\n\n if (!TunnelIn) {\n throw Error(\n 'Failed to find a tunnel to use. Consider setting a default tunnel.'\n );\n }\n\n return (\n <TunnelIn>\n <Fragment key={pipeObjects}>{props.children}</Fragment>\n <NotificationHandler\n key={unique}\n callback={props.onReady}\n sceneReady={props.sceneReady}\n setSceneReady={props.setSceneReady}\n />\n </TunnelIn>\n );\n}\n\nfunction NotificationHandler(props: {\n callback?: (isSceneReady: boolean) => void;\n sceneReady: boolean;\n setSceneReady: (value: boolean) => void;\n}) {\n /**\n * `useFrame` is expensive for something that only triggers once, so yea,\n * we'll remove the notification as soon as the job is done.\n */\n return !props.sceneReady && <RenderNotification {...props} />;\n}\n\nfunction RenderNotification(props: {\n callback?: (isSceneReady: boolean) => void;\n sceneReady: boolean;\n loadTaskDelay?: number;\n setSceneReady: (value: boolean) => void;\n}) {\n const scheduledForCallback = useRef(false);\n\n useFrame(() => {\n if (!props.sceneReady && !scheduledForCallback.current) {\n scheduledForCallback.current = true;\n setTimeout(() => {\n if (props.callback) {\n props.callback(true);\n }\n props.setSceneReady(true);\n }, props.loadTaskDelay ?? 50);\n }\n });\n\n return null;\n}\n","import Lenis from 'lenis';\nimport { ReactNode } from 'react';\n\nexport let lenisInstance: Lenis | undefined = undefined;\n\nexport type BasicTunnelIn = ({ children }: { children: ReactNode }) => null;\nexport let Default3DTunnelIn: BasicTunnelIn | undefined = undefined;\n\nexport const weaverSetup = {\n setLenisInstance(instance: Lenis) {\n lenisInstance = instance;\n },\n set3DTunnel(tunnelIn: BasicTunnelIn) {\n Default3DTunnelIn = tunnelIn;\n },\n};\n","import { Hud } from '@react-three/drei';\nimport { useThree, type Viewport } from '@react-three/fiber';\nimport { cancelFrame, frame } from 'motion/react';\nimport React, {\n type ReactNode,\n type RefObject,\n useCallback,\n useId,\n useLayoutEffect,\n useRef,\n useState,\n} from 'react';\nimport { Group } from 'three';\nimport { useLayoutEffectOnce } from '../hooks/effectOnce';\nimport { useLenisCallback } from '../hooks/lenisCallback';\nimport { useOrbit } from '../hooks/orbit';\nimport { BasicTunnelIn, Default3DTunnelIn, lenisInstance } from '../setup';\n\nexport type Basic3DTransforms = {\n scale: {\n set: (x: number, y: number, z: number) => void;\n };\n position: {\n x: number;\n y: number;\n };\n};\n\ninterface SyncProps {\n /**\n * HTML element ref that `<SceneSync />` will use to sync with the scene.\n *\n * ```tsx\n * <div ref={container} />\n * <SceneSync attach={container}>\n * <group />\n * </SceneSync>\n * ```\n */\n attach: RefObject<HTMLElement | null>;\n\n /**\n * This variable allows fine-grain control over your scene when passed to `<SceneSync />`.\n *\n * `<SceneSync />` will use its own ref and group when creating your scene to control its scale and position.\n * Setting this variable will disable the internal ref, and you can decide on which object gets controlled.\n *\n * This variable is needed for `hud` if you wanted to add a custom camera.\n *\n * For listening to change details, use `onLayoutChange` instead.\n */\n control?: RefObject<Basic3DTransforms | null>;\n\n /**\n * When this variable is set, `<SceneSync />` will send updates when the scene update its positions.\n *\n * The function return the calculated DOM rect, with dimension and position in 3D measurements.\n */\n onLayoutUpdate?: (\n rect: DOMRect,\n dimension: { w: number; h: number },\n position: { x: number; y: number }\n ) => void;\n\n /**\n * Use `Hud` for this scene or not.\n *\n * This is useful when you want to apply custom camera for this scene, or renders multiple scenes on each other.\n *\n * NOTE: When setting a custom camera, the `control` variable must also be set and mount to your scene, not related to the camera\n * to avoid unwanted behavior.\n *\n * `<SceneSync />` groups children passed to it by default, so the camera is also in the group, when syncer updates the group,\n * the camera is also change, ruining the effect.\n */\n hud?: boolean;\n\n /**\n * Control the scene's scaling when positioning.\n */\n scaleFactor?: number;\n\n /**\n * `<SceneSync />` avoid stretching the object by default by using the smallest dimension of the DOM element.\n *\n * This variable will tell `<SceneSync />` to stretch it anyways.\n */\n stretch?: boolean;\n\n /**\n * Disable automatic scaling on the object.\n *\n * This variable will also disable any scaling settings like `stretch` and `scaleFactor`.\n */\n disableScaling?: boolean;\n\n /**\n * `<SceneSync />` will depend on this variable to adjust how it should update.\n *\n * There are 3 modes: `relaxed`, `balanced` and `aggressive`.\n *\n * For each mode, there will be some very distinct trade-offs\n *\n * - `relaxed`: Uses IntersectionObserver paired with a scroll hook, together with ResizeObserver.\n * - (+): Minimal update calls, best performance.\n * - (-): The scene get desynced the moment DOM element moves without changing its sizes.\n * When the scene bleeds out of the DOM element too much, if IntersectionObserver reported that the DOM element\n * is out of view, the scene that did not fully moved out of view will stay there, as scroll hook will be disabled.\n * - `balanced`: Uses IntersectionObserver paired with frame-based update, together with ResizeObserver.\n * - (+): Just enough update calls to allow the DOM element to move freely while maintain aceptable performance.\n * - (-): It will update on every frame when the object gets into view as reported by IntersectionObserver. And the same\n * problem with `relaxed` mode when the scene bleeds out too much.\n * - `aggressive`: Frame-based update only. This mode is like how `<View />` from `@react-three/drei` kepts track of DOM elements.\n * - (+): Designed for precise element <-> scene updates. Can't be desynced, if desynced, that's a bug.\n * - (-): This is frame-based. It will fire updates as long as the scene is still mounted. Too many scenes with this\n * mode enabled is not a good idea. Acceptable amount would be 3 scenes with this mode.\n *\n * Best of both worlds is `balanced` mode, for simpler scenes that doesn't change its position, `relaxed` should be used.\n */\n trackingMode: 'relaxed' | 'balanced' | 'aggressive';\n\n /**\n * Set a custom tunnel for `<SceneSync />` send the components to for this scene only.\n *\n * Which is useful for example, put the objects inside a container in the scene.\n *\n * To set a default tunnel, pass it to `setDefaulTunnel` before use.\n */\n tunnelIn?: BasicTunnelIn;\n\n children: ReactNode;\n}\n\ninterface HudProps extends SyncProps {\n hud: true;\n /**\n * Set the `renderPriority` to render things for `Hud`.\n *\n * This variable is ignored when `hud` is not `true`.\n */\n hudRenderPriority: number;\n}\n\ninterface NormalProps extends SyncProps {\n hud?: false;\n}\n\n/**\n * A core part of an in-house tool called `weaver`.\n *\n * A component to allow three objects to track and sync with DOM element.\n *\n * The component uses `<Hud />` under the \"hud\", so if you want to use more than one `<SceneSync />`,\n * you must set `renderPriority`. If not, the component will render the last scene pushed through React.\n */\nexport default function SceneSync(props: NormalProps | HudProps) {\n const unique = useId();\n\n const TunnelIn = props.tunnelIn ?? Default3DTunnelIn;\n\n if (!TunnelIn) {\n throw Error(\n 'Failed to find a tunnel to use. Consider setting a default tunnel.'\n );\n }\n\n if (props.hud) {\n return (\n <TunnelIn>\n <Hud key={unique} renderPriority={props.hudRenderPriority}>\n <SyncInternal {...props} />\n </Hud>\n </TunnelIn>\n );\n }\n\n return (\n <TunnelIn>\n <SyncInternal key={unique} {...props} />\n </TunnelIn>\n );\n}\n\nfunction SyncInternal(props: SyncProps) {\n const { viewport, camera } = useThree();\n\n const defaultControl = useRef<Group>(null);\n const {\n attach,\n control,\n scaleFactor,\n stretch,\n disableScaling,\n onLayoutUpdate,\n } = props;\n\n const properties: RefObject<{\n viewport?: Omit<Viewport, 'dpr' | 'initialDpr'>;\n }> = useRef({\n viewport: undefined,\n });\n\n const updatePosition = useCallback(() => {\n const activeControl = control ?? defaultControl;\n\n const vp = properties.current.viewport;\n if (!vp) return;\n\n const domRect = attach.current!.getBoundingClientRect();\n const screenH = document.documentElement.clientHeight;\n const screenW = document.body.clientWidth;\n\n const vpWidthRatio = vp.width / screenW;\n const vpHeightRatio = vp.height / screenH;\n\n const scrollOffset = (lenisInstance!.actualScroll / screenH) * vp.height;\n\n const w = domRect.width * vpWidthRatio;\n const h = domRect.height * vpHeightRatio;\n\n const x = domRect.x * vpWidthRatio + w * 0.5 - vp.width * 0.5;\n const y =\n vp.height * 0.5 -\n (domRect.y + lenisInstance!.actualScroll) * vpHeightRatio -\n h * 0.5 +\n scrollOffset;\n\n if (onLayoutUpdate) {\n onLayoutUpdate(domRect, { w, h }, { x, y });\n }\n\n const unwrapedScaleFactor = scaleFactor ?? 1;\n\n if (!disableScaling) {\n if (!stretch) {\n const minScale = Math.min(w, h) * unwrapedScaleFactor;\n activeControl.current!.scale.set(minScale, minScale, minScale);\n } else {\n activeControl.current!.scale.set(\n w * unwrapedScaleFactor,\n h * unwrapedScaleFactor,\n Math.min(w, h) * unwrapedScaleFactor\n );\n }\n }\n\n // eslint-disable-next-line react-hooks/immutability\n activeControl.current!.position.x = x;\n activeControl.current!.position.y = y;\n }, [attach, onLayoutUpdate, control, scaleFactor, disableScaling, stretch]);\n\n /**\n * Update position when `camera` changes.\n */\n useLayoutEffect(() => {\n properties.current.viewport = viewport.getCurrentViewport(camera);\n updatePosition();\n }, [camera, updatePosition, viewport]);\n\n const graceUpdate = useCallback(() => {\n try {\n updatePosition();\n } catch {\n /* empty */\n }\n }, [updatePosition]);\n\n const mode = {\n relaxed: (\n <RelaxedUpdate attach={props.attach} updatePosition={graceUpdate} />\n ),\n balanced: (\n <BalancedUpdate attach={props.attach} updatePosition={graceUpdate} />\n ),\n aggressive: <AggressiveUpdate updatePosition={graceUpdate} />,\n };\n\n if (props.control) {\n return (\n <>\n {props.children}\n {mode[props.trackingMode]}\n </>\n );\n }\n\n return (\n <group ref={defaultControl}>\n {props.children}\n {mode[props.trackingMode]}\n </group>\n );\n}\n\nfunction RelaxedUpdate(props: {\n attach: RefObject<HTMLElement | null>;\n updatePosition: () => void;\n}) {\n const { updatePosition } = props;\n\n /**\n * Scroll hook to update object correctly to the current HTML scroll position.\n */\n useLenisCallback(updatePosition, {\n initialCall: true,\n intersectOn: props.attach,\n });\n\n /**\n * Allows the element to resize too.\n */\n useOrbit({\n target: props.attach,\n events: {\n onIntersect: updatePosition,\n onResize: updatePosition,\n },\n });\n\n useLayoutEffectOnce(updatePosition);\n return null;\n}\n\nfunction BalancedUpdate(props: {\n attach: RefObject<HTMLElement | null>;\n updatePosition: () => void;\n}) {\n const { updatePosition } = props;\n\n const [shouldUpdate, setShouldUpdate] = useState(false);\n\n useOrbit({\n target: props.attach,\n events: {\n onIntersect(entry) {\n setShouldUpdate(entry.isIntersecting);\n },\n onResize: updatePosition,\n },\n rootMargin: '50% 0px 50% 0px',\n });\n\n useLayoutEffect(() => {\n if (shouldUpdate) {\n frame.read(updatePosition, true);\n } else {\n cancelFrame(updatePosition);\n }\n\n return () => {\n cancelFrame(updatePosition);\n };\n }, [updatePosition, shouldUpdate]);\n\n useLayoutEffectOnce(updatePosition);\n return null;\n}\n\nfunction AggressiveUpdate(props: { updatePosition: () => void }) {\n const { updatePosition } = props;\n\n useLayoutEffect(() => {\n frame.read(updatePosition, true);\n\n return () => {\n cancelFrame(updatePosition);\n };\n }, [updatePosition]);\n\n return null;\n}\n","import { useEffect, useLayoutEffect } from 'react';\n\nexport function useEffectOnce(callback: React.EffectCallback) {\n // eslint-disable-next-line react-hooks/exhaustive-deps\n useEffect(callback, []);\n}\n\nexport function useLayoutEffectOnce(callback: React.EffectCallback) {\n // eslint-disable-next-line react-hooks/exhaustive-deps\n useLayoutEffect(callback, []);\n}\n","import { type RefObject, useCallback, useLayoutEffect, useMemo } from 'react';\nimport { lenisInstance } from '../setup';\nimport { useOrbit } from './orbit';\n\ninterface HookOptions {\n /**\n * Hook will report when first initialized without waiting for scroll event to actually happens.\n */\n initialCall?: boolean;\n /**\n * Set an element to only call when the element is actually entering the viewport (with 25% `rootMargin`).\n */\n intersectOn?: RefObject<HTMLOrSVGElement | null>;\n}\n\nexport const scrollCallbackReason = {\n Resize: 'resize',\n Scroll: 'scroll',\n Initialize: 'initialize',\n} as const;\nexport type ScrollCallbackReason =\n (typeof scrollCallbackReason)[keyof typeof scrollCallbackReason];\n\ntype Callback = (latest: number, reason: ScrollCallbackReason) => void;\n\nexport function useLenisCallback(callback: Callback, options?: HookOptions) {\n const callbackWrapScroll = useCallback(\n () => callback(lenisInstance!.actualScroll, scrollCallbackReason.Scroll),\n [callback]\n );\n const callbackWrapResize = useCallback(\n () => callback(lenisInstance!.actualScroll, scrollCallbackReason.Resize),\n [callback]\n );\n\n const intersectOn = useMemo(\n () => options?.intersectOn,\n [options?.intersectOn]\n );\n const initialCall = useMemo(\n () => options?.initialCall,\n [options?.initialCall]\n );\n\n useOrbit({\n target: intersectOn as RefObject<HTMLElement | null> | undefined,\n events: {\n onIntersect(entry) {\n if (entry.isIntersecting) {\n lenisInstance!.on('scroll', callbackWrapScroll);\n window.addEventListener('resize', callbackWrapResize);\n } else {\n lenisInstance!.off('scroll', callbackWrapScroll);\n window.removeEventListener('resize', callbackWrapResize);\n }\n },\n },\n rootMargin: '50% 0px 50% 0px',\n });\n\n useLayoutEffect(() => {\n if (!intersectOn) {\n lenisInstance!.on('scroll', callbackWrapScroll);\n window.addEventListener('resize', callbackWrapResize);\n }\n\n if (initialCall) {\n callback(lenisInstance!.actualScroll, scrollCallbackReason.Initialize);\n }\n\n return () => {\n lenisInstance!.off('scroll', callbackWrapScroll);\n window.removeEventListener('resize', callbackWrapResize);\n };\n }, [\n callback,\n callbackWrapResize,\n callbackWrapScroll,\n initialCall,\n intersectOn,\n ]);\n}\n","import { type RefObject, useLayoutEffect } from 'react';\n\n/**\n * A simple Orbit hook.\n *\n * @param target HTML element ref to attach to.\n * @param events Specify which events should the orbit tracks.\n */\nexport function useOrbit(options: {\n target?: RefObject<HTMLElement | null>;\n events: {\n onResize?: (entry: ResizeObserverEntry) => void;\n onIntersect?: (entry: IntersectionObserverEntry) => void;\n };\n rootMargin?: string;\n}) {\n const { onResize, onIntersect } = options.events;\n const { rootMargin = '25% 0px 25% 0px' } = options;\n\n useLayoutEffect(() => {\n if (!options.target) return;\n if (!options.target.current) return;\n\n let orbitResize = undefined;\n if (onResize) {\n orbitResize = new ResizeObserver((entries) => onResize(entries[0]));\n orbitResize.observe(options.target.current);\n }\n let orbitIntersect = undefined;\n if (onIntersect) {\n orbitIntersect = new IntersectionObserver(\n (entries) => onIntersect(entries[0]),\n { rootMargin }\n );\n orbitIntersect.observe(options.target.current);\n }\n\n return () => {\n orbitResize?.disconnect();\n orbitIntersect?.disconnect();\n };\n }, [onIntersect, onResize, rootMargin, options.target]);\n}\n"],"mappings":"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","names":["React","useCallback","useId","useLayoutEffect","useRef","useLayoutEffect","useLayoutEffect","useLayoutEffect","useId","React","useRef","useCallback","useLayoutEffect"]}
1
+ {"version":3,"sources":["../src/scene/BakeScene.tsx","../src/setup.ts","../src/scene/SceneSync.tsx","../src/hooks/effectOnce.ts","../src/hooks/lenisCallback.ts","../src/hooks/orbit.ts"],"sourcesContent":["import { useFrame } from '@react-three/fiber';\nimport React, {\n type Dispatch,\n Fragment,\n type ReactNode,\n type SetStateAction,\n useId,\n useRef,\n} from 'react';\nimport { BasicTunnelIn, Default3DTunnelIn } from '../setup';\n\n/**\n * A core part of an in-house tool called `weaver`.\n *\n * `BakeScene`: This component will notifiy when the global 3D scene is ready.\n *\n * It works by tune in the `useFrame` from `@react-three/fiber`. When the scene is loaded, `useFreame` will fire\n * with ease, the component takes advantage of that, and because `useLoader` is unreliable.\n *\n * This component also accepts 3D elements `children` to be rendered directly to the canvas with some camera options.\n * But you don't have to put every 3D components inside the baker, for example, `SceneSync`s in the page are also\n * being watched by this component.\n *\n * The route renderer **CAN'T** detect if the page has 3D elements or not, so if a page uses any sort of 3D rendering,\n * this component **MUST** be a children iniside `Pipeline` (`index.tsx`), then pass the state value that bake changes\n * to `Pipeline`'s `contentReady` in order for the `BakeScene` to work behind loading fallback screen.\n */\nexport default function BakeScene(props: {\n children?: ReactNode;\n sceneReady: boolean;\n tunnelIn?: BasicTunnelIn;\n loadTaskDelay?: number;\n setSceneReady: Dispatch<SetStateAction<boolean>>;\n onReady?: () => void;\n}) {\n const unique = useId();\n const pipeObjects = useId();\n\n const TunnelIn = props.tunnelIn ?? Default3DTunnelIn;\n\n if (!TunnelIn) {\n throw Error(\n 'Failed to find a tunnel to use. Consider setting a default tunnel.'\n );\n }\n\n return (\n <TunnelIn>\n <Fragment key={pipeObjects}>{props.children}</Fragment>\n <NotificationHandler\n key={unique}\n callback={props.onReady}\n sceneReady={props.sceneReady}\n setSceneReady={props.setSceneReady}\n />\n </TunnelIn>\n );\n}\n\nfunction NotificationHandler(props: {\n callback?: (isSceneReady: boolean) => void;\n sceneReady: boolean;\n setSceneReady: (value: boolean) => void;\n}) {\n /**\n * `useFrame` is expensive for something that only triggers once, so yea,\n * we'll remove the notification as soon as the job is done.\n */\n return !props.sceneReady && <RenderNotification {...props} />;\n}\n\nfunction RenderNotification(props: {\n callback?: (isSceneReady: boolean) => void;\n sceneReady: boolean;\n loadTaskDelay?: number;\n setSceneReady: (value: boolean) => void;\n}) {\n const scheduledForCallback = useRef(false);\n\n useFrame(() => {\n if (!props.sceneReady && !scheduledForCallback.current) {\n scheduledForCallback.current = true;\n setTimeout(() => {\n if (props.callback) {\n props.callback(true);\n }\n props.setSceneReady(true);\n }, props.loadTaskDelay ?? 50);\n }\n });\n\n return null;\n}\n","import Lenis from 'lenis';\nimport { ReactNode } from 'react';\n\nexport let lenisInstance: Lenis | undefined = undefined;\n\nexport type BasicTunnelIn = ({ children }: { children: ReactNode }) => null;\nexport let Default3DTunnelIn: BasicTunnelIn | undefined = undefined;\n\nexport const weaverSetup = {\n setLenisInstance(instance: Lenis) {\n lenisInstance = instance;\n },\n set3DTunnel(tunnelIn: BasicTunnelIn) {\n Default3DTunnelIn = tunnelIn;\n },\n};\n","import { Hud } from '@react-three/drei';\nimport { useThree, type Viewport } from '@react-three/fiber';\nimport { cancelFrame, frame } from 'motion/react';\nimport React, {\n type ReactNode,\n type RefObject,\n useCallback,\n useId,\n useLayoutEffect,\n useRef,\n useState,\n} from 'react';\nimport { Group } from 'three';\nimport { useLayoutEffectOnce } from '../hooks/effectOnce';\nimport { useLenisCallback } from '../hooks/lenisCallback';\nimport { useOrbit } from '../hooks/orbit';\nimport { BasicTunnelIn, Default3DTunnelIn, lenisInstance } from '../setup';\n\nexport type Basic3DTransforms = {\n scale: {\n set: (x: number, y: number, z: number) => void;\n };\n position: {\n x: number;\n y: number;\n };\n};\n\ninterface SyncProps {\n /**\n * HTML element ref that `<SceneSync />` will use to sync with the scene.\n *\n * ```tsx\n * <div ref={container} />\n * <SceneSync attach={container}>\n * <group />\n * </SceneSync>\n * ```\n */\n attach: RefObject<HTMLElement | null>;\n\n /**\n * This variable allows fine-grain control over your scene when passed to `<SceneSync />`.\n *\n * `<SceneSync />` will use its own ref and group when creating your scene to control its scale and position.\n * Setting this variable will disable the internal ref, and you can decide on which object gets controlled.\n *\n * This variable is needed for `hud` if you wanted to add a custom camera.\n *\n * For listening to change details, use `onLayoutChange` instead.\n */\n control?: RefObject<Basic3DTransforms | null>;\n\n /**\n * When this variable is set, `<SceneSync />` will send updates when the scene update its positions.\n *\n * The function return the calculated DOM rect, with dimension and position in 3D measurements.\n */\n onLayoutUpdate?: (\n rect: DOMRect,\n dimension: { w: number; h: number },\n position: { x: number; y: number }\n ) => void;\n\n /**\n * Use `Hud` for this scene or not.\n *\n * This is useful when you want to apply custom camera for this scene, or renders multiple scenes on each other.\n *\n * NOTE: When setting a custom camera, the `control` variable must also be set and mount to your scene, not related to the camera\n * to avoid unwanted behavior.\n *\n * `<SceneSync />` groups children passed to it by default, so the camera is also in the group, when syncer updates the group,\n * the camera is also change, ruining the effect.\n */\n hud?: boolean;\n\n /**\n * Control the scene's scaling when positioning.\n */\n scaleFactor?: number;\n\n /**\n * `<SceneSync />` avoid stretching the object by default by using the smallest dimension of the DOM element.\n *\n * This variable will tell `<SceneSync />` to stretch it anyways.\n */\n stretch?: boolean;\n\n /**\n * Disable automatic scaling on the object.\n *\n * This variable will also disable any scaling settings like `stretch` and `scaleFactor`.\n */\n disableScaling?: boolean;\n\n /**\n * `<SceneSync />` will depend on this variable to adjust how it should update.\n *\n * There are 3 modes: `relaxed`, `balanced` and `aggressive`.\n *\n * For each mode, there will be some very distinct trade-offs\n *\n * - `relaxed`: Uses IntersectionObserver paired with a scroll hook, together with ResizeObserver.\n * - (+): Minimal update calls, best performance.\n * - (-): The scene get desynced the moment DOM element moves without changing its sizes.\n * When the scene bleeds out of the DOM element too much, if IntersectionObserver reported that the DOM element\n * is out of view, the scene that did not fully moved out of view will stay there, as scroll hook will be disabled.\n * - `balanced`: Uses IntersectionObserver paired with frame-based update, together with ResizeObserver.\n * - (+): Just enough update calls to allow the DOM element to move freely while maintain aceptable performance.\n * - (-): It will update on every frame when the object gets into view as reported by IntersectionObserver. And the same\n * problem with `relaxed` mode when the scene bleeds out too much.\n * - `aggressive`: Frame-based update only. This mode is like how `<View />` from `@react-three/drei` kepts track of DOM elements.\n * - (+): Designed for precise element <-> scene updates. Can't be desynced, if desynced, that's a bug.\n * - (-): This is frame-based. It will fire updates as long as the scene is still mounted. Too many scenes with this\n * mode enabled is not a good idea. Acceptable amount would be 3 scenes with this mode.\n *\n * Best of both worlds is `balanced` mode, for simpler scenes that doesn't change its position, `relaxed` should be used.\n */\n trackingMode: 'relaxed' | 'balanced' | 'aggressive';\n\n /**\n * Set a custom tunnel for `<SceneSync />` send the components to for this scene only.\n *\n * Which is useful for example, put the objects inside a container in the scene.\n *\n * To set a default tunnel, pass it to `setDefaulTunnel` before use.\n */\n tunnelIn?: BasicTunnelIn;\n\n children: ReactNode;\n}\n\ninterface HudProps extends SyncProps {\n hud: true;\n /**\n * Set the `renderPriority` to render things for `Hud`.\n *\n * This variable is ignored when `hud` is not `true`.\n */\n hudRenderPriority: number;\n}\n\ninterface NormalProps extends SyncProps {\n hud?: false;\n}\n\n/**\n * A core part of an in-house tool called `weaver`.\n *\n * A component to allow three objects to track and sync with DOM element.\n *\n * The component uses `<Hud />` under the \"hud\", so if you want to use more than one `<SceneSync />`,\n * you must set `renderPriority`. If not, the component will render the last scene pushed through React.\n */\nexport default function SceneSync(props: NormalProps | HudProps) {\n const unique = useId();\n\n const TunnelIn = props.tunnelIn ?? Default3DTunnelIn;\n\n if (!TunnelIn) {\n throw Error(\n 'Failed to find a tunnel to use. Consider setting a default tunnel.'\n );\n }\n\n if (props.hud) {\n return (\n <TunnelIn>\n <Hud key={unique} renderPriority={props.hudRenderPriority}>\n <SyncInternal {...props} />\n </Hud>\n </TunnelIn>\n );\n }\n\n return (\n <TunnelIn>\n <SyncInternal key={unique} {...props} />\n </TunnelIn>\n );\n}\n\nfunction SyncInternal(props: SyncProps) {\n const { viewport, camera } = useThree();\n\n const defaultControl = useRef<Group>(null);\n const {\n attach,\n control,\n scaleFactor,\n stretch,\n disableScaling,\n onLayoutUpdate,\n } = props;\n\n const properties: RefObject<{\n viewport?: Omit<Viewport, 'dpr' | 'initialDpr'>;\n }> = useRef({\n viewport: undefined,\n });\n\n const updatePosition = useCallback(() => {\n const activeControl = control ?? defaultControl;\n\n const vp = properties.current.viewport;\n if (!vp) return;\n\n const domRect = attach.current!.getBoundingClientRect();\n const screenH = document.documentElement.clientHeight;\n const screenW = document.body.clientWidth;\n\n const vpWidthRatio = vp.width / screenW;\n const vpHeightRatio = vp.height / screenH;\n\n const scrollOffset = (lenisInstance!.actualScroll / screenH) * vp.height;\n\n const w = domRect.width * vpWidthRatio;\n const h = domRect.height * vpHeightRatio;\n\n const x = domRect.x * vpWidthRatio + w * 0.5 - vp.width * 0.5;\n const y =\n vp.height * 0.5 -\n (domRect.y + lenisInstance!.actualScroll) * vpHeightRatio -\n h * 0.5 +\n scrollOffset;\n\n if (onLayoutUpdate) {\n onLayoutUpdate(domRect, { w, h }, { x, y });\n }\n\n const unwrapedScaleFactor = scaleFactor ?? 1;\n\n if (!disableScaling) {\n if (!stretch) {\n const minScale = Math.min(w, h) * unwrapedScaleFactor;\n activeControl.current!.scale.set(minScale, minScale, minScale);\n } else {\n activeControl.current!.scale.set(\n w * unwrapedScaleFactor,\n h * unwrapedScaleFactor,\n Math.min(w, h) * unwrapedScaleFactor\n );\n }\n }\n\n // eslint-disable-next-line react-hooks/immutability\n activeControl.current!.position.x = x;\n activeControl.current!.position.y = y;\n }, [attach, onLayoutUpdate, control, scaleFactor, disableScaling, stretch]);\n\n /**\n * Update position when `camera` changes.\n */\n useLayoutEffect(() => {\n properties.current.viewport = viewport.getCurrentViewport(camera);\n updatePosition();\n }, [camera, updatePosition, viewport]);\n\n const graceUpdate = useCallback(() => {\n try {\n updatePosition();\n } catch {\n /* empty */\n }\n }, [updatePosition]);\n\n const mode = {\n relaxed: (\n <RelaxedUpdate attach={props.attach} updatePosition={graceUpdate} />\n ),\n balanced: (\n <BalancedUpdate attach={props.attach} updatePosition={graceUpdate} />\n ),\n aggressive: <AggressiveUpdate updatePosition={graceUpdate} />,\n };\n\n if (props.control) {\n return (\n <>\n {props.children}\n {mode[props.trackingMode]}\n </>\n );\n }\n\n return (\n <group ref={defaultControl}>\n {props.children}\n {mode[props.trackingMode]}\n </group>\n );\n}\n\nfunction RelaxedUpdate(props: {\n attach: RefObject<HTMLElement | null>;\n updatePosition: () => void;\n}) {\n const { updatePosition } = props;\n\n /**\n * Scroll hook to update object correctly to the current HTML scroll position.\n */\n useLenisCallback(updatePosition, {\n initialCall: true,\n intersectOn: props.attach,\n });\n\n /**\n * Allows the element to resize too.\n */\n useOrbit({\n target: props.attach,\n events: {\n onIntersect: updatePosition,\n onResize: updatePosition,\n },\n });\n\n useLayoutEffectOnce(updatePosition);\n return null;\n}\n\nfunction BalancedUpdate(props: {\n attach: RefObject<HTMLElement | null>;\n updatePosition: () => void;\n}) {\n const { updatePosition } = props;\n\n const [shouldUpdate, setShouldUpdate] = useState(false);\n\n useOrbit({\n target: props.attach,\n events: {\n onIntersect(entry) {\n setShouldUpdate(entry.isIntersecting);\n },\n onResize: updatePosition,\n },\n rootMargin: '50% 0px 50% 0px',\n });\n\n useLayoutEffect(() => {\n if (shouldUpdate) {\n frame.read(updatePosition, true);\n } else {\n cancelFrame(updatePosition);\n }\n\n return () => {\n cancelFrame(updatePosition);\n };\n }, [updatePosition, shouldUpdate]);\n\n useLayoutEffectOnce(updatePosition);\n return null;\n}\n\nfunction AggressiveUpdate(props: { updatePosition: () => void }) {\n const { updatePosition } = props;\n\n useLayoutEffect(() => {\n frame.read(updatePosition, true);\n\n return () => {\n cancelFrame(updatePosition);\n };\n }, [updatePosition]);\n\n return null;\n}\n","import { useEffect, useLayoutEffect } from 'react';\n\nexport function useEffectOnce(callback: React.EffectCallback) {\n // eslint-disable-next-line react-hooks/exhaustive-deps\n useEffect(callback, []);\n}\n\nexport function useLayoutEffectOnce(callback: React.EffectCallback) {\n // eslint-disable-next-line react-hooks/exhaustive-deps\n useLayoutEffect(callback, []);\n}\n","import { type RefObject, useCallback, useLayoutEffect, useMemo } from 'react';\nimport { lenisInstance } from '../setup';\nimport { useOrbit } from './orbit';\n\ninterface HookOptions {\n /**\n * Hook will report when first initialized without waiting for scroll event to actually happens.\n */\n initialCall?: boolean;\n /**\n * Set an element to only call when the element is actually entering the viewport (with 25% `rootMargin`).\n */\n intersectOn?: RefObject<HTMLOrSVGElement | null>;\n}\n\nexport const scrollCallbackReason = {\n Resize: 'resize',\n Scroll: 'scroll',\n Initialize: 'initialize',\n} as const;\nexport type ScrollCallbackReason =\n (typeof scrollCallbackReason)[keyof typeof scrollCallbackReason];\n\ntype Callback = (latest: number, reason: ScrollCallbackReason) => void;\n\nexport function useLenisCallback(callback: Callback, options?: HookOptions) {\n const callbackWrapScroll = useCallback(\n () => callback(lenisInstance!.actualScroll, scrollCallbackReason.Scroll),\n [callback]\n );\n const callbackWrapResize = useCallback(\n () => callback(lenisInstance!.actualScroll, scrollCallbackReason.Resize),\n [callback]\n );\n\n const intersectOn = useMemo(\n () => options?.intersectOn,\n [options?.intersectOn]\n );\n const initialCall = useMemo(\n () => options?.initialCall,\n [options?.initialCall]\n );\n\n useOrbit({\n target: intersectOn as RefObject<HTMLElement | null> | undefined,\n events: {\n onIntersect(entry) {\n if (entry.isIntersecting) {\n lenisInstance!.on('scroll', callbackWrapScroll);\n window.addEventListener('resize', callbackWrapResize);\n } else {\n lenisInstance!.off('scroll', callbackWrapScroll);\n window.removeEventListener('resize', callbackWrapResize);\n }\n },\n },\n rootMargin: '50% 0px 50% 0px',\n });\n\n useLayoutEffect(() => {\n if (!intersectOn) {\n lenisInstance!.on('scroll', callbackWrapScroll);\n window.addEventListener('resize', callbackWrapResize);\n }\n\n if (initialCall) {\n callback(lenisInstance!.actualScroll, scrollCallbackReason.Initialize);\n }\n\n return () => {\n lenisInstance!.off('scroll', callbackWrapScroll);\n window.removeEventListener('resize', callbackWrapResize);\n };\n }, [\n callback,\n callbackWrapResize,\n callbackWrapScroll,\n initialCall,\n intersectOn,\n ]);\n}\n","import { type RefObject, useLayoutEffect } from 'react';\n\n/**\n * A simple Orbit hook.\n *\n * @param target HTML element ref to attach to.\n * @param events Specify which events should the orbit tracks.\n */\nexport function useOrbit(options: {\n target?: RefObject<HTMLElement | null>;\n events: {\n onResize?: (entry: ResizeObserverEntry) => void;\n onIntersect?: (entry: IntersectionObserverEntry) => void;\n };\n rootMargin?: string;\n}) {\n const { onResize, onIntersect } = options.events;\n const { rootMargin = '25% 0px 25% 0px' } = options;\n\n useLayoutEffect(() => {\n if (!options.target) return;\n if (!options.target.current) return;\n\n let orbitResize = undefined;\n if (onResize) {\n orbitResize = new ResizeObserver((entries) => onResize(entries[0]));\n orbitResize.observe(options.target.current);\n }\n let orbitIntersect = undefined;\n if (onIntersect) {\n orbitIntersect = new IntersectionObserver(\n (entries) => onIntersect(entries[0]),\n { rootMargin }\n );\n orbitIntersect.observe(options.target.current);\n }\n\n return () => {\n orbitResize?.disconnect();\n orbitIntersect?.disconnect();\n };\n }, [onIntersect, onResize, rootMargin, options.target]);\n}\n"],"mappings":"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","names":["React","useCallback","useId","useLayoutEffect","useRef","useLayoutEffect","useLayoutEffect","useLayoutEffect","useId","React","useRef","useCallback","useLayoutEffect"]}
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "author": "neveranyart",
3
3
  "license": "GPL-3.0-or-later",
4
4
  "name": "@neveranyart/weaver",
5
- "version": "1.0.3",
5
+ "version": "1.0.5",
6
6
  "description": "An in-house package by neverany for making interactive React CSR.",
7
7
  "packageManager": "yarn@4.10.3",
8
8
  "publishConfig": {