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
    / Introduction

    Differences from After Effects

    Where Nubu Motion scripting deliberately departs from After Effects expressions, and the trouble each departure removes.

    If you arrive with After Effects expressions in your fingers, most of your instincts transfer: value, time, thisComp, thisLayer, wiggle, linear, clamp and seedRandom all mean what you expect, and each member's reference page notes its AE equivalent where one exists. The differences below are deliberate, and each one removes a class of AE trouble. If you have never used After Effects, skip this page happily - the rest of the documentation assumes nothing.

    References travel by id, not by name#

    AE looks layers up by name and silently takes the first match - rename a layer, or add a second with the same name, and expressions break or change meaning. Here every layer, comp, property and control has a stable id, and references store the id. The editor still lets you TYPE and READ names (completions offer them, applied scripts display them), but what is stored can never be broken by a rename. See References and ids.

    Scripts, not per-property expression slots#

    There is no option-click on a stopwatch and no expression box per property. Scripts are the one surface: each declares the properties it drives in outputs, and one script may drive many properties across many comps. A driven property row shows a small indicator naming its script; the row's own controls still edit the BASE value the script reads through value.

    Zero-based counting, bottom-first layers#

    Indices start at 0 everywhere, like the rest of JavaScript. layer.index 0 is the BOTTOM layer of the stack, not the top - the same order every array in the document uses. AE's 1-based, top-first thisComp.layer(1) has no counterpart to trip over.

    The frame grid is canonical#

    Frames are integers on the comp's exact rational frame rate, and frame is the canonical clock; time in seconds is derived from it. AE's floating seconds accumulate rounding error over long comps; here the grid cannot drift. timeToFrames and framesToTime convert between the two spellings.

    return is required#

    A single-output script produces its value with an explicit return. AE's habit of leaving a trailing expression as the implicit result does not parse as a rule here - the IDE offers the fix when it sees the pattern.

    Scripts can remember#

    state() gives a script a store that survives from frame to frame, folded deterministically from the first frame so scrubbing equals playing. memo() caches expensive one-off computation per document revision. AE expressions are stateless by design; simulations that were impossible there (bounces, trails, counters) are a few lines here. See State and time.

    Errors are typed and harmless#

    A failing script never crashes the editor or the render. It reports one of fifteen typed error codes on its status, its outputs fall back to their base values for that frame, and the next frame evaluates afresh. Infinite loops are stopped by a poll budget and presented as a fixable budget issue.

    What does not exist here#

    No 3D, cameras or lights - the engine has no such features yet. No sampleImage. No Intl or Temporal (see JavaScript support). The old AE instinct that only some properties take expressions has no counterpart either: scripts write every ANIMATABLE property in the drive set - transforms, paint, text content, effects, physics forces, text animators and the per-layer audio level alike - and only the command-changed statics sit outside it.