Integrations
Chrome extension guide
Chrome extension Beta. Named web platforms are examples only, not confirmed integrations.
The neuromore Chrome extension connects a browser tab to neuromore Studio and applies feedback values from a running session to the page: the volume of audio and video elements and the brightness of the page. This page describes the browser client, the WebSocket protocol, the volume and brightness mapping, and how to install, run and troubleshoot the extension. For the big picture see Browser neurofeedback; for a step-by-step test see Browser test workflow.
Safety: Feedback can change screen brightness and volume quickly. Avoid this setup if you are sensitive to flashing or flickering light. Keep volume moderate. Stop if you feel uncomfortable. To stop feedback, end the session with the stop button in the Session Control window (tooltip “End the Session”), or click Disconnect in the Chrome extension popup.
How the browser client works
Section titled “How the browser client works”The extension (Manifest V3, name “neuromore”, version 1.0.0) has a popup with Connect and Disconnect buttons and a content script. It asks only for the activeTab and scripting permissions. Nothing is injected on page load. When you click Connect, the popup injects the content script into the top frame of the active tab. The script opens a WebSocket to neuromore Studio and sends the current URL. It then reports play, pause and ended events for <video> and <audio> elements in that document, including elements added later.
The site links in the popup (Netflix, YouTube, Prime Video, Spotify, Apple Music) are examples only. They open the site in a new tab and do not connect anything. The popup’s styles are local, so it does not need internet access.
Status: Beta for plain <video> and <audio> elements. DRM players and sites that route audio through the Web Audio API may not respond.
Connection and message flow
Section titled “Connection and message flow”The content script connects to a fixed address and has no configuration UI.
| Setting | Value |
|---|---|
| Address | ws://127.0.0.1:4547 (WS_URI in extension/) |
| Studio default port | 4547, set in NMStudio > Settings > Network > Websocket Server > Listen TCP Port |
| Transport | Plain WebSocket (ws://), JSON text messages plus binary feedback frames |
| Addressing | neuromore Studio sends every message to all connected clients, so two connected tabs both respond |
Caution: The WebSocket interface is an unauthenticated local protocol. Keep its port (4547 by default) firewalled and don’t expose it to untrusted networks.
Studio starts the server when it starts, in both 1.7.3 and 1.8.2. You don’t need a classifier or an experience loaded for the extension to connect. A changed port takes effect only after you restart Studio. The extension always connects to 4547, so keep that port unless you also change WS_URI in your copy of the extension. If the port is already in use, Studio shows no message.
All JSON messages have the shape {"header":{"type":"<TYPE>"},"data":{...}}.
| Type | Direction | Data | Notes |
|---|---|---|---|
ON_URL_OPENED |
Browser to Studio | {"url":"<page URL>"} |
Sent once when the socket opens |
ON_ |
Browser to Studio | {"media_ |
On play |
ON_ |
Browser to Studio | {"progress":<0-1>} |
On pause. 0 when the media length is unknown, as with a live stream |
ON_ |
Browser to Studio | {"progress": |
Only when media ends |
ON_CLASSIFIER_LOADED |
Studio to browser | {"name": |
When the active classifier changes. The extension ignores it |
ON_, ON_EXPERIENCE_LOADED |
Studio to browser | {"name":"<name>"} |
The extension ignores them |
ON_SESSION_STARTED |
Studio to browser | {"start": |
Followed by ON_FEEDBACK_LAYOUT. The extension ignores it |
ON_FEEDBACK_LAYOUT |
Studio to browser | {"feedbacks": |
Defines the node index used in binary frames |
ON_SESSION_STOPPED |
Studio to browser | {} |
The extension clears its layout and restores the page’s own volume and brightness |
| BROWSER_START_PLAYER | Studio to browser | {"progress": |
Seeks the first <video> to that fraction of its length, then plays it. See the note below |
| BROWSER_PAUSE_PLAYER | Studio to browser | {} |
Pauses the first <video> |
| BROWSER_STOP_PLAYER | Studio to browser | {} |
The extension ignores it |
| OPEN_URL | Studio to browser | {"url":"<URL>"} |
Opens the URL in a new tab, for http and https URLs only |
The Start Browser Player action in a state machine labels its attribute “Progress (s)”, but the value is a relative position from 0.0 to 1.0. Its default of 1.0 means the end of the media, so set the position you want. If the browser refuses to play or go fullscreen, the extension logs a warning in the tab’s developer console.
On every new connection Studio replays its current state, including ON_SESSION_STARTED and ON_FEEDBACK_LAYOUT if a session is already running, so connecting late works. The player and URL messages only matter for state machines; volume and brightness do not depend on them.
Feedback values arrive as binary frames: one frame per feedback node every 100 ms (about 10 Hz) while a session runs, independent of the node’s Resolution setting. Byte order is little-endian.
| Bytes | Type | Content |
|---|---|---|
| 0-1 | uint16 | Message type, always 1 (custom feedback) |
| 2-3 | uint16 | Node index: position in the feedbacks array of ON_FEEDBACK_LAYOUT |
| 4-11 | float64 | Value of channel 0 |
| 12 onwards | float64 each | One slot per further input channel; all slots carry the same value |
The feedbacks array lists every feedback-type node of the active classifier (Custom Feedback, Volume Control, Brightness Control and the environment control nodes), sorted by vertical position in the canvas. The extension resolves the node index through that array and matches on name.
A node with no input connected sends no frames. A node with an input connected but no samples yet sends 0.0, for example when a device is not streaming or a processing chain is still filling its window. The extension applies that value, so the page content goes black and media is muted until data flows.
Volume control
Section titled “Volume control”The extension matches the node name “Volume Control” exactly. This is the node’s user-editable name. Studio sets it when you drag a Volume Control node from the Output category of the palette, so leave the default name in place. The extension ignores a renamed node, with no message.
The value is assigned to .volume of every <audio> and <video> element in the page. The extension looks up the elements again for each frame, so elements added after Connect are covered. It remembers each element’s own volume and restores it when the session stops or the connection closes. It does not reach media inside iframes or shadow roots.
The value should be between 0.0 and 1.0. Studio declares this range but does not clamp: an out-of-range sample sets the node error “Value not in range” and the raw value is still sent. The extension clamps it to 0.0 to 1.0 and ignores values that are not finite numbers. The node error matters even so, see Troubleshooting.
The node’s Mode attribute (default Studio Volume) does not change what is sent over WebSocket to the extension, but the default also scales the audio in Studio’s Experience window. Status: Beta.
Brightness control
Section titled “Brightness control”The extension matches the node name “Brightness Control” exactly. This is the default name from the Output category of the palette. The value is applied as a CSS filter: brightness(<value>):
| Page | Target |
|---|---|
Host is youtube.com or a subdomain, and the page has an element with class html5- |
The first such element |
| Any other page | document.body |
1.0 is the original brightness. At 0.0 the page content goes black, or on YouTube the video. A background painted on the page’s canvas can stay bright. As with volume, an out-of-range sample sets the node error “Value not in range”, and the extension clamps it: values above 1.0 show as 1.0, so the page never gets brighter than its original level, and negative values show as 0.0. This is brightness, not alpha or opacity: the page does not become transparent. The extension changes only the filter style and restores the page’s own filter when the session stops or the connection closes.
A filter on the page normally also dims embedded iframes, and native fullscreen video may not show it. Both are browser behaviour. Status: brightness Beta; an opacity mode is R&D and not implemented.
Install
Section titled “Install”Install the extension from its GitHub repository as an unpacked extension:
- Open github.com/neuromore/chrome-plugin, click Code, then Download ZIP.
- Unpack the zip file anywhere you can keep it. Chrome loads the extension from this folder each time.
- Open Chrome and go to
chrome://extensions. - Enable Developer mode.
- Click “Load unpacked”.
- Select the folder that contains
manifest.json: theextensionfolder inside the unpacked download. - Check that the extension appears in the list, then pin it to the toolbar.
Chrome is the only browser the extension targets (Beta). Firefox and Safari are Not available, see Browser constraints.
Read the safety note at the top of this page first.
- Start neuromore Studio and sign in with your neuromore account. The WebSocket server starts with Studio.
- Open the website of your choice in a tab.
- Click the extension icon, then Connect.
- Chrome may ask whether the site can access your local network. Allow it, or the connection fails. The popup can close at this point, possibly because the prompt takes focus. If it does, answer the prompt and reopen the popup. Whether the connection works on a given site also depends on that site’s security policy and Chrome’s rules.
- The button shows “Connected” and stays disabled while connected. If it still shows Connect, or the popup shows an error, see Troubleshooting.
- In Studio, load a classifier with a Volume Control node, a Brightness Control node, or both, each fed a signal from 0.0 to 1.0. To build one with a synthetic signal, follow Step A of Phase 2 of the Browser test workflow. Use a slowly changing signal: the extension applies each value directly, with no smoothing, up to 10 times a second.
- In the Session Control window, click the Begin Session button. See Running a session.
- Frames arrive every 100 ms and the page responds. Pause in Studio does not stop the frames and does not pause media in the browser, so brightness and volume can keep changing while paused.
- Stop the session when done, with the stop button (tooltip “End the Session”). The page returns to its own volume and brightness, and the tab stays connected for the next session. Disconnect in the popup, or closing Studio, also restores the page.
A full page load or reload ends the content script and closes the socket, and there is no automatic reconnect. Click Connect again. Navigation inside a single-page site can keep the socket open. If the button already shows “Connected”, you don’t need to do anything.
Troubleshooting
Section titled “Troubleshooting”| Symptom | Cause | What to do |
|---|---|---|
| The popup shows “Cannot connect on this page. Open a normal website, reopen the extension, then click Connect.” | The active tab is a page that does not allow injection, such as a chrome:// page or the Chrome Web Store |
Do what the message says: open a normal website tab. |
| The popup shows “Could not connect. Check that neuromore Studio is running on port 4547, and that this site is allowed to access your local network.” Or the button still shows Connect after you answered Chrome’s prompt and reopened the popup. | Studio is not running, its port is not 4547, or the site does not have local network permission | Start Studio first; it does not need a classifier or an experience loaded. In NMStudio > Settings > Network check that Websocket Server > Listen TCP Port is 4547, and restart Studio after changing it. If the setting is missing, your Studio is too old: see Setup. To allow local network access: open the site’s settings from the icon to the left of the address bar, allow Local network access, reload the page, then click Connect again. |
| Connection fails although Studio is running on 4547 | Another process holds the port. Studio shows no message for this | Check for the other process: lsof -i :4547 on macOS or Linux, netstat - on Windows. Close it and restart Studio. |
| Begin Session is disabled and Session Control shows “A graph contains errors” | A node has an error. A signal outside 0.0 to 1.0 sets “Value not in range” on a feedback node, also before a session starts. The Signal Generator’s defaults give -1 to 1 | Scale the signal to 0.0 to 1.0 in the classifier. The error clears when in-range samples arrive. |
| Connected, but nothing changes | No session running, or the feedback node is named differently, or it has no input | Start the session. Keep the default names “Volume Control” and “Brightness Control”. Check the node has an input connected. |
| The page content goes black or media is muted as soon as the session starts | The node has an input but no samples yet, so it sends 0.0 | Check that the device is streaming and that the processing chain produces output. Stop the session or click Disconnect to restore the page. |
| No volume change | No <audio> or <video> element in the page, media inside an iframe or shadow root, or a DRM or custom player |
The extension does not reach media inside iframes or shadow roots. Playback through DRM or the Web Audio API may not respond. Try a page with a plain media element. |
| Brightness stuck at the top level | Values are 1.0 or higher | Scale the signal to 0.0 to 1.0 in the classifier, and look for “Value not in range” on the node. |
| Brightness not visible | Video in native fullscreen | Leave fullscreen. |
Node errors show on the node and in the Session Control window. The extension logs to the tab’s developer console.
Licensing
Section titled “Licensing”Licensing: see neuromore Licensing, the Terms & Conditions, the End User Agreement and the Privacy Policy.