[{"data":1,"prerenderedAt":957},["ShallowReactive",2],{"\u002Fdocs\u002Fone-template-two-outputs":3},{"id":4,"title":5,"body":6,"category":947,"date":948,"description":949,"extension":950,"heroImage":951,"meta":952,"navigation":484,"path":953,"readingMinutes":185,"seo":954,"stem":955,"tool":947,"__hash__":956},"docs\u002Fdocs\u002Fone-template-two-outputs.md","One template, two outputs: still and video",{"type":7,"value":8,"toc":940},"minimark",[9,14,23,35,65,76,80,103,119,230,237,246,310,316,320,326,337,345,356,880,884,912,920,924,927,936],[10,11,13],"h2",{"id":12},"the-idea","The idea",[15,16,17,18,22],"p",{},"A Bluepic template is ",[19,20,21],"strong",{},"reactive",". Position, scale, opacity, colour, and text are expressions, not fixed values. That is what lets one template render a thousand on-brand images from your data.",[15,24,25,26,30,31,34],{},"Add one input, a ",[27,28,29],"code",{},"TIME"," clock, and those same expressions become an animation. So the template you already use for images is also a video template. You do not build a second thing. You change the ",[27,32,33],{},"format"," on the same request.",[36,37,38,56],"ul",{},[39,40,41,44,45,48,49,48,52,55],"li",{},[27,42,43],{},"format: \"png\""," (or ",[27,46,47],{},"jpeg",", ",[27,50,51],{},"pdf",[27,53,54],{},"svg",") gives you a still.",[39,57,58,44,61,64],{},[27,59,60],{},"format: \"mp4\"",[27,62,63],{},"mov",") gives you the animated clip.",[15,66,67,68,71,72,75],{},"Same ",[27,69,70],{},"templateId",", same ",[27,73,74],{},"data",". One design, two outputs.",[10,77,79],{"id":78},"try-it-with-no-key","Try it with no key",[15,81,82,83,86,87,91,92,95,96,48,99,102],{},"There is a public demo ",[19,84,85],{},"video"," template you can render with no API key and no credit cost. It is the same one on the ",[88,89,90],"a",{"href":90},"\u002Fvideo"," playground. Its inputs are a photo (",[27,93,94],{},"image4_image",") and two lines of text (",[27,97,98],{},"text2_text",[27,100,101],{},"text1_text",").",[15,104,105,106,109,110,112,113,115,116,118],{},"First, render a ",[19,107,108],{},"still",". An animated template is a function of ",[27,111,29],{},", so pick the frame you want by passing ",[27,114,29],{}," in ",[27,117,74],{}," (in seconds):",[120,121,126],"pre",{"className":122,"code":123,"language":124,"meta":125,"style":125},"language-bash shiki shiki-themes github-dark","curl -X POST \"https:\u002F\u002Fapi.bluepic.io\u002Fapi\u002Frender\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\n    \"templateId\": \"7ccf097c-10f2-4efc-bd03-8abe967c4711\",\n    \"data\": {\n      \"TIME\": 4,\n      \"text2_text\": \"HEAR ME SPEAK AT\",\n      \"text1_text\": \"THE BLUEPIC EVENT!\"\n    },\n    \"format\": \"png\"\n  }' \\\n  --output frame.png\n","bash","",[27,127,128,151,162,171,177,183,189,195,201,207,213,221],{"__ignoreMap":125},[129,130,133,137,141,145,148],"span",{"class":131,"line":132},"line",1,[129,134,136],{"class":135},"svObZ","curl",[129,138,140],{"class":139},"sDLfK"," -X",[129,142,144],{"class":143},"sU2Wk"," POST",[129,146,147],{"class":143}," \"https:\u002F\u002Fapi.bluepic.io\u002Fapi\u002Frender\"",[129,149,150],{"class":139}," \\\n",[129,152,154,157,160],{"class":131,"line":153},2,[129,155,156],{"class":139},"  -H",[129,158,159],{"class":143}," \"Content-Type: application\u002Fjson\"",[129,161,150],{"class":139},[129,163,165,168],{"class":131,"line":164},3,[129,166,167],{"class":139},"  -d",[129,169,170],{"class":143}," '{\n",[129,172,174],{"class":131,"line":173},4,[129,175,176],{"class":143},"    \"templateId\": \"7ccf097c-10f2-4efc-bd03-8abe967c4711\",\n",[129,178,180],{"class":131,"line":179},5,[129,181,182],{"class":143},"    \"data\": {\n",[129,184,186],{"class":131,"line":185},6,[129,187,188],{"class":143},"      \"TIME\": 4,\n",[129,190,192],{"class":131,"line":191},7,[129,193,194],{"class":143},"      \"text2_text\": \"HEAR ME SPEAK AT\",\n",[129,196,198],{"class":131,"line":197},8,[129,199,200],{"class":143},"      \"text1_text\": \"THE BLUEPIC EVENT!\"\n",[129,202,204],{"class":131,"line":203},9,[129,205,206],{"class":143},"    },\n",[129,208,210],{"class":131,"line":209},10,[129,211,212],{"class":143},"    \"format\": \"png\"\n",[129,214,216,219],{"class":131,"line":215},11,[129,217,218],{"class":143},"  }'",[129,220,150],{"class":139},[129,222,224,227],{"class":131,"line":223},12,[129,225,226],{"class":139},"  --output",[129,228,229],{"class":143}," frame.png\n",[15,231,232,233,236],{},"You get ",[27,234,235],{},"frame.png",", the design at the 4-second mark.",[15,238,239,240,242,243,245],{},"Now render the ",[19,241,85],{},". Same template, same data, ",[27,244,60],{},":",[120,247,249],{"className":122,"code":248,"language":124,"meta":125,"style":125},"curl -N -X POST \"https:\u002F\u002Fapi.bluepic.io\u002Fapi\u002Frender\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\n    \"templateId\": \"7ccf097c-10f2-4efc-bd03-8abe967c4711\",\n    \"data\": {\n      \"text2_text\": \"HEAR ME SPEAK AT\",\n      \"text1_text\": \"THE BLUEPIC EVENT!\"\n    },\n    \"format\": \"mp4\"\n  }'\n",[27,250,251,266,274,280,284,288,292,296,300,305],{"__ignoreMap":125},[129,252,253,255,258,260,262,264],{"class":131,"line":132},[129,254,136],{"class":135},[129,256,257],{"class":139}," -N",[129,259,140],{"class":139},[129,261,144],{"class":143},[129,263,147],{"class":143},[129,265,150],{"class":139},[129,267,268,270,272],{"class":131,"line":153},[129,269,156],{"class":139},[129,271,159],{"class":143},[129,273,150],{"class":139},[129,275,276,278],{"class":131,"line":164},[129,277,167],{"class":139},[129,279,170],{"class":143},[129,281,282],{"class":131,"line":173},[129,283,176],{"class":143},[129,285,286],{"class":131,"line":179},[129,287,182],{"class":143},[129,289,290],{"class":131,"line":185},[129,291,194],{"class":143},[129,293,294],{"class":131,"line":191},[129,295,200],{"class":143},[129,297,298],{"class":131,"line":197},[129,299,206],{"class":143},[129,301,302],{"class":131,"line":203},[129,303,304],{"class":143},"    \"format\": \"mp4\"\n",[129,306,307],{"class":131,"line":209},[129,308,309],{"class":143},"  }'\n",[15,311,312,313,315],{},"That is the whole point. Nothing changed but the ",[27,314,33],{},".",[10,317,319],{"id":318},"video-streams-stills-come-back-whole","Video streams; stills come back whole",[15,321,322,323,315],{},"A still is small, so the request returns the file bytes directly. That is why the PNG example uses ",[27,324,325],{},"--output",[15,327,328,329,332,333,336],{},"A video takes longer to render (frames first, then encode), so instead of making you wait blind, the request returns a ",[19,330,331],{},"Server-Sent Events"," stream. You get live progress events and, at the end, a hosted URL for the finished MP4. That is what ",[27,334,335],{},"-N"," does: it tells curl not to buffer, so the events arrive as they happen.",[120,338,343],{"className":339,"code":341,"language":342},[340],"language-text","data: {\"type\":\"init\",\"sessionId\":\"…\"}\ndata: {\"type\":\"keyframe\",\"frame\":48,\"totalFrames\":192}\ndata: {\"type\":\"encode_video\",\"frame\":140,\"totalFrames\":192}\ndata: {\"type\":\"end\",\"result\":\"https:\u002F\u002F…\u002Fresult.mp4\"}\n","text",[27,344,341],{"__ignoreMap":125},[15,346,347,348,351,352,355],{},"Read the stream until the ",[27,349,350],{},"end"," event and take its ",[27,353,354],{},"result",". That is your video's URL. In JavaScript:",[120,357,361],{"className":358,"code":359,"language":360,"meta":125,"style":125},"language-js shiki shiki-themes github-dark","const res = await fetch(\"https:\u002F\u002Fapi.bluepic.io\u002Fapi\u002Frender\", {\n  method: \"POST\",\n  headers: { Authorization: \"\u003Cyour API key>\", \"Content-Type\": \"application\u002Fjson\" },\n  body: JSON.stringify({\n    templateId: \"7ccf097c-10f2-4efc-bd03-8abe967c4711\",\n    data: { text1_text: \"THE BLUEPIC EVENT!\" },\n    format: \"mp4\",\n  }),\n});\n\nconst reader = res.body.getReader();\nconst decoder = new TextDecoder();\nlet buffer = \"\";\nlet url = \"\";\nfor (;;) {\n  const { value, done } = await reader.read();\n  if (value) buffer += decoder.decode(value, { stream: true });\n  let i;\n  while ((i = buffer.indexOf(\"\\n\\n\")) !== -1) {\n    const line = buffer.slice(0, i).split(\"\\n\").find((l) => l.startsWith(\"data:\"));\n    buffer = buffer.slice(i + 2);\n    if (!line) continue;\n    const evt = JSON.parse(line.slice(5).trim());\n    if (evt.type === \"end\") url = evt.result;\n    \u002F\u002F otherwise evt.frame \u002F evt.totalFrames drives a progress bar\n  }\n  if (done) break;\n}\n\u002F\u002F `url` is your rendered MP4\n","js",[27,362,363,391,402,424,440,450,460,470,475,480,486,504,521,539,553,562,594,621,630,672,740,764,784,820,842,849,855,868,874],{"__ignoreMap":125},[129,364,365,369,372,375,378,381,385,388],{"class":131,"line":132},[129,366,368],{"class":367},"snl16","const",[129,370,371],{"class":139}," res",[129,373,374],{"class":367}," =",[129,376,377],{"class":367}," await",[129,379,380],{"class":135}," fetch",[129,382,384],{"class":383},"s95oV","(",[129,386,387],{"class":143},"\"https:\u002F\u002Fapi.bluepic.io\u002Fapi\u002Frender\"",[129,389,390],{"class":383},", {\n",[129,392,393,396,399],{"class":131,"line":153},[129,394,395],{"class":383},"  method: ",[129,397,398],{"class":143},"\"POST\"",[129,400,401],{"class":383},",\n",[129,403,404,407,410,412,415,418,421],{"class":131,"line":164},[129,405,406],{"class":383},"  headers: { Authorization: ",[129,408,409],{"class":143},"\"\u003Cyour API key>\"",[129,411,48],{"class":383},[129,413,414],{"class":143},"\"Content-Type\"",[129,416,417],{"class":383},": ",[129,419,420],{"class":143},"\"application\u002Fjson\"",[129,422,423],{"class":383}," },\n",[129,425,426,429,432,434,437],{"class":131,"line":173},[129,427,428],{"class":383},"  body: ",[129,430,431],{"class":139},"JSON",[129,433,315],{"class":383},[129,435,436],{"class":135},"stringify",[129,438,439],{"class":383},"({\n",[129,441,442,445,448],{"class":131,"line":179},[129,443,444],{"class":383},"    templateId: ",[129,446,447],{"class":143},"\"7ccf097c-10f2-4efc-bd03-8abe967c4711\"",[129,449,401],{"class":383},[129,451,452,455,458],{"class":131,"line":185},[129,453,454],{"class":383},"    data: { text1_text: ",[129,456,457],{"class":143},"\"THE BLUEPIC EVENT!\"",[129,459,423],{"class":383},[129,461,462,465,468],{"class":131,"line":191},[129,463,464],{"class":383},"    format: ",[129,466,467],{"class":143},"\"mp4\"",[129,469,401],{"class":383},[129,471,472],{"class":131,"line":197},[129,473,474],{"class":383},"  }),\n",[129,476,477],{"class":131,"line":203},[129,478,479],{"class":383},"});\n",[129,481,482],{"class":131,"line":209},[129,483,485],{"emptyLinePlaceholder":484},true,"\n",[129,487,488,490,493,495,498,501],{"class":131,"line":215},[129,489,368],{"class":367},[129,491,492],{"class":139}," reader",[129,494,374],{"class":367},[129,496,497],{"class":383}," res.body.",[129,499,500],{"class":135},"getReader",[129,502,503],{"class":383},"();\n",[129,505,506,508,511,513,516,519],{"class":131,"line":223},[129,507,368],{"class":367},[129,509,510],{"class":139}," decoder",[129,512,374],{"class":367},[129,514,515],{"class":367}," new",[129,517,518],{"class":135}," TextDecoder",[129,520,503],{"class":383},[129,522,524,527,530,533,536],{"class":131,"line":523},13,[129,525,526],{"class":367},"let",[129,528,529],{"class":383}," buffer ",[129,531,532],{"class":367},"=",[129,534,535],{"class":143}," \"\"",[129,537,538],{"class":383},";\n",[129,540,542,544,547,549,551],{"class":131,"line":541},14,[129,543,526],{"class":367},[129,545,546],{"class":383}," url ",[129,548,532],{"class":367},[129,550,535],{"class":143},[129,552,538],{"class":383},[129,554,556,559],{"class":131,"line":555},15,[129,557,558],{"class":367},"for",[129,560,561],{"class":383}," (;;) {\n",[129,563,565,568,571,574,576,579,582,584,586,589,592],{"class":131,"line":564},16,[129,566,567],{"class":367},"  const",[129,569,570],{"class":383}," { ",[129,572,573],{"class":139},"value",[129,575,48],{"class":383},[129,577,578],{"class":139},"done",[129,580,581],{"class":383}," } ",[129,583,532],{"class":367},[129,585,377],{"class":367},[129,587,588],{"class":383}," reader.",[129,590,591],{"class":135},"read",[129,593,503],{"class":383},[129,595,597,600,603,606,609,612,615,618],{"class":131,"line":596},17,[129,598,599],{"class":367},"  if",[129,601,602],{"class":383}," (value) buffer ",[129,604,605],{"class":367},"+=",[129,607,608],{"class":383}," decoder.",[129,610,611],{"class":135},"decode",[129,613,614],{"class":383},"(value, { stream: ",[129,616,617],{"class":139},"true",[129,619,620],{"class":383}," });\n",[129,622,624,627],{"class":131,"line":623},18,[129,625,626],{"class":367},"  let",[129,628,629],{"class":383}," i;\n",[129,631,633,636,639,641,644,647,649,652,655,657,660,663,666,669],{"class":131,"line":632},19,[129,634,635],{"class":367},"  while",[129,637,638],{"class":383}," ((i ",[129,640,532],{"class":367},[129,642,643],{"class":383}," buffer.",[129,645,646],{"class":135},"indexOf",[129,648,384],{"class":383},[129,650,651],{"class":143},"\"",[129,653,654],{"class":139},"\\n\\n",[129,656,651],{"class":143},[129,658,659],{"class":383},")) ",[129,661,662],{"class":367},"!==",[129,664,665],{"class":367}," -",[129,667,668],{"class":139},"1",[129,670,671],{"class":383},") {\n",[129,673,675,678,681,683,685,688,690,693,696,699,701,703,706,708,710,713,716,720,723,726,729,732,734,737],{"class":131,"line":674},20,[129,676,677],{"class":367},"    const",[129,679,680],{"class":139}," line",[129,682,374],{"class":367},[129,684,643],{"class":383},[129,686,687],{"class":135},"slice",[129,689,384],{"class":383},[129,691,692],{"class":139},"0",[129,694,695],{"class":383},", i).",[129,697,698],{"class":135},"split",[129,700,384],{"class":383},[129,702,651],{"class":143},[129,704,705],{"class":139},"\\n",[129,707,651],{"class":143},[129,709,102],{"class":383},[129,711,712],{"class":135},"find",[129,714,715],{"class":383},"((",[129,717,719],{"class":718},"s9osk","l",[129,721,722],{"class":383},") ",[129,724,725],{"class":367},"=>",[129,727,728],{"class":383}," l.",[129,730,731],{"class":135},"startsWith",[129,733,384],{"class":383},[129,735,736],{"class":143},"\"data:\"",[129,738,739],{"class":383},"));\n",[129,741,743,746,748,750,752,755,758,761],{"class":131,"line":742},21,[129,744,745],{"class":383},"    buffer ",[129,747,532],{"class":367},[129,749,643],{"class":383},[129,751,687],{"class":135},[129,753,754],{"class":383},"(i ",[129,756,757],{"class":367},"+",[129,759,760],{"class":139}," 2",[129,762,763],{"class":383},");\n",[129,765,767,770,773,776,779,782],{"class":131,"line":766},22,[129,768,769],{"class":367},"    if",[129,771,772],{"class":383}," (",[129,774,775],{"class":367},"!",[129,777,778],{"class":383},"line) ",[129,780,781],{"class":367},"continue",[129,783,538],{"class":383},[129,785,787,789,792,794,797,799,802,805,807,809,812,814,817],{"class":131,"line":786},23,[129,788,677],{"class":367},[129,790,791],{"class":139}," evt",[129,793,374],{"class":367},[129,795,796],{"class":139}," JSON",[129,798,315],{"class":383},[129,800,801],{"class":135},"parse",[129,803,804],{"class":383},"(line.",[129,806,687],{"class":135},[129,808,384],{"class":383},[129,810,811],{"class":139},"5",[129,813,102],{"class":383},[129,815,816],{"class":135},"trim",[129,818,819],{"class":383},"());\n",[129,821,823,825,828,831,834,837,839],{"class":131,"line":822},24,[129,824,769],{"class":367},[129,826,827],{"class":383}," (evt.type ",[129,829,830],{"class":367},"===",[129,832,833],{"class":143}," \"end\"",[129,835,836],{"class":383},") url ",[129,838,532],{"class":367},[129,840,841],{"class":383}," evt.result;\n",[129,843,845],{"class":131,"line":844},25,[129,846,848],{"class":847},"sAwPA","    \u002F\u002F otherwise evt.frame \u002F evt.totalFrames drives a progress bar\n",[129,850,852],{"class":131,"line":851},26,[129,853,854],{"class":383},"  }\n",[129,856,858,860,863,866],{"class":131,"line":857},27,[129,859,599],{"class":367},[129,861,862],{"class":383}," (done) ",[129,864,865],{"class":367},"break",[129,867,538],{"class":383},[129,869,871],{"class":131,"line":870},28,[129,872,873],{"class":383},"}\n",[129,875,877],{"class":131,"line":876},29,[129,878,879],{"class":847},"\u002F\u002F `url` is your rendered MP4\n",[10,881,883],{"id":882},"on-your-own-templates","On your own templates",[15,885,886,887,891,892,895,896,899,900,902,903,907,908,911],{},"To render one of your own templates, add your API key (issue one on the ",[88,888,890],{"href":889},"\u002Fidml\u002Faccount","account page"," and pass it as a raw ",[27,893,894],{},"Authorization"," header, with no ",[27,897,898],{},"Bearer"," prefix) and use its ",[27,901,70],{},". Any template you built in ",[88,904,906],{"href":905},"\u002Fdocs\u002Fbuilding-templates-in-bluepic-studio","Bluepic Studio"," with an ",[27,909,910],{},"animation"," (a duration and a frame rate) renders as video. Every other template renders as a still.",[15,913,914,915,919],{},"Metering is simple. A still costs 1 credit; a video is metered by length and resolution (1 credit per second of 2K at 24fps, see ",[88,916,918],{"href":917},"\u002Fdocs\u002Fvideo-credits","how video credits work","). The two public demo templates (this one and the image demo) are free and unmetered.",[10,921,923],{"id":922},"why-this-matters","Why this matters",[15,925,926],{},"Personalized video is normally a separate, expensive pipeline: a video editor, a timeline API, or a render farm you operate. Here it is the template you already have and the request you already make, with one field changed. Change the data, get a fresh clip. One per recipient, product, city, or language.",[15,928,929,930,115,932,315],{},"Next, read how any property animates as a function of ",[27,931,29],{},[88,933,935],{"href":934},"\u002Fdocs\u002Fexpression-engine-over-time","the expression engine",[937,938,939],"style",{},"html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .s9osk, html code.shiki .s9osk{--shiki-default:#FFAB70}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}",{"title":125,"searchDepth":153,"depth":153,"links":941},[942,943,944,945,946],{"id":12,"depth":153,"text":13},{"id":78,"depth":153,"text":79},{"id":318,"depth":153,"text":319},{"id":882,"depth":153,"text":883},{"id":922,"depth":153,"text":923},"platform","2026-07-25","The same Bluepic template renders a PNG or an animated MP4. Change one thing, the format, and the same design becomes a personalized video. No second tool, no separate video template.","md","\u002Fdocs-images\u002Fone-template-two-outputs.svg",{},"\u002Fdocs\u002Fone-template-two-outputs",{"title":5,"description":949},"docs\u002Fone-template-two-outputs","QXKN2F5Ma6tZMrbeUdictR2dWtCzPblUFwIEq3kVE-M",1785414150476]