ble
免费Bluetooth context for the Megahub project. Use when working on BLE GATT server, Classic Bluetooth HID host, Web Bluetooth API integration, btremote library, connection handling, or any Bluetooth-related firmware code.
中文简介正在准备中。当前显示原文说明。
Blockly visual programming context for the Megahub project. Use when adding, modifying, or debugging custom Blockly blocks, the Lua code generator, the toolbox, block colors, or the BLOCKS.md documentation generation script.
中文简介正在准备中。当前显示原文说明。
查看安装方法安装前可以查看交给 AI 代理的指令内容。
blockly/lua)<custom-blockly> in frontend/src/components/blockly/component.jsBLOCKS.md is auto-generated via Puppeteerfrontend/src/components/blockly/
component.js Main component — init, toolbox, workspace, Lua generation
component.html Minimal web component template
colors.js Color hue constants for all categories (0–360)
mh_*.js 20 Megahub core blocks (motors, GPIO, threads, debug)
lego_*.js 2 LEGO Powered Up blocks
ui_*.js 1 UI display block
Every block is one file. All fields are required unless noted:
export const definition = {
category: 'Category Name', // Groups this block in the toolbox
colour: colorConstant, // Import from colors.js — never hardcode
blockdefinition: { // Standard Blockly JSON definition
type: 'mh_block_name', // Must match filename (minus .js)
message0: 'label %1 %2', // %N = input/field placeholders
args0: [ /* inputs */ ],
previousStatement: null, // Include for statement blocks
nextStatement: null, // Include for statement blocks
// OR: output: null // For value blocks that return a value
tooltip: 'Description for BLOCKS.md and hover UI',
helpUrl: ''
},
generator: (block, generator) => {
// Return string + "\n" for statement blocks
// Return [ "code", precedence ] for value blocks
},
inputsForToolbox: { /* optional shadow defaults */ }
};
generator: (block, generator) => {
const val = generator.valueToCode(block, 'VALUE', 0);
const stmt = generator.statementToCode(block, 'DO');
const field = block.getFieldValue('FIELD_NAME');
return `myFunction(${val}, ${field})\n`;
}
generator: (block, generator) => {
const val = block.getFieldValue('VALUE');
return [ val, 0 ]; // [ code, precedence ]
}
| Prefix | Category | Example |
|---|---|---|
mh_ | Megahub core | mh_set_motor_speed, mh_wait, mh_startthread |
lego_ | LEGO Powered Up | lego_get_mode_dataset, lego_select_mode |
ui_ | User interface | ui_show_value |
mh_wait.js → type: 'mh_wait')colors.js)Colors are Blockly hue values (0–360). Always import — never hardcode a number.
| Constant | Hue | Category |
|---|---|---|
colorControlFlow | 20 | Control flow |
colorLogic | 40 | Logic |
colorMath | 60 | Math |
colorText | 80 | Text |
colorLists | 100 | Lists |
colorIO | 120 | I/O |
colorLego | 140 | LEGO© |
colorGamepad | 160 | Gamepad |
colorFastLED | 180 | FastLED |
colorIMU | 200 | IMU |
colorUI | 220 | UI |
colorAlgorithms | 230 | Algorithms |
colorDebug | 240 | Debug |
frontend/src/components/blockly/mh_myblock.js using the pattern abovefrontend/src/components/blockly/component.js — add import + entry in customBlocksfrontend/scripts/block-renderer.js — add import + entry in customBlocksfrontend/scripts/generate-block-docs-simple.js — add dynamic import in blockModules + entry in customBlocksgenerateToolbox() groups by category fieldnpm run dev or npm testcd frontend
npm run generate-docs
This regenerates BLOCKS.md and all PNG images in docs/blocks/. Never skip this step.Every new block file must have a corresponding test file. This is a hard requirement.
Location: frontend/test/blockly/{block_type}.test.js
Test file must cover:
mh_startthread pattern) — both forms generate correct outputMinimal test pattern:
import { describe, it, expect } from 'vitest';
// Import the block definition
import { definition } from '../../../../src/components/blockly/mh_myblock.js';
describe('mh_myblock generator', () => {
it('generates correct Lua for basic case', () => {
const mockBlock = {
getFieldValue: (name) => name === 'MY_FIELD' ? 'VALUE' : '',
outputConnection: null,
};
const mockGenerator = {
valueToCode: (_b, _name, _prec) => '42',
};
const result = definition.generator(mockBlock, mockGenerator);
expect(result).toBe('myFunction(42, "VALUE")\n');
});
});
Run tests:
cd frontend
npm test
When to create tests: Immediately after creating the block file, before registering it in component.js. Tests run in CI — a block without tests is incomplete.
The component.js registration loop handles everything:
// Blockly block definition
Blockly.Blocks[type].init = function() { this.jsonInit(def.blockdefinition); }
// Lua generator
luaGenerator.forBlock[type] = (block) => def.generator(block, luaGenerator);
The workspace generates Lua code on every change:
// In component.js — called on workspace change events
generateLUAPreview() {
const code = luaGenerator.workspaceToCode(this.workspace);
// code is the complete Lua script
}
Generated Lua script structure (from mh_init and mh_startthread blocks):
hub.init(function()
-- initialization block contents
end)
hub.startthread('Thread Name', blockId, stackSize, false, function()
-- thread loop contents
end)
BLOCKS.md is automatically generated — never edit it manually.
Command:
cd frontend
npm run generate-docs
How it works (frontend/scripts/generate-block-docs-simple.js):
vite build to produce a renderer bundleblock-renderer.html which runs Blockly in the browserdocs/blocks/{category}/{blocktype}.pngOutput structure:
docs/blocks/
control flow/mh_init.png
lego©/lego_get_mode_dataset.png
...
BLOCKS.md ← regenerated in full
When to regenerate: after adding, removing, or changing any block definition, tooltip, inputs, or fields. The tooltip field in blockdefinition becomes the description in BLOCKS.md — keep it informative.
All stateful algorithm blocks in the Algorithms category follow an explicit handle pattern. This is a hard convention — never use block.id as an implicit state key.
A stateful algorithm requires two Blockly blocks:
mh_alg_*_init.js) — creates a filter/controller instance, returns a handle string. The user stores this in a variable.mh_alg_*.js) — takes the handle as first input, plus algorithm parameters.libluaalg.cpp)// State map keyed by handle string ("ma_0", "ma_1", ...)
static std::map<std::string, MyState> myStates;
static int myHandleCounter = 0;
// Init: creates instance, returns handle
int alg_init_my(lua_State* L) {
std::string handle = "my_" + std::to_string(myHandleCounter++);
myStates[handle] = MyState{};
lua_pushstring(L, handle.c_str());
return 1;
}
// Compute: looks up by handle
int alg_my(lua_State* L) {
const char* handle = luaL_checkstring(L, 1);
auto it = myStates.find(handle);
if (it == myStates.end()) {
WARN("alg_my: handle '%s' not found", handle);
lua_pushnumber(L, 0.0);
return 1;
}
// ... use it->second ...
}
// Clear all: called in alg_library() at init
int alg_clear_all_my(lua_State* L) {
myStates.clear();
myHandleCounter = 0;
return 0;
}
Register all three in alg_library(), and call alg_clear_all_my at the top of alg_library().
Init block — no inputs, output is a handle value:
generator: (block, generator) => {
return [`alg.initMy()`, 0];
},
Compute block — HANDLE is first input, uses variables_get shadow:
inputsForToolbox: {
HANDLE: {
shadow: { type: 'variables_get', fields: { VAR: { name: 'myFilter' } } },
},
// ... other inputs ...
},
generator: (block, generator) => {
const handle = generator.valueToCode(block, 'HANDLE', 0) || '"my_0"';
// ...
return [`alg.my(${handle}, ...)`, 0];
},
Both blocks must be added to all three registration files:
frontend/src/components/blockly/component.jsfrontend/scripts/block-renderer.jsfrontend/scripts/generate-block-docs-simple.jsalg.map)Stateless algorithms (no persistent state) need only one block, no handle, no init, no clearAll. Register only the single block file.
inputsForToolbox)To pre-populate inputs in the toolbox with useful defaults, add inputsForToolbox:
inputsForToolbox: {
VALUE: {
shadow: {
type: 'math_number',
fields: { NUM: 500 }
}
}
}
The generateToolbox() function reads this and adds <shadow> elements automatically.
还没有评价。欢迎分享你的使用感受。
无需登录即可发表。欢迎分享使用感受、提问,或说明在哪些环境下无法运行。
还没有评论。来写第一条吧。
Bluetooth context for the Megahub project. Use when working on BLE GATT server, Classic Bluetooth HID host, Web Bluetooth API integration, btremote library, connection handling, or any Bluetooth-related firmware code.
中文简介正在准备中。当前显示原文说明。
Documentation structure and maintenance rules for the Megahub project. Use whenever making user-facing changes — adding features, changing behavior, fixing hardware compatibility, or modifying configuration. Describes which files to update, the README structure, and writing style.
中文简介正在准备中。当前显示原文说明。
Core firmware context for the Megahub ESP32 project. Use when working on PlatformIO configuration, build scripts, library structure, main.cpp, or general ESP32 firmware development. Covers build system, project structure, common pitfalls, and debugging.
中文简介正在准备中。当前显示原文说明。
Frontend development context for the Megahub project. Use when working on the web-based IDE, Vite build system, Blockly visual programming, Web Bluetooth API integration, JavaScript frontend code, CSS/styles, UI components, or anything in the /frontend/ directory.
中文简介正在准备中。当前显示原文说明。
LEGO Powered Up protocol context for the Megahub project. Use when working on LEGO device communication, lpfuart library, UART parsing, motor control, sensor modes, device initialization, or debugging UART noise/corruption issues.
中文简介正在准备中。当前显示原文说明。
Code formatting and linting context for the Megahub project. Use when writing or reviewing code in C++ or JavaScript, or when running format/lint checks. Describes tool commands, style conventions, and when to apply them.
中文简介正在准备中。当前显示原文说明。