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

    Time conversion

    The helpers that turn frames into seconds and back without letting floating point drift creep into the clock.

    Frames and seconds are two spellings of the same clock: the comp's frame grid is canonical, and these helpers convert between the two without accumulating float error.

    Table of contentstimeToFramesWorked example: A frame mark from secondsframesToTimeWorked example: Hold, then go

    timeToFrames#

    timeToFrames(t?: number, fps?: number): number
    

    Seconds to a floored frame count (the comp fps by default).

    Determinism: pure.

    After Effects equivalent: timeToFrames.

    Worked example: A frame mark from seconds#

    The scene. One orange square resting on a dark 640 by 360 stage.

    • The comp Drift: 640 by 360 at 25 fps, 100 frames (4 seconds).
    • Square: a solid layer, at [320, 180], 60 by 60, filled #f2a833.

    The script. Add a project script named Two second mark and paste:

    export const outputs = ["layer_1:transform.opacity"];
    
    export function frame({ frame }) {
      const mark = timeToFrames(2);
      return frame >= mark ? 40 : 100;
    }
    

    Line by line:

    • Line 4: timeToFrames() turns seconds into a frame count on the comp's grid (rounded down) - at 25 fps, two seconds is frame 50. Write the intent in seconds and let the helper find the frame.
    • Line 5: Before the mark the Square is solid; from frame 50 on it dims to 40.

    What you see. The square holds full strength for exactly two seconds, then steps down to 40 percent for the rest of the comp.

    The square holds full strength for exactly two seconds, then steps down to 40 percent for the rest of the comp.

    framesToTime#

    framesToTime(f: number, fps?: number): number
    

    A frame count to seconds (the comp fps by default).

    Determinism: pure.

    After Effects equivalent: framesToTime.

    Worked example: Hold, then go#

    The scene. One orange square resting on a dark 640 by 360 stage.

    • The comp Drift: 640 by 360 at 25 fps, 100 frames (4 seconds).
    • Square: a solid layer, at [320, 180], 60 by 60, filled #f2a833.

    The script. Add a project script named Delayed start and paste:

    export const outputs = ["layer_1:transform.position"];
    
    export function frame() {
      const start = framesToTime(50);
      return [value[0] + Math.max(0, time - start) * 60, value[1]];
    }
    

    Line by line:

    • Line 4: framesToTime() is the other direction: frame 50 on this comp's grid is 2.0 seconds. Author the cue in frames, do the maths in seconds.
    • Line 5: Math.max holds the offset at zero until the start time passes, then the Square slides right at 60 pixels per second.

    What you see. The square sits still for two seconds, then sets off rightwards at a steady 60 pixels per second.

    The square sits still for two seconds, then sets off rightwards at a steady 60 pixels per second.