@fluxlay/react 1.2.0 → 1.3.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/README.md +196 -42
- package/dist/index.d.mts +674 -74
- package/dist/index.mjs +3 -4
- package/dist/mimo/index.d.mts +302 -0
- package/dist/mimo/index.mjs +2 -0
- package/dist/use-mouse-events-DSFSfRBX.mjs +7 -0
- package/package.json +7 -1
package/README.md
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
SDK for building [Fluxlay](https://fluxlay.com) wallpapers with React.
|
|
4
4
|
|
|
5
|
+
- Documentation: <https://fluxlay.com/docs/developer/tutorials/getting-started>
|
|
6
|
+
- SDK reference: <https://fluxlay.com/docs/developer/reference/sdk/use-mouse-position>
|
|
7
|
+
- Examples: <https://github.com/fluxlay/examples>
|
|
8
|
+
|
|
5
9
|
## Installation
|
|
6
10
|
|
|
7
11
|
```sh
|
|
@@ -10,28 +14,169 @@ npm install @fluxlay/react
|
|
|
10
14
|
bun add @fluxlay/react
|
|
11
15
|
```
|
|
12
16
|
|
|
13
|
-
|
|
17
|
+
The SDK ships its own styles (xterm CSS is imported automatically by `useTerminal`); no additional stylesheet import is required.
|
|
14
18
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
19
|
+
## Runtime constraints
|
|
20
|
+
|
|
21
|
+
Wallpapers run in an isolated `fluxlay://` origin with a minimal Content Security Policy enforced by the desktop app. As a result:
|
|
22
|
+
|
|
23
|
+
- **No external hosts.** `fetch` / `XMLHttpRequest` / `WebSocket` to arbitrary origins is blocked by `connect-src`. The only non-`'self'` endpoint allowed by default is the local Fluxlay API (`http://127.0.0.1:*`), which the SDK uses internally. To reach an external host, declare it under `network:` in `fluxlay.yaml` — its scheme + host[:port] is then injected into `connect-src` / `img-src` / `media-src` / `font-src` (passive resources only; never `script-src`).
|
|
24
|
+
- **No `eval` / `new Function`.** `script-src` is `'self'` only — no `'unsafe-eval'`, no `'unsafe-inline'`. Bundlers, template engines, and runtime-compiled code paths that rely on `eval` will not run. (Dev mode loosens this for HMR; production does not.)
|
|
25
|
+
- **No `__TAURI__.core.invoke`.** Wallpaper windows are excluded from every Tauri capability, so `invoke` is unavailable. All host interactions must go through SDK hooks, which talk to the local API over HTTP / WebSocket.
|
|
26
|
+
- **Inline styles are allowed** (`style-src 'self' 'unsafe-inline'`) so React `style={...}` and CSS-in-JS keep working.
|
|
18
27
|
|
|
19
28
|
## API
|
|
20
29
|
|
|
21
30
|
### `useMousePosition()`
|
|
22
31
|
|
|
23
|
-
Subscribes to
|
|
32
|
+
Subscribes to mouse position events for the current wallpaper window. Both axes are normalized to `[-1, 1]` (`x`: `-1` left → `1` right; `y`: `-1` bottom → `1` top — the Y axis is inverted to match a standard mathematical coordinate system, opposite to CSS). Returns `{ x: 0, y: 0 }` until the first event is received or when running outside the Fluxlay desktop app.
|
|
24
33
|
|
|
25
34
|
```tsx
|
|
26
35
|
import { useMousePosition } from "@fluxlay/react";
|
|
27
36
|
|
|
28
37
|
function Wallpaper() {
|
|
29
38
|
const { x, y } = useMousePosition();
|
|
30
|
-
|
|
39
|
+
// Convert normalized coordinates to pixels, flipping Y back to CSS orientation.
|
|
40
|
+
const px = ((x + 1) / 2) * window.innerWidth;
|
|
41
|
+
const py = (1 - (y + 1) / 2) * window.innerHeight;
|
|
42
|
+
return <div style={{ transform: `translate(${px}px, ${py}px)` }} />;
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### `useMouseEvents(handlers)`
|
|
47
|
+
|
|
48
|
+
Subscribes to mouse click and wheel events for the current wallpaper window. Coordinates are normalized to `[-1, 1]` with the Y axis inverted (positive Y points upward).
|
|
49
|
+
|
|
50
|
+
```tsx
|
|
51
|
+
import { useMouseEvents } from "@fluxlay/react";
|
|
52
|
+
|
|
53
|
+
function Wallpaper() {
|
|
54
|
+
useMouseEvents({
|
|
55
|
+
onButton: event => {
|
|
56
|
+
if (event.pressed) console.log("pressed", event.button, event.x, event.y);
|
|
57
|
+
},
|
|
58
|
+
onWheel: event => {
|
|
59
|
+
console.log("scroll", event.deltaX, event.deltaY);
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
return <div />;
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
On macOS, mouse events require the user to grant Fluxlay "Input Monitoring" permission. On Windows, events from windows running with elevated privileges are not delivered (UIPI).
|
|
67
|
+
|
|
68
|
+
### `useKeyboard(handlers)`
|
|
69
|
+
|
|
70
|
+
Subscribes to global keyboard events. Events are delivered to every subscriber on every window while the user is anywhere on the desktop, which is useful for game-like wallpapers. `event.code` follows the Web `KeyboardEvent.code` convention (e.g. `"KeyA"`, `"Space"`, `"ArrowLeft"`, `"ShiftLeft"`) and identifies a physical key independent of layout.
|
|
71
|
+
|
|
72
|
+
Because this hook receives every keystroke the user types anywhere on the desktop — including text typed into other applications — it requires the wallpaper to declare the `keyboard` permission in `fluxlay.yaml`. Without the declaration, the backend rejects the subscription with HTTP 403 and no events are delivered.
|
|
73
|
+
|
|
74
|
+
```yaml
|
|
75
|
+
# fluxlay.yaml
|
|
76
|
+
schemaVersion: 1
|
|
77
|
+
name: My Wallpaper
|
|
78
|
+
slug: my-wallpaper
|
|
79
|
+
version: 1.0.0
|
|
80
|
+
permissions:
|
|
81
|
+
- keyboard
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
```tsx
|
|
85
|
+
import { useKeyboard } from "@fluxlay/react";
|
|
86
|
+
|
|
87
|
+
function Wallpaper() {
|
|
88
|
+
useKeyboard({
|
|
89
|
+
onKeyDown: event => console.log("down", event.code, event.modifiers, event.repeat),
|
|
90
|
+
onKeyUp: event => console.log("up", event.code)
|
|
91
|
+
});
|
|
92
|
+
return <div />;
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Same platform requirements as `useMouseEvents` (macOS Input Monitoring permission; UIPI on Windows).
|
|
97
|
+
|
|
98
|
+
### `useImeInput()`
|
|
99
|
+
|
|
100
|
+
Receives IME-composed text (Japanese / Chinese / Korean / etc.) for wallpapers that want to accept text input — for example a wallpaper-resident notepad, search box, or chat input.
|
|
101
|
+
|
|
102
|
+
Unlike `useKeyboard`, which sees raw pre-IME keystrokes from every window on the desktop, `useImeInput` only delivers text that the user explicitly directs at the wallpaper. Internally Fluxlay creates a tiny invisible proxy window per wallpaper; calling `activate()` (typically in response to the user clicking an in-wallpaper input field) gives that proxy keyboard focus so IME composition is routed through it. The wallpaper window itself never becomes a key window.
|
|
103
|
+
|
|
104
|
+
Wallpapers must declare the `ime-input` permission in `fluxlay.yaml`:
|
|
105
|
+
|
|
106
|
+
```yaml
|
|
107
|
+
# fluxlay.yaml
|
|
108
|
+
permissions:
|
|
109
|
+
- ime-input
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
```tsx
|
|
113
|
+
import { useImeInput } from "@fluxlay/react";
|
|
114
|
+
import { useEffect, useState } from "react";
|
|
115
|
+
|
|
116
|
+
function NotePad() {
|
|
117
|
+
const ime = useImeInput();
|
|
118
|
+
const [text, setText] = useState("");
|
|
119
|
+
|
|
120
|
+
useEffect(() => {
|
|
121
|
+
return ime.onCommit(committed => setText(prev => prev + committed));
|
|
122
|
+
}, [ime]);
|
|
123
|
+
|
|
124
|
+
return (
|
|
125
|
+
<div onClick={ime.activate} onBlur={ime.deactivate}>
|
|
126
|
+
<span>{text}</span>
|
|
127
|
+
{ime.composition !== null && <span style={{ opacity: 0.5 }}>{ime.composition}</span>}
|
|
128
|
+
</div>
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
The hook returns:
|
|
134
|
+
|
|
135
|
+
- `composition: string | null` — the in-progress composition text (e.g. `"か"` while typing `"漢字"`), or `null` when no composition is active
|
|
136
|
+
- `cursor: number` — caret position within `composition`, in code points
|
|
137
|
+
- `activate()` / `deactivate()` — start / stop receiving IME input. The hook automatically calls `deactivate()` on unmount
|
|
138
|
+
- `onCommit(handler)` — register a callback for finalized text. Returns a cleanup function
|
|
139
|
+
|
|
140
|
+
While `activate()` is in effect, `useKeyboard` events are paused on the same wallpaper to avoid IME candidate-window keys (arrows, Enter, Esc) double-firing as raw key events.
|
|
141
|
+
|
|
142
|
+
If the wallpaper does not declare `ime-input`, the hook becomes a no-op and emits one `console.warn` describing the missing declaration.
|
|
143
|
+
|
|
144
|
+
### `useProperties<T>()`
|
|
145
|
+
|
|
146
|
+
Returns the current values of the custom properties declared under `properties:` in `fluxlay.yaml`. Updates in real time when the user adjusts settings in the Fluxlay app.
|
|
147
|
+
|
|
148
|
+
```tsx
|
|
149
|
+
import { useProperties } from "@fluxlay/react";
|
|
150
|
+
|
|
151
|
+
type Props = {
|
|
152
|
+
particleCount: number;
|
|
153
|
+
themeColor: string;
|
|
154
|
+
showClock: boolean;
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
function Wallpaper() {
|
|
158
|
+
const { particleCount, themeColor, showClock } = useProperties<Props>();
|
|
159
|
+
return <div style={{ color: themeColor }}>{particleCount}</div>;
|
|
31
160
|
}
|
|
32
161
|
```
|
|
33
162
|
|
|
34
|
-
|
|
163
|
+
For `image` / `file` properties, the value is a local file path on the host OS (or `null` if the user has not selected a file). Pass it through `getPropertyFileUrl()` to obtain a URL the webview can load.
|
|
164
|
+
|
|
165
|
+
### `getPropertyFileUrl(path)`
|
|
166
|
+
|
|
167
|
+
Builds a URL the wallpaper webview can use to load a local file referenced by an `image` or `file` property. Returns `null` when the path is missing.
|
|
168
|
+
|
|
169
|
+
```tsx
|
|
170
|
+
import { useProperties, getPropertyFileUrl } from "@fluxlay/react";
|
|
171
|
+
|
|
172
|
+
function Wallpaper() {
|
|
173
|
+
const { customLogo } = useProperties<{ customLogo: string | null }>();
|
|
174
|
+
const url = getPropertyFileUrl(customLogo);
|
|
175
|
+
return url ? <img src={url} alt="logo" /> : null;
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### `useSystemMonitor(options?)`
|
|
35
180
|
|
|
36
181
|
Subscribes to real-time system and hardware metrics streamed from the Fluxlay backend. Returns CPU, memory, battery, network, disk, and other system information.
|
|
37
182
|
|
|
@@ -39,7 +184,11 @@ Subscribes to real-time system and hardware metrics streamed from the Fluxlay ba
|
|
|
39
184
|
import { useSystemMonitor } from "@fluxlay/react";
|
|
40
185
|
|
|
41
186
|
function Wallpaper() {
|
|
42
|
-
const { cpuUsage, memoryUsage, batteryLevel } = useSystemMonitor(
|
|
187
|
+
const { cpuUsage, memoryUsage, batteryLevel } = useSystemMonitor({
|
|
188
|
+
cpuIntervalMs: 500,
|
|
189
|
+
memoryIntervalMs: 1000,
|
|
190
|
+
batteryIntervalMs: 10000
|
|
191
|
+
});
|
|
43
192
|
return (
|
|
44
193
|
<div style={{ fontFamily: "monospace" }}>
|
|
45
194
|
<p>CPU: {cpuUsage.toFixed(1)}%</p>
|
|
@@ -50,25 +199,26 @@ function Wallpaper() {
|
|
|
50
199
|
}
|
|
51
200
|
```
|
|
52
201
|
|
|
53
|
-
|
|
202
|
+
| Option | Type | Default | Description |
|
|
203
|
+
| ----------------------- | -------- | ------- | ----------------------------------------- |
|
|
204
|
+
| `cpuIntervalMs` | `number` | `500` | CPU usage, per-core usage, and frequency. |
|
|
205
|
+
| `memoryIntervalMs` | `number` | `1000` | Memory and swap usage. |
|
|
206
|
+
| `networkIntervalMs` | `number` | `1000` | Network receive/transmit speed. |
|
|
207
|
+
| `diskIoIntervalMs` | `number` | `2000` | Disk read/write speed. |
|
|
208
|
+
| `diskSpaceIntervalMs` | `number` | `30000` | Disk capacity per mount point. |
|
|
209
|
+
| `batteryIntervalMs` | `number` | `10000` | Battery level and charging status. |
|
|
210
|
+
| `processIntervalMs` | `number` | `10000` | Running process count. |
|
|
211
|
+
| `loadAverageIntervalMs` | `number` | `5000` | System load average. |
|
|
54
212
|
|
|
55
|
-
|
|
56
|
-
sdk:
|
|
57
|
-
system_monitor:
|
|
58
|
-
cpu_interval_ms: 500
|
|
59
|
-
memory_interval_ms: 1000
|
|
60
|
-
battery_interval_ms: 10000
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
### `useAudio()`
|
|
213
|
+
### `useAudio(options?)`
|
|
64
214
|
|
|
65
|
-
Subscribes to real-time system audio information streamed from the Fluxlay backend. Returns RMS volume, peak level, and a
|
|
215
|
+
Subscribes to real-time system audio information streamed from the Fluxlay backend. Returns RMS volume, peak level, and a logarithmically-scaled frequency spectrum useful for building audio visualizers.
|
|
66
216
|
|
|
67
217
|
```tsx
|
|
68
218
|
import { useAudio } from "@fluxlay/react";
|
|
69
219
|
|
|
70
220
|
function Wallpaper() {
|
|
71
|
-
const { rms, peak, spectrum } = useAudio();
|
|
221
|
+
const { rms, peak, spectrum } = useAudio({ numBands: 64 });
|
|
72
222
|
return (
|
|
73
223
|
<div>
|
|
74
224
|
<p>Volume: {(rms * 100).toFixed(0)}%</p>
|
|
@@ -82,13 +232,19 @@ function Wallpaper() {
|
|
|
82
232
|
}
|
|
83
233
|
```
|
|
84
234
|
|
|
85
|
-
|
|
|
86
|
-
| ---------- |
|
|
87
|
-
| `
|
|
88
|
-
|
|
89
|
-
|
|
|
235
|
+
| Option | Type | Default | Description |
|
|
236
|
+
| ---------- | -------- | ------- | ----------------------------------- |
|
|
237
|
+
| `numBands` | `number` | `32` | Number of frequency spectrum bands. |
|
|
238
|
+
|
|
239
|
+
| Return field | Type | Description |
|
|
240
|
+
| ------------ | ---------- | -------------------------------------------------------------------------------------------- |
|
|
241
|
+
| `rms` | `number` | RMS (Root Mean Square) volume level (0.0 – 1.0). |
|
|
242
|
+
| `peak` | `number` | Peak volume level (0.0 – 1.0). |
|
|
243
|
+
| `spectrum` | `number[]` | Frequency spectrum bands on a logarithmic scale (0.0 – 1.0 each). Length matches `numBands`. |
|
|
244
|
+
|
|
245
|
+
On macOS, the Fluxlay desktop app captures system audio via the Core Audio Tap API and prompts the user for audio capture permission (`NSAudioCaptureUsageDescription`); macOS 14.2+ is required. The spectrum is A-weighted (IEC 61672) so the frequency balance matches human hearing.
|
|
90
246
|
|
|
91
|
-
### `useMediaMetadata()`
|
|
247
|
+
### `useMediaMetadata(options?)`
|
|
92
248
|
|
|
93
249
|
Subscribes to media metadata for the currently playing track from system media players (e.g. Spotify, Apple Music). Returns title, artist, album artwork, playback progress, and playback state.
|
|
94
250
|
|
|
@@ -96,7 +252,9 @@ Subscribes to media metadata for the currently playing track from system media p
|
|
|
96
252
|
import { useMediaMetadata } from "@fluxlay/react";
|
|
97
253
|
|
|
98
254
|
function Wallpaper() {
|
|
99
|
-
const { title, artist, artwork, isPlaying, elapsedTime, duration } = useMediaMetadata(
|
|
255
|
+
const { title, artist, artwork, isPlaying, elapsedTime, duration } = useMediaMetadata({
|
|
256
|
+
intervalMs: 1000
|
|
257
|
+
});
|
|
100
258
|
return (
|
|
101
259
|
<div>
|
|
102
260
|
{artwork && <img src={artwork} alt="Album art" width={200} />}
|
|
@@ -107,13 +265,9 @@ function Wallpaper() {
|
|
|
107
265
|
}
|
|
108
266
|
```
|
|
109
267
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
sdk:
|
|
114
|
-
media_metadata:
|
|
115
|
-
interval_ms: 1000
|
|
116
|
-
```
|
|
268
|
+
| Option | Type | Default | Description |
|
|
269
|
+
| ------------ | -------- | ------- | --------------------------------- |
|
|
270
|
+
| `intervalMs` | `number` | `1000` | Polling interval in milliseconds. |
|
|
117
271
|
|
|
118
272
|
| Field | Type | Description |
|
|
119
273
|
| -------------- | ---------------- | ---------------------------------------------------- |
|
|
@@ -141,14 +295,14 @@ function Wallpaper() {
|
|
|
141
295
|
}
|
|
142
296
|
```
|
|
143
297
|
|
|
144
|
-
| Option | Type
|
|
145
|
-
| ----------------- |
|
|
146
|
-
| `refreshInterval` | `number`
|
|
147
|
-
| `showStdout` | `boolean`
|
|
148
|
-
| `showStderr` | `boolean`
|
|
149
|
-
| `terminal` | `TerminalInstance` | — | Terminal instance from `useTerminal`.
|
|
150
|
-
| `columns` | `number`
|
|
151
|
-
| `lines` | `number`
|
|
298
|
+
| Option | Type | Default | Description |
|
|
299
|
+
| ----------------- | -------------------------- | ------- | ------------------------------------------------------------------------------------------------------- |
|
|
300
|
+
| `refreshInterval` | `number` | `30000` | Auto-refresh interval in ms. `0` to disable. |
|
|
301
|
+
| `showStdout` | `boolean` | `true` | Write stdout to the linked terminal. |
|
|
302
|
+
| `showStderr` | `boolean` | `false` | Write stderr to the linked terminal. |
|
|
303
|
+
| `terminal` | `TerminalInstance \| null` | — | Terminal instance from `useTerminal`. When set, the terminal's dimensions override `columns` / `lines`. |
|
|
304
|
+
| `columns` | `number` | — | Pseudo-terminal column width. |
|
|
305
|
+
| `lines` | `number` | — | Pseudo-terminal line height. |
|
|
152
306
|
|
|
153
307
|
Returns `{ execute, isRunning, error, result }`.
|
|
154
308
|
|