Signal Console

Client

Independent Study

Category

Creative Coding + Interaction

Year

2026

Blue Voice community dashboard interface

Overview

Signal Console is an interactive study built around an imaginary piece of signal hardware. I wanted the controls to feel consequential: changing the pattern engine, signal source or parameters directly changes a continuously rendered visual field.

The interface borrows from scientific instruments, old computing hardware and signal-processing equipment without trying to reproduce any one real machine.

Role & Scope

I designed the interface, visual system, interaction behavior and working prototype.

Most of the project was about making a relatively small set of controls produce very different kinds of behavior while keeping the panel itself consistent.

What I Built

The console has five pattern engines — Dot Field, Node Mesh, Scanline Field, Echo Trails and Type Distortion — along with multiple signal sources and hardware themes.

Density, phase, decay and frequency affect the generated field differently depending on the active engine. Pointer movement also feeds into the viewport, so the output reacts locally instead of behaving like a passive animation.

Implementation

React · TypeScript · Canvas 2D · Vite · Tailwind

The viewport is rendered continuously in Canvas rather than assembled from fixed interface graphics. The same parameters are interpreted differently by each pattern engine: density can change node count or character spacing, phase changes spatial relationships, decay affects persistence and fading, and frequency controls the rate of movement.

Pointer position is also part of the rendering input. Instead of simply following the cursor, nearby elements change their position, intensity or behavior according to proximity. That makes each engine feel responsive without turning the visualization into a cursor effect.

src/app/components/SignalViewport.tsx

const dx = baseX - mx
const dy = baseY - my
const dist = Math.sqrt(dx * dx + dy * dy)

const cursorInfluence = Math.max(
  0,
  1 - dist / cursorRadius
)

const waveX =
  Math.sin(t * freq * 2 + r * ph * 3 + c) *
  (2 + dec * 15) *
  (1 + cursorInfluence * 3)

const waveY =
  Math.cos(t * freq * 1.5 + c * ph * 3 + r) *
  (2 + dec * 15) *
  (1 + cursorInfluence * 3)

let charSpeed = t * 3 + r * 7 + c * 3
charSpeed += cursorInfluence * 20

const char =
  chars[Math.floor(charSpeed % chars.length)]

ctx.fillText(
  char,
  baseX + waveX,
  baseY + waveY
)
const dx = baseX - mx
const dy = baseY - my
const dist = Math.sqrt(dx * dx + dy * dy)

const cursorInfluence = Math.max(
  0,
  1 - dist / cursorRadius
)

const waveX =
  Math.sin(t * freq * 2 + r * ph * 3 + c) *
  (2 + dec * 15) *
  (1 + cursorInfluence * 3)

const waveY =
  Math.cos(t * freq * 1.5 + c * ph * 3 + r) *
  (2 + dec * 15) *
  (1 + cursorInfluence * 3)

let charSpeed = t * 3 + r * 7 + c * 3
charSpeed += cursorInfluence * 20

const char =
  chars[Math.floor(charSpeed % chars.length)]

ctx.fillText(
  char,
  baseX + waveX,
  baseY + waveY
)
const dx = baseX - mx
const dy = baseY - my
const dist = Math.sqrt(dx * dx + dy * dy)

const cursorInfluence = Math.max(
  0,
  1 - dist / cursorRadius
)

const waveX =
  Math.sin(t * freq * 2 + r * ph * 3 + c) *
  (2 + dec * 15) *
  (1 + cursorInfluence * 3)

const waveY =
  Math.cos(t * freq * 1.5 + c * ph * 3 + r) *
  (2 + dec * 15) *
  (1 + cursorInfluence * 3)

let charSpeed = t * 3 + r * 7 + c * 3
charSpeed += cursorInfluence * 20

const char =
  chars[Math.floor(charSpeed % chars.length)]

ctx.fillText(
  char,
  baseX + waveX,
  baseY + waveY
)

cursor gets closer → influence increases → characters distort and cycle more aggressively.

Project State

Signal Console is a finished interaction study rather than a product prototype. The point was to build one coherent control system and see how many distinct visual behaviors it could support without changing the basic interface.

I’d like to keep extending it with new signal engines and input types, but the current version already works as a complete small instrument.