Skip to main content

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.

Decorator controls in the Inspector Component Starter demo

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 showIf field 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.

Copyright © 2026 TikTok. All rights reserved.
About TikTokHelp CenterCareersContactLegalTerms of ServicePrivacy PolicyCookies