{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "displacement",
  "title": "Displacement",
  "description": "The frame breaks into a grid of cells that shear apart into offset, colour-fringed tiles under film grain, then settle back carrying the next scene.",
  "dependencies": ["remotion", "@remotion/transitions"],
  "registryDependencies": ["@remocn/canvas-presentation"],
  "files": [
    {
      "path": "registry/remocn/displacement/index.tsx",
      "content": "\"use client\";\n\nimport type {\n  TransitionPresentation,\n  TransitionPresentationComponentProps,\n} from \"@remotion/transitions\";\nimport type React from \"react\";\nimport { AbsoluteFill } from \"remotion\";\nimport {\n  makeCanvasPresentation,\n  makeSceneShader,\n} from \"@/lib/remocn/canvas-presentation\";\n\nexport type DisplacementProps = {\n  grid?: number;\n  cellAspect?: number;\n  shift?: number;\n  aberration?: number;\n  grain?: number;\n  stagger?: number;\n};\n\nconst DEFAULTS = {\n  grid: 60,\n  cellAspect: 1,\n  shift: 1,\n  aberration: 1,\n  grain: 0.5,\n  stagger: 0.45,\n};\n\nconst FRAGMENT_SHADER = `#version 300 es\nprecision highp float;\n\nuniform sampler2D u_from;\nuniform sampler2D u_to;\nuniform float u_progress;\nuniform float u_aspect;\nuniform vec2 u_cells;\nuniform float u_shift;\nuniform float u_aberration;\nuniform float u_grain;\nuniform float u_stagger;\n\nin vec2 v_uv;\nout vec4 outColor;\n\nconst float PI = 3.141592653589793;\n\nfloat hash(vec2 p) {\n  return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);\n}\n\nvoid main() {\n  vec2 cell = floor(v_uv * u_cells);\n  float h1 = hash(cell);\n  float h2 = hash(cell + 7.3);\n  float h3 = hash(cell + 13.1);\n\n  float delay = h3 * u_stagger;\n  float phase =\n    clamp((u_progress - delay) / max(1.0 - u_stagger, 0.1), 0.0, 1.0);\n  float shear = sin(phase * PI);\n\n  vec2 aim = vec2((h1 - 0.5) * 2.0, (h2 - 0.5) * 0.7);\n  vec2 dir = aim / max(length(aim), 0.0001);\n  vec2 slide = dir * shear * u_shift * 1.4;\n  vec2 off = slide / u_cells;\n  vec2 fringe = off * u_aberration * 0.35;\n\n  float swap = smoothstep(0.34, 0.66, phase);\n\n  vec4 mid = mix(\n    texture(u_from, v_uv - off),\n    texture(u_to, v_uv - off),\n    swap\n  );\n  float red = mix(\n    texture(u_from, v_uv - off - fringe).r,\n    texture(u_to, v_uv - off - fringe).r,\n    swap\n  );\n  float blue = mix(\n    texture(u_from, v_uv - off + fringe).b,\n    texture(u_to, v_uv - off + fringe).b,\n    swap\n  );\n\n  vec4 col = vec4(red, mid.g, blue, mid.a);\n\n  float tick = floor(u_progress * 30.0);\n  float speck =\n    hash(floor(v_uv * vec2(u_aspect, 1.0) * 460.0) + tick * 1.7) - 0.5;\n  col.rgb += vec3(speck * u_grain * shear * 0.5) * col.a;\n  col.rgb *= 1.0 - 0.12 * shear;\n\n  outColor = col;\n}`;\n\nconst shader = makeSceneShader<DisplacementProps>(\n  FRAGMENT_SHADER,\n  ({ gl, uniform, width, height, passedProps }) => {\n    const {\n      grid = DEFAULTS.grid,\n      cellAspect = DEFAULTS.cellAspect,\n      shift = DEFAULTS.shift,\n      aberration = DEFAULTS.aberration,\n      grain = DEFAULTS.grain,\n      stagger = DEFAULTS.stagger,\n    } = passedProps;\n    const across = Math.max(grid, 4);\n    const ratio = Math.max(cellAspect, 0.25);\n    gl.uniform2f(\n      uniform(\"u_cells\"),\n      across,\n      Math.max((across * ratio * height) / width, 2),\n    );\n    gl.uniform1f(uniform(\"u_shift\"), shift);\n    gl.uniform1f(uniform(\"u_aberration\"), aberration);\n    gl.uniform1f(uniform(\"u_grain\"), grain);\n    gl.uniform1f(uniform(\"u_stagger\"), Math.min(Math.max(stagger, 0), 0.85));\n  },\n);\n\nconst DisplacementFallback: React.FC<\n  TransitionPresentationComponentProps<DisplacementProps>\n> = ({ children, presentationProgress, presentationDirection }) => {\n  const p = presentationProgress;\n  const entering = presentationDirection === \"entering\";\n  const t = entering ? p : 1 - p;\n  const settle = Math.min(1, Math.max(0, (t - 0.3) / 0.4));\n  const jolt = Math.max(0, Math.sin(t * Math.PI)) * 10;\n\n  return (\n    <AbsoluteFill\n      style={{\n        opacity: settle,\n        transform: `translateX(${entering ? jolt : -jolt}px)`,\n      }}\n    >\n      {children}\n    </AbsoluteFill>\n  );\n};\n\nconst presentation = makeCanvasPresentation<DisplacementProps>({\n  shader,\n  fallback: DisplacementFallback,\n});\n\nexport function displacement(\n  props: DisplacementProps = {},\n): TransitionPresentation<DisplacementProps> {\n  return presentation(props);\n}\n",
      "type": "registry:component",
      "target": "components/remocn/displacement.tsx"
    }
  ],
  "type": "registry:component"
}
