uv venv .venv
source .venv/bin/activate # on Windows use `.venv/Scripts/activate`
uv sync --active
python -m pupil_labs.neon_player [path/to/my/recording]- Global settings are saved in
$HOME/Pupil Labs/Neon Player/settings.json - Per-recording settings are saved in
recording/path/.neon_player/settings.json - Plugin cache data is saved in
recording/path/.neon_player/cache/PluginName/
- Drop your plugin python file into
$HOME/Pupil Labs/Neon Player/plugins(you may need to create the directory) - If your plugin has multiple files, put them in a folder with a
__init__.pyfile that either defines yourPluginclass or imports a module which does. Do not create an instance of your plugin - just define the class which inherits frompupil_labs.neon_player.Plugin. - If your plugin needs python dependencies, list them as inline script metadata (aka PEP 723). Neon Player will detect these and install them to
$HOME/Pupil Labs/Neon Player/plugins/site-packagesautomatically.
To expose a plugin setting to the GUI, define a property with getter/setter functions and appropriate type hints. You can control some options of the parameter GUI widget using th @property_params decorator. For example, by defining a min and max for int or float properties, the UI will present a slider.
You can also expose a function to the GUI by using the @action decorator. It will appear as a button, with each of its arguments as an input field
from pupil_labs.neon_player import Plugin, action
from PySide6.QtWidgets import QMessageBox
from qt_property_widgets.utilities import property_params
class MyPlugin(Plugin):
def __init__(self):
super().__init__()
self._my_variable = 0.5
@property
@property_params(min=-1, max=100, decimals=2)
def my_variable(self) -> float:
return self._my_variable
@my_variable.setter
def my_variable(self, value: float):
self._my_variable = value
@action
def show_message(self, text: str) -> None:
QMessageBox.information(None, "Message", text)Long-running actions should be ran as a background job so you don't lock-up the GUI. You can report progress back to the GUI by yielding a ProgressUpdate
import logging
import time
import typing as T
from pupil_labs.neon_player import Plugin, ProgressUpdate, action
from PySide6.QtWidgets import QMessageBox
class MyPlugin(Plugin):
def bg_task(self, count_to: int) -> T.Generator[ProgressUpdate, None, None]:
for i in range(count_to):
time.sleep(0.5)
logging.info(i)
yield ProgressUpdate(i / count_to)
@action
def start_slow_job(self, count_to: int = 5) -> None:
job = self.job_manager.run_background_action(
"Slow Job Test", "MyPlugin.bg_task", count_to
)
job.finished.connect(lambda: QMessageBox.information(
None,
"Attention",
"Slow job finished!"
))Every function defined in a plugin can be scripted from the command line without using the GUI. Please use type hints in your function signature so that arguments can be typcast/coerced for you.
from pupil_labs.neon_player import Plugin
class MyPlugin(Plugin):
def my_function(self, arg1: int, arg2: str) -> None:
print(f"arg1 = {arg1}, arg2 = {arg2}")$EXECUTABLE path/to/my/recording --job MyPlugin.my_function 123 "Hello, World!"Where $EXECUTABLE is either python -m pupil_labs.neon_player (if running from source) or the path to the compiled binary.
- Left click and/or drag to scrub
- Drag with the middle mouse to pan
- Shift + scroll zooms the Y axis
- Control + scroll wheel zooms the X axis
- Control + left click+drag zooms to a box you draw
