Kinetic States

Client

Independent Study

Category

Interaction Design

Year

2026

Three-dimensional Rhythm, Texture and Pitch mood space developed for the Being Good music classification system.

Kinetic States is a set of interaction experiments exploring what a pointer can communicate before a person clicks anything. Across ten behaviors, I used inertia, attraction, resistance, dwell time, velocity, and spatial distortion to make interface elements feel heavier, more intentional, or more responsive to approach, treating movement itself as the design material rather than decoration added after the interface was finished.

React · TypeScript · Motion · Vite · Tailwind

Each state is implemented as its own interaction component, using pointer position, distance, velocity, or dwell time as input. The behaviors range from proximity-based magnetic attraction and field reshaping to delayed activation and velocity-sensitive movement, with spring stiffness, damping, and mass controlling how much weight or resistance each interaction appears to have.


Selection Gravity Component

const dx = latestX - nodeCX
const dy = latestY - nodeCY
const dist = Math.sqrt(dx * dx + dy * dy)

if (dist < 150) {
  const pullFactor = (150 - dist) / 150

  targetScale.set(
    1 + pullFactor * 0.5
  )

  targetX.set(
    dx * pullFactor * 0.3
  )

  targetY.set(
    dy * pullFactor * 0.3
  )
} else {
  targetScale.set(1)
  targetX.set(0)
  targetY.set(0)
}
const dx = latestX - nodeCX
const dy = latestY - nodeCY
const dist = Math.sqrt(dx * dx + dy * dy)

if (dist < 150) {
  const pullFactor = (150 - dist) / 150

  targetScale.set(
    1 + pullFactor * 0.5
  )

  targetX.set(
    dx * pullFactor * 0.3
  )

  targetY.set(
    dy * pullFactor * 0.3
  )
} else {
  targetScale.set(1)
  targetX.set(0)
  targetY.set(0)
}
const dx = latestX - nodeCX
const dy = latestY - nodeCY
const dist = Math.sqrt(dx * dx + dy * dy)

if (dist < 150) {
  const pullFactor = (150 - dist) / 150

  targetScale.set(
    1 + pullFactor * 0.5
  )

  targetX.set(
    dx * pullFactor * 0.3
  )

  targetY.set(
    dy * pullFactor * 0.3
  )
} else {
  targetScale.set(1)
  targetX.set(0)
  targetY.set(0)
}

The ten states are intentionally exaggerated so differences between attraction, resistance, inertia, timing, and velocity are easy to feel. Some could translate into much subtler interface interactions, while others are useful as experiments in their own right.