Skip to content
Open
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
4d481be
Improve script/get-started-with-scripting
zedwick Feb 2, 2026
7d22d19
Minor improvements to script/write-scripts
zedwick Feb 3, 2026
7574c15
Improve script/js-tips
zedwick Feb 3, 2026
563c6ba
Convert script/interface-scripts from markdown to reStructuredText
zedwick Feb 3, 2026
8727dfe
Fix example code in script/js-tips
zedwick Feb 4, 2026
86715fd
Final touches to script/interface-scripts
zedwick Feb 4, 2026
1c43615
Covnerted script/assignment-client-scripts from markdown to reStructu…
zedwick Feb 4, 2026
7284865
Update code example in script/assignment-client-scripts with "use str…
zedwick Feb 4, 2026
fc26577
Convert script/avatar-scripts from markdown to reStructuredText
zedwick Feb 4, 2026
01b8f55
Update example script in script/avatar-scripts
zedwick Feb 4, 2026
36a4473
Improve script/avatar-scripts
zedwick Feb 4, 2026
b4b53bf
Rename script/client-entity-scripts from .md to .rst
zedwick Feb 4, 2026
5bcf4e8
Remove image file already removed from script/avatar-scripts
zedwick Feb 4, 2026
f26b1ad
script/client-entity-scripts markdown -> reStructuredText
zedwick Feb 4, 2026
3f5617b
Improve script/client-entity-scripts
zedwick Feb 4, 2026
f0eb1de
Renamed script/server-entity-scripts .md -> .rst
zedwick Feb 4, 2026
1793b6d
Convert script/server-entity-scripts from Markdown to reStructuredText
zedwick Feb 4, 2026
ea6e9e2
Improve script/server-entity-scripts
zedwick Feb 5, 2026
86ed9d5
Minor improvement to script/midi-tutorial
zedwick Feb 5, 2026
d6dc17b
Revert the removal of a single letter which had been removed incorrectly
zedwick Feb 22, 2026
5bcb3fb
Overte scripting now runs on the V8 engine
zedwick Feb 23, 2026
7787dc0
Add note about use of to 3 script pages.
zedwick Feb 23, 2026
44dc419
Update the example interface script to be a little more interesting.
zedwick Feb 24, 2026
e7f2281
Use mousePressOnEntity in client entity script example
zedwick Feb 24, 2026
e0c4a91
Apply suggestions from code review
zedwick Feb 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file removed source/script/_images/add-script.png
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
58 changes: 0 additions & 58 deletions source/script/assignment-client-scripts.md

This file was deleted.

67 changes: 67 additions & 0 deletions source/script/assignment-client-scripts.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#########################
Assignment Client Scripts
#########################

Assignment Client (AC) scripts (also known as "persistent scripts") run persistently in a domain and aren't affected by other scripts. These scripts run on an assignment client separate from the Interface, so the script will continue to run until you either remove the script from the domain or you shut down the domain entirely.

With AC scripts, you can do things like coordinate actions between entities and avatars, and add virtual pets to greet visitors to your domain.

.. contents:: On This Page
:depth: 2

----------------
Add an AC Script
----------------

Once you've written and hosted your script, you need to add it to a domain, either your own or one where you have permissions to run an AC script.

1. Open your 'Domain Administration Panel'. If you are on a local sandbox, open it by clicking on the Overte icon in the taskbar notifications and 'click Settings'.
2. From the menu, go to **Content > Scripts**.
3. In the Persistent Scripts section, click **+** and paste the URL to your script under 'Script URL'.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume these are the same as the assignment client script under http://localhost:40100/assignment ?
If you think so too, maybe we should open an issue about streamlining the UI there. It is quite confusing to have more or less the same thing in two different places.


.. image:: _images/ac-script.png

4. At the top of the page, click 'Save and Restart'. Now, every time you enter that domain, the AC script will be running.

-----------------------
Example of an AC Script
-----------------------

The following script counts the number of entities found in a domain using Overte's `EntityViewer <https://apidocs.overte.org/EntityViewer.html>`_.

.. code-block:: javascript

"use strict"
const SEARCH_CENTER = {x: 0, y: -10, z: 0};
const SEARCH_RADIUS = 100;

let isInitialized = false;
const timeout = 1000;

const update = function(deltaTime) {
if (!isInitialized) {
if (Entities.serversExist() && Entities.canRez()) {
EntityViewer.setPosition(SEARCH_CENTER);
EntityViewer.setCenterRadius(SEARCH_RADIUS);
EntityViewer.queryOctree();

Script.setTimeout(function(){
var foundEntities = Entities.findEntities(SEARCH_CENTER, SEARCH_RADIUS).length;

print("AC Script found: " + foundEntities + " entities within " + SEARCH_RADIUS + "m of " + JSON.stringify(SEARCH_CENTER));

}, timeout);

isInitialized = true;
Script.update.disconnect(update);
}
}
};

Script.update.connect(update);

**See Also**

- `Configure Your Domain Settings <../host/configure-settings>`_
- `Get Started with Scripting <get-started-with-scripting>`_
- `Write Your Own Scripts <write-scripts>`_
82 changes: 0 additions & 82 deletions source/script/avatar-scripts.md

This file was deleted.

119 changes: 119 additions & 0 deletions source/script/avatar-scripts.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
##############
Avatar Scripts
##############

Avatar scripts are bound to an avatar. This means that they run when a user puts on a specific avatar. Likewise, avatar scripts stop running when the avatar is removed or changed. Other users in the domain will be able to see the script in action, but they will not be able to run the script themselves.

With avatar scripts, you can do things like make your hair flow or create particle clouds around your avatar.

.. contents:: On This Page
:depth: 2

--------------------
Add an Avatar Script
--------------------

The recommended way to add an avatar script to your FST file is by manually editing the file to add your script url:

1. Open the FST file for your avatar in the text editor of your choice.
2. Add a line telling the avatar where to find the script file using the syntax ``script = [SCRIPT URL]``.

.. code-block:: javascript
:emphasize-lines: 5
:caption: A sample of woody's FST file with a script added

name = mannequin
type = body+head
scale = 1
filename = mannequin/mannequin.fbx
script = mannequin/scripts/throw_ball.js
joint = jointNeck = Neck
joint = jointLean = Spine
joint = jointEyeLeft = LeftEye
joint = jointEyeRight = RightEye
joint = jointRoot = Hips
joint = jointLeftHand = LeftHand
joint = jointRightHand = RightHand
joint = jointHead = Head

You can add multiple scripts to your avatar by adding multiple ``script = url`` lines.

---------------------------
Example of an Avatar Script
---------------------------

The following script makes your avatar throw balls when its right hand moves.

.. code-block:: javascript
:caption: throw_ball.js
Comment on lines +47 to +48
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
.. code-block:: javascript
:caption: throw_ball.js
.. code-block:: javascript
:caption: throw_ball.js

If you prefer having 4-space indentation for the directive, instead of having the first indentation of the script be 3 spaces.


(function(){
"use strict"
let triggerDistance = 0.0;
const TRIGGER_THRESHOLD = 0.9;
const LOAD_THRESHOLD = 0.6
const rightHandIndex = MyAvatar.getJointIndex("RightHand");
const rightArmIndex = MyAvatar.getJointIndex("RightArm");
let triggered = false;

function fireBall(position, speed) {
const baseID = Entities.addEntity({
type: "Sphere",
color: { blue: 128, green: 128, red: 20 },
dimensions: { x: 0.1, y: 0.1, z: 0.1 },
position: position,
dynamic: true,
collisionless: false,
lifetime: 10, // Thrown fireball will despawn after 10 seconds
gravity: speed,
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
});
Entities.editEntity(baseID, { velocity: speed });
}

// VR users can push their right hand forwards from their shoulder to throw
Script.update.connect(function() {
const rightHandPos = MyAvatar.getJointPosition(rightHandIndex);
const rightArmPos = MyAvatar.getJointPosition(rightArmIndex);
const fireDir = Vec3.subtract(rightHandPos, rightArmPos);
const distance = Vec3.length(fireDir);
triggerDistance = distance > triggerDistance ? distance : triggerDistance;
if (!triggered) {
if (distance < LOAD_THRESHOLD * triggerDistance) {
triggered = true;
}
} else if (distance > TRIGGER_THRESHOLD * triggerDistance) {
triggered = false;
fireBall(rightHandPos, Vec3.normalize(fireDir));
}
});
MyAvatar.scaleChanged.connect(function () {
triggerDistance = 0.0;
});

// Desktop users can press and release "x" to throw
function keyReleaseEvent(event) {
if ((event.text.toUpperCase() === "X") && !event.isAutoRepeat && !event.isShifted && !event.isMeta && !event.isControl && !event.isAlt) {
const rightHandPos = MyAvatar.getJointPosition(rightHandIndex);
const rightArmPos = MyAvatar.getJointPosition(rightArmIndex);
const fireDir = getPointingDirection();
fireBall(rightHandPos, Vec3.normalize(fireDir));
}
}
// Runs desktop function whenever (any) key is released
Controller.keyReleaseEvent.connect(keyReleaseEvent);
// It is a good idea to clean up when the script stops
Script.scriptEnding.connect(function () {
print("removing key mapping");
Controller.keyReleaseEvent.disconnect(keyReleaseEvent);
});
}());
Comment on lines 50 to 110
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
(function(){
"use strict"
let triggerDistance = 0.0;
const TRIGGER_THRESHOLD = 0.9;
const LOAD_THRESHOLD = 0.6
const rightHandIndex = MyAvatar.getJointIndex("RightHand");
const rightArmIndex = MyAvatar.getJointIndex("RightArm");
let triggered = false;
function fireBall(position, speed) {
const baseID = Entities.addEntity({
type: "Sphere",
color: { blue: 128, green: 128, red: 20 },
dimensions: { x: 0.1, y: 0.1, z: 0.1 },
position: position,
dynamic: true,
collisionless: false,
lifetime: 10, // Thrown fireball will despawn after 10 seconds
gravity: speed,
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
});
Entities.editEntity(baseID, { velocity: speed });
}
// VR users can push their right hand forwards from their shoulder to throw
Script.update.connect(function() {
const rightHandPos = MyAvatar.getJointPosition(rightHandIndex);
const rightArmPos = MyAvatar.getJointPosition(rightArmIndex);
const fireDir = Vec3.subtract(rightHandPos, rightArmPos);
const distance = Vec3.length(fireDir);
triggerDistance = distance > triggerDistance ? distance : triggerDistance;
if (!triggered) {
if (distance < LOAD_THRESHOLD * triggerDistance) {
triggered = true;
}
} else if (distance > TRIGGER_THRESHOLD * triggerDistance) {
triggered = false;
fireBall(rightHandPos, Vec3.normalize(fireDir));
}
});
MyAvatar.scaleChanged.connect(function () {
triggerDistance = 0.0;
});
// Desktop users can press and release "x" to throw
function keyReleaseEvent(event) {
if ((event.text.toUpperCase() === "X") && !event.isAutoRepeat && !event.isShifted && !event.isMeta && !event.isControl && !event.isAlt) {
const rightHandPos = MyAvatar.getJointPosition(rightHandIndex);
const rightArmPos = MyAvatar.getJointPosition(rightArmIndex);
const fireDir = getPointingDirection();
fireBall(rightHandPos, Vec3.normalize(fireDir));
}
}
// Runs desktop function whenever (any) key is released
Controller.keyReleaseEvent.connect(keyReleaseEvent);
// It is a good idea to clean up when the script stops
Script.scriptEnding.connect(function () {
print("removing key mapping");
Controller.keyReleaseEvent.disconnect(keyReleaseEvent);
});
}());
(function(){
"use strict"
let triggerDistance = 0.0;
const TRIGGER_THRESHOLD = 0.9;
const LOAD_THRESHOLD = 0.6
const rightHandIndex = MyAvatar.getJointIndex("RightHand");
const rightArmIndex = MyAvatar.getJointIndex("RightArm");
let triggered = false;
function fireBall(position, speed) {
const baseID = Entities.addEntity({
type: "Sphere",
color: { blue: 128, green: 128, red: 20 },
dimensions: { x: 0.1, y: 0.1, z: 0.1 },
position: position,
dynamic: true,
collisionless: false,
lifetime: 10, // Thrown fireball will despawn after 10 seconds
gravity: speed,
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
});
Entities.editEntity(baseID, { velocity: speed });
}
// VR users can push their right hand forwards from their shoulder to throw
Script.update.connect(function() {
const rightHandPos = MyAvatar.getJointPosition(rightHandIndex);
const rightArmPos = MyAvatar.getJointPosition(rightArmIndex);
const fireDir = Vec3.subtract(rightHandPos, rightArmPos);
const distance = Vec3.length(fireDir);
triggerDistance = distance > triggerDistance ? distance : triggerDistance;
if (!triggered) {
if (distance < LOAD_THRESHOLD * triggerDistance) {
triggered = true;
}
} else if (distance > TRIGGER_THRESHOLD * triggerDistance) {
triggered = false;
fireBall(rightHandPos, Vec3.normalize(fireDir));
}
});
MyAvatar.scaleChanged.connect(function () {
triggerDistance = 0.0;
});
// Desktop users can press and release "x" to throw
function keyReleaseEvent(event) {
if ((event.text.toUpperCase() === "X") && !event.isAutoRepeat && !event.isShifted && !event.isMeta && !event.isControl && !event.isAlt) {
const rightHandPos = MyAvatar.getJointPosition(rightHandIndex);
const rightArmPos = MyAvatar.getJointPosition(rightArmIndex);
const fireDir = getPointingDirection();
fireBall(rightHandPos, Vec3.normalize(fireDir));
}
}
// Runs desktop function whenever (any) key is released
Controller.keyReleaseEvent.connect(keyReleaseEvent);
// It is a good idea to clean up when the script stops
Script.scriptEnding.connect(function () {
print("removing key mapping");
Controller.keyReleaseEvent.disconnect(keyReleaseEvent);
});
}());

The indentation of the code-block directive is 3 spaces, so by adding 4 spaces, the resulting code-block has everything indented one space too far. You can change the indentation of the directive to 4 spaces, to avoid having to use 3 spaces in the first indentation instead. (See my other comment/suggestion.)



This example script uses the `MyAvatar <https://apidocs.overte.org/MyAvatar.html>`_ namespace to determine if your avatar's hand moves. Upon detecting movement, the script makes your avatar launch balls. It also uses some other namespaces such as `Entities <https://apidocs.overte.org/Entities.html>`_ (to create the ball you will launch) and `Vec3 <https://apidocs.overte.org/Vec3.html>`_ (to determine the right positions and distances). Add it to your avatar to see how it works.

**See Also**

- `Get Started with Scripting <get-started-with-scripting>`_
- `Write Your Own Scripts <write-scripts>`_
- `API Reference <https://apidocs.overte.org>`_
48 changes: 0 additions & 48 deletions source/script/client-entity-scripts.md

This file was deleted.

Loading