Decorators: Inspector Component Starter
The same demo project as the Script Base tutorial, viewed through the Inspector-design lens. The component turns plain serialized fields into creator-friendly controls with headers, tooltips, constrained numbers, conditional fields, and read-only runtime state.

What you'll build
- A script component with two serialized SceneObject references.
- A grouped Inspector section for live tuning.
- A numeric dropdown for theme presets.
- Sliders and spin boxes that constrain user input.
- A
showIffield that appears only when pulse animation is enabled. - A multiline note field and a read-only runtime tick counter.
Open the demo
↓ inspector-component-starter.zip
Open GameController > InspectorComponentStarter in the Inspector. Tune
the fields, then run preview to see the StatusText readout and the pulsing
PreviewBlock react to those values.
Decorator block
InspectorComponentStarter.ts
@component()
export class InspectorComponentStarter extends APJS.BasicScriptComponent {
@header("Scene Wiring")
@serializeProperty()
@tooltip("Screen Image object that this component animates.")
previewBlock!: APJS.SceneObject;
@serializeProperty()
@tooltip("2D Text object used as a live runtime readout.")
statusText!: APJS.SceneObject;
@separator()
@header("Inspector Controls")
@serializeProperty()
@tooltip("Text shown in the runtime HUD.")
labelText: string = "Inspector Component";
@serializeProperty()
@dropDown([
["Calm", 0],
["Energy", 1],
["Warning", 2],
])
theme: number = 1;
@serializeProperty()
@slider(0, 1, 0.01)
pulseStrength: number = 0.32;
@serializeProperty()
@spinBox(1, 10, 1)
scoreStep: number = 3;
@serializeProperty()
enablePulse: boolean = true;
@serializeProperty()
@showIf("enablePulse", true)
@slider(0.25, 3, 0.05)
pulseSpeed: number = 1.2;
@serializeProperty()
@textArea(3)
note: string = "Tune fields in the Inspector, then preview to see runtime state.";
@serializeProperty()
@readOnly()
runtimeTicks: number = 0;
}
Why each decorator is here
@component()registers the class as a script component type that can be attached to a SceneObject.@serializeProperty()exposes a field in the Inspector and lets the editor persist it.@header()and@separator()make long components easier to scan.@tooltip()explains a field without adding extra objects to the scene.@dropDown()is good for named presets that map to stable string or number values.@slider()is best for continuous values like pulse strength and pulse speed.@spinBox()is best for discrete values like score increments.@showIf()keeps dependent controls hidden until they matter.@textArea()gives authors room for multiline text.@readOnly()exposes runtime state without inviting manual edits.
Runtime usage
The script reads the decorated fields like normal TypeScript properties:
const pulse = this.enablePulse
? 1 + Math.sin(this.elapsed * this.pulseSpeed * 6.28318) * this.pulseStrength
: 1;
this.status.text =
this.labelText +
"\nTheme: " + this.themeName() +
" | Step: +" + this.scoreStep +
"\nTicks: " + this.runtimeTicks +
"\n" + this.note;
Decorators shape the editor experience; they do not require a special runtime read API. Once the project is running, the fields are just properties on the component instance.