@fiddle-digital/string-tune 1.0.1 → 1.0.3

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/core/controllers/CursorController.ts","../src/core/managers/EventManager.ts","../src/core/managers/ModuleManager.ts","../src/objects/StringObject.ts","../src/core/managers/ObjectManager.ts","../src/core/controllers/ScrollController.ts","../src/core/controllers/StringScrollDefault.ts","../src/core/controllers/StringScrollDisable.ts","../src/core/controllers/StringScrollSmooth.ts","../src/core/managers/ScrollManager.ts","../src/states/CursorState.ts","../src/states/RenderState.ts","../src/states/ScrollState.ts","../src/states/TimeState.ts","../src/states/ViewportState.ts","../src/core/StringData.ts","../src/core/StringModule.ts","../src/tools/BoundingClientRectTool.ts","../src/tools/DOMAttributeTool.ts","../src/tools/RecordAttributeTool.ts","../src/tools/TransformNullifyTool.ts","../src/tools/RelativePositionTool.ts","../src/tools/LerpTool.ts","../src/tools/UnitParserTool.ts","../src/tools/AdaptiveLerpTool.ts","../src/tools/OriginParserTool.ts","../src/tools/ColorParserTool.ts","../src/tools/ValidationTool.ts","../src/tools/EasingFunctionTool.ts","../src/tools/MagneticPullTool.ts","../src/tools/LerpColorTool.ts","../src/tools/LerpVector2Tool.ts","../src/tools/TransformScaleParserTool.ts","../src/tools/CharIndexerTool.ts","../src/tools/LayoutLineSplitterTool.ts","../src/tools/SplitDomBuilderTool.ts","../src/tools/WordIndexerTool.ts","../src/tools/SplitOptionsParserTool.ts","../src/core/StringToolsContainer.ts","../src/modules/cursor/StringCursor.ts","../src/modules/cursor/StringMagnetic.ts","../src/modules/loading/StringLazy.ts","../src/modules/loading/StringLoading.ts","../src/modules/screen/StringInview.ts","../src/modules/screen/StringResponsive.ts","../src/modules/scroll/StringAnchor.ts","../src/modules/scroll/StringGlide.ts","../src/modules/scroll/StringLerp.ts","../src/modules/scroll/StringProgress.ts","../src/modules/scroll/StringParallax.ts","../src/modules/scrollbar/StringScrollbarHorizontal.ts","../src/modules/scrollbar/StringScrollbarVertical.ts","../src/modules/scrollbar/StringScrollbar.ts","../src/modules/text/StringSplit.ts","../src/modules/tracker/StringDelayLerpTracker.ts","../src/modules/tracker/StringFPSTracker.ts","../src/modules/tracker/StringLerpTracker.ts","../src/modules/tracker/StringPositionTracker.ts","../src/utils/Debounce.ts","../src/utils/StringFPS.ts","../src/modules/loading/StringVideoAutoplay.ts"],"sourcesContent":["import { CursorController } from \"./core/controllers/CursorController\";\r\nimport { IStringModule } from \"./core/IStringModule\";\r\nimport { EventManager } from \"./core/managers/EventManager\";\r\nimport { ModuleManager } from \"./core/managers/ModuleManager\";\r\nimport { ObjectManager } from \"./core/managers/ObjectManager\";\r\nimport { ScrollManager } from \"./core/managers/ScrollManager\";\r\nimport { StringContext } from \"./core/StringContext\";\r\nimport { StringData } from \"./core/StringData\";\r\nimport { StringModule } from \"./core/StringModule\";\r\nimport { DefaultToolsContainer } from \"./core/StringToolsContainer\";\r\nimport { StringCursor } from \"./modules/cursor/StringCursor\";\r\nimport { StringMagnetic } from \"./modules/cursor/StringMagnetic\";\r\nimport { StringLazy } from \"./modules/loading/StringLazy\";\r\nimport { StringLoading } from \"./modules/loading/StringLoading\";\r\nimport { StringInview } from \"./modules/screen/StringInview\";\r\nimport { StringResponsive } from \"./modules/screen/StringResponsive\";\r\nimport { StringAnchor } from \"./modules/scroll/StringAnchor\";\r\nimport { StringGlide } from \"./modules/scroll/StringGlide\";\r\nimport { StringLerp } from \"./modules/scroll/StringLerp\";\r\nimport { StringParallax } from \"./modules/scroll/StringParallax\";\r\nimport { StringProgress } from \"./modules/scroll/StringProgress\";\r\nimport { StringScrollbar } from \"./modules/scrollbar/StringScrollbar\";\r\nimport { StringSplit } from \"./modules/text/StringSplit\";\r\nimport { StringDelayLerpTracker } from \"./modules/tracker/StringDelayLerpTracker\";\r\nimport { StringFPSTracker } from \"./modules/tracker/StringFPSTracker\";\r\nimport { StringLerpTracker } from \"./modules/tracker/StringLerpTracker\";\r\nimport { StringPositionTracker } from \"./modules/tracker/StringPositionTracker\";\r\nimport { StringObject } from \"./objects/StringObject\";\r\nimport { ScrollMode } from \"./states/ScrollState\";\r\nimport { Debounce } from \"./utils/Debounce\";\r\nimport { EventCallback } from \"./models/event/EventCallback\";\r\nimport { StringFPS } from \"./utils/StringFPS\";\r\nimport { StringSettings } from \"./utils/StringSettings\";\r\nimport { StringVideoAutoplay } from \"./modules/loading/StringVideoAutoplay\";\r\n\r\nfunction isTouchDevice() {\r\n return \"ontouchstart\" in window || navigator.maxTouchPoints > 0;\r\n}\r\nfunction isSafari(): boolean {\r\n let ua = navigator.userAgent.toLowerCase();\r\n if (ua.indexOf(\"safari\") != -1) {\r\n if (ua.indexOf(\"chrome\") > -1) {\r\n return false;\r\n } else {\r\n return true;\r\n }\r\n } else {\r\n return false;\r\n }\r\n}\r\n\r\nclass StringTune {\r\n /** Bound handler for the scroll start event */\r\n private onScrollStartBind: any;\r\n\r\n /** Bound handler for the scroll stop event */\r\n private onScrollStopBind: any;\r\n\r\n /** Bound handler for the scroll direction change event */\r\n private onDirectionChangeBind: any;\r\n\r\n /** Bound wheel event handler */\r\n private onWheelBind: any;\r\n\r\n /** Bound scroll event handler */\r\n private onScrollBind: any;\r\n\r\n /** Bound resize event handler */\r\n private onResizeBind: any;\r\n\r\n /** Bound mouse move handler */\r\n private onMouseMoveBind: any;\r\n\r\n /** Singleton instance of StringTune */\r\n private static i: StringTune;\r\n\r\n /** Root scrollable element (typically <body>) */\r\n private root: any;\r\n\r\n /** Window object (used for event bindings and dimensions) */\r\n private window: any;\r\n\r\n /** Previous window width for resize diff check */\r\n private prevWidth: number = 0;\r\n\r\n /** Previous window height for resize diff check */\r\n private prevHeight: number = 0;\r\n\r\n /** Manages all modules registered in the system */\r\n private moduleManager: ModuleManager;\r\n\r\n /** Manages scroll modes and active scroll engine */\r\n private scrollManager: ScrollManager;\r\n\r\n /** Manages all interactive objects (elements with `string-*` attributes) */\r\n private objectManager: ObjectManager;\r\n\r\n /** Central event manager for internal pub-sub logic */\r\n private eventManager: EventManager;\r\n\r\n /** Handles custom cursor logic (if enabled) */\r\n private cursorController: CursorController;\r\n\r\n /** Provides default utility tools (parsers, interpolation, etc.) */\r\n private tools: DefaultToolsContainer;\r\n\r\n /** Main loop used for frame updates (with fixed FPS) */\r\n private loop: StringFPS = new StringFPS();\r\n\r\n /** Global reactive data store (scroll, viewport, etc.) */\r\n private data: StringData;\r\n\r\n /** Context shared across all modules (events, data, tools, settings) */\r\n private context: StringContext;\r\n\r\n /**\r\n * Sets the scroll position manually.\r\n * This overrides all internal scroll states including target and lerped values.\r\n * Useful for programmatic jumps or syncing scroll externally.\r\n *\r\n * @param value The new scroll position in pixels.\r\n */\r\n public set scrollPosition(value: number) {\r\n this.data.scroll.current = value;\r\n this.data.scroll.target = value;\r\n this.data.scroll.delta = 0;\r\n this.data.scroll.lerped = 0;\r\n this.scrollManager.updatePosition();\r\n }\r\n\r\n /**\r\n * Configures the container element(s) used for scroll tracking.\r\n * Accepts either the `Window` object or an `HTMLElement`.\r\n * Determines the appropriate internal element references based on the input type\r\n * and triggers a resize calculation.\r\n *\r\n * @param {Window | HTMLElement | any} container The target window or HTML element to associate with scrolling.\r\n * Handles `Window`, `HTMLElement`, and potentially other types via fallback.\r\n */\r\n public set scrollContainer(container: any) {\r\n if (container instanceof Window) {\r\n this.data.scroll.container = document.body;\r\n this.data.scroll.elementContainer = document.documentElement;\r\n this.data.scroll.scrollContainer = container;\r\n } else if (container instanceof HTMLElement) {\r\n this.data.scroll.container = container;\r\n this.data.scroll.elementContainer = container;\r\n this.data.scroll.scrollContainer = container;\r\n } else {\r\n // Fallback case\r\n this.data.scroll.container = document.body;\r\n this.data.scroll.elementContainer = document.documentElement;\r\n this.data.scroll.scrollContainer = container; // Assigns the original (potentially non-standard) container\r\n }\r\n this.debouncedResize();\r\n }\r\n\r\n /**\r\n * Gets the current scroll position in pixels.\r\n * This is typically updated every frame.\r\n */\r\n public get speed() {\r\n return this.data.scroll.current;\r\n }\r\n\r\n /**\r\n * Sets the base scroll speed for smooth scrolling.\r\n * Typically a value between 0 and 1.\r\n */\r\n public set speed(value: number) {\r\n this.data.scroll.speed = value;\r\n }\r\n\r\n /**\r\n * Sets the scroll acceleration using a normalized value from 0 to 1.\r\n * Internally maps it to a real acceleration value between 0.1 and 0.5.\r\n *\r\n * @param speed A normalized acceleration factor (0 to 1).\r\n */\r\n public set speedAccelerate(speed: number) {\r\n const min = 0.1;\r\n const max = 0.5;\r\n this.data.scroll.speedAccelerate = min + (max - min) * speed;\r\n }\r\n\r\n /**\r\n * Sets the scroll mode for desktop devices.\r\n * Can be 'smooth', 'default', or 'disable'.\r\n */\r\n public set scrollDesktopMode(mode: ScrollMode) {\r\n this.scrollManager.setDesktopMode(mode);\r\n }\r\n\r\n /**\r\n * Sets the scroll mode for mobile devices.\r\n * Can be 'smooth', 'default', or 'disable'.\r\n */\r\n public set scrollMobileMode(mode: ScrollMode) {\r\n this.scrollManager.setMobileMode(mode);\r\n }\r\n\r\n private debouncedResize = Debounce(this.onResize, 30);\r\n\r\n private constructor() {\r\n this.root = document.body;\r\n this.window = window;\r\n\r\n this.tools = new DefaultToolsContainer();\r\n this.data = new StringData();\r\n this.eventManager = new EventManager();\r\n this.moduleManager = new ModuleManager(this.data);\r\n this.objectManager = new ObjectManager(\r\n this.data,\r\n this.moduleManager,\r\n this.eventManager\r\n );\r\n\r\n this.context = {\r\n events: this.eventManager,\r\n data: this.data,\r\n tools: this.tools,\r\n settings: {},\r\n };\r\n\r\n this.cursorController = new CursorController(1, this.context);\r\n this.scrollManager = new ScrollManager(this.context);\r\n\r\n this.setupSettings({\r\n \"offset-top\": \"0%\",\r\n \"offset-bottom\": \"0%\",\r\n key: \"--progress\",\r\n \"inview-top\": \"0%\",\r\n \"inview-bottom\": \"0%\",\r\n \"enter-el\": \"top\",\r\n \"enter-vp\": \"bottom\",\r\n \"exit-el\": \"bottom\",\r\n \"exit-vp\": \"top\",\r\n \"parallax-bias\": \"0.0\",\r\n parallax: \"0.2\",\r\n lerp: \"0.2\",\r\n radius: \"150\",\r\n strength: \"0.3\",\r\n glide: \"1\",\r\n anchor: \"center center\",\r\n timeout: 900,\r\n alignment: \"center\",\r\n \"target-disable\": \"false\",\r\n \"target-style-disable\": \"false\",\r\n \"target-class\": \"\",\r\n active: \"false\",\r\n fixed: \"false\",\r\n repeat: \"false\",\r\n \"self-disable\": \"false\",\r\n abs: \"false\",\r\n easing: \"cubic-bezier(0.25, 0.25, 0.25, 0.25)\",\r\n \"glide-base-velocity\": 0.00125,\r\n \"glide-reduce-velocity\": 0.0000625,\r\n \"glide-negative-velocity\": -0.0001,\r\n });\r\n\r\n this.onWheelBind = this.onWheelEvent.bind(this);\r\n this.onScrollBind = this.onScrollEvent.bind(this);\r\n this.onResizeBind = this.onResize.bind(this);\r\n this.onMouseMoveBind = this.onMouseMoveEvent.bind(this);\r\n\r\n this.onScrollStartBind = this.onScrollStart.bind(this);\r\n this.onScrollStopBind = this.onScrollStop.bind(this);\r\n this.onDirectionChangeBind = this.onDirectionChange.bind(this);\r\n\r\n this.scrollManager.bindEvents({\r\n onScrollStart: this.onScrollStartBind,\r\n onScrollStop: this.onScrollStopBind,\r\n onDirectionChange: this.onDirectionChangeBind,\r\n });\r\n\r\n this.loop.setOnFrame((time: number) => {\r\n this.data.time.delta = time - this.data.time.now;\r\n this.data.time.previous = this.data.time.now;\r\n this.data.time.now = time;\r\n this.data.time.elapsed += this.data.time.delta;\r\n this.onUpdateEvent();\r\n });\r\n this.on(\"image:load:all\", () => {\r\n this.onResize();\r\n });\r\n\r\n this.scrollContainer = window;\r\n }\r\n\r\n /**\r\n * Returns the singleton instance of StringTune.\r\n * If not already created, initializes it.\r\n */\r\n public static getInstance(): StringTune {\r\n if (!StringTune.i) {\r\n StringTune.i = new StringTune();\r\n }\r\n return StringTune.i;\r\n }\r\n\r\n /**\r\n * Finds and returns an existing module by its class.\r\n * Useful for reusing a module instance without re-registering.\r\n *\r\n * @template T The type of the module to retrieve.\r\n * @param type The module class constructor.\r\n * @returns The module instance if found, otherwise undefined.\r\n */\r\n public reuse<T>(type: new (...args: any[]) => T): T | undefined {\r\n return this.moduleManager.find(type);\r\n }\r\n\r\n /**\r\n * Instantiates and registers a new module.\r\n * Accepts optional per-instance settings that override global settings.\r\n *\r\n * @param objectClass The module class to instantiate.\r\n * @param settings Optional settings specific to this module.\r\n */\r\n public use(objectClass: typeof StringModule, settings: any = null) {\r\n const effectiveSettings = {\r\n ...this.context.settings,\r\n ...settings,\r\n };\r\n const module = new objectClass({\r\n events: this.eventManager,\r\n data: this.data,\r\n tools: this.tools,\r\n settings: effectiveSettings,\r\n });\r\n this.moduleManager.register(module);\r\n }\r\n\r\n /**\r\n * Subscribes to a global event within the system.\r\n *\r\n * @param eventName The name of the event to listen for.\r\n * @param callback The function to call when the event is triggered.\r\n * @param id Optional subscription ID (for easier management).\r\n */\r\n public on(eventName: string, callback: EventCallback<any>, id: string = \"\") {\r\n this.eventManager.on(eventName, callback, id);\r\n }\r\n\r\n /**\r\n * Unsubscribes from a global event.\r\n *\r\n * @param eventName The name of the event.\r\n * @param callback The previously registered callback.\r\n * @param id Optional ID used during subscription.\r\n */\r\n public off(eventName: string, callback: EventCallback<any>, id: string = \"\") {\r\n this.eventManager.off(eventName, callback, id);\r\n }\r\n\r\n /**\r\n * Starts the scroll engine and initializes all listeners, observers, and modules.\r\n *\r\n * @param fps Desired frames per second for the update loop.\r\n */\r\n public start(fps: number) {\r\n // window.addEventListener('scroll', this.onScrollBind);\r\n // this.root.addEventListener('wheel', this.onWheelBind, { passive: false });\r\n\r\n this.data.scroll.scrollContainer?.addEventListener(\r\n \"scroll\",\r\n this.onScrollBind\r\n );\r\n this.data.scroll.container?.addEventListener(\"wheel\", this.onWheelBind, {\r\n passive: false,\r\n });\r\n\r\n window.addEventListener(\"resize\", this.onResizeBind);\r\n this.root.addEventListener(\"mousemove\", this.onMouseMoveBind);\r\n\r\n const observerContainerResize = new ResizeObserver(() => {\r\n this.debouncedResize();\r\n });\r\n observerContainerResize.observe(this.context.data.scroll.container);\r\n\r\n const observerContainerMutation = new MutationObserver(\r\n (mutationsList: MutationRecord[], observer: MutationObserver) => {\r\n for (const mutation of mutationsList) {\r\n if (\r\n mutation.type === \"attributes\" &&\r\n (mutation.attributeName === \"style\" ||\r\n mutation.attributeName === \"class\")\r\n ) {\r\n this.onResize();\r\n }\r\n }\r\n }\r\n );\r\n const config: MutationObserverInit = {\r\n attributes: true,\r\n attributeFilter: [\"style\", \"class\"],\r\n };\r\n observerContainerMutation.observe(\r\n this.context.data.scroll.container,\r\n config\r\n );\r\n\r\n this.use(StringInview);\r\n\r\n const htmlFontSize = window.getComputedStyle(\r\n document.documentElement\r\n ).fontSize;\r\n const fontSizeNumber = parseFloat(htmlFontSize);\r\n this.context.data.viewport.baseRem = fontSizeNumber;\r\n\r\n document.documentElement.classList.add(\"-string\");\r\n this.moduleManager.onInit();\r\n this.onResize();\r\n this.initObjects();\r\n this.objectManager.observeDOM();\r\n\r\n this.loop.start(fps);\r\n this.eventManager.emit(`start`, null);\r\n }\r\n\r\n /**\r\n * Initializes all DOM elements with `string` or `string-copy-from` attributes.\r\n * Registers them with the object manager and triggers resize/scroll/frame hooks.\r\n */\r\n private initObjects() {\r\n document.querySelectorAll(\"[string],[data-string]\").forEach((element) => {\r\n this.objectManager.add(element as HTMLElement);\r\n });\r\n document\r\n .querySelectorAll(\"[string-copy-from],[data-string-copy-from]\")\r\n .forEach((element) => {\r\n let connectTargetId = this.tools.domAttribute.process({\r\n element: element as HTMLElement,\r\n key: \"copy-from\",\r\n fallback: \"\",\r\n });\r\n if (connectTargetId && connectTargetId.length > 0) {\r\n this.objectManager.enqueueConnection(\r\n connectTargetId,\r\n element as HTMLElement\r\n );\r\n }\r\n });\r\n this.moduleManager.onResize();\r\n this.moduleManager.onScroll();\r\n this.moduleManager.onFrame();\r\n }\r\n\r\n /**\r\n * Sets global fallback settings for all modules.\r\n * These can be overridden by module-specific settings during `use(...)`.\r\n *\r\n * @param settings A key-value map of default settings (e.g. 'offset-top': '-10%').\r\n */\r\n public setupSettings(settings: StringSettings): void {\r\n this.context.settings = {\r\n ...this.context.settings,\r\n ...settings,\r\n };\r\n this.onSettingsChange();\r\n }\r\n\r\n /**\r\n * Handles mouse move event and dispatches it to cursor and modules.\r\n * @param e Native mouse move event.\r\n */\r\n private onMouseMoveEvent(e: MouseEvent) {\r\n this.cursorController.onMouseMove(e);\r\n this.moduleManager.onMouseMove(e);\r\n }\r\n\r\n /**\r\n * Handles wheel scroll event and passes it to the scroll engine and modules.\r\n * @param e Native wheel event.\r\n */\r\n private onWheelEvent(e: WheelEvent) {\r\n this.scrollManager.get().onWheel(e);\r\n this.moduleManager.onWheel(e);\r\n }\r\n\r\n /**\r\n * Called when scrolling begins.\r\n * Triggers module scroll start lifecycle hook.\r\n */\r\n private onScrollStart() {\r\n this.moduleManager.onScrollStart();\r\n }\r\n\r\n /**\r\n * Called when scrolling ends.\r\n * Triggers module scroll stop lifecycle hook.\r\n */\r\n private onScrollStop() {\r\n this.moduleManager.onScrollStop();\r\n }\r\n\r\n /**\r\n * Called when scrolling ends.\r\n * Triggers module scroll stop lifecycle hook.\r\n */\r\n private onDirectionChange() {\r\n this.moduleManager.onDirectionChange();\r\n }\r\n\r\n /**\r\n * Called when global or module settings are updated.\r\n * Notifies all managers and modules to re-read new settings.\r\n */\r\n private onSettingsChange() {\r\n this.cursorController.onSettingsChange();\r\n this.objectManager.onSettingsChange();\r\n this.moduleManager.onSettingsChange();\r\n }\r\n\r\n /**\r\n * Handles native scroll event.\r\n * Prevents default behavior and triggers internal scroll logic and event emissions.\r\n *\r\n * @param e The native scroll event.\r\n */\r\n private onScrollEvent(e: Event) {\r\n e.preventDefault();\r\n this.scrollManager.get().onScroll(e);\r\n this.moduleManager.onScroll();\r\n this.eventManager.emit(`lerp`, this.data.scroll.lerped);\r\n this.eventManager.emit(`scroll`, this.data.scroll.current);\r\n return false;\r\n }\r\n\r\n /**\r\n * Called every frame by the update loop.\r\n * Triggers scroll engine, modules, and global `update` event.\r\n */\r\n private onUpdateEvent() {\r\n this.cursorController.onFrame();\r\n this.scrollManager.get().onFrame();\r\n this.moduleManager.onFrame();\r\n this.eventManager.emit(`update`, null);\r\n }\r\n\r\n /**\r\n * Handles resize events from scroll container or window.\r\n * Ignores height-only changes on mobile to prevent layout jumps.\r\n * Rebuilds layout and triggers module resize if size really changed.\r\n */\r\n public onResize(): void {\r\n const container = this.data.scroll.container;\r\n const scroll = this.context.data.scroll;\r\n let width = 0;\r\n let height = 0;\r\n var newScrollHeight;\r\n var newContainerTopPosition = 0;\r\n const rect = container.getBoundingClientRect();\r\n\r\n if (container.tagName == \"BODY\") {\r\n width = window.innerWidth;\r\n height = window.innerHeight;\r\n } else {\r\n width = rect.width;\r\n height = rect.height;\r\n }\r\n\r\n newContainerTopPosition = rect.top;\r\n newScrollHeight = scroll.container.scrollHeight;\r\n const transformScale = this.tools.transformScaleParser.process({\r\n value: window.getComputedStyle(container).transform,\r\n });\r\n this.context.data.viewport.transformScale = transformScale;\r\n\r\n const isDesktop = width > 1080;\r\n\r\n const widthChanged = this.prevWidth !== width;\r\n const heightChanged = this.prevHeight !== height;\r\n const scrollHeightChanged =\r\n this.context.data.viewport.contentHeight !== newScrollHeight;\r\n\r\n const shouldRebuild =\r\n widthChanged || (isDesktop && heightChanged) || scrollHeightChanged;\r\n\r\n this.context.data.scroll.topPosition = newContainerTopPosition;\r\n this.context.data.viewport.contentWidth = width;\r\n this.context.data.viewport.contentHeight = newScrollHeight;\r\n\r\n this.prevWidth = width;\r\n this.prevHeight = height;\r\n\r\n this.context.data.viewport.windowWidth = width;\r\n this.context.data.viewport.windowHeight = height;\r\n\r\n const htmlFontSize = window.getComputedStyle(\r\n document.documentElement\r\n ).fontSize;\r\n const fontSizeNumber = parseFloat(htmlFontSize);\r\n this.context.data.viewport.baseRem = fontSizeNumber * transformScale;\r\n\r\n scroll.bottomPosition = this.context.data.viewport.contentHeight - height;\r\n\r\n if (shouldRebuild) {\r\n this.context.data.scroll.current =\r\n this.context.data.scroll.container.scrollTop;\r\n this.context.data.scroll.target =\r\n this.context.data.scroll.container.scrollTop;\r\n this.context.data.scroll.transformedCurrent =\r\n this.context.data.scroll.current *\r\n this.context.data.viewport.transformScale;\r\n this.scrollManager.updateResponsiveMode();\r\n this.moduleManager.onResize();\r\n this.onSettingsChange();\r\n this.moduleManager.onScroll();\r\n this.moduleManager.onFrame();\r\n }\r\n }\r\n\r\n /**\r\n * Cleans up the system, removes all event listeners, stops the loop,\r\n * and destroys modules and event subscriptions.\r\n */\r\n public destroy() {\r\n this.data.scroll.scrollContainer?.removeEventListener(\r\n \"scroll\",\r\n this.onScrollBind\r\n );\r\n this.data.scroll.container?.removeEventListener(\"wheel\", this.onScrollBind);\r\n\r\n this.window.removeEventListener(\"resize\", this.onResizeBind);\r\n this.root.removeEventListener(\"mousemove\", this.onMouseMoveBind);\r\n this.loop.stop();\r\n this.moduleManager.destroy();\r\n this.eventManager.clearAll();\r\n }\r\n}\r\n\r\nexport {\r\n StringTune as default,\r\n StringCursor,\r\n StringDelayLerpTracker,\r\n StringFPSTracker,\r\n StringGlide,\r\n StringLazy,\r\n StringLerp,\r\n StringLerpTracker,\r\n StringLoading,\r\n StringMagnetic,\r\n StringParallax,\r\n StringPositionTracker,\r\n StringProgress,\r\n StringResponsive,\r\n StringScrollbar,\r\n StringSplit,\r\n StringAnchor,\r\n StringTune as StringTune,\r\n StringVideoAutoplay,\r\n StringModule,\r\n StringObject,\r\n StringData,\r\n type StringContext,\r\n};\r\n","import { CursorState } from \"../../states/CursorState\"\r\nimport { EventManager } from \"../managers/EventManager\"\r\nimport { StringContext } from \"../StringContext\"\r\nimport { StringData } from \"../StringData\"\r\nimport { StringToolsContainer } from \"../StringToolsContainer\"\r\n\r\n/**\r\n * Manages virtual cursor logic: smoothing, updating, and syncing with mouse events.\r\n * \r\n * This controller handles cursor position tracking with smoothing (lerp) logic.\r\n * Useful for animated cursor effects and interaction modules.\r\n */\r\nexport class CursorController {\r\n /** Context providing access to shared data, tools, and settings. */\r\n protected context: StringContext\r\n\r\n /** Threshold below which cursor is considered settled (no movement). */\r\n private readonly SETTLE_THRESHOLD = 0.1\r\n\r\n /** Smoothing factor used to interpolate cursor movement. */\r\n private smoothingFactor: number\r\n\r\n /**\r\n * Constructs a new `CursorController` instance.\r\n * @param smoothing The initial lerp smoothing factor (0 to 1).\r\n * @param context The shared context containing state and tools.\r\n */\r\n constructor(smoothing: number = 0.1, context: StringContext) {\r\n this.smoothingFactor = smoothing\r\n this.context = context\r\n this.onSettingsChange()\r\n }\r\n\r\n /**\r\n * Updates the target cursor position from a mouse event.\r\n * This is the raw position that smoothing will interpolate toward.\r\n * @param e MouseEvent with current cursor position.\r\n */\r\n public onMouseMove(e: MouseEvent): void {\r\n this.context.data.cursor.targetX = e.clientX\r\n this.context.data.cursor.targetY = e.clientY\r\n }\r\n\r\n /**\r\n * Updates smoothed cursor position using linear interpolation (lerp).\r\n * Should be called on every animation frame.\r\n * Handles snapping when movement is below threshold.\r\n */\r\n public onFrame(): void {\r\n const { targetX, targetY, smoothedX, smoothedY } = this.context.data.cursor\r\n\r\n const stepX = this.context.tools.lerp.process({ from: smoothedX, to: targetX, progress: this.smoothingFactor })\r\n const stepY = this.context.tools.lerp.process({ from: smoothedY, to: targetY, progress: this.smoothingFactor })\r\n\r\n const distance = this.getStepDistance(stepX, stepY)\r\n\r\n if (this.isSettled(distance)) {\r\n this.snapToTarget()\r\n } else {\r\n this.applyStep(stepX, stepY)\r\n }\r\n }\r\n\r\n /**\r\n * Called when global settings change.\r\n * Updates the internal lerp factor from context settings.\r\n */\r\n public onSettingsChange(): void {\r\n let lerp = Number(this.context.settings['lerp'])\r\n this.setLerpFactor(lerp)\r\n }\r\n\r\n /**\r\n * Dynamically adjusts the smoothing factor using adaptive mapping.\r\n * @param t The raw input lerp value (usually from 0 to 1).\r\n */\r\n public setLerpFactor(t: number): void {\r\n this.smoothingFactor = this.context.tools.adaptiveLerp.process({ \r\n value: t,\r\n inMin: 0.1,\r\n inMax: 1.0,\r\n outMin: 0.05,\r\n outMax: 0.65\r\n })\r\n }\r\n\r\n /**\r\n * Calculates the Euclidean distance from the cursor step.\r\n * @param x Step in X direction.\r\n * @param y Step in Y direction.\r\n * @returns The length of the movement vector.\r\n */\r\n private getStepDistance(x: number, y: number): number {\r\n return Math.hypot(x, y)\r\n }\r\n\r\n /**\r\n * Determines whether the movement is below the settle threshold.\r\n * @param distance Distance between smoothed and target positions.\r\n * @returns Whether the cursor should snap to target.\r\n */\r\n private isSettled(distance: number): boolean {\r\n return distance < this.SETTLE_THRESHOLD\r\n }\r\n\r\n /**\r\n * Immediately sets smoothed position to the target and zeroes deltas.\r\n */\r\n private snapToTarget(): void {\r\n this.context.data.cursor.smoothedX = this.context.data.cursor.targetX\r\n this.context.data.cursor.smoothedY = this.context.data.cursor.targetY\r\n this.context.data.cursor.stepX = 0\r\n this.context.data.cursor.stepY = 0\r\n }\r\n\r\n /**\r\n * Applies lerped movement step to smoothed position and stores delta.\r\n * @param x Step in X direction.\r\n * @param y Step in Y direction.\r\n */\r\n private applyStep(x: number, y: number): void {\r\n this.context.data.cursor.smoothedX += x\r\n this.context.data.cursor.smoothedY += y\r\n this.context.data.cursor.stepX = x\r\n this.context.data.cursor.stepY = y\r\n }\r\n}\r\n","import { EventCallback } from \"../../models/event/EventCallback\";\r\n\r\n/**\r\n * Manages custom event subscriptions and dispatching.\r\n * Allows multiple listeners per event and supports optional `id` suffixing.\r\n */\r\nexport class EventManager {\r\n private listeners: Record<string, Set<EventCallback<any>>> = {};\r\n\r\n /**\r\n * Subscribes to an event.\r\n * Optionally appends an `id` to the event name for namespacing.\r\n *\r\n * @param eventName The base event name (e.g. \"scroll\", \"update\").\r\n * @param callback The function to call when the event is emitted.\r\n * @param id Optional unique identifier to scope the event (e.g. element ID).\r\n */\r\n on<T = any>(\r\n eventName: string,\r\n callback: EventCallback<T>,\r\n id?: string\r\n ): void {\r\n const fullEvent = id ? `${eventName}_${id}` : eventName;\r\n\r\n if (!this.listeners[fullEvent]) {\r\n this.listeners[fullEvent] = new Set();\r\n }\r\n this.listeners[fullEvent].add(callback);\r\n }\r\n\r\n /**\r\n * Unsubscribes from a specific event listener.\r\n * Must match the original `eventName`, `callback`, and optional `id`.\r\n *\r\n * @param eventName The base event name to unsubscribe from.\r\n * @param callback The callback function to remove.\r\n * @param id Optional identifier used when subscribing.\r\n */\r\n off<T = any>(\r\n eventName: string,\r\n callback: EventCallback<T>,\r\n id?: string\r\n ): void {\r\n const fullEvent = id ? `${eventName}_${id}` : eventName;\r\n\r\n if (this.listeners[fullEvent]) {\r\n this.listeners[fullEvent].delete(callback);\r\n }\r\n }\r\n\r\n /**\r\n * Emits an event with an optional payload.\r\n * All matching listeners will be called.\r\n *\r\n * @param eventName The full event name (must include `id` if used).\r\n * @param payload Optional data passed to event listeners.\r\n */\r\n emit<T = any>(eventName: string, payload?: T): void {\r\n const set = this.listeners[eventName];\r\n if (!set) return;\r\n\r\n for (const callback of set) {\r\n callback(payload as T);\r\n }\r\n }\r\n\r\n /**\r\n * Subscribes to a per-object progress event.\r\n * @param id The object ID.\r\n * @param callback The callback to handle progress value.\r\n */\r\n onProgress(id: string, callback: EventCallback<number>): void {\r\n this.on(`progress:${id}`, callback);\r\n }\r\n\r\n /**\r\n * Emits a per-object progress event.\r\n * @param id The object ID.\r\n * @param value The progress value.\r\n */\r\n emitProgress(id: string, value: number): void {\r\n this.emit(`progress:${id}`, value);\r\n }\r\n\r\n /**\r\n * Subscribes to a per-object in-view event.\r\n * @param id The object ID.\r\n * @param callback The callback to handle visibility.\r\n */\r\n onInview(id: string, callback: EventCallback<boolean>): void {\r\n this.on(`object:inview:${id}`, callback);\r\n }\r\n\r\n /**\r\n * Emits a per-object in-view event.\r\n * @param id The object ID.\r\n * @param visible Whether the object is visible.\r\n */\r\n emitInview(id: string, visible: boolean): void {\r\n this.emit(`object:inview${id}`, visible);\r\n }\r\n\r\n /**\r\n * Subscribes to the global scroll event.\r\n * @param callback The callback to handle scroll value.\r\n */\r\n onScroll(callback: EventCallback<number>): void {\r\n this.on(`scroll`, callback);\r\n }\r\n\r\n /**\r\n * Emits the global scroll event.\r\n * @param value The scroll value.\r\n */\r\n emitScroll(value: number): void {\r\n this.emit(`scroll`, value);\r\n }\r\n\r\n /**\r\n * Subscribes to the global update event.\r\n * @param callback The callback to handle update.\r\n */\r\n onUpdate(callback: EventCallback<void>): void {\r\n this.on(`update`, callback);\r\n }\r\n\r\n /**\r\n * Emits the global update event.\r\n */\r\n emitUpdate(): void {\r\n this.emit(`update`);\r\n }\r\n\r\n /**\r\n * Clears all listeners for a specific event.\r\n *\r\n * @param eventName The full event name (including optional `id`).\r\n */\r\n clear(eventName: string): void {\r\n delete this.listeners[eventName];\r\n }\r\n\r\n /**\r\n * Clears all registered events.\r\n */\r\n clearAll(): void {\r\n this.listeners = {};\r\n }\r\n}\r\n","import { StringData } from \"../..\";\r\nimport { IStringModule } from \"../IStringModule\";\r\nimport { StringModule } from \"../StringModule\";\r\n\r\n/**\r\n * Central manager for registering, tracking and delegating lifecycle events \r\n * to core and UI modules in the system.\r\n * \r\n * Handles scroll, resize, animation frame updates and DOM events.\r\n */\r\nexport class ModuleManager {\r\n /** All core logic modules (e.g., scroll, in-view, parallax). */\r\n private modules: StringModule[] = [];\r\n\r\n /** All UI or visual/interaction-based modules (e.g., cursor, split text). */\r\n private uiModules: StringModule[] = [];\r\n\r\n /**\r\n * @param data Shared state container for scroll, viewport, etc.\r\n */\r\n constructor(private data: StringData) {}\r\n\r\n /**\r\n * Registers a module into the appropriate group based on its type.\r\n * @param module The module instance to register.\r\n */\r\n register(module: StringModule): void {\r\n if (module.type === 1) this.modules.push(module);\r\n if (module.type === 2) this.uiModules.push(module);\r\n }\r\n\r\n /**\r\n * Finds the first registered module of the given class/type.\r\n * @param type The module class constructor.\r\n * @returns The instance, if found.\r\n */\r\n find<T>(type: new (...args: any[]) => T): T | undefined {\r\n return this.modules.find(m => m instanceof type) as T | undefined;\r\n }\r\n\r\n /** Invokes `onInit` on all modules. */\r\n onInit(): void {\r\n [...this.modules, ...this.uiModules].forEach(m => m.onInit());\r\n }\r\n\r\n /** Invokes `onFrame` on all modules, passing shared state. */\r\n onFrame(): void {\r\n [...this.modules, ...this.uiModules].forEach(m => m.onFrame(this.data));\r\n }\r\n\r\n /** Invokes `onScroll` on all modules with current scroll state. */\r\n onScroll(): void {\r\n [...this.modules, ...this.uiModules].forEach(m => m.onScroll(this.data));\r\n }\r\n\r\n /** Invokes `onResize` on all modules. */\r\n onResize(): void {\r\n [...this.modules, ...this.uiModules].forEach(m => m.onResize());\r\n }\r\n\r\n /**\r\n * Delegates mouse movement events to modules.\r\n * @param e The mousemove event.\r\n */\r\n onMouseMove(e: MouseEvent): void {\r\n [...this.modules, ...this.uiModules].forEach(m => m.onMouseMove(e));\r\n }\r\n\r\n /**\r\n * Delegates wheel events to modules.\r\n * @param e The wheel event.\r\n */\r\n onWheel(e: WheelEvent): void {\r\n [...this.modules, ...this.uiModules].forEach(m => m.onWheel(e));\r\n }\r\n\r\n /** Notifies all modules that scroll has changed diraction. */\r\n onDirectionChange(): void {\r\n [...this.modules, ...this.uiModules].forEach(m => m.onDirectionChange());\r\n }\r\n\r\n /** Notifies all modules that scroll has started. */\r\n onScrollStart(): void {\r\n [...this.modules, ...this.uiModules].forEach(m => m.onScrollStart());\r\n }\r\n\r\n /** Notifies all modules that scroll has stopped. */\r\n onScrollStop(): void {\r\n [...this.modules, ...this.uiModules].forEach(m => m.onScrollStop());\r\n }\r\n\r\n /** Notifies all modules that scroll axis (horizontal/vertical) has changed. */\r\n onAxisChange(): void {\r\n [...this.modules, ...this.uiModules].forEach(m => m.onAxisChange());\r\n }\r\n\r\n /** Notifies all modules that device type (desktop/mobile) has changed. */\r\n onDeviceChange(): void {\r\n [...this.modules, ...this.uiModules].forEach(m => m.onDeviceChange());\r\n }\r\n\r\n /** Notifies modules of updates to scroll-related configuration. */\r\n onScrollConfigChange(): void {\r\n [...this.modules, ...this.uiModules].forEach(m => m.onScrollConfigChange());\r\n }\r\n\r\n /** Notifies modules of updated global or module-specific settings. */\r\n onSettingsChange(): void {\r\n [...this.modules, ...this.uiModules].forEach(m => m.onSettingsChange());\r\n }\r\n\r\n /**\r\n * Called when DOM is mutated — e.g. new elements added/removed.\r\n * @param added Newly added DOM nodes.\r\n * @param removed Removed DOM nodes.\r\n */\r\n onDOMMutate(added: NodeList, removed: NodeList): void {\r\n [...this.modules, ...this.uiModules].forEach(m => m.onDOMMutate(added, removed));\r\n }\r\n\r\n /** Cleans up all modules and clears internal lists. */\r\n destroy(): void {\r\n [...this.modules, ...this.uiModules].forEach(m => m.destroy());\r\n this.modules = [];\r\n this.uiModules = [];\r\n }\r\n\r\n /**\r\n * Returns all modules (core + UI) as a flat array.\r\n */\r\n get all(): IStringModule[] {\r\n return [...this.modules, ...this.uiModules];\r\n }\r\n\r\n /**\r\n * Returns only core modules (type === 1).\r\n */\r\n get core(): IStringModule[] {\r\n return this.modules;\r\n }\r\n\r\n /**\r\n * Returns only UI modules (type === 2).\r\n */\r\n get ui(): IStringModule[] {\r\n return this.uiModules;\r\n }\r\n}\r\n","import { IStringModule } from \"../core/IStringModule\";\r\nimport { EventManager } from \"../core/managers/EventManager\";\r\n\r\n/**\r\n * Internal class representing a DOM-bound interactive object.\r\n * Connected to modules and holds its own internal state.\r\n */\r\nexport class StringObject {\r\n /**\r\n * The DOM element this object wraps.\r\n */\r\n public htmlElement: HTMLElement;\r\n\r\n /**\r\n * Unique global ID assigned by the system.\r\n */\r\n public id: string = \"\";\r\n\r\n /**\r\n * Space-separated list of all attribute keys associated with this object.\r\n */\r\n public keys: string[] = [];\r\n\r\n /**\r\n * A list of elements that should be affected in sync with this one.\r\n */\r\n public connects: HTMLElement[] = [];\r\n\r\n /**\r\n * Internal key-value store of dynamic object properties (like offsets, progress, etc.).\r\n */\r\n private properties: Map<string, any> = new Map();\r\n\r\n /**\r\n * Modules currently connected to this object.\r\n */\r\n private modules: IStringModule[] = [];\r\n\r\n /**\r\n * Manages and handles events for the object.\r\n * Provides functionality to register, trigger, and manage event listeners.\r\n */\r\n events: EventManager = new EventManager();\r\n\r\n constructor(id: string, element: HTMLElement) {\r\n this.htmlElement = element;\r\n this.id = id;\r\n }\r\n\r\n /**\r\n * Stores a property value for this object.\r\n * @param key - Property name\r\n * @param value - Value to store\r\n */\r\n public setProperty<T>(key: string, value: T): void {\r\n this.properties.set(key, value);\r\n }\r\n\r\n /**\r\n * Retrieves a previously stored property value.\r\n * @param key - Property name\r\n * @returns The value or null if not set\r\n */\r\n public getProperty<T>(key: string): T {\r\n return this.properties.get(key) ?? null;\r\n }\r\n\r\n /**\r\n * Marks this object as \"active\" (usually on intersection/scroll enter).\r\n */\r\n public enter(): void {\r\n this.events.emit(\"enter\", this);\r\n this.setProperty(\"active\", true);\r\n this.modules.forEach((module) => {\r\n module.enterObject(this.id, this);\r\n });\r\n }\r\n\r\n /**\r\n * Marks this object as \"inactive\" (usually on intersection/scroll leave).\r\n */\r\n public leave(): void {\r\n this.events.emit(\"leave\", this);\r\n this.setProperty(\"active\", false);\r\n this.modules.forEach((module) => {\r\n module.exitObject(this.id);\r\n });\r\n }\r\n\r\n /**\r\n * Shows the object, applies visual class and notifies connected modules.\r\n */\r\n public show(): void {\r\n this.htmlElement.classList.add(\"-inview\");\r\n }\r\n\r\n /**\r\n * Hides the object, removes visual class (if repeat is enabled), and notifies modules.\r\n */\r\n public hide(): void {\r\n const shouldRepeat = this.getProperty<boolean>(\"repeat\");\r\n if (shouldRepeat) {\r\n this.htmlElement.classList.remove(\"-inview\");\r\n }\r\n }\r\n\r\n /**\r\n * Connects a module to this object if not already connected.\r\n * @param module - The module to connect\r\n */\r\n public connect(module: IStringModule): void {\r\n if (!this.modules.includes(module)) {\r\n this.modules.push(module);\r\n }\r\n }\r\n}\r\n","import { ModuleManager } from \"./ModuleManager\";\r\nimport { StringData } from \"../StringData\";\r\nimport { StringObject } from \"../../objects/StringObject\";\r\nimport { EventManager } from \"./EventManager\";\r\n\r\nexport class ObjectManager {\r\n private objects = new Map<string, StringObject>();\r\n private connectQueue: { id: string; element: HTMLElement }[] = [];\r\n private globalId = 1;\r\n\r\n constructor(\r\n private data: StringData,\r\n private modules: ModuleManager,\r\n private events: EventManager\r\n ) {}\r\n\r\n /**\r\n * Returns the object map (read-only).\r\n */\r\n get all(): ReadonlyMap<string, StringObject> {\r\n return this.objects;\r\n }\r\n\r\n /**\r\n * Adds a new object from an element.\r\n */\r\n public add(el: HTMLElement) {\r\n const idAttr = el.getAttribute(\"string-id\") ?? `string-${this.globalId++}`;\r\n\r\n const object =\r\n idAttr && this.objects.has(idAttr)\r\n ? this.objects.get(idAttr)!\r\n : new StringObject(idAttr, el);\r\n\r\n el.setAttribute(\"string-id\", object.id);\r\n\r\n const keysAttr =\r\n el.getAttribute(\"string\") ?? el.getAttribute(\"data-string\");\r\n\r\n if (keysAttr) {\r\n object.keys = (keysAttr ?? \"\").split(\"|\");\r\n }\r\n\r\n el.setAttribute(\"string-inited\", \"\");\r\n this.objects.set(object.id, object);\r\n\r\n const attributes = this.getAllAttributes(el);\r\n\r\n // Delegate core setup (dimensions, offsets, key, start/end, etc.)\r\n this.modules.core.forEach((m) => {\r\n if (\r\n \"setupCoreProperties\" in m &&\r\n typeof m[\"setupCoreProperties\"] === \"function\"\r\n ) {\r\n (m as any).setupCoreProperties(object, el, attributes);\r\n }\r\n });\r\n\r\n // Try connecting to modules\r\n this.modules.core.forEach((m) => {\r\n if (m.canConnect(object)) {\r\n m.initializeObject(this.globalId, object, el, attributes);\r\n m.calculatePositions(object, this.data.viewport.windowHeight);\r\n m.connectObject(object);\r\n }\r\n });\r\n\r\n // Restore connect-from\r\n const queueItems = this.connectQueue.filter((q) => q.id === object.id);\r\n queueItems.forEach((item) => object.connects.push(item.element));\r\n this.connectQueue = this.connectQueue.filter((q) => q.id !== object.id);\r\n\r\n // Set up observers\r\n this.initObservers(object, el);\r\n }\r\n\r\n /**\r\n * Removes an object by its id.\r\n */\r\n public remove(id: string) {\r\n const obj = this.objects.get(id);\r\n if (!obj) return;\r\n\r\n obj.events.clearAll();\r\n obj.getProperty<IntersectionObserver>(\"observer-progress\")?.disconnect();\r\n obj.getProperty<IntersectionObserver>(\"observer-inview\")?.disconnect();\r\n\r\n obj.htmlElement.removeAttribute(\"string-inited\");\r\n obj.leave();\r\n\r\n this.objects.delete(id);\r\n }\r\n\r\n /**\r\n * Add an element that will connect later.\r\n */\r\n public enqueueConnection(id: string, element: HTMLElement) {\r\n this.connectQueue.push({ id, element });\r\n }\r\n\r\n private getAllAttributes(el: HTMLElement): Record<string, any> {\r\n const attributes: Record<string, any> = {};\r\n Array.from(el.attributes).forEach((attr) => {\r\n attributes[attr.name] = attr.value;\r\n });\r\n return attributes;\r\n }\r\n\r\n private initObservers(obj: StringObject, el: HTMLElement) {\r\n const start = obj.getProperty<number>(\"offset-top\") ?? 0;\r\n const end = obj.getProperty<number>(\"offset-bottom\") ?? 0;\r\n const inviewTop = obj.getProperty<number>(\"inview-top\") ?? 0;\r\n const inviewBottom = obj.getProperty<number>(\"inview-bottom\") ?? 0;\r\n\r\n obj.getProperty<IntersectionObserver>(\"observer-progress\")?.disconnect();\r\n obj.getProperty<IntersectionObserver>(\"observer-inview\")?.disconnect();\r\n\r\n const progressCallback = (entries: IntersectionObserverEntry[]) => {\r\n entries.forEach((e) => {\r\n this.events.emit(`object:activate:${obj.id}`, e.isIntersecting);\r\n e.isIntersecting ? obj.enter() : obj.leave();\r\n });\r\n };\r\n\r\n const inviewCallback = (entries: IntersectionObserverEntry[]) => {\r\n entries.forEach((e) => {\r\n this.events.emit(`object:inview:${obj.id}`, e.isIntersecting);\r\n e.isIntersecting ? obj.show() : obj.hide();\r\n });\r\n };\r\n\r\n const progressObserver = new IntersectionObserver(progressCallback, {\r\n root: null,\r\n rootMargin: `${end + this.data.viewport.windowHeight}px 0px ${\r\n start + this.data.viewport.windowHeight\r\n }px 0px`,\r\n threshold: 0.001,\r\n });\r\n\r\n const inviewObserver = new IntersectionObserver(inviewCallback, {\r\n root: null,\r\n rootMargin: `${end + inviewTop}px 0px ${start + inviewBottom}px 0px`,\r\n threshold: 0.001,\r\n });\r\n\r\n progressObserver.observe(el);\r\n inviewObserver.observe(el);\r\n\r\n obj.setProperty(\"observer-progress\", progressObserver);\r\n obj.setProperty(\"observer-inview\", inviewObserver);\r\n }\r\n\r\n /**\r\n * Observes DOM mutations to auto-add/remove elements with [string] attribute.\r\n * Should be called once after DOM is ready.\r\n */\r\n public observeDOM(): void {\r\n const observer = new MutationObserver((mutations) => {\r\n mutations.forEach((mutation) => {\r\n if (mutation.type === \"childList\") {\r\n // Removed elements\r\n mutation.removedNodes.forEach((node) => {\r\n if (node.nodeType !== Node.ELEMENT_NODE) return;\r\n\r\n const element = node as HTMLElement;\r\n\r\n if (this.isFixed(element)) return;\r\n\r\n if (element.hasAttribute(\"string\")) {\r\n this.handleRemoved(element);\r\n }\r\n\r\n element\r\n .querySelectorAll(\"[string],[data-string]\")\r\n .forEach((child) => {\r\n if (this.isFixed(child as HTMLElement)) return;\r\n this.handleRemoved(child as HTMLElement);\r\n });\r\n });\r\n\r\n // Added elements\r\n mutation.addedNodes.forEach((node) => {\r\n if (node.nodeType !== Node.ELEMENT_NODE) return;\r\n\r\n const element = node as HTMLElement;\r\n\r\n if (this.isFixed(element)) return;\r\n\r\n if (\r\n element.hasAttribute(\"string\") &&\r\n !element.hasAttribute(\"string-inited\")\r\n ) {\r\n this.add(element);\r\n }\r\n\r\n element\r\n .querySelectorAll(\r\n \"[string]:not([string-inited]),[data-string]:not([string-inited])\"\r\n )\r\n .forEach((child) => this.add(child as HTMLElement));\r\n\r\n // Check for connect-from logic\r\n const copyFrom =\r\n element.getAttribute(\"string-copy-from\") ??\r\n element.getAttribute(\"data-string-copy-from\");\r\n if (copyFrom) {\r\n if (this.objects.has(copyFrom)) {\r\n this.objects.get(copyFrom)!.connects.push(element);\r\n } else {\r\n this.enqueueConnection(copyFrom, element);\r\n }\r\n }\r\n });\r\n\r\n // Let modules know about DOM rebuild\r\n this.modules.all.forEach((m) => m.onDOMRebuild());\r\n }\r\n });\r\n });\r\n\r\n observer.observe(document.body, {\r\n childList: true,\r\n subtree: true,\r\n });\r\n }\r\n\r\n /**\r\n * Removes an object and its observers.\r\n */\r\n private handleRemoved(el: HTMLElement): void {\r\n const id = el.getAttribute(\"string-id\");\r\n if (!id) return;\r\n\r\n const copyFrom =\r\n el.getAttribute(\"string-copy-from\") ??\r\n el.getAttribute(\"data-string-copy-from\");\r\n if (copyFrom) {\r\n this.connectQueue = this.connectQueue.filter((q) => q.id !== copyFrom);\r\n }\r\n\r\n this.remove(id);\r\n }\r\n\r\n /**\r\n * Re-applies module initialization logic to all managed objects after settings change.\r\n *\r\n * This method should be called when `StringSettings` are updated at runtime,\r\n * especially if the new settings affect how modules calculate offsets,\r\n * easing, origins, or custom configuration.\r\n *\r\n * Internally, it re-runs `initializeObject`, `calculatePositions`, and `connectObject`\r\n * for each core module that can connect to the object.\r\n *\r\n * This is useful for supporting dynamic configuration updates without requiring\r\n * a full DOM rebuild or reinitialization.\r\n */\r\n public onSettingsChange() {\r\n this.objects.forEach((object) => {\r\n this.modules.core.forEach((m) => {\r\n if (m.canConnect(object)) {\r\n const attributes = this.getAllAttributes(object.htmlElement);\r\n m.initializeObject(\r\n this.globalId,\r\n object,\r\n object.htmlElement,\r\n attributes\r\n );\r\n m.calculatePositions(object, this.data.viewport.windowHeight);\r\n m.connectObject(object);\r\n }\r\n });\r\n });\r\n }\r\n\r\n /**\r\n * Checks whether the element is marked as fixed (not managed).\r\n */\r\n private isFixed(el: HTMLElement): boolean {\r\n return el.hasAttribute(\"string-fixed\");\r\n }\r\n}\r\n","import { StringContext } from \"../StringContext\";\r\n\r\n/**\r\n * Base class for managing scroll behavior in the system.\r\n * Handles abstract scroll state and updates, intended for extension.\r\n */\r\nexport class ScrollController {\r\n /** Shared context containing data and tools */\r\n protected context: StringContext;\r\n\r\n /** Reference to the document object */\r\n protected document: Document;\r\n\r\n /** Name of the scroll mode (e.g. 'default', 'smooth', etc.) */\r\n public name: string = \"\";\r\n\r\n /** Whether the system is in programmatic scroll mode */\r\n public isProg: boolean = false;\r\n\r\n /** Whether parallax-related logic should be active */\r\n public isParallaxEnabled: boolean = false;\r\n\r\n /** Scroll direction: vertical or horizontal */\r\n protected _scrollDirection: \"vertical\" | \"horizontal\" = \"vertical\";\r\n\r\n /**\r\n * Sets scroll direction and updates internal scroll logic.\r\n * @param scrollDirection Either 'vertical' or 'horizontal'.\r\n */\r\n public set scrollDirection(scrollDirection: \"vertical\" | \"horizontal\") {\r\n this._scrollDirection = scrollDirection;\r\n\r\n if (this._scrollDirection === \"vertical\") {\r\n this.onCalcUpdate = () => {\r\n this.context.data.scroll.scrollContainer?.scrollTo(\r\n 0,\r\n this.context.data.scroll.current\r\n );\r\n // this.scrollContainer.scrollTo(0, this.context.data.scroll.current);\r\n };\r\n } else if (this._scrollDirection === \"horizontal\") {\r\n this.onCalcUpdate = () => {\r\n this.context.data.scroll.scrollContainer?.scrollTo(\r\n this.context.data.scroll.current,\r\n 0\r\n );\r\n // this.scrollContainer.scrollTo(this.context.data.scroll.current, 0);\r\n };\r\n }\r\n }\r\n\r\n /**\r\n * Creates a new ScrollController instance.\r\n * @param context Shared context containing data and settings.\r\n */\r\n constructor(context: StringContext) {\r\n this.document = document;\r\n this.context = context;\r\n }\r\n\r\n /**\r\n * Called when scroll direction changes (up ↔ down).\r\n * Override this callback in subclasses or instances.\r\n */\r\n public onChangeDirection = () => {};\r\n\r\n /**\r\n * Called when scroll starts (user input).\r\n * Override this callback in subclasses or instances.\r\n */\r\n public onScrollStart = () => {};\r\n\r\n /**\r\n * Called when scroll ends.\r\n * Override this callback in subclasses or instances.\r\n */\r\n public onScrollStop = () => {};\r\n\r\n /**\r\n * Scroll-to function called on each frame.\r\n * This will be reassigned depending on scroll direction.\r\n */\r\n public onCalcUpdate: () => void = () => {\r\n this.context.data.scroll.scrollContainer?.scrollTo(\r\n 0,\r\n this.context.data.scroll.current\r\n );\r\n };\r\n\r\n /**\r\n * Called every animation frame.\r\n * Intended to be overridden in subclasses.\r\n */\r\n public onFrame(): void {}\r\n\r\n /**\r\n * Called when wheel event is fired.\r\n * Override to implement custom scroll interaction.\r\n * @param e Wheel event.\r\n */\r\n public onWheel(e: any): void {}\r\n\r\n /**\r\n * Called when native scroll event is fired.\r\n * Override to track native scroll position.\r\n * @param e Scroll event.\r\n */\r\n public onScroll(e: any): void {}\r\n\r\n public disableScrollEvents(): void {}\r\n\r\n public enableScrollEvents(): void {}\r\n}\r\n","import { StringContext } from \"../StringContext\";\r\nimport { ScrollController } from \"./ScrollController\";\r\n\r\n/**\r\n * Default scroll controller using native browser scrolling behavior.\r\n * Handles `scrollTop`, easing delta over time for smooth lerped animations.\r\n */\r\nexport class StringScrollDefault extends ScrollController {\r\n /** Unique name identifier for this scroll mode. */\r\n public readonly name: string = 'default';\r\n\r\n /**\r\n * Constructs a new instance of the default scroll controller.\r\n * @param context Shared string system context.\r\n */\r\n constructor(context: StringContext) {\r\n super(context);\r\n }\r\n\r\n /**\r\n * Called every animation frame.\r\n * Applies easing to scroll delta and updates lerped value.\r\n * Fires `onScrollStop` once movement has settled.\r\n */\r\n public onFrame(): void {\r\n if (this.context.data.scroll.delta !== 0) {\r\n const delta = this.context.data.scroll.delta * this.context.data.scroll.speedAccelerate;\r\n this.context.data.scroll.delta -= delta;\r\n this.context.data.scroll.lerped = delta;\r\n\r\n if (Math.abs(this.context.data.scroll.lerped) < 0.1) {\r\n this.context.data.scroll.delta = 0;\r\n this.context.data.scroll.lerped = 0;\r\n this.onScrollStop();\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Called on native scroll event.\r\n * Syncs the internal scroll state with the current page scroll.\r\n * @param e Scroll event object (unused).\r\n */\r\n public onScroll(e: any): void {\r\n const scrollTop = this.context.data.scroll.elementContainer.scrollTop;\r\n this.context.data.scroll.current = scrollTop;\r\n this.context.data.scroll.target = scrollTop;\r\n this.context.data.scroll.transformedCurrent = scrollTop\r\n }\r\n\r\n /**\r\n * Handles wheel input by updating scroll delta for easing.\r\n * Triggers `onScrollStart` if delta begins from zero.\r\n * @param e Wheel event.\r\n */\r\n public onWheel(e: any): void {\r\n if (e.deltaY !== 0) {\r\n if (this.context.data.scroll.delta === 0) {\r\n this.onScrollStart();\r\n }\r\n\r\n const plusDelta = e.deltaY;\r\n\r\n // Prevent negative delta from triggering at top of scroll\r\n if (this.context.data.scroll.target === 0) {\r\n this.context.data.scroll.delta += Math.max(0, e.deltaY);\r\n }\r\n\r\n this.context.data.scroll.delta += plusDelta;\r\n }\r\n }\r\n}\r\n","import { StringContext } from \"../StringContext\";\r\nimport { ScrollController } from \"./ScrollController\";\r\n\r\n/**\r\n * Scroll controller that disables all user-initiated scrolling.\r\n * Prevents native scroll and wheel behavior, effectively locking the page.\r\n */\r\nexport class StringScrollDisable extends ScrollController {\r\n /** Unique name identifier for this scroll mode. */\r\n public readonly name: string = \"disable\";\r\n\r\n /**\r\n * Constructs the scroll disabling controller.\r\n * @param context The shared string system context.\r\n */\r\n\r\n private preventScroll = (e: Event) => {\r\n e.preventDefault();\r\n };\r\n\r\n private preventKeyScroll = (e: KeyboardEvent) => {\r\n const keysThatScroll = [\r\n \"ArrowUp\",\r\n \"ArrowDown\",\r\n \"PageUp\",\r\n \"PageDown\",\r\n \" \",\r\n \"Home\",\r\n \"End\",\r\n ];\r\n if (keysThatScroll.includes(e.key)) {\r\n e.preventDefault();\r\n }\r\n };\r\n\r\n private onPreventScroll = this.preventScroll.bind(this);\r\n private onPreventKeyScroll = this.preventKeyScroll.bind(this);\r\n\r\n constructor(context: StringContext) {\r\n super(context);\r\n }\r\n\r\n disableScrollEvents() {\r\n window.addEventListener(\"touchmove\", this.onPreventScroll, {\r\n passive: false,\r\n });\r\n window.addEventListener(\"keydown\", this.onPreventKeyScroll);\r\n }\r\n\r\n enableScrollEvents() {\r\n window.removeEventListener(\"touchmove\", this.onPreventScroll);\r\n window.removeEventListener(\"keydown\", this.onPreventKeyScroll);\r\n }\r\n\r\n /**\r\n * Called on each animation frame.\r\n * Not used in this controller since scrolling is disabled.\r\n */\r\n public onFrame(): void {}\r\n\r\n /**\r\n * Prevents scroll via mouse wheel.\r\n * @param e Wheel event.\r\n */\r\n public onWheel(e: any): void {\r\n e.preventDefault();\r\n }\r\n\r\n /**\r\n * Prevents scroll via native scroll interaction (e.g. touch).\r\n * @param e Scroll event.\r\n */\r\n public onScroll(e: any): void {\r\n e.preventDefault();\r\n }\r\n}\r\n","import { StringContext } from \"../StringContext\";\r\nimport { ScrollController } from \"./ScrollController\";\r\n\r\n/**\r\n * CSS class names applied to `<html>` element based on scroll direction.\r\n */\r\nconst CLASS_NAMES = {\r\n SCROLL_FORWARD: '-scroll-forward',\r\n SCROLL_BACK: '-scroll-back',\r\n} as const;\r\n\r\n/**\r\n * Smooth scroll controller with delta-based acceleration and direction tracking.\r\n * Handles wheel events and scroll position updates with smooth interpolation.\r\n */\r\nexport class StringScrollSmooth extends ScrollController {\r\n /** \r\n * Unique identifier for this scroll controller type.\r\n * Used for selection and debug purposes.\r\n */\r\npublic readonly name: string = 'smooth';\r\n\r\n/** \r\n * Whether the user has manually scrolled using the native scrollbar.\r\n * When true, the scroll position is directly synced from DOM on next frame.\r\n */\r\nprivate isScrollbarManipulation = false;\r\n\r\n/** \r\n * Current internal force applied to the scroll target.\r\n * Calculated from accumulated scroll impulse and acceleration.\r\n */\r\nprivate scrollForce: number = 0;\r\n\r\n/** \r\n * Latest raw scroll impulse received from the wheel event (`deltaY`).\r\n * Temporarily stored for direction and boundary checks.\r\n */\r\nprivate wheelImpulse: number = 0;\r\n\r\n/** \r\n * Scroll position from the previous frame.\r\n * Used to detect actual movement and trigger updates only when needed.\r\n */\r\nprivate previousCurrent: number = 0;\r\n\r\n/** \r\n * Current scroll direction.\r\n * - `true` — scrolling down\r\n * - `false` — scrolling up\r\n * - `null` — unknown (initial state)\r\n */\r\nprivate isBottomScrollDirection: boolean | null = null;\r\n\r\n/** \r\n * Minimum velocity threshold below which scrolling is considered stopped.\r\n * Prevents micro-movements from continuing infinite smooth scroll.\r\n */\r\nprivate readonly velocityThreshold = 0.1;\r\n\r\n\r\n constructor(context: StringContext) {\r\n super(context);\r\n }\r\n\r\n /**\r\n * Handles scroll direction changes and toggles CSS classes accordingly.\r\n * @param newDirection `true` if scrolling down, `false` if up.\r\n */\r\n private updateScrollDirection(newDirection: boolean) {\r\n if (this.isBottomScrollDirection === null) {\r\n this.isBottomScrollDirection = newDirection;\r\n return;\r\n }\r\n this.context.data.scroll.isScrollingDown = newDirection;\r\n this.onChangeDirection();\r\n\r\n document.documentElement.classList.toggle(CLASS_NAMES.SCROLL_FORWARD, newDirection);\r\n document.documentElement.classList.toggle(CLASS_NAMES.SCROLL_BACK, !newDirection);\r\n }\r\n\r\n /**\r\n * Immediately stops scrolling and resets all deltas and directions.\r\n */\r\n public stopScroll(): void {\r\n this.context.data.scroll.lerped = 0;\r\n this.context.data.scroll.delta = 0;\r\n this.context.data.scroll.target = this.context.data.scroll.current;\r\n this.isProg = false;\r\n this.onCalcUpdate();\r\n document.documentElement.classList.remove(CLASS_NAMES.SCROLL_BACK, CLASS_NAMES.SCROLL_FORWARD);\r\n this.isBottomScrollDirection = null;\r\n }\r\n\r\n /**\r\n * Called on each animation frame to apply lerped scroll logic.\r\n */\r\n public onFrame(): void {\r\n if (this.isScrollbarManipulation) {\r\n this.isScrollbarManipulation = false;\r\n this.context.data.scroll.current = this.context.data.scroll.elementContainer.scrollTop\r\n this.context.data.scroll.target = this.context.data.scroll.elementContainer.scrollTop\r\n this.context.data.scroll.transformedCurrent = this.context.data.scroll.current * this.context.data.viewport.transformScale\r\n return;\r\n }\r\n\r\n \r\n if (this.context.data.scroll.delta !== 0) {\r\n this.scrollForce = this.context.data.scroll.delta * this.context.data.scroll.speedAccelerate;\r\n\r\n this.context.data.scroll.target = Math.min(\r\n Math.max(0, this.context.data.scroll.target + this.scrollForce),\r\n this.context.data.scroll.bottomPosition\r\n );\r\n this.context.data.scroll.delta -= this.scrollForce;\r\n\r\n this.context.data.scroll.lerped = \r\n (this.context.data.scroll.target - this.context.data.scroll.current) * \r\n this.context.data.scroll.speed;\r\n\r\n const absVelocity = Math.abs(this.context.data.scroll.lerped);\r\n if (this.context.data.scroll.lerped > 0) {\r\n this.context.data.scroll.current = Math.ceil(this.context.data.scroll.current + this.context.data.scroll.lerped);\r\n } else {\r\n this.context.data.scroll.current = Math.floor(this.context.data.scroll.current + this.context.data.scroll.lerped);\r\n }\r\n \r\n this.context.data.scroll.transformedCurrent = this.context.data.scroll.current * this.context.data.viewport.transformScale\r\n this.updateScrollDirection(this.context.data.scroll.lerped > 0);\r\n\r\n if (absVelocity < this.velocityThreshold) {\r\n this.stopScroll();\r\n this.onScrollStop();\r\n } else {\r\n this.isProg = true;\r\n if (this.previousCurrent !== this.context.data.scroll.current) {\r\n this.previousCurrent = this.context.data.scroll.current;\r\n this.onCalcUpdate();\r\n }\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Handles user wheel input to accumulate scroll delta.\r\n * @param e The WheelEvent from the browser.\r\n */\r\n public onWheel(e: WheelEvent): void {\r\n if (e.deltaY !== 0) {\r\n e.preventDefault();\r\n }\r\n\r\n this.wheelImpulse = e.deltaY;\r\n if (this.wheelImpulse === 0) return;\r\n\r\n if (this.context.data.scroll.delta === 0) {\r\n this.onScrollStart();\r\n }\r\n \r\n const scrollDirection = Math.sign(this.wheelImpulse);\r\n const atTop = this.context.data.scroll.target === 0 && scrollDirection < 0;\r\n const atBottom = this.context.data.scroll.target === this.context.data.scroll.bottomPosition && scrollDirection > 0;\r\n if (atTop || atBottom) return;\r\n this.context.data.scroll.delta += this.wheelImpulse;\r\n }\r\n\r\n /**\r\n * Detects native scrollbar manipulation when smooth scroll is idle.\r\n * @param e Scroll event.\r\n */\r\n public onScroll(e: Event): void {\r\n if (!this.isProg) {\r\n this.isScrollbarManipulation = true;\r\n }\r\n }\r\n}\r\n","import { ScrollMode } from \"../../states/ScrollState\";\r\nimport { ScrollController } from \"../controllers/ScrollController\";\r\nimport { StringScrollDefault } from \"../controllers/StringScrollDefault\";\r\nimport { StringScrollDisable } from \"../controllers/StringScrollDisable\";\r\nimport { StringScrollSmooth } from \"../controllers/StringScrollSmooth\";\r\nimport { StringContext } from \"../StringContext\";\r\n\r\n/**\r\n * Handles scroll engine setup and switching logic.\r\n * Synchronizes scroll modes with the centralized ScrollState inside StringContext.\r\n */\r\nexport class ScrollManager {\r\n private modes: Map<ScrollMode, ScrollController> = new Map();\r\n\r\n constructor(private context: StringContext) {\r\n this.modes.set(\"smooth\", new StringScrollSmooth(context));\r\n this.modes.set(\"default\", new StringScrollDefault(context));\r\n this.modes.set(\"disable\", new StringScrollDisable(context));\r\n\r\n // Initial mode based on screen width\r\n this.updateResponsiveMode();\r\n }\r\n\r\n /**\r\n * Manually sets the scroll mode for mobile devices.\r\n * @param mode The scroll mode: 'smooth', 'default', or 'disable'.\r\n */\r\n public setMobileMode(mode: ScrollMode): void {\r\n this.context.data.scroll.modeMobile = mode;\r\n this.updateResponsiveMode();\r\n }\r\n\r\n /**\r\n * Manually sets the scroll mode for desktop devices.\r\n * @param mode The scroll mode: 'smooth', 'default', or 'disable'.\r\n */\r\n public setDesktopMode(mode: ScrollMode): void {\r\n this.context.data.scroll.modeDesktop = mode;\r\n this.updateResponsiveMode();\r\n }\r\n\r\n /**\r\n * Automatically switches scroll mode based on screen width.\r\n * Call this inside your resize handler.\r\n */\r\n public updateResponsiveMode(): void {\r\n const isMobile = window.innerWidth < 1080;\r\n const newMode = isMobile\r\n ? this.context.data.scroll.modeMobile\r\n : this.context.data.scroll.modeDesktop;\r\n\r\n this.setMode(newMode);\r\n }\r\n\r\n public updatePosition(): void {\r\n this.modes.forEach((engine) => {\r\n engine.onCalcUpdate();\r\n });\r\n }\r\n\r\n /**\r\n * Sets the current scroll mode and updates the active scroll engine.\r\n * @param mode The scroll mode to activate.\r\n */\r\n public setMode(mode: ScrollMode): void {\r\n if (!this.modes.has(mode)) {\r\n console.warn(`[ScrollManager] Unknown scroll mode: ${mode}`);\r\n return;\r\n }\r\n this.get().enableScrollEvents();\r\n this.context.data.scroll.mode = mode;\r\n this.get().disableScrollEvents();\r\n }\r\n\r\n /**\r\n * Returns the currently active scroll engine based on state.\r\n */\r\n public get(): ScrollController {\r\n return this.modes.get(this.context.data.scroll.mode)!;\r\n }\r\n\r\n /**\r\n * Returns all available scroll engine instances.\r\n */\r\n public getEngines(): Map<ScrollMode, ScrollController> {\r\n return this.modes;\r\n }\r\n\r\n /**\r\n * Calls `onFrame()` on the current scroll engine.\r\n */\r\n public onFrame(): void {\r\n this.get().onFrame();\r\n }\r\n\r\n /**\r\n * Forwards native scroll event to the current scroll engine.\r\n * @param e The scroll event.\r\n */\r\n public onScroll(e: Event): void {\r\n this.get().onScroll(e);\r\n }\r\n\r\n /**\r\n * Forwards wheel event to the current scroll engine.\r\n * @param e The wheel event.\r\n */\r\n public onWheel(e: WheelEvent): void {\r\n this.get().onWheel(e);\r\n }\r\n\r\n /**\r\n * Subscribes lifecycle event handlers to all scroll engines.\r\n * @param events Scroll lifecycle callbacks.\r\n */\r\n public bindEvents(events: {\r\n onScrollStart: () => void;\r\n onScrollStop: () => void;\r\n onDirectionChange: () => void;\r\n }) {\r\n this.modes.forEach((engine) => {\r\n engine.onScrollStart = events.onScrollStart;\r\n engine.onScrollStop = events.onScrollStop;\r\n engine.onChangeDirection = events.onDirectionChange;\r\n });\r\n }\r\n}\r\n","/**\r\n * Reactive cursor data for raw, target, smoothed and step deltas.\r\n */\r\nexport class CursorState {\r\n /**\r\n * Target X position of the cursor (e.g., from `mousemove`)\r\n */\r\n targetX: number = 0\r\n\r\n /**\r\n * Target Y position of the cursor.\r\n */\r\n targetY: number = 0\r\n\r\n /**\r\n * Smoothed X position after applying lerp.\r\n */\r\n smoothedX: number = 0\r\n\r\n /**\r\n * Smoothed Y position after applying lerp.\r\n */\r\n smoothedY: number = 0\r\n\r\n /**\r\n * Delta step between current and target X (used internally for lerp).\r\n */\r\n stepX: number = 0\r\n\r\n /**\r\n * Delta step between current and target Y.\r\n */\r\n stepY: number = 0\r\n}\r\n","/**\r\n * Global Three.js or rendering context reference.\r\n */\r\nexport class RenderState {\r\n /** Instance of Three.js or another render context */\r\n threeInstance: any = null\r\n}\r\n","export type ScrollDirection = 'vertical' | 'horizontal'\r\nexport type ScrollMode = 'smooth' | 'disable' | 'default'\r\n\r\n/**\r\n * Describes current scroll-related state for all calculations and modules.\r\n */\r\nexport class ScrollState {\r\n /** Target scroll value — where we want to scroll to (used in smooth scroll) */\r\n target: number = 0\r\n\r\n /** Current scroll value (actual scroll position) */\r\n current: number = 0\r\n\r\n /** Transformed current scroll value (with transform by scroll container) */\r\n transformedCurrent: number = 0\r\n\r\n /** Delta between frames (used for animation / velocity) */\r\n delta: number = 0\r\n\r\n /** Interpolated scroll value for smooth transitions */\r\n lerped: number = 0\r\n\r\n /** Displacement value (similar to lerped, but used for other animations) */\r\n displacement: number = 0\r\n\r\n /** Whether scroll direction is downward */\r\n isScrollingDown: boolean = false\r\n\r\n /** Top screen scroll position */\r\n topPosition: number = 0\r\n\r\n /** Bottom screen scroll position */\r\n bottomPosition: number = 0\r\n\r\n /** Scroll direction (vertical / horizontal) */\r\n direction: ScrollDirection = 'vertical'\r\n\r\n /** Scroll container element */\r\n elementContainer: HTMLElement = document.documentElement\r\n\r\n /** Scroll container element */\r\n scrollContainer: HTMLElement | Window = window\r\n\r\n /** Scroll container element */\r\n container: HTMLElement = document.body\r\n\r\n /**\r\n * Currently active scroll mode.\r\n * Can be 'smooth', 'default', or 'disable'.\r\n */\r\n mode: ScrollMode = 'smooth'\r\n\r\n /**\r\n * Scroll mode to use on mobile devices.\r\n * Can be 'smooth', 'default', or 'disable'.\r\n */\r\n modeMobile: ScrollMode = 'smooth'\r\n\r\n /**\r\n * Scroll mode to use on desktop devices.\r\n * Can be 'smooth', 'default', or 'disable'.\r\n */\r\n modeDesktop: ScrollMode = 'smooth'\r\n\r\n /**\r\n * Base scroll speed used for calculating smooth scrolling.\r\n * Typically a small value between 0 and 1.\r\n */\r\n speed: number = 0.1\r\n\r\n /**\r\n * Acceleration factor used for scroll easing or velocity-based animations.\r\n * Also typically a value between 0 and 1.\r\n */\r\n speedAccelerate: number = 0.25\r\n}\r\n","/**\r\n * Represents the time-related state of the current and previous animation frames.\r\n * \r\n * Useful for calculating delta time, total elapsed time, and implementing\r\n * time-based animations or physics.\r\n */\r\nexport class TimeState {\r\n /**\r\n * Timestamp of the current animation frame in milliseconds.\r\n * This value is typically obtained via `performance.now()`.\r\n */\r\n now: number = 0;\r\n\r\n /**\r\n * Timestamp of the previous animation frame in milliseconds.\r\n */\r\n previous: number = 0;\r\n\r\n /**\r\n * Time difference between the current and previous frames in milliseconds.\r\n * Commonly used to calculate animation progress.\r\n */\r\n delta: number = 0;\r\n\r\n /**\r\n * Total time elapsed since the start of the animation or system in milliseconds.\r\n */\r\n elapsed: number = 0;\r\n}\r\n","/**\r\n * Describes current viewport size and scaling.\r\n */\r\nexport class ViewportState {\r\n /** Width of the visible window */\r\n windowWidth: number = 0\r\n\r\n /** Height of the visible window */\r\n windowHeight: number = 0\r\n\r\n /** Full scroll width (content width inside scroll container) */\r\n contentWidth: number = 0\r\n\r\n /** Full scroll height (content height inside scroll container) */\r\n contentHeight: number = 0\r\n\r\n /** Screen scale ratio for width (e.g. device pixel ratio or zoom level) */\r\n scaleWidth: number = 1\r\n\r\n /** Screen scale ratio for height */\r\n scaleHeight: number = 1\r\n\r\n transformScale: number = 1\r\n\r\n baseRem: number = 16\r\n}\r\n","import { CursorState } from \"../states/CursorState\"\r\nimport { RenderState } from \"../states/RenderState\"\r\nimport { ScrollState } from \"../states/ScrollState\"\r\nimport { TimeState } from \"../states/TimeState\"\r\nimport { ViewportState } from \"../states/ViewportState\"\r\n\r\n/**\r\n * Container for global dynamic state used throughout the string-tune system.\r\n * Provides access to live scroll, viewport, cursor, and render states,\r\n * which are updated each frame and shared across modules and tools.\r\n */\r\nexport class StringData {\r\n /**\r\n * Scroll-related state object.\r\n * Contains live values like `target`, `current`, `delta`, `direction`, and more.\r\n * Used for scroll-based animations, transitions, and effects.\r\n */\r\n scroll = new ScrollState()\r\n\r\n /**\r\n * Viewport-related state object.\r\n * Holds dimensions like window size, content size, aspect ratios, and more.\r\n * Useful for layout calculations, unit parsing, and element positioning.\r\n */\r\n viewport = new ViewportState()\r\n\r\n /**\r\n * Cursor-related state object.\r\n * Tracks cursor position, velocity, movement, and derived values.\r\n * Can be used for pointer interactions, proximity effects, and hover states.\r\n */\r\n cursor = new CursorState()\r\n\r\n /**\r\n * Render-related state object.\r\n * Stores data related to rendering context (e.g. WebGL, Three.js),\r\n * such as shared materials, textures, or active render frame data.\r\n */\r\n render = new RenderState()\r\n\r\n /**\r\n * Time-related state object.\r\n * Tracks frame timings, including current timestamp, delta between frames,\r\n * and total elapsed time since animation start.\r\n * Useful for time-based animations, easing, frame consistency, and syncing logic.\r\n */\r\n time = new TimeState()\r\n}\r\n","import { IStringModule } from './IStringModule'\r\nimport { StringObject } from '../objects/StringObject'\r\nimport { StringToolsContainer } from './StringToolsContainer'\r\nimport { StringData } from './StringData'\r\nimport { AttributeType } from '../models/attribute/AttributeType'\r\nimport { StringContext } from './StringContext'\r\nimport { EventManager } from './managers/EventManager'\r\nimport { AttributeMapping } from '../models/attribute/AttributeMapping'\r\n\r\n\r\n\r\n\r\n/**\r\n * Base class for a module used in the string-tune system.\r\n * Extend this class to create custom modules that respond to scroll, resize, input, etc.\r\n */\r\nexport class StringModule implements IStringModule {\r\n \r\n /**\r\n * List of attribute names this module should automatically read\r\n * from the DOM element and assign to the object properties.\r\n * Example: [\"offset-top\", \"offset-bottom\"]\r\n */\r\n protected attributesToMap: AttributeMapping[]\r\n\r\n /**\r\n * A map of all entered objects by their unique ID.\r\n */\r\n protected objectMap: Map<string, StringObject> = new Map()\r\n\r\n /**\r\n * A flat array of all connected objects.\r\n */\r\n protected objects: StringObject[] = []\r\n\r\n /**\r\n * The HTML attribute key that identifies objects this module is responsible for.\r\n */\r\n protected htmlKey: string = ''\r\n\r\n /**\r\n * Module type ID used internally to categorize module behavior.\r\n */\r\n protected _type: number = 1\r\n\r\n /**\r\n * Returns the type of the module.\r\n * Type 1 = core module, type 2 = UI module.\r\n */\r\n public get type(): number {\r\n return this._type\r\n }\r\n\r\n /**\r\n * Tools container providing utilities for attribute parsing, unit conversion, etc.\r\n * Acts as a dependency injection hub for core IStringTool implementations.\r\n */\r\n protected tools: StringToolsContainer\r\n\r\n /**\r\n * Shared global data object containing scroll state, viewport info, cursor position, etc.\r\n * Used for calculations within lifecycle hooks like `onScroll`, `onFrame`, and `onResize`.\r\n */\r\n protected data: StringData\r\n\r\n /**\r\n * Configuration object specific to the current module.\r\n * Passed in during module registration or initialization.\r\n */\r\n protected settings: Record<string, any>\r\n\r\n /**\r\n * Event hub for communication between modules or systems.\r\n * Supports custom event emitting, listening, and unsubscription.\r\n */\r\n protected events: EventManager\r\n\r\n\r\n\r\n constructor(context: StringContext) {\r\n this.tools = context.tools\r\n this.data = context.data\r\n this.settings = context.settings\r\n this.events = context.events\r\n\r\n\r\n\r\n this.attributesToMap = [\r\n { key: 'active', type: \"boolean\", fallback: this.settings['active'] },\r\n { key: 'fixed', type: \"boolean\", fallback: this.settings['fixed'] },\r\n { key: 'repeat', type: \"boolean\", fallback: this.settings['repeat'] },\r\n { key: 'self-disable', type: \"boolean\", fallback: this.settings['self-disable'] },\r\n { key: 'abs', type: \"boolean\", fallback: this.settings['abs'] },\r\n { key: 'key', type: \"string\", fallback: this.settings['key'] },\r\n { key: 'offset-top', type: \"dimension\", fallback: this.settings['offset-top'] },\r\n { key: 'offset-bottom', type: \"dimension\", fallback: this.settings['offset-bottom'] },\r\n { key: 'inview-top', type: \"dimension\", fallback: this.settings['inview-top'] },\r\n { key: 'inview-bottom', type: \"dimension\", fallback: this.settings['inview-bottom'] },\r\n {\r\n key: 'start', type: \"number\", fallback: (element: HTMLElement, object: StringObject, boundingRect: DOMRect) => {\r\n const top = boundingRect.top\r\n return Math.floor(top) + this.data.scroll.container.scrollTop * this.data.viewport.transformScale\r\n }\r\n },\r\n {\r\n key: 'end', type: \"number\", fallback: (element: HTMLElement, object: StringObject, boundingRect: DOMRect) => {\r\n const top = boundingRect.top\r\n const height = boundingRect.height\r\n return top + height - this.data.scroll.transformedCurrent\r\n }\r\n },\r\n {\r\n key: 'size', type: \"number\", fallback: (element: HTMLElement, object: StringObject, boundingRect: DOMRect) => {\r\n return boundingRect.height\r\n }\r\n },\r\n {\r\n key: 'half-width', type: \"number\", fallback: (element: HTMLElement, object: StringObject, boundingRect: DOMRect) => {\r\n return boundingRect.width / 2\r\n }\r\n },\r\n {\r\n key: 'half-height', type: \"number\", fallback: (element: HTMLElement, object: StringObject, boundingRect: DOMRect) => {\r\n return boundingRect.height / 2\r\n }\r\n },\r\n ]\r\n }\r\n\r\n /**\r\n * Called when a DOM element is detected as a potential interactive object.\r\n */\r\n initializeObject(\r\n globalId: number,\r\n object: StringObject,\r\n element: HTMLElement,\r\n attributes: Record<string, any>\r\n ): void {\r\n let boundingRect = this.tools.boundingClientRect.process({ element })\r\n for (const { key, type, fallback, transform } of this.attributesToMap) {\r\n const resolvedFallback =\r\n typeof fallback === 'function' ? fallback(element, object, boundingRect) : fallback\r\n const raw = this.tools.domAttribute.process({\r\n element,\r\n key,\r\n fallback: attributes[key] ?? this.settings[key] ?? resolvedFallback\r\n })\r\n\r\n let parsed = this.parseAttribute(raw, type, {\r\n element,\r\n viewportHeight: this.data.viewport.windowHeight,\r\n baseRem: this.data.viewport.baseRem\r\n })\r\n\r\n if (transform) {\r\n parsed = transform(parsed)\r\n }\r\n object.setProperty(key, parsed)\r\n }\r\n }\r\n\r\n /**\r\n * Calculates object-specific positions or metrics based on the current layout or scroll state.\r\n * This method is intended to be overridden in subclasses if the module needs to precompute\r\n * layout-dependent values (e.g. parallax offsets, trigger zones, distances).\r\n *\r\n * @param object The `StringObject` instance whose positions are being calculated.\r\n * @param windowSize The current window height or width (depending on scroll axis).\r\n */\r\n calculatePositions(object: StringObject, windowSize: number) {\r\n }\r\n\r\n /**\r\n * Parses a raw DOM attribute value into the correct type based on mapping.\r\n * Handles fallback resolution, transformation, and special units.\r\n *\r\n * @param value Raw attribute string from DOM.\r\n * @param type The expected attribute type (e.g. number, boolean, dimension).\r\n * @param context Optional helper values like element or viewport size.\r\n * @returns The parsed and transformed value.\r\n */\r\n protected parseAttribute(\r\n value: string | null,\r\n type: AttributeType,\r\n context: {\r\n element?: HTMLElement\r\n viewportHeight?: number\r\n baseRem?: number\r\n } = {}\r\n ): any {\r\n if (value == null) return null\r\n\r\n if (typeof type === 'object' && type.type === 'enum') {\r\n return type.values.includes(value) ? value : type.values[0]\r\n }\r\n\r\n switch (type) {\r\n case \"number\":\r\n return parseFloat(value)\r\n\r\n case \"boolean\":\r\n return value === \"\" || value === \"true\";\r\n\r\n case \"json\":\r\n try {\r\n return JSON.parse(value)\r\n } catch {\r\n return null\r\n }\r\n\r\n case \"tuple\":\r\n return value.trim().split(/\\s+/)\r\n \r\n case \"easing\":\r\n return this.tools.easingFunction.process({ easing: value })\r\n \r\n case \"color\":\r\n return this.tools.colorParser.process({ value: value })\r\n \r\n case \"dimension\":\r\n if (value == \"0\") return 0;\r\n if (context.element != null && context.viewportHeight != null && context.baseRem != null) {\r\n return this.tools.unitParser.process({\r\n value,\r\n element: context.element,\r\n viewportHeight: context.viewportHeight,\r\n baseRem: context.baseRem\r\n })\r\n } else {\r\n return 0\r\n }\r\n \r\n default:\r\n return value\r\n }\r\n }\r\n\r\n /**\r\n * Determines whether the module should attach to a given object,\r\n * based on the presence of the module's `htmlKey` in the object keys.\r\n *\r\n * @param object The target object to test.\r\n * @returns `true` if the module can connect, `false` otherwise.\r\n */\r\n canConnect(object: StringObject): boolean {\r\n return object.keys.includes(this.htmlKey)\r\n }\r\n\r\n /**\r\n * Registers the module on a given object, adds the object to internal list,\r\n * and triggers connection logic.\r\n *\r\n * @param object The object to connect to.\r\n */\r\n connectObject(object: StringObject): void {\r\n object.connect(this)\r\n this.onObjectConnected(object)\r\n }\r\n\r\n /**\r\n * Registers the object internally when it enters the module’s scope.\r\n */\r\n enterObject(id: string, object: StringObject): void {\r\n if (!this.objectMap.has(id)) {\r\n this.objectMap.set(id, object)\r\n this.objects.push(object)\r\n }\r\n }\r\n\r\n /**\r\n * Unregisters the object when it leaves the module’s scope.\r\n */\r\n exitObject(id: string): void {\r\n const object = this.objectMap.get(id)\r\n if (!object) return\r\n\r\n this.objectMap.delete(id)\r\n\r\n const index = this.objects.indexOf(object)\r\n if (index !== -1) {\r\n this.objects.splice(index, 1)\r\n }\r\n }\r\n\r\n /**\r\n * Called when an object is connected. Can be overridden to apply initial styles or logic.\r\n * @param object The connected object.\r\n */\r\n onObjectConnected(object: StringObject): void { }\r\n \r\n /**\r\n * Applies a style or callback to both the main element and all its connected elements.\r\n * \r\n * @param object The object whose elements to update.\r\n * @param applyFn The function that receives an HTMLElement and performs any update.\r\n */\r\n protected applyToElementAndConnects(object: StringObject, applyFn: (el: HTMLElement) => void) {\r\n applyFn(object.htmlElement)\r\n object.connects.forEach(applyFn)\r\n }\r\n\r\n /**\r\n * Cleans up internal state and detaches the module from the system.\r\n */\r\n destroy(): void {\r\n this.objects = []\r\n this.objectMap = new Map()\r\n }\r\n\r\n // ───────────────────────────────\r\n // Lifecycle Hooks\r\n // ───────────────────────────────\r\n\r\n /** Called once when the module is initialized. */\r\n onInit(): void {}\r\n\r\n /** Called on each frame with current scroll and state data. */\r\n onFrame(data: StringData): void {}\r\n\r\n /** Called when the window or layout is resized. */\r\n onResize(): void {}\r\n\r\n /** Called when scroll position changes. */\r\n onScroll(data: StringData): void {}\r\n\r\n /** Called when user changed scroll diraction. */\r\n onDirectionChange(): void {}\r\n\r\n /** Called when user starts scrolling. */\r\n onScrollStart(): void {}\r\n\r\n /** Called when user stops scrolling. */\r\n onScrollStop(): void {}\r\n\r\n /** Called when scroll direction changes (e.g., up ↔ down). */\r\n onScrollDirectionChange(): void {}\r\n\r\n /** Called when scroll axis changes (vertical ↔ horizontal). */\r\n onAxisChange(): void {}\r\n\r\n /** Called when device type changes (e.g., desktop ↔ mobile). */\r\n onDeviceChange(): void {}\r\n\r\n /** Called when scroll-related system settings or parameters change. */\r\n onScrollConfigChange(): void {}\r\n\r\n /** Called when scroll-related system settings or parameters change. */\r\n onSettingsChange(): void {}\r\n\r\n /** Called when the DOM is rebuilt, such as after a major mutation. */\r\n onDOMRebuild(): void {}\r\n\r\n /** Called on every mouse movement. */\r\n onMouseMove(event: MouseEvent): void {}\r\n\r\n /** Called on wheel input (independent of scroll). */\r\n onWheel(event: WheelEvent): void {}\r\n\r\n /**\r\n * Called when DOM elements are added or removed.\r\n */\r\n onDOMMutate(added: NodeList, removed: NodeList): void {}\r\n}\r\n","import { IStringTool } from \"../core/IStringTool\"\r\n\r\n/**\r\n * Input for `BoundingClientRectTool`.\r\n */\r\ninterface BoundingClientRectInput {\r\n /** The DOM element to retrieve bounding rect from. */\r\n element: HTMLElement\r\n}\r\n\r\n/**\r\n * Tool for accessing `getBoundingClientRect()` in a consistent, testable way.\r\n */\r\nexport default class BoundingClientRectTool\r\n implements IStringTool<BoundingClientRectInput, DOMRect>\r\n{\r\n /**\r\n * @returns The bounding client rect of the provided element.\r\n */\r\n process({ element }: BoundingClientRectInput): DOMRect {\r\n return element.getBoundingClientRect()\r\n }\r\n}\r\n","import { IStringTool } from \"../core/IStringTool\"\r\n\r\ninterface DOMAttributeInput {\r\n element: HTMLElement\r\n key: string // for example: \"offset-tom\"\r\n fallback?: string | null\r\n}\r\n\r\nexport default class DOMAttributeTool implements IStringTool<DOMAttributeInput, string | null> {\r\n /**\r\n * Retrieves the value of either `string-${key}` or `data-string-${key}` attribute.\r\n *\r\n * @example key = \"offset-tom\" → tries:\r\n * - element.getAttribute(\"string-offset-tom\")\r\n * - element.getAttribute(\"data-string-offset-tom\")\r\n */\r\n process({ element, key, fallback = null }: DOMAttributeInput): string | null {\r\n return (\r\n element.getAttribute(`string-${key}`) ??\r\n element.getAttribute(`data-string-${key}`) ??\r\n fallback\r\n )\r\n }\r\n}\r\n","import { IStringTool } from \"../core/IStringTool\"\r\n\r\n/**\r\n * Input for retrieving a value from a key-value object or dataset-like structure.\r\n */\r\ninterface RecordAttributeInput {\r\n /** Source object to read from (e.g. dataset or plain record). */\r\n record: Record<string, any>\r\n\r\n /** Key to look up (without `\"data-\"` prefix). */\r\n name: string\r\n\r\n /** Fallback value if both keys are missing. */\r\n fallback?: any\r\n}\r\n\r\n/**\r\n * Retrieves a value from an object or dataset-like structure.\r\n * Tries `record[name]` first, then `record[\"data-\" + name]`, or returns fallback.\r\n */\r\nexport default class RecordAttributeTool implements IStringTool<RecordAttributeInput, any> {\r\n /**\r\n * @returns Value from the record or fallback.\r\n */\r\n process({ record, name, fallback = null }: RecordAttributeInput): any {\r\n return (\r\n record[name] ??\r\n record[`data-${name}`] ??\r\n fallback\r\n )\r\n }\r\n}\r\n","import { IStringTool } from \"../core/IStringTool\"\r\n\r\n/**\r\n * Input for removing transform effects from an element's bounding box.\r\n */\r\ninterface TransformNullifyInput {\r\n /** The DOM element whose CSS transform should be nullified. */\r\n element: HTMLElement\r\n}\r\n\r\n/**\r\n * Output with corrected bounding box values.\r\n */\r\ninterface TransformNullifyOutput {\r\n /** Top position without transform effects. */\r\n top: number\r\n\r\n /** Left position without transform effects. */\r\n left: number\r\n\r\n /** Width without transform scaling. */\r\n width: number\r\n\r\n /** Height without transform scaling. */\r\n height: number\r\n}\r\n\r\n/**\r\n * Computes the true bounding box of a DOM element,\r\n * nullifying CSS `transform: matrix(...)` effects.\r\n */\r\nexport default class TransformNullifyTool\r\n implements IStringTool<TransformNullifyInput, TransformNullifyOutput>\r\n{\r\n /**\r\n * @returns Element position and size without transform influence.\r\n */\r\n process({ element }: TransformNullifyInput): TransformNullifyOutput {\r\n const rect = element.getBoundingClientRect()\r\n const matrix = getComputedStyle(element).transform\r\n\r\n const values = matrix\r\n .match(/-?[\\d.]+/g)\r\n ?.map(parseFloat) ?? []\r\n\r\n if (values.length === 6) {\r\n const [a, b, c, d, e, f] = values\r\n const det = a * d - b * c\r\n\r\n return {\r\n width: rect.width / (a || 1),\r\n height: rect.height / (d || 1),\r\n left: (rect.left * d - rect.top * c + c * f - e * d) / det,\r\n top: (-rect.left * b + rect.top * a + e * b - a * f) / det,\r\n }\r\n }\r\n\r\n return rect\r\n }\r\n}\r\n","import { IStringTool } from \"../core/IStringTool\"\r\nimport TransformNullifyTool from \"./TransformNullifyTool\"\r\n\r\n/**\r\n * Input for calculating the position of an element relative to a container.\r\n */\r\ninterface RelativePositionInput {\r\n /** The DOM element whose position should be calculated. */\r\n element: HTMLElement\r\n\r\n /** Optional container to measure against. Defaults to `document.body`. */\r\n container?: HTMLElement\r\n}\r\n\r\n/**\r\n * Output: relative position in pixels.\r\n */\r\ninterface RelativePositionOutput {\r\n /** Distance from the top of the container. */\r\n top: number\r\n\r\n /** Distance from the left of the container. */\r\n left: number\r\n}\r\n\r\n/**\r\n * Calculates an element's position relative to a container.\r\n * Uses `TransformNullifyTool` to account for CSS transforms.\r\n */\r\nexport default class RelativePositionTool\r\n implements IStringTool<RelativePositionInput, RelativePositionOutput>\r\n{\r\n constructor(\r\n /** Optional tool for CSS transform-neutral measurements. */\r\n private transformTool = new TransformNullifyTool()\r\n ) {}\r\n\r\n /**\r\n * @returns Relative top/left position of element within container.\r\n */\r\n process({ element, container = document.body }: RelativePositionInput): RelativePositionOutput {\r\n let containerRect: DOMRect\r\n try {\r\n containerRect = container.getBoundingClientRect()\r\n } catch {\r\n containerRect = document.body.getBoundingClientRect()\r\n }\r\n\r\n const elRect = this.transformTool.process({ element })\r\n\r\n return {\r\n top: elRect.top - containerRect.top,\r\n left: elRect.left - containerRect.left,\r\n }\r\n }\r\n}\r\n","import { IStringTool } from \"../core/IStringTool\"\r\n\r\ninterface LerpInput {\r\n /** Starting value of the interpolation. */\r\n from: number\r\n\r\n /** Target value to interpolate towards. */\r\n to: number\r\n\r\n /** Interpolation progress between 0 (start) and 1 (end). */\r\n progress: number\r\n}\r\n\r\nexport default class LerpTool implements IStringTool<LerpInput, number> {\r\n /**\r\n * Calculates the linear interpolation between two values.\r\n * @returns Interpolated value.\r\n */\r\n process({ from, to, progress }: LerpInput): number {\r\n return (to - from) * progress\r\n }\r\n}\r\n\r\n","import { IStringTool } from \"../core/IStringTool\"\r\n\r\n/**\r\n * Input for parsing unit-based strings into numeric pixel values.\r\n */\r\ninterface UnitParserInput {\r\n /** Unit string, e.g. `\"20px\"`, `\"50%\"`, `\"1.5rem\"`, or `\"selfHeight\"` */\r\n value: string\r\n\r\n /** DOM element used for `\"selfHeight\"` calculation */\r\n element: HTMLElement\r\n\r\n /** Viewport height in pixels (for percentage conversion) */\r\n viewportHeight: number\r\n\r\n /** Root font size in pixels (for rem conversion) */\r\n baseRem: number\r\n}\r\n\r\n/**\r\n * Converts unit-based strings to numeric pixel values.\r\n * Supports `px`, `%`, `rem`, and `\"selfHeight\"` keyword. Handles negatives.\r\n */\r\nexport default class UnitParserTool implements IStringTool<UnitParserInput, number> {\r\n /**\r\n * @returns Numeric value in pixels (positive or negative).\r\n */\r\n process({ value, element, viewportHeight, baseRem }: UnitParserInput): number {\r\n const isNegative = value.startsWith(\"-\")\r\n if (isNegative) value = value.slice(1)\r\n\r\n let result = 0\r\n\r\n if (value === \"selfHeight\") {\r\n result = element.offsetHeight\r\n } else if (value.endsWith(\"px\")) {\r\n result = parseFloat(value)\r\n } else if (value.endsWith(\"%\")) {\r\n result = (parseFloat(value) / 100) * viewportHeight\r\n } else if (value.endsWith(\"rem\")) {\r\n result = parseFloat(value) * baseRem\r\n }\r\n\r\n return isNegative ? -result : result\r\n }\r\n}\r\n","import { IStringTool } from \"../core/IStringTool\"\r\n\r\n/**\r\n * Input for adaptive lerp factor calculation.\r\n * Maps a speed-like value to a lerp factor, where:\r\n * - lower speed ⇒ slower smoothing (higher lerp factor)\r\n * - higher speed ⇒ faster response (lower lerp factor)\r\n */\r\ninterface AdaptiveLerpInput {\r\n /** Current value (e.g., speed or delta). */\r\n value: number\r\n\r\n /** Minimum input threshold (default: 0.1) */\r\n inMin?: number\r\n\r\n /** Maximum input threshold (default: 1.0) */\r\n inMax?: number\r\n\r\n /** Output when input is at minimum (default: 0.65) */\r\n outMax?: number\r\n\r\n /** Output when input is at maximum (default: 0.05) */\r\n outMin?: number\r\n}\r\n\r\n/**\r\n * Converts a numeric input (like velocity) into an adaptive lerp factor.\r\n * Useful for scroll or speed-based smoothing effects.\r\n */\r\nexport default class AdaptiveLerpTool implements IStringTool<AdaptiveLerpInput, number> {\r\n /**\r\n * @returns A remapped lerp factor from `outMax` to `outMin`.\r\n */\r\n process({\r\n value,\r\n inMin = 0.1,\r\n inMax = 1.0,\r\n outMin = 0.05,\r\n outMax = 0.65\r\n }: AdaptiveLerpInput): number {\r\n if (value < inMin) return outMax\r\n if (value > 1.0) value = 1.0\r\n\r\n if (value <= inMax) {\r\n const t = (value - inMin) / (inMax - inMin)\r\n return outMax - t * (outMax - outMin)\r\n }\r\n\r\n return outMin\r\n }\r\n}\r\n","import { IStringTool } from \"../core/IStringTool\"\r\n\r\n/**\r\n * Input for origin parser.\r\n * Supports static values or `random(...)` expressions.\r\n */\r\ninterface OriginInput {\r\n /** Raw origin string, e.g. `'center'` or `'random(top, bottom)'`. */\r\n value: string\r\n}\r\n\r\n/**\r\n * Tool that parses origin strings.\r\n * Allows static values like `'center'`, or expressions like `'random(...)'` to select one randomly.\r\n */\r\nexport default class OriginParserTool implements IStringTool<OriginInput, string> {\r\n /**\r\n * @returns Parsed string value (static or randomly chosen).\r\n */\r\n process({ value }: OriginInput): string {\r\n const raw = value.trim()\r\n\r\n if (raw.startsWith(\"random(\") && raw.endsWith(\")\")) {\r\n const options = raw\r\n .slice(7, -1)\r\n .split(\",\")\r\n .map((s) => s.trim())\r\n .filter(Boolean)\r\n\r\n const index = Math.floor(Math.random() * options.length)\r\n return options[index]\r\n }\r\n\r\n return raw\r\n }\r\n}\r\n","import { IStringTool } from \"../core/IStringTool\"\r\nimport { StringColor } from \"../models/color/StringColor\"\r\n\r\n/**\r\n * Input for parsing color strings into RGBA format.\r\n */\r\ninterface ColorParserInput {\r\n /** Color string in hex, rgb[a], or hsl[a] format. */\r\n value: string\r\n}\r\n\r\n/**\r\n * Parses a CSS color string (`#fff`, `rgb(...)`, `hsl(...)`, etc.)\r\n * into an object with `r`, `g`, `b`, `a` values.\r\n */\r\nexport default class ColorParserTool\r\n implements IStringTool<ColorParserInput, StringColor>\r\n{\r\n /**\r\n * @returns RGBA object parsed from color string.\r\n */\r\n process({ value }: ColorParserInput): StringColor {\r\n const str = value.trim().toLowerCase()\r\n\r\n // --- HEX ---\r\n if (str.startsWith(\"#\")) {\r\n let hex = str.slice(1)\r\n\r\n if (hex.length === 3) {\r\n hex = hex.split(\"\").map((ch) => ch + ch).join(\"\")\r\n }\r\n\r\n const r = parseInt(hex.slice(0, 2), 16)\r\n const g = parseInt(hex.slice(2, 4), 16)\r\n const b = parseInt(hex.slice(4, 6), 16)\r\n const a = hex.length === 8 ? parseInt(hex.slice(6, 8), 16) / 255 : 1\r\n\r\n return { r, g, b, a }\r\n }\r\n\r\n // --- RGB / RGBA ---\r\n const rgbMatch = str.match(/rgba?\\(([^)]+)\\)/)\r\n if (rgbMatch) {\r\n const [r, g, b, a = 1] = rgbMatch[1]\r\n .split(\",\")\r\n .map((v) => parseFloat(v.trim()))\r\n\r\n return { r, g, b, a }\r\n }\r\n\r\n // --- HSL / HSLA ---\r\n const hslMatch = str.match(/hsla?\\(([^)]+)\\)/)\r\n if (hslMatch) {\r\n const [h, s, l, a = \"1\"] = hslMatch[1].split(\",\").map((v) => v.trim())\r\n const [r, g, b] = this.hslToRgb(parseFloat(h), parseFloat(s), parseFloat(l))\r\n return { r, g, b, a: parseFloat(a) }\r\n }\r\n\r\n // fallback: transparent\r\n return { r: 0, g: 0, b: 0, a: 0 }\r\n }\r\n\r\n private hslToRgb(h: number, s: string | number, l: string | number): [number, number, number] {\r\n h = h / 360\r\n s = parseFloat(s.toString()) / 100\r\n l = parseFloat(l.toString()) / 100\r\n\r\n const hue2rgb = (p: number, q: number, t: number) => {\r\n if (t < 0) t += 1\r\n if (t > 1) t -= 1\r\n if (t < 1 / 6) return p + (q - p) * 6 * t\r\n if (t < 1 / 2) return q\r\n if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6\r\n return p\r\n }\r\n\r\n const q = l < 0.5 ? l * (1 + s) : l + s - l * s\r\n const p = 2 * l - q\r\n\r\n const r = Math.round(hue2rgb(p, q, h + 1 / 3) * 255)\r\n const g = Math.round(hue2rgb(p, q, h) * 255)\r\n const b = Math.round(hue2rgb(p, q, h - 1 / 3) * 255)\r\n\r\n return [r, g, b]\r\n }\r\n}\r\n","import { IStringTool } from \"../core/IStringTool\"\r\n\r\ntype RuleType = \"required\" | \"email\" | \"minLength\" | \"maxLength\"\r\n\r\nexport type ValidationErrorCode =\r\n | \"required\"\r\n | \"invalid-email\"\r\n | \"too-short\"\r\n | \"too-long\"\r\n\r\nexport type ValidationRule =\r\n | \"required\"\r\n | \"email\"\r\n | { type: \"minLength\"; value: number }\r\n | { type: \"maxLength\"; value: number }\r\n\r\ninterface ValidationInput {\r\n /** Value to validate. */\r\n value: string\r\n\r\n /** List of rules to apply. */\r\n rules: ValidationRule[]\r\n\r\n /**\r\n * Optional message map: key = errorCode, value = string or function returning a message.\r\n */\r\n messages?: Partial<\r\n Record<\r\n ValidationErrorCode,\r\n string | ((args: { value: string; rule: ValidationRule }) => string)\r\n >\r\n >\r\n}\r\n\r\nexport interface ValidationOutput {\r\n /** `true` if valid, `false` if error found. */\r\n valid: boolean\r\n\r\n /** One of the known error codes (or null if no error). */\r\n error: ValidationErrorCode | null\r\n\r\n /** Final message (either default or user-defined). */\r\n message: string | null\r\n}\r\n\r\n/**\r\n * Tool for validating strings using rules like `required`, `minLength`, etc.\r\n * Allows custom error messages (as string or generator function).\r\n */\r\nexport default class ValidationTool implements IStringTool<ValidationInput, ValidationOutput> {\r\n /**\r\n * Validates input value and returns error code + message.\r\n */\r\n process({ value, rules, messages = {} }: ValidationInput): ValidationOutput {\r\n for (const rule of rules) {\r\n let code: ValidationErrorCode | null = null\r\n\r\n if (rule === \"required\" && value.trim() === \"\") {\r\n code = \"required\"\r\n } else if (rule === \"email\" && !/^\\S+@\\S+\\.\\S+$/.test(value)) {\r\n code = \"invalid-email\"\r\n } else if (typeof rule === \"object\") {\r\n if (rule.type === \"minLength\" && value.length < rule.value) code = \"too-short\"\r\n if (rule.type === \"maxLength\" && value.length > rule.value) code = \"too-long\"\r\n }\r\n\r\n if (code) {\r\n const raw = messages[code]\r\n const message =\r\n typeof raw === \"function\" ? raw({ value, rule }) : raw ?? this.defaultMessage(code, rule)\r\n return { valid: false, error: code, message }\r\n }\r\n }\r\n\r\n return { valid: true, error: null, message: null }\r\n }\r\n\r\n private defaultMessage(code: ValidationErrorCode, rule?: ValidationRule): string {\r\n switch (code) {\r\n case \"required\":\r\n return \"This field is required.\"\r\n case \"invalid-email\":\r\n return \"Please enter a valid email.\"\r\n case \"too-short\":\r\n return `Too short${typeof rule === \"object\" && \"value\" in rule ? ` (min ${rule.value})` : \"\"}.`\r\n case \"too-long\":\r\n return `Too long${typeof rule === \"object\" && \"value\" in rule ? ` (max ${rule.value})` : \"\"}.`\r\n }\r\n }\r\n}\r\n","import { IStringTool } from \"../core/IStringTool\"\r\n\r\n/**\r\n * Input parameters for EasingFunctionTool.\r\n */\r\ninterface EasingFunctionInput {\r\n /**\r\n * The easing string.\r\n * Can be: 'linear', 'ease', 'ease-in', 'ease-out', 'ease-in-out', or 'cubic-bezier(...)'\r\n */\r\n easing: string\r\n}\r\n\r\n/**\r\n * Output of the easing function: receives t in [0,1] and returns eased value.\r\n */\r\nexport type EasingFunctionOutput = (t: number) => number\r\n\r\n/**\r\n * Tool for parsing easing strings into easing functions.\r\n * Supports standard keywords (`ease-in`, `ease-out`, etc.) and `cubic-bezier(...)` expressions.\r\n */\r\nexport default class EasingFunctionTool implements IStringTool<EasingFunctionInput, EasingFunctionOutput> {\r\n private namedCurves: Record<string, [number, number, number, number]> = {\r\n \"linear\": [0, 0, 1, 1],\r\n \"ease\": [0.25, 0.1, 0.25, 1],\r\n \"ease-in\": [0.42, 0, 1, 1],\r\n \"ease-out\": [0, 0, 0.58, 1],\r\n \"ease-in-out\": [0.42, 0, 0.58, 1],\r\n }\r\n\r\n /**\r\n * Parses an easing string and returns a corresponding easing function.\r\n */\r\n process({ easing }: EasingFunctionInput): EasingFunctionOutput {\r\n const def = easing.trim()\r\n\r\n if (this.namedCurves[def]) {\r\n return this.cubicBezier(...this.namedCurves[def])\r\n }\r\n\r\n const match = def.match(/^cubic-bezier\\s*\\(\\s*([-+]?\\d*\\.?\\d+)\\s*,\\s*([-+]?\\d*\\.?\\d+)\\s*,\\s*([-+]?\\d*\\.?\\d+)\\s*,\\s*([-+]?\\d*\\.?\\d+)\\s*\\)$/);\r\n\r\n if (match) {\r\n const [x1, y1, x2, y2] = match.slice(1).map(Number)\r\n return this.cubicBezier(x1, y1, x2, y2)\r\n }\r\n\r\n // fallback: linear\r\n return (t: number) => t\r\n }\r\n\r\n /**\r\n * Generates a cubic-bezier easing function.\r\n * Ported from https://github.com/gre/bezier-easing (MIT)\r\n */\r\n private cubicBezier(x1: number, y1: number, x2: number, y2: number): EasingFunctionOutput {\r\n const cx = 3 * x1\r\n const bx = 3 * (x2 - x1) - cx\r\n const ax = 1 - cx - bx\r\n\r\n const cy = 3 * y1\r\n const by = 3 * (y2 - y1) - cy\r\n const ay = 1 - cy - by\r\n\r\n function sampleCurveX(t: number) {\r\n return ((ax * t + bx) * t + cx) * t\r\n }\r\n\r\n function sampleCurveY(t: number) {\r\n return ((ay * t + by) * t + cy) * t\r\n }\r\n\r\n function sampleCurveDerivativeX(t: number) {\r\n return (3 * ax * t + 2 * bx) * t + cx\r\n }\r\n\r\n function solveCurveX(x: number, epsilon = 1e-5) {\r\n let t0, t1, t2 = x, x2, d2, i\r\n\r\n // Newton-Raphson method\r\n for (i = 0; i < 8; i++) {\r\n x2 = sampleCurveX(t2) - x\r\n if (Math.abs(x2) < epsilon) return t2\r\n d2 = sampleCurveDerivativeX(t2)\r\n if (Math.abs(d2) < 1e-6) break\r\n t2 = t2 - x2 / d2\r\n }\r\n\r\n // Bisection fallback\r\n t0 = 0\r\n t1 = 1\r\n t2 = x\r\n\r\n while (t0 < t1) {\r\n x2 = sampleCurveX(t2) - x\r\n if (Math.abs(x2) < epsilon) return t2\r\n if (x2 > 0) t1 = t2\r\n else t0 = t2\r\n t2 = (t1 + t0) / 2\r\n }\r\n\r\n return t2\r\n }\r\n\r\n return function (x: number) {\r\n return sampleCurveY(solveCurveX(x))\r\n }\r\n }\r\n}\r\n","import { IStringTool } from \"../core/IStringTool\"\r\n\r\n/**\r\n * Input parameters for calculating magnetic pull factor.\r\n */\r\ninterface MagneticPullInput {\r\n /** Distance between pointer and element center (px). */\r\n distance: number\r\n\r\n /** Max distance within which magnetic pull is active. */\r\n radius: number\r\n\r\n /** Strength of the magnetic pull (0–1 recommended). */\r\n strength: number\r\n}\r\n\r\n/**\r\n * Output: factor to multiply by direction vector (dx/dy) to get magnetic offset.\r\n */\r\ntype MagneticPullOutput = number\r\n\r\n/**\r\n * Tool for calculating magnetic attraction based on distance to element.\r\n * Returns a scalar value (0..strength) depending on proximity.\r\n */\r\nexport default class MagneticPullTool implements IStringTool<MagneticPullInput, MagneticPullOutput> {\r\n /**\r\n * Returns a pull factor based on distance to target within a radius.\r\n * @param input - Magnetic pull parameters.\r\n * @returns A multiplier (typically < 1) to apply to dx/dy.\r\n */\r\n process({ distance, radius, strength }: MagneticPullInput): number {\r\n if (distance >= radius) return 0\r\n const proximity = (radius - distance) / radius // 1 when close, 0 at edge\r\n return strength * proximity\r\n }\r\n}\r\n","import { IStringTool } from \"../core/IStringTool\"\r\nimport { StringColor } from \"../models/color/StringColor\"\r\n\r\n/**\r\n * Input parameters for `LerpColorTool`.\r\n */\r\ninterface LerpColorInput {\r\n /**\r\n * Starting color as an object `{ r, g, b, a }` where each value is in the range `0–1`.\r\n */\r\n from: StringColor\r\n\r\n /**\r\n * Target color as an object `{ r, g, b, a }` where each value is in the range `0–1`.\r\n */\r\n to: StringColor\r\n\r\n /**\r\n * Interpolation progress from `0` (start) to `1` (end).\r\n */\r\n progress: number\r\n}\r\n\r\n/**\r\n * Tool for linearly interpolating between two RGBA colors using `StringColor` format.\r\n * Each channel (`r`, `g`, `b`, `a`) is interpolated independently.\r\n * Returns a new `StringColor` with the interpolated values.\r\n */\r\nexport default class LerpColorTool implements IStringTool<LerpColorInput, StringColor> {\r\n /**\r\n * Performs linear interpolation between two `StringColor` values.\r\n *\r\n * @param input.from - The starting color `{ r, g, b, a }`.\r\n * @param input.to - The target color `{ r, g, b, a }`.\r\n * @param input.progress - A number from `0` to `1` indicating interpolation progress.\r\n * @returns Interpolated color as a new `StringColor`.\r\n */\r\n process({ from, to, progress }: LerpColorInput): StringColor {\r\n return {\r\n r: from.r + (to.r - from.r) * progress,\r\n g: from.g + (to.g - from.g) * progress,\r\n b: from.b + (to.b - from.b) * progress,\r\n a: from.a + (to.a - from.a) * progress,\r\n }\r\n }\r\n}\r\n","import { IStringTool } from \"../core/IStringTool\"\r\nimport { StringVector } from \"../models/vector/StringVector\"\r\n\r\n/**\r\n * Input parameters for LerpVector2Tool.\r\n */\r\ninterface LerpVector2Input {\r\n /**\r\n * Starting vector value `{ x, y }`.\r\n */\r\n from: StringVector\r\n\r\n /**\r\n * Target vector value `{ x, y }`.\r\n */\r\n to: StringVector\r\n\r\n /**\r\n * Interpolation progress from `0` (start) to `1` (end).\r\n */\r\n progress: number\r\n}\r\n\r\n/**\r\n * Tool for linearly interpolating between two 2D vectors.\r\n * Useful for cursor smoothing, UI element animations, and motion blending.\r\n */\r\nexport default class LerpVector2Tool implements IStringTool<LerpVector2Input, StringVector> {\r\n /**\r\n * Calculates the interpolated vector between `from` and `to`.\r\n *\r\n * @param input.from - The starting vector `{ x, y }`.\r\n * @param input.to - The target vector `{ x, y }`.\r\n * @param input.progress - Interpolation progress from `0` (start) to `1` (end).\r\n * @returns Interpolated vector `{ x, y }`.\r\n */\r\n process({ from, to, progress }: LerpVector2Input): { x: number, y: number } {\r\n return {\r\n x: (to.x - from.x) * progress,\r\n y: (to.y - from.y) * progress,\r\n }\r\n }\r\n}\r\n\r\n","import { IStringTool } from \"../core/IStringTool\"; // Переконайтесь, що шлях правильний\r\n\r\n/**\r\n * Input for parsing the transform string to extract scale.\r\n */\r\ninterface TransformParserInput {\r\n /** CSS transform string (e.g., \"matrix(0.5, 0, 0, 0.5, 10, 20)\", \"scale(0.5)\", \"none\"). */\r\n value: string;\r\n}\r\n\r\n/**\r\n * Parses a CSS transform string to extract the primary scale factor.\r\n * Assumes uniform scale or extracts the X-axis scale factor from matrix/scale functions.\r\n */\r\nexport default class TransformScaleParserTool\r\n implements IStringTool<TransformParserInput, number> // Output is a number\r\n{\r\n /**\r\n * Processes the transform string and extracts the scale factor.\r\n * @returns Numeric scale factor (defaults to 1 if no scale transform is found or parsing fails).\r\n */\r\n process({ value }: TransformParserInput): number {\r\n const defaultScale = 1;\r\n const str = value?.trim();\r\n\r\n if (!str || str === 'none') {\r\n return defaultScale;\r\n }\r\n try {\r\n if (str.startsWith('matrix(')) {\r\n const matrixValues = str.match(/matrix\\(([^)]+)\\)/);\r\n if (matrixValues && matrixValues[1]) {\r\n const matrixNumbers = matrixValues[1].split(',').map(s => parseFloat(s.trim()));\r\n if (matrixNumbers.length >= 1 && !isNaN(matrixNumbers[0])) {\r\n return matrixNumbers[0];\r\n }\r\n }\r\n }\r\n\r\n if (str.startsWith('scale(')) {\r\n const scaleValue = str.match(/scale\\(([^)]+)\\)/);\r\n if (scaleValue && scaleValue[1]) {\r\n const scaleNumbers = scaleValue[1].split(',').map(s => parseFloat(s.trim()));\r\n if (scaleNumbers.length >= 1 && !isNaN(scaleNumbers[0])) {\r\n return scaleNumbers[0];\r\n }\r\n }\r\n }\r\n\r\n if (str.startsWith('scaleX(')) {\r\n const scaleXValue = str.match(/scaleX\\(([^)]+)\\)/);\r\n if (scaleXValue && scaleXValue[1]) {\r\n const scaleNumber = parseFloat(scaleXValue[1].trim());\r\n if (!isNaN(scaleNumber)) {\r\n return scaleNumber;\r\n }\r\n }\r\n }\r\n\r\n if (str.startsWith('scale3d(')) {\r\n const scale3dValue = str.match(/scale3d\\(([^)]+)\\)/);\r\n if (scale3dValue && scale3dValue[1]) {\r\n const scaleNumbers = scale3dValue[1].split(',').map(s => parseFloat(s.trim()));\r\n if (scaleNumbers.length >= 1 && !isNaN(scaleNumbers[0])) {\r\n return scaleNumbers[0]; // Повертаємо sx\r\n }\r\n }\r\n }\r\n\r\n if (str.startsWith('matrix3d(')) {\r\n const matrix3dValues = str.match(/matrix3d\\(([^)]+)\\)/);\r\n if (matrix3dValues && matrix3dValues[1]) {\r\n const matrixNumbers = matrix3dValues[1].split(',').map(s => parseFloat(s.trim()));\r\n if (matrixNumbers.length >= 1 && !isNaN(matrixNumbers[0])) {\r\n return matrixNumbers[0];\r\n }\r\n }\r\n }\r\n\r\n } catch (error) {\r\n console.error(`Error parsing transform string \"${str}\":`, error);\r\n return defaultScale;\r\n }\r\n\r\n return defaultScale;\r\n }\r\n}\r\n","import { IStringTool } from \"../core/IStringTool\";\r\nimport { CalculatedValue } from \"../models/text/CalculatedValue\";\r\nimport { CharIndexerInput } from \"../models/text/CharIndexerInput\";\r\nimport { ISplitOptionItem } from \"../models/text/ISplitOptionItem\";\r\nimport { ProcessedChar } from \"../models/text/ProcessedChar\";\r\n\r\n/**\r\n * Tool to process words split by layout, breaking them into characters\r\n * and assigning relevant indices (global, line, word) for each character.\r\n * Calculates index values based on ISplitOptions for characters ('char', 'charLine', 'charWord').\r\n * Produces an array of ProcessedChar objects.\r\n */\r\nexport class CharIndexerTool implements IStringTool<CharIndexerInput, ProcessedChar[]> {\r\n\r\n /**\r\n * Iterates through processed words, splits them into characters, assigns\r\n * global, line, and word character indices, and calculates index values\r\n * based on the provided character options ('char', 'charLine', 'charWord').\r\n *\r\n * @param input.processedWords - Array of ProcessedWord objects from WordIndexerTool.\r\n * @param input.lines - Array of LayoutLine objects (needed for calculating total characters per line).\r\n * @param input.options - The relevant ISplitOptions ('char', 'charLine', 'charWord').\r\n * @param input.totalChars - Total number of non-whitespace characters in the original text.\r\n * @returns An array of ProcessedChar objects, ready for DOM building/styling.\r\n */\r\n process({ processedWords, lines, options, totalChars }: CharIndexerInput): ProcessedChar[] {\r\n const processedChars: ProcessedChar[] = [];\r\n let globalCharIndex = 0; // Global character counter (non-whitespace)\r\n\r\n // Pre-calculate total characters per line for efficiency\r\n const totalLineCharsMap = new Map<number, number>();\r\n lines.forEach((line, lineIndex) => {\r\n const totalCharsInLine = line.words.reduce((sum, word) => sum + word.text.length, 0);\r\n totalLineCharsMap.set(lineIndex, totalCharsInLine);\r\n });\r\n\r\n let currentLineCharIndex = 0; // Character index within the current line\r\n let previousLineIndex = -1; // Tracks when we move to a new line\r\n\r\n // Iterate through the processed words provided as input\r\n processedWords.forEach(pWord => {\r\n const wordText = pWord.text;\r\n const parentLineIndex = pWord.lineIndex;\r\n const wordLength = wordText.length; // Number of characters in the current word\r\n const totalCharsInCurrentLine = totalLineCharsMap.get(parentLineIndex) || 0; // Get pre-calculated total\r\n\r\n // Reset line character index when moving to a new line\r\n if (parentLineIndex !== previousLineIndex) {\r\n currentLineCharIndex = 0;\r\n previousLineIndex = parentLineIndex;\r\n }\r\n\r\n const chars = Array.from(wordText); // Split word into characters (handles Unicode correctly)\r\n\r\n // Iterate through each character of the word\r\n chars.forEach((char, wordCharIndex) => {\r\n const calculatedValues: CalculatedValue[] = []; // Use the unified CalculatedValue\r\n\r\n // 1. Calculate for 'char' options (global context)\r\n if (options.char) {\r\n options.char.forEach(optDef => {\r\n // Use globalCharIndex as primary, totalChars as parentLength\r\n const value = this.calculateIndex(optDef, globalCharIndex, wordCharIndex, totalChars);\r\n // Create CalculatedValue object\r\n calculatedValues.push({ value, type: 'char', align: optDef.align });\r\n });\r\n }\r\n\r\n // 2. Calculate for 'charLine' options (line context)\r\n if (options.charLine) {\r\n options.charLine.forEach(optDef => {\r\n // Use currentLineCharIndex as primary, totalCharsInCurrentLine as parentLength\r\n const value = this.calculateIndex(optDef, currentLineCharIndex, wordCharIndex, totalCharsInCurrentLine);\r\n // Create CalculatedValue object\r\n calculatedValues.push({ value, type: 'charLine', align: optDef.align });\r\n });\r\n }\r\n\r\n // 3. Calculate for 'charWord' options (word context)\r\n if (options.charWord) {\r\n options.charWord.forEach(optDef => {\r\n // Use wordCharIndex as primary, wordLength as parentLength\r\n const value = this.calculateIndex(optDef, wordCharIndex, wordCharIndex, wordLength);\r\n // Create CalculatedValue object\r\n calculatedValues.push({ value, type: 'charWord', align: optDef.align });\r\n });\r\n }\r\n\r\n // Create the ProcessedChar object\r\n processedChars.push({\r\n text: char,\r\n globalCharIndex: globalCharIndex,\r\n lineCharIndex: currentLineCharIndex,\r\n wordCharIndex: wordCharIndex,\r\n parentGlobalWordIndex: pWord.globalIndex, // Carry over parent info\r\n parentLineIndex: pWord.lineIndex,\r\n parentWordIndexInLine: pWord.wordIndexInLine,\r\n calculatedValues: calculatedValues // Store the array of CalculatedValue\r\n });\r\n\r\n // Increment character counters for the next iteration\r\n globalCharIndex++;\r\n currentLineCharIndex++;\r\n }); // end character loop\r\n }); // end word loop\r\n\r\n return processedChars;\r\n }\r\n\r\n /**\r\n * Calculates the final numerical index value based on alignment options, context indices, and parent length.\r\n * (Identical helper function as in WordIndexerTool - could be extracted to a common utility).\r\n *\r\n * @param option - The specific option item definition ({ align, random, abs }).\r\n * @param primaryIndex - The main index used for calculation (global, line, or word char index).\r\n * @param localIndex - The secondary index (e.g., index within word).\r\n * @param parentLength - The total count in the relevant context (total chars, line chars, or word chars).\r\n * @returns The calculated numerical index value.\r\n */\r\n private calculateIndex(\r\n option: ISplitOptionItem,\r\n primaryIndex: number,\r\n localIndex: number,\r\n parentLength: number\r\n ): number {\r\n let index = primaryIndex;\r\n\r\n if (option.align === 'random') {\r\n const min = option.random?.min ?? 0;\r\n const max = option.random?.max ?? (parentLength > 0 ? parentLength - 1 : 0);\r\n const effectiveMin = Math.min(min, max);\r\n const effectiveMax = Math.max(min, max);\r\n index = Math.floor(Math.random() * (effectiveMax - effectiveMin + 1)) + effectiveMin;\r\n } else if (option.align === 'end') {\r\n index = (parentLength > 0 ? parentLength - 1 : 0) - primaryIndex;\r\n } else if (option.align === 'center') {\r\n index = primaryIndex - Math.floor(parentLength / 2);\r\n }\r\n\r\n if (option.abs) {\r\n index = Math.abs(index);\r\n }\r\n return index;\r\n }\r\n}","import { IStringTool } from \"../core/IStringTool\";\r\nimport { LayoutLine } from \"../models/text/LayoutLine\";\r\nimport { LayoutSplitInput } from \"../models/text/LayoutSplitInput\";\r\n\r\n/**\r\n * Tool to split a text string into structured lines and words based on how\r\n * the text would visually wrap within a given target HTML element.\r\n * This simulates browser rendering by measuring word widths.\r\n * Returns an array of LayoutLine objects.\r\n */\r\nexport class LayoutLineSplitterTool implements IStringTool<LayoutSplitInput, LayoutLine[]> {\r\n\r\n /**\r\n * Processes the input text and splits it into lines containing words,\r\n * simulating word wrapping within the boundaries of the targetElement.\r\n *\r\n * @param input.text - The text content to split.\r\n * @param input.targetElement - The HTMLElement used as a reference for width and font styles.\r\n * @returns An array of LayoutLine objects, each containing the line's text and an array of its words.\r\n * Returns an empty array on error or invalid input.\r\n */\r\n process({ text, targetElement }: LayoutSplitInput): LayoutLine[] {\r\n if (!text || !targetElement || targetElement.offsetWidth <= 0) {\r\n console.warn(\"LayoutLineSplitterTool: Invalid input or target element has zero width.\");\r\n return [];\r\n }\r\n\r\n const cleanedText = this.decodeHtmlEntity(text);\r\n // Split by whitespace and filter out empty strings that might result from multiple spaces\r\n const words = cleanedText.trim().split(/\\s+/).filter(word => word.length > 0);\r\n\r\n if (words.length === 0) {\r\n return []; // No words to process\r\n }\r\n\r\n // Create and configure the temporary span for measurements\r\n const tempSpan = document.createElement('span');\r\n const compStyles = window.getComputedStyle(targetElement);\r\n // Copy relevant styles that affect width\r\n tempSpan.style.fontFamily = compStyles.fontFamily;\r\n tempSpan.style.fontSize = compStyles.fontSize;\r\n tempSpan.style.fontWeight = compStyles.fontWeight;\r\n tempSpan.style.letterSpacing = compStyles.letterSpacing;\r\n tempSpan.style.textTransform = compStyles.textTransform;\r\n tempSpan.style.wordSpacing = compStyles.wordSpacing;\r\n // Ensure the measurement span itself doesn't wrap and is hidden\r\n tempSpan.style.whiteSpace = 'nowrap';\r\n tempSpan.style.visibility = 'hidden';\r\n tempSpan.style.position = 'absolute'; // Prevent affecting layout\r\n tempSpan.style.top = '-9999px';\r\n tempSpan.style.left = '-9999px';\r\n document.body.appendChild(tempSpan); // Must be in DOM for offsetWidth\r\n\r\n const layoutLines: LayoutLine[] = [];\r\n let currentLineWords: string[] = []; // Accumulates words for the current line\r\n let currentLineWidth = 0; // Tracks the width of the current line\r\n const spaceWidth = this.measureWidth(' ', tempSpan); // Measure space width once\r\n const containerWidth = targetElement.offsetWidth; // Target width for wrapping\r\n\r\n try {\r\n words.forEach((word) => {\r\n const wordWidth = this.measureWidth(word, tempSpan);\r\n // Calculate width if this word is added: current width + space (if needed) + word width\r\n const potentialWidth = currentLineWidth + (currentLineWords.length > 0 ? spaceWidth : 0) + wordWidth;\r\n\r\n // Check if the word fits on the current line\r\n if (currentLineWords.length > 0 && potentialWidth > containerWidth) {\r\n // Word doesn't fit: finalize the current line\r\n layoutLines.push({\r\n text: currentLineWords.join(' '),\r\n words: currentLineWords.map(w => ({ text: w })) // Convert word strings to LayoutWord objects\r\n });\r\n // Start a new line with the current word\r\n currentLineWords = [word];\r\n currentLineWidth = wordWidth;\r\n } else {\r\n // Word fits: add it to the current line\r\n currentLineWords.push(word);\r\n // Update the current line width\r\n currentLineWidth = (currentLineWords.length === 1) ? wordWidth : potentialWidth;\r\n }\r\n });\r\n\r\n // Add the last remaining line after the loop finishes\r\n if (currentLineWords.length > 0) {\r\n layoutLines.push({\r\n text: currentLineWords.join(' '),\r\n words: currentLineWords.map(w => ({ text: w }))\r\n });\r\n }\r\n } finally {\r\n // Ensure the temporary span is removed from the DOM\r\n if (tempSpan.parentNode === document.body) {\r\n document.body.removeChild(tempSpan);\r\n }\r\n }\r\n\r\n return layoutLines;\r\n }\r\n\r\n /**\r\n * Measures the width of a given text string using the provided temporary span.\r\n * @param text - The text to measure.\r\n * @param tempSpan - The pre-styled temporary span element used for measurement.\r\n * @returns The width of the text in pixels.\r\n */\r\n private measureWidth(text: string, tempSpan: HTMLSpanElement): number {\r\n tempSpan.textContent = text;\r\n return tempSpan.offsetWidth;\r\n }\r\n\r\n /**\r\n * Decodes basic HTML entities (currently just &amp;).\r\n * Can be expanded if more entities need handling.\r\n * @param str - The string potentially containing HTML entities.\r\n * @returns The string with '&amp;' decoded to '&'.\r\n */\r\n private decodeHtmlEntity(str: string): string {\r\n // Basic decoding, extend as needed\r\n return str.replace(/&amp;/g, '&');\r\n }\r\n}","import { IStringTool } from \"../core/IStringTool\";\r\nimport { CalculatedValue } from \"../models/text/CalculatedValue\";\r\nimport { DomBuilderInput } from \"../models/text/DomBuilderInput\";\r\nimport { ISplitOptions } from \"../models/text/ISplitOptions\";\r\n\r\n/**\r\n * Tool to build the final innerHTML string with nested spans (-s-line, -s-word, -s-char)\r\n * and apply calculated CSS variables based on processed data from indexer tools.\r\n * Implements the IStringTool interface.\r\n */\r\nexport class SplitDomBuilderTool implements IStringTool<DomBuilderInput, string> { // Output is string\r\n\r\n /**\r\n * Generates the innerHTML string for the split text by creating nested spans\r\n * (-s-line, -s-word, -s-char) and applying styles based on calculated index values.\r\n *\r\n * @param input An object containing layout lines, processed words, processed characters, and the original split options.\r\n * @returns The generated HTML string representing the split content.\r\n */\r\n process({ lines, words, chars, options }: DomBuilderInput): string { // Output is string\r\n // Temporary container element to build the HTML structure safely.\r\n const rootElement = document.createElement('div');\r\n let wordCounter = 0; // Tracks the current position in the flat 'words' array\r\n let charCounter = 0; // Tracks the current position in the flat 'chars' array\r\n\r\n const needsLineSpans = this.hasLineOptions(options);\r\n const needsCharSpans = this.hasCharOptions(options);\r\n\r\n lines.forEach((line) => {\r\n // If line spans are needed, create one; otherwise, append directly to the root.\r\n const lineSpanContainer = needsLineSpans ? document.createElement('span') : rootElement;\r\n\r\n if (needsLineSpans) {\r\n lineSpanContainer.classList.add('-s-line');\r\n // TODO: Apply 'line' options if they were processed by an indexer and included in the input data.\r\n // Example: this.applyStyles(lineSpanContainer, lineData.calculatedValues);\r\n rootElement.appendChild(lineSpanContainer);\r\n }\r\n\r\n // Get the subset of words belonging to the current line\r\n const wordsInThisLine = words.slice(wordCounter, wordCounter + line.words.length);\r\n wordCounter += line.words.length; // Move the counter for the next line\r\n\r\n wordsInThisLine.forEach((pWord, indexInLine) => {\r\n const wordSpan = document.createElement('span');\r\n wordSpan.classList.add('-s-word');\r\n\r\n // Get the subset of characters belonging to the current word\r\n const charsInThisWord = chars.slice(charCounter, charCounter + pWord.text.length);\r\n\r\n // Generate character spans only if needed based on options\r\n if (needsCharSpans && pWord.text.length > 0) {\r\n charsInThisWord.forEach(pChar => {\r\n const charSpan = document.createElement('span');\r\n charSpan.classList.add('-s-char');\r\n charSpan.textContent = pChar.text; // Set the character content\r\n this.applyStyles(charSpan, pChar.calculatedValues); // Apply character styles based on calculated values\r\n wordSpan.appendChild(charSpan);\r\n });\r\n // Advance character counter only if individual character spans were created\r\n charCounter += pWord.text.length;\r\n } else {\r\n // If no character spans are needed, set the word's text content directly\r\n wordSpan.textContent = pWord.text;\r\n // Important: Still advance the character counter by the word's length\r\n // to keep the main charCounter in sync for subsequent words/lines.\r\n charCounter += pWord.text.length;\r\n }\r\n\r\n this.applyStyles(wordSpan, pWord.calculatedValues); // Apply word styles based on calculated values\r\n lineSpanContainer.appendChild(wordSpan);\r\n\r\n // Add a non-breaking space between words if it's not the last word in the line\r\n if (indexInLine < wordsInThisLine.length - 1) {\r\n // Using a text node is generally safer and cleaner than manipulating innerHTML\r\n lineSpanContainer.appendChild(document.createTextNode('\\u00a0')); // Non-breaking space\r\n }\r\n }); // End of words loop\r\n }); // End of lines loop\r\n\r\n // Return the complete innerHTML generated within the temporary root element\r\n return rootElement.innerHTML;\r\n }\r\n\r\n /**\r\n * Checks if any line-level splitting options (line, wordLine, charLine) are present.\r\n * This determines if `-s-line` container spans are required in the output HTML.\r\n * @param options - The ISplitOptions object parsed from the element's attribute.\r\n * @returns True if any line-level options exist and have definitions, false otherwise.\r\n */\r\n private hasLineOptions(options: ISplitOptions): boolean {\r\n // Check if the option arrays exist and contain at least one definition\r\n return (options.line?.length ?? 0) > 0 ||\r\n (options.wordLine?.length ?? 0) > 0 ||\r\n (options.charLine?.length ?? 0) > 0;\r\n }\r\n\r\n /**\r\n * Checks if any character-level splitting options (char, charLine, charWord) are present.\r\n * This determines if individual `-s-char` spans should be generated inside word spans.\r\n * @param options - The ISplitOptions object parsed from the element's attribute.\r\n * @returns True if any character-level options exist and have definitions, false otherwise.\r\n */\r\n private hasCharOptions(options: ISplitOptions): boolean {\r\n // Check if the option arrays exist and contain at least one definition\r\n return (options.char?.length ?? 0) > 0 ||\r\n (options.charLine?.length ?? 0) > 0 ||\r\n (options.charWord?.length ?? 0) > 0;\r\n }\r\n\r\n\r\n /**\r\n * Applies the pre-calculated index values as CSS custom properties (variables)\r\n * to the provided HTML element's style attribute.\r\n * @param span - The HTMLElement (line, word, or char span) to apply styles to.\r\n * @param calculatedValues - An array of calculated values derived from the ISplitOptions\r\n * by the corresponding indexer tool (WordIndexerTool or CharIndexerTool).\r\n */\r\n private applyStyles(span: HTMLElement, calculatedValues: CalculatedValue[]): void {\r\n if (calculatedValues) {\r\n calculatedValues.forEach(calcValue => {\r\n // Generate the specific CSS variable name (e.g., --word-center)\r\n const variableName = this.generateVariableName(calcValue.type, calcValue.align);\r\n // Set the CSS variable on the element's inline style\r\n span.style.setProperty(variableName, String(calcValue.value));\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * Generates a CSS custom property name (variable name) based on the split type and alignment option.\r\n * Example: type='word', align='center' -> '--word-center'.\r\n * (Current simplified version assumes one variable per type/align combination).\r\n * @param type - The type of split element ('line', 'word', 'char', 'wordLine', 'charLine', 'charWord').\r\n * @param align - The alignment option ('start', 'center', 'end', 'random').\r\n * @returns The generated CSS variable name string.\r\n */\r\n private generateVariableName(type: string, align: string): string {\r\n // TODO: This might need adjustment if multiple option definitions of the same type/align\r\n // need to result in distinct CSS variables (e.g., by appending an index).\r\n // This would require the 'CalculatedValue' structure to carry more information.\r\n return `--${type}-${align}`;\r\n }\r\n}","import { IStringTool } from \"../core/IStringTool\";\r\nimport { CalculatedValue } from \"../models/text/CalculatedValue\";\r\nimport { ISplitOptionItem } from \"../models/text/ISplitOptionItem\";\r\nimport { ProcessedWord } from \"../models/text/ProcessedWord\";\r\nimport { WordIndexerInput } from \"../models/text/WordIndexerInput\";\r\n\r\n/**\r\n * Tool to process layout lines and words, assigning relevant indices\r\n * and calculating index values based on ISplitOptions ('word', 'wordLine').\r\n * Produces an array of ProcessedWord objects.\r\n */\r\nexport class WordIndexerTool\r\n implements IStringTool<WordIndexerInput, ProcessedWord[]>\r\n{\r\n /**\r\n * Iterates through lines and words, assigning global and local indices,\r\n * and calculating index values based on the provided options ('word', 'wordLine').\r\n *\r\n * @param input.lines - Array of LayoutLine objects from LayoutLineSplitterTool.\r\n * @param input.options - The relevant ISplitOptions ('word', 'wordLine').\r\n * @returns An array of ProcessedWord objects, each containing word text, indices,\r\n * and an array of calculated values based on options.\r\n */\r\n process({ lines, options }: WordIndexerInput): ProcessedWord[] {\r\n const processedWords: ProcessedWord[] = [];\r\n let globalWordIndex = 0;\r\n // Calculate total words once if needed by calculateIndex, though current logic uses parentLength dynamically\r\n const totalWords = lines.reduce((sum, line) => sum + line.words.length, 0);\r\n\r\n lines.forEach((line, lineIndex) => {\r\n const wordsInLine = line.words;\r\n const lineWordCount = wordsInLine.length; // Number of words in the current line\r\n\r\n wordsInLine.forEach((word, wordIndexInLine) => {\r\n const calculatedValues: CalculatedValue[] = []; // Use the unified CalculatedValue\r\n\r\n // 1. Calculate for 'word' options (global context)\r\n if (options.word) {\r\n options.word.forEach((optDef) => {\r\n // Use globalWordIndex as primary, totalWords as parentLength\r\n const value = this.calculateIndex(\r\n optDef,\r\n globalWordIndex,\r\n wordIndexInLine,\r\n totalWords\r\n );\r\n // Create CalculatedValue object\r\n calculatedValues.push({ value, type: \"word\", align: optDef.align });\r\n });\r\n }\r\n\r\n // 2. Calculate for 'wordLine' options (line context)\r\n if (options.wordLine) {\r\n options.wordLine.forEach((optDef) => {\r\n // Use wordIndexInLine as primary, lineWordCount as parentLength\r\n const value = this.calculateIndex(\r\n optDef,\r\n wordIndexInLine,\r\n wordIndexInLine,\r\n lineWordCount\r\n );\r\n // Create CalculatedValue object\r\n calculatedValues.push({\r\n value,\r\n type: \"wordLine\",\r\n align: optDef.align,\r\n });\r\n });\r\n }\r\n\r\n // Create the ProcessedWord object with the unified calculatedValues\r\n processedWords.push({\r\n text: word.text,\r\n globalIndex: globalWordIndex,\r\n lineIndex: lineIndex,\r\n wordIndexInLine: wordIndexInLine,\r\n calculatedValues: calculatedValues, // Store the array of CalculatedValue\r\n });\r\n\r\n globalWordIndex++; // Increment global index for the next word\r\n }); // End word loop\r\n }); // End line loop\r\n\r\n return processedWords;\r\n }\r\n\r\n /**\r\n * Calculates the final numerical index value based on alignment options, context indices, and parent length.\r\n * This logic determines the value eventually set as a CSS variable.\r\n *\r\n * @param option - The specific option item definition ({ align, random, abs }).\r\n * @param primaryIndex - The main index used for calculation (global index for 'word', index within line for 'wordLine').\r\n * @param localIndex - The secondary index (e.g., index within the line), potentially useful for some alignment logic.\r\n * @param parentLength - The total count in the relevant context (total words for 'word', words in the current line for 'wordLine').\r\n * @returns The calculated numerical index value.\r\n */\r\n private calculateIndex(\r\n option: ISplitOptionItem,\r\n primaryIndex: number,\r\n localIndex: number, // Kept for potential future use, e.g., complex centering\r\n parentLength: number\r\n ): number {\r\n let index = primaryIndex; // Base value is the primary contextual index\r\n\r\n // Apply alignment logic\r\n if (option.align === \"random\") {\r\n const min = option.random?.min ?? 0;\r\n // Ensure max is valid (length - 1 for zero-based index)\r\n const max =\r\n option.random?.max ?? (parentLength > 0 ? parentLength - 1 : 0);\r\n // Handle cases where min might be > max\r\n const effectiveMin = Math.min(min, max);\r\n const effectiveMax = Math.max(min, max);\r\n // Generate random integer within the effective range\r\n index =\r\n Math.floor(Math.random() * (effectiveMax - effectiveMin + 1)) +\r\n effectiveMin;\r\n } else if (option.align === \"end\") {\r\n // Calculate index relative to the end (e.g., 0 -> length-1, 1 -> length-2)\r\n index = (parentLength > 0 ? parentLength - 1 : 0) - primaryIndex;\r\n } else if (option.align === \"center\") {\r\n // Calculate index relative to the center point\r\n index = primaryIndex - Math.floor(parentLength / 2);\r\n }\r\n // 'start' alignment uses the primaryIndex directly, no modification needed here.\r\n\r\n // Apply absolute value if requested\r\n if (option.abs) {\r\n index = Math.abs(index);\r\n }\r\n return index;\r\n }\r\n}\r\n","import { IStringTool } from \"../core/IStringTool\";\r\nimport { ISplitOptionItem } from \"../models/text/ISplitOptionItem\";\r\nimport { ISplitOptions } from \"../models/text/ISplitOptions\";\r\nimport { SplitOptionsParserInput } from \"../models/text/SplitOptionsParserInput\";\r\n\r\n/**\r\n * Tool responsible for parsing the string value of a split attribute\r\n * (e.g., \"line[center]|char[random(0,10)|abs]\") into a structured\r\n * ISplitOptions object.\r\n * Implements the IStringTool interface.\r\n */\r\nexport class SplitOptionsParserTool\r\n implements IStringTool<SplitOptionsParserInput, ISplitOptions>\r\n{\r\n /**\r\n * Parses the attribute string into an ISplitOptions object.\r\n * Handles splitting by '|', parsing prefixes (word-, char-), main types (line, word, char),\r\n * and parameters within brackets (align, random, abs).\r\n *\r\n * @param input - An object containing the attributeValue string (can be null).\r\n * @returns An ISplitOptions object representing the parsed rules.\r\n * Returns an object with empty arrays if the attributeValue is null or empty.\r\n */\r\n process({ attributeValue }: SplitOptionsParserInput): ISplitOptions {\r\n // Initialize with empty arrays for all possible options\r\n const options: ISplitOptions = {\r\n line: [],\r\n word: [],\r\n char: [],\r\n charLine: [],\r\n charWord: [],\r\n wordLine: [],\r\n };\r\n\r\n // Return default empty options if attribute value is null or empty string\r\n if (!attributeValue) {\r\n return options;\r\n }\r\n\r\n // Split the main attribute value by the pipe '|' separator\r\n const parts = attributeValue.split(\"|\");\r\n\r\n parts.forEach((part) => {\r\n // Trim whitespace from each part\r\n const trimmedPart = part.trim();\r\n if (!trimmedPart) return; // Skip empty parts resulting from separators like '||' or trailing '|'\r\n\r\n // Regex to capture:\r\n // 1. Optional prefix (word-, char-) - (\\w+-)?\r\n // 2. Main option type (line, word, char) - (\\w+)\r\n // 3. Optional parameters section including brackets - (\\[(.*?)\\])?\r\n // 4. Content within the brackets (params string) - (.*?)\r\n const match = trimmedPart.match(/^(\\w+-)?(\\w+)(\\[(.*?)\\])?$/);\r\n\r\n if (match) {\r\n const prefix = match[1] || \"\"; // e.g., \"word-\" or \"\"\r\n const optionType = match[2]; // e.g., \"line\", \"word\", \"char\"\r\n const fullOptionKey = prefix + optionType; // Combined key like \"line\", \"word\", \"charLine\"\r\n // Extract params string inside brackets, or empty string if no brackets\r\n const paramsString = match[4] || \"\";\r\n // Split params by comma and trim each resulting param string\r\n const params = paramsString\r\n .split(\";\")\r\n .map((p) => p.trim())\r\n .filter((p) => p.length > 0); // Filter out empty params\r\n\r\n // Parse the parameters within brackets using the helper method\r\n const parsedParam: ISplitOptionItem = this.parseParamsArray(params);\r\n\r\n // Add the parsed parameters object to the correct array in the options object\r\n // Use a type assertion for simplicity. More complex type guards could be used.\r\n switch (fullOptionKey) {\r\n case \"line\":\r\n (options.line as ISplitOptionItem[]).push(parsedParam);\r\n break;\r\n case \"word\":\r\n (options.word as ISplitOptionItem[]).push(parsedParam);\r\n break;\r\n case \"char\":\r\n (options.char as ISplitOptionItem[]).push(parsedParam);\r\n break;\r\n case \"charLine\": // e.g., char-line\r\n (options.charLine as ISplitOptionItem[]).push(parsedParam);\r\n break;\r\n case \"charWord\": // e.g., char-word\r\n (options.charWord as ISplitOptionItem[]).push(parsedParam);\r\n break;\r\n case \"wordLine\": // e.g., word-line\r\n (options.wordLine as ISplitOptionItem[]).push(parsedParam);\r\n break;\r\n default:\r\n // Log a warning for unrecognized option combinations\r\n console.warn(\r\n `SplitOptionsParserTool: Unrecognized option type \"${fullOptionKey}\" in part \"${trimmedPart}\"`\r\n );\r\n break;\r\n }\r\n } else {\r\n // Log a warning for parts that don't match the expected format \"type[params]\" or \"prefix-type[params]\"\r\n console.warn(\r\n `SplitOptionsParserTool: Could not parse part format \"${trimmedPart}\"`\r\n );\r\n }\r\n }); // End forEach part\r\n\r\n return options; // Return the populated options object\r\n }\r\n\r\n /**\r\n * Parses an array of string parameters (extracted from within brackets `[...]`).\r\n * Determines alignment, random settings, and absolute flag.\r\n * Example input: ['center'], ['random(0, 10)', 'abs']\r\n *\r\n * @param params - An array of string parameters.\r\n * @returns An ISplitOptionItem object representing the parsed parameters.\r\n */\r\n private parseParamsArray(params: string[]): ISplitOptionItem {\r\n // Default result with 'start' alignment\r\n const result: ISplitOptionItem = { align: \"start\" };\r\n\r\n params.forEach((param) => {\r\n if (param === \"abs\") {\r\n // Set the absolute flag\r\n result.abs = true;\r\n } else if (param.startsWith(\"random\")) {\r\n // Handle random alignment\r\n result.align = \"random\"; // Set alignment type\r\n // Try to parse min/max values like random(10,50)\r\n // Allows optional whitespace around numbers and comma\r\n const randomMatch = param.match(/random\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*\\)/);\r\n if (randomMatch) {\r\n // If numbers found, parse and store them\r\n result.random = {\r\n min: parseInt(randomMatch[1], 10),\r\n max: parseInt(randomMatch[2], 10),\r\n };\r\n // Optional: Add validation like min <= max here if desired\r\n }\r\n // If 'random' specified without valid numbers, result.align is 'random',\r\n // and result.random remains undefined (defaults will apply later based on context).\r\n } else if ([\"start\", \"center\", \"end\"].includes(param)) {\r\n // Handle specific alignment keywords\r\n result.align = param;\r\n }\r\n // Silently ignore any other unrecognized parameters within the brackets\r\n });\r\n\r\n return result; // Return the parsed option item definition\r\n }\r\n}\r\n","import BoundingClientRectTool from \"../tools/BoundingClientRectTool\"\r\nimport DOMAttributeTool from \"../tools/DOMAttributeTool\"\r\nimport RecordAttributeTool from \"../tools/RecordAttributeTool\"\r\nimport RelativePositionTool from \"../tools/RelativePositionTool\"\r\nimport LerpTool from \"../tools/LerpTool\"\r\nimport TransformNullifyTool from \"../tools/TransformNullifyTool\"\r\nimport UnitParserTool from \"../tools/UnitParserTool\"\r\nimport AdaptiveLerpTool from \"../tools/AdaptiveLerpTool\"\r\nimport OriginParserTool from \"../tools/OriginParserTool\"\r\nimport ColorParserTool from \"../tools/ColorParserTool\"\r\nimport ValidationTool from \"../tools/ValidationTool\"\r\nimport EasingFunctionTool from \"../tools/EasingFunctionTool\"\r\nimport MagneticPullTool from \"../tools/MagneticPullTool\"\r\nimport LerpColorTool from \"../tools/LerpColorTool\"\r\nimport LerpVector2Tool from \"../tools/LerpVector2Tool\"\r\nimport TransformScaleParserTool from \"../tools/TransformScaleParserTool\"\r\nimport { CharIndexerTool } from \"../tools/CharIndexerTool\"\r\nimport { LayoutLineSplitterTool } from \"../tools/LayoutLineSplitterTool\"\r\nimport { SplitDomBuilderTool } from \"../tools/SplitDomBuilderTool\"\r\nimport { WordIndexerTool } from \"../tools/WordIndexerTool\"\r\nimport { SplitOptionsParserTool } from \"../tools/SplitOptionsParserTool\"\r\n\r\n/**\r\n * Interface describing all available tools used inside modules.\r\n */\r\nexport interface StringToolsContainer {\r\n /** Tool for reading DOM attributes (including data-*). */\r\n domAttribute: DOMAttributeTool\r\n\r\n /** Tool for reading attributes from a plain JS object or dataset. */\r\n recordAttribute: RecordAttributeTool\r\n\r\n /** Tool for calculating the relative position between two elements. */\r\n relativePosition: RelativePositionTool\r\n\r\n /** Tool that nullifies the effect of CSS transform matrix. */\r\n transformNullify: TransformNullifyTool\r\n\r\n /** Tool that wraps getBoundingClientRect with consistent output. */\r\n boundingClientRect: BoundingClientRectTool\r\n\r\n /** Tool for parsing string-based values like '50%', '2rem', 'selfHeight'. */\r\n unitParser: UnitParserTool\r\n\r\n /** Tool for performing linear interpolation (lerp). */\r\n lerp: LerpTool\r\n\r\n /** \r\n * Tool for adaptive interpolation based on dynamic input value.\r\n * Useful when smoothing cursor speed, scroll velocity, etc.\r\n */\r\n adaptiveLerp: AdaptiveLerpTool\r\n\r\n /**\r\n * Tool for parsing origin strings.\r\n * Supports values like `'top'`, `'center'`, or random expressions like `'random(top, bottom)'`.\r\n */\r\n originParser: OriginParserTool\r\n\r\n /**\r\n * Tool for parsing CSS color strings into { r, g, b, a } format.\r\n * Supports `#hex`, `rgb[a](...)`, `hsl[a](...)` inputs.\r\n */\r\n colorParser: ColorParserTool\r\n\r\n /**\r\n * Tool for validating strings using rules like `required`, `minLength`, `email`, etc.\r\n * Returns validation status, error code, and optional message.\r\n */\r\n validation: ValidationTool\r\n\r\n /**\r\n * Tool for parsing CSS-like easing strings into easing functions.\r\n * Supports keywords like `'ease'`, `'linear'`, and full `cubic-bezier(...)` expressions.\r\n */\r\n easingFunction: EasingFunctionTool\r\n\r\n /**\r\n * Tool for calculating magnetic offset strength based on proximity to pointer.\r\n */\r\n magneticPull: MagneticPullTool\r\n\r\n /**\r\n * Tool for interpolating between two RGBA colors.\r\n * Accepts `from` and `to` colors as `{ r, g, b, a }`, and a `progress` value from `0` to `1`.\r\n * Returns an interpolated `StringColor` object.\r\n */\r\n lerpColor: LerpColorTool\r\n\r\n /**\r\n * Tool for interpolating between two 2D vectors.\r\n * Accepts `{ x, y }` objects and a `progress` value between `0` and `1`.\r\n * Returns a new `{ x, y }` vector.\r\n */\r\n lerpVector: LerpVector2Tool\r\n\r\n transformScaleParser: TransformScaleParserTool\r\n\r\n layoutSplitter: LayoutLineSplitterTool\r\n\r\n wordIndexer: WordIndexerTool\r\n\r\n charIndexer: CharIndexerTool\r\n\r\n domBuilder: SplitDomBuilderTool\r\n\r\n optionsParser: SplitOptionsParserTool\r\n\r\n}\r\n\r\n/**\r\n * Default implementation of the StringToolContainer,\r\n * which provides ready-to-use instances of all core tools.\r\n */\r\nexport class DefaultToolsContainer implements StringToolsContainer {\r\n public domAttribute = new DOMAttributeTool()\r\n public recordAttribute = new RecordAttributeTool()\r\n public transformNullify = new TransformNullifyTool()\r\n public boundingClientRect = new BoundingClientRectTool()\r\n public relativePosition = new RelativePositionTool(this.transformNullify)\r\n public unitParser = new UnitParserTool()\r\n public lerp = new LerpTool()\r\n public adaptiveLerp = new AdaptiveLerpTool()\r\n public originParser = new OriginParserTool()\r\n public colorParser = new ColorParserTool()\r\n public validation = new ValidationTool()\r\n public easingFunction = new EasingFunctionTool()\r\n public magneticPull = new MagneticPullTool()\r\n public lerpColor = new LerpColorTool()\r\n public lerpVector = new LerpVector2Tool()\r\n public transformScaleParser = new TransformScaleParserTool()\r\n public layoutSplitter = new LayoutLineSplitterTool()\r\n public wordIndexer = new WordIndexerTool()\r\n public charIndexer = new CharIndexerTool()\r\n public domBuilder = new SplitDomBuilderTool()\r\n public optionsParser = new SplitOptionsParserTool()\r\n\r\n}\r\n","import { StringContext } from \"../../core/StringContext\";\r\nimport { StringData } from \"../../core/StringData\";\r\nimport { StringModule } from \"../../core/StringModule\";\r\nimport { StringObject } from \"../../objects/StringObject\";\r\n\r\nexport class StringCursor extends StringModule {\r\n protected enterObjectsMap: Map<string, StringObject> = new Map<\r\n string,\r\n StringObject\r\n >();\r\n protected enterObjects: Array<StringObject> = new Array<StringObject>();\r\n cursor: any;\r\n cursorContent: any;\r\n overCount: number = 0;\r\n\r\n constructor(context: StringContext) {\r\n super(context);\r\n this.htmlKey = \"cursor\";\r\n this.cursor = document.querySelector(\r\n \"[string-cursor],[data-string-cursor]\"\r\n ) as HTMLElement;\r\n this.cursorContent = document.querySelector(\r\n \"[string-cursor-content],[data-string-cursor-content]\"\r\n ) as HTMLElement;\r\n\r\n this.attributesToMap = [\r\n ...this.attributesToMap,\r\n {\r\n key: \"target-disable\",\r\n type: \"boolean\",\r\n fallback: this.settings[\"target-disable\"],\r\n },\r\n {\r\n key: \"target-style-disable\",\r\n type: \"boolean\",\r\n fallback: this.settings[\"target-style-disable\"],\r\n },\r\n {\r\n key: \"target-class\",\r\n type: \"string\",\r\n fallback: this.settings[\"target-class\"],\r\n },\r\n {\r\n key: \"cursor-class\",\r\n type: \"string\",\r\n fallback: this.settings[\"cursor-class\"],\r\n },\r\n {\r\n key: \"alignment\",\r\n type: { type: \"enum\", values: [\"start\", \"center\", \"end\"] },\r\n fallback: this.settings[\"alignment\"],\r\n },\r\n {\r\n key: \"lerp\",\r\n type: \"number\",\r\n fallback: this.settings[\"lerp\"],\r\n transform: (value: number) => {\r\n return this.tools.adaptiveLerp.process({\r\n value,\r\n inMin: 0.1,\r\n inMax: 1.0,\r\n outMin: 0.05,\r\n outMax: 0.65,\r\n });\r\n },\r\n },\r\n ];\r\n }\r\n\r\n initializeObject(\r\n globalId: number,\r\n object: StringObject,\r\n element: HTMLElement,\r\n attributes: Record<string, any>\r\n ): void {\r\n super.initializeObject(globalId, object, element, attributes);\r\n object.setProperty(\"mouse-x\", 0);\r\n object.setProperty(\"mouse-y\", 0);\r\n object.setProperty(\"mouse-pixel-x\", 0);\r\n object.setProperty(\"mouse-pixel-y\", 0);\r\n object.setProperty(\"is-mouse-over\", false);\r\n object.setProperty(\"is-mouse-move\", false);\r\n }\r\n\r\n onFrame(data: StringData): void {\r\n requestAnimationFrame(() => {\r\n this.objects.forEach((object) => {\r\n const isOver = object.getProperty<boolean>(\"is-mouse-over\");\r\n const isDisabled = object.getProperty<boolean>(\"cursor-target-disable\");\r\n const lerpFactor = object.getProperty<number>(\"lerp\") ?? 0.15;\r\n\r\n if (isOver && !isDisabled) {\r\n const rect = object.htmlElement.getBoundingClientRect();\r\n const cursorX = this.data.cursor.targetX;\r\n const cursorY = this.data.cursor.targetY;\r\n const elementX = cursorX - rect.left;\r\n const elementY = cursorY - rect.top;\r\n\r\n let px = object.getProperty<number>(\"mouse-pixel-x\") ?? 0;\r\n let py = object.getProperty<number>(\"mouse-pixel-y\") ?? 0;\r\n\r\n const dx = px - elementX;\r\n const dy = py - elementY;\r\n const distSquared = dx * dx + dy * dy;\r\n\r\n if (distSquared > 0.0001) {\r\n const isMoving =\r\n object.getProperty<boolean>(\"is-mouse-move\") ?? false;\r\n if (!isMoving) {\r\n object.setProperty(\"is-mouse-move\", true);\r\n object.setProperty(\"mouse-pixel-x\", elementX);\r\n object.setProperty(\"mouse-pixel-y\", elementY);\r\n object.setProperty(\"mouse-x\", elementX);\r\n object.setProperty(\"mouse-y\", elementY);\r\n px = elementX;\r\n py = elementY;\r\n this.events.emit(`cursor:start:${object.id}`, null);\r\n }\r\n\r\n const lerpedX = this.tools.lerp.process({\r\n from: px,\r\n to: elementX,\r\n progress: lerpFactor,\r\n });\r\n const lerpedY = this.tools.lerp.process({\r\n from: py,\r\n to: elementY,\r\n progress: lerpFactor,\r\n });\r\n\r\n const updatedX = px + lerpedX;\r\n const updatedY = py + lerpedY;\r\n\r\n object.setProperty(\"mouse-pixel-x\", updatedX);\r\n object.setProperty(\"mouse-pixel-y\", updatedY);\r\n\r\n const alignment =\r\n object.getProperty<string>(\"alignment\") ?? \"center\";\r\n const offsetX = this.calculateOffset(\r\n alignment,\r\n updatedX,\r\n rect.width\r\n );\r\n const offsetY = this.calculateOffset(\r\n alignment,\r\n updatedY,\r\n rect.height\r\n );\r\n\r\n object.setProperty(\"mouse-x\", offsetX);\r\n object.setProperty(\"mouse-y\", offsetY);\r\n\r\n this.setMouseCoordinates(object, offsetX, offsetY);\r\n\r\n this.events.emit(`cursor:move:${object.id}`, {\r\n x: offsetX,\r\n y: offsetY,\r\n });\r\n this.events.emit(`cursor:pixel:${object.id}`, {\r\n x: updatedX,\r\n y: updatedY,\r\n });\r\n } else {\r\n object.setProperty(\"mouse-pixel-x\", elementX);\r\n object.setProperty(\"mouse-pixel-y\", elementY);\r\n this.events.emit(`cursor:end:${object.id}`, null);\r\n }\r\n } else {\r\n const mouseX = object.getProperty<number>(\"mouse-x\") ?? 0;\r\n const mouseY = object.getProperty<number>(\"mouse-y\") ?? 0;\r\n if (mouseX !== 0 || mouseY !== 0) {\r\n object.setProperty(\"is-mouse-move\", false);\r\n\r\n const rect = object.htmlElement.getBoundingClientRect();\r\n const halfWidth =\r\n object.getProperty<number>(\"half-width\") ?? rect.width / 2;\r\n const halfHeight =\r\n object.getProperty<number>(\"half-height\") ?? rect.height / 2;\r\n\r\n const targetX = this.calculateOffset(\r\n \"center\",\r\n halfWidth,\r\n rect.width\r\n );\r\n const targetY = this.calculateOffset(\r\n \"center\",\r\n halfHeight,\r\n rect.height\r\n );\r\n\r\n const newMouseX =\r\n mouseX +\r\n this.tools.lerp.process({\r\n from: mouseX,\r\n to: targetX,\r\n progress: lerpFactor,\r\n });\r\n const newMouseY =\r\n mouseY +\r\n this.tools.lerp.process({\r\n from: mouseY,\r\n to: targetY,\r\n progress: lerpFactor,\r\n });\r\n\r\n object.setProperty(\"mouse-x\", newMouseX);\r\n object.setProperty(\"mouse-y\", newMouseY);\r\n\r\n if (Math.abs(newMouseX) < 0.001 && Math.abs(newMouseY) < 0.001) {\r\n object.setProperty(\"mouse-x\", 0);\r\n object.setProperty(\"mouse-y\", 0);\r\n object.setProperty(\"mouse-pixel-x\", 0);\r\n object.setProperty(\"mouse-pixel-y\", 0);\r\n }\r\n\r\n this.setMouseCoordinates(object, newMouseX, newMouseY);\r\n }\r\n }\r\n });\r\n\r\n const { stepX, stepY, smoothedX, smoothedY } = this.data.cursor;\r\n if (stepX !== 0 || stepY !== 0) {\r\n this.events.emit(\"cursor\", {\r\n stepX,\r\n stepY,\r\n x: smoothedX,\r\n y: smoothedY,\r\n });\r\n\r\n this.cursor.style.setProperty(\"--x\", smoothedX.toString());\r\n this.cursor.style.setProperty(\"--y\", smoothedY.toString());\r\n this.cursor.style.setProperty(\"--x-lerp\", stepX.toString());\r\n this.cursor.style.setProperty(\"--y-lerp\", stepY.toString());\r\n }\r\n });\r\n }\r\n\r\n onObjectConnected(object: StringObject) {\r\n const element = object.htmlElement;\r\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\r\n\r\n object.setProperty(\"timeoutId\", timeoutId);\r\n\r\n object.setProperty(\"mouseleave\", () => {\r\n this.onMouseLeave(object);\r\n });\r\n object.setProperty(\"mouseenter\", () => {\r\n this.onMouseEnter(object);\r\n });\r\n\r\n object.setProperty(\"onEnterEvent\", this.onEnterObject.bind(this));\r\n object.events.on(\r\n \"enter\",\r\n object.getProperty<(object: StringObject) => void>(\"onEnterEvent\")\r\n );\r\n object.setProperty(\"onLeaveEvent\", this.onLeaveObject.bind(this));\r\n object.events.on(\r\n \"leave\",\r\n object.getProperty<(object: StringObject) => void>(\"onLeaveEvent\")\r\n );\r\n }\r\n\r\n getCursorClass(object: StringObject) {\r\n const value = object.getProperty<string>(\"cursor-class\");\r\n return value != null && value.length > 0 ? value : null;\r\n }\r\n\r\n onMouseEnter(object: StringObject) {\r\n this.overCount++;\r\n object.setProperty(\"is-mouse-over\", true);\r\n\r\n const cursorClass = this.getCursorClass(object);\r\n if (cursorClass) {\r\n this.cursor.classList.add(cursorClass);\r\n }\r\n\r\n this.cursor.classList.add(\"-showing\");\r\n\r\n object.setProperty(\r\n \"timeoutId\",\r\n setTimeout(() => {\r\n this.cursor.classList.remove(\"-showing\");\r\n this.cursor.classList.add(\"-show\");\r\n }, 1200)\r\n );\r\n\r\n object.htmlElement.addEventListener(\r\n \"mouseleave\",\r\n object.getProperty(\"mouseleave\")\r\n );\r\n }\r\n\r\n onMouseLeave(object: StringObject) {\r\n this.overCount--;\r\n object.setProperty(\"is-mouse-over\", false);\r\n\r\n if (object.getProperty(\"timeoutId\")) {\r\n clearTimeout(object.getProperty(\"timeoutId\"));\r\n object.setProperty(\"timeoutId\", null);\r\n }\r\n\r\n const cursorClass = this.getCursorClass(object);\r\n if (cursorClass) {\r\n this.cursor.classList.remove(cursorClass);\r\n }\r\n\r\n this.cursor.classList.remove(\"-showing\");\r\n this.cursor.classList.remove(\"-show\");\r\n\r\n object.htmlElement.removeEventListener(\r\n \"mouseleave\",\r\n object.getProperty(\"mouseleave\")\r\n );\r\n }\r\n\r\n private onEnterObject(object: StringObject) {\r\n object.htmlElement.addEventListener(\r\n \"mouseenter\",\r\n object.getProperty(\"mouseenter\")\r\n );\r\n }\r\n private onLeaveObject(object: StringObject) {\r\n object.htmlElement.removeEventListener(\r\n \"mouseenter\",\r\n object.getProperty(\"mouseenter\")\r\n );\r\n object.htmlElement.removeEventListener(\r\n \"mouseleave\",\r\n object.getProperty(\"mouseleave\")\r\n );\r\n }\r\n\r\n private setMouseCoordinates(object: StringObject, x: number, y: number) {\r\n if (!object.getProperty(\"cursor-target-style-disable\")) {\r\n this.applyToElementAndConnects(object, (el) => {\r\n el.style.setProperty(\"--x\", x.toFixed(2));\r\n el.style.setProperty(\"--y\", y.toFixed(2));\r\n });\r\n }\r\n }\r\n\r\n private calculateOffset(\r\n alignment: string,\r\n mousePos: number,\r\n size: number\r\n ): number {\r\n switch (alignment) {\r\n case \"start\":\r\n return mousePos / size;\r\n case \"end\":\r\n return (mousePos - size) / size;\r\n case \"center\":\r\n default:\r\n return (mousePos - size / 2) / (size / 2);\r\n }\r\n }\r\n}\r\n","import { StringContext } from \"../../core/StringContext\";\r\nimport { StringData } from \"../../core/StringData\";\r\nimport { StringModule } from \"../../core/StringModule\";\r\nimport { StringObject } from \"../../objects/StringObject\";\r\n\r\nexport class StringMagnetic extends StringModule {\r\n constructor(context: StringContext) {\r\n super(context);\r\n this.htmlKey = \"magnetic\";\r\n\r\n this.attributesToMap = [\r\n ...this.attributesToMap,\r\n { key: \"strength\", type: \"number\", fallback: this.settings[\"strength\"] },\r\n { key: \"radius\", type: \"number\", fallback: this.settings[\"radius\"] },\r\n ];\r\n }\r\n\r\n override initializeObject(\r\n globalId: number,\r\n object: StringObject,\r\n element: HTMLElement,\r\n attributes: Record<string, any>\r\n ): void {\r\n super.initializeObject(globalId, object, element, attributes);\r\n object.setProperty(\"is-magneting\", false);\r\n object.setProperty(\"magnetic-target-x\", 0);\r\n object.setProperty(\"magnetic-target-y\", 0);\r\n object.setProperty(\"magnetic-x\", 0);\r\n object.setProperty(\"magnetic-y\", 0);\r\n object.setProperty(\"lerp\", 0.1);\r\n }\r\n\r\n onMouseMove(e: MouseEvent): void {\r\n this.objects.forEach((object) => {\r\n const element = object.htmlElement as HTMLElement;\r\n const rect = element.getBoundingClientRect();\r\n const centerX =\r\n rect.left + (object.getProperty<number>(\"half-width\") ?? 0);\r\n const centerY =\r\n rect.top + (object.getProperty<number>(\"half-height\") ?? 0);\r\n const dx = e.clientX - centerX;\r\n const dy = e.clientY - centerY;\r\n const distance = Math.sqrt(dx ** 2 + dy ** 2);\r\n\r\n const radius = object.getProperty<number>(\"radius\") ?? 0;\r\n const strength = object.getProperty<number>(\"strength\") ?? 0;\r\n\r\n const factor = this.tools.magneticPull.process({\r\n distance,\r\n radius,\r\n strength,\r\n });\r\n\r\n object.setProperty(\"magnetic-target-x\", dx * factor);\r\n object.setProperty(\"magnetic-target-y\", dy * factor);\r\n if (factor > 0) {\r\n object.setProperty(\"is-magneting\", true);\r\n }\r\n });\r\n }\r\n\r\n onFrame(data: StringData): void {\r\n this.objects.forEach((object) => {\r\n if (object.getProperty(\"is-magneting\")) {\r\n let magneticX = object.getProperty<number>(\"magnetic-x\") ?? 0;\r\n let magneticY = object.getProperty<number>(\"magnetic-y\") ?? 0;\r\n\r\n let lerp = object.getProperty<number>(\"lerp\") ?? 0;\r\n\r\n let targetMagneticX =\r\n object.getProperty<number>(\"magnetic-target-x\") ?? 0;\r\n let targetMagneticY =\r\n object.getProperty<number>(\"magnetic-target-y\") ?? 0;\r\n\r\n let lerpX = this.tools.lerp.process({\r\n from: magneticX,\r\n to: targetMagneticX,\r\n progress: lerp,\r\n });\r\n let lerpY = this.tools.lerp.process({\r\n from: magneticY,\r\n to: targetMagneticY,\r\n progress: lerp,\r\n });\r\n\r\n if (lerpX > -0.01 && lerpX < 0.01) {\r\n lerpX = 0;\r\n object.setProperty(\r\n \"magnetic-x\",\r\n object.getProperty(\"magnetic-target-x\")\r\n );\r\n }\r\n if (lerpY > -0.01 && lerpY < 0.01) {\r\n lerpY = 0;\r\n object.setProperty(\r\n \"magnetic-y\",\r\n object.getProperty(\"magnetic-target-y\")\r\n );\r\n }\r\n magneticX += lerpX;\r\n magneticY += lerpY;\r\n object.setProperty<number>(\"magnetic-x\", magneticX);\r\n object.setProperty<number>(\"magnetic-y\", magneticY);\r\n this.events.emit(`magnetic:move:${object.id}`, {\r\n x: magneticX,\r\n y: magneticY,\r\n });\r\n\r\n this.applyToElementAndConnects(object, (el) => {\r\n el.style.setProperty(\"--magnetic-x\", magneticX.toString());\r\n el.style.setProperty(\"--magnetic-y\", magneticY.toString());\r\n });\r\n\r\n if (\r\n object.getProperty(\"magnetic-target-x\") == magneticX ||\r\n object.getProperty(\"magnetic-target-y\") == magneticY\r\n ) {\r\n object.setProperty(\"is-magneting\", false);\r\n }\r\n }\r\n });\r\n }\r\n}\r\n","import { StringContext } from \"../../core/StringContext\";\r\nimport { StringModule } from \"../../core/StringModule\";\r\nimport { StringObject } from \"../../objects/StringObject\";\r\n\r\n/**\r\n * Module that handles lazy-loading of images with `string-lazy` attribute.\r\n * Automatically loads and applies aspect-ratio once image is loaded.\r\n */\r\nexport class StringLazy extends StringModule {\r\n private isStartLoaded = false;\r\n private loadingCount = 0;\r\n\r\n constructor(context: StringContext) {\r\n super(context);\r\n this.htmlKey = \"lazy\";\r\n }\r\n\r\n /**\r\n * Called on module start — preloads all <img string-lazy> in DOM.\r\n */\r\n onInit(): void {\r\n const images = document.querySelectorAll(\r\n \"img[string-lazy], img[data-string-lazy]\"\r\n );\r\n images.forEach((img) => this.loadImage(img as HTMLImageElement));\r\n this.isStartLoaded = true;\r\n }\r\n\r\n /**\r\n * Called when an image becomes a managed object.\r\n */\r\n onObjectConnected(object: StringObject): void {\r\n this.loadingCount++;\r\n\r\n if (this.isStartLoaded) {\r\n const img = object.htmlElement as HTMLImageElement;\r\n this.loadImage(img);\r\n }\r\n }\r\n\r\n /**\r\n * Loads image and sets aspect-ratio based on real dimensions.\r\n */\r\n private async loadImage(img: HTMLImageElement): Promise<void> {\r\n const src = this.tools.domAttribute.process({\r\n element: img,\r\n key: this.htmlKey,\r\n fallback: \"\",\r\n });\r\n\r\n if (!src) return;\r\n\r\n try {\r\n img.classList.add(\"lazyLoad\");\r\n img.src = src;\r\n\r\n img.addEventListener(\"load\", () => {\r\n img.classList.add(\"-loaded\");\r\n });\r\n await this.setAspectRatio(img, src);\r\n } catch (err) {\r\n console.warn(\"Failed to load image:\", src);\r\n }\r\n }\r\n\r\n /**\r\n * Loads image data to extract real dimensions and apply aspect-ratio style.\r\n */\r\n private setAspectRatio(el: HTMLElement, url: string): Promise<void> {\r\n return new Promise((resolve, reject) => {\r\n const xhr = new XMLHttpRequest();\r\n xhr.open(\"GET\", url, true);\r\n xhr.responseType = \"arraybuffer\";\r\n xhr.setRequestHeader(\"Range\", \"bytes=0-\");\r\n xhr.onload = () => {\r\n if (xhr.status === 200 || xhr.status === 206) {\r\n const blob = new Blob([xhr.response]);\r\n const img = new Image();\r\n img.onload = () => {\r\n el.style.aspectRatio = `${img.width} / ${img.height}`;\r\n URL.revokeObjectURL(img.src);\r\n\r\n this.loadingCount--;\r\n if (this.loadingCount <= 0) {\r\n this.events.emit(\"image:load:all\", null);\r\n this.loadingCount = 0;\r\n }\r\n\r\n resolve();\r\n };\r\n img.onerror = () => {\r\n URL.revokeObjectURL(img.src);\r\n this.loadingCount--;\r\n reject(new Error(\"Image failed to decode\"));\r\n };\r\n img.src = URL.createObjectURL(blob);\r\n } else {\r\n reject(new Error(\"Image request failed\"));\r\n }\r\n };\r\n xhr.onerror = () => reject(new Error(\"XHR error\"));\r\n xhr.send();\r\n });\r\n }\r\n}\r\n","import { StringContext } from \"../../core/StringContext\";\r\nimport { StringModule } from \"../../core/StringModule\";\r\n\r\n\r\nexport class StringLoading extends StringModule{\r\n loadingTimeout: number = 0\r\n\r\n constructor(context: StringContext) {\r\n super(context)\r\n this._type = 2\r\n this.loadingTimeout = this.settings['timeout']\r\n }\r\n onInit(): void {\r\n setTimeout(() => {\r\n const htmlElement = document.documentElement;\r\n htmlElement.classList.add('-loaded');\r\n }, this.loadingTimeout);\r\n \r\n }\r\n}","import { StringModule } from \"../../core/StringModule\";\r\nimport { StringObject } from \"../../objects/StringObject\";\r\n\r\nexport class StringInview extends StringModule {\r\n constructor(visitor: any) {\r\n super(visitor);\r\n this.htmlKey = '';\r\n }\r\n canConnect(object: StringObject): boolean {\r\n return object.keys[0]==undefined;\r\n }\r\n}\r\n","import { StringContext } from \"../../core/StringContext\";\r\nimport { StringModule } from \"../../core/StringModule\";\r\n\r\nenum DeviceType {\r\n Mobile,\r\n Tablet,\r\n Laptop,\r\n Desktop,\r\n}\r\n\r\ninterface DeviceQueryConfig {\r\n min?: number;\r\n max?: number;\r\n enable?: boolean;\r\n}\r\n\r\ninterface QueryConfig {\r\n mobile?: DeviceQueryConfig;\r\n tablet?: DeviceQueryConfig;\r\n laptop?: DeviceQueryConfig;\r\n desktop?: DeviceQueryConfig;\r\n}\r\n\r\nclass StringResponsiveQueryDevice {\r\n public min?: number = undefined;\r\n public max?: number = undefined;\r\n public enable: boolean = true;\r\n\r\n constructor(config?: DeviceQueryConfig) {\r\n this.min = config?.min;\r\n this.max = config?.max;\r\n this.enable = config?.enable ?? true;\r\n }\r\n\r\n setEnable(enable: boolean = true) {\r\n this.enable = enable;\r\n }\r\n setRange(min?: number, max?: number) {\r\n this.min = min ?? undefined;\r\n this.max = max ?? undefined;\r\n }\r\n\r\n get mediaQuery(): string {\r\n let query = \"screen\";\r\n if (this.min) {\r\n query += ` and (min-width: ${this.min}px)`;\r\n }\r\n if (this.max) {\r\n query += ` and (max-width: ${this.max}px)`;\r\n }\r\n return query;\r\n }\r\n}\r\n\r\nexport class StringResponsive extends StringModule {\r\n private queries: { [key in DeviceType]: StringResponsiveQueryDevice } = {\r\n [DeviceType.Mobile]: new StringResponsiveQueryDevice({ max: 359 }),\r\n [DeviceType.Tablet]: new StringResponsiveQueryDevice({\r\n min: 360,\r\n max: 1079,\r\n }),\r\n [DeviceType.Laptop]: new StringResponsiveQueryDevice({\r\n min: 1080,\r\n max: 1365,\r\n }),\r\n [DeviceType.Desktop]: new StringResponsiveQueryDevice({ min: 1366 }),\r\n };\r\n\r\n private matchMedias: { [key in DeviceType]: MediaQueryList } = {\r\n [DeviceType.Mobile]: window.matchMedia(\r\n this.queries[DeviceType.Mobile].mediaQuery\r\n ),\r\n [DeviceType.Tablet]: window.matchMedia(\r\n this.queries[DeviceType.Tablet].mediaQuery\r\n ),\r\n [DeviceType.Laptop]: window.matchMedia(\r\n this.queries[DeviceType.Laptop].mediaQuery\r\n ),\r\n [DeviceType.Desktop]: window.matchMedia(\r\n this.queries[DeviceType.Desktop].mediaQuery\r\n ),\r\n };\r\n\r\n constructor(context: StringContext) {\r\n super(context);\r\n this._type = 2;\r\n }\r\n\r\n onConnect() {}\r\n\r\n onInit(): void {\r\n if (this.settings != null) {\r\n if (this.settings[\"settings\"] != null) {\r\n let config = this.settings[\"settings\"];\r\n if (config.mobile) {\r\n this.queries[DeviceType.Mobile].enable = true;\r\n this.queries[DeviceType.Mobile].setRange(\r\n config.mobile.min == undefined ? null : config.mobile.min,\r\n config.mobile.max ?? null\r\n );\r\n this.matchMedias[DeviceType.Mobile] = window.matchMedia(\r\n this.queries[DeviceType.Mobile].mediaQuery\r\n );\r\n } else {\r\n this.queries[DeviceType.Mobile].enable = false;\r\n }\r\n\r\n if (config.tablet) {\r\n this.queries[DeviceType.Tablet].enable = true;\r\n this.queries[DeviceType.Tablet].setRange(\r\n config.mobile.min == undefined ? null : config.mobile.min,\r\n config.mobile.max ?? null\r\n );\r\n this.matchMedias[DeviceType.Tablet] = window.matchMedia(\r\n this.queries[DeviceType.Mobile].mediaQuery\r\n );\r\n } else {\r\n this.queries[DeviceType.Tablet].enable = false;\r\n }\r\n\r\n if (config.laptop) {\r\n this.queries[DeviceType.Laptop].enable = true;\r\n this.queries[DeviceType.Laptop].setRange(\r\n config.mobile.min == undefined ? null : config.mobile.min,\r\n config.mobile.max ?? null\r\n );\r\n this.matchMedias[DeviceType.Laptop] = window.matchMedia(\r\n this.queries[DeviceType.Mobile].mediaQuery\r\n );\r\n } else {\r\n this.queries[DeviceType.Laptop].enable = false;\r\n }\r\n\r\n if (config.desktop) {\r\n this.queries[DeviceType.Desktop].enable = true;\r\n this.queries[DeviceType.Desktop].setRange(\r\n config.mobile.min == undefined ? null : config.mobile.min,\r\n config.mobile.max ?? null\r\n );\r\n this.matchMedias[DeviceType.Desktop] = window.matchMedia(\r\n this.queries[DeviceType.Mobile].mediaQuery\r\n );\r\n } else {\r\n this.queries[DeviceType.Desktop].enable = false;\r\n }\r\n }\r\n }\r\n this.updateElements();\r\n }\r\n\r\n onResize(): void {\r\n this.updateElements();\r\n }\r\n\r\n private updateElements() {\r\n const isMobileMedia =\r\n this.matchMedias[DeviceType.Mobile].matches &&\r\n this.queries[DeviceType.Mobile].enable;\r\n const isTabletMedia =\r\n this.matchMedias[DeviceType.Tablet].matches &&\r\n this.queries[DeviceType.Tablet].enable;\r\n const isLaptopMedia =\r\n this.matchMedias[DeviceType.Laptop].matches &&\r\n this.queries[DeviceType.Laptop].enable;\r\n const isDesktopMedia =\r\n this.matchMedias[DeviceType.Desktop].matches &&\r\n this.queries[DeviceType.Desktop].enable;\r\n\r\n const elements = document.querySelectorAll(\r\n \"[string-mobile], [string-tablet], [string-laptop], [string-desktop]\"\r\n );\r\n\r\n elements.forEach((element: any) => {\r\n let showElement = false;\r\n\r\n if (element.hasAttribute(\"string-mobile\") && isMobileMedia) {\r\n showElement = true;\r\n this.events.emit(\"screen:mobile\", isMobileMedia);\r\n }\r\n if (element.hasAttribute(\"string-tablet\") && isTabletMedia) {\r\n showElement = true;\r\n this.events.emit(\"screen:tablet\", isTabletMedia);\r\n }\r\n if (element.hasAttribute(\"string-laptop\") && isLaptopMedia) {\r\n showElement = true;\r\n this.events.emit(\"screen:laptop\", isLaptopMedia);\r\n }\r\n if (element.hasAttribute(\"string-desktop\") && isDesktopMedia) {\r\n showElement = true;\r\n this.events.emit(\"screen:desktop\", isDesktopMedia);\r\n }\r\n\r\n if (showElement) {\r\n element.style.display = null;\r\n } else {\r\n element.style.display = `none`;\r\n }\r\n });\r\n }\r\n}\r\n","import { StringContext } from \"../../core/StringContext\";\r\nimport { StringModule } from \"../../core/StringModule\";\r\nimport { StringObject } from \"../../objects/StringObject\";\r\n\r\nexport class StringAnchor extends StringModule {\r\n constructor(context: StringContext) {\r\n super(context);\r\n this.htmlKey = 'anchor';\r\n this.attributesToMap = [\r\n ...this.attributesToMap,\r\n {\r\n key: 'anchor',\r\n type: 'tuple',\r\n fallback: this.settings['anchor'],\r\n transform: (tuple: string[]) => {\r\n const [xRaw, yRaw] = tuple;\r\n const x = this.tools.originParser.process({value: xRaw});\r\n const y = this.tools.originParser.process({value: yRaw});\r\n return { x, y };\r\n },\r\n }\r\n ];\r\n }\r\n onObjectConnected(object: StringObject) {\r\n super.onObjectConnected(object)\r\n const anchor = object.getProperty<{ x: string, y: string }>('anchor')\r\n if (anchor) {\r\n this.applyToElementAndConnects(object, (el) => {\r\n el.style.transformOrigin = `${anchor.x} ${anchor.y}`;\r\n })\r\n }\r\n }\r\n\r\n}","import { StringContext } from \"../../core/StringContext\";\r\nimport { StringData } from \"../../core/StringData\";\r\nimport { StringModule } from \"../../core/StringModule\";\r\nimport { StringObject } from \"../../objects/StringObject\";\r\n\r\nconst ACCELERATION_STEP: number = 0.05;\r\nconst MIN_DISPLACEMENT: number = 0.01;\r\nconst MAX_DISPLACEMENT: number = 1;\r\nconst MIN_VELOCITY: number = -1;\r\nconst MAX_VELOCITY: number = 1;\r\n\r\nexport class StringGlide extends StringModule {\r\n private previousLerp: number = 0;\r\n private displacement: number = 0;\r\n private acceleration: number = 0;\r\n private velocityMultiplier: number = 0.00125;\r\n private isInitialScroll: boolean = true;\r\n\r\n private baseVelocityMultiplier: number = 0.00125;\r\n private reducedVelocityMultiplier: number = this.baseVelocityMultiplier / 20;\r\n private negativeVelocityMultiplier: number = -0.0001;\r\n\r\n private maxDisplacementValue: number = 0;\r\n\r\n constructor(context: StringContext) {\r\n super(context);\r\n this.htmlKey = \"glide\";\r\n\r\n this.baseVelocityMultiplier =\r\n this.settings[\"glide-base-velocity\"] ?? this.baseVelocityMultiplier;\r\n this.reducedVelocityMultiplier =\r\n this.settings[\"glide-reduce-velocity\"] ?? this.reducedVelocityMultiplier;\r\n this.negativeVelocityMultiplier =\r\n this.settings[\"glide-negative-velocity\"] ??\r\n this.negativeVelocityMultiplier;\r\n\r\n this.attributesToMap = [\r\n ...this.attributesToMap,\r\n { key: \"glide\", type: \"number\", fallback: this.settings[\"glide\"] },\r\n ];\r\n }\r\n\r\n private setupItem = (object: StringObject) => {\r\n let glide = object.getProperty<number>(\"glide\") ?? 0;\r\n\r\n let glideValue =\r\n -this.data.scroll.displacement * this.maxDisplacementValue * glide;\r\n this.events.emit(`glide:${object.id}`, glideValue);\r\n\r\n const transformCompute = `translate3d(0, ${glideValue}px, 0)`;\r\n object.htmlElement.style.transform = transformCompute;\r\n };\r\n\r\n private onUpdateDesktopEvent = () => {\r\n for (let i = 0; i < this.objects.length; i++) {\r\n let object = this.objects[i];\r\n this.setupItem(object);\r\n }\r\n };\r\n private onUpdateMobileEvent = () => {};\r\n private onUpdateEvent = this.onUpdateDesktopEvent;\r\n\r\n private calcExpanderFactor(isDirectionUp: boolean): void {\r\n const isConditionMet = isDirectionUp\r\n ? this.data.scroll.lerped < this.previousLerp\r\n : this.data.scroll.lerped > this.previousLerp;\r\n\r\n this.velocityMultiplier = isConditionMet\r\n ? this.isInitialScroll\r\n ? this.baseVelocityMultiplier\r\n : this.reducedVelocityMultiplier\r\n : this.negativeVelocityMultiplier;\r\n\r\n if (!isConditionMet) {\r\n this.isInitialScroll = false;\r\n }\r\n }\r\n onStart(): void {\r\n this.maxDisplacementValue = this.data.viewport.windowHeight * 0.1;\r\n }\r\n\r\n onResize(): void {\r\n if (window.innerWidth > 1080) {\r\n this.maxDisplacementValue = this.data.viewport.windowHeight * 0.1;\r\n this.onUpdateEvent = this.onUpdateDesktopEvent;\r\n } else {\r\n this.onUpdateEvent = this.onUpdateMobileEvent;\r\n this.resetState();\r\n this.objects.forEach((object) => {\r\n this.setupItem(object);\r\n });\r\n }\r\n }\r\n\r\n private resetState(): void {\r\n this.displacement = 0;\r\n this.acceleration = 0;\r\n this.isInitialScroll = true;\r\n this.velocityMultiplier = this.baseVelocityMultiplier;\r\n }\r\n\r\n onScrollStart(): void {\r\n this.resetState();\r\n }\r\n\r\n onScrollStop(): void {\r\n this.resetState();\r\n this.previousLerp = 0;\r\n //document.documentElement.style.setProperty('--glide', '0');\r\n for (let i = 0; i < this.objects.length; i++) {\r\n let object = this.objects[i];\r\n const transformCompute = `translate3d(0, 0px, 0)`;\r\n object.htmlElement.style.transform = transformCompute;\r\n object.htmlElement.style.setProperty(\r\n \"--glide\",\r\n this.data.scroll.displacement.toString()\r\n );\r\n }\r\n }\r\n\r\n onFrame(data: StringData): void {\r\n this.calcExpanderFactor(this.data.scroll.isScrollingDown === false);\r\n this.acceleration = Math.min(\r\n MAX_DISPLACEMENT,\r\n this.acceleration + ACCELERATION_STEP\r\n );\r\n this.displacement = Math.max(\r\n MIN_DISPLACEMENT,\r\n Math.min(MAX_DISPLACEMENT, this.displacement + this.velocityMultiplier)\r\n );\r\n this.data.scroll.displacement = Math.min(\r\n MAX_VELOCITY,\r\n Math.max(\r\n MIN_VELOCITY,\r\n this.data.scroll.lerped * this.displacement * this.acceleration\r\n )\r\n );\r\n this.objects.forEach((object) => {\r\n this.applyToElementAndConnects(object, (el) => {\r\n el.style.setProperty(\r\n \"--glide\",\r\n this.data.scroll.displacement.toString()\r\n );\r\n });\r\n });\r\n this.previousLerp = this.data.scroll.lerped;\r\n this.onUpdateEvent();\r\n }\r\n}\r\n","import { StringContext } from \"../../core/StringContext\";\r\nimport { StringData } from \"../../core/StringData\";\r\nimport { StringModule } from \"../../core/StringModule\";\r\nimport { StringToolsContainer } from \"../../core/StringToolsContainer\";\r\nimport { StringObject } from \"../../objects/StringObject\";\r\n\r\n/**\r\n * Module that updates the `--lerp` CSS variable on elements\r\n * based on current scroll velocity.\r\n */\r\nexport class StringLerp extends StringModule {\r\n constructor(context: StringContext) {\r\n super(context);\r\n this.htmlKey = \"lerp\";\r\n }\r\n\r\n /**\r\n * Resets the `--lerp` value to 0 when scroll stops.\r\n */\r\n onScrollStop(): void {\r\n this.objects.forEach((object) => {\r\n this.setLerpValue(object, 0);\r\n });\r\n }\r\n\r\n /**\r\n * Updates `--lerp` value for each connected object during scroll.\r\n */\r\n onFrame(data: StringData): void {\r\n const velocity = data.scroll.lerped;\r\n this.objects.forEach((object) => {\r\n this.setLerpValue(object, velocity);\r\n });\r\n }\r\n\r\n /**\r\n * Sets the `--lerp` CSS variable on the object.\r\n */\r\n private setLerpValue(object: StringObject, value: number): void {\r\n this.events.emit(`lerp:${object.id}`, value);\r\n object.htmlElement.style.setProperty(\"--lerp\", value.toString());\r\n }\r\n}\r\n","import { StringContext } from \"../../core/StringContext\";\r\nimport { StringData } from \"../../core/StringData\";\r\nimport { StringModule } from \"../../core/StringModule\";\r\nimport { StringToolsContainer } from \"../../core/StringToolsContainer\";\r\nimport { StringObject } from \"../../objects/StringObject\";\r\nimport { EasingFunctionOutput } from \"../../tools/EasingFunctionTool\";\r\nimport LerpVector2Tool from \"../../tools/LerpVector2Tool\";\r\n\r\nexport class StringProgress extends StringModule {\r\n constructor(context: StringContext) {\r\n super(context);\r\n this.htmlKey = \"progress\";\r\n\r\n this.attributesToMap = [\r\n ...this.attributesToMap,\r\n { key: \"enter-el\", type: \"string\", fallback: this.settings[\"enter-el\"] },\r\n { key: \"enter-vp\", type: \"string\", fallback: this.settings[\"enter-vp\"] },\r\n { key: \"exit-el\", type: \"string\", fallback: this.settings[\"exit-el\"] },\r\n { key: \"exit-vp\", type: \"string\", fallback: this.settings[\"exit-vp\"] },\r\n { key: \"easing\", type: \"easing\", fallback: this.settings[\"easing\"] },\r\n ];\r\n }\r\n\r\n /**\r\n * Called when an object is initialized.\r\n */\r\n initializeObject(\r\n globalId: number,\r\n object: StringObject,\r\n element: HTMLElement,\r\n attributes: Record<string, any>\r\n ): void {\r\n super.initializeObject(globalId, object, element, attributes);\r\n }\r\n\r\n /**\r\n * Called on scroll.\r\n */\r\n onScroll(data: StringData): void {\r\n super.onScroll(data);\r\n this.objects.forEach((object) => {\r\n this.setUpObject(object);\r\n });\r\n }\r\n\r\n onObjectConnected(object: StringObject) {\r\n super.onObjectConnected(object);\r\n\r\n object.setProperty(\"setUpObject\", this.setUpObject.bind(this));\r\n object.events.on(\r\n \"enter\",\r\n object.getProperty<(object: StringObject) => void>(\"setUpObject\")\r\n );\r\n }\r\n\r\n private setUpObject(object: StringObject) {\r\n const startPosition = object.getProperty<number>(\"start-position\");\r\n const differencePosition = object.getProperty<number>(\r\n \"difference-position\"\r\n );\r\n const key = object.getProperty<string>(\"key\");\r\n\r\n const progress = object.getProperty<EasingFunctionOutput>(\"easing\")(\r\n Math.min(\r\n 1,\r\n Math.max(\r\n 0,\r\n (this.data.scroll.transformedCurrent - startPosition) /\r\n differencePosition\r\n )\r\n )\r\n );\r\n\r\n if (object.getProperty<number>(\"progress\") !== progress) {\r\n this.events.emit(`progress:${object.id}`, progress);\r\n object.setProperty<number>(\"progress\", progress);\r\n const progressStr = progress.toString();\r\n this.applyToElementAndConnects(object, (el) => {\r\n el.style.setProperty(key, progressStr);\r\n });\r\n }\r\n }\r\n\r\n calculatePositions(object: StringObject, windowSize: number) {\r\n const start = object.getProperty<number>(\"start\");\r\n const size = object.getProperty<number>(\"size\");\r\n\r\n const offsetStart = object.getProperty<number>(\"offset-bottom\");\r\n const offsetEnd = object.getProperty<number>(\"offset-top\");\r\n\r\n const startElement = object.getProperty(\"enter-el\");\r\n const startViewport = object.getProperty(\"enter-vp\");\r\n const endElement = object.getProperty(\"exit-el\");\r\n const endViewport = object.getProperty(\"exit-vp\");\r\n\r\n let startPosition = 0;\r\n let endPosition = 0;\r\n\r\n if (\r\n (startElement === \"top\" && startViewport === \"top\") ||\r\n (startElement === \"left\" && startViewport === \"left\")\r\n ) {\r\n startPosition = start - offsetStart;\r\n } else if (\r\n (startElement === \"top\" && startViewport === \"bottom\") ||\r\n (startElement === \"left\" && startViewport === \"right\")\r\n ) {\r\n startPosition = start - windowSize - offsetStart;\r\n } else if (\r\n (startElement === \"bottom\" && startViewport === \"top\") ||\r\n (startElement === \"right\" && startViewport === \"left\")\r\n ) {\r\n startPosition = start + size - offsetStart;\r\n } else if (\r\n (startElement === \"bottom\" && startViewport === \"bottom\") ||\r\n (startElement === \"right\" && startViewport === \"right\")\r\n ) {\r\n startPosition = start - windowSize + size - offsetStart;\r\n }\r\n\r\n // End position calculation\r\n if (\r\n (endElement === \"top\" && endViewport === \"top\") ||\r\n (endElement === \"left\" && endViewport === \"left\")\r\n ) {\r\n endPosition = start + offsetEnd;\r\n } else if (\r\n (endElement === \"top\" && endViewport === \"bottom\") ||\r\n (endElement === \"left\" && endViewport === \"right\")\r\n ) {\r\n endPosition = start - windowSize + offsetEnd;\r\n } else if (\r\n (endElement === \"bottom\" && endViewport === \"top\") ||\r\n (endElement === \"right\" && endViewport === \"left\")\r\n ) {\r\n endPosition = start + size + offsetEnd;\r\n } else if (\r\n (endElement === \"bottom\" && endViewport === \"bottom\") ||\r\n (endElement === \"right\" && endViewport === \"right\")\r\n ) {\r\n endPosition = start - windowSize + size + offsetEnd;\r\n }\r\n\r\n object.setProperty<number>(\r\n \"start-position\",\r\n startPosition - this.data.scroll.topPosition\r\n );\r\n object.setProperty<number>(\"end-position\", endPosition);\r\n object.setProperty<number>(\r\n \"difference-position\",\r\n endPosition - startPosition\r\n );\r\n }\r\n}\r\n","import { StringContext } from \"../../core/StringContext\";\r\nimport { StringData } from \"../../core/StringData\";\r\nimport { StringObject } from \"../../objects/StringObject\";\r\nimport { StringProgress } from \"./StringProgress\";\r\n\r\nexport class StringParallax extends StringProgress {\r\n constructor(context: StringContext) {\r\n super(context);\r\n this.htmlKey = \"parallax\";\r\n\r\n this.attributesToMap = [\r\n ...this.attributesToMap,\r\n { key: \"parallax\", type: \"number\", fallback: this.settings[\"parallax\"] },\r\n {\r\n key: \"parallax-bias\",\r\n type: \"number\",\r\n fallback: this.settings[\"parallax-bias\"],\r\n },\r\n ];\r\n }\r\n\r\n /**\r\n * Called when an object is initialized.\r\n */\r\n override initializeObject(\r\n globalId: number,\r\n object: StringObject,\r\n element: HTMLElement,\r\n attributes: Record<string, any>\r\n ): void {\r\n super.initializeObject(globalId, object, element, attributes);\r\n const bias = object.getProperty<number>(\"parallax-bias\") ?? 0.0;\r\n const factor = object.getProperty<number>(\"parallax\") ?? 0.2;\r\n\r\n object.setProperty(\"parallax-position-start\", -0.5 + 0.5 * bias);\r\n object.setProperty(\"parallax-position-end\", 0.5 + 0.5 * (1 - bias));\r\n\r\n const screenSize = this.data.viewport.windowHeight;\r\n\r\n object.setProperty(\"offset-top\", factor * screenSize);\r\n object.setProperty(\"offset-bottom\", factor * screenSize);\r\n }\r\n\r\n /**\r\n * Called on scroll.\r\n */\r\n override onScroll(data: StringData): void {\r\n super.onScroll(data);\r\n this.scrollHandler();\r\n }\r\n\r\n /**\r\n * Called on resize.\r\n */\r\n override onResize(): void {\r\n const isDesktop = window.innerWidth > 1080;\r\n this.scrollHandler = isDesktop\r\n ? this.handleScrollDesktop\r\n : this.handleScrollMobile;\r\n\r\n if (!isDesktop) {\r\n this.handleScrollDesktop();\r\n }\r\n }\r\n\r\n private handleScrollDesktop = (): void => {\r\n this.objects.forEach((object) => {\r\n const progress = object.getProperty<number>(\"progress\") ?? 0;\r\n const factor = object.getProperty<number>(\"parallax\") ?? 0;\r\n const start = object.getProperty<number>(\"parallax-position-start\") ?? 0;\r\n const end = object.getProperty<number>(\"parallax-position-end\") ?? 1;\r\n\r\n const screenSize = this.data.viewport.windowHeight;\r\n const translation =\r\n factor * screenSize * start + progress * factor * screenSize * end;\r\n\r\n this.events.emit(`parallax:${object.id}`, translation);\r\n const transform = `translate3d(0, ${translation}px, 0)`;\r\n this.applyToElementAndConnects(object, (el) => {\r\n el.style.transform = transform;\r\n });\r\n });\r\n };\r\n\r\n private handleScrollMobile = (): void => {};\r\n\r\n private scrollHandler = this.handleScrollDesktop;\r\n}\r\n","import { StringData } from \"../../core/StringData\";\r\n\r\nexport class StringScrollbarHorizontal {\r\n private scrollbar: any;\r\n private thumb: any;\r\n private isDragging = false;\r\n private startY: number = 0;\r\n private startScrollPosition: number = 0;\r\n data: StringData;\r\n\r\n constructor(data: StringData, scrollbar: any, thumb: any) {\r\n this.data = data;\r\n this.scrollbar = scrollbar;\r\n this.thumb = thumb;\r\n }\r\n\r\n onResize(): void {\r\n const contentWidth = this.data.viewport.contentWidth;\r\n const visibleWidth = this.data.viewport.windowWidth;\r\n\r\n const thumbSize = (visibleWidth / contentWidth) * visibleWidth;\r\n this.thumb.style.setProperty('--size', thumbSize + 'px');\r\n\r\n if (contentWidth <= visibleWidth) {\r\n this.scrollbar.classList.add('-hide');\r\n } else {\r\n this.scrollbar.classList.remove('-hide');\r\n }\r\n }\r\n\r\n updateThumb() {\r\n const contentWidth = this.data.viewport.contentWidth;\r\n const visibleWidth = this.data.viewport.windowWidth;\r\n this.thumb.style.setProperty('--position', `${(this.data.scroll.current / contentWidth) * visibleWidth + 'px'}`);\r\n }\r\n\r\n mouseDownEvent(e: MouseEvent) {\r\n this.startY = e.clientY;\r\n this.startScrollPosition = this.data.scroll.current;\r\n }\r\n\r\n mouseMoveEvent(e: MouseEvent) {\r\n const deltaY = e.clientY - this.startY;\r\n const newScrollPosition = this.startScrollPosition + (deltaY / this.data.viewport.windowWidth) * this.data.viewport.contentWidth;\r\n this.data.scroll.current = newScrollPosition;\r\n this.data.scroll.target = newScrollPosition;\r\n window.scrollTo(0, newScrollPosition);\r\n this.updateThumb();\r\n }\r\n}\r\n","import { StringData } from \"../../core/StringData\";\r\n\r\nexport class StringScrollbarVertical {\r\n private scrollbar: any;\r\n private thumb: any;\r\n private isDragging = false;\r\n private startCoordinate: number = 0;\r\n private startScrollPosition: number = 0;\r\n data: StringData;\r\n\r\n constructor(data: StringData, scrollbar: any, thumb: any) {\r\n this.data = data;\r\n this.scrollbar = scrollbar;\r\n this.thumb = thumb;\r\n }\r\n\r\n onResize(): void {\r\n const contentSize = this.data.viewport.contentHeight;\r\n const visibleSize = this.data.viewport.windowHeight;\r\n const thumbSize = (visibleSize / contentSize) * visibleSize;\r\n this.thumb.style.setProperty('--height', thumbSize + 'px');\r\n if (contentSize <= visibleSize) {\r\n this.scrollbar.classList.add('-hide');\r\n } else {\r\n this.scrollbar.classList.remove('-hide');\r\n }\r\n }\r\n\r\n updateThumb() {\r\n const contentHeight = this.data.viewport.contentHeight;\r\n const visibleHeight = this.data.viewport.windowHeight;\r\n \r\n this.thumb.style.setProperty('--position', `${(this.data.scroll.current / contentHeight) * visibleHeight + 'px'}`);\r\n }\r\n\r\n mouseDownEvent(e: MouseEvent) {\r\n this.startCoordinate = e.clientY;\r\n this.startScrollPosition = this.data.scroll.current;\r\n }\r\n\r\n mouseMoveEvent(e: MouseEvent) {\r\n const deltaY = e.clientY - this.startCoordinate;\r\n const newScrollPosition = this.startScrollPosition + (deltaY / this.data.viewport.windowHeight) * this.data.viewport.contentHeight;\r\n const maxScroll = this.data.scroll.bottomPosition;\r\n const clamped = Math.max(0, Math.min(newScrollPosition, maxScroll));\r\n this.data.scroll.current = clamped;\r\n this.data.scroll.target = clamped;\r\n window.scrollTo(0, clamped);\r\n this.updateThumb();\r\n }\r\n}\r\n","import { StringContext } from '../../core/StringContext';\r\nimport { StringData } from '../../core/StringData';\r\nimport { StringModule } from '../../core/StringModule';\r\nimport { StringScrollbarHorizontal } from './StringScrollbarHorizontal';\r\nimport { StringScrollbarVertical } from './StringScrollbarVertical';\r\n\r\nexport class StringScrollbar extends StringModule {\r\n private scrollbar: any;\r\n private thumb: any;\r\n private scrollTimeout: any;\r\n\r\n private isDragging = false;\r\n private scrollMode: 'smooth' | 'disable' | 'default' = 'smooth';\r\n\r\n private mouseUpEventBind: any;\r\n private mouseDownEventBind: any;\r\n private mouseMoveEventBind: any;\r\n\r\n private scrollbarState: any;\r\n private scrollbarStateHorizontal: any;\r\n private scrollbarStateVertical: any;\r\n\r\n constructor(context: StringContext) {\r\n super(context)\r\n\r\n this.mouseUpEventBind = this.mouseUpEvent.bind(this);\r\n this.mouseDownEventBind = this.mouseDownEvent.bind(this);\r\n this.mouseMoveEventBind = this.mouseMoveEvent.bind(this);\r\n }\r\n destructor(): void {\r\n document.removeEventListener('mouseup', this.mouseUpEventBind);\r\n this.thumb.removeEventListener('mousedown', this.mouseDownEventBind);\r\n document.removeEventListener('mousemove', this.mouseMoveEventBind);\r\n }\r\n\r\n onInit(): void {\r\n this.createScrollbar();\r\n this.updateThumb();\r\n this.addCustomStyles();\r\n document.addEventListener('mouseup', this.mouseUpEventBind);\r\n this.thumb.addEventListener('mousedown', this.mouseDownEventBind);\r\n document.addEventListener('mousemove', this.mouseMoveEventBind);\r\n document.documentElement.classList.add(`-no-scrollbar`);\r\n }\r\n\r\n onScroll(data: StringData): void {\r\n this.updateThumb();\r\n this.showScrollbar();\r\n this.hideScrollbar();\r\n }\r\n\r\n onResize(): void {\r\n this.scrollbarState.onResize();\r\n }\r\n\r\n private addCustomStyles() {\r\n const style = document.createElement('style');\r\n style.textContent = `\r\n ::-webkit-scrollbar {\r\n display: none;\r\n width: 0;\r\n height: 0;\r\n -webkit-appearance: none;\r\n }\r\n body {\r\n -ms-overflow-style: none; /* IE and Edge */\r\n scrollbar-width: none; /* Firefox */\r\n }\r\n .-without-scrollbar::-webkit-scrollbar {\r\n display: none;\r\n }\r\n .-without-scrollbar {\r\n -ms-overflow-style: none; /* IE and Edge */\r\n scrollbar-width: none; /* Firefox */\r\n }\r\n `;\r\n document.head.appendChild(style);\r\n }\r\n\r\n private createScrollbar() {\r\n this.scrollbar = document.createElement('div');\r\n this.scrollbar.classList.add('scrollbar');\r\n this.thumb = document.createElement('div');\r\n this.thumb.classList.add('thumb');\r\n this.scrollbar.appendChild(this.thumb);\r\n document.body.appendChild(this.scrollbar);\r\n\r\n this.scrollbarStateHorizontal = new StringScrollbarHorizontal(this.data, this.scrollbar, this.thumb);\r\n this.scrollbarStateVertical = new StringScrollbarVertical(this.data, this.scrollbar, this.thumb);\r\n this.scrollbarState = this.scrollbarStateVertical;\r\n }\r\n\r\n private updateThumb() {\r\n this.scrollbarState.updateThumb();\r\n }\r\n\r\n private mouseDownEvent(e: MouseEvent) {\r\n this.isDragging = true;\r\n this.scrollbarState.mouseDownEvent(e);\r\n document.body.style.userSelect = 'none';\r\n this.scrollbar.classList.add('-touch');\r\n }\r\n\r\n private mouseMoveEvent(e: MouseEvent) {\r\n if (!this.isDragging) return;\r\n\r\n this.scrollbarState.mouseMoveEvent(e);\r\n }\r\n\r\n private mouseUpEvent() {\r\n this.isDragging = false;\r\n document.body.style.userSelect = '';\r\n this.hideScrollbar();\r\n this.scrollbar.classList.remove('-touch');\r\n }\r\n\r\n private showScrollbar() {\r\n this.scrollbar.classList.add('-scroll');\r\n }\r\n\r\n private hideScrollbar() {\r\n if (this.scrollTimeout) {\r\n clearTimeout(this.scrollTimeout);\r\n }\r\n this.scrollTimeout = setTimeout(() => {\r\n this.scrollbar.classList.remove('-scroll');\r\n }, 1000);\r\n }\r\n}\r\n","// Assuming core framework classes are available\r\nimport { StringContext } from \"../../core/StringContext\";\r\nimport { StringModule } from \"../../core/StringModule\";\r\nimport { ISplitOptions } from \"../../models/text/ISplitOptions\";\r\nimport { LayoutLine } from \"../../models/text/LayoutLine\";\r\nimport { ProcessedChar } from \"../../models/text/ProcessedChar\";\r\nimport { ProcessedWord } from \"../../models/text/ProcessedWord\";\r\nimport { StringObject } from \"../../objects/StringObject\";\r\n\r\n/**\r\n * StringModule responsible for splitting text within HTML elements\r\n * into lines, words, and characters based on layout and attributes,\r\n * and applying CSS variables for animation purposes.\r\n * Uses a tool-based approach for modularity.\r\n */\r\nexport class StringSplit extends StringModule {\r\n /**\r\n * Initializes the StringSplit module and its tools.\r\n * @param context - The global StringContext.\r\n */\r\n constructor(context: StringContext) {\r\n super(context);\r\n this.htmlKey = 'split';\r\n }\r\n\r\n /**\r\n * Called when the module initializes.\r\n * Processes elements already present in the DOM on load.\r\n */\r\n onInit(): void {\r\n // Find all elements matching the htmlKey that might need processing\r\n document.querySelectorAll(`[string=\"${this.htmlKey}\"]`).forEach(element => {\r\n if (element instanceof HTMLElement) {\r\n this.processElement(element);\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Called when the window is resized.\r\n * Re-processes already split elements as their layout might have changed.\r\n */\r\n onResize(): void {\r\n // Find only elements that have been previously split\r\n document.querySelectorAll(`[string=\"${this.htmlKey}\"].-splited`).forEach((element) => {\r\n if (element instanceof HTMLElement) {\r\n this.processElement(element);\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Called when a new StringObject associated with this module connects.\r\n * Processes the newly connected element.\r\n * @param object - The StringObject representing the connected element.\r\n */\r\n onObjectConnected(object: StringObject): void {\r\n // Process the specific element that just connected\r\n this.processElement(object.htmlElement);\r\n }\r\n\r\n /**\r\n * Central method to process splitting for a given HTML element.\r\n * Orchestrates the use of various tools: parsing options, calculating layout,\r\n * indexing words and characters, building the final HTML, and updating the DOM.\r\n * Includes error handling.\r\n * @param element - The HTMLElement to process.\r\n */\r\n private processElement(element: HTMLElement): void {\r\n if (!element) return; // Exit if element is invalid\r\n\r\n const isAlreadySplit = element.classList.contains('-splited');\r\n let originalHtml = element.getAttribute('string-split-original');\r\n\r\n // Store the original HTML content on the first run\r\n if (!isAlreadySplit || originalHtml === null) {\r\n originalHtml = element.innerHTML;\r\n element.setAttribute('string-split-original', originalHtml);\r\n element.classList.add('-splited'); // Mark element as processed\r\n }\r\n\r\n // If there's no original content to split, clear the element and exit\r\n if (!originalHtml || originalHtml.trim() === '') {\r\n if (element.innerHTML !== '') element.innerHTML = ''; // Clear if not already empty\r\n return;\r\n }\r\n\r\n try {\r\n // === Step 1: Parse Options ===\r\n const attributeValue = element.getAttribute('string-split');\r\n // Note: Assuming SplitOptionsParserTool exists and has the necessary 'process' method\r\n const options: ISplitOptions = this.tools.optionsParser.process({ attributeValue });\r\n\r\n // === Step 2: Calculate Total Non-Whitespace Characters ===\r\n // Use originalHtml for consistency with layout tool, decode entities first\r\n // Assumes originalHtml is primarily text for splitting.\r\n // More robust handling might be needed if originalHtml contains complex markup.\r\n const textForCharCount = this.tools.layoutSplitter['decodeHtmlEntity'](originalHtml); // Access private method if needed, or make it public/utility\r\n const totalChars = textForCharCount.replace(/\\s+/g, '').length;\r\n\r\n // === Step 3: Calculate Layout (Lines and Words) ===\r\n const layoutLines: LayoutLine[] = this.tools.layoutSplitter.process({ text: originalHtml, targetElement: element });\r\n\r\n // Handle cases where layout calculation yields no lines (e.g., element is display:none)\r\n // Avoid unnecessary processing or clearing content if the original wasn't empty.\r\n if (layoutLines.length === 0 && originalHtml.trim() !== '') {\r\n console.warn(\"StringSplit: Layout calculation resulted in no lines for element:\", element);\r\n // Decide recovery strategy: maybe revert to originalHtml or leave empty?\r\n // For now, we just stop processing further to avoid errors.\r\n // If the element becomes visible later, onResize should trigger reprocessing.\r\n return;\r\n }\r\n\r\n // === Step 4: Index Words ===\r\n const processedWords: ProcessedWord[] = this.tools.wordIndexer.process({\r\n lines: layoutLines,\r\n options: { word: options.word, wordLine: options.wordLine },\r\n // totalWords: layoutLines.reduce((sum, line) => sum + line.words.length, 0) // Pass if needed\r\n });\r\n\r\n // === Step 5: Index Characters ===\r\n const processedChars: ProcessedChar[] = this.tools.charIndexer.process({\r\n processedWords: processedWords,\r\n lines: layoutLines, // Pass lines again for calculating total chars per line\r\n options: { char: options.char, charLine: options.charLine, charWord: options.charWord },\r\n totalChars: totalChars\r\n });\r\n\r\n // === Step 6: Build Final DOM Structure ===\r\n const newHtml: string = this.tools.domBuilder.process({\r\n lines: layoutLines,\r\n words: processedWords,\r\n chars: processedChars,\r\n options: options // Pass options to DOM builder for checks like needsCharSpans\r\n });\r\n\r\n // === Step 7: Update Element's innerHTML (if changed) ===\r\n // Direct comparison can be slow for very large strings. Consider alternatives if performance becomes an issue.\r\n if (element.innerHTML !== newHtml) {\r\n element.innerHTML = newHtml;\r\n }\r\n\r\n } catch (error) {\r\n // Log the error and the element where it occurred\r\n console.error(\"StringSplit: Error processing element:\", element, error);\r\n // Revert to original HTML as a fallback strategy\r\n if (originalHtml !== null) { // Check if we have the original content stored\r\n try {\r\n if(element.innerHTML !== originalHtml) {\r\n element.innerHTML = originalHtml;\r\n }\r\n } catch (revertError) {\r\n console.error(\"StringSplit: Error reverting element to original HTML:\", element, revertError);\r\n // If reverting fails, at least clear it to avoid broken state\r\n element.innerHTML = '';\r\n }\r\n } else {\r\n // If no original HTML was stored, just clear it\r\n element.innerHTML = '';\r\n }\r\n // Remove the split marker class as processing failed\r\n element.classList.remove('-splited');\r\n // Optional: Add an error class? element.classList.add('-split-error');\r\n }\r\n }\r\n\r\n // No other private methods needed here, logic is in the tools.\r\n}","import { StringContext } from \"../../core/StringContext\"\r\nimport { StringData } from \"../../core/StringData\"\r\nimport { StringModule } from \"../../core/StringModule\"\r\n\r\n/**\r\n * Visual tracker that plots scroll displacement (velocity) in real time.\r\n * Useful for debugging and tuning smoothing behavior.\r\n */\r\nexport class StringDelayLerpTracker extends StringModule {\r\n private canvas!: HTMLCanvasElement\r\n private context!: CanvasRenderingContext2D\r\n private history: number[] = []\r\n\r\n private maxPoints = 0\r\n private height = 0\r\n private value = 0\r\n private target = 0\r\n\r\n constructor(context: StringContext) {\r\n super(context)\r\n this._type = 2\r\n }\r\n\r\n /**\r\n * Called when the module starts — sets up canvas.\r\n */\r\n onInit(): void {\r\n this.initCanvas()\r\n this.maxPoints = this.canvas.width\r\n }\r\n\r\n /**\r\n * Called on scroll — stores current displacement and redraws.\r\n */\r\n onScroll(data: StringData): void {\r\n const d = Math.abs(data.scroll.displacement)\r\n this.value = d\r\n this.history.push(d)\r\n\r\n if (this.history.length > this.maxPoints) {\r\n this.history.shift()\r\n }\r\n\r\n this.draw()\r\n }\r\n\r\n /**\r\n * Draws the displacement graph to canvas.\r\n */\r\n private draw(): void {\r\n const ctx = this.context\r\n const w = this.canvas.width\r\n const h = this.canvas.height\r\n\r\n ctx.clearRect(0, 0, w, h)\r\n\r\n ctx.strokeStyle = \"red\"\r\n ctx.lineWidth = 2\r\n ctx.beginPath()\r\n\r\n this.history.forEach((val, i) => {\r\n const x = i\r\n const y = h - val * this.height\r\n i === 0 ? ctx.moveTo(x, y) : ctx.lineTo(x, y)\r\n })\r\n\r\n ctx.stroke()\r\n }\r\n\r\n /**\r\n * Creates and styles the tracking canvas.\r\n */\r\n private initCanvas(): void {\r\n const canvas = document.createElement(\"canvas\")\r\n const width = window.innerWidth * 0.5\r\n this.height = window.innerHeight / 15 - 20\r\n\r\n canvas.width = width\r\n canvas.height = this.height\r\n\r\n Object.assign(canvas.style, {\r\n position: \"fixed\",\r\n bottom: `${window.innerHeight / 20 + 10}px`,\r\n left: \"50%\",\r\n transform: \"translateX(-50%)\",\r\n backgroundColor: \"#000000\",\r\n border: \"1px solid rgba(255, 255, 255, 0.2)\",\r\n zIndex: \"1000\",\r\n pointerEvents: \"none\",\r\n })\r\n\r\n this.canvas = canvas\r\n this.context = canvas.getContext(\"2d\")!\r\n document.body.appendChild(canvas)\r\n }\r\n\r\n /**\r\n * Optional method to update external comparison target.\r\n */\r\n public setTarget(position: number): void {\r\n this.target = position\r\n }\r\n\r\n /**\r\n * Removes the canvas from DOM and resets.\r\n */\r\n public clear(): void {\r\n this.canvas.remove()\r\n this.history = []\r\n }\r\n}\r\n","import { StringData } from \"../..\"\r\nimport { StringContext } from \"../../core/StringContext\"\r\nimport { StringModule } from \"../../core/StringModule\"\r\n\r\n/**\r\n * FPS Tracker Module.\r\n * Displays how many times `onFrame()` is called per second.\r\n * Useful for debugging rendering performance or vsync issues.\r\n */\r\nexport class StringFPSTracker extends StringModule {\r\n private displayElement!: HTMLDivElement\r\n private intervalId!: number\r\n private frameCount = 0\r\n\r\n constructor(context: StringContext) {\r\n super(context)\r\n this._type = 2\r\n }\r\n\r\n /**\r\n * Initializes the visual FPS counter and update interval.\r\n */\r\n onInit(): void {\r\n this.createDisplayElement()\r\n\r\n this.intervalId = window.setInterval(() => {\r\n this.displayElement.textContent = `FPS: ${this.frameCount}`\r\n this.frameCount = 0\r\n }, 1000)\r\n }\r\n\r\n /**\r\n * Increments the frame counter each frame.\r\n */\r\n onFrame(_data: StringData): void {\r\n this.frameCount++\r\n }\r\n\r\n /**\r\n * Cleans up DOM and interval.\r\n */\r\n destroy(): void {\r\n clearInterval(this.intervalId)\r\n this.displayElement.remove()\r\n }\r\n\r\n /**\r\n * Creates and styles the floating FPS display.\r\n */\r\n private createDisplayElement(): void {\r\n const el = document.createElement(\"div\")\r\n\r\n Object.assign(el.style, {\r\n position: \"fixed\",\r\n bottom: \"10px\",\r\n right: \"10px\",\r\n backgroundColor: \"#000\",\r\n color: \"#fff\",\r\n padding: \"4px 8px\",\r\n fontSize: \"12px\",\r\n fontFamily: \"monospace\",\r\n border: \"1px solid rgba(255,255,255,0.2)\",\r\n zIndex: \"1000\",\r\n pointerEvents: \"none\",\r\n })\r\n\r\n el.textContent = \"FPS: 0\"\r\n document.body.appendChild(el)\r\n\r\n this.displayElement = el\r\n }\r\n}\r\n","import { StringData } from \"../..\"\r\nimport { StringContext } from \"../../core/StringContext\"\r\nimport { StringModule } from \"../../core/StringModule\"\r\n\r\n/**\r\n * Visual tracker that plots lerped scroll velocity (v) in real time.\r\n * Useful for analyzing smooth scroll interpolation behavior.\r\n */\r\nexport class StringLerpTracker extends StringModule {\r\n private canvas!: HTMLCanvasElement\r\n private context!: CanvasRenderingContext2D\r\n private history: number[] = []\r\n\r\n private maxPoints = 0\r\n private canvasHeight = 0\r\n private currentValue = 0\r\n private targetValue = 0\r\n\r\n constructor(context: StringContext) {\r\n super(context)\r\n this._type = 2\r\n }\r\n\r\n /**\r\n * Called on start — sets up canvas overlay.\r\n */\r\n onInit(): void {\r\n this.initCanvas()\r\n this.maxPoints = this.canvas.width\r\n }\r\n\r\n /**\r\n * Called on scroll — reads smoothed scroll velocity (v).\r\n */\r\n onScroll(data: StringData): void {\r\n const v = Math.abs(data.scroll.displacement)\r\n this.currentValue = v\r\n this.history.push(v)\r\n\r\n if (this.history.length > this.maxPoints) {\r\n this.history.shift()\r\n }\r\n\r\n this.draw()\r\n }\r\n\r\n /**\r\n * Draws the current graph line based on v-history.\r\n */\r\n private draw(): void {\r\n const ctx = this.context\r\n const w = this.canvas.width\r\n const h = this.canvas.height\r\n\r\n ctx.clearRect(0, 0, w, h)\r\n\r\n ctx.strokeStyle = \"#007bff\"\r\n ctx.lineWidth = 2\r\n ctx.beginPath()\r\n\r\n this.history.forEach((val, i) => {\r\n const x = i\r\n const y = h - val / 2\r\n i === 0 ? ctx.moveTo(x, y) : ctx.lineTo(x, y)\r\n })\r\n\r\n ctx.stroke()\r\n }\r\n\r\n /**\r\n * Creates the canvas overlay and applies style.\r\n */\r\n private initCanvas(): void {\r\n this.canvas = document.createElement(\"canvas\")\r\n this.canvasHeight = window.innerHeight / 15 - 20\r\n this.canvas.width = window.innerWidth * 0.5\r\n this.canvas.height = this.canvasHeight\r\n\r\n Object.assign(this.canvas.style, {\r\n position: \"fixed\",\r\n bottom: \"10px\",\r\n left: \"50%\",\r\n transform: \"translateX(-50%)\",\r\n backgroundColor: \"#000\",\r\n border: \"1px solid rgba(255,255,255,0.2)\",\r\n zIndex: \"1000\",\r\n pointerEvents: \"none\",\r\n })\r\n\r\n this.context = this.canvas.getContext(\"2d\")!\r\n document.body.appendChild(this.canvas)\r\n }\r\n\r\n /**\r\n * Optional external target value for debugging.\r\n */\r\n public setTarget(position: number): void {\r\n this.targetValue = position\r\n }\r\n\r\n /**\r\n * Removes canvas from DOM and clears history.\r\n */\r\n public clear(): void {\r\n this.canvas.remove()\r\n this.history = []\r\n }\r\n}\r\n","import { StringData } from \"../..\"\r\nimport { StringContext } from \"../../core/StringContext\"\r\nimport { StringModule } from \"../../core/StringModule\"\r\n\r\n/**\r\n * Tracker module that shows current scroll position and direction.\r\n * Displays a fixed label in the corner of the screen for debugging.\r\n */\r\nexport class StringPositionTracker extends StringModule {\r\n private displayElement!: HTMLDivElement\r\n\r\n constructor(context: StringContext) {\r\n super(context)\r\n this._type = 2\r\n }\r\n\r\n /**\r\n * Called on start — creates the DOM element for position display.\r\n */\r\n onInit(): void {\r\n this.createDisplayElement()\r\n }\r\n\r\n /**\r\n * Called on scroll — updates scroll position and direction symbol.\r\n */\r\n onScroll(data: StringData): void {\r\n const current = data.scroll.current\r\n const target = data.scroll.target\r\n\r\n const direction = current < target ? \"↓\" : current > target ? \"↑\" : \"-\"\r\n\r\n this.displayElement.setAttribute(\"data-dir\", direction)\r\n this.displayElement.setAttribute(\"data-val\", `${Math.round(current)}`)\r\n }\r\n\r\n /**\r\n * Removes display element from DOM.\r\n */\r\n destroy(): void {\r\n this.displayElement.remove()\r\n }\r\n\r\n /**\r\n * Creates and styles the floating position indicator.\r\n */\r\n private createDisplayElement(): void {\r\n const el = document.createElement(\"div\")\r\n\r\n Object.assign(el.style, {\r\n position: \"fixed\",\r\n bottom: \"10px\",\r\n left: \"10px\",\r\n backgroundColor: \"#000\",\r\n color: \"#fff\",\r\n border: \"1px solid rgba(255,255,255,0.2)\",\r\n padding: \"5px 8px\",\r\n fontSize: \"12px\",\r\n fontFamily: \"monospace\",\r\n zIndex: \"1000\",\r\n pointerEvents: \"none\",\r\n })\r\n\r\n el.setAttribute(\"data-dir\", \"-\")\r\n el.setAttribute(\"data-val\", \"0\")\r\n document.body.appendChild(el)\r\n\r\n // Inject dynamic CSS if needed\r\n const style = document.createElement(\"style\")\r\n style.innerHTML = `\r\n div[data-dir][data-val]::before {\r\n content: attr(data-dir) ' Top: ' attr(data-val) 'px';\r\n }\r\n `\r\n document.head.appendChild(style)\r\n\r\n this.displayElement = el\r\n }\r\n}\r\n","/**\r\n * Creates a debounced version of a function that delays invoking the function\r\n * until after `delay` milliseconds have passed since the last time the\r\n * debounced function was invoked.\r\n *\r\n * @template T The type of the function to debounce.\r\n * @param func The function to debounce.\r\n * @param delay The number of milliseconds to delay.\r\n * @returns The new debounced function.\r\n */\r\nexport function Debounce<T extends (...args: any[]) => any>(func: T, delay: number): (...args: Parameters<T>) => void {\r\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\r\n\r\n // Return a new function that will be called instead of the original\r\n return function(this: ThisParameterType<T>, ...args: Parameters<T>) {\r\n // Capture the 'this' context and arguments for the original function\r\n const context = this;\r\n\r\n // If there is already a scheduled call, cancel it\r\n if (timeoutId) {\r\n clearTimeout(timeoutId);\r\n }\r\n\r\n // Schedule a new call to the original function after 'delay' ms\r\n timeoutId = setTimeout(() => {\r\n func.apply(context, args); // Call the original function with the correct 'this' and arguments\r\n timeoutId = null; // Clear the timer ID after execution (optional but good practice)\r\n }, delay);\r\n };\r\n}","/**\r\n * Utility class that provides a customizable requestAnimationFrame loop.\r\n * Allows running a callback function on every frame or at a specific FPS rate.\r\n * Automatically pauses on `document.hidden` and resumes on visibility change.\r\n */\r\nexport class StringFPS {\r\n /** Target frames per second (FPS). */\r\n private fps: number = 0;\r\n\r\n /** Whether the animation loop is currently active. */\r\n private isAnimationStarted: boolean = false;\r\n\r\n /** Time interval between frames in milliseconds, based on FPS. */\r\n private fpsInterval: number = 0;\r\n\r\n /** Timestamp of the previous frame (used for timing calculations). */\r\n private then: number = 0;\r\n\r\n /** The requestAnimationFrame ID (used to cancel the loop). */\r\n private requestAnimationId: number = 0;\r\n\r\n /** Bound function for visibilitychange event handler. */\r\n private onVisibilityChangeBind: any;\r\n\r\n /** Callback executed on each frame. */\r\n private onFrameCallback: (time: number) => void = (time: number) => {};\r\n\r\n /** Internal animation loop function. */\r\n private animate: () => void = () => {};\r\n\r\n constructor() {\r\n this.onVisibilityChangeBind = this.onVisibilityChange.bind(this);\r\n }\r\n\r\n /**\r\n * Handles visibility change events.\r\n * Stops the loop when the document is hidden and resumes it when visible.\r\n */\r\n private onVisibilityChange() {\r\n if (document.hidden) {\r\n this.stop();\r\n this.isAnimationStarted = false;\r\n } else {\r\n this.start(this.fps);\r\n }\r\n }\r\n\r\n /**\r\n * Starts the animation loop at a given FPS rate.\r\n * If `fps` is 0, runs the callback as fast as possible (uncapped).\r\n * \r\n * @param fps Target frames per second (0 = uncapped).\r\n */\r\n public start(fps: number) {\r\n this.fps = fps;\r\n if (this.isAnimationStarted) return;\r\n\r\n this.fpsInterval = 1000 / fps;\r\n this.then = performance.now();\r\n this.isAnimationStarted = true;\r\n\r\n if (fps === 0) {\r\n this.animate = () => {\r\n const now = performance.now();\r\n this.requestAnimationId = requestAnimationFrame(() => this.animate());\r\n this.onFrameCallback(now);\r\n };\r\n } else {\r\n this.animate = () => {\r\n const now = performance.now();\r\n const elapsed = now - this.then;\r\n if (elapsed > this.fpsInterval) {\r\n this.then = now - (elapsed % this.fpsInterval);\r\n this.onFrameCallback(now);\r\n }\r\n this.requestAnimationId = requestAnimationFrame(() => this.animate());\r\n };\r\n }\r\n\r\n this.animate();\r\n // document.addEventListener(\"visibilitychange\", this.onVisibilityChangeBind);\r\n }\r\n\r\n /**\r\n * Stops the animation loop and removes the animation frame.\r\n */\r\n public stop() {\r\n if (!this.isAnimationStarted) return;\r\n cancelAnimationFrame(this.requestAnimationId);\r\n this.requestAnimationId = 0;\r\n this.isAnimationStarted = false;\r\n }\r\n\r\n /**\r\n * Assigns a callback function to be called on each frame.\r\n * \r\n * @param callback The function to execute per frame.\r\n */\r\n public setOnFrame(callback: (time: number) => void) {\r\n this.onFrameCallback = callback;\r\n }\r\n\r\n /**\r\n * Stops the loop and removes event listeners.\r\n * Should be called when the loop is no longer needed.\r\n */\r\n public destructor() {\r\n this.stop();\r\n // document.removeEventListener(\"visibilitychange\", this.onVisibilityChangeBind);\r\n }\r\n}\r\n","import { StringObject } from \"../../objects/StringObject\";\r\nimport { StringModule } from \"../../core/StringModule\";\r\nimport { StringContext } from \"../../core/StringContext\";\r\n\r\nexport class StringVideoAutoplay extends StringModule {\r\n constructor(context: StringContext) {\r\n super(context);\r\n this.htmlKey = \"autoplay\";\r\n\r\n this.attributesToMap = [\r\n ...this.attributesToMap,\r\n {\r\n key: \"src\",\r\n type: \"string\",\r\n fallback: \"\",\r\n },\r\n ];\r\n }\r\n\r\n onObjectConnected(object: StringObject) {\r\n object.setProperty(\"onEnterEvent\", this.onEnterObject.bind(this));\r\n object.events.on(\r\n \"enter\",\r\n object.getProperty<(object: StringObject) => void>(\"onEnterEvent\")\r\n );\r\n object.setProperty(\"onLeaveEvent\", this.onLeaveObject.bind(this));\r\n object.events.on(\r\n \"leave\",\r\n object.getProperty<(object: StringObject) => void>(\"onLeaveEvent\")\r\n );\r\n\r\n const videoElement = object.htmlElement as HTMLVideoElement;\r\n const started =\r\n this.tools.domAttribute.process({\r\n element: videoElement,\r\n key: \"string-started\",\r\n fallback: null,\r\n }) !== null;\r\n\r\n if (videoElement.tagName.toLowerCase() === \"video\" && !started) {\r\n videoElement.setAttribute(\"string-started\", \"\");\r\n videoElement.muted = true;\r\n videoElement.setAttribute(\"muted\", \"muted\");\r\n videoElement.setAttribute(\"playsinline\", \"\");\r\n videoElement.setAttribute(\"loop\", \"\");\r\n videoElement.setAttribute(\"autoplay\", \"\");\r\n videoElement.src = object.getProperty(\"src\");\r\n videoElement.load();\r\n videoElement.addEventListener(\"canplay\", () => {});\r\n }\r\n }\r\n\r\n private onEnterObject(object: StringObject) {\r\n const videoElement = object.htmlElement as HTMLVideoElement;\r\n this.tryPlay(videoElement);\r\n }\r\n private onLeaveObject(object: StringObject) {\r\n const videoElement = object.htmlElement as HTMLVideoElement;\r\n videoElement.pause();\r\n }\r\n\r\n private tryPlay(element: HTMLVideoElement) {\r\n element\r\n .play()\r\n .catch((err) =>\r\n console.warn(\"[StringVideoAutoplay] Autoplay failed:\", err)\r\n );\r\n }\r\n}\r\n"],"mappings":"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","names":["index_exports","__export","StringAnchor","StringCursor","StringData","StringDelayLerpTracker","StringFPSTracker","StringGlide","StringLazy","StringLerp","StringLerpTracker","StringLoading","StringMagnetic","StringModule","StringObject","StringParallax","StringPositionTracker","StringProgress","StringResponsive","StringScrollbar","StringSplit","StringTune","StringVideoAutoplay","__toCommonJS","CursorController","smoothing","context","e","targetX","targetY","smoothedX","smoothedY","stepX","stepY","distance","lerp","x","y","EventManager","eventName","callback","id","fullEvent","payload","set","value","visible","ModuleManager","data","module","type","m","e","added","removed","StringObject","id","element","EventManager","key","value","module","ObjectManager","data","modules","events","el","idAttr","object","StringObject","keysAttr","attributes","m","q","item","id","obj","element","attr","start","end","inviewTop","inviewBottom","progressCallback","entries","e","inviewCallback","progressObserver","inviewObserver","mutations","mutation","node","child","copyFrom","ScrollController","context","scrollDirection","e","StringScrollDefault","ScrollController","context","delta","scrollTop","plusDelta","StringScrollDisable","ScrollController","context","CLASS_NAMES","StringScrollSmooth","ScrollController","context","newDirection","absVelocity","scrollDirection","atTop","atBottom","ScrollManager","context","StringScrollSmooth","StringScrollDefault","StringScrollDisable","mode","newMode","engine","e","events","CursorState","RenderState","ScrollState","TimeState","ViewportState","StringData","ScrollState","ViewportState","CursorState","RenderState","TimeState","StringModule","context","element","object","boundingRect","top","height","globalId","attributes","key","type","fallback","transform","resolvedFallback","raw","parsed","windowSize","value","id","index","applyFn","data","event","added","removed","BoundingClientRectTool","element","DOMAttributeTool","element","key","fallback","RecordAttributeTool","record","name","fallback","TransformNullifyTool","element","rect","values","a","b","c","d","e","f","det","RelativePositionTool","transformTool","TransformNullifyTool","element","container","containerRect","elRect","LerpTool","from","to","progress","UnitParserTool","value","element","viewportHeight","baseRem","isNegative","result","AdaptiveLerpTool","value","inMin","inMax","outMin","outMax","t","OriginParserTool","value","raw","options","s","index","ColorParserTool","value","str","hex","ch","r","g","b","a","rgbMatch","v","hslMatch","h","l","s","hue2rgb","p","q","t","ValidationTool","value","rules","messages","rule","code","raw","message","EasingFunctionTool","easing","def","match","x1","y1","x2","y2","t","cx","bx","ax","cy","by","ay","sampleCurveX","sampleCurveY","sampleCurveDerivativeX","solveCurveX","x","epsilon","t0","t1","t2","d2","i","MagneticPullTool","distance","radius","strength","proximity","LerpColorTool","from","to","progress","LerpVector2Tool","from","to","progress","TransformScaleParserTool","value","str","matrixValues","matrixNumbers","scaleValue","scaleNumbers","scaleXValue","scaleNumber","scale3dValue","matrix3dValues","error","CharIndexerTool","processedWords","lines","options","totalChars","processedChars","globalCharIndex","totalLineCharsMap","line","lineIndex","totalCharsInLine","sum","word","currentLineCharIndex","previousLineIndex","pWord","wordText","parentLineIndex","wordLength","totalCharsInCurrentLine","char","wordCharIndex","calculatedValues","optDef","value","option","primaryIndex","localIndex","parentLength","index","min","max","effectiveMin","effectiveMax","LayoutLineSplitterTool","text","targetElement","words","word","tempSpan","compStyles","layoutLines","currentLineWords","currentLineWidth","spaceWidth","containerWidth","wordWidth","potentialWidth","w","str","SplitDomBuilderTool","lines","words","chars","options","rootElement","wordCounter","charCounter","needsLineSpans","needsCharSpans","line","lineSpanContainer","wordsInThisLine","pWord","indexInLine","wordSpan","charsInThisWord","pChar","charSpan","span","calculatedValues","calcValue","variableName","type","align","WordIndexerTool","lines","options","processedWords","globalWordIndex","totalWords","sum","line","lineIndex","wordsInLine","lineWordCount","word","wordIndexInLine","calculatedValues","optDef","value","option","primaryIndex","localIndex","parentLength","index","min","max","effectiveMin","effectiveMax","SplitOptionsParserTool","attributeValue","options","part","trimmedPart","match","prefix","optionType","fullOptionKey","params","p","parsedParam","result","param","randomMatch","DefaultToolsContainer","DOMAttributeTool","RecordAttributeTool","TransformNullifyTool","BoundingClientRectTool","RelativePositionTool","UnitParserTool","LerpTool","AdaptiveLerpTool","OriginParserTool","ColorParserTool","ValidationTool","EasingFunctionTool","MagneticPullTool","LerpColorTool","LerpVector2Tool","TransformScaleParserTool","LayoutLineSplitterTool","WordIndexerTool","CharIndexerTool","SplitDomBuilderTool","SplitOptionsParserTool","StringCursor","StringModule","context","value","globalId","object","element","attributes","data","isOver","isDisabled","lerpFactor","rect","cursorX","cursorY","elementX","elementY","px","py","dx","dy","lerpedX","lerpedY","updatedX","updatedY","alignment","offsetX","offsetY","mouseX","mouseY","halfWidth","halfHeight","targetX","targetY","newMouseX","newMouseY","stepX","stepY","smoothedX","smoothedY","cursorClass","x","y","el","mousePos","size","StringMagnetic","StringModule","context","globalId","object","element","attributes","e","rect","centerX","centerY","dx","dy","distance","radius","strength","factor","data","magneticX","magneticY","lerp","targetMagneticX","targetMagneticY","lerpX","lerpY","el","StringLazy","StringModule","context","img","object","src","el","url","resolve","reject","xhr","blob","StringLoading","StringModule","context","StringInview","StringModule","visitor","object","StringResponsiveQueryDevice","config","enable","min","max","query","StringResponsive","StringModule","context","isMobileMedia","isTabletMedia","isLaptopMedia","isDesktopMedia","element","showElement","StringAnchor","StringModule","context","tuple","xRaw","yRaw","x","y","object","anchor","el","ACCELERATION_STEP","MIN_DISPLACEMENT","MAX_DISPLACEMENT","MIN_VELOCITY","MAX_VELOCITY","StringGlide","StringModule","context","object","glide","glideValue","transformCompute","i","isDirectionUp","isConditionMet","data","el","StringLerp","StringModule","context","object","data","velocity","value","StringProgress","StringModule","context","globalId","object","element","attributes","data","startPosition","differencePosition","key","progress","progressStr","el","windowSize","start","size","offsetStart","offsetEnd","startElement","startViewport","endElement","endViewport","endPosition","StringParallax","StringProgress","context","object","progress","factor","start","end","screenSize","translation","transform","el","globalId","element","attributes","bias","data","isDesktop","StringScrollbarHorizontal","data","scrollbar","thumb","contentWidth","visibleWidth","thumbSize","e","deltaY","newScrollPosition","StringScrollbarVertical","data","scrollbar","thumb","contentSize","visibleSize","thumbSize","contentHeight","visibleHeight","e","deltaY","newScrollPosition","maxScroll","clamped","StringScrollbar","StringModule","context","data","style","StringScrollbarHorizontal","StringScrollbarVertical","StringSplit","StringModule","context","element","object","isAlreadySplit","originalHtml","attributeValue","options","totalChars","layoutLines","processedWords","processedChars","newHtml","error","revertError","StringDelayLerpTracker","StringModule","context","data","d","ctx","w","h","val","i","x","y","canvas","width","position","StringFPSTracker","StringModule","context","_data","el","StringLerpTracker","StringModule","context","data","v","ctx","w","h","val","i","x","y","position","StringPositionTracker","StringModule","context","data","current","target","direction","el","style","Debounce","func","delay","timeoutId","args","context","StringFPS","time","fps","now","elapsed","callback","StringVideoAutoplay","StringModule","context","object","videoElement","started","element","err","StringTune","_StringTune","StringFPS","Debounce","DefaultToolsContainer","StringData","EventManager","ModuleManager","ObjectManager","CursorController","ScrollManager","time","value","container","speed","mode","type","objectClass","settings","effectiveSettings","module","eventName","callback","id","fps","observerContainerMutation","mutationsList","observer","mutation","config","StringInview","htmlFontSize","fontSizeNumber","element","connectTargetId","e","scroll","width","height","newScrollHeight","newContainerTopPosition","rect","transformScale","isDesktop","widthChanged","heightChanged","scrollHeightChanged","shouldRebuild"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/core/controllers/CursorController.ts","../src/core/managers/EventManager.ts","../src/core/managers/ModuleManager.ts","../src/objects/StringObject.ts","../src/core/managers/ObjectManager.ts","../src/core/controllers/ScrollController.ts","../src/core/controllers/StringScrollDefault.ts","../src/core/controllers/StringScrollDisable.ts","../src/core/controllers/StringScrollSmooth.ts","../src/core/managers/ScrollManager.ts","../src/states/CursorState.ts","../src/states/RenderState.ts","../src/states/ScrollState.ts","../src/states/TimeState.ts","../src/states/ViewportState.ts","../src/core/StringData.ts","../src/core/StringModule.ts","../src/tools/BoundingClientRectTool.ts","../src/tools/DOMAttributeTool.ts","../src/tools/RecordAttributeTool.ts","../src/tools/TransformNullifyTool.ts","../src/tools/RelativePositionTool.ts","../src/tools/LerpTool.ts","../src/tools/UnitParserTool.ts","../src/tools/AdaptiveLerpTool.ts","../src/tools/OriginParserTool.ts","../src/tools/ColorParserTool.ts","../src/tools/ValidationTool.ts","../src/tools/EasingFunctionTool.ts","../src/tools/MagneticPullTool.ts","../src/tools/LerpColorTool.ts","../src/tools/LerpVector2Tool.ts","../src/tools/TransformScaleParserTool.ts","../src/tools/CharIndexerTool.ts","../src/tools/LayoutLineSplitterTool.ts","../src/tools/SplitDomBuilderTool.ts","../src/tools/WordIndexerTool.ts","../src/tools/SplitOptionsParserTool.ts","../src/core/StringToolsContainer.ts","../src/modules/cursor/StringCursor.ts","../src/modules/cursor/StringMagnetic.ts","../src/modules/loading/StringLazy.ts","../src/modules/loading/StringLoading.ts","../src/modules/screen/StringInview.ts","../src/modules/screen/StringResponsive.ts","../src/modules/scroll/StringAnchor.ts","../src/modules/scroll/StringGlide.ts","../src/modules/scroll/StringLerp.ts","../src/modules/scroll/StringProgress.ts","../src/modules/scroll/StringParallax.ts","../src/modules/scrollbar/StringScrollbarHorizontal.ts","../src/modules/scrollbar/StringScrollbarVertical.ts","../src/modules/scrollbar/StringScrollbar.ts","../src/modules/text/StringSplit.ts","../src/modules/tracker/StringDelayLerpTracker.ts","../src/modules/tracker/StringFPSTracker.ts","../src/modules/tracker/StringLerpTracker.ts","../src/modules/tracker/StringPositionTracker.ts","../src/utils/Debounce.ts","../src/utils/StringFPS.ts","../src/modules/loading/StringVideoAutoplay.ts"],"sourcesContent":["import { CursorController } from \"./core/controllers/CursorController\";\r\nimport { IStringModule } from \"./core/IStringModule\";\r\nimport { EventManager } from \"./core/managers/EventManager\";\r\nimport { ModuleManager } from \"./core/managers/ModuleManager\";\r\nimport { ObjectManager } from \"./core/managers/ObjectManager\";\r\nimport { ScrollManager } from \"./core/managers/ScrollManager\";\r\nimport { StringContext } from \"./core/StringContext\";\r\nimport { StringData } from \"./core/StringData\";\r\nimport { StringModule } from \"./core/StringModule\";\r\nimport { DefaultToolsContainer } from \"./core/StringToolsContainer\";\r\nimport { StringCursor } from \"./modules/cursor/StringCursor\";\r\nimport { StringMagnetic } from \"./modules/cursor/StringMagnetic\";\r\nimport { StringLazy } from \"./modules/loading/StringLazy\";\r\nimport { StringLoading } from \"./modules/loading/StringLoading\";\r\nimport { StringInview } from \"./modules/screen/StringInview\";\r\nimport { StringResponsive } from \"./modules/screen/StringResponsive\";\r\nimport { StringAnchor } from \"./modules/scroll/StringAnchor\";\r\nimport { StringGlide } from \"./modules/scroll/StringGlide\";\r\nimport { StringLerp } from \"./modules/scroll/StringLerp\";\r\nimport { StringParallax } from \"./modules/scroll/StringParallax\";\r\nimport { StringProgress } from \"./modules/scroll/StringProgress\";\r\nimport { StringScrollbar } from \"./modules/scrollbar/StringScrollbar\";\r\nimport { StringSplit } from \"./modules/text/StringSplit\";\r\nimport { StringDelayLerpTracker } from \"./modules/tracker/StringDelayLerpTracker\";\r\nimport { StringFPSTracker } from \"./modules/tracker/StringFPSTracker\";\r\nimport { StringLerpTracker } from \"./modules/tracker/StringLerpTracker\";\r\nimport { StringPositionTracker } from \"./modules/tracker/StringPositionTracker\";\r\nimport { StringObject } from \"./objects/StringObject\";\r\nimport { ScrollMode } from \"./states/ScrollState\";\r\nimport { Debounce } from \"./utils/Debounce\";\r\nimport { EventCallback } from \"./models/event/EventCallback\";\r\nimport { StringFPS } from \"./utils/StringFPS\";\r\nimport { StringSettings } from \"./utils/StringSettings\";\r\nimport { StringVideoAutoplay } from \"./modules/loading/StringVideoAutoplay\";\r\n\r\nfunction isTouchDevice() {\r\n return \"ontouchstart\" in window || navigator.maxTouchPoints > 0;\r\n}\r\nfunction isSafari(): boolean {\r\n let ua = navigator.userAgent.toLowerCase();\r\n if (ua.indexOf(\"safari\") != -1) {\r\n if (ua.indexOf(\"chrome\") > -1) {\r\n return false;\r\n } else {\r\n return true;\r\n }\r\n } else {\r\n return false;\r\n }\r\n}\r\n\r\nclass StringTune {\r\n /** Bound handler for the scroll start event */\r\n private onScrollStartBind: any;\r\n\r\n /** Bound handler for the scroll stop event */\r\n private onScrollStopBind: any;\r\n\r\n /** Bound handler for the scroll direction change event */\r\n private onDirectionChangeBind: any;\r\n\r\n /** Bound wheel event handler */\r\n private onWheelBind: any;\r\n\r\n /** Bound scroll event handler */\r\n private onScrollBind: any;\r\n\r\n /** Bound resize event handler */\r\n private onResizeBind: any;\r\n\r\n /** Bound mouse move handler */\r\n private onMouseMoveBind: any;\r\n\r\n /** Singleton instance of StringTune */\r\n private static i: StringTune;\r\n\r\n /** Root scrollable element (typically <body>) */\r\n private root: any;\r\n\r\n /** Window object (used for event bindings and dimensions) */\r\n private window: any;\r\n\r\n /** Previous window width for resize diff check */\r\n private prevWidth: number = 0;\r\n\r\n /** Previous window height for resize diff check */\r\n private prevHeight: number = 0;\r\n\r\n /** Manages all modules registered in the system */\r\n private moduleManager: ModuleManager;\r\n\r\n /** Manages scroll modes and active scroll engine */\r\n private scrollManager: ScrollManager;\r\n\r\n /** Manages all interactive objects (elements with `string-*` attributes) */\r\n private objectManager: ObjectManager;\r\n\r\n /** Central event manager for internal pub-sub logic */\r\n private eventManager: EventManager;\r\n\r\n /** Handles custom cursor logic (if enabled) */\r\n private cursorController: CursorController;\r\n\r\n /** Provides default utility tools (parsers, interpolation, etc.) */\r\n private tools: DefaultToolsContainer;\r\n\r\n /** Main loop used for frame updates (with fixed FPS) */\r\n private loop: StringFPS = new StringFPS();\r\n\r\n /** Global reactive data store (scroll, viewport, etc.) */\r\n private data: StringData;\r\n\r\n /** Context shared across all modules (events, data, tools, settings) */\r\n private context: StringContext;\r\n\r\n /**\r\n * Sets the scroll position manually.\r\n * This overrides all internal scroll states including target and lerped values.\r\n * Useful for programmatic jumps or syncing scroll externally.\r\n *\r\n * @param value The new scroll position in pixels.\r\n */\r\n public set scrollPosition(value: number) {\r\n this.data.scroll.current = value;\r\n this.data.scroll.target = value;\r\n this.data.scroll.delta = 0;\r\n this.data.scroll.lerped = 0;\r\n this.scrollManager.updatePosition();\r\n }\r\n\r\n /**\r\n * Configures the container element(s) used for scroll tracking.\r\n * Accepts either the `Window` object or an `HTMLElement`.\r\n * Determines the appropriate internal element references based on the input type\r\n * and triggers a resize calculation.\r\n *\r\n * @param {Window | HTMLElement | any} container The target window or HTML element to associate with scrolling.\r\n * Handles `Window`, `HTMLElement`, and potentially other types via fallback.\r\n */\r\n public set scrollContainer(container: any) {\r\n if (container instanceof Window) {\r\n this.data.scroll.container = document.body;\r\n this.data.scroll.elementContainer = document.documentElement;\r\n this.data.scroll.scrollContainer = container;\r\n } else if (container instanceof HTMLElement) {\r\n this.data.scroll.container = container;\r\n this.data.scroll.elementContainer = container;\r\n this.data.scroll.scrollContainer = container;\r\n } else {\r\n // Fallback case\r\n this.data.scroll.container = document.body;\r\n this.data.scroll.elementContainer = document.documentElement;\r\n this.data.scroll.scrollContainer = container; // Assigns the original (potentially non-standard) container\r\n }\r\n this.debouncedResize();\r\n }\r\n\r\n /**\r\n * Gets the current scroll position in pixels.\r\n * This is typically updated every frame.\r\n */\r\n public get speed() {\r\n return this.data.scroll.current;\r\n }\r\n\r\n /**\r\n * Sets the base scroll speed for smooth scrolling.\r\n * Typically a value between 0 and 1.\r\n */\r\n public set speed(value: number) {\r\n this.data.scroll.speed = value;\r\n }\r\n\r\n /**\r\n * Sets the scroll acceleration using a normalized value from 0 to 1.\r\n * Internally maps it to a real acceleration value between 0.1 and 0.5.\r\n *\r\n * @param speed A normalized acceleration factor (0 to 1).\r\n */\r\n public set speedAccelerate(speed: number) {\r\n const min = 0.1;\r\n const max = 0.5;\r\n this.data.scroll.speedAccelerate = min + (max - min) * speed;\r\n }\r\n\r\n /**\r\n * Sets the scroll mode for desktop devices.\r\n * Can be 'smooth', 'default', or 'disable'.\r\n */\r\n public set scrollDesktopMode(mode: ScrollMode) {\r\n this.scrollManager.setDesktopMode(mode);\r\n }\r\n\r\n /**\r\n * Sets the scroll mode for mobile devices.\r\n * Can be 'smooth', 'default', or 'disable'.\r\n */\r\n public set scrollMobileMode(mode: ScrollMode) {\r\n this.scrollManager.setMobileMode(mode);\r\n }\r\n\r\n private debouncedResize = Debounce(this.onResize, 30);\r\n\r\n private constructor() {\r\n this.root = document.body;\r\n this.window = window;\r\n\r\n this.tools = new DefaultToolsContainer();\r\n this.data = new StringData();\r\n this.eventManager = new EventManager();\r\n this.moduleManager = new ModuleManager(this.data);\r\n this.objectManager = new ObjectManager(\r\n this.data,\r\n this.moduleManager,\r\n this.eventManager\r\n );\r\n\r\n this.context = {\r\n events: this.eventManager,\r\n data: this.data,\r\n tools: this.tools,\r\n settings: {},\r\n };\r\n\r\n this.cursorController = new CursorController(1, this.context);\r\n this.scrollManager = new ScrollManager(this.context);\r\n\r\n this.setupSettings({\r\n \"offset-top\": \"0%\",\r\n \"offset-bottom\": \"0%\",\r\n key: \"--progress\",\r\n \"inview-top\": \"0%\",\r\n \"inview-bottom\": \"0%\",\r\n \"enter-el\": \"top\",\r\n \"enter-vp\": \"bottom\",\r\n \"exit-el\": \"bottom\",\r\n \"exit-vp\": \"top\",\r\n \"parallax-bias\": \"0.0\",\r\n parallax: \"0.2\",\r\n lerp: \"0.2\",\r\n radius: \"150\",\r\n strength: \"0.3\",\r\n glide: \"1\",\r\n anchor: \"center center\",\r\n timeout: 900,\r\n alignment: \"center\",\r\n \"target-disable\": \"false\",\r\n \"target-style-disable\": \"false\",\r\n \"target-class\": \"\",\r\n active: \"false\",\r\n fixed: \"false\",\r\n repeat: \"false\",\r\n \"self-disable\": \"false\",\r\n abs: \"false\",\r\n easing: \"cubic-bezier(0.25, 0.25, 0.25, 0.25)\",\r\n \"glide-base-velocity\": 0.00125,\r\n \"glide-reduce-velocity\": 0.0000625,\r\n \"glide-negative-velocity\": -0.0001,\r\n });\r\n\r\n this.onWheelBind = this.onWheelEvent.bind(this);\r\n this.onScrollBind = this.onScrollEvent.bind(this);\r\n this.onResizeBind = this.onResize.bind(this);\r\n this.onMouseMoveBind = this.onMouseMoveEvent.bind(this);\r\n\r\n this.onScrollStartBind = this.onScrollStart.bind(this);\r\n this.onScrollStopBind = this.onScrollStop.bind(this);\r\n this.onDirectionChangeBind = this.onDirectionChange.bind(this);\r\n\r\n this.scrollManager.bindEvents({\r\n onScrollStart: this.onScrollStartBind,\r\n onScrollStop: this.onScrollStopBind,\r\n onDirectionChange: this.onDirectionChangeBind,\r\n });\r\n\r\n this.loop.setOnFrame((time: number) => {\r\n this.data.time.delta = time - this.data.time.now;\r\n this.data.time.previous = this.data.time.now;\r\n this.data.time.now = time;\r\n this.data.time.elapsed += this.data.time.delta;\r\n this.onUpdateEvent();\r\n });\r\n this.on(\"image:load:all\", () => {\r\n this.onResize();\r\n });\r\n\r\n this.scrollContainer = window;\r\n }\r\n\r\n /**\r\n * Returns the singleton instance of StringTune.\r\n * If not already created, initializes it.\r\n */\r\n public static getInstance(): StringTune {\r\n if (!StringTune.i) {\r\n StringTune.i = new StringTune();\r\n }\r\n return StringTune.i;\r\n }\r\n\r\n /**\r\n * Finds and returns an existing module by its class.\r\n * Useful for reusing a module instance without re-registering.\r\n *\r\n * @template T The type of the module to retrieve.\r\n * @param type The module class constructor.\r\n * @returns The module instance if found, otherwise undefined.\r\n */\r\n public reuse<T>(type: new (...args: any[]) => T): T | undefined {\r\n return this.moduleManager.find(type);\r\n }\r\n\r\n /**\r\n * Instantiates and registers a new module.\r\n * Accepts optional per-instance settings that override global settings.\r\n *\r\n * @param objectClass The module class to instantiate.\r\n * @param settings Optional settings specific to this module.\r\n */\r\n public use(objectClass: typeof StringModule, settings: any = null) {\r\n const effectiveSettings = {\r\n ...this.context.settings,\r\n ...settings,\r\n };\r\n const module = new objectClass({\r\n events: this.eventManager,\r\n data: this.data,\r\n tools: this.tools,\r\n settings: effectiveSettings,\r\n });\r\n this.moduleManager.register(module);\r\n }\r\n\r\n /**\r\n * Subscribes to a global event within the system.\r\n *\r\n * @param eventName The name of the event to listen for.\r\n * @param callback The function to call when the event is triggered.\r\n * @param id Optional subscription ID (for easier management).\r\n */\r\n public on(eventName: string, callback: EventCallback<any>, id: string = \"\") {\r\n this.eventManager.on(eventName, callback, id);\r\n }\r\n\r\n /**\r\n * Unsubscribes from a global event.\r\n *\r\n * @param eventName The name of the event.\r\n * @param callback The previously registered callback.\r\n * @param id Optional ID used during subscription.\r\n */\r\n public off(eventName: string, callback: EventCallback<any>, id: string = \"\") {\r\n this.eventManager.off(eventName, callback, id);\r\n }\r\n\r\n /**\r\n * Starts the scroll engine and initializes all listeners, observers, and modules.\r\n *\r\n * @param fps Desired frames per second for the update loop.\r\n */\r\n public start(fps: number) {\r\n // window.addEventListener('scroll', this.onScrollBind);\r\n // this.root.addEventListener('wheel', this.onWheelBind, { passive: false });\r\n\r\n this.data.scroll.scrollContainer?.addEventListener(\r\n \"scroll\",\r\n this.onScrollBind\r\n );\r\n this.data.scroll.container?.addEventListener(\"wheel\", this.onWheelBind, {\r\n passive: false,\r\n });\r\n\r\n window.addEventListener(\"resize\", this.onResizeBind);\r\n this.root.addEventListener(\"mousemove\", this.onMouseMoveBind);\r\n\r\n const observerContainerResize = new ResizeObserver(() => {\r\n this.debouncedResize();\r\n });\r\n observerContainerResize.observe(this.context.data.scroll.container);\r\n\r\n const observerContainerMutation = new MutationObserver(\r\n (mutationsList: MutationRecord[], observer: MutationObserver) => {\r\n for (const mutation of mutationsList) {\r\n if (\r\n mutation.type === \"attributes\" &&\r\n (mutation.attributeName === \"style\" ||\r\n mutation.attributeName === \"class\")\r\n ) {\r\n this.onResize();\r\n }\r\n }\r\n }\r\n );\r\n const config: MutationObserverInit = {\r\n attributes: true,\r\n attributeFilter: [\"style\", \"class\"],\r\n };\r\n observerContainerMutation.observe(\r\n this.context.data.scroll.container,\r\n config\r\n );\r\n\r\n this.use(StringInview);\r\n\r\n const htmlFontSize = window.getComputedStyle(\r\n document.documentElement\r\n ).fontSize;\r\n const fontSizeNumber = parseFloat(htmlFontSize);\r\n this.context.data.viewport.baseRem = fontSizeNumber;\r\n\r\n document.documentElement.classList.add(\"-string\");\r\n this.moduleManager.onInit();\r\n this.onResize();\r\n this.initObjects();\r\n this.objectManager.observeDOM();\r\n\r\n this.loop.start(fps);\r\n this.eventManager.emit(`start`, null);\r\n }\r\n\r\n /**\r\n * Initializes all DOM elements with `string` or `string-copy-from` attributes.\r\n * Registers them with the object manager and triggers resize/scroll/frame hooks.\r\n */\r\n private initObjects() {\r\n document.querySelectorAll(\"[string],[data-string]\").forEach((element) => {\r\n this.objectManager.add(element as HTMLElement);\r\n });\r\n document\r\n .querySelectorAll(\"[string-copy-from],[data-string-copy-from]\")\r\n .forEach((element) => {\r\n let connectTargetId = this.tools.domAttribute.process({\r\n element: element as HTMLElement,\r\n key: \"copy-from\",\r\n fallback: \"\",\r\n });\r\n if (connectTargetId && connectTargetId.length > 0) {\r\n this.objectManager.enqueueConnection(\r\n connectTargetId,\r\n element as HTMLElement\r\n );\r\n }\r\n });\r\n this.moduleManager.onResize();\r\n this.moduleManager.onScroll();\r\n this.moduleManager.onFrame();\r\n }\r\n\r\n /**\r\n * Sets global fallback settings for all modules.\r\n * These can be overridden by module-specific settings during `use(...)`.\r\n *\r\n * @param settings A key-value map of default settings (e.g. 'offset-top': '-10%').\r\n */\r\n public setupSettings(settings: StringSettings): void {\r\n this.context.settings = {\r\n ...this.context.settings,\r\n ...settings,\r\n };\r\n this.onSettingsChange();\r\n }\r\n\r\n /**\r\n * Handles mouse move event and dispatches it to cursor and modules.\r\n * @param e Native mouse move event.\r\n */\r\n private onMouseMoveEvent(e: MouseEvent) {\r\n this.cursorController.onMouseMove(e);\r\n this.moduleManager.onMouseMove(e);\r\n }\r\n\r\n /**\r\n * Handles wheel scroll event and passes it to the scroll engine and modules.\r\n * @param e Native wheel event.\r\n */\r\n private onWheelEvent(e: WheelEvent) {\r\n this.scrollManager.get().onWheel(e);\r\n this.moduleManager.onWheel(e);\r\n }\r\n\r\n /**\r\n * Called when scrolling begins.\r\n * Triggers module scroll start lifecycle hook.\r\n */\r\n private onScrollStart() {\r\n this.moduleManager.onScrollStart();\r\n }\r\n\r\n /**\r\n * Called when scrolling ends.\r\n * Triggers module scroll stop lifecycle hook.\r\n */\r\n private onScrollStop() {\r\n this.moduleManager.onScrollStop();\r\n }\r\n\r\n /**\r\n * Called when scrolling ends.\r\n * Triggers module scroll stop lifecycle hook.\r\n */\r\n private onDirectionChange() {\r\n this.moduleManager.onDirectionChange();\r\n }\r\n\r\n /**\r\n * Called when global or module settings are updated.\r\n * Notifies all managers and modules to re-read new settings.\r\n */\r\n private onSettingsChange() {\r\n this.cursorController.onSettingsChange();\r\n this.objectManager.onSettingsChange();\r\n this.moduleManager.onSettingsChange();\r\n }\r\n\r\n /**\r\n * Handles native scroll event.\r\n * Prevents default behavior and triggers internal scroll logic and event emissions.\r\n *\r\n * @param e The native scroll event.\r\n */\r\n private onScrollEvent(e: Event) {\r\n e.preventDefault();\r\n this.scrollManager.get().onScroll(e);\r\n this.moduleManager.onScroll();\r\n this.eventManager.emit(`lerp`, this.data.scroll.lerped);\r\n this.eventManager.emit(`scroll`, this.data.scroll.current);\r\n return false;\r\n }\r\n\r\n /**\r\n * Called every frame by the update loop.\r\n * Triggers scroll engine, modules, and global `update` event.\r\n */\r\n private onUpdateEvent() {\r\n this.cursorController.onFrame();\r\n this.scrollManager.get().onFrame();\r\n this.moduleManager.onFrame();\r\n this.eventManager.emit(`update`, null);\r\n }\r\n\r\n /**\r\n * Handles resize events from scroll container or window.\r\n * Ignores height-only changes on mobile to prevent layout jumps.\r\n * Rebuilds layout and triggers module resize if size really changed.\r\n */\r\n public onResize(): void {\r\n const container = this.data.scroll.container;\r\n const scroll = this.context.data.scroll;\r\n let width = 0;\r\n let height = 0;\r\n var newScrollHeight;\r\n var newContainerTopPosition = 0;\r\n const rect = container.getBoundingClientRect();\r\n\r\n if (container.tagName == \"BODY\") {\r\n width = window.innerWidth;\r\n height = window.innerHeight;\r\n } else {\r\n width = rect.width;\r\n height = rect.height;\r\n }\r\n\r\n newContainerTopPosition = rect.top;\r\n newScrollHeight = scroll.container.scrollHeight;\r\n const transformScale = this.tools.transformScaleParser.process({\r\n value: window.getComputedStyle(container).transform,\r\n });\r\n this.context.data.viewport.transformScale = transformScale;\r\n\r\n const isDesktop = width > 1080;\r\n\r\n const widthChanged = this.prevWidth !== width;\r\n const heightChanged = this.prevHeight !== height;\r\n const scrollHeightChanged =\r\n this.context.data.viewport.contentHeight !== newScrollHeight;\r\n\r\n const shouldRebuild =\r\n widthChanged || (isDesktop && heightChanged) || scrollHeightChanged;\r\n\r\n this.context.data.scroll.topPosition = newContainerTopPosition;\r\n this.context.data.viewport.contentWidth = width;\r\n this.context.data.viewport.contentHeight = newScrollHeight;\r\n\r\n this.prevWidth = width;\r\n this.prevHeight = height;\r\n\r\n this.context.data.viewport.windowWidth = width;\r\n this.context.data.viewport.windowHeight = height;\r\n\r\n const htmlFontSize = window.getComputedStyle(\r\n document.documentElement\r\n ).fontSize;\r\n const fontSizeNumber = parseFloat(htmlFontSize);\r\n this.context.data.viewport.baseRem = fontSizeNumber * transformScale;\r\n\r\n scroll.bottomPosition = this.context.data.viewport.contentHeight - height;\r\n\r\n if (shouldRebuild) {\r\n if (this.context.data.scroll.container.scrollTop > 0) {\r\n this.context.data.scroll.current =\r\n this.context.data.scroll.container.scrollTop;\r\n this.context.data.scroll.target =\r\n this.context.data.scroll.container.scrollTop;\r\n this.context.data.scroll.transformedCurrent =\r\n this.context.data.scroll.current *\r\n this.context.data.viewport.transformScale;\r\n }\r\n\r\n this.scrollManager.updateResponsiveMode();\r\n this.moduleManager.onResize();\r\n this.onSettingsChange();\r\n this.moduleManager.onScroll();\r\n this.moduleManager.onFrame();\r\n }\r\n }\r\n\r\n /**\r\n * Cleans up the system, removes all event listeners, stops the loop,\r\n * and destroys modules and event subscriptions.\r\n */\r\n public destroy() {\r\n this.data.scroll.scrollContainer?.removeEventListener(\r\n \"scroll\",\r\n this.onScrollBind\r\n );\r\n this.data.scroll.container?.removeEventListener(\"wheel\", this.onScrollBind);\r\n\r\n this.window.removeEventListener(\"resize\", this.onResizeBind);\r\n this.root.removeEventListener(\"mousemove\", this.onMouseMoveBind);\r\n this.loop.stop();\r\n this.moduleManager.destroy();\r\n this.eventManager.clearAll();\r\n }\r\n}\r\n\r\nexport {\r\n StringTune as default,\r\n StringCursor,\r\n StringDelayLerpTracker,\r\n StringFPSTracker,\r\n StringGlide,\r\n StringLazy,\r\n StringLerp,\r\n StringLerpTracker,\r\n StringLoading,\r\n StringMagnetic,\r\n StringParallax,\r\n StringPositionTracker,\r\n StringProgress,\r\n StringResponsive,\r\n StringScrollbar,\r\n StringSplit,\r\n StringAnchor,\r\n StringTune as StringTune,\r\n StringVideoAutoplay,\r\n StringModule,\r\n StringObject,\r\n StringData,\r\n type StringContext,\r\n};\r\n","import { CursorState } from \"../../states/CursorState\"\r\nimport { EventManager } from \"../managers/EventManager\"\r\nimport { StringContext } from \"../StringContext\"\r\nimport { StringData } from \"../StringData\"\r\nimport { StringToolsContainer } from \"../StringToolsContainer\"\r\n\r\n/**\r\n * Manages virtual cursor logic: smoothing, updating, and syncing with mouse events.\r\n * \r\n * This controller handles cursor position tracking with smoothing (lerp) logic.\r\n * Useful for animated cursor effects and interaction modules.\r\n */\r\nexport class CursorController {\r\n /** Context providing access to shared data, tools, and settings. */\r\n protected context: StringContext\r\n\r\n /** Threshold below which cursor is considered settled (no movement). */\r\n private readonly SETTLE_THRESHOLD = 0.1\r\n\r\n /** Smoothing factor used to interpolate cursor movement. */\r\n private smoothingFactor: number\r\n\r\n /**\r\n * Constructs a new `CursorController` instance.\r\n * @param smoothing The initial lerp smoothing factor (0 to 1).\r\n * @param context The shared context containing state and tools.\r\n */\r\n constructor(smoothing: number = 0.1, context: StringContext) {\r\n this.smoothingFactor = smoothing\r\n this.context = context\r\n this.onSettingsChange()\r\n }\r\n\r\n /**\r\n * Updates the target cursor position from a mouse event.\r\n * This is the raw position that smoothing will interpolate toward.\r\n * @param e MouseEvent with current cursor position.\r\n */\r\n public onMouseMove(e: MouseEvent): void {\r\n this.context.data.cursor.targetX = e.clientX\r\n this.context.data.cursor.targetY = e.clientY\r\n }\r\n\r\n /**\r\n * Updates smoothed cursor position using linear interpolation (lerp).\r\n * Should be called on every animation frame.\r\n * Handles snapping when movement is below threshold.\r\n */\r\n public onFrame(): void {\r\n const { targetX, targetY, smoothedX, smoothedY } = this.context.data.cursor\r\n\r\n const stepX = this.context.tools.lerp.process({ from: smoothedX, to: targetX, progress: this.smoothingFactor })\r\n const stepY = this.context.tools.lerp.process({ from: smoothedY, to: targetY, progress: this.smoothingFactor })\r\n\r\n const distance = this.getStepDistance(stepX, stepY)\r\n\r\n if (this.isSettled(distance)) {\r\n this.snapToTarget()\r\n } else {\r\n this.applyStep(stepX, stepY)\r\n }\r\n }\r\n\r\n /**\r\n * Called when global settings change.\r\n * Updates the internal lerp factor from context settings.\r\n */\r\n public onSettingsChange(): void {\r\n let lerp = Number(this.context.settings['lerp'])\r\n this.setLerpFactor(lerp)\r\n }\r\n\r\n /**\r\n * Dynamically adjusts the smoothing factor using adaptive mapping.\r\n * @param t The raw input lerp value (usually from 0 to 1).\r\n */\r\n public setLerpFactor(t: number): void {\r\n this.smoothingFactor = this.context.tools.adaptiveLerp.process({ \r\n value: t,\r\n inMin: 0.1,\r\n inMax: 1.0,\r\n outMin: 0.05,\r\n outMax: 0.65\r\n })\r\n }\r\n\r\n /**\r\n * Calculates the Euclidean distance from the cursor step.\r\n * @param x Step in X direction.\r\n * @param y Step in Y direction.\r\n * @returns The length of the movement vector.\r\n */\r\n private getStepDistance(x: number, y: number): number {\r\n return Math.hypot(x, y)\r\n }\r\n\r\n /**\r\n * Determines whether the movement is below the settle threshold.\r\n * @param distance Distance between smoothed and target positions.\r\n * @returns Whether the cursor should snap to target.\r\n */\r\n private isSettled(distance: number): boolean {\r\n return distance < this.SETTLE_THRESHOLD\r\n }\r\n\r\n /**\r\n * Immediately sets smoothed position to the target and zeroes deltas.\r\n */\r\n private snapToTarget(): void {\r\n this.context.data.cursor.smoothedX = this.context.data.cursor.targetX\r\n this.context.data.cursor.smoothedY = this.context.data.cursor.targetY\r\n this.context.data.cursor.stepX = 0\r\n this.context.data.cursor.stepY = 0\r\n }\r\n\r\n /**\r\n * Applies lerped movement step to smoothed position and stores delta.\r\n * @param x Step in X direction.\r\n * @param y Step in Y direction.\r\n */\r\n private applyStep(x: number, y: number): void {\r\n this.context.data.cursor.smoothedX += x\r\n this.context.data.cursor.smoothedY += y\r\n this.context.data.cursor.stepX = x\r\n this.context.data.cursor.stepY = y\r\n }\r\n}\r\n","import { EventCallback } from \"../../models/event/EventCallback\";\r\n\r\n/**\r\n * Manages custom event subscriptions and dispatching.\r\n * Allows multiple listeners per event and supports optional `id` suffixing.\r\n */\r\nexport class EventManager {\r\n private listeners: Record<string, Set<EventCallback<any>>> = {};\r\n\r\n /**\r\n * Subscribes to an event.\r\n * Optionally appends an `id` to the event name for namespacing.\r\n *\r\n * @param eventName The base event name (e.g. \"scroll\", \"update\").\r\n * @param callback The function to call when the event is emitted.\r\n * @param id Optional unique identifier to scope the event (e.g. element ID).\r\n */\r\n on<T = any>(\r\n eventName: string,\r\n callback: EventCallback<T>,\r\n id?: string\r\n ): void {\r\n const fullEvent = id ? `${eventName}_${id}` : eventName;\r\n\r\n if (!this.listeners[fullEvent]) {\r\n this.listeners[fullEvent] = new Set();\r\n }\r\n this.listeners[fullEvent].add(callback);\r\n }\r\n\r\n /**\r\n * Unsubscribes from a specific event listener.\r\n * Must match the original `eventName`, `callback`, and optional `id`.\r\n *\r\n * @param eventName The base event name to unsubscribe from.\r\n * @param callback The callback function to remove.\r\n * @param id Optional identifier used when subscribing.\r\n */\r\n off<T = any>(\r\n eventName: string,\r\n callback: EventCallback<T>,\r\n id?: string\r\n ): void {\r\n const fullEvent = id ? `${eventName}_${id}` : eventName;\r\n\r\n if (this.listeners[fullEvent]) {\r\n this.listeners[fullEvent].delete(callback);\r\n }\r\n }\r\n\r\n /**\r\n * Emits an event with an optional payload.\r\n * All matching listeners will be called.\r\n *\r\n * @param eventName The full event name (must include `id` if used).\r\n * @param payload Optional data passed to event listeners.\r\n */\r\n emit<T = any>(eventName: string, payload?: T): void {\r\n const set = this.listeners[eventName];\r\n if (!set) return;\r\n\r\n for (const callback of set) {\r\n callback(payload as T);\r\n }\r\n }\r\n\r\n /**\r\n * Subscribes to a per-object progress event.\r\n * @param id The object ID.\r\n * @param callback The callback to handle progress value.\r\n */\r\n onProgress(id: string, callback: EventCallback<number>): void {\r\n this.on(`progress:${id}`, callback);\r\n }\r\n\r\n /**\r\n * Emits a per-object progress event.\r\n * @param id The object ID.\r\n * @param value The progress value.\r\n */\r\n emitProgress(id: string, value: number): void {\r\n this.emit(`progress:${id}`, value);\r\n }\r\n\r\n /**\r\n * Subscribes to a per-object in-view event.\r\n * @param id The object ID.\r\n * @param callback The callback to handle visibility.\r\n */\r\n onInview(id: string, callback: EventCallback<boolean>): void {\r\n this.on(`object:inview:${id}`, callback);\r\n }\r\n\r\n /**\r\n * Emits a per-object in-view event.\r\n * @param id The object ID.\r\n * @param visible Whether the object is visible.\r\n */\r\n emitInview(id: string, visible: boolean): void {\r\n this.emit(`object:inview${id}`, visible);\r\n }\r\n\r\n /**\r\n * Subscribes to the global scroll event.\r\n * @param callback The callback to handle scroll value.\r\n */\r\n onScroll(callback: EventCallback<number>): void {\r\n this.on(`scroll`, callback);\r\n }\r\n\r\n /**\r\n * Emits the global scroll event.\r\n * @param value The scroll value.\r\n */\r\n emitScroll(value: number): void {\r\n this.emit(`scroll`, value);\r\n }\r\n\r\n /**\r\n * Subscribes to the global update event.\r\n * @param callback The callback to handle update.\r\n */\r\n onUpdate(callback: EventCallback<void>): void {\r\n this.on(`update`, callback);\r\n }\r\n\r\n /**\r\n * Emits the global update event.\r\n */\r\n emitUpdate(): void {\r\n this.emit(`update`);\r\n }\r\n\r\n /**\r\n * Clears all listeners for a specific event.\r\n *\r\n * @param eventName The full event name (including optional `id`).\r\n */\r\n clear(eventName: string): void {\r\n delete this.listeners[eventName];\r\n }\r\n\r\n /**\r\n * Clears all registered events.\r\n */\r\n clearAll(): void {\r\n this.listeners = {};\r\n }\r\n}\r\n","import { StringData } from \"../..\";\r\nimport { IStringModule } from \"../IStringModule\";\r\nimport { StringModule } from \"../StringModule\";\r\n\r\n/**\r\n * Central manager for registering, tracking and delegating lifecycle events \r\n * to core and UI modules in the system.\r\n * \r\n * Handles scroll, resize, animation frame updates and DOM events.\r\n */\r\nexport class ModuleManager {\r\n /** All core logic modules (e.g., scroll, in-view, parallax). */\r\n private modules: StringModule[] = [];\r\n\r\n /** All UI or visual/interaction-based modules (e.g., cursor, split text). */\r\n private uiModules: StringModule[] = [];\r\n\r\n /**\r\n * @param data Shared state container for scroll, viewport, etc.\r\n */\r\n constructor(private data: StringData) {}\r\n\r\n /**\r\n * Registers a module into the appropriate group based on its type.\r\n * @param module The module instance to register.\r\n */\r\n register(module: StringModule): void {\r\n if (module.type === 1) this.modules.push(module);\r\n if (module.type === 2) this.uiModules.push(module);\r\n }\r\n\r\n /**\r\n * Finds the first registered module of the given class/type.\r\n * @param type The module class constructor.\r\n * @returns The instance, if found.\r\n */\r\n find<T>(type: new (...args: any[]) => T): T | undefined {\r\n return this.modules.find(m => m instanceof type) as T | undefined;\r\n }\r\n\r\n /** Invokes `onInit` on all modules. */\r\n onInit(): void {\r\n [...this.modules, ...this.uiModules].forEach(m => m.onInit());\r\n }\r\n\r\n /** Invokes `onFrame` on all modules, passing shared state. */\r\n onFrame(): void {\r\n [...this.modules, ...this.uiModules].forEach(m => m.onFrame(this.data));\r\n }\r\n\r\n /** Invokes `onScroll` on all modules with current scroll state. */\r\n onScroll(): void {\r\n [...this.modules, ...this.uiModules].forEach(m => m.onScroll(this.data));\r\n }\r\n\r\n /** Invokes `onResize` on all modules. */\r\n onResize(): void {\r\n [...this.modules, ...this.uiModules].forEach(m => m.onResize());\r\n }\r\n\r\n /**\r\n * Delegates mouse movement events to modules.\r\n * @param e The mousemove event.\r\n */\r\n onMouseMove(e: MouseEvent): void {\r\n [...this.modules, ...this.uiModules].forEach(m => m.onMouseMove(e));\r\n }\r\n\r\n /**\r\n * Delegates wheel events to modules.\r\n * @param e The wheel event.\r\n */\r\n onWheel(e: WheelEvent): void {\r\n [...this.modules, ...this.uiModules].forEach(m => m.onWheel(e));\r\n }\r\n\r\n /** Notifies all modules that scroll has changed diraction. */\r\n onDirectionChange(): void {\r\n [...this.modules, ...this.uiModules].forEach(m => m.onDirectionChange());\r\n }\r\n\r\n /** Notifies all modules that scroll has started. */\r\n onScrollStart(): void {\r\n [...this.modules, ...this.uiModules].forEach(m => m.onScrollStart());\r\n }\r\n\r\n /** Notifies all modules that scroll has stopped. */\r\n onScrollStop(): void {\r\n [...this.modules, ...this.uiModules].forEach(m => m.onScrollStop());\r\n }\r\n\r\n /** Notifies all modules that scroll axis (horizontal/vertical) has changed. */\r\n onAxisChange(): void {\r\n [...this.modules, ...this.uiModules].forEach(m => m.onAxisChange());\r\n }\r\n\r\n /** Notifies all modules that device type (desktop/mobile) has changed. */\r\n onDeviceChange(): void {\r\n [...this.modules, ...this.uiModules].forEach(m => m.onDeviceChange());\r\n }\r\n\r\n /** Notifies modules of updates to scroll-related configuration. */\r\n onScrollConfigChange(): void {\r\n [...this.modules, ...this.uiModules].forEach(m => m.onScrollConfigChange());\r\n }\r\n\r\n /** Notifies modules of updated global or module-specific settings. */\r\n onSettingsChange(): void {\r\n [...this.modules, ...this.uiModules].forEach(m => m.onSettingsChange());\r\n }\r\n\r\n /**\r\n * Called when DOM is mutated — e.g. new elements added/removed.\r\n * @param added Newly added DOM nodes.\r\n * @param removed Removed DOM nodes.\r\n */\r\n onDOMMutate(added: NodeList, removed: NodeList): void {\r\n [...this.modules, ...this.uiModules].forEach(m => m.onDOMMutate(added, removed));\r\n }\r\n\r\n /** Cleans up all modules and clears internal lists. */\r\n destroy(): void {\r\n [...this.modules, ...this.uiModules].forEach(m => m.destroy());\r\n this.modules = [];\r\n this.uiModules = [];\r\n }\r\n\r\n /**\r\n * Returns all modules (core + UI) as a flat array.\r\n */\r\n get all(): IStringModule[] {\r\n return [...this.modules, ...this.uiModules];\r\n }\r\n\r\n /**\r\n * Returns only core modules (type === 1).\r\n */\r\n get core(): IStringModule[] {\r\n return this.modules;\r\n }\r\n\r\n /**\r\n * Returns only UI modules (type === 2).\r\n */\r\n get ui(): IStringModule[] {\r\n return this.uiModules;\r\n }\r\n}\r\n","import { IStringModule } from \"../core/IStringModule\";\r\nimport { EventManager } from \"../core/managers/EventManager\";\r\n\r\n/**\r\n * Internal class representing a DOM-bound interactive object.\r\n * Connected to modules and holds its own internal state.\r\n */\r\nexport class StringObject {\r\n /**\r\n * The DOM element this object wraps.\r\n */\r\n public htmlElement: HTMLElement;\r\n\r\n /**\r\n * Unique global ID assigned by the system.\r\n */\r\n public id: string = \"\";\r\n\r\n /**\r\n * Space-separated list of all attribute keys associated with this object.\r\n */\r\n public keys: string[] = [];\r\n\r\n /**\r\n * A list of elements that should be affected in sync with this one.\r\n */\r\n public connects: HTMLElement[] = [];\r\n\r\n /**\r\n * Internal key-value store of dynamic object properties (like offsets, progress, etc.).\r\n */\r\n private properties: Map<string, any> = new Map();\r\n\r\n /**\r\n * Modules currently connected to this object.\r\n */\r\n private modules: IStringModule[] = [];\r\n\r\n /**\r\n * Manages and handles events for the object.\r\n * Provides functionality to register, trigger, and manage event listeners.\r\n */\r\n events: EventManager = new EventManager();\r\n\r\n constructor(id: string, element: HTMLElement) {\r\n this.htmlElement = element;\r\n this.id = id;\r\n }\r\n\r\n /**\r\n * Stores a property value for this object.\r\n * @param key - Property name\r\n * @param value - Value to store\r\n */\r\n public setProperty<T>(key: string, value: T): void {\r\n this.properties.set(key, value);\r\n }\r\n\r\n /**\r\n * Retrieves a previously stored property value.\r\n * @param key - Property name\r\n * @returns The value or null if not set\r\n */\r\n public getProperty<T>(key: string): T {\r\n return this.properties.get(key) ?? null;\r\n }\r\n\r\n /**\r\n * Marks this object as \"active\" (usually on intersection/scroll enter).\r\n */\r\n public enter(): void {\r\n this.events.emit(\"enter\", this);\r\n this.setProperty(\"active\", true);\r\n this.modules.forEach((module) => {\r\n module.enterObject(this.id, this);\r\n });\r\n }\r\n\r\n /**\r\n * Marks this object as \"inactive\" (usually on intersection/scroll leave).\r\n */\r\n public leave(): void {\r\n this.events.emit(\"leave\", this);\r\n this.setProperty(\"active\", false);\r\n this.modules.forEach((module) => {\r\n module.exitObject(this.id);\r\n });\r\n }\r\n\r\n /**\r\n * Shows the object, applies visual class and notifies connected modules.\r\n */\r\n public show(): void {\r\n this.htmlElement.classList.add(\"-inview\");\r\n }\r\n\r\n /**\r\n * Hides the object, removes visual class (if repeat is enabled), and notifies modules.\r\n */\r\n public hide(): void {\r\n const shouldRepeat = this.getProperty<boolean>(\"repeat\");\r\n if (shouldRepeat) {\r\n this.htmlElement.classList.remove(\"-inview\");\r\n }\r\n }\r\n\r\n /**\r\n * Connects a module to this object if not already connected.\r\n * @param module - The module to connect\r\n */\r\n public connect(module: IStringModule): void {\r\n if (!this.modules.includes(module)) {\r\n this.modules.push(module);\r\n }\r\n }\r\n}\r\n","import { ModuleManager } from \"./ModuleManager\";\r\nimport { StringData } from \"../StringData\";\r\nimport { StringObject } from \"../../objects/StringObject\";\r\nimport { EventManager } from \"./EventManager\";\r\n\r\nexport class ObjectManager {\r\n private objects = new Map<string, StringObject>();\r\n private connectQueue: { id: string; element: HTMLElement }[] = [];\r\n private globalId = 1;\r\n\r\n constructor(\r\n private data: StringData,\r\n private modules: ModuleManager,\r\n private events: EventManager\r\n ) {}\r\n\r\n /**\r\n * Returns the object map (read-only).\r\n */\r\n get all(): ReadonlyMap<string, StringObject> {\r\n return this.objects;\r\n }\r\n\r\n /**\r\n * Adds a new object from an element.\r\n */\r\n public add(el: HTMLElement) {\r\n let idAttr = `string-${this.globalId++}`;\r\n let key = \"string-id\";\r\n\r\n if (el.getAttribute(\"string-id\")) {\r\n idAttr = el.getAttribute(\"string-id\")!;\r\n key = \"string-id\";\r\n }\r\n if (el.getAttribute(\"data-string-id\")) {\r\n idAttr = el.getAttribute(\"data-string-id\")!;\r\n key = \"data-string-id\";\r\n }\r\n\r\n const object =\r\n idAttr && this.objects.has(idAttr)\r\n ? this.objects.get(idAttr)!\r\n : new StringObject(idAttr, el);\r\n\r\n el.setAttribute(key, object.id);\r\n\r\n const keysAttr =\r\n el.getAttribute(\"string\") ?? el.getAttribute(\"data-string\");\r\n\r\n if (keysAttr) {\r\n object.keys = (keysAttr ?? \"\").split(\"|\");\r\n }\r\n\r\n el.setAttribute(\"string-inited\", \"\");\r\n this.objects.set(object.id, object);\r\n\r\n const attributes = this.getAllAttributes(el);\r\n\r\n // Delegate core setup (dimensions, offsets, key, start/end, etc.)\r\n this.modules.core.forEach((m) => {\r\n if (\r\n \"setupCoreProperties\" in m &&\r\n typeof m[\"setupCoreProperties\"] === \"function\"\r\n ) {\r\n (m as any).setupCoreProperties(object, el, attributes);\r\n }\r\n });\r\n\r\n // Try connecting to modules\r\n this.modules.core.forEach((m) => {\r\n if (m.canConnect(object)) {\r\n m.initializeObject(this.globalId, object, el, attributes);\r\n m.calculatePositions(object, this.data.viewport.windowHeight);\r\n m.connectObject(object);\r\n }\r\n });\r\n\r\n // Restore connect-from\r\n const queueItems = this.connectQueue.filter((q) => q.id === object.id);\r\n queueItems.forEach((item) => object.connects.push(item.element));\r\n this.connectQueue = this.connectQueue.filter((q) => q.id !== object.id);\r\n\r\n // Set up observers\r\n this.initObservers(object, el);\r\n }\r\n\r\n /**\r\n * Removes an object by its id.\r\n */\r\n public remove(id: string) {\r\n const obj = this.objects.get(id);\r\n if (!obj) return;\r\n\r\n obj.events.clearAll();\r\n obj.getProperty<IntersectionObserver>(\"observer-progress\")?.disconnect();\r\n obj.getProperty<IntersectionObserver>(\"observer-inview\")?.disconnect();\r\n\r\n obj.htmlElement.removeAttribute(\"string-inited\");\r\n obj.leave();\r\n\r\n this.objects.delete(id);\r\n }\r\n\r\n /**\r\n * Add an element that will connect later.\r\n */\r\n public enqueueConnection(id: string, element: HTMLElement) {\r\n this.connectQueue.push({ id, element });\r\n }\r\n\r\n private getAllAttributes(el: HTMLElement): Record<string, any> {\r\n const attributes: Record<string, any> = {};\r\n Array.from(el.attributes).forEach((attr) => {\r\n attributes[attr.name] = attr.value;\r\n });\r\n return attributes;\r\n }\r\n\r\n private initObservers(obj: StringObject, el: HTMLElement) {\r\n const start = obj.getProperty<number>(\"offset-top\") ?? 0;\r\n const end = obj.getProperty<number>(\"offset-bottom\") ?? 0;\r\n const inviewTop = obj.getProperty<number>(\"inview-top\") ?? 0;\r\n const inviewBottom = obj.getProperty<number>(\"inview-bottom\") ?? 0;\r\n\r\n obj.getProperty<IntersectionObserver>(\"observer-progress\")?.disconnect();\r\n obj.getProperty<IntersectionObserver>(\"observer-inview\")?.disconnect();\r\n\r\n const progressCallback = (entries: IntersectionObserverEntry[]) => {\r\n entries.forEach((e) => {\r\n this.events.emit(`object:activate:${obj.id}`, e.isIntersecting);\r\n e.isIntersecting ? obj.enter() : obj.leave();\r\n });\r\n };\r\n\r\n const inviewCallback = (entries: IntersectionObserverEntry[]) => {\r\n entries.forEach((e) => {\r\n this.events.emit(`object:inview:${obj.id}`, e.isIntersecting);\r\n e.isIntersecting ? obj.show() : obj.hide();\r\n });\r\n };\r\n\r\n const progressObserver = new IntersectionObserver(progressCallback, {\r\n root: null,\r\n rootMargin: `${end + this.data.viewport.windowHeight}px 0px ${\r\n start + this.data.viewport.windowHeight\r\n }px 0px`,\r\n threshold: 0.001,\r\n });\r\n\r\n const inviewObserver = new IntersectionObserver(inviewCallback, {\r\n root: null,\r\n rootMargin: `${\r\n end + inviewTop + obj.getProperty<number>(\"end-bias\")\r\n }px 0px ${\r\n start + inviewBottom + obj.getProperty<number>(\"start-bias\")\r\n }px 0px`,\r\n threshold: 0.001,\r\n });\r\n\r\n progressObserver.observe(el);\r\n inviewObserver.observe(el);\r\n\r\n obj.setProperty(\"observer-progress\", progressObserver);\r\n obj.setProperty(\"observer-inview\", inviewObserver);\r\n }\r\n\r\n /**\r\n * Observes DOM mutations to auto-add/remove elements with [string] attribute.\r\n * Should be called once after DOM is ready.\r\n */\r\n public observeDOM(): void {\r\n const observer = new MutationObserver((mutations) => {\r\n mutations.forEach((mutation) => {\r\n if (mutation.type === \"childList\") {\r\n // Removed elements\r\n mutation.removedNodes.forEach((node) => {\r\n if (node.nodeType !== Node.ELEMENT_NODE) return;\r\n\r\n const element = node as HTMLElement;\r\n\r\n if (this.isFixed(element)) return;\r\n\r\n if (element.hasAttribute(\"string\")) {\r\n this.handleRemoved(element);\r\n }\r\n\r\n element\r\n .querySelectorAll(\"[string],[data-string]\")\r\n .forEach((child) => {\r\n if (this.isFixed(child as HTMLElement)) return;\r\n this.handleRemoved(child as HTMLElement);\r\n });\r\n });\r\n\r\n // Added elements\r\n mutation.addedNodes.forEach((node) => {\r\n if (node.nodeType !== Node.ELEMENT_NODE) return;\r\n\r\n const element = node as HTMLElement;\r\n\r\n if (this.isFixed(element)) return;\r\n\r\n if (\r\n element.hasAttribute(\"string\") &&\r\n !element.hasAttribute(\"string-inited\")\r\n ) {\r\n this.add(element);\r\n }\r\n\r\n element\r\n .querySelectorAll(\r\n \"[string]:not([string-inited]),[data-string]:not([string-inited])\"\r\n )\r\n .forEach((child) => this.add(child as HTMLElement));\r\n\r\n // Check for connect-from logic\r\n const copyFrom =\r\n element.getAttribute(\"string-copy-from\") ??\r\n element.getAttribute(\"data-string-copy-from\");\r\n if (copyFrom) {\r\n if (this.objects.has(copyFrom)) {\r\n this.objects.get(copyFrom)!.connects.push(element);\r\n } else {\r\n this.enqueueConnection(copyFrom, element);\r\n }\r\n }\r\n });\r\n\r\n // Let modules know about DOM rebuild\r\n this.modules.all.forEach((m) => m.onDOMRebuild());\r\n }\r\n });\r\n });\r\n\r\n observer.observe(document.body, {\r\n childList: true,\r\n subtree: true,\r\n });\r\n }\r\n\r\n /**\r\n * Removes an object and its observers.\r\n */\r\n private handleRemoved(el: HTMLElement): void {\r\n const id =\r\n el.getAttribute(\"string-id\") ?? el.getAttribute(\"data-string-id\");\r\n if (!id) return;\r\n\r\n const copyFrom =\r\n el.getAttribute(\"string-copy-from\") ??\r\n el.getAttribute(\"data-string-copy-from\");\r\n if (copyFrom) {\r\n this.connectQueue = this.connectQueue.filter((q) => q.id !== copyFrom);\r\n }\r\n\r\n this.remove(id);\r\n }\r\n\r\n /**\r\n * Re-applies module initialization logic to all managed objects after settings change.\r\n *\r\n * This method should be called when `StringSettings` are updated at runtime,\r\n * especially if the new settings affect how modules calculate offsets,\r\n * easing, origins, or custom configuration.\r\n *\r\n * Internally, it re-runs `initializeObject`, `calculatePositions`, and `connectObject`\r\n * for each core module that can connect to the object.\r\n *\r\n * This is useful for supporting dynamic configuration updates without requiring\r\n * a full DOM rebuild or reinitialization.\r\n */\r\n public onSettingsChange() {\r\n this.objects.forEach((object) => {\r\n this.modules.core.forEach((m) => {\r\n if (m.canConnect(object)) {\r\n const attributes = this.getAllAttributes(object.htmlElement);\r\n m.initializeObject(\r\n this.globalId,\r\n object,\r\n object.htmlElement,\r\n attributes\r\n );\r\n m.calculatePositions(object, this.data.viewport.windowHeight);\r\n m.connectObject(object);\r\n }\r\n });\r\n });\r\n }\r\n\r\n /**\r\n * Checks whether the element is marked as fixed (not managed).\r\n */\r\n private isFixed(el: HTMLElement): boolean {\r\n return el.hasAttribute(\"string-fixed\");\r\n }\r\n}\r\n","import { StringContext } from \"../StringContext\";\r\n\r\n/**\r\n * Base class for managing scroll behavior in the system.\r\n * Handles abstract scroll state and updates, intended for extension.\r\n */\r\nexport class ScrollController {\r\n /** Shared context containing data and tools */\r\n protected context: StringContext;\r\n\r\n /** Reference to the document object */\r\n protected document: Document;\r\n\r\n /** Name of the scroll mode (e.g. 'default', 'smooth', etc.) */\r\n public name: string = \"\";\r\n\r\n /** Whether the system is in programmatic scroll mode */\r\n public isProg: boolean = false;\r\n\r\n /** Whether parallax-related logic should be active */\r\n public isParallaxEnabled: boolean = false;\r\n\r\n /** Scroll direction: vertical or horizontal */\r\n protected _scrollDirection: \"vertical\" | \"horizontal\" = \"vertical\";\r\n\r\n /**\r\n * Sets scroll direction and updates internal scroll logic.\r\n * @param scrollDirection Either 'vertical' or 'horizontal'.\r\n */\r\n public set scrollDirection(scrollDirection: \"vertical\" | \"horizontal\") {\r\n this._scrollDirection = scrollDirection;\r\n\r\n if (this._scrollDirection === \"vertical\") {\r\n this.onCalcUpdate = () => {\r\n this.context.data.scroll.scrollContainer?.scrollTo(\r\n 0,\r\n this.context.data.scroll.current\r\n );\r\n // this.scrollContainer.scrollTo(0, this.context.data.scroll.current);\r\n };\r\n } else if (this._scrollDirection === \"horizontal\") {\r\n this.onCalcUpdate = () => {\r\n this.context.data.scroll.scrollContainer?.scrollTo(\r\n this.context.data.scroll.current,\r\n 0\r\n );\r\n // this.scrollContainer.scrollTo(this.context.data.scroll.current, 0);\r\n };\r\n }\r\n }\r\n\r\n /**\r\n * Creates a new ScrollController instance.\r\n * @param context Shared context containing data and settings.\r\n */\r\n constructor(context: StringContext) {\r\n this.document = document;\r\n this.context = context;\r\n }\r\n\r\n /**\r\n * Called when scroll direction changes (up ↔ down).\r\n * Override this callback in subclasses or instances.\r\n */\r\n public onChangeDirection = () => {};\r\n\r\n /**\r\n * Called when scroll starts (user input).\r\n * Override this callback in subclasses or instances.\r\n */\r\n public onScrollStart = () => {};\r\n\r\n /**\r\n * Called when scroll ends.\r\n * Override this callback in subclasses or instances.\r\n */\r\n public onScrollStop = () => {};\r\n\r\n /**\r\n * Scroll-to function called on each frame.\r\n * This will be reassigned depending on scroll direction.\r\n */\r\n public onCalcUpdate: () => void = () => {\r\n this.context.data.scroll.scrollContainer?.scrollTo(\r\n 0,\r\n this.context.data.scroll.current\r\n );\r\n };\r\n\r\n /**\r\n * Called every animation frame.\r\n * Intended to be overridden in subclasses.\r\n */\r\n public onFrame(): void {}\r\n\r\n /**\r\n * Called when wheel event is fired.\r\n * Override to implement custom scroll interaction.\r\n * @param e Wheel event.\r\n */\r\n public onWheel(e: any): void {}\r\n\r\n /**\r\n * Called when native scroll event is fired.\r\n * Override to track native scroll position.\r\n * @param e Scroll event.\r\n */\r\n public onScroll(e: any): void {}\r\n\r\n public disableScrollEvents(): void {}\r\n\r\n public enableScrollEvents(): void {}\r\n}\r\n","import { StringContext } from \"../StringContext\";\r\nimport { ScrollController } from \"./ScrollController\";\r\n\r\n/**\r\n * Default scroll controller using native browser scrolling behavior.\r\n * Handles `scrollTop`, easing delta over time for smooth lerped animations.\r\n */\r\nexport class StringScrollDefault extends ScrollController {\r\n /** Unique name identifier for this scroll mode. */\r\n public readonly name: string = 'default';\r\n\r\n /**\r\n * Constructs a new instance of the default scroll controller.\r\n * @param context Shared string system context.\r\n */\r\n constructor(context: StringContext) {\r\n super(context);\r\n }\r\n\r\n /**\r\n * Called every animation frame.\r\n * Applies easing to scroll delta and updates lerped value.\r\n * Fires `onScrollStop` once movement has settled.\r\n */\r\n public onFrame(): void {\r\n if (this.context.data.scroll.delta !== 0) {\r\n const delta = this.context.data.scroll.delta * this.context.data.scroll.speedAccelerate;\r\n this.context.data.scroll.delta -= delta;\r\n this.context.data.scroll.lerped = delta;\r\n\r\n if (Math.abs(this.context.data.scroll.lerped) < 0.1) {\r\n this.context.data.scroll.delta = 0;\r\n this.context.data.scroll.lerped = 0;\r\n this.onScrollStop();\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Called on native scroll event.\r\n * Syncs the internal scroll state with the current page scroll.\r\n * @param e Scroll event object (unused).\r\n */\r\n public onScroll(e: any): void {\r\n const scrollTop = this.context.data.scroll.elementContainer.scrollTop;\r\n this.context.data.scroll.current = scrollTop;\r\n this.context.data.scroll.target = scrollTop;\r\n this.context.data.scroll.transformedCurrent = scrollTop\r\n }\r\n\r\n /**\r\n * Handles wheel input by updating scroll delta for easing.\r\n * Triggers `onScrollStart` if delta begins from zero.\r\n * @param e Wheel event.\r\n */\r\n public onWheel(e: any): void {\r\n if (e.deltaY !== 0) {\r\n if (this.context.data.scroll.delta === 0) {\r\n this.onScrollStart();\r\n }\r\n\r\n const plusDelta = e.deltaY;\r\n\r\n // Prevent negative delta from triggering at top of scroll\r\n if (this.context.data.scroll.target === 0) {\r\n this.context.data.scroll.delta += Math.max(0, e.deltaY);\r\n }\r\n\r\n this.context.data.scroll.delta += plusDelta;\r\n }\r\n }\r\n}\r\n","import { StringContext } from \"../StringContext\";\r\nimport { ScrollController } from \"./ScrollController\";\r\n\r\n/**\r\n * Scroll controller that disables all user-initiated scrolling.\r\n * Prevents native scroll and wheel behavior, effectively locking the page.\r\n */\r\nexport class StringScrollDisable extends ScrollController {\r\n /** Unique name identifier for this scroll mode. */\r\n public readonly name: string = \"disable\";\r\n\r\n /**\r\n * Constructs the scroll disabling controller.\r\n * @param context The shared string system context.\r\n */\r\n\r\n private preventScroll = (e: Event) => {\r\n e.preventDefault();\r\n };\r\n\r\n private preventKeyScroll = (e: KeyboardEvent) => {\r\n const keysThatScroll = [\r\n \"ArrowUp\",\r\n \"ArrowDown\",\r\n \"PageUp\",\r\n \"PageDown\",\r\n \" \",\r\n \"Home\",\r\n \"End\",\r\n ];\r\n if (keysThatScroll.includes(e.key)) {\r\n e.preventDefault();\r\n }\r\n };\r\n\r\n private onPreventScroll = this.preventScroll.bind(this);\r\n private onPreventKeyScroll = this.preventKeyScroll.bind(this);\r\n\r\n constructor(context: StringContext) {\r\n super(context);\r\n }\r\n\r\n disableScrollEvents() {\r\n window.addEventListener(\"touchmove\", this.onPreventScroll, {\r\n passive: false,\r\n });\r\n window.addEventListener(\"keydown\", this.onPreventKeyScroll);\r\n }\r\n\r\n enableScrollEvents() {\r\n window.removeEventListener(\"touchmove\", this.onPreventScroll);\r\n window.removeEventListener(\"keydown\", this.onPreventKeyScroll);\r\n }\r\n\r\n /**\r\n * Called on each animation frame.\r\n * Not used in this controller since scrolling is disabled.\r\n */\r\n public onFrame(): void {}\r\n\r\n /**\r\n * Prevents scroll via mouse wheel.\r\n * @param e Wheel event.\r\n */\r\n public onWheel(e: any): void {\r\n e.preventDefault();\r\n }\r\n\r\n /**\r\n * Prevents scroll via native scroll interaction (e.g. touch).\r\n * @param e Scroll event.\r\n */\r\n public onScroll(e: any): void {\r\n e.preventDefault();\r\n }\r\n}\r\n","import { StringContext } from \"../StringContext\";\r\nimport { ScrollController } from \"./ScrollController\";\r\n\r\n/**\r\n * CSS class names applied to `<html>` element based on scroll direction.\r\n */\r\nconst CLASS_NAMES = {\r\n SCROLL_FORWARD: '-scroll-forward',\r\n SCROLL_BACK: '-scroll-back',\r\n} as const;\r\n\r\n/**\r\n * Smooth scroll controller with delta-based acceleration and direction tracking.\r\n * Handles wheel events and scroll position updates with smooth interpolation.\r\n */\r\nexport class StringScrollSmooth extends ScrollController {\r\n /** \r\n * Unique identifier for this scroll controller type.\r\n * Used for selection and debug purposes.\r\n */\r\npublic readonly name: string = 'smooth';\r\n\r\n/** \r\n * Whether the user has manually scrolled using the native scrollbar.\r\n * When true, the scroll position is directly synced from DOM on next frame.\r\n */\r\nprivate isScrollbarManipulation = false;\r\n\r\n/** \r\n * Current internal force applied to the scroll target.\r\n * Calculated from accumulated scroll impulse and acceleration.\r\n */\r\nprivate scrollForce: number = 0;\r\n\r\n/** \r\n * Latest raw scroll impulse received from the wheel event (`deltaY`).\r\n * Temporarily stored for direction and boundary checks.\r\n */\r\nprivate wheelImpulse: number = 0;\r\n\r\n/** \r\n * Scroll position from the previous frame.\r\n * Used to detect actual movement and trigger updates only when needed.\r\n */\r\nprivate previousCurrent: number = 0;\r\n\r\n/** \r\n * Current scroll direction.\r\n * - `true` — scrolling down\r\n * - `false` — scrolling up\r\n * - `null` — unknown (initial state)\r\n */\r\nprivate isBottomScrollDirection: boolean | null = null;\r\n\r\n/** \r\n * Minimum velocity threshold below which scrolling is considered stopped.\r\n * Prevents micro-movements from continuing infinite smooth scroll.\r\n */\r\nprivate readonly velocityThreshold = 0.1;\r\n\r\n\r\n constructor(context: StringContext) {\r\n super(context);\r\n }\r\n\r\n /**\r\n * Handles scroll direction changes and toggles CSS classes accordingly.\r\n * @param newDirection `true` if scrolling down, `false` if up.\r\n */\r\n private updateScrollDirection(newDirection: boolean) {\r\n if (this.isBottomScrollDirection === null) {\r\n this.isBottomScrollDirection = newDirection;\r\n return;\r\n }\r\n this.context.data.scroll.isScrollingDown = newDirection;\r\n this.onChangeDirection();\r\n\r\n document.documentElement.classList.toggle(CLASS_NAMES.SCROLL_FORWARD, newDirection);\r\n document.documentElement.classList.toggle(CLASS_NAMES.SCROLL_BACK, !newDirection);\r\n }\r\n\r\n /**\r\n * Immediately stops scrolling and resets all deltas and directions.\r\n */\r\n public stopScroll(): void {\r\n this.context.data.scroll.lerped = 0;\r\n this.context.data.scroll.delta = 0;\r\n this.context.data.scroll.target = this.context.data.scroll.current;\r\n this.isProg = false;\r\n this.onCalcUpdate();\r\n document.documentElement.classList.remove(CLASS_NAMES.SCROLL_BACK, CLASS_NAMES.SCROLL_FORWARD);\r\n this.isBottomScrollDirection = null;\r\n }\r\n\r\n /**\r\n * Called on each animation frame to apply lerped scroll logic.\r\n */\r\n public onFrame(): void {\r\n if (this.isScrollbarManipulation) {\r\n this.isScrollbarManipulation = false;\r\n this.context.data.scroll.current = this.context.data.scroll.elementContainer.scrollTop\r\n this.context.data.scroll.target = this.context.data.scroll.elementContainer.scrollTop\r\n this.context.data.scroll.transformedCurrent = this.context.data.scroll.current * this.context.data.viewport.transformScale\r\n return;\r\n }\r\n\r\n \r\n if (this.context.data.scroll.delta !== 0) {\r\n this.scrollForce = this.context.data.scroll.delta * this.context.data.scroll.speedAccelerate;\r\n\r\n this.context.data.scroll.target = Math.min(\r\n Math.max(0, this.context.data.scroll.target + this.scrollForce),\r\n this.context.data.scroll.bottomPosition\r\n );\r\n this.context.data.scroll.delta -= this.scrollForce;\r\n\r\n this.context.data.scroll.lerped = \r\n (this.context.data.scroll.target - this.context.data.scroll.current) * \r\n this.context.data.scroll.speed;\r\n\r\n const absVelocity = Math.abs(this.context.data.scroll.lerped);\r\n if (this.context.data.scroll.lerped > 0) {\r\n this.context.data.scroll.current = Math.ceil(this.context.data.scroll.current + this.context.data.scroll.lerped);\r\n } else {\r\n this.context.data.scroll.current = Math.floor(this.context.data.scroll.current + this.context.data.scroll.lerped);\r\n }\r\n \r\n this.context.data.scroll.transformedCurrent = this.context.data.scroll.current * this.context.data.viewport.transformScale\r\n this.updateScrollDirection(this.context.data.scroll.lerped > 0);\r\n\r\n if (absVelocity < this.velocityThreshold) {\r\n this.stopScroll();\r\n this.onScrollStop();\r\n } else {\r\n this.isProg = true;\r\n if (this.previousCurrent !== this.context.data.scroll.current) {\r\n this.previousCurrent = this.context.data.scroll.current;\r\n this.onCalcUpdate();\r\n }\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Handles user wheel input to accumulate scroll delta.\r\n * @param e The WheelEvent from the browser.\r\n */\r\n public onWheel(e: WheelEvent): void {\r\n if (e.deltaY !== 0) {\r\n e.preventDefault();\r\n }\r\n\r\n this.wheelImpulse = e.deltaY;\r\n if (this.wheelImpulse === 0) return;\r\n\r\n if (this.context.data.scroll.delta === 0) {\r\n this.onScrollStart();\r\n }\r\n \r\n const scrollDirection = Math.sign(this.wheelImpulse);\r\n const atTop = this.context.data.scroll.target === 0 && scrollDirection < 0;\r\n const atBottom = this.context.data.scroll.target === this.context.data.scroll.bottomPosition && scrollDirection > 0;\r\n if (atTop || atBottom) return;\r\n this.context.data.scroll.delta += this.wheelImpulse;\r\n }\r\n\r\n /**\r\n * Detects native scrollbar manipulation when smooth scroll is idle.\r\n * @param e Scroll event.\r\n */\r\n public onScroll(e: Event): void {\r\n if (!this.isProg) {\r\n this.isScrollbarManipulation = true;\r\n }\r\n }\r\n}\r\n","import { ScrollMode } from \"../../states/ScrollState\";\r\nimport { ScrollController } from \"../controllers/ScrollController\";\r\nimport { StringScrollDefault } from \"../controllers/StringScrollDefault\";\r\nimport { StringScrollDisable } from \"../controllers/StringScrollDisable\";\r\nimport { StringScrollSmooth } from \"../controllers/StringScrollSmooth\";\r\nimport { StringContext } from \"../StringContext\";\r\n\r\n/**\r\n * Handles scroll engine setup and switching logic.\r\n * Synchronizes scroll modes with the centralized ScrollState inside StringContext.\r\n */\r\nexport class ScrollManager {\r\n private modes: Map<ScrollMode, ScrollController> = new Map();\r\n\r\n constructor(private context: StringContext) {\r\n this.modes.set(\"smooth\", new StringScrollSmooth(context));\r\n this.modes.set(\"default\", new StringScrollDefault(context));\r\n this.modes.set(\"disable\", new StringScrollDisable(context));\r\n\r\n // Initial mode based on screen width\r\n this.updateResponsiveMode();\r\n }\r\n\r\n /**\r\n * Manually sets the scroll mode for mobile devices.\r\n * @param mode The scroll mode: 'smooth', 'default', or 'disable'.\r\n */\r\n public setMobileMode(mode: ScrollMode): void {\r\n this.context.data.scroll.modeMobile = mode;\r\n this.updateResponsiveMode();\r\n }\r\n\r\n /**\r\n * Manually sets the scroll mode for desktop devices.\r\n * @param mode The scroll mode: 'smooth', 'default', or 'disable'.\r\n */\r\n public setDesktopMode(mode: ScrollMode): void {\r\n this.context.data.scroll.modeDesktop = mode;\r\n this.updateResponsiveMode();\r\n }\r\n\r\n /**\r\n * Automatically switches scroll mode based on screen width.\r\n * Call this inside your resize handler.\r\n */\r\n public updateResponsiveMode(): void {\r\n const isMobile = window.innerWidth < 1080;\r\n const newMode = isMobile\r\n ? this.context.data.scroll.modeMobile\r\n : this.context.data.scroll.modeDesktop;\r\n\r\n this.setMode(newMode);\r\n }\r\n\r\n public updatePosition(): void {\r\n this.modes.forEach((engine) => {\r\n engine.onCalcUpdate();\r\n });\r\n }\r\n\r\n /**\r\n * Sets the current scroll mode and updates the active scroll engine.\r\n * @param mode The scroll mode to activate.\r\n */\r\n public setMode(mode: ScrollMode): void {\r\n if (!this.modes.has(mode)) {\r\n console.warn(`[ScrollManager] Unknown scroll mode: ${mode}`);\r\n return;\r\n }\r\n this.get().enableScrollEvents();\r\n this.context.data.scroll.mode = mode;\r\n this.get().disableScrollEvents();\r\n }\r\n\r\n /**\r\n * Returns the currently active scroll engine based on state.\r\n */\r\n public get(): ScrollController {\r\n return this.modes.get(this.context.data.scroll.mode)!;\r\n }\r\n\r\n /**\r\n * Returns all available scroll engine instances.\r\n */\r\n public getEngines(): Map<ScrollMode, ScrollController> {\r\n return this.modes;\r\n }\r\n\r\n /**\r\n * Calls `onFrame()` on the current scroll engine.\r\n */\r\n public onFrame(): void {\r\n this.get().onFrame();\r\n }\r\n\r\n /**\r\n * Forwards native scroll event to the current scroll engine.\r\n * @param e The scroll event.\r\n */\r\n public onScroll(e: Event): void {\r\n this.get().onScroll(e);\r\n }\r\n\r\n /**\r\n * Forwards wheel event to the current scroll engine.\r\n * @param e The wheel event.\r\n */\r\n public onWheel(e: WheelEvent): void {\r\n this.get().onWheel(e);\r\n }\r\n\r\n /**\r\n * Subscribes lifecycle event handlers to all scroll engines.\r\n * @param events Scroll lifecycle callbacks.\r\n */\r\n public bindEvents(events: {\r\n onScrollStart: () => void;\r\n onScrollStop: () => void;\r\n onDirectionChange: () => void;\r\n }) {\r\n this.modes.forEach((engine) => {\r\n engine.onScrollStart = events.onScrollStart;\r\n engine.onScrollStop = events.onScrollStop;\r\n engine.onChangeDirection = events.onDirectionChange;\r\n });\r\n }\r\n}\r\n","/**\r\n * Reactive cursor data for raw, target, smoothed and step deltas.\r\n */\r\nexport class CursorState {\r\n /**\r\n * Target X position of the cursor (e.g., from `mousemove`)\r\n */\r\n targetX: number = 0\r\n\r\n /**\r\n * Target Y position of the cursor.\r\n */\r\n targetY: number = 0\r\n\r\n /**\r\n * Smoothed X position after applying lerp.\r\n */\r\n smoothedX: number = 0\r\n\r\n /**\r\n * Smoothed Y position after applying lerp.\r\n */\r\n smoothedY: number = 0\r\n\r\n /**\r\n * Delta step between current and target X (used internally for lerp).\r\n */\r\n stepX: number = 0\r\n\r\n /**\r\n * Delta step between current and target Y.\r\n */\r\n stepY: number = 0\r\n}\r\n","/**\r\n * Global Three.js or rendering context reference.\r\n */\r\nexport class RenderState {\r\n /** Instance of Three.js or another render context */\r\n threeInstance: any = null\r\n}\r\n","export type ScrollDirection = 'vertical' | 'horizontal'\r\nexport type ScrollMode = 'smooth' | 'disable' | 'default'\r\n\r\n/**\r\n * Describes current scroll-related state for all calculations and modules.\r\n */\r\nexport class ScrollState {\r\n /** Target scroll value — where we want to scroll to (used in smooth scroll) */\r\n target: number = 0\r\n\r\n /** Current scroll value (actual scroll position) */\r\n current: number = 0\r\n\r\n /** Transformed current scroll value (with transform by scroll container) */\r\n transformedCurrent: number = 0\r\n\r\n /** Delta between frames (used for animation / velocity) */\r\n delta: number = 0\r\n\r\n /** Interpolated scroll value for smooth transitions */\r\n lerped: number = 0\r\n\r\n /** Displacement value (similar to lerped, but used for other animations) */\r\n displacement: number = 0\r\n\r\n /** Whether scroll direction is downward */\r\n isScrollingDown: boolean = false\r\n\r\n /** Top screen scroll position */\r\n topPosition: number = 0\r\n\r\n /** Bottom screen scroll position */\r\n bottomPosition: number = 0\r\n\r\n /** Scroll direction (vertical / horizontal) */\r\n direction: ScrollDirection = 'vertical'\r\n\r\n /** Scroll container element */\r\n elementContainer: HTMLElement = document.documentElement\r\n\r\n /** Scroll container element */\r\n scrollContainer: HTMLElement | Window = window\r\n\r\n /** Scroll container element */\r\n container: HTMLElement = document.body\r\n\r\n /**\r\n * Currently active scroll mode.\r\n * Can be 'smooth', 'default', or 'disable'.\r\n */\r\n mode: ScrollMode = 'smooth'\r\n\r\n /**\r\n * Scroll mode to use on mobile devices.\r\n * Can be 'smooth', 'default', or 'disable'.\r\n */\r\n modeMobile: ScrollMode = 'smooth'\r\n\r\n /**\r\n * Scroll mode to use on desktop devices.\r\n * Can be 'smooth', 'default', or 'disable'.\r\n */\r\n modeDesktop: ScrollMode = 'smooth'\r\n\r\n /**\r\n * Base scroll speed used for calculating smooth scrolling.\r\n * Typically a small value between 0 and 1.\r\n */\r\n speed: number = 0.1\r\n\r\n /**\r\n * Acceleration factor used for scroll easing or velocity-based animations.\r\n * Also typically a value between 0 and 1.\r\n */\r\n speedAccelerate: number = 0.25\r\n}\r\n","/**\r\n * Represents the time-related state of the current and previous animation frames.\r\n * \r\n * Useful for calculating delta time, total elapsed time, and implementing\r\n * time-based animations or physics.\r\n */\r\nexport class TimeState {\r\n /**\r\n * Timestamp of the current animation frame in milliseconds.\r\n * This value is typically obtained via `performance.now()`.\r\n */\r\n now: number = 0;\r\n\r\n /**\r\n * Timestamp of the previous animation frame in milliseconds.\r\n */\r\n previous: number = 0;\r\n\r\n /**\r\n * Time difference between the current and previous frames in milliseconds.\r\n * Commonly used to calculate animation progress.\r\n */\r\n delta: number = 0;\r\n\r\n /**\r\n * Total time elapsed since the start of the animation or system in milliseconds.\r\n */\r\n elapsed: number = 0;\r\n}\r\n","/**\r\n * Describes current viewport size and scaling.\r\n */\r\nexport class ViewportState {\r\n /** Width of the visible window */\r\n windowWidth: number = 0\r\n\r\n /** Height of the visible window */\r\n windowHeight: number = 0\r\n\r\n /** Full scroll width (content width inside scroll container) */\r\n contentWidth: number = 0\r\n\r\n /** Full scroll height (content height inside scroll container) */\r\n contentHeight: number = 0\r\n\r\n /** Screen scale ratio for width (e.g. device pixel ratio or zoom level) */\r\n scaleWidth: number = 1\r\n\r\n /** Screen scale ratio for height */\r\n scaleHeight: number = 1\r\n\r\n transformScale: number = 1\r\n\r\n baseRem: number = 16\r\n}\r\n","import { CursorState } from \"../states/CursorState\"\r\nimport { RenderState } from \"../states/RenderState\"\r\nimport { ScrollState } from \"../states/ScrollState\"\r\nimport { TimeState } from \"../states/TimeState\"\r\nimport { ViewportState } from \"../states/ViewportState\"\r\n\r\n/**\r\n * Container for global dynamic state used throughout the string-tune system.\r\n * Provides access to live scroll, viewport, cursor, and render states,\r\n * which are updated each frame and shared across modules and tools.\r\n */\r\nexport class StringData {\r\n /**\r\n * Scroll-related state object.\r\n * Contains live values like `target`, `current`, `delta`, `direction`, and more.\r\n * Used for scroll-based animations, transitions, and effects.\r\n */\r\n scroll = new ScrollState()\r\n\r\n /**\r\n * Viewport-related state object.\r\n * Holds dimensions like window size, content size, aspect ratios, and more.\r\n * Useful for layout calculations, unit parsing, and element positioning.\r\n */\r\n viewport = new ViewportState()\r\n\r\n /**\r\n * Cursor-related state object.\r\n * Tracks cursor position, velocity, movement, and derived values.\r\n * Can be used for pointer interactions, proximity effects, and hover states.\r\n */\r\n cursor = new CursorState()\r\n\r\n /**\r\n * Render-related state object.\r\n * Stores data related to rendering context (e.g. WebGL, Three.js),\r\n * such as shared materials, textures, or active render frame data.\r\n */\r\n render = new RenderState()\r\n\r\n /**\r\n * Time-related state object.\r\n * Tracks frame timings, including current timestamp, delta between frames,\r\n * and total elapsed time since animation start.\r\n * Useful for time-based animations, easing, frame consistency, and syncing logic.\r\n */\r\n time = new TimeState()\r\n}\r\n","import { IStringModule } from \"./IStringModule\";\r\nimport { StringObject } from \"../objects/StringObject\";\r\nimport { StringToolsContainer } from \"./StringToolsContainer\";\r\nimport { StringData } from \"./StringData\";\r\nimport { AttributeType } from \"../models/attribute/AttributeType\";\r\nimport { StringContext } from \"./StringContext\";\r\nimport { EventManager } from \"./managers/EventManager\";\r\nimport { AttributeMapping } from \"../models/attribute/AttributeMapping\";\r\n\r\n/**\r\n * Base class for a module used in the string-tune system.\r\n * Extend this class to create custom modules that respond to scroll, resize, input, etc.\r\n */\r\nexport class StringModule implements IStringModule {\r\n /**\r\n * List of attribute names this module should automatically read\r\n * from the DOM element and assign to the object properties.\r\n * Example: [\"offset-top\", \"offset-bottom\"]\r\n */\r\n protected attributesToMap: AttributeMapping[];\r\n\r\n /**\r\n * A map of all entered objects by their unique ID.\r\n */\r\n protected objectMap: Map<string, StringObject> = new Map();\r\n\r\n /**\r\n * A flat array of all connected objects.\r\n */\r\n protected objects: StringObject[] = [];\r\n\r\n /**\r\n * The HTML attribute key that identifies objects this module is responsible for.\r\n */\r\n protected htmlKey: string = \"\";\r\n\r\n /**\r\n * Module type ID used internally to categorize module behavior.\r\n */\r\n protected _type: number = 1;\r\n\r\n /**\r\n * Returns the type of the module.\r\n * Type 1 = core module, type 2 = UI module.\r\n */\r\n public get type(): number {\r\n return this._type;\r\n }\r\n\r\n /**\r\n * Tools container providing utilities for attribute parsing, unit conversion, etc.\r\n * Acts as a dependency injection hub for core IStringTool implementations.\r\n */\r\n protected tools: StringToolsContainer;\r\n\r\n /**\r\n * Shared global data object containing scroll state, viewport info, cursor position, etc.\r\n * Used for calculations within lifecycle hooks like `onScroll`, `onFrame`, and `onResize`.\r\n */\r\n protected data: StringData;\r\n\r\n /**\r\n * Configuration object specific to the current module.\r\n * Passed in during module registration or initialization.\r\n */\r\n protected settings: Record<string, any>;\r\n\r\n /**\r\n * Event hub for communication between modules or systems.\r\n * Supports custom event emitting, listening, and unsubscription.\r\n */\r\n protected events: EventManager;\r\n\r\n constructor(context: StringContext) {\r\n this.tools = context.tools;\r\n this.data = context.data;\r\n this.settings = context.settings;\r\n this.events = context.events;\r\n\r\n this.attributesToMap = [\r\n { key: \"active\", type: \"boolean\", fallback: this.settings[\"active\"] },\r\n { key: \"fixed\", type: \"boolean\", fallback: this.settings[\"fixed\"] },\r\n { key: \"repeat\", type: \"boolean\", fallback: this.settings[\"repeat\"] },\r\n {\r\n key: \"self-disable\",\r\n type: \"boolean\",\r\n fallback: this.settings[\"self-disable\"],\r\n },\r\n { key: \"abs\", type: \"boolean\", fallback: this.settings[\"abs\"] },\r\n { key: \"key\", type: \"string\", fallback: this.settings[\"key\"] },\r\n {\r\n key: \"offset-top\",\r\n type: \"dimension\",\r\n fallback: this.settings[\"offset-top\"],\r\n },\r\n {\r\n key: \"offset-bottom\",\r\n type: \"dimension\",\r\n fallback: this.settings[\"offset-bottom\"],\r\n },\r\n {\r\n key: \"inview-top\",\r\n type: \"dimension\",\r\n fallback: this.settings[\"inview-top\"],\r\n },\r\n {\r\n key: \"inview-bottom\",\r\n type: \"dimension\",\r\n fallback: this.settings[\"inview-bottom\"],\r\n },\r\n {\r\n key: \"start\",\r\n type: \"number\",\r\n fallback: (\r\n element: HTMLElement,\r\n object: StringObject,\r\n boundingRect: DOMRect\r\n ) => {\r\n const top = boundingRect.top;\r\n return (\r\n Math.floor(top) +\r\n this.data.scroll.container.scrollTop *\r\n this.data.viewport.transformScale\r\n );\r\n },\r\n },\r\n {\r\n key: \"end\",\r\n type: \"number\",\r\n fallback: (\r\n element: HTMLElement,\r\n object: StringObject,\r\n boundingRect: DOMRect\r\n ) => {\r\n const top = boundingRect.top;\r\n const height = boundingRect.height;\r\n return top + height - this.data.scroll.transformedCurrent;\r\n },\r\n },\r\n {\r\n key: \"size\",\r\n type: \"number\",\r\n fallback: (\r\n element: HTMLElement,\r\n object: StringObject,\r\n boundingRect: DOMRect\r\n ) => {\r\n return boundingRect.height;\r\n },\r\n },\r\n {\r\n key: \"half-width\",\r\n type: \"number\",\r\n fallback: (\r\n element: HTMLElement,\r\n object: StringObject,\r\n boundingRect: DOMRect\r\n ) => {\r\n return boundingRect.width / 2;\r\n },\r\n },\r\n {\r\n key: \"half-height\",\r\n type: \"number\",\r\n fallback: (\r\n element: HTMLElement,\r\n object: StringObject,\r\n boundingRect: DOMRect\r\n ) => {\r\n return boundingRect.height / 2;\r\n },\r\n },\r\n ];\r\n }\r\n\r\n /**\r\n * Called when a DOM element is detected as a potential interactive object.\r\n */\r\n initializeObject(\r\n globalId: number,\r\n object: StringObject,\r\n element: HTMLElement,\r\n attributes: Record<string, any>\r\n ): void {\r\n let boundingRect = this.tools.boundingClientRect.process({ element });\r\n for (const { key, type, fallback, transform } of this.attributesToMap) {\r\n const resolvedFallback =\r\n typeof fallback === \"function\"\r\n ? fallback(element, object, boundingRect)\r\n : fallback;\r\n const raw = this.tools.domAttribute.process({\r\n element,\r\n key,\r\n fallback: attributes[key] ?? this.settings[key] ?? resolvedFallback,\r\n });\r\n\r\n let parsed = this.parseAttribute(raw, type, {\r\n element,\r\n viewportHeight: this.data.viewport.windowHeight,\r\n baseRem: this.data.viewport.baseRem,\r\n });\r\n\r\n if (transform) {\r\n parsed = transform(parsed);\r\n }\r\n object.setProperty(key, parsed);\r\n }\r\n }\r\n\r\n /**\r\n * Calculates object-specific positions or metrics based on the current layout or scroll state.\r\n * This method is intended to be overridden in subclasses if the module needs to precompute\r\n * layout-dependent values (e.g. parallax offsets, trigger zones, distances).\r\n *\r\n * @param object The `StringObject` instance whose positions are being calculated.\r\n * @param windowSize The current window height or width (depending on scroll axis).\r\n */\r\n calculatePositions(object: StringObject, windowSize: number) {\r\n const start = object.getProperty<number>(\"start\");\r\n const size = object.getProperty<number>(\"size\");\r\n\r\n const offsetStart = object.getProperty<number>(\"offset-bottom\");\r\n const offsetEnd = object.getProperty<number>(\"offset-top\");\r\n\r\n const startElement = object.getProperty(\"enter-el\");\r\n const startViewport = object.getProperty(\"enter-vp\");\r\n const endElement = object.getProperty(\"exit-el\");\r\n const endViewport = object.getProperty(\"exit-vp\");\r\n\r\n let startPosition = 0;\r\n let endPosition = 0;\r\n let startBias = 0;\r\n let endBias = 0;\r\n\r\n if (\r\n (startElement === \"top\" && startViewport === \"top\") ||\r\n (startElement === \"left\" && startViewport === \"left\")\r\n ) {\r\n startBias = -windowSize + 1;\r\n startPosition = start - offsetStart;\r\n } else if (\r\n (startElement === \"top\" && startViewport === \"bottom\") ||\r\n (startElement === \"left\" && startViewport === \"right\")\r\n ) {\r\n startPosition = start - windowSize - offsetStart;\r\n } else if (\r\n (startElement === \"bottom\" && startViewport === \"top\") ||\r\n (startElement === \"right\" && startViewport === \"left\")\r\n ) {\r\n startBias = -windowSize - size + 1;\r\n startPosition = start + size - offsetStart;\r\n } else if (\r\n (startElement === \"bottom\" && startViewport === \"bottom\") ||\r\n (startElement === \"right\" && startViewport === \"right\")\r\n ) {\r\n startBias = -size + 1;\r\n startPosition = start - windowSize + size - offsetStart;\r\n }\r\n\r\n // End position calculation\r\n if (\r\n (endElement === \"top\" && endViewport === \"top\") ||\r\n (endElement === \"left\" && endViewport === \"left\")\r\n ) {\r\n endBias = -size + 1;\r\n endPosition = start + offsetEnd;\r\n } else if (\r\n (endElement === \"top\" && endViewport === \"bottom\") ||\r\n (endElement === \"left\" && endViewport === \"right\")\r\n ) {\r\n endBias = -windowSize - size + 1;\r\n endPosition = start - windowSize + offsetEnd;\r\n } else if (\r\n (endElement === \"bottom\" && endViewport === \"top\") ||\r\n (endElement === \"right\" && endViewport === \"left\")\r\n ) {\r\n endPosition = start + size + offsetEnd;\r\n } else if (\r\n (endElement === \"bottom\" && endViewport === \"bottom\") ||\r\n (endElement === \"right\" && endViewport === \"right\")\r\n ) {\r\n endBias = -windowSize + 1;\r\n endPosition = start - windowSize + size + offsetEnd;\r\n }\r\n\r\n object.setProperty<number>(\"start-bias\", startBias);\r\n object.setProperty<number>(\"end-bias\", endBias);\r\n\r\n object.setProperty<number>(\r\n \"start-position\",\r\n startPosition - this.data.scroll.topPosition\r\n );\r\n object.setProperty<number>(\"end-position\", endPosition);\r\n object.setProperty<number>(\r\n \"difference-position\",\r\n endPosition - startPosition\r\n );\r\n }\r\n\r\n /**\r\n * Parses a raw DOM attribute value into the correct type based on mapping.\r\n * Handles fallback resolution, transformation, and special units.\r\n *\r\n * @param value Raw attribute string from DOM.\r\n * @param type The expected attribute type (e.g. number, boolean, dimension).\r\n * @param context Optional helper values like element or viewport size.\r\n * @returns The parsed and transformed value.\r\n */\r\n protected parseAttribute(\r\n value: string | null,\r\n type: AttributeType,\r\n context: {\r\n element?: HTMLElement;\r\n viewportHeight?: number;\r\n baseRem?: number;\r\n } = {}\r\n ): any {\r\n if (value == null) return null;\r\n\r\n if (typeof type === \"object\" && type.type === \"enum\") {\r\n return type.values.includes(value) ? value : type.values[0];\r\n }\r\n\r\n switch (type) {\r\n case \"number\":\r\n return parseFloat(value);\r\n\r\n case \"boolean\":\r\n return value === \"\" || value === \"true\";\r\n\r\n case \"json\":\r\n try {\r\n return JSON.parse(value);\r\n } catch {\r\n return null;\r\n }\r\n\r\n case \"tuple\":\r\n return value.trim().split(/\\s+/);\r\n\r\n case \"easing\":\r\n return this.tools.easingFunction.process({ easing: value });\r\n\r\n case \"color\":\r\n return this.tools.colorParser.process({ value: value });\r\n\r\n case \"dimension\":\r\n if (value == \"0\") return 0;\r\n if (\r\n context.element != null &&\r\n context.viewportHeight != null &&\r\n context.baseRem != null\r\n ) {\r\n return this.tools.unitParser.process({\r\n value,\r\n element: context.element,\r\n viewportHeight: context.viewportHeight,\r\n baseRem: context.baseRem,\r\n });\r\n } else {\r\n return 0;\r\n }\r\n\r\n default:\r\n return value;\r\n }\r\n }\r\n\r\n /**\r\n * Determines whether the module should attach to a given object,\r\n * based on the presence of the module's `htmlKey` in the object keys.\r\n *\r\n * @param object The target object to test.\r\n * @returns `true` if the module can connect, `false` otherwise.\r\n */\r\n canConnect(object: StringObject): boolean {\r\n return object.keys.includes(this.htmlKey);\r\n }\r\n\r\n /**\r\n * Registers the module on a given object, adds the object to internal list,\r\n * and triggers connection logic.\r\n *\r\n * @param object The object to connect to.\r\n */\r\n connectObject(object: StringObject): void {\r\n object.connect(this);\r\n this.onObjectConnected(object);\r\n }\r\n\r\n /**\r\n * Registers the object internally when it enters the module’s scope.\r\n */\r\n enterObject(id: string, object: StringObject): void {\r\n if (!this.objectMap.has(id)) {\r\n this.objectMap.set(id, object);\r\n this.objects.push(object);\r\n }\r\n }\r\n\r\n /**\r\n * Unregisters the object when it leaves the module’s scope.\r\n */\r\n exitObject(id: string): void {\r\n const object = this.objectMap.get(id);\r\n if (!object) return;\r\n\r\n this.objectMap.delete(id);\r\n\r\n const index = this.objects.indexOf(object);\r\n if (index !== -1) {\r\n this.objects.splice(index, 1);\r\n }\r\n }\r\n\r\n /**\r\n * Called when an object is connected. Can be overridden to apply initial styles or logic.\r\n * @param object The connected object.\r\n */\r\n onObjectConnected(object: StringObject): void {}\r\n\r\n /**\r\n * Applies a style or callback to both the main element and all its connected elements.\r\n *\r\n * @param object The object whose elements to update.\r\n * @param applyFn The function that receives an HTMLElement and performs any update.\r\n */\r\n protected applyToElementAndConnects(\r\n object: StringObject,\r\n applyFn: (el: HTMLElement) => void\r\n ) {\r\n applyFn(object.htmlElement);\r\n object.connects.forEach(applyFn);\r\n }\r\n\r\n /**\r\n * Cleans up internal state and detaches the module from the system.\r\n */\r\n destroy(): void {\r\n this.objects = [];\r\n this.objectMap = new Map();\r\n }\r\n\r\n // ───────────────────────────────\r\n // Lifecycle Hooks\r\n // ───────────────────────────────\r\n\r\n /** Called once when the module is initialized. */\r\n onInit(): void {}\r\n\r\n /** Called on each frame with current scroll and state data. */\r\n onFrame(data: StringData): void {}\r\n\r\n /** Called when the window or layout is resized. */\r\n onResize(): void {}\r\n\r\n /** Called when scroll position changes. */\r\n onScroll(data: StringData): void {}\r\n\r\n /** Called when user changed scroll diraction. */\r\n onDirectionChange(): void {}\r\n\r\n /** Called when user starts scrolling. */\r\n onScrollStart(): void {}\r\n\r\n /** Called when user stops scrolling. */\r\n onScrollStop(): void {}\r\n\r\n /** Called when scroll direction changes (e.g., up ↔ down). */\r\n onScrollDirectionChange(): void {}\r\n\r\n /** Called when scroll axis changes (vertical ↔ horizontal). */\r\n onAxisChange(): void {}\r\n\r\n /** Called when device type changes (e.g., desktop ↔ mobile). */\r\n onDeviceChange(): void {}\r\n\r\n /** Called when scroll-related system settings or parameters change. */\r\n onScrollConfigChange(): void {}\r\n\r\n /** Called when scroll-related system settings or parameters change. */\r\n onSettingsChange(): void {}\r\n\r\n /** Called when the DOM is rebuilt, such as after a major mutation. */\r\n onDOMRebuild(): void {}\r\n\r\n /** Called on every mouse movement. */\r\n onMouseMove(event: MouseEvent): void {}\r\n\r\n /** Called on wheel input (independent of scroll). */\r\n onWheel(event: WheelEvent): void {}\r\n\r\n /**\r\n * Called when DOM elements are added or removed.\r\n */\r\n onDOMMutate(added: NodeList, removed: NodeList): void {}\r\n}\r\n","import { IStringTool } from \"../core/IStringTool\"\r\n\r\n/**\r\n * Input for `BoundingClientRectTool`.\r\n */\r\ninterface BoundingClientRectInput {\r\n /** The DOM element to retrieve bounding rect from. */\r\n element: HTMLElement\r\n}\r\n\r\n/**\r\n * Tool for accessing `getBoundingClientRect()` in a consistent, testable way.\r\n */\r\nexport default class BoundingClientRectTool\r\n implements IStringTool<BoundingClientRectInput, DOMRect>\r\n{\r\n /**\r\n * @returns The bounding client rect of the provided element.\r\n */\r\n process({ element }: BoundingClientRectInput): DOMRect {\r\n return element.getBoundingClientRect()\r\n }\r\n}\r\n","import { IStringTool } from \"../core/IStringTool\"\r\n\r\ninterface DOMAttributeInput {\r\n element: HTMLElement\r\n key: string // for example: \"offset-tom\"\r\n fallback?: string | null\r\n}\r\n\r\nexport default class DOMAttributeTool implements IStringTool<DOMAttributeInput, string | null> {\r\n /**\r\n * Retrieves the value of either `string-${key}` or `data-string-${key}` attribute.\r\n *\r\n * @example key = \"offset-tom\" → tries:\r\n * - element.getAttribute(\"string-offset-tom\")\r\n * - element.getAttribute(\"data-string-offset-tom\")\r\n */\r\n process({ element, key, fallback = null }: DOMAttributeInput): string | null {\r\n return (\r\n element.getAttribute(`string-${key}`) ??\r\n element.getAttribute(`data-string-${key}`) ??\r\n fallback\r\n )\r\n }\r\n}\r\n","import { IStringTool } from \"../core/IStringTool\"\r\n\r\n/**\r\n * Input for retrieving a value from a key-value object or dataset-like structure.\r\n */\r\ninterface RecordAttributeInput {\r\n /** Source object to read from (e.g. dataset or plain record). */\r\n record: Record<string, any>\r\n\r\n /** Key to look up (without `\"data-\"` prefix). */\r\n name: string\r\n\r\n /** Fallback value if both keys are missing. */\r\n fallback?: any\r\n}\r\n\r\n/**\r\n * Retrieves a value from an object or dataset-like structure.\r\n * Tries `record[name]` first, then `record[\"data-\" + name]`, or returns fallback.\r\n */\r\nexport default class RecordAttributeTool implements IStringTool<RecordAttributeInput, any> {\r\n /**\r\n * @returns Value from the record or fallback.\r\n */\r\n process({ record, name, fallback = null }: RecordAttributeInput): any {\r\n return (\r\n record[name] ??\r\n record[`data-${name}`] ??\r\n fallback\r\n )\r\n }\r\n}\r\n","import { IStringTool } from \"../core/IStringTool\"\r\n\r\n/**\r\n * Input for removing transform effects from an element's bounding box.\r\n */\r\ninterface TransformNullifyInput {\r\n /** The DOM element whose CSS transform should be nullified. */\r\n element: HTMLElement\r\n}\r\n\r\n/**\r\n * Output with corrected bounding box values.\r\n */\r\ninterface TransformNullifyOutput {\r\n /** Top position without transform effects. */\r\n top: number\r\n\r\n /** Left position without transform effects. */\r\n left: number\r\n\r\n /** Width without transform scaling. */\r\n width: number\r\n\r\n /** Height without transform scaling. */\r\n height: number\r\n}\r\n\r\n/**\r\n * Computes the true bounding box of a DOM element,\r\n * nullifying CSS `transform: matrix(...)` effects.\r\n */\r\nexport default class TransformNullifyTool\r\n implements IStringTool<TransformNullifyInput, TransformNullifyOutput>\r\n{\r\n /**\r\n * @returns Element position and size without transform influence.\r\n */\r\n process({ element }: TransformNullifyInput): TransformNullifyOutput {\r\n const rect = element.getBoundingClientRect()\r\n const matrix = getComputedStyle(element).transform\r\n\r\n const values = matrix\r\n .match(/-?[\\d.]+/g)\r\n ?.map(parseFloat) ?? []\r\n\r\n if (values.length === 6) {\r\n const [a, b, c, d, e, f] = values\r\n const det = a * d - b * c\r\n\r\n return {\r\n width: rect.width / (a || 1),\r\n height: rect.height / (d || 1),\r\n left: (rect.left * d - rect.top * c + c * f - e * d) / det,\r\n top: (-rect.left * b + rect.top * a + e * b - a * f) / det,\r\n }\r\n }\r\n\r\n return rect\r\n }\r\n}\r\n","import { IStringTool } from \"../core/IStringTool\"\r\nimport TransformNullifyTool from \"./TransformNullifyTool\"\r\n\r\n/**\r\n * Input for calculating the position of an element relative to a container.\r\n */\r\ninterface RelativePositionInput {\r\n /** The DOM element whose position should be calculated. */\r\n element: HTMLElement\r\n\r\n /** Optional container to measure against. Defaults to `document.body`. */\r\n container?: HTMLElement\r\n}\r\n\r\n/**\r\n * Output: relative position in pixels.\r\n */\r\ninterface RelativePositionOutput {\r\n /** Distance from the top of the container. */\r\n top: number\r\n\r\n /** Distance from the left of the container. */\r\n left: number\r\n}\r\n\r\n/**\r\n * Calculates an element's position relative to a container.\r\n * Uses `TransformNullifyTool` to account for CSS transforms.\r\n */\r\nexport default class RelativePositionTool\r\n implements IStringTool<RelativePositionInput, RelativePositionOutput>\r\n{\r\n constructor(\r\n /** Optional tool for CSS transform-neutral measurements. */\r\n private transformTool = new TransformNullifyTool()\r\n ) {}\r\n\r\n /**\r\n * @returns Relative top/left position of element within container.\r\n */\r\n process({ element, container = document.body }: RelativePositionInput): RelativePositionOutput {\r\n let containerRect: DOMRect\r\n try {\r\n containerRect = container.getBoundingClientRect()\r\n } catch {\r\n containerRect = document.body.getBoundingClientRect()\r\n }\r\n\r\n const elRect = this.transformTool.process({ element })\r\n\r\n return {\r\n top: elRect.top - containerRect.top,\r\n left: elRect.left - containerRect.left,\r\n }\r\n }\r\n}\r\n","import { IStringTool } from \"../core/IStringTool\"\r\n\r\ninterface LerpInput {\r\n /** Starting value of the interpolation. */\r\n from: number\r\n\r\n /** Target value to interpolate towards. */\r\n to: number\r\n\r\n /** Interpolation progress between 0 (start) and 1 (end). */\r\n progress: number\r\n}\r\n\r\nexport default class LerpTool implements IStringTool<LerpInput, number> {\r\n /**\r\n * Calculates the linear interpolation between two values.\r\n * @returns Interpolated value.\r\n */\r\n process({ from, to, progress }: LerpInput): number {\r\n return (to - from) * progress\r\n }\r\n}\r\n\r\n","import { IStringTool } from \"../core/IStringTool\"\r\n\r\n/**\r\n * Input for parsing unit-based strings into numeric pixel values.\r\n */\r\ninterface UnitParserInput {\r\n /** Unit string, e.g. `\"20px\"`, `\"50%\"`, `\"1.5rem\"`, or `\"selfHeight\"` */\r\n value: string\r\n\r\n /** DOM element used for `\"selfHeight\"` calculation */\r\n element: HTMLElement\r\n\r\n /** Viewport height in pixels (for percentage conversion) */\r\n viewportHeight: number\r\n\r\n /** Root font size in pixels (for rem conversion) */\r\n baseRem: number\r\n}\r\n\r\n/**\r\n * Converts unit-based strings to numeric pixel values.\r\n * Supports `px`, `%`, `rem`, and `\"selfHeight\"` keyword. Handles negatives.\r\n */\r\nexport default class UnitParserTool implements IStringTool<UnitParserInput, number> {\r\n /**\r\n * @returns Numeric value in pixels (positive or negative).\r\n */\r\n process({ value, element, viewportHeight, baseRem }: UnitParserInput): number {\r\n const isNegative = value.startsWith(\"-\")\r\n if (isNegative) value = value.slice(1)\r\n\r\n let result = 0\r\n\r\n if (value === \"selfHeight\") {\r\n result = element.offsetHeight\r\n } else if (value.endsWith(\"px\")) {\r\n result = parseFloat(value)\r\n } else if (value.endsWith(\"%\")) {\r\n result = (parseFloat(value) / 100) * viewportHeight\r\n } else if (value.endsWith(\"rem\")) {\r\n result = parseFloat(value) * baseRem\r\n }\r\n\r\n return isNegative ? -result : result\r\n }\r\n}\r\n","import { IStringTool } from \"../core/IStringTool\"\r\n\r\n/**\r\n * Input for adaptive lerp factor calculation.\r\n * Maps a speed-like value to a lerp factor, where:\r\n * - lower speed ⇒ slower smoothing (higher lerp factor)\r\n * - higher speed ⇒ faster response (lower lerp factor)\r\n */\r\ninterface AdaptiveLerpInput {\r\n /** Current value (e.g., speed or delta). */\r\n value: number\r\n\r\n /** Minimum input threshold (default: 0.1) */\r\n inMin?: number\r\n\r\n /** Maximum input threshold (default: 1.0) */\r\n inMax?: number\r\n\r\n /** Output when input is at minimum (default: 0.65) */\r\n outMax?: number\r\n\r\n /** Output when input is at maximum (default: 0.05) */\r\n outMin?: number\r\n}\r\n\r\n/**\r\n * Converts a numeric input (like velocity) into an adaptive lerp factor.\r\n * Useful for scroll or speed-based smoothing effects.\r\n */\r\nexport default class AdaptiveLerpTool implements IStringTool<AdaptiveLerpInput, number> {\r\n /**\r\n * @returns A remapped lerp factor from `outMax` to `outMin`.\r\n */\r\n process({\r\n value,\r\n inMin = 0.1,\r\n inMax = 1.0,\r\n outMin = 0.05,\r\n outMax = 0.65\r\n }: AdaptiveLerpInput): number {\r\n if (value < inMin) return outMax\r\n if (value > 1.0) value = 1.0\r\n\r\n if (value <= inMax) {\r\n const t = (value - inMin) / (inMax - inMin)\r\n return outMax - t * (outMax - outMin)\r\n }\r\n\r\n return outMin\r\n }\r\n}\r\n","import { IStringTool } from \"../core/IStringTool\"\r\n\r\n/**\r\n * Input for origin parser.\r\n * Supports static values or `random(...)` expressions.\r\n */\r\ninterface OriginInput {\r\n /** Raw origin string, e.g. `'center'` or `'random(top, bottom)'`. */\r\n value: string\r\n}\r\n\r\n/**\r\n * Tool that parses origin strings.\r\n * Allows static values like `'center'`, or expressions like `'random(...)'` to select one randomly.\r\n */\r\nexport default class OriginParserTool implements IStringTool<OriginInput, string> {\r\n /**\r\n * @returns Parsed string value (static or randomly chosen).\r\n */\r\n process({ value }: OriginInput): string {\r\n const raw = value.trim()\r\n\r\n if (raw.startsWith(\"random(\") && raw.endsWith(\")\")) {\r\n const options = raw\r\n .slice(7, -1)\r\n .split(\",\")\r\n .map((s) => s.trim())\r\n .filter(Boolean)\r\n\r\n const index = Math.floor(Math.random() * options.length)\r\n return options[index]\r\n }\r\n\r\n return raw\r\n }\r\n}\r\n","import { IStringTool } from \"../core/IStringTool\"\r\nimport { StringColor } from \"../models/color/StringColor\"\r\n\r\n/**\r\n * Input for parsing color strings into RGBA format.\r\n */\r\ninterface ColorParserInput {\r\n /** Color string in hex, rgb[a], or hsl[a] format. */\r\n value: string\r\n}\r\n\r\n/**\r\n * Parses a CSS color string (`#fff`, `rgb(...)`, `hsl(...)`, etc.)\r\n * into an object with `r`, `g`, `b`, `a` values.\r\n */\r\nexport default class ColorParserTool\r\n implements IStringTool<ColorParserInput, StringColor>\r\n{\r\n /**\r\n * @returns RGBA object parsed from color string.\r\n */\r\n process({ value }: ColorParserInput): StringColor {\r\n const str = value.trim().toLowerCase()\r\n\r\n // --- HEX ---\r\n if (str.startsWith(\"#\")) {\r\n let hex = str.slice(1)\r\n\r\n if (hex.length === 3) {\r\n hex = hex.split(\"\").map((ch) => ch + ch).join(\"\")\r\n }\r\n\r\n const r = parseInt(hex.slice(0, 2), 16)\r\n const g = parseInt(hex.slice(2, 4), 16)\r\n const b = parseInt(hex.slice(4, 6), 16)\r\n const a = hex.length === 8 ? parseInt(hex.slice(6, 8), 16) / 255 : 1\r\n\r\n return { r, g, b, a }\r\n }\r\n\r\n // --- RGB / RGBA ---\r\n const rgbMatch = str.match(/rgba?\\(([^)]+)\\)/)\r\n if (rgbMatch) {\r\n const [r, g, b, a = 1] = rgbMatch[1]\r\n .split(\",\")\r\n .map((v) => parseFloat(v.trim()))\r\n\r\n return { r, g, b, a }\r\n }\r\n\r\n // --- HSL / HSLA ---\r\n const hslMatch = str.match(/hsla?\\(([^)]+)\\)/)\r\n if (hslMatch) {\r\n const [h, s, l, a = \"1\"] = hslMatch[1].split(\",\").map((v) => v.trim())\r\n const [r, g, b] = this.hslToRgb(parseFloat(h), parseFloat(s), parseFloat(l))\r\n return { r, g, b, a: parseFloat(a) }\r\n }\r\n\r\n // fallback: transparent\r\n return { r: 0, g: 0, b: 0, a: 0 }\r\n }\r\n\r\n private hslToRgb(h: number, s: string | number, l: string | number): [number, number, number] {\r\n h = h / 360\r\n s = parseFloat(s.toString()) / 100\r\n l = parseFloat(l.toString()) / 100\r\n\r\n const hue2rgb = (p: number, q: number, t: number) => {\r\n if (t < 0) t += 1\r\n if (t > 1) t -= 1\r\n if (t < 1 / 6) return p + (q - p) * 6 * t\r\n if (t < 1 / 2) return q\r\n if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6\r\n return p\r\n }\r\n\r\n const q = l < 0.5 ? l * (1 + s) : l + s - l * s\r\n const p = 2 * l - q\r\n\r\n const r = Math.round(hue2rgb(p, q, h + 1 / 3) * 255)\r\n const g = Math.round(hue2rgb(p, q, h) * 255)\r\n const b = Math.round(hue2rgb(p, q, h - 1 / 3) * 255)\r\n\r\n return [r, g, b]\r\n }\r\n}\r\n","import { IStringTool } from \"../core/IStringTool\"\r\n\r\ntype RuleType = \"required\" | \"email\" | \"minLength\" | \"maxLength\"\r\n\r\nexport type ValidationErrorCode =\r\n | \"required\"\r\n | \"invalid-email\"\r\n | \"too-short\"\r\n | \"too-long\"\r\n\r\nexport type ValidationRule =\r\n | \"required\"\r\n | \"email\"\r\n | { type: \"minLength\"; value: number }\r\n | { type: \"maxLength\"; value: number }\r\n\r\ninterface ValidationInput {\r\n /** Value to validate. */\r\n value: string\r\n\r\n /** List of rules to apply. */\r\n rules: ValidationRule[]\r\n\r\n /**\r\n * Optional message map: key = errorCode, value = string or function returning a message.\r\n */\r\n messages?: Partial<\r\n Record<\r\n ValidationErrorCode,\r\n string | ((args: { value: string; rule: ValidationRule }) => string)\r\n >\r\n >\r\n}\r\n\r\nexport interface ValidationOutput {\r\n /** `true` if valid, `false` if error found. */\r\n valid: boolean\r\n\r\n /** One of the known error codes (or null if no error). */\r\n error: ValidationErrorCode | null\r\n\r\n /** Final message (either default or user-defined). */\r\n message: string | null\r\n}\r\n\r\n/**\r\n * Tool for validating strings using rules like `required`, `minLength`, etc.\r\n * Allows custom error messages (as string or generator function).\r\n */\r\nexport default class ValidationTool implements IStringTool<ValidationInput, ValidationOutput> {\r\n /**\r\n * Validates input value and returns error code + message.\r\n */\r\n process({ value, rules, messages = {} }: ValidationInput): ValidationOutput {\r\n for (const rule of rules) {\r\n let code: ValidationErrorCode | null = null\r\n\r\n if (rule === \"required\" && value.trim() === \"\") {\r\n code = \"required\"\r\n } else if (rule === \"email\" && !/^\\S+@\\S+\\.\\S+$/.test(value)) {\r\n code = \"invalid-email\"\r\n } else if (typeof rule === \"object\") {\r\n if (rule.type === \"minLength\" && value.length < rule.value) code = \"too-short\"\r\n if (rule.type === \"maxLength\" && value.length > rule.value) code = \"too-long\"\r\n }\r\n\r\n if (code) {\r\n const raw = messages[code]\r\n const message =\r\n typeof raw === \"function\" ? raw({ value, rule }) : raw ?? this.defaultMessage(code, rule)\r\n return { valid: false, error: code, message }\r\n }\r\n }\r\n\r\n return { valid: true, error: null, message: null }\r\n }\r\n\r\n private defaultMessage(code: ValidationErrorCode, rule?: ValidationRule): string {\r\n switch (code) {\r\n case \"required\":\r\n return \"This field is required.\"\r\n case \"invalid-email\":\r\n return \"Please enter a valid email.\"\r\n case \"too-short\":\r\n return `Too short${typeof rule === \"object\" && \"value\" in rule ? ` (min ${rule.value})` : \"\"}.`\r\n case \"too-long\":\r\n return `Too long${typeof rule === \"object\" && \"value\" in rule ? ` (max ${rule.value})` : \"\"}.`\r\n }\r\n }\r\n}\r\n","import { IStringTool } from \"../core/IStringTool\"\r\n\r\n/**\r\n * Input parameters for EasingFunctionTool.\r\n */\r\ninterface EasingFunctionInput {\r\n /**\r\n * The easing string.\r\n * Can be: 'linear', 'ease', 'ease-in', 'ease-out', 'ease-in-out', or 'cubic-bezier(...)'\r\n */\r\n easing: string\r\n}\r\n\r\n/**\r\n * Output of the easing function: receives t in [0,1] and returns eased value.\r\n */\r\nexport type EasingFunctionOutput = (t: number) => number\r\n\r\n/**\r\n * Tool for parsing easing strings into easing functions.\r\n * Supports standard keywords (`ease-in`, `ease-out`, etc.) and `cubic-bezier(...)` expressions.\r\n */\r\nexport default class EasingFunctionTool implements IStringTool<EasingFunctionInput, EasingFunctionOutput> {\r\n private namedCurves: Record<string, [number, number, number, number]> = {\r\n \"linear\": [0, 0, 1, 1],\r\n \"ease\": [0.25, 0.1, 0.25, 1],\r\n \"ease-in\": [0.42, 0, 1, 1],\r\n \"ease-out\": [0, 0, 0.58, 1],\r\n \"ease-in-out\": [0.42, 0, 0.58, 1],\r\n }\r\n\r\n /**\r\n * Parses an easing string and returns a corresponding easing function.\r\n */\r\n process({ easing }: EasingFunctionInput): EasingFunctionOutput {\r\n const def = easing.trim()\r\n\r\n if (this.namedCurves[def]) {\r\n return this.cubicBezier(...this.namedCurves[def])\r\n }\r\n\r\n const match = def.match(/^cubic-bezier\\s*\\(\\s*([-+]?\\d*\\.?\\d+)\\s*,\\s*([-+]?\\d*\\.?\\d+)\\s*,\\s*([-+]?\\d*\\.?\\d+)\\s*,\\s*([-+]?\\d*\\.?\\d+)\\s*\\)$/);\r\n\r\n if (match) {\r\n const [x1, y1, x2, y2] = match.slice(1).map(Number)\r\n return this.cubicBezier(x1, y1, x2, y2)\r\n }\r\n\r\n // fallback: linear\r\n return (t: number) => t\r\n }\r\n\r\n /**\r\n * Generates a cubic-bezier easing function.\r\n * Ported from https://github.com/gre/bezier-easing (MIT)\r\n */\r\n private cubicBezier(x1: number, y1: number, x2: number, y2: number): EasingFunctionOutput {\r\n const cx = 3 * x1\r\n const bx = 3 * (x2 - x1) - cx\r\n const ax = 1 - cx - bx\r\n\r\n const cy = 3 * y1\r\n const by = 3 * (y2 - y1) - cy\r\n const ay = 1 - cy - by\r\n\r\n function sampleCurveX(t: number) {\r\n return ((ax * t + bx) * t + cx) * t\r\n }\r\n\r\n function sampleCurveY(t: number) {\r\n return ((ay * t + by) * t + cy) * t\r\n }\r\n\r\n function sampleCurveDerivativeX(t: number) {\r\n return (3 * ax * t + 2 * bx) * t + cx\r\n }\r\n\r\n function solveCurveX(x: number, epsilon = 1e-5) {\r\n let t0, t1, t2 = x, x2, d2, i\r\n\r\n // Newton-Raphson method\r\n for (i = 0; i < 8; i++) {\r\n x2 = sampleCurveX(t2) - x\r\n if (Math.abs(x2) < epsilon) return t2\r\n d2 = sampleCurveDerivativeX(t2)\r\n if (Math.abs(d2) < 1e-6) break\r\n t2 = t2 - x2 / d2\r\n }\r\n\r\n // Bisection fallback\r\n t0 = 0\r\n t1 = 1\r\n t2 = x\r\n\r\n while (t0 < t1) {\r\n x2 = sampleCurveX(t2) - x\r\n if (Math.abs(x2) < epsilon) return t2\r\n if (x2 > 0) t1 = t2\r\n else t0 = t2\r\n t2 = (t1 + t0) / 2\r\n }\r\n\r\n return t2\r\n }\r\n\r\n return function (x: number) {\r\n return sampleCurveY(solveCurveX(x))\r\n }\r\n }\r\n}\r\n","import { IStringTool } from \"../core/IStringTool\"\r\n\r\n/**\r\n * Input parameters for calculating magnetic pull factor.\r\n */\r\ninterface MagneticPullInput {\r\n /** Distance between pointer and element center (px). */\r\n distance: number\r\n\r\n /** Max distance within which magnetic pull is active. */\r\n radius: number\r\n\r\n /** Strength of the magnetic pull (0–1 recommended). */\r\n strength: number\r\n}\r\n\r\n/**\r\n * Output: factor to multiply by direction vector (dx/dy) to get magnetic offset.\r\n */\r\ntype MagneticPullOutput = number\r\n\r\n/**\r\n * Tool for calculating magnetic attraction based on distance to element.\r\n * Returns a scalar value (0..strength) depending on proximity.\r\n */\r\nexport default class MagneticPullTool implements IStringTool<MagneticPullInput, MagneticPullOutput> {\r\n /**\r\n * Returns a pull factor based on distance to target within a radius.\r\n * @param input - Magnetic pull parameters.\r\n * @returns A multiplier (typically < 1) to apply to dx/dy.\r\n */\r\n process({ distance, radius, strength }: MagneticPullInput): number {\r\n if (distance >= radius) return 0\r\n const proximity = (radius - distance) / radius // 1 when close, 0 at edge\r\n return strength * proximity\r\n }\r\n}\r\n","import { IStringTool } from \"../core/IStringTool\"\r\nimport { StringColor } from \"../models/color/StringColor\"\r\n\r\n/**\r\n * Input parameters for `LerpColorTool`.\r\n */\r\ninterface LerpColorInput {\r\n /**\r\n * Starting color as an object `{ r, g, b, a }` where each value is in the range `0–1`.\r\n */\r\n from: StringColor\r\n\r\n /**\r\n * Target color as an object `{ r, g, b, a }` where each value is in the range `0–1`.\r\n */\r\n to: StringColor\r\n\r\n /**\r\n * Interpolation progress from `0` (start) to `1` (end).\r\n */\r\n progress: number\r\n}\r\n\r\n/**\r\n * Tool for linearly interpolating between two RGBA colors using `StringColor` format.\r\n * Each channel (`r`, `g`, `b`, `a`) is interpolated independently.\r\n * Returns a new `StringColor` with the interpolated values.\r\n */\r\nexport default class LerpColorTool implements IStringTool<LerpColorInput, StringColor> {\r\n /**\r\n * Performs linear interpolation between two `StringColor` values.\r\n *\r\n * @param input.from - The starting color `{ r, g, b, a }`.\r\n * @param input.to - The target color `{ r, g, b, a }`.\r\n * @param input.progress - A number from `0` to `1` indicating interpolation progress.\r\n * @returns Interpolated color as a new `StringColor`.\r\n */\r\n process({ from, to, progress }: LerpColorInput): StringColor {\r\n return {\r\n r: from.r + (to.r - from.r) * progress,\r\n g: from.g + (to.g - from.g) * progress,\r\n b: from.b + (to.b - from.b) * progress,\r\n a: from.a + (to.a - from.a) * progress,\r\n }\r\n }\r\n}\r\n","import { IStringTool } from \"../core/IStringTool\"\r\nimport { StringVector } from \"../models/vector/StringVector\"\r\n\r\n/**\r\n * Input parameters for LerpVector2Tool.\r\n */\r\ninterface LerpVector2Input {\r\n /**\r\n * Starting vector value `{ x, y }`.\r\n */\r\n from: StringVector\r\n\r\n /**\r\n * Target vector value `{ x, y }`.\r\n */\r\n to: StringVector\r\n\r\n /**\r\n * Interpolation progress from `0` (start) to `1` (end).\r\n */\r\n progress: number\r\n}\r\n\r\n/**\r\n * Tool for linearly interpolating between two 2D vectors.\r\n * Useful for cursor smoothing, UI element animations, and motion blending.\r\n */\r\nexport default class LerpVector2Tool implements IStringTool<LerpVector2Input, StringVector> {\r\n /**\r\n * Calculates the interpolated vector between `from` and `to`.\r\n *\r\n * @param input.from - The starting vector `{ x, y }`.\r\n * @param input.to - The target vector `{ x, y }`.\r\n * @param input.progress - Interpolation progress from `0` (start) to `1` (end).\r\n * @returns Interpolated vector `{ x, y }`.\r\n */\r\n process({ from, to, progress }: LerpVector2Input): { x: number, y: number } {\r\n return {\r\n x: (to.x - from.x) * progress,\r\n y: (to.y - from.y) * progress,\r\n }\r\n }\r\n}\r\n\r\n","import { IStringTool } from \"../core/IStringTool\"; // Переконайтесь, що шлях правильний\r\n\r\n/**\r\n * Input for parsing the transform string to extract scale.\r\n */\r\ninterface TransformParserInput {\r\n /** CSS transform string (e.g., \"matrix(0.5, 0, 0, 0.5, 10, 20)\", \"scale(0.5)\", \"none\"). */\r\n value: string;\r\n}\r\n\r\n/**\r\n * Parses a CSS transform string to extract the primary scale factor.\r\n * Assumes uniform scale or extracts the X-axis scale factor from matrix/scale functions.\r\n */\r\nexport default class TransformScaleParserTool\r\n implements IStringTool<TransformParserInput, number> // Output is a number\r\n{\r\n /**\r\n * Processes the transform string and extracts the scale factor.\r\n * @returns Numeric scale factor (defaults to 1 if no scale transform is found or parsing fails).\r\n */\r\n process({ value }: TransformParserInput): number {\r\n const defaultScale = 1;\r\n const str = value?.trim();\r\n\r\n if (!str || str === 'none') {\r\n return defaultScale;\r\n }\r\n try {\r\n if (str.startsWith('matrix(')) {\r\n const matrixValues = str.match(/matrix\\(([^)]+)\\)/);\r\n if (matrixValues && matrixValues[1]) {\r\n const matrixNumbers = matrixValues[1].split(',').map(s => parseFloat(s.trim()));\r\n if (matrixNumbers.length >= 1 && !isNaN(matrixNumbers[0])) {\r\n return matrixNumbers[0];\r\n }\r\n }\r\n }\r\n\r\n if (str.startsWith('scale(')) {\r\n const scaleValue = str.match(/scale\\(([^)]+)\\)/);\r\n if (scaleValue && scaleValue[1]) {\r\n const scaleNumbers = scaleValue[1].split(',').map(s => parseFloat(s.trim()));\r\n if (scaleNumbers.length >= 1 && !isNaN(scaleNumbers[0])) {\r\n return scaleNumbers[0];\r\n }\r\n }\r\n }\r\n\r\n if (str.startsWith('scaleX(')) {\r\n const scaleXValue = str.match(/scaleX\\(([^)]+)\\)/);\r\n if (scaleXValue && scaleXValue[1]) {\r\n const scaleNumber = parseFloat(scaleXValue[1].trim());\r\n if (!isNaN(scaleNumber)) {\r\n return scaleNumber;\r\n }\r\n }\r\n }\r\n\r\n if (str.startsWith('scale3d(')) {\r\n const scale3dValue = str.match(/scale3d\\(([^)]+)\\)/);\r\n if (scale3dValue && scale3dValue[1]) {\r\n const scaleNumbers = scale3dValue[1].split(',').map(s => parseFloat(s.trim()));\r\n if (scaleNumbers.length >= 1 && !isNaN(scaleNumbers[0])) {\r\n return scaleNumbers[0]; // Повертаємо sx\r\n }\r\n }\r\n }\r\n\r\n if (str.startsWith('matrix3d(')) {\r\n const matrix3dValues = str.match(/matrix3d\\(([^)]+)\\)/);\r\n if (matrix3dValues && matrix3dValues[1]) {\r\n const matrixNumbers = matrix3dValues[1].split(',').map(s => parseFloat(s.trim()));\r\n if (matrixNumbers.length >= 1 && !isNaN(matrixNumbers[0])) {\r\n return matrixNumbers[0];\r\n }\r\n }\r\n }\r\n\r\n } catch (error) {\r\n console.error(`Error parsing transform string \"${str}\":`, error);\r\n return defaultScale;\r\n }\r\n\r\n return defaultScale;\r\n }\r\n}\r\n","import { IStringTool } from \"../core/IStringTool\";\r\nimport { CalculatedValue } from \"../models/text/CalculatedValue\";\r\nimport { CharIndexerInput } from \"../models/text/CharIndexerInput\";\r\nimport { ISplitOptionItem } from \"../models/text/ISplitOptionItem\";\r\nimport { ProcessedChar } from \"../models/text/ProcessedChar\";\r\n\r\n/**\r\n * Tool to process words split by layout, breaking them into characters\r\n * and assigning relevant indices (global, line, word) for each character.\r\n * Calculates index values based on ISplitOptions for characters ('char', 'charLine', 'charWord').\r\n * Produces an array of ProcessedChar objects.\r\n */\r\nexport class CharIndexerTool\r\n implements IStringTool<CharIndexerInput, ProcessedChar[]>\r\n{\r\n /**\r\n * Iterates through processed words, splits them into characters, assigns\r\n * global, line, and word character indices, and calculates index values\r\n * based on the provided character options ('char', 'charLine', 'charWord').\r\n *\r\n * @param input.processedWords - Array of ProcessedWord objects from WordIndexerTool.\r\n * @param input.lines - Array of LayoutLine objects (needed for calculating total characters per line).\r\n * @param input.options - The relevant ISplitOptions ('char', 'charLine', 'charWord').\r\n * @param input.totalChars - Total number of non-whitespace characters in the original text.\r\n * @returns An array of ProcessedChar objects, ready for DOM building/styling.\r\n */\r\n process({\r\n processedWords,\r\n lines,\r\n options,\r\n totalChars,\r\n }: CharIndexerInput): ProcessedChar[] {\r\n const processedChars: ProcessedChar[] = [];\r\n let globalCharIndex = 0; // Global character counter (non-whitespace)\r\n\r\n // Pre-calculate total characters per line for efficiency\r\n const totalLineCharsMap = new Map<number, number>();\r\n lines.forEach((line, lineIndex) => {\r\n const totalCharsInLine = line.words.reduce(\r\n (sum, word) => sum + word.text.length,\r\n 0\r\n );\r\n totalLineCharsMap.set(lineIndex, totalCharsInLine);\r\n });\r\n\r\n let currentLineCharIndex = 0; // Character index within the current line\r\n let previousLineIndex = -1; // Tracks when we move to a new line\r\n\r\n // Iterate through the processed words provided as input\r\n processedWords.forEach((pWord) => {\r\n const wordText = pWord.text;\r\n const parentLineIndex = pWord.lineIndex;\r\n const wordLength = wordText.length; // Number of characters in the current word\r\n const totalCharsInCurrentLine =\r\n totalLineCharsMap.get(parentLineIndex) || 0; // Get pre-calculated total\r\n\r\n // Reset line character index when moving to a new line\r\n if (parentLineIndex !== previousLineIndex) {\r\n currentLineCharIndex = 0;\r\n previousLineIndex = parentLineIndex;\r\n }\r\n\r\n const chars = Array.from(wordText); // Split word into characters (handles Unicode correctly)\r\n\r\n // Iterate through each character of the word\r\n chars.forEach((char, wordCharIndex) => {\r\n const calculatedValues: CalculatedValue[] = []; // Use the unified CalculatedValue\r\n\r\n // 1. Calculate for 'char' options (global context)\r\n if (options.char) {\r\n options.char.forEach((optDef) => {\r\n // Use globalCharIndex as primary, totalChars as parentLength\r\n const value = this.calculateIndex(\r\n optDef,\r\n globalCharIndex,\r\n wordCharIndex,\r\n totalChars\r\n );\r\n // Create CalculatedValue object\r\n calculatedValues.push({ value, type: \"char\", align: optDef.align });\r\n });\r\n }\r\n\r\n // 2. Calculate for 'charLine' options (line context)\r\n if (options.charLine) {\r\n options.charLine.forEach((optDef) => {\r\n // Use currentLineCharIndex as primary, totalCharsInCurrentLine as parentLength\r\n const value = this.calculateIndex(\r\n optDef,\r\n currentLineCharIndex,\r\n wordCharIndex,\r\n totalCharsInCurrentLine\r\n );\r\n // Create CalculatedValue object\r\n calculatedValues.push({\r\n value,\r\n type: \"charLine\",\r\n align: optDef.align,\r\n });\r\n });\r\n }\r\n\r\n // 3. Calculate for 'charWord' options (word context)\r\n if (options.charWord) {\r\n options.charWord.forEach((optDef) => {\r\n // Use wordCharIndex as primary, wordLength as parentLength\r\n const value = this.calculateIndex(\r\n optDef,\r\n wordCharIndex,\r\n wordCharIndex,\r\n wordLength\r\n );\r\n // Create CalculatedValue object\r\n calculatedValues.push({\r\n value,\r\n type: \"charWord\",\r\n align: optDef.align,\r\n });\r\n });\r\n }\r\n\r\n // Create the ProcessedChar object\r\n processedChars.push({\r\n text: char,\r\n globalCharIndex: globalCharIndex,\r\n lineCharIndex: currentLineCharIndex,\r\n wordCharIndex: wordCharIndex,\r\n parentGlobalWordIndex: pWord.globalIndex, // Carry over parent info\r\n parentLineIndex: pWord.lineIndex,\r\n parentWordIndexInLine: pWord.wordIndexInLine,\r\n calculatedValues: calculatedValues, // Store the array of CalculatedValue\r\n });\r\n\r\n // Increment character counters for the next iteration\r\n globalCharIndex++;\r\n currentLineCharIndex++;\r\n }); // end character loop\r\n }); // end word loop\r\n\r\n return processedChars;\r\n }\r\n\r\n /**\r\n * Calculates the final numerical index value based on alignment options, context indices, and parent length.\r\n * (Identical helper function as in WordIndexerTool - could be extracted to a common utility).\r\n *\r\n * @param option - The specific option item definition ({ align, random, abs }).\r\n * @param primaryIndex - The main index used for calculation (global, line, or word char index).\r\n * @param localIndex - The secondary index (e.g., index within word).\r\n * @param parentLength - The total count in the relevant context (total chars, line chars, or word chars).\r\n * @returns The calculated numerical index value.\r\n */\r\n private calculateIndex(\r\n option: ISplitOptionItem,\r\n primaryIndex: number,\r\n localIndex: number,\r\n parentLength: number\r\n ): number {\r\n let index = primaryIndex;\r\n\r\n if (option.align === \"random\") {\r\n const min = option.random?.min ?? 0;\r\n const max =\r\n option.random?.max ?? (parentLength > 0 ? parentLength - 1 : 0);\r\n const effectiveMin = Math.min(min, max);\r\n const effectiveMax = Math.max(min, max);\r\n index =\r\n Math.floor(Math.random() * (effectiveMax - effectiveMin + 1)) +\r\n effectiveMin;\r\n } else if (option.align === \"end\") {\r\n index = (parentLength > 0 ? parentLength - 1 : 0) - primaryIndex;\r\n } else if (option.align === \"center\") {\r\n index = primaryIndex - Math.floor(parentLength / 2);\r\n }\r\n\r\n if (option.abs) {\r\n index = Math.abs(index);\r\n }\r\n return index;\r\n }\r\n}\r\n","import { IStringTool } from \"../core/IStringTool\";\r\nimport { LayoutLine } from \"../models/text/LayoutLine\";\r\nimport { LayoutSplitInput } from \"../models/text/LayoutSplitInput\";\r\n\r\n/**\r\n * Tool to split a text string into structured lines and words based on how\r\n * the text would visually wrap within a given target HTML element.\r\n * This simulates browser rendering by measuring word widths.\r\n * Returns an array of LayoutLine objects.\r\n */\r\nexport class LayoutLineSplitterTool\r\n implements IStringTool<LayoutSplitInput, LayoutLine[]>\r\n{\r\n /**\r\n * Processes the input text and splits it into lines containing words,\r\n * simulating word wrapping within the boundaries of the targetElement.\r\n *\r\n * @param input.text - The text content to split.\r\n * @param input.targetElement - The HTMLElement used as a reference for width and font styles.\r\n * @returns An array of LayoutLine objects, each containing the line's text and an array of its words.\r\n * Returns an empty array on error or invalid input.\r\n */\r\n process({ text, targetElement }: LayoutSplitInput): LayoutLine[] {\r\n if (!text || !targetElement || targetElement.offsetWidth <= 0) {\r\n console.warn(\r\n \"LayoutLineSplitterTool: Invalid input or target element has zero width.\"\r\n );\r\n return [];\r\n }\r\n\r\n const cleanedText = this.decodeHtmlEntity(text);\r\n // Split by whitespace and filter out empty strings that might result from multiple spaces\r\n const words = cleanedText\r\n .trim()\r\n .split(/\\s+/)\r\n .filter((word) => word.length > 0);\r\n\r\n if (words.length === 0) {\r\n return []; // No words to process\r\n }\r\n\r\n // Create and configure the temporary span for measurements\r\n const tempSpan = document.createElement(\"span\");\r\n const compStyles = window.getComputedStyle(targetElement);\r\n // Copy relevant styles that affect width\r\n tempSpan.style.fontFamily = compStyles.fontFamily;\r\n tempSpan.style.fontSize = compStyles.fontSize;\r\n tempSpan.style.fontWeight = compStyles.fontWeight;\r\n tempSpan.style.letterSpacing = compStyles.letterSpacing;\r\n tempSpan.style.textTransform = compStyles.textTransform;\r\n tempSpan.style.wordSpacing = compStyles.wordSpacing;\r\n // Ensure the measurement span itself doesn't wrap and is hidden\r\n tempSpan.style.whiteSpace = \"nowrap\";\r\n tempSpan.style.visibility = \"hidden\";\r\n tempSpan.style.position = \"absolute\"; // Prevent affecting layout\r\n tempSpan.style.top = \"-9999px\";\r\n tempSpan.style.left = \"-9999px\";\r\n document.body.appendChild(tempSpan); // Must be in DOM for offsetWidth\r\n\r\n const layoutLines: LayoutLine[] = [];\r\n let currentLineWords: string[] = []; // Accumulates words for the current line\r\n let currentLineWidth = 0; // Tracks the width of the current line\r\n const spaceWidth = this.measureWidth(\" \", tempSpan); // Measure space width once\r\n const containerWidth = targetElement.offsetWidth; // Target width for wrapping\r\n\r\n try {\r\n words.forEach((word) => {\r\n const wordWidth = this.measureWidth(word, tempSpan);\r\n // Calculate width if this word is added: current width + space (if needed) + word width\r\n const potentialWidth =\r\n currentLineWidth +\r\n (currentLineWords.length > 0 ? spaceWidth : 0) +\r\n wordWidth;\r\n\r\n // Check if the word fits on the current line\r\n if (currentLineWords.length > 0 && potentialWidth > containerWidth) {\r\n // Word doesn't fit: finalize the current line\r\n layoutLines.push({\r\n text: currentLineWords.join(\" \"),\r\n words: currentLineWords.map((w) => ({ text: w })), // Convert word strings to LayoutWord objects\r\n });\r\n // Start a new line with the current word\r\n currentLineWords = [word];\r\n currentLineWidth = wordWidth;\r\n } else {\r\n // Word fits: add it to the current line\r\n currentLineWords.push(word);\r\n // Update the current line width\r\n currentLineWidth =\r\n currentLineWords.length === 1 ? wordWidth : potentialWidth;\r\n }\r\n });\r\n\r\n // Add the last remaining line after the loop finishes\r\n if (currentLineWords.length > 0) {\r\n layoutLines.push({\r\n text: currentLineWords.join(\" \"),\r\n words: currentLineWords.map((w) => ({ text: w })),\r\n });\r\n }\r\n } finally {\r\n // Ensure the temporary span is removed from the DOM\r\n if (tempSpan.parentNode === document.body) {\r\n document.body.removeChild(tempSpan);\r\n }\r\n }\r\n\r\n return layoutLines;\r\n }\r\n\r\n /**\r\n * Measures the width of a given text string using the provided temporary span.\r\n * @param text - The text to measure.\r\n * @param tempSpan - The pre-styled temporary span element used for measurement.\r\n * @returns The width of the text in pixels.\r\n */\r\n private measureWidth(text: string, tempSpan: HTMLSpanElement): number {\r\n tempSpan.textContent = text;\r\n return tempSpan.offsetWidth;\r\n }\r\n\r\n /**\r\n * Decodes basic HTML entities (currently just &amp;).\r\n * Can be expanded if more entities need handling.\r\n * @param str - The string potentially containing HTML entities.\r\n * @returns The string with '&amp;' decoded to '&'.\r\n */\r\n private decodeHtmlEntity(str: string): string {\r\n // Basic decoding, extend as needed\r\n return str.replace(/&amp;/g, \"&\");\r\n }\r\n}\r\n","import { IStringTool } from \"../core/IStringTool\";\r\nimport { CalculatedValue } from \"../models/text/CalculatedValue\";\r\nimport { DomBuilderInput } from \"../models/text/DomBuilderInput\";\r\nimport { ISplitOptions } from \"../models/text/ISplitOptions\";\r\nimport { LayoutLine } from \"../models/text/LayoutLine\"; // Assuming LayoutLine might be needed for line styles\r\nimport { ProcessedChar } from \"../models/text/ProcessedChar\"; // Assuming ProcessedChar structure\r\nimport { ProcessedWord } from \"../models/text/ProcessedWord\"; // Assuming ProcessedWord structure\r\n\r\n/**\r\n * Tool to build the final innerHTML string with nested spans (-s-line, -s-word, -s-char)\r\n * and apply calculated CSS variables based on processed data from indexer tools.\r\n * Implements the IStringTool interface.\r\n */\r\nexport class SplitDomBuilderTool\r\n implements IStringTool<DomBuilderInput, string>\r\n{\r\n /**\r\n * Generates the innerHTML string for the split text by creating nested spans\r\n * (-s-line, -s-word, -s-char) based on options and applying styles from calculated index values.\r\n *\r\n * @param input An object containing layout lines, processed words, processed characters, and the original split options.\r\n * @returns The generated HTML string representing the split content.\r\n */\r\n process({ lines, words, chars, options }: DomBuilderInput): string {\r\n const rootElement = document.createElement(\"div\");\r\n let wordCounter = 0;\r\n let charCounter = 0;\r\n\r\n const needsLineSpans = this.hasLineOptions(options);\r\n const needsWordSpans = this.hasWordOptions(options);\r\n const needsCharSpans = this.hasCharOptions(options);\r\n\r\n lines.forEach((line, lineIndex) => {\r\n // Added lineIndex for potential line style application\r\n const lineContainer = needsLineSpans\r\n ? document.createElement(\"span\")\r\n : rootElement;\r\n if (needsLineSpans) {\r\n lineContainer.classList.add(\"-s-line\");\r\n // TODO: Apply 'line' options if available on line object\r\n // this.applyStyles(lineContainer, line.calculatedValues);\r\n rootElement.appendChild(lineContainer);\r\n }\r\n\r\n const wordsInThisLine = words.slice(\r\n wordCounter,\r\n wordCounter + line.words.length\r\n );\r\n wordCounter += line.words.length;\r\n\r\n wordsInThisLine.forEach((pWord, indexInLine) => {\r\n const currentWordChars = chars.slice(\r\n charCounter,\r\n charCounter + pWord.text.length\r\n );\r\n // Advance charCounter regardless of how chars are added below\r\n charCounter += pWord.text.length;\r\n\r\n if (needsWordSpans) {\r\n // --- Create Word Span ---\r\n const wordSpan = document.createElement(\"span\");\r\n wordSpan.classList.add(\"-s-word\");\r\n this.applyStyles(wordSpan, pWord.calculatedValues);\r\n\r\n if (needsCharSpans && pWord.text.length > 0) {\r\n // Add char spans inside word span\r\n currentWordChars.forEach((pChar) => {\r\n const charSpan = this.createCharSpan(pChar);\r\n wordSpan.appendChild(charSpan);\r\n });\r\n } else if (pWord.text.length > 0) {\r\n // Add word text directly if no char spans needed\r\n wordSpan.appendChild(document.createTextNode(pWord.text));\r\n }\r\n wordSpan.appendChild(document.createTextNode(\"\\u00a0\"));\r\n // Append the completed word span to the line container\r\n lineContainer.appendChild(wordSpan);\r\n } else {\r\n // --- No Word Span Needed ---\r\n if (needsCharSpans && pWord.text.length > 0) {\r\n // Add char spans directly to line container\r\n currentWordChars.forEach((pChar) => {\r\n const charSpan = this.createCharSpan(pChar);\r\n lineContainer.appendChild(charSpan);\r\n });\r\n lineContainer.appendChild(document.createTextNode(\"\\u00a0\"));\r\n } else if (pWord.text.length > 0) {\r\n // Add word text directly to line container\r\n lineContainer.appendChild(document.createTextNode(pWord.text));\r\n }\r\n }\r\n }); // End words loop\r\n }); // End lines loop\r\n\r\n return rootElement.innerHTML;\r\n }\r\n\r\n /**\r\n * Creates and styles a character span.\r\n * @param pChar - The processed character data.\r\n * @returns The styled HTMLSpanElement for the character.\r\n * @private\r\n */\r\n private createCharSpan(pChar: ProcessedChar): HTMLSpanElement {\r\n const charSpan = document.createElement(\"span\");\r\n charSpan.classList.add(\"-s-char\");\r\n // Handle potential whitespace characters if needed, otherwise use textContent\r\n charSpan.textContent = pChar.text; // Use textContent for safety\r\n this.applyStyles(charSpan, pChar.calculatedValues);\r\n return charSpan;\r\n }\r\n\r\n /**\r\n * Checks if any line-level splitting options (line, wordLine, charLine) are present.\r\n * @param options - The ISplitOptions object.\r\n * @returns True if any line-level options exist and have definitions, false otherwise.\r\n * @private\r\n */\r\n private hasLineOptions(options: ISplitOptions): boolean {\r\n return (\r\n (options.line?.length ?? 0) > 0 ||\r\n (options.wordLine?.length ?? 0) > 0 ||\r\n (options.charLine?.length ?? 0) > 0\r\n );\r\n }\r\n\r\n /**\r\n * Checks if any word-level splitting options (word, wordLine) are present.\r\n * @param options - The ISplitOptions object.\r\n * @returns True if any word-level options exist and have definitions, false otherwise.\r\n * @private\r\n */\r\n private hasWordOptions(options: ISplitOptions): boolean {\r\n return (\r\n (options.word?.length ?? 0) > 0 || (options.wordLine?.length ?? 0) > 0\r\n );\r\n }\r\n\r\n /**\r\n * Checks if any character-level splitting options (char, charLine, charWord) are present.\r\n * @param options - The ISplitOptions object.\r\n * @returns True if any character-level options exist and have definitions, false otherwise.\r\n * @private\r\n */\r\n private hasCharOptions(options: ISplitOptions): boolean {\r\n return (\r\n (options.char?.length ?? 0) > 0 ||\r\n (options.charLine?.length ?? 0) > 0 ||\r\n (options.charWord?.length ?? 0) > 0\r\n );\r\n }\r\n\r\n /**\r\n * Applies the pre-calculated index values as CSS custom properties to the element's style.\r\n * @param span - The HTMLElement (line, word, or char span) to apply styles to.\r\n * @param calculatedValues - An array of calculated values from the indexer tool.\r\n * @private\r\n */\r\n private applyStyles(\r\n span: HTMLElement,\r\n calculatedValues: CalculatedValue[]\r\n ): void {\r\n if (calculatedValues) {\r\n calculatedValues.forEach((calcValue) => {\r\n const variableName = this.generateVariableName(\r\n calcValue.type,\r\n calcValue.align\r\n );\r\n span.style.setProperty(variableName, String(calcValue.value));\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * Generates a CSS custom property name based on the split type and alignment.\r\n * @param type - The type of split element ('line', 'word', 'char', etc.).\r\n * @param align - The alignment option ('start', 'center', 'end', 'random').\r\n * @returns The generated CSS variable name string (e.g., '--word-center').\r\n * @private\r\n */\r\n private generateVariableName(type: string, align: string): string {\r\n // This simplified version assumes one variable per type/align combo.\r\n // More complex logic might be needed if multiple definitions require distinct variables.\r\n return `--${type}-${align}`;\r\n }\r\n}\r\n","import { IStringTool } from \"../core/IStringTool\";\r\nimport { CalculatedValue } from \"../models/text/CalculatedValue\";\r\nimport { ISplitOptionItem } from \"../models/text/ISplitOptionItem\";\r\nimport { ProcessedWord } from \"../models/text/ProcessedWord\";\r\nimport { WordIndexerInput } from \"../models/text/WordIndexerInput\";\r\n\r\n/**\r\n * Tool to process layout lines and words, assigning relevant indices\r\n * and calculating index values based on ISplitOptions ('word', 'wordLine').\r\n * Produces an array of ProcessedWord objects.\r\n */\r\nexport class WordIndexerTool\r\n implements IStringTool<WordIndexerInput, ProcessedWord[]>\r\n{\r\n /**\r\n * Iterates through lines and words, assigning global and local indices,\r\n * and calculating index values based on the provided options ('word', 'wordLine').\r\n *\r\n * @param input.lines - Array of LayoutLine objects from LayoutLineSplitterTool.\r\n * @param input.options - The relevant ISplitOptions ('word', 'wordLine').\r\n * @returns An array of ProcessedWord objects, each containing word text, indices,\r\n * and an array of calculated values based on options.\r\n */\r\n process({ lines, options }: WordIndexerInput): ProcessedWord[] {\r\n const processedWords: ProcessedWord[] = [];\r\n let globalWordIndex = 0;\r\n // Calculate total words once if needed by calculateIndex, though current logic uses parentLength dynamically\r\n const totalWords = lines.reduce((sum, line) => sum + line.words.length, 0);\r\n\r\n lines.forEach((line, lineIndex) => {\r\n const wordsInLine = line.words;\r\n const lineWordCount = wordsInLine.length; // Number of words in the current line\r\n\r\n wordsInLine.forEach((word, wordIndexInLine) => {\r\n const calculatedValues: CalculatedValue[] = []; // Use the unified CalculatedValue\r\n\r\n // 1. Calculate for 'word' options (global context)\r\n if (options.word && options.word.length > 0) {\r\n options.word.forEach((optDef) => {\r\n // Use globalWordIndex as primary, totalWords as parentLength\r\n const value = this.calculateIndex(\r\n optDef,\r\n globalWordIndex,\r\n wordIndexInLine,\r\n totalWords\r\n );\r\n // Create CalculatedValue object\r\n calculatedValues.push({ value, type: \"word\", align: optDef.align });\r\n });\r\n }\r\n\r\n // 2. Calculate for 'wordLine' options (line context)\r\n if (options.wordLine && options.wordLine.length > 0) {\r\n options.wordLine.forEach((optDef) => {\r\n // Use wordIndexInLine as primary, lineWordCount as parentLength\r\n const value = this.calculateIndex(\r\n optDef,\r\n wordIndexInLine,\r\n wordIndexInLine,\r\n lineWordCount\r\n );\r\n // Create CalculatedValue object\r\n calculatedValues.push({\r\n value,\r\n type: \"wordLine\",\r\n align: optDef.align,\r\n });\r\n });\r\n }\r\n\r\n // Create the ProcessedWord object with the unified calculatedValues\r\n processedWords.push({\r\n text: word.text,\r\n globalIndex: globalWordIndex,\r\n lineIndex: lineIndex,\r\n wordIndexInLine: wordIndexInLine,\r\n calculatedValues: calculatedValues, // Store the array of CalculatedValue\r\n });\r\n\r\n globalWordIndex++; // Increment global index for the next word\r\n }); // End word loop\r\n }); // End line loop\r\n\r\n return processedWords;\r\n }\r\n\r\n /**\r\n * Calculates the final numerical index value based on alignment options, context indices, and parent length.\r\n * This logic determines the value eventually set as a CSS variable.\r\n *\r\n * @param option - The specific option item definition ({ align, random, abs }).\r\n * @param primaryIndex - The main index used for calculation (global index for 'word', index within line for 'wordLine').\r\n * @param localIndex - The secondary index (e.g., index within the line), potentially useful for some alignment logic.\r\n * @param parentLength - The total count in the relevant context (total words for 'word', words in the current line for 'wordLine').\r\n * @returns The calculated numerical index value.\r\n */\r\n private calculateIndex(\r\n option: ISplitOptionItem,\r\n primaryIndex: number,\r\n localIndex: number, // Kept for potential future use, e.g., complex centering\r\n parentLength: number\r\n ): number {\r\n let index = primaryIndex; // Base value is the primary contextual index\r\n\r\n // Apply alignment logic\r\n if (option.align === \"random\") {\r\n const min = option.random?.min ?? 0;\r\n // Ensure max is valid (length - 1 for zero-based index)\r\n const max =\r\n option.random?.max ?? (parentLength > 0 ? parentLength - 1 : 0);\r\n // Handle cases where min might be > max\r\n const effectiveMin = Math.min(min, max);\r\n const effectiveMax = Math.max(min, max);\r\n // Generate random integer within the effective range\r\n index =\r\n Math.floor(Math.random() * (effectiveMax - effectiveMin + 1)) +\r\n effectiveMin;\r\n } else if (option.align === \"end\") {\r\n // Calculate index relative to the end (e.g., 0 -> length-1, 1 -> length-2)\r\n index = (parentLength > 0 ? parentLength - 1 : 0) - primaryIndex;\r\n } else if (option.align === \"center\") {\r\n // Calculate index relative to the center point\r\n index = primaryIndex - Math.floor(parentLength / 2);\r\n }\r\n // 'start' alignment uses the primaryIndex directly, no modification needed here.\r\n\r\n // Apply absolute value if requested\r\n if (option.abs) {\r\n index = Math.abs(index);\r\n }\r\n return index;\r\n }\r\n}\r\n","import { IStringTool } from \"../core/IStringTool\";\r\nimport { ISplitOptionItem } from \"../models/text/ISplitOptionItem\";\r\nimport { ISplitOptions } from \"../models/text/ISplitOptions\";\r\nimport { SplitOptionsParserInput } from \"../models/text/SplitOptionsParserInput\";\r\n\r\n/**\r\n * Tool responsible for parsing the string value of a split attribute\r\n * (e.g., \"line[center]|char[random(0,10)|abs]\") into a structured\r\n * ISplitOptions object.\r\n * Implements the IStringTool interface.\r\n */\r\nexport class SplitOptionsParserTool\r\n implements IStringTool<SplitOptionsParserInput, ISplitOptions>\r\n{\r\n /**\r\n * Parses the attribute string into an ISplitOptions object.\r\n * Handles splitting by '|', parsing prefixes (word-, char-), main types (line, word, char),\r\n * and parameters within brackets (align, random, abs).\r\n *\r\n * @param input - An object containing the attributeValue string (can be null).\r\n * @returns An ISplitOptions object representing the parsed rules.\r\n * Returns an object with empty arrays if the attributeValue is null or empty.\r\n */\r\n process({ attributeValue }: SplitOptionsParserInput): ISplitOptions {\r\n // Initialize with empty arrays for all possible options\r\n const options: ISplitOptions = {\r\n line: [],\r\n word: [],\r\n char: [],\r\n charLine: [],\r\n charWord: [],\r\n wordLine: [],\r\n };\r\n\r\n // Return default empty options if attribute value is null or empty string\r\n if (!attributeValue) {\r\n return options;\r\n }\r\n\r\n // Split the main attribute value by the pipe '|' separator\r\n const parts = attributeValue.split(\"|\");\r\n\r\n parts.forEach((part) => {\r\n // Trim whitespace from each part\r\n const trimmedPart = part.trim();\r\n if (!trimmedPart) return; // Skip empty parts resulting from separators like '||' or trailing '|'\r\n\r\n // Regex to capture:\r\n // 1. Optional prefix (word-, char-) - (\\w+-)?\r\n // 2. Main option type (line, word, char) - (\\w+)\r\n // 3. Optional parameters section including brackets - (\\[(.*?)\\])?\r\n // 4. Content within the brackets (params string) - (.*?)\r\n const match = trimmedPart.match(/^(\\w+-)?(\\w+)(\\[(.*?)\\])?$/);\r\n\r\n if (match) {\r\n const prefix = match[1] || \"\"; // e.g., \"word-\" or \"\"\r\n const optionType = match[2]; // e.g., \"line\", \"word\", \"char\"\r\n const fullOptionKey = prefix + optionType; // Combined key like \"line\", \"word\", \"charLine\"\r\n // Extract params string inside brackets, or empty string if no brackets\r\n const paramsString = match[4] || \"\";\r\n // Split params by comma and trim each resulting param string\r\n const params = paramsString\r\n .split(\";\")\r\n .map((p) => p.trim())\r\n .filter((p) => p.length > 0); // Filter out empty params\r\n\r\n // Parse the parameters within brackets using the helper method\r\n const parsedParam: ISplitOptionItem = this.parseParamsArray(params);\r\n\r\n // Add the parsed parameters object to the correct array in the options object\r\n // Use a type assertion for simplicity. More complex type guards could be used.\r\n switch (fullOptionKey) {\r\n case \"line\":\r\n (options.line as ISplitOptionItem[]).push(parsedParam);\r\n break;\r\n case \"word\":\r\n (options.word as ISplitOptionItem[]).push(parsedParam);\r\n break;\r\n case \"char\":\r\n (options.char as ISplitOptionItem[]).push(parsedParam);\r\n break;\r\n case \"charLine\": // e.g., char-line\r\n (options.charLine as ISplitOptionItem[]).push(parsedParam);\r\n break;\r\n case \"charWord\": // e.g., char-word\r\n (options.charWord as ISplitOptionItem[]).push(parsedParam);\r\n break;\r\n case \"wordLine\": // e.g., word-line\r\n (options.wordLine as ISplitOptionItem[]).push(parsedParam);\r\n break;\r\n default:\r\n // Log a warning for unrecognized option combinations\r\n console.warn(\r\n `SplitOptionsParserTool: Unrecognized option type \"${fullOptionKey}\" in part \"${trimmedPart}\"`\r\n );\r\n break;\r\n }\r\n } else {\r\n // Log a warning for parts that don't match the expected format \"type[params]\" or \"prefix-type[params]\"\r\n console.warn(\r\n `SplitOptionsParserTool: Could not parse part format \"${trimmedPart}\"`\r\n );\r\n }\r\n }); // End forEach part\r\n\r\n return options; // Return the populated options object\r\n }\r\n\r\n /**\r\n * Parses an array of string parameters (extracted from within brackets `[...]`).\r\n * Determines alignment, random settings, and absolute flag.\r\n * Example input: ['center'], ['random(0, 10)', 'abs']\r\n *\r\n * @param params - An array of string parameters.\r\n * @returns An ISplitOptionItem object representing the parsed parameters.\r\n */\r\n private parseParamsArray(params: string[]): ISplitOptionItem {\r\n // Default result with 'start' alignment\r\n const result: ISplitOptionItem = { align: \"start\" };\r\n\r\n params.forEach((param) => {\r\n if (param === \"abs\") {\r\n // Set the absolute flag\r\n result.abs = true;\r\n } else if (param.startsWith(\"random\")) {\r\n // Handle random alignment\r\n result.align = \"random\"; // Set alignment type\r\n // Try to parse min/max values like random(10,50)\r\n // Allows optional whitespace around numbers and comma\r\n const randomMatch = param.match(/random\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*\\)/);\r\n if (randomMatch) {\r\n // If numbers found, parse and store them\r\n result.random = {\r\n min: parseInt(randomMatch[1], 10),\r\n max: parseInt(randomMatch[2], 10),\r\n };\r\n // Optional: Add validation like min <= max here if desired\r\n }\r\n // If 'random' specified without valid numbers, result.align is 'random',\r\n // and result.random remains undefined (defaults will apply later based on context).\r\n } else if ([\"start\", \"center\", \"end\"].includes(param)) {\r\n // Handle specific alignment keywords\r\n result.align = param;\r\n }\r\n // Silently ignore any other unrecognized parameters within the brackets\r\n });\r\n\r\n return result; // Return the parsed option item definition\r\n }\r\n}\r\n","import BoundingClientRectTool from \"../tools/BoundingClientRectTool\"\r\nimport DOMAttributeTool from \"../tools/DOMAttributeTool\"\r\nimport RecordAttributeTool from \"../tools/RecordAttributeTool\"\r\nimport RelativePositionTool from \"../tools/RelativePositionTool\"\r\nimport LerpTool from \"../tools/LerpTool\"\r\nimport TransformNullifyTool from \"../tools/TransformNullifyTool\"\r\nimport UnitParserTool from \"../tools/UnitParserTool\"\r\nimport AdaptiveLerpTool from \"../tools/AdaptiveLerpTool\"\r\nimport OriginParserTool from \"../tools/OriginParserTool\"\r\nimport ColorParserTool from \"../tools/ColorParserTool\"\r\nimport ValidationTool from \"../tools/ValidationTool\"\r\nimport EasingFunctionTool from \"../tools/EasingFunctionTool\"\r\nimport MagneticPullTool from \"../tools/MagneticPullTool\"\r\nimport LerpColorTool from \"../tools/LerpColorTool\"\r\nimport LerpVector2Tool from \"../tools/LerpVector2Tool\"\r\nimport TransformScaleParserTool from \"../tools/TransformScaleParserTool\"\r\nimport { CharIndexerTool } from \"../tools/CharIndexerTool\"\r\nimport { LayoutLineSplitterTool } from \"../tools/LayoutLineSplitterTool\"\r\nimport { SplitDomBuilderTool } from \"../tools/SplitDomBuilderTool\"\r\nimport { WordIndexerTool } from \"../tools/WordIndexerTool\"\r\nimport { SplitOptionsParserTool } from \"../tools/SplitOptionsParserTool\"\r\n\r\n/**\r\n * Interface describing all available tools used inside modules.\r\n */\r\nexport interface StringToolsContainer {\r\n /** Tool for reading DOM attributes (including data-*). */\r\n domAttribute: DOMAttributeTool\r\n\r\n /** Tool for reading attributes from a plain JS object or dataset. */\r\n recordAttribute: RecordAttributeTool\r\n\r\n /** Tool for calculating the relative position between two elements. */\r\n relativePosition: RelativePositionTool\r\n\r\n /** Tool that nullifies the effect of CSS transform matrix. */\r\n transformNullify: TransformNullifyTool\r\n\r\n /** Tool that wraps getBoundingClientRect with consistent output. */\r\n boundingClientRect: BoundingClientRectTool\r\n\r\n /** Tool for parsing string-based values like '50%', '2rem', 'selfHeight'. */\r\n unitParser: UnitParserTool\r\n\r\n /** Tool for performing linear interpolation (lerp). */\r\n lerp: LerpTool\r\n\r\n /** \r\n * Tool for adaptive interpolation based on dynamic input value.\r\n * Useful when smoothing cursor speed, scroll velocity, etc.\r\n */\r\n adaptiveLerp: AdaptiveLerpTool\r\n\r\n /**\r\n * Tool for parsing origin strings.\r\n * Supports values like `'top'`, `'center'`, or random expressions like `'random(top, bottom)'`.\r\n */\r\n originParser: OriginParserTool\r\n\r\n /**\r\n * Tool for parsing CSS color strings into { r, g, b, a } format.\r\n * Supports `#hex`, `rgb[a](...)`, `hsl[a](...)` inputs.\r\n */\r\n colorParser: ColorParserTool\r\n\r\n /**\r\n * Tool for validating strings using rules like `required`, `minLength`, `email`, etc.\r\n * Returns validation status, error code, and optional message.\r\n */\r\n validation: ValidationTool\r\n\r\n /**\r\n * Tool for parsing CSS-like easing strings into easing functions.\r\n * Supports keywords like `'ease'`, `'linear'`, and full `cubic-bezier(...)` expressions.\r\n */\r\n easingFunction: EasingFunctionTool\r\n\r\n /**\r\n * Tool for calculating magnetic offset strength based on proximity to pointer.\r\n */\r\n magneticPull: MagneticPullTool\r\n\r\n /**\r\n * Tool for interpolating between two RGBA colors.\r\n * Accepts `from` and `to` colors as `{ r, g, b, a }`, and a `progress` value from `0` to `1`.\r\n * Returns an interpolated `StringColor` object.\r\n */\r\n lerpColor: LerpColorTool\r\n\r\n /**\r\n * Tool for interpolating between two 2D vectors.\r\n * Accepts `{ x, y }` objects and a `progress` value between `0` and `1`.\r\n * Returns a new `{ x, y }` vector.\r\n */\r\n lerpVector: LerpVector2Tool\r\n\r\n transformScaleParser: TransformScaleParserTool\r\n\r\n layoutSplitter: LayoutLineSplitterTool\r\n\r\n wordIndexer: WordIndexerTool\r\n\r\n charIndexer: CharIndexerTool\r\n\r\n domBuilder: SplitDomBuilderTool\r\n\r\n optionsParser: SplitOptionsParserTool\r\n\r\n}\r\n\r\n/**\r\n * Default implementation of the StringToolContainer,\r\n * which provides ready-to-use instances of all core tools.\r\n */\r\nexport class DefaultToolsContainer implements StringToolsContainer {\r\n public domAttribute = new DOMAttributeTool()\r\n public recordAttribute = new RecordAttributeTool()\r\n public transformNullify = new TransformNullifyTool()\r\n public boundingClientRect = new BoundingClientRectTool()\r\n public relativePosition = new RelativePositionTool(this.transformNullify)\r\n public unitParser = new UnitParserTool()\r\n public lerp = new LerpTool()\r\n public adaptiveLerp = new AdaptiveLerpTool()\r\n public originParser = new OriginParserTool()\r\n public colorParser = new ColorParserTool()\r\n public validation = new ValidationTool()\r\n public easingFunction = new EasingFunctionTool()\r\n public magneticPull = new MagneticPullTool()\r\n public lerpColor = new LerpColorTool()\r\n public lerpVector = new LerpVector2Tool()\r\n public transformScaleParser = new TransformScaleParserTool()\r\n public layoutSplitter = new LayoutLineSplitterTool()\r\n public wordIndexer = new WordIndexerTool()\r\n public charIndexer = new CharIndexerTool()\r\n public domBuilder = new SplitDomBuilderTool()\r\n public optionsParser = new SplitOptionsParserTool()\r\n\r\n}\r\n","import { StringContext } from \"../../core/StringContext\";\r\nimport { StringData } from \"../../core/StringData\";\r\nimport { StringModule } from \"../../core/StringModule\";\r\nimport { StringObject } from \"../../objects/StringObject\";\r\n\r\nexport class StringCursor extends StringModule {\r\n protected enterObjectsMap: Map<string, StringObject> = new Map<\r\n string,\r\n StringObject\r\n >();\r\n protected enterObjects: Array<StringObject> = new Array<StringObject>();\r\n cursor: any;\r\n cursorContent: any;\r\n overCount: number = 0;\r\n\r\n constructor(context: StringContext) {\r\n super(context);\r\n this.htmlKey = \"cursor\";\r\n this.cursor = document.querySelector(\r\n \"[string-cursor],[data-string-cursor]\"\r\n ) as HTMLElement;\r\n this.cursorContent = document.querySelector(\r\n \"[string-cursor-content],[data-string-cursor-content]\"\r\n ) as HTMLElement;\r\n\r\n this.attributesToMap = [\r\n ...this.attributesToMap,\r\n {\r\n key: \"target-disable\",\r\n type: \"boolean\",\r\n fallback: this.settings[\"target-disable\"],\r\n },\r\n {\r\n key: \"target-style-disable\",\r\n type: \"boolean\",\r\n fallback: this.settings[\"target-style-disable\"],\r\n },\r\n {\r\n key: \"target-class\",\r\n type: \"string\",\r\n fallback: this.settings[\"target-class\"],\r\n },\r\n {\r\n key: \"cursor-class\",\r\n type: \"string\",\r\n fallback: this.settings[\"cursor-class\"],\r\n },\r\n {\r\n key: \"alignment\",\r\n type: { type: \"enum\", values: [\"start\", \"center\", \"end\"] },\r\n fallback: this.settings[\"alignment\"],\r\n },\r\n {\r\n key: \"lerp\",\r\n type: \"number\",\r\n fallback: this.settings[\"lerp\"],\r\n transform: (value: number) => {\r\n return this.tools.adaptiveLerp.process({\r\n value,\r\n inMin: 0.1,\r\n inMax: 1.0,\r\n outMin: 0.05,\r\n outMax: 0.65,\r\n });\r\n },\r\n },\r\n ];\r\n }\r\n\r\n initializeObject(\r\n globalId: number,\r\n object: StringObject,\r\n element: HTMLElement,\r\n attributes: Record<string, any>\r\n ): void {\r\n super.initializeObject(globalId, object, element, attributes);\r\n object.setProperty(\"mouse-x\", 0);\r\n object.setProperty(\"mouse-y\", 0);\r\n object.setProperty(\"mouse-pixel-x\", 0);\r\n object.setProperty(\"mouse-pixel-y\", 0);\r\n object.setProperty(\"is-mouse-over\", false);\r\n object.setProperty(\"is-mouse-move\", false);\r\n }\r\n\r\n onFrame(data: StringData): void {\r\n requestAnimationFrame(() => {\r\n this.objects.forEach((object) => {\r\n const isOver = object.getProperty<boolean>(\"is-mouse-over\");\r\n const isDisabled = object.getProperty<boolean>(\"cursor-target-disable\");\r\n const lerpFactor = object.getProperty<number>(\"lerp\") ?? 0.15;\r\n\r\n if (isOver && !isDisabled) {\r\n const rect = object.htmlElement.getBoundingClientRect();\r\n const cursorX = this.data.cursor.targetX;\r\n const cursorY = this.data.cursor.targetY;\r\n const elementX = cursorX - rect.left;\r\n const elementY = cursorY - rect.top;\r\n\r\n let px = object.getProperty<number>(\"mouse-pixel-x\") ?? 0;\r\n let py = object.getProperty<number>(\"mouse-pixel-y\") ?? 0;\r\n\r\n const dx = px - elementX;\r\n const dy = py - elementY;\r\n const distSquared = dx * dx + dy * dy;\r\n\r\n if (distSquared > 0.0001) {\r\n const isMoving =\r\n object.getProperty<boolean>(\"is-mouse-move\") ?? false;\r\n if (!isMoving) {\r\n object.setProperty(\"is-mouse-move\", true);\r\n object.setProperty(\"mouse-pixel-x\", elementX);\r\n object.setProperty(\"mouse-pixel-y\", elementY);\r\n object.setProperty(\"mouse-x\", elementX);\r\n object.setProperty(\"mouse-y\", elementY);\r\n px = elementX;\r\n py = elementY;\r\n this.events.emit(`cursor:start:${object.id}`, null);\r\n }\r\n\r\n const lerpedX = this.tools.lerp.process({\r\n from: px,\r\n to: elementX,\r\n progress: lerpFactor,\r\n });\r\n const lerpedY = this.tools.lerp.process({\r\n from: py,\r\n to: elementY,\r\n progress: lerpFactor,\r\n });\r\n\r\n const updatedX = px + lerpedX;\r\n const updatedY = py + lerpedY;\r\n\r\n object.setProperty(\"mouse-pixel-x\", updatedX);\r\n object.setProperty(\"mouse-pixel-y\", updatedY);\r\n\r\n const alignment =\r\n object.getProperty<string>(\"alignment\") ?? \"center\";\r\n const offsetX = this.calculateOffset(\r\n alignment,\r\n updatedX,\r\n rect.width\r\n );\r\n const offsetY = this.calculateOffset(\r\n alignment,\r\n updatedY,\r\n rect.height\r\n );\r\n\r\n object.setProperty(\"mouse-x\", offsetX);\r\n object.setProperty(\"mouse-y\", offsetY);\r\n\r\n this.setMouseCoordinates(object, offsetX, offsetY);\r\n\r\n this.events.emit(`cursor:move:${object.id}`, {\r\n x: offsetX,\r\n y: offsetY,\r\n });\r\n this.events.emit(`cursor:pixel:${object.id}`, {\r\n x: updatedX,\r\n y: updatedY,\r\n });\r\n } else {\r\n object.setProperty(\"mouse-pixel-x\", elementX);\r\n object.setProperty(\"mouse-pixel-y\", elementY);\r\n this.events.emit(`cursor:end:${object.id}`, null);\r\n }\r\n } else {\r\n const mouseX = object.getProperty<number>(\"mouse-x\") ?? 0;\r\n const mouseY = object.getProperty<number>(\"mouse-y\") ?? 0;\r\n if (mouseX !== 0 || mouseY !== 0) {\r\n object.setProperty(\"is-mouse-move\", false);\r\n\r\n const rect = object.htmlElement.getBoundingClientRect();\r\n const halfWidth =\r\n object.getProperty<number>(\"half-width\") ?? rect.width / 2;\r\n const halfHeight =\r\n object.getProperty<number>(\"half-height\") ?? rect.height / 2;\r\n\r\n const targetX = this.calculateOffset(\r\n \"center\",\r\n halfWidth,\r\n rect.width\r\n );\r\n const targetY = this.calculateOffset(\r\n \"center\",\r\n halfHeight,\r\n rect.height\r\n );\r\n\r\n const newMouseX =\r\n mouseX +\r\n this.tools.lerp.process({\r\n from: mouseX,\r\n to: targetX,\r\n progress: lerpFactor,\r\n });\r\n const newMouseY =\r\n mouseY +\r\n this.tools.lerp.process({\r\n from: mouseY,\r\n to: targetY,\r\n progress: lerpFactor,\r\n });\r\n\r\n object.setProperty(\"mouse-x\", newMouseX);\r\n object.setProperty(\"mouse-y\", newMouseY);\r\n\r\n if (Math.abs(newMouseX) < 0.001 && Math.abs(newMouseY) < 0.001) {\r\n object.setProperty(\"mouse-x\", 0);\r\n object.setProperty(\"mouse-y\", 0);\r\n object.setProperty(\"mouse-pixel-x\", 0);\r\n object.setProperty(\"mouse-pixel-y\", 0);\r\n }\r\n\r\n this.setMouseCoordinates(object, newMouseX, newMouseY);\r\n }\r\n }\r\n });\r\n\r\n const { stepX, stepY, smoothedX, smoothedY } = this.data.cursor;\r\n if (stepX !== 0 || stepY !== 0) {\r\n this.events.emit(\"cursor\", {\r\n stepX,\r\n stepY,\r\n x: smoothedX,\r\n y: smoothedY,\r\n });\r\n\r\n this.cursor.style.setProperty(\"--x\", smoothedX.toString());\r\n this.cursor.style.setProperty(\"--y\", smoothedY.toString());\r\n this.cursor.style.setProperty(\"--x-lerp\", stepX.toString());\r\n this.cursor.style.setProperty(\"--y-lerp\", stepY.toString());\r\n }\r\n });\r\n }\r\n\r\n onObjectConnected(object: StringObject) {\r\n const element = object.htmlElement;\r\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\r\n\r\n object.setProperty(\"timeoutId\", timeoutId);\r\n\r\n object.setProperty(\"mouseleave\", () => {\r\n this.onMouseLeave(object);\r\n });\r\n object.setProperty(\"mouseenter\", () => {\r\n this.onMouseEnter(object);\r\n });\r\n\r\n object.setProperty(\"onEnterEvent\", this.onEnterObject.bind(this));\r\n object.events.on(\r\n \"enter\",\r\n object.getProperty<(object: StringObject) => void>(\"onEnterEvent\")\r\n );\r\n object.setProperty(\"onLeaveEvent\", this.onLeaveObject.bind(this));\r\n object.events.on(\r\n \"leave\",\r\n object.getProperty<(object: StringObject) => void>(\"onLeaveEvent\")\r\n );\r\n }\r\n\r\n getCursorClass(object: StringObject) {\r\n const value = object.getProperty<string>(\"cursor-class\");\r\n return value != null && value.length > 0 ? value : null;\r\n }\r\n\r\n onMouseEnter(object: StringObject) {\r\n this.overCount++;\r\n object.setProperty(\"is-mouse-over\", true);\r\n\r\n const cursorClass = this.getCursorClass(object);\r\n if (cursorClass) {\r\n this.cursor.classList.add(cursorClass);\r\n }\r\n\r\n this.cursor.classList.add(\"-showing\");\r\n\r\n object.setProperty(\r\n \"timeoutId\",\r\n setTimeout(() => {\r\n this.cursor.classList.remove(\"-showing\");\r\n this.cursor.classList.add(\"-show\");\r\n }, 1200)\r\n );\r\n\r\n object.htmlElement.addEventListener(\r\n \"mouseleave\",\r\n object.getProperty(\"mouseleave\")\r\n );\r\n }\r\n\r\n onMouseLeave(object: StringObject) {\r\n this.overCount--;\r\n object.setProperty(\"is-mouse-over\", false);\r\n\r\n if (object.getProperty(\"timeoutId\")) {\r\n clearTimeout(object.getProperty(\"timeoutId\"));\r\n object.setProperty(\"timeoutId\", null);\r\n }\r\n\r\n const cursorClass = this.getCursorClass(object);\r\n if (cursorClass) {\r\n this.cursor.classList.remove(cursorClass);\r\n }\r\n\r\n this.cursor.classList.remove(\"-showing\");\r\n this.cursor.classList.remove(\"-show\");\r\n\r\n object.htmlElement.removeEventListener(\r\n \"mouseleave\",\r\n object.getProperty(\"mouseleave\")\r\n );\r\n }\r\n\r\n private onEnterObject(object: StringObject) {\r\n object.htmlElement.addEventListener(\r\n \"mouseenter\",\r\n object.getProperty(\"mouseenter\")\r\n );\r\n }\r\n private onLeaveObject(object: StringObject) {\r\n object.htmlElement.removeEventListener(\r\n \"mouseenter\",\r\n object.getProperty(\"mouseenter\")\r\n );\r\n object.htmlElement.removeEventListener(\r\n \"mouseleave\",\r\n object.getProperty(\"mouseleave\")\r\n );\r\n }\r\n\r\n private setMouseCoordinates(object: StringObject, x: number, y: number) {\r\n if (!object.getProperty(\"cursor-target-style-disable\")) {\r\n this.applyToElementAndConnects(object, (el) => {\r\n el.style.setProperty(\"--x\", x.toFixed(2));\r\n el.style.setProperty(\"--y\", y.toFixed(2));\r\n });\r\n }\r\n }\r\n\r\n private calculateOffset(\r\n alignment: string,\r\n mousePos: number,\r\n size: number\r\n ): number {\r\n switch (alignment) {\r\n case \"start\":\r\n return mousePos / size;\r\n case \"end\":\r\n return (mousePos - size) / size;\r\n case \"center\":\r\n default:\r\n return (mousePos - size / 2) / (size / 2);\r\n }\r\n }\r\n}\r\n","import { StringContext } from \"../../core/StringContext\";\r\nimport { StringData } from \"../../core/StringData\";\r\nimport { StringModule } from \"../../core/StringModule\";\r\nimport { StringObject } from \"../../objects/StringObject\";\r\n\r\nexport class StringMagnetic extends StringModule {\r\n constructor(context: StringContext) {\r\n super(context);\r\n this.htmlKey = \"magnetic\";\r\n\r\n this.attributesToMap = [\r\n ...this.attributesToMap,\r\n { key: \"strength\", type: \"number\", fallback: this.settings[\"strength\"] },\r\n { key: \"radius\", type: \"number\", fallback: this.settings[\"radius\"] },\r\n ];\r\n }\r\n\r\n override initializeObject(\r\n globalId: number,\r\n object: StringObject,\r\n element: HTMLElement,\r\n attributes: Record<string, any>\r\n ): void {\r\n super.initializeObject(globalId, object, element, attributes);\r\n object.setProperty(\"is-magneting\", false);\r\n object.setProperty(\"magnetic-target-x\", 0);\r\n object.setProperty(\"magnetic-target-y\", 0);\r\n object.setProperty(\"magnetic-x\", 0);\r\n object.setProperty(\"magnetic-y\", 0);\r\n object.setProperty(\"lerp\", 0.1);\r\n }\r\n\r\n onMouseMove(e: MouseEvent): void {\r\n this.objects.forEach((object) => {\r\n const element = object.htmlElement as HTMLElement;\r\n const rect = element.getBoundingClientRect();\r\n const centerX =\r\n rect.left + (object.getProperty<number>(\"half-width\") ?? 0);\r\n const centerY =\r\n rect.top + (object.getProperty<number>(\"half-height\") ?? 0);\r\n const dx = e.clientX - centerX;\r\n const dy = e.clientY - centerY;\r\n const distance = Math.sqrt(dx ** 2 + dy ** 2);\r\n\r\n const radius = object.getProperty<number>(\"radius\") ?? 0;\r\n const strength = object.getProperty<number>(\"strength\") ?? 0;\r\n\r\n const factor = this.tools.magneticPull.process({\r\n distance,\r\n radius,\r\n strength,\r\n });\r\n\r\n object.setProperty(\"magnetic-target-x\", dx * factor);\r\n object.setProperty(\"magnetic-target-y\", dy * factor);\r\n if (factor > 0) {\r\n object.setProperty(\"is-magneting\", true);\r\n }\r\n });\r\n }\r\n\r\n onFrame(data: StringData): void {\r\n this.objects.forEach((object) => {\r\n if (object.getProperty(\"is-magneting\")) {\r\n let magneticX = object.getProperty<number>(\"magnetic-x\") ?? 0;\r\n let magneticY = object.getProperty<number>(\"magnetic-y\") ?? 0;\r\n\r\n let lerp = object.getProperty<number>(\"lerp\") ?? 0;\r\n\r\n let targetMagneticX =\r\n object.getProperty<number>(\"magnetic-target-x\") ?? 0;\r\n let targetMagneticY =\r\n object.getProperty<number>(\"magnetic-target-y\") ?? 0;\r\n\r\n let lerpX = this.tools.lerp.process({\r\n from: magneticX,\r\n to: targetMagneticX,\r\n progress: lerp,\r\n });\r\n let lerpY = this.tools.lerp.process({\r\n from: magneticY,\r\n to: targetMagneticY,\r\n progress: lerp,\r\n });\r\n\r\n if (lerpX > -0.01 && lerpX < 0.01) {\r\n lerpX = 0;\r\n object.setProperty(\r\n \"magnetic-x\",\r\n object.getProperty(\"magnetic-target-x\")\r\n );\r\n }\r\n if (lerpY > -0.01 && lerpY < 0.01) {\r\n lerpY = 0;\r\n object.setProperty(\r\n \"magnetic-y\",\r\n object.getProperty(\"magnetic-target-y\")\r\n );\r\n }\r\n magneticX += lerpX;\r\n magneticY += lerpY;\r\n object.setProperty<number>(\"magnetic-x\", magneticX);\r\n object.setProperty<number>(\"magnetic-y\", magneticY);\r\n this.events.emit(`magnetic:move:${object.id}`, {\r\n x: magneticX,\r\n y: magneticY,\r\n });\r\n\r\n this.applyToElementAndConnects(object, (el) => {\r\n el.style.setProperty(\"--magnetic-x\", magneticX.toString());\r\n el.style.setProperty(\"--magnetic-y\", magneticY.toString());\r\n });\r\n\r\n if (\r\n object.getProperty(\"magnetic-target-x\") == magneticX ||\r\n object.getProperty(\"magnetic-target-y\") == magneticY\r\n ) {\r\n object.setProperty(\"is-magneting\", false);\r\n }\r\n }\r\n });\r\n }\r\n}\r\n","import { StringContext } from \"../../core/StringContext\";\r\nimport { StringModule } from \"../../core/StringModule\";\r\nimport { StringObject } from \"../../objects/StringObject\";\r\n\r\n/**\r\n * Module that handles lazy-loading of images with `string-lazy` attribute.\r\n * Automatically loads and applies aspect-ratio once image is loaded.\r\n */\r\nexport class StringLazy extends StringModule {\r\n private isStartLoaded = false;\r\n private loadingCount = 0;\r\n\r\n constructor(context: StringContext) {\r\n super(context);\r\n this.htmlKey = \"lazy\";\r\n }\r\n\r\n /**\r\n * Called on module start — preloads all <img string-lazy> in DOM.\r\n */\r\n onInit(): void {\r\n const images = document.querySelectorAll(\r\n \"img[string-lazy], img[data-string-lazy]\"\r\n );\r\n images.forEach((img) => this.loadImage(img as HTMLImageElement));\r\n this.isStartLoaded = true;\r\n }\r\n\r\n /**\r\n * Called when an image becomes a managed object.\r\n */\r\n onObjectConnected(object: StringObject): void {\r\n this.loadingCount++;\r\n\r\n if (this.isStartLoaded) {\r\n const img = object.htmlElement as HTMLImageElement;\r\n this.loadImage(img);\r\n }\r\n }\r\n\r\n /**\r\n * Loads image and sets aspect-ratio based on real dimensions.\r\n */\r\n private async loadImage(img: HTMLImageElement): Promise<void> {\r\n const src = this.tools.domAttribute.process({\r\n element: img,\r\n key: this.htmlKey,\r\n fallback: \"\",\r\n });\r\n\r\n if (!src) return;\r\n\r\n try {\r\n img.classList.add(\"lazyLoad\");\r\n img.src = src;\r\n\r\n img.addEventListener(\"load\", () => {\r\n img.classList.add(\"-loaded\");\r\n });\r\n await this.setAspectRatio(img, src);\r\n } catch (err) {\r\n console.warn(\"Failed to load image:\", src);\r\n }\r\n }\r\n\r\n /**\r\n * Loads image data to extract real dimensions and apply aspect-ratio style.\r\n */\r\n private setAspectRatio(el: HTMLElement, url: string): Promise<void> {\r\n return new Promise((resolve, reject) => {\r\n const xhr = new XMLHttpRequest();\r\n xhr.open(\"GET\", url, true);\r\n xhr.responseType = \"arraybuffer\";\r\n xhr.setRequestHeader(\"Range\", \"bytes=0-\");\r\n xhr.onload = () => {\r\n if (xhr.status === 200 || xhr.status === 206) {\r\n const blob = new Blob([xhr.response]);\r\n const img = new Image();\r\n img.onload = () => {\r\n el.style.aspectRatio = `${img.width} / ${img.height}`;\r\n URL.revokeObjectURL(img.src);\r\n\r\n this.loadingCount--;\r\n if (this.loadingCount <= 0) {\r\n this.events.emit(\"image:load:all\", null);\r\n this.loadingCount = 0;\r\n }\r\n\r\n resolve();\r\n };\r\n img.onerror = () => {\r\n URL.revokeObjectURL(img.src);\r\n this.loadingCount--;\r\n reject(new Error(\"Image failed to decode\"));\r\n };\r\n img.src = URL.createObjectURL(blob);\r\n } else {\r\n reject(new Error(\"Image request failed\"));\r\n }\r\n };\r\n xhr.onerror = () => reject(new Error(\"XHR error\"));\r\n xhr.send();\r\n });\r\n }\r\n}\r\n","import { StringContext } from \"../../core/StringContext\";\r\nimport { StringModule } from \"../../core/StringModule\";\r\n\r\n\r\nexport class StringLoading extends StringModule{\r\n loadingTimeout: number = 0\r\n\r\n constructor(context: StringContext) {\r\n super(context)\r\n this._type = 2\r\n this.loadingTimeout = this.settings['timeout']\r\n }\r\n onInit(): void {\r\n setTimeout(() => {\r\n const htmlElement = document.documentElement;\r\n htmlElement.classList.add('-loaded');\r\n }, this.loadingTimeout);\r\n \r\n }\r\n}","import { StringModule } from \"../../core/StringModule\";\r\nimport { StringObject } from \"../../objects/StringObject\";\r\n\r\nexport class StringInview extends StringModule {\r\n constructor(visitor: any) {\r\n super(visitor);\r\n this.htmlKey = '';\r\n }\r\n canConnect(object: StringObject): boolean {\r\n return object.keys[0]==undefined;\r\n }\r\n}\r\n","import { StringContext } from \"../../core/StringContext\";\r\nimport { StringModule } from \"../../core/StringModule\";\r\n\r\nenum DeviceType {\r\n Mobile,\r\n Tablet,\r\n Laptop,\r\n Desktop,\r\n}\r\n\r\ninterface DeviceQueryConfig {\r\n min?: number;\r\n max?: number;\r\n enable?: boolean;\r\n}\r\n\r\ninterface QueryConfig {\r\n mobile?: DeviceQueryConfig;\r\n tablet?: DeviceQueryConfig;\r\n laptop?: DeviceQueryConfig;\r\n desktop?: DeviceQueryConfig;\r\n}\r\n\r\nclass StringResponsiveQueryDevice {\r\n public min?: number = undefined;\r\n public max?: number = undefined;\r\n public enable: boolean = true;\r\n\r\n constructor(config?: DeviceQueryConfig) {\r\n this.min = config?.min;\r\n this.max = config?.max;\r\n this.enable = config?.enable ?? true;\r\n }\r\n\r\n setEnable(enable: boolean = true) {\r\n this.enable = enable;\r\n }\r\n setRange(min?: number, max?: number) {\r\n this.min = min ?? undefined;\r\n this.max = max ?? undefined;\r\n }\r\n\r\n get mediaQuery(): string {\r\n let query = \"screen\";\r\n if (this.min) {\r\n query += ` and (min-width: ${this.min}px)`;\r\n }\r\n if (this.max) {\r\n query += ` and (max-width: ${this.max}px)`;\r\n }\r\n return query;\r\n }\r\n}\r\n\r\nexport class StringResponsive extends StringModule {\r\n private queries: { [key in DeviceType]: StringResponsiveQueryDevice } = {\r\n [DeviceType.Mobile]: new StringResponsiveQueryDevice({ max: 359 }),\r\n [DeviceType.Tablet]: new StringResponsiveQueryDevice({\r\n min: 360,\r\n max: 1079,\r\n }),\r\n [DeviceType.Laptop]: new StringResponsiveQueryDevice({\r\n min: 1080,\r\n max: 1365,\r\n }),\r\n [DeviceType.Desktop]: new StringResponsiveQueryDevice({ min: 1366 }),\r\n };\r\n\r\n private matchMedias: { [key in DeviceType]: MediaQueryList } = {\r\n [DeviceType.Mobile]: window.matchMedia(\r\n this.queries[DeviceType.Mobile].mediaQuery\r\n ),\r\n [DeviceType.Tablet]: window.matchMedia(\r\n this.queries[DeviceType.Tablet].mediaQuery\r\n ),\r\n [DeviceType.Laptop]: window.matchMedia(\r\n this.queries[DeviceType.Laptop].mediaQuery\r\n ),\r\n [DeviceType.Desktop]: window.matchMedia(\r\n this.queries[DeviceType.Desktop].mediaQuery\r\n ),\r\n };\r\n\r\n constructor(context: StringContext) {\r\n super(context);\r\n this._type = 2;\r\n }\r\n\r\n onConnect() {}\r\n\r\n onInit(): void {\r\n if (this.settings != null) {\r\n if (this.settings[\"settings\"] != null) {\r\n let config = this.settings[\"settings\"];\r\n if (config.mobile) {\r\n this.queries[DeviceType.Mobile].enable = true;\r\n this.queries[DeviceType.Mobile].setRange(\r\n config.mobile.min == undefined ? null : config.mobile.min,\r\n config.mobile.max ?? null\r\n );\r\n this.matchMedias[DeviceType.Mobile] = window.matchMedia(\r\n this.queries[DeviceType.Mobile].mediaQuery\r\n );\r\n } else {\r\n this.queries[DeviceType.Mobile].enable = false;\r\n }\r\n\r\n if (config.tablet) {\r\n this.queries[DeviceType.Tablet].enable = true;\r\n this.queries[DeviceType.Tablet].setRange(\r\n config.mobile.min == undefined ? null : config.mobile.min,\r\n config.mobile.max ?? null\r\n );\r\n this.matchMedias[DeviceType.Tablet] = window.matchMedia(\r\n this.queries[DeviceType.Mobile].mediaQuery\r\n );\r\n } else {\r\n this.queries[DeviceType.Tablet].enable = false;\r\n }\r\n\r\n if (config.laptop) {\r\n this.queries[DeviceType.Laptop].enable = true;\r\n this.queries[DeviceType.Laptop].setRange(\r\n config.mobile.min == undefined ? null : config.mobile.min,\r\n config.mobile.max ?? null\r\n );\r\n this.matchMedias[DeviceType.Laptop] = window.matchMedia(\r\n this.queries[DeviceType.Mobile].mediaQuery\r\n );\r\n } else {\r\n this.queries[DeviceType.Laptop].enable = false;\r\n }\r\n\r\n if (config.desktop) {\r\n this.queries[DeviceType.Desktop].enable = true;\r\n this.queries[DeviceType.Desktop].setRange(\r\n config.mobile.min == undefined ? null : config.mobile.min,\r\n config.mobile.max ?? null\r\n );\r\n this.matchMedias[DeviceType.Desktop] = window.matchMedia(\r\n this.queries[DeviceType.Mobile].mediaQuery\r\n );\r\n } else {\r\n this.queries[DeviceType.Desktop].enable = false;\r\n }\r\n }\r\n }\r\n this.updateElements();\r\n }\r\n\r\n onResize(): void {\r\n this.updateElements();\r\n }\r\n\r\n private updateElements() {\r\n const isMobileMedia =\r\n this.matchMedias[DeviceType.Mobile].matches &&\r\n this.queries[DeviceType.Mobile].enable;\r\n const isTabletMedia =\r\n this.matchMedias[DeviceType.Tablet].matches &&\r\n this.queries[DeviceType.Tablet].enable;\r\n const isLaptopMedia =\r\n this.matchMedias[DeviceType.Laptop].matches &&\r\n this.queries[DeviceType.Laptop].enable;\r\n const isDesktopMedia =\r\n this.matchMedias[DeviceType.Desktop].matches &&\r\n this.queries[DeviceType.Desktop].enable;\r\n\r\n const elements = document.querySelectorAll(\r\n \"[string-mobile], [string-tablet], [string-laptop], [string-desktop]\"\r\n );\r\n\r\n elements.forEach((element: any) => {\r\n let showElement = false;\r\n\r\n if (element.hasAttribute(\"string-mobile\") && isMobileMedia) {\r\n showElement = true;\r\n this.events.emit(\"screen:mobile\", isMobileMedia);\r\n }\r\n if (element.hasAttribute(\"string-tablet\") && isTabletMedia) {\r\n showElement = true;\r\n this.events.emit(\"screen:tablet\", isTabletMedia);\r\n }\r\n if (element.hasAttribute(\"string-laptop\") && isLaptopMedia) {\r\n showElement = true;\r\n this.events.emit(\"screen:laptop\", isLaptopMedia);\r\n }\r\n if (element.hasAttribute(\"string-desktop\") && isDesktopMedia) {\r\n showElement = true;\r\n this.events.emit(\"screen:desktop\", isDesktopMedia);\r\n }\r\n\r\n if (showElement) {\r\n element.style.display = null;\r\n } else {\r\n element.style.display = `none`;\r\n }\r\n });\r\n }\r\n}\r\n","import { StringContext } from \"../../core/StringContext\";\r\nimport { StringModule } from \"../../core/StringModule\";\r\nimport { StringObject } from \"../../objects/StringObject\";\r\n\r\nexport class StringAnchor extends StringModule {\r\n constructor(context: StringContext) {\r\n super(context);\r\n this.htmlKey = 'anchor';\r\n this.attributesToMap = [\r\n ...this.attributesToMap,\r\n {\r\n key: 'anchor',\r\n type: 'tuple',\r\n fallback: this.settings['anchor'],\r\n transform: (tuple: string[]) => {\r\n const [xRaw, yRaw] = tuple;\r\n const x = this.tools.originParser.process({value: xRaw});\r\n const y = this.tools.originParser.process({value: yRaw});\r\n return { x, y };\r\n },\r\n }\r\n ];\r\n }\r\n onObjectConnected(object: StringObject) {\r\n super.onObjectConnected(object)\r\n const anchor = object.getProperty<{ x: string, y: string }>('anchor')\r\n if (anchor) {\r\n this.applyToElementAndConnects(object, (el) => {\r\n el.style.transformOrigin = `${anchor.x} ${anchor.y}`;\r\n })\r\n }\r\n }\r\n\r\n}","import { StringContext } from \"../../core/StringContext\";\r\nimport { StringData } from \"../../core/StringData\";\r\nimport { StringModule } from \"../../core/StringModule\";\r\nimport { StringObject } from \"../../objects/StringObject\";\r\n\r\nconst ACCELERATION_STEP: number = 0.05;\r\nconst MIN_DISPLACEMENT: number = 0.01;\r\nconst MAX_DISPLACEMENT: number = 1;\r\nconst MIN_VELOCITY: number = -1;\r\nconst MAX_VELOCITY: number = 1;\r\n\r\nexport class StringGlide extends StringModule {\r\n private previousLerp: number = 0;\r\n private displacement: number = 0;\r\n private acceleration: number = 0;\r\n private velocityMultiplier: number = 0.00125;\r\n private isInitialScroll: boolean = true;\r\n\r\n private baseVelocityMultiplier: number = 0.00125;\r\n private reducedVelocityMultiplier: number = this.baseVelocityMultiplier / 20;\r\n private negativeVelocityMultiplier: number = -0.0001;\r\n\r\n private maxDisplacementValue: number = 0;\r\n\r\n constructor(context: StringContext) {\r\n super(context);\r\n this.htmlKey = \"glide\";\r\n\r\n this.baseVelocityMultiplier =\r\n this.settings[\"glide-base-velocity\"] ?? this.baseVelocityMultiplier;\r\n this.reducedVelocityMultiplier =\r\n this.settings[\"glide-reduce-velocity\"] ?? this.reducedVelocityMultiplier;\r\n this.negativeVelocityMultiplier =\r\n this.settings[\"glide-negative-velocity\"] ??\r\n this.negativeVelocityMultiplier;\r\n\r\n this.attributesToMap = [\r\n ...this.attributesToMap,\r\n { key: \"glide\", type: \"number\", fallback: this.settings[\"glide\"] },\r\n ];\r\n }\r\n\r\n private setupItem = (object: StringObject) => {\r\n let glide = object.getProperty<number>(\"glide\") ?? 0;\r\n\r\n let glideValue =\r\n -this.data.scroll.displacement * this.maxDisplacementValue * glide;\r\n this.events.emit(`object:glide:${object.id}`, glideValue);\r\n\r\n const transformCompute = `translate3d(0, ${glideValue}px, 0)`;\r\n object.htmlElement.style.transform = transformCompute;\r\n };\r\n\r\n private onUpdateDesktopEvent = () => {\r\n for (let i = 0; i < this.objects.length; i++) {\r\n let object = this.objects[i];\r\n this.setupItem(object);\r\n }\r\n };\r\n private onUpdateMobileEvent = () => {};\r\n private onUpdateEvent = this.onUpdateDesktopEvent;\r\n\r\n private calcExpanderFactor(isDirectionUp: boolean): void {\r\n const isConditionMet = isDirectionUp\r\n ? this.data.scroll.lerped < this.previousLerp\r\n : this.data.scroll.lerped > this.previousLerp;\r\n\r\n this.velocityMultiplier = isConditionMet\r\n ? this.isInitialScroll\r\n ? this.baseVelocityMultiplier\r\n : this.reducedVelocityMultiplier\r\n : this.negativeVelocityMultiplier;\r\n\r\n if (!isConditionMet) {\r\n this.isInitialScroll = false;\r\n }\r\n }\r\n onStart(): void {\r\n this.maxDisplacementValue = this.data.viewport.windowHeight * 0.1;\r\n }\r\n\r\n onResize(): void {\r\n if (window.innerWidth > 1080) {\r\n this.maxDisplacementValue = this.data.viewport.windowHeight * 0.1;\r\n this.onUpdateEvent = this.onUpdateDesktopEvent;\r\n } else {\r\n this.onUpdateEvent = this.onUpdateMobileEvent;\r\n this.resetState();\r\n this.objects.forEach((object) => {\r\n this.setupItem(object);\r\n });\r\n }\r\n }\r\n\r\n private resetState(): void {\r\n this.displacement = 0;\r\n this.acceleration = 0;\r\n this.isInitialScroll = true;\r\n this.velocityMultiplier = this.baseVelocityMultiplier;\r\n }\r\n\r\n onScrollStart(): void {\r\n this.resetState();\r\n }\r\n\r\n onScrollStop(): void {\r\n this.resetState();\r\n this.previousLerp = 0;\r\n //document.documentElement.style.setProperty('--glide', '0');\r\n for (let i = 0; i < this.objects.length; i++) {\r\n let object = this.objects[i];\r\n const transformCompute = `translate3d(0, 0px, 0)`;\r\n object.htmlElement.style.transform = transformCompute;\r\n object.htmlElement.style.setProperty(\r\n \"--glide\",\r\n this.data.scroll.displacement.toString()\r\n );\r\n }\r\n }\r\n\r\n onFrame(data: StringData): void {\r\n this.calcExpanderFactor(this.data.scroll.isScrollingDown === false);\r\n this.acceleration = Math.min(\r\n MAX_DISPLACEMENT,\r\n this.acceleration + ACCELERATION_STEP\r\n );\r\n this.displacement = Math.max(\r\n MIN_DISPLACEMENT,\r\n Math.min(MAX_DISPLACEMENT, this.displacement + this.velocityMultiplier)\r\n );\r\n this.data.scroll.displacement = Math.min(\r\n MAX_VELOCITY,\r\n Math.max(\r\n MIN_VELOCITY,\r\n this.data.scroll.lerped * this.displacement * this.acceleration\r\n )\r\n );\r\n this.objects.forEach((object) => {\r\n this.applyToElementAndConnects(object, (el) => {\r\n el.style.setProperty(\r\n \"--glide\",\r\n this.data.scroll.displacement.toString()\r\n );\r\n });\r\n });\r\n this.previousLerp = this.data.scroll.lerped;\r\n this.onUpdateEvent();\r\n }\r\n}\r\n","import { StringContext } from \"../../core/StringContext\";\r\nimport { StringData } from \"../../core/StringData\";\r\nimport { StringModule } from \"../../core/StringModule\";\r\nimport { StringToolsContainer } from \"../../core/StringToolsContainer\";\r\nimport { StringObject } from \"../../objects/StringObject\";\r\n\r\n/**\r\n * Module that updates the `--lerp` CSS variable on elements\r\n * based on current scroll velocity.\r\n */\r\nexport class StringLerp extends StringModule {\r\n constructor(context: StringContext) {\r\n super(context);\r\n this.htmlKey = \"lerp\";\r\n }\r\n\r\n /**\r\n * Resets the `--lerp` value to 0 when scroll stops.\r\n */\r\n onScrollStop(): void {\r\n this.objects.forEach((object) => {\r\n this.setLerpValue(object, 0);\r\n });\r\n }\r\n\r\n /**\r\n * Updates `--lerp` value for each connected object during scroll.\r\n */\r\n onFrame(data: StringData): void {\r\n const velocity = data.scroll.lerped;\r\n this.objects.forEach((object) => {\r\n this.setLerpValue(object, velocity);\r\n });\r\n }\r\n\r\n /**\r\n * Sets the `--lerp` CSS variable on the object.\r\n */\r\n private setLerpValue(object: StringObject, value: number): void {\r\n this.events.emit(`object:lerp:${object.id}`, value);\r\n object.htmlElement.style.setProperty(\"--lerp\", value.toString());\r\n }\r\n}\r\n","import { StringContext } from \"../../core/StringContext\";\r\nimport { StringData } from \"../../core/StringData\";\r\nimport { StringModule } from \"../../core/StringModule\";\r\nimport { StringToolsContainer } from \"../../core/StringToolsContainer\";\r\nimport { StringObject } from \"../../objects/StringObject\";\r\nimport { EasingFunctionOutput } from \"../../tools/EasingFunctionTool\";\r\nimport LerpVector2Tool from \"../../tools/LerpVector2Tool\";\r\n\r\nexport class StringProgress extends StringModule {\r\n constructor(context: StringContext) {\r\n super(context);\r\n this.htmlKey = \"progress\";\r\n\r\n this.attributesToMap = [\r\n ...this.attributesToMap,\r\n { key: \"enter-el\", type: \"string\", fallback: this.settings[\"enter-el\"] },\r\n { key: \"enter-vp\", type: \"string\", fallback: this.settings[\"enter-vp\"] },\r\n { key: \"exit-el\", type: \"string\", fallback: this.settings[\"exit-el\"] },\r\n { key: \"exit-vp\", type: \"string\", fallback: this.settings[\"exit-vp\"] },\r\n { key: \"easing\", type: \"easing\", fallback: this.settings[\"easing\"] },\r\n ];\r\n }\r\n\r\n /**\r\n * Called when an object is initialized.\r\n */\r\n initializeObject(\r\n globalId: number,\r\n object: StringObject,\r\n element: HTMLElement,\r\n attributes: Record<string, any>\r\n ): void {\r\n super.initializeObject(globalId, object, element, attributes);\r\n }\r\n\r\n /**\r\n * Called on scroll.\r\n */\r\n onScroll(data: StringData): void {\r\n super.onScroll(data);\r\n this.objects.forEach((object) => {\r\n this.setUpObject(object);\r\n });\r\n }\r\n\r\n onObjectConnected(object: StringObject) {\r\n super.onObjectConnected(object);\r\n\r\n object.setProperty(\"setUpObject\", this.setUpObject.bind(this));\r\n object.events.on(\r\n \"enter\",\r\n object.getProperty<(object: StringObject) => void>(\"setUpObject\")\r\n );\r\n }\r\n\r\n private setUpObject(object: StringObject) {\r\n const startPosition = object.getProperty<number>(\"start-position\");\r\n const differencePosition = object.getProperty<number>(\r\n \"difference-position\"\r\n );\r\n const key = object.getProperty<string>(\"key\");\r\n const progress = object.getProperty<EasingFunctionOutput>(\"easing\")(\r\n Math.min(\r\n 1,\r\n Math.max(\r\n 0,\r\n (this.data.scroll.transformedCurrent - startPosition) /\r\n differencePosition\r\n )\r\n )\r\n );\r\n\r\n if (object.getProperty<number>(\"progress\") !== progress) {\r\n this.events.emit(`object:progress:${object.id}`, progress);\r\n object.setProperty<number>(\"progress\", progress);\r\n const progressStr = progress.toString();\r\n this.applyToElementAndConnects(object, (el) => {\r\n el.style.setProperty(key, progressStr);\r\n });\r\n }\r\n }\r\n}\r\n","import { StringContext } from \"../../core/StringContext\";\r\nimport { StringData } from \"../../core/StringData\";\r\nimport { StringObject } from \"../../objects/StringObject\";\r\nimport { StringProgress } from \"./StringProgress\";\r\n\r\nexport class StringParallax extends StringProgress {\r\n constructor(context: StringContext) {\r\n super(context);\r\n this.htmlKey = \"parallax\";\r\n\r\n this.attributesToMap = [\r\n ...this.attributesToMap,\r\n { key: \"parallax\", type: \"number\", fallback: this.settings[\"parallax\"] },\r\n {\r\n key: \"parallax-bias\",\r\n type: \"number\",\r\n fallback: this.settings[\"parallax-bias\"],\r\n },\r\n ];\r\n }\r\n\r\n /**\r\n * Called when an object is initialized.\r\n */\r\n override initializeObject(\r\n globalId: number,\r\n object: StringObject,\r\n element: HTMLElement,\r\n attributes: Record<string, any>\r\n ): void {\r\n super.initializeObject(globalId, object, element, attributes);\r\n const bias = object.getProperty<number>(\"parallax-bias\") ?? 0.0;\r\n const factor = object.getProperty<number>(\"parallax\") ?? 0.2;\r\n\r\n object.setProperty(\"parallax-position-start\", -0.5 + 0.5 * bias);\r\n object.setProperty(\"parallax-position-end\", 0.5 + 0.5 * (1 - bias));\r\n\r\n const screenSize = this.data.viewport.windowHeight;\r\n\r\n object.setProperty(\"offset-top\", factor * screenSize);\r\n object.setProperty(\"offset-bottom\", factor * screenSize);\r\n }\r\n\r\n /**\r\n * Called on scroll.\r\n */\r\n override onScroll(data: StringData): void {\r\n super.onScroll(data);\r\n this.scrollHandler();\r\n }\r\n\r\n /**\r\n * Called on resize.\r\n */\r\n override onResize(): void {\r\n const isDesktop = window.innerWidth > 1080;\r\n this.scrollHandler = isDesktop\r\n ? this.handleScrollDesktop\r\n : this.handleScrollMobile;\r\n\r\n if (!isDesktop) {\r\n this.handleScrollDesktop();\r\n }\r\n }\r\n\r\n private handleScrollDesktop = (): void => {\r\n this.objects.forEach((object) => {\r\n const progress = object.getProperty<number>(\"progress\") ?? 0;\r\n const factor = object.getProperty<number>(\"parallax\") ?? 0;\r\n const start = object.getProperty<number>(\"parallax-position-start\") ?? 0;\r\n const end = object.getProperty<number>(\"parallax-position-end\") ?? 1;\r\n\r\n const screenSize = this.data.viewport.windowHeight;\r\n const translation =\r\n factor * screenSize * start + progress * factor * screenSize * end;\r\n\r\n this.events.emit(`object:parallax:${object.id}`, translation);\r\n const transform = `translate3d(0, ${translation}px, 0)`;\r\n this.applyToElementAndConnects(object, (el) => {\r\n el.style.transform = transform;\r\n });\r\n });\r\n };\r\n\r\n private handleScrollMobile = (): void => {};\r\n\r\n private scrollHandler = this.handleScrollDesktop;\r\n}\r\n","import { StringData } from \"../../core/StringData\";\r\n\r\nexport class StringScrollbarHorizontal {\r\n private scrollbar: any;\r\n private thumb: any;\r\n private isDragging = false;\r\n private startY: number = 0;\r\n private startScrollPosition: number = 0;\r\n data: StringData;\r\n\r\n constructor(data: StringData, scrollbar: any, thumb: any) {\r\n this.data = data;\r\n this.scrollbar = scrollbar;\r\n this.thumb = thumb;\r\n }\r\n\r\n onResize(): void {\r\n const contentWidth = this.data.viewport.contentWidth;\r\n const visibleWidth = this.data.viewport.windowWidth;\r\n\r\n const thumbSize = (visibleWidth / contentWidth) * visibleWidth;\r\n this.thumb.style.setProperty('--size', thumbSize + 'px');\r\n\r\n if (contentWidth <= visibleWidth) {\r\n this.scrollbar.classList.add('-hide');\r\n } else {\r\n this.scrollbar.classList.remove('-hide');\r\n }\r\n }\r\n\r\n updateThumb() {\r\n const contentWidth = this.data.viewport.contentWidth;\r\n const visibleWidth = this.data.viewport.windowWidth;\r\n this.thumb.style.setProperty('--position', `${(this.data.scroll.current / contentWidth) * visibleWidth + 'px'}`);\r\n }\r\n\r\n mouseDownEvent(e: MouseEvent) {\r\n this.startY = e.clientY;\r\n this.startScrollPosition = this.data.scroll.current;\r\n }\r\n\r\n mouseMoveEvent(e: MouseEvent) {\r\n const deltaY = e.clientY - this.startY;\r\n const newScrollPosition = this.startScrollPosition + (deltaY / this.data.viewport.windowWidth) * this.data.viewport.contentWidth;\r\n this.data.scroll.current = newScrollPosition;\r\n this.data.scroll.target = newScrollPosition;\r\n window.scrollTo(0, newScrollPosition);\r\n this.updateThumb();\r\n }\r\n}\r\n","import { StringData } from \"../../core/StringData\";\r\n\r\nexport class StringScrollbarVertical {\r\n private scrollbar: any;\r\n private thumb: any;\r\n private isDragging = false;\r\n private startCoordinate: number = 0;\r\n private startScrollPosition: number = 0;\r\n data: StringData;\r\n\r\n constructor(data: StringData, scrollbar: any, thumb: any) {\r\n this.data = data;\r\n this.scrollbar = scrollbar;\r\n this.thumb = thumb;\r\n }\r\n\r\n onResize(): void {\r\n const contentSize = this.data.viewport.contentHeight;\r\n const visibleSize = this.data.viewport.windowHeight;\r\n const thumbSize = (visibleSize / contentSize) * visibleSize;\r\n this.thumb.style.setProperty('--height', thumbSize + 'px');\r\n if (contentSize <= visibleSize) {\r\n this.scrollbar.classList.add('-hide');\r\n } else {\r\n this.scrollbar.classList.remove('-hide');\r\n }\r\n }\r\n\r\n updateThumb() {\r\n const contentHeight = this.data.viewport.contentHeight;\r\n const visibleHeight = this.data.viewport.windowHeight;\r\n \r\n this.thumb.style.setProperty('--position', `${(this.data.scroll.current / contentHeight) * visibleHeight + 'px'}`);\r\n }\r\n\r\n mouseDownEvent(e: MouseEvent) {\r\n this.startCoordinate = e.clientY;\r\n this.startScrollPosition = this.data.scroll.current;\r\n }\r\n\r\n mouseMoveEvent(e: MouseEvent) {\r\n const deltaY = e.clientY - this.startCoordinate;\r\n const newScrollPosition = this.startScrollPosition + (deltaY / this.data.viewport.windowHeight) * this.data.viewport.contentHeight;\r\n const maxScroll = this.data.scroll.bottomPosition;\r\n const clamped = Math.max(0, Math.min(newScrollPosition, maxScroll));\r\n this.data.scroll.current = clamped;\r\n this.data.scroll.target = clamped;\r\n window.scrollTo(0, clamped);\r\n this.updateThumb();\r\n }\r\n}\r\n","import { StringContext } from '../../core/StringContext';\r\nimport { StringData } from '../../core/StringData';\r\nimport { StringModule } from '../../core/StringModule';\r\nimport { StringScrollbarHorizontal } from './StringScrollbarHorizontal';\r\nimport { StringScrollbarVertical } from './StringScrollbarVertical';\r\n\r\nexport class StringScrollbar extends StringModule {\r\n private scrollbar: any;\r\n private thumb: any;\r\n private scrollTimeout: any;\r\n\r\n private isDragging = false;\r\n private scrollMode: 'smooth' | 'disable' | 'default' = 'smooth';\r\n\r\n private mouseUpEventBind: any;\r\n private mouseDownEventBind: any;\r\n private mouseMoveEventBind: any;\r\n\r\n private scrollbarState: any;\r\n private scrollbarStateHorizontal: any;\r\n private scrollbarStateVertical: any;\r\n\r\n constructor(context: StringContext) {\r\n super(context)\r\n\r\n this.mouseUpEventBind = this.mouseUpEvent.bind(this);\r\n this.mouseDownEventBind = this.mouseDownEvent.bind(this);\r\n this.mouseMoveEventBind = this.mouseMoveEvent.bind(this);\r\n }\r\n destructor(): void {\r\n document.removeEventListener('mouseup', this.mouseUpEventBind);\r\n this.thumb.removeEventListener('mousedown', this.mouseDownEventBind);\r\n document.removeEventListener('mousemove', this.mouseMoveEventBind);\r\n }\r\n\r\n onInit(): void {\r\n this.createScrollbar();\r\n this.updateThumb();\r\n this.addCustomStyles();\r\n document.addEventListener('mouseup', this.mouseUpEventBind);\r\n this.thumb.addEventListener('mousedown', this.mouseDownEventBind);\r\n document.addEventListener('mousemove', this.mouseMoveEventBind);\r\n document.documentElement.classList.add(`-no-scrollbar`);\r\n }\r\n\r\n onScroll(data: StringData): void {\r\n this.updateThumb();\r\n this.showScrollbar();\r\n this.hideScrollbar();\r\n }\r\n\r\n onResize(): void {\r\n this.scrollbarState.onResize();\r\n }\r\n\r\n private addCustomStyles() {\r\n const style = document.createElement('style');\r\n style.textContent = `\r\n ::-webkit-scrollbar {\r\n display: none;\r\n width: 0;\r\n height: 0;\r\n -webkit-appearance: none;\r\n }\r\n body {\r\n -ms-overflow-style: none; /* IE and Edge */\r\n scrollbar-width: none; /* Firefox */\r\n }\r\n .-without-scrollbar::-webkit-scrollbar {\r\n display: none;\r\n }\r\n .-without-scrollbar {\r\n -ms-overflow-style: none; /* IE and Edge */\r\n scrollbar-width: none; /* Firefox */\r\n }\r\n `;\r\n document.head.appendChild(style);\r\n }\r\n\r\n private createScrollbar() {\r\n this.scrollbar = document.createElement('div');\r\n this.scrollbar.classList.add('scrollbar');\r\n this.thumb = document.createElement('div');\r\n this.thumb.classList.add('thumb');\r\n this.scrollbar.appendChild(this.thumb);\r\n document.body.appendChild(this.scrollbar);\r\n\r\n this.scrollbarStateHorizontal = new StringScrollbarHorizontal(this.data, this.scrollbar, this.thumb);\r\n this.scrollbarStateVertical = new StringScrollbarVertical(this.data, this.scrollbar, this.thumb);\r\n this.scrollbarState = this.scrollbarStateVertical;\r\n }\r\n\r\n private updateThumb() {\r\n this.scrollbarState.updateThumb();\r\n }\r\n\r\n private mouseDownEvent(e: MouseEvent) {\r\n this.isDragging = true;\r\n this.scrollbarState.mouseDownEvent(e);\r\n document.body.style.userSelect = 'none';\r\n this.scrollbar.classList.add('-touch');\r\n }\r\n\r\n private mouseMoveEvent(e: MouseEvent) {\r\n if (!this.isDragging) return;\r\n\r\n this.scrollbarState.mouseMoveEvent(e);\r\n }\r\n\r\n private mouseUpEvent() {\r\n this.isDragging = false;\r\n document.body.style.userSelect = '';\r\n this.hideScrollbar();\r\n this.scrollbar.classList.remove('-touch');\r\n }\r\n\r\n private showScrollbar() {\r\n this.scrollbar.classList.add('-scroll');\r\n }\r\n\r\n private hideScrollbar() {\r\n if (this.scrollTimeout) {\r\n clearTimeout(this.scrollTimeout);\r\n }\r\n this.scrollTimeout = setTimeout(() => {\r\n this.scrollbar.classList.remove('-scroll');\r\n }, 1000);\r\n }\r\n}\r\n","import { StringContext } from \"../../core/StringContext\";\r\nimport { StringModule } from \"../../core/StringModule\";\r\nimport { ISplitOptions } from \"../../models/text/ISplitOptions\";\r\nimport { LayoutLine } from \"../../models/text/LayoutLine\";\r\nimport { ProcessedChar } from \"../../models/text/ProcessedChar\";\r\nimport { ProcessedWord } from \"../../models/text/ProcessedWord\";\r\nimport { StringObject } from \"../../objects/StringObject\";\r\n\r\n/**\r\n * StringModule responsible for splitting text within HTML elements\r\n * into lines, words, and characters based on layout and attributes,\r\n * and applying CSS variables for animation purposes.\r\n * Uses a tool-based approach for modularity.\r\n */\r\nexport class StringSplit extends StringModule {\r\n /**\r\n * Initializes the StringSplit module and its tools.\r\n * @param context - The global StringContext.\r\n */\r\n constructor(context: StringContext) {\r\n super(context);\r\n this.htmlKey = \"split\";\r\n // Assuming tools are initialized in the base class or here if needed\r\n }\r\n\r\n /**\r\n * Called when the module initializes.\r\n * Processes elements already present in the DOM on load.\r\n */\r\n onInit(): void {\r\n document\r\n .querySelectorAll(`[string=\"${this.htmlKey}\"]`)\r\n .forEach((element) => {\r\n if (element instanceof HTMLElement) {\r\n this.processElement(element);\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Called when the window is resized.\r\n * Re-processes already split elements as their layout might have changed.\r\n */\r\n onResize(): void {\r\n document\r\n .querySelectorAll(`[string=\"${this.htmlKey}\"].-splited`)\r\n .forEach((element) => {\r\n if (element instanceof HTMLElement) {\r\n this.processElement(element);\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Called when a new StringObject associated with this module connects.\r\n * Processes the newly connected element.\r\n * @param object - The StringObject representing the connected element.\r\n */\r\n onObjectConnected(object: StringObject): void {\r\n this.processElement(object.htmlElement);\r\n }\r\n\r\n /**\r\n * Central method to process splitting for a given HTML element for automatic DOM manipulation.\r\n * Orchestrates the use of various tools: parsing options, calculating layout,\r\n * indexing words and characters, building the final HTML, and updating the DOM.\r\n * Includes error handling.\r\n * @param element - The HTMLElement to process.\r\n * @private\r\n */\r\n private processElement(element: HTMLElement): void {\r\n if (!element) return;\r\n\r\n const isAlreadySplit = element.classList.contains(\"-splited\");\r\n let originalHtml = element.getAttribute(\"string-split-original\");\r\n\r\n if (!isAlreadySplit || originalHtml === null) {\r\n originalHtml = element.innerHTML;\r\n element.setAttribute(\"string-split-original\", originalHtml);\r\n element.classList.add(\"-splited\");\r\n }\r\n\r\n if (!originalHtml || originalHtml.trim() === \"\") {\r\n if (element.innerHTML !== \"\") element.innerHTML = \"\";\r\n return;\r\n }\r\n\r\n try {\r\n // Note: Assumes SplitOptionsParserTool exists on this.tools\r\n const attributeValue = element.getAttribute(\"string-split\");\r\n const options: ISplitOptions = this.tools.optionsParser.process({\r\n attributeValue,\r\n });\r\n\r\n const newHtml = this.generateSplitHtml(originalHtml, element, options);\r\n\r\n // Only update DOM if the generated HTML is different\r\n if (element.innerHTML !== newHtml) {\r\n element.innerHTML = newHtml;\r\n }\r\n } catch (error) {\r\n console.error(\"StringSplit: Error processing element:\", element, error);\r\n // Revert to original HTML as a fallback strategy\r\n if (originalHtml !== null) {\r\n try {\r\n if (element.innerHTML !== originalHtml) {\r\n element.innerHTML = originalHtml;\r\n }\r\n } catch (revertError) {\r\n console.error(\r\n \"StringSplit: Error reverting element to original HTML:\",\r\n element,\r\n revertError\r\n );\r\n // If reverting fails, at least clear it to avoid broken state\r\n element.innerHTML = \"\";\r\n }\r\n } else {\r\n // If no original HTML was stored, just clear it\r\n element.innerHTML = \"\";\r\n }\r\n // Remove the split marker class as processing failed\r\n element.classList.remove(\"-splited\");\r\n }\r\n }\r\n\r\n /**\r\n * Generates an HTML string with split text based on the provided text,\r\n * a reference element for layout measurement, and options. Does not modify the DOM.\r\n *\r\n * @param textToSplit - The text or HTML string to split.\r\n * @param layoutReferenceElement - The HTMLElement used for layout calculations. Should be in the DOM for accurate results.\r\n * @param options - The splitting options (ISplitOptions).\r\n * @returns The generated HTML string with split elements, or an empty string on error.\r\n * @public\r\n */\r\n public generateSplitHtml(\r\n textToSplit: string,\r\n layoutReferenceElement: HTMLElement,\r\n options: ISplitOptions\r\n ): string {\r\n // Basic validation for tools and inputs\r\n if (\r\n !this.tools?.layoutSplitter ||\r\n !this.tools?.wordIndexer ||\r\n !this.tools?.charIndexer ||\r\n !this.tools?.domBuilder\r\n ) {\r\n console.error(\"StringSplit: Required tools are not initialized.\");\r\n return \"\";\r\n }\r\n if (!textToSplit || !layoutReferenceElement) {\r\n console.error(\"StringSplit.generateSplitHtml: Invalid input provided.\");\r\n return \"\";\r\n }\r\n // Warn if the reference element isn't in the DOM, as measurements might be incorrect\r\n if (!layoutReferenceElement.isConnected) {\r\n console.warn(\r\n \"StringSplit.generateSplitHtml: layoutReferenceElement is not connected to the DOM. Layout calculation might be inaccurate.\"\r\n );\r\n }\r\n\r\n try {\r\n // Steps analogous to processElement, but without DOM mutation or attribute handling\r\n const textForLayout = textToSplit; // Assuming input text is ready\r\n\r\n // Note: Assumes layoutSplitter has 'decodeHtmlEntity' or similar utility\r\n const textForCharCount =\r\n this.tools.layoutSplitter[\"decodeHtmlEntity\"](textForLayout);\r\n const totalChars = textForCharCount.replace(/\\s+/g, \"\").length;\r\n\r\n // Calculate layout (lines and words) using the reference element\r\n const layoutLines: LayoutLine[] = this.tools.layoutSplitter.process({\r\n text: textForLayout,\r\n targetElement: layoutReferenceElement,\r\n });\r\n\r\n // If layout calculation yields no lines (e.g., element is display:none) return empty string.\r\n if (layoutLines.length === 0 && textForLayout.trim() !== \"\") {\r\n console.warn(\r\n \"StringSplit: Layout calculation resulted in no lines for text:\",\r\n textForLayout,\r\n \"within element:\",\r\n layoutReferenceElement\r\n );\r\n return \"\";\r\n }\r\n\r\n // Index words based on layout and options\r\n const processedWords: ProcessedWord[] = this.tools.wordIndexer.process({\r\n lines: layoutLines,\r\n options: { word: options.word, wordLine: options.wordLine },\r\n });\r\n\r\n // Index characters based on words, lines, options, and total count\r\n const processedChars: ProcessedChar[] = this.tools.charIndexer.process({\r\n processedWords: processedWords,\r\n lines: layoutLines,\r\n options: {\r\n char: options.char,\r\n charLine: options.charLine,\r\n charWord: options.charWord,\r\n },\r\n totalChars: totalChars,\r\n });\r\n\r\n // Build the final DOM structure as a string\r\n // Note: Assumes domBuilder tool exists\r\n const newHtml: string = this.tools.domBuilder.process({\r\n lines: layoutLines,\r\n words: processedWords,\r\n chars: processedChars,\r\n options: options, // Pass all options for potential checks in builder\r\n });\r\n\r\n return newHtml; // Return the generated string\r\n } catch (error) {\r\n console.error(\r\n \"StringSplit.generateSplitHtml: Error processing text:\",\r\n textToSplit,\r\n \"within element:\",\r\n layoutReferenceElement,\r\n error\r\n );\r\n return \"\"; // Return empty string on error\r\n }\r\n }\r\n\r\n /**\r\n * Example demonstrating how to use generateSplitHtml.\r\n * @param spanElement - The element to split and use for layout reference.\r\n * @returns The resulting HTML string.\r\n * @public\r\n */\r\n public exampleUsage(spanElement: HTMLElement): string {\r\n // Define sample options\r\n const options: ISplitOptions = {\r\n word: [{ align: \"center\" }],\r\n char: [\r\n {\r\n align: \"start\",\r\n random: { min: 0, max: spanElement.textContent?.length || 0 },\r\n abs: true,\r\n },\r\n ],\r\n };\r\n // Get the text content to split (use innerHTML if splitting HTML tags is intended)\r\n const textContent = spanElement.innerHTML;\r\n\r\n // Generate the split HTML string\r\n const splitedHTML = this.generateSplitHtml(\r\n textContent,\r\n spanElement, // Use the element itself for layout reference\r\n options\r\n );\r\n\r\n return splitedHTML;\r\n }\r\n}\r\n","import { StringContext } from \"../../core/StringContext\"\r\nimport { StringData } from \"../../core/StringData\"\r\nimport { StringModule } from \"../../core/StringModule\"\r\n\r\n/**\r\n * Visual tracker that plots scroll displacement (velocity) in real time.\r\n * Useful for debugging and tuning smoothing behavior.\r\n */\r\nexport class StringDelayLerpTracker extends StringModule {\r\n private canvas!: HTMLCanvasElement\r\n private context!: CanvasRenderingContext2D\r\n private history: number[] = []\r\n\r\n private maxPoints = 0\r\n private height = 0\r\n private value = 0\r\n private target = 0\r\n\r\n constructor(context: StringContext) {\r\n super(context)\r\n this._type = 2\r\n }\r\n\r\n /**\r\n * Called when the module starts — sets up canvas.\r\n */\r\n onInit(): void {\r\n this.initCanvas()\r\n this.maxPoints = this.canvas.width\r\n }\r\n\r\n /**\r\n * Called on scroll — stores current displacement and redraws.\r\n */\r\n onScroll(data: StringData): void {\r\n const d = Math.abs(data.scroll.displacement)\r\n this.value = d\r\n this.history.push(d)\r\n\r\n if (this.history.length > this.maxPoints) {\r\n this.history.shift()\r\n }\r\n\r\n this.draw()\r\n }\r\n\r\n /**\r\n * Draws the displacement graph to canvas.\r\n */\r\n private draw(): void {\r\n const ctx = this.context\r\n const w = this.canvas.width\r\n const h = this.canvas.height\r\n\r\n ctx.clearRect(0, 0, w, h)\r\n\r\n ctx.strokeStyle = \"red\"\r\n ctx.lineWidth = 2\r\n ctx.beginPath()\r\n\r\n this.history.forEach((val, i) => {\r\n const x = i\r\n const y = h - val * this.height\r\n i === 0 ? ctx.moveTo(x, y) : ctx.lineTo(x, y)\r\n })\r\n\r\n ctx.stroke()\r\n }\r\n\r\n /**\r\n * Creates and styles the tracking canvas.\r\n */\r\n private initCanvas(): void {\r\n const canvas = document.createElement(\"canvas\")\r\n const width = window.innerWidth * 0.5\r\n this.height = window.innerHeight / 15 - 20\r\n\r\n canvas.width = width\r\n canvas.height = this.height\r\n\r\n Object.assign(canvas.style, {\r\n position: \"fixed\",\r\n bottom: `${window.innerHeight / 20 + 10}px`,\r\n left: \"50%\",\r\n transform: \"translateX(-50%)\",\r\n backgroundColor: \"#000000\",\r\n border: \"1px solid rgba(255, 255, 255, 0.2)\",\r\n zIndex: \"1000\",\r\n pointerEvents: \"none\",\r\n })\r\n\r\n this.canvas = canvas\r\n this.context = canvas.getContext(\"2d\")!\r\n document.body.appendChild(canvas)\r\n }\r\n\r\n /**\r\n * Optional method to update external comparison target.\r\n */\r\n public setTarget(position: number): void {\r\n this.target = position\r\n }\r\n\r\n /**\r\n * Removes the canvas from DOM and resets.\r\n */\r\n public clear(): void {\r\n this.canvas.remove()\r\n this.history = []\r\n }\r\n}\r\n","import { StringData } from \"../..\"\r\nimport { StringContext } from \"../../core/StringContext\"\r\nimport { StringModule } from \"../../core/StringModule\"\r\n\r\n/**\r\n * FPS Tracker Module.\r\n * Displays how many times `onFrame()` is called per second.\r\n * Useful for debugging rendering performance or vsync issues.\r\n */\r\nexport class StringFPSTracker extends StringModule {\r\n private displayElement!: HTMLDivElement\r\n private intervalId!: number\r\n private frameCount = 0\r\n\r\n constructor(context: StringContext) {\r\n super(context)\r\n this._type = 2\r\n }\r\n\r\n /**\r\n * Initializes the visual FPS counter and update interval.\r\n */\r\n onInit(): void {\r\n this.createDisplayElement()\r\n\r\n this.intervalId = window.setInterval(() => {\r\n this.displayElement.textContent = `FPS: ${this.frameCount}`\r\n this.frameCount = 0\r\n }, 1000)\r\n }\r\n\r\n /**\r\n * Increments the frame counter each frame.\r\n */\r\n onFrame(_data: StringData): void {\r\n this.frameCount++\r\n }\r\n\r\n /**\r\n * Cleans up DOM and interval.\r\n */\r\n destroy(): void {\r\n clearInterval(this.intervalId)\r\n this.displayElement.remove()\r\n }\r\n\r\n /**\r\n * Creates and styles the floating FPS display.\r\n */\r\n private createDisplayElement(): void {\r\n const el = document.createElement(\"div\")\r\n\r\n Object.assign(el.style, {\r\n position: \"fixed\",\r\n bottom: \"10px\",\r\n right: \"10px\",\r\n backgroundColor: \"#000\",\r\n color: \"#fff\",\r\n padding: \"4px 8px\",\r\n fontSize: \"12px\",\r\n fontFamily: \"monospace\",\r\n border: \"1px solid rgba(255,255,255,0.2)\",\r\n zIndex: \"1000\",\r\n pointerEvents: \"none\",\r\n })\r\n\r\n el.textContent = \"FPS: 0\"\r\n document.body.appendChild(el)\r\n\r\n this.displayElement = el\r\n }\r\n}\r\n","import { StringData } from \"../..\"\r\nimport { StringContext } from \"../../core/StringContext\"\r\nimport { StringModule } from \"../../core/StringModule\"\r\n\r\n/**\r\n * Visual tracker that plots lerped scroll velocity (v) in real time.\r\n * Useful for analyzing smooth scroll interpolation behavior.\r\n */\r\nexport class StringLerpTracker extends StringModule {\r\n private canvas!: HTMLCanvasElement\r\n private context!: CanvasRenderingContext2D\r\n private history: number[] = []\r\n\r\n private maxPoints = 0\r\n private canvasHeight = 0\r\n private currentValue = 0\r\n private targetValue = 0\r\n\r\n constructor(context: StringContext) {\r\n super(context)\r\n this._type = 2\r\n }\r\n\r\n /**\r\n * Called on start — sets up canvas overlay.\r\n */\r\n onInit(): void {\r\n this.initCanvas()\r\n this.maxPoints = this.canvas.width\r\n }\r\n\r\n /**\r\n * Called on scroll — reads smoothed scroll velocity (v).\r\n */\r\n onScroll(data: StringData): void {\r\n const v = Math.abs(data.scroll.displacement)\r\n this.currentValue = v\r\n this.history.push(v)\r\n\r\n if (this.history.length > this.maxPoints) {\r\n this.history.shift()\r\n }\r\n\r\n this.draw()\r\n }\r\n\r\n /**\r\n * Draws the current graph line based on v-history.\r\n */\r\n private draw(): void {\r\n const ctx = this.context\r\n const w = this.canvas.width\r\n const h = this.canvas.height\r\n\r\n ctx.clearRect(0, 0, w, h)\r\n\r\n ctx.strokeStyle = \"#007bff\"\r\n ctx.lineWidth = 2\r\n ctx.beginPath()\r\n\r\n this.history.forEach((val, i) => {\r\n const x = i\r\n const y = h - val / 2\r\n i === 0 ? ctx.moveTo(x, y) : ctx.lineTo(x, y)\r\n })\r\n\r\n ctx.stroke()\r\n }\r\n\r\n /**\r\n * Creates the canvas overlay and applies style.\r\n */\r\n private initCanvas(): void {\r\n this.canvas = document.createElement(\"canvas\")\r\n this.canvasHeight = window.innerHeight / 15 - 20\r\n this.canvas.width = window.innerWidth * 0.5\r\n this.canvas.height = this.canvasHeight\r\n\r\n Object.assign(this.canvas.style, {\r\n position: \"fixed\",\r\n bottom: \"10px\",\r\n left: \"50%\",\r\n transform: \"translateX(-50%)\",\r\n backgroundColor: \"#000\",\r\n border: \"1px solid rgba(255,255,255,0.2)\",\r\n zIndex: \"1000\",\r\n pointerEvents: \"none\",\r\n })\r\n\r\n this.context = this.canvas.getContext(\"2d\")!\r\n document.body.appendChild(this.canvas)\r\n }\r\n\r\n /**\r\n * Optional external target value for debugging.\r\n */\r\n public setTarget(position: number): void {\r\n this.targetValue = position\r\n }\r\n\r\n /**\r\n * Removes canvas from DOM and clears history.\r\n */\r\n public clear(): void {\r\n this.canvas.remove()\r\n this.history = []\r\n }\r\n}\r\n","import { StringData } from \"../..\"\r\nimport { StringContext } from \"../../core/StringContext\"\r\nimport { StringModule } from \"../../core/StringModule\"\r\n\r\n/**\r\n * Tracker module that shows current scroll position and direction.\r\n * Displays a fixed label in the corner of the screen for debugging.\r\n */\r\nexport class StringPositionTracker extends StringModule {\r\n private displayElement!: HTMLDivElement\r\n\r\n constructor(context: StringContext) {\r\n super(context)\r\n this._type = 2\r\n }\r\n\r\n /**\r\n * Called on start — creates the DOM element for position display.\r\n */\r\n onInit(): void {\r\n this.createDisplayElement()\r\n }\r\n\r\n /**\r\n * Called on scroll — updates scroll position and direction symbol.\r\n */\r\n onScroll(data: StringData): void {\r\n const current = data.scroll.current\r\n const target = data.scroll.target\r\n\r\n const direction = current < target ? \"↓\" : current > target ? \"↑\" : \"-\"\r\n\r\n this.displayElement.setAttribute(\"data-dir\", direction)\r\n this.displayElement.setAttribute(\"data-val\", `${Math.round(current)}`)\r\n }\r\n\r\n /**\r\n * Removes display element from DOM.\r\n */\r\n destroy(): void {\r\n this.displayElement.remove()\r\n }\r\n\r\n /**\r\n * Creates and styles the floating position indicator.\r\n */\r\n private createDisplayElement(): void {\r\n const el = document.createElement(\"div\")\r\n\r\n Object.assign(el.style, {\r\n position: \"fixed\",\r\n bottom: \"10px\",\r\n left: \"10px\",\r\n backgroundColor: \"#000\",\r\n color: \"#fff\",\r\n border: \"1px solid rgba(255,255,255,0.2)\",\r\n padding: \"5px 8px\",\r\n fontSize: \"12px\",\r\n fontFamily: \"monospace\",\r\n zIndex: \"1000\",\r\n pointerEvents: \"none\",\r\n })\r\n\r\n el.setAttribute(\"data-dir\", \"-\")\r\n el.setAttribute(\"data-val\", \"0\")\r\n document.body.appendChild(el)\r\n\r\n // Inject dynamic CSS if needed\r\n const style = document.createElement(\"style\")\r\n style.innerHTML = `\r\n div[data-dir][data-val]::before {\r\n content: attr(data-dir) ' Top: ' attr(data-val) 'px';\r\n }\r\n `\r\n document.head.appendChild(style)\r\n\r\n this.displayElement = el\r\n }\r\n}\r\n","/**\r\n * Creates a debounced version of a function that delays invoking the function\r\n * until after `delay` milliseconds have passed since the last time the\r\n * debounced function was invoked.\r\n *\r\n * @template T The type of the function to debounce.\r\n * @param func The function to debounce.\r\n * @param delay The number of milliseconds to delay.\r\n * @returns The new debounced function.\r\n */\r\nexport function Debounce<T extends (...args: any[]) => any>(func: T, delay: number): (...args: Parameters<T>) => void {\r\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\r\n\r\n // Return a new function that will be called instead of the original\r\n return function(this: ThisParameterType<T>, ...args: Parameters<T>) {\r\n // Capture the 'this' context and arguments for the original function\r\n const context = this;\r\n\r\n // If there is already a scheduled call, cancel it\r\n if (timeoutId) {\r\n clearTimeout(timeoutId);\r\n }\r\n\r\n // Schedule a new call to the original function after 'delay' ms\r\n timeoutId = setTimeout(() => {\r\n func.apply(context, args); // Call the original function with the correct 'this' and arguments\r\n timeoutId = null; // Clear the timer ID after execution (optional but good practice)\r\n }, delay);\r\n };\r\n}","/**\r\n * Utility class that provides a customizable requestAnimationFrame loop.\r\n * Allows running a callback function on every frame or at a specific FPS rate.\r\n * Automatically pauses on `document.hidden` and resumes on visibility change.\r\n */\r\nexport class StringFPS {\r\n /** Target frames per second (FPS). */\r\n private fps: number = 0;\r\n\r\n /** Whether the animation loop is currently active. */\r\n private isAnimationStarted: boolean = false;\r\n\r\n /** Time interval between frames in milliseconds, based on FPS. */\r\n private fpsInterval: number = 0;\r\n\r\n /** Timestamp of the previous frame (used for timing calculations). */\r\n private then: number = 0;\r\n\r\n /** The requestAnimationFrame ID (used to cancel the loop). */\r\n private requestAnimationId: number = 0;\r\n\r\n /** Bound function for visibilitychange event handler. */\r\n private onVisibilityChangeBind: any;\r\n\r\n /** Callback executed on each frame. */\r\n private onFrameCallback: (time: number) => void = (time: number) => {};\r\n\r\n /** Internal animation loop function. */\r\n private animate: () => void = () => {};\r\n\r\n constructor() {\r\n this.onVisibilityChangeBind = this.onVisibilityChange.bind(this);\r\n }\r\n\r\n /**\r\n * Handles visibility change events.\r\n * Stops the loop when the document is hidden and resumes it when visible.\r\n */\r\n private onVisibilityChange() {\r\n if (document.hidden) {\r\n this.stop();\r\n this.isAnimationStarted = false;\r\n } else {\r\n this.start(this.fps);\r\n }\r\n }\r\n\r\n /**\r\n * Starts the animation loop at a given FPS rate.\r\n * If `fps` is 0, runs the callback as fast as possible (uncapped).\r\n * \r\n * @param fps Target frames per second (0 = uncapped).\r\n */\r\n public start(fps: number) {\r\n this.fps = fps;\r\n if (this.isAnimationStarted) return;\r\n\r\n this.fpsInterval = 1000 / fps;\r\n this.then = performance.now();\r\n this.isAnimationStarted = true;\r\n\r\n if (fps === 0) {\r\n this.animate = () => {\r\n const now = performance.now();\r\n this.requestAnimationId = requestAnimationFrame(() => this.animate());\r\n this.onFrameCallback(now);\r\n };\r\n } else {\r\n this.animate = () => {\r\n const now = performance.now();\r\n const elapsed = now - this.then;\r\n if (elapsed > this.fpsInterval) {\r\n this.then = now - (elapsed % this.fpsInterval);\r\n this.onFrameCallback(now);\r\n }\r\n this.requestAnimationId = requestAnimationFrame(() => this.animate());\r\n };\r\n }\r\n\r\n this.animate();\r\n // document.addEventListener(\"visibilitychange\", this.onVisibilityChangeBind);\r\n }\r\n\r\n /**\r\n * Stops the animation loop and removes the animation frame.\r\n */\r\n public stop() {\r\n if (!this.isAnimationStarted) return;\r\n cancelAnimationFrame(this.requestAnimationId);\r\n this.requestAnimationId = 0;\r\n this.isAnimationStarted = false;\r\n }\r\n\r\n /**\r\n * Assigns a callback function to be called on each frame.\r\n * \r\n * @param callback The function to execute per frame.\r\n */\r\n public setOnFrame(callback: (time: number) => void) {\r\n this.onFrameCallback = callback;\r\n }\r\n\r\n /**\r\n * Stops the loop and removes event listeners.\r\n * Should be called when the loop is no longer needed.\r\n */\r\n public destructor() {\r\n this.stop();\r\n // document.removeEventListener(\"visibilitychange\", this.onVisibilityChangeBind);\r\n }\r\n}\r\n","import { StringObject } from \"../../objects/StringObject\";\r\nimport { StringModule } from \"../../core/StringModule\";\r\nimport { StringContext } from \"../../core/StringContext\";\r\n\r\nexport class StringVideoAutoplay extends StringModule {\r\n constructor(context: StringContext) {\r\n super(context);\r\n this.htmlKey = \"autoplay\";\r\n\r\n this.attributesToMap = [\r\n ...this.attributesToMap,\r\n {\r\n key: \"src\",\r\n type: \"string\",\r\n fallback: \"\",\r\n },\r\n ];\r\n }\r\n\r\n onObjectConnected(object: StringObject) {\r\n object.setProperty(\"onEnterEvent\", this.onEnterObject.bind(this));\r\n object.events.on(\r\n \"enter\",\r\n object.getProperty<(object: StringObject) => void>(\"onEnterEvent\")\r\n );\r\n object.setProperty(\"onLeaveEvent\", this.onLeaveObject.bind(this));\r\n object.events.on(\r\n \"leave\",\r\n object.getProperty<(object: StringObject) => void>(\"onLeaveEvent\")\r\n );\r\n\r\n const videoElement = object.htmlElement as HTMLVideoElement;\r\n const started =\r\n this.tools.domAttribute.process({\r\n element: videoElement,\r\n key: \"string-started\",\r\n fallback: null,\r\n }) !== null;\r\n\r\n if (videoElement.tagName.toLowerCase() === \"video\" && !started) {\r\n videoElement.setAttribute(\"string-started\", \"\");\r\n videoElement.muted = true;\r\n videoElement.setAttribute(\"muted\", \"muted\");\r\n videoElement.setAttribute(\"playsinline\", \"\");\r\n videoElement.setAttribute(\"loop\", \"\");\r\n videoElement.setAttribute(\"autoplay\", \"\");\r\n videoElement.src = object.getProperty(\"src\");\r\n videoElement.load();\r\n videoElement.addEventListener(\"canplay\", () => {});\r\n }\r\n }\r\n\r\n private onEnterObject(object: StringObject) {\r\n const videoElement = object.htmlElement as HTMLVideoElement;\r\n this.tryPlay(videoElement);\r\n }\r\n private onLeaveObject(object: StringObject) {\r\n const videoElement = object.htmlElement as HTMLVideoElement;\r\n videoElement.pause();\r\n }\r\n\r\n private tryPlay(element: HTMLVideoElement) {\r\n element\r\n .play()\r\n .catch((err) =>\r\n console.warn(\"[StringVideoAutoplay] Autoplay failed:\", err)\r\n );\r\n }\r\n}\r\n"],"mappings":"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","names":["index_exports","__export","StringAnchor","StringCursor","StringData","StringDelayLerpTracker","StringFPSTracker","StringGlide","StringLazy","StringLerp","StringLerpTracker","StringLoading","StringMagnetic","StringModule","StringObject","StringParallax","StringPositionTracker","StringProgress","StringResponsive","StringScrollbar","StringSplit","StringTune","StringVideoAutoplay","__toCommonJS","CursorController","smoothing","context","e","targetX","targetY","smoothedX","smoothedY","stepX","stepY","distance","lerp","x","y","EventManager","eventName","callback","id","fullEvent","payload","set","value","visible","ModuleManager","data","module","type","m","e","added","removed","StringObject","id","element","EventManager","key","value","module","ObjectManager","data","modules","events","el","idAttr","key","object","StringObject","keysAttr","attributes","m","q","item","id","obj","element","attr","start","end","inviewTop","inviewBottom","progressCallback","entries","e","inviewCallback","progressObserver","inviewObserver","mutations","mutation","node","child","copyFrom","ScrollController","context","scrollDirection","e","StringScrollDefault","ScrollController","context","delta","scrollTop","plusDelta","StringScrollDisable","ScrollController","context","CLASS_NAMES","StringScrollSmooth","ScrollController","context","newDirection","absVelocity","scrollDirection","atTop","atBottom","ScrollManager","context","StringScrollSmooth","StringScrollDefault","StringScrollDisable","mode","newMode","engine","e","events","CursorState","RenderState","ScrollState","TimeState","ViewportState","StringData","ScrollState","ViewportState","CursorState","RenderState","TimeState","StringModule","context","element","object","boundingRect","top","height","globalId","attributes","key","type","fallback","transform","resolvedFallback","raw","parsed","windowSize","start","size","offsetStart","offsetEnd","startElement","startViewport","endElement","endViewport","startPosition","endPosition","startBias","endBias","value","id","index","applyFn","data","event","added","removed","BoundingClientRectTool","element","DOMAttributeTool","element","key","fallback","RecordAttributeTool","record","name","fallback","TransformNullifyTool","element","rect","values","a","b","c","d","e","f","det","RelativePositionTool","transformTool","TransformNullifyTool","element","container","containerRect","elRect","LerpTool","from","to","progress","UnitParserTool","value","element","viewportHeight","baseRem","isNegative","result","AdaptiveLerpTool","value","inMin","inMax","outMin","outMax","t","OriginParserTool","value","raw","options","s","index","ColorParserTool","value","str","hex","ch","r","g","b","a","rgbMatch","v","hslMatch","h","s","l","hue2rgb","p","q","t","ValidationTool","value","rules","messages","rule","code","raw","message","EasingFunctionTool","easing","def","match","x1","y1","x2","y2","t","cx","bx","ax","cy","by","ay","sampleCurveX","sampleCurveY","sampleCurveDerivativeX","solveCurveX","x","epsilon","t0","t1","t2","d2","i","MagneticPullTool","distance","radius","strength","proximity","LerpColorTool","from","to","progress","LerpVector2Tool","from","to","progress","TransformScaleParserTool","value","str","matrixValues","matrixNumbers","s","scaleValue","scaleNumbers","scaleXValue","scaleNumber","scale3dValue","matrix3dValues","error","CharIndexerTool","processedWords","lines","options","totalChars","processedChars","globalCharIndex","totalLineCharsMap","line","lineIndex","totalCharsInLine","sum","word","currentLineCharIndex","previousLineIndex","pWord","wordText","parentLineIndex","wordLength","totalCharsInCurrentLine","char","wordCharIndex","calculatedValues","optDef","value","option","primaryIndex","localIndex","parentLength","index","min","max","effectiveMin","effectiveMax","LayoutLineSplitterTool","text","targetElement","words","word","tempSpan","compStyles","layoutLines","currentLineWords","currentLineWidth","spaceWidth","containerWidth","wordWidth","potentialWidth","w","str","SplitDomBuilderTool","lines","words","chars","options","rootElement","wordCounter","charCounter","needsLineSpans","needsWordSpans","needsCharSpans","line","lineIndex","lineContainer","wordsInThisLine","pWord","indexInLine","currentWordChars","wordSpan","pChar","charSpan","span","calculatedValues","calcValue","variableName","type","align","WordIndexerTool","lines","options","processedWords","globalWordIndex","totalWords","sum","line","lineIndex","wordsInLine","lineWordCount","word","wordIndexInLine","calculatedValues","optDef","value","option","primaryIndex","localIndex","parentLength","index","min","max","effectiveMin","effectiveMax","SplitOptionsParserTool","attributeValue","options","part","trimmedPart","match","prefix","optionType","fullOptionKey","params","p","parsedParam","result","param","randomMatch","DefaultToolsContainer","DOMAttributeTool","RecordAttributeTool","TransformNullifyTool","BoundingClientRectTool","RelativePositionTool","UnitParserTool","LerpTool","AdaptiveLerpTool","OriginParserTool","ColorParserTool","ValidationTool","EasingFunctionTool","MagneticPullTool","LerpColorTool","LerpVector2Tool","TransformScaleParserTool","LayoutLineSplitterTool","WordIndexerTool","CharIndexerTool","SplitDomBuilderTool","SplitOptionsParserTool","StringCursor","StringModule","context","value","globalId","object","element","attributes","data","isOver","isDisabled","lerpFactor","rect","cursorX","cursorY","elementX","elementY","px","py","dx","dy","lerpedX","lerpedY","updatedX","updatedY","alignment","offsetX","offsetY","mouseX","mouseY","halfWidth","halfHeight","targetX","targetY","newMouseX","newMouseY","stepX","stepY","smoothedX","smoothedY","cursorClass","x","y","el","mousePos","size","StringMagnetic","StringModule","context","globalId","object","element","attributes","e","rect","centerX","centerY","dx","dy","distance","radius","strength","factor","data","magneticX","magneticY","lerp","targetMagneticX","targetMagneticY","lerpX","lerpY","el","StringLazy","StringModule","context","img","object","src","el","url","resolve","reject","xhr","blob","StringLoading","StringModule","context","StringInview","StringModule","visitor","object","StringResponsiveQueryDevice","config","enable","min","max","query","StringResponsive","StringModule","context","isMobileMedia","isTabletMedia","isLaptopMedia","isDesktopMedia","element","showElement","StringAnchor","StringModule","context","tuple","xRaw","yRaw","x","y","object","anchor","el","ACCELERATION_STEP","MIN_DISPLACEMENT","MAX_DISPLACEMENT","MIN_VELOCITY","MAX_VELOCITY","StringGlide","StringModule","context","object","glide","glideValue","transformCompute","i","isDirectionUp","isConditionMet","data","el","StringLerp","StringModule","context","object","data","velocity","value","StringProgress","StringModule","context","globalId","object","element","attributes","data","startPosition","differencePosition","key","progress","progressStr","el","StringParallax","StringProgress","context","object","progress","factor","start","end","screenSize","translation","transform","el","globalId","element","attributes","bias","data","isDesktop","StringScrollbarHorizontal","data","scrollbar","thumb","contentWidth","visibleWidth","thumbSize","e","deltaY","newScrollPosition","StringScrollbarVertical","data","scrollbar","thumb","contentSize","visibleSize","thumbSize","contentHeight","visibleHeight","e","deltaY","newScrollPosition","maxScroll","clamped","StringScrollbar","StringModule","context","data","style","StringScrollbarHorizontal","StringScrollbarVertical","StringSplit","StringModule","context","element","object","isAlreadySplit","originalHtml","attributeValue","options","newHtml","error","revertError","textToSplit","layoutReferenceElement","textForLayout","totalChars","layoutLines","processedWords","processedChars","spanElement","textContent","StringDelayLerpTracker","StringModule","context","data","d","ctx","w","h","val","i","x","y","canvas","width","position","StringFPSTracker","StringModule","context","_data","el","StringLerpTracker","StringModule","context","data","v","ctx","w","h","val","i","x","y","position","StringPositionTracker","StringModule","context","data","current","target","direction","el","style","Debounce","func","delay","timeoutId","args","context","StringFPS","time","fps","now","elapsed","callback","StringVideoAutoplay","StringModule","context","object","videoElement","started","element","err","StringTune","_StringTune","StringFPS","Debounce","DefaultToolsContainer","StringData","EventManager","ModuleManager","ObjectManager","CursorController","ScrollManager","time","value","container","speed","mode","type","objectClass","settings","effectiveSettings","module","eventName","callback","id","fps","observerContainerMutation","mutationsList","observer","mutation","config","StringInview","htmlFontSize","fontSizeNumber","element","connectTargetId","e","scroll","width","height","newScrollHeight","newContainerTopPosition","rect","transformScale","isDesktop","widthChanged","heightChanged","scrollHeightChanged","shouldRebuild"]}