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 propertiesRig propertiesRigging propertiesRig controllers propertiesRigging weights propertiesRigging mesh propertiesRig items propertiesRig splines propertiesRig simulation propertiesRig properties propertiesRig drivers propertiesRig draw order propertiesTransform propertiesTrim path properties
    Error codesBudgets
    Changelog
    API overviewAuthentication and keysRate limits and errorsUploading assetsFoldersUploading templatesTriggering a flowRuns and creativesAPI Request deliveryCallbacks
    All docs
    Motion Scripting
    / Properties

    Fills properties

    Per-fill members by fill id: colour, opacity, gradient handles and stops, and the media transform.

    Per-fill members - colour, opacity, gradient handles and stops, media transforms - addressed by fill id.

    Every pattern below is readable from scripts through prop() and layer.prop(); ids in a pattern (like <effect_id>) stand for the entity's real id. Every pattern here is in the drive set: scripts may WRITE each one with set() or a single-output return, per frame.

    PatternWire kindUnitsReadsWrites
    fills.<fill_id>.adjustments.contrastscalarnumber (wire units of the key)yesdrive set
    fills.<fill_id>.adjustments.exposurescalarnumber (wire units of the key)yesdrive set
    fills.<fill_id>.adjustments.highlightsscalarnumber (wire units of the key)yesdrive set
    fills.<fill_id>.adjustments.saturationscalarnumber (wire units of the key)yesdrive set
    fills.<fill_id>.adjustments.shadowsscalarnumber (wire units of the key)yesdrive set
    fills.<fill_id>.adjustments.temperaturescalarnumber (wire units of the key)yesdrive set
    fills.<fill_id>.adjustments.tintscalarnumber (wire units of the key)yesdrive set
    fills.<fill_id>.assetasset_refasset referenceyesdrive set
    fills.<fill_id>.blend_modeenumenum name (string)yesdrive set
    fills.<fill_id>.colourcolour[r, g, b, a] 0..1yesdrive set
    fills.<fill_id>.crop_transformcrop_transformcrop transformyesdrive set
    fills.<fill_id>.gradient_endpoint2[x, y] pxyesdrive set
    fills.<fill_id>.gradient_startpoint2[x, y] pxyesdrive set
    fills.<fill_id>.gradient_width_handlepoint2[x, y] pxyesdrive set
    fills.<fill_id>.modeenumenum name (string)yesdrive set
    fills.<fill_id>.opacityscalarpercent (0..100)yesdrive set
    fills.<fill_id>.rotationscalardegreesyesdrive set
    fills.<fill_id>.stopsgradient_stopsgradient stop listyesdrive set
    fills.<fill_id>.stops.<stop_id>.alphascalarpercent (0..100)yesdrive set
    fills.<fill_id>.stops.<stop_id>.colourcolour[r, g, b, a] 0..1yesdrive set
    fills.<fill_id>.stops.<stop_id>.offsetscalarnumber (wire units of the key)yesdrive set
    fills.<fill_id>.tile_scalescalar[x, y] percent (100 = 1:1)yesdrive set

    Worked examples#

    A layer's paint is a STACK of fills and strokes - the model every shape and frame uses, and the one the quick start's colour cycle drives. Each fill is addressed by its own id: fills.<fill_id>.colour for a colour fill's colour, fills.<fill_id>.opacity for its translucency, the gradient handles and stops for a gradient fill. The id comes from the scene itself (the Scripts panel and the @ pick whip write it for you); the walkthroughs below name each fill by its role and show the id the code stores.

    A plain solid with an empty stack still paints through the older single fill, content.fill_colour on the content family page - the second example keeps that form so both stay executable.

    Worked example: A colour cycle#

    The scene. One 200 by 200 swatch near the centre of a dark 640 by 360 stage, painted by a single coral fill in its fill stack - the paint model shapes and frames use - ready for a script to drive that fill's colour.

    • The comp Swatch: 640 by 360 at 25 fps, 150 frames (6 seconds).
    • Swatch: a solid layer, at [320, 180], 200 by 200.
      • The stack fill Base (fills.fill_1 in scripts): a colour fill, #ff5d73.

    The script. Add a project script named Colour cycle and paste:

    export const outputs = ["layer_1:fills.fill_1.colour"];
    
    const palette = [
      [1, 0.365, 0.451, 1],
      [0.949, 0.659, 0.2, 1],
      [0.18, 0.769, 0.714, 1],
    ];
    
    export function frame() {
      const phase = (time / 2) % 3;
      const from = palette[Math.floor(phase)];
      const to = palette[(Math.floor(phase) + 1) % 3];
      return linear(phase - Math.floor(phase), 0, 1, from, to);
    }
    

    Line by line:

    • Line 1: One output: the colour of the swatch's STACK FILL - the fill named Base in the scene, addressed by the id the document minted for it (fills.fill_1). Shapes and frames paint through a stack of fills like this one, and the Scripts panel and the @ pick whip write the id for you. Colours are writable like any other animatable property - the script hands back [r, g, b, a] in 0..1 (a "#rrggbb" string works too).
    • Lines 3-7: The three colours of the cycle as [r, g, b, a] arrays: coral, gold and teal.
    • Line 10: phase crawls 0, 1, 2 and wraps - one whole colour every two seconds.
    • Lines 11-12: The colour the phase is leaving and the one it is heading for; the modulo wraps teal back round to coral so the loop closes seamlessly.
    • Line 13: linear() works component by component on arrays: the fraction of the way through the current step blends every channel from one colour to the next, and the single-output return drives the fill directly.

    What you see. The one swatch melts through coral, gold and teal on a six second loop, each colour cross-fading smoothly into the next - its stack fill's colour driven by the script.

    The one swatch melts through coral, gold and teal on a six second loop, each colour cross-fading smoothly into the next - its stack fill's colour driven by the script.

    Worked example: The single-fill colour cycle#

    The scene. One coral 200 by 200 swatch near the centre of a dark 640 by 360 stage, ready for a script to drive its fill colour.

    • The comp Swatch: 640 by 360 at 25 fps, 150 frames (6 seconds).
    • Swatch: a solid layer, at [320, 180], 200 by 200, filled #ff5d73.

    The script. Add a project script named Colour cycle (single fill) and paste:

    export const outputs = ["layer_1:content.fill_colour"];
    
    const palette = [
      [1, 0.365, 0.451, 1],
      [0.949, 0.659, 0.2, 1],
      [0.18, 0.769, 0.714, 1],
    ];
    
    export function frame() {
      const phase = (time / 2) % 3;
      const from = palette[Math.floor(phase)];
      const to = palette[(Math.floor(phase) + 1) % 3];
      return linear(phase - Math.floor(phase), 0, 1, from, to);
    }
    

    Line by line:

    • Line 1: One output: the swatch's legacy FILL COLOUR - content.fill_colour, the single fill a plain solid paints with while its stack is empty. The quick start's form drives fills.<fill_id>.colour on a stack fill instead; everything else about the script is identical.
    • Lines 3-7: The three colours of the cycle as [r, g, b, a] arrays: coral, gold and teal.
    • Line 10: phase crawls 0, 1, 2 and wraps - one whole colour every two seconds.
    • Lines 11-12: The colour the phase is leaving and the one it is heading for; the modulo wraps teal back round to coral so the loop closes seamlessly.
    • Line 13: linear() works component by component on arrays: the fraction of the way through the current step blends every channel from one colour to the next, and the single-output return drives the fill directly.

    What you see. The one swatch melts through coral, gold and teal on a six second loop, each colour cross-fading smoothly into the next - its single fill colour driven by the script.

    The one swatch melts through coral, gold and teal on a six second loop, each colour cross-fading smoothly into the next - its single fill colour driven by the script.