GUI API Reference
The MistWarp GUI provides programmatic access to interface components, themes, project management, and VM integration. This API is primarily used by extensions, addons, and advanced integrations.
Core GUI Instance
Redux Store Access
The GUI state is managed through Redux and is accessible via the global store:
// Access the Redux store (note: capital R in ReduxStore)
const store = window.ReduxStore;
// Get current state
const state = store.getState();
// Access different parts of the GUI state
const projectState = state.scratchGui.projectState;
const targets = state.scratchGui.targets;
const projectChanged = state.scratchGui.projectChanged;
ScratchBlocks Integration
window.ScratchBlocks
Access to the ScratchBlocks/Blockly workspace when available:
// Access ScratchBlocks when available
const ScratchBlocks = window.ScratchBlocks;
if (ScratchBlocks) {
// Access the main workspace
const workspace = ScratchBlocks.getMainWorkspace();
// Get all blocks in workspace
const blocks = workspace.getAllBlocks();
}
Loading ScratchBlocks
ScratchBlocks is loaded lazily by the GUI. It becomes available when the blocks tab is opened:
// ScratchBlocks is available after blocks are loaded
if (window.ScratchBlocks) {
console.log('ScratchBlocks is available');
} else {
console.log('ScratchBlocks not yet loaded');
}
State Management
Redux State Access
Access and modify GUI state through the Redux store:
// Get current state
const state = store.getState();
// Get current theme
const currentTheme = state.scratchGui.theme.theme;
// Dispatch actions to change state
store.dispatch({
type: 'scratch-gui/theme/SET_THEME',
theme: 'dark'
});
// Available themes
const themes = ['light', 'dark', 'midnight'];
State Structure
The Redux state contains various GUI-related data:
const guiState = {
// Project state
projectState: state.scratchGui.projectState,
// Theme information
theme: state.scratchGui.theme,
// VM instance
vm: state.scratchGui.vm,
// Project title and metadata
projectTitle: state.scratchGui.projectTitle,
projectChanged: state.scratchGui.projectChanged
};
Common Actions
Dispatch common GUI actions:
// Set editing target
store.dispatch({
type: 'scratch-gui/targets/SET_EDITING_TARGET',
targetId: 'sprite1'
});
// Set project title
store.dispatch({
type: 'scratch-gui/project-title/SET_PROJECT_TITLE',
title: 'My Project'
});
// Set project as changed
store.dispatch({
type: 'scratch-gui/project-changed/SET_PROJECT_CHANGED'
Project Management
Project State
Access project information through Redux:
const state = store.getState().scratchGui.projectState;
// Project properties
const projectId = state.projectId;
const loadingState = state.loadingState;
// Get project title from different location in state
const projectTitle = store.getState().scratchGui.projectTitle;
const hasUnsavedChanges = store.getState().scratchGui.projectChanged;
Project Actions
Project operations are typically handled by components rather than direct API calls:
// Project actions are handled through Redux reducers
// Most project operations require user interaction
// Example: Request new project (used internally)
store.dispatch({
type: 'scratch-gui/project-state/START_FETCHING_NEW'
});
// Project loading is typically handled by file upload components
// rather than direct API calls
VM Integration
Virtual Machine Access
Access the Scratch VM instance:
// Get VM instance from Redux state
const vm = store.getState().scratchGui.vm;
// Or access directly from global
const vm = window.vm;
// VM operations
vm.greenFlag(); // Start project
vm.stopAll(); // Stop project
vm.setTurboMode(true); // Enable turbo mode
// Load project data
await vm.loadProject(projectData);
Target Management
Manage sprites and stage:
// Get targets (sprites + stage)
const targets = vm.runtime.targets;
const stage = vm.runtime.getTargetForStage();
const sprites = vm.runtime.getSpriteTargets();
// Get editing target
const editingTarget = vm.editingTarget;
// Set editing target
vm.setEditingTarget(targetId);
Monitors
Control variable and list monitors:
// Get monitors
const monitors = vm.runtime._monitorState;
// Show/hide monitor
vm.requestAddMonitor({
id: 'variableId',
spriteName: null, // null for global
opcode: 'data_variable'
});
vm.requestRemoveMonitor('variableId');
GUI Components
Modal Management
Control modal dialogs:
// Open modals
store.dispatch({ type: 'scratch-gui/modals/OPEN_EXTENSION_LIBRARY' });
store.dispatch({ type: 'scratch-gui/modals/OPEN_COSTUME_LIBRARY' });
// Close modals
store.dispatch({ type: 'scratch-gui/modals/CLOSE_EXTENSION_LIBRARY' });
store.dispatch({ type: 'scratch-gui/modals/CLOSE_COSTUME_LIBRARY' });
Tab Management
Switch between editor tabs:
// Tab indices
const BLOCKS_TAB = 0;
const COSTUMES_TAB = 1;
const SOUNDS_TAB = 2;
// Activate tab
store.dispatch({
type: 'scratch-gui/editor-tab/ACTIVATE_TAB',
activeTabIndex: COSTUMES_TAB
});
Stage Size Control
Manage stage dimensions:
// Set stage size mode
store.dispatch({
type: 'scratch-gui/stage-size/SET_STAGE_SIZE',
stageSize: 'large' // 'small', 'large'
});
// Custom stage size
store.dispatch({
type: 'scratch-gui/custom-stage-size/SET_CUSTOM_STAGE_SIZE',
width: 480,
height: 360
});
Extension Integration
Custom Extensions
Load custom extensions:
// Load extension from URL
vm.extensionManager.loadExtensionURL('https://example.com/extension.js');
// Load extension from text
vm.extensionManager.loadExtensionFromText(extensionCode, 'extensionName');
Extension Library
Manage extension library visibility:
// Show extension library
store.dispatch({
type: 'scratch-gui/modals/OPEN_EXTENSION_LIBRARY'
});
// Handle extension selection
const handleExtensionSelect = (extensionId) => {
vm.extensionManager.loadExtensionIdSync(extensionId);
};
Event Handling
GUI Events
Listen to GUI state changes:
// Subscribe to store changes
const unsubscribe = store.subscribe(() => {
const state = store.getState();
// Handle state changes
});
// Unsubscribe when done
unsubscribe();
VM Events
Listen to VM events:
// Project events
vm.on('PROJECT_LOADED', () => {
console.log('Project loaded');
});
vm.on('PROJECT_CHANGED', () => {
console.log('Project modified');
});
// Target events
vm.on('targetsUpdate', (data) => {
console.log('Targets updated:', data.targetList);
});
// Monitor events
vm.on('MONITORS_UPDATE', (monitors) => {
console.log('Monitors updated:', monitors);
});
Asset Management
Costume Operations
Manage sprite costumes:
// Add costume to target
vm.addCostume(costumeId, costume, targetId);
// Delete costume
vm.deleteCostume(costumeId);
// Set active costume
vm.setActiveCostume(targetId, costumeId);
Sound Operations
Manage sprite sounds:
// Add sound to target
vm.addSound(sound, targetId);
// Delete sound
vm.deleteSound(soundId);
// Play sound
vm.runtime.audioEngine.playSound(sound);
Performance Monitoring
Metrics Access
Access performance data:
// Runtime metrics
const metrics = vm.runtime.stats;
console.log('FPS:', metrics.fps);
console.log('Frame count:', metrics.frameCount);
// Workspace metrics
const workspaceMetrics = store.getState().scratchGui.workspaceMetrics;
Memory Usage
Monitor memory consumption:
// Check memory usage
if (performance.memory) {
console.log('Used heap:', performance.memory.usedJSHeapSize);
console.log('Total heap:', performance.memory.totalJSHeapSize);
}
Error Handling
Error Boundaries
Handle GUI errors:
// Set up error handling
window.addEventListener('error', (event) => {
console.error('GUI Error:', event.error);
});
// React error boundary
window.addEventListener('unhandledrejection', (event) => {
console.error('Unhandled Promise:', event.reason);
});
VM Error Handling
Handle VM runtime errors:
vm.on('RUNTIME_ERROR', (error) => {
console.error('VM Runtime Error:', error);
});
vm.on('COMPILE_ERROR', (error) => {
console.error('VM Compile Error:', error);
});
Development Tools
Debug Utilities
Access debugging features:
// Enable debug mode
window.DEBUG = true;
// Access internal components
window._gui = gui;
window._vm = vm;
window._blockly = blockly;
// Performance profiling
window.guiProfiler = {
startProfile: () => performance.mark('profile-start'),
endProfile: () => {
performance.mark('profile-end');
performance.measure('profile', 'profile-start', 'profile-end');
}
};
Redux DevTools
When Redux DevTools are available:
// Access Redux DevTools
const devTools = window.__REDUX_DEVTOOLS_EXTENSION__;
if (devTools) {
// DevTools are available
console.log('Redux DevTools detected');
}
Type Definitions
For TypeScript users:
interface GUIInstance {
store: ReduxStore;
getBlockly(): Promise<ScratchBlocks>;
getBlocklyEagerly(): Promise<ScratchBlocks>;
handleFileUpload(file: File): void;
setCustomTheme(theme: ThemeConfig): void;
}
interface ThemeConfig {
name: string;
gui: GUITheme;
blocks: BlockTheme;
accent: AccentTheme;
id: string;
}
interface VMInstance {
runtime: Runtime;
editingTarget: Target;
greenFlag(): void;
stopAll(): void;
loadProject(data: ArrayBuffer): Promise<void>;
setTurboMode(enabled: boolean): void;
}
Renderer API Access
Canvas Operations
Access to renderer canvas and coordinate conversion:
// Get canvas dimensions
const canvas = vm.renderer.canvas;
const width = canvas.width;
const height = canvas.height;
// Access native size
const nativeSize = vm.renderer._nativeSize; // [width, height]
// Extract pixel color at coordinates
const colorData = vm.renderer.extractColor(x, y, radius);
const pixelColor = colorData.color; // {r, g, b, a}
Layer Management
Control rendering layer ordering:
// Set layer group ordering
vm.renderer.setLayerGroupOrdering(['background', 'video', 'pen', 'sprite']);
// Access layer configuration
const layerGroups = vm.renderer._layerGroups;
Advanced Runtime APIs
Target Management
Access and manipulate sprites and stage:
// Get sprite by name
const sprite = vm.runtime.getSpriteTargetByName('Sprite1');
// Get stage target
const stage = vm.runtime.getTargetForStage();
// Delete sprite
vm.deleteSprite(targetId);
// Export sprite
const spriteBlob = await vm.exportSprite(targetId);
Project Operations
Save and load projects:
// Save project as SB3 blob
const projectBlob = await vm.saveProjectSb3();
// Load project from buffer
await vm.loadProject(arrayBuffer);
// Get project as JSON
const projectData = vm.toJSON();
Costume and Sound Management
Manage target assets:
// Delete costume by index
target.deleteCostume(costumeIndex);
// Get costume index by name
const index = target.getCostumeIndexByName('costume1');
// Delete sound by index
target.deleteSound(soundIndex);
// Access sprite sounds
const sounds = target.sprite.sounds;
Frame Rate Control
Control animation frame rate:
// Set unclamped frame rate
vm.runtime.frameLoop.framerate = 60;
vm.runtime.frameLoop._restart();
Advanced Thread Management
Thread Control
The VM runtime provides advanced thread management capabilities for controlling script execution:
// Get all active threads
const activeThreads = vm.runtime.threads;
// Check if a thread is active
const isActive = vm.runtime.isActiveThread(thread);
// Stop a specific thread
thread.stopThisScript();
// Restart a thread
vm.runtime._restartThread(thread);
// Push a new thread for execution
const newThread = vm.runtime._pushThread(blockId, target, options);
Thread Properties
Thread objects contain execution state and context:
// Thread properties
console.log(thread.topBlock); // Starting block ID
console.log(thread.target); // Target sprite/stage
console.log(thread.blockContainer); // Block container
console.log(thread.stack); // Execution stack
console.log(thread.stackFrames); // Stack frames
// Thread status constants
const Thread = vm.runtime.sequencer.constructor.prototype.constructor;
console.log(Thread.STATUS_RUNNING);
console.log(Thread.STATUS_YIELD);
console.log(Thread.STATUS_DONE);
Custom Thread Data Storage
Store custom data in thread context:
// Store data in thread
if (!thread.customStorage) thread.customStorage = {};
thread.customStorage['myKey'] = 'myValue';
// Retrieve stored data
const value = thread.customStorage?.['myKey'];
Thread Execution Control
Control thread stepping and execution:
// Manually step a thread
vm.runtime.sequencer.stepThread(thread);
// Control thread stepping
thread.dontStepJustThisOneTime = true; // Skip next step
// Force thread compilation (if compiler enabled)
if (thread.tryCompile) {
thread.tryCompile();
}
Script Monitoring
Monitor and track script execution:
// Create a thread registry for monitoring
const monitoredThreads = {};
// Register a thread for monitoring
monitoredThreads['myThreadId'] = thread;
// Check if monitored thread is running
const isRunning = vm.runtime.isActiveThread(monitoredThreads['myThreadId']);
// Get blocks in a thread's script
const topBlock = thread.topBlock;
const blocks = thread.blockContainer;
let currentBlock = blocks.getBlock(topBlock);
const blockIds = [];
while (currentBlock) {
blockIds.push(currentBlock.id);
currentBlock = currentBlock.next ? blocks.getBlock(currentBlock.next) : null;
}
Block Glow Control
Control visual feedback for blocks:
// Make a block glow
vm.runtime.glowBlock(blockId, true);
// Stop block glow
vm.runtime.glowBlock(blockId, false);
// Quiet glow (internal use)
vm.runtime.quietGlow(blockId);
Script Management
Manage scripts and their execution:
// Toggle script on/off
vm.runtime.toggleScript(blockId, target);
// Get all scripts in a target
const scripts = target.blocks.getScripts();
// Add a new script
target.blocks._addScript(topBlockId);
// Delete a script
target.blocks._deleteScript(topBlockId);
Redux State Structure
GUI Mode Information
Access editor state through Redux:
const guiState = window.ReduxStore.getState().scratchGui;
// Check editor mode
const isEmbedded = guiState.mode?.isEmbedded;
const isPlayerOnly = guiState.mode?.isPlayerOnly;
const isFullscreen = guiState.mode?.isFullScreen;
const hasEverEnteredEditor = guiState.mode?.hasEverEnteredEditor;
// Get theme information
const currentTheme = guiState.theme?.theme;
Packaging Detection
Detect if running in packaged environment:
// Check if running in TurboWarp Packager
const isPackaged = !window.ReduxStore?.getState && !!window.scaffolding?.vm;
This API provides comprehensive access to MistWarp's GUI functionality while maintaining compatibility with the underlying Scratch architecture.
Block Manipulation
Advanced block management and manipulation:
// Get block by ID
const block = target.blocks.getBlock(blockId);
// Create a new block
target.blocks.createBlock(blockData);
// Delete a block
delete target.blocks._blocks[blockId];
// Get block's branch (substack)
const branchBlockId = target.blocks.getBranch(blockId, index);
// Get next block in sequence
const nextBlockId = target.blocks.getNextBlock(blockId);
// Clone block structure
function cloneBlock(blockId, target) {
const block = target.blocks.getBlock(blockId);
if (!block) return [];
let clonedBlocks = [block];
// Clone inputs
Object.values(block.inputs || {}).forEach(input => {
if (input.block) clonedBlocks.push(...cloneBlock(input.block, target));
if (input.shadow && input.shadow !== input.block) {
clonedBlocks.push(...cloneBlock(input.shadow, target));
}
});
// Clone field references
Object.values(block.fields || {}).forEach(field => {
if (field.id) clonedBlocks.push(...cloneBlock(field.id, target));
});
return clonedBlocks;
}
ScratchBlocks Integration
Work with the visual block editor:
// Get main workspace
const workspace = window.ScratchBlocks?.getMainWorkspace();
if (workspace) {
// Get all blocks in workspace
const allBlocks = workspace.getAllBlocks();
// Get blocks by type
const motionBlocks = allBlocks.filter(block => block.type.startsWith('motion_'));
// Set block warnings
const block = workspace.getBlockById(blockId);
if (block) {
block.setWarningText('Warning message', 'warningId');
block.setTooltip('Tooltip text');
}
// Listen for workspace updates
vm.on('workspaceUpdate', () => {
console.log('Workspace updated');
});
}
Runtime Hooks
Modify runtime behavior through hooks:
// Hook into block conversion for ScratchBlocks
const originalConvert = vm.runtime._convertBlockForScratchBlocks;
vm.runtime._convertBlockForScratchBlocks = function(blockInfo, categoryInfo) {
// Modify block info before conversion
if (blockInfo.customProperty) {
blockInfo.outputShape = 3; // Custom output shape
}
return originalConvert.call(this, blockInfo, categoryInfo);
};
// Hook into thread stepping
const sequencer = vm.runtime.sequencer;
const originalStep = sequencer.stepThread;
sequencer.stepThread = function(thread) {
// Custom logic before stepping
if (thread.skipThisStep) {
thread.skipThisStep = false;
return;
}
return originalStep.call(this, thread);
};