logo
Kurashizu Blogwhere ideas flow
  • Home
  • News
  • Blog
  • About
  • Home
  • News
  • Blog
  • About

© 2026 Kurashizu. All rights reserved.

Admin·New Post·Service Status
Powered by Cloudflare·31.10.26
← Back to news

Creating the Aetheryte Radio

Original article
haz.ee|40 points|8 comments|by wonger_|Aug 28, 2026

Engineering the Aetheryte Radio

The Motivation

When I'm in the zone at work, I rely heavily on ambient noise. Specifically, I've spent the last six years obsessively looping a YouTube video titled "aetheryte asmr," which captures the crystalline humming of the teleportation crystals from Final Fantasy XIV.

However, relying on a browser tab for six years revealed several minor significant flaws:

FeatureYouTube ExperienceDesired Experience
LoopingUnreliable; occasionally breaks and auto-plays random videos.Infinite and unbreakable.
SeamlessnessNoticeable gaps/cuts every ~7 minutes.Perfectly gapless playback.
ResourcesHigh CPU/RAM usage for a simple audio loop.Lightweight and efficient.
ControlStatic recording.Dynamic, generative ambiance.

Note: I previously spent an absurd amount of time rewriting my music player's internals just to achieve gapless playback, so the lack of seamlessness was particularly grating.

The Quest for Assets

I eventually decided to stop settling and build my own solution. To do this, I needed the raw game files.

The "Brute Force" Phase

I discovered that FFXIV isn't heavily encrypted. Using a Java-based FFXIV Data Explorer, I was able to extract compressed assets from the game's installation directory. I had a hash table mapping files to English names, but I didn't use it.

My "Genius" Plan:

  1. Export 4,000 .wav files.
  2. Load them all into mpv.
  3. Manually press the left/right arrow keys to listen to every single one.

"I spent four hours scrubbing through 4,000 audio assets... I didn't even find the right ones before I had to go to sleep at 3 AM."

The "Work Smarter" Phase

I realized I should leverage the existing modding community. By using xivlauncher (recommended by my roommate, who has a staggering 180 days of playtime), I gained access to several plugins:

  • vfxeditor
  • soundfilter ←\leftarrow← The MVP

The soundfilter plugin allows you to see the name of the asset currently playing in real-time. By teleporting to an Aetheryte in-game, I instantly identified the target file: bgcommon/sound/fst/placednpc_ethelight_big_loop.scd/0

Technical Implementation

The asset was a container. Index 0 was the low-frequency "hum," while other indices contained "whirs." I decided to recreate this dynamically using the Web Audio API rather than just mixing it in Logic Pro.

The Architecture

Audio processing generally follows a "node" philosophy—similar to modular synthesizers—where samples are produced, transformed, and consumed.

1. The Hum (The Foundation)

The hum is a nearly perfect loop. With some help from a friend to ensure sample-accurate looping (preventing that annoying "click" by resetting the offset in the sink node), I built a simple chain:

2. The Whirs (The Life)

To prevent the brain from detecting a repeating pattern, FFXIV triggers "whir" sounds at random intervals, pitches, and volumes. I translated the game's internal min/max parameters into JavaScript logic:

Randomization Parameters:

  • Pitch (Playback Rate): Range=[0.794,1.0]\text{Range} = [0.794, 1.0]Range=[0.794,1.0]
  • Volume (Gain): Range=[0.6,1.0]\text{Range} = [0.6, 1.0]Range=[0.6,1.0]
// Logic for generating a random whir event
const whirIndex = Math.floor(Math.random() * whirs.length);
const whirPlaybackRate = Math.random() * (1 - 0.794) + 0.794;
const whirGainValue = Math.random() * (1 - 0.6) + 0.6;

The Code Structure

Setting up the hum involves allocating the node, setting metadata, and connecting it before starting playback:

const humSource = audioContext.createBufferSource();
// Asset mapping: "assets/hum.wav.opus.aac" -> "assets/hum.wav.opus"
humSource.loop = true; 
humSource.connect(humGainNode);
humSource.start(0);

To handle the whirs, I avoided while(true) loops to prevent blocking the main thread. Instead, I used a recursive setTimeout to schedule the next random event.

Project Checklist:

  • Extract raw .scd assets
  • Identify "Hum" vs "Whir" tracks
  • Implement gapless Web Audio loop
  • Program random pitch/gain modulation
  • Schedule asynchronous triggers via setTimeout

Aetheryte Concept Figure 1: Conceptual representation of the generative audio flow.