UNPKG

@motion-core/motion-gpu

Version:

Framework-agnostic WebGPU runtime for fullscreen WGSL shaders with explicit Svelte, React, and Vue adapter entrypoints.

80 lines (69 loc) 2.69 kB
import { createMotionGPUError } from './error-report.js'; import { builtInRenderPassBrand, managedPassBrand, type BuiltInRenderPassFormatContract } from './pass-brand.js'; import type { AnyPass, ComputePassLike, PingPongShaderPassLike, RenderPass } from './types.js'; function isRecord(value: unknown): value is Record<PropertyKey, unknown> { return (typeof value === 'object' && value !== null) || typeof value === 'function'; } /** Reports whether a value is a renderer-managed compute pass. */ export function isManagedComputePass(value: unknown): value is ComputePassLike { return isRecord(value) && value[managedPassBrand] === 'compute' && value.isCompute === true; } /** Reports whether a value is a renderer-managed fragment-feedback pass. */ export function isManagedFeedbackPass(value: unknown): value is PingPongShaderPassLike { return ( isRecord(value) && value[managedPassBrand] === 'feedback' && value.isPingPongShader === true ); } /** Reports whether a render pass is a MotionGPU built-in with a known format contract. */ export function isBuiltInRenderPass( value: unknown ): value is RenderPass & { readonly [builtInRenderPassBrand]: BuiltInRenderPassFormatContract } { if (!isRecord(value)) return false; const contract = value[builtInRenderPassBrand]; return ( isRecord(contract) && typeof contract.passName === 'string' && contract.input === 'float-sampled' && contract.output === 'float-renderable' ); } /** * Validates the public JavaScript boundary before a pass enters graph planning. * Compute and feedback passes are nominal; custom render passes remain structural. */ export function assertMotionGPUPass(value: unknown): asserts value is AnyPass { if (isManagedComputePass(value) || isManagedFeedbackPass(value)) { return; } if (!isRecord(value)) { throw createMotionGPUError('RENDER_GRAPH_INVALID', 'A render graph pass must be an object.'); } if (value.isCompute === true) { throw createMotionGPUError( 'RENDER_GRAPH_INVALID', 'Objects with isCompute: true are not custom compute passes. Use ComputePass or PingPongComputePass.' ); } if (value.isPingPongShader === true) { throw createMotionGPUError( 'RENDER_GRAPH_INVALID', 'Objects with isPingPongShader: true are not custom feedback passes. Use PingPongShaderPass.' ); } if (value[managedPassBrand] !== undefined) { throw createMotionGPUError( 'RENDER_GRAPH_INVALID', 'MotionGPU-managed pass has an invalid internal contract.' ); } if (typeof (value as unknown as RenderPass).render !== 'function') { throw createMotionGPUError( 'RENDER_GRAPH_INVALID', 'A custom RenderPass must provide render(context).' ); } }