JSPM

liquid-distort

0.1.0
    • ESM via JSPM
    • ES Module Entrypoint
    • Export Map
    • Keywords
    • License
    • Repository URL
    • TypeScript Types
    • README
    • Created
    • Published
    • Downloads 27
    • Score
      100M100P100Q63179F
    • License MIT

    Cursor-driven liquid distortion effect for any DOM element. Zero dependencies, 9kb, works with any framework.

    Package Exports

    • liquid-distort

    Readme

    liquid-distort

    Cursor-driven liquid distortion effect for any DOM element. Warps text, images, and UI using SVG displacement maps — no WebGL, no canvas overlay, no dependencies.

    9kb gzipped. Zero dependencies. Works with any framework.


    Install

    npm install liquid-distort

    Or via CDN (no bundler needed):

    <script src="https://cdn.jsdelivr.net/npm/liquid-distort/dist/liquid-distort.umd.cjs"></script>

    Quick start

    import { LiquidDistort } from 'liquid-distort'
    
    new LiquidDistort(document.getElementById('hero'))

    That's it. The effect attaches to the element and follows the cursor automatically.


    Framework examples

    React

    import { useEffect, useRef } from 'react'
    import { LiquidDistort } from 'liquid-distort'
    
    export default function Hero() {
      const ref = useRef(null)
    
      useEffect(() => {
        const effect = new LiquidDistort(ref.current)
        return () => effect.destroy()
      }, [])
    
      return <section ref={ref}>...</section>
    }

    Vue

    <script setup>
    import { onMounted, onUnmounted, ref } from 'vue'
    import { LiquidDistort } from 'liquid-distort'
    
    const el = ref(null)
    let effect
    
    onMounted(() => effect = new LiquidDistort(el.value))
    onUnmounted(() => effect.destroy())
    </script>
    
    <template>
      <section ref="el">...</section>
    </template>

    Svelte

    <script>
    import { LiquidDistort } from 'liquid-distort'
    
    function distort(node) {
      const effect = new LiquidDistort(node)
      return { destroy: () => effect.destroy() }
    }
    </script>
    
    <section use:distort>...</section>

    Plain HTML (CDN)

    <script src="https://cdn.jsdelivr.net/npm/liquid-distort/dist/liquid-distort.umd.cjs"></script>
    <script>
      new LiquidDistort.LiquidDistort(document.querySelector('main'))
    </script>

    Excluding elements

    Apply the effect to a specific container — everything outside it stays untouched:

    <!-- No effect — lives outside the filtered section -->
    <nav>...</nav>
    <button class="cta">Buy Now</button>
    
    <!-- Gets the distortion -->
    <section id="hero">
      <h1>Big headline</h1>
      <img src="photo.jpg" />
    </section>
    
    <!-- No effect -->
    <footer>...</footer>
    new LiquidDistort(document.getElementById('hero'))

    Options

    new LiquidDistort(element, {
      // Zone
      radius: 193,         // Blob radius in px
      shape: 'circle',     // 'circle' | 'ellipse' | 'rect' | 'roundedRect'
      aspectRatio: 0.8,    // Stretch shape X axis (ellipse / roundedRect)
      cornerRadius: 0.3,   // Corner radius for roundedRect (0–1)
    
      // Effect
      mode: 'attract',     // 'refract' | 'attract' | 'swirl' | 'ripple' | 'wave'
      strength: 72,        // Displacement intensity
      frequency: 3,        // Ring count (ripple / wave modes)
      falloff: 'smoothstep', // 'smoothstep' | 'linear' | 'exponential' | 'cosine'
    
      // Physics
      follow: 0.98,        // Cursor lag (0 = instant, ~1 = heavy lag)
      spring: true,        // Springy overshoot physics
      stiffness: 0.15,     // Spring stiffness
      damping: 0.75,       // Spring damping
      decay: 0.9,          // Seconds to fade after cursor stops (0 = always on)
      velocityBoost: 0,    // Boost strength when moving fast
    
      // Tail
      tail: 0.14,          // Trail strength (0 = no tail, 1 = full)
      tailLength: 68,      // Number of trail history points
    
      // Trigger
      trigger: 'always',   // 'always' | 'hover' | 'click'
    
      // Performance
      resolution: 0.15,    // Canvas scale (lower = faster)
    })

    Modes

    Mode Effect
    refract Pushes content outward — convex glass lens
    attract Pulls content inward — gravity well
    swirl Spins content around the cursor
    ripple Concentric sine-wave rings
    wave Horizontal sine wave

    Shapes

    Shape Description
    circle Uniform circular zone
    ellipse Stretched by aspectRatio
    rect Rectangular zone
    roundedRect Rounded rectangle

    API

    const effect = new LiquidDistort(element, options)
    
    // Update any option live
    effect.setOptions({ mode: 'swirl', strength: 120 })
    
    // Remove effect and clean up all DOM changes
    effect.destroy()

    How it works

    The effect renders a tiny off-screen canvas every frame — a displacement map where pixel color encodes direction and magnitude of distortion. This map is fed into an SVG feDisplacementMap filter which the browser applies to your element in GPU hardware.

    No WebGL. No DOM overlay. Just two browser APIs (Canvas 2D + SVG filters) doing the heavy lifting.


    License

    MIT