Inspector Parameters
Declare a public field on your script class and Awaken turns it into an editable control on the Script component - a slider, a checkbox, a dropdown, or an object picker - configurable per instance.
This is how one Rotator script drives a dozen objects at different speeds without touching code. Each object's Script entry stores its own overrides; the class ships sensible defaults.
Why fields become params
TypeScript types are erased at compile time, so Awaken cannot rely on the compiled class alone to know your fields. Instead, discoverScriptParams combines two sources:
- Instance introspection - it constructs the class and reads primitive-valued own properties. This gives accurate defaults, even computed ones.
#privatefields and methods are excluded automatically. - Source parsing - it scans the TypeScript for declared fields, catching typed-but-uninitialized fields (
speed: number;) that have no runtime value, plus the type annotations and//comments the compiled JS threw away.
The annotated type wins; the default comes from the instance value, falling back to the literal initializer, falling back to a type default (0 / "" / false).
Discovery runs on every Compile and on project load. Attach a script but never compile it, and the Inspector shows "Compile the script to expose its fields".
What counts as a param
A field is exposed if it is public and Awaken can determine a supported type. These are skipped:
- Methods, constructors, getters/setters, and arrow-function fields.
#privatefields (genuinely absent at runtime) and TSprivate/protectedfields (honoured by name from the source).- Bare identifiers with no type and no initializer.
The six param types
| Type | Declared as | Inspector control |
|---|---|---|
number | speed = 5 or speed: number; | Number box (scrub the label to drag-adjust) |
number (bounded) | turn = 90 // 0..360 | Slider + number box |
boolean | loop = true | Checkbox |
string | label = "Go" | Text field |
enum | mode: "loop" | "ping" | Dropdown |
vec3 | offset = { x: 0, y: 1, z: 0 } | X/Y/Z widget |
entity | target: Entity / camera: Camera | Object picker |
Numbers and sliders
A plain number field renders a number box whose label you can scrub (drag left/right) to adjust. Add a min..max range in the field's // comment and it becomes a bounded slider paired with a precise number box:
ts
speed = 2; // number box
turnRate = 90; // spin degrees 0..360 → slider from 0 to 360
health = 100; // hit points 0..100 → sliderThe range is parsed out of the comment text, so // turn rate 0..360 works - the surrounding words are just the tooltip.
Booleans
ts
clockwise = true; // checkbox, default tickedStrings and enums
A plain string is a free text field. A string-literal union type becomes a dropdown, so the user picks a valid value instead of typing an exact string:
ts
label = "Start"; // text field
mode: "loop" | "ping" | "once" = "loop"; // dropdown, defaults to "loop"If a stored value is no longer one of the declared options (you edited the union), it is added to the dropdown so it is never silently lost.
Vec3
Any { x, y, z } field renders the same X/Y/Z widget the Transform uses:
ts
offset = { x: 0, y: 1, z: 0 }; // three scrubable axesFor pivot-like fields - those named offset, pivot, center/centre, or anchor - the widget also shows a center button that sets the vector to the selected object's local mesh-geometry centre. Handy for rotating an off-centre object about its visual middle.
Entity references
A field typed Entity (or GameObject) renders an object picker listing scene objects. Type it as a component alias and the picker is filtered to objects carrying that component:
ts
target: Entity; // picks any object
camera: Camera; // lists only cameras
lamp: Light; // lists only lights
body: RigidBody; // lists only rigid bodiesThe filterable aliases are Camera, Light, MeshRenderer, MeshMaterial, RigidBody, Collider, AudioSource, Animator, UINode, and Tag. An unrecognised annotation falls back to listing all objects. This is exactly how the first-person controller exposes its camera: Camera field - a picker filtered to cameras - for the user to assign - see Examples.
Tooltips from comments
A field's trailing // comment becomes its Inspector tooltip (hover the param name):
ts
mouseSensitivity = 0.0025; // radians per pixel of mouse movement
jumpHeight = 1.2; // metres 0..3The comment does double duty: it is the help text, and any min..max inside it also makes a number a slider.
A worked example
ts
// Component behavior - runs during Play.
export default class implements ScriptBehavior {
speed = 90; // spin speed 0..360 (slider + tooltip)
axis: "x" | "y" | "z" = "y"; // rotation axis (dropdown)
clockwise = true; // reverse direction (checkbox)
pivot = { x: 0, y: 0, z: 0 }; // rotate about this offset (vec3 + center button)
lookAt: Entity; // face this object (object picker)
private phase = 0; // hidden: TS private → not a param
onUpdate(api: ScriptApi, dt: number) {
const a = this.axis;
const dir = this.clockwise ? 1 : -1;
const rad = (this.speed * Math.PI / 180) * dt * dir;
api.rotate(a === "x" ? 1 : 0, a === "y" ? 1 : 0, a === "z" ? 1 : 0, rad);
}
}This yields five controls: a speed slider (0–360), an axis dropdown, a clockwise checkbox, a pivot vec3 with a center button, and a lookAt object picker. phase is hidden because it is private.
📸 Screenshot - save as img/scripting-generated-params.png
The Inspector's Script component showing the generated controls for the worked example: the speed slider, the axis dropdown, the clockwise checkbox, the pivot vec3 widget with its center button, and the lookAt object picker.
How params are stored
Overrides live on the ScriptEntry - the per-object attachment - not on the class:
- Primitive, enum, and vec3 values are stored in
entry.params(aRecordof name → value). Only keys the user actually changed are stored; the rest use the class default. - Entity references are stored separately in
entry.refs(name → entity). These are remapped across save/load like any entity reference, so acameralink survives serialization and duplication.
At Play start, the runtime applies params then refs to the fresh instance before onStart. Only declared fields are set - stale params from an earlier version of the script cannot inject junk. Object values are deep-cloned so the running instance never aliases the stored data.
Editing a param while Play is running replaces that slot's params/refs object; the runtime detects the change and restarts that one behaviour from its play-start pose, so the preview reflects the game from the start. See Scripting Overview for the live-edit lifecycle.
See also
- ScriptApi Reference - the methods your fields feed into
- Writing & Compiling - Compile refreshes discovered params
- Inspector - where the controls render
- Examples - params in complete scripts