Skip to content

Oberon

Oberon — Claude Context

Reusable Metal-based audio-reactive visualization engine. Standalone SPM package — no dependencies on Horatio, Enobarbus, Touchstone, or Ariel. Used by Hecate (full-screen Immerse mode) and VizLab (shader design workbench).

Architecture

App provides VizInput (audio analysis + musical fields + params)
    → VizCanvasView (SwiftUI wrapper)
        → VizRenderer (MTKViewDelegate)
            → Metal fragment shader (from ShaderCatalog)
            → Ping-pong feedback textures (decay + warp)
            → Cosine palette coloring
        → Drawable output

Audio isolation: Oberon runs entirely on GPU via Metal. No audio framework dependencies, no shared mutable state with audio threads, no locks that could contend with real-time audio. Zero performance impact on audio processing.

Modules

Config

File Purpose
Config/ShaderCatalog.swift Enum of 21 shaders with display names, descriptions, and per-shader VizConfig defaults
Config/VizConfig.swift Codable shader configuration: fragment function name, feedback decay/warp, palette, up to 6 parameter definitions
Config/VizParamDef.swift Codable per-parameter metadata: name, display name, default value, range
Config/CosinePalette.swift SIMD3-based cosine palette (Inigo Quilez formula), 11 presets: cosmic, fire, ocean, aurora, neon, mercury, earth, moss, amber, cathedral, coven

Input

File Purpose
Input/VizInput.swift Per-frame data struct: audio analysis (rms, bass, mid, high, spectralCentroid, dominantFrequency), musical fields (chordIntervalMask, vowelF1, vowelF2), shader params (param0–5), optional overrides (feedbackDecay, feedbackWarp, palette), raw waveform/spectrum arrays
Input/AudioAnalyzer.swift 1024-point FFT analyzer (Accelerate): 3-band RMS (bass/mid/high, smoothed α=0.3), spectral centroid, 32 log-spaced spectrum bins. Call analyze(_:) at ~30 Hz from main thread.

Renderer

File Purpose
Renderer/VizRenderer.swift MTKViewDelegate: compiles all .metal files into single MTLLibrary, lazy pipeline creation per fragment function, ping-pong feedback textures (BGRA8Unorm), 2-frame inflight semaphore, two-pass render (offscreen → blit to drawable)
Renderer/VizUniforms.swift Struct matching Metal layout: time, resolution, audio bands, dominantFrequency, musical fields (chordIntervalMask as UInt32, vowelF1, vowelF2), params, feedback, cosine palette components

Views

File Purpose
Views/VizCanvasView.swift SwiftUI wrapper (UIViewRepresentable / NSViewRepresentable), maps VizInputVizUniforms, idle throttling (60 fps → 10 fps when RMS < 0.005)

VizInput Fields

Audio Analysis (updated ~30 Hz by AudioAnalyzer)

Field Type Range Description
rms Float 0–1 Overall loudness, smoothed
bass Float 0–1 Low-frequency RMS (20–250 Hz)
mid Float 0–1 Mid-frequency RMS (250–4000 Hz)
high Float 0–1 High-frequency RMS (4000+ Hz)
spectralCentroid Float 0–1 Brightness proxy, normalized log scale
dominantFrequency Float Hz Peak FFT bin frequency, 0 = not populated

Musical Fields (populated by host app)

Field Type Range Description
chordIntervalMask UInt8 0–63 Bitmask: bit 0=root, 1=3rd, 2=5th, 3=7th, 4=9th, 5=octave. 0 = not populated.
vowelF1 Float 0–1 Formant 1 (jaw openness): 0=closed, 1=wide open
vowelF2 Float 0–1 Formant 2 (vowel shape): 0=back vowel, 1=front vowel

Shader Parameters

Field Type Range Description
param0–param5 Float 0–1 Host-defined, shader-specific meaning — see ShaderCatalog per-shader defaults

Metal Shaders (21 + shared)

OberonShaders.metal — shared utilities: fullscreen vertex, gradient noise (Perlin-style with quintic interpolation), FBM 2D/3D, domain warping, cosine palette, SDF primitives, feedback sampling, vowelColor, chordPopcount, soapFilm (thin-film interference), sacredRing (n-fold petal ring with float petal count + variable depth), flameForm (flame SDF), blit fragment.

Shader Fragment Function Character
Nebula nebula_fragment Triple-nested domain warp with luminous hot spots
Metaballs metaball_fragment SDF liquid mercury + specular
CRT Scope lissajous_fragment Autonomous Lissajous trace with CRT phosphor
Volumetric volumetric_fragment Luminous fog/cloud volume
Circuit circuit_fragment Rotating grid with morphing junction shapes + diagonal traces
Aurora aurora_fragment 5-layer smooth curtains, sine-based (no noise artifacts)
Attractor Trace attractor_trace_fragment Lorenz attractor, 3D tumble rotation, large scale
Warp Field warp_field_fragment Continuous domain-warped feedback (no atan2 seam)
Flocking Metaballs flocking_metaballs_fragment Boids + SDF liquid
Spiral Plasma spiral_plasma_fragment Spiraling plasma vortex (reference shader)
Living EQ living_eq_fragment 16-bar organic spectrum, soft edges, subdued palette
Moss Grid moss_grid_fragment Wandering luminous dots with tendril connections
Wind Erosion wind_erosion_fragment Diving through layered geological strata
Physarum physarum_fragment Slime mold vein networks
Ink Diffusion ink_diffusion_fragment Ink in still water with autonomous seeping
Soap Film soap_film_fragment Smooth thin-film interference membrane
Bioluminescence bioluminescence_fragment Wandering/spiraling deep-sea organisms, configurable dot size
Sacred Geometry sacred_geometry_fragment Morphing petal rings with spinning trails
Candle Oracle candle_oracle_fragment Floating flames on random orbits, configurable count
Stellar Nebula stellar_nebula_fragment Gas cloud with visual reverb (smoothed energy via feedback)
Vowel Weave vowel_weave_fragment Wide woven threads colored by vowel formants

All shaders accept uniforms (buffer 0), waveform samples (buffer 1, up to 256), spectrum bins (buffer 2, 32 bands), and the previous frame's feedback texture.

Shader Design Principles

All shaders follow these consistency rules (Spiral Plasma is the reference): - Always visible at rest: Minimum brightness floor of 0.4+ when all audio is zero. No shader goes black. - Always animated: Time-driven autonomous motion independent of audio. Never static at silence. - Audio enhances, never gates: Audio makes things brighter/larger/faster but doesn't enable/disable content. - No cheap sparkle: Avoid hash21 + step white-dot sparkle. Use luminous hot spots, smooth shimmer, or soft Gaussian points instead. - No atan2 for color: atan2 creates a visible seam at ±π. Use normDir.x/normDir.y (continuous cos/sin components) for angular color variation. - Gradient noise only: noise2d/noise3d use Perlin-style gradient noise with quintic interpolation. Never value noise (grid artifacts).

Cosine Palette Presets

cosmic, fire, ocean, aurora, neon, mercury, earth, moss, amber, cathedral, coven

Tests

Test Validates
shaderCatalogHasConfigs All 21 shaders have non-empty fragment functions and parameter definitions
vizConfigRoundTrips VizConfig JSON encode/decode
cosinePaletteRoundTrips CosinePalette JSON encode/decode
vizInputDefaults VizInput zero-initializes correctly (includes new fields)
chordIntervalMaskPopcount activeChordToneCount popcount helper returns correct values
cd Packages/Oberon && swift test

Rules

  • No dependencies on other packages — Oberon is standalone Metal + SwiftUI.
  • All shaders gracefully handle zero audio input (no NaN, always visible, always animated).
  • When chordIntervalMask is 0, shaders that use it must fall back to a sensible default (e.g. 3-fold symmetry).
  • Feedback textures use .private storage mode (GPU-only).
  • Idle throttling: 60 fps active → 10 fps when RMS < 0.005.
  • Shader library compiled by concatenating all .metal files (OberonShaders.metal first for shared utilities).
  • VizUniforms layout must match exactly between Swift (VizUniforms.swift) and Metal (OberonShaders.metal). chordIntervalMask is UInt32 in Swift / uint in Metal for alignment.
  • thread is a reserved Metal keyword — never use it as a variable name.
  • sacredRing() accepts float petal count for smooth morphing and variable depth parameter.