DylanOS

A playful browser phone simulation drawn on one p5.js canvas, with generated notifications, gestures, quick settings, and a passcode flow.

Project at a glance

My responsibility
Built the canvas renderer, input pipeline, notification generators, and state modules with assistance from an AI coding tool.
Frontend / Creative Engineering
This browser toy explores canvas rendering and interaction design. It brings drawing, input, generated content, and state together in a small, inspectable application.
Rendering
Single p5.js canvas
Notifications
Generated by category
Format
One self-contained page
Next.jsReactTypeScriptp5.jsCanvasInteraction Design
Visit projectView resume

Product screens

Under The Hood

The page diagrams its own build - page shell, p5.js renderer, state modules, and notification generators.

Under The Hood

Generated Notifications

A per-source engine fills the lock screen with varied, in-character alerts on every visit.

Generated Notifications

One Canvas, Live

The status bar, notification cards, and phone frame are all drawn on a single p5.js canvas.

One Canvas, Live

The work

Problem, implementation, and result.

01

Problem

01

I wanted to build a phone interface on a canvas and work directly with rendering, hit-testing, gestures, and state transitions.

Problem
02

Build

02

DylanOS is a fake phone, built way too seriously. A React page loads p5.js in the browser to draw the status bar, notifications, quick settings, passcode pad, home screen, and camera on one canvas. Notification generators produce in-character alerts from dozens of fictional apps. One input handler supports mouse, touch, drag, swipe, and keyboard controls.

System design
03

Outcome

03

A self-contained phone simulation with an accompanying explanation of the rendering, input, state, and performance decisions.

Delivered behavior

Framing

Scope and constraints.

This browser toy explores canvas rendering and interaction design. It brings drawing, input, generated content, and state together in a small, inspectable application. I separated drawing, input, state, notifications, settings, passcode, fake OS, and camera code into modules. They share one coordinate system for the phone. Notification generators vary the alerts by source category, and the render loop pauses when the phone is not visible.

Technologies

Next.js
React
TypeScript
p5.js
Canvas
Interaction Design
Animation

Key features in scope

A full phone lock screen with a live status bar, all rendered on one p5.js canvas
A generated-notification engine drawing from dozens of fictional app sources across categories
Gesture handling: drag down for quick settings, swipe to dismiss, swipe up into a passcode unlock
A fake home screen and app grid behind a passcode, plus camera photo, video, and AI modes with hidden surprises
Notification sounds and device haptics where the browser supports them
An accessibility foundation with ARIA descriptions, a live notification region, and keyboard handling

Responsibility and context

Role: Built the canvas renderer, input pipeline, notification generators, and state modules with assistance from an AI coding tool.
Category: Frontend / Creative Engineering

Engineering

Architecture and decisions.

DylanOS is a fake phone, built way too seriously. A React page loads p5.js in the browser to draw the status bar, notifications, quick settings, passcode pad, home screen, and camera on one canvas. Notification generators produce in-character alerts from dozens of fictional apps. One input handler supports mouse, touch, drag, swipe, and keyboard controls.

Technologies

Next.js 15
React 19
TypeScript
Tailwind CSS v4
p5.js
Motion
Next.js page shell (RSC)
N/A - no persistence

Architecture choices

React Server Component page shell that loads the p5.js renderer only on the client, so the canvas runtime never evaluates during server rendering
One p5.js canvas that draws the whole phone on a single internal coordinate system while the page scales the outer frame responsively
Notification engine with a manager, grouped-notification models, and generators organized by category - development, finance, social, productivity, lifestyle, and more
State modules for authentication, quick settings, passcode, fake OS, camera, and menu bar, kept as separate concerns
One input layer that funnels mouse, touch, drag, swipe, and keyboard events through a shared handler without hijacking normal page scroll
Performance guards: assets and icons preload up front, and the draw loop pauses when the phone is off-screen or the tab is hidden

Key decisions

Use one canvas coordinate system for rendering and hit-testing
Load p5.js only on the client to keep the renderer out of server execution
Organize notification generators by source category
Pause rendering when the phone is off-screen or the browser tab is hidden

Results

Results and limitations.

A self-contained phone simulation with an accompanying explanation of the rendering, input, state, and performance decisions.

Delivered behavior

Built a self-contained interactive page with a lock screen, generated notifications, quick settings, a passcode flow, and camera modes
The notification engine produces varied, in-character alerts across dozens of fictional sources on every visit
Includes a writeup on the same page with diagrams of rendering, state, input, and performance decisions

Constraints

Canvas drawing requires custom layout, focus handling, and hit-testing
An always-animating canvas had to stay light enough not to degrade the surrounding page
Input had to support mouse, touch, drag, swipe, and keyboard without hijacking normal page scroll
The canvas needed ARIA descriptions and a live region because its drawings have no built-in accessibility semantics

Lessons

What the build taught me.

01

Canvas rendering requires explicit work on hit-testing, focus, and accessibility

02

Notification generators can vary synthetic content without a fixed list

03

Visibility checks can avoid unnecessary drawing when an animated interface is off-screen

Retrospective

I would separate the state modules further before adding a public API. I would also improve screen-reader support and automate the browser checks that I currently run manually.