Skip to content

Script overte#71

Open
zedwick wants to merge 25 commits intooverte-org:masterfrom
zedwick:script_overte
Open

Script overte#71
zedwick wants to merge 25 commits intooverte-org:masterfrom
zedwick:script_overte

Conversation

@zedwick
Copy link
Contributor

@zedwick zedwick commented Feb 22, 2026

This PR brings the Script section of the docs up to date.

  • Some files have been converted from markdown to reStructuredText to standardise the docs, however usually only when I felt it necessary or simpler for the changes I intended to make.
  • Removed recommendations to use incomplete or non-working functionality.
  • Corrected instructions where the interface had changed, including images where appropriate.
  • Example JavaScript code has been updated to use Strict mode.
  • Changed examples to accommodate and entertain both VR and Desktop users.
  • Rewrote text to remove negative framing in certain places
  • Corrected inaccuracies about the current features of Overte
  • Tested all example code to ensure they work, and fixed them if they did not.
  • Improved clarity in some areas
  • Other miscellaneous changes

* De-emphasise Overte being just a VR platform
* Don't use var in example scripts
* Convert from markdown to reStructuredText format
* Fix syntax error in example code
* Expand Equip Item section with full working example
* Add "use strict" and remove vars in example code
* console.log in an exported function will not show in logs
* "use strict", etc.
* Also add a way for desktop users to try out the avatar script by pressing "x" on their keyboard.
* Remove section on using Package Model to add scripts; does not work
* Replace image of text editor with code block, including highlighted line
* Encourage use of server entity script in some situations
* Correct steps to add a client entity script, with scripts page icon.
* Example script now wil "use strict", etc.
* Correct steps to attach a Server Entity Script to an Entity
* Example script will now "use strict", etc.
* I don't mean to alarm anyone, but it is now closer to 40 years since the 80s. A slight change to the wording to make this tutorial timeless.
* Loading a script from the UI will load it persistently
* clickDownOnEntity only responds to mouse click events; cannot be used in VR with controllers
* mousePressOnEntity responds to both mouse click and controller trigger events
@zedwick zedwick marked this pull request as ready for review February 24, 2026 12:58

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.

Comment on lines 50 to 110
(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);
});
}());
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.)

Comment on lines +47 to +48
.. code-block:: javascript
:caption: throw_ball.js
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.

Server Entity Scripts
#####################

You can make content in Overte interactive by attaching scripts to entities. *Server entity scripts* are entity scripts that run on the server (or domain) that hosts the entity. These scripts run persistently in a domain, even if there are no users present. This means that there is only one instance of the script is running at a time, and it is running on the server. Any behavior that is controlled by your script will be seen and heard by everyone in the domain.
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
You can make content in Overte interactive by attaching scripts to entities. *Server entity scripts* are entity scripts that run on the server (or domain) that hosts the entity. These scripts run persistently in a domain, even if there are no users present. This means that there is only one instance of the script is running at a time, and it is running on the server. Any behavior that is controlled by your script will be seen and heard by everyone in the domain.
You can make content in Overte interactive by attaching scripts to entities. *Server entity scripts* are entity scripts that run on the server (or domain) that hosts the entity. These scripts run persistently in a domain, even if there are no users present. This means that there is only one instance of the script running at a time, and it is running on the server. Any behavior that is controlled by your script will be seen or heard by everyone in the domain.


.. note:: An entity can have multiple server entity scripts attached to it, but all of these must be through a single file URL.

.. |scripts-icon| image:: _images/create-properties-scripts-icon.png
Copy link
Member

Choose a reason for hiding this comment

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

Too low contrast.

3. In the **Create** app, go to the 'Properties' tab and select the Scripts icon. |scripts-icon|
4. For 'Server Script', enter the URL to your server entity script.

.. note:: An entity can have multiple server entity scripts attached to it, but all of these must be through a single file URL.
Copy link
Member

Choose a reason for hiding this comment

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

Does this apply to client scripts as well? I had no idea we could do this, and thought this is what we added Script Entities for.

@@ -0,0 +1,76 @@
#####################
Server Entity Scripts
#####################
Copy link
Member

Choose a reason for hiding this comment

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

This page should probably mention the DeveloperScriptingEntity Script Server Log.


<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Entity scripts, unlike interface scripts, are in containing functions. The example scripts here cannot be attached to an entity (and be used as an entity script) unless they are in a containing function ``function() {}``.</p>
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
<p>Entity scripts, unlike interface scripts, are in containing functions. The example scripts here cannot be attached to an entity (and be used as an entity script) unless they are in a containing function <code>function() {}</code>.</p>

@JulianGro
Copy link
Member

You can apply multiple suggestions at once from the Files changed page.

Co-authored-by: Julian Groß  <julian.g@posteo.de>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants