Skip to content

Transform 2D

Moves, scales, and rotates its input in 2D space. Works on images (GPU sampling), shapes, and points (CPU affine).

Category: Utility Menu path: Utility > Transform2D

Ports

PortTypeDirectionDescription
inimageRgba16f / shape / pointsinputInput to transform. Output type matches input.
outimageRgba16f / shape / pointsoutputTransformed result

Parameters

ParamTypeDefaultDescription
positionModeenumPixelsHow position is interpreted. See Position mode below.
positionAnchorenumCenterComp edge/corner the offset is measured from when positionMode is Anchored. Hidden in other modes.
positionvec2(0, 0)Translation. Units depend on positionMode: pixels-from-comp-center (Pixels), normalized 0–1 from top-left (Normalized), or pixel offset from the chosen positionAnchor (Anchored).
scalevec2(1, 1)Scale factor (1 = 100%). Linked by default.
rotationscalar0Rotation in degrees
anchorvec2(0.5, 0.5)Pivot point in normalized coordinates. (0,0) = top-left, (0.5,0.5) = center, (1,1) = bottom-right. The frame of reference depends on anchorSpace.
anchorSpaceenumContentWhat the anchor is normalized to. Content = the input's bounding box (recommended, composes correctly in chains). Comp = the composition. Texture inputs ignore this — anchor is always canvas-normalized for textures.

Expose Channels

PortTypeOverrides
position_invec2position
scale_invec2scale
rotation_inscalarrotation
anchor_invec2anchor

How It Works

For images: applies an inverse affine matrix via GPU sampling. The engine evaluates at a larger canvas size (overscan) to prevent content from being clipped at composition boundaries during transforms.

For shapes and points: applies a CPU affine transform to vertex positions (~1us). This is the standard way to position geometry before rasterization via DrawShape/DrawPoints.

Transform2D is the sole spatial transform node. The Output node handles compositing (opacity + blend mode) but has no spatial transform — use T2D for all positioning.

Position mode

positionMode decides how position translates into a final pixel offset. The downstream pipeline (overscan computation, matrix construction, gizmo) only ever sees absolute pixels-from-comp-center; the mode is resolved at the start of T2D evaluation.

All three modes share one forward formula: T(P) = (P − pivot) × S × R + position. position is where the anchor lands in comp space. The mode just controls how the position value's coordinates are interpreted before being resolved to comp-space pixels:

  • Pixels (default): position is in absolute pixels with comp center = (0, 0). (0, 0) = anchor at comp center, (960, 0) on a 1920px-wide comp = anchor at right edge.
  • Normalized: position is [0, 1] from top-left to bottom-right. (0.5, 0.5) = anchor at comp center, (0.5, 0.78) = anchor at a typical lower-thirds Y. Designs survive resolution and aspect changes — (0.5, 0.78) lands at the same relative spot whether the comp is 1920×1080 or 1080×1920.
  • Anchored: positionAnchor selects a comp corner or edge (TopLeft, BottomCenter, etc.) and position is a pixel offset from that anchor in standard screen coords (+X right, +Y down). For "32px from the bottom-right corner with the content's bottom-right corner pinned there", set positionAnchor=BottomRight, anchor=(1, 1), and position=(-32, -32).

Because position is where the anchor lands, you get clean placement with zero half-width math: anchor=(0, 0.5) plus any position places the content's left-middle at that position.

Switch modes freely while iterating — values aren't auto-converted between modes, so the visual position will jump when you change positionMode. Re-key once you're settled on a mode.

Anchor space

anchorSpace controls where the pivot point lives:

  • Content (default): Anchor is normalized within the input's AABB. Anchor (0.5, 0.5) pivots around whatever the input's current bounding box center is. This composes correctly when chaining T2Ds — a second T2D added after the first scales/rotates around the current shape, not around comp center.
  • Comp: Anchor is normalized within the composition. Anchor (0.5, 0.5) pivots around comp center regardless of where the input sits. Useful for spinning or scaling content around a fixed point in comp space (e.g. rotate a whole scene around its top-left corner with anchor (0, 0)).

Rule of thumb: leave it on Content for 99% of cases. Flip to Comp when you specifically want a pivot anchored to the composition rather than the content.

Texture inputs resolve to Comp behavior regardless of the param value — the GPU texture render path doesn't branch on anchorSpace, it always pivots at anchor * compSize. The engine reports this as effectiveAnchorSpace: "Comp" in ResolvedNodeTransform so the gizmo math stays in sync.

Note for the future anchor gizmo

When corner/edge snap helpers are added to the anchor gizmo, the snap targets depend on anchorSpace:

  • In Content mode, snap to the input AABB's corners/edges (anchor (0, 0) = input top-left, etc.).
  • In Comp mode, snap to the composition's corners/edges (anchor (0, 0) = comp top-left). The helpers still work, they just align to the comp frame instead of the content frame.

Positioning T2D relative to Draw nodes

Prefer to do all transforms before Draw nodes. The pattern Shape → T2D → T2D → … → DrawShape → Output composes cleanly: each T2D pivots around the current geometry AABB, the gizmo wraps the shape tightly, and chained T2Ds inherit each other's positioning the way nested parent transforms do.

T2D placed after a Draw node (DrawShape / DrawText / DrawPoints) operates on a canvas-sized texture. That's by design — rasterized output is sized for compositing uniformity. But it means the gizmo bounds wrap the full canvas rather than the visible drawn content, because the engine reports inputBounds as the texture's pixel dimensions. The transform itself works correctly; only the gizmo sizing is loose. Use this pattern when you specifically want to transform the rasterized canvas as a whole (canvas-level effects, compositing multiple drawn layers), not for positioning individual shapes.

(Tracked as a future engine improvement: have rasterizer nodes report their tight content AABB alongside the texture so downstream gizmos can wrap actual pixels.)

Usage Examples

Basic: Position a layer

Every image layer typically has an ImageSource -> Transform2D -> Output chain. T2D controls where the image appears in the composition.

Geometry pipeline

Rectangle -> Transform2D -> DrawShape -> Output. The T2D positions and scales the shape before it's rasterized.

Procedural animation

Connect Time -> Math (multiply by speed) -> T2D's rotation_in expose channel for continuous rotation. Or use Noise.scalar for organic drift on position.

Tips

  • Scale is linked by default (X and Y move together). Click the link icon in Properties to unlink for independent axis scaling.
  • Shelf tools (R, O, P, G, T) auto-create a geometry -> T2D -> DrawShape -> Output chain
  • Click a layer in the viewport to auto-select its T2D node. If no T2D exists, one is auto-inserted.
  • Shift constrains gizmo rotation to 15-degree increments
  • Shift constrains gizmo scale to proportional
  • Output — compositing interface (opacity + blend mode, no spatial transform)
  • DrawShape — rasterizes shapes positioned by T2D