Docs/Primitives/createTransform

createTransform

createTransform produces a new MotionValue derived from one or more source values. Pass a transformer function, or pass input and output ranges and let motion interpolate between them.

import { createMotionValue, createTransform, motion } from 'motion-solidjs'

const x = createMotionValue(0)
const opacity = createTransform(x, [-100, 0, 100], [0, 1, 0])
const bg = createTransform(x, [-100, 0, 100], ['#36e0c5', '#7c5cff', '#ff4d8d'])

// Function form
const angle = createTransform(() => x.get() * 0.4)
createTransform

Scroll line 1

Scroll line 2

Scroll line 3

Scroll line 4

Scroll line 5

Scroll line 6

Scroll line 7

Scroll line 8

Scroll line 9

Scroll line 10

Scroll line 11

Scroll line 12

Scroll line 13

Scroll line 14

Scroll line 15

Scroll line 16

Scroll line 17

Scroll line 18

parallax.tsxOpen ↗
import { motion, createScroll, createTransform } from 'motion-solidjs'
import { createSignal } from 'solid-js'

export const meta = {
  slug: 'parallax',
  title: 'Parallax layers',
  category: 'scroll',
  description: 'Two shapes drift at different speeds as you scroll the box.',
  tag: 'createTransform',
} as const

export default function Parallax() {
  const [container, setContainer] = createSignal<HTMLDivElement | null>(null)
  const { scrollYProgress } = createScroll({ container })
  const yBack = createTransform(scrollYProgress, [0, 1], [0, -80])
  const yFront = createTransform(scrollYProgress, [0, 1], [0, -160])

  return (
    <div
      ref={setContainer}
      class="relative h-64 w-56 overflow-y-scroll rounded-2xl border border-border bg-card"
    >
      <div class="pointer-events-none sticky top-0 h-0">
        <motion.div
          style={{ y: yBack }}
          class="absolute top-10 left-6 h-20 w-20 rounded-2xl bg-grad-violet opacity-60 blur-[2px]"
        />
        <motion.div
          style={{ y: yFront }}
          class="absolute top-24 right-6 h-12 w-12 rounded-2xl bg-grad-rose"
        />
      </div>
      <div class="p-4 text-xs text-fg-muted">
        {Array.from({ length: 18 }).map((_, i) => (
          <p class="py-2">Scroll line {i + 1}</p>
        ))}
      </div>
    </div>
  )
}

Signatures

createTransform<T>(input: MotionValue, transform: (v: any) => T): MotionValue<T>
createTransform<I, O>(
  input: MotionValue<I> | MotionValue<I>[],
  inputRange: I[],
  outputRange: O[],
  options?: { clamp?: boolean; ease?: Easing | Easing[]; mixer?: Mixer<O> },
): MotionValue<O>
createTransform<O>(transform: () => O, deps?: MotionValue[]): MotionValue<O>

Range form interpolates string colors, numbers, complex strings (e.g. '1px solid red'), and arrays. clamp: false lets the output extrapolate past the bounds.