Skip to content
Abdul Alzokm
All case studies

SHARP Imaging Labs

Bringing adaptive optics out of the command line

Redesigning pyRTC, an open-source astronomy real-time controller, into a unified dashboard a junior researcher can run on day one.

The pyRTC dashboard on a laptop: live telemetry across the top, and PSF, DM surface, wavefront slopes and interaction matrix as separate blocks
Role
UX Designer and Researcher
Team
Team of 4
Timeline
14 weeks, Jan to Apr 2026
Tools
Figma, Tailwind, Lucide
Context
UX capstone, client project with SHARP Imaging Labs, University of Toronto

The short version

The problem

pyRTC runs entirely in a terminal, spread across four separate windows, with almost no documentation. The only way to learn it is from someone who already knows it, so when that person leaves, the knowledge leaves too.

What I did

I worked on the design, created the design system for the open-source handoff, and ran interviews with adaptive optics researchers.

  • 4 → 1

    Fragmented viewer windows collapsed into one workspace

  • 0 → 5

    Onboarding steps for first-time users, from none

  • 4

    Usability findings shipped as design iterations

  • 1

    Design system for open-source handoff

What pyRTC is, and who it is for

Adaptive optics is how ground-based telescopes cancel atmospheric distortion in real time. A real-time controller is the software running that closed loop, measuring the wavefront and reshaping a deformable mirror thousands of times a second.

Most controllers in the field are written in low-level C, locked to expensive hardware bundles, and built for full-scale observatories. pyRTC is the outlier: open source, written in Python, made by U of T PhD student Jacob Taylor with Robin Swanson and Ryan Dungee. It is the only realistic learning tool for a graduate student who wants to actually run adaptive optics without buying a $200k bundle.

That accessibility is its superpower, and the existing interface hides it behind a wall of terminal commands and four disconnected plotting windows.

  • The brief

    Modernise the pyRTC graphical interface, and lower the barrier to entry for newly admitted AO researchers.

  • Stakeholders

    Robin Swanson as client, Jacob Taylor as creator, the grad-student developers, and the wider open-source AO community.

  • My part

    UX designer and researcher on a team of four. I worked on the interface design, ran interviews with AO researchers, and built the design system with the team.

  1. 01

    Discovery

    Weeks 1 to 4. Lab visit, secondary research, competitive scan.

  2. 02

    Synthesis

    Weeks 5 to 7. Interviews, codebooks, affinity mapping, personas.

  3. 03

    Ideation

    Weeks 8 to 9. Low-fi flows, moodboard, logo redesign.

  4. 04

    Mid-fi and test

    Weeks 10 to 12. Clickable prototype, three usability sessions.

  5. 05

    Iterate and hand off

    Weeks 13 to 14. Hi-fi prototype, design system, final report.

Listening before designing

None of us were astronomers. Designing a real-time controller without that grounding would have produced a beautiful terminal replacement that no one in a basement lab could actually use.

So the first half of the project was about getting close to the work. Visiting the lab, watching a closed loop run on the optical table, and interviewing the people who use these systems for a living.

  1. 01

    Field study

    One hour contextual inquiry at the Dunlap Institute, observing a closed-loop demo on a vibration-isolated optical table in a 30 °C basement.

  2. 02

    Interviews

    Four semi-structured remote interviews with AO researchers at U of T, U of Hawai'i and Carnegie Science, 30 to 45 minutes each.

  3. 03

    Competitive scan

    Benchmarked four industry real-time controllers, ALPAO, CACAO, DARC and ESO SPARTA, on cost, accessibility and visual approach.

Seven affinity boards clustering research notes: context and background, environment, competitors, lack of guidance and high learning curve, software workflow, functionality usage and wants, and error prevention and debugging
Synthesis: codebooks, affinity mapping, jobs-to-be-done, personas and an impact / effort matrix.

Three patterns kept surfacing

Across four interviews, every researcher, junior or senior, eventually described the same three problems in different words.

01

The learning curve has no railing

What changed

A guided onboarding that personalises the workspace by experience level, so a junior researcher starts somewhere safe instead of nowhere.

What we saw

There is no formal onboarding for pyRTC, or for adaptive optics in general. New users are expected to absorb decades of tribal knowledge from senior staff. When that staff retires, the knowledge leaves with them.

  • Most of these systems rely on knowledge that is in the head of someone that retired.

    Software developer, Carnegie Science

02

Calibration burns hours that should be minutes

What changed

Per-block start and stop controls, so stopping one component no longer means stopping the system.

What we saw

Tiny config changes force a full loop restart. Telemetry filenames are typed by hand, every time. Routine work is brittle, manual and easy to break, which are exactly the wrong properties for a research tool.

  • I have to restart the entire loop and shut everything down just to make a small change. It's very, very annoying.

    Postdoc, Dunlap Institute

03

Live data is visible but never inspectable

What changed

A single dashboard where every data block is inspectable, and clicking one reveals the code behind it.

What we saw

The current interface shows four separate windows of dots moving around. You cannot read a value, correlate sensors at the same time slice, or save a moment for review later.

  • I want to view data efficiently without bringing up a bunch of separate windows and fiddling with their scalings.

    Grad student, U of Hawai'i

How might we design an interface that makes complex AO tasks simpler, so students can run experiments safely without needing an expert to guide them?

One workspace, three flows, zero terminal-only steps

Rather than redesigning the whole product, we focused on three flows that map directly to the three insights: onboarding for the learning curve, a modular dashboard for live data, and embedded docs for the knowledge gap.

01

A guided onboarding that respects expertise

Two onboarding steps side by side: step one asking whether you are a student or researcher, and step five selecting which data streams matter most

Before

No formal onboarding existed. A new researcher opened a terminal and either had a mentor beside them or did not.

After

Five short questions, role, AO familiarity, optional institutional sign-on and which data streams matter most, populate the dashboard before the user ever sees it. Junior researchers land on a beginner-safe layout. Senior researchers can skip and configure freely.

02

A bento-box dashboard you can actually rearrange

The bento-box workspace: Strehl ratio, loop rate, wavefront error and DM status along the top, with PSF, DM surface, wavefront slopes, Strehl, interaction matrix and camera as rearrangeable blocks

Before

Four separate viewer windows of moving dots, with no way to read a value or correlate sensors at the same time slice.

After

One drag-and-drop workspace. Drag a data block in from the left rail to add it, drag it back out to remove it. Top-bar telemetry stays visible, and clicking any block opens the live code terminal scoped to that data stream.

03

Documentation that lives inside the workspace

The API reference open inside the workspace, showing the ImageSHM class with its methods listed and linked to source

Before

Our first idea was an adaptive optics concept glossary, on the assumption that new users needed the vocabulary.

After

A test participant pointed out that pyRTC users already know AO. What they need is the API. We replaced the glossary with the project's actual function reference, searchable from any data block's overflow menu, and kept the glossary as a secondary tab.

Three sessions, four shipped fixes

We ran 25 to 46 minute moderated sessions with three participants, two returning interviewees and one new. Findings were ranked on an impact and effort matrix. Everything below was high impact and feasible within the remaining sprint.

  • Per-component start and stop

    Testing surfaced that stopping the system is not one action but many. A camera might need a reboot while the deformable mirror keeps holding. Per-block controls now sit next to the overflow menu, with a single system-wide toggle in the header.

  • API reference over glossary

    A domain expert flagged that pyRTC's audience already speaks AO. We swapped the glossary for the README's API content and kept the glossary as a secondary tab.

  • Cloud sync made optional and disclosed

    Two participants pushed back on mandatory institutional login, since lab data already lives on local servers. Sign-on became optional, with explicit disclosure during onboarding and a kill switch in settings.

  • Visible quick menu over hover tooltip

    Peer critique flagged the info-icon tooltip as an accessibility risk, since content was hidden behind hover and not keyboard-reachable. It became a visible ellipsis menu with keyboard-navigable controls.

Built for an open-source handoff

pyRTC is community maintained. Anything we shipped had to be re-implementable by a grad-student volunteer with no design tooling, so the system leans entirely on things that are free and already documented. Every variable maps cleanly to a line of CSS.

  • Colour, pulled from the optical-table lens

    The accent palette comes from a photograph taken through a lens on the Dunlap optical table, the same indigo and teal flares that appear when light passes through stacked optics. We rebuilt them as Tailwind indigo and teal ramps so developers can reference shades by name. Indigo carries headings, links and focus; teal carries success and active states.

  • Type, Geist and Geist Mono

    Geist for headings and body, Geist Mono for telemetry, code, and any value a researcher might read off a sensor. Both are Google Fonts, so there is no licensing friction for a volunteer picking the project up.

  • Components, the data block

    The atomic unit of the dashboard. Built on Figma's slots beta so a developer can swap the inner visualisation, PSF, WFS, DM or Strehl, without rebuilding the chrome around it. Three states: default, focused and paused.

  • Icons

    The Lucide library plus a handful of custom adaptive optics icons drawn to match Lucide's stroke weight, so the set reads as one family.

Design system sheet: indigo, teal and grey Tailwind ramps of eleven steps each, above a type scale showing display at 48, body at 16, mono at 14 and caption at 11
The ramps and the type scale. Indigo carries headings and focus, teal carries success and active states, and mono holds anything read off a sensor.

Where it landed

viewer windows collapsed into a single workspace
4 → 1
onboarding steps for a first-time user, from none at all
0 → 5
usability findings shipped as design changes
4
design system built for open-source handoff
1

Capstone client project. These are design and testing outcomes, not live product metrics. The prototype was handed off rather than shipped.

What I would take into the next one

Domain immersion is non-negotiable. The single biggest lift came from an hour in a 30 °C basement watching a closed loop run. None of the secondary research had prepared us for the optical-table reality: vibration isolation, dark-room observation, four laptops humming at once. The redesign that emerged was shaped by that room more than any interview transcript.

Designing for an open-source handoff changes everything. When the developers are volunteers, every opinionated design choice has to come with a re-implementable default. Tailwind, Geist and Lucide were not aesthetic picks. They were the only stack that survived the question "could a grad student rebuild this in a weekend?"

If I had another sprint, I would pair-test the API reference with a junior researcher running an actual closed loop, not a static prototype. Testing showed it was the right idea. I want to know whether jumping to a function from a block is a path users actually walk, or one we hope they walk.