User Tools

Site Tools


Ruth HUDs


I have an implemention of Fred's XTEA encryption idea using the r2_xtea.lsl script. The control and receiver scripts will auto-detect r2_xtea and use it if it is present.

One HUD To Rule Them All

I have combined the various smaller HUDs created for Ruth into a single multi-pane HUD. You too can build it from scratch following the steps below. The primary assembly script is configured with the UUIDs of the full perm textures that I have already loaded into Second Life and OSGrid. Users on other grids will need to upload those textures and modify the hud-maker script accordingly.

So here is the steps I took to build the current (ss-q) combined HUD:

  • Create/upload textures (Ruth2 source, Roth2 source)
    • ruth2_v3_hud_gradient.png - hud_texture
    • ruth2_v3_hud_header.png - header_texture - the top tab-bar
    • ruth2_v3_hud_skin.png - skin_texture
    • ruth2_v3_hud_options.png - Ruth options_texture
    • ruth2_v3_hud_fingernail_shape.png - fingernails_shape_texture
    • roth2_v2_hud_options.png - Roth options_texture
    • r2_hud_alpha_buttons.png - alpha_button_texture
    • r2_hud_alpha_doll.png - alpha_doll_texture
  • Create scripts
    • r2_hud_maker (source)
      • set the *_texture UUIDs in the get_textures() function
      • set ROTH = TRUE to build a Roth2 HUD
    • hud-control (source)
  • Upload mesh
  • hud-maker box
    • Create a new cube and take a copy to inventory named 'Object'
    • Rename new cube on ground to hud-maker
    • Add to new cube contents:
      • the cube taken above named 'Object'
      • the mesh button objects
      • the hud-maker script
  • Take a copy of the hud-maker box as you may want to try this more than once and it is transformative to the starting cube
  • Click on the box and watch it work!
    • Click 'Yes' to allow linking
  • Remove all contents from the root prim
  • Add the ru2HUD_combined script
    • Add the other scripts to complete the skin functionality
    • Add the animations for the hand and foot poses to function
  • Test it! click on the top bar, the HUD will rotate so the 'current' selection is at the bottom
  • Take the HUD into inventory and attach it to one of the 'top' HUD points. It should re-position itself so it is visible. With only the control script present only the alpha selections and the top navigation bar will be functional, plus the Bakes on Mesh button on the Skin panel.
  • fini! Limoncello for all!

Now to prepare the body!

Roth2 v2

Roth2 v2 is a complete mesh body in one bit of mesh and 8 faces. The original import includes eyes that are linked to the body. We need a root prim added…

  • Rez the imported Roth2 v2 body on the ground
  • Create a new prim, resize it to <0.1, 0.1, 0.1> (or whatever you like that is small) and make it transparent
  • Position the new root prim near the center of the body, the position is not critical but putting it inside the mesh makes it unobtrusive when the body is razzed and not worn.
  • Link the body to the new root prim, taking care to shift-click the new root prim last so it is actually the root prim :)
  • Rename the body parts:
    • root: whatever you want it to be in inventory: Roth2 v2 TEST
    • main body: body
    • eyes: righteye, lefteye
  • Add the ru2HUD_receiver.lsl script to the root prim
  • Take the body into inventory and attach it to Avatar Center

Ruth2 v3

The current HUD script is not compatible with Ruth2 v3 as the alpha cuts are radically different. Version ss-r of the HUD controller script has the Ruth2 v3 body mapping in it but also requires the old Alpha HUD with the unrigged doll mesh.

Alpha HUD Data


Buttons are known internally as groups, why? Because it isn't always going to be a button controlling things and they operate on one or more faces at once.

  • a region is one of the areas identified for skin textures using the current list for Bakes on Mesh
    • head, upper, lower, eyes, skirt, hair, leftarm, leftleg, aux1, aux2, aux3
    • we add fingernails and toenails at the end to handle our own textures
  • each unit of alpha cut, aka 'element', is identified by a prim name and a face number, written as (prim, face)
    • the body prim names are considered well-known and that list may be assumed for any given mesh release
    • A face of -1 implies all faces (ALL_SIDES)
  • each prim has an alpha state stored in an integer, mapping faces to the lower 8 bits; the upper 8 bits are reserved
    • the state of an element with a face value of -1 is carried in all 8 lower bits, ie 'visible' = 255
  • each group maps to a list of elements
  • both the body receiver and the HUD controller will build a list of prim names mapped to link numbers
    • all identification of prims is by name not by link number
    • these link numbers will almost certainly not be the same in the HUD and the body
  • alpha state can be stored as a list of prims and its state
    • (prim, state)
    • it would be nice on memory use if the prim was able to not be kept as a string

Data Structures

  • regions (with two added at the end):
    list regions = [
  • prim_map: list of prim names (string) indexed by link number
    list prim_map = [
  • element_map: list with stride 4 of prim name (string), face (integer), group (string), region (integer):
    integer element_stride = 4;
    list element_map = [
        "head", -1, "head", 0,
        "chest", -1, "chest", 1,
        "breastright", -1, "breasts", 1,
        "breastleft", -1, "breasts", 1,
        "armright", 0, "armsupper", 1,
        "armright", 1, "armsupper", 1,
        "armleft", 0, "armsupper", 1,
        "armleft", 1, "armsupper", 1,
        "armleft", -1, "arms", 1,
        "armleft", -1, "arms", 1,
        "hands", -1, "hands", 1,
        "fingernails", -1, "hands", 1,
        "pelvisfront", 5, "crotch", 2,
        "pelvisfront", 5, "crotch", 2,
        "pelvisback", -1, "pelvis", 2,
        "pelvisback", -1, "pelvis", 2,
        "legright1", -1, "legsupper", 2,
        "legright2", -1, "legsupper", 2,
        "legright6", -1, "legslower", 2,
        "legright7", -1, "legslower", 2,
        "legright1", -1, "legs", 2,
        "legright2", -1, "legs", 2,
        "legright6", -1, "legs", 2,
        "legright7", -1, "legs", 2,
        "feet", -1", "feet", 2,
        "toenails", -1, "feet", 2,

    Note: this mapping is based on the Ruth2 v3 mesh, Roth2 v2 and Ruth2 v4 are expected to have a much simpler set of faces and links and will rely on system alphas and Bakes on Mesh support for detailed alpha cuts. As of this writing the current map for Roth2 v2 looks like:

    list element_map = [
        "body", 3, "head", 0,
        "body", 4, "neck", 1,
        "body", 6, "arms", 1,
        "body", 1, "hands", 1,
        "fingernails", -1, "hands", 11,
        "body", 7, "torso", 2,
        "body", 5, "legs", 2,
        "body", 0, "feet", 2,
        "body", 2, "hair", 5,
        "toenails", -1, "feet", 12,
        "lefteye", -1, "eyes", 3,
        "righteye", -1, "eyes", 3
  • Alpha state:
    • The state of the alpha selections is stored as a JSON string internally. It is a single object that uses the prim names as keys and a bit-mapped integer as the value.
    • The state of each face is stored as a single bit in each prim's value with the face number determining the bit position. ie, face 0 is bit 0 (the lowest-order bit in the integer), etc. LSL integers are 32 bit but due to weirdness with signed integers these values are masked to only use the low 16 bits. Mesh objects are limited to 8 faces so typically we will only use the low 8 bits but the manipulation functions support 16.
    • The script uses 1 or 1.0 to represent 'visible', corresponding to the alpha value that LSL functions use, and 0 or 0.0 for transparent. Since we alpha body parts fully in either direction only integers are actually used.
    • The JSON blob stores the alpha state exactly the opposite of this, ie a 1 bit represents an invisible face. This allows the storage of faces to not be dependent on the number of bits in use. For example, saving a prim with faces 0 and 2 transparent would be the value 0101 in binary or 5 in decimal and hex. Storing this to match the alpha values would make the stored value 1010 in binary or 10 decimal or 0x0a in hex. But only if 4 bits are used. As an 8 bit value it would be 11111010 (binary), 250 (decimal) or 0xfa in hex. This would require us to also keep track of the number of bits. The translation between these two states is completely encapsulated in the json_get_alpha() and json_set_alpha() functions and should not be of concern to script writers.

This storage method for alpha state allows us to keep an arbitrary number of saved states in a list where each set is a single JSON string. These strings are human-readable, and could even be put into notecards or easily passed between scripts as required.


  • Map button to elements:
        integer i;
        list groups = llList2ListStrided(llDeleteSubList(element_map, 0, 1), 0, -1, element_stride); 
        integer len = llGetListLength(groups);
        for (; i <= len; ++i) {
            if (llList2String(groups, i) == group_name) {
                // process matching group entry
                string prim_name = llList2String(element_map, i * element_stride);
                integer face = llList2Integer(element_map, (i * element_stride) + 1);
                // do something with each (prim, face) here

Page Tools