Documentation
The studio is at noacg.studio/app and it is free. You need an account only to publish a production or to let a coding agent save into your library. Making and exporting graphics works without one.
NoaCG Studio makes broadcast graphics in the browser: lower thirds, scoreboards, tickers, quiz boards and countdowns. You make a graphic, then put it on air in the system your studio already uses.
Then put it on air:
Draw your graphic in Illustrator, Figma or Inkscape and import it as an SVG. Every text layer becomes a field the operator can retype. The layer names tell NoaCG what kind of graphic it is, so a scoreboard gets score buttons and a quiz gets quiz buttons.
Pick a type to see how to lay it out:
Any other graphic needs no special names. Its text layers become fields.
Add to the production takes you to the production with your graphic in the rundown. Press Take to put it on air. Type new text, then press Update to send it. Until you do, the panel says "1 change not on air yet" (before you publish, "not on PROGRAM yet"). Out takes the graphic off. For OBS, vMix or CasparCG, see the playout dashboard.
<foreignObject> are removed. Add motion in the Animation
step.| App | Settings |
|---|---|
| Illustrator | File → Save a Copy… → SVG, with Use Artboards ticked. In SVG Options: Fonts Type SVG, Subsetting None (Use System Fonts) · Image Location Embed · Preserve Illustrator Editing Capabilities off · under More Options, CSS Properties Style Elements. Do not use Export → Export As for a graphic with hidden layers: Illustrator 2026 leaves every hidden layer out of that file. |
| Figma | Select the frame, Export → SVG. Include "id" attribute on, Outline text off. |
| Inkscape | Save As… → Plain SVG. Do not run Object to Path on text. Click to place text instead of dragging a text box: a dragged box exports as <flowRoot>, which browsers do not show. |
NoaCG lists every font the file uses. For each one it uses a bundled font, offers the same family from Google Fonts, or takes a font file you upload. The font is embedded in the graphic, so it plays offline. If nothing matches, you get a warning and the graphic uses a fallback font.
Text is what the operator types, Moments is what NoaCG shows or moves, Board stays as drawn. No moments, no Moments layer.Question, Answer A, Team 1, Score 1. A title is Title and Subtitle, a name tag Name and Role, credits Heading and Credits.Selected A, Flash 1, Full time. A bar is drawn at full length and left visible: Bar 1.Panel, a plate under a text is that text's name plus box (Question box, Answer box A, Score box 1), and fixed words start with static: (static:Letter A).Layer names are shared across graphic types. Use the layers your graphic needs.
To start from a working file, download the SVG examples: editable Illustrator and SVG sources covering every SVG import behaviour, with previews and authoring guides for clocks, timers and editable credits.
Download an SVG to try it in NoaCG or edit it in Illustrator or Inkscape. The complete package also includes Illustrator sources and layer-name guides.
Text holds what the operator types. One text object per field,
named for what it is: Question, Team 1.Moments holds what NoaCG shows, hides or moves. A hidden group for
each moment, such as Selected A or Full time, and a bar
drawn at its full length, such as Bar 1.Board holds what stays as drawn: the panel, the row plates, the
letters and the labels.Text and Board. Illustrator leaves an
empty layer out of the SVG anyway.Panel.box, with the row
last: Question box, Answer box A, Score box 1.
The wizard lists each plate by that name, so the plate and its text read as a
pair.static:, as in static:Letter A.Edge or
Rule.Answer A, Score 1, Winner 2. A quiz
counts in letters, because the letters are drawn on the board. Everything else
counts in numbers.Answer B,
Selected B, Correct B and Wrong B are all
answer B.static:, as in
static:Letter A. A text that is a single letter, like the A on a quiz
row, starts unticked whatever it is called.Answer A, answer_a
and ANSWER-A are one name. AnswerA is Answer A too, and
Score1 is Score 1.Antwort A,
Puntos 1. The three layers can be called Text,
Moments and Board in your own language, because NoaCG
reads the names inside them.Question is
Question. Four unnamed texts inside a layer called Answers are all
Answers, and no type is found. Save the file with Save a Copy as above,
because Export As leaves hidden layers out.
The quiz example, exactly as Illustrator's Layers panel shows it. Amber names are
the ones NoaCG reads. In Board, Panel is the background,
each answer sits on its own Answer box, the letters are fixed words
and Edge is decoration.
Illustrator opens the three as groups inside one layer. Three layers of your own with the same names work the same way.
quiz.svg, scoreboard.svg, live-vote.svg, countdown.svg, end-credits.svg, ticker.svg and name-tag.svg.
The layers each type looks for. Name it is the spelling the examples
use; the names under Also works are read the same way. Change the
row to match your own rows: Answer A is also Answer B,
and Team 1 is also Team 2.
| Layer | Name it | Also works | What it does |
|---|---|---|---|
| Score tracker | |||
| Team (one per row) | Team 1 | Side 1, Player 1, Joukkue 1, Lag 1 | a field the operator types |
| Score (one per row) | Score 1 | Points 1, Goals 1, Team 1 Score, Pisteet 1, Poäng 1 | a field - draw a plain number in it |
| Flash (one per row) | Flash 1 | Goal 1, Scored 1, Maali 1, Mål 1 | shown for the moment that team's point lands |
| Full time | Full time | Final, Game over, Loppu, Full tid | once the game is called (one, whole board) |
| Two to eight teams. | |||
| Quiz | |||
| Question | Question | Kysymys, Fråga | always - it is a field the operator types |
| Answer (one per row) | Answer A | Vastaus A, Svar A | always - a field |
| Selected (one per row) | Selected A | Picked A, Chosen A, Valittu A, Vald A | while that answer is the pick |
| Correct (one per row) | Correct A | Right A, Oikein A, Rätt A | on the reveal, if it is the correct answer |
| Wrong (one per row) | Wrong A | Incorrect A, Väärin A, Fel A | on the reveal, if it is not |
| Locked in | Locked in | Locked, Lukittu, Låst | once the answer is locked (one, whole board) |
| Two to six answers. | |||
| Live vote | |||
| Question | Question | Kysymys, Fråga | written from the round |
| Option (one per row) | Option 1 | Choice 1, Answer 1, Vaihtoehto 1, Alternativ 1 | written from the round |
| Bar (one per row) | Bar 1 | Palkki 1, Stapel 1 | draw it at its FULL length - that length is 100% |
| Percent (one per row) | Percent 1 | Share 1, Osuus 1, Procent 1 | appears with the result |
| Winner (one per row) | Winner 1 | Voittaja 1, Vinnare 1 | only on the row that won, and never on a tie |
| Total votes | Total votes | Ääntä, Röster | written from the round |
| Vote badge | Vote badge | Äänestä, Rösta | while voting is open |
| Two to eight options. | |||
| Countdown | |||
| Clock | anything | the readout - set its row to Countdown | |
| Timer bar | Timer bar | Drain, Countdown bar, Aikapalkki, Tidsbalk | draw it at its FULL length - that length is the whole count |
| Warning | Warning | Last stretch, Hurry, Varoitus, Varning | the look the final seconds wear |
| Paused | Paused | Hold, Tauko, Paus | while the operator is holding the clock |
| Time up | Time up | Expired, Finished, Aika loppu, Tiden ute | once it reaches zero |
| Standings | |||
| Competitor (one per row) | Name 1 | Row 1 name, Competitor 1, Player 1, Nimi 1 | a field the operator types - it travels with its row |
| Points (one per row) | Points 1 | Row 1 points, Pts 1, Score 1, Pisteet 1 | a field - draw a plain number in it; the rows sort by it |
| Position (one per row) | Position 1 | Row 1 position, Rank 1, Place 1, Sija 1 | the place number drawn in that slot - it stays put and is renumbered on a tie (1, 2, 2, 4) |
| Row plate (one per row) | Row 1 | Plate 1, Card 1, Rivi 1 | a drawing behind the row that travels with it (optional) |
| Two to ten rows, each drawn in its starting place with first place at the top. Tick Lowest first for times and golf scores. | |||
| Meter | |||
| Bar | Progress bar | Meter | draw it at its FULL length - that length is the target |
| Percent | Percent | Share, Osuus | written as the current figure's share of the target |
| Survey board | |||
| Question | Question | Kysymys, Fråga | a field the operator types |
| Answer (one per row) | Answer 1 | Vastaus 1, Svar 1 | draw it as it looks revealed - written from the Answers box, hidden until its reveal |
| Points (one per row) | Points 1 | Pts 1, Pisteet 1 | a plain figure - written from the Answers box, shown with its answer |
| Revealed (one per row) | Revealed 1 | Flip 1, Open 1 | shown once that answer is revealed |
| Strike 1 | Strike 1 | X 1 | the first X, lit from the first strike on |
| Strike 2 | Strike 2 | the second X | |
| Strike 3 | Strike 3 | the third X - and the Strike button greys | |
| Total | Total | Sum, Yhteensä | written by NoaCG: the points of the revealed answers, added up |
| Two to eight answers. | |||
| Stepped list | |||
| Entry (one per row) | Item 10 | Entry 10, Number 10, Kohta 10 | draw it as it looks revealed - written from the Entries box, hidden until its number comes up |
| Mark (one per row) | Mark 10 | Current 10, Highlight 10 | shown on the entry that just arrived, until the next one does |
| Two to twelve entries; the option decides whether they arrive from the last number down or from 1 up. | |||
| Lineup | |||
| Guest (one per row) | Guest 1 | Act 1, Speaker 1, Vieras 1 | a field the operator types |
| On now (one per row) | Now 1 | Current 1, Nyt 1 | shown on the guest who is on |
| Been on (one per row) | Done 1 | Been 1, Past 1 | shown on every guest who has already been on |
| Two to eight guests, in the order they come on. | |||
| Puzzle board | |||
| Category | Category | a field the operator types | |
| Letter (one per row) | Letter 1 | Tile 1, Kirjain 1 | one letter, drawn as it looks revealed - written from the phrase, shown once its letter is called |
| Used (one per row) | Used 1 | White 1 | shown on every tile the phrase reaches - the white face behind a letter still hidden |
| Solved | Solved | Ratkaistu | once the puzzle is solved (one, whole board) |
| Four to forty tiles, numbered left to right and then down; the phrase is laid over them in that order, so put spaces where the tiles should stay blank. | |||
| Reveal | |||
| The reveal | Price | Secret, Reveal, Hinta | draw it as it looks revealed - written from The reveal box, hidden until the press |
| Cover | Cover | Envelope, Sealed, Kansi | shown until the reveal - the sealed plate over the text |
| Bingo caller | |||
| Numeral (one per row) | Number 7 | Ball 7, Numero 7 | the numeral on a tile, left as you drew it - naming it keeps it out of the operator’s fields |
| Called (one per row) | Called 7 | Marked 7, Huudettu 7 | shown on a number once it has been called |
| Last called (one per row) | Last 7 | Latest 7, Ring 7 | shown on the number called most recently, until the next call |
| Last call readout | Last call | Latest, Now calling | the number called most recently, written large - hidden until the first call |
| Count | Count | Calls, So far | how many numbers have been called, written by the board |
| Five to ninety numbers, one Called layer each. Name the numeral on each tile Number 1, Number 2 and so on, and it stays your drawing instead of arriving as a field. | |||
| Credits roll | |||
| Credits | Credits | Credit list, End credits, Lopputekstit, Eftertexter | the layer the credits are read from: the first role, when each role and each name is its own text layer, or one text object holding every line, which scrolls as fixed artwork |
| Credits box | Credits box | Credits panel, Credits window, Lopputekstit laatikko | a window used only by credits saved by an earlier version; new imports use the whole frame and need no box |
static: at the start of a text layer's name, as in
static:Heading, keeps the text as drawn. It is not an operator
field.f: at the start of a picture's name, as in f:Logo, makes
it a field the operator can swap. Pictures without it start unticked.84, becomes a number field with
+ and − buttons.05:00, can become a clock or a
countdown.Bar, the
second one becomes Bar 2.When the operator types more than fits, NoaCG first uses the room in the shape behind the text, then wraps it onto a new line, then makes it smaller. Nothing is cut off.
Draw each role and each name as its own text layer, in one role look and one name look, and the credits stay an editable list in your styling. Draw the whole list as one text object and it scrolls as fixed artwork. No special names are needed. See End credits.
Two team names and two scores. The operator adds a point with one press.
Team 1 and Team 2: text. Required.Score 1 and Score 2: text, drawn as a plain number
such as 2. Required.Flash 1 and Flash 2: hidden group. Shows for a
moment when that team scores. Optional.Full time: hidden group. Shows at the end of the game.
Optional.Up to eight teams: Team 3, Score 3 and so on.
Flash layer.Flash layer again.Full time layer.The operator can also type any score straight into its field.
A question and two to six answers. The operator selects an answer, locks it in and reveals the correct one.
Question: text. Required.Answer A, Answer B and on to Answer F:
text. At least two. Required.Selected A: hidden group. Shows on the answer the operator
picks. Optional.Correct A: hidden group. Shows on the correct answer at the
reveal. Optional.Wrong A: hidden group. Shows on every other answer at the
reveal. Optional.Locked in: hidden group. Shows once the answer is locked in.
Optional.
Draw the same three for every answer: Selected B,
Correct B and so on. A moment you do not draw gets NoaCG's own
highlight. The letters on the rows are static:Letter A and so on,
so they stay as drawn.
Reveal choice keeps the pick secret until you reveal it: choose the letter in Selected answer, press Update, then Lock it in without pressing Select answer. The board shows it is locked but not which answer. Reveal choice then shows the pick.
The audience votes on their phones at your join link, and the bars grow with the count.
Option 1, Option 2 and on to Option 8:
text. At least two. Required. The vote writes each option's wording here.Bar 1, Bar 2 and so on: a rectangle drawn at full
length. Full length is 100%. Required.Question: text. Optional.Percent 1 and so on: text. Shows that option's share.
Optional.Winner 1 and so on: hidden group. Shows on the winning row.
Optional.Total votes: text. Optional.Vote badge: hidden group. Shows while voting is open.
Optional.
The Bar layers are what make the wizard pick Live vote. A bar grows
from its left edge. Draw it as a plain rectangle with square ends, because other
shapes are stretched. Draw the empty track behind it as its own layer in
Board, called Track 1 and so on, never Bar.
Winner layer on the row
that won.You open the vote itself on the production's Audience tab. The counts reach the graphic as a cue that you still take to air.
A clock that counts down to zero. The operator sets the length in minutes.
05:00. Any name; the
example calls it Clock. Required. Keep it the only text in the
file shaped like a time.Timer bar: a rectangle drawn at its full length. It shrinks as
the time runs out. Optional.Warning: hidden group. Shows in the last 10 seconds.
Optional.Paused: hidden group. Shows while the clock is paused.
Optional.Time up: hidden group. Shows at zero. Optional.
The wizard picks Countdown when the file has the time layer and at least one of
the four named layers. With only the time layer, drawn as minutes and seconds such
as 05:00, the Fields step offers a Clock instead: it
counts up, counts down from its time, or counts down to a set date and time. A clock can sit beside a score tracker.
3 is three minutes and
0.5 is thirty seconds.2:30 is two minutes, not two
and a half.Warning shows.
Credits are one list of roles and names. Draw them so they stay easy to edit, or keep them as fixed artwork. Import the SVG and choose Credits roll.
Credits: one long text object containing the complete layout.
This example scrolls as fixed artwork.
No Credits box, background or special punctuation is needed.
To change a name or add one, edit the Illustrator source and import its SVG again.
The operator gets one list to paste or edit, kept in your styling. A paste from Google Sheets or Excel works, and the list can be linked to a Google Sheet. A roll or cards on air keep the list they took; the next Take shows the new one.
The text stays part of the artwork: it scrolls exactly as drawn and cannot be edited on the production page. That happens when you choose Show as: Fixed artwork, or when the drawing cannot be read as roles and names, such as one text object holding every line. The Fields step says which, in one line. Scroll speed controls the pace. Each Take restarts the roll, and Out clears it.
The editable list, in imported credits and in the catalog credits designs, is written like this:
Director: Alex Rivera
Camera Operators:
Jonas Berg
Lena Fors
# PRODUCTION is a department
heading.A tag and a story line along the bottom of the screen.
Kicker: text. The tag, such as SPORT.Story: text. The headline.Both are ordinary fields. Panel is the strip and
Kicker box is the kicker's plate.
An imported ticker shows one story and does not move. For a crawl or a rundown of several stories, start from a ticker design in the catalog instead. It has one text box for the whole rundown:
SPORT: United win 3-0
SPORT:
City held at home
Rovers sign a goalkeeper
Storm warning issued
2:1 and 20:45 stay
part of the story.An SVG is the best thing to bring in, because its text stays text. Other files work too.
| File | What it is good for |
|---|---|
| PNG, WebP | A finished design, or a logo. Both carry transparency, which is what lets video show through. |
| JPEG, AVIF, GIF | Photographs and stills. No transparency in a JPEG, so it covers whatever is behind it. |
Lottie (.json) | A vector animation from After Effects. Stays sharp at any size. |
A font file (.woff2, .woff, .ttf, .otf) | A licensed face your design needs. Taken by the SVG import when it lists the families it found. |
Video (.webm, .mp4) | A short sting inside a graphic. Capped at 3 MB, so it is not the way to play a clip. |
Pictures for a live show are separate. On a production, Add pictures builds one picture graphic that holds all of them, with a cue each. Taking picture three replaces picture one instead of stacking on top of it. A production takes up to twenty.
A file you bring in is copied into the graphic. Nothing links back to your computer and nothing is fetched when the graphic plays, so a package works on a playout machine with no internet. A web address is not a substitute for the file: the studio warns about one, and a machine that cannot reach it shows nothing.
A picture larger than the frame is re-encoded at the frame's size, which costs no quality. A PNG stays a PNG and a JPEG stays a JPEG. An SVG is never touched, and a smaller picture is never enlarged.
Get the transparency right before you import. A full-frame picture with no transparent areas covers the whole picture on air. That is right for a title card and wrong for a lower third. Export it again as a PNG or a WebP with a transparent background.
images/, fonts under fonts/. Paths are relative, so the
folder can be copied anywhere.Either way the package is complete and works from a local disk.
The operator page in the package lets an image field switch between the pictures that graphic already carries, plus None. It is not a file browser. If an operator will need another logo on the night, bring it in before you export.
Adding a Lottie is not available yet. A graphic that already carries one keeps it.
A Lottie plays as soon as the graphic loads and it loops. It does not follow the graphic on and off air, so it suits a badge, a spinner or a looping ornament rather than something that has to hit a cue. It travels inside the package.
A missing font is silent. The browser uses the next font it has, so the graphic airs in the wrong typeface and nothing warns you.
So NoaCG puts the fonts in the package, with their licences. A font of your own comes in through the SVG import's font matching.
When a font file is missing:
fonts/.First: are you exporting at all? If NoaCG is running the show, the answer is no. A production gives you an output URL to add as a browser source and an operator page to drive it from, and nothing is downloaded.
Export when another system will own the graphic, or when it has to run without NoaCG. Every graphic exports to every package below. Take the row for the system that will play it.
| Playing it in | Take | What you get |
|---|---|---|
| OBS, vMix, or anything that renders a web page | HTML overlay (OBS / vMix) | One .html that plays itself when the source loads, and an operator
page for live edits. The guide. |
| CasparCG | CasparCG export | One .html with everything inlined that reads CasparCG's own data
payloads, and an operator page. The guide. |
| A playout system that loads a folder of templates, such as SPX | SPX export | A folder to drop into that system's templates directory. Your fields appear in its rundown by name, and an operator page comes with it for anything else. |
| An OGraf renderer | OGraf (EBU) export | A folder holding the OGraf manifest and the graphic as a web component. This is the EBU's interchange format, so it is also the one to take when you do not yet know what will play it. |
| LiveOS (NetOn.Live) | LiveOS (NetOn.Live) export | The same OGraf package, with that engine's install steps beside it. Its fields become LiveOS operator inputs. |
| H2R Graphics | H2R Graphics export | One .html for H2R's Custom HTML graphic type. The fields become H2R
inputs, and its on and off drive the entrance and the exit. |
None of them needs the internet: everything the graphic uses travels inside the package (what comes out in an export). If you pick the wrong one, export again. The last step of making a graphic offers the export.
A published production has one output URL. It shows the whole show on a transparent background, and the playout dashboard drives it live. Any source that can load a web page can show it.
…/output?production=<slug>, where the slug is a
random id made when you publish.For every browser source:
<name>.html from inside the unzipped folder.Leave "Shutdown source when not visible" off for a production output. When it is on, OBS tears the page down each time you hide the scene and rebuilds it when the scene comes back.
An exported overlay comes with a small launcher: Start controller.cmd on
Windows, start-controller.command on macOS and
./start-controller.sh on Linux. It serves the folder locally, opens the
operator page and relays every command into the graphic that OBS or vMix is showing.
It needs no network and nothing to install.
Take graphics in and out from NoaCG, so they animate. Taking the input off its overlay in vMix removes every graphic at once, with no exit animation: keep that for emergencies.
| What you see | Do this |
|---|---|
| Black or white box behind the graphic | Clear any custom CSS setting a background. Do not add a chroma key. |
| Graphic looks soft or wrong-sized | Set the browser source to the graphic's own resolution. Resize the source, never the layer. |
| Motion judders | Set the source's FPS to the channel's. |
| Output URL shows "not available" | Re-copy the URL from the production page. Unpublishing revokes the URL. |
| Blank after a network drop | Wait. It rebuilds on its own without replaying animations on screen. If it does not, reload the layer. |
| A take airs nothing | Read the playout status in the production page's header. Offline means there is no output to air to, so press ▶ Start production. If the production is started, press the status to see which check is failing, then re-copy the output URL and check the browser source is still loading it. |
The full playout setup reference, including the self-hosted routes, is PLAYOUT_INTEGRATION.md.
CasparCG plays web pages through its HTML producer, so there are two ways in: load the production's live output URL, or play an exported file from disk with no network at all.
CG 1-20 ADD 1 "https://noacg.studio/output?production=<slug>" 1
1-20 is channel 1, layer 20. Use whatever your rundown expects.&debug=1 to see a status readout on screen.
Take it off before air.| Server | Engine | What it means |
|---|---|---|
| 2.3.x | Chromium 71 | The live output URL works with nothing to do. A graphic's own modern CSS can render differently: see below. |
| 2.4.x | CEF 117 | The oldest version NoaCG designs for. Nothing special to do. |
| 2.5.x | CEF 142 | Current. |
gap. Every export and the output page carry
a shim that puts it back.color-mix(),
the inset shorthand or backdrop-filter renders differently
here.?. or ?? stops the
layer with a SyntaxError that only the server log shows.Every export screen has a Playout compatibility section with one line per system: whether the graphic renders as designed there, and which CSS needs which version.
Instead of typing the command into the CasparCG Client, you can let the production page send it. A browser cannot talk to CasparCG directly, so a small program on the machine you operate from does it: NoaCG Bridge.
NoaCG Bridge remembers each server and its setup: the channels and their names, the slot NoaCG's output plays on and the channel new media starts on. Every browser paired with the same Bridge connects to the last server by itself and opens with the same setup. To pair another browser, copy a pairing link into it: the pairing page, Playout settings and Enter in the NoaCG Bridge window each make one. A link works once, within two minutes. With a Bridge older than 0.8.0 each browser keeps its own setup.
The production page has a Put on air / Take off row beside its output URL, and Put on air sits beside Connect in its Playout settings too. Put on air sends the one command above, and only when you press it: pairing and connecting never touch a layer. After that, every cue reaches the page CasparCG is showing through the production itself, and the Bridge sends nothing more.
127.0.0.1 only. CasparCG can be any machine on
the studio network, as with the Client, and nothing is exposed to the
internet.With the Bridge paired, the foot of the rundown has + From the playout server…. It lists the HTML templates and media in the server's own folders, folder by folder. Pick one to add it as a cue beside the production's graphics.
The list comes from the server's media scanner, which runs beside
CasparCG: scanner.exe in the Windows download, a separate
scanner process on Linux. When it is not running, the picker says so and
still lets you type a template or clip name.
A template NoaCG exported brings its fields with it. For any other template, type its
field ids (f0, f1) once. Get them from its own FIELDS.md or from its
author.
List the channels your server has under Settings → Playout, then put each server item where it belongs:
Channel 2. A name is optional.2-10 is channel 2, layer 10.1-20 unless you change it. Media on that channel plays under the
graphics on a lower layer (videos and stills start on 10, audio on 5) and over them
on a higher one. No server item may use the output's own layer: playing something
there would replace the output.A studio with one channel sees one row, and nothing changes.
A video with an alpha channel can play over the programme from a key channel, for example as fill and key into a vision mixer's downstream keyer. Render it as ProRes 4444 or QuickTime Animation with premultiplied alpha (in After Effects, "Premultiplied (Matted)" with black). CasparCG reads a video's alpha as premultiplied, so a straight-alpha render looks too bright wherever it is partly transparent: soft edges, shadows and fades. WebM (VP9) alpha does not work on CasparCG 2.3. Transparent PNG stills are always right. On the vision mixer, set the keyer to a pre-multiplied key.
Checked on CasparCG 2.3 and 2.5 by recording the channel. Not yet checked through an SDI card and a vision mixer.
On a real CasparCG 2.5.0 with its media scanner running: the Bridge paired, and a published quiz and scoreboard went on the channel with one command. They were revealed and scored from the dashboard. A template and a still from the server's own library were cued, taken, updated and taken off.
The 2.3.2 install answered the same listing and one template round.
Not yet verified: the pairing prompt on the hosted studio, a Linux server, and Safari. If it misbehaves on yours, the manual command above is the same live link, and we would like to hear about it.
Export with the CasparCG target and you get one self-contained
.html, with fonts and images inside it and no network needed. Put it in
the server's template folder, which is the template-path in
casparcg.config, and drive it as a normal HTML template.
Below, <template-name> is the file name without its
.html extension, relative to that folder:
CG 1-20 ADD 1 "<template-name>" 1 "<templateData>…</templateData>"
CG 1-20 PLAY
CG 1-20 NEXT
CG 1-20 STOP
The <templateData> block carries the field values, and a CasparCG
client sends them by field id (f0, f1, …). Every
exported package has a FIELDS.md that lists each field's id, name,
type and default, with ready-to-paste payloads for that graphic. Keep it open beside
the client.
A production is one show: its graphics, a rundown of cues you prepare in advance, and one output URL that stays the same. Each graphic is its own layer, so a bug, a lower third and a ticker can be on air at once.
Publishing needs an account, because the published pages live in your cloud space. Everything before it works offline.
The header has one status for playout, a colour with a short text beside it. Press it to open the Playout panel: it says which check set the colour, lists the outputs, and holds the actions, the playout setup and the links, each with a Copy button.
| Colour | Means | For example |
|---|---|---|
| Grey | Not started, or nothing to check yet | Offline, Connected, Checking |
| Amber | Something needs your attention | Unpublished changes, an output behind, preparing, loading on CasparCG, no output connected |
| Green | Live, connected and ready | Ready · on air 1-20 |
| Red | Something that should work is broken | Bridge not running, CasparCG not answering, output not on air, another production on the layer, a channel the server does not have, a graphic that cannot play |
The program monitor says the same in its heading: PROGRAM · ON AIR once the production is started, PREVIEW · NOT LIVE before. A clip or still from the playout server is on air as soon as you take it, so while one plays the monitor reads PROGRAM · ON AIR. To send later changes to the output, press ⟳ Publish changes in the Playout panel. The status reads Preparing until the outputs have loaded the new version.
Two different things both get called sharing, and they have different answers:
A published production has links that work for whoever holds them. They are in the Playout panel, which opens from the playout status in the production page header.
Several people can run one show this way with one account and nothing to set up. The playout dashboard and audience join pages cover what each link does. Only the account that made the production can edit its rundown or republish it.
Teams need an account, so sign in first.
Teammates see your name and nothing else. Email addresses are never shown to anybody.
The team screen shows a large join code. Under it is a link ending
#/join-team/<code>, with a Copy link button.
Send the link, not the code. The screen that takes a code opens only from a join link, so a code read out to a room gets nobody in who does not already hold a link. Paste the link into the class chat, or wherever you already talk. There is no email invitation.
A code is still a key. Anybody who has ever held a join link to any team is one paste away from using a code they overheard.
The person who gets the link opens it, signs in or makes an account, types the name teammates will see and presses Join team. Joining shares nothing from their library, and nothing from yours.
Anyone in the team can pass the link on. Only the owner can press Rotate code, which makes a new code and retires the old one. Everybody already in the team stays in, so rotate when a link reaches the wrong chat.
Your display name is fixed when you join. To change it, join again through the team's current link with a different name.
There are two roles. Whoever made the team is its owner, and everyone else is a member.
Every Yes below has one condition: you need a production of your own to open the team dialog. An empty one is enough.
| Owner | Member | |
|---|---|---|
| See the join code, and pass the link on | Yes | Yes |
| See who else is in the team | Yes | Yes |
| Rotate the join code | Yes | No |
| Remove somebody from the team | Yes | No |
| Leave the team | No | Yes |
| Delete the team | Yes | No |
There is no Leave button for an owner. An owner gets out by deleting the team, which cannot be undone and takes the productions the team holds with it. That button asks a second time before it does anything.
Removing somebody, or being removed, takes nothing away from their own library.
Run against the live service: making a team, handing out its link, joining through it, reading the member list, rotating the code and deleting the team.
Removing a member and leaving a team have not yet been run with a second person in the team, so treat them as expected rather than proven.
Moving a production into a team does not work yet. The Move to team button in that dialog is switched off. To work on a show together in the meantime, use the links above.
A public join page at noacg.studio/join/<name> collects viewer
messages and votes from any phone, with no app and no account.
The link is in the same Playout panel as the output URL. Its name comes from the production's name at the first publish, and the Readable name row changes it to something you can say out loud. Do that before you give the link out, because a new name breaks the old one.
You do not need a Twitch or YouTube channel for any of this. An audience with no Twitch and no YouTube walks through it on one small show, from publishing to a vote on air.
A lower third plays and stops. A quiz board has to know which answer was locked in, and whether it has been revealed. NoaCG graphics carry that as states and buttons, and a button the current state does not allow is greyed out.
You build behaviour without code: draw each moment as a hidden layer in your SVG and the import wires it up. See Layer names.
A data update changes what a graphic shows, and nothing else. It cannot play a graphic, take it off, or change its state. Data updates and operator commands apply in the order they arrive, so an operator's change made after a feed update wins.
Every field is editable live from the production page: edit, then take. For most shows nothing else is needed.
A Sheet connects to the production, not to the graphic. On the Playout tab, select a cue of the graphic and press Connect data…. Paste the link from the Sheet's Share button and press Read. Every field is offered a column or a row of that tab; check the list on the PREVIEW monitor and press Connect once.
A graphic that reads a Sheet in its own code. Older graphics could carry their own Sheet reader. They keep working, in the studio and in every export. The production lists such a graphic beside its sources and says that Pause does not stop it. To connect it here instead, press Connect data… on it and choose Stop its own reader: the reader leaves the graphic's code (in every production that uses it), and then you connect the Sheet as above. On a published production, publish the change first, so only one reader ever writes the fields.
For a timing system, a results service or your own scripts: push values into a published production over HTTPS, with the production's own data key. In the studio this source is called Another system.
Connect the fields first. On the Playout tab, select a cue of the
graphic, press Connect data… and then Another
system. Every field is offered its own path, such as
api.riverside_count.leading. Check the list and press
Connect.
Where to find the address and the key. Publish the production and open its Data tab. The Another system card shows the address, the key behind Reveal, an example made from the connected fields and when the last values arrived. Put the key in your integration's server-side configuration. Publishing again makes a new key and the old one stops working, which is also how you revoke one.
curl -X PATCH https://noacg.studio/api/data/patch \
-H "Authorization: Bearer $NOACG_DATA_KEY" \
-H "Content-Type: application/json" \
-d '{"api": {"riverside_count": {"leading": "Harbour List", "margin": "412"}}}'
/api/data/patch (PATCH, or POST behind a proxy that eats PATCH)
writes data paths. Every field connected to a path follows, so the feed does not have
to know the rundown. A null removes a value from the tree; the field
keeps what it shows."paused": true. Your own
presses still go on air. Resume sends the latest values once./api/data/update is the older door that addresses one graphic by name
and its fields by the labels the operator sees. It still works, and Pause holds it
too.One show, worked through puts all of this in a real rundown.
Production data, bindings and tables decide where the number on screen comes from. They are easier to tell apart in a real show, so here is a small one.
Hall Cup is a school sports night. It has four graphics, one data tree, one table and a hall full of phones. Every picture below was taken while building it.
Make each one from the catalog. On the wizard's Finish step, the Production box says where the graphic goes.
| Graphic | Catalog category | What it asks you to type |
|---|---|---|
| Match Strip the bug that stays up |
Scoreboards | Team A, Score A, Team B, Score B |
| Quiet Score the card you cut to at half time |
Scoreboards | Team A, Score A, Team B, Score B |
| House Wire the ticker along the bottom |
Tickers | Ticker items, Label, Scroll speed (%) |
| House Strap the name under an interviewee |
Lower thirds | Name, Title |
The field names matter. The rest of this example binds by them, which is why the two scoreboards use the same four.
Open the production and go to its Data tab. Press ▾ Raw JSON, paste this in, and press Apply JSON.
{
"match": { "teamA": "Otava", "scoreA": 2, "teamB": "Karhut", "scoreB": 1 },
"tickerItems": [
"Junior final starts at 19:30",
"Canteen closes at 20:00",
"The bus home leaves from gate 4"
]
}
That address is a path. Dots walk down the tree. The number 2 lives
at match.scoreA, and the three ticker lines live together at
tickerItems.
You do not have to paste JSON. The row at the bottom adds a path and a value by hand. If the path does not exist yet, it is created.
4 is a number, true
is a boolean, [1, 2] is a list, and anything else is text. Number rows
get − and + buttons. A list is one line per item, which is what a ticker's
text box takes.A path does nothing on its own. A binding points one field of one graphic at one path. Scroll to Bindings and press Bind all by title.
It matched by the words. "Score A" found match.scoreA: the last part of
that path is the field's title, once case, spaces and punctuation are ignored.
"Ticker items" found tickerItems the same way.
If two paths match one title, the row stays empty and names both. The strap's Name and Title matched nothing, which is right: a guest's name is not something the whole show shares.
To bind a row by hand, click its box and pick a path from the list, or type one. To unbind it, press ✕ twice.
Press + beside match.scoreA on the Data tab. Both scoreboards now say 3,
whichever of them is on air and whichever was cued first.
The score belongs to the show, not to one cue, so nobody retypes it on the half-time card.
You can also change it from the Playout tab. A bound field shows there read-only, with its path beside it. The ± LIVE NUMBERS row underneath changes the shared value with one press.
Where the tree lives depends on one thing, publishing:
Hall Cup interviews three people. Their names belong to no particular moment in the show. That is what a table is for: a bank of rows, none of them live. The operator loads the row they want, when they want it.
Under Tables, choose Line-up / roster and press + New table. Call it Interviews. It starts with the columns Name, Number and Position. Rename Position to Title, remove Number, and type the rows.
The matching is by words again:
So a spreadsheet that already uses your field names needs no mapping step. ⬆ Import CSV / JSON takes it as it is, and then says which of its columns matched. ⬇ Blank CSV goes the other way: it gives you a file with the right header row to fill in.
Now go back to the Playout tab and select the House Strap cue. It now has a Load data row control. Picking a guest fills the cue you are editing, which is the preview, and nothing more. The name goes on air when you press ⟳ Take, like everything else.
| Production data | Tables | |
|---|---|---|
| What it holds | One value that is true right now | Many rows, none of them current |
| Who writes it | An operator, a feed, or the Data API | You, or a spreadsheet you import |
| How a graphic gets it | A binding, and then always | An operator loads a row into one cue |
| Changing it | Moves every bound graphic at once | Changes nothing until a row is loaded |
| Hall Cup uses it for | The score and the ticker lines | The guest list |
When both would work: if more than one graphic needs the same value at the same time, use the tree.
The first panel on the Audience tab is Chat sources. It asks for a Twitch channel or a YouTube video. Most people running a hall, a school event or a club night have neither, and they are not missing anything.
Those two only pull an existing chat into the same inbox. The room's own join page takes messages without them, and that is what Hall Cup uses.
First add two more graphics from the catalog: House Question (Audience & questions) for the messages, and House Vote (Live votes) for the poll. Then:
noacg.studio/join/<name>. The name comes from the production's
name when you first published it.Hall Cup leaves the mode beside that tick box on Questions. Comments works the same way and asks for something shorter.
Every message lands in the inbox on the same tab. It takes two steps to reach air:
Before sending, the operator can edit a broadcast version of the message. What the viewer sent is never changed.
Rehearse first. On an unpublished production the bar has ⟳ Simulate 3 arrivals. It makes up messages marked "(rehearsal)" so you can practise moderating. A published production has no such button.
Type a question under Put a question to the room. Give it two to eight options, one per line, and press Open voting. Every phone with the link switches to the ballot at once. A viewer can change their vote while voting is open.
Stage counts to a graphic writes the question, the options and the counts into a cue for House Vote. Take puts it on air. Pressing it again while voting is open updates the same cue.
The figures on air change when the operator shows the result, not while the room is still voting.
A board you drew yourself can have a Live figures layer. The Audience tab then offers a tick box to show the percentages live instead. A catalog board like House Vote has no such layer, so this show does not get the tick box.
Everything in this section was run in the studio: the tree, the bindings, the table and loading a row, the inbox, and a vote from opening it to staging the counts.
One step is taken on trust: the published
noacg.studio/join/<name> link itself, which needs an account and
the hosted backend. The page a phone loads there is the one in the picture above,
drawn by the same code.
/noacg:graphic.HTML an agent writes on its own has no operator controls and no promise about how it behaves in a playout system. The NoaCG CLI adds them:
The result is an ordinary NoaCG graphic: put it in a production, operate it with its buttons, and feed it live data.
It works in the session you have open, with nothing to install first. The agent checks its setup and, if this computer is not connected yet, asks you to connect your NoaCG account in the browser. Then it asks what to make. Each graphic it finishes goes into your library, and it gives you the links. If you do not connect, it works locally and says that nothing was saved.
Use npx -y @noacg/cli@0.12.4 for every NoaCG command in this session. Run its doctor, read docs skill and follow it, and check whoami. If I am not logged in, run login so I can connect my account in the browser; if I decline, work locally and say nothing was saved. Then ask what to make. Build, validate with screenshots, save every graphic to my library, and return the direct links. Clearly state anything still pending or unconfirmed.
You need:
To install the plugin as well, see Reference. It brings the NoaCG skill from your next session on.
For example: "Make me a clean scoreboard for a floorball stream: home, away, period,
clock." In Claude Code, /noacg:graphic starts the same thing.
The noacg-graphic skill tells the agent how a NoaCG graphic is built,
validated and saved. How it looks is up to the agent. The plugin brings the skill from
your next session on. Until then, noacg docs prints the same texts.
The agent then works in five steps:
Saving is the one step that needs you. Log in once per machine, and approve it in the browser that opens:
npx @noacg/cli login
The key it stores can save graphics to your library, make productions of the graphics it saves, and send packages to your Home. It cannot publish or play anything. To revoke it, go to Settings, then Account, then Agent access.
save refuses a graphic that does not pass validation. A saved graphic is
editable in the studio like any other, and exports to every target NoaCG supports.
For example: "Make me the graphics for a fight night: opener, name straps, fight bug, round card."
The agent builds each graphic and saves the whole set to your library in one save, with a link for each graphic. If you also ask for a production with a running order, the same save makes it, with its layers and running order, and the agent gives you its link. There is nothing to install. If the agent says a save is unconfirmed, it runs the same command again, which never saves a second copy.
A package sent with noacg pack --save is the older route. It waits on
your Home under Waiting to install until you press
Install, and Home tells you when its graphics were already delivered.
The install commands, one by one. The plugin is optional: the prompt above works without it. All three routes install the same package.
Claude Code. The plugin brings the /noacg:graphic skill
and runs nothing until you make a
graphic. Type this in a Claude Code session (version 2.1.275 or newer). It adds the
NoaCG marketplace, asks you to confirm it, and installs the plugin:
/plugin install noacg --marketplace NoaCG/NoaCG-Studio
From a terminal or a setup script, the same install is two commands:
claude plugin marketplace add NoaCG/NoaCG-Studio
claude plugin install noacg@noacg-studio
An optional second plugin adds an MCP server that is always on. It puts the
noacg tool in every session and keeps a browser ready between calls, at
the cost of a process and some context in every session.
/plugin install noacg-mcp --marketplace NoaCG/NoaCG-Studio
Codex. The same plugin, from the same repository. Codex has no one-command form, so run these two in a terminal:
codex plugin marketplace add NoaCG/NoaCG-Studio
codex plugin add noacg@noacg-studio
Any other agent that speaks MCP. Register the server over stdio,
with the command npx and the arguments -y @noacg/cli mcp.
It brings the tools, and the contract text comes with them as the server's resources.
npx -y @noacg/cli mcp
The package. All three routes install one npm package,
@noacg/cli. It
gives you one command, noacg. You can also install it yourself:
npm i -g @noacg/cli
Or run any command with nothing installed, as
npx @noacg/cli <command>. The loop by hand is three commands:
npx @noacg/cli scaffold --type scoreboard --design neutral --out my-scorebug
npx @noacg/cli validate my-scorebug --screenshots shots
npx @noacg/cli save my-scorebug
scaffold creates the --out folder relative to where you
run it. The folder has to be new or empty. noacg types lists the
graphic types you can pass to --type, with their fields and operator
events.
The MCP server without the skill. This gives Claude Code the tools without the plugin, for the folder you run it in:
claude mcp add noacg -- npx -y @noacg/cli mcp
To have it in every folder, add --scope user before the name:
claude mcp add --scope user noacg -- npx -y @noacg/cli mcp
A server added this way runs in every session of that scope. It has one tool,
noacg, whose command is the CLI verb: types, scaffold,
validate, inspect, screenshot, docs or save.
Which files to edit. A package holds sources and generated files.
Edit the sources: <name>.html, css/template.css,
js/template.js, and the images/ and fonts/
folders.
Leave the generated files alone: <name>.ograf.json,
graphic.mjs, FIELDS.md, README.md,
GETTING-ON-AIR.md and controlpanel.html.
validate rewrites them from the sources, so an edit made there is lost.
Which deployment it talks to. https://noacg.studio,
unless you set one of these environment variables:
NOACG_URL points it at a local dev server or a self-hosted one.NOACG_BROWSER names a Chromium executable, when the system Chrome or
Edge is not the one to use.NOACG_AGENT_KEY supplies a key in CI, where nothing can open a
consent page in a browser.
When something fails and the findings do not say why, run
doctor. It prints which browser it will drive, which deployment
NOACG_URL points at, the bridge version it found there, and whether a key
is held.
npx @noacg/cli doctor
What the package is. The folder is at the same time a valid SPX package and an EBU OGraf v1 graphic, with no build step. Zip it and it imports through the studio's Import door, or plays in any OGraf renderer.
The graphic itself is plain HTML, CSS and JavaScript. So the same sources also export to CasparCG, an OBS or vMix overlay, H2R and LiveOS. The full reference is AGENT_CLI.md.
Add NoaCG to a chat app as a connector and sign in. The app can then read your library and put a production with its rundown on your Home. You open it with Install.
Checked with Claude.ai, the Claude desktop app and Claude Code. ChatGPT and other apps that take a custom connector are expected to work the same way, but have not been tried yet.
The connector address:
https://noacg.studio/mcp
In Claude Code, the same connector is one command:
claude mcp add --transport http noacg https://noacg.studio/mcp
The connector reads your graphics, brands and productions (team productions too), picks designs from the catalog, copies your own graphics, applies a brand and fills the cues. It does not write new graphic code, and it does not edit, delete, publish or play anything. For new designs, use a coding agent with the CLI.
Every connected app is listed in Settings → Account → Agent access, where Revoke ends it. What an app reads goes to that app’s provider, under its terms (privacy).