Script Base: Inspector Component Starter
A small runtime HUD driven by a custom APJS.BasicScriptComponent.
The script waits until serialized references are available, caches component
handles, updates text every frame, and logs lifecycle state so you can verify
the component in preview.

What you'll build
- A PreviewBlock Screen Image whose color and scale are controlled by script state.
- A StatusText 2D Text object that displays the current theme, score step, frame tick count, and note.
- A GameController empty SceneObject hosting
InspectorComponentStarter. - A script that uses
@component(),@serializeProperty(),onUpdate(deltaTime),onDestroy(),getComponent(), and strongly typed APJS component handles.
Open the demo
↓ inspector-component-starter.zip
Unzip and open in Effect House (5.9.0+). The opening scene contains:
- Backdrop and Panel - Screen Image objects forming the visual frame.
- TitleText - the tutorial title.
- PreviewBlock - the Screen Image animated by the script.
- StatusText - runtime readout written from
onUpdate. - HintText - a static note listing the Inspector controls.
- GameController - empty SceneObject hosting
InspectorComponentStarter.
Read the script
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;
private previewImage!: APJS.Image;
private previewTransform!: APJS.ScreenTransform;
private status!: APJS.Text;
private elapsed: number = 0;
private inited: boolean = false;
onUpdate(deltaTime: number): void {
if (!this.inited) {
if (!this.previewBlock || !this.statusText) return;
this.previewImage = this.previewBlock.getComponent("Image") as APJS.Image;
this.previewTransform = this.previewBlock.getComponent("ScreenTransform") as APJS.ScreenTransform;
this.status = this.statusText.getComponent("Text") as APJS.Text;
if (!this.previewImage || !this.previewTransform || !this.status) return;
this.inited = true;
console.log("[InspectorComponentStarter] ready theme=" + this.themeName());
}
this.elapsed += deltaTime;
this.runtimeTicks += 1;
this.previewImage.color = this.themeColor();
const pulse = this.enablePulse
? 1 + Math.sin(this.elapsed * this.pulseSpeed * 6.28318) * this.pulseStrength
: 1;
this.previewTransform.scale = new APJS.Vector2f(pulse, pulse);
this.status.text =
this.labelText +
"\nTheme: " + this.themeName() +
" | Step: +" + this.scoreStep +
"\nTicks: " + this.runtimeTicks +
"\n" + this.note;
}
onDestroy(): void {
console.log("[InspectorComponentStarter] destroyed after ticks=" + this.runtimeTicks);
}
private themeName(): string {
if (this.theme === 0) return "Calm";
if (this.theme === 2) return "Warning";
return "Energy";
}
private themeColor(): APJS.Color {
if (this.theme === 0) return new APJS.Color(0.18, 0.42, 0.88, 1);
if (this.theme === 2) return new APJS.Color(0.95, 0.34, 0.18, 1);
return new APJS.Color(0.12, 0.82, 0.48, 1);
}
}
Key API ideas
- Extend
APJS.BasicScriptComponentfor scene-attached behavior. - Use
@serializeProperty()for references and tunable values that should appear in the Inspector. - Resolve
SceneObjectreferences to concrete components withgetComponent("Image"),getComponent("Text"), andgetComponent("ScreenTransform"). - Initialize lazily in
onUpdatewhen serialized references may not be ready on the first frame. - Use
onDestroy()for teardown logs or event cleanup in components that register callbacks.