# MPP - Rotator Script V1.0.3 - Documentation

Turns the object it is on: a ceiling fan, a windmill, a planet, a sign, a door, a radar dish, a floating crystal. Around one axis or several at once, around the object's own axes or the world axes, without end or by a set number of degrees per axis, one way, there and back, or back and forth with a pause at each end. It starts when the scene loads, on a click, when an avatar touches the object, or on a Script Event from another script, and it tells other scripts when it starts, stops and reaches each end of its path.

This script is **standalone** - it does not require any other MPP script to function. It works with **MPP - Action Button** (a button that starts, stops, reverses or brings the object back) and with any MPP script that listens to Script Events, such as **MPP - Light Switch**.

**First release on the Store (V1.0.3).** The motion is computed by the Sansar server and interpolated for every visitor, so it stays smooth whatever their connection, and an object that is stopped resumes exactly where it was. The object can be carried or moved by another script (an **MPP - MyMood** item that follows its avatar, for example): the rotation resumes from wherever the object now stands.

---

## Quick Start

1. In Build mode, select the object and tick **Movable from Script** in its properties. If the object has physics, set it to **Keyframed** (a Static or Dynamic body cannot be turned by a script: the script says so in the script console and does nothing).
2. After purchase, the script is in your **Inventory**. Add it to the object, build and visit: the object turns around its vertical axis (Z), one full turn every 8 seconds.
3. Change `Rotation/Seconds Per Turn` for the speed, tick `Rotation/Reverse Z` for the other way, or turn on `Rotation/Axis X` or `Axis Y` instead of, or in addition to, Z.

That is all a fan or a planet needs. The rest of this guide details every option.

---

## How It Works

Two kinds of motion, chosen by the `Rotation/Degrees X`, `Degrees Y` and `Degrees Z` settings:

| Degrees | Motion |
|---|---|
| **Every enabled axis at 0** (default) | The object turns **without end**, one full turn every `Seconds Per Turn` seconds on each enabled axis |
| **At least one enabled axis with degrees** | The object follows a **path**: from its start pose (where you placed it) to an end pose where each enabled axis has turned by its own degrees, in `Seconds Per Turn` seconds. What happens at the end is set by `Path Mode (1-3)` |

Four ways to start and stop it:

| Trigger | Settings | What it does |
|---|---|---|
| **Scene load** | `Activation/Start On Load` (On) | The object turns as soon as the scene starts |
| **Click** | `Activation/Enable Click` (Off), `Hover Text When Stopped`, `Hover Text When Turning` | Each click stops a turning object, or starts a stopped one |
| **Collision** | `Activation/Use Collision` (Off) | An avatar touching the object (or entering it, for a trigger volume) does the same as a click, once per second at most |
| **Script Events** | `Events/Enable Script Events` (On), `Script Event Prefix` | Another script, such as an MPP - Action Button, sends `mpp_rotator_start`, `_stop`, `_toggle`, `_reverse` or `_return` |

Clicks, collisions and the events that carry an avatar go through the access control (`Access/Permission Mode (1-3)`) and, for clicks and collisions, the per-avatar cooldown.

In the Build panel the settings are grouped by category: `Activation/`, `Rotation/`, `Access/`, `Events/`, `Sound/` and `Debug/`.

---

## Axes and Direction

- `Rotation/Axis X`, `Axis Y`, `Axis Z`: the axes the object turns around. Z is the vertical axis of Sansar (default On). Several axes can be On at once: the object then **tumbles**, the rotations composing X, then Y, then Z.
- `Rotation/Reverse X`, `Reverse Y`, `Reverse Z`: run that axis the other way. Ignored when the axis is Off.
- `Rotation/Local Axes` (On): the axes are those of the object itself, as it is placed and tilted in the scene. A tilted fan keeps turning around its own hub. Off: the axes are the X, Y and Z of the world, whatever the tilt of the object.

If no axis is On, the script warns in the script console and does nothing.

---

## Speed

`Rotation/Seconds Per Turn` (default 8, minimum 0.5) is the time of one full turn when the object turns without end, and the time to go from the start pose to the end pose when degrees are set. The same value serves both cases, so a 720 degree path with 8 seconds takes 8 seconds, not 16.

A very fast setting (a large number of degrees in a short time) is slowed down by the script so the motion stays smooth, with a warning in the script console that gives the value used. Lower the degrees or raise the seconds to keep your own value.

---

## A Path With Degrees

Give degrees to one or several enabled axes: `Rotation/Degrees X`, `Degrees Y`, `Degrees Z`. Each enabled axis turns by its own degrees, and every axis reaches its end at the same moment. An enabled axis left at 0 while another has degrees does not turn. Degrees can be above 360 (720 = two turns).

`Rotation/Path Mode (1-3)` sets what happens at the end pose:

| Mode | Behaviour | Typical use |
|---|---|---|
| **1** | **One way.** The object stops at the end pose. The next click, touch or `_toggle` brings it back to the start pose, and so on | A door, a lever, a hatch |
| **2** | **There and back, then stop.** Pause at the end pose, return to the start pose, stop | A peek-a-boo panel, a bow |
| **3** (default) | **Back and forth without end**, with a pause at each end | A pendulum, a radar sweep, a swinging sign |

- `Rotation/Pause Seconds` (default 0): how long the object waits at an end of the path before it comes back, in modes 2 and 3.
- `Rotation/Motion Mode (1-4)` (default 2): the shape of each leg. 1 = constant speed, 2 = smooth start and stop, 3 = ease in (slow start, fast end), 4 = ease out (fast start, slow end). A rotation without end is always at constant speed.

A stopped object keeps its place on the path: click again and it continues from there, toward the end it was heading to. At an end pose, a start goes toward the other end.

---

## Starting and Stopping

### Scene load

`Activation/Start On Load` (On): the object turns as soon as the scene is ready. Off: it waits for a click, a touch or a Script Event.

### Click

`Activation/Enable Click` (Off): the object highlights on hover and shows `Activation/Hover Text When Stopped` ("Start") or `Hover Text When Turning` ("Stop"). Empty texts = highlight only. A click **toggles**: it stops a turning object (also during a pause at an end), and starts a stopped one.

- `Activation/Cooldown Seconds` (default 0, 0 to 600): a visitor who clicks again within this time is ignored. A silent 0.1 second anti double-click safety always remains.
- `Activation/Cooldown Notice` (On): the ignored visitor receives a private message, by default "Please wait {time} before using this object again." (`{time}` = the remaining time with its unit, `{seconds}` = the whole seconds). At most one message every 3 seconds per visitor. Empty text, or the notice Off, = silent.

### Collision

`Activation/Use Collision` (Off): an avatar touching the object toggles it like a click, at most **once per second per avatar**, so an avatar leaning on a turning object does not make it flicker. The object needs a rigid body (Keyframed). For a trigger volume, entering the volume counts. The `Cooldown Seconds` and the access control apply too.

### Script Events

See "Script Events" below: `_start`, `_stop`, `_toggle`, `_reverse` and `_return`.

If `Start On Load`, `Enable Click`, `Use Collision` and `Enable Script Events` are all Off, nothing can ever start the object: the script warns in the script console.

---

## Access

Who may start or stop the object by click, touch or event follows `Access/Permission Mode (1-3)`:

| Mode | Who is allowed |
|---|---|
| **1** | The scene owner only |
| **2** | The scene owner and the avatars of `Access/Whitelist` |
| **3** (default) | Everyone, except the avatars of `Access/Blacklist` (empty list = everyone) |

The scene owner is always allowed, in every mode. The lists take avatar **handles** (the name in the profile link, `https://www.sansar.com/profiles/<handle>`) or avatar **UUIDs**, separated by commas or semicolons; `@` and letter case are ignored. A display name with a space is ignored with a warning.

- `Access/Denied Text`: private message to an avatar who clicks or touches without being allowed (default "You are not allowed to use this object."), at most once every 5 seconds; empty = silent.
- `Access/Hide From Denied` (Off): in click mode, the avatars who are not allowed do not see the object as clickable at all (no highlight, no hover text). The check on click stays active.

Start On Load is not subject to the access control: it is the scene itself that starts the object.

---

## Script Events

Everything goes through one name, `Events/Script Event Prefix` (default `mpp_rotator`). Two rotators with different prefixes are controlled separately; two with the same prefix move together.

### Events the object listens to

With `Events/Enable Script Events` (On):

| Event | Effect |
|---|---|
| `<prefix>_start` | Start: spin, or go to the end pose. Nothing happens if the object already turns that way, or already stands at the end pose (Path Mode 1: use `_toggle` or `_return` to bring it back). An object on its way back turns around |
| `<prefix>_stop` | Stop where it is |
| `<prefix>_toggle` | Stop if turning, start otherwise: the same as a click |
| `<prefix>_reverse` | The other way, at once while turning. For a rotation without end, the new direction is kept for the next start |
| `<prefix>_return` | Back to the start pose at the normal speed, then stop, even in Path Mode 3. A rotation without end goes to the nearest full turn |

Set an **MPP - Action Button** to "Send as Command" with one of these names: a control desk with Start, Stop and Reverse buttons takes three buttons.

`Events/Use Click Permission` (On): an event that carries the avatar who pressed the button (every MPP button does) is checked against `Permission Mode` like a click, the owner always allowed; an event without an avatar (a timer, a scheduler) is accepted in mode 3 only. Off: every event is accepted, with or without an avatar.

### Events the object sends

With `Events/Send Script Events` (Off):

| Event | When |
|---|---|
| `<prefix>_started` | The object starts turning from a stop |
| `<prefix>_stopped` | The object stops, whatever the reason: click, touch, event, end of the path in modes 1 and 2 |
| `<prefix>_arrived` | The end pose is reached (paths with degrees) |
| `<prefix>_returned` | The start pose is reached: at the end of a return leg, or after `_return` |

The events carry the avatar who started the object (empty when the scene started it), so an **MPP - Light Switch** set to the same prefix lights a lamp while the object turns, and any MPP script that listens to Script Events can follow.

---

## Sounds

Three optional sounds, all played at the object with `Sound/Sound Volume` (0 to 200 percent, 100 = the original volume, 0 = no sound):

- `Sound/Start Sound`: once, when the object starts turning.
- `Sound/Turning Sound`: in a loop while the object turns (a motor hum, wind in the blades), stopped with a short fade when it stops or pauses at an end of the path.
- `Sound/Stop Sound`: once, when the object stops, by a click, an event or the end of the path.

The sounds play on the object's audio emitter when it has one, else at the object's position.

---

## Editor Properties Reference (36 total)

### Activation
| Property | Type | Default | Description |
|---|---|---|---|
| Activation/Start On Load | bool | On | The rotation starts when the scene loads |
| Activation/Enable Click | bool | Off | A click starts or stops the rotation (Access applies) |
| Activation/Use Collision | bool | Off | An avatar touching the object starts or stops it, once per second at most; needs a rigid body |
| Activation/Hover Text When Stopped | string | "Start" | Hover text while stopped; empty = highlight only |
| Activation/Hover Text When Turning | string | "Stop" | Hover text while turning or pausing; empty = highlight only |
| Activation/Cooldown Seconds | number, 0-600 | 0 | Wait per avatar between two clicks or touches; 0 = none (0.1 s safety) |
| Activation/Cooldown Notice | bool | On | Private "please wait" message for a click during the cooldown |
| Activation/Cooldown Notice Text | string | "Please wait {time} before using this object again." | Text of that message; `{time}` and `{seconds}` are replaced; empty = no message |

### Rotation
| Property | Type | Default | Description |
|---|---|---|---|
| Rotation/Axis X | bool | Off | Turn around X |
| Rotation/Axis Y | bool | Off | Turn around Y |
| Rotation/Axis Z | bool | On | Turn around Z (vertical) |
| Rotation/Reverse X | bool | Off | X the other way |
| Rotation/Reverse Y | bool | Off | Y the other way |
| Rotation/Reverse Z | bool | Off | Z the other way |
| Rotation/Local Axes | bool | On | On = the object's own axes; Off = the world axes |
| Rotation/Seconds Per Turn | number | 8 | Seconds for one full turn, or for the path from start pose to end pose; minimum 0.5 |
| Rotation/Degrees X | number | 0 | Degrees turned around X before the end pose; 0 on every enabled axis = without end |
| Rotation/Degrees Y | number | 0 | Same for Y |
| Rotation/Degrees Z | number | 0 | Same for Z |
| Rotation/Path Mode (1-3) | integer, 1-3 | 3 | 1 = one way (the next start comes back), 2 = there and back then stop, 3 = back and forth without end |
| Rotation/Pause Seconds | number | 0 | Wait at an end of the path before turning back (modes 2 and 3) |
| Rotation/Motion Mode (1-4) | integer, 1-4 | 2 | 1 = constant, 2 = smooth, 3 = ease in, 4 = ease out; paths with degrees only |

### Access
| Property | Type | Default | Description |
|---|---|---|---|
| Access/Permission Mode (1-3) | integer, 1-3 | 3 | Who may start or stop the object; the owner always |
| Access/Whitelist | string | (empty) | Handles or UUIDs allowed in mode 2 |
| Access/Blacklist | string | (empty) | Handles or UUIDs refused in mode 3 |
| Access/Denied Text | string | "You are not allowed to use this object." | Private refusal, at most every 5 s; empty = silent |
| Access/Hide From Denied | bool | Off | Click mode: the object is not clickable for refused avatars |

### Events
| Property | Type | Default | Description |
|---|---|---|---|
| Events/Enable Script Events | bool | On | Listen to `<prefix>_start`, `_stop`, `_toggle`, `_reverse`, `_return` |
| Events/Script Event Prefix | string | "mpp_rotator" | Base name of every event, received and sent; empty = mpp_rotator |
| Events/Use Click Permission | bool | On | Events with an avatar follow Permission Mode; without avatar, mode 3 only. Off = every event accepted |
| Events/Send Script Events | bool | Off | Post `<prefix>_started`, `_stopped`, `_arrived`, `_returned` |

### Sound
| Property | Type | Default | Description |
|---|---|---|---|
| Sound/Start Sound | sound | (none) | Played once at start |
| Sound/Turning Sound | sound | (none) | Looped while turning, faded out at stops and pauses |
| Sound/Stop Sound | sound | (none) | Played once at stop |
| Sound/Sound Volume | integer, 0-200 | 100 | Loudness in percent; 0 = no sound |

### Debug
| Property | Type | Default | Description |
|---|---|---|---|
| Debug/Debug Logging | bool | Off | Writes the settings read at start, every start, stop, end of path and access decision (with the avatar handle and UUID) to the script console. Warnings are always written |

---

## Version Notes

| Version | What changed |
|---|---|
| V1.0.0 - V1.0.2 | Internal versions, never released: one Degrees value shared by every axis, then degrees per axis, then the first take on a Mover shared with another script |
| **V1.0.3** (this version) | First release on the Store. Rotation without end or by degrees per axis (X, Y, Z) in three Path Modes with a pause; local or world axes; start at load, by click, by collision or by Script Events; events sent at start, stop and each end of the path; access by permission mode; per-avatar cooldown with a "please wait" notice; three sounds; settings grouped by category; the rotation resumes by itself when another script moves the object (an MPP - MyMood item, for example) |

---

## Recipes

**A - The ceiling fan.** Defaults, `Seconds Per Turn` 2, a hum in `Sound/Turning Sound`. Tick `Reverse Z` if the blades turn the wrong way for their shape.

**B - The slow planet.** Tilt the object in the scene, `Local Axes` On, `Seconds Per Turn` 120: it turns around its own tilted pole.

**C - The door.** `Degrees Z` 90, `Seconds Per Turn` 2, `Path Mode (1-3)` 1, `Motion Mode (1-4)` 2, `Start On Load` Off, `Enable Click` On, `Hover Text When Stopped` "Open / Close", a creak in `Start Sound` and a thud in `Stop Sound`. The hinge side of the door must be the object's pivot. Each click opens or closes.

**D - The pendulum or radar sweep.** `Degrees X` 60 (or `Degrees Z` for a radar), `Seconds Per Turn` 2, `Path Mode` 3, `Pause Seconds` 0.5, `Motion Mode` 2: it swings without end.

**E - The control desk.** Three MPP - Action Buttons set to "Send as Command" with `mpp_rotator_start`, `mpp_rotator_stop` and `mpp_rotator_reverse`; `Start On Load` Off on the rotator. Add `mpp_rotator_return` for a "home" button.

**F - The tumbling crystal.** `Axis X`, `Axis Y` and `Axis Z` On, every Degrees at 0, `Seconds Per Turn` 20, `Reverse Y` On for a less regular pattern.

**G - The windmill you can stop.** Defaults plus `Use Collision` On on a Keyframed body: touch the wheel to stop it, touch it again to start it, once per second at most.

**H - Two doors that open together.** The same `Script Event Prefix` (`door_hall`) on both rotators, one Action Button sending `door_hall_toggle`.

---

## Troubleshooting

| Symptom | Check |
|---|---|
| The object does not move at all | **Movable from Script** must be ticked on the object; a Static or Dynamic rigid body must be set to Keyframed; at least one `Axis` must be On; something must start it (`Start On Load`, a click, a touch or an event). The script console says which one |
| It turns around the wrong axis | Sansar's vertical axis is Z. With `Local Axes` On the axes follow the object's own tilt; try Off, or another axis |
| It turns the wrong way | Tick the `Reverse` switch of that axis |
| It is slower than the value I set | Too many degrees in too few seconds: the script slows the motion down and writes the value used in the script console. Lower the degrees or raise `Seconds Per Turn` |
| A click does nothing | `Enable Click` Off; or your own cooldown (with `Cooldown Notice` On you get the "please wait" message); or `Permission Mode` refuses you (Denied Text) |
| The Action Button does nothing | `Events/Enable Script Events` On, the button's command equal to `<prefix>_start` (or `_toggle`...), and, with `Use Click Permission` On, the avatar who presses must pass `Permission Mode` |
| `_start` does not bring the door back | In Path Mode 1, `_start` only goes to the end pose: use `_toggle` or `_return` to come back |
| The object comes back after a `_return` in Path Mode 3 | It does not: `_return` stops at the start pose. Only a click, `_start` or `_toggle` starts it again |
| The hum keeps playing after a stop | `Turning Sound` is stopped with a short fade; `Start Sound` and `Stop Sound` are not loops: put the loop in `Turning Sound` only |
| Touching the object does nothing | `Use Collision` On and a rigid body on the object (Keyframed). One touch per second per avatar |
| The object stops turning after another script moved it | It resumes within a second, from its new place. While the other script keeps moving it (an MPP - MyMood item following a walking avatar), the rotation is interrupted; it comes back as soon as the object is left alone |
| A friend on the Whitelist is refused | The list takes the **handle** (from the profile link) or the avatar UUID, not the display name; an entry with a space is ignored with a warning |
| I want to know what the script does | Turn `Debug/Debug Logging` On: the script console shows the settings read at start and every start, stop and end of path |

---

## Limits

- The object must be **Movable from Script**. With a rigid body, only a Keyframed one follows the rotation; a Static or Dynamic body is refused.
- The script turns the object in place: it does not move it along, and does not scale it.
- `Seconds Per Turn` cannot go under 0.5; very fast paths are slowed down with a warning so the motion stays smooth.
- The start pose is the object's pose in the scene. A stopped object resumes from where it stopped; a scene restart puts it back at its start pose.
- When another script moves or turns the object, the rotation resumes within a second from the object's new pose, which becomes its new start pose: a path with degrees then measures its ends from there.
- A Script Event without an avatar (sent by a script that is not an MPP button) is accepted only when `Use Click Permission` is Off or `Permission Mode` is 3.

---

## Related MPP Items

| Item | What it adds |
|---|---|
| **Action Button Script** | Buttons that start, stop, reverse or bring the object back through Script Events, on a control desk. Store: https://www.sansar.com/store/listings/3e1a3546-6c79-4527-bc1e-78d02648d19e/action-button-script |
| **Light Switch Script** | Lamps that follow the object: set to the same prefix, they light on `_started` and go off on `_stopped`. Store: https://www.sansar.com/store/listings/7379d48c-2b6f-45f6-b6f1-205ce95aec1c/light-switch-script |
| **MyMood Package** | A mood item that turns above your head: put the Rotator on the item; the rotation follows the item wherever your avatar goes |
| **Random Object Spawner Script** | Spawns copies of a turning object: each copy turns from where it appears, and they all answer the same events. Store: https://www.sansar.com/store/listings/1de81a6d-1e59-4b68-9423-c11b4deaa61d/random-object-spawner-script |
| **Commands Help On Chat Script** | Lists your scene commands when a visitor asks for help, and greets arrivals. Store: https://www.sansar.com/store/listings/fea2df6b-21ce-48eb-94fc-4b7a7aad2777/commands-help-on-chat-script |

---

*MPP - My Pretty Pixels. Rotator Script V1.0.3 (script `MPP - Rotator`). Store: https://www.sansar.com/store/listings/89d478b4-0897-4f94-a690-4bf992e138da/rotator-script*
