|
| 1 | +# Visualizer Architecture and Contributing |
| 2 | + |
| 3 | +The PyLabRobot visualizer renders the state of a running protocol in a browser. |
| 4 | +It is implemented as a lightweight web application served by the |
| 5 | +{class}`~pylabrobot.visualizer.visualizer.Visualizer` class in Python. The |
| 6 | +visualizer itself does not perform any simulation logic; instead it receives |
| 7 | +messages over a websocket from Python and passively updates the drawing. |
| 8 | + |
| 9 | +This document gives an overview of how the visualizer is structured and where the |
| 10 | +code lives so new contributors can quickly get started. |
| 11 | + |
| 12 | +## File layout |
| 13 | + |
| 14 | +The source lives in the :mod:`pylabrobot.visualizer` package: |
| 15 | + |
| 16 | +``` |
| 17 | +pylabrobot/visualizer/ |
| 18 | +├── index.html # entry point served to the browser |
| 19 | +├── lib.js # helper functions and resource definitions |
| 20 | +├── vis.js # websocket setup and event handling |
| 21 | +├── main.css # styling for the page |
| 22 | +├── gif.js, gif.worker.js # GIF recording utilities |
| 23 | +└── visualizer.py # Python server component |
| 24 | +``` |
| 25 | + |
| 26 | +The HTML/JS/CSS files make up a static web page. The Python |
| 27 | +:mod:`visualizer.visualizer` module exposes a :class:`Visualizer` class which |
| 28 | +spins up two threads: |
| 29 | + |
| 30 | +1. **File server** – a simple HTTP server that serves the static files above. |
| 31 | +2. **Websocket server** – used to push state updates from Python to the browser. |
| 32 | + |
| 33 | +When `Visualizer.setup()` is called, it launches both servers and optionally |
| 34 | +opens a browser pointing to the file server. As resources are assigned to the |
| 35 | +root resource or their state changes, callbacks in Python send JSON messages to |
| 36 | +the browser via the websocket. |
| 37 | + |
| 38 | +## Browser side |
| 39 | + |
| 40 | +The web page establishes a websocket connection when loaded. Incoming messages |
| 41 | +are dispatched in `vis.js` and update the Konva.js drawing. The main events are: |
| 42 | + |
| 43 | +- `set_root_resource` – initial resource tree sent when the connection is ready. |
| 44 | +- `resource_assigned` / `resource_unassigned` – update the tree structure. |
| 45 | +- `set_state` – update tracker state such as volumes or tip usage. |
| 46 | + |
| 47 | +The JavaScript does not compute new state on its own; it simply renders what it |
| 48 | +receives. |
| 49 | + |
| 50 | +## Developing the visualizer |
| 51 | + |
| 52 | +To work on the frontend, run a Python script that starts the |
| 53 | +:class:`Visualizer` and open the provided URL in your browser. Changes to the |
| 54 | +HTML/JS/CSS files require a reload in the browser. If you modify the Python |
| 55 | +side you may need to restart the script. |
| 56 | + |
| 57 | +Useful entry points are the examples in the user guide or the unit tests in |
| 58 | +`pylabrobot/visualizer/visualizer_tests.py` which demonstrate typical usage. |
| 59 | + |
| 60 | +Because communication happens over websockets, you can also drive the visualizer |
| 61 | +from unit tests or scripts without a physical robot. The |
| 62 | +{class}`~pylabrobot.liquid_handling.backends.chatterbox.ChatterboxBackend` works |
| 63 | +well for this purpose. |
| 64 | + |
| 65 | +## Contributing tips |
| 66 | + |
| 67 | +- Keep the Python server lightweight. All rendering logic should stay in the |
| 68 | + JavaScript code. |
| 69 | +- When sending new events from Python, add matching handlers in `vis.js` and |
| 70 | + document the payload format in comments. |
| 71 | +- Try to keep the websocket protocol stable; update the |
| 72 | + `STANDARD_FORM_JSON_VERSION` if breaking changes are introduced. |
| 73 | + |
| 74 | +If you have ideas for improvements or run into issues, feel free to open a topic |
| 75 | +on the development forum before submitting a pull request. |
0 commit comments