vue3-bits
v0.1.2
Published
Vue3 + TresJS reusable 3D components (ModelViewer first).
Readme
vue3-bits
A small, publishable Vue 3 + TypeScript component library built on
TresJS v5 (declarative Three.js for Vue). Components
include ModelViewer — a faithful Vue port of the
react-bits ModelViewer, with drag-to-rotate, inertia,
mouse parallax, hover rotation, auto-rotate, auto-framing, fade-in, environment
lighting, contact shadows, and PNG screenshot export — and Lightfall, a
shader light-streak background built on ogl, and TextType, a typewriter
text animation (react-bits port, no extra dependencies). It also ships six
text-animation components ported 1:1 from
react-bits — ShinyText, CurvedLoop,
FuzzyText, GradientText, LineSidebar and AnimatedList —
all reimplemented with native requestAnimationFrame / IntersectionObserver /
Canvas 2D / SVG, with zero new runtime or peer dependencies. It now also ships
seven interaction / 3D components ported from react-bits — SpotlightCard,
BorderGlow, Dock, ScrollStack, CircularGallery,
MagicBento and FluidGlass. Six are zero-dependency DOM + CSS ports;
CircularGallery reuses the already-bundled ogl engine, MagicBento
adds gsap as a bundled runtime dependency, and FluidGlass is built on
the peer @tresjs/core + three (no @react-three/*, drei, maath or
external GLB assets — programmatic geometry + MeshPhysicalMaterial transmission
replace them).
Single package, multiple components. More components will land under
src/components/following the same structure.
Components
| Component | Category | Runtime deps | Notes |
| --- | --- | --- | --- |
| SpotlightCard | Interaction | none | Mouse-following radial spotlight (CSS ::before). |
| BorderGlow | Interaction | none | Mesh-gradient border + edge-proximity glow. |
| Dock | Interaction | none | macOS dock magnification (hand-rolled rAF spring). |
| ScrollStack | Interaction | none | Scroll-pinned stacking cards (native scroll, no Lenis). |
| CircularGallery | 3D | ogl (bundled) | WebGL plane ring; engine in gallery.ts. |
| MagicBento | Interaction | gsap (bundled) | Tilt / magnetism / particles / spotlight. |
| FluidGlass | 3D | @tresjs/core + three (peer) | MeshPhysicalMaterial transmission; no GLB/drei. |
Install
npm install vue3-bits
# peer deps (provided by the host app)
npm install vue@^3.4 three @tresjs/core@^5 @tresjs/cientos@^5vue, three, @tresjs/core and @tresjs/cientos are peer dependencies
and are kept external in the build — your app controls their versions. three
is allowed at >=0.166.0, so newer releases (e.g. [email protected]) install cleanly
without --legacy-peer-deps.
Usage
<script setup lang="ts">
import { ModelViewer } from 'vue3-bits';
</script>
<template>
<ModelViewer
url="https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Models/main/2.0/ToyCar/glTF-Binary/ToyCar.glb"
:width="480"
:height="480"
environment-preset="forest"
/>
</template>Screenshot / capture programmatically
<script setup lang="ts">
import { ref } from 'vue';
import { ModelViewer } from 'vue3-bits';
import type { ModelViewerExpose } from 'vue3-bits';
const viewer = ref<ModelViewerExpose | null>(null);
</script>
<template>
<ModelViewer ref="viewer" url="model.glb" :show-screenshot-button="false" />
<button @click="viewer?.capture()">Download PNG</button>
</template>Note:
preserveDrawingBufferis enabled on the canvas, so the screenshot button /capture()works without a manual re-render. The screenshot downloads asmodel.png.
Props
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| url | string | — (required) | Model URL. Supports .glb, .gltf, .fbx, .obj. |
| width | number \| string | 400 | Canvas width (number → px). |
| height | number \| string | 400 | Canvas height (number → px). |
| modelXOffset | number | 0 | Billboard horizontal NDC offset. |
| modelYOffset | number | 0 | Billboard vertical NDC offset. |
| defaultRotationX | number | -50 | Initial X rotation (degrees). |
| defaultRotationY | number | 20 | Initial Y rotation (degrees). |
| defaultZoom | number | 0.5 | Initial camera Z (clamped to [min,max]). |
| minZoomDistance | number | 0.5 | Min zoom distance. |
| maxZoomDistance | number | 10 | Max zoom distance. |
| enableMouseParallax | boolean | true | Mouse parallax (non-touch). |
| enableManualRotation | boolean | true | Drag to rotate. |
| enableHoverRotation | boolean | true | Hover rotation (non-touch). |
| enableManualZoom | boolean | true | Zoom (OrbitControls + pinch). |
| ambientIntensity | number | 0.3 | Ambient light intensity. |
| keyLightIntensity | number | 1 | Key (top-right) light intensity. |
| fillLightIntensity | number | 0.5 | Fill (left) light intensity. |
| rimLightIntensity | number | 0.8 | Rim (back) light intensity. |
| environmentPreset | EnvironmentPreset | 'forest' | cientos <Environment> preset. 'none' disables it. |
| autoFrame | boolean | false | Auto-compute camera distance from fov. |
| placeholderSrc | string | '' | Blurred image shown while loading. |
| showScreenshotButton | boolean | true | Show the screenshot button. |
| fadeIn | boolean | false | Fade material opacity 0→1 on load. |
| autoRotate | boolean | false | Continuously auto-rotate. |
| autoRotateSpeed | number | 0.35 | Auto-rotate speed (rad/s). |
| onModelLoaded | () => void | — | Called once the model is loaded & normalized. |
EnvironmentPreset
Aligned to the presets shipped by
@tresjs/[email protected].'none'disables the environment. (Earlier docs suggestedapartment/lobby/park/warehouse, but those are not present in cientos v5 and would throw at runtime, so they are omitted.)
'none' | 'city' | 'dawn' | 'forest' | 'hangar' | 'modern' | 'night' | 'shangai' | 'snow' | 'studio' | 'sunset' | 'umbrellas' | 'urban'
Exposed method
capture(): void — render the current frame and download a PNG. Available via
ref on <ModelViewer>.
Lightfall
A shader-driven light-streak background. It renders via
ogl, which is a bundled runtime dependency
— npm install vue3-bits is enough, no separate npm install ogl required.
<script setup lang="ts">
import { Lightfall } from 'vue3-bits';
</script>
<template>
<Lightfall :speed="0.6" background-color="#0A29FF" />
</template>Props
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| color1 / color2 / color3 | string | — | Beam colors (override colors). |
| colors | string[] | ['#A6C8FF', ...] | Color palette. |
| backgroundColor | string | '#0A29FF' | Background color. |
| speed | number | 0.5 | Animation speed. |
| streakCount | number | 2 | Number of beams (1–16). |
| streakWidth | number | 1 | Beam width. |
| streakLength | number | 1 | Beam length. |
| glow | number | 1 | Glow intensity. |
| density | number | 0.6 | Density. |
| zoom | number | 3 | Zoom. |
| mouseInteraction | boolean | true | Mouse interaction. |
| opacity | number | 1 | Opacity. |
| paused | boolean | false | Pause animation. |
Full prop list with live controls is in
src/play/demos/LightfallDemo.vue.
TextType
A typewriter text animation — a faithful Vue port of the
react-bits TextType. It
types out one or more phrases (looping, with an optional blinking cursor) using
only Vue + CSS — no extra runtime dependencies (the cursor blink is a plain
CSS @keyframes, not GSAP).
<script setup lang="ts">
import { TextType } from 'vue3-bits';
</script>
<template>
<TextType
:text="['Hello world', 'Built with Vue 3', 'Happy coding!']"
:typing-speed="50"
:pause-duration="2000"
:show-cursor="true"
/>
</template>Props
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| text | string \| string[] | — (required) | Phrase(s) typed in rotation. A string is treated as a single-element array. |
| texts | string \| string[] | — | Alias of text, used only when text is omitted. |
| tag | string | 'div' | Root element tag name. |
| typingSpeed | number | 50 | Milliseconds per typed character. |
| initialDelay | number | 0 | Delay before typing starts (ms). |
| pauseDuration | number | 2000 | Pause after a phrase completes (ms). |
| deletingSpeed | number | 30 | Milliseconds per deleted character. |
| loop | boolean | true | Cycle through phrases indefinitely. |
| showCursor | boolean | true | Show the blinking cursor. |
| cursorCharacter | string | '\|' | Cursor character. |
| cursorBlinkDuration | number | 0.5 | Cursor blink period (seconds). |
| textColors | string[] | [] | Per-phrase text colors, cycled by index. |
Full prop list with live controls is in
src/play/demos/TextTypeDemo.vue. Emitssentence-complete(payload:[text, index]) after each phrase finishes typing.
ShinyText
A shiny / flowing-gradient text effect — a Vue port of the
react-bits ShinyText. The
shine travels across the text via an animated background-position, driven by a
native requestAnimationFrame loop (no motion/framer-motion dependency).
<script setup lang="ts">
import { ShinyText } from 'vue3-bits';
</script>
<template>
<ShinyText
text="Just shuffle!"
:speed="2"
:shine-color="'#ffffff'"
:color="'#b5b5b5'"
:spread="120"
/>
</template>Props
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| text | string | '' | Text content (rendered inside the shine <span>). |
| disabled | boolean | false | Stop the rAF animation loop. |
| speed | number | 2 | Animation duration (seconds). |
| className | string | '' | Extra class merged onto the root <span>. |
| color | string | '#b5b5b5' | Base text color. |
| shineColor | string | '#ffffff' | Highlight color that sweeps across. |
| spread | number | 120 | Gradient angle (degrees). |
| yoyo | boolean | false | 4-phase ping-pong (forward → hold → reverse → hold). |
| pauseOnHover | boolean | false | Pause animation while hovered. |
| direction | 'left' \| 'right' | 'left' | Sweep direction (symbol-flipped internally). |
| delay | number | 0 | Hold delay at each end (seconds). |
Full prop list with live controls is in
src/play/demos/ShinyTextDemo.vue.
CurvedLoop
A curved marquee that flows text along an SVG arc — a Vue port of the
react-bits CurvedLoop. The
text rides an SVG <textPath>; a single rAF advances the startOffset and wraps
at the measured spacing. Pointer drag scrubs the offset. Unique DOM ids use a
module-level counter (not useId(), for vue <3.5 safety).
<script setup lang="ts">
import { CurvedLoop } from 'vue3-bits';
</script>
<template>
<CurvedLoop
marquee-text="REACT BITS • VUE3 BITS • "
:speed="2"
:curve-amount="400"
:direction="'left'"
:interactive="true"
/>
</template>Props
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| marqueeText | string | '' | Text to flow; a trailing non-breaking space is appended automatically. |
| speed | number | 2 | startOffset step per frame. |
| className | string | '' | Extra class merged onto the <text> element. |
| curveAmount | number | 400 | Bézier control-point offset (arc curvature). |
| direction | 'left' \| 'right' | 'left' | Flow direction. |
| interactive | boolean | true | Enable pointer-drag scrubbing. |
Full prop list with live controls is in
src/play/demos/CurvedLoopDemo.vue.
FuzzyText
A fuzzy / glitchy text effect rendered on a <canvas> — a Vue port of the
react-bits FuzzyText. Each
row of the text is drawn onto an offscreen canvas then re-blitted with per-frame
jitter. When text is empty it falls back to the default slot content (decision
1); in jsdom (and SSR) getContext('2d') returns null and the effect
early-returns without throwing.
<script setup lang="ts">
import { FuzzyText } from 'vue3-bits';
</script>
<template>
<!-- Option A: text prop -->
<FuzzyText text="Fuzzy" :base-intensity="0.18" :hover-intensity="0.5" />
<!-- Option B: default slot (probe fallback) -->
<FuzzyText>Fuzzy</FuzzyText>
</template>Props
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| text | string | '' | Primary text source; falls back to the default slot if empty. |
| fontSize | number \| string | 'clamp(2rem, 8vw, 8rem)' | Canvas font size. |
| fontWeight | string \| number | 900 | Canvas font weight. |
| fontFamily | string | 'inherit' | Canvas font family. |
| color | string | '#fff' | Text fill color. |
| enableHover | boolean | true | Intensify jitter on hover. |
| baseIntensity | number | 0.18 | Idle jitter intensity. |
| hoverIntensity | number | 0.5 | Hover jitter intensity. |
| fuzzRange | number | 30 | Max jitter amplitude (px). |
| fps | number | 60 | Frame rate cap. |
| direction | 'horizontal' \| 'vertical' \| 'both' | 'horizontal' | Jitter direction. |
| transitionDuration | number | 0 | Step transition duration (seconds). |
| clickEffect | boolean | false | Burst on click. |
| glitchMode | boolean | false | Periodic glitch bursts. |
| glitchInterval | number | 2000 | Glitch interval (ms). |
| glitchDuration | number | 200 | Glitch duration (ms). |
| gradient | string[] \| null | null | Optional multi-stop canvas gradient (else solid color). |
| letterSpacing | number | 0 | Per-glyph spacing (canvas units). |
| className | string | '' | Extra class merged onto the <canvas>. |
Full prop list with live controls is in
src/play/demos/FuzzyTextDemo.vue.
GradientText
Animated multi-color gradient text — a Vue port of the
react-bits GradientText.
Content is passed via the default slot; the gradient flows via an animated
background-position driven by the shared useRafProgress rAF engine (no
motion dependency). showBorder renders a masked outline.
<script setup lang="ts">
import { GradientText } from 'vue3-bits';
</script>
<template>
<GradientText
:colors="['#5227FF', '#FF9FFC', '#B497CF']"
:animation-speed="8"
:show-border="false"
:direction="'horizontal'"
:yoyo="true"
>
Gradient Text
</GradientText>
</template>Props
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| (default slot) | — | — | Text content (replaces react children). |
| className | string | '' | Extra class merged onto the root element. |
| colors | string[] | ['#5227FF','#FF9FFC','#B497CF'] | Gradient stops; first color is duplicated at the end for a seamless loop. |
| animationSpeed | number | 8 | Loop duration (seconds). |
| showBorder | boolean | false | Render a masked gradient outline. |
| direction | 'horizontal' \| 'vertical' \| 'diagonal' | 'horizontal' | Flow direction. |
| pauseOnHover | boolean | false | Pause animation while hovered. |
| yoyo | boolean | true | 2-phase ping-pong (forward → reverse). |
Full prop list with live controls is in
src/play/demos/GradientTextDemo.vue.
LineSidebar
A sidebar navigation whose items light up with proximity to the pointer — a Vue
port of the react-bits LineSidebar.
A single rAF eases a shared --effect CSS variable (frame-rate-independent
exponential smoothing), and color-mix / translateX / scaleX all read that
one variable so there is no CSS-transition desync.
<script setup lang="ts">
import { LineSidebar } from 'vue3-bits';
const items = ['Home', 'Projects', 'About', 'Contact'];
function onItemClick(index: number, label: string) {
console.log(index, label);
}
</script>
<template>
<LineSidebar :items="items" falloff="smooth" @item-click="onItemClick" />
</template>Props
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| items | string[] | 12-item default list | Nav labels. |
| accentColor | string | '#A855F7' | Active accent color. |
| textColor | string | '#c4c4c4' | Idle text color. |
| markerColor | string | '#6c6c6c' | Marker / tick color. |
| showIndex | boolean | true | Show the numeric index prefix. |
| showMarker | boolean | true | Show the side marker line. |
| proximityRadius | number | 100 | Pointer influence radius (px). |
| maxShift | number | 30 | Max horizontal shift (px). |
| falloff | 'linear' \| 'smooth' \| 'sharp' | 'smooth' | Proximity→effect curve (exported as Falloff). |
| markerLength | number | 60 | Marker length (px). |
| markerGap | number | 0 | Gap before the marker (px). |
| tickScale | number | 0.5 | Tick scale factor. |
| scaleTick | boolean | true | Scale the tick with effect. |
| itemGap | number | 20 | Gap between items (px). |
| fontSize | number | 1.1 | Font size (rem). |
| smoothing | number | 100 | Easing time constant (ms). |
| defaultActive | number \| null | null | Index of the pre-activated item (null = none). |
| className | string | '' | Extra class merged onto the root <nav>. |
Emits
itemClick(payload:[index, label]). Full prop list with live controls is insrc/play/demos/LineSidebarDemo.vue.
AnimatedList
A scroll-reveal list whose items fade & scale in when they enter the viewport — a
Vue port of the react-bits AnimatedList.
Reveal is driven by a native IntersectionObserver (root = the list container,
threshold = 0.5, once = false) toggling a .in-view class; a CSS transition
completes the scale .7→1 / opacity 0→1. Keyboard arrow navigation is supported.
<script setup lang="ts">
import { AnimatedList } from 'vue3-bits';
const items = ['Item 1', 'Item 2', 'Item 3'];
function onItemSelect(item: string, index: number) {
console.log(item, index);
}
</script>
<template>
<AnimatedList :items="items" @item-select="onItemSelect" />
</template>Props
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| items | string[] | 15-item default list | List entries. |
| className | string | '' | Extra class merged onto the root container. |
| itemClassName | string | '' | Extra class merged onto each item. |
| showGradients | boolean | true | Render top/bottom fade masks. |
| enableArrowNavigation | boolean | true | Arrow-up/down + Tab + Enter keyboard selection. |
| displayScrollbar | boolean | true | Show the scrollbar. |
| initialSelectedIndex | number | -1 | Pre-selected index (-1 = none). |
Emits
itemSelect(payload:[item, index]). Full prop list with live controls is insrc/play/demos/AnimatedListDemo.vue.
SpotlightCard
Mouse-following radial spotlight rendered with a CSS ::before layer.
<script setup lang="ts">
import { SpotlightCard } from 'vue3-bits';
</script>
<template>
<SpotlightCard spotlight-color="rgba(0, 229, 255, 0.2)">
<h2>Spotlight Card</h2>
</SpotlightCard>
</template>Props
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| className | string | '' | Extra class on the root. |
| spotlightColor | string | 'rgba(255,255,255,0.25)' | Spotlight radial-gradient color. |
BorderGlow
Mesh-gradient border + outer glow that intensifies as the pointer nears the edge.
Props
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| className | string | '' | Extra class. |
| edgeSensitivity | number | 120 | Edge distance (px) where glow starts. |
| glowColor | string | '40 80 80' | Inner glow HSL triplet. |
| backgroundColor | string | '#120F17' | Card background. |
| borderRadius | number | 16 | Corner radius (px). |
| glowRadius | number | 12 | Outer glow spread (px). |
| glowIntensity | number | 1 | Opacity multiplier. |
| coneSpread | number | 180 | Half-angle of cursor cone. |
| animated | boolean | false | Run idle sweep on mount. |
| colors | string[] | ['40 80 80', ...] | Mesh-gradient stops. |
| fillOpacity | number | 0.1 | Inner fill opacity. |
Dock
macOS-style dock that springs the pointer-proximity item larger (hand-rolled rAF spring, no framer-motion).
<script setup lang="ts">
import { Dock } from 'vue3-bits';
</script>
<template>
<Dock :items="[{ icon: MyIcon, label: 'Home' }]" :magnification="64" />
</template>Props
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| items | DockItemData[] | [] | { icon, label, onClick, className }. |
| className | string | '' | Extra class on panel. |
| spring | SpringOptions | { mass: 1, stiffness: 150, damping: 15 } | Magnification spring. |
| magnification | number | 64 | Max item size (px). |
| distance | number | 120 | Falloff distance (px). |
| panelHeight | number | 64 | Resting panel height (px). |
| dockHeight | number | paddleHeight + 24 | Outer wrapper height. |
| baseItemSize | number | 48 | Resting item size (px). |
ScrollStack
Scroll-pinned stacking cards. Drives the same pin / scale / rotation / blur math as
react-bits from native scroll events (no lenis).
<script setup lang="ts">
import { ScrollStack, ScrollStackItem } from 'vue3-bits';
</script>
<template>
<div style="height: 360px">
<ScrollStack :blur-amount="4">
<ScrollStackItem><h2>Card 1</h2></ScrollStackItem>
</ScrollStack>
</div>
</template>Props
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| className | string | '' | Extra class on scroller. |
| itemDistance | number | 100 | Gap between cards (px). |
| itemScale | number | 0.03 | Per-index scale increment. |
| itemStackDistance | number | 30 | Extra stack offset (px). |
| stackPosition | string | '20%' | Pin start position. |
| scaleEndPosition | string | '10%' | Base-scale position. |
| baseScale | number | 0.85 | Top card scale when stacked. |
| scaleDuration | number | 0.5 | (API parity; unused). |
| rotationAmount | number | 0 | Max rotation (deg). |
| blurAmount | number | 0 | Buried-card blur (px). |
| useWindowScroll | boolean | false | Use window as scroller. |
| onStackComplete | () => void | — | Emitted when last card stacks. |
CircularGallery
WebGL plane ring built on the bundled ogl engine (gallery.ts).
<script setup lang="ts">
import { CircularGallery } from 'vue3-bits';
</script>
<template>
<div style="height: 420px">
<CircularGallery :items="[{ image: '/a.jpg', text: 'A' }]" :bend="3" />
</div>
</template>Props
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| items | GalleryItem[] | built-in set | { image, text }. |
| bend | number | 3 | Curvature (0 = flat). |
| textColor | string | '#ffffff' | Caption color. |
| borderRadius | number | 0.05 | Plane corner radius (0..1). |
| font | string | 'bold 30px Figtree' | Canvas font string. |
| fontUrl | string | undefined | Optional font URL. |
| scrollSpeed | number | 2 | Scroll sensitivity. |
| scrollEase | number | 0.05 | Scroll easing (0..1). |
MagicBento
Magnetic bento grid: gsap drives tilt / magnetism / particles / ripples and a section
spotlight. CSS is a 1:1 port of react-bits MagicBento.css.
<script setup lang="ts">
import { MagicBento } from 'vue3-bits';
</script>
<template>
<MagicBento :enable-spotlight="true" :enable-border-glow="true" glow-color="132, 0, 255" />
</template>Props
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| items | BentoCardProps[] | 6-card demo set | { color, title, description, label, textAutoHide, disableAnimations }. |
| textAutoHide | boolean | true | Hide title/desc until hover. |
| enableStars | boolean | false | Floating star particles. |
| enableSpotlight | boolean | false | Section-following spotlight. |
| enableBorderGlow | boolean | false | Glowing border per card. |
| disableAnimations | boolean | false | Force-off animations. |
| spotlightRadius | number | 300 | Spotlight radius (px). |
| particleCount | number | 12 | Particles per card on hover. |
| enableTilt | boolean | true | 3D tilt on pointer move. |
| glowColor | string | '132, 0, 255' | Glow RGB triplet. |
| clickEffect | boolean | false | Ripple on click. |
| enableMagnetism | boolean | false | Magnetic pull to pointer. |
FluidGlass
Fluid glass — a faithful 1:1 port of react-bits FluidGlass, built on the peer
@tresjs/core + three. An offscreen FBO (a THREE.Scene rendered into a
WebGLRenderTarget every frame) provides the refracted content — the
"React Bits" wordmark, demo images and coloured shapes — while a real
THREE.MeshPhysicalMaterial (transmission) is the glass. Geometry is loaded
from GLB (lens.glb→Cylinder, bar.glb/cube.glb→Cube) via three's built-in
GLTFLoader, with a programmatic fallback when the asset is missing.
<script setup lang="ts">
import { FluidGlass } from 'vue3-bits';
</script>
<template>
<div style="position: relative; height: 400px">
<FluidGlass mode="lens" :lens-props="{ scale: 0.25, ior: 1.15, thickness: 5, chromaticAberration: 0.1, anisotropy: 0.01 }" />
</div>
</template>Props
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| mode | 'lens' \| 'bar' \| 'cube' | 'lens' | Glass geometry / behaviour. |
| lensProps | FluidGlassModeProps | {} | lens overrides (scale/ior/thickness/roughness/transmission/chromaticAberration/anisotropy/color/attenuationColor/attenuationDistance). |
| barProps | FluidGlassModeProps | {} | bar overrides (carries navItems). |
| cubeProps | FluidGlassModeProps | {} | cube overrides. |
| className | string | '' | Class on root wrapper. |
| width | number \| string | 400 | Canvas width. |
| height | number \| string | 400 | Canvas height. |
Note:
CircularGalleryneedsogl(bundled).MagicBentoneedsgsap(bundled).FluidGlassneeds the peer@tresjs/core+threealready present in the host app —npm install vue3-bits @tresjs/core three. The transmission material is intentionally nottransparent(red line 34). GLB geometry (public/assets/3d/*.glb) and demo images (public/assets/demo/*.webp) are optional — missing files fall back to programmatic geometry / gradients so the component never crashes. Scroll the canvas with the mouse wheel (3 pages).
LiquidEther
WebGL fluid simulation built on three — multiple WebGLRenderTarget ping-pong
plus advection / pressure / viscous / divergence shaders, with a pointer force
and an auto-pilot driver. The component fills its parent, so wrap it in a sized
container.
<script setup lang="ts">
import { LiquidEther } from 'vue3-bits';
</script>
<template>
<div style="position: relative; height: 400px">
<LiquidEther :mouse-force="20" :colors="['#5227FF', '#FF9FFC', '#B497CF']" />
</div>
</template>Props
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| colors | string[] | ['#5227FF','#FF9FFC','#B497CF'] | Palette (builds a DataTexture). |
| mouseForce | number | 20 | Pointer force strength. |
| cursorSize | number | 100 | Force brush radius (px). |
| isViscous | boolean | false | Enable viscous diffusion. |
| viscous | number | 30 | Viscosity coefficient. |
| iterationsViscous | number | 32 | Viscous Jacobi iterations. |
| iterationsPoisson | number | 32 | Pressure (Poisson) iterations. |
| dt | number | 0.014 | Simulation time step. |
| BFECC | boolean | true | BFECC advection (MacCormack). |
| resolution | number | 0.5 | FBO size as a fraction of the container. |
| isBounce | boolean | false | Bounce at boundary (false = soft wall). |
| autoDemo | boolean | true | Auto-pilot driver. |
| autoSpeed | number | 0.5 | Auto-pilot speed. |
| autoIntensity | number | 2.2 | Auto-pilot force multiplier. |
| takeoverDuration | number | 0.25 | Takeover lerp duration (s). |
| autoResumeDelay | number | 1000 | Idle ms before auto-pilot resumes. |
| autoRampDuration | number | 0.6 | Auto-pilot ramp-up (s). |
| className | string | '' | Class on the root container. |
Note:
LiquidEtherandFloatingLinesuse the bundled peerthree(npm install vue3-bits three).LightRaysreuses the bundledogl. No new dependencies are added.
FloatingLines
Full-screen shader of floating lines built on three — multiple waves flow
along curves with pointer bending and parallax. The component fills its parent.
<script setup lang="ts">
import { FloatingLines } from 'vue3-bits';
</script>
<template>
<div style="position: relative; height: 400px">
<FloatingLines :line-count="8" :animation-speed="1" />
</div>
</template>Props
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| linesGradient | string[] | undefined | Line gradient stops (max 8). |
| enabledWaves | ('top'\|'middle'\|'bottom')[] | ['top','middle','bottom'] | Waves to render. |
| lineCount | number \| number[] | [6] | Lines per wave. |
| lineDistance | number \| number[] | [5] | Distance per wave (×0.01). |
| topWavePosition | WavePosition | {x:10,y:0.5,rotate:-0.4} | Top wave position. |
| middleWavePosition | WavePosition | {x:5,y:0,rotate:0.2} | Middle wave position. |
| bottomWavePosition | WavePosition | {x:2.0,y:-0.7,rotate:-1} | Bottom wave position. |
| animationSpeed | number | 1 | Time multiplier. |
| interactive | boolean | true | Pointer bending interaction. |
| bendRadius | number | 5.0 | Bend radial falloff. |
| bendStrength | number | -0.5 | Bend strength. |
| mouseDamping | number | 0.05 | Mouse / parallax easing. |
| parallax | boolean | true | Parallax offset. |
| parallaxStrength | number | 0.2 | Parallax strength. |
| mixBlendMode | string | 'screen' | Container mix-blend-mode. |
| className | string | '' | Class on the root container. |
WavePosition = { x: number; y: number; rotate: number }.
LightRays
Full-screen shader of light rays built on the bundled ogl — rays emit from an
anchor with pulsing, mouse deflection and noise. The component fills its parent.
<script setup lang="ts">
import { LightRays } from 'vue3-bits';
</script>
<template>
<div style="position: relative; height: 400px">
<LightRays rays-origin="top-center" rays-color="#ffffff" />
</div>
</template>Props
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| raysOrigin | 'top-center'\|'top-left'\|'top-right'\|'right'\|'left'\|'bottom-center'\|'bottom-right'\|'bottom-left' | 'top-center' | Ray anchor + direction. |
| raysColor | string | '#ffffff' | Ray color (hex). |
| raysSpeed | number | 1 | Ray pulse speed. |
| lightSpread | number | 1 | Spread exponent. |
| rayLength | number | 2 | Ray length. |
| pulsating | boolean | false | Breathing pulse. |
| fadeDistance | number | 1.0 | Far fade distance. |
| saturation | number | 1.0 | Color saturation. |
| followMouse | boolean | true | Mouse deflects rays. |
| mouseInfluence | number | 0.1 | Mouse influence weight. |
| noiseAmount | number | 0.0 | Noise amount. |
| distortion | number | 0.0 | Angle distortion. |
| className | string | '' | Class on the root container. |
Note:
LightRaysreuses the bundledogl— no extra install needed.
Components ported from react-bits (#16–46)
31 个组件,1:1 还原 props / uniforms / GLSL。背景类复用 peer
three或 bundledogl;交互类为纯 DOM/SVG/CSS,部分用 bundledgsap。0 新增依赖(构建external列表不变,ogl/gsap仍 bundled)。完整 Props 以src/components/<Name>/types.ts与<Name>Demo.vue为准。
LineWaves (Background · ogl)
ogl 全屏波浪线着色器背景。
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| color | string | '#ffffff' | 线条颜色 |
| speed | number | 1 | 动画速度 |
| waveWidth | number | 1 | 波宽 |
| lineColor | string[] | — | 多色线条 |
| className | string | '' | 根 class |
Radar (Background · ogl)
ogl 雷达扫描着色器背景。
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| color | string | '#ffffff' | 扫描线颜色 |
| speed | number | 1 | 扫描速度 |
| strokeColor | string | '#ffffff' | 网格描边色 |
| className | string | '' | 根 class |
SoftAurora (Background · ogl)
ogl 极光着色器背景。
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| colors | string[] | 3 色 | 极光配色 |
| speed | number | 1 | 流动速度 |
| className | string | '' | 根 class |
Plasma (Background · ogl)
ogl 等离子着色器背景。
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| color | string | '#ff0000' | 等离子主色 |
| speed | number | 1 | 动画速度 |
| className | string | '' | 根 class |
Particles (Background · ogl)
ogl 粒子着色器背景。
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| color | string | '#ffffff' | 粒子颜色 |
| particleCount | number | 200 | 粒子数量 |
| particleSpread | number | 10 | 扩散范围 |
| speed | number | 1 | 动画速度 |
| className | string | '' | 根 class |
GradientBlinds (Background · ogl)
ogl 渐变百叶着色器背景。
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| color | string | '#ffffff' | 百叶颜色 |
| speed | number | 1 | 动画速度 |
| className | string | '' | 根 class |
GridScan (Background · three)
three 网格扫描着色器背景(引擎在 gridScanEngine.ts)。
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| lineColor | string | '#ffffff' | 扫描线颜色 |
| gridColor | string | '#ffffff' | 网格颜色 |
| cellSize | number | 20 | 单元格尺寸 |
| gridThickness | number | 1 | 网格线宽 |
| gridOpacity | number | 0.3 | 网格透明度 |
| scanColor | string | '#ffffff' | 扫描光带色 |
| scanSpeed | number | 1 | 扫描速度 |
| className | string | '' | 根 class |
Lightning (Background · 原生 WebGL)
原生 canvas.getContext('webgl') 闪电背景(无 three/ogl)。
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| hue | number | 230 | 色相 |
| xOffset | number | 0 | 横向偏移 |
| speed | number | 1 | 动画速度 |
| intensity | number | 1 | 强度 |
| size | number | 1 | 尺寸 |
Galaxy (Background · ogl)
ogl 星系粒子背景。
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| radius | number | Math.PI | 星系半径 |
| density | number | 1 | 密度 |
| maxParticles | number | 7000 | 最大粒子数 |
| color | string | '#ffffff' | 粒子颜色 |
| className | string | '' | 根 class |
DotField (Background · Canvas2D)
Canvas2D 点阵背景(getContext('2d') 已做 null 守卫)。
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| dotColor | string | '#ffffff' | 点颜色 |
| gap | number | 20 | 点间距 |
| size | number | 2 | 点大小 |
| className | string | '' | 根 class |
DotGrid (Background · Canvas2D + gsap)
Canvas2D 点阵网格,指针交互(bundled gsap 驱动)。
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| dotColor | string | '#ffffff' | 点颜色 |
| gap | number | 20 | 点间距 |
| size | number | 2 | 点大小 |
| className | string | '' | 根 class |
Hyperspeed (Background · three)
three 超光速隧道背景(复杂多 pass 引擎在 hyperspeedEngine.ts)。
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| effectOptions | object | DEFAULT_EFFECT_OPTIONS | 隧道/星点/光带全套配置 |
| className | string | '' | 根 class |
Waves (Background · Canvas2D + gsap)
Canvas2D 波浪背景(bundled gsap)。
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| lineColor | string | '#ffffff' | 线颜色 |
| backgroundColor | string | '#000000' | 背景色 |
| waveSpeed | number | 1 | 波浪速度 |
| className | string | '' | 根 class |
Ballpit (Background · ogl)
ogl 弹球物理背景(含 three 向量数学)。
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| className | string | '' | 根 class |
| followCursor | boolean | true | 跟随指针 |
| count | number | — | 球数 |
| maxVelocity | number | — | 最大速度 |
| radius | number | — | 球半径 |
Orb (Background · ogl)
ogl 光球着色器背景,悬停旋转。
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| hue | number | 0 | 色相 |
| rotateOnHover | boolean | true | 悬停旋转 |
| hoverIntensity | number | 2 | 悬停强度 |
| forceHoverState | boolean | false | 强制悬停 |
| backgroundColor | string | '#000000' | 背景色 |
ShapeGrid (Background · Canvas2D)
Canvas2D 形状网格,悬停拖尾(null 守卫)。
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| speed | number | 0.1 | 动画速度 |
| squareSize | number | 40 | 单元尺寸 |
| direction | 'up'\|'down'\|'left'\|'right'\|'diagonal' | 'diagonal' | 流动方向 |
| borderColor | string | '#5408df' | 边框色 |
| hoverFillColor | string | '#222' | 悬停填充 |
| shape | 'square'\|'hexagon'\|'circle'\|'triangle' | 'square' | 形状 |
| hoverTrailAmount | number | 2 | 拖尾数 |
| hoverColor | string | '#5bbd98' | 悬停色 |
| size | number | 20 | 点大小 |
Stepper (Interaction · DOM)
分步导航,使用 <Step> 子组件 / 插槽。
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| initialStep | number | 0 | 初始步 |
| onStepChange | (step: number) => void | — | 步变化回调 |
| onFinalStepCompleted | () => void | — | 完成回调 |
| backButtonText | string | 'Previous' | 返回按钮文案 |
| nextButtonText | string | 'Next' | 下一步文案 |
| disableStepIndicators | boolean | false | 隐藏步指示 |
InfiniteMenu (Interaction · 原生 WebGL2 + DOM)
无限循环菜单,带 WebGL2 扭曲背景(jsdom 下早退,不 throw)。
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| items | { image: string; link: string; title: string; description: string }[] | [] | 菜单项 |
| className | string | '' | 根 class |
Counter (Interaction · gsap)
数字滚动计数器。原 motion/react 已重写为 bundled gsap / 原生 rAF。
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| value | number | 0 | 目标值 |
| places | (number \| '.')[] | [100, 10, 1] | 数位权重 |
| fontSize | number | 80 | 字号 |
| padding | number | 5 | 内边距 |
| gap | number | 10 | 位间距 |
| textColor | string | 'white' | 文字色 |
| fontWeight | number | 900 | 字重 |
| digitPlaceHolders | boolean | false | 占位符 |
ElasticSlider (Interaction · gsap)
弹性滑块。原 motion/react+@chakra-ui/react+react-icons 已重写为 gsap / 内联 SVG 图标(未引入新依赖)。
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| leftIcon / rightIcon | slot | — | 左右图标 |
| startingValue | number | 0 | 起始值 |
| defaultValue | number | 50 | 默认值 |
| maxValue | number | 100 | 最大值 |
| isStepped | boolean | false | 步进 |
| stepSize | number | 10 | 步长 |
DecayCard (Interaction · gsap)
消散卡片,悬停粒子衰减(bundled gsap)。
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| width | number | 300 | 宽度 |
| height | number | 300 | 高度 |
| className | string | '' | 根 class |
GlassIcons (Interaction · DOM)
玻璃质感图标(图标经插槽传入,非 React 元素)。
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| items | { icon: ...; color: string; label: string; customClass?: string }[] | [] | 图标项 |
| colorful | boolean | false | 彩色模式 |
| className | string | '' | 根 class |
PixelCard (Interaction · Canvas2D + DOM)
像素化卡片,悬停像素动画(Canvas2D null 守卫)。
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| variant | 'pink'\|'blue'\|'green'\|... | 'pink' | 配色变体 |
| className | string | '' | 根 class |
GooeyNav (Interaction · SVG filter)
粘滞导航,SVG gooey 滤镜 + 粒子。
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| items | { label: string; href: string }[] | [] | 导航项 |
| particleCount | number | 15 | 粒子数 |
| particleDistances | [number, number] | [90, 10] | 粒子距离 |
| particleR | number | 100 | 粒子半径 |
| initialActiveIndex | number | 0 | 初始激活项 |
| animationTime | number | 600 | 动画时长 |
| timeVariance | number | 300 | 时间方差 |
| colors | number[] | [1, 2, 3, 1, 2, 3, 1, 4] | 配色 |
ChromaGrid (Interaction · gsap)
色块网格,悬停高亮(bundled gsap)。
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| items | { image: string; title: string; subtitle: string; handle: string; borderColor: string; gradient: string; url: string }[] | [] | 网格项 |
| className | string | '' | 根 class |
DomeGallery (Interaction · DOM)
穹顶画廊,3D 变换拖拽。原 @use-gesture/react 已重写为原生 pointer 事件(未引入新依赖)。
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| images | (string \| { src: string; alt?: string })[] | [] | 图片 |
| fit | number | 0.8 | 适配 |
| fitBasis | 'auto'\|'min'\|'max'\|'width'\|'height' | 'auto' | 适配基准 |
| minRadius | number | 400 | 最小半径 |
| maxVerticalRotationDeg | number | 0 | 最大纵向旋转 |
| segments | number | 34 | 分片数 |
| dragDampening | number | 2 | 拖拽阻尼 |
| grayscale | boolean | false | 灰度 |
GlassSurface (Interaction · SVG displacement)
玻璃表面,SVG feDisplacementMap 位移扭曲。
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| width | number | 300 | 宽度 |
| height | number | 200 | 高度 |
| borderRadius | number | 50 | 圆角 |
| displace | number | 0.5 | 位移量 |
| distortionScale | number | -180 | 扭曲缩放 |
| redOffset / greenOffset / blueOffset | number | 0/10/20 | RGB 偏移 |
| brightness | number | 50 | 亮度 |
| opacity | number | 0.93 | 不透明度 |
| mixBlendMode | string | 'screen' | 混合模式 |
| className | string | '' | 根 class |
TiltedCard (Interaction · gsap)
倾斜卡片,3D 悬停。原 motion/react 已重写为 bundled gsap / 原生 spring。
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| imageSrc | string | — | 图片地址 |
| altText | string | — | 替代文本 |
| captionText | string | — | 标题 |
| containerHeight / containerWidth | string | '300px' | 容器尺寸 |
| imageHeight / imageWidth | string | '300px' | 图片尺寸 |
| rotateAmplitude | number | 12 | 旋转幅度 |
| scaleOnHover | number | 1.05 | 悬停缩放 |
| showMobileWarning | boolean | false | 移动端警告 |
| showTooltip | boolean | false | 提示 |
| displayOverlayContent | boolean | false | 显示覆盖内容 |
| overlayContent | slot | — | 覆盖内容 |
PillNav (Interaction · gsap)
胶囊导航,悬停高亮(bundled gsap)。
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| items | { label: string; href: string }[] | [] | 导航项 |
| className | string | '' | 根 class |
Stack (Interaction · DOM)
堆叠卡片,自动轮播(卡片经插槽传入)。
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| randomRotation | boolean | false | 随机旋转 |
| sensitivity | number | 150 | 灵敏度 |
| sendToBackOnClick | boolean | true | 点击置底 |
| cards | slot | — | 卡片 |
| autoplay | boolean | false | 自动播放 |
| autoplayDelay | number | 2000 | 自动间隔 |
| pauseOnHover | boolean | false | 悬停暂停 |
CardNav (Interaction · gsap)
卡片导航,悬停展开链接(bundled gsap)。
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| items | { label: string; bgColor: string; textColor: string; links: { label: string; ariaLabel: string }[] }[] | [] | 卡片项 |
| className | string | '' | 根 class |
Development
npm install # install deps
npm run dev # vite dev server (play/ demo at index.html)
npm run typecheck # vue-tsc --noEmit
npm run test # vitest run
npm run build # type-check + library build to dist/The dev demo (src/play/App.vue) showcases prop combinations live.
Publish
npm run build # emits dist/ (es + cjs + d.ts)
npm publish # uses "files": ["dist"]License
MIT
