Skip to content

Repository files navigation

The Aeroadvisor — Motion Graphics

The Aeroadvisor · Motion Graphics

Image placeholders live in docs/images/ — swap them for real stills and screenshots whenever you like.

A library of broadcast-ready motion graphics for The Aeroadvisor, built with Remotion — React components rendered to video. Every graphic is data-driven through a live prop editor, rendered to a transparent ProRes overlay (with audio) or a standard MP4, and ready to drop straight onto a timeline in DaVinci Resolve, Premiere, Final Cut or CapCut.

  • 🎬 23 finished compositions — lower thirds, chart animations, logo reveals, overlays and more.
  • 🎛️ Edit in the browser — the Remotion Studio gives every graphic live, typed controls.
  • 🔷 On-brand by default — the amber #E6B234, the Inter typeface and the logo are pre-wired.
  • 🪟 Real alpha overlays — one command renders a transparent ProRes 4444 .mov that keeps its audio.
  • 🔁 Resolution/fps-safe — durations and sizes route through helpers, so retargeting is a one-line change.
  • 💻 Cross-platform — develop and render on Windows, macOS or Linux.

Contents


Composition catalog

Composition catalog

Each entry below is a registered composition id — the exact string you pass to remotion render. Open any of them in the Studio to edit its props live.

Titles, captions & lower thirds

id What it does
LowerLeftThird Name/title lower third, anchored bottom-left
LowerRightThird Name/title lower third, anchored bottom-right
ChapterTitle Section/chapter divider card
KineticTypography Word-by-word animated headline
AnimatedCaptions Karaoke-style word-timed subtitles

Branding, intros & transitions

id What it does
LogoReveal Animated logo sting with light sweep + particles
YouTubeEndScreen 10s end card with subscribe + video slots
SubscribeBellCTA Subscribe/bell call-to-action bug
StingerTransition Full-frame logo wipe between scenes

Data visualisation

id What it does
BarChartHorizontal Animated horizontal bars
BarChartVertical Animated vertical/column bars
LineChart Straight-segment line chart
SplineChart Smoothed (curved) line chart
PieChart Pie / donut (holeRatio) chart
DataTable Row-by-row animated comparison table
KpiTile KPI stat tiles with delta indicators
ProgressBarHorizontal Timed horizontal progress / countdown bar
ProgressBarCircular Timed circular progress ring

Overlays & effects

id What it does
CinematicOverlay Film grain, light leak and vignette pass
CameraViewfinder REC / viewfinder HUD frame
BrowserHighlight Browser-chrome mock with a highlight box
SplitScreenMask Split-screen / circular picture-in-picture mask
AudioSpectrum Reactive audio spectrum bars

Charts derive their own duration from the number of data points via calculateMetadata, so they accept any number of values without a fixed-count variant.


Requirements

  • Node.js 18 or newer (LTS recommended; developed on Node 24).
  • Git.
  • ffmpeg is bundled with Remotion — you don't need to install it separately.
  • On the first render, Remotion downloads a headless Chromium build automatically.

Linux only — headless Chromium needs a few system libraries. On Debian/Ubuntu:

sudo apt-get update && sudo apt-get install -y \
  libnss3 libdbus-1-3 libatk1.0-0 libgbm-dev libasound2 libxrandr2 \
  libxkbcommon-dev libxfixes3 libxcomposite1 libxdamage1 \
  libatk-bridge2.0-0 libpango-1.0-0 libcairo2 libcups2

macOS and Windows need no extra system packages.


Getting started

1. Clone

HTTPS

git clone https://github.com/SonapSav/MotionGraphicsStudio.git
cd MotionGraphicsStudio

SSH

git clone git@github.com:SonapSav/MotionGraphicsStudio.git
cd MotionGraphicsStudio

2. Install

npm install

The commands above are identical on Windows (PowerShell or Git Bash), macOS and Linux.

3. Launch the Studio

npm run studio

This opens the Remotion Studio at http://localhost:3014 — pick a composition from the sidebar, scrub the timeline, and edit its props live in the right-hand panel.

Remotion Studio


Rendering

Renders are written to out/ (git-ignored). Replace <id> with any composition id from the catalog.

MP4 — standard opaque delivery:

npx remotion render <id> out/<id>.mp4 --codec=h264 --crf=18

--crf runs 0–51; lower is better quality and a bigger file. 18 is visually lossless.

Transparent MOV — ProRes 4444 with a real alpha channel and audio (the default for overlays):

npx remotion render <id> out/<id>.mov \
  --codec=prores --prores-profile=4444 --pixel-format=yuva444p10le --image-format=png

PNG sequence — maximum quality, keeps alpha, largest on disk, no audio:

npx remotion render <id> out/<id> --sequence --image-format=png

Two verified gotchas for PNG sequences:

  • --sequence is required — without it Remotion expects a video filename and errors.
  • Pass a directory, not a filename pattern. Frames are named element-000.png, element-001.png, … (rename afterwards if needed).

Verify a transparent file actually carries alpha:

npx remotion ffprobe out/<id>.mov

The pixel format should start with yuva — the a is the alpha channel.

Why there's no global CRF: remotion.config.ts deliberately does not call Config.setCrf(). CRF is h264/h265-only, and setting it project-wide makes every ProRes render fail. Keep --crf on the command line.


Previewing renders

Transparent ProRes is a mezzanine format — not every player handles it the same way.

Player Platforms Good for Watch out
Remotion Studio all everything, before rendering has a transparency checkerboard toggle — check here first
DaVinci Resolve Win / macOS / Linux the definitive alpha check drop the clip on V2 over a solid on V1
QuickTime Player macOS ProRes playback shows alpha over black, not a checkerboard
VLC all motion, timing, layout ignores the alpha channel — see below
Windows Media Player / Films & TV Windows nothing Windows ships no ProRes decoder

VLC does not merely show alpha on black — it ignores the alpha channel and shows raw RGB. A soft radial glow fading to transparent comes back as a hard-edged solid circle. Use VLC for motion and timing only; use Resolve or the Studio for anything involving transparency.


Project layout

src/
  index.ts              registerRoot entry point
  Root.tsx              composition registry (all 23 graphics)
  video-config.ts       CANVAS + seconds() / px() / usePx() / titleSafePadding
  animation.ts          useEnterExit — shared enter/exit envelope
  fonts.ts              FONT_FAMILY (Inter via @remotion/google-fonts)
  compositions/         one file per graphic
tools/
  generate-sfx.mjs      npm run sfx — synthesises public/audio/*.wav
  check-audio.mjs       peak / clipping report for a rendered wav
  bbox.mjs              opaque bounding-box of a rendered PNG (layout checks)
public/                 fonts, images, audio — reachable via staticFile()
out/                    renders (git-ignored)
docs/images/            README image placeholders
remotion.config.ts      project-wide render defaults

Creating a new graphic

1. Create the component in src/compositions/MyGraphic.tsx — a component plus a matching zod schema and defaultProps:

import { AbsoluteFill } from "remotion";
import { z } from "zod";
import { zColor } from "@remotion/zod-types";
import { useEnterExit } from "../animation";
import { usePx, seconds } from "../video-config";

export const myGraphicSchema = z.object({
  headline: z.string(),
  accentColor: zColor(),
});

export type MyGraphicProps = z.infer<typeof myGraphicSchema>;

export const myGraphicDefaultProps: MyGraphicProps = {
  headline: "Hello",
  accentColor: "#E6B234",
};

export const MyGraphic: React.FC<MyGraphicProps> = ({ headline, accentColor }) => {
  const px = usePx();
  const { present } = useEnterExit({ enterDuration: seconds(0.8), exitDuration: seconds(0.7) });
  return (
    <AbsoluteFill style={{ opacity: present, fontSize: px(48), color: accentColor }}>
      {headline}
    </AbsoluteFill>
  );
};

2. Register it in src/Root.tsx at CANVAS size. The id is what you pass to remotion render; the schema + defaultProps pair is what gives you live editable controls in the Studio. Use zColor() for colours so you get a real picker.

3. Give it a full enter and exit via useEnterExit so it never pops at either end, and for a variable-length graphic derive durationInFrames from props with calculateMetadata rather than hardcoding it.


Canvas, resolution and fps

1920×1080 @ 24fps — the single delivery target. Register every composition at CANVAS size and render one master per graphic. It's set in one place, src/video-config.ts:

export const CANVAS = {
  width: 1920,
  height: 1080,
  fps: 24,
} as const;

Two helpers keep that flexible:

  • seconds(5) → frames at the current fps, so a 5-second graphic stays 5 seconds at any fps.
  • px(96) → sizes in 1080p design units (the identity function at 1080p).

The rule that keeps this working: never write a raw frame number. Route every duration, spring length and stagger through seconds(), and every size through px(). A hardcoded durationInFrames: 30 looks right at 30fps and silently becomes a 1.25× slower animation at 24fps.

px() vs usePx()

px() reads the global CANVAS; usePx() scales against the actual composition width via useVideoConfig(). While everything is registered at CANVAS size the two are identical — but usePx() earns its keep the moment a component is registered at a different size (e.g. a 1080×1920 vertical cut for Shorts). Defaulting to usePx(), and positioning with percentages (left: "7%") rather than CANVAS.width * 0.07, is free insurance.


Transparency

An overlay renders with real alpha when nothing in the tree paints a full-frame background — give the root <AbsoluteFill> no backgroundColor. If an overlay comes out black, something is filling the frame.

Three flags must line up, and all three matter:

Flag Why
--codec=prores h264 has no alpha channel at all
--prores-profile=4444 only 4444 and 4444xq carry alpha
--image-format=png JPEG frames discard alpha before encoding starts

Two constraints specific to overlays:

  • Keep any background plate near-opaque across its full width. A gradient fading to transparent looks great over dark footage and makes white text unreadable over bright footage — and you don't know what's behind an overlay at render time. Layer a colour tint on top of a ~95% opaque base.
  • backdrop-filter does nothing at render time. There is no footage behind the element yet, so it costs render time and produces no pixels. Fake glass with translucent gradients plus a 1px light inner border.

Choosing an alpha format: default to ProRes 4444 — one file, and it carries the audio track. Switch to a PNG sequence only for a silent graphic that needs bit-exact quality or half the file size. ProRes 4444 XQ is pointless here (byte-identical output to plain 4444). H.265 silently discards alpha — it writes a valid file with transparency composited away, no error. H.264 has no alpha under any circumstances.


Sound

public/audio/ holds five synthesised, royalty-free cues. Regenerate or retune them with npm run sfx (tools/generate-sfx.mjs). Each starts its transient at sample 0, so no trimBefore is needed.

File Character Typical use
whoosh.wav bandpassed noise, swell entrance
click.wav noise transient + 1400→380 Hz drop primary press
pop.wav brighter, shorter, 2300→700 Hz secondary action
chime.wav two bell notes C6→G6, inharmonic partials success
swish.wav fast descending noise sweep exit

Wiring a cue

import { Audio, Sequence, staticFile } from "remotion";

<Sequence name="SFX click" from={PRESS_AT} durationInFrames={seconds(0.3)} layout="none">
  <Audio src={staticFile("audio/click.wav")} volume={0.55 * masterVolume} />
</Sequence>
  • Anchor from to the same constant that drives the visual, so retiming the animation retimes its sound — they can't drift apart.
  • layout="none" matters: a Sequence otherwise wraps children in an AbsoluteFill, stacking invisible full-frame divs over your graphic.
  • PNG-sequence renders discard audio entirely; use MP4 or MOV if you need sound.

Checking levels

npx remotion render <id> out/mix.wav --codec=wav
node tools/check-audio.mjs out/mix.wav

Reports true sample peak, RMS and clipped-sample count. Aim for a few dB of headroom (around −8 dBFS peak) so the graphic sits under a music bed.


Fonts

src/fonts.ts loads Inter through @remotion/google-fonts:

import { loadFont } from "@remotion/google-fonts/Inter";
const { fontFamily } = loadFont("normal", { weights: ["400", "600", "700"], subsets: ["latin"] });

Swap the import path for another family (@remotion/google-fonts/Roboto, etc.). Remotion blocks rendering until the font is ready, so frame 0 never flashes a fallback face. For a custom font, put the .woff2 in public/fonts/ and load it with staticFile().


Production tips

  • Keep text in the title-safe area. Spread titleSafePadding (a 5% inset on every edge) onto your root element — platforms crop frame edges unpredictably.
  • Always give an animation a full enter and exit. Anything still moving on the last frame reads as a hard cut. useEnterExit returns a present value (0 → 1 → 0); drive opacity and transforms from it.
  • Seed particles with Remotion's random(seed), never Math.random(). Frames render concurrently and re-evaluate per frame, so Math.random() strobes and won't reproduce between renders.
  • Use drop-shadow, not box-shadow, with an animated clip-path — a clip-path wipe clips box-shadow away; filter: drop-shadow() on the parent traces the clipped silhouette.
  • Springs for entrances, interpolate + Easing for exits. Springs overshoot naturally — great arriving, distracting leaving.

Scripts

Command Does
npm run studio live preview + prop editor at http://localhost:3014
npm run sfx regenerate public/audio/*.wav
npm run build bundle for a Remotion server/Lambda deploy
npm run typecheck tsc --noEmit
npm run upgrade bump all Remotion packages together

Remotion packages are pinned to matching versions on purpose — mixing versions across remotion / @remotion/* causes hard-to-read failures. Use npm run upgrade rather than bumping one by hand.


Tech stack & license

Built with Remotion 4, React 19, TypeScript, Zod and Tailwind CSS v4.

The source code in this repository is released under the MIT License — MIT © Panos Vasilopoulos. See LICENSE for the full text.

Remotion is licensed separately and is not covered by this MIT license. It is free for individuals and small teams but requires a company license in some cases. Review the Remotion license before using it commercially.

About

Broadcast-ready motion graphics for The Aeroadvisor — data-driven, on-brand video overlays (lower thirds, chart animations, logo reveals, transparent ProRes overlays) built with Remotion + React.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages