Widgets

Embeddable components for any site. No frameworks, no build steps.

ll-radio

Lucian Labs Radio player. Streams live audio from the relay with now-playing metadata via SSE. Minimizes to a pulsing teal orb. Shadow DOM isolated.

web componentaudiozero-dep

Install

Drop the script and the element wherever you want it.

<script src="https://cdn.lucianlabs.ca/scripts/ll-radio.js"></script>
<ll-radio></ll-radio>

Attributes

AttributeDefaultPurpose
streamhttps://relay.elijahlucian.ca/radioIcecast-style audio stream URL
metahttps://relay.elijahlucian.ca/radio/meta/sseSSE endpoint for now-playing updates
positionbottom-leftbottom-left | bottom-right | top-left | top-right
accent#4ecdc4CSS color — applies to border, orb, progress bar, button

localStorage keys

KeyValuesPurpose
ll-radio-min"0" / "1"Persists minimized state

ll-clock

Clock + weather pill. Ticks every second, fetches weather from the GroundControl /weather endpoint every 10 minutes for a configured city (or lat/lon). Minimizes to a compact time-and-temp pill. Shadow DOM isolated.

web componentweatherzero-dep

Install

<script src="https://cdn.lucianlabs.ca/scripts/ll-clock.js"></script>
<ll-clock></ll-clock>

Attributes

AttributeDefaultPurpose
cityVancouver,CAFallback when no lat/lon is given or cached
latOverride coordinate latitude
lonOverride coordinate longitude
weather-urlhttps://control.lucianlabs.ca/weatherWeather endpoint
positiontop-righttop-right | top-left | bottom-left | bottom-right
accent#d4a843CSS color — applies to border, date, geo button, orb time

Weather endpoint

The widget calls GET {weather-url}?lat=…&lon=… (or ?city=…) and expects a JSON payload with temp, description, icon (OpenWeather code), and location. Server-side cache TTL is 1 hour; the widget refreshes every 10 minutes but most hits will be cached.

Browser geolocation

The crosshair button on the expanded panel prompts for navigator.geolocation and caches the result. No auto-prompt — the user has to opt in. Once granted, subsequent loads use the cached coordinates until they're cleared.

localStorage keys

KeyValuesPurpose
ll-clock-min"0" / "1"Persists minimized state
ll-clock-coords{"lat":…,"lon":…}Last granted browser geolocation
ll-clock-citystringUser-override city, beats the city attribute

ll-shop

The Lucian Labs shop — a miniature vending machine that sits in any corner you point it at, listing LAOE and the WaveLoop family. Minimizes to a blue orb. State persists across page loads via localStorage.

web componentshadow domzero-dep

Install

Add one script tag before </body>. The component auto-injects itself.

<script src="https://cdn.lucianlabs.ca/scripts/ll-shop.js"></script>

That's it. The <ll-shop> element is created automatically. Shadow DOM isolates all styles — no CSS conflicts with your page.

To place it yourself, write the element explicitly instead of letting it auto-inject:

<script src="https://cdn.lucianlabs.ca/scripts/ll-shop.js"></script>
<ll-shop position="top-left" expand="down"></ll-shop>

Attributes

AttributeValuesDefault
positionbottom-right / bottom-left / top-left / top-rightbottom-right
expandup / down / left / rightup for bottom corners, down for top corners

The panel is anchored to its corner, so expand picks which way it grows away from that corner (and which way the open/close animation scales). If a direction would push the panel off-screen, it flips to whichever side has more room — an unknown or contradictory value never strands the panel off the edge.

Behavior

ActionResult
Page loadWidget appears at its corner (or as orb if previously minimized)
Click XMachine shrinks into the orb with a scale animation
Click orbMachine expands back from the orb
Click product slotOpens App Store link, fires gtag event if available

localStorage keys

KeyValuesPurpose
ll-shop-min"0" / "1"Persists minimized state

yamabruh-notify

FM synth notification sounds powered by a software YM2413 OPLL chip. 99 presets, 10 mood-driven scale systems, deterministic melodies from any seed string. No WASM, no dependencies, no UI — just sound.

web audioym2413 opllzero-dep

Canonical reference: yama-bruh.lucianlabs.ca/ringtones

Install

<script src="https://cdn.lucianlabs.ca/scripts/yamabruh-notify.js"></script>

Usage

const yb = new YamaBruhNotify();

// Play a seeded ringtone (deterministic melody from the string)
yb.play('user-abc123');

// Play with options
yb.play('order-456', {
  preset: 88,    // 0–98, default 88 (Telephone Bell)
  bpm: 160,      // tempo, default 140
  volume: 0.5,   // 0–1, default 0.8
  mode: 'jazzy'  // mood — controls scale/movement palette
});

// Stop playback
yb.stop();

How it works

Each call to .play(seed) hashes the seed string into a deterministic RNG, generates a short melody (notes, rhythm, octave), renders it through the full YM2413 signal chain (2-op FM, ADSR envelopes, waveform selection, tremolo, vibrato, KSR, KSL), and plays it via the Web Audio API. Same seed + preset + mood always produces the same ringtone.

Constructor options

OptionDefaultDescription
preset88YM2413 preset index (0–98). 88 = Telephone Bell.
bpm140Tempo in beats per minute
volume0.8Master volume (0–1)
mode'experimental'Mood — selects scale pool and sequence behavior
sampleRate44100AudioContext sample rate
seednullRoot seed combined with per-call seed

Moods

Moods control which scales, intervals, and rhythms the sequence generator draws from. Set via constructor mode or per-call override.

MoodCharacter
prettyMajor/pentatonic, gentle movement, resolves to root
experimentalAll scales, wide intervals, no resolution
depressingMinor modes, descending motion, low register
spookyDiminished/whole-tone, wide leaps, unsettling
dreamyLydian/whole-tone, slow durations, resolves
aggressivePhrygian/blues, fast rhythms, low root
exoticPersian/Arabian/Balinese, non-Western scales
jazzyDorian/bebop/blues, syncopated, resolves
etherealWhole-tone/augmented, slow, spacious
mechanicalDiminished/symmetric, repetitive, fast

Live demo

Click a button to hear the preset. Each uses a different seed string.

mood:

Preset highlights

#Name#Name
0Piano 168Synth Lead
18Vibraphone88Telephone Bell
37Flute97Steel Drum
44Brass Ensemble104Fireworks
56String Ensemble116Wave

Full preset and mood reference at yama-bruh.lucianlabs.ca/ringtones.


GA4 analytics

Shared Google Analytics 4 tag for all Lucian Labs properties. Single measurement ID across every site.

analyticsga4

Install

Drop this in <head> on any Lucian Labs site.

<script async src="https://www.googletagmanager.com/gtag/js?id=G-HJPFEY11D7"></script>
<script>
  window.dataLayer = window.dataLayer || [];
  function gtag() { dataLayer.push(arguments); }
  gtag('js', new Date());
  gtag('config', 'G-HJPFEY11D7');
</script>

Custom events

Fire custom events with gtag('event', ...) anywhere after the snippet loads.

gtag('event', 'download_click', {
  event_category: 'engagement',
  event_label: 'choppa-ios'
});
PropertyValue
Measurement IDG-HJPFEY11D7
ScopeAll *.lucianlabs.ca properties