import { type ComputedRef, type WritableComputedRef } from '#imports'; import type { UiProvider } from './ui.js'; import type { ProgramInfo } from 'twgl.js'; import type { TwglHelpers } from '../libraries/twgl.js'; import type { StorageProvider } from './storage.js'; import type { CursorKeyword } from '#blokkli/editor/types'; import type { SelectionProvider } from './selection.js'; import type { RectangleBufferCollector } from '../helpers/webgl/index.js'; import type { DebugProvider } from './debug.js'; import type { KeyboardProvider } from './keyboard.js'; import type { BlokkliEventBus, CanvasDrawEvent } from '../events/index.js'; import type { Coord } from '../types/geometry.js'; export type RenderContext = CanvasDrawEvent & { changeOptionsTransition: number; }; type PreferredRenderingMode = 'auto' | 'webgl' | '2d'; export type Renderer> = { /** * Unique identifier for this renderer. */ id: string; /** * Z-index for rendering order. * * Lower values render first (bottom), higher values render last (top). */ zIndex: number; /** * Whether this renderer is currently enabled. * * If not provided or returns true, the renderer will execute. */ enabled?: () => boolean; /** * Whether this renderer should be the only one rendered. * * When true or returns true, all other renderers are skipped. * Useful for debugging or exclusive rendering modes. */ only?: boolean | (() => boolean); /** * Get the cursor style when hovering over this renderer's content. * * Higher zIndex renderers take precedence. * @returns The cursor keyword, or null/undefined to defer to lower renderers */ cursor?: () => CursorKeyword | undefined | null; /** * Handle click events on this renderer's content. * * Renderers are checked from highest to lowest zIndex. * @param coord - Mouse coordinates in screen and artboard space * @returns True to claim the click and stop propagation, false/undefined to continue */ onClick?: (coord: { mouse: Coord; mouseArtboard: Coord; }) => boolean | undefined; /** * Create the buffer collector instance for this renderer. * * The collector manages data buffers and rendering state. */ collector: () => T; /** * Define the WebGL shader program for this renderer. * * @returns Object with vertex and fragment shader source code */ program?: () => { shaders: [string, string]; }; /** * Render using WebGL. * * @param ctx - Rendering context with viewport, mouse, artboard data * @param gl - WebGL rendering context * @param program - Compiled shader program */ render: (ctx: RenderContext, gl: WebGLRenderingContext, program: ProgramInfo, twgl: TwglHelpers) => void; /** * Fallback rendering using 2D canvas context. * * Used when WebGL is disabled or unavailable. * @param ctx - Rendering context * @param ctx2d - 2D canvas rendering context */ renderFallback?: (ctx: RenderContext, ctx2d: CanvasRenderingContext2D) => void; }; export type AnimationProvider = { /** * Request an animation loop. Should be called when UI state changes. */ requestDraw: () => void; /** * Reset the animation state and force a remount of all renderer components. */ reset: () => void; /** * Get the WebGL rendering context. * Returns undefined if context is lost or not available. */ gl: () => WebGLRenderingContext | undefined; /** * Get the raw WebGL context even if it's lost. * For debugging purposes only (e.g., context loss testing). */ getRawGL: () => WebGLRenderingContext | null; /** * Set shared uniforms that are common across all renderers. * * Sets resolution, artboard offset, scale, and DPI uniforms. * @param gl - WebGL rendering context * @param programInfo - Shader program to set uniforms on */ setSharedUniforms: (gl: WebGLRenderingContext, programInfo: ProgramInfo) => void; /** * Device pixel ratio adjusted for canvas size limits. * * Automatically scales down to prevent exceeding WebGL/2D canvas size limits * and memory constraints. Lower in low-performance mode. */ dpi: ComputedRef; /** * Whether WebGL is supported and enabled. * * Null initially, then true/false after detection. */ webglSupported: ComputedRef; /** * Whether WebGL rendering is currently enabled. * * Can be set to force WebGL on/off. Automatically disables if unsupported. */ webglEnabled: WritableComputedRef; /** * User's preferred rendering mode. * * - 'auto': Uses WebGL if supported, falls back to 2D * - 'webgl': Forces WebGL rendering * - '2d': Forces 2D canvas rendering */ preferredRenderingMode: WritableComputedRef; /** * Reactive property that indicates if we're currently rendering with WebGL. * True when WebGL context exists and is not lost. */ isRenderingWebGL: ComputedRef; /** * Reactive property that indicates if we have a WebGL context. * True even if the context is lost (for debugging purposes). */ hasWebGLContext: ComputedRef; /** * Reactive key that increments when WebGL context is restored. * Use this as a component key to force remounting renderer components on context loss/restore. */ renderKey: ComputedRef; /** * Reactive key that changes when switching between WebGL and 2D rendering modes. * Use this as the canvas element key to force creating a new canvas with the appropriate context. */ canvasKey: ComputedRef; /** * Set the canvas element to use for rendering. * This initializes the appropriate context based on webglEnabled. */ setCanvasElement: (canvas: HTMLCanvasElement) => void; /** * Remove the canvas element and clean up contexts. */ removeCanvasElement: () => void; /** * Current cursor style determined by active renderers. * * Automatically updated each frame based on mouse position and renderer priorities. * Defaults to 'move' when pressing Space, otherwise determined by highest zIndex renderer. */ cursor: ComputedRef; /** * Get the current mouse coordinates. */ getMouseCoords: () => Coord; /** * Handle a click event by calling onClick handlers on renderers. * Returns true if any renderer claimed the click, false otherwise. */ handleClick: (x: number, y: number) => boolean; /** * Register a WebGL renderer with a specific zIndex. * Returns an object with the collector instance and an unregister function. */ registerRenderer: >(id: string, config: Omit, 'id'>) => Promise<{ collector: T; unregister: () => void; }>; /** * Unregister a WebGL renderer. */ unregisterRenderer: (id: string) => void; }; export default function (eventBus: BlokkliEventBus, ui: UiProvider, storage: StorageProvider, selection: SelectionProvider, debug: DebugProvider, keyboard: KeyboardProvider): AnimationProvider; export {};