Log inGet started
World

The Eighth Ketyl

Branchmain
Branchesmain
Commite99ff0a216

README.md

KetylBody

The ketyl radical's look — the thing the player IS, and the brightest object in the still.

The player is a sodium benzophenone ketyl: a ketone that took one extra electron and went deep blue-violet, and that dies the instant it meets water. So the body is built as the molecule it is rather than as a ball of light. A carbonyl carbon at the centre, an oxygen off-axis carrying the charge, two phenyl rings in benzophenone's propeller — each ring six thin glowing rods closing a hexagon — the C=O drawn as the double bond it is, and one small fast spark on an inclined orbit for the unpaired electron. Around that: a shell of light with an edge you can see, a soft aura with no edge at all, and the afterimages the radical lays down as it drifts.

It reads no input and moves nothing. Where the ketyl IS belongs to KetylPilot; what it LOOKS LIKE belongs here.

What it listens for

EventWhat it does
charge(v, max)the light in it, the speed of the spark and the rings, the pitch of its hum
wetness(v, max)takes the colour out first, then the light; the corona breaks into beads
discharged(pos, dir)flares, and throws a forward half-circle of cyan-white light out to Still.DISCHARGE_RADIUS
surged()flares shorter, and lays the trail down four times as fast
quenched() / sealed() / runStart()the two endings and the reset

Still.state.charge / .wetness are read directly until the first event of that kind arrives, so the radical is right on its very first frame rather than after core has spoken once.

How one material serves forty parts

Every piece draws through one of two shaders in /source/ketyl, and every piece reads the same per-instance lane:

lane 0 = ( charge 0..1, wetness 0..1, flare 0..1, fade 0..1 )

renderer.instanceData.set writes it. That is what lets one .material serve the nucleus, both rings, the whole trail and the discharge fan while each of them differs in a number. A block nothing has written yet is all zeros, which would read as a dead, invisible radical, so both shaders fall back to (1, 0, 0, 1) when the whole lane is zero.

Fields

FieldDefaultWhat it is
scale1.45size, as a multiple of Still.KETYL_RADIUS
trailNodes14how many afterimages the trail is made of
trailStep0.045seconds between trail samples while moving
trailLife0.85seconds an afterimage takes to go out
lightIntensity26peak intensity of the point light the radical throws
lightRange11that light's range, in world units
humVolume0.62how loud its own hum sits under the rest of the mix
claimBloomtrueregister a bloom pass if nothing else in the world has

claimBloom yields: it looks for an effect already named bloom and does nothing if one is there, so whichever slice owns the atmosphere wins simply by registering its own.

The sound of it

/source/ketyl/bake_hum.luau computes ketyl_hum.soundClip in Luau — a low fundamental with its fifth and its octave, three of them half a hertz apart so the tone beats, and a thin shimmer above. It travels with the body on the ambient channel, under everything else. Charge pitches it up, water pulls it flat and shuts it, a discharge lifts it.

It is a loop, so every partial is a whole number of cycles across its two seconds and it is encoded as codec = "pcm". Re-bake it with execute { file = "/zero/source/ketyl/bake_hum.luau" }; it is idempotent.