// Type definitions for scratch-vm
// Project: https://github.com/LLK/scratch-vm
///
///
///
///
///
///
///
declare namespace VM {
/**
* Indicates the type is dependent on the existence of a renderer.
*/
type IfRenderer = HasRenderer;
/**
* Indicates the type is dependent on the existence of an audio engine.
*/
type IfAudioEngine = HasAudioEngine;
/**
* Indicates thte type is dependent on the existence of an attached storage.
*/
type IfStorage = HasStorage;
/**
* Indicates the type is dependent of whether the VM is attached to scratch-gui.
*/
type IfGui = HasGui;
type ScratchCompatibleValue = string | boolean | number;
type ScratchList = ScratchCompatibleValue[];
type VariableValue = ScratchCompatibleValue | ScratchList;
interface BaseAsset {
/**
* The md5 of this asset.
*/
assetId: string;
/**
* The md5 + file extension of this asset. May be missing.
*/
md5?: string;
name: string;
asset: ScratchStorage.Asset;
}
interface Costume extends BaseAsset {
dataFormat: 'svg' | 'png' | 'jpg';
bitmapResolution: number;
rotationCenterX: number;
rotationCenterY: number;
size: [number, number];
skinId: number;
}
interface Sound extends BaseAsset {
dataFormat: 'mp3' | 'wav';
format: ''; // TODO
rate: number;
sampleCount: number;
soundId: string;
}
interface Sprite {
runtime: Runtime;
blocks: Blocks;
name: string;
costumes: Costume[];
sounds: Sound[];
clones: RenderedTarget[];
soundBank: AudioEngine.SoundBank | null;
}
interface Field {
id: string | null;
name: string;
value: string;
}
interface Input {
name: string;
block: string;
shadow: string | null;
}
interface BaseMutation {
tagName: 'mutation';
children: [];
}
/**
* Found on blocks with an opcode of procedures_call
*/
interface ProcedureCallMutation extends BaseMutation {
proccode: string;
/**
* JSON-stringified list of strings.
*/
argumentids: string;
/**
* JSON-stringified boolean.
*/
warp: string;
}
/**
* Found on blocks with an opcode of procedures_prototype
*/
interface ProcedurePrototypeMutation extends ProcedureCallMutation {
/**
* JSON-stringified list of strings.
*/
argumentdefaults: string;
/**
* JSON-stringified list of strings.
*/
argumentnames: string;
}
interface Block {
id: string;
opcode: string;
parent: string | null;
next: string | null;
shadow: boolean;
topLevel: boolean;
inputs: Record;
fields: Record;
mutation: null | ProcedureCallMutation | ProcedurePrototypeMutation;
}
interface Blocks {
runtime: Runtime;
_blocks: Record;
getBlock(id: string): Block | undefined;
getOpcode(id: string): string | null;
getFields(id: string): object | null;
getInputs(id: string): object | null;
getProcedureDefinition(procedureCode: string): string | null;
getProcedureParamNamesAndIds(procedureCode: string): [
// Argument name
string[],
// Argument IDs
string[]
];
getProcedureParamNamesIdsAndDefaults(procedureCode: string): [
// Argument names
string[],
// Argument IDs
string[],
// Argument defaults
unknown[]
];
duplicate(): Blocks;
resetCache(): void;
emitProjectChanged(): void;
toXML(): string;
forceNoGlow: boolean;
}
interface RuntimeScriptCache {
container: Blocks;
blockId: string;
fieldsOfInputs: Record;
}
interface BaseVariable {
id: string;
name: string;
isCloud: boolean;
toXML(isLocal?: boolean): string;
}
const enum VariableType {
Scalar = '',
List = 'list',
Broadcast = 'broadcast_msg'
}
interface ScalarVariable extends BaseVariable {
type: '';
value: ScratchCompatibleValue;
}
interface ListVariable extends BaseVariable {
type: 'list';
value: ScratchList;
_monitorUpToDate?: boolean;
}
interface BroadcastVariable extends BaseVariable {
type: 'broadcast_msg';
/**
* Always the same as name.
*/
value: string;
}
type Variable = ScalarVariable | ListVariable | BroadcastVariable;
interface Comment {
id: string;
blockId: string | null;
minimized: boolean;
text: string;
x: number;
y: number;
width: number;
height: number;
}
interface PostedSpriteInfo {
force?: boolean;
x?: number;
y?: number;
direction?: number;
draggable?: boolean;
rotationStyle?: VM.RotationStyle;
visible?: boolean;
size?: number;
}
const enum TextToSpeechVoice {
Alto = 'ALTO',
Tenor = 'TENOR',
Squeak = 'SQUEAK',
Giant = 'GIANT',
Kitten = 'KITTEN'
}
interface CustomState {
'Scratch.looks': {
drawableId: null | number;
skinId: null | number;
onSpriteRight: boolean;
text: string;
type: RenderWebGL.TextBubbleType;
};
'Scratch.sound': {
effects: {
pitch: number;
pan: number;
};
};
'Scratch.music': {
currentInstrument: number;
};
'Scratch.pen': {
penDown: boolean;
color: number;
saturation: number;
brightness: number;
transparency: number;
_shade: number;
penAttributes: RenderWebGL.PenAttributes;
};
'Scratch.text2speech': {
voiceId: TextToSpeechVoice;
};
'Scratch.videoSensing': {
motionFrameNumber: number;
motionAmount: number;
motionDirection: number;
};
}
interface BaseTarget extends EventEmitter {
runtime: Runtime;
id: string;
blocks: Blocks;
variables: Record;
comments: Record;
createComment(id: string, blockId: string, text: string, x: number, y: number, width: number, height: number, minimized?: boolean): void;
/**
* Called by runtime when the green flag is pressed.
*/
onGreenFlag(): void;
getName(): string;
lookupOrCreateVariable(id: string, name: string): ScalarVariable;
lookupBroadcastMsg(id: string, name: string): BroadcastVariable | undefined;
lookupBroadcastByInputValue(name: string): BroadcastVariable | undefined;
/**
* Look for a variable by its ID in this target.
* If it doesn't exist in this target, will check if it exists in the stage target.
* If it still doesn't exist, returns undefined.
*/
lookupVariableById(id: string): Variable | undefined;
lookupVariableByNameAndType(name: string): ScalarVariable | undefined;
lookupVariableByNameAndType(name: string, type: '', skipStage?: boolean): ScalarVariable | undefined;
lookupVariableByNameAndType(name: string, type: 'list', skipStage?: boolean): ListVariable | undefined;
lookupVariableByNameAndType(name: string, type: 'broadcast_msg', skipStage?: boolean): BroadcastVariable | undefined;
lookupOrCreateList(id: string, name: string): ListVariable;
/**
* Create a new variable. If the ID is already used, silently does nothing.
* isCloud is ignored if the sprite is not the stage or if the cloud variable limit has been reached.
*/
createVariable(id: string, name: string, type: VariableType, isCloud?: boolean): void;
_customState: Partial;
getCustomState(name: T): CustomState[T] | undefined;
setCustomState(name: T, value: CustomState[T]): void;
/**
* Mirrors custom state.
*/
soundEffects?: CustomState['Scratch.sound']['effects'];
postSpriteInfo(spriteInfo: PostedSpriteInfo): void;
dispose(): void;
}
const enum RotationStyle {
AllAround = 'all-around',
LeftRight = 'left-right',
None = "don't rotate"
}
interface RenderedTargetEventMap {
TARGET_MOVED: [RenderedTarget, number, number, boolean?];
EVENT_TARGET_VISUAL_CHANGE: [RenderedTarget];
}
const enum Effect {
// TODO: document ranges
Color = 'color',
Fisheye = 'fisheye',
Whirl = 'whirl',
Pixelate = 'pixelate',
Mosaic = 'mosaic',
Brightness = 'brightness',
Ghost = 'ghost'
}
/**
* @see {Renderer.Rectangle}
*/
interface SimpleRectangle {
left: number;
right: number;
top: number;
bottom: number;
}
interface RenderedTarget extends BaseTarget {
sprite: Sprite;
renderer: IfRenderer;
drawableID: number;
isOriginal: boolean;
isStage: boolean;
/**
* Returns true if the target is not the stage and is not a clone.
*/
isSprite(): boolean;
x: number;
y: number;
/**
* Update the sprite's position. The given coordinates may be fenced to make the target fit on screen.
* Set force to true to force the sprite to move even if it's being dragged.
*/
setXY(x: number, y: number, force?: boolean): void;
keepInFence(newX: number, newY: number, fence?: SimpleRectangle): [number, number];
/**
* Direction in degrees. Defaults to 90 (right). Can be from -179 to 180.
*/
direction: number;
/**
* Change the sprite's direction. The direction will be wrapped as needed to fit in the expected range.
*/
setDirection(direction: number): void;
rotationStyle: RotationStyle;
setRotationStyle(rotationStyle: RotationStyle): void;
_getRenderedDirectionAndScale(): {
direction: number;
/**
* X scale then Y scale, both from 100.
* A negative scale means that the target should be flipped on that axis.
*/
scale: [number, number];
};
visible: boolean;
setVisible(visible: boolean): void;
/**
* The sprite's size. Default is 100.
*/
size: number;
/**
* Change the sprite's size. The given size may be fenced to make the target fit on screen and isn't negative.
*/
setSize(size: number): void;
getBounds(): IfRenderer;
getBoundsForBubble(): IfRenderer;
draggable: boolean;
setDraggable(draggable: boolean): void;
/**
* The index of the current costume.
*/
currentCostume: number;
getCurrentCostume(): Costume;
getCostumes(): Costume[];
/**
* Update the current costume index.
* If index is not finite, it will be converted to 0.
* If index is not in the list, it will wrap around.
*/
setCostume(costumeIndex: number): void;
addCostume(costume: Costume, index: number): void;
/**
* Rename the costume at a given index.
* Will throw an error if the index is out of bounds.
* If the new name is already used, it may be modified.
*/
renameCostume(costumeIndex: number, newName: string): void;
/**
* Get the index of a costume with a given name.
* If the costume doesn't exist, returns -1.
*/
getCostumeIndexByName(name: string): number;
/**
* Delete the costume at a given index.
* Returns the deleted costume if one exists at that index, otherwise null.
*/
deleteCostume(costumeIndex: number): Costume | null;
/**
* Move the costume from one index to another.
* Returns true if any change was made.
*/
reorderCostume(costumeIndex: number, newIndex: number): boolean;
getSounds(): Sound[];
addSound(sound: Sound, index: number): void;
/**
* @see {renameCostume}
*/
renameSound(soundIndex: number, name: string): void;
/**
* @see {deleteCostume}
*/
deleteSound(soundIndex: number): Sound | null;
/**
* @see {reorderCostume}
*/
reorderSound(soundIndex: number, newIndex: number): boolean;
/**
* Visual effects on the target. All default to 0.
*/
effects: Record;
/**
* Update the value of an effect.
* @param effectName
* @param value
*/
setEffect(effectName: Effect, value: number): void;
clearEffects(): void;
isTouchingObject(object: '_mouse_' | '_edge_' | string): boolean;
isTouchingPoint(x: number, y: number): boolean;
isTouchingEdge(): boolean;
isTouchingSprite(spriteName: string): boolean;
/**
* @param rgb RGB channels from [0-255]
*/
isTouchingColor(rgb: [number, number, number]): boolean;
/**
* @param rgb RGB channels from [0-255]
* @param mask RGB channels from [0-255]
*/
colorIsTouchingColor(rgb: [number, number, number], mask: [number, number, number]): boolean;
getLayerOrder(): IfRenderer;
/**
* Make sure this target is not the stage before calling this method.
*/
goToFront(): void;
/**
* Make sure this target is not the stage before calling this method.
*/
goToBack(): void;
/**
* Make sure this target is not the stage before calling this method.
*/
goForwardLayers(layers: number): void;
/**
* Make sure this target is not the stage before calling this method.
*/
goBackwardLayers(layers: number): void;
/**
* Make sure this target and the target being moved behind are not the stage before calling this method.
*/
goBehindOther(other: RenderedTarget): void;
/**
* Defaults to 100.
*/
volume: number;
tempo: number;
videoTransparency: number;
/**
* Create a clone of this sprite if the clone limit has not been reached.
*/
makeClone(): RenderedTarget | null;
duplicate(): Promise;
startDrag(): void;
stopDrag(): void;
/**
* Called by the runtime when the project is stopped.
*/
onStopAll(): void;
updateAllDrawableProperties(): void;
toJSON(): SerializedTarget;
}
// These types are intended for use in a browser environment where a base Target can never be created as
// all targets are RenderedTarget.
type Target = RenderedTarget;
interface SerializedTarget {
// TODO
}
interface StackFrame {
isLoop: boolean;
warpMode: boolean;
justReported: unknown;
reporting: string;
reported: unknown;
/** @deprecated unused */
waitingReporter: unknown;
params: unknown;
executionContext: unknown;
reset(): void;
}
interface BlockUtility {
sequencer: Sequencer;
thread: Thread;
_nowObj: {
now(): number;
};
nowObj: BlockUtility['_nowObj'],
target: Target;
runtime: Runtime;
stackFrame: StackFrame;
stackTimerFinished(): boolean;
stackTimerNeedsInit(): boolean;
startStackTimer(milliseconds: number): void;
yield(): void;
yieldTick(): void;
startBranch(branchNumber: number, isLoop: boolean): void;
/**
* @see {Runtime.stopAll}
*/
stopAll(): void;
/**
* @see {Runtime.stopForTarget}
*/
stopOtherTargetThreads(): void;
/**
* @see {Thread.stopThisScript}
*/
stopThisScript(): void;
/**
* @see {Blocks.getProcedureParamNamesAndIds}
*/
getProcedureParamNamesAndIds(): [string[], string[]];
/**
* @see {Blocks.getProcedureParamNamesIdsAndDefaults}
*/
getProcedureParamNamesIdsAndDefaults(): [string[], string[], string[]];
/**
* @see {Thread.initParams}
*/
initParams(): void;
/**
* @see {Thread.pushParam}
*/
pushParam(name: string, value: ScratchCompatibleValue): void;
/**
* @see {Thread.getParam}
*/
getParam(name: string): ScratchCompatibleValue;
/**
* Use instead of runtime.startHats inside blocks.
* @see {Runtime.startHats}
*/
startHats: Runtime['startHats'];
ioQuery(device: Device, func: keyof IODevices[Device], args: unknown[]): unknown;
}
const enum ThreadStatus {
STATUS_RUNNING = 0,
STATUS_PROMISE_WAIT = 1,
STATUS_YIELD = 2,
STATUS_YIELD_TICK = 3,
STATUS_DONE = 4
}
interface Thread {
topBlock: string;
stack: string[];
stackFrames: StackFrame[];
status: ThreadStatus;
isKilled: boolean;
target: Target;
blockContainer: Blocks;
requestScriptGlowInFrame: boolean;
blockGlowInFrame: string | null;
warpTimer: Timer | null;
justReported: unknown;
reuseStackForNextBlock(blockId: string): void;
pushStack(blockId: string): void;
popStack(): string;
peekStack(): string;
peekStackFrame(): StackFrame | null;
peekParentStackFrame(): StackFrame | null;
pushReportedValue(value: ScratchCompatibleValue): void;
initParams(): void;
pushParam(name: string, value: ScratchCompatibleValue): void;
getParam(name: string): ScratchCompatibleValue | null;
atStackTop(): boolean;
goToNextBlock(): void;
stopThisScript(): void;
isRecursiveCall(procedureCode: string): boolean;
stackClick: boolean;
updateMonitor: boolean;
}
interface HatInfo {
edgeActivated?: boolean;
restartExistingThreads?: boolean;
}
interface ExtensionInfo {
// TODO
}
interface Peripheral {
// TODO
}
interface ProfilerFrame {
id: number;
totalTime: number;
selfTime: number;
arg: unknown;
depth: number;
count: number;
}
type FrameCallback = (frame: ProfilerFrame) => void;
interface Profiler {
records: unknown[];
increments: ProfilerFrame[];
counters: ProfilerFrame[];
nullFrame: ProfilerFrame;
_stack: ProfilerFrame[];
onFrame: FrameCallback;
START: 0;
STOP: 1;
start(id: number, arg: unknown): void;
stop(): void;
increment(id: number): void;
frame(id: string, arg: unknown): ProfilerFrame;
reportFrames(): void;
idByName(name: string): number;
nameById(id: number): string;
}
interface Sequencer {
timer: Timer;
runtime: Runtime;
activeThread: Thread | null;
stepThreads(): void;
stepThread(thread: Thread): void;
stepToBranch(thread: Thread, branch: number, isLoop: boolean): void;
stepToProcedure(thread: Thread, procedureCode: string): void;
retireThread(thread: Thread): void;
}
interface ImportedExtensionsInfo {
extensionIDs: string[];
extensionURLs: string[];
}
interface ExtensionManager {
runtime: Runtime;
refreshBlocks(): Promise;
isExtensionLoaded(extensionID: string): boolean;
/**
* Load a builtin extension.
* Logs a warning if the extension is already loaded or could not be found.
*/
loadExtensionIdSync(extensionID: string): void;
/**
* Load a remote extension. Does not work on scratch.mit.edu.
*/
loadExtensionURL(extensionID: string): Promise;
}
/**
* Timer operates on milliseconds.
*/
interface Timer {
startTime: number;
time(): number;
relativeTime(): number;
start(): void;
timeElapsed(): number;
/**
* @see {window.setTimeout}
*/
setTimeout(callback: () => void, timeoutMS: number): number;
/**
* @see {window.clearTImeout}
*/
clearTimeout(timeoutID: number): void;
}
interface Clock {
_projectTimer: Timer;
_paused: boolean;
_pausedTime: number | null;
runtime: Runtime;
/**
* Project's current time in seconds.
*/
projectTimer(): number;
pause(): void;
resume(): void;
resetProjectTimer(): void;
}
interface CloudProvider {
createVariable(name: string, value: ScratchCompatibleValue): void;
updateVariable(name: string, value: ScratchCompatibleValue): void;
renameVariable(oldName: string, newName: string): void;
deleteVariable(name: string): void;
requestCloseConnection(): void;
}
interface CloudVariableUpdate {
name: string;
value: ScratchCompatibleValue;
}
interface CloudData {
varUpdate: CloudVariableUpdate;
}
interface Cloud {
runtime: Runtime;
provider: CloudProvider | null;
setProvider(provider: CloudProvider | null): void;
stage: Target | null;
setStage(stage: Target | null): void;
postData(data: CloudData): void;
requestCreateVariable(variable: ScalarVariable): void;
requestUpdateVariable(name: string, value: ScratchCompatibleValue): void;
requestRenameVariable(oldName: string, newName: string): void;
requestDeleteVariable(name: string): void;
updateCloudVariable(varUpdate: CloudVariableUpdate): void;
clear(): void;
}
interface KeyboardData {
key: string;
isDown: boolean;
}
interface Keyboard {
runtime: Runtime;
postData(data: KeyboardData): void;
_keyStringToScratchKey(key: string): string;
_keyArgToScratchKey(key: string | number): string;
getKeyIsDown(key: string | number): boolean;
}
interface MouseData {
x?: number;
y?: number;
canvasWidth?: number;
canvasHeight?: number;
isDown?: boolean;
}
interface Mouse {
runtime: Runtime;
_clientX: number;
_clientY: number;
getClientX(): number;
getClientY(): number;
_scratchX: number;
_scratchY: number;
getScratchX(): number;
getScratchY(): number;
_isDown: boolean;
getIsDown(): boolean;
postData(data: MouseData): void;
_activateClickHats(target: Target): void;
_pickTarget(x: number, y: number): Target;
}
interface MouseWheelData {
deltaY: number;
}
interface MouseWheel {
runtime: Runtime;
postData(data: MouseWheelData): void;
}
interface UserDataData {
username: string;
}
interface UserData {
_username: string;
getUsername(): string;
postData(data: UserDataData): void;
}
interface VideoProvider {
// TODO
}
interface VideoData {
// TODO
}
interface Video {
// TODO
postData(data: VideoData): void;
}
interface IODevices {
clock: Clock;
cloud: Cloud;
keyboard: Keyboard;
mouse: Mouse;
mouseWheel: MouseWheel;
userData: UserData;
video: Video;
}
interface RuntimeAndVirtualMachineEventMap {
SCRIPT_GLOW_ON: [{
id: string;
}];
SCRIPT_GLOW_OFF: [{
id: string;
}];
BLOCK_GLOW_ON: [{
id: string;
}];
BLOCK_GLOW_OFF: [{
id: string
}];
PROJECT_START: [{
id: string;
value: string;
}];
PROJECT_RUN_START: [];
PROJECT_RUN_STOP: [];
PROJECT_CHANGED: [];
VISUAL_REPORT: [{
id: string;
value: string;
}];
MONITORS_UPDATE: [OrderedMap];
BLOCK_DRAG_UPDATE: [
// Are blocks over GUI?
boolean
];
BLOCK_DRAG_END: [
// Blocks being dragged to the GUI
unknown[],
// Original ID of top block being dragged
string
];
EXTENSION_ADDED: [ExtensionInfo];
EXTENSION_FIELD_ADDED: [{
name: string;
implementation: unknown;
}];
BLOCKSINFO_UPDATE: [ExtensionInfo];
// TODO: is this number or string?
PERIPHERAL_LIST_UPDATE: [Record];
// TODO: is this number or string?
USER_PICKED_PERIPHERAL: [Record];
PERIPHERAL_CONNECTED: [];
PERIPHERAL_DISCONNECTED: [];
PERIPHERAL_REQUEST_ERROR: [{
message: string;
extensionId: string;
}];
PERIPHERAL_CONNECTION_LOST_ERROR: [{
message: string;
extensionId: string;
}];
PERIPHERAL_SCAN_TIMEOUT: [];
MIC_LISTENING: [
// Is the mic listening?
boolean
];
RUNTIME_STARTED: [];
RUNTIME_STOPPED: [];
HAS_CLOUD_DATA_UPDATE: [
// Has cloud data?
boolean
];
}
interface RuntimeEventMap extends RuntimeAndVirtualMachineEventMap {
PROJECT_STOP_ALL: [];
STOP_FOR_TARGET: [
// Target whose scripts are being stopped
Target,
// Optional thread exception to keep running
Thread | undefined
];
PROJECT_LOADED: [];
RUNTIME_DISPOSED: [];
TARGETS_UPDATE: [
// Whether to emit project changed
boolean
];
BLOCKS_NEED_UPDATE: [];
TOOLBOX_EXTENSIONS_NEED_UPDATE: [];
targetWasCreated: [
// The new target
Target,
// The original target, if any. This will be set for clones.
Target?
];
targetWasRemoved: [Target];
SAY: [Target, 'say' | 'think', string];
QUESTION: [string | null];
ANSWER: [string];
}
interface Runtime extends EventEmitter {
/**
* Start the runtime's event loop. This doesn't start any scripts.
*/
start(): void;
/**
* Stop all timers.
*/
quit(): void;
/**
* Start "when green flag pressed" scripts.
*/
greenFlag(): void;
/**
* Press the stop sign.
*/
stopAll(): void;
/**
* The event loop function.
*/
_step(): void;
turboMode: boolean;
/**
* If true, the runtime is running at 60 FPS. If false, the runtime is running at 30 FPS.
*/
compatibilityMode: boolean;
renderer: IfRenderer;
attachRenderer(renderer: RenderWebGL): void;
audioEngine: IfAudioEngine;
attachAudioEngine(audioEngine: AudioEngine): void;
v2BitmapAdapter?: ScratchSVGRenderer.BitmapAdapter;
attachV2BitmapAdapter(bitmapAdapter: ScratchSVGRenderer.BitmapAdapter): void;
storage: IfGui;
attachStorage(storage: ScratchStorage): void;
targets: Target[];
executableTargets: Target[];
addTarget(target: Target): void;
moveExecutable(target: Target, delta: number): void;
setExecutablePosition(target: Target, newIndex: number): void;
removeExecutable(target: Target): void;
disposeTarget(target: Target): void;
stopForTarget(target: Target): void;
/**
* Returns the target that is the stage.
* Returns undefined if called before the project has loaded or if the stage has somehow been removed.
*/
getTargetForStage(): Target | undefined;
/**
* Look up a target by its ID.
* Returns undefined if the target doesn't exist.
*/
getTargetById(targetId: string): Target | undefined;
/**
* Find a sprite's original target (not a clone or stage) using the sprite's name.
* Returns undefined if the target doesn't exist.
*/
getSpriteTargetByName(spriteName: string): Target | undefined;
/**
* Look up a target by it's drawable ID.
* Returns undefined if the target doesn't exist.
*/
getTargetByDrawableId(drawableID: number): Target | undefined;
/**
* Emit a targetWasCreated event.
*/
fireTargetWasCreated(newTarget: Target, oldTarget?: Target): void;
/**
* Emit a targetWasRemoved event.
*/
fireTargetWasRemoved(target: Target): void;
threads: Thread[];
_pushThread(topBlockId: string, target: Target, options?: {
stackClick?: boolean;
updateMonitor?: boolean;
}): Thread;
_stopThread(thread: Thread): void;
_restartThread(thread: Thread): Thread;
/**
* A thread is considered active if it is in the thread list and is not STATUS_DONE.
*/
isActiveThread(thread: Thread): boolean;
/**
* A thread is considered waiting if:
* - It is in STATUS_PROMISE_WAIT, or
* - It is in STATUS_YIELD_TICK, or
* - It is not considered active
* @see {isActiveThread}
*/
isWaitingThread(thread: Thread): boolean;
_getMonitorThreadCount(threads: Thread[]): number;
startHats(opcode: string, matchFields?: Record, target?: Target): Thread[] | undefined;
toggleScript(topBlockId: string, options?: {
target?: string;
stackClick?: boolean;
}): void;
allScriptsDo(callback: (blockId: string, target: Target) => void, target?: Target): void;
allScriptsByOpcodeDo(opcode: string, callback: (script: RuntimeScriptCache, target: Target) => void, target?: Target): void;
sequencer: Sequencer;
flyoutBlocks: Blocks;
monitorBlocks: Blocks;
visualReport(blockId: string, value: any): void;
_primitives: Record;
getOpcodeFunction(opcode: string): Function;
getLabelForOpcode(opcode: string): {
category: 'extension';
label: string;
} | undefined;
getBlocksXML(target?: Target): Array<{
id: string;
xml: string;
}>;
_blockInfo: ExtensionInfo[];
_hats: Record;
getIsHat(opcode: string): boolean;
getIsEdgeActivatedHat(opcode: string): boolean;
_cloneCounter: number;
changeCloneCounter(changeAmount: number): void;
clonesAvailable(): boolean;
/**
* The time of a step, measured in milliseconds. null if accessed before the project has started.
*/
currentStepTime: number | null;
/**
* Interval ID returned by setInterval(). null if accessed before the project has started.
*/
_steppingInterval: number | null;
redrawRequested: boolean;
requestRedraw(): void;
currentMSecs: number;
updateCurrentMSecs(): void;
ioDevices: IODevices;
/**
* Returns true if the runtime's cloud variable counter is non-zero.
*/
hasCloudData(): boolean;
/**
* Returns true if the runtime's cloud variable counter is under the limit.
*/
canAddCloudVariable(): boolean;
/**
* Returns the value of the runtime's cloud variable counter.
*/
getNumberOfCloudVariables(): number;
/**
* Increment the value of the runtime's cloud variable counter.
* Check the value before you call this method; it will let the counter go above the limit.
* This method does not actually create a new cloud variable.
*/
addCloudVariable(): void;
/**
* Decrement the value of the runtime's cloud variable counter.
* Check the value before you call this method; it will let the counter go under 0.
* This method does not actually remove a cloud variable.
*/
removeCloudVariable(): void;
createNewGlobalVariable(variableName: string): ScalarVariable;
createNewGlobalVariable(variableName: string, variableId: string): ScalarVariable;
createNewGlobalVariable(variableName: string, variableId: string, type: ''): ScalarVariable;
createNewGlobalVariable(variableName: string, variableId: string, type: 'list'): ListVariable;
createNewGlobalVariable(variableName: string, variableId: string, type: 'broadcast_msg'): BroadcastVariable;
getAllVarNamesOfType(variableType: VariableType): string[];
origin: string | null;
/**
* Remove everything from the Runtime.
*/
dispose(): void;
requestTargetsUpdate(target: Target): void;
requestBlocksUpdate(): void;
requestToolboxExtensionsUpdate(): void;
emitProjectLoaded(): void;
emitProjectChanged(): void;
_editingTarget: Target | null;
getEditingTarget(): Target | null;
setEditingTarget(target: Target): void;
scanForPeripheral(extensionID: string): void;
connectPeripheral(extensionID: string, peripheralId: number): void;
disconnectPeripheral(extensionID: string): void;
getPeripheralIsConnected(extensionID: string): boolean;
profiler: Profiler | null;
enableProfiling(callback: (profilerFrame: ProfilerFrame) => void): void;
disableProfiling(): void;
}
interface VirtualMachineEventMap extends RuntimeAndVirtualMachineEventMap {
TURBO_MODE_ON: [];
TURBO_MODE_OFF: [];
targetsUpdate: [{
targetList: SerializedTarget[];
editingTarget: string | null;
}];
workspaceUpdate: [{
xml: string;
}];
playgroundData: [{
blocks: Blocks;
// Stringified JSON of Thread[]
thread: string;
}];
}
}
declare class VM extends EventEmitter {
constructor();
runtime: VM.Runtime;
renderer: VM.IfRenderer;
/**
* @see {VM.Runtime.attachRenderer}
*/
attachRenderer(renderer: RenderWebGL): void;
/**
* @see {VM.Runtime.attachAudioEngine}
*/
attachAudioEngine(audioEngine: AudioEngine): void;
/**
* @deprecated Does nothing.
*/
attachV2SVGAdapter(): void;
/**
* @see {VM.Runtime.attachV2BitmapAdapter}
*/
attachV2BitmapAdapter(bitmapAdapter: ScratchSVGRenderer.BitmapAdapter): void;
/**
* @see {VM.Runtime.attachStorage}
*/
attachStorage(storage: ScratchStorage): void;
extensionManager: VM.ExtensionManager;
/**
* @see {VM.Runtime.start}
*/
start(): void;
/**
* @see {VM.Runtime.quit}
*/
quit(): void;
/**
* @see {VM.Runtime.greenFlag}
*/
greenFlag(): void;
/**
* Changes whether the runtime is in turbo mode or not.
* Emits either TURBO_MODE_ON or TURBO_MODE_OFF.
* @param turboMode whether turbo mode should be enabled
*/
setTurboMode(turboMode: boolean): void;
/**
* Changes whether the runtime is in "compatibility mode" (true by default)
* Compatibility mode sets the runtime's framerate to 30 FPS. Disabling it sets the framerate to 60 FPS.
* @param compatibilityMode
*/
setCompatibilityMode(compatibilityMode: boolean): void;
/**
* @see {Runtime.stopAll}
*/
stopAll(): void;
/**
* Remove everything from the VM.
*/
clear(): void;
/**
* Load a project.
* @param input Compressed sb, sb2, sb3 or sb2 project.json or sb3 project.json.
*/
loadProject(input: ArrayBufferView | ArrayBuffer | string | object): Promise;
/**
* Load a project usings its ID from scratch.mit.edu.
*/
downloadProjectId(id: string | number): Promise;
deserializeProject(json: object, zip?: JSZip): Promise;
installTargets(targets: VM.Target[], extensions: VM.ImportedExtensionsInfo, wholeProject: boolean): Promise;
/**
* @deprecated
* @see {loadProject}
*/
fromJSON(input: ArrayBufferView | ArrayBuffer | string | object): Promise;
/**
* the project to a compressed sb3 file.
*/
saveProjectSb3(): Promise;
toJSON(targetId?: string): string;
/**
* @see {VM.Runtime.getEditingTarget}
*/
editingTarget: VM.Target | null;
/**
* Change the editing target. If a target with the ID doesn't exist, silently does nothing.
* @see {VM.Runtime.setEditingTarget}
*/
setEditingTarget(targetId: string): void;
getTargetIdForDrawableId(drawableId: number): string | null;
/**
* Updates the value of a variable.
* Returns true if the target and variable were successfully found and updated, otherwise null.
*/
setVariableValue(targetId: string, variableId: string, value: VM.VariableValue): boolean;
getVariableValue(targetId: string, variableId: string): VM.VariableValue | null;
assets: ScratchStorage.Asset[];
/**
* Export a specific sprite to a compressed sprite3 file.
* @param targetId The ID of the target
*/
exportSprite(targetId: string): Promise;
exportSprite(targetId: string, zipType: string): Promise;
/**
* Gets the string representation of a costume.
* For an SVG costume, returns the text.
* For a PNG or JPG costume, returns a data URL.
* If costume doesn't exist, returns null.
*/
getCostume(costumeIndex: number): string | null;
getSoundBuffer(soundIndex: number): AudioBuffer | null;
/**
* Loads a sprite from a compressed .sprite2 or .sprite3 or JSON.
*/
addSprite(data: ArrayBufferView | ArrayBuffer | string | object): Promise;
addCostume(md5ext: string, costume?: VM.Costume, targetId?: string, version?: 2): Promise;
addCostumeFromLibrary(md5ext: string, costume: VM.Costume): Promise;
addBackdrop(md5ext: string, costume?: VM.Costume): Promise;
addSound(sound: VM.Sound, targetId?: string): Promise;
duplicateSprite(targetId: string): Promise;
duplicateCostume(costumeIndex: number): Promise;
duplicateSound(soundIndex: number): Promise;
updateSvg(costumeIndex: number, svg: string, rotationCenterX: number, rotationCenterY: number): void;
updateBitmap(costumeIndex: number, bitmap: ImageData, rotationCenterX: number, rotationCenterY: number, bitmapResolution: number): void;
/**
* Update a sound.
* @param soundIndex The index of the sound in the current sprite
* @param buffer The new audio data
* @param encodedWAV The data of an encoded WAV. If not provided, the new sound won't be saved if the project is exported.
*/
updateSoundBuffer(soundIndex: number, buffer: AudioBuffer, encodedWAV?: ArrayBuffer): void;
reorderTarget(targetId: string, newIndex: number): boolean;
reorderCostume(targetId: string, costumeIndex: number, newIndex: number): boolean;
reorderSound(targetId: string, soundIndex: number, newIndex: number): boolean;
renameSprite(targetId: string, newName: string): void;
renameCostume(costumeIndex: number, newName: string): void;
renameSound(soundIndex: number, newName: string): void;
/**
* Deletes the target with the given ID and any of its clones.
* @returns If a sprite was deleted, returns a function to undo the deletion.
*/
deleteSprite(targetId: string): (() => void) | null;
/**
* Deletes the costume at a given index int he editing target.
* @returns If a costume was deleted, returns a function to undo the deletion.
*/
deleteCostume(costumeIndex: number): (() => void) | null;
/**
* Deletes the sound at a given index in the editing target.
* @returns If a sound was deleted, returns a function to undo the deletion.
*/
deleteSound(soundIndex: number): (() => void) | null;
/**
* Returns a promise that resolves when all required extensions have been imported.
*/
shareBlocksToTarget(blocks: VM.Block[], targetId: string, fromTargetId?: string): Promise;
/**
* Share a costume from the editing target to another target.
*/
shareCostumeToTarget(costumeIndex: number, targetId: string): Promise;
/**
* Share a sound from the editing target to another target.
*/
shareSoundToTarget(soundIndex: number, targetId: string): Promise;
refreshWorkspace(): void;
/**
* Emit a targetsUpdate event about the current target information.
* @param shouldTriggerProjectChange Whether a PROJECT_CHANGED event should be emitted. Defaults to true.
*/
emitTargetsUpdate(shouldTriggerProjectChange?: boolean): void;
/**
* Emit a workspaceUpdate event.
*/
emitWorkspaceUpdate(): void;
/**
* Post sprite info to the target that's being dragged, otherwise the editing target.
* @see {VM.Target.postSpriteInfo}
*/
postSpriteInfo(spriteInfo: VM.PostedSpriteInfo): void;
/**
* The target that's currently being dragged, if any.
*/
_dragTarget: VM.Target | null;
startDrag(targetId: string): void;
stopDrag(targetId: string): void;
postIOData(device: 'cloud', data: VM.CloudData): void;
postIOData(device: 'keyboard', data: VM.KeyboardData): void;
postIOData(device: 'mouse', data: VM.MouseData): void;
postIOData(device: 'mouseWheel', data: VM.MouseWheelData): void;
postIOData(device: 'userData', data: VM.UserDataData): void;
postIOData(device: 'video', data: VM.VideoData): void;
setVideoProvider(videoProvider: VM.VideoProvider): void;
setCloudProvider(cloudProvider: VM.CloudProvider): void;
/**
* @see {VM.Runtime.scanForPeripheral}
*/
scanForPeripheral(extensionID: string): void;
/**
* @see {VM.Runtime.connectPeripheral}
*/
connectPeripheral(extensionID: string, peripheralId: number): void;
/**
* @see {VM.Runtime.disconnectPeripheral}
*/
disconnectPeripheral(extensionID: string): void;
/**
* @see {VM.Runtime.getPeripheralIsConnected}
*/
getPeripheralIsConnected(extensionID: string): boolean;
}