← lucian labs

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 component audio zero-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 component weather zero-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

Floating shop badge — a miniature vending machine that sits in the bottom-right corner. Minimizes to a golden orb. State persists across page loads via localStorage.

web component shadow dom zero-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.

Behavior

ActionResult
Page loadWidget appears bottom-right (or as orb if previously minimized)
Click XMachine shrinks into a golden 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 audio ym2413 opll zero-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.

analytics ga4

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