Nubu
  • Features
  • How it works
  • Pricing
  • Integrations
  • FAQ
  • Contact
  • Docs
  • Blog
  • Log in
  • Log inSign up
    Nubu

    Creative automation for teams that ship campaigns, not busywork.

    Try for free
    Product
    FeaturesNubu MotionHow it worksPricingIntegrationsFAQ
    Company
    AboutContactDocsBlogLog in
    Legal
    Privacy policyTerms of serviceData deletion
    © 2026 Bear Studios · Nubu
    Introduction
    Templates overviewInstalling Nubu BuilderAdding template compsAdding propertiesAdding footageSetting defaultsExporting your templateUploading a template
    Flows overviewAvailable nodesAdding a nodeConnecting nodesWorking with dataTemplates and outputsUsing AI nodesBuilding a creative
    CampaignsTemplatesAssetsGlossariesRendersSettings
    Connecting Meta AdsConnecting Google AdsConnecting OpenAIConnecting Gemini AI StudioConnecting Anthropic
    AI Assistant overviewPrompt examplesAssistant settings and controls
    Nubu Motion scripts: the reference
    OverviewQuick startDifferences from After EffectsDeterminism
    JavaScript supportReferences and idsProject scriptsState and timeBudgets and errorsFormatting values
    GlobalTime conversionInterpolationVector mathsRandom and noiseColour conversionOther maths
    LayerCompPropertyKeyframePathGeometryProjectComponentConsoleComponentControlExpressionControl
    The property vocabularyAnimators propertiesAudio propertiesContent propertiesContents propertiesEffects propertiesExpression controls propertiesFills propertiesInstance controls propertiesLayer propertiesLayout propertiesMasks propertiesStrokes propertiesText style propertiesTransform propertiesTrim path properties
    Error codesBudgets
    Changelog
    All docs
    Motion Scripting
    / Objects

    ComponentControl

    The members of one component control: its identity, its kind and the effective value for the instance being evaluated.

    One component control with its effective value for the evaluating instance.

    Table of contentsidWorked example: A control's stable idlabelWorked example: The human labelkindWorked example: Branch on the control's kindvalueWorked example: The effective value, per context

    id#

    Type: string (field).

    The control id (stable per definition).

    Worked example: A control's stable id#

    The scene. A Badge component whose internal comp holds one blue face layer, exposed with a scalar Amount control, plus one Badge instance placed in the Host comp with Amount overridden to 65.

    • The comp Host: 640 by 360 at 25 fps, 100 frames (4 seconds).
    • The comp Badge internals: 200 by 200 at 25 fps, 100 frames (4 seconds).
    • Badge face in Badge internals: a solid layer, at [100, 100], 120 by 120, filled #4d9de0.
    • Badge in Host: a component instance, at [320, 180].
      • The instance overrides the component's c_amount control to 65.
    • The component Badge wraps Badge internals and exposes 1 control: Amount (scalar, default 20).

    The script is EMBEDDED in the Badge component - add it from the component's own Scripts group, and it travels with the component wherever it is placed.

    The script. Add a component script named Id check and paste:

    export const outputs = ["layer_1:transform.opacity"];
    
    export function frame() {
      const first = thisComponent.controls[0];
      return first.id === "c_amount" ? 75 : 5;
    }
    

    Line by line:

    • Lines 4-5: Each exposed control keeps a stable id per definition - the key control(id) uses and the one instance overrides are stored against. Relabelling the control never touches it. The check passes, so the face rests at 75.

    What you see. The badge face rests at 75 percent - confirmation that the first exposed control's id is the stable c_amount whatever its label says.

    The badge face rests at 75 percent - confirmation that the first exposed control's id is the stable c_amount whatever its label says.

    label#

    Type: string (field).

    The display label.

    Worked example: The human label#

    The scene. A Badge component whose internal comp holds one blue face layer, exposed with a scalar Amount control, plus one Badge instance placed in the Host comp with Amount overridden to 65.

    • The comp Host: 640 by 360 at 25 fps, 100 frames (4 seconds).
    • The comp Badge internals: 200 by 200 at 25 fps, 100 frames (4 seconds).
    • Badge face in Badge internals: a solid layer, at [100, 100], 120 by 120, filled #4d9de0.
    • Badge in Host: a component instance, at [320, 180].
      • The instance overrides the component's c_amount control to 65.
    • The component Badge wraps Badge internals and exposes 1 control: Amount (scalar, default 20).

    The script is EMBEDDED in the Badge component - add it from the component's own Scripts group, and it travels with the component wherever it is placed.

    The script. Add a component script named Label seat and paste:

    export const outputs = ["layer_1:transform.position"];
    
    export function frame() {
      const label = thisComponent.controls[0].label;
      return [value[0], 60 + label.length * 8];
    }
    

    Line by line:

    • Lines 4-5: label is what the component's surface shows people - "Amount", six characters, seating the face at y 108. Use labels for display logic; keep references on ids.

    What you see. The badge face seats itself at y 108 - eight pixels per letter of the control's label.

    The badge face seats itself at y 108 - eight pixels per letter of the control's label.

    kind#

    Type: 'text' | 'scalar' | 'colour' | 'point2' | 'image' | 'video' | 'audio' | 'boolean' | 'dropdown' (field).

    The control kind.

    Worked example: Branch on the control's kind#

    The scene. A Badge component whose internal comp holds one blue face layer, exposed with a scalar Amount control, plus one Badge instance placed in the Host comp with Amount overridden to 65.

    • The comp Host: 640 by 360 at 25 fps, 100 frames (4 seconds).
    • The comp Badge internals: 200 by 200 at 25 fps, 100 frames (4 seconds).
    • Badge face in Badge internals: a solid layer, at [100, 100], 120 by 120, filled #4d9de0.
    • Badge in Host: a component instance, at [320, 180].
      • The instance overrides the component's c_amount control to 65.
    • The component Badge wraps Badge internals and exposes 1 control: Amount (scalar, default 20).

    The script is EMBEDDED in the Badge component - add it from the component's own Scripts group, and it travels with the component wherever it is placed.

    The script. Add a component script named Kind gate and paste:

    export const outputs = ["layer_1:transform.scale"];
    
    export function frame() {
      const amount = thisComponent.control("c_amount");
      return amount.kind === "scalar" ? [130, 130] : [70, 70];
    }
    

    Line by line:

    • Lines 4-5: kind names the control's value shape - text, scalar, colour or point2 - and therefore what .value will be (string, number, [r, g, b, a] or [x, y]). Amount is a scalar, so the wide branch wins and the face renders at 130 percent. Kind checks keep a generic script honest about what it was handed.

    What you see. The badge face renders at 130 percent scale - the branch for a scalar control, chosen by inspecting the control's kind.

    The badge face renders at 130 percent scale - the branch for a scalar control, chosen by inspecting the control's kind.

    value#

    Type: T (field).

    The EFFECTIVE value in wire units (the instance's track sample over its stored override over the default). Per kind: text/dropdown a string (the dropdown's item index or the effect enum's spelling, exactly as the bound member accepts it), scalar a number, colour [r, g, b, a] 0..1, point2 [x, y], boolean a boolean, image/video/audio the asset id string or null (the definition's own asset).

    Worked example: The effective value, per context#

    The scene. A Badge component whose internal comp holds one blue face layer, exposed with a scalar Amount control, plus one Badge instance placed in the Host comp with Amount overridden to 65.

    • The comp Host: 640 by 360 at 25 fps, 100 frames (4 seconds).
    • The comp Badge internals: 200 by 200 at 25 fps, 100 frames (4 seconds).
    • Badge face in Badge internals: a solid layer, at [100, 100], 120 by 120, filled #4d9de0.
    • Badge in Host: a component instance, at [320, 180].
      • The instance overrides the component's c_amount control to 65.
    • The component Badge wraps Badge internals and exposes 1 control: Amount (scalar, default 20).

    The script is EMBEDDED in the Badge component - add it from the component's own Scripts group, and it travels with the component wherever it is placed.

    The script. Add a component script named Amount seat and paste:

    export const outputs = ["layer_1:transform.position"];
    
    export function frame() {
      const amount = thisComponent.control("c_amount").value;
      return [amount * 3, value[1]];
    }
    

    Line by line:

    • Line 4: value is the control's EFFECTIVE value for the evaluating context: the definition's default (20) in the component editor, each instance's override (65 in the Host comp's Badge) when placed, and any keyframed track wins over both. This one member is what makes a component's controls feel live.
    • Line 5: Three pixels of slide per unit of Amount: x 60 under the default, x 195 inside the overridden instance.

    What you see. The badge face parks at x 60 while editing the definition; the placed instance carries it right out to x 195 under its Amount of 65 - the same script reading each context's own truth.

    The badge face parks at x 60 while editing the definition; the placed instance carries it right out to x 195 under its Amount of 65 - the same script reading each context's own truth.