skimi3d Grid Log in Visit the grid
All scripts
Signs and text

Hover Text Sign

Floating words above a prim, and the trick of running twenty different signs off one script by putting the words in each object's Description.

Goes inThe prim the words should float above
Setup5 to set
Code120 lines
Open toOpen to everyone

What it does

It writes your lines as hover text above the prim. Written into the LINES list, that is a sign. Switched to READ_FROM_DESCRIPTION, it takes its words from the object's Description instead, with a vertical bar between lines, and that changes what the script is for: the same script goes into twenty prims and each one says something different, edited from the build tool without ever opening the code. It also warns you when your text is longer than a sign can hold, because that cut is silent otherwise.

What you can build with it

The label on a door, the name over a shop, a price on a stall, an arrow at the landing point, room names in a maze, a memorial plaque, the number on a house. With HIDE_THE_PRIM the words hang in the air with nothing holding them up, which is how most floating labels are done.

How to use it

1 Drop the script into the prim the words should float above.
2 Edit the LINES list. One line per entry, and keep it short.
3 For a set of signs, set READ_FROM_DESCRIPTION to TRUE instead, then put the words into each object's Description with a vertical bar between lines: Ferry|leaves on the hour.
4 After changing a Description, touch the sign. It has no way of noticing on its own.
5 Set HIDE_THE_PRIM to TRUE if only the words should show.

Settings you can change

5

Edit these at the top of the script. Everything works on the defaults · change them only when you need to.

LINES The words, one line per entry. Read at a glance, so keep them short. two example lines
READ_FROM_DESCRIPTION Take the words from the object's Description instead, with a vertical bar between lines. This is how one script runs twenty different signs. FALSE
COLOUR Colour of the text. <1.0, 1.0, 1.0>
ALPHA How solid the text is, from 0.0 to 1.0. 1.0
HIDE_THE_PRIM Make the prim itself invisible so the words hang in the air on their own. It is still there, still solid and still clickable. FALSE
The code LSL · 120 lines · updated 8 Sep 2026 Download .lsl
// =====================================================================
//  Hover Text Sign
//  skimi3d script library
//  https://grid.skimi3d.com/scripts/hover-text-sign
//
//  Floating words above a prim. The label on a door, the name of a
//  shop, the price on a stall, the arrow that says which way the
//  landing point is.
//
//  It can also read its words out of the object's Description, which is
//  the trick worth knowing: one script, twenty signs, and you change
//  each one from the build tool without ever opening the code.
//
//  Plain LSL.
// =====================================================================


// ---------------------------------------------------------------------
//  Settings
// ---------------------------------------------------------------------

// The words, one line per entry. Keep it short: hover text is read at a
// glance and there is a hard limit of about 254 characters in total.
list LINES = [
    "The Old Forge",
    "open to visitors"
];

// Take the words from the object's Description instead of from the list
// above. Use a vertical bar to separate lines: Ferry|leaves on the hour
//
// This is how you run twenty signs off one script. Drop the same script
// into all of them and give each one a different Description.
integer READ_FROM_DESCRIPTION = FALSE;

// Colour of the text, and how solid it is.
vector COLOUR = <1.0, 1.0, 1.0>;
float  ALPHA  = 1.0;

// Make the prim itself invisible, so the words hang in the air on their
// own. The prim is still there and can still be clicked.
integer HIDE_THE_PRIM = FALSE;


// ---------------------------------------------------------------------
//  Everything below here is the machinery
// ---------------------------------------------------------------------

// Hover text is cut off past roughly this many characters, and the cut
// is silent. Better to say so than to let somebody wonder where the
// last line went.
integer LIMIT = 254;


write()
{
    string text = "";

    if (READ_FROM_DESCRIPTION)
    {
        string d = llGetObjectDesc();

        // A brand new prim says "(No Description)" in some viewers and
        // nothing in others. Neither is a sign.
        if (d == "" || d == "(No Description)")
        {
            llSetText("", COLOUR, ALPHA);
            llOwnerSay("My Description is empty, so I have nothing to say. Put the words in the Description, and use | between lines.");
            return;
        }

        text = llDumpList2String(llParseString2List(d, ["|"], []), "\n");
    }
    else
    {
        text = llDumpList2String(LINES, "\n");
    }

    if (llStringLength(text) > LIMIT)
    {
        llOwnerSay("My text is longer than a sign can hold, so the end of it will not show. Around " + (string)LIMIT + " characters is the whole budget, newlines included.");
    }

    llSetText(text, COLOUR, ALPHA);
}


default
{
    state_entry()
    {
        if (HIDE_THE_PRIM) llSetAlpha(0.0, ALL_SIDES);
        write();
    }

    changed(integer what)
    {
        // A sign that changes hands should read itself again, because
        // the new owner's Description is the one that counts.
        if (what & CHANGED_OWNER) write();
    }

    touch_start(integer total)
    {
        // THERE IS NO EVENT FOR A CHANGED DESCRIPTION. Editing it in
        // the build tool tells the script nothing at all, and a sign
        // that polled its own Description every few seconds would be
        // twenty signs polling for ever to catch an edit that happens
        // twice a year. So: change the Description, then touch the
        // sign. Owner only, because a visitor touching a sign should
        // not be able to set it working.
        if (llDetectedKey(0) != llGetOwner()) return;
        write();
    }

    on_rez(integer start)
    {
        llResetScript();
    }
}

Copy it, make a new script inworld, paste over what is there and save. Nothing here phones home.