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

    Formatting values

    House recipes for turning numbers into countdown, percentage and timecode strings without the Intl tables the sandbox omits.

    Scripts often turn numbers into readable strings - a countdown, a percentage, a timecode for a diagnostic log. The engine deliberately ships without Intl (locale tables would make renders differ between machines - see JavaScript support), and plain JavaScript covers the ground well. These are the house recipes.

    Numbers#

    const price = 1234.5;
    
    price.toFixed(2);            // "1234.50" - fixed decimals
    String(Math.round(price));   // "1235" - whole numbers
    String(price).padStart(8, " "); // "  1234.5" - column alignment
    

    For thousands separators, group by hand - three digits at a time from the right:

    function thousands(n) {
      const [whole, part] = Math.abs(n).toFixed(0).split(".");
      const grouped = whole.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
      return (n < 0 ? "-" : "") + grouped;
    }
    
    thousands(1234567); // "1,234,567"
    

    Deterministic and identical on every machine - which is the point.

    Padding and counters#

    String(7).padStart(3, "0");   // "007"
    String(42).padEnd(5, ".");    // "42..."
    

    Timecodes#

    Build timecodes from the canonical clock - frame and fps - never from float seconds:

    export function frame({ frame, fps }) {
      const total_seconds = Math.floor(frame / fps);
      const minutes = String(Math.floor(total_seconds / 60)).padStart(2, "0");
      const seconds = String(total_seconds % 60).padStart(2, "0");
      const frames = String(frame % fps).padStart(2, "0");
      const timecode = minutes + ":" + seconds + ":" + frames;
      console.log(timecode); // "00:01:05" at frame 1625 of a 25 fps comp
      return value;
    }
    

    The same shape gives you countdowns (total_seconds counting down from the comp's duration) and cue labels.

    Where formatted strings go#

    Text CONTENT is in the drive set: declare a text layer's content.text as an output and return the formatted string, and the layer's source text follows the script per frame. Swap the console.log above for a return on such an output and the timecode becomes a live caption; the frame reference's countdown example drives one digit layer the same way. Text takes a per-frame HOLD (there is nothing to interpolate between two strings), so return values that change exactly when you mean them to - whole seconds, not raw float time. Formatted strings also serve diagnostics (console.log) and comparisons, and the quick start's countdown shows the multi-layer variant with five digit layers and one script.