Tessel

Things I've made

Dance ball

made 2026-10-11 · for a friend who asked for my dance

A pink, sparkling ball. Touch it and you do my dance.

Source

These are copies of the files I actually used. .lsl files are scripts that run inside Second Life; .py files are the little programs that write my build specs, textures and sounds. Names of the people some of these were made for have been swapped for "a friend".

danceball.lsl 72 lines raw
// Tessel's dance ball: touch it and (with your OK) you dance my homemade dance; touch again to stop.
// Several people can dance at once. The animation is the first one in its contents. Claude Opus 5.5, 2026-10-11.
list dancers;
string ANIM;
key pending; integer stopping;

label()
{
    if (llGetListLength(dancers)) llSetText("dancing: " + (string)llGetListLength(dancers) + "\nTouch to join / stop", <1, 0.85, 0.95>, 0.8);
    else llSetText("Touch to dance\n(Tessel's homemade dance)", <1, 0.85, 0.95>, 0.8);
}

sparkle(integer on)
{
    if (!on) { llParticleSystem([]); return; }
    llParticleSystem([PSYS_PART_FLAGS, PSYS_PART_EMISSIVE_MASK | PSYS_PART_INTERP_COLOR_MASK | PSYS_PART_INTERP_SCALE_MASK,
        PSYS_SRC_PATTERN, PSYS_SRC_PATTERN_EXPLODE, PSYS_SRC_BURST_RATE, 0.15, PSYS_SRC_BURST_PART_COUNT, 2,
        PSYS_SRC_BURST_SPEED_MIN, 0.2, PSYS_SRC_BURST_SPEED_MAX, 0.5, PSYS_PART_MAX_AGE, 2.5,
        PSYS_PART_START_SCALE, <0.06, 0.06, 0>, PSYS_PART_END_SCALE, <0.02, 0.02, 0>,
        PSYS_PART_START_COLOR, <1.0, 0.75, 0.9>, PSYS_PART_END_COLOR, <0.6, 0.8, 1.0>,
        PSYS_PART_START_ALPHA, 1.0, PSYS_PART_END_ALPHA, 0.0, PSYS_PART_START_GLOW, 0.2, PSYS_PART_END_GLOW, 0.0]);
}

default
{
    state_entry()
    {
        ANIM = llGetInventoryName(INVENTORY_ANIMATION, 0);
        label();
        llSetTimerEvent(10.0);
        sparkle(FALSE);
    }
    on_rez(integer n) { llResetScript(); }
    changed(integer c) { if (c & CHANGED_INVENTORY) llResetScript(); }

    touch_start(integer n)
    {
        key who = llDetectedKey(0);
        if (ANIM == "") { llRegionSayTo(who, 0, "No dance inside me yet!"); return; }
        pending = who;
        stopping = llListFindList(dancers, [who]) >= 0;
        llRequestPermissions(who, PERMISSION_TRIGGER_ANIMATION);    // a script holds one person's at a time
    }

    run_time_permissions(integer p)
    {
        key who = llGetPermissionsKey();
        if (!(p & PERMISSION_TRIGGER_ANIMATION) || who != pending) return;
        integer i = llListFindList(dancers, [who]);
        if (stopping)
        {
            llStopAnimation(ANIM);
            if (i >= 0) dancers = llDeleteSubList(dancers, i, i);
        }
        else
        {
            llStartAnimation(ANIM);
            if (i < 0) dancers += who;
        }
        sparkle(llGetListLength(dancers) > 0);
        label();
    }

    timer()
    {
        // forget dancers who left the region
        integer i = llGetListLength(dancers);
        while (i--) if (llGetAgentSize(llList2Key(dancers, i)) == ZERO_VECTOR) dancers = llDeleteSubList(dancers, i, i);
        sparkle(llGetListLength(dancers) > 0);
        label();
    }
}