You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Music Blocks has an existing plugin system that allows developers to add new palettes and blocks via JSON-encoded plugin files (.json), without modifying core code. Plugins can define new blocks (BLOCKPLUGINS), flow logic (FLOWPLUGINS), argument blocks (ARGPLUGINS), macros (MACROPLUGINS), palette colors, and lifecycle hooks (ONLOAD, ONSTART, ONSTOP).
However, the current system has significant limitations that prevent complex integrations:
eval()-based execution — Block and global code is executed via eval(), which is broken on Chrome due to Content Security Policy (CSP) restrictions (unsafe-eval not allowed). There is an existing FIXME comment in js/utils/utils.js acknowledging this.
No structured plugin API — Plugins access internals (e.g., globalActivity, logo, turtle) directly with no stable, versioned API surface. This makes plugins fragile against core changes.
No plugin-to-plugin communication — There is no mechanism for plugins to declare dependencies on or communicate with other plugins.
No access to the music synthesis pipeline — Plugins cannot hook into the Tone.js-based audio synthesis pipeline, the Singer component, or the Turtle system in a structured way.
No widget creation from plugins — Plugins cannot add new widgets (like Phrase Maker, Rhythm Maker, etc.) to the UI.
No plugin versioning or metadata — There is no schema for plugin version, author, description, or compatibility information.
No async block support — Plugins have no clean way to define blocks with asynchronous behavior (e.g., fetching data, waiting for hardware).
Limited tooling — The pluginify.py tool converts .rtp to .json but provides no validation, testing harness, or developer feedback.
This project aims to redesign and expand the plugin API to address these limitations, enabling richer, more reliable, and more complex integrations.
Goals & Mid-Point Milestone
Goals
Replace eval()-based plugin execution with a CSP-compliant mechanism (e.g., using Function constructor with a sandboxed scope, or ES module dynamic imports via blob: URLs)
Design and implement a stable, versioned plugin API object that exposes controlled access to activity, logo, Singer, Turtles, and the block/palette systems
Add plugin metadata schema (name, version, author, description, Music Blocks compatibility range) and a loader that validates it
Implement plugin-to-plugin dependency declaration and a basic dependency resolution mechanism
Add support for async blocks in plugins (blocks that can pause execution and resume after a Promise resolves)
Enable plugins to register custom widgets in the UI
Update pluginify.py (or create a new JS/Node.js-based tool) with validation, linting, and a developer test harness
Write comprehensive documentation and at least two example plugins demonstrating the new API capabilities
Goals Achieved By Mid-point Milestone:
CSP-compliant execution mechanism implemented and tested on Chrome and Firefox
Stable plugin API object designed and documented, with controlled access to core subsystems
Plugin metadata schema defined and enforced by the loader
At least one existing plugin (e.g., rodi.json) migrated to the new API as a proof of concept
Setup/Installation
Clone the repository: git clone https://github.com/sugarlabs/musicblocks.git
Install dependencies: npm install
Run a local instance: npm run serve
Load an existing plugin (e.g., plugins/rodi.json) via the Load Plugin button in the secondary toolbar to understand the current system
Read plugins/README.md for plugin authoring documentation
Read js/utils/utils.js (processPluginData, processRawPluginData, updatePluginObj) for the current plugin loading pipeline
Read js/activity.js (doPluginsAndPaletteCols, _deletePlugin) for plugin lifecycle management
Expected Outcome
A CSP-compliant plugin execution engine that works on Chrome, Firefox, and other modern browsers without requiring unsafe-eval
A documented, stable MusicBlocksPluginAPI object that plugins use instead of accessing globalActivity directly, providing controlled access to blocks, palettes, the Singer/Turtle music pipeline, and UI widgets
A plugin metadata format (JSON schema) that includes versioning and compatibility information, validated at load time
Support for async blocks in plugins, enabling hardware integrations (like the existing rodi robot plugin) and network-dependent blocks to work cleanly
The ability for plugins to register custom widgets alongside the built-in ones (Phrase Maker, Rhythm Maker, etc.)
An updated or new developer toolchain (pluginify tool) with validation and a test harness
At least two fully working example plugins demonstrating the new capabilities
All existing plugins (rodi.json, maths.json, nutrition.json) migrated to or verified compatible with the new API
Acceptance Criteria
All existing plugins load and function correctly under the new system on Chrome and Firefox
No use of bare eval() remains in the plugin loading pipeline
The plugin API is documented with JSDoc and a developer guide
New plugins can be authored using only the public API object without needing to reference globalActivity directly
Async blocks work correctly: execution pauses and resumes without breaking the Logo interpreter's flow
Plugin metadata is validated at load time; invalid or incompatible plugins show a clear error message
At least one plugin registers a custom widget successfully
All changes pass the existing ESLint configuration and CI checks
Implementation Details
Current plugin loading pipeline (files to modify):
js/utils/utils.js — processPluginData() (lines 575–790): replace eval() calls for BLOCKPLUGINS, GLOBALS, and ONLOAD with a CSP-compliant alternative
js/activity.js — doPluginsAndPaletteCols() (lines 606–666) and _deletePlugin() (lines 2058–2114): update plugin object structure to include metadata
plugins/pluginify.py — extend or replace with a Node.js tool that validates against the new schema
CSP-compliant execution approach:
Use new Function(...) with an explicit scope object passed as arguments, or
Use dynamic import() with blob: URLs for ES module plugins (modern approach)
Investigate using a Web Worker sandbox for plugin execution isolation
Plugin API object design:
Ticket Contents
Description
Music Blocks has an existing plugin system that allows developers to add new palettes and blocks via JSON-encoded plugin files (.json), without modifying core code. Plugins can define new blocks (BLOCKPLUGINS), flow logic (FLOWPLUGINS), argument blocks (ARGPLUGINS), macros (MACROPLUGINS), palette colors, and lifecycle hooks (ONLOAD, ONSTART, ONSTOP).
However, the current system has significant limitations that prevent complex integrations:
eval()-based execution — Block and global code is executed via eval(), which is broken on Chrome due to Content Security Policy (CSP) restrictions (unsafe-eval not allowed). There is an existing FIXME comment in js/utils/utils.js acknowledging this.
No structured plugin API — Plugins access internals (e.g., globalActivity, logo, turtle) directly with no stable, versioned API surface. This makes plugins fragile against core changes.
No plugin-to-plugin communication — There is no mechanism for plugins to declare dependencies on or communicate with other plugins.
No access to the music synthesis pipeline — Plugins cannot hook into the Tone.js-based audio synthesis pipeline, the Singer component, or the Turtle system in a structured way.
No widget creation from plugins — Plugins cannot add new widgets (like Phrase Maker, Rhythm Maker, etc.) to the UI.
No plugin versioning or metadata — There is no schema for plugin version, author, description, or compatibility information.
No async block support — Plugins have no clean way to define blocks with asynchronous behavior (e.g., fetching data, waiting for hardware).
Limited tooling — The pluginify.py tool converts .rtp to .json but provides no validation, testing harness, or developer feedback.
This project aims to redesign and expand the plugin API to address these limitations, enabling richer, more reliable, and more complex integrations.
Goals & Mid-Point Milestone
Goals
Setup/Installation
Clone the repository: git clone https://github.com/sugarlabs/musicblocks.git
Install dependencies: npm install
Run a local instance: npm run serve
Load an existing plugin (e.g., plugins/rodi.json) via the Load Plugin button in the secondary toolbar to understand the current system
Read plugins/README.md for plugin authoring documentation
Read js/utils/utils.js (processPluginData, processRawPluginData, updatePluginObj) for the current plugin loading pipeline
Read js/activity.js (doPluginsAndPaletteCols, _deletePlugin) for plugin lifecycle management
Expected Outcome
A CSP-compliant plugin execution engine that works on Chrome, Firefox, and other modern browsers without requiring unsafe-eval
A documented, stable MusicBlocksPluginAPI object that plugins use instead of accessing globalActivity directly, providing controlled access to blocks, palettes, the Singer/Turtle music pipeline, and UI widgets
A plugin metadata format (JSON schema) that includes versioning and compatibility information, validated at load time
Support for async blocks in plugins, enabling hardware integrations (like the existing rodi robot plugin) and network-dependent blocks to work cleanly
The ability for plugins to register custom widgets alongside the built-in ones (Phrase Maker, Rhythm Maker, etc.)
An updated or new developer toolchain (pluginify tool) with validation and a test harness
At least two fully working example plugins demonstrating the new capabilities
All existing plugins (rodi.json, maths.json, nutrition.json) migrated to or verified compatible with the new API
Acceptance Criteria
All existing plugins load and function correctly under the new system on Chrome and Firefox
No use of bare eval() remains in the plugin loading pipeline
The plugin API is documented with JSDoc and a developer guide
New plugins can be authored using only the public API object without needing to reference globalActivity directly
Async blocks work correctly: execution pauses and resumes without breaking the Logo interpreter's flow
Plugin metadata is validated at load time; invalid or incompatible plugins show a clear error message
At least one plugin registers a custom widget successfully
All changes pass the existing ESLint configuration and CI checks
Implementation Details
Current plugin loading pipeline (files to modify):
js/utils/utils.js — processPluginData() (lines 575–790): replace eval() calls for BLOCKPLUGINS, GLOBALS, and ONLOAD with a CSP-compliant alternative
js/activity.js — doPluginsAndPaletteCols() (lines 606–666) and _deletePlugin() (lines 2058–2114): update plugin object structure to include metadata
plugins/pluginify.py — extend or replace with a Node.js tool that validates against the new schema
CSP-compliant execution approach:
Use new Function(...) with an explicit scope object passed as arguments, or
Use dynamic import() with blob: URLs for ES module plugins (modern approach)
Investigate using a Web Worker sandbox for plugin execution isolation
Plugin API object design:
// Proposed API surface exposed to plugins
const MusicBlocksPluginAPI = {
version: "1.0",
blocks: { register, addToPalette },
palettes: { add, update },
singer: { onNoteStart, onNoteEnd, registerInstrument },
turtles: { onTurtleStart, onTurtleStop },
widgets: { register },
i18n: { translate: _ },
storage: { get, set },
events: { on, emit }
};
Plugin metadata schema (new required field):
{
"METADATA": {
"name": "my-plugin",
"version": "1.0.0",
"author": "Developer Name",
"description": "What this plugin does",
"musicblocksVersion": ">=3.0"
}
}
Technologies: JavaScript (ES2020+), Node.js (for tooling), JSON Schema (for validation), Tone.js (for audio pipeline hooks), Web Workers (optional sandboxing)
Mockups/Wireframes
No response
Product Name
Music Blocks
Organisation Name
Sugar Labs
Domain
Education
Tech Skills Needed
JavaScript
Mentor(s)
@sum2it @walterbender @omsuneri
Category
Frontend