Skip to content

Repository files navigation

DepthFlow Web

Images to → 3D Parallax implemented with web apis. Enjoy iOS 26 Spatial scene on the web. Inspired by DepthFlow.

demo-h264.mp4

Open depth-flow.pages.dev to create a new 3D parallax flow.

NPM package

To use the depth-flow npm package, first create a flow zip file depth-flow.zip on the site.

import {
  loadFlowZip,
  createFlowSimpleRenderer,
  flowSimpleRendererPresets,
} from "depth-flow"
import flowZipUrl from "./depth-flow.zip?url"

async function main() {
  const canvas = document.createElement("canvas")
  const blob = await fetch(flowZipUrl).then(res => res.blob())
  const flow = await loadFlowZip(blob)

  const renderer = await createFlowSimpleRenderer(canvas, flow, {
    forwardSteps: 120,
    backwardSteps: 8,
    timer: "gl",
  })

  const origin: [number, number, number] = [0, 0, -30]
  const target: [number, number, number] = [0, 0, 0]
  const zoomScale = 0.9

  let originChanged = false

  const renderLoop = () => {
    requestAnimationFrame(renderLoop)
    renderer.timer.poll()
    if (originChanged) {
      renderer.render({ origin, target, zoomScale })
    }
  }

  canvas.addEventListener("pointermove", event => {
    const rect = canvas.getBoundingClientRect()
    const x = (event.clientX - rect.left) / rect.width * -2 + 1
    const y = (event.clientY - rect.top) / rect.height * 2 - 1

    // or add spring animation here
    origin[0] = x
    origin[1] = y
    originChanged = true
  })

  requestAnimationFrame(renderLoop)

  canvas.style.position = "absolute"
  canvas.style.top = "0"
  canvas.style.left = "0"
  canvas.style.width = "100%"
  canvas.style.height = "100%"

  const root = document.querySelector<HTMLDivElement>("#app")!
  root.appendChild(canvas)
}

main()

Render params details:

Parameter Type Description
origin [number, number, number] Camera position in 3D space. The x and y components can be controlled by pointer movement, and z can be controlled by mouse wheel
target [number, number, number] Look-at target point. Fixed at [0,0,0] to look at the center of the scene
zoomScale number Controls the zoom level/field of view. A value smaller than 1 to ensure the scene covers all the visible parts

Renderer creation options:

Parameter Range Default Description
forwardSteps 16–256 120 Controls primary ray-marching quality and GPU cost
backwardSteps 1–16 8 Controls hit refinement quality
edgeBlurThreshold 0–0.25 0.05 Controls the soft blur at the image edge
blurMipmapSize 1–4096 200 Size of the precomputed edge-blur texture
blurMipmapRadius 0–100 10 Blur radius for that texture
pixelRatio 0.25–4 device pixel ratio Canvas rendering resolution scale
timer "noop" | "performance" | "gl" "noop" Optional draw-call timing mode

Call renderer.dispose() when the canvas is no longer needed.

Timer modes:

  • "noop": default; no timing overhead.
  • "performance": measures CPU time around the draw call.
  • "gl": measures GPU draw-call time when the browser supports EXT_disjoint_timer_query_webgl2; otherwise it falls back to noop.

Built-in presets are exported as flowSimpleRendererPresets:

const renderer = await createFlowSimpleRenderer(canvas, flow, "performance")

Available presets: performance (64/4), balanced (120/8), and quality (180/12). Preset objects remain available through flowSimpleRendererPresets for reuse or extension.

The whole scene is inside the box from [-1,-1,-1] to [1,1,1], and the bottom sits on the plane at [x,y,1]. The camera is expected to locate at a position with negative z value and look down through the z axis.

Community

Checkout DepthFlow if you want to create a video.

About

DepthFlow (spatial scene) implemented with web apis

Resources

Stars

9 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages