A script is a small piece of code that changes the game on your computer only. Nobody else sees it, and it does not need anyone's approval. Scripts run through a free browser extension called Tampermonkey, the same one players used on the original EyeWire.
1. Install Tampermonkey
- Add Tampermonkey from the Tampermonkey site. It links to the right store for your browser.
- In Chrome or Edge, open
chrome://extensions, click Details on Tampermonkey, and switch on Allow User Scripts. On older versions the switch is Developer mode, at the top right of that page. Without it, scripts do nothing and give no error.
2. Add your first script
- Click the Tampermonkey icon, then Create a new script.
- Delete everything in the editor and paste the script below.
- Press Ctrl+S to save, then reload the game.
A Layers? button appears at the bottom left. Click it to list the layers in your view.
// ==UserScript==
// @name EyeWire II: list my layers
// @match https://eyewire-ii-community-dot-brain-wire-dot-seung-lab.ue.r.appspot.com/*
// @grant none
// @run-at document-idle
// ==/UserScript==
(function () {
'use strict';
// The game takes a few seconds to start, so wait for the viewer.
const wait = setInterval(() => {
if (!window.viewer) return;
clearInterval(wait);
const btn = document.createElement('button');
btn.textContent = 'Layers?';
btn.style.cssText = 'position:fixed;bottom:12px;left:12px;z-index:9999;padding:6px 10px;';
btn.onclick = () => {
const state = window.viewer.state.toJSON();
alert((state.layers || []).map(l => `${l.name} (${l.type})`).join('\n'));
};
document.body.appendChild(btn);
}, 1000);
})();How a script is put together
- The top block (between the
==UserScript==lines) tells Tampermonkey where to run.@matchis the game's address. If you play at a different address, add another@matchline for it. @grant noneruns the script inside the page. That is what lets it see the game. Leave it as is.window.vieweris the 3D viewer.window.viewer.state.toJSON()returns your whole view: layers, selected cells, position and annotations.window.viewer.state.changed.add(fn)calls your function every time the view changes.
Example: live position readout
Shows your current x, y, z at the bottom of the screen and updates as you move.
// ==UserScript==
// @name EyeWire II: position readout
// @match https://eyewire-ii-community-dot-brain-wire-dot-seung-lab.ue.r.appspot.com/*
// @grant none
// @run-at document-idle
// ==/UserScript==
(function () {
'use strict';
const wait = setInterval(() => {
if (!window.viewer) return;
clearInterval(wait);
const box = document.createElement('div');
box.style.cssText = 'position:fixed;bottom:12px;left:12px;z-index:9999;padding:6px 10px;'
+ 'border-radius:6px;background:rgba(8,14,28,.9);color:#dce6f5;font:12px monospace;';
document.body.appendChild(box);
const show = () => {
const p = window.viewer.state.toJSON().position || [];
box.textContent = p.map(n => Math.round(n)).join(', ');
};
show();
window.viewer.state.changed.add(show);
}, 1000);
})();Example: copy your selected cell IDs
Press Shift+C to copy the IDs of every cell selected in your view. It does nothing while you are typing in a box.
// ==UserScript==
// @name EyeWire II: copy selected cell IDs
// @match https://eyewire-ii-community-dot-brain-wire-dot-seung-lab.ue.r.appspot.com/*
// @grant none
// @run-at document-idle
// ==/UserScript==
(function () {
'use strict';
function selectedCells() {
const layers = window.viewer.state.toJSON().layers || [];
return layers.filter(l => l.type === 'segmentation')
.flatMap(l => l.segments || [])
.filter(id => !String(id).startsWith('!')); // "!" marks a hidden cell
}
window.addEventListener('keydown', e => {
if (!window.viewer || !e.shiftKey || e.code !== 'KeyC') return;
if (e.target.closest('input, textarea, [contenteditable]')) return;
const ids = selectedCells();
navigator.clipboard.writeText(ids.join(', '));
console.log(`Copied ${ids.length} cell ID(s)`);
});
})();The eyewire API
The game gives scripts a small set of tools at window.eyewire. These are the parts we promise to keep working when the game updates. This is version 1.
| Call | What it does |
|---|---|
eyewire.cells.selected() | IDs of the cells selected in your view. |
eyewire.cells.atCrosshair() | The cell under the crosshairs. Returns a promise of { position, supervoxel, root }. |
eyewire.cells.mine() | Your claimed and completed cells in this dataset. |
eyewire.view.get() / .set(state) | Read or replace the whole view: layers, selected cells, position, annotations. |
eyewire.view.position() / .goTo([x, y, z]) | Read or move the crosshairs. |
eyewire.dataset() | The dataset on screen: { id, label, layer }. |
eyewire.user() | Who is signed in: { id, username }, or null. |
eyewire.on(event, fn) | Run your function when something happens. Returns a function that stops listening. |
eyewire.ui.addButton({ id, label, title, onClick }) | Add a button to the top bar. Returns { el, remove }. |
eyewire.ui.addPanel({ id, title, open }) | Add a side panel. Put your content in el. Returns { el, open, close, toggle, isOpen, remove }. |
eyewire.annotations.addLayer(name, { color }) | Make (or reuse) an annotation layer. Returns { addPoint, addLine, list, removeAnnotation, remove }. |
eyewire.settings(name) | A place to save your script's settings in this browser: { get, set, all, clear }. |
eyewire.viewer | The viewer itself, for anything not covered here. This part can change. |
Events
| Event | When | What your function gets |
|---|---|---|
claim | You claim a cell. | { taskId, cellId, dataset } |
release | You release a claim. | { taskId, cellId, dataset } |
complete | You complete a cell. | { taskId, cellId, dataset } |
cellschange | The selected cells change. | { selected, added, removed } |
datasetchange | You switch datasets. | { dataset } |
viewchange | Anything in the view changes, such as moving. | { position } |
Annotations your script adds are not counted in the Annotations number on your profile.
Example: a panel of your selected cells
Adds a Cells button to the top bar. It opens a side panel that lists your selected cell IDs and stays up to date.
// ==UserScript==
// @name EyeWire II: selected cells panel
// @match https://eyewire-ii-community-dot-brain-wire-dot-seung-lab.ue.r.appspot.com/*
// @grant none
// @run-at document-idle
// ==/UserScript==
(function () {
'use strict';
// The game takes a few seconds to start, so wait for the API.
const wait = setInterval(() => {
if (!window.eyewire) return;
clearInterval(wait);
const ew = window.eyewire;
const panel = ew.ui.addPanel({ id: 'selected-cells', title: 'Selected cells', open: false });
const draw = () => {
const ids = ew.cells.selected();
panel.el.textContent = ids.length ? ids.join('\n') : 'No cells selected.';
panel.el.style.whiteSpace = 'pre';
};
draw();
ew.on('cellschange', draw);
ew.ui.addButton({ id: 'selected-cells', label: 'Cells', title: 'Show selected cell IDs', onClick: panel.toggle });
}, 1000);
})();Example: count your completions
Shows how many cells you have completed on this computer. Click the button to reset it.
// ==UserScript==
// @name EyeWire II: count my completions
// @match https://eyewire-ii-community-dot-brain-wire-dot-seung-lab.ue.r.appspot.com/*
// @grant none
// @run-at document-idle
// ==/UserScript==
(function () {
'use strict';
const wait = setInterval(() => {
if (!window.eyewire) return;
clearInterval(wait);
const ew = window.eyewire;
const saved = ew.settings('completion-counter');
const btn = ew.ui.addButton({
id: 'completion-counter',
label: 'Done: ' + saved.get('count', 0),
title: 'Cells you completed on this computer. Click to reset.',
onClick: () => { saved.set('count', 0); btn.el.textContent = 'Done: 0'; },
});
ew.on('complete', cell => {
const n = saved.get('count', 0) + 1;
saved.set('count', n);
btn.el.textContent = 'Done: ' + n;
console.log('Completed cell', cell.cellId, 'in', cell.dataset);
});
}, 1000);
})();Example: mark where you are
Adds a Mark button that drops a gold point at the crosshairs, in its own layer.
// ==UserScript==
// @name EyeWire II: mark where I am
// @match https://eyewire-ii-community-dot-brain-wire-dot-seung-lab.ue.r.appspot.com/*
// @grant none
// @run-at document-idle
// ==/UserScript==
(function () {
'use strict';
const wait = setInterval(() => {
if (!window.eyewire) return;
clearInterval(wait);
const ew = window.eyewire;
ew.ui.addButton({
id: 'mark-here',
label: 'Mark',
title: 'Drop a point at the crosshairs in a "My marks" layer',
onClick: () => {
const layer = ew.annotations.addLayer('My marks', { color: '#ffd700' });
layer.addPoint(ew.view.position(), 'marked ' + new Date().toLocaleTimeString());
},
});
}, 1000);
})();Need something the API does not have?
Ask in the API requests thread on the forum and we will add it. Until then, eyewire.viewer (the same as window.viewer) gives you the whole neuroglancer viewer.
Good to know
- Scripts can break after an update. The game changes often. Everything in the eyewire API table is kept stable. Anything you reach through
window.viewermay move. - Nothing happens? Check that Allow User Scripts is on, that the script is enabled in Tampermonkey, and that the
@matchline is the address in your browser's address bar. - See what went wrong. Press F12 and open the Console tab. Errors from your script show there.
- Made something useful? Share it in chat, and tell us with the feedback button if you would like it built into the game.
Scripts are made by players and are not reviewed by the EyeWire team.