Ymotion
Help
Dashboard
All pages

Guides

Type and titles

Choosing a face, sizing and spacing type, point and paragraph text, styled runs, outlines and shadows, and type on a path.

This page covers setting type: faces, sizes and spacing in Ymotion's units, placing text in the frame, styling part of a line, legibility over footage, and After Effects' Character and Paragraph features. Moving type letter by letter is in Text animators and presets.

How a text layer sits in the frame

A text layer is set inside a box the size of the whole frame. Three fields decide where the block lands before the layer's transform moves it:

  • align — left, centre, right or justify. Left-aligned lines start at the frame's left edge, right-aligned lines end at its right edge, and centred lines are centred in the frame. Note the spelling centre.
  • anchor — top, middle or bottom: which edge of the frame the block sits against vertically.
  • maxWidth — where paragraph text wraps, as a fraction of the frame's width (1 is the whole width). It changes where lines break, not where they start.

A new text layer is left-aligned, vertically centred and as wide as the frame. Its content's text can be a plain string, or an object carrying any of these fields at once:

ymotion_edit {"ops":[{"verb":"addLayer","args":{"trackId":"<track id>","start":0,"duration":4,"name":"Title","content":{"kind":"text","text":{"text":"The long way home","align":"centre"}}}}]}

transform.x and transform.y then move the whole block, as fractions of the frame from its centre, positive y down. Two arrangements cover a lot:

  • A caption near the bottom: "anchor":"bottom", then transform.y of about −0.08 on a landscape film, or about −0.25 on a vertical one so it clears the buttons a phone app draws over the bottom of the picture. The last line keeps its distance from the bottom however many lines the text wraps to.
  • Left-aligned type with a margin: a paragraph indent such as "paragraph":{"indent":0.08}, 8% of the frame's width.

To place type exactly, measure rather than calculate: ymotion_read {"what":"box","layerId":"<layer id>"} returns the box the letters really occupy, and alignLayers and centerAnchor do the arithmetic. Type is measured with its real face, which loads when a frame is rendered or a verb that measures type runs, so a box of zeros early in a session means the face hasn't arrived yet; render a frame and ask again. See Formats and layout.

Choosing a face

ymotion_find {"catalogue":"fonts"} lists the built-in faces, and a search reaches every Google family too:

ymotion_find {"catalogue":"fonts","text":"playfair"}

Each result has an id — a built-in one like playfair, or a Google family like gf:playfair-display. Ids are matched exactly, so copy them from the reply:

ymotion_edit {"ops":[{"verb":"setTextStyle","args":{"layerId":"<layer id>","patch":{"font":"gf:playfair-display","weight":700}}}]}
  • Each built-in id has its own default weight, and the default face, inter, is Inter at 800 — a heavy cut. For lighter text, choose an id like inter-light or set weight.
  • The first six built-in ids — helvetica, helvetica-light, times, times-italic, georgia and impact, in group system in the reply's data — have no font file on the server, so renders and exports draw them in the fallback face, Inter. For those looks, gf:arimo stands in for Helvetica, gf:tinos for Times, gf:gelasio for Georgia and anton for Impact.
  • weight runs from 100 to 900. Built-in families load every weight they have, and a static Google family fetches its published cut nearest each weight written in a style or a segment. An animated weight asks that family's complete published ladder, including cuts an ease, continuation or wiggle may reach; ymotion_find {"catalogue":"fonts","id":"gf:playfair-display"} lists them. Type is set in the loaded cut nearest the weight asked for, and thickened where that cut is lighter, but nothing makes a face lighter than its lightest cut.
  • italic uses the family's true italic where there is one, and a slanted roman otherwise.
  • Preview and export discover faces from layer and run styles, every Source Text state and font-ID paint keys, including nested compositions. Unknown unregistered IDs and cuts unavailable under the existing font resource limits are named by the export, while system IDs retain their documented fallback behavior. Custom faces already registered by the host remain usable.
  • For another script, choose a family that covers it — search noto sans with the script's name — and render a frame to confirm it draws.

Pairing faces

Pairs look intentional when they differ clearly in one way. Some starting points from the built-in catalogue:

  • A serif display face over a plain sans: playfair, dm-serif or abril for the title; inter, dm-sans or manrope beneath, at weight 400 — all three are bold cuts by default.
  • A condensed face for punch: bebas-neue, anton, oswald or barlow-condensed for a headline, usually in capitals with a little tracking, over a regular sans.
  • One family at two weights, the safest pair: inter-black with inter-light, mulish-bold with mulish-regular, or raleway-bold with raleway-regular.

A type system for the film

A face becomes a system when each job has a recognisable treatment. Decide how a headline, a spoken caption, a supporting label and a number differ, then reuse those roles. A headline can carry the expressive face; captions need immediate reading; a label can be quieter. Size, weight and space usually provide enough contrast without a new face or colour for every layer.

Keep a shared alignment edge, a small palette with a clear accent, and the same spacing between related roles. A label belongs near what it labels; a headline and its explanation should read as one group. Formats and layout explains aligning the letters rather than their canvas-sized boxes. restyleAll makes a correction consistent across the layers of one role; changing every text layer together would also erase the hierarchy between roles.

Choose the treatment against the footage and the tone, rather than from a generic idea of luxury. A product detail may suit quiet, precise type; an energetic statement can support a heavy display face. A long headline is better reflowed into deliberate lines than squeezed until it is unreadable. Captions keep the spoken words; titles can be made more concise only while preserving the source's meaning. Look at the actual longest line and at a phone-sized preview before adopting the system for the rest of the film.

Size

Type size is a percentage of the frame's short edge — the one size in Ymotion written as a percentage. The default is 5 and the range is 0.5 to 120. A 1920x1080 film and a 1080x1920 one both have a short edge of 1080 pixels, so a number means the same pixel size in either: 5 is 54-pixel type.

Starting points, to adjust by eye:

  • Captions: 6 to 7 on a vertical film; 4.5 to 5.5 on a landscape one.
  • A lower third: about 4.5 for the name and 3 for the line beneath.
  • Titles: 9 to 14. On a vertical frame, about sixteen characters at 11 in the default face already span the whole width, so a longer title wants a smaller size or two lines.
  • A single short display word: 20 to 40.
  • Anything read on a phone gets hard going below about 3.

A size written 0.09 for 9% is kept as written and draws type about a pixel tall on a 1080-pixel short edge, so if a title seems missing, check its size first. setTextStyle adds a check: line to its reply when a size falls outside the range, saying you probably meant 9; a size given inside addLayer's content is kept without one.

Letter-spacing and line height

tracking adds space between letters and lineHeight sets the distance between lines. Both are multiples of the type size; the default line height is 1.2.

  • Capitals and small caps usually want a little air: tracking of 0.05 to 0.12.
  • Large display type often looks better slightly tight: −0.01 to −0.03.
  • Captions and running text are best left at 0.
  • Multi-line titles sit well at a line height of 1.0 to 1.1; captions and paragraphs at 1.15 to 1.3.

Both can be keyframed — the classic tracking-in title:

ymotion_edit {"label":"tracking in","ops":[{"verb":"keyRamp","args":{"layerId":"<layer id>","path":"content.text.style.tracking","from":0.3,"to":0.02,"opts":{"start":0,"end":1.2,"ease":"cubicOut"}}}]}

Point text and paragraph text

As in After Effects, there are two kinds of text. Paragraph text, the default, wraps at maxWidth. Point text breaks only at a Return and ignores maxWidth — right for a headline or a ticker that should stay on one line:

ymotion_edit {"ops":[{"verb":"setText","args":{"layerId":"<layer id>","patch":{"point":true}}}]}

"point":false makes it paragraph text again. A Return is a newline in the text, "Line one\nLine two", and it ends a paragraph as well as a line; two in a row leave an empty line.

justify spreads each line's spare room into its word gaps, except on the last line of a paragraph, and doesn't open gaps inside words. Point text has no width to justify to, so it sets as left.

Paragraph settings

The Paragraph panel's settings live under paragraph:

  • indent and indentRight — fractions of the frame's width, for every line.
  • firstLine — also a fraction of the width, added to the indent on a paragraph's first line; negative hangs it.
  • spaceBefore and spaceAfter — multiples of the type size, placed wholly between paragraphs at each Return. Before uses the next paragraph's first-line type size; after uses the preceding paragraph's last-line type size. Neither moves type inside its own line box, and no gap is added outside the first or final paragraph.

Left-aligned and justified lines start at the frame's left edge plus the indent and wrap at maxWidth less the right indent, so at the default maxWidth of 1, equal indents on both sides make a centred column — here 70% of the width:

ymotion_edit {"ops":[{"verb":"setText","args":{"layerId":"<layer id>","patch":{"align":"justify","paragraph":{"indent":0.15,"indentRight":0.15,"firstLine":0.03,"spaceBefore":0.5}}}}]}

Styling part of a line

Text is a list of segments, each with an optional style laid over the layer's. To colour one word, give it a segment:

ymotion_edit {"ops":[{"verb":"setText","args":{"layerId":"<layer id>","patch":{"segments":[{"text":"The long way"},{"text":"home","style":{"paint":"#FFD23F","italic":true}}]}}}]}

A boundary between segments is a word gap unless the second has "join":true, which continues the word — that's how one letter gets a style of its own. "breakAfter":true ends a segment with a Return. Setting segments replaces all the words on the layer, and restyleAll applies one style patch to a list of layers.

Character features

  • uppercase sets everything in capitals. smallCaps sets lowercase letters as small capitals and leaves real capitals full size; smallCapSize is their size as a share of the type size (0.76 by default).
  • baseline shifts a run up (positive) or down, in multiples of that run's own size. A superscript is a baseline shift and a smaller size on a joined segment; at 60% of the line's size, a shift of about 0.6 brings its top level with the capitals:
ymotion_edit {"ops":[{"verb":"setText","args":{"layerId":"<layer id>","patch":{"segments":[{"text":"E = mc"},{"text":"2","join":true,"style":{"baseline":0.6,"size":3}}]}}}]}
  • scaleX and scaleY stretch the letters themselves, 1 being unchanged. Unlike scaling the layer, the line rewraps to the new widths, and one run can be condensed inside a line that isn't.
  • underline and strikethrough draw rules where the face places them, continuing across the word spaces of that style. A whitespace segment can set its own rule flags, paint and face, including an explicit false between two ruled words. Rules stop at visual line breaks. Whitespace-only text still has no layout advance under the existing collapsed-space model.

Keeping type readable over footage

The text style has its own outline and shadow, the usual tools for legibility:

ymotion_edit {"ops":[{"verb":"setTextStyle","args":{"layerId":"<layer id>","patch":{"stroke":{"width":0.04,"paint":"#000000"},"shadow":{"blur":0.25,"x":0,"y":0.04,"paint":"#000000@60"}}}}]}
  • A stroke's width is a multiple of the type size and shows that far outside each letter. A newly requested partial stroke, including a width key under a previously null stroke, uses black unless a paint is supplied; an explicitly transparent paint stays transparent. It's drawn under the fill, which keeps thin letters readable; "strokeOver":true draws it on top, as a deliberate outline.
  • A shadow's blur, x and y are multiples of the type size. A soft shadow just below — blur 0.2 to 0.3, y about 0.04 — lifts white type off a busy shot without looking like an effect.
  • null removes either. Outline-only type is a transparent fill with a stroke: "paint":"#FFFFFF@0". With no fill over it, the half of the stroke inside each letter shows too, so the line reads about twice width.
  • For a solid plate behind the words, put a shape layer on a track below; see Shapes, icons, masks and mattes.

The box reading shows how far an outline and shadow reach: its margin is the difference between letters and ink on each side.

Type on a path

Set path and the type runs along an outline. The outline is a list of vertices with optional in and out handles relative to each, in fractions of the frame from its centre.

Each shaped glyph stands on the curve, keeping its advance, kerning, tracking and word spaces. This stays the same with no animator, with a live animator, and when a typewriter or another animator settles. A no-op animator is unnecessary. For a line set at size 9, this arches it over the middle of a landscape frame, glyph by glyph:

ymotion_edit {"ops":[{"verb":"setText","args":{"layerId":"<layer id>","patch":{"path":{"shape":{"vertices":[{"x":-0.3,"y":0.1,"out":[0.1,-0.3]},{"x":0.3,"y":0.1,"in":[-0.1,-0.3]}],"closed":false}}}}}]}

The line starts at the path's beginning and runs as far as its own length takes it; align doesn't apply on a path. Keyframing first slides it along — here in from below the left end over three seconds, coming to rest near the top of the arch:

ymotion_edit {"ops":[{"verb":"keyRamp","args":{"layerId":"<layer id>","path":"content.text.path.first","from":-0.8,"to":0.12,"opts":{"start":0,"end":3,"ease":"cubicOut"}}}]}
  • first is where the line begins, as a fraction of the path's length. An open path extends along its endpoint tangents before 0 and past 1. A closed path wraps for positive or negative laps, so a keyed first margin can circulate type round a ring.
  • last is the far margin. It's read by forceAlign, which spreads the pieces evenly between first and last — the gaps grow, not the letters.
  • reverse runs it the other way, and "perpendicular":false keeps the pieces upright.
  • Where the line comes to rest depends on the face and the size, so render a frame to judge it.
  • "mask":0 follows one of the layer's own masks instead, by index, with its keyed outline, offset, width, height, rotation and space. Frame-space guides stay with the canvas; layer-space guides follow the cropped layer box and its transform and parents. An open guide stays open. A mask of kind none keeps its path but cuts nothing — After Effects' mask mode None — which makes it a good guide:
ymotion_edit {"ops":[{"verb":"addMask","args":{"layerId":"<layer id>","mask":{"kind":"none","path":{"vertices":[{"x":-0.4,"y":0.1,"out":[0.2,-0.2]},{"x":0.4,"y":0.1,"in":[-0.2,-0.2]}],"closed":false}}}},{"verb":"setText","args":{"layerId":"<layer id>","patch":{"path":{"mask":0}}}}]}

See also