This is an old revision of the document!
Hive Driver for PIXILAB Blocks
A driver, a media feed and three ready-made blocks for Hive media players, controlled through the Nectar API (apiVersion 1.0). The driver publishes every layer, the play list, the media catalogue and the timecode cue lists, and can act as a Blocks clock follower so a Hive layer or play list runs in step with a Blocks timeline.
| Component | Role | Transport | Feedback |
|---|---|---|---|
| Hive (driver) | Layers, play list, media, cue lists, synchronisation | REST on port 80 and a patch WebSocket on port 9002 (Network Device type: TCP) | Yes. Watches state and reads clocks. |
| HiveMedia (feed) | The player's media folder by folder, with cached thumbnails | Reads the driver; copies thumbnails over HTTP | Follows the driver's mediaRevision |
| Hive/TestPanel, Hive/MediaBrowser, Hive/MediaPanel (blocks) | A bench panel, a folder browser and a flat media list | Property bindings only |
Developed and verified against a Hive BeeBlade player on the bench, September–October 2026. Both transports are used at once: the WebSocket carries live state, REST carries commands.
Source files
script/driver/Hive.ts script/feed/HiveMedia.ts public/block/Hive/TestPanel public/block/Hive/MediaBrowser public/block/Hive/MediaPanel
If this document conflicts with the source code, the header comment in script/driver/Hive.ts takes precedence.
1. Device setup
Create a TCP Network Device with the following settings:
- Address: Player IP address
- Port: 80
The driver opens the patch WebSocket on port 9002 by itself. Nothing else needs configuring for a player out of the box.
Driver options
All options are JSON, set on the Network Device page, and all are optional:
{
"uiDerivedPaths": true,
"timeReadInterval": 5000,
"username": "",
"password": ""
}
| Option | Default | Description |
|---|---|---|
port | 80 | Nectar HTTP port. |
wsPort | 9002 | Patch WebSocket port. |
useHttps | false | Use https:// and wss:// rather than http:// and ws://. A password-protected player cannot be logged in to over https see Password protection. |
verbose | false | Log every request and sync decision. |
keepAlive | false | True to stop sending Connection: close with each request. |
autoInit | true | Read the player's structure at startup. |
maxLayers | 8 | Most layers published, whatever the player reports. |
uiDerivedPaths | true | False to use only the documented API. See UI-derived paths below for what stops working. |
defaultPlayMode | 2 | Running mode used before the driver has seen one: 2 is Loop Forward, 4 is Play Once Forward. |
timeReadInterval | 5000 | mS between reads of a running layer's clock. |
playlistTimeReadInterval | 1000 | mS between reads of the running play list's clock. |
pollInterval | 1000 | mS between REST poll passes while the stream is down. |
reconnectInterval | 5000 | mS before retrying a dropped stream connection. |
maxMessageSize | 262144 | Bytes. A JSON document watch makes for a big frame. |
probeInterval | 30000 | mS between HTTP probes, 0 to disable. |
mediaCheckInterval | 60000 | mS between checks of the media catalogue for files changed outside Hive's UI, 0 to disable. |
driftTolerance | 100 | mS the published time may drift before it is re-anchored. |
syncPollInterval | 3000 | mS between drift checks while synchronising. |
syncDrift | 250 | mS of drift tolerated before the position is corrected. |
syncJump | 1000 | mS of sudden change treated as a seek rather than drift. |
syncLatency | 0 | mS added to the commanded position, to offset latency. |
syncRate | true | Match the master's rate as well, using PLAY SPEED. |
syncStopAction | "auto" | A stopped sync source: auto stops if it rewound to the start and pauses otherwise; pause and stop force one. |
syncDeadDelay | 1000 | mS a dead sync source a stopped Blocks timeline must stay dead before it counts as stopped. |
scrubInterval | 200 | mS between seeks while time is being driven, 0 to disable. |
scrubDrift | 150 | mS a written position may differ before it counts as a move. |
username, password | "" | Nectar login, needed only where the player has password protection turned on. |
2. Player properties
| Property | Type | Description |
|---|---|---|
connected | Boolean, read-only | The player answers, its stream is up and, on a protected player, its login worked so commands are obeyed and state is current. |
deviceName | String, read-only | Device name as set on the player, from its System Settings. |
upTime | Number, read-only | Seconds Hive's renderer has been running. |
mediaRevision | Number, read-only | Goes up whenever the media catalogue or its lengths change. A feed refreshes on it. |
passwordProtected | Boolean, read-only | Whether the player requires a login. Read at startup and at every probeInterval. |
testMode | Boolean | BeeMonitoring's test flag. Handy while commissioning a cluster. |
3. The play list
| Property | Type | Description |
|---|---|---|
playlistStatus | String: play, pause, stop | The play list's state; stop means Use Playlist is off. Writing it drives the list. |
playlistEnabled | Boolean | Use Playlist, the tick box on Hive's play list page. |
playlistTime | TimeFlow, read-only | Position in the whole play list the clock to follow while the play list is on. |
playlistRowTime | TimeFlow, read-only | Position within the current row. |
playlistRow | Number, read-only | Current row, 1 for the first, 0 for none. |
playlistRowCount | Number, read-only | Rows in the play list. |
playlistRowName | String, read-only | File the current row plays, with its folder. |
playlistRowDuration | Number, read-only | Length of the current row, mS. |
playlistDuration | Number, read-only | Length of the whole play list, mS, less the transition overlaps. |
playlistTransitionDuration | Number, read-only | Cross-fade between rows, mS. |
playlistTargetLayer | Number, read-only | Layer the play list goes out on. Set up in Hive's UI. |
playlistMarker | String | Name of the marker last passed, as Hive's UI writes it 5: Chapte1. Writable: write a marker name to jump there, which is how a panel button can do it. |
playlistMarkers[] | Indexed property, read-only | One member per marker: name, number, label, time (mS), timeText (m:ss). |
playlistSyncSource | String, read-only | Path of the Blocks time property the play list follows, empty if not synchronising. |
Play list callables
| Callable | Description |
|---|---|
playlistPlayRow(row, then) | Play a row of the play list. |
playlistSeek(time, then) | Jump to a position in the whole play list. |
playlistGoToMarker(number, then) | Jump to a marker by its number, as Hive's UI shows it. |
playlistGoToMarkerByName(name, then) | Jump to a marker by name. |
playlistStartSync(fullPath) | Slave the play list to a Blocks TimeFlow property, making Blocks the master clock. |
playlistStopSync(ending) | Stop following. Ends by stopping the list; pass pause or keep for the alternatives. |
The then argument says what to do once the jump has landed: play, pause or stop. Left out, the list keeps doing whatever it was doing. The same argument is on the layer callables that move the play head.
4. Layers
Layers are published as a named aggregate, layers.layer_1, layers.layer_2 and so on. The numbering is Hive's own and cannot be renamed.
Transport and selection
| Property | Type | Description |
|---|---|---|
status | String: play, pause, stop | Playback. stop means the layer shows black (0000_BLACK.jpg). While the play list uses the layer, this is the play list's state. |
playMode | Number | Hive's play mode: 7 pauses, 6 is its own Stop, and every other value runs 2 Loop Forward, 4 Play Once Forward, 8 Bounce. |
speed | Number, 0…1 | 0 halts, 0.5 is normal speed, 1 is ten times. |
time | TimeFlow | Position and rate. Two-way: write rate 0/1 to pause and play, or a new position to seek. |
media | Number | Media by the number Hive shows before the name, within the selected folder. 0 is black, which stops the layer. |
folder | Number | Media folder: 0 is the media root, then Hive's folders alphabetically. |
mediaName | String, read-only | Name of the selected media. |
folderName | String, read-only | Name of the selected folder, empty for the media root. |
fileName | String, read-only | What the layer shows right now. While the play list uses the layer, its current row. |
duration | Number, read-only | Length of the selected media, mS. |
intensity | Number, 0…1 | Opacity. |
volume | Number, 0…1 | 1 is 100 % on Hive's Parameters page. Only for video carrying uncompressed embedded audio. |
syncSource | String, read-only | Path of the Blocks time property this layer follows. |
media and folder wrap round, so a panel's +/− buttons can run past either end: past a folder's last file comes its first, below 0 comes its last, and a number no file uses moves on to the next file in the direction of travel. Changing folder selects that folder's first file. Media 0 is left alone, since it is black and stops the layer.
Geometry, colour and effects
| Property | Type | Description |
|---|---|---|
scale | Number, 0…1 | Zoom. 0.5 is 100 %; below zooms out, above zooms in. |
framingMode | String | How media fits the output: LETTERBOX, CROP, STRETCH, MULTI LETTERBOX, CENTERED. |
aspectRatio | Number, 0…1 | 0.5 is none; below squeezes horizontally, above vertically. |
positionX, positionY | Number, 0…1 | 0.5 is centred. |
rotationX, rotationY, rotationZ | Number, 0…1 | 0.5 is none. The extremes of rotationX auto-rotate. |
blendMode | String | Blend against the layers below: ALPHA, ADDITIVE, MULTIPLY, DIFFERENCE, SCREEN and 27 more, through to GLITCH. |
red, green, blue | Number, 0…1 | 0.5 leaves the channel at 100 %. |
hue | Number, 0…1 | Across the full 360 degrees. |
saturation, contrast | Number, 0…1 | 0.5 leaves them alone. |
lut | Number | LUT from the player's LUTS folder, 0 for none. |
strobe | Number, 0…1 | Below 0.5 is on/off strobe slow to fast, above is punch strobe. |
inFrame, outFrame | Number | Frame numbers playback starts from and ends or loops at. |
fx1Select, fx2Select | Number | Effect by number, 0 for none. Hive documents 1 Old TV, 2 Sepia, 3 Feedback, 4 Blur and on to 15. |
fx1Opacity, fx2Opacity | Number, 0…1 | Effect opacity. |
transitionDuration | Number, mS | Cross-fade duration. |
transitionMode | String | Cross-fade mode, named as blendMode. |
blendMode, transitionMode and framingMode are enumerated string properties, so the editor offers a drop-down of the names rather than a number.
Timecode cue list
| Property | Type | Description |
|---|---|---|
cueListEnabled | Boolean | Whether this layer follows its timecode cue list. |
cueCount | Number, read-only | Cues in the list. |
cue | Number, read-only | Current cue, 1 for the first. |
cueName | String, read-only | Media the current cue plays. |
cueStart | String, read-only | Timecode the cue triggers at, hh:mm:ss:ff. |
cueClock | TimeFlow, read-only | Timecode clock the cue list follows. |
mtcHour, mtcMinute, mtcSecond, mtcFrame | Number | Timecode trigger point. Only active with TC Offsets set to Layer Param. |
cue, cueName, cueStart and cueClock need uiDerivedPaths.
Layer callables
| Callable | Description |
|---|---|
selectMedia(folder, media, then) | Select folder and media together one swap on a playing layer, where setting folder and media separately makes two. |
setTimePosition(time, then) | Jump to a position in the media on the layer. |
playFrom(time) | Play the selected media from a given position. |
toggle() | Run the layer if it is stopped or paused, pause it if it is running. |
setFxParam(effect, param, value) | Set one of an effect's 16 parameters. |
setFxParams(effect, p1 … p16) | Set any of them together in one call; a parameter left out keeps its value. |
readFxParam(effect, param) | Read one parameter into the log. |
logCues() | Log this layer's cue list, with each cue's trigger time and length. |
refresh() | Re-read every watched value on this layer. |
startSync(fullPath) / stopSync(ending) | Follow, or stop following, a Blocks clock. |
5. The media catalogue
The player's files are published twice over, from one catalogue read:
mediaList[]an indexed property, folder then number order, for a replicated list.media.<key>the same rows keyedISE_2026_0007orroot_0001: the folder name, orroot, then the 4-digit number. A key survives folders coming and going, where a folder number shifts, so a binding made through a key keeps working.
| Property | Type | Description |
|---|---|---|
mediaName, folderName, mediaKey | String, read-only | The file, its folder and its key. |
media, folder | Number, read-only | The numbers a layer selects it by. |
kind | String, read-only | video, image or other, from the file extension. |
duration, lengthText | Number / String, read-only | Length in mS, and as m:ss. |
playing | Boolean, read-only | Playing on some layer right now. |
onLayers | String, read-only | The layers showing it, e.g. 1,2. Paused counts; stopped does not. |
layer | Number | The layer showing it, lowest if several, 0 if none. Write a layer number to play it there, 0 to stop it wherever it plays. |
onLayer1 … onLayer8 | Boolean | One per layer: true while that layer shows the file. Write true to play it there, false to stop just that layer, leaving the others alone. |
Black has a member of its own, media.root_0000 (0000_BLACK.jpg), which mediaList leaves out. Its onLayerN reads true while that layer is stopped, writing true stops the layer, and writing false plays the layer's selection again so a panel can put a layer to black from the same list it picks media from.
The catalogue is re-read at startup, on refresh(), when refreshMedia() finishes, when Hive's UI rewrites its media list (an upload or a delete, within about a second), and every mediaCheckInterval for changes nothing announces.
6. Maintenance callables
| Callable | Description |
|---|---|
refresh() | Re-probe the player and re-read every published value. |
refreshMedia() | Refresh the media list, as REFRESH LIST on Hive's Media tab does. Returns only when it is done the refresh, any cache rebuild still running and a re-read of the list so a Task's next step sees the new files. Fails, stopping a Task set to abort on error, if the player refuses it or a rebuild takes over five minutes. |
stopAll() | Stop every published layer. |
resendFromQueen() | Ask the queen to rebroadcast its parameters to every worker. |
timecodeCueList(layer, on) | Turn timecode cue-list triggering on or off for one layer. |
verboseLogging(verbose) | Turn detailed logging on or off without editing the options. |
reset() | Reinitialise the driver, discarding everything it knows. |
system.logging
Eleven read-only callables that print what the player says into the Blocks log: logNames, logMedia, logPlaylist, logSystemInfo, logStorage, logNetwork, logPlaybackLog, logHiveLog, logNectarLog, logDeviceLog and logSyncStatus (the BeeSync and PTP summary how well a cluster is locked together).
system.logging.lastLog holds what the last of them printed, so a panel or a Task can show it without reading the log.
patch
Generic access for anything the driver does not publish the vendor states the path list is not exhaustive, so this is the escape hatch:
| Callable | Description |
|---|---|
patch.paths.patchDouble(path, value) | Read or write any numeric patch path. Omit the value to only read and log it. |
patch.paths.patchString(path, value) | The same for a string path. |
patch.documents.patchJson(path, json) | Read or replace a whole JSON document. |
patch.documents.updateJson(path, operations) | Change one field of a document, leaving the rest alone (RFC 6902). |
Note: an unknown patch path is not refused. It reads back as 0, "" or null with success: true, so a mistyped path looks like a working one with a boring value.
7. Behaviour
Hive has no transport verbs. Play, pause and stop are writes to PLAY MODE, and stop is media: 0000_BLACK.jpg, which Hive keeps in every folder. The driver hides that behind status, and remembers the running mode so a layer authored as Play Once Forward is not quietly turned into a loop.
The player is authoritative. State is watched over the WebSocket and applied as it arrives, so a change made in Hive's own UI shows up in Blocks without polling.
Clocks are read, not watched. A watch on a running clock pushes a message every frame measured at 50 messages/s per clock path on the bench player, 201 messages/s and 25.6 kB/s in total with a play list running. The API offers no throttle or deadband, so instead the driver reads a running layer's clock every timeReadInterval (5 s) and the play list's every playlistTimeReadInterval (1 s), with one extra read just after a row should end. A still clock is watched, since it sends nothing until it moves. The trade-off: a pause made in Hive's UI shows within about a second, a seek on a running layer within five.
A still is published still. Hive runs a picture or a .url page as a one-second clip on a loop, so its clock wraps every second. The driver publishes time at 0 with rate 0 for those, as Hive's own progress bar does, while status stays play.
Stopping a play list takes two steps. The driver pauses the list first, waits 400 mS and then turns Use Playlist off, which leaves the target layer clean. A play or pause command sent meanwhile cancels the pending turn-off.
The play list owns its target layer. Transport, media and seek commands to that layer are refused while the list is on, with one warning in the log. Setting media on it is remembered and applied once the list lets go.
Commands go over REST, state comes over the WebSocket. If the stream drops, the driver falls back to polling the watched paths every pollInterval and says so once; connected goes false while either half is missing.
Synchronisation
startSync(path) on a layer, or playlistStartSync(path), makes a Blocks TimeFlow property the master. The driver then follows position and, with syncRate, rate. A drift beyond syncDrift is corrected; a change beyond syncJump counts as a seek. A dead master a stopped Blocks timeline is treated per syncStopAction.
Hive has ratecontrol - PLAY SPEED, 0…1, where 0.5 is normal so it can follow a master's rate rather than chase its position.
Password protection
Turn protection on in Hive's UI and every route each /api call, the thumbnails and the UI itself answers a request without a session with a redirect to the login page. Give the driver username and password in the options and it logs in by itself; the session lasts an hour, and the next request after that logs in again.
Important: the login is sent over the device's own TCP connection, not through the HTTP client, because Hive sets the session cookie on a redirect that the client follows and discards. One consequence: a protected player cannot be logged in to over https, since that raw connection speaks plain HTTP only.
Without a working login connected reads false, even though the stream is up, because every command would be refused. The log says once what to add.
Port 9002 has no authentication of any kind, and password protection does not cover it. Anything that can reach the player there can read and write any patch path, and stop the show. Keep it on a trusted network.
8. Blocks and the media feed
script/feed/HiveMedia.ts publishes, for every network device running this driver:
| Feed instance | Rows |
|---|---|
<Device>_folders | One per media folder holding files |
<Device>_folderPages | The same rows again, for a second list on the same Spot |
<Device>_root | The files in the media root |
<Device>_folder_<name> | The files in that folder |
<Device>_folderAt_<n> | The files of the folder at row n, so a Book page can pick its own feed |
Each file row carries subPath, the path of its live member in the driver's media aggregate, so a row's lamp and buttons bind through it Network.[Relative.subPath].playing, .onLayer1 and so on.
Thumbnails are copied, not linked. The feed caches each one under /public/hivethumbs/<device>/ with the player's ETag in the file name, and a row's thumbnail is that served path so Spots never need to reach the player. On a protected player the feed borrows the driver's session to fetch them.
The three blocks are ready to use and are described in their own README.md:
- Hive/TestPanel every layer control, the play list and its markers, for the bench.
- Hive/MediaBrowser the media folder by folder, with thumbnails, one page per folder.
- Hive/MediaPanel the whole media list, flat.
9. UI-derived paths
Hive's documented path list is explicitly not exhaustive, and some useful state lives on paths found in the player's own web UI rather than in the catalogue. Those are used only while uiDerivedPaths is true, which is the default.
Set it false and the driver uses the documented API alone. What stops working:
playlistTimeandplaylistRowTimestay at 0, so nothing can follow the play list's clock;cue,cueName,cueStartandcueClockstop reporting;- the play list's pause goes through Use Playlist alone, so stopping it may leave a video running;
- seeks within a layer use the documented path only.