@fugood/bricks-project 2.23.0-beta.9 → 2.23.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. package/api/instance.ts +37 -5
  2. package/compile/action-name-map.ts +107 -0
  3. package/compile/index.ts +172 -66
  4. package/compile/util.ts +13 -4
  5. package/package.json +9 -5
  6. package/skills/bricks-project/SKILL.md +32 -0
  7. package/skills/bricks-project/rules/animation.md +159 -0
  8. package/skills/bricks-project/rules/architecture-patterns.md +62 -0
  9. package/skills/bricks-project/rules/automations.md +221 -0
  10. package/skills/bricks-project/rules/buttress.md +153 -0
  11. package/skills/bricks-project/rules/data-calculation.md +208 -0
  12. package/skills/bricks-project/rules/local-sync.md +129 -0
  13. package/skills/bricks-project/rules/media-flow.md +158 -0
  14. package/skills/bricks-project/rules/remote-data-bank.md +196 -0
  15. package/skills/bricks-project/rules/standby-transition.md +124 -0
  16. package/skills/rive-marketplace/SKILL.md +99 -0
  17. package/tools/deploy.ts +74 -12
  18. package/tools/icons/.gitattributes +1 -0
  19. package/tools/icons/fa6pro-glyphmap.json +4686 -0
  20. package/tools/icons/fa6pro-meta.json +26127 -0
  21. package/tools/mcp-server.ts +818 -9
  22. package/tools/postinstall.ts +75 -13
  23. package/tools/preview-main.mjs +54 -4
  24. package/tools/preview.ts +54 -7
  25. package/tools/pull.ts +37 -16
  26. package/types/automation.ts +232 -0
  27. package/types/brick-base.ts +1 -0
  28. package/types/bricks/Camera.ts +26 -10
  29. package/types/bricks/Chart.ts +1 -0
  30. package/types/bricks/GenerativeMedia.ts +21 -3
  31. package/types/bricks/Icon.ts +1 -0
  32. package/types/bricks/Image.ts +6 -0
  33. package/types/bricks/Items.ts +1 -0
  34. package/types/bricks/Lottie.ts +1 -0
  35. package/types/bricks/Maps.ts +254 -0
  36. package/types/bricks/QrCode.ts +1 -0
  37. package/types/bricks/Rect.ts +1 -0
  38. package/types/bricks/RichText.ts +1 -0
  39. package/types/bricks/Rive.ts +1 -0
  40. package/types/bricks/Slideshow.ts +1 -0
  41. package/types/bricks/Svg.ts +1 -0
  42. package/types/bricks/Text.ts +1 -0
  43. package/types/bricks/TextInput.ts +1 -0
  44. package/types/bricks/Video.ts +1 -0
  45. package/types/bricks/VideoStreaming.ts +1 -0
  46. package/types/bricks/WebRtcStream.ts +1 -0
  47. package/types/bricks/WebView.ts +8 -1
  48. package/types/bricks/index.ts +2 -0
  49. package/types/canvas.ts +1 -0
  50. package/types/common.ts +2 -0
  51. package/types/data-calc-command.ts +7003 -0
  52. package/types/data-calc-script.ts +21 -0
  53. package/types/data-calc.ts +3 -6977
  54. package/types/data.ts +3 -0
  55. package/types/generators/AlarmClock.ts +2 -0
  56. package/types/generators/Assistant.ts +30 -6
  57. package/types/generators/BleCentral.ts +2 -0
  58. package/types/generators/BlePeripheral.ts +2 -0
  59. package/types/generators/CanvasMap.ts +2 -0
  60. package/types/generators/CastlesPay.ts +2 -0
  61. package/types/generators/DataBank.ts +2 -0
  62. package/types/generators/File.ts +2 -0
  63. package/types/generators/GraphQl.ts +2 -0
  64. package/types/generators/Http.ts +84 -2
  65. package/types/generators/HttpServer.ts +5 -1
  66. package/types/generators/Information.ts +2 -0
  67. package/types/generators/Intent.ts +51 -0
  68. package/types/generators/Iterator.ts +11 -2
  69. package/types/generators/Keyboard.ts +2 -0
  70. package/types/generators/LlmAnthropicCompat.ts +2 -0
  71. package/types/generators/LlmAppleBuiltin.ts +144 -0
  72. package/types/generators/LlmGgml.ts +28 -4
  73. package/types/generators/LlmOnnx.ts +2 -0
  74. package/types/generators/LlmOpenAiCompat.ts +2 -0
  75. package/types/generators/LlmQualcommAiEngine.ts +2 -0
  76. package/types/generators/Mcp.ts +6 -4
  77. package/types/generators/McpServer.ts +8 -6
  78. package/types/generators/MediaFlow.ts +2 -0
  79. package/types/generators/MqttBroker.ts +2 -0
  80. package/types/generators/MqttClient.ts +2 -0
  81. package/types/generators/Question.ts +9 -0
  82. package/types/generators/RealtimeTranscription.ts +18 -8
  83. package/types/generators/RerankerGgml.ts +23 -16
  84. package/types/generators/SerialPort.ts +2 -0
  85. package/types/generators/SoundPlayer.ts +2 -0
  86. package/types/generators/SoundRecorder.ts +2 -0
  87. package/types/generators/SpeechToTextGgml.ts +19 -4
  88. package/types/generators/SpeechToTextOnnx.ts +2 -0
  89. package/types/generators/SpeechToTextPlatform.ts +2 -0
  90. package/types/generators/SqLite.ts +32 -1
  91. package/types/generators/Step.ts +2 -0
  92. package/types/generators/SttAppleBuiltin.ts +117 -0
  93. package/types/generators/Tcp.ts +2 -0
  94. package/types/generators/TcpServer.ts +5 -1
  95. package/types/generators/TextToSpeechApple.ts +113 -0
  96. package/types/generators/TextToSpeechAppleBuiltin.ts +114 -0
  97. package/types/generators/TextToSpeechGgml.ts +24 -3
  98. package/types/generators/TextToSpeechOnnx.ts +2 -0
  99. package/types/generators/TextToSpeechOpenAiLike.ts +2 -0
  100. package/types/generators/ThermalPrinter.ts +2 -0
  101. package/types/generators/Tick.ts +5 -1
  102. package/types/generators/TtsAppleBuiltin.ts +105 -0
  103. package/types/generators/Udp.ts +2 -0
  104. package/types/generators/VadGgml.ts +4 -2
  105. package/types/generators/VadOnnx.ts +201 -0
  106. package/types/generators/VadTraditional.ts +123 -0
  107. package/types/generators/VectorStore.ts +15 -2
  108. package/types/generators/Watchdog.ts +2 -0
  109. package/types/generators/WebCrawler.ts +2 -0
  110. package/types/generators/WebRtc.ts +4 -2
  111. package/types/generators/WebSocket.ts +2 -0
  112. package/types/generators/index.ts +5 -0
  113. package/types/index.ts +3 -0
  114. package/types/system.ts +48 -6
  115. package/utils/calc.ts +15 -9
  116. package/utils/data.ts +1 -0
  117. package/utils/event-props.ts +112 -2
  118. package/utils/id.ts +3 -1
package/compile/util.ts CHANGED
@@ -3,6 +3,7 @@ import { makeId } from '../utils/id'
3
3
  type ScriptConfig = {
4
4
  inputs: Record<string, string>
5
5
  enable_async: boolean
6
+ trigger_mode?: 'auto' | 'manual'
6
7
  disabled_triggers: Record<string, boolean>
7
8
  output: string | null
8
9
  outputs: Record<string, string[]>
@@ -13,6 +14,8 @@ type ScriptConfig = {
13
14
  const errorMsg = 'Not allow duplicate set property id between inputs / outputs / output / error.'
14
15
 
15
16
  export const validateConfig = (config: ScriptConfig) => {
17
+ // Skip input/output overlap validation in manual mode (allows same data node in both)
18
+ if (config.trigger_mode === 'manual') return
16
19
  if (config.error && config.inputs[config.error]) {
17
20
  throw new Error(`${errorMsg}. key: error`)
18
21
  }
@@ -87,7 +90,8 @@ export const generateCalulationMap = (config: ScriptConfig, opts?: { snapshotMod
87
90
  {
88
91
  id: key,
89
92
  port: 'value',
90
- disable_trigger_command: config.disabled_triggers?.[key] ? true : undefined,
93
+ disable_trigger_command:
94
+ config.trigger_mode === 'manual' || config.disabled_triggers?.[key] || undefined,
91
95
  },
92
96
  ],
93
97
  },
@@ -152,6 +156,8 @@ export const generateCalulationMap = (config: ScriptConfig, opts?: { snapshotMod
152
156
  points: {},
153
157
  }
154
158
  pbList.forEach((pb, pbIndex) => {
159
+ // Check if this data node already exists (it might be used as both input and output)
160
+ const existingNode = acc.map[pb] || inputs.map[pb]
155
161
  acc.map[pb] = {
156
162
  type: 'data-node',
157
163
  properties: {},
@@ -164,7 +170,8 @@ export const generateCalulationMap = (config: ScriptConfig, opts?: { snapshotMod
164
170
  ],
165
171
  },
166
172
  out: {
167
- value: null,
173
+ // Preserve existing out.value if node is also used as input
174
+ value: existingNode?.out?.value ?? null,
168
175
  },
169
176
  }
170
177
  acc.editorInfo[pb] = {
@@ -292,7 +299,8 @@ export const generateCalulationMap = (config: ScriptConfig, opts?: { snapshotMod
292
299
  ],
293
300
  },
294
301
  out: {
295
- value: null,
302
+ // Preserve existing out.value if node is also used as input
303
+ value: inputs.map[config.error]?.out?.value ?? null,
296
304
  },
297
305
  },
298
306
  }),
@@ -309,7 +317,8 @@ export const generateCalulationMap = (config: ScriptConfig, opts?: { snapshotMod
309
317
  ],
310
318
  },
311
319
  out: {
312
- value: null,
320
+ // Preserve existing out.value if node is also used as input
321
+ value: inputs.map[config.output]?.out?.value ?? null,
313
322
  },
314
323
  },
315
324
  }),
package/package.json CHANGED
@@ -1,18 +1,22 @@
1
1
  {
2
2
  "name": "@fugood/bricks-project",
3
- "version": "2.23.0-beta.9",
3
+ "version": "2.23.2",
4
4
  "main": "index.ts",
5
5
  "scripts": {
6
- "build": "node scripts/build.js"
6
+ "build": "bun scripts/build.js"
7
7
  },
8
8
  "dependencies": {
9
+ "@fugood/bricks-cli": "^2.23.0",
10
+ "@huggingface/gguf": "^0.3.2",
11
+ "@iarna/toml": "^3.0.0",
9
12
  "@modelcontextprotocol/sdk": "^1.15.0",
13
+ "@toon-format/toon": "^2.1.0",
10
14
  "@types/escodegen": "^0.0.10",
11
15
  "@types/lodash": "^4.17.12",
12
16
  "acorn": "^8.13.0",
13
- "escodegen": "^2.1.0",
17
+ "escodegen": "2.1.0",
18
+ "fuse.js": "^7.0.0",
14
19
  "lodash": "^4.17.4",
15
20
  "uuid": "^8.3.1"
16
- },
17
- "gitHead": "6e869e1530a63c8574e3f7250f84923a184dfbc8"
21
+ }
18
22
  }
@@ -0,0 +1,32 @@
1
+ ---
2
+ name: bricks-project
3
+ description: Advanced BRICKS configuration knowledge. Covers Standby Transition, Automations (E2E testing), Data Calculation (JS sandbox libraries), Local Sync, Remote Data Bank, Media Flow, and Buttress (remote inference). Triggers on multi-device sync, cloud data, media assets, AI offloading, E2E testing, or canvas transitions.
4
+ ---
5
+
6
+ # BRICKS Project - Advanced Features
7
+
8
+ This skill covers advanced BRICKS features not in the main project instructions.
9
+
10
+ ## Rules Index
11
+
12
+ | Rule | Description |
13
+ |------|-------------|
14
+ | [Architecture Patterns](rules/architecture-patterns.md) | **Read first** — decompose flows and select patterns |
15
+ | [Animation](rules/animation.md) | Animation system for brick transforms and opacity |
16
+ | [Standby Transition](rules/standby-transition.md) | Canvas enter/exit animations |
17
+ | [Automations](rules/automations.md) | E2E testing and scheduled tasks |
18
+ | [Data Calculation](rules/data-calculation.md) | JS sandbox libraries (25+ available) |
19
+ | [Local Sync](rules/local-sync.md) | LAN device synchronization |
20
+ | [Remote Data Bank](rules/remote-data-bank.md) | Cloud data sync and API access |
21
+ | [Media Flow](rules/media-flow.md) | Media asset management |
22
+ | [Buttress](rules/buttress.md) | Remote inference for AI generators |
23
+
24
+ ## Quick Reference
25
+
26
+ - **Complex flows**: See [Architecture Patterns](rules/architecture-patterns.md) for decomposing multi-step workflows
27
+ - **Multi-device**: See [Local Sync](rules/local-sync.md) for LAN coordination
28
+ - **Cloud data**: See [Remote Data Bank](rules/remote-data-bank.md) for sync and API access
29
+ - **Media assets**: See [Media Flow](rules/media-flow.md) for centralized asset management
30
+ - **AI offloading**: See [Buttress](rules/buttress.md) for GPU server delegation
31
+ - **E2E testing**: See [Automations](rules/automations.md) for test automation
32
+ - **Enter animations**: See [Standby Transition](rules/standby-transition.md) for canvas transitions
@@ -0,0 +1,159 @@
1
+ # Animation
2
+
3
+ BRICKS Animation system for animating brick transforms and opacity. Animations are defined at the Subspace level and triggered via events or Dynamic Animation actions.
4
+
5
+ ## Animation Types
6
+
7
+ ### Timing Animation
8
+ Standard duration-based animation with easing.
9
+
10
+ ```typescript
11
+ import { makeId } from 'bricks-project'
12
+
13
+ const fadeIn: AnimationDef = {
14
+ __typename: 'Animation',
15
+ id: makeId('animation'),
16
+ title: 'Fade In',
17
+ runType: 'once', // 'once' | 'loop'
18
+ property: 'opacity',
19
+ config: {
20
+ __type: 'AnimationTimingConfig',
21
+ toValue: 1,
22
+ duration: 300, // ms
23
+ easing: 'easeOutCubic',
24
+ delay: 0, // ms
25
+ isInteraction: true,
26
+ },
27
+ }
28
+ ```
29
+
30
+ ### Spring Animation
31
+ Physics-based spring animation.
32
+
33
+ ```typescript
34
+ const bounce: AnimationDef = {
35
+ __typename: 'Animation',
36
+ id: makeId('animation'),
37
+ title: 'Bounce In',
38
+ property: 'transform.scale',
39
+ config: {
40
+ __type: 'AnimationSpringConfig',
41
+ toValue: 1,
42
+ friction: 7,
43
+ tension: 40,
44
+ speed: 12,
45
+ bounciness: 8,
46
+ },
47
+ }
48
+ ```
49
+
50
+ ### Decay Animation
51
+ Velocity-based deceleration animation.
52
+
53
+ ```typescript
54
+ const slideOut: AnimationDef = {
55
+ __typename: 'Animation',
56
+ id: makeId('animation'),
57
+ title: 'Slide Out',
58
+ property: 'transform.translateX',
59
+ config: {
60
+ __type: 'AnimationDecayConfig',
61
+ toValue: 500,
62
+ velocity: 0.5,
63
+ deceleration: 0.997,
64
+ isInteraction: true,
65
+ },
66
+ }
67
+ ```
68
+
69
+ ## Animatable Properties
70
+
71
+ | Property | Description |
72
+ |----------|-------------|
73
+ | `transform.translateX` | Horizontal position offset |
74
+ | `transform.translateY` | Vertical position offset |
75
+ | `transform.scale` | Uniform scale |
76
+ | `transform.scaleX` | Horizontal scale |
77
+ | `transform.scaleY` | Vertical scale |
78
+ | `transform.rotate` | Rotation (degrees) |
79
+ | `transform.rotateX` | X-axis rotation |
80
+ | `transform.rotateY` | Y-axis rotation |
81
+ | `opacity` | Transparency (0-1) |
82
+
83
+ ## Easing Functions
84
+
85
+ Standard easing from [easings.net](https://easings.net):
86
+ - `easeInSine`, `easeOutSine`, `easeInOutSine`
87
+ - `easeInQuad`, `easeOutQuad`, `easeInOutQuad`
88
+ - `easeInCubic`, `easeOutCubic`, `easeInOutCubic`
89
+ - `easeInQuart`, `easeOutQuart`, `easeInOutQuart`
90
+ - `easeInQuint`, `easeOutQuint`, `easeInOutQuint`
91
+ - `easeInExpo`, `easeOutExpo`, `easeInOutExpo`
92
+ - `easeInCirc`, `easeOutCirc`, `easeInOutCirc`
93
+ - `easeInBack`, `easeOutBack`, `easeInOutBack`
94
+ - `easeInElastic`, `easeOutElastic`, `easeInOutElastic`
95
+ - `easeInBounce`, `easeOutBounce`, `easeInOutBounce`
96
+ - Custom: `'cubic-bezier(x1, y1, x2, y2)'`
97
+
98
+ ## Composed Animations
99
+
100
+ Combine multiple animations in parallel or sequence.
101
+
102
+ ```typescript
103
+ const enterAnimation: AnimationComposeDef = {
104
+ __typename: 'AnimationCompose',
105
+ id: makeId('animation'),
106
+ title: 'Enter Animation',
107
+ runType: 'once',
108
+ composeType: 'parallel', // 'parallel' | 'sequence'
109
+ items: [
110
+ () => fadeIn,
111
+ () => scaleUp,
112
+ ],
113
+ }
114
+ ```
115
+
116
+ ## Brick Animation Events
117
+
118
+ Bricks support automatic animation binding:
119
+
120
+ ```typescript
121
+ // In brick definition
122
+ animations: {
123
+ showStart: () => fadeInAnimation, // On brick first render
124
+ standby: () => standbyAnimation, // After standby transition
125
+ breatheStart: () => pulseAnimation, // Breathing effect (looping)
126
+ }
127
+ ```
128
+
129
+ ## Dynamic Animation (Runtime)
130
+
131
+ Trigger animations programmatically via System Action:
132
+
133
+ ```typescript
134
+ const runAnimation: EventAction = {
135
+ handler: 'system',
136
+ action: {
137
+ __actionName: 'DYNAMIC_ANIMATION',
138
+ parent: 'System',
139
+ params: [
140
+ { input: 'brickId', value: () => targetBrick },
141
+ { input: 'animationId', value: () => pulseAnimation },
142
+ { input: 'runType', value: 'once' }, // 'once' | 'loop'
143
+ { input: 'resetInitialValue', value: false },
144
+ ],
145
+ },
146
+ }
147
+ ```
148
+
149
+ Related actions:
150
+ - `DYNAMIC_ANIMATION_RESET` - Reset animation state
151
+ - `DYNAMIC_ANIMATION_STOP` - Stop running animation
152
+
153
+ ## Best Practices
154
+
155
+ 1. **Performance**: Keep animations simple, prefer `opacity` and `transform` over layout changes
156
+ 2. **Timing**: Use `easeOut` for enter animations, `easeIn` for exit
157
+ 3. **Spring animations**: Good for natural, bouncy UI elements
158
+ 4. **Looping**: Use `runType: 'loop'` for attention-grabbing elements
159
+ 5. **Composition**: Use `sequence` for staged reveals, `parallel` for coordinated effects
@@ -0,0 +1,62 @@
1
+ # Architecture Patterns
2
+
3
+ How to decompose complex flows into the right combination of BRICKS patterns.
4
+
5
+ ## Pattern Selection Priority
6
+
7
+ Prefer higher-priority patterns; only fall to lower when they genuinely can't solve the sub-problem:
8
+
9
+ | Priority | Pattern | Use For |
10
+ |----------|---------|---------|
11
+ | 1 | Generator + Events | I/O, AI inference, external data |
12
+ | 2 | Event Action Chains | Orchestration, sequential steps |
13
+ | 3 | System Actions | State changes, navigation, UI triggers |
14
+ | 4 | Data Calculation | Pure data transformation ONLY |
15
+
16
+ ### Generators (Priority 1)
17
+ For all external I/O and AI inference. Each generator emits events that naturally chain into actions.
18
+ - **GeneratorAssistant**: multi-turn LLM conversations, function calling, built-in message history
19
+ - **GeneratorLLM**: single-shot local inference (GGML)
20
+ - **GeneratorHttp**: REST API calls
21
+ - **GeneratorMqtt / GeneratorWebSocket**: real-time messaging
22
+
23
+ ### Event Action Chains (Priority 2)
24
+ The primary way to orchestrate multi-step flows. A single event can contain an array of EventActions executed sequentially.
25
+ - Use `waitAsync: true` to await async actions before the next step
26
+ - Use `dataParams` + `mapping` to pass event data downstream
27
+ - This is the "glue" that wires generators, state, and UI together
28
+
29
+ ### System Actions (Priority 3)
30
+ Built-in commands for direct state and UI changes.
31
+ - **PROPERTY_BANK**: set data value
32
+ - **PROPERTY_BANK_EXPRESSION**: inline JS expression for simple compute
33
+ - **CHANGE_CANVAS**: navigate to another canvas
34
+ - **DYNAMIC_ANIMATION**: trigger animation
35
+ - **ALERT / MESSAGE**: system feedback
36
+
37
+ ### Data Calculation (Priority 4)
38
+ ONLY for deriving, formatting, or aggregating values from other data. Not for orchestration, side effects, or flow control.
39
+
40
+ ## Flow Decomposition
41
+
42
+ When the user describes a complex flow, decompose it BEFORE writing code:
43
+
44
+ ### Step 1: Extract I/O boundaries
45
+ Every external interaction maps to a Generator:
46
+ - "call LLM" → GeneratorAssistant or GeneratorLLM
47
+ - "fetch API" → GeneratorHttp
48
+ - "speech to text" → GeneratorSpeechInference
49
+
50
+ ### Step 2: Extract state transitions
51
+ Every UI change maps to a System Action in an event chain:
52
+ - "show loading" → PROPERTY_BANK on a boolean data
53
+ - "go to result screen" → CHANGE_CANVAS
54
+ - "animate in" → DYNAMIC_ANIMATION
55
+
56
+ ### Step 3: Extract pure transformations
57
+ Only actual data derivation maps to Data Calculation:
58
+ - "format the response" → DataCalculationScript
59
+ - "compute a score" → DataCalculationScript or DataCalculationMap
60
+
61
+ ### Step 4: Wire with Event Action Chains
62
+ Connect the pieces through events on generators and bricks.
@@ -0,0 +1,221 @@
1
+ # Automations
2
+
3
+ E2E testing and scheduled execution for BRICKS applications. Simulates user behavior and validates application state.
4
+
5
+ ## Automation Types
6
+
7
+ | Type | Description |
8
+ | --------- | ---------------------------------------------------------- |
9
+ | `launch` | Run on application launch (restarts app when run manually) |
10
+ | `anytime` | Execute anytime via manual trigger |
11
+ | `cron` | Scheduled execution using crontab expressions |
12
+
13
+ ## Simulation Actions
14
+
15
+ Automations can simulate:
16
+
17
+ - **Brick Press**: Tap/click on bricks
18
+ - **Key Events**: Key up/down for keyboard input
19
+ - **HTTP Request**: API calls
20
+ - **Execute Action**: Trigger system or generator actions
21
+
22
+ ## Assertions
23
+
24
+ Automations can validate:
25
+
26
+ - **Brick Exists**: Check if brick is rendered
27
+ - **Event Triggered**: Verify event from Brick/Generator/Canvas
28
+ - **Canvas Changed**: Confirm canvas navigation
29
+ - **Property Assert**: Check Data Bank values
30
+ - **Property Updated**: Wait for property change
31
+ - **Match Screenshot**: Visual regression testing
32
+
33
+ ## TypeScript Example
34
+
35
+ ```typescript
36
+ const testLoginFlow: AutomationTest = {
37
+ __typename: 'AutomationTest',
38
+ id: 'test-login-flow',
39
+ title: 'Test Login Flow',
40
+ timeout: 30000,
41
+ trigger_type: 'launch',
42
+ cases: [
43
+ {
44
+ __typename: 'TestCase',
45
+ id: 'wait-login-canvas',
46
+ name: 'Wait for login canvas',
47
+ run: ['wait_until_canvas_change', () => mainSubspace, () => loginCanvas, 5000],
48
+ exit_on_failed: true,
49
+ commented: false,
50
+ pre_delay: 0,
51
+ post_delay: 0,
52
+ jump_cond: [],
53
+ },
54
+ {
55
+ __typename: 'TestCase',
56
+ id: 'press-username',
57
+ name: 'Press username input',
58
+ run: ['brick_press', () => mainSubspace, () => usernameInput],
59
+ exit_on_failed: true,
60
+ commented: false,
61
+ pre_delay: 0,
62
+ post_delay: 100,
63
+ jump_cond: [],
64
+ },
65
+ {
66
+ __typename: 'TestCase',
67
+ id: 'assert-username',
68
+ name: 'Assert username value',
69
+ run: ['assert_property', () => mainSubspace, () => usernameData, 'testuser'],
70
+ exit_on_failed: true,
71
+ commented: false,
72
+ pre_delay: 0,
73
+ post_delay: 0,
74
+ jump_cond: [],
75
+ },
76
+ {
77
+ __typename: 'TestCase',
78
+ id: 'press-login',
79
+ name: 'Press login button',
80
+ run: ['brick_press', () => mainSubspace, () => loginButton],
81
+ exit_on_failed: true,
82
+ commented: false,
83
+ pre_delay: 0,
84
+ post_delay: 0,
85
+ jump_cond: [],
86
+ },
87
+ {
88
+ __typename: 'TestCase',
89
+ id: 'wait-dashboard',
90
+ name: 'Wait for dashboard',
91
+ run: ['wait_until_canvas_change', () => mainSubspace, () => dashboardCanvas, 10000],
92
+ exit_on_failed: true,
93
+ commented: false,
94
+ pre_delay: 0,
95
+ post_delay: 0,
96
+ jump_cond: [],
97
+ },
98
+ ],
99
+ variables: [],
100
+ }
101
+ ```
102
+
103
+ ## Test Methods
104
+
105
+ | Method | Signature | Description |
106
+ | ---------------------------- | ------------------------------------------------ | -------------------- |
107
+ | `brick_press` | `[subspace, brick, options?]` | Simulate brick press |
108
+ | `brick_exists` | `[subspace, brick, frame?]` | Check brick exists |
109
+ | `wait_until_brick_exists` | `[subspace, brick, timeout?, frame?]` | Wait for brick |
110
+ | `wait_until_event_trigger` | `[subspace, sender, eventKey, timeout?]` | Wait for event |
111
+ | `wait_until_canvas_change` | `[subspace, canvas, timeout?]` | Wait for canvas |
112
+ | `keydown` | `[keyCode, pressedKey?, flags?]` | Key down event |
113
+ | `keyup` | `[keyCode, pressedKey?, flags?]` | Key up event |
114
+ | `http_request` | `[url, options?]` | HTTP request |
115
+ | `assert_property` | `[subspace, property, value]` | Assert data value |
116
+ | `wait_until_property_change` | `[subspace, property, value, timeout?]` | Wait for value |
117
+ | `execute_action` | `[subspace, handler, action, params?, options?]` | Execute action |
118
+ | `match_screenshot` | `[name, threshold?, maxRetry?]` | Screenshot compare |
119
+ | `delay` | `[subspace?, property?, defaultValue?]` | Delay execution |
120
+
121
+ ### execute_action Params
122
+
123
+ The `params` object in `execute_action` uses **runtime event property keys** from `event-props.ts`, NOT the action config `input` names from type definitions.
124
+
125
+ ```typescript
126
+ // CORRECT — use runtime event property key
127
+ run: ['execute_action', () => subspace0, bricks.bInput.id, 'BRICK_TEXT_INPUT_SET_TEXT',
128
+ { BRICK_TEXT_INPUT_TEXT: 'hello' }]
129
+
130
+ // WRONG — action config input name doesn't work in automation
131
+ run: ['execute_action', () => subspace0, bricks.bInput.id, 'BRICK_TEXT_INPUT_SET_TEXT',
132
+ { text: 'hello' }]
133
+ ```
134
+
135
+ Reference `event-props.ts` for the correct runtime keys (e.g., `BRICK_TEXT_INPUT_TEXT`, `GENERATOR_MQTT_PAYLOAD`).
136
+
137
+ ### Prefer UI Interactions Over Direct Generator Calls
138
+
139
+ For realistic E2E testing, prefer simulating user actions (set text input + press button) over calling generator actions directly:
140
+
141
+ ```typescript
142
+ // GOOD — simulates real user behavior
143
+ { run: ['execute_action', () => sub, bricks.bInput.id, 'BRICK_TEXT_INPUT_SET_TEXT',
144
+ { BRICK_TEXT_INPUT_TEXT: 'hello' }] },
145
+ { run: ['brick_press', () => sub, () => bricks.bSendBtn] },
146
+ { run: ['wait_until_property_change', () => sub, () => data.dPayload, 'hello', 10000] },
147
+
148
+ // AVOID — bypasses UI, doesn't test the full flow
149
+ { run: ['execute_action', () => sub, generators.gClient.id, 'GENERATOR_MQTT_PUBLISH',
150
+ { topic: 'test', payload: 'hello', qos: '0' }] },
151
+ ```
152
+
153
+ ## Recording Automations
154
+
155
+ In BRICKS Editor Preview mode:
156
+
157
+ 1. Perform operations normally
158
+ 2. Open menu (right-bottom corner)
159
+ 3. Select "Record Events as Automation"
160
+ 4. Generated automation appears in Automations list
161
+
162
+ ## Running Automations
163
+
164
+ ### Manual Run
165
+
166
+ `Menu` → `Automations` → Select automation → `Run`
167
+
168
+ ### On Launch
169
+
170
+ `Bind Device` → `Select Automation` (only `launch` or `cron` types)
171
+
172
+ ### Scheduled (Cron)
173
+
174
+ `Bind Device` → `Cron Automation` (allows multi-select)
175
+
176
+ Use [crontab.guru](https://crontab.guru) to build cron expressions.
177
+
178
+ ## Screenshot Testing
179
+
180
+ Visual regression testing with screenshot comparison:
181
+
182
+ ```typescript
183
+ {
184
+ __typename: 'TestCase',
185
+ id: 'screenshot-dashboard',
186
+ name: 'Match dashboard screenshot',
187
+ run: ['match_screenshot', 'dashboard-initial-state', 0.01, 3],
188
+ exit_on_failed: true,
189
+ commented: false,
190
+ pre_delay: 500, // Wait for UI to settle
191
+ post_delay: 0,
192
+ jump_cond: [],
193
+ }
194
+ ```
195
+
196
+ Screenshots can be stored:
197
+
198
+ - Local file system
199
+ - Media Flow workspace
200
+
201
+ First run captures baseline. Use "Run with Update" to update baseline.
202
+
203
+ ## Module Support
204
+
205
+ Automations work with Modules. Use Manual Run in Preview mode for module testing.
206
+
207
+ ## Important Notes
208
+
209
+ - **Automation map key**: Always use `'AUTOMATION_MAP_DEFAULT'` as the automation map ID (not `makeId()`). The preview test runner reads from `automationMap['AUTOMATION_MAP_DEFAULT']?.map`.
210
+ - **Valid makeId types**: Use `'test'` for AutomationTest, `'test_case'` for TestCase, `'test_var'` for TestVariable. Do NOT use `'automation_test'` or `'automation_test_map'`.
211
+ - **handler in execute_action**: Pass the entity's `.id` string (e.g., `bricks.bInput.id`), not a getter function.
212
+
213
+ ## Best Practices
214
+
215
+ 1. **Test culture**: Create automations for every significant flow
216
+ 2. **CI/CD integration**: Use `launch` automations for deployment validation
217
+ 3. **Incremental waits**: Use `wait_until_property_change` with appropriate timeouts
218
+ 4. **Visual testing**: Add screenshot comparisons for critical UI states
219
+ 5. **Cron monitoring**: Schedule health checks for production displays
220
+ 6. **Isolation**: Each automation should be independent and idempotent
221
+ 7. **UI-first testing**: Simulate real user interactions (text input, button press) rather than calling generators directly