layershift 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,7 +2,7 @@
2
2
  * <layershift-parallax> Web Component
3
3
  *
4
4
  * A self-contained Custom Element that renders a depth-aware parallax
5
- * video effect. Encapsulates the entire Three.js pipeline inside a
5
+ * video effect. Encapsulates the entire WebGL pipeline inside a
6
6
  * Shadow DOM — consumers just drop in the tag and provide asset URLs.
7
7
  *
8
8
  * Usage:
@@ -1,21 +1,21 @@
1
1
  /**
2
2
  * Parallax Renderer — GPU-accelerated depth-aware video parallax.
3
3
  *
4
- * Renders a single full-viewport plane textured with the source video
5
- * (via THREE.VideoTexture) and a precomputed depth map. A custom
6
- * fragment shader displaces UV coordinates per-pixel based on the
7
- * depth value and current mouse/gyro input, creating a continuous
8
- * parallax effect with no discrete layer banding.
4
+ * Renders a single fullscreen quad textured with the source video
5
+ * and a precomputed depth map using pure WebGL 2. A custom fragment
6
+ * shader displaces UV coordinates per-pixel based on the depth value
7
+ * and current mouse/gyro input, creating a continuous parallax effect
8
+ * with no discrete layer banding.
9
9
  *
10
10
  * ## Rendering pipeline (per frame)
11
11
  *
12
- * 1. THREE.VideoTexture auto-updates from the <video> element,
13
- * providing the color frame at native display resolution.
12
+ * 1. The video element's current frame is uploaded to the GPU via
13
+ * `gl.texImage2D`, providing the color frame at native resolution.
14
14
  *
15
15
  * 2. The depth interpolator produces a Uint8Array for the current
16
16
  * playback time (interpolated between precomputed 5fps keyframes,
17
17
  * bilateral-filtered on the CPU, then quantized to 0-255).
18
- * This is copied into a single-channel DataTexture on the GPU.
18
+ * This is copied into a single-channel R8 texture on the GPU.
19
19
  *
20
20
  * 3. The InputHandler provides a smoothed {x, y} offset in [-1, 1].
21
21
  * This is passed to the shader as the uOffset uniform.
@@ -31,10 +31,8 @@
31
31
  *
32
32
  * ## Texture memory
33
33
  *
34
- * Only 2 textures per frame: 1 VideoTexture (GPU-managed, zero CPU
35
- * upload) + 1 depth DataTexture (1024×1024 Uint8 = 1 MB, uploaded
36
- * only when depth changes at ~5fps). This is ~5× less bandwidth
37
- * than the old 5-layer RGBA system.
34
+ * Only 2 textures per frame: 1 video texture (uploaded from HTMLVideoElement)
35
+ * + 1 depth texture (R8 format, uploaded only when depth changes at ~5fps).
38
36
  */
39
37
  import type { ParallaxInput } from './input-handler';
40
38
  /** Configuration subset relevant to the parallax renderer. */
@@ -59,13 +57,16 @@ export declare class ParallaxRenderer {
59
57
  private static readonly RESIZE_DEBOUNCE_MS;
60
58
  /** Compile-time upper bound for the POM for-loop in GLSL. */
61
59
  private static readonly MAX_POM_STEPS;
62
- private readonly scene;
63
- private readonly camera;
64
- private readonly renderer;
65
- private readonly container;
60
+ private readonly canvas;
61
+ private gl;
62
+ private program;
63
+ private uniforms;
64
+ private vao;
66
65
  private videoTexture;
67
66
  private depthTexture;
68
- private mesh;
67
+ private readonly container;
68
+ private depthWidth;
69
+ private depthHeight;
69
70
  private videoAspect;
70
71
  private readDepth;
71
72
  private readInput;
@@ -82,8 +83,10 @@ export declare class ParallaxRenderer {
82
83
  private rvfcSupported;
83
84
  private resizeObserver;
84
85
  private resizeTimer;
85
- private currentPlaneWidth;
86
- private currentPlaneHeight;
86
+ private uvOffset;
87
+ private uvScale;
88
+ /** Resolved config with all optional shader params filled from defaults. */
89
+ private readonly config;
87
90
  /**
88
91
  * Create the renderer and attach its canvas to the DOM.
89
92
  *
@@ -92,12 +95,10 @@ export declare class ParallaxRenderer {
92
95
  * @param config - Parallax-specific settings (strength, POM, overscan).
93
96
  * Optional shader parameters are merged with calibrated defaults.
94
97
  */
95
- /** Resolved config with all optional shader params filled from defaults. */
96
- private readonly config;
97
98
  constructor(parent: HTMLElement, config: ParallaxRendererConfig);
98
99
  /**
99
- * Set up the scene: create VideoTexture, depth DataTexture, and the
100
- * single mesh with the custom parallax ShaderMaterial.
100
+ * Set up the scene: create video texture, depth texture, and set
101
+ * static shader uniforms.
101
102
  *
102
103
  * Call this once after the video element and depth data are loaded.
103
104
  *
@@ -116,82 +117,59 @@ export declare class ParallaxRenderer {
116
117
  *
117
118
  * When RVFC is not available, falls back to a single RAF loop that
118
119
  * does everything (the pre-RVFC behavior).
119
- *
120
- * @param readDepth - Called with the current video time.
121
- * Returns a Uint8Array of depth values (0=near, 255=far) at the
122
- * depth texture's resolution. The interpolator handles caching
123
- * so redundant calls (same depth frame) return instantly.
124
- * @param readInput - Returns the smoothed parallax input {x, y}
125
- * in [-1, 1].
126
- * @param onVideoFrame - Optional callback invoked on each new
127
- * video frame. Receives the accurate media time and the
128
- * browser's presented-frame counter.
129
120
  */
130
121
  start(video: HTMLVideoElement, readDepth: (timeSec: number) => Uint8Array, readInput: () => ParallaxInput, onVideoFrame?: (currentTime: number, frameNumber: number) => void): void;
131
122
  /** Stop both render loops and release callbacks. */
132
123
  stop(): void;
133
124
  /** Stop rendering and release all GPU resources. */
134
125
  dispose(): void;
126
+ /** Create the shader program, fullscreen quad VAO, and cache uniform locations. */
127
+ private initGPUResources;
135
128
  /** Check whether requestVideoFrameCallback is available. */
136
129
  private static isRVFCSupported;
137
130
  /**
138
131
  * RVFC callback — fires only when the browser presents a new video frame.
139
132
  *
140
- * Handles the expensive depth texture update, which only needs to happen
133
+ * Handles the depth texture update, which only needs to happen
141
134
  * when the video frame actually changes (~24-30fps, not 60-120fps).
142
- *
143
- * Uses `metadata.mediaTime` for more accurate depth reads than
144
- * `video.currentTime` (which can lag behind the presented frame).
145
135
  */
146
136
  private readonly videoFrameLoop;
147
137
  /**
148
138
  * Main render loop — called every animation frame at display refresh rate.
149
139
  *
150
140
  * When RVFC is active, this only handles:
151
- * 1. Updating the parallax offset uniform from input (buttery smooth).
152
- * 2. Rendering the scene (single draw call).
153
- *
154
- * The depth texture is updated separately by videoFrameLoop at video
155
- * frame rate. This separation means parallax stays smooth at 60/120fps
156
- * even though depth only updates at 24-30fps.
141
+ * 1. Uploading the current video frame to the GPU texture.
142
+ * 2. Updating the parallax offset uniform from input (buttery smooth).
143
+ * 3. Rendering the fullscreen quad (single draw call).
157
144
  *
158
145
  * When RVFC is NOT supported, this falls back to the original behavior:
159
146
  * depth update + input update + render all in a single RAF tick.
160
147
  */
161
148
  private readonly renderLoop;
149
+ /** Upload fresh depth data to the GPU texture. */
150
+ private updateDepthTexture;
162
151
  /**
163
152
  * Set up a ResizeObserver on the container element and a fallback
164
- * window resize listener. Both trigger a debounced recalculation
165
- * of the viewport layout, camera, and plane geometry.
153
+ * window resize listener.
166
154
  */
167
155
  private setupResizeHandling;
168
156
  /** Debounce resize events to avoid expensive layout recalculations. */
169
157
  private readonly scheduleResizeRecalculate;
170
158
  /**
171
- * Recalculate the WebGL canvas size, orthographic camera frustum,
172
- * and plane geometry to match the current container dimensions.
159
+ * Recalculate the WebGL canvas size and UV transform to match the
160
+ * current container dimensions.
173
161
  *
174
- * The plane is sized to "cover" the viewport (like CSS object-fit:
175
- * cover) plus extra overscan padding so that parallax displacement
176
- * doesn't reveal the plane edges.
162
+ * Cover-fit + overscan is expressed as a UV-space transform (offset + scale)
163
+ * rather than geometry resize. The fullscreen quad stays fixed at -1 to 1.
177
164
  */
178
165
  private recalculateViewportLayout;
179
- /** Read the container's pixel dimensions, with a minimum of 1×1. */
166
+ /** Read the container's pixel dimensions, with a minimum of 1x1. */
180
167
  private getViewportSize;
181
- /**
182
- * Compute the plane dimensions needed to cover the viewport while
183
- * preserving the video's aspect ratio, plus overscan padding.
184
- *
185
- * "Cover" means the plane is scaled so the shorter axis fills the
186
- * viewport (the longer axis overflows). Overscan adds extra size
187
- * proportional to the parallax strength so that maximum displacement
188
- * never reveals the plane edge.
189
- *
190
- * @returns planeWidth/planeHeight in world units (= pixels, since
191
- * the camera is set up 1:1).
192
- */
193
- private computeCoverPlaneSize;
194
- /** Dispose the mesh, material, and textures from the scene. */
195
- private disposeScene;
168
+ private readonly handleContextLost;
169
+ private readonly handleContextRestored;
170
+ /** Dispose textures only. */
171
+ private disposeTextures;
172
+ /** Dispose the shader program and VAO. */
173
+ private disposeGPUResources;
196
174
  }
197
175
  //# sourceMappingURL=parallax-renderer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"parallax-renderer.d.ts","sourceRoot":"","sources":["../../src/parallax-renderer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"parallax-renderer.d.ts","sourceRoot":"","sources":["../../src/parallax-renderer.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "layershift",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Embeddable video effects as Web Components. Drop-in parallax, depth-aware motion, and more.",
5
5
  "type": "module",
6
6
  "main": "dist/components/layershift.js",
@@ -49,8 +49,8 @@
49
49
  "video",
50
50
  "depth",
51
51
  "web-component",
52
- "three.js",
53
52
  "webgl",
53
+ "webgl2",
54
54
  "depth-map",
55
55
  "3d-effect"
56
56
  ],
@@ -60,10 +60,7 @@
60
60
  "url": "https://github.com/jeremysykes/layershift/issues"
61
61
  },
62
62
  "homepage": "https://layershift.io",
63
- "dependencies": {
64
- "@types/three": "^0.182.0",
65
- "three": "^0.182.0"
66
- },
63
+ "dependencies": {},
67
64
  "devDependencies": {
68
65
  "@playwright/test": "^1.58.2",
69
66
  "@vitest/browser": "^4.0.18",