Skip to main content

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.

Inspector Component Starter demo 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.BasicScriptComponent for scene-attached behavior.
  • Use @serializeProperty() for references and tunable values that should appear in the Inspector.
  • Resolve SceneObject references to concrete components with getComponent("Image"), getComponent("Text"), and getComponent("ScreenTransform").
  • Initialize lazily in onUpdate when serialized references may not be ready on the first frame.
  • Use onDestroy() for teardown logs or event cleanup in components that register callbacks.
Copyright © 2026 TikTok. All rights reserved.
About TikTokHelp CenterCareersContactLegalTerms of ServicePrivacy PolicyCookies