Getting Started¶
Install¶
ScrollKit lives in src/scrollkit/. For desktop development you need the
simulator extras (pygame + numpy + Pillow):
pip install "scrollkit[simulator]"
Or, to modify ScrollKit itself or run the bundled demos (what the rest of
this page assumes), clone the repo and install it editable — your edits to
src/scrollkit/ take effect without reinstalling:
git clone https://github.com/czei/scrollkit.git
cd scrollkit
pip install -e ".[simulator]"
Run anything from the repo root with src on the path:
PYTHONPATH=src python demos/easy/hello_world.py
Running the tests
Use PYTHONSAFEPATH=1 PYTHONPATH=src python -m pytest test/unit/....
PYTHONSAFEPATH=1 keeps the repo root off sys.path (see make test-unit).
Your first app¶
import asyncio
import sys
sys.path.insert(0, "src")
from scrollkit.app.base import ScrollKitApp
from scrollkit.display.content import ScrollingText
from scrollkit.display.simulator import SimulatorDisplay
class HelloWorldApp(ScrollKitApp):
async def create_display(self):
return SimulatorDisplay(width=64, height=32)
async def setup(self):
self.content_queue.add(
ScrollingText("Hello, World!", y=12, color=(0, 255, 128)))
asyncio.run(HelloWorldApp().run())
On desktop this opens a window showing the simulated 64×32 matrix (the
create_display() override above is what opens it — omit it and the app still
runs, just headless, since plain UnifiedDisplay stays headless on desktop
unless a window is explicitly asked for). On a supported
CircuitPython board (the MatrixPortal S3 or the Interstate 75 W) the identical
code drives the physical panel.
Writing an app¶
Subclass ScrollKitApp and override the hooks you need; the framework runs
them as cooperative async tasks.
import asyncio
from scrollkit.app.base import ScrollKitApp
from scrollkit.display.content import ScrollingText
class MyApp(ScrollKitApp):
def __init__(self):
super().__init__(enable_web=False, update_interval=60)
async def setup(self):
self.content_queue.add(ScrollingText("Hello from ScrollKit"))
async def update_data(self):
... # fetch fresh data every update_interval seconds
asyncio.run(MyApp().run())
Deploying to hardware¶
- Connect a supported board (MatrixPortal S3 or Interstate 75 W) over USB (it
mounts as
CIRCUITPY). - Copy
src/to the device, or runmake copy-to-circuitpy. - Configure WiFi — two ways:
- On the device itself, no file editing (the end-user path): wire the
onboarding portal into your app's
setup()and the panel walks the user through joining the device's own access point and picking a network from a phone — see WiFi onboarding portal. secrets.py(the developer shortcut): addsecrets = {"ssid": "your-network", "password": "your-password"}on the device (the standard CircuitPython convention — seescrollkit.utils.url_utils.load_credentials). Portal-saved settings take precedence oversecrets.py.
- On the device itself, no file editing (the end-user path): wire the
onboarding portal into your app's
The same app code runs unchanged: UnifiedDisplay auto-selects the hardware
backend on CircuitPython and auto-detects which board it's on (pass board="..."
to force one). See Adding New Hardware.
CircuitPython dependencies (circup)¶
The device also needs the Adafruit libraries ScrollKit uses (e.g.
adafruit_requests, adafruit_httpserver, adafruit_display_text,
adafruit_bitmap_font, and — on the MatrixPortal S3 — adafruit_matrixportal).
Manage them with circup:
pip install circup
circup install adafruit_requests adafruit_httpserver adafruit_display_text adafruit_bitmap_font adafruit_matrixportal
Saving RAM with .mpy (optional)¶
These boards are memory-constrained (the RP2350 Interstate 75 W especially, with
no PSRAM). Cross-compiling the library to .mpy
loads faster and uses less RAM than shipping raw .py. With mpy-cross installed
(matching your CircuitPython version):
pip install mpy-cross # match your CircuitPython version
make mpy # -> build/scrollkit/*.mpy
Then copy build/scrollkit/ to the device (e.g. CIRCUITPY/lib/scrollkit/)
instead of the raw src/scrollkit/.
Next: the Easy tutorial.