// Type definitions for scratch-render // Project: https://github.com/LLK/scratch-render /// /// declare namespace RenderWebGL { type AnyWebGLContext = WebGLRenderingContext | WebGL2RenderingContext; type BitmapResolution = 1 | 2; type BitmapData = ImageData | ImageBitmap | HTMLImageElement | HTMLCanvasElement | HTMLVideoElement; type LayerGroup = 'background' | 'video' | 'pen' | 'sprite' | string; const enum UseGpuModes { Automatic = 'Automatic', ForceGPU = 'ForceGPU', ForceCPU = 'ForceCPU' } const enum Effect { Color = 'color', Fisheye = 'fisheye', Whirl = 'whirl', Pixelate = 'pixelate', Brightness = 'brightness', Ghost = 'ghost' } // TODO: document bit masks type EffectMask = number; const enum DrawMode { Default = 'default', StraightAlpha = 'straightAlpha', Silhouette = 'silhouette', ColorMask = 'colorMask', Line = 'line', Background = 'background' } interface Rectangle { left: number; right: number; bottom: number; top: number; width: number; height: number; intersects(other: Rectangle): boolean; contains(other: Rectangle): boolean; initFromBounds(left: number, right: number, bottom: number, top: number): void; initFromPointsAABB(points: [number, number][]): void; initFromModelMatrix(matrix4x4: number[]): void; clamp(left: number, right: number, bottom: number, top: number): void; snapToInt(): void; } /** * Suggested properties of a drawing region. Strictly, this can really be whatever you want it to be. */ interface DrawingRegion { enter?(): void; exit?(): void; } interface Shader { // TODO } class ShaderManager { static EFFECT_INFO: Record; static EFFECTS: Effect[]; static DRAW_MODE: Record; _gl: AnyWebGLContext; _shaderCache: Record>; _buildShader(drawMode: DrawMode, effectMask: EffectMask): twgl.ProgramInfo; getShader(drawMode: DrawMode, effectMask: EffectMask): twgl.ProgramInfo; } class Silhouette { static _updateCanvas(): HTMLCanvasElement; _width: number; _height: number; _colorData: Uint8ClampedArray | null; _getColor(silhouette: Silhouette, x: number, y: number, destination?: Uint8ClampedArray): Uint8ClampedArray; /** * @param image Image data * @param isPremultiplied Whether alpha is premultiplied. Defaults to false. */ update(image: BitmapData, isPremultiplied?: boolean): void; colorAtNearest(textureCoordinate: twgl.V3, destination?: Uint8ClampedArray): Uint8ClampedArray; colorAtLinear(textureCoordinate: twgl.V3, destination?: Uint8ClampedArray): Uint8ClampedArray; isTouchingNearest(textureCoordinate: twgl.V3): void; isTouchingLinear(textureCoordinate: twgl.V3): void; } interface SkinEventMap { WasAltered: void; } class Skin extends EventEmitter { _id: number; get id(): number; get size(): [number, number]; _rotationCenter: twgl.V3; get rotationCenter(): twgl.V3; /** * Always returns the middle of the skin (size / 2). * No relation to Skin._rotationCenter or Skin.rotationCenter. */ calculateRotationCenter(): [number, number]; _texture: WebGLTexture | null; _uniforms: { u_skinSize: [number, number]; u_skin: WebGLTexture | null; }; getUniforms(): Skin['_uniforms']; _silhouette: Silhouette; updateSilhouette(): void; /** * @see {Silhouette.isTouchingNearest} */ isTouchingNearest(textureCoordinate: twgl.V3): boolean; /** * @see {Silhouette.isTouchingLinear} */ isTouchingLinear(textureCoordinate: twgl.V3): boolean; useNearest(scale: [number, number], drawable: Drawable): boolean; getTexture(scale: [number, number]): WebGLTexture; _setTexture(image: BitmapData): void; setEmptyImageData(): void; getFenceBounds(): Rectangle; dispose(): void; } class BitmapSkin extends Skin { static _getBitmapSize(image: BitmapData): [number, number]; _renderer: RenderWebGL; _costumeResolution: BitmapResolution; _textureSize: [number, number]; /** * Synchronously update the content of the skin. * @param image The new image. * @param bitmapResolution Defaults to 2. * @param rotationCenter Defaults to the center of the image. */ setBitmap(image: BitmapData, bitmapResolution?: BitmapResolution, rotationCenter?: [number, number]): void; } class SVGSkin extends Skin { _renderer: RenderWebGL; _svgImage: HTMLImageElement; _svgImageLoaded: boolean; _size: [number, number]; _canvas: HTMLCanvasElement; _context: CanvasRenderingContext2D; _scaledMIPs: WebGLTexture[]; _largestMIPScale: number; _maxTextureScale: number; createMIP(scale: number): WebGLTexture; resetMIPs(): void; /** * Asynchronously update the content of the skin. May take a couple frames for changes to appear. * @param svgData SVG source code * @param rotationCenter Defaults to the center of the image. */ setSVG(svgData: string, rotationCenter?: [number, number]): void; } interface PenAttributes { /** * Pen color in RGBA from 0-1. */ color4f: [number, number, number, number]; diameter: number; } class PenSkin extends Skin { _renderer: RenderWebGL; _size: [number, number]; _framebuffer: WebGLFramebuffer; _silhouetteDirty: boolean; _silhouettePixels: Uint8Array; _silhouetteImageData: ImageData; _lineOnBufferDrawRegionId: DrawingRegion; _enterDrawLineOnBuffer(): void; _exitDrawLineOnBuffer(): void; _drawLineOnBuffer(attributes: PenAttributes, x1: number, y1: number, x2: number, y2: number): void; _usePenBufferDrawRegionId: DrawingRegion; _enterUsePenBuffer(): void; _exitUsePenBuffer(): void; _lineBufferInfo: twgl.BufferInfo; _lineShader: Shader; clear(): void; drawPoint(attributes: PenAttributes, x: number, y: number): void; drawLine(attributes: PenAttributes, x1: number, y1: number, x2: number, y2: number): void; onNativeSizeChanged(event: ScratchRenderEventMap['NativeSizeChanged']): void; _setCanvasSize(size: [number, number]): void; } const enum TextBubbleType { Say = 'say', Think = 'think', } class CanvasMeasurementProvider { _ctx: CanvasRenderingContext2D; _cache: Record; measureText(text: string): number; /** * Does nothing. */ beginMeasurementSession(): void; /** * Does nothing. */ endMeasurementSession(): void; } class TextWrapper { _measurementProvider: CanvasMeasurementProvider; _cache: Record; wrapText(maxWidth: number, text: string): string[]; } class TextBubbleSkin extends Skin { _renderer: RenderWebGL; _canvas: HTMLCanvasElement; _size: [number, number]; _renderedScale: number; _lines: string[]; _textAreaSize: { width: number; height: number }; _bubbleType: TextBubbleType; _pointsLeft: boolean; _textDirty: boolean; _textureDirty: boolean; measurementProvider: CanvasMeasurementProvider; textWrapper: TextWrapper; /** * @param type Type of bubble. * @param text Text to display. * @param pointsLeft True if this bubble points left, false if this bubble points right. */ setTextBubble(type: TextBubbleType, text: string, pointsLeft: boolean): void; _restyleCanvas(): void; _reflowLines(): void; _renderTextBubble(scale: number): void; } class Drawable { static color4fFromID(id: number): [number, number, number, number]; static color3bToID(r: number, g: number, b: number): number; static sampleColor4b(coordinate: twgl.V3, drawable :Drawable, destination: Uint8ClampedArray, effectMask?: EffectMask): Uint8ClampedArray; _id: number; get id(): number; _uniforms: { u_modelMatrix: twgl.M4; /** * Only used in some debugging modes. */ u_silhouetteColor: [number, number, number, number]; } & Record; getUniforms(): Drawable['_uniforms']; _skin: Skin; get skin(): Skin; set skin(skin: Skin); _skinWasAltered(): void; _position: twgl.V3; /** * @param position The new position. This will be rounded. */ updatePosition(position: [number, number]): void; _scale: twgl.V3; get scale(): twgl.V3; updateScale(scale: number): void; _direction: number; updateDirection(direction: number): void; _visible: boolean; getVisible(): boolean; updateVisible(visible: boolean): void; enabledEffects: EffectMask; updateEffect(effect: Effect, value: number): void; /** * @deprecated Use the specific update* methods instead. */ updateProperties(properties: { position?: [number, number]; direction?: number; scale?: number; visible?: boolean; } | Record): void; _transformDirty: boolean; _calculateTransform(): void; _rotationMatrix: twgl.M4; _rotationTransformDirty: boolean; _rotationAdjusted: twgl.V3; _rotationCenterDirty: boolean; _skinScale: twgl.V3; _skinScaleDirty: boolean; _convexHullPoints: Array<[number, number]>; _convexHullDirty: boolean; needsConvexHullPoints(): boolean; setConvexHullDirty(): boolean; setConvexHullPoints(points: Array<[number, number]>): void; _transformedHullPoints: Array<[number, number]>; _transformedHullDirty: boolean; _getTransformedHullPoints(): Array<[number, number]>; setTransformDirty(): void; _inverseMatrix: twgl.M4; _inverseTransformDirty: boolean; updateMatrix(): void; getBounds(result?: Rectangle): Rectangle; getBoundsForBubble(result?: Rectangle): Rectangle; getAABB(result?: Rectangle): Rectangle; getFastBounds(result?: Rectangle): Rectangle; updateCPURenderAttributes(): void; isTouching(textureCoordinate: twgl.V3): boolean; _isTouchingNearest(textureCoordinate: twgl.V3): boolean; _isTouchingLinear(textureCoordinate: twgl.V3): boolean; _isTouchingNever(textureCoordinate: twgl.V3): false; dispose(): void; } interface ScratchRenderEventMap { NativeSizeChanged: { newSize: [number, number]; } } } declare class RenderWebGL extends EventEmitter { static isSupported(canvas?: HTMLCanvasElement): boolean; /** * If WebGL 1 is supported, returns a WebGL 1 context. * If WebGL 1 is not supported but WebGL 2 is supported, returns a WebGL 2 context. * Otherwise, returns null. */ static _getContext(canvas: HTMLCanvasElement): RenderWebGL.AnyWebGLContext | null; static sampleColor3b(vector: twgl.V3, drawableIds: number[], destination?: Uint8ClampedArray): Uint8ClampedArray; constructor(canvas: HTMLCanvasElement, xLeft?: number, xRight?: number, yBottom?: number, yTop?: number); get canvas(): HTMLCanvasElement; _gl: RenderWebGL.AnyWebGLContext; get gl(): RenderWebGL.AnyWebGLContext; _xRight: number; _xLeft: number; _yTop: number; _yBottom: number; setStageSize(xLeft: number, xRight: number, yBottom: number, yTop: number): void; resize(width: number, height: number): void; _nativeSize: [number, number]; getNativeSize(): [number, number]; _setNativeSize(width: number, height: number): void; onNativeSizeChanged(event: RenderWebGL.ScratchRenderEventMap['NativeSizeChanged']): void; /** * Renders the stage on the canvas. */ draw(): void; _drawThese(drawableIds: number[], drawMode: RenderWebGL.DrawMode, projection: twgl.M4, opts?: { filter?: (drawableId: number) => boolean; extraUniforms?: object; effectMask?: RenderWebGL.EffectMask; ignoreVisibility?: boolean; framebufferWidth?: number; framebufferHeight?: number; }): void; _drawList: number[]; _addToDrawList(drawableID: number, group: RenderWebGL.LayerGroup): void; _updateOffsets(updateType: 'add' | 'delete', index: number): void; get _visibleDrawList(): number[]; getDrawableOrder(drawableID: number): number | -1; setDrawableOrder(drawableID: number, order: number, group: RenderWebGL.LayerGroup, isRelative?: boolean, min?: number): void; _groupOrdering: RenderWebGL.LayerGroup[]; _layerGroups: Record; setLayerGroupOrdering(groupOrdering: RenderWebGL.LayerGroup[]): void; _endIndexForKnownLayerGroup(layerGroup: RenderWebGL.LayerGroup): number; _nextDrawableId: number; _allDrawables: RenderWebGL.Drawable[]; createDrawable(group: string): number; destroyDrawable(drawableID: number, group: RenderWebGL.LayerGroup): void; _allSkins: RenderWebGL.Skin[]; _nextSkinId: number; /** * @see {RenderWebGL.BitmapSkin.setBitmap} */ createBitmapSkin(image: RenderWebGL.BitmapData, bitmapResolution?: RenderWebGL.BitmapResolution, rotationCenter?: [number, number]): number; /** * @see {RenderWebGL.BitmapSkin.setBitmap} */ updateBitmapSkin(skinId: number, image: RenderWebGL.BitmapData, bitmapResolution?: RenderWebGL.BitmapResolution, rotationCenter?: [number, number]): void; /** * @see {RenderWebGL.SVGSkin.setSVG} */ createSVGSkin(svgData: string, rotationCenter?: [number, number]): number; /** * @see {RenderWebGL.SVGSkin.setSVG} */ updateSVGSkin(skinId: number, svgData: string, rotationCenter?: [number, number]): void; /** * @see {RenderWebGL.TextBubbleSkin.setTextBubble} */ createTextSkin(type: RenderWebGL.TextBubbleType, text: string, pointsLeft: boolean): number; /** * @see {RenderWebGL.TextBubbleSkin.setTextBubble} */ updateTextSkin(skinId: number, type: RenderWebGL.TextBubbleType, text: string, pointsLeft: boolean): void; createPenSkin(): number; destroySkin(skinId: number): void; _reskin(skinId: number, newSkin: RenderWebGL.Skin): void; getBounds(drawableId: number): RenderWebGL.Rectangle; getBoundsForBubble(drawableId: number): RenderWebGL.Rectangle; _getConvexHullPointsForDrawable(drawableID: number): Array<[number, number]>; getCurrentSkinSize(drawableId: number): [number, number]; getSkinSize(skinId: number): [number, number]; getSkinRotationCenter(skinId: number): [number, number]; /** * Determine if a drawable is touching a color or if a certain color of the drawable is touching a color. * @param color RGB color from 0-255 * @param mask RGB color from 0-255. Used by "is color touching color" block. */ isTouchingColor(drawableId: number, color: [number, number, number], mask?: [number, number, number]): boolean; _isTouchingColorGpuStart(drawableId: number, candidateIds: number[], bounds: RenderWebGL.Rectangle, color: [number, number, number], mask?: [number, number, number]): void; _isTouchingColorGpuFin(bounds: RenderWebGL.Rectangle, color: [number, number, number], stop: number): boolean; /** * Determine if a drawable is intersecting a set of other drawables. * @param drawableId ID of the target drawable * @param candidateIds The IDs of the drawables to test for collision with the target drawable. Defaults to all drawables. */ isTouchingDrawables(drawableId: number, candidateIds?: number[]): boolean; /** * @param centerX X coordinate in client space * @param centerY Y coordinate in client space * @param width Defaults to 1 * @param height Defaults to 1 */ clientSpaceToScratchBounds(centerX: number, centerY: number, width?: number, height?: number): RenderWebGL.Rectangle; /** * Determine if a drawable is touching a point. * @param drawableId ID of the target drawable * @param centerX X coordinate in client space * @param centerY Y coordinate in client space * @param width Defaults to 1 * @param height Defaults to 1 */ drawableTouching(drawableId: number, centerX: number, centerY: number, width?: number, height?: number): boolean; /** * Determine the top-most drawable at a point. * @param centerX X coordinate in client space * @param centerY Y coordinate in client space * @param width Defaults to 1 * @param height Defaults to 1 * @param candidateIds Defaults to all drawables * @returns The ID of the top-most drawable, or -1 or false if there is none. */ pick(centerX: number, centerY: number, width?: number, height?: number, candidateIds?: number[]): number | -1 | false; extractDrawableScreenSpace(drawableId: number): { data: ImageData; x: number; y: number; width: number; height: number; }; /** * :3 * @see {RenderWebGL.extractDrawableScreenSpace} */ canHazPixels(drawableID: number): ReturnType; /** * @param x X coordinate in client space * @param y Y coordinate in client space * @param radius "Radius" of the square, in pixels * @returns Data about the pixels in a square around the coordinates. Color channels are RGBA from 0-255 */ extractColor(x: number, y: number, radius: number): { data: Uint8Array; width: number; height: number; color: { r: number; g: number; b: number; a: number; } }; /** * Get the "candidate bounding box" to use for "touching" queries. * @returns The rectangle, or null if the drawable is offscreen or has no skin. */ _touchingBounds(drawableId: number): RenderWebGL.Rectangle | null; _candidatesTouching(drawableId: number, candidateIds: number[]): Array<{ id: number; drawable: RenderWebGL.Drawable; intersection: RenderWebGL.Rectangle; }>; _candidatesBounds(candidates: ReturnType): RenderWebGL.Rectangle; updateDrawableSkinId(drawableId: number, skinId: number): void; updateDrawablePosition(drawableId: number, position: [number, number]): void; updateDrawableDirection(drawableId: number, direction: number): void; updateDrawableScale(drawableId: number, scale: [number, number]): void; updateDrawableDirectionScale(drawableId: number, direction: number, scale: [number, number]): void; updateDrawableVisible(drawableId: number, visible: boolean): void; updateDrawableEffect(drawableId: number, effectName: RenderWebGL.Effect, value: number): void; /** * @deprecated Use the individual updateDrawable* methods instead. */ updateDrawableProperties(drawableId: number, properties: { skinId?: number; position?: [number, number]; direction?: number; scale?: number; visible?: number; } | Record): void; getFencedPositionOfDrawable(drawableId: number, position: [number, number]): [number, number]; penClear(penSkinId: number): void; penPoint(penSkinId: number, penAttributes: RenderWebGL.PenAttributes, x: number, y: number): void; penLine(penSkinId: number, penAttributes: RenderWebGL.PenAttributes, x1: number, y1: number, x2: number, y2: number): void; penStamp(penSkinId: number, stampDrawableId: number): void; _projection: twgl.M4; _shaderManager: RenderWebGL.ShaderManager; _regionId: unknown | null; _exitRegion: Function | null; /** * Enter a drawing region. * @param regionId Any arbitrary unique object. * @param enter Called when entering the drawing region (which is what this function does). Defaults to regionId.enter. * @param exit Called when leaving the drawing region. Defaults to regionId.exit. */ enterDrawRegion(regionId: unknown, enter?: Function, exit?: Function): void; _doExitDrawRegion(): void; _backgroundDrawRegionId: RenderWebGL.DrawingRegion; _enterDrawBackground(): void; _exitDrawBackground(): void; /** * RGBA from 0-1 */ _backgroundColor4f: [number, number, number, number]; /** * RGB from 0-255 */ _backgroundColor3b: [number, number, number]; /** * @param red Red from 0-1 * @param green Green from 0-1 * @param blue Blue from 0-1 */ setBackgroundColor(red: number, green: number, blue: number): void; _snapshotCallbacks: Array<(dataURL: string) => void>; requestSnapshot(callback: (dataURL: string) => void): void; _useGpuMode: RenderWebGL.UseGpuModes; setUseGpuMode(useGpuMode: RenderWebGL.UseGpuModes): void; _getMaxPixelsForCPU(): number; _debugCanvas?: HTMLCanvasElement; setDebugCanvas(canvas: HTMLCanvasElement): void; _bufferInfo: twgl.BufferInfo; _createGeometry(): void; }