skimi3d Grid Log in Visit the grid
All scripts
Change how it looks

Colour Menu

Touch it, pick a colour from a menu, and the prim takes it. Twelve named colours to start with, and the list is yours to rewrite.

Goes inThe prim that should change colour
Setup5 to set
Code197 lines
Open toOpen to everyone

What it does

It offers the colours as a menu of named buttons and tints the face you choose. The names and the colours live in one list, side by side, so adding a colour is adding two entries and nothing else has to change. Above nine colours it pages the menu, because a dialog holds nine buttons and quietly loses the tenth. With WHOLE_LINKSET a wall built from six prims changes as one.

What you can build with it

A house somebody is choosing the walls of, a car in a showroom, a dress on a stand, the cushions in a room being tried out, a demo of something you sell in eight colours, team colours at an event. It is the cheapest way to make one build look like eight.

How to use it

1 Drop the script into the prim that should change colour.
2 Touch it and pick a colour. That is the whole of it working.
3 Rewrite the COLOURS list for your own set. Each colour is a name and then the colour it stands for, in that order.
4 Keep the names to about eleven characters, because the viewer cuts off longer buttons without telling anybody.
5 If only one face should change, put its number into FACE instead of -1.

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.

COLOURS The colours offered, as a name and then the colour it stands for. The names become the buttons, so keep them to about eleven characters and put them in the order you want shown. twelve named colours
FACE Which face takes the colour. -1 is every face; a single face number paints the cushion and leaves the frame. -1
WHOLE_LINKSET Colour every prim in the linkset rather than only this one. FALSE
HEADING The line above the buttons. Which colour?
WHO_MAY_CHANGE 0 for everyone, 1 for the owner alone, 2 for anyone wearing the same group tag. 0
The code LSL · 197 lines · updated 8 Sep 2026 Download .lsl
// =====================================================================
//  Colour Menu
//  skimi3d script library
//  https://grid.skimi3d.com/scripts/colour-menu
//
//  Touch it, pick a colour, and the prim takes it. The wall of a house
//  somebody is buying, a car in a showroom, a dress on a stand, the
//  cushions in a room they are trying out.
//
//  Plain LSL.
// =====================================================================


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

// The colours offered, as a name and then the colour it stands for.
// The names become the buttons, so keep them to about eleven
// characters, and put them in the order you want them shown.
list COLOURS = [
    "White",  <1.00, 1.00, 1.00>,
    "Bone",   <0.94, 0.90, 0.82>,
    "Sand",   <0.85, 0.74, 0.55>,
    "Rust",   <0.65, 0.28, 0.16>,
    "Moss",   <0.36, 0.45, 0.28>,
    "Slate",  <0.35, 0.39, 0.44>,
    "Ink",    <0.10, 0.11, 0.14>,
    "Rose",   <0.90, 0.60, 0.62>,
    "Sky",    <0.55, 0.72, 0.90>,
    "Gold",   <0.85, 0.68, 0.25>,
    "Plum",   <0.42, 0.24, 0.42>,
    "Sea",    <0.20, 0.52, 0.52>
];

// Which face takes the colour. -1 is every face; a single face number
// paints the cushion and leaves the frame.
integer FACE = -1;

// Colour every prim in the linkset rather than only this one.
integer WHOLE_LINKSET = FALSE;

// The line above the buttons.
string HEADING = "Which colour?";

// Who may change it. 0 = everyone, 1 = only the owner, 2 = same group.
integer WHO_MAY_CHANGE = 0;


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

float   PATIENCE = 60.0;    // how long the menu waits for an answer
integer PER_PAGE = 9;       // a dialog holds nine buttons and no more

integer gChannel = 0;
integer gListen  = 0;
integer gPage    = 0;


// Just the names, which are the buttons.
list names()
{
    list out = [];
    integer n = llGetListLength(COLOURS);
    integer i;

    // Two entries make one colour, so the step is two and not one.
    for (i = 0; i < n; i += 2)
    {
        out += [llList2String(COLOURS, i)];
    }

    return out;
}


list page(integer n, list all)
{
    integer total = llGetListLength(all);
    if (total <= PER_PAGE) return all;

    integer room  = PER_PAGE - 2;
    integer pages = (total + room - 1) / room;

    if (n < 0) n = pages - 1;
    if (n >= pages) n = 0;
    gPage = n;

    integer from = n * room;
    integer to   = from + room - 1;
    if (to > total - 1) to = total - 1;

    return llList2List(all, from, to) + ["< Back", "Next >"];
}


integer privateChannel(key who)
{
    return -1 - (integer)("0x" + llGetSubString((string)who, 0, 6));
}


menu(key who, integer n)
{
    if (gListen) llListenRemove(gListen);

    gChannel = privateChannel(who);
    gListen  = llListen(gChannel, "", who, "");

    llDialog(who, HEADING, page(n, names()), gChannel);
    llSetTimerEvent(PATIENCE);
}


shut()
{
    if (gListen) llListenRemove(gListen);
    gListen = 0;
    gPage   = 0;
    llSetTimerEvent(0.0);
}


paint(string name)
{
    integer at = llListFindList(COLOURS, [name]);
    if (at == -1) return;

    // The colour sits directly after its name, which is what the stride
    // of two is for.
    vector c = llList2Vector(COLOURS, at + 1);

    integer link = LINK_THIS;
    if (WHOLE_LINKSET) link = LINK_SET;

    llSetLinkPrimitiveParamsFast(link, [PRIM_COLOR, FACE, c, 1.0]);
}


integer mayChange(key who)
{
    if (WHO_MAY_CHANGE == 1) return who == llGetOwner();
    if (WHO_MAY_CHANGE == 2) return llSameGroup(who);
    return TRUE;
}


default
{
    state_entry()
    {
        shut();
    }

    touch_start(integer total)
    {
        key who = llDetectedKey(0);

        if (!mayChange(who))
        {
            llRegionSayTo(who, 0, "This one is not yours to change.");
            return;
        }

        menu(who, 0);
    }

    listen(integer channel, string name, key who, string message)
    {
        if (message == "Next >")
        {
            menu(who, gPage + 1);
            return;
        }

        if (message == "< Back")
        {
            menu(who, gPage - 1);
            return;
        }

        shut();
        paint(message);
    }

    timer()
    {
        shut();
    }

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

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