Skip to main content

Annotated line, Sketch notes 1.0.0

TemplateAnnotated line, tpl_d9661b6f8d97
VariantSketch notes
Version1.0.0, the newest: what a channel following this variant draws
Shapes9x16, 4x5, 1x1, 16x9, 2x3
Length14 seconds

Example video​

The 1x1 cut of this version, drawn from its own worked example. Open the video on its own.

What it accepts​

One line drawn left to right with the story written onto it: up to three reference levels drawing across as the line first reaches them, up to four events popping on at their points as the line pauses there, and the value at the head counting along to the last. metaData is the post's title, descriptions and hashtags and is never drawn.

FieldTypeRequiredLimitWhat it is
clipDatagroupyesClip data: Everything drawn: a kicker, what the line shows, the unit, the points of the line, the reference levels, the events written on it, the source and the look.
clipData.kickertextup to 20 charactersKicker: A word above the title, such as RECORD or SINCE 1987.
clipData.titletextyesup to 80 charactersTitle: What the line shows, read before it draws.
clipData.unittextup to 24 charactersUnit: What the values are, written above the value axis.
clipData.pointslistyesat least 2, up to 60Points: The line, oldest first: a label for each point (a year, a month, a day) and its value. Two to sixty.
clipData.points[]groupPoint
clipData.points[].labeltextyesup to 10 charactersLabel: Shown under the axis, thinned where labels would crowd. Events name a point by this label.
clipData.points[].valuenumberyes4 decimalsValue
clipData.levelslistup to 3Reference levels: Up to three levels drawn across the chart as dashed lines, each with its label and value, drawing across the moment the line first reaches it: a previous record, a target, an average.
clipData.levels[]groupLevel
clipData.levels[].labeltextyesup to 24 charactersLabel
clipData.levels[].valuenumberyes4 decimalsValue
clipData.eventslistup to 4Events: Up to four moments written on the line, each naming its point: the line pauses on the point as it reaches it and the event pops on there. Every event adds a second to the clip.
clipData.events[]groupEvent
clipData.events[].attextyesup to 10 charactersAt: The label of the point it marks, exactly as written in the points.
clipData.events[].labeltextyesup to 28 charactersWhat happened
clipData.sourcetextup to 60 charactersSource: Where the values come from, or what they are where the source is not an official one.
clipData.lookgroupLook: How the clip looks and moves within its style. The same five switches in every format of the collections. Leave a switch out, or set it to the style's own, and the style decides.
clipData.look.themeenumauto, brand, light, dark, boldTheme: The style's own choice; your brand's own colours and background; a light or dark page tinted with your brand colour; or your brand colour as the page.
clipData.look.paceenumauto, calm, standard, punchyPace: How things arrive: the style's own rhythm, calm fades, a standard rhythm, or punchy slams and cuts.
clipData.look.cornersenumauto, square, soft, roundCorners: The shape of cards, panels and marks.
clipData.look.alignenumauto, start, centreText alignment: Where the text lines up.
clipData.look.logoenumauto, freeLogo: The style's own: the logo on the style's plate (a card, a disc, a badge) so it reads on any page. As it is: the logo whole, with no plate, frame or crop, for a logo made to stand on the page, such as one with a transparent background. As it is, make sure your logo reads on the page of the theme you choose.
metaDatagroupMeta data: Everything about the post that is never drawn in the clip: its title, its description in four lengths, one per kind of platform, and its hashtags. Reelwire adds the brand's description, link and hashtags after it. Left out, the post text is generated from the clip data.
metaData.titletextup to 100 charactersTitle: Used where the platform has a title of its own: Facebook Feed, LinkedIn, Pinterest and YouTube. Up to 100 characters, which every one of them takes.
metaData.captionTinytextup to 200 charactersTiny description (Pinterest, Threads, X): Up to 200 characters. The brand's description, link and hashtags follow it within the platform's limit.
metaData.captionShorttextup to 500 charactersShort description (Telegram, Threema, WeChat, WhatsApp): Up to 500 characters. The brand's description, link and hashtags follow it within the platform's limit.
metaData.captionMediumtextup to 1500 charactersMedium description (Discord, Facebook Reels, Instagram, LinkedIn, Signal, Slack, TikTok): Up to 1500 characters. The brand's description, link and hashtags follow it within the platform's limit.
metaData.captionLongtextup to 4000 charactersLong description (Facebook Feed, YouTube): Up to 4000 characters. The brand's description, link and hashtags follow it within the platform's limit.
metaData.hashtagslistup to 15Hashtags: Written without the #. Up to 15, which every platform takes.
metaData.hashtags[]textup to 60 charactersHashtag

locales carries other languages: under each language code, the parts of clipData and metaData that differ, laid over the default, so a language with no copy still renders.

A picture is always a file from your media library: media:// followed by its id or its name. Anything the table does not list is refused, and so is anything over its limit, with a 400 schema_validation error that names the field.

The JSON Schema
{
"type": "object",
"properties": {
"clipData": {
"type": "object",
"properties": {
"kicker": {
"type": "string",
"maxLength": 20,
"title": "Kicker",
"description": "A word above the title, such as RECORD or SINCE 1987."
},
"title": {
"type": "string",
"maxLength": 80,
"title": "Title",
"description": "What the line shows, read before it draws."
},
"unit": {
"type": "string",
"maxLength": 24,
"title": "Unit",
"description": "What the values are, written above the value axis."
},
"points": {
"type": "array",
"items": {
"type": "object",
"properties": {
"label": {
"type": "string",
"maxLength": 10,
"title": "Label",
"description": "Shown under the axis, thinned where labels would crowd. Events name a point by this label."
},
"value": {
"type": "number",
"title": "Value"
}
},
"required": [
"label",
"value"
],
"additionalProperties": false,
"title": "Point"
},
"minItems": 2,
"maxItems": 60,
"title": "Points",
"description": "The line, oldest first: a label for each point (a year, a month, a day) and its value. Two to sixty."
},
"levels": {
"type": "array",
"items": {
"type": "object",
"properties": {
"label": {
"type": "string",
"maxLength": 24,
"title": "Label"
},
"value": {
"type": "number",
"title": "Value"
}
},
"required": [
"label",
"value"
],
"additionalProperties": false,
"title": "Level"
},
"maxItems": 3,
"title": "Reference levels",
"description": "Up to three levels drawn across the chart as dashed lines, each with its label and value, drawing across the moment the line first reaches it: a previous record, a target, an average."
},
"events": {
"type": "array",
"items": {
"type": "object",
"properties": {
"at": {
"type": "string",
"maxLength": 10,
"title": "At",
"description": "The label of the point it marks, exactly as written in the points."
},
"label": {
"type": "string",
"maxLength": 28,
"title": "What happened"
}
},
"required": [
"at",
"label"
],
"additionalProperties": false,
"title": "Event"
},
"maxItems": 4,
"title": "Events",
"description": "Up to four moments written on the line, each naming its point: the line pauses on the point as it reaches it and the event pops on there. Every event adds a second to the clip."
},
"source": {
"type": "string",
"maxLength": 60,
"title": "Source",
"description": "Where the values come from, or what they are where the source is not an official one."
},
"look": {
"type": "object",
"properties": {
"theme": {
"type": "string",
"enum": [
"auto",
"brand",
"light",
"dark",
"bold"
],
"title": "Theme",
"description": "The style's own choice; your brand's own colours and background; a light or dark page tinted with your brand colour; or your brand colour as the page.",
"enumNames": [
"The style's own",
"Brand colours",
"Light",
"Dark",
"Bold brand colour"
]
},
"pace": {
"type": "string",
"enum": [
"auto",
"calm",
"standard",
"punchy"
],
"title": "Pace",
"description": "How things arrive: the style's own rhythm, calm fades, a standard rhythm, or punchy slams and cuts.",
"enumNames": [
"The style's own",
"Calm",
"Standard",
"Punchy"
]
},
"corners": {
"type": "string",
"enum": [
"auto",
"square",
"soft",
"round"
],
"title": "Corners",
"description": "The shape of cards, panels and marks.",
"enumNames": [
"The style's own",
"Square",
"Softly rounded",
"Round"
]
},
"align": {
"type": "string",
"enum": [
"auto",
"start",
"centre"
],
"title": "Text alignment",
"description": "Where the text lines up.",
"enumNames": [
"The style's own",
"At the start of the line",
"Centred"
]
},
"logo": {
"type": "string",
"enum": [
"auto",
"free"
],
"title": "Logo",
"description": "The style's own: the logo on the style's plate (a card, a disc, a badge) so it reads on any page. As it is: the logo whole, with no plate, frame or crop, for a logo made to stand on the page, such as one with a transparent background. As it is, make sure your logo reads on the page of the theme you choose.",
"enumNames": [
"The style's own",
"As it is, no plate or crop"
]
}
},
"additionalProperties": false,
"title": "Look",
"description": "How the clip looks and moves within its style. The same five switches in every format of the collections. Leave a switch out, or set it to the style's own, and the style decides."
}
},
"required": [
"title",
"points"
],
"additionalProperties": false,
"title": "Clip data",
"description": "Everything drawn: a kicker, what the line shows, the unit, the points of the line, the reference levels, the events written on it, the source and the look."
},
"metaData": {
"type": "object",
"properties": {
"title": {
"type": "string",
"maxLength": 100,
"title": "Title",
"description": "Used where the platform has a title of its own: Facebook Feed, LinkedIn, Pinterest and YouTube. Up to 100 characters, which every one of them takes."
},
"captionTiny": {
"type": "string",
"maxLength": 200,
"title": "Tiny description (Pinterest, Threads, X)",
"description": "Up to 200 characters. The brand's description, link and hashtags follow it within the platform's limit."
},
"captionShort": {
"type": "string",
"maxLength": 500,
"title": "Short description (Telegram, Threema, WeChat, WhatsApp)",
"description": "Up to 500 characters. The brand's description, link and hashtags follow it within the platform's limit."
},
"captionMedium": {
"type": "string",
"maxLength": 1500,
"title": "Medium description (Discord, Facebook Reels, Instagram, LinkedIn, Signal, Slack, TikTok)",
"description": "Up to 1500 characters. The brand's description, link and hashtags follow it within the platform's limit."
},
"captionLong": {
"type": "string",
"maxLength": 4000,
"title": "Long description (Facebook Feed, YouTube)",
"description": "Up to 4000 characters. The brand's description, link and hashtags follow it within the platform's limit."
},
"hashtags": {
"type": "array",
"items": {
"type": "string",
"maxLength": 60,
"title": "Hashtag"
},
"maxItems": 15,
"title": "Hashtags",
"description": "Written without the #. Up to 15, which every platform takes."
}
},
"additionalProperties": false,
"title": "Meta data",
"description": "Everything about the post that is never drawn in the clip: its title, its description in four lengths, one per kind of platform, and its hashtags. Reelwire adds the brand's description, link and hashtags after it. Left out, the post text is generated from the clip data."
},
"locales": {
"type": "object",
"additionalProperties": {
"type": "object",
"properties": {
"clipData": {
"type": "object",
"properties": {
"kicker": {
"type": "string",
"maxLength": 20,
"title": "Kicker",
"description": "A word above the title, such as RECORD or SINCE 1987."
},
"title": {
"type": "string",
"maxLength": 80,
"title": "Title",
"description": "What the line shows, read before it draws."
},
"unit": {
"type": "string",
"maxLength": 24,
"title": "Unit",
"description": "What the values are, written above the value axis."
},
"points": {
"type": "array",
"items": {
"type": "object",
"properties": {
"label": {
"type": "string",
"maxLength": 10,
"title": "Label",
"description": "Shown under the axis, thinned where labels would crowd. Events name a point by this label."
},
"value": {
"type": "number",
"title": "Value"
}
},
"required": [
"label",
"value"
],
"additionalProperties": false,
"title": "Point"
},
"minItems": 2,
"maxItems": 60,
"title": "Points",
"description": "The line, oldest first: a label for each point (a year, a month, a day) and its value. Two to sixty."
},
"levels": {
"type": "array",
"items": {
"type": "object",
"properties": {
"label": {
"type": "string",
"maxLength": 24,
"title": "Label"
},
"value": {
"type": "number",
"title": "Value"
}
},
"required": [
"label",
"value"
],
"additionalProperties": false,
"title": "Level"
},
"maxItems": 3,
"title": "Reference levels",
"description": "Up to three levels drawn across the chart as dashed lines, each with its label and value, drawing across the moment the line first reaches it: a previous record, a target, an average."
},
"events": {
"type": "array",
"items": {
"type": "object",
"properties": {
"at": {
"type": "string",
"maxLength": 10,
"title": "At",
"description": "The label of the point it marks, exactly as written in the points."
},
"label": {
"type": "string",
"maxLength": 28,
"title": "What happened"
}
},
"required": [
"at",
"label"
],
"additionalProperties": false,
"title": "Event"
},
"maxItems": 4,
"title": "Events",
"description": "Up to four moments written on the line, each naming its point: the line pauses on the point as it reaches it and the event pops on there. Every event adds a second to the clip."
},
"source": {
"type": "string",
"maxLength": 60,
"title": "Source",
"description": "Where the values come from, or what they are where the source is not an official one."
},
"look": {
"type": "object",
"properties": {
"theme": {
"type": "string",
"enum": [
"auto",
"brand",
"light",
"dark",
"bold"
],
"title": "Theme",
"description": "The style's own choice; your brand's own colours and background; a light or dark page tinted with your brand colour; or your brand colour as the page.",
"enumNames": [
"The style's own",
"Brand colours",
"Light",
"Dark",
"Bold brand colour"
]
},
"pace": {
"type": "string",
"enum": [
"auto",
"calm",
"standard",
"punchy"
],
"title": "Pace",
"description": "How things arrive: the style's own rhythm, calm fades, a standard rhythm, or punchy slams and cuts.",
"enumNames": [
"The style's own",
"Calm",
"Standard",
"Punchy"
]
},
"corners": {
"type": "string",
"enum": [
"auto",
"square",
"soft",
"round"
],
"title": "Corners",
"description": "The shape of cards, panels and marks.",
"enumNames": [
"The style's own",
"Square",
"Softly rounded",
"Round"
]
},
"align": {
"type": "string",
"enum": [
"auto",
"start",
"centre"
],
"title": "Text alignment",
"description": "Where the text lines up.",
"enumNames": [
"The style's own",
"At the start of the line",
"Centred"
]
},
"logo": {
"type": "string",
"enum": [
"auto",
"free"
],
"title": "Logo",
"description": "The style's own: the logo on the style's plate (a card, a disc, a badge) so it reads on any page. As it is: the logo whole, with no plate, frame or crop, for a logo made to stand on the page, such as one with a transparent background. As it is, make sure your logo reads on the page of the theme you choose.",
"enumNames": [
"The style's own",
"As it is, no plate or crop"
]
}
},
"additionalProperties": false,
"title": "Look",
"description": "How the clip looks and moves within its style. The same five switches in every format of the collections. Leave a switch out, or set it to the style's own, and the style decides."
}
},
"additionalProperties": false,
"title": "Clip data",
"description": "Everything drawn: a kicker, what the line shows, the unit, the points of the line, the reference levels, the events written on it, the source and the look."
},
"metaData": {
"type": "object",
"properties": {
"title": {
"type": "string",
"maxLength": 100,
"title": "Title",
"description": "Used where the platform has a title of its own: Facebook Feed, LinkedIn, Pinterest and YouTube. Up to 100 characters, which every one of them takes."
},
"captionTiny": {
"type": "string",
"maxLength": 200,
"title": "Tiny description (Pinterest, Threads, X)",
"description": "Up to 200 characters. The brand's description, link and hashtags follow it within the platform's limit."
},
"captionShort": {
"type": "string",
"maxLength": 500,
"title": "Short description (Telegram, Threema, WeChat, WhatsApp)",
"description": "Up to 500 characters. The brand's description, link and hashtags follow it within the platform's limit."
},
"captionMedium": {
"type": "string",
"maxLength": 1500,
"title": "Medium description (Discord, Facebook Reels, Instagram, LinkedIn, Signal, Slack, TikTok)",
"description": "Up to 1500 characters. The brand's description, link and hashtags follow it within the platform's limit."
},
"captionLong": {
"type": "string",
"maxLength": 4000,
"title": "Long description (Facebook Feed, YouTube)",
"description": "Up to 4000 characters. The brand's description, link and hashtags follow it within the platform's limit."
},
"hashtags": {
"type": "array",
"items": {
"type": "string",
"maxLength": 60,
"title": "Hashtag"
},
"maxItems": 15,
"title": "Hashtags",
"description": "Written without the #. Up to 15, which every platform takes."
}
},
"additionalProperties": false,
"title": "Meta data",
"description": "Everything about the post that is never drawn in the clip: its title, its description in four lengths, one per kind of platform, and its hashtags. Reelwire adds the brand's description, link and hashtags after it. Left out, the post text is generated from the clip data."
}
},
"additionalProperties": false
},
"propertyNames": {
"enum": [
"aa",
"ab",
"ae",
"af",
"ak",
"am",
"an",
"ar",
"as",
"av",
"ay",
"az",
"ba",
"be",
"bg",
"bi",
"bm",
"bn",
"bo",
"br",
"bs",
"ca",
"ce",
"ch",
"co",
"cr",
"cs",
"cu",
"cv",
"cy",
"da",
"de",
"dv",
"dz",
"ee",
"el",
"en",
"eo",
"es",
"et",
"eu",
"fa",
"ff",
"fi",
"fj",
"fo",
"fr",
"fy",
"ga",
"gd",
"gl",
"gn",
"gu",
"gv",
"ha",
"he",
"hi",
"ho",
"hr",
"ht",
"hu",
"hy",
"hz",
"ia",
"id",
"ie",
"ig",
"ii",
"ik",
"io",
"is",
"it",
"iu",
"ja",
"jv",
"ka",
"kg",
"ki",
"kj",
"kk",
"kl",
"km",
"kn",
"ko",
"kr",
"ks",
"ku",
"kv",
"kw",
"ky",
"la",
"lb",
"lg",
"li",
"ln",
"lo",
"lt",
"lu",
"lv",
"mg",
"mh",
"mi",
"mk",
"ml",
"mn",
"mr",
"ms",
"mt",
"my",
"na",
"nb",
"nd",
"ne",
"ng",
"nl",
"nn",
"no",
"nr",
"nv",
"ny",
"oc",
"oj",
"om",
"or",
"os",
"pa",
"pi",
"pl",
"ps",
"pt",
"qu",
"rm",
"rn",
"ro",
"ru",
"rw",
"sa",
"sc",
"sd",
"se",
"sg",
"si",
"sk",
"sl",
"sm",
"sn",
"so",
"sq",
"sr",
"ss",
"st",
"su",
"sv",
"sw",
"ta",
"te",
"tg",
"th",
"ti",
"tk",
"tl",
"tn",
"to",
"tr",
"ts",
"tt",
"tw",
"ty",
"ug",
"uk",
"ur",
"uz",
"ve",
"vi",
"vo",
"wa",
"wo",
"xh",
"yi",
"yo",
"za",
"zh",
"zu",
"zh-CN",
"zh-TW",
"pt-BR"
]
}
}
},
"required": [
"clipData"
],
"additionalProperties": false,
"$schema": "http://json-schema.org/draft-07/schema#"
}

Ask Reelwire for the same document yourself, without signing in:

curl "http://localhost:4000/v1/formats/template/tpl_d9661b6f8d97?variant=Sketch%20notes&version=1.0.0"

Delivery JSON​

Your own system sends this to one of your streams, POST /v1/stream, and every channel listening to that stream draws it with its template. data is the document described above; a stream with an empty field map passes it to the template unchanged. Try it first on POST /v1/stream/validate, which answers the same without publishing anything. Streams and feeds explains the rest, including how to map a document of your own shape instead.

{
"streamId": "st_your_stream_id",
"eventId": "01M2SQMKK3G1NVFXV31DCBVB95",
"occurredAt": "2026-09-23T07:00:00Z",
"locale": "en",
"data": {
"clipData": {
"kicker": "Record close",
"title": "The Harbour 50 closes at a record 6,184 points, through four crashes since 1987",
"unit": "Index points, year end",
"points": [
{
"label": "1987",
"value": 312
},
{
"label": "1988",
"value": 348
},
{
"label": "1989",
"value": 402
},
{
"label": "1990",
"value": 371
},
{
"label": "1991",
"value": 455
},
{
"label": "1992",
"value": 478
},
{
"label": "1993",
"value": 541
},
{
"label": "1994",
"value": 528
},
{
"label": "1995",
"value": 690
},
{
"label": "1996",
"value": 842
},
{
"label": "1997",
"value": 1105
},
{
"label": "1998",
"value": 1398
},
{
"label": "1999",
"value": 2410
},
{
"label": "2000",
"value": 2190
},
{
"label": "2001",
"value": 1810
},
{
"label": "2002",
"value": 1302
},
{
"label": "2003",
"value": 1588
},
{
"label": "2004",
"value": 1702
},
{
"label": "2005",
"value": 1811
},
{
"label": "2006",
"value": 2064
},
{
"label": "2007",
"value": 2350
},
{
"label": "2008",
"value": 1386
},
{
"label": "2009",
"value": 1702
},
{
"label": "2010",
"value": 1924
},
{
"label": "2011",
"value": 1918
},
{
"label": "2012",
"value": 2185
},
{
"label": "2013",
"value": 2790
},
{
"label": "2014",
"value": 3112
},
{
"label": "2015",
"value": 3046
},
{
"label": "2016",
"value": 3310
},
{
"label": "2017",
"value": 3902
},
{
"label": "2018",
"value": 3610
},
{
"label": "2019",
"value": 4380
},
{
"label": "2020",
"value": 4710
},
{
"label": "2021",
"value": 5480
},
{
"label": "2022",
"value": 4620
},
{
"label": "2023",
"value": 5240
},
{
"label": "2024",
"value": 5810
},
{
"label": "2025",
"value": 5960
},
{
"label": "2026",
"value": 6184
}
],
"levels": [
{
"label": "Dot-com peak",
"value": 2410
},
{
"label": "Previous record",
"value": 5480
}
],
"events": [
{
"at": "1987",
"label": "Crash of 1987"
},
{
"at": "2002",
"label": "Dot-com bust bottoms out"
},
{
"at": "2008",
"label": "Financial crisis"
},
{
"at": "2022",
"label": "Rate shock"
}
],
"source": "Closing values on the last trading day of each year",
"look": {
"theme": "auto",
"pace": "auto",
"corners": "auto",
"align": "auto",
"logo": "auto"
}
},
"metaData": {
"title": "The Harbour 50 closes the year at a record 6,184 points",
"captionTiny": "The Harbour 50 closes at a record 6,184 points: twenty times its level after the crash of 1987, and through the dot-com bust, 2008 and the rate shock.",
"captionShort": "The Harbour 50 closes at a record 6,184 points, almost twenty times its level at the end of 1987. It took the index until 2007 to get back near its dot-com peak of 2,410, lost 41 percent in the financial crisis of 2008, and fell again in the rate shock of 2022. It passed its previous record of 5,480 in 2024.",
"captionMedium": "The Harbour 50 closes at a record 6,184 points, almost twenty times its level at the end of 1987. The way up was anything but smooth. The index peaked at 2,410 at the end of 1999, lost almost half of that by 2002 and only came close to it again in 2007. Then the financial crisis took 41 percent off it in a single year. It went on to set records through the 2010s, dropped by more than 15 percent in the rate shock of 2022, and passed its previous record of 5,480 in 2024. Anyone who bought at the dot-com peak has now seen their money multiply by about two and a half, before dividends.",
"captionLong": "The Harbour 50 closes at a record 6,184 points, almost twenty times its level at the end of 1987. The way up was anything but smooth. The index peaked at 2,410 at the end of 1999, lost almost half of that by 2002 and only came close to it again in 2007. Then the financial crisis took 41 percent off it in a single year. It went on to set records through the 2010s, dropped by more than 15 percent in the rate shock of 2022, and passed its previous record of 5,480 in 2024. Anyone who bought at the dot-com peak has now seen their money multiply by about two and a half, before dividends. The chart shows each year's closing value on the last trading day of the year, so falls and recoveries within a year do not show. The Harbour 50 tracks fifty of the largest listed companies, weighted by the value of their freely traded shares.",
"hashtags": [
"markets",
"stocks",
"harbour50",
"record",
"investing"
]
}
}
}

The delivery names no version: which build draws it is the channel's choice, the newest of its variant or the one it is pinned to. eventId is a ULID you make once per event: sending the same one again changes nothing. occurredAt is when the thing happened, not when you sent it. locale is the language of the text in data, and data.locales carries other languages beside it.