@once-ui-system/core 1.7.10 → 1.7.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ai/catalog.json +1650 -0
- package/ai/catalog.seed.json +411 -0
- package/ai/components/Accordion.json +136 -0
- package/ai/components/AccordionGroup.json +128 -0
- package/ai/components/Animation.json +146 -0
- package/ai/components/Arrow.json +128 -0
- package/ai/components/AutoScroll.json +130 -0
- package/ai/components/Avatar.json +133 -0
- package/ai/components/AvatarGroup.json +129 -0
- package/ai/components/Background.json +131 -0
- package/ai/components/Badge.json +132 -0
- package/ai/components/Banner.json +122 -0
- package/ai/components/BarChart.json +123 -0
- package/ai/components/BlobFx.json +125 -0
- package/ai/components/BlockQuote.json +132 -0
- package/ai/components/Button.json +26 -0
- package/ai/components/Card.json +129 -0
- package/ai/components/Carousel.json +134 -0
- package/ai/components/CelebrationFx.json +132 -0
- package/ai/components/ChartHeader.json +130 -0
- package/ai/components/ChartStatus.json +12 -0
- package/ai/components/Checkbox.json +13 -0
- package/ai/components/Chip.json +132 -0
- package/ai/components/CodeBlock.json +122 -0
- package/ai/components/ColorInput.json +13 -0
- package/ai/components/Column.json +128 -0
- package/ai/components/CompareImage.json +126 -0
- package/ai/components/ContextMenu.json +22 -0
- package/ai/components/CountFx.json +82 -0
- package/ai/components/CountdownFx.json +11 -0
- package/ai/components/Cursor.json +9 -0
- package/ai/components/CursorCard.json +128 -0
- package/ai/components/DataTooltip.json +15 -0
- package/ai/components/DateInput.json +21 -0
- package/ai/components/DatePicker.json +143 -0
- package/ai/components/DateRangeInput.json +18 -0
- package/ai/components/DateRangePicker.json +129 -0
- package/ai/components/Dialog.json +134 -0
- package/ai/components/DialogProvider.json +8 -0
- package/ai/components/Dropdown.json +128 -0
- package/ai/components/DropdownWrapper.json +28 -0
- package/ai/components/EmojiPicker.json +129 -0
- package/ai/components/EmojiPickerDropdown.json +13 -0
- package/ai/components/Fade.json +130 -0
- package/ai/components/FadingLettersFx.json +77 -0
- package/ai/components/Feedback.json +132 -0
- package/ai/components/Flex.json +125 -0
- package/ai/components/FlipFx.json +133 -0
- package/ai/components/GlitchFx.json +128 -0
- package/ai/components/Grid.json +121 -0
- package/ai/components/Heading.json +75 -0
- package/ai/components/HeadingLink.json +127 -0
- package/ai/components/HeadingNav.json +124 -0
- package/ai/components/HoloFx.json +128 -0
- package/ai/components/Hover.json +130 -0
- package/ai/components/HoverCard.json +122 -0
- package/ai/components/Icon.json +132 -0
- package/ai/components/IconButton.json +22 -0
- package/ai/components/InfiniteScroll.json +130 -0
- package/ai/components/InlineCode.json +126 -0
- package/ai/components/Input.json +24 -0
- package/ai/components/InteractiveDetails.json +14 -0
- package/ai/components/Kbar.json +10 -0
- package/ai/components/Kbd.json +127 -0
- package/ai/components/Legend.json +14 -0
- package/ai/components/LetterFx.json +14 -0
- package/ai/components/Line.json +125 -0
- package/ai/components/LineBarChart.json +123 -0
- package/ai/components/LineChart.json +123 -0
- package/ai/components/LinearGauge.json +130 -0
- package/ai/components/LinearGradient.json +15 -0
- package/ai/components/List.json +127 -0
- package/ai/components/ListItem.json +77 -0
- package/ai/components/Logo.json +16 -0
- package/ai/components/LogoCloud.json +124 -0
- package/ai/components/Mask.json +131 -0
- package/ai/components/MasonryGrid.json +132 -0
- package/ai/components/MatrixFx.json +135 -0
- package/ai/components/Media.json +142 -0
- package/ai/components/MediaUpload.json +122 -0
- package/ai/components/MegaMenu.json +125 -0
- package/ai/components/MobileMegaMenu.json +125 -0
- package/ai/components/Modal.json +12 -0
- package/ai/components/NavIcon.json +127 -0
- package/ai/components/NumberInput.json +16 -0
- package/ai/components/OTPInput.json +13 -0
- package/ai/components/OgCard.json +135 -0
- package/ai/components/Option.json +137 -0
- package/ai/components/Particle.json +135 -0
- package/ai/components/PasswordInput.json +8 -0
- package/ai/components/PieChart.json +123 -0
- package/ai/components/ProgressBar.json +131 -0
- package/ai/components/Pulse.json +129 -0
- package/ai/components/RadialGauge.json +134 -0
- package/ai/components/RadialGradient.json +16 -0
- package/ai/components/RadioButton.json +17 -0
- package/ai/components/RevealFx.json +131 -0
- package/ai/components/Row.json +128 -0
- package/ai/components/Schema.json +17 -0
- package/ai/components/ScrollContainer.json +126 -0
- package/ai/components/ScrollToTop.json +124 -0
- package/ai/components/Scroller.json +128 -0
- package/ai/components/SegmentedControl.json +132 -0
- package/ai/components/Select.json +21 -0
- package/ai/components/ShineFx.json +80 -0
- package/ai/components/Skeleton.json +129 -0
- package/ai/components/Slider.json +17 -0
- package/ai/components/SmartLink.json +17 -0
- package/ai/components/Spinner.json +127 -0
- package/ai/components/SplitView.json +129 -0
- package/ai/components/StatusIndicator.json +128 -0
- package/ai/components/StyleOverlay.json +126 -0
- package/ai/components/StylePanel.json +125 -0
- package/ai/components/Swiper.json +130 -0
- package/ai/components/Switch.json +20 -0
- package/ai/components/Table.json +125 -0
- package/ai/components/Tag.json +129 -0
- package/ai/components/TagInput.json +12 -0
- package/ai/components/Text.json +72 -0
- package/ai/components/Textarea.json +24 -0
- package/ai/components/ThemeSwitcher.json +122 -0
- package/ai/components/TiltFx.json +126 -0
- package/ai/components/Timeline.json +126 -0
- package/ai/components/Toast.json +13 -0
- package/ai/components/Toaster.json +14 -0
- package/ai/components/ToggleButton.json +24 -0
- package/ai/components/Tooltip.json +129 -0
- package/ai/components/TypeFx.json +15 -0
- package/ai/components/User.json +15 -0
- package/ai/components/UserMenu.json +16 -0
- package/ai/components/WeatherFx.json +133 -0
- package/ai/examples/auth.tsx +105 -0
- package/ai/examples/blocks/Background6.tsx +25 -0
- package/ai/examples/blocks/Chat1.tsx +70 -0
- package/ai/examples/blocks/Dashboard1.tsx +404 -0
- package/ai/examples/blocks/Feed3.tsx +151 -0
- package/ai/examples/blocks/Footer1.tsx +30 -0
- package/ai/examples/blocks/Footer2.tsx +96 -0
- package/ai/examples/blocks/Footer3.tsx +127 -0
- package/ai/examples/blocks/Footer4.tsx +406 -0
- package/ai/examples/blocks/Header1.tsx +370 -0
- package/ai/examples/blocks/Header2.tsx +98 -0
- package/ai/examples/blocks/Header3.tsx +133 -0
- package/ai/examples/blocks/Header4.tsx +123 -0
- package/ai/examples/blocks/Productivity1.tsx +318 -0
- package/ai/examples/blocks/Roadmap1.tsx +133 -0
- package/ai/examples/blocks/Sidebar1.tsx +34 -0
- package/ai/examples/blocks/Sidebar2.tsx +17 -0
- package/ai/examples/blocks/Sidebar4.tsx +92 -0
- package/ai/examples/blocks/Sidebar5.tsx +73 -0
- package/ai/examples/blocks/Streaming1.tsx +353 -0
- package/ai/examples/blocks/Table1.tsx +303 -0
- package/ai/examples/blocks/Waitlist1.tsx +141 -0
- package/ai/examples/blocks/content/chat1content.ts +65 -0
- package/ai/examples/blocks/content/resources.ts +5 -0
- package/ai/examples/blocks/content/roadmap1content.ts +51 -0
- package/ai/examples/blocks/manifest.json +191 -0
- package/ai/examples/dashboard.tsx +150 -0
- package/ai/examples/marketing-hero.tsx +152 -0
- package/ai/examples/pricing.tsx +219 -0
- package/ai/examples/settings.tsx +140 -0
- package/ai/gotchas.json +85 -0
- package/ai/manifest.json +21 -0
- package/ai/rules.compact.md +73 -0
- package/ai/spec.json +2679 -2701
- package/ai/tasks/auth.json +23 -0
- package/ai/tasks/chat.json +28 -0
- package/ai/tasks/dashboard.json +39 -0
- package/ai/tasks/index.json +12 -0
- package/ai/tasks/marketing-hero.json +38 -0
- package/ai/tasks/pricing.json +42 -0
- package/ai/tasks/roadmap.json +22 -0
- package/ai/tasks/settings.json +34 -0
- package/dist/ai/catalog.json +1650 -0
- package/dist/ai/catalog.seed.json +411 -0
- package/dist/ai/components/Accordion.json +136 -0
- package/dist/ai/components/AccordionGroup.json +128 -0
- package/dist/ai/components/Animation.json +146 -0
- package/dist/ai/components/Arrow.json +128 -0
- package/dist/ai/components/AutoScroll.json +130 -0
- package/dist/ai/components/Avatar.json +133 -0
- package/dist/ai/components/AvatarGroup.json +129 -0
- package/dist/ai/components/Background.json +131 -0
- package/dist/ai/components/Badge.json +132 -0
- package/dist/ai/components/Banner.json +122 -0
- package/dist/ai/components/BarChart.json +123 -0
- package/dist/ai/components/BlobFx.json +125 -0
- package/dist/ai/components/BlockQuote.json +132 -0
- package/dist/ai/components/Button.json +26 -0
- package/dist/ai/components/Card.json +129 -0
- package/dist/ai/components/Carousel.json +134 -0
- package/dist/ai/components/CelebrationFx.json +132 -0
- package/dist/ai/components/ChartHeader.json +130 -0
- package/dist/ai/components/ChartStatus.json +12 -0
- package/dist/ai/components/Checkbox.json +13 -0
- package/dist/ai/components/Chip.json +132 -0
- package/dist/ai/components/CodeBlock.json +122 -0
- package/dist/ai/components/ColorInput.json +13 -0
- package/dist/ai/components/Column.json +128 -0
- package/dist/ai/components/CompareImage.json +126 -0
- package/dist/ai/components/ContextMenu.json +22 -0
- package/dist/ai/components/CountFx.json +82 -0
- package/dist/ai/components/CountdownFx.json +11 -0
- package/dist/ai/components/Cursor.json +9 -0
- package/dist/ai/components/CursorCard.json +128 -0
- package/dist/ai/components/DataTooltip.json +15 -0
- package/dist/ai/components/DateInput.json +21 -0
- package/dist/ai/components/DatePicker.json +143 -0
- package/dist/ai/components/DateRangeInput.json +18 -0
- package/dist/ai/components/DateRangePicker.json +129 -0
- package/dist/ai/components/Dialog.json +134 -0
- package/dist/ai/components/DialogProvider.json +8 -0
- package/dist/ai/components/Dropdown.json +128 -0
- package/dist/ai/components/DropdownWrapper.json +28 -0
- package/dist/ai/components/EmojiPicker.json +129 -0
- package/dist/ai/components/EmojiPickerDropdown.json +13 -0
- package/dist/ai/components/Fade.json +130 -0
- package/dist/ai/components/FadingLettersFx.json +77 -0
- package/dist/ai/components/Feedback.json +132 -0
- package/dist/ai/components/Flex.json +125 -0
- package/dist/ai/components/FlipFx.json +133 -0
- package/dist/ai/components/GlitchFx.json +128 -0
- package/dist/ai/components/Grid.json +121 -0
- package/dist/ai/components/Heading.json +75 -0
- package/dist/ai/components/HeadingLink.json +127 -0
- package/dist/ai/components/HeadingNav.json +124 -0
- package/dist/ai/components/HoloFx.json +128 -0
- package/dist/ai/components/Hover.json +130 -0
- package/dist/ai/components/HoverCard.json +122 -0
- package/dist/ai/components/Icon.json +132 -0
- package/dist/ai/components/IconButton.json +22 -0
- package/dist/ai/components/InfiniteScroll.json +130 -0
- package/dist/ai/components/InlineCode.json +126 -0
- package/dist/ai/components/Input.json +24 -0
- package/dist/ai/components/InteractiveDetails.json +14 -0
- package/dist/ai/components/Kbar.json +10 -0
- package/dist/ai/components/Kbd.json +127 -0
- package/dist/ai/components/Legend.json +14 -0
- package/dist/ai/components/LetterFx.json +14 -0
- package/dist/ai/components/Line.json +125 -0
- package/dist/ai/components/LineBarChart.json +123 -0
- package/dist/ai/components/LineChart.json +123 -0
- package/dist/ai/components/LinearGauge.json +130 -0
- package/dist/ai/components/LinearGradient.json +15 -0
- package/dist/ai/components/List.json +127 -0
- package/dist/ai/components/ListItem.json +77 -0
- package/dist/ai/components/Logo.json +16 -0
- package/dist/ai/components/LogoCloud.json +124 -0
- package/dist/ai/components/Mask.json +131 -0
- package/dist/ai/components/MasonryGrid.json +132 -0
- package/dist/ai/components/MatrixFx.json +135 -0
- package/dist/ai/components/Media.json +142 -0
- package/dist/ai/components/MediaUpload.json +122 -0
- package/dist/ai/components/MegaMenu.json +125 -0
- package/dist/ai/components/MobileMegaMenu.json +125 -0
- package/dist/ai/components/Modal.json +12 -0
- package/dist/ai/components/NavIcon.json +127 -0
- package/dist/ai/components/NumberInput.json +16 -0
- package/dist/ai/components/OTPInput.json +13 -0
- package/dist/ai/components/OgCard.json +135 -0
- package/dist/ai/components/Option.json +137 -0
- package/dist/ai/components/Particle.json +135 -0
- package/dist/ai/components/PasswordInput.json +8 -0
- package/dist/ai/components/PieChart.json +123 -0
- package/dist/ai/components/ProgressBar.json +131 -0
- package/dist/ai/components/Pulse.json +129 -0
- package/dist/ai/components/RadialGauge.json +134 -0
- package/dist/ai/components/RadialGradient.json +16 -0
- package/dist/ai/components/RadioButton.json +17 -0
- package/dist/ai/components/RevealFx.json +131 -0
- package/dist/ai/components/Row.json +128 -0
- package/dist/ai/components/Schema.json +17 -0
- package/dist/ai/components/ScrollContainer.json +126 -0
- package/dist/ai/components/ScrollToTop.json +124 -0
- package/dist/ai/components/Scroller.json +128 -0
- package/dist/ai/components/SegmentedControl.json +132 -0
- package/dist/ai/components/Select.json +21 -0
- package/dist/ai/components/ShineFx.json +80 -0
- package/dist/ai/components/Skeleton.json +129 -0
- package/dist/ai/components/Slider.json +17 -0
- package/dist/ai/components/SmartLink.json +17 -0
- package/dist/ai/components/Spinner.json +127 -0
- package/dist/ai/components/SplitView.json +129 -0
- package/dist/ai/components/StatusIndicator.json +128 -0
- package/dist/ai/components/StyleOverlay.json +126 -0
- package/dist/ai/components/StylePanel.json +125 -0
- package/dist/ai/components/Swiper.json +130 -0
- package/dist/ai/components/Switch.json +20 -0
- package/dist/ai/components/Table.json +125 -0
- package/dist/ai/components/Tag.json +129 -0
- package/dist/ai/components/TagInput.json +12 -0
- package/dist/ai/components/Text.json +72 -0
- package/dist/ai/components/Textarea.json +24 -0
- package/dist/ai/components/ThemeSwitcher.json +122 -0
- package/dist/ai/components/TiltFx.json +126 -0
- package/dist/ai/components/Timeline.json +126 -0
- package/dist/ai/components/Toast.json +13 -0
- package/dist/ai/components/Toaster.json +14 -0
- package/dist/ai/components/ToggleButton.json +24 -0
- package/dist/ai/components/Tooltip.json +129 -0
- package/dist/ai/components/TypeFx.json +15 -0
- package/dist/ai/components/User.json +15 -0
- package/dist/ai/components/UserMenu.json +16 -0
- package/dist/ai/components/WeatherFx.json +133 -0
- package/dist/ai/eval-tasks.md +71 -0
- package/dist/ai/examples/blocks/manifest.json +191 -0
- package/dist/ai/gotchas.json +85 -0
- package/dist/ai/manifest.json +21 -0
- package/dist/ai/recipes.md +149 -0
- package/dist/ai/rules.compact.md +73 -0
- package/dist/ai/rules.md +217 -0
- package/dist/ai/spec.json +2680 -0
- package/dist/ai/tasks/auth.json +23 -0
- package/dist/ai/tasks/chat.json +28 -0
- package/dist/ai/tasks/dashboard.json +39 -0
- package/dist/ai/tasks/index.json +12 -0
- package/dist/ai/tasks/marketing-hero.json +38 -0
- package/dist/ai/tasks/pricing.json +42 -0
- package/dist/ai/tasks/roadmap.json +22 -0
- package/dist/ai/tasks/settings.json +34 -0
- package/dist/components/Accordion.d.ts +2 -1
- package/dist/components/Accordion.d.ts.map +1 -1
- package/dist/components/Accordion.js.map +1 -1
- package/dist/components/Accordion.module.scss +1 -0
- package/dist/components/AccordionGroup.d.ts +2 -1
- package/dist/components/AccordionGroup.d.ts.map +1 -1
- package/dist/components/AccordionGroup.js +17 -1
- package/dist/components/AccordionGroup.js.map +1 -1
- package/dist/components/Avatar.d.ts +2 -1
- package/dist/components/Avatar.d.ts.map +1 -1
- package/dist/components/Avatar.js.map +1 -1
- package/dist/components/AvatarGroup.d.ts +2 -1
- package/dist/components/AvatarGroup.d.ts.map +1 -1
- package/dist/components/AvatarGroup.js.map +1 -1
- package/dist/components/Button.d.ts +7 -5
- package/dist/components/Button.d.ts.map +1 -1
- package/dist/components/Button.js +3 -3
- package/dist/components/Button.js.map +1 -1
- package/dist/components/Button.module.scss +233 -111
- package/dist/components/Carousel.d.ts.map +1 -1
- package/dist/components/Carousel.js +14 -3
- package/dist/components/Carousel.js.map +1 -1
- package/dist/components/ColorInput.d.ts.map +1 -1
- package/dist/components/ColorInput.js +11 -11
- package/dist/components/ColorInput.js.map +1 -1
- package/dist/components/CompareImage.d.ts.map +1 -1
- package/dist/components/CompareImage.js +24 -23
- package/dist/components/CompareImage.js.map +1 -1
- package/dist/components/CompareImage.module.scss +0 -2
- package/dist/components/CursorCard.d.ts.map +1 -1
- package/dist/components/CursorCard.js.map +1 -1
- package/dist/components/CursorCard.module.scss +1 -1
- package/dist/components/DatePicker.d.ts +2 -1
- package/dist/components/DatePicker.d.ts.map +1 -1
- package/dist/components/DatePicker.js +11 -15
- package/dist/components/DatePicker.js.map +1 -1
- package/dist/components/DateRangePicker.d.ts +2 -1
- package/dist/components/DateRangePicker.d.ts.map +1 -1
- package/dist/components/DateRangePicker.js.map +1 -1
- package/dist/components/DropdownWrapper.d.ts.map +1 -1
- package/dist/components/DropdownWrapper.js +9 -9
- package/dist/components/DropdownWrapper.js.map +1 -1
- package/dist/components/ElementType.d.ts +5 -6
- package/dist/components/ElementType.d.ts.map +1 -1
- package/dist/components/ElementType.js.map +1 -1
- package/dist/components/EmojiPicker.d.ts +2 -2
- package/dist/components/EmojiPickerDropdown.d.ts +2 -2
- package/dist/components/Feedback.d.ts.map +1 -1
- package/dist/components/Feedback.js +1 -1
- package/dist/components/Feedback.js.map +1 -1
- package/dist/components/Heading.d.ts +3 -3
- package/dist/components/Heading.d.ts.map +1 -1
- package/dist/components/Heading.js +6 -3
- package/dist/components/Heading.js.map +1 -1
- package/dist/components/Icon.d.ts +2 -2
- package/dist/components/Icon.d.ts.map +1 -1
- package/dist/components/IconButton.d.ts +7 -5
- package/dist/components/IconButton.d.ts.map +1 -1
- package/dist/components/IconButton.js +2 -2
- package/dist/components/IconButton.js.map +1 -1
- package/dist/components/Input.d.ts +2 -1
- package/dist/components/Input.d.ts.map +1 -1
- package/dist/components/Input.js.map +1 -1
- package/dist/components/Input.module.scss +1 -196
- package/dist/components/Logo.d.ts +2 -1
- package/dist/components/Logo.d.ts.map +1 -1
- package/dist/components/MatrixFx.d.ts.map +1 -1
- package/dist/components/MatrixFx.js +521 -481
- package/dist/components/MatrixFx.js.map +1 -1
- package/dist/components/Media.d.ts.map +1 -1
- package/dist/components/Media.js +5 -1
- package/dist/components/Media.js.map +1 -1
- package/dist/components/ProgressBar.d.ts +1 -0
- package/dist/components/ProgressBar.d.ts.map +1 -1
- package/dist/components/ProgressBar.js +9 -3
- package/dist/components/ProgressBar.js.map +1 -1
- package/dist/components/Pulse.d.ts +1 -0
- package/dist/components/Pulse.d.ts.map +1 -1
- package/dist/components/Pulse.js +2 -2
- package/dist/components/Pulse.js.map +1 -1
- package/dist/components/Scroller.js +1 -1
- package/dist/components/Scroller.js.map +1 -1
- package/dist/components/ServerFlex.d.ts +2 -2
- package/dist/components/ServerFlex.d.ts.map +1 -1
- package/dist/components/ServerFlex.js +4 -1
- package/dist/components/ServerFlex.js.map +1 -1
- package/dist/components/ServerGrid.d.ts +2 -2
- package/dist/components/ServerGrid.d.ts.map +1 -1
- package/dist/components/SmartLink.d.ts +5 -4
- package/dist/components/SmartLink.d.ts.map +1 -1
- package/dist/components/SmartLink.js.map +1 -1
- package/dist/components/Spinner.d.ts +2 -1
- package/dist/components/Spinner.d.ts.map +1 -1
- package/dist/components/Spinner.js.map +1 -1
- package/dist/components/SplitView.d.ts +1 -1
- package/dist/components/SplitView.d.ts.map +1 -1
- package/dist/components/SplitView.js +1 -1
- package/dist/components/SplitView.js.map +1 -1
- package/dist/components/StatusIndicator.d.ts +2 -1
- package/dist/components/StatusIndicator.d.ts.map +1 -1
- package/dist/components/StatusIndicator.js.map +1 -1
- package/dist/components/Swiper.d.ts.map +1 -1
- package/dist/components/Swiper.js +3 -3
- package/dist/components/Swiper.js.map +1 -1
- package/dist/components/Tag.d.ts +2 -2
- package/dist/components/Tag.d.ts.map +1 -1
- package/dist/components/Text.d.ts +3 -3
- package/dist/components/Text.d.ts.map +1 -1
- package/dist/components/Text.js +6 -3
- package/dist/components/Text.js.map +1 -1
- package/dist/components/Textarea.d.ts +2 -1
- package/dist/components/Textarea.d.ts.map +1 -1
- package/dist/components/Textarea.js.map +1 -1
- package/dist/components/Toast.d.ts +1 -1
- package/dist/components/Toast.d.ts.map +1 -1
- package/dist/components/Toast.js +2 -0
- package/dist/components/Toast.js.map +1 -1
- package/dist/components/Toaster.d.ts +1 -1
- package/dist/components/Toaster.d.ts.map +1 -1
- package/dist/components/ToggleButton.d.ts +6 -5
- package/dist/components/ToggleButton.d.ts.map +1 -1
- package/dist/components/ToggleButton.js.map +1 -1
- package/dist/components/ToggleButton.module.scss +19 -0
- package/dist/components/index.d.ts +0 -3
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +0 -3
- package/dist/components/index.js.map +1 -1
- package/dist/contexts/ToastProvider.d.ts +1 -1
- package/dist/contexts/ToastProvider.d.ts.map +1 -1
- package/dist/css/tokens.css +1 -1
- package/dist/css/tokens.css.map +1 -1
- package/dist/interfaces.d.ts +9 -10
- package/dist/interfaces.d.ts.map +1 -1
- package/dist/modules/code/CodeBlock.impl.d.ts +2 -0
- package/dist/modules/code/CodeBlock.impl.d.ts.map +1 -1
- package/dist/modules/code/CodeBlock.impl.js +48 -16
- package/dist/modules/code/CodeBlock.impl.js.map +1 -1
- package/dist/modules/code/index.d.ts +3 -0
- package/dist/modules/code/index.d.ts.map +1 -0
- package/dist/modules/code/index.js +2 -0
- package/dist/modules/code/index.js.map +1 -0
- package/dist/modules/data/BarChart.impl.d.ts +2 -2
- package/dist/modules/data/DataTooltip.d.ts +1 -1
- package/dist/modules/data/DataTooltip.d.ts.map +1 -1
- package/dist/modules/data/DataTooltip.js.map +1 -1
- package/dist/modules/data/Legend.d.ts +1 -1
- package/dist/modules/data/Legend.d.ts.map +1 -1
- package/dist/modules/data/Legend.js.map +1 -1
- package/dist/modules/data/LineBarChart.impl.d.ts +2 -2
- package/dist/modules/data/LinearGauge.d.ts +1 -2
- package/dist/modules/data/LinearGauge.d.ts.map +1 -1
- package/dist/modules/data/RadialGauge.d.ts +1 -2
- package/dist/modules/data/RadialGauge.d.ts.map +1 -1
- package/dist/modules/data/interfaces.d.ts +4 -4
- package/dist/modules/index.d.ts +3 -4
- package/dist/modules/index.d.ts.map +1 -1
- package/dist/modules/index.js +3 -4
- package/dist/modules/index.js.map +1 -1
- package/dist/modules/media/index.d.ts +3 -0
- package/dist/modules/media/index.d.ts.map +1 -0
- package/dist/modules/media/index.js +2 -0
- package/dist/modules/media/index.js.map +1 -0
- package/dist/modules/navigation/HeadingLink.d.ts +1 -2
- package/dist/modules/navigation/HeadingLink.d.ts.map +1 -1
- package/dist/modules/navigation/HeadingNav.d.ts +2 -2
- package/dist/modules/navigation/HeadingNav.d.ts.map +1 -1
- package/dist/modules/navigation/HeadingNav.js.map +1 -1
- package/dist/modules/navigation/Kbar.d.ts +6 -5
- package/dist/modules/navigation/Kbar.d.ts.map +1 -1
- package/dist/modules/navigation/Kbar.js +20 -12
- package/dist/modules/navigation/Kbar.js.map +1 -1
- package/dist/modules/navigation/MobileMegaMenu.d.ts +4 -4
- package/dist/modules/navigation/MobileMegaMenu.d.ts.map +1 -1
- package/dist/modules/navigation/index.d.ts +2 -2
- package/dist/modules/navigation/index.d.ts.map +1 -1
- package/dist/modules/navigation/index.js +2 -2
- package/dist/modules/navigation/index.js.map +1 -1
- package/dist/modules/seo/index.d.ts +5 -0
- package/dist/modules/seo/index.d.ts.map +1 -0
- package/dist/modules/seo/index.js +3 -0
- package/dist/modules/seo/index.js.map +1 -0
- package/dist/package.json +13 -2
- package/dist/tokens/theme.scss +20 -2
- package/dist/types.d.ts +3 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +5 -5
- package/dist/types.js.map +1 -1
- package/dist/utils/dropdownState.d.ts +4 -0
- package/dist/utils/dropdownState.d.ts.map +1 -0
- package/dist/utils/dropdownState.js +9 -0
- package/dist/utils/dropdownState.js.map +1 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -0
- package/dist/utils/index.js.map +1 -1
- package/package.json +139 -127
- package/LICENSE.md +0 -21
- package/next-env.d.ts +0 -5
|
@@ -58,368 +58,216 @@ const MatrixFx = React.forwardRef(({ speed = 1, colors = ["brand-solid-medium"],
|
|
|
58
58
|
const ctx = canvas.getContext("2d", { willReadFrequently: true });
|
|
59
59
|
if (!ctx)
|
|
60
60
|
return;
|
|
61
|
-
// Set canvas size
|
|
61
|
+
// Set canvas size — skip until the container has layout (0×0 crashes getImageData)
|
|
62
62
|
let canvasWidth = 0;
|
|
63
63
|
let canvasHeight = 0;
|
|
64
|
-
|
|
64
|
+
let initialized = false;
|
|
65
|
+
let disposed = false;
|
|
66
|
+
const applySize = () => {
|
|
65
67
|
const rect = container.getBoundingClientRect();
|
|
68
|
+
if (rect.width <= 0 || rect.height <= 0) {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
66
71
|
canvasWidth = rect.width;
|
|
67
72
|
canvasHeight = rect.height;
|
|
68
|
-
canvas.width = rect.width * 2;
|
|
69
|
-
canvas.height = rect.height * 2;
|
|
73
|
+
canvas.width = Math.floor(rect.width * 2);
|
|
74
|
+
canvas.height = Math.floor(rect.height * 2);
|
|
70
75
|
canvas.style.width = `${rect.width}px`;
|
|
71
76
|
canvas.style.height = `${rect.height}px`;
|
|
72
|
-
ctx.
|
|
77
|
+
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
78
|
+
ctx.scale(2, 2);
|
|
79
|
+
return true;
|
|
73
80
|
};
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
// Get computed value from CSS variable
|
|
79
|
-
const computedColor = getComputedStyle(container).getPropertyValue(`--${color}`);
|
|
80
|
-
return computedColor || color;
|
|
81
|
-
});
|
|
82
|
-
// Create dot grid with padding to prevent edge gaps during displacement
|
|
83
|
-
const totalSize = size + spacing;
|
|
84
|
-
const maxDisplacement = (bulge?.intensity ?? 10) * 2; // Account for max possible displacement
|
|
85
|
-
const paddedWidth = canvasWidth + maxDisplacement * 2;
|
|
86
|
-
const paddedHeight = canvasHeight + maxDisplacement * 2;
|
|
87
|
-
const cols = Math.ceil(paddedWidth / totalSize);
|
|
88
|
-
const rows = Math.ceil(paddedHeight / totalSize);
|
|
89
|
-
// Only create new dots if grid doesn't exist or dimensions/size changed
|
|
90
|
-
let dots = dotsRef.current;
|
|
91
|
-
let maxDistance = 0;
|
|
92
|
-
if (dots.length === 0 || dots[0]?.gridSize !== totalSize || dots[0]?.canvasW !== canvasWidth || dots[0]?.canvasH !== canvasHeight) {
|
|
93
|
-
// Create new dot grid
|
|
94
|
-
dots = [];
|
|
95
|
-
for (let row = 0; row < rows; row++) {
|
|
96
|
-
for (let col = 0; col < cols; col++) {
|
|
97
|
-
const x = col * totalSize + size / 2 - maxDisplacement;
|
|
98
|
-
const y = row * totalSize + size / 2 - maxDisplacement;
|
|
99
|
-
// Calculate distance from reveal origin
|
|
100
|
-
let distanceFromOrigin = 0;
|
|
101
|
-
const centerX = canvasWidth / 2;
|
|
102
|
-
const centerY = canvasHeight / 2;
|
|
103
|
-
switch (revealFrom) {
|
|
104
|
-
case "center":
|
|
105
|
-
const dx = x - centerX;
|
|
106
|
-
const dy = y - centerY;
|
|
107
|
-
distanceFromOrigin = Math.sqrt(dx * dx + dy * dy);
|
|
108
|
-
break;
|
|
109
|
-
case "top":
|
|
110
|
-
distanceFromOrigin = y;
|
|
111
|
-
break;
|
|
112
|
-
case "bottom":
|
|
113
|
-
distanceFromOrigin = canvasHeight - y;
|
|
114
|
-
break;
|
|
115
|
-
case "left":
|
|
116
|
-
distanceFromOrigin = x;
|
|
117
|
-
break;
|
|
118
|
-
case "right":
|
|
119
|
-
distanceFromOrigin = canvasWidth - x;
|
|
120
|
-
break;
|
|
121
|
-
}
|
|
122
|
-
dots.push({
|
|
123
|
-
x,
|
|
124
|
-
y,
|
|
125
|
-
gridX: col,
|
|
126
|
-
gridY: row,
|
|
127
|
-
color: parsedColors[Math.floor(Math.random() * parsedColors.length)],
|
|
128
|
-
baseOpacity: 0.3 + Math.random() * 0.7,
|
|
129
|
-
distanceFromOrigin,
|
|
130
|
-
randomOffset: Math.random() * 0.3,
|
|
131
|
-
flickerPhase: Math.random() * Math.PI * 2,
|
|
132
|
-
flickerSpeed: 0.8 + Math.random() * 0.4,
|
|
133
|
-
gridSize: totalSize,
|
|
134
|
-
canvasW: canvasWidth,
|
|
135
|
-
canvasH: canvasHeight,
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
// Find max distance for normalization
|
|
140
|
-
maxDistance = Math.max(...dots.map((d) => d.distanceFromOrigin));
|
|
141
|
-
dotsRef.current = dots;
|
|
142
|
-
}
|
|
143
|
-
else {
|
|
144
|
-
// Update colors on existing dots
|
|
145
|
-
dots.forEach((dot) => {
|
|
146
|
-
dot.color = parsedColors[Math.floor(Math.random() * parsedColors.length)];
|
|
147
|
-
});
|
|
148
|
-
maxDistance = Math.max(...dots.map((d) => d.distanceFromOrigin));
|
|
149
|
-
}
|
|
150
|
-
// Animation loop
|
|
151
|
-
const startTime = Date.now();
|
|
152
|
-
const frameInterval = 1000 / fps; // Target ms per frame
|
|
153
|
-
// Bulge configuration
|
|
154
|
-
const bulgeEnabled = !!bulge;
|
|
155
|
-
const bulgeType = bulge?.type ?? "ripple"; // Default: ripple
|
|
156
|
-
const bulgeDuration = bulge?.duration ?? 3; // Default: 3 seconds per wave
|
|
157
|
-
const bulgeIntensity = bulge?.intensity ?? 10; // Default: 10px displacement
|
|
158
|
-
const bulgeRepeat = bulge?.repeat ?? true; // Default: true
|
|
159
|
-
const bulgeDelay = bulge?.delay ?? 0; // Default: 0ms
|
|
160
|
-
// Calculate center point for circular wave
|
|
161
|
-
const centerX = canvasWidth / 2;
|
|
162
|
-
const centerY = canvasHeight / 2;
|
|
163
|
-
const maxRadius = Math.sqrt(centerX * centerX + centerY * centerY);
|
|
164
|
-
// Cache for static rendering (when animation completes)
|
|
165
|
-
let cachedImageData = null;
|
|
166
|
-
// When reduced motion is active, force static rendering after first frame
|
|
167
|
-
if (!shouldAnimate) {
|
|
168
|
-
isStaticRef.current = true;
|
|
169
|
-
mountAnimationCompleteRef.current = true;
|
|
170
|
-
}
|
|
171
|
-
const animate = (currentTime = 0) => {
|
|
172
|
-
// Skip rendering if not visible in viewport
|
|
173
|
-
if (!isVisibleRef.current) {
|
|
174
|
-
animationRef.current = requestAnimationFrame(animate);
|
|
81
|
+
const handleResize = () => {
|
|
82
|
+
const prevW = canvasWidth;
|
|
83
|
+
const prevH = canvasHeight;
|
|
84
|
+
if (!applySize())
|
|
175
85
|
return;
|
|
86
|
+
if (initialized && (prevW !== canvasWidth || prevH !== canvasHeight)) {
|
|
87
|
+
dotsRef.current = [];
|
|
88
|
+
isStaticRef.current = false;
|
|
176
89
|
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
90
|
+
};
|
|
91
|
+
window.addEventListener("resize", handleResize);
|
|
92
|
+
const setup = () => {
|
|
93
|
+
if (disposed || initialized)
|
|
180
94
|
return;
|
|
181
|
-
|
|
182
|
-
lastFrameTimeRef.current = currentTime;
|
|
183
|
-
// If static and we have cached image, just render that and stop animating
|
|
184
|
-
if (isStaticRef.current && cachedImageData) {
|
|
185
|
-
ctx.putImageData(cachedImageData, 0, 0);
|
|
186
|
-
// Don't request another frame - animation is complete
|
|
95
|
+
if (!applySize())
|
|
187
96
|
return;
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
const
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
const
|
|
216
|
-
|
|
97
|
+
initialized = true;
|
|
98
|
+
// Parse colors - convert token names to CSS variables
|
|
99
|
+
const parsedColors = colors.map((color) => {
|
|
100
|
+
const computedColor = getComputedStyle(container).getPropertyValue(`--${color}`);
|
|
101
|
+
return computedColor || color;
|
|
102
|
+
});
|
|
103
|
+
// Create dot grid with padding to prevent edge gaps during displacement
|
|
104
|
+
const totalSize = size + spacing;
|
|
105
|
+
const maxDisplacement = (bulge?.intensity ?? 10) * 2;
|
|
106
|
+
const paddedWidth = canvasWidth + maxDisplacement * 2;
|
|
107
|
+
const paddedHeight = canvasHeight + maxDisplacement * 2;
|
|
108
|
+
const cols = Math.ceil(paddedWidth / totalSize);
|
|
109
|
+
const rows = Math.ceil(paddedHeight / totalSize);
|
|
110
|
+
let dots = dotsRef.current;
|
|
111
|
+
let maxDistance = 0;
|
|
112
|
+
if (dots.length === 0 || dots[0]?.gridSize !== totalSize || dots[0]?.canvasW !== canvasWidth || dots[0]?.canvasH !== canvasHeight) {
|
|
113
|
+
dots = [];
|
|
114
|
+
for (let row = 0; row < rows; row++) {
|
|
115
|
+
for (let col = 0; col < cols; col++) {
|
|
116
|
+
const x = col * totalSize + size / 2 - maxDisplacement;
|
|
117
|
+
const y = row * totalSize + size / 2 - maxDisplacement;
|
|
118
|
+
let distanceFromOrigin = 0;
|
|
119
|
+
const centerX = canvasWidth / 2;
|
|
120
|
+
const centerY = canvasHeight / 2;
|
|
121
|
+
switch (revealFrom) {
|
|
122
|
+
case "center": {
|
|
123
|
+
const dx = x - centerX;
|
|
124
|
+
const dy = y - centerY;
|
|
125
|
+
distanceFromOrigin = Math.sqrt(dx * dx + dy * dy);
|
|
126
|
+
break;
|
|
217
127
|
}
|
|
128
|
+
case "top":
|
|
129
|
+
distanceFromOrigin = y;
|
|
130
|
+
break;
|
|
131
|
+
case "bottom":
|
|
132
|
+
distanceFromOrigin = canvasHeight - y;
|
|
133
|
+
break;
|
|
134
|
+
case "left":
|
|
135
|
+
distanceFromOrigin = x;
|
|
136
|
+
break;
|
|
137
|
+
case "right":
|
|
138
|
+
distanceFromOrigin = canvasWidth - x;
|
|
139
|
+
break;
|
|
218
140
|
}
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
141
|
+
dots.push({
|
|
142
|
+
x,
|
|
143
|
+
y,
|
|
144
|
+
gridX: col,
|
|
145
|
+
gridY: row,
|
|
146
|
+
color: parsedColors[Math.floor(Math.random() * parsedColors.length)],
|
|
147
|
+
baseOpacity: 0.3 + Math.random() * 0.7,
|
|
148
|
+
distanceFromOrigin,
|
|
149
|
+
randomOffset: Math.random() * 0.3,
|
|
150
|
+
flickerPhase: Math.random() * Math.PI * 2,
|
|
151
|
+
flickerSpeed: 0.8 + Math.random() * 0.4,
|
|
152
|
+
gridSize: totalSize,
|
|
153
|
+
canvasW: canvasWidth,
|
|
154
|
+
canvasH: canvasHeight,
|
|
155
|
+
});
|
|
223
156
|
}
|
|
224
157
|
}
|
|
158
|
+
maxDistance = dots.length > 0 ? Math.max(...dots.map((d) => d.distanceFromOrigin)) : 0;
|
|
159
|
+
dotsRef.current = dots;
|
|
225
160
|
}
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
161
|
+
else {
|
|
162
|
+
dots.forEach((dot) => {
|
|
163
|
+
dot.color = parsedColors[Math.floor(Math.random() * parsedColors.length)];
|
|
164
|
+
});
|
|
165
|
+
maxDistance = dots.length > 0 ? Math.max(...dots.map((d) => d.distanceFromOrigin)) : 0;
|
|
166
|
+
}
|
|
167
|
+
const startTime = Date.now();
|
|
168
|
+
const frameInterval = 1000 / fps;
|
|
169
|
+
const bulgeEnabled = !!bulge;
|
|
170
|
+
const bulgeType = bulge?.type ?? "ripple";
|
|
171
|
+
const bulgeDuration = bulge?.duration ?? 3;
|
|
172
|
+
const bulgeIntensity = bulge?.intensity ?? 10;
|
|
173
|
+
const bulgeRepeat = bulge?.repeat ?? true;
|
|
174
|
+
const bulgeDelay = bulge?.delay ?? 0;
|
|
175
|
+
const centerX = canvasWidth / 2;
|
|
176
|
+
const centerY = canvasHeight / 2;
|
|
177
|
+
const maxRadius = Math.sqrt(centerX * centerX + centerY * centerY);
|
|
178
|
+
let cachedImageData = null;
|
|
179
|
+
const cacheStaticFrame = () => {
|
|
180
|
+
if (canvas.width <= 0 || canvas.height <= 0)
|
|
181
|
+
return;
|
|
182
|
+
try {
|
|
183
|
+
cachedImageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
|
234
184
|
}
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
dots.forEach((dot) => {
|
|
238
|
-
ctx.fillStyle = dot.color;
|
|
239
|
-
let opacity = dot.baseOpacity;
|
|
240
|
-
// Apply flicker effect if enabled
|
|
241
|
-
if (flicker) {
|
|
242
|
-
const flickerValue = Math.sin(time * dot.flickerSpeed * 3 + dot.flickerPhase);
|
|
243
|
-
const flickerMultiplier = 0.6 + (flickerValue * 0.4); // Oscillate between 0.6 and 1.0
|
|
244
|
-
opacity *= flickerMultiplier;
|
|
245
|
-
}
|
|
246
|
-
// Calculate bulge displacement
|
|
247
|
-
let offsetX = 0;
|
|
248
|
-
let offsetY = 0;
|
|
249
|
-
let sizeMultiplier = 1;
|
|
250
|
-
let bulgeOpacity = 1;
|
|
251
|
-
if (bulgeEnabled && showBulge) {
|
|
252
|
-
if (bulgeType === "ripple") {
|
|
253
|
-
// Ripple: circular wave from center
|
|
254
|
-
const dx = dot.x - centerX;
|
|
255
|
-
const dy = dot.y - centerY;
|
|
256
|
-
const distanceFromCenter = Math.sqrt(dx * dx + dy * dy);
|
|
257
|
-
const distanceToWave = Math.abs(distanceFromCenter - waveRadius);
|
|
258
|
-
const waveWidth = maxRadius * 0.15;
|
|
259
|
-
const distanceNorm = distanceToWave / waveWidth;
|
|
260
|
-
const waveFactor = Math.exp(-distanceNorm * distanceNorm * 4);
|
|
261
|
-
const angle = Math.atan2(dy, dx);
|
|
262
|
-
const displacementAmount = waveFactor * bulgeIntensity * bulgeFadeOut;
|
|
263
|
-
offsetX = Math.cos(angle) * displacementAmount;
|
|
264
|
-
offsetY = Math.sin(angle) * displacementAmount;
|
|
265
|
-
sizeMultiplier = 1 + waveFactor * 0.8 * bulgeFadeOut;
|
|
266
|
-
const waveOpacity = 0.3 + waveFactor * 0.7;
|
|
267
|
-
bulgeOpacity = 1 + (waveOpacity - 1) * bulgeFadeOut;
|
|
268
|
-
}
|
|
269
|
-
else if (bulgeType === "wave") {
|
|
270
|
-
// Wave: Organic S-curve from bottom-left to top-right with rotation
|
|
271
|
-
const diagonalLength = Math.sqrt(canvasWidth * canvasWidth + canvasHeight * canvasHeight);
|
|
272
|
-
// Start wave off-screen before bottom-left, end off-screen after top-right
|
|
273
|
-
const wavePosOnDiagonal = (waveProgress * diagonalLength * 1.4) - (diagonalLength * 0.2);
|
|
274
|
-
// Calculate distance along the diagonal (from bottom-left to top-right)
|
|
275
|
-
const normalizedX = dot.x / canvasWidth;
|
|
276
|
-
const normalizedY = 1 - (dot.y / canvasHeight);
|
|
277
|
-
const dotDiagonalPos = (normalizedX + normalizedY) / 2 * diagonalLength;
|
|
278
|
-
// Distance from wave front
|
|
279
|
-
const distanceToWaveFront = dotDiagonalPos - wavePosOnDiagonal;
|
|
280
|
-
const waveWidth = diagonalLength * 0.25;
|
|
281
|
-
const distanceNorm = distanceToWaveFront / waveWidth;
|
|
282
|
-
// Smooth wave factor with wider influence
|
|
283
|
-
const waveFactor = Math.exp(-distanceNorm * distanceNorm * 2.5);
|
|
284
|
-
// Create rotating S-curve with multiple frequency components
|
|
285
|
-
const perpendicularOffset = normalizedY - normalizedX;
|
|
286
|
-
// Primary S-curve that rotates over time
|
|
287
|
-
const rotationPhase = waveProgress * Math.PI * 3; // Rotates 1.5 times during animation
|
|
288
|
-
const primaryFreq = 3; // Number of S-curves along the wave
|
|
289
|
-
const sCurvePrimary = Math.sin(perpendicularOffset * Math.PI * primaryFreq + rotationPhase);
|
|
290
|
-
// Secondary curve for complexity (higher frequency, lower amplitude)
|
|
291
|
-
const secondaryFreq = 7;
|
|
292
|
-
const sCurveSecondary = Math.sin(perpendicularOffset * Math.PI * secondaryFreq - rotationPhase * 1.5) * 0.4;
|
|
293
|
-
// Combine curves for organic motion
|
|
294
|
-
const sCurveFactor = sCurvePrimary + sCurveSecondary;
|
|
295
|
-
// Wave straightens at the edges (distanceNorm affects curve strength)
|
|
296
|
-
const curveStrength = 1 - Math.abs(distanceNorm) * 0.5;
|
|
297
|
-
const modulatedCurve = sCurveFactor * curveStrength;
|
|
298
|
-
// Apply displacement
|
|
299
|
-
const baseDisplacement = waveFactor * bulgeIntensity * bulgeFadeOut;
|
|
300
|
-
const diagonalAngle = Math.PI / 4;
|
|
301
|
-
// Perpendicular displacement creates the S-curve
|
|
302
|
-
const perpAngle = diagonalAngle + Math.PI / 2;
|
|
303
|
-
offsetX = Math.cos(diagonalAngle) * baseDisplacement + Math.cos(perpAngle) * modulatedCurve * baseDisplacement * 0.8;
|
|
304
|
-
offsetY = -Math.sin(diagonalAngle) * baseDisplacement - Math.sin(perpAngle) * modulatedCurve * baseDisplacement * 0.8;
|
|
305
|
-
sizeMultiplier = 1 + waveFactor * 0.5 * bulgeFadeOut;
|
|
306
|
-
const waveOpacity = 0.4 + waveFactor * 0.6;
|
|
307
|
-
bulgeOpacity = 1 + (waveOpacity - 1) * bulgeFadeOut;
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
ctx.globalAlpha = opacity * bulgeOpacity;
|
|
311
|
-
const adjustedSize = size * sizeMultiplier;
|
|
312
|
-
const sizeOffset = (adjustedSize - size) / 2;
|
|
313
|
-
ctx.fillRect(dot.x + offsetX - sizeOffset, dot.y + offsetY - sizeOffset, adjustedSize, adjustedSize);
|
|
314
|
-
});
|
|
315
|
-
// Cache if now static
|
|
316
|
-
if (isCurrentlyStatic) {
|
|
317
|
-
cachedImageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
|
318
|
-
isStaticRef.current = true;
|
|
319
|
-
}
|
|
185
|
+
catch {
|
|
186
|
+
cachedImageData = null;
|
|
320
187
|
}
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
188
|
+
};
|
|
189
|
+
// When reduced motion is active, force static rendering after first frame
|
|
190
|
+
if (!shouldAnimate) {
|
|
191
|
+
isStaticRef.current = true;
|
|
192
|
+
mountAnimationCompleteRef.current = true;
|
|
193
|
+
}
|
|
194
|
+
const animate = (currentTime = 0) => {
|
|
195
|
+
if (canvasWidth <= 0 || canvasHeight <= 0) {
|
|
324
196
|
animationRef.current = requestAnimationFrame(animate);
|
|
197
|
+
return;
|
|
325
198
|
}
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
animationRef.current =
|
|
199
|
+
// Skip rendering if not visible in viewport
|
|
200
|
+
if (!isVisibleRef.current) {
|
|
201
|
+
animationRef.current = requestAnimationFrame(animate);
|
|
202
|
+
return;
|
|
329
203
|
}
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
204
|
+
// FPS throttling
|
|
205
|
+
if (currentTime - lastFrameTimeRef.current < frameInterval) {
|
|
206
|
+
animationRef.current = requestAnimationFrame(animate);
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
lastFrameTimeRef.current = currentTime;
|
|
210
|
+
// If static and we have cached image, just render that and stop animating
|
|
211
|
+
if (isStaticRef.current && cachedImageData) {
|
|
212
|
+
ctx.putImageData(cachedImageData, 0, 0);
|
|
213
|
+
// Don't request another frame - animation is complete
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
ctx.clearRect(0, 0, canvasWidth, canvasHeight);
|
|
217
|
+
const time = (Date.now() - startTime) / 1000; // Time in seconds
|
|
218
|
+
// Calculate circular wave radius (travels from center to edge)
|
|
219
|
+
let waveProgress = 0;
|
|
220
|
+
let showBulge = false;
|
|
221
|
+
let bulgeFadeOut = 1; // Multiplier for fading out bulge effect (1 = full effect, 0 = no effect)
|
|
222
|
+
if (bulgeEnabled) {
|
|
223
|
+
const bulgeElapsed = (Date.now() - bulgeStartTimeRef.current) / 1000;
|
|
224
|
+
const delaySeconds = bulgeDelay / 1000;
|
|
225
|
+
const totalCycleDuration = bulgeDuration + delaySeconds;
|
|
226
|
+
const adjustedTime = bulgeElapsed - delaySeconds;
|
|
227
|
+
const fadeStartPercent = 0.6; // Start fading at 60% of wave duration
|
|
228
|
+
if (adjustedTime >= 0) {
|
|
229
|
+
showBulge = true;
|
|
230
|
+
if (bulgeRepeat) {
|
|
231
|
+
// Continuous repeating wave
|
|
232
|
+
const cycleTime = adjustedTime % totalCycleDuration;
|
|
233
|
+
waveProgress = cycleTime < bulgeDuration ? cycleTime / bulgeDuration : 0;
|
|
234
|
+
showBulge = cycleTime < bulgeDuration; // Only show during active wave, not delay
|
|
357
235
|
}
|
|
358
|
-
|
|
359
|
-
//
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
const dx = dot.x - centerX;
|
|
367
|
-
const dy = dot.y - centerY;
|
|
368
|
-
const distanceFromCenter = Math.sqrt(dx * dx + dy * dy);
|
|
369
|
-
const distanceToWave = Math.abs(distanceFromCenter - waveRadius);
|
|
370
|
-
const waveWidth = maxRadius * 0.15;
|
|
371
|
-
const distanceNorm = distanceToWave / waveWidth;
|
|
372
|
-
const waveFactor = Math.exp(-distanceNorm * distanceNorm * 4);
|
|
373
|
-
const angle = Math.atan2(dy, dx);
|
|
374
|
-
const displacementAmount = waveFactor * bulgeIntensity;
|
|
375
|
-
offsetX = Math.cos(angle) * displacementAmount;
|
|
376
|
-
offsetY = Math.sin(angle) * displacementAmount;
|
|
377
|
-
sizeMultiplier = 1 + waveFactor * 0.8;
|
|
378
|
-
bulgeOpacity = 0.3 + waveFactor * 0.7;
|
|
379
|
-
}
|
|
380
|
-
else if (bulgeType === "wave") {
|
|
381
|
-
const diagonalLength = Math.sqrt(canvasWidth * canvasWidth + canvasHeight * canvasHeight);
|
|
382
|
-
const wavePosOnDiagonal = waveProgress * diagonalLength * 1.2;
|
|
383
|
-
const normalizedX = dot.x / canvasWidth;
|
|
384
|
-
const normalizedY = 1 - (dot.y / canvasHeight);
|
|
385
|
-
const dotDiagonalPos = (normalizedX + normalizedY) / 2 * diagonalLength;
|
|
386
|
-
const distanceToWaveFront = dotDiagonalPos - wavePosOnDiagonal;
|
|
387
|
-
const waveWidth = diagonalLength * 0.2;
|
|
388
|
-
const distanceNorm = Math.abs(distanceToWaveFront) / waveWidth;
|
|
389
|
-
const waveFactor = Math.exp(-distanceNorm * distanceNorm * 3);
|
|
390
|
-
const perpendicularOffset = normalizedY - normalizedX;
|
|
391
|
-
const sCurvePhase = perpendicularOffset * Math.PI * 2;
|
|
392
|
-
const sCurveFactor = Math.sin(sCurvePhase + waveProgress * Math.PI * 2);
|
|
393
|
-
const baseDisplacement = waveFactor * bulgeIntensity;
|
|
394
|
-
const diagonalAngle = Math.PI / 4;
|
|
395
|
-
offsetX = Math.cos(diagonalAngle) * baseDisplacement + sCurveFactor * baseDisplacement * 0.5;
|
|
396
|
-
offsetY = -Math.sin(diagonalAngle) * baseDisplacement + sCurveFactor * baseDisplacement * 0.5;
|
|
397
|
-
sizeMultiplier = 1 + waveFactor * 0.6;
|
|
398
|
-
bulgeOpacity = 0.4 + waveFactor * 0.6;
|
|
236
|
+
else {
|
|
237
|
+
// Single wave with opacity fade during last 40%
|
|
238
|
+
if (adjustedTime <= bulgeDuration) {
|
|
239
|
+
waveProgress = adjustedTime / bulgeDuration;
|
|
240
|
+
// Start fading opacity at 60% of duration
|
|
241
|
+
if (waveProgress >= fadeStartPercent) {
|
|
242
|
+
const fadeProgress = (waveProgress - fadeStartPercent) / (1 - fadeStartPercent);
|
|
243
|
+
bulgeFadeOut = 1 - fadeProgress; // Fade from 1 to 0
|
|
399
244
|
}
|
|
400
245
|
}
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
ctx.fillRect(dot.x + offsetX - sizeOffset, dot.y + offsetY - sizeOffset, adjustedSize, adjustedSize);
|
|
246
|
+
else {
|
|
247
|
+
waveProgress = 0;
|
|
248
|
+
showBulge = false;
|
|
249
|
+
}
|
|
406
250
|
}
|
|
407
|
-
}
|
|
251
|
+
}
|
|
408
252
|
}
|
|
409
|
-
|
|
410
|
-
|
|
253
|
+
const waveRadius = waveProgress * maxRadius * 1.5; // Travel beyond edges for smooth cycle
|
|
254
|
+
// For instant trigger, show all dots immediately at full opacity
|
|
255
|
+
if (trigger === "instant") {
|
|
256
|
+
// Check if we're in a static state (no flicker, no active bulge)
|
|
411
257
|
const isCurrentlyStatic = !flicker && (!bulgeEnabled || !showBulge);
|
|
412
258
|
if (isCurrentlyStatic && isStaticRef.current && cachedImageData) {
|
|
413
|
-
// Use cached render
|
|
259
|
+
// Use cached render
|
|
414
260
|
ctx.putImageData(cachedImageData, 0, 0);
|
|
415
261
|
}
|
|
416
262
|
else {
|
|
263
|
+
// Render dots
|
|
417
264
|
dots.forEach((dot) => {
|
|
418
265
|
ctx.fillStyle = dot.color;
|
|
419
266
|
let opacity = dot.baseOpacity;
|
|
267
|
+
// Apply flicker effect if enabled
|
|
420
268
|
if (flicker) {
|
|
421
269
|
const flickerValue = Math.sin(time * dot.flickerSpeed * 3 + dot.flickerPhase);
|
|
422
|
-
const flickerMultiplier = 0.6 + (flickerValue * 0.4);
|
|
270
|
+
const flickerMultiplier = 0.6 + (flickerValue * 0.4); // Oscillate between 0.6 and 1.0
|
|
423
271
|
opacity *= flickerMultiplier;
|
|
424
272
|
}
|
|
425
273
|
// Calculate bulge displacement
|
|
@@ -427,8 +275,9 @@ const MatrixFx = React.forwardRef(({ speed = 1, colors = ["brand-solid-medium"],
|
|
|
427
275
|
let offsetY = 0;
|
|
428
276
|
let sizeMultiplier = 1;
|
|
429
277
|
let bulgeOpacity = 1;
|
|
430
|
-
if (bulgeEnabled) {
|
|
278
|
+
if (bulgeEnabled && showBulge) {
|
|
431
279
|
if (bulgeType === "ripple") {
|
|
280
|
+
// Ripple: circular wave from center
|
|
432
281
|
const dx = dot.x - centerX;
|
|
433
282
|
const dy = dot.y - centerY;
|
|
434
283
|
const distanceFromCenter = Math.sqrt(dx * dx + dy * dy);
|
|
@@ -437,31 +286,52 @@ const MatrixFx = React.forwardRef(({ speed = 1, colors = ["brand-solid-medium"],
|
|
|
437
286
|
const distanceNorm = distanceToWave / waveWidth;
|
|
438
287
|
const waveFactor = Math.exp(-distanceNorm * distanceNorm * 4);
|
|
439
288
|
const angle = Math.atan2(dy, dx);
|
|
440
|
-
const displacementAmount = waveFactor * bulgeIntensity;
|
|
289
|
+
const displacementAmount = waveFactor * bulgeIntensity * bulgeFadeOut;
|
|
441
290
|
offsetX = Math.cos(angle) * displacementAmount;
|
|
442
291
|
offsetY = Math.sin(angle) * displacementAmount;
|
|
443
|
-
sizeMultiplier = 1 + waveFactor * 0.8;
|
|
444
|
-
|
|
292
|
+
sizeMultiplier = 1 + waveFactor * 0.8 * bulgeFadeOut;
|
|
293
|
+
const waveOpacity = 0.3 + waveFactor * 0.7;
|
|
294
|
+
bulgeOpacity = 1 + (waveOpacity - 1) * bulgeFadeOut;
|
|
445
295
|
}
|
|
446
296
|
else if (bulgeType === "wave") {
|
|
297
|
+
// Wave: Organic S-curve from bottom-left to top-right with rotation
|
|
447
298
|
const diagonalLength = Math.sqrt(canvasWidth * canvasWidth + canvasHeight * canvasHeight);
|
|
448
|
-
|
|
299
|
+
// Start wave off-screen before bottom-left, end off-screen after top-right
|
|
300
|
+
const wavePosOnDiagonal = (waveProgress * diagonalLength * 1.4) - (diagonalLength * 0.2);
|
|
301
|
+
// Calculate distance along the diagonal (from bottom-left to top-right)
|
|
449
302
|
const normalizedX = dot.x / canvasWidth;
|
|
450
303
|
const normalizedY = 1 - (dot.y / canvasHeight);
|
|
451
304
|
const dotDiagonalPos = (normalizedX + normalizedY) / 2 * diagonalLength;
|
|
305
|
+
// Distance from wave front
|
|
452
306
|
const distanceToWaveFront = dotDiagonalPos - wavePosOnDiagonal;
|
|
453
|
-
const waveWidth = diagonalLength * 0.
|
|
454
|
-
const distanceNorm =
|
|
455
|
-
|
|
307
|
+
const waveWidth = diagonalLength * 0.25;
|
|
308
|
+
const distanceNorm = distanceToWaveFront / waveWidth;
|
|
309
|
+
// Smooth wave factor with wider influence
|
|
310
|
+
const waveFactor = Math.exp(-distanceNorm * distanceNorm * 2.5);
|
|
311
|
+
// Create rotating S-curve with multiple frequency components
|
|
456
312
|
const perpendicularOffset = normalizedY - normalizedX;
|
|
457
|
-
|
|
458
|
-
const
|
|
459
|
-
const
|
|
313
|
+
// Primary S-curve that rotates over time
|
|
314
|
+
const rotationPhase = waveProgress * Math.PI * 3; // Rotates 1.5 times during animation
|
|
315
|
+
const primaryFreq = 3; // Number of S-curves along the wave
|
|
316
|
+
const sCurvePrimary = Math.sin(perpendicularOffset * Math.PI * primaryFreq + rotationPhase);
|
|
317
|
+
// Secondary curve for complexity (higher frequency, lower amplitude)
|
|
318
|
+
const secondaryFreq = 7;
|
|
319
|
+
const sCurveSecondary = Math.sin(perpendicularOffset * Math.PI * secondaryFreq - rotationPhase * 1.5) * 0.4;
|
|
320
|
+
// Combine curves for organic motion
|
|
321
|
+
const sCurveFactor = sCurvePrimary + sCurveSecondary;
|
|
322
|
+
// Wave straightens at the edges (distanceNorm affects curve strength)
|
|
323
|
+
const curveStrength = 1 - Math.abs(distanceNorm) * 0.5;
|
|
324
|
+
const modulatedCurve = sCurveFactor * curveStrength;
|
|
325
|
+
// Apply displacement
|
|
326
|
+
const baseDisplacement = waveFactor * bulgeIntensity * bulgeFadeOut;
|
|
460
327
|
const diagonalAngle = Math.PI / 4;
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
328
|
+
// Perpendicular displacement creates the S-curve
|
|
329
|
+
const perpAngle = diagonalAngle + Math.PI / 2;
|
|
330
|
+
offsetX = Math.cos(diagonalAngle) * baseDisplacement + Math.cos(perpAngle) * modulatedCurve * baseDisplacement * 0.8;
|
|
331
|
+
offsetY = -Math.sin(diagonalAngle) * baseDisplacement - Math.sin(perpAngle) * modulatedCurve * baseDisplacement * 0.8;
|
|
332
|
+
sizeMultiplier = 1 + waveFactor * 0.5 * bulgeFadeOut;
|
|
333
|
+
const waveOpacity = 0.4 + waveFactor * 0.6;
|
|
334
|
+
bulgeOpacity = 1 + (waveOpacity - 1) * bulgeFadeOut;
|
|
465
335
|
}
|
|
466
336
|
}
|
|
467
337
|
ctx.globalAlpha = opacity * bulgeOpacity;
|
|
@@ -471,133 +341,121 @@ const MatrixFx = React.forwardRef(({ speed = 1, colors = ["brand-solid-medium"],
|
|
|
471
341
|
});
|
|
472
342
|
// Cache if now static
|
|
473
343
|
if (isCurrentlyStatic) {
|
|
474
|
-
|
|
344
|
+
cacheStaticFrame();
|
|
475
345
|
isStaticRef.current = true;
|
|
476
346
|
}
|
|
477
347
|
}
|
|
348
|
+
ctx.globalAlpha = 1;
|
|
349
|
+
// Only continue animating if there's something dynamic (flicker or bulge)
|
|
350
|
+
if (!isCurrentlyStatic) {
|
|
351
|
+
animationRef.current = requestAnimationFrame(animate);
|
|
352
|
+
}
|
|
353
|
+
else {
|
|
354
|
+
// Clear the ref so the animation can be restarted
|
|
355
|
+
animationRef.current = undefined;
|
|
356
|
+
}
|
|
357
|
+
return;
|
|
478
358
|
}
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
}
|
|
491
|
-
// For hover, click, and manual triggers with animation
|
|
492
|
-
if (trigger === "hover" || trigger === "click" || trigger === "manual") {
|
|
493
|
-
if (isHoveredRef.current) {
|
|
494
|
-
// Revealing animation with explosive easing
|
|
495
|
-
const now = Date.now();
|
|
496
|
-
const elapsed = (now - revealStartTimeRef.current) / 1000;
|
|
497
|
-
// Cubic easing: starts very slow, then explodes
|
|
498
|
-
const revealProgress = Math.pow(elapsed, 3) * speed * 3;
|
|
499
|
-
// Cap progress to prevent infinite growth (max offset is ~1.3)
|
|
500
|
-
const cappedProgress = Math.min(revealProgress, 2.0);
|
|
501
|
-
// Track maximum progress for reverse animation
|
|
502
|
-
maxRevealProgressRef.current = cappedProgress;
|
|
503
|
-
dots.forEach((dot) => {
|
|
504
|
-
const normalizedDistance = dot.distanceFromOrigin / maxDistance;
|
|
505
|
-
const introOffset = normalizedDistance * 0.8 + dot.randomOffset * 0.5; // Much lower threshold
|
|
506
|
-
let opacity = 0;
|
|
507
|
-
if (cappedProgress > introOffset) {
|
|
508
|
-
// Explosive opacity increase
|
|
509
|
-
const fadeIn = (cappedProgress - introOffset) * 8; // Faster fade-in
|
|
510
|
-
opacity = Math.min(1, fadeIn * fadeIn) * dot.baseOpacity;
|
|
511
|
-
// Apply flicker effect if enabled
|
|
512
|
-
if (flicker) {
|
|
513
|
-
const flickerValue = Math.sin(time * dot.flickerSpeed * 3 + dot.flickerPhase);
|
|
514
|
-
const flickerMultiplier = 0.6 + (flickerValue * 0.4); // Oscillate between 0.6 and 1.0
|
|
515
|
-
opacity *= flickerMultiplier;
|
|
516
|
-
}
|
|
359
|
+
// For mount trigger - progressive reveal on load, then static
|
|
360
|
+
if (trigger === "mount") {
|
|
361
|
+
if (!mountAnimationCompleteRef.current) {
|
|
362
|
+
// Revealing animation with explosive easing
|
|
363
|
+
const now = Date.now();
|
|
364
|
+
const elapsed = (now - revealStartTimeRef.current) / 1000;
|
|
365
|
+
// Cubic easing: starts very slow, then explodes
|
|
366
|
+
const revealProgress = Math.pow(elapsed, 3) * speed * 3;
|
|
367
|
+
// Check if animation is complete (max offset is ~1.3)
|
|
368
|
+
if (revealProgress >= 2.0) {
|
|
369
|
+
mountAnimationCompleteRef.current = true;
|
|
517
370
|
}
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
let
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
const
|
|
528
|
-
const
|
|
529
|
-
|
|
530
|
-
const waveWidth = maxRadius * 0.15;
|
|
531
|
-
const distanceNorm = distanceToWave / waveWidth;
|
|
532
|
-
const waveFactor = Math.exp(-distanceNorm * distanceNorm * 4);
|
|
533
|
-
const angle = Math.atan2(dy, dx);
|
|
534
|
-
const displacementAmount = waveFactor * bulgeIntensity;
|
|
535
|
-
offsetX = Math.cos(angle) * displacementAmount;
|
|
536
|
-
offsetY = Math.sin(angle) * displacementAmount;
|
|
537
|
-
sizeMultiplier = 1 + waveFactor * 0.8;
|
|
538
|
-
bulgeOpacity = 0.3 + waveFactor * 0.7;
|
|
371
|
+
dots.forEach((dot) => {
|
|
372
|
+
const normalizedDistance = dot.distanceFromOrigin / maxDistance;
|
|
373
|
+
const introOffset = normalizedDistance * 0.8 + dot.randomOffset * 0.5;
|
|
374
|
+
let opacity = 0;
|
|
375
|
+
if (revealProgress > introOffset) {
|
|
376
|
+
const fadeIn = (revealProgress - introOffset) * 8;
|
|
377
|
+
opacity = Math.min(1, fadeIn * fadeIn) * dot.baseOpacity;
|
|
378
|
+
// Apply flicker effect if enabled
|
|
379
|
+
if (flicker) {
|
|
380
|
+
const flickerValue = Math.sin(time * dot.flickerSpeed * 3 + dot.flickerPhase);
|
|
381
|
+
const flickerMultiplier = 0.6 + (flickerValue * 0.4);
|
|
382
|
+
opacity *= flickerMultiplier;
|
|
539
383
|
}
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
384
|
+
}
|
|
385
|
+
if (opacity > 0) {
|
|
386
|
+
// Calculate bulge displacement
|
|
387
|
+
let offsetX = 0;
|
|
388
|
+
let offsetY = 0;
|
|
389
|
+
let sizeMultiplier = 1;
|
|
390
|
+
let bulgeOpacity = 1;
|
|
391
|
+
if (bulgeEnabled) {
|
|
392
|
+
if (bulgeType === "ripple") {
|
|
393
|
+
const dx = dot.x - centerX;
|
|
394
|
+
const dy = dot.y - centerY;
|
|
395
|
+
const distanceFromCenter = Math.sqrt(dx * dx + dy * dy);
|
|
396
|
+
const distanceToWave = Math.abs(distanceFromCenter - waveRadius);
|
|
397
|
+
const waveWidth = maxRadius * 0.15;
|
|
398
|
+
const distanceNorm = distanceToWave / waveWidth;
|
|
399
|
+
const waveFactor = Math.exp(-distanceNorm * distanceNorm * 4);
|
|
400
|
+
const angle = Math.atan2(dy, dx);
|
|
401
|
+
const displacementAmount = waveFactor * bulgeIntensity;
|
|
402
|
+
offsetX = Math.cos(angle) * displacementAmount;
|
|
403
|
+
offsetY = Math.sin(angle) * displacementAmount;
|
|
404
|
+
sizeMultiplier = 1 + waveFactor * 0.8;
|
|
405
|
+
bulgeOpacity = 0.3 + waveFactor * 0.7;
|
|
406
|
+
}
|
|
407
|
+
else if (bulgeType === "wave") {
|
|
408
|
+
const diagonalLength = Math.sqrt(canvasWidth * canvasWidth + canvasHeight * canvasHeight);
|
|
409
|
+
const wavePosOnDiagonal = waveProgress * diagonalLength * 1.2;
|
|
410
|
+
const normalizedX = dot.x / canvasWidth;
|
|
411
|
+
const normalizedY = 1 - (dot.y / canvasHeight);
|
|
412
|
+
const dotDiagonalPos = (normalizedX + normalizedY) / 2 * diagonalLength;
|
|
413
|
+
const distanceToWaveFront = dotDiagonalPos - wavePosOnDiagonal;
|
|
414
|
+
const waveWidth = diagonalLength * 0.2;
|
|
415
|
+
const distanceNorm = Math.abs(distanceToWaveFront) / waveWidth;
|
|
416
|
+
const waveFactor = Math.exp(-distanceNorm * distanceNorm * 3);
|
|
417
|
+
const perpendicularOffset = normalizedY - normalizedX;
|
|
418
|
+
const sCurvePhase = perpendicularOffset * Math.PI * 2;
|
|
419
|
+
const sCurveFactor = Math.sin(sCurvePhase + waveProgress * Math.PI * 2);
|
|
420
|
+
const baseDisplacement = waveFactor * bulgeIntensity;
|
|
421
|
+
const diagonalAngle = Math.PI / 4;
|
|
422
|
+
offsetX = Math.cos(diagonalAngle) * baseDisplacement + sCurveFactor * baseDisplacement * 0.5;
|
|
423
|
+
offsetY = -Math.sin(diagonalAngle) * baseDisplacement + sCurveFactor * baseDisplacement * 0.5;
|
|
424
|
+
sizeMultiplier = 1 + waveFactor * 0.6;
|
|
425
|
+
bulgeOpacity = 0.4 + waveFactor * 0.6;
|
|
426
|
+
}
|
|
559
427
|
}
|
|
428
|
+
ctx.fillStyle = dot.color;
|
|
429
|
+
ctx.globalAlpha = opacity * bulgeOpacity;
|
|
430
|
+
const adjustedSize = size * sizeMultiplier;
|
|
431
|
+
const sizeOffset = (adjustedSize - size) / 2;
|
|
432
|
+
ctx.fillRect(dot.x + offsetX - sizeOffset, dot.y + offsetY - sizeOffset, adjustedSize, adjustedSize);
|
|
560
433
|
}
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
434
|
+
});
|
|
435
|
+
}
|
|
436
|
+
else {
|
|
437
|
+
// Animation complete - show all dots with optional flicker
|
|
438
|
+
const isCurrentlyStatic = !flicker && (!bulgeEnabled || !showBulge);
|
|
439
|
+
if (isCurrentlyStatic && isStaticRef.current && cachedImageData) {
|
|
440
|
+
// Use cached render for completed static state
|
|
441
|
+
ctx.putImageData(cachedImageData, 0, 0);
|
|
566
442
|
}
|
|
567
|
-
|
|
568
|
-
}
|
|
569
|
-
else {
|
|
570
|
-
// Reverse animation when hover ends - only run if there's something to hide
|
|
571
|
-
if (hideStartProgressRef.current > 0) {
|
|
572
|
-
const elapsed = (Date.now() - hideStartTimeRef.current) / 1000;
|
|
573
|
-
// Use quadratic easing for faster hide (power of 2)
|
|
574
|
-
const hideSpeed = speed * 6; // Faster to handle max progress of 2.0
|
|
575
|
-
const hideProgress = Math.pow(elapsed, 2) * hideSpeed;
|
|
576
|
-
// Reverse from the progress we had when hide started
|
|
577
|
-
const reverseProgress = Math.max(0, hideStartProgressRef.current - hideProgress);
|
|
578
|
-
if (reverseProgress > 0.01) { // Small threshold to ensure completion
|
|
579
|
-
// Still have dots to hide
|
|
443
|
+
else {
|
|
580
444
|
dots.forEach((dot) => {
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
const
|
|
586
|
-
opacity
|
|
587
|
-
// Apply flicker effect if enabled
|
|
588
|
-
if (flicker) {
|
|
589
|
-
const flickerValue = Math.sin(time * dot.flickerSpeed * 3 + dot.flickerPhase);
|
|
590
|
-
const flickerMultiplier = 0.6 + (flickerValue * 0.4);
|
|
591
|
-
opacity *= flickerMultiplier;
|
|
592
|
-
}
|
|
445
|
+
ctx.fillStyle = dot.color;
|
|
446
|
+
let opacity = dot.baseOpacity;
|
|
447
|
+
if (flicker) {
|
|
448
|
+
const flickerValue = Math.sin(time * dot.flickerSpeed * 3 + dot.flickerPhase);
|
|
449
|
+
const flickerMultiplier = 0.6 + (flickerValue * 0.4);
|
|
450
|
+
opacity *= flickerMultiplier;
|
|
593
451
|
}
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
if (
|
|
452
|
+
// Calculate bulge displacement
|
|
453
|
+
let offsetX = 0;
|
|
454
|
+
let offsetY = 0;
|
|
455
|
+
let sizeMultiplier = 1;
|
|
456
|
+
let bulgeOpacity = 1;
|
|
457
|
+
if (bulgeEnabled) {
|
|
458
|
+
if (bulgeType === "ripple") {
|
|
601
459
|
const dx = dot.x - centerX;
|
|
602
460
|
const dy = dot.y - centerY;
|
|
603
461
|
const distanceFromCenter = Math.sqrt(dx * dx + dy * dy);
|
|
@@ -607,48 +465,230 @@ const MatrixFx = React.forwardRef(({ speed = 1, colors = ["brand-solid-medium"],
|
|
|
607
465
|
const waveFactor = Math.exp(-distanceNorm * distanceNorm * 4);
|
|
608
466
|
const angle = Math.atan2(dy, dx);
|
|
609
467
|
const displacementAmount = waveFactor * bulgeIntensity;
|
|
610
|
-
offsetX = Math.cos(angle) * displacementAmount
|
|
611
|
-
offsetY = Math.sin(angle) * displacementAmount
|
|
468
|
+
offsetX = Math.cos(angle) * displacementAmount;
|
|
469
|
+
offsetY = Math.sin(angle) * displacementAmount;
|
|
612
470
|
sizeMultiplier = 1 + waveFactor * 0.8;
|
|
613
471
|
bulgeOpacity = 0.3 + waveFactor * 0.7;
|
|
614
472
|
}
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
473
|
+
else if (bulgeType === "wave") {
|
|
474
|
+
const diagonalLength = Math.sqrt(canvasWidth * canvasWidth + canvasHeight * canvasHeight);
|
|
475
|
+
const wavePosOnDiagonal = waveProgress * diagonalLength * 1.2;
|
|
476
|
+
const normalizedX = dot.x / canvasWidth;
|
|
477
|
+
const normalizedY = 1 - (dot.y / canvasHeight);
|
|
478
|
+
const dotDiagonalPos = (normalizedX + normalizedY) / 2 * diagonalLength;
|
|
479
|
+
const distanceToWaveFront = dotDiagonalPos - wavePosOnDiagonal;
|
|
480
|
+
const waveWidth = diagonalLength * 0.2;
|
|
481
|
+
const distanceNorm = Math.abs(distanceToWaveFront) / waveWidth;
|
|
482
|
+
const waveFactor = Math.exp(-distanceNorm * distanceNorm * 3);
|
|
483
|
+
const perpendicularOffset = normalizedY - normalizedX;
|
|
484
|
+
const sCurvePhase = perpendicularOffset * Math.PI * 2;
|
|
485
|
+
const sCurveFactor = Math.sin(sCurvePhase + waveProgress * Math.PI * 2);
|
|
486
|
+
const baseDisplacement = waveFactor * bulgeIntensity;
|
|
487
|
+
const diagonalAngle = Math.PI / 4;
|
|
488
|
+
offsetX = Math.cos(diagonalAngle) * baseDisplacement + sCurveFactor * baseDisplacement * 0.5;
|
|
489
|
+
offsetY = -Math.sin(diagonalAngle) * baseDisplacement + sCurveFactor * baseDisplacement * 0.5;
|
|
490
|
+
sizeMultiplier = 1 + waveFactor * 0.6;
|
|
491
|
+
bulgeOpacity = 0.4 + waveFactor * 0.6;
|
|
492
|
+
}
|
|
620
493
|
}
|
|
494
|
+
ctx.globalAlpha = opacity * bulgeOpacity;
|
|
495
|
+
const adjustedSize = size * sizeMultiplier;
|
|
496
|
+
const sizeOffset = (adjustedSize - size) / 2;
|
|
497
|
+
ctx.fillRect(dot.x + offsetX - sizeOffset, dot.y + offsetY - sizeOffset, adjustedSize, adjustedSize);
|
|
621
498
|
});
|
|
499
|
+
// Cache if now static
|
|
500
|
+
if (isCurrentlyStatic) {
|
|
501
|
+
cacheStaticFrame();
|
|
502
|
+
isStaticRef.current = true;
|
|
503
|
+
}
|
|
622
504
|
}
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
505
|
+
}
|
|
506
|
+
ctx.globalAlpha = 1;
|
|
507
|
+
// Only continue animating if mount animation is incomplete or there's something dynamic
|
|
508
|
+
const isCurrentlyStatic = mountAnimationCompleteRef.current && !flicker && (!bulgeEnabled || !showBulge);
|
|
509
|
+
if (!isCurrentlyStatic) {
|
|
510
|
+
animationRef.current = requestAnimationFrame(animate);
|
|
511
|
+
}
|
|
512
|
+
else {
|
|
513
|
+
// Clear the ref so the animation can be restarted
|
|
514
|
+
animationRef.current = undefined;
|
|
515
|
+
}
|
|
516
|
+
return;
|
|
517
|
+
}
|
|
518
|
+
// For hover, click, and manual triggers with animation
|
|
519
|
+
if (trigger === "hover" || trigger === "click" || trigger === "manual") {
|
|
520
|
+
if (isHoveredRef.current) {
|
|
521
|
+
// Revealing animation with explosive easing
|
|
522
|
+
const now = Date.now();
|
|
523
|
+
const elapsed = (now - revealStartTimeRef.current) / 1000;
|
|
524
|
+
// Cubic easing: starts very slow, then explodes
|
|
525
|
+
const revealProgress = Math.pow(elapsed, 3) * speed * 3;
|
|
526
|
+
// Cap progress to prevent infinite growth (max offset is ~1.3)
|
|
527
|
+
const cappedProgress = Math.min(revealProgress, 2.0);
|
|
528
|
+
// Track maximum progress for reverse animation
|
|
529
|
+
maxRevealProgressRef.current = cappedProgress;
|
|
530
|
+
dots.forEach((dot) => {
|
|
531
|
+
const normalizedDistance = dot.distanceFromOrigin / maxDistance;
|
|
532
|
+
const introOffset = normalizedDistance * 0.8 + dot.randomOffset * 0.5; // Much lower threshold
|
|
533
|
+
let opacity = 0;
|
|
534
|
+
if (cappedProgress > introOffset) {
|
|
535
|
+
// Explosive opacity increase
|
|
536
|
+
const fadeIn = (cappedProgress - introOffset) * 8; // Faster fade-in
|
|
537
|
+
opacity = Math.min(1, fadeIn * fadeIn) * dot.baseOpacity;
|
|
538
|
+
// Apply flicker effect if enabled
|
|
539
|
+
if (flicker) {
|
|
540
|
+
const flickerValue = Math.sin(time * dot.flickerSpeed * 3 + dot.flickerPhase);
|
|
541
|
+
const flickerMultiplier = 0.6 + (flickerValue * 0.4); // Oscillate between 0.6 and 1.0
|
|
542
|
+
opacity *= flickerMultiplier;
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
if (opacity > 0) {
|
|
546
|
+
// Calculate bulge displacement
|
|
547
|
+
let offsetX = 0;
|
|
548
|
+
let offsetY = 0;
|
|
549
|
+
let sizeMultiplier = 1;
|
|
550
|
+
let bulgeOpacity = 1;
|
|
551
|
+
if (bulgeEnabled) {
|
|
552
|
+
if (bulgeType === "ripple") {
|
|
553
|
+
const dx = dot.x - centerX;
|
|
554
|
+
const dy = dot.y - centerY;
|
|
555
|
+
const distanceFromCenter = Math.sqrt(dx * dx + dy * dy);
|
|
556
|
+
const distanceToWave = Math.abs(distanceFromCenter - waveRadius);
|
|
557
|
+
const waveWidth = maxRadius * 0.15;
|
|
558
|
+
const distanceNorm = distanceToWave / waveWidth;
|
|
559
|
+
const waveFactor = Math.exp(-distanceNorm * distanceNorm * 4);
|
|
560
|
+
const angle = Math.atan2(dy, dx);
|
|
561
|
+
const displacementAmount = waveFactor * bulgeIntensity;
|
|
562
|
+
offsetX = Math.cos(angle) * displacementAmount;
|
|
563
|
+
offsetY = Math.sin(angle) * displacementAmount;
|
|
564
|
+
sizeMultiplier = 1 + waveFactor * 0.8;
|
|
565
|
+
bulgeOpacity = 0.3 + waveFactor * 0.7;
|
|
566
|
+
}
|
|
567
|
+
else if (bulgeType === "wave") {
|
|
568
|
+
const diagonalLength = Math.sqrt(canvasWidth * canvasWidth + canvasHeight * canvasHeight);
|
|
569
|
+
const wavePosOnDiagonal = waveProgress * diagonalLength * 1.2;
|
|
570
|
+
const normalizedX = dot.x / canvasWidth;
|
|
571
|
+
const normalizedY = 1 - (dot.y / canvasHeight);
|
|
572
|
+
const dotDiagonalPos = (normalizedX + normalizedY) / 2 * diagonalLength;
|
|
573
|
+
const distanceToWaveFront = dotDiagonalPos - wavePosOnDiagonal;
|
|
574
|
+
const waveWidth = diagonalLength * 0.2;
|
|
575
|
+
const distanceNorm = Math.abs(distanceToWaveFront) / waveWidth;
|
|
576
|
+
const waveFactor = Math.exp(-distanceNorm * distanceNorm * 3);
|
|
577
|
+
const perpendicularOffset = normalizedY - normalizedX;
|
|
578
|
+
const sCurvePhase = perpendicularOffset * Math.PI * 2;
|
|
579
|
+
const sCurveFactor = Math.sin(sCurvePhase + waveProgress * Math.PI * 2);
|
|
580
|
+
const baseDisplacement = waveFactor * bulgeIntensity;
|
|
581
|
+
const diagonalAngle = Math.PI / 4;
|
|
582
|
+
offsetX = Math.cos(diagonalAngle) * baseDisplacement + sCurveFactor * baseDisplacement * 0.5;
|
|
583
|
+
offsetY = -Math.sin(diagonalAngle) * baseDisplacement + sCurveFactor * baseDisplacement * 0.5;
|
|
584
|
+
sizeMultiplier = 1 + waveFactor * 0.6;
|
|
585
|
+
bulgeOpacity = 0.4 + waveFactor * 0.6;
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
ctx.fillStyle = dot.color;
|
|
589
|
+
ctx.globalAlpha = opacity * bulgeOpacity;
|
|
590
|
+
const adjustedSize = size * sizeMultiplier;
|
|
591
|
+
const sizeOffset = (adjustedSize - size) / 2;
|
|
592
|
+
ctx.fillRect(dot.x + offsetX - sizeOffset, dot.y + offsetY - sizeOffset, adjustedSize, adjustedSize);
|
|
593
|
+
}
|
|
594
|
+
});
|
|
595
|
+
}
|
|
596
|
+
else {
|
|
597
|
+
// Reverse animation when hover ends - only run if there's something to hide
|
|
598
|
+
if (hideStartProgressRef.current > 0) {
|
|
599
|
+
const elapsed = (Date.now() - hideStartTimeRef.current) / 1000;
|
|
600
|
+
// Use quadratic easing for faster hide (power of 2)
|
|
601
|
+
const hideSpeed = speed * 6; // Faster to handle max progress of 2.0
|
|
602
|
+
const hideProgress = Math.pow(elapsed, 2) * hideSpeed;
|
|
603
|
+
// Reverse from the progress we had when hide started
|
|
604
|
+
const reverseProgress = Math.max(0, hideStartProgressRef.current - hideProgress);
|
|
605
|
+
if (reverseProgress > 0.01) { // Small threshold to ensure completion
|
|
606
|
+
// Still have dots to hide
|
|
607
|
+
dots.forEach((dot) => {
|
|
608
|
+
const normalizedDistance = dot.distanceFromOrigin / maxDistance;
|
|
609
|
+
const introOffset = normalizedDistance * 0.8 + dot.randomOffset * 0.5;
|
|
610
|
+
let opacity = 0;
|
|
611
|
+
if (reverseProgress > introOffset) {
|
|
612
|
+
const fadeIn = (reverseProgress - introOffset) * 8;
|
|
613
|
+
opacity = Math.min(1, fadeIn * fadeIn) * dot.baseOpacity;
|
|
614
|
+
// Apply flicker effect if enabled
|
|
615
|
+
if (flicker) {
|
|
616
|
+
const flickerValue = Math.sin(time * dot.flickerSpeed * 3 + dot.flickerPhase);
|
|
617
|
+
const flickerMultiplier = 0.6 + (flickerValue * 0.4);
|
|
618
|
+
opacity *= flickerMultiplier;
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
if (opacity > 0) {
|
|
622
|
+
// Calculate bulge displacement
|
|
623
|
+
let offsetX = 0;
|
|
624
|
+
let offsetY = 0;
|
|
625
|
+
let sizeMultiplier = 1;
|
|
626
|
+
let bulgeOpacity = 1;
|
|
627
|
+
if (bulgeEnabled) {
|
|
628
|
+
const dx = dot.x - centerX;
|
|
629
|
+
const dy = dot.y - centerY;
|
|
630
|
+
const distanceFromCenter = Math.sqrt(dx * dx + dy * dy);
|
|
631
|
+
const distanceToWave = Math.abs(distanceFromCenter - waveRadius);
|
|
632
|
+
const waveWidth = maxRadius * 0.15;
|
|
633
|
+
const distanceNorm = distanceToWave / waveWidth;
|
|
634
|
+
const waveFactor = Math.exp(-distanceNorm * distanceNorm * 4);
|
|
635
|
+
const angle = Math.atan2(dy, dx);
|
|
636
|
+
const displacementAmount = waveFactor * bulgeIntensity;
|
|
637
|
+
offsetX = Math.cos(angle) * displacementAmount * 0.3;
|
|
638
|
+
offsetY = Math.sin(angle) * displacementAmount * 0.3 - waveFactor * bulgeIntensity;
|
|
639
|
+
sizeMultiplier = 1 + waveFactor * 0.8;
|
|
640
|
+
bulgeOpacity = 0.3 + waveFactor * 0.7;
|
|
641
|
+
}
|
|
642
|
+
ctx.fillStyle = dot.color;
|
|
643
|
+
ctx.globalAlpha = opacity * bulgeOpacity;
|
|
644
|
+
const adjustedSize = size * sizeMultiplier;
|
|
645
|
+
const sizeOffset = (adjustedSize - size) / 2;
|
|
646
|
+
ctx.fillRect(dot.x + offsetX - sizeOffset, dot.y + offsetY - sizeOffset, adjustedSize, adjustedSize);
|
|
647
|
+
}
|
|
648
|
+
});
|
|
649
|
+
}
|
|
650
|
+
else {
|
|
651
|
+
// Hide animation complete, reset progress and clear canvas
|
|
652
|
+
hideStartProgressRef.current = 0;
|
|
653
|
+
}
|
|
626
654
|
}
|
|
627
655
|
}
|
|
628
656
|
}
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
657
|
+
ctx.globalAlpha = 1;
|
|
658
|
+
// Only continue animating if there's active animation or dynamic content
|
|
659
|
+
const hasActiveAnimation = isHoveredRef.current || hideStartProgressRef.current > 0;
|
|
660
|
+
const hasDynamicContent = flicker || (bulgeEnabled && showBulge);
|
|
661
|
+
if (hasActiveAnimation || hasDynamicContent) {
|
|
662
|
+
animationRef.current = requestAnimationFrame(animate);
|
|
663
|
+
}
|
|
664
|
+
else {
|
|
665
|
+
// Clear the ref so the animation can be restarted
|
|
666
|
+
animationRef.current = undefined;
|
|
667
|
+
}
|
|
668
|
+
};
|
|
669
|
+
// Store animate function in ref so it can be restarted
|
|
670
|
+
animateFnRef.current = animate;
|
|
671
|
+
animate();
|
|
672
|
+
};
|
|
673
|
+
setup();
|
|
674
|
+
const resizeObserver = new ResizeObserver(() => {
|
|
675
|
+
if (!initialized) {
|
|
676
|
+
setup();
|
|
636
677
|
}
|
|
637
678
|
else {
|
|
638
|
-
|
|
639
|
-
animationRef.current = undefined;
|
|
679
|
+
handleResize();
|
|
640
680
|
}
|
|
641
|
-
};
|
|
642
|
-
|
|
643
|
-
animateFnRef.current = animate;
|
|
644
|
-
animate();
|
|
681
|
+
});
|
|
682
|
+
resizeObserver.observe(container);
|
|
645
683
|
return () => {
|
|
646
|
-
|
|
684
|
+
disposed = true;
|
|
685
|
+
resizeObserver.disconnect();
|
|
686
|
+
window.removeEventListener("resize", handleResize);
|
|
647
687
|
if (animationRef.current) {
|
|
648
688
|
cancelAnimationFrame(animationRef.current);
|
|
649
689
|
}
|
|
650
690
|
};
|
|
651
|
-
}, [colors, size, spacing, speed, revealFrom, trigger, flicker, bulge, fps]);
|
|
691
|
+
}, [colors, size, spacing, speed, revealFrom, trigger, flicker, bulge, fps, shouldAnimate]);
|
|
652
692
|
// Manual trigger control via `active` prop
|
|
653
693
|
useEffect(() => {
|
|
654
694
|
if (trigger !== "manual")
|