Loading case study…
Loading case study…
Personal Project
•2025
A cinematic control surface built to test the limits of diegetic interface design and motion logic.
HUE 9000 is a study in high-craft interface engineering, pushing a single-screen control surface to a level of UI complexity exceeding most production applications. Built as a diegetic prototype, it serves as a technical benchmark for motion logic, state management, and cinematic front-end execution.
Proof points
Shipped artifact
A cinematic UI with a parametric lens, scanline displays, rotary inputs, dynamic hue mapping, a choreographed boot sequence, and immersive audio.
Working method
Built in early 2025, before agentic workflows were reliable. Used a manual AI-assisted process across planning, building, debugging, refinement, and simplification.
Technical growth
Built practical fluency in XState, Howler.js, OKLCH, GSAP, canvas controls, trigonometric input handling, CSS lighting simulation, and advanced Chrome DevTools debugging.
This project began as an on/off status light for a different interface.
AI was gaining momentum around me, and I wanted to explore a HAL 9000-inspired power light with adjustable color. I built the component in isolation. It looked great. Then I dropped it into the original project.
It looked absolutely terrible.
The lighting and tone were a complete mismatch. Total failure in context. But the button still had something. Rather than throw it away, I built a new project where the lens could become the hero.
I wanted the cinematic language to extend across the full interface, not just the lens. I studied the dark framing, backlit console buttons, all-caps labels, and abbreviated control language used throughout the movie.
Creating the HAL 9000-inspired lens began with the bezel. I created a high-fidelity angular gradient for the inner and outer rings. I used a reference photo of the original hardware and generally followed it, but made intentional changes to simplify the number of colors (which would become CSS variables so I could animate their intensity), and also to have more left-right symmetry.
Once the bezel looked right, I converted the shades of gray into parametric CSS variables. This allowed me to adjust the global lighting intensity dynamically.
To sell the illusion of a physical glass surface, I created SVG highlights to overlay with ::after pseudo-elements. I found a high-quality image of what I believed was the original HAL 9000 and carefully traced its sharp specular highlights.
After the highlights were finished, I rewatched the actual movie and realized my reference image was not a production photo. It was a fan-made 3D recreation. Fortunately, these looked great and the sharpness was helpful to keep.
The internal lens illumination follows the physics of the original optic. I carefully mapped a photo of the lens into a reconstructed CSS radial gradient. I paid extra attention to the boundaries. I then converted all the color stops into CSS variables using the OKLCH color space, which allowed me to vary the hue dynamically across the different stops.
One key challenge was the inner glow. It has a noticeable hue shift at its brightest point. I used a CSS calculation variable to create an offset hue. If a user changes the overall lens color from red to blue, the inner region mathematically maintains that shifted, brighter center.
I used OKLCH because the color changes needed to feel perceptually uniform and continuous. It gave me separate control over lightness, chroma, and hue, making it possible to rotate color while preserving the structure of the lighting system: glow, bloom, shadow, and the brighter inner core of the lens.
It also made the neutral state cleaner. Instead of creating a separate grayscale palette, the system reduces chroma to zero and keeps the same lighting model intact.
I had to model how the light behaves at different intensities to make the interface feel alive. I used the exact same gradient color stops but adjusted their physical positions based on power levels. At zero percent intensity, the bright inner glow compresses to nothing, and gets overlapped with the more subtle gradient stops. As the power increases, those color stops expand outward.
To simulate a realistic camera bloom, I treated the light spill as a dynamic after-effect. The bloom grows in both opacity and radial size as the lens intensity increases. This creates the illusion that the lens is generating enough energy to glow past its physical edges.
As the project visual language took shape, I explored a variety of layout options. Each iteration made a bit more sense, and eventually I landed on a symmetric left-right layout, with some asymmetry within the macro regions.
Medium fidelity exploration of the overall layout.
When no high-resolution photo reference exists for a 1960s speaker grille, you build it yourself. I looked across the internet for a usable image of the original grille texture, but could not find anything high-resolution enough to recreate it properly. The texture had a specific ridge-and-hole pattern, so I measured the spacing and modeled it in SolidWorks.
I made the texture slightly larger than needed, then exported it to KeyShot. From there, I applied a custom metal material and recreated the same lighting environment used on the lens. I rendered the asset in two modes to match the two lighting states in the project.
I built a dynamic hue control system that manages color across the full interface: ambient background lighting, LCD backlights, the logo, and LED-backlit buttons.
Each button row maps to a specific hue. The top row acts as a neutral state by reducing chroma to zero, creating a grayscale version of the same lighting model.
The button system adapts to those hue assignments. Larger buttons use multiple simulated light sources, while smaller buttons use one. Active buttons cast a soft bloom. Inactive buttons subtly oscillate in intensity, giving the console a low-power breathing quality.
I built two custom canvas-based dials to make the controls feel tactile, precise, and novel. The inspiration came from jog dials on high-end 1980s audio components. I used trigonometric math to convert pointer movement into dial rotation, then mapped that rotation into live values for mood and intensity.
The displays use a retro electronic readout language: bright segmented regions, scanline texture, and a subtle shadow-mask overlay. The intensity control used a simple horizontal percentage scale and was fairly straightforward to pull off.
The mood control required a more nuanced approach. Simply mapping hue angles felt impersonal, so I designed a system to show semantic mood names instead. This involved complex interpolation between moods to create a continuous physical scale without overloading the display. The final solution used linear interpolation with a text-scramble effect to bridge the transitions.
I created a terminal layer to make the HUE 9000 feel like it was talking back.
The display uses a CRT texture, scanline effect, shadow mask, and a chromatic aberration glitch effect built with CSS pseudo-elements. As users interact with the system, the terminal generates dynamic status strings tied to controls and state changes.
I added debouncing and rate-limiting to keep repeated interactions from overwhelming the display. The goal was controlled system chatter, not a wall of fake diagnostics.
The scan buttons include custom sequences, supported by a small nine-dot activity animation. It cycles through multiple patterns and gives the interface a quiet “thinking” state without overplaying it.
Because the project has a large amount of styling and audio, I needed to ensure the cinematic startup sequence loaded cleanly. I built a lightweight preloader to improve perceived performance and prevent any FOUC, or Flash of Unstyled Content, on page load.
I used the logo typography, added a custom line-tracing animation, and kept the whole sequence visually aligned with the technical language of the interface.
The loading states show actual progress across raw data, graphics, and audio. This gave the preloader utility while still reinforcing the system aesthetic.
Once the assets are ready, the preloader shows one of the project’s custom LED-backlit buttons. A single rotating hue drives the full animation, connecting the loading experience back to the core “HUE” concept of the project.
I built a choreographed startup sequence to make the interface feel like it was powering itself back online. The sequence plays like a backup power system coming up in stages. The lens wakes first. Then the controls. Then the ambient light kicks in.
I used XState to manage the boot logic and keep each phase predictable. This became one of the more useful state-management lessons in the project.
Dialing in the dim state took a surprising amount of effort. I wanted subtle visible life: low power, but not dead. As each button lights up, the surrounding illumination increases slightly, creating the feeling that each component is contributing to the room lighting.
I built a layered sound system using open-source effects and Howler.js. The goal was to make the interface feel immersive without turning audio into a gimmick. Ambient tracks run underneath the experience, while buttons, dials, and state changes trigger their own interaction sounds.
I tested a range of background tracks, including a few that felt more unsettling than I thought would be appropriate. I almost cut them. Early testers liked the creepy ones best, so I kept that tension in the final version.
The power-off interaction also includes special sound and animation states. It nods to HAL 9000, and to the question sitting in the back of many people’s minds in the AI era: what happens when the AI does not want to be turned off?
Even though the primary experience was designed for desktop, I wanted to make it work as well as I could on mobile. I first tried making it landscape-only and keeping it close to the desktop version. That was a cop-out, and the end result quite frankly sucked.
I shifted the goal to keeping the lens as the hero. I kept the mood and intensity dials since they matter most to the lens. The full hue grid became a simpler floating slider outside the physical interface, giving the user practical control without overloading the screen. The terminal moved behind a floating button, with a smooth transition to bring it in and out of view.
Ultimately, the hardest part was not the layout. It was the state model. Because several desktop controls do not exist on mobile, including the on/off buttons, auxiliary lighting, and hue assignment grid, the startup sequence needed a fundamentally different state architecture. What started as responsive cleanup became a mobile-specific refactor.
I would use a very different workflow today. HUE 9000 was built in an early 2025 window when agents were still immature. I tested agentic workflows during the project, but they were slower and flakier than the manual human-AI process I developed: plan, build, troubleshoot, refine, simplify.
I am proud of how far I pushed the project with limited AI tooling. I also learned a lot. Today, I would build it with agents, use React, manage state with Jotai, leverage Radix for headless primitives, and structure the styling with CSS Modules.
I would also connect the interface to a real LLM. That was something I had not done at the time of this project, but have done a lot since.
The original version proved the control surface could feel alive. The next version would let it think back.