brilliant-msg 2.0.0

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.
package/LICENSE ADDED
@@ -0,0 +1,28 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2025, CitizenOneX
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright notice, this
9
+ list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+
15
+ 3. Neither the name of the copyright holder nor the names of its
16
+ contributors may be used to endorse or promote products derived from
17
+ this software without specific prior written permission.
18
+
19
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package/README.md ADDED
@@ -0,0 +1,122 @@
1
+ # brilliant-msg
2
+
3
+ A TypeScript package for handling rich application-level messages for [Brilliant Labs Frame and Halo](https://brilliant.xyz/) devices, including sprites, text, audio, IMU data, photos, and click events.
4
+
5
+ [Frame SDK documentation](https://docs.brilliant.xyz/frame/frame-sdk/) | [GitHub Repo](https://github.com/brilliantlabsAR/brilliant_sdk/tree/main/webbluetooth/packages/brilliant-msg) | [API Docs](https://brilliantlabsAR.github.io/brilliant_sdk/brilliant-msg/api) | [Live Examples](https://brilliantlabsAR.github.io/brilliant_sdk/brilliant-msg/)
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install brilliant-msg
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ ```typescript
16
+ import { BrilliantMsg, StdLua, TxCaptureSettings, RxPhoto, BrilliantDeviceType } from 'brilliant-msg';
17
+ import frameApp from './lua/camera_frame_app.lua?raw';
18
+
19
+ // Take a photo using the Frame camera and display it
20
+ export async function run() {
21
+ const frame = new BrilliantMsg();
22
+
23
+ try {
24
+ const deviceId = await frame.connect();
25
+
26
+ // send the std lua files to Frame
27
+ await frame.uploadStdLuaLibs([StdLua.DataMin, StdLua.CameraMin]);
28
+
29
+ // Send the main lua application from this project to Frame that will run the app
30
+ await frame.uploadFrameApp(frameApp);
31
+
32
+ frame.attachPrintResponseHandler(console.log);
33
+
34
+ // "require" the main frame_app lua file to run it, and block until it has started.
35
+ // It signals that it is ready by sending something on the string response channel.
36
+ await frame.startFrameApp();
37
+
38
+ // hook up the RxPhoto receiver
39
+ const rxPhoto = new RxPhoto({});
40
+ const photoQueue = await rxPhoto.attach(frame);
41
+
42
+ // give Frame some time for the autoexposure to settle
43
+ await new Promise(resolve => setTimeout(resolve, 5000));
44
+
45
+ // Request the photo by sending a TxCaptureSettings message
46
+ await frame.sendMessage(0x0d, new TxCaptureSettings({}).pack());
47
+
48
+ const jpegBytes = await photoQueue.get();
49
+
50
+ // display the image on the web page
51
+ const img = document.createElement('img');
52
+ img.src = URL.createObjectURL(new Blob([jpegBytes], { type: 'image/jpeg' }));
53
+ document.body.appendChild(img);
54
+
55
+ // stop the photo listener and clean up its resources
56
+ rxPhoto.detach(frame);
57
+
58
+ frame.detachPrintResponseHandler()
59
+
60
+ // break out of the frame app loop and reboot Frame
61
+ await frame.stopFrameApp()
62
+ }
63
+ catch (error) {
64
+ console.error("Error:", error);
65
+ }
66
+ finally {
67
+ // Ensure the device is disconnected in case of an error
68
+ try {
69
+ await frame.disconnect();
70
+ console.log("Disconnected.");
71
+ } catch (disconnectError) {
72
+ console.error("Error during disconnection:", disconnectError);
73
+ }
74
+ }
75
+ };
76
+ ```
77
+
78
+ ## Halo support
79
+
80
+ Frame and Halo are detected automatically after `connect()`. The `BrilliantDeviceType` enum is re-exported from `brilliant-msg` for convenience.
81
+
82
+ ### Circular text layout (Halo)
83
+
84
+ Halo has a circular display. Use `CircularTextLayout` with `TxTextPage` to fit text within the circle:
85
+
86
+ ```typescript
87
+ import { TxTextPage, CircularTextLayout, RectangularTextLayout } from 'brilliant-msg';
88
+
89
+ // For Halo's circular display
90
+ const layout = new CircularTextLayout({ width: 640, height: 400, fontSize: 36 });
91
+
92
+ // For Frame's rectangular display
93
+ // const layout = new RectangularTextLayout({ width: 640, height: 400, fontSize: 36 });
94
+
95
+ const page = new TxTextPage({ layout, text: 'Hello from Halo!' });
96
+ const pageData = await page.rasterizeNextPage();
97
+ if (pageData) {
98
+ // Send header packet, then each sprite
99
+ await frame.sendMessage(0x0a, pageData.pack());
100
+ for (const sprite of pageData.rasterizedSprites) {
101
+ await frame.sendMessage(0x0a, sprite.pack());
102
+ }
103
+ }
104
+ ```
105
+
106
+ ### Click events (Halo)
107
+
108
+ Halo sends tap/click events with single, double, and long-press types:
109
+
110
+ ```typescript
111
+ import { RxClick, ClickType } from 'brilliant-msg';
112
+
113
+ const rxClick = new RxClick();
114
+ const clickQueue = await rxClick.attach(frame);
115
+
116
+ const click = await clickQueue.get();
117
+ if (click === ClickType.SINGLE) console.log('single click');
118
+ if (click === ClickType.DOUBLE) console.log('double click');
119
+ if (click === ClickType.LONG) console.log('long press');
120
+
121
+ rxClick.detach(frame);
122
+ ```
@@ -0,0 +1,48 @@
1
+ /**
2
+ A simple Promise-based queue used by the Rx classes
3
+ to manage asynchronous operations. This queue allows for
4
+ putting and getting values in a FIFO manner, handling
5
+ asynchronous operations without blocking the main thread.
6
+ */
7
+ export declare class AsyncQueue<T> {
8
+ private promises;
9
+ private resolvers;
10
+ /**
11
+ * Constructs a new AsyncQueue instance.
12
+ * Initializes an empty queue for storing promises and their resolvers.
13
+ */
14
+ constructor();
15
+ private add;
16
+ /**
17
+ * Adds a value to the end of the queue.
18
+ * If there are pending `get` operations, this will resolve the oldest one.
19
+ * Otherwise, the value is stored until a `get` operation is called.
20
+ * @param value The value to add to the queue.
21
+ */
22
+ put(value: T): void;
23
+ /**
24
+ * Retrieves a value from the front of the queue.
25
+ * If the queue is empty, this method waits until a value is added.
26
+ * @returns A Promise that resolves with the value from the front of the queue.
27
+ */
28
+ get(): Promise<T>;
29
+ /**
30
+ * Checks if the queue is currently empty.
31
+ * This checks if there are any resolved or pending promises in the queue.
32
+ * @returns True if the queue is empty, false otherwise.
33
+ */
34
+ isEmpty(): boolean;
35
+ /**
36
+ * Gets the current number of items in the queue.
37
+ * This represents the number of promises (resolved or pending) currently held by the queue.
38
+ * @returns The number of items in the queue.
39
+ */
40
+ size(): number;
41
+ /**
42
+ * Clears all items from the queue.
43
+ * This removes all pending promises and their resolvers.
44
+ * Note: This does not explicitly reject pending promises from `get()` calls,
45
+ * so consumers awaiting `get()` might remain pending indefinitely if not handled.
46
+ */
47
+ clear(): void;
48
+ }
@@ -0,0 +1,175 @@
1
+ import { BrilliantBle } from 'brilliant-ble';
2
+ /**
3
+ * Enum representing the available standard Lua libraries that can be uploaded.
4
+ */
5
+ export declare enum StdLua {
6
+ DataMin = "stdDataMin",
7
+ AudioMin = "stdAudioMin",
8
+ CameraMin = "stdCameraMin",
9
+ CodeMin = "stdCodeMin",
10
+ IMUMin = "stdIMUMin",
11
+ ImageSpriteBlockMin = "stdImageSpriteBlockMin",
12
+ PlainTextMin = "stdPlainTextMin",
13
+ SpriteMin = "stdSpriteMin",
14
+ SpriteCoordsMin = "stdSpriteCoordsMin",
15
+ TapMin = "stdTapMin",
16
+ TextSpriteBlockMin = "stdTextSpriteBlockMin"
17
+ }
18
+ type BrilliantMsgDataHandler = (data: Uint8Array) => void;
19
+ /**
20
+ * BrilliantMsg class handles communication with the Frame device.
21
+ * It wraps the BrilliantBle class and provides higher-level methods for uploading standard Lua libraries
22
+ * and Frame applications.
23
+ * It also manages the registration and unregistration of data response handlers for different Rx message types.
24
+ * Subscribers can register their own handlers for specific message codes.
25
+ */
26
+ export declare class BrilliantMsg {
27
+ /** The underlying {@link BrilliantBle} instance used for Bluetooth Low Energy communication. */
28
+ ble: BrilliantBle;
29
+ private dataResponseHandlers;
30
+ /**
31
+ * Constructs an instance of the BrilliantMsg class.
32
+ * Initializes a new BrilliantBle instance and sets up internal data response handling.
33
+ */
34
+ constructor();
35
+ /**
36
+ * Connects to the Frame device and optionally runs the initialization sequence.
37
+ * Note: Print and Disconnect handlers should be set directly on the BrilliantBle instance
38
+ * (e.g., `frameMsg.ble.setPrintResponseHandler(...)`, `frameMsg.ble.setDisconnectHandler(...)`)
39
+ * or via `frameMsg.attachPrintResponseHandler(...)` before or after calling connect.
40
+ * @param initialize If true, runs the break/reset/break sequence after connecting. Defaults to true.
41
+ * @param connectOptions Options including name and namePrefix for device filtering.
42
+ * @returns The device ID or name if connection was successful.
43
+ * @throws Any exceptions from the underlying BrilliantBle connection or initialization.
44
+ */
45
+ connect(initialize?: boolean, connectOptions?: {
46
+ name?: string;
47
+ namePrefix?: string;
48
+ }): Promise<string | undefined>;
49
+ /**
50
+ * Disconnects from the Frame device if currently connected.
51
+ * @returns A Promise that resolves when disconnection is complete.
52
+ */
53
+ disconnect(): Promise<void>;
54
+ /**
55
+ * Checks if the Frame device is currently connected.
56
+ * @returns True if connected, false otherwise.
57
+ */
58
+ isConnected(): boolean;
59
+ /**
60
+ * Displays a short string of text on the Frame's display.
61
+ * The text is sanitized to escape single quotes and remove newlines.
62
+ * @param text The text to display. Defaults to an empty string.
63
+ * @returns A Promise that resolves with the print response from the device if `awaitPrint` is true (default), otherwise void.
64
+ */
65
+ printShortText(text?: string): Promise<string | void>;
66
+ /**
67
+ * Uploads specified standard Lua libraries to the Frame device.
68
+ * @param libs An array of {@link StdLua} enum values indicating which libraries to upload.
69
+ * @returns A Promise that resolves when all specified libraries have been uploaded.
70
+ */
71
+ uploadStdLuaLibs(libs: StdLua[]): Promise<void>;
72
+ /**
73
+ * Uploads a Frame application (Lua script) to the device.
74
+ * @param fileContent The content of the Lua application file as a string.
75
+ * @param frameFileName The target filename on the Frame device. Defaults to 'frame_app.lua'.
76
+ * @returns A Promise that resolves when the file has been uploaded.
77
+ */
78
+ uploadFrameApp(fileContent: string, frameFileName?: string): Promise<void>;
79
+ /**
80
+ * Starts a Frame application on the device by requiring its module name.
81
+ * @param frameAppName The name of the Frame application module (without .lua extension). Defaults to 'frame_app'.
82
+ * @param awaitPrint Whether to wait for a print response from the device. Defaults to true.
83
+ * @returns A Promise that resolves with the print response if `awaitPrint` is true, otherwise void.
84
+ */
85
+ startFrameApp(frameAppName?: string, awaitPrint?: boolean): Promise<string | void>;
86
+ /**
87
+ * Stops the currently running Frame application by sending a break signal.
88
+ * Optionally, it can also reset the device.
89
+ * @param reset If true, sends a reset signal after the break signal. Defaults to true.
90
+ * @returns A Promise that resolves when the signals have been sent.
91
+ */
92
+ stopFrameApp(reset?: boolean): Promise<void>;
93
+ /**
94
+ * Attaches a handler for print responses from the Frame device.
95
+ * This handler will be called with any text data printed by Lua scripts on the device.
96
+ * @param handler A function to handle the print response string. Defaults to `console.log`.
97
+ */
98
+ attachPrintResponseHandler(handler?: (data: string) => void | Promise<void>): void;
99
+ /**
100
+ * Detaches the currently set print response handler.
101
+ * After calling this, print responses from the device will no longer be processed by a custom handler.
102
+ */
103
+ detachPrintResponseHandler(): void;
104
+ /**
105
+ * Sends a message (msg_code and payload) to the Frame device.
106
+ * @param msgCode The message code (an integer identifying the message type).
107
+ * @param payload The Uint8Array payload for the message.
108
+ * @param showMe If true, prints the message being sent to the console. Defaults to false.
109
+ * @returns A Promise that resolves when the message has been sent.
110
+ */
111
+ sendMessage(msgCode: number, payload: Uint8Array, showMe?: boolean): Promise<void>;
112
+ /**
113
+ * Registers a handler for a subscriber interested in specific message codes from Frame.
114
+ * @param subscriber The subscriber object/identifier.
115
+ * @param msgCodes Array of message codes the subscriber is interested in.
116
+ * @param handler The function to call with the incoming data (Uint8Array).
117
+ */
118
+ registerDataResponseHandler(subscriber: any, msgCodes: number[], handler: BrilliantMsgDataHandler): void;
119
+ /**
120
+ * Unregisters all data response handlers associated with a specific subscriber.
121
+ * @param subscriber The subscriber object/identifier whose handlers should be removed.
122
+ */
123
+ unregisterDataResponseHandler(subscriber: any): void;
124
+ /**
125
+ * Internal method to handle incoming data responses from BrilliantBle (as Uint8Array)
126
+ * and dispatch to appropriate BrilliantMsg subscribers.
127
+ * @param data The incoming data response as a Uint8Array.
128
+ */
129
+ private _handleDataResponse;
130
+ /**
131
+ * Sends a Lua command string to the Frame device.
132
+ * This is a proxy to `BrilliantBle.sendLua()`.
133
+ * @param str The Lua command string to send.
134
+ * @param options Configuration options for sending the Lua command.
135
+ * @returns A Promise that resolves with the print response if `awaitPrint` is true, otherwise void.
136
+ */
137
+ sendLua(str: string, options?: {
138
+ showMe?: boolean;
139
+ awaitPrint?: boolean;
140
+ timeout?: number;
141
+ }): Promise<string | void>;
142
+ /**
143
+ * Sends raw data to the device.
144
+ * @param data The Uint8Array payload to send.
145
+ * @param options Configuration options.
146
+ * @returns A Promise that resolves with the Uint8Array data response if awaitData is true, or void.
147
+ */
148
+ sendData(data: Uint8Array, options?: {
149
+ showMe?: boolean;
150
+ awaitData?: boolean;
151
+ timeout?: number;
152
+ }): Promise<Uint8Array | void>;
153
+ /**
154
+ * Sends a reset signal to the Frame device.
155
+ * This is a proxy to `BrilliantBle.sendResetSignal()`.
156
+ * @param showMe If true, prints a message to the console indicating the signal was sent. Defaults to false.
157
+ * @returns A Promise that resolves when the signal has been sent.
158
+ */
159
+ sendResetSignal(showMe?: boolean): Promise<void>;
160
+ /**
161
+ * Sends a break signal (Ctrl+C) to the Frame device.
162
+ * This is a proxy to `BrilliantBle.sendBreakSignal()`.
163
+ * @param showMe If true, prints a message to the console indicating the signal was sent. Defaults to false.
164
+ * @returns A Promise that resolves when the signal has been sent.
165
+ */
166
+ sendBreakSignal(showMe?: boolean): Promise<void>;
167
+ /**
168
+ * Gets the maximum payload size for sending data to the Frame device.
169
+ * This is a proxy to `BrilliantBle.getMaxPayload()`.
170
+ * @param isLua True if the payload is for a Lua command, false for other data types.
171
+ * @returns The maximum payload size in bytes.
172
+ */
173
+ getMaxPayload(isLua: boolean): number;
174
+ }
175
+ export {};