Esc

Try “tilt”, “reveal”, “drag”, or “reduced motion”.

Guide

Vue and other frameworks

The Vue plugin and directive, and patterns for React, Svelte, and server rendering.

Kinesis works in any framework in one of two ways:

  1. CSS. Call initKinesis() once in the browser. Kinesis watches the page, so components that mount, change classes, or unmount need nothing else.
  2. JavaScript. Call kinesis(element, props) on mount, set() when state changes, and destroy() on unmount.

Vue

// main.js
import { createApp } from "vue"
import { KinesisPlugin } from "@amineyarman/kinesis/vue"
import App from "./App.vue"

createApp(App).use(KinesisPlugin).mount("#app")

The plugin starts CSS discovery and registers a v-kinesis directive. The directive takes the same props as kinesis() and updates with your data:

<script setup>
import { ref } from "vue"
const selected = ref(false)
</script>

<template>
  <article
    v-kinesis="{ tilt: selected ? 14 : 6, area: 'self', when: 'hover', y: -6 }"
    @click="selected = !selected"
  >
    …
  </article>
</template>

Props removed from the object go back to CSS. Everything is cleaned up on unmount.

Plugin options go in the second argument: app.use(KinesisPlugin, { reducedMotion: "user", debug: true }). { auto: false } skips CSS discovery.

Nuxt

Register the directive in a client plugin, and start discovery after hydration so Kinesis never changes markup before Vue checks it:

// plugins/kinesis.client.ts
import { initKinesis } from "@amineyarman/kinesis"
import { KinesisPlugin } from "@amineyarman/kinesis/vue"

export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.vueApp.use(KinesisPlugin, { auto: false })
  onNuxtReady(() => initKinesis())
})

Server-rendered pages already contain your CSS. Elements sit at rest until Kinesis starts, so nothing flashes.

Coming from vue-kinesis

The component wrappers are gone. A container and its elements become a scope with CSS properties, or the directive:

<!-- vue-kinesis -->
<kinesis-container>
  <kinesis-element :strength="10" type="depth">…</kinesis-element>
</kinesis-container>

<!-- Kinesis 2 -->
<div data-kinesis>
  <div v-kinesis="{ parallax: 10 }">…</div>
</div>

The migration guide maps every old option.

React

Start discovery once, then write CSS:

// main.jsx
import { initKinesis } from "@amineyarman/kinesis"
initKinesis()

For motion driven by state, keep a handle in an effect and call set(). It's cheap enough to call on every render:

import { useEffect, useRef } from "react"
import { kinesis } from "@amineyarman/kinesis"

function Card({ selected }) {
  const ref = useRef(null)
  const handle = useRef(null)

  useEffect(() => {
    handle.current = kinesis(ref.current, { area: "self", when: "hover", y: -6 })
    return () => handle.current.destroy()
  }, [])

  useEffect(() => {
    handle.current.set({ tilt: selected ? 14 : 6 })
  }, [selected])

  return <article ref={ref} className="card">…</article>
}

Inline --k-* styles also work, but each change costs a style recalculation that set() avoids.

Svelte

Use an action:

<script>
  import { kinesis } from "@amineyarman/kinesis"

  function motion(node, props) {
    const handle = kinesis(node, props)
    return {
      update: (next) => handle.reset().set(next),
      destroy: () => handle.destroy(),
    }
  }
</script>

<div use:motion={{ magnetic: 0.3, radius: 140 }}>…</div>

Server rendering

Importing Kinesis on the server is safe. It does nothing until called in the browser, and initKinesis() returns without a document.

Edit this page on GitHub