[{"data":1,"prerenderedAt":3373},["ShallowReactive",2],{"docs-index":3},[4,956,1360,1869,2125,2564,2721,2889],{"id":5,"title":6,"body":7,"category":945,"date":946,"description":947,"extension":948,"heroImage":949,"meta":950,"navigation":951,"path":952,"readingMinutes":244,"seo":953,"stem":954,"tool":945,"__hash__":955},"docs\u002Fdocs\u002Fapi-reference.md","API reference",{"type":8,"value":9,"toc":935},"minimark",[10,15,26,36,40,43,118,126,132,143,147,153,161,259,412,423,552,556,562,569,575,582,673,682,686,692,787,794,797,820,824,900,904,931],[11,12,14],"h2",{"id":13},"base-url","Base URL",[16,17,22],"pre",{"className":18,"code":20,"language":21},[19],"language-text","https:\u002F\u002Fapi.bluepic.io\n","text",[23,24,20],"code",{"__ignoreMap":25},"",[27,28,29,30,35],"p",{},"Every path below is relative to that. There's no staging\u002Fsandbox host — the same API key works everywhere, and the free monthly credits (see ",[31,32,34],"a",{"href":33},"#credits","Credits",") are the only thing separating experimentation from production traffic.",[11,37,39],{"id":38},"authentication","Authentication",[27,41,42],{},"There are two different credentials in play, and mixing them up is the most common integration mistake:",[44,45,46,61],"table",{},[47,48,49],"thead",{},[50,51,52,55,58],"tr",{},[53,54],"th",{},[53,56,57],{},"Used for",[53,59,60],{},"Header",[62,63,64,97],"tbody",{},[50,65,66,73,83],{},[67,68,69],"td",{},[70,71,72],"strong",{},"API key",[67,74,75,78,79,82],{},[23,76,77],{},"POST \u002Fapi\u002Frender",", ",[23,80,81],{},"POST \u002Fapi\u002Fidml\u002Frender"," — the endpoints your backend calls",[67,84,85,88,89,92,93,96],{},[23,86,87],{},"Authorization: \u003Ckey>"," — ",[70,90,91],{},"no"," ",[23,94,95],{},"Bearer "," prefix",[50,98,99,104,113],{},[67,100,101],{},[70,102,103],{},"Studio session token",[67,105,106,78,109,112],{},[23,107,108],{},"\u002Fapi\u002Fapi-keys",[23,110,111],{},"GET \u002Fapi\u002Fidml\u002Fme"," — managing keys and checking balance from your own account",[67,114,115],{},[23,116,117],{},"Authorization: Bearer \u003Ctoken>",[27,119,120,121,125],{},"For almost every integration, you only need the first row. Grab your key once from the ",[31,122,124],{"href":123},"\u002Fidml\u002Faccount","account page"," — it's created for you on first visit — and treat it like any other server-side secret: never ship it to a browser or mobile client.",[16,127,130],{"className":128,"code":129,"language":21},[19],"POST https:\u002F\u002Fapi.bluepic.io\u002Fapi\u002Frender\nAuthorization: bpk_xxxxxxxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n",[23,131,129],{"__ignoreMap":25},[27,133,134,135,137,138,142],{},"A key that starts with ",[23,136,95],{}," is rejected — that prefix is reserved for the session-token routes above, which authenticate ",[139,140,141],"em",{},"you",", not your backend.",[11,144,146],{"id":145},"render-a-studio-template","Render a Studio template",[16,148,151],{"className":149,"code":150,"language":21},[19],"POST \u002Fapi\u002Frender\n",[23,152,150],{"__ignoreMap":25},[27,154,155,156,160],{},"This is the endpoint for templates you built visually in ",[31,157,159],{"href":158},"\u002Fdocs\u002Fbuilding-templates-in-bluepic-studio","Bluepic Studio",". You send the template's ID and the field values to fill in; Bluepic renders it server-side and hands back the image.",[16,162,166],{"className":163,"code":164,"language":165,"meta":25,"style":25},"language-json shiki shiki-themes github-dark","{\n  \"templateId\": \"efa8ff2c-262b-4488-b8cf-e01521c6fbb5\",\n  \"data\": {\n    \"headline_text_content\": \"Ship it Friday\",\n    \"avatar_image\": { \"src\": \"https:\u002F\u002Fcdn.example.com\u002Favatar.jpg\" }\n  },\n  \"format\": \"png\"\n}\n","json",[23,167,168,177,194,203,216,236,242,253],{"__ignoreMap":25},[169,170,173],"span",{"class":171,"line":172},"line",1,[169,174,176],{"class":175},"s95oV","{\n",[169,178,180,184,187,191],{"class":171,"line":179},2,[169,181,183],{"class":182},"sDLfK","  \"templateId\"",[169,185,186],{"class":175},": ",[169,188,190],{"class":189},"sU2Wk","\"efa8ff2c-262b-4488-b8cf-e01521c6fbb5\"",[169,192,193],{"class":175},",\n",[169,195,197,200],{"class":171,"line":196},3,[169,198,199],{"class":182},"  \"data\"",[169,201,202],{"class":175},": {\n",[169,204,206,209,211,214],{"class":171,"line":205},4,[169,207,208],{"class":182},"    \"headline_text_content\"",[169,210,186],{"class":175},[169,212,213],{"class":189},"\"Ship it Friday\"",[169,215,193],{"class":175},[169,217,219,222,225,228,230,233],{"class":171,"line":218},5,[169,220,221],{"class":182},"    \"avatar_image\"",[169,223,224],{"class":175},": { ",[169,226,227],{"class":182},"\"src\"",[169,229,186],{"class":175},[169,231,232],{"class":189},"\"https:\u002F\u002Fcdn.example.com\u002Favatar.jpg\"",[169,234,235],{"class":175}," }\n",[169,237,239],{"class":171,"line":238},6,[169,240,241],{"class":175},"  },\n",[169,243,245,248,250],{"class":171,"line":244},7,[169,246,247],{"class":182},"  \"format\"",[169,249,186],{"class":175},[169,251,252],{"class":189},"\"png\"\n",[169,254,256],{"class":171,"line":255},8,[169,257,258],{"class":175},"}\n",[44,260,261,277],{},[47,262,263],{},[50,264,265,268,271,274],{},[53,266,267],{},"Field",[53,269,270],{},"Type",[53,272,273],{},"Default",[53,275,276],{},"Notes",[62,278,279,295,313,347,374,394],{},[50,280,281,286,289,292],{},[67,282,283],{},[23,284,285],{},"templateId",[67,287,288],{},"string",[67,290,291],{},"— required",[67,293,294],{},"The UUID from the template's editor URL. Must belong to your account.",[50,296,297,302,305,310],{},[67,298,299],{},[23,300,301],{},"data",[67,303,304],{},"object",[67,306,307],{},[23,308,309],{},"{}",[67,311,312],{},"Keys are the input-field names you defined in Studio. Anything you omit keeps its design-time default.",[50,314,315,320,341,345],{},[67,316,317],{},[23,318,319],{},"format",[67,321,322,325,326,325,329,325,332,325,335,325,338],{},[23,323,324],{},"png"," | ",[23,327,328],{},"jpeg",[23,330,331],{},"pdf",[23,333,334],{},"svg",[23,336,337],{},"webp",[23,339,340],{},"gif",[67,342,343],{},[23,344,324],{},[67,346],{},[50,348,349,354,362,366],{},[67,350,351],{},[23,352,353],{},"engine",[67,355,356,325,359],{},[23,357,358],{},"puppeteer",[23,360,361],{},"resvg",[67,363,364],{},[23,365,358],{},[67,367,368,369,373],{},"See ",[31,370,372],{"href":371},"\u002Fdocs\u002Fautomate-indesign-projects#engine-fidelity-vs-throughput","engine trade-offs"," — same choice applies here.",[50,375,376,385,388,391],{},[67,377,378,381,382],{},[23,379,380],{},"width"," \u002F ",[23,383,384],{},"height",[67,386,387],{},"number",[67,389,390],{},"template size",[67,392,393],{},"Override the rendered pixel size.",[50,395,396,404,406,409],{},[67,397,398,381,401],{},[23,399,400],{},"dpi",[23,402,403],{},"quality",[67,405,387],{},[67,407,408],{},"—",[67,410,411],{},"Resolution and compression, where the format supports them.",[27,413,414,415,418,419,422],{},"Response is the rendered file's raw bytes with a matching ",[23,416,417],{},"Content-Type"," — no wrapper JSON, no polling. Fetch it, save it, or pipe it straight into an ",[23,420,421],{},"\u003Cimg>"," or email attachment.",[16,424,428],{"className":425,"code":426,"language":427,"meta":25,"style":25},"language-js shiki shiki-themes github-dark","const res = await fetch('https:\u002F\u002Fapi.bluepic.io\u002Fapi\u002Frender', {\n  method: 'POST',\n  headers: { Authorization: apiKey, 'Content-Type': 'application\u002Fjson' },\n  body: JSON.stringify({\n    templateId: 'efa8ff2c-262b-4488-b8cf-e01521c6fbb5',\n    data: { headline_text_content: 'Ship it Friday' },\n  }),\n});\nconst png = await res.blob();\n","js",[23,429,430,458,468,484,501,511,521,526,531],{"__ignoreMap":25},[169,431,432,436,439,442,445,449,452,455],{"class":171,"line":172},[169,433,435],{"class":434},"snl16","const",[169,437,438],{"class":182}," res",[169,440,441],{"class":434}," =",[169,443,444],{"class":434}," await",[169,446,448],{"class":447},"svObZ"," fetch",[169,450,451],{"class":175},"(",[169,453,454],{"class":189},"'https:\u002F\u002Fapi.bluepic.io\u002Fapi\u002Frender'",[169,456,457],{"class":175},", {\n",[169,459,460,463,466],{"class":171,"line":179},[169,461,462],{"class":175},"  method: ",[169,464,465],{"class":189},"'POST'",[169,467,193],{"class":175},[169,469,470,473,476,478,481],{"class":171,"line":196},[169,471,472],{"class":175},"  headers: { Authorization: apiKey, ",[169,474,475],{"class":189},"'Content-Type'",[169,477,186],{"class":175},[169,479,480],{"class":189},"'application\u002Fjson'",[169,482,483],{"class":175}," },\n",[169,485,486,489,492,495,498],{"class":171,"line":205},[169,487,488],{"class":175},"  body: ",[169,490,491],{"class":182},"JSON",[169,493,494],{"class":175},".",[169,496,497],{"class":447},"stringify",[169,499,500],{"class":175},"({\n",[169,502,503,506,509],{"class":171,"line":218},[169,504,505],{"class":175},"    templateId: ",[169,507,508],{"class":189},"'efa8ff2c-262b-4488-b8cf-e01521c6fbb5'",[169,510,193],{"class":175},[169,512,513,516,519],{"class":171,"line":238},[169,514,515],{"class":175},"    data: { headline_text_content: ",[169,517,518],{"class":189},"'Ship it Friday'",[169,520,483],{"class":175},[169,522,523],{"class":171,"line":244},[169,524,525],{"class":175},"  }),\n",[169,527,528],{"class":171,"line":255},[169,529,530],{"class":175},"});\n",[169,532,534,536,539,541,543,546,549],{"class":171,"line":533},9,[169,535,435],{"class":434},[169,537,538],{"class":182}," png",[169,540,441],{"class":434},[169,542,444],{"class":434},[169,544,545],{"class":175}," res.",[169,547,548],{"class":447},"blob",[169,550,551],{"class":175},"();\n",[11,553,555],{"id":554},"render-a-raw-idml-file","Render a raw IDML file",[16,557,560],{"className":558,"code":559,"language":21},[19],"POST \u002Fapi\u002Fidml\u002Frender\nContent-Type: multipart\u002Fform-data\n",[23,561,559],{"__ignoreMap":25},[27,563,564,565,568],{},"Use this when your source of truth is an InDesign file rather than a Studio template — no upload step, no template to manage, just the ",[23,566,567],{},".idml"," export and whatever assets it links to, on every request.",[16,570,573],{"className":571,"code":572,"language":21},[19],"idml=@certificate.idml\nassets=@seal.png\nassets=@Signature-Font.ttf\n",[23,574,572],{"__ignoreMap":25},[27,576,577,578,581],{},"Assets are matched back to the document ",[70,579,580],{},"by filename",". Options go as query params:",[44,583,584,594],{},[47,585,586],{},[50,587,588,591],{},[53,589,590],{},"Param",[53,592,593],{},"What it does",[62,595,596,613,629,643,654],{},[50,597,598,602],{},[67,599,600],{},[23,601,319],{},[67,603,604,78,606,78,608,610,611],{},[23,605,324],{},[23,607,328],{},[23,609,331],{}," or ",[23,612,334],{},[50,614,615,620],{},[67,616,617],{},[23,618,619],{},"pages",[67,621,622,625,626],{},[23,623,624],{},"all",", or a 1-based list like ",[23,627,628],{},"1,3,5",[50,630,631,635],{},[67,632,633],{},[23,634,353],{},[67,636,637,639,640,642],{},[23,638,358],{}," (default, full fidelity) or ",[23,641,361],{}," (faster raster, no Chromium)",[50,644,645,651],{},[67,646,647,381,649],{},[23,648,400],{},[23,650,403],{},[67,652,653],{},"Output resolution \u002F compression",[50,655,656,661],{},[67,657,658],{},[23,659,660],{},"textOverrides",[67,662,663,664,667,668,672],{},"JSON ",[23,665,666],{},"{\"\u003CpageIndex>:\u003CelementId>\": \"value\"}"," — see ",[31,669,671],{"href":670},"\u002Fdocs\u002Fautomate-indesign-projects","Automate InDesign projects"," for the full walkthrough",[27,674,675,676,679,680,494],{},"Multiple pages come back as one merged PDF (",[23,677,678],{},"format=pdf",") or a zip (everything else) — same one-request, one-response shape as the Studio endpoint. Full detail, including a complete pipeline example, is in ",[31,681,671],{"href":670},[11,683,685],{"id":684},"check-your-balance","Check your balance",[16,687,690],{"className":688,"code":689,"language":21},[19],"GET \u002Fapi\u002Fidml\u002Fme\nAuthorization: Bearer \u003Cstudio session token>\n",[23,691,689],{"__ignoreMap":25},[16,693,695],{"className":163,"code":694,"language":165,"meta":25,"style":25},"{\n  \"plan\": \"free\",\n  \"monthlyCredits\": 100,\n  \"period\": \"2026-07\",\n  \"used\": 34,\n  \"remaining\": 66,\n  \"resetsAt\": \"2026-08-01T00:00:00.000Z\",\n  \"upgradeUrl\": \"https:\u002F\u002Fbluepic.io\u002Fpricing\"\n}\n",[23,696,697,701,713,725,737,749,761,773,783],{"__ignoreMap":25},[169,698,699],{"class":171,"line":172},[169,700,176],{"class":175},[169,702,703,706,708,711],{"class":171,"line":179},[169,704,705],{"class":182},"  \"plan\"",[169,707,186],{"class":175},[169,709,710],{"class":189},"\"free\"",[169,712,193],{"class":175},[169,714,715,718,720,723],{"class":171,"line":196},[169,716,717],{"class":182},"  \"monthlyCredits\"",[169,719,186],{"class":175},[169,721,722],{"class":182},"100",[169,724,193],{"class":175},[169,726,727,730,732,735],{"class":171,"line":205},[169,728,729],{"class":182},"  \"period\"",[169,731,186],{"class":175},[169,733,734],{"class":189},"\"2026-07\"",[169,736,193],{"class":175},[169,738,739,742,744,747],{"class":171,"line":218},[169,740,741],{"class":182},"  \"used\"",[169,743,186],{"class":175},[169,745,746],{"class":182},"34",[169,748,193],{"class":175},[169,750,751,754,756,759],{"class":171,"line":238},[169,752,753],{"class":182},"  \"remaining\"",[169,755,186],{"class":175},[169,757,758],{"class":182},"66",[169,760,193],{"class":175},[169,762,763,766,768,771],{"class":171,"line":244},[169,764,765],{"class":182},"  \"resetsAt\"",[169,767,186],{"class":175},[169,769,770],{"class":189},"\"2026-08-01T00:00:00.000Z\"",[169,772,193],{"class":175},[169,774,775,778,780],{"class":171,"line":255},[169,776,777],{"class":182},"  \"upgradeUrl\"",[169,779,186],{"class":175},[169,781,782],{"class":189},"\"https:\u002F\u002Fbluepic.io\u002Fpricing\"\n",[169,784,785],{"class":171,"line":533},[169,786,258],{"class":175},[27,788,789,790,793],{},"This one uses your session token, not your API key — it's meant for your own dashboard or a build script running as you, not for a server checking on behalf of end users. Despite the ",[23,791,792],{},"\u002Fidml\u002F"," in the path, it covers both render endpoints — 1 credit is 1 rendered page, regardless of which one produced it.",[11,795,34],{"id":796},"credits",[27,798,799,800,803,804,807,808,811,812,815,816,819],{},"Every account gets ",[70,801,802],{},"100 free credits a month",", shared across ",[23,805,806],{},"\u002Fapi\u002Frender"," and ",[23,809,810],{},"\u002Fapi\u002Fidml\u002Frender",". A render that produces multiple pages costs one credit per page. Once you're out, both endpoints return ",[23,813,814],{},"402"," until the next monthly reset (see ",[23,817,818],{},"resetsAt"," above) or an upgrade.",[11,821,823],{"id":822},"errors","Errors",[44,825,826,836],{},[47,827,828],{},[50,829,830,833],{},[53,831,832],{},"Status",[53,834,835],{},"Meaning",[62,837,838,848,862,874,886],{},[50,839,840,845],{},[67,841,842],{},[23,843,844],{},"400",[67,846,847],{},"Malformed request — check the field against the tables above.",[50,849,850,855],{},[67,851,852],{},[23,853,854],{},"401",[67,856,857,858,861],{},"Missing or invalid ",[23,859,860],{},"Authorization"," header.",[50,863,864,868],{},[67,865,866],{},[23,867,814],{},[67,869,870,871,494],{},"Out of credits this period. Body includes ",[23,872,873],{},"upgradeUrl",[50,875,876,881],{},[67,877,878],{},[23,879,880],{},"404",[67,882,883,885],{},[23,884,285],{}," doesn't exist, or isn't owned by your account.",[50,887,888,893],{},[67,889,890],{},[23,891,892],{},"500",[67,894,895,896,899],{},"Render failed server-side. Body includes ",[23,897,898],{},"details"," — worth attaching to a support request.",[11,901,903],{"id":902},"next-steps","Next steps",[905,906,907,916,924],"ul",{},[908,909,910,913,914,494],"li",{},[31,911,912],{"href":158},"Build a template visually in Bluepic Studio",", then drive it with ",[23,915,806],{},[908,917,918,920,921,923],{},[31,919,671],{"href":670}," for the full ",[23,922,810],{}," walkthrough, including a batch-pipeline example.",[908,925,926,927,494],{},"Try requests live, with your own key, in the ",[31,928,930],{"href":929},"\u002Fidml\u002Fapi","interactive playground",[932,933,934],"style",{},"html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}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 .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}",{"title":25,"searchDepth":179,"depth":179,"links":936},[937,938,939,940,941,942,943,944],{"id":13,"depth":179,"text":14},{"id":38,"depth":179,"text":39},{"id":145,"depth":179,"text":146},{"id":554,"depth":179,"text":555},{"id":684,"depth":179,"text":685},{"id":796,"depth":179,"text":34},{"id":822,"depth":179,"text":823},{"id":902,"depth":179,"text":903},"platform","2026-07-16","Every endpoint in the Bluepic developer API — authentication, rendering a Studio template, rendering a raw IDML file, checking your credit balance, and the errors you'll actually hit.","md","\u002Fdocs-images\u002Fapi-reference.svg",{},true,"\u002Fdocs\u002Fapi-reference",{"title":6,"description":947},"docs\u002Fapi-reference","L-oE8LxWLSXAhpqtO9gGFel4RvIfCzSB-mpWlWPID6I",{"id":957,"title":958,"body":959,"category":1351,"date":946,"description":1352,"extension":948,"heroImage":1353,"meta":1354,"navigation":951,"path":1355,"readingMinutes":238,"seo":1356,"stem":1357,"tool":1358,"__hash__":1359},"docs\u002Fdocs\u002Fautomate-figma-photoshop-canva-illustrator.md","Automate Figma, Photoshop, Canva & Illustrator graphics",{"type":8,"value":960,"toc":1343},[961,965,968,971,975,981,994,1001,1006,1266,1269,1273,1280,1284,1294,1296,1303,1305,1340],[11,962,964],{"id":963},"the-problem","The problem",[27,966,967],{},"You designed a social post in Canva, a banner in Figma, a product shot in Photoshop, an icon set in Illustrator. Now marketing wants fifty versions with different names, fifty different sizes, or a weekly refresh with new numbers — and none of those tools are built to be called from a script. Someone opens the app and does it by hand, every time.",[27,969,970],{},"Bluepic's IDML API is a plain HTTP endpoint built for exactly this: render a template with different field values, at scale, from your own automation. It doesn't speak Figma's or Canva's file formats directly — but a thin InDesign wrapper around your existing artwork (five minutes to set up, once) turns any of them into an automatable pipeline.",[11,972,974],{"id":973},"the-pattern","The pattern",[27,976,977,980],{},[70,978,979],{},"1. Export your artwork."," From Figma or Canva, export PNG, JPG or PDF. From Photoshop or Illustrator, keep the native PSD\u002FAI or export flattened — either works. PDF is the simplest universal choice if you're unsure.",[27,982,983,92,986,989,990,993],{},[70,984,985],{},"2. Wrap it in InDesign, once.",[23,987,988],{},"File → Place"," the exported artwork into an InDesign document, add the text frames (or other elements) you want to control programmatically — a name, a price, a date, a location — then ",[23,991,992],{},"File → Export → InDesign Markup (IDML)",". This file is your reusable template from now on.",[27,995,996,997,494],{},"Draw each of those frames with headroom for your longest real value (a long store name, a long price string) — the frame's size is a hard ceiling for anything you substitute in later, not just a starting point. See ",[31,998,1000],{"href":999},"\u002Fdocs\u002Ftext-frames-and-best-practices","Text frames, bounds & best practices",[27,1002,1003],{},[70,1004,1005],{},"3. Render it from code.",[16,1007,1009],{"className":425,"code":1008,"language":427,"meta":25,"style":25},"const variants = await getVariantsFromYourData(); \u002F\u002F e.g. 50 store locations, 50 SKUs, 50 event dates\n\nfor (const variant of variants) {\n  const textOverrides = {\n    '0:TextFrame_headline': variant.title,\n    '0:TextFrame_price': variant.price,\n  };\n\n  const form = new FormData();\n  form.append('idml', bannerIdml);\n  form.append('assets', backgroundArt, 'background.pdf'); \u002F\u002F your Figma\u002FPhotoshop\u002FCanva\u002FIllustrator export\n\n  const res = await fetch(\n    `https:\u002F\u002Fapi.bluepic.io\u002Fapi\u002Fidml\u002Frender?format=png&textOverrides=${encodeURIComponent(JSON.stringify(textOverrides))}`,\n    { method: 'POST', headers: { Authorization: apiKey }, body: form },\n  );\n\n  await saveFile(`banner-${variant.id}.png`, await res.blob());\n}\n",[23,1010,1011,1032,1037,1056,1069,1077,1085,1090,1094,1111,1128,1152,1157,1173,1202,1213,1219,1224,1261],{"__ignoreMap":25},[169,1012,1013,1015,1018,1020,1022,1025,1028],{"class":171,"line":172},[169,1014,435],{"class":434},[169,1016,1017],{"class":182}," variants",[169,1019,441],{"class":434},[169,1021,444],{"class":434},[169,1023,1024],{"class":447}," getVariantsFromYourData",[169,1026,1027],{"class":175},"(); ",[169,1029,1031],{"class":1030},"sAwPA","\u002F\u002F e.g. 50 store locations, 50 SKUs, 50 event dates\n",[169,1033,1034],{"class":171,"line":179},[169,1035,1036],{"emptyLinePlaceholder":951},"\n",[169,1038,1039,1042,1045,1047,1050,1053],{"class":171,"line":196},[169,1040,1041],{"class":434},"for",[169,1043,1044],{"class":175}," (",[169,1046,435],{"class":434},[169,1048,1049],{"class":182}," variant",[169,1051,1052],{"class":434}," of",[169,1054,1055],{"class":175}," variants) {\n",[169,1057,1058,1061,1064,1066],{"class":171,"line":205},[169,1059,1060],{"class":434},"  const",[169,1062,1063],{"class":182}," textOverrides",[169,1065,441],{"class":434},[169,1067,1068],{"class":175}," {\n",[169,1070,1071,1074],{"class":171,"line":218},[169,1072,1073],{"class":189},"    '0:TextFrame_headline'",[169,1075,1076],{"class":175},": variant.title,\n",[169,1078,1079,1082],{"class":171,"line":238},[169,1080,1081],{"class":189},"    '0:TextFrame_price'",[169,1083,1084],{"class":175},": variant.price,\n",[169,1086,1087],{"class":171,"line":244},[169,1088,1089],{"class":175},"  };\n",[169,1091,1092],{"class":171,"line":255},[169,1093,1036],{"emptyLinePlaceholder":951},[169,1095,1096,1098,1101,1103,1106,1109],{"class":171,"line":533},[169,1097,1060],{"class":434},[169,1099,1100],{"class":182}," form",[169,1102,441],{"class":434},[169,1104,1105],{"class":434}," new",[169,1107,1108],{"class":447}," FormData",[169,1110,551],{"class":175},[169,1112,1114,1117,1120,1122,1125],{"class":171,"line":1113},10,[169,1115,1116],{"class":175},"  form.",[169,1118,1119],{"class":447},"append",[169,1121,451],{"class":175},[169,1123,1124],{"class":189},"'idml'",[169,1126,1127],{"class":175},", bannerIdml);\n",[169,1129,1131,1133,1135,1137,1140,1143,1146,1149],{"class":171,"line":1130},11,[169,1132,1116],{"class":175},[169,1134,1119],{"class":447},[169,1136,451],{"class":175},[169,1138,1139],{"class":189},"'assets'",[169,1141,1142],{"class":175},", backgroundArt, ",[169,1144,1145],{"class":189},"'background.pdf'",[169,1147,1148],{"class":175},"); ",[169,1150,1151],{"class":1030},"\u002F\u002F your Figma\u002FPhotoshop\u002FCanva\u002FIllustrator export\n",[169,1153,1155],{"class":171,"line":1154},12,[169,1156,1036],{"emptyLinePlaceholder":951},[169,1158,1160,1162,1164,1166,1168,1170],{"class":171,"line":1159},13,[169,1161,1060],{"class":434},[169,1163,438],{"class":182},[169,1165,441],{"class":434},[169,1167,444],{"class":434},[169,1169,448],{"class":447},[169,1171,1172],{"class":175},"(\n",[169,1174,1176,1179,1182,1184,1186,1188,1190,1192,1194,1197,1200],{"class":171,"line":1175},14,[169,1177,1178],{"class":189},"    `https:\u002F\u002Fapi.bluepic.io\u002Fapi\u002Fidml\u002Frender?format=png&textOverrides=${",[169,1180,1181],{"class":447},"encodeURIComponent",[169,1183,451],{"class":189},[169,1185,491],{"class":182},[169,1187,494],{"class":189},[169,1189,497],{"class":447},[169,1191,451],{"class":189},[169,1193,660],{"class":175},[169,1195,1196],{"class":189},"))",[169,1198,1199],{"class":189},"}`",[169,1201,193],{"class":175},[169,1203,1205,1208,1210],{"class":171,"line":1204},15,[169,1206,1207],{"class":175},"    { method: ",[169,1209,465],{"class":189},[169,1211,1212],{"class":175},", headers: { Authorization: apiKey }, body: form },\n",[169,1214,1216],{"class":171,"line":1215},16,[169,1217,1218],{"class":175},"  );\n",[169,1220,1222],{"class":171,"line":1221},17,[169,1223,1036],{"emptyLinePlaceholder":951},[169,1225,1227,1230,1233,1235,1238,1241,1243,1246,1249,1251,1254,1256,1258],{"class":171,"line":1226},18,[169,1228,1229],{"class":434},"  await",[169,1231,1232],{"class":447}," saveFile",[169,1234,451],{"class":175},[169,1236,1237],{"class":189},"`banner-${",[169,1239,1240],{"class":175},"variant",[169,1242,494],{"class":189},[169,1244,1245],{"class":175},"id",[169,1247,1248],{"class":189},"}.png`",[169,1250,78],{"class":175},[169,1252,1253],{"class":434},"await",[169,1255,545],{"class":175},[169,1257,548],{"class":447},[169,1259,1260],{"class":175},"());\n",[169,1262,1264],{"class":171,"line":1263},19,[169,1265,258],{"class":175},[27,1267,1268],{},"Linked PDF, AI, EPS and PSD assets are rasterized automatically on Bluepic's servers — nothing from Adobe or Figma needs to be installed anywhere near this script.",[11,1270,1272],{"id":1271},"multiple-output-sizes-from-one-file","Multiple output sizes from one file",[27,1274,1275,807,1277,1279],{},[23,1276,380],{},[23,1278,384],{}," query parameters override the rendered size independent of the document's own dimensions — useful if the same layout needs to ship as a square post and a story-format crop. Render the same request twice with different dimensions rather than maintaining two separate template files.",[11,1281,1283],{"id":1282},"where-the-field-keys-come-from","Where the field keys come from",[27,1285,1286,1287,1290,1291,1293],{},"Load your wrapper IDML into the ",[31,1288,1289],{"href":929},"interactive API playground"," once, tick the override checkbox, and it lists every text element with an empty input — type into the ones you want to control and copy the generated ",[23,1292,660],{}," JSON as your starting shape. From there, driving the same keys with real data from your own system is the whole job.",[11,1295,34],{"id":796},[27,1297,799,1298,1300,1301,494],{},[70,1299,802],{},", 1 credit per rendered output. Fifty banners in three sizes is 150 renders; check usage or ask about higher volume on the ",[31,1302,124],{"href":123},[11,1304,903],{"id":902},[905,1306,1307,1313,1320,1333],{},[908,1308,1309,1312],{},[31,1310,1311],{"href":929},"Get your API key"," and try the playground with your own artwork.",[908,1314,1315,1316,494],{},"If the automation is specifically about shipping the same design in multiple languages rather than multiple data variants, see ",[31,1317,1319],{"href":1318},"\u002Fdocs\u002Ftranslate-figma-photoshop-canva-illustrator","Translate Figma, Photoshop, Canva & Illustrator graphics automatically",[908,1321,1322,1323,1326,1327,78,1329,807,1331,494],{},"Read the ",[31,1324,1325],{"href":929},"full API reference"," for every parameter, including ",[23,1328,619],{},[23,1330,400],{},[23,1332,353],{},[908,1334,1335,1336,494],{},"If a field needs mixed formatting (part bold, a different color), see ",[31,1337,1339],{"href":1338},"\u002Fdocs\u002Frichtext-override-format","Rich text format for overrides",[932,1341,1342],{},"html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}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);}",{"title":25,"searchDepth":179,"depth":179,"links":1344},[1345,1346,1347,1348,1349,1350],{"id":963,"depth":179,"text":964},{"id":973,"depth":179,"text":974},{"id":1271,"depth":179,"text":1272},{"id":1282,"depth":179,"text":1283},{"id":796,"depth":179,"text":34},{"id":902,"depth":179,"text":903},"automate","Batch-generate variants of artwork made in Figma, Photoshop, Canva or Illustrator — personalized fields, multiple sizes, hundreds of outputs — with no design software running in your pipeline.","\u002Fdocs-images\u002Fautomate-figma-photoshop-canva-illustrator.svg",{},"\u002Fdocs\u002Fautomate-figma-photoshop-canva-illustrator",{"title":958,"description":1352},"docs\u002Fautomate-figma-photoshop-canva-illustrator","other-tools","_wddlFBbMZmVbG-1zKGGKilyC90YWNrnb5XV5jaIVaI",{"id":1361,"title":671,"body":1362,"category":1351,"date":946,"description":1862,"extension":948,"heroImage":1863,"meta":1864,"navigation":951,"path":670,"readingMinutes":238,"seo":1865,"stem":1866,"tool":1867,"__hash__":1868},"docs\u002Fdocs\u002Fautomate-indesign-projects.md",{"type":8,"value":1363,"toc":1853},[1364,1366,1369,1376,1380,1389,1394,1400,1418,1424,1501,1507,1514,1533,1542,1546,1788,1791,1797,1807,1809,1819,1821,1851],[11,1365,964],{"id":963},[27,1367,1368],{},"InDesign is a design tool, not a rendering server. The moment you need to generate a hundred name badges, a thousand certificates, or a weekly batch of social posts from one master layout, you're stuck: either someone opens InDesign and does it by hand, or you buy and run InDesign Server — a license, a machine, and an operations burden, just to turn a template into pixels.",[27,1370,1371,1372,1375],{},"Bluepic's IDML renderer is a plain HTTP API that does exactly that one job: take an InDesign file (exported as IDML) and a set of field values, and hand back rendered output. No InDesign install, no server to maintain, no license — a ",[23,1373,1374],{},"POST"," request from wherever your automation already lives (a cron job, a serverless function, a CI pipeline, your app's backend).",[11,1377,1379],{"id":1378},"the-building-blocks","The building blocks",[27,1381,1382,1385,1386,1388],{},[70,1383,1384],{},"1. Export once."," Design your master in InDesign, ",[23,1387,992],{},". This is your template — the thing you POST every time.",[27,1390,1391],{},[70,1392,1393],{},"2. Render it.",[16,1395,1398],{"className":1396,"code":1397,"language":21},[19],"POST https:\u002F\u002Fapi.bluepic.io\u002Fapi\u002Fidml\u002Frender\nAuthorization: \u003Cyour API key>\nContent-Type: multipart\u002Fform-data\n\nidml=@certificate.idml\nassets=@seal.png\nassets=@Signature-Font.ttf\n",[23,1399,1397],{"__ignoreMap":25},[27,1401,1402,1403,1406,1407,1409,1410,1413,1414,1417],{},"Every asset the IDML links to (images, fonts) goes in a repeated ",[23,1404,1405],{},"assets"," field, matched back to the document ",[70,1408,580],{}," — so name each part after what the IDML actually links (",[23,1411,1412],{},"hero.jpg",", not ",[23,1415,1416],{},"hero-final-v2.jpg","). Anything you leave out renders as a placeholder rather than failing the request, so partial asset sets are safe to iterate on.",[27,1419,1420,1423],{},[70,1421,1422],{},"3. Pick your output."," Query parameters control the render:",[44,1425,1426,1434],{},[47,1427,1428],{},[50,1429,1430,1432],{},[53,1431,590],{},[53,1433,593],{},[62,1435,1436,1452,1464,1478,1490],{},[50,1437,1438,1442],{},[67,1439,1440],{},[23,1441,319],{},[67,1443,1444,78,1446,78,1448,610,1450],{},[23,1445,324],{},[23,1447,328],{},[23,1449,331],{},[23,1451,334],{},[50,1453,1454,1458],{},[67,1455,1456],{},[23,1457,619],{},[67,1459,1460,625,1462],{},[23,1461,624],{},[23,1463,628],{},[50,1465,1466,1470],{},[67,1467,1468],{},[23,1469,353],{},[67,1471,1472,1474,1475,1477],{},[23,1473,358],{}," (full fidelity — the default) or ",[23,1476,361],{}," (faster PNG\u002FJPEG, no Chromium)",[50,1479,1480,1484],{},[67,1481,1482],{},[23,1483,400],{},[67,1485,1486,1487],{},"Output resolution for raster and PDF, default ",[23,1488,1489],{},"300",[50,1491,1492,1498],{},[67,1493,1494,381,1496],{},[23,1495,380],{},[23,1497,384],{},[67,1499,1500],{},"Override the rendered size in px",[27,1502,1503,1504,1506],{},"Multiple pages come back as a single merged PDF (for ",[23,1505,678],{},") or a zip with one file per page (PNG\u002FJPEG\u002FSVG) — one request, one response, no follow-up polling.",[27,1508,1509],{},[1510,1511],"img",{"alt":1512,"src":1513},"The API playground's Files and Options cards — the same parameters as the table above, live","\u002Fscreenshots\u002Fapi-files-options.png",[27,1515,1516,1519,1520,1522,1523,1525,1526,1528,1529,1532],{},[70,1517,1518],{},"4. Fill in the dynamic fields."," This is what turns a converter into automation: ",[23,1521,660],{},", a JSON object of ",[23,1524,666],{}," pairs. Any text element you name gets replaced; anything you don't name keeps its source value. The ",[31,1527,930],{"href":929}," generates this JSON for you — load your IDML once, type into the fields you want to control, and copy the live-updating ",[23,1530,1531],{},"curl"," command as your starting point.",[27,1534,1535,1536,1538,1539,1541],{},"One field you'll almost always vary this way is a name — and names vary a lot in length. The text frame's size in InDesign is the hard ceiling any override gets fit inside (it shrinks or wraps, it never grows the frame), so size name\u002Fvalue fields generously for your longest real record, not just your test data. Full detail in ",[31,1537,1000],{"href":999},". If a field has mixed formatting inside it, its override needs the array shape from ",[31,1540,1339],{"href":1338}," instead of a plain string.",[11,1543,1545],{"id":1544},"a-concrete-pipeline-personalized-certificates","A concrete pipeline: personalized certificates",[16,1547,1549],{"className":425,"code":1548,"language":427,"meta":25,"style":25},"const attendees = await getAttendeesFromYourDatabase(); \u002F\u002F [{ name, date, score }, ...]\n\nfor (const attendee of attendees) {\n  const textOverrides = {\n    '0:TextFrame_name': attendee.name,\n    '0:TextFrame_date': attendee.date,\n    '0:TextFrame_score': `${attendee.score}%`,\n  };\n\n  const form = new FormData();\n  form.append('idml', certificateIdml);\n  form.append('assets', sealImage, 'seal.png');\n\n  const res = await fetch(\n    `https:\u002F\u002Fapi.bluepic.io\u002Fapi\u002Fidml\u002Frender?format=pdf&textOverrides=${encodeURIComponent(JSON.stringify(textOverrides))}`,\n    { method: 'POST', headers: { Authorization: apiKey }, body: form },\n  );\n\n  await saveFile(`certificate-${attendee.name}.pdf`, await res.blob());\n}\n",[23,1550,1551,1570,1574,1590,1600,1608,1616,1639,1643,1647,1661,1674,1693,1697,1711,1736,1744,1748,1752,1783],{"__ignoreMap":25},[169,1552,1553,1555,1558,1560,1562,1565,1567],{"class":171,"line":172},[169,1554,435],{"class":434},[169,1556,1557],{"class":182}," attendees",[169,1559,441],{"class":434},[169,1561,444],{"class":434},[169,1563,1564],{"class":447}," getAttendeesFromYourDatabase",[169,1566,1027],{"class":175},[169,1568,1569],{"class":1030},"\u002F\u002F [{ name, date, score }, ...]\n",[169,1571,1572],{"class":171,"line":179},[169,1573,1036],{"emptyLinePlaceholder":951},[169,1575,1576,1578,1580,1582,1585,1587],{"class":171,"line":196},[169,1577,1041],{"class":434},[169,1579,1044],{"class":175},[169,1581,435],{"class":434},[169,1583,1584],{"class":182}," attendee",[169,1586,1052],{"class":434},[169,1588,1589],{"class":175}," attendees) {\n",[169,1591,1592,1594,1596,1598],{"class":171,"line":205},[169,1593,1060],{"class":434},[169,1595,1063],{"class":182},[169,1597,441],{"class":434},[169,1599,1068],{"class":175},[169,1601,1602,1605],{"class":171,"line":218},[169,1603,1604],{"class":189},"    '0:TextFrame_name'",[169,1606,1607],{"class":175},": attendee.name,\n",[169,1609,1610,1613],{"class":171,"line":238},[169,1611,1612],{"class":189},"    '0:TextFrame_date'",[169,1614,1615],{"class":175},": attendee.date,\n",[169,1617,1618,1621,1623,1626,1629,1631,1634,1637],{"class":171,"line":244},[169,1619,1620],{"class":189},"    '0:TextFrame_score'",[169,1622,186],{"class":175},[169,1624,1625],{"class":189},"`${",[169,1627,1628],{"class":175},"attendee",[169,1630,494],{"class":189},[169,1632,1633],{"class":175},"score",[169,1635,1636],{"class":189},"}%`",[169,1638,193],{"class":175},[169,1640,1641],{"class":171,"line":255},[169,1642,1089],{"class":175},[169,1644,1645],{"class":171,"line":533},[169,1646,1036],{"emptyLinePlaceholder":951},[169,1648,1649,1651,1653,1655,1657,1659],{"class":171,"line":1113},[169,1650,1060],{"class":434},[169,1652,1100],{"class":182},[169,1654,441],{"class":434},[169,1656,1105],{"class":434},[169,1658,1108],{"class":447},[169,1660,551],{"class":175},[169,1662,1663,1665,1667,1669,1671],{"class":171,"line":1130},[169,1664,1116],{"class":175},[169,1666,1119],{"class":447},[169,1668,451],{"class":175},[169,1670,1124],{"class":189},[169,1672,1673],{"class":175},", certificateIdml);\n",[169,1675,1676,1678,1680,1682,1684,1687,1690],{"class":171,"line":1154},[169,1677,1116],{"class":175},[169,1679,1119],{"class":447},[169,1681,451],{"class":175},[169,1683,1139],{"class":189},[169,1685,1686],{"class":175},", sealImage, ",[169,1688,1689],{"class":189},"'seal.png'",[169,1691,1692],{"class":175},");\n",[169,1694,1695],{"class":171,"line":1159},[169,1696,1036],{"emptyLinePlaceholder":951},[169,1698,1699,1701,1703,1705,1707,1709],{"class":171,"line":1175},[169,1700,1060],{"class":434},[169,1702,438],{"class":182},[169,1704,441],{"class":434},[169,1706,444],{"class":434},[169,1708,448],{"class":447},[169,1710,1172],{"class":175},[169,1712,1713,1716,1718,1720,1722,1724,1726,1728,1730,1732,1734],{"class":171,"line":1204},[169,1714,1715],{"class":189},"    `https:\u002F\u002Fapi.bluepic.io\u002Fapi\u002Fidml\u002Frender?format=pdf&textOverrides=${",[169,1717,1181],{"class":447},[169,1719,451],{"class":189},[169,1721,491],{"class":182},[169,1723,494],{"class":189},[169,1725,497],{"class":447},[169,1727,451],{"class":189},[169,1729,660],{"class":175},[169,1731,1196],{"class":189},[169,1733,1199],{"class":189},[169,1735,193],{"class":175},[169,1737,1738,1740,1742],{"class":171,"line":1215},[169,1739,1207],{"class":175},[169,1741,465],{"class":189},[169,1743,1212],{"class":175},[169,1745,1746],{"class":171,"line":1221},[169,1747,1218],{"class":175},[169,1749,1750],{"class":171,"line":1226},[169,1751,1036],{"emptyLinePlaceholder":951},[169,1753,1754,1756,1758,1760,1763,1765,1767,1770,1773,1775,1777,1779,1781],{"class":171,"line":1263},[169,1755,1229],{"class":434},[169,1757,1232],{"class":447},[169,1759,451],{"class":175},[169,1761,1762],{"class":189},"`certificate-${",[169,1764,1628],{"class":175},[169,1766,494],{"class":189},[169,1768,1769],{"class":175},"name",[169,1771,1772],{"class":189},"}.pdf`",[169,1774,78],{"class":175},[169,1776,1253],{"class":434},[169,1778,545],{"class":175},[169,1780,548],{"class":447},[169,1782,1260],{"class":175},[169,1784,1786],{"class":171,"line":1785},20,[169,1787,258],{"class":175},[27,1789,1790],{},"Same shape works for event badges, invoice-style documents, personalized social graphics, or a weekly report that only changes three numbers — anywhere you'd otherwise open InDesign, change some text, and export by hand.",[11,1792,1794,1796],{"id":1793},"engine-fidelity-vs-throughput",[23,1795,353],{},": fidelity vs. throughput",[27,1798,1799,1800,1802,1803,1806],{},"For a handful of renders, the default ",[23,1801,358],{}," engine (a real, full layout engine — the same technology behind the free converter) is the right call: full fidelity, every feature. For a large batch of simple PNG\u002FJPEG exports where you're rendering hundreds or thousands of variants, ",[23,1804,1805],{},"engine=resvg"," skips the Chromium instance entirely and renders faster — worth benchmarking against your own document before committing to it for a production batch job.",[11,1808,34],{"id":796},[27,1810,799,1811,1813,1814,1816,1817,494],{},[70,1812,802],{}," — 1 credit per rendered page, regardless of format or how many ",[23,1815,660],{}," you send. A 500-badge batch job is 500 credits; check usage and get in touch for higher volume from the ",[31,1818,124],{"href":123},[11,1820,903],{"id":902},[905,1822,1823,1828,1833,1844],{},[908,1824,1825,1827],{},[31,1826,1311],{"href":929}," and try the playground against your own IDML.",[908,1829,1322,1830,1832],{},[31,1831,1325],{"href":929}," for every parameter.",[908,1834,1835,1836,1840,1841,1843],{},"If your automation is specifically about shipping the same layout in multiple languages, see ",[31,1837,1839],{"href":1838},"\u002Fdocs\u002Ftranslate-indesign-automatically","Translate InDesign projects automatically"," — same API, same ",[23,1842,660],{}," mechanism.",[908,1845,1846,807,1848,1850],{},[31,1847,1000],{"href":999},[31,1849,1339],{"href":1338}," — worth reading before your first production batch.",[932,1852,1342],{},{"title":25,"searchDepth":179,"depth":179,"links":1854},[1855,1856,1857,1858,1860,1861],{"id":963,"depth":179,"text":964},{"id":1378,"depth":179,"text":1379},{"id":1544,"depth":179,"text":1545},{"id":1793,"depth":179,"text":1859},"engine: fidelity vs. throughput",{"id":796,"depth":179,"text":34},{"id":902,"depth":179,"text":903},"Turn a single InDesign layout into a rendering pipeline — batch outputs, dynamic fields, and PDF\u002FPNG\u002FJPEG\u002FSVG generation with no InDesign install anywhere.","\u002Fdocs-images\u002Fautomate-indesign-projects.svg",{},{"title":671,"description":1862},"docs\u002Fautomate-indesign-projects","indesign","62e0euc3H7eCxiSGHCIbg_lM3eMCR0_kUmIQuOzgwtg",{"id":1870,"title":1871,"body":1872,"category":945,"date":946,"description":2119,"extension":948,"heroImage":2120,"meta":2121,"navigation":951,"path":158,"readingMinutes":238,"seo":2122,"stem":2123,"tool":945,"__hash__":2124},"docs\u002Fdocs\u002Fbuilding-templates-in-bluepic-studio.md","Building templates in Bluepic Studio",{"type":8,"value":1873,"toc":2110},[1874,1878,1890,1895,1899,1906,1926,1934,1938,1941,1960,1964,1977,2035,2041,2045,2051,2057,2069,2073,2083,2085,2107],[11,1875,1877],{"id":1876},"design-once-render-forever","Design once, render forever",[27,1879,1880,1885,1886,1889],{},[31,1881,159],{"href":1882,"rel":1883},"https:\u002F\u002Fbx-studio.bluepic.io",[1884],"nofollow"," is where the actual design work happens — the layout, the fonts, the exact pixel a logo sits at. Everything downstream (the ",[31,1887,1888],{"href":952},"render API",", batch jobs, personalization) just fills in values on a template you already built visually. You never hand-write the JSON a template is made of; Studio is the editor for it.",[27,1891,1892,1893,494],{},"This guide covers the Studio side specifically: creating a template, wiring up the parts that should change per-render, and finding the ID your code needs. If you're looking for the raw-IDML path instead — importing an existing InDesign file without touching Studio's canvas — see ",[31,1894,671],{"href":670},[11,1896,1898],{"id":1897},"create-a-template","Create a template",[27,1900,1901,1902,1905],{},"From the templates view, ",[70,1903,1904],{},"Create Template"," opens three starting points:",[905,1907,1908,1914,1920],{},[908,1909,1910,1913],{},[70,1911,1912],{},"Empty Template"," — a blank canvas at a size you pick.",[908,1915,1916,1919],{},[70,1917,1918],{},"Presets"," — common starting layouts.",[908,1921,1922,1925],{},[70,1923,1924],{},"Import from IDML"," — bring in an existing InDesign export as an editable Studio template, rather than rendering it raw.",[27,1927,1928,1929,1931,1932,494],{},"Pick a size from the aspect-ratio grid (square, portrait 4:5, story 9:16, and a handful of others), or set exact dimensions — this is the pixel size every render comes back at unless a request overrides ",[23,1930,380],{},"\u002F",[23,1933,384],{},[11,1935,1937],{"id":1936},"the-editor","The editor",[27,1939,1940],{},"The canvas works like any layered design tool — text, image, shape, and pen tools on the toolbar, a layers panel on the right, and a property panel on the left for whatever's selected: position and size, fill and stroke, opacity, and (for text) content, font, size and alignment.",[27,1942,1943,1944,1950,1951,1954,1955,1959],{},"The part that matters for automation is the ",[70,1945,1946,1949],{},[23,1947,1948],{},"fx"," expression icon"," in the toolbar. Any numeric property — position, size, rotation, opacity — can be bound to an expression instead of a fixed number, and an expression can repeat one element a computed number of times: a rectangle whose count is ",[23,1952,1953],{},"body.lines.length",", say, drawn once and multiplied automatically at render time. Design the element once; let the expression handle \"one per line,\" \"one per row,\" or \"one per item in the data\" — see the ",[31,1956,1958],{"href":1957},"\u002F#how-it-works","live example on the homepage"," for exactly this pattern.",[11,1961,1963],{"id":1962},"connect-input-fields","Connect input fields",[27,1965,1966,1969,1970,1973,1974,1976],{},[70,1967,1968],{},"Add Input Field",", then click the element you want to expose. That element's editable property (its text content, its image source, sometimes its fill color) becomes a ",[70,1971,1972],{},"named field"," — the name you give it here is the exact key your API request's ",[23,1975,301],{}," object uses later:",[16,1978,1980],{"className":163,"code":1979,"language":165,"meta":25,"style":25},"{\n  \"templateId\": \"efa8ff2c-262b-4488-b8cf-e01521c6fbb5\",\n  \"data\": {\n    \"headline_text_content\": \"Ship it Friday\",\n    \"avatar_image\": { \"src\": \"https:\u002F\u002Fcdn.example.com\u002Favatar.jpg\" }\n  }\n}\n",[23,1981,1982,1986,1996,2002,2012,2026,2031],{"__ignoreMap":25},[169,1983,1984],{"class":171,"line":172},[169,1985,176],{"class":175},[169,1987,1988,1990,1992,1994],{"class":171,"line":179},[169,1989,183],{"class":182},[169,1991,186],{"class":175},[169,1993,190],{"class":189},[169,1995,193],{"class":175},[169,1997,1998,2000],{"class":171,"line":196},[169,1999,199],{"class":182},[169,2001,202],{"class":175},[169,2003,2004,2006,2008,2010],{"class":171,"line":205},[169,2005,208],{"class":182},[169,2007,186],{"class":175},[169,2009,213],{"class":189},[169,2011,193],{"class":175},[169,2013,2014,2016,2018,2020,2022,2024],{"class":171,"line":218},[169,2015,221],{"class":182},[169,2017,224],{"class":175},[169,2019,227],{"class":182},[169,2021,186],{"class":175},[169,2023,232],{"class":189},[169,2025,235],{"class":175},[169,2027,2028],{"class":171,"line":238},[169,2029,2030],{"class":175},"  }\n",[169,2032,2033],{"class":171,"line":244},[169,2034,258],{"class":175},[27,2036,2037,2040],{},[70,2038,2039],{},"Show Input Fields"," toggles a preview of every field you've wired up so far, letting you check names and defaults before you publish. Anything you don't expose as a field stays fixed — logos, backgrounds, decorative shapes never need a field at all.",[11,2042,2044],{"id":2043},"publish-and-find-your-template-id","Publish, and find your template ID",[27,2046,2047,2050],{},[70,2048,2049],{},"Publish"," makes the template renderable via the API. The ID itself is simpler than a separate \"copy ID\" step: it's the UUID already sitting in your browser's address bar while you're editing —",[16,2052,2055],{"className":2053,"code":2054,"language":21},[19],"https:\u002F\u002Fbx-studio.bluepic.io\u002Feditor\u002Fefa8ff2c-262b-4488-b8cf-e01521c6fbb5\n                                       └──────────────── templateId ────────────────┘\n",[23,2056,2054],{"__ignoreMap":25},[27,2058,2059,2060,2062,2063,2068],{},"— the same string goes straight into ",[23,2061,285],{}," on a ",[31,2064,2066],{"href":2065},"\u002Fdocs\u002Fapi-reference#render-a-studio-template",[23,2067,77],{}," call.",[11,2070,2072],{"id":2071},"sharing-url-vs-the-api","Sharing URL vs. the API",[27,2074,2075,2076,2079,2080,2082],{},"Studio's settings panel (the gear icon next to Publish) also offers a ",[70,2077,2078],{},"Sharing URL"," — a public, no-code page where anyone can fill in the fields and export an image by hand, useful for handing a template to someone who isn't writing code at all. That's a different mechanism from calling ",[23,2081,806],{}," directly: the sharing URL is for a human filling in a form once; the API is for your own backend rendering the same template hundreds of times from data it already has. Both read the same published template and the same input fields — pick whichever matches who's actually triggering the render.",[11,2084,903],{"id":902},[905,2086,2087,2097,2102],{},[908,2088,2089,2091,2092,2094,2095,494],{},[31,2090,6],{"href":952}," — the exact request shape for ",[23,2093,806],{},", once you have a ",[23,2096,285],{},[908,2098,2099,2100,494],{},"Try it immediately with the demo template in the ",[31,2101,930],{"href":929},[908,2103,2104,2105,494],{},"Need the raw-IDML path instead of designing in Studio? See ",[31,2106,671],{"href":670},[932,2108,2109],{},"html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}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);}",{"title":25,"searchDepth":179,"depth":179,"links":2111},[2112,2113,2114,2115,2116,2117,2118],{"id":1876,"depth":179,"text":1877},{"id":1897,"depth":179,"text":1898},{"id":1936,"depth":179,"text":1937},{"id":1962,"depth":179,"text":1963},{"id":2043,"depth":179,"text":2044},{"id":2071,"depth":179,"text":2072},{"id":902,"depth":179,"text":903},"Design a template visually in Bluepic Studio — elements, expressions and input fields — then find its ID and drive it from your own code with a single POST \u002Fapi\u002Frender call.","\u002Fdocs-images\u002Fbuilding-templates-in-bluepic-studio.svg",{},{"title":1871,"description":2119},"docs\u002Fbuilding-templates-in-bluepic-studio","qwUwqy4K1AWxbV7nan0lGn4GGl8KEoKHrHRDAOBYQqM",{"id":2126,"title":1339,"body":2127,"category":2557,"date":946,"description":2558,"extension":948,"heroImage":2559,"meta":2560,"navigation":951,"path":1338,"readingMinutes":218,"seo":2561,"stem":2562,"tool":1867,"__hash__":2563},"docs\u002Fdocs\u002Frichtext-override-format.md",{"type":8,"value":2128,"toc":2548},[2129,2139,2143,2155,2159,2162,2254,2274,2280,2283,2381,2398,2402,2415,2419,2425,2528,2530,2546],[27,2130,2131,2132,2134,2135,2138],{},"Most text elements are plain — a single string is all ",[23,2133,660],{}," needs for them. But when a text element has ",[70,2136,2137],{},"mixed formatting inside it"," (part bold, a different color on one word, a linked phrase), it's in \"rich text\" mode, and its override value needs to be a small array of formatted runs instead of a plain string.",[11,2140,2142],{"id":2141},"how-to-tell-which-mode-an-element-needs","How to tell which mode an element needs",[27,2144,2145,2146,2150,2151,2154],{},"You don't have to inspect the IDML for this — load the file into the ",[31,2147,2149],{"href":2148},"\u002Fidml","Convert tool"," or the ",[31,2152,2153],{"href":929},"API playground"," and open the text-overrides table. Plain elements get a normal text box; rich-text elements get a small formatting toolbar on their input automatically. If you see the toolbar, that row needs the array shape below, not a string.",[11,2156,2158],{"id":2157},"the-shape","The shape",[27,2160,2161],{},"A rich-text override value is an array of runs. Each run is a chunk of text plus the formatting that applies to just that chunk:",[16,2163,2165],{"className":163,"code":2164,"language":165,"meta":25,"style":25},"[\n  { \"text\": \"Save \", \"format\": {} },\n  { \"text\": \"30%\", \"format\": { \"fontWeight\": 700, \"color\": \"#e0392b\" } },\n  { \"text\": \" this week only.\", \"format\": {} }\n]\n",[23,2166,2167,2172,2193,2231,2249],{"__ignoreMap":25},[169,2168,2169],{"class":171,"line":172},[169,2170,2171],{"class":175},"[\n",[169,2173,2174,2177,2180,2182,2185,2187,2190],{"class":171,"line":179},[169,2175,2176],{"class":175},"  { ",[169,2178,2179],{"class":182},"\"text\"",[169,2181,186],{"class":175},[169,2183,2184],{"class":189},"\"Save \"",[169,2186,78],{"class":175},[169,2188,2189],{"class":182},"\"format\"",[169,2191,2192],{"class":175},": {} },\n",[169,2194,2195,2197,2199,2201,2204,2206,2208,2210,2213,2215,2218,2220,2223,2225,2228],{"class":171,"line":196},[169,2196,2176],{"class":175},[169,2198,2179],{"class":182},[169,2200,186],{"class":175},[169,2202,2203],{"class":189},"\"30%\"",[169,2205,78],{"class":175},[169,2207,2189],{"class":182},[169,2209,224],{"class":175},[169,2211,2212],{"class":182},"\"fontWeight\"",[169,2214,186],{"class":175},[169,2216,2217],{"class":182},"700",[169,2219,78],{"class":175},[169,2221,2222],{"class":182},"\"color\"",[169,2224,186],{"class":175},[169,2226,2227],{"class":189},"\"#e0392b\"",[169,2229,2230],{"class":175}," } },\n",[169,2232,2233,2235,2237,2239,2242,2244,2246],{"class":171,"line":205},[169,2234,2176],{"class":175},[169,2236,2179],{"class":182},[169,2238,186],{"class":175},[169,2240,2241],{"class":189},"\" this week only.\"",[169,2243,78],{"class":175},[169,2245,2189],{"class":182},[169,2247,2248],{"class":175},": {} }\n",[169,2250,2251],{"class":171,"line":218},[169,2252,2253],{"class":175},"]\n",[27,2255,2256,2257,2259,2260,2263,2264,2266,2267,2270,2271,2273],{},"Concatenate every run's ",[23,2258,21],{}," in order and you get the plain-text content — ",[23,2261,2262],{},"\"Save 30% this week only.\""," here. The ",[23,2265,319],{}," object carries only what's ",[139,2268,2269],{},"different"," from the element's own base style; an empty ",[23,2272,309],{}," just means \"use whatever the element already looks like.\"",[11,2275,2277,2279],{"id":2276},"format-fields",[23,2278,319],{}," fields",[27,2281,2282],{},"Every field is optional — omit one to inherit the element's base value rather than overriding it.",[44,2284,2285,2296],{},[47,2286,2287],{},[50,2288,2289,2291,2293],{},[53,2290,267],{},[53,2292,270],{},[53,2294,2295],{},"Effect",[62,2297,2298,2311,2332,2345,2357,2369],{},[50,2299,2300,2305,2308],{},[67,2301,2302],{},[23,2303,2304],{},"fontWeight",[67,2306,2307],{},"number (100–900)",[67,2309,2310],{},"Weight of just this run.",[50,2312,2313,2318,2329],{},[67,2314,2315],{},[23,2316,2317],{},"fontStyle",[67,2319,2320,325,2323,325,2326],{},[23,2321,2322],{},"'normal'",[23,2324,2325],{},"'italic'",[23,2327,2328],{},"'condensed'",[67,2330,2331],{},"Style of just this run.",[50,2333,2334,2339,2342],{},[67,2335,2336],{},[23,2337,2338],{},"fontSize",[67,2340,2341],{},"number (px)",[67,2343,2344],{},"Size of just this run.",[50,2346,2347,2352,2354],{},[67,2348,2349],{},[23,2350,2351],{},"letterSpacing",[67,2353,387],{},[67,2355,2356],{},"Tracking, as a ratio (InDesign-style), for just this run.",[50,2358,2359,2364,2366],{},[67,2360,2361],{},[23,2362,2363],{},"color",[67,2365,288],{},[67,2367,2368],{},"Any CSS color for just this run's text.",[50,2370,2371,2376,2378],{},[67,2372,2373],{},[23,2374,2375],{},"href",[67,2377,288],{},[67,2379,2380],{},"Wraps this run in a link (carries through to PDF export).",[27,2382,2383,2386,2387,2390,2391,2394,2395,2397],{},[23,2384,2385],{},"fontFamily"," and a horizontal ",[23,2388,2389],{},"scale"," also exist on the underlying type, but there's no need to set them per run: a font-family or scale difference always causes the conversion to split that content into a ",[70,2392,2393],{},"separate element"," rather than a mixed run within one element (see ",[31,2396,1000],{"href":999},") — so within a single rich-text array, every run already shares the same family and scale by construction.",[11,2399,2401],{"id":2400},"line-breaks","Line breaks",[27,2403,2404,2405,2408,2409,2411,2412,2414],{},"A literal ",[23,2406,2407],{},"\\n"," inside a run's ",[23,2410,21],{}," is a valid line break — you don't need a separate array entry per line, just embed ",[23,2413,2407],{}," wherever a break belongs within a run.",[11,2416,2418],{"id":2417},"a-full-request-example","A full request example",[27,2420,2421,2422,2424],{},"Plain and rich-text keys sit side by side in the same ",[23,2423,660],{}," object without any special marker — the shape of each value is all that distinguishes them:",[16,2426,2428],{"className":163,"code":2427,"language":165,"meta":25,"style":25},"{\n  \"0:TextFrame_headline\": \"Willkommen in Berlin\",\n  \"0:TextFrame_promo\": [\n    { \"text\": \"Save \", \"format\": {} },\n    { \"text\": \"30%\", \"format\": { \"fontWeight\": 700, \"color\": \"#e0392b\" } },\n    { \"text\": \" this week only.\", \"format\": {} }\n  ]\n}\n",[23,2429,2430,2434,2446,2454,2471,2503,2519,2524],{"__ignoreMap":25},[169,2431,2432],{"class":171,"line":172},[169,2433,176],{"class":175},[169,2435,2436,2439,2441,2444],{"class":171,"line":179},[169,2437,2438],{"class":182},"  \"0:TextFrame_headline\"",[169,2440,186],{"class":175},[169,2442,2443],{"class":189},"\"Willkommen in Berlin\"",[169,2445,193],{"class":175},[169,2447,2448,2451],{"class":171,"line":196},[169,2449,2450],{"class":182},"  \"0:TextFrame_promo\"",[169,2452,2453],{"class":175},": [\n",[169,2455,2456,2459,2461,2463,2465,2467,2469],{"class":171,"line":205},[169,2457,2458],{"class":175},"    { ",[169,2460,2179],{"class":182},[169,2462,186],{"class":175},[169,2464,2184],{"class":189},[169,2466,78],{"class":175},[169,2468,2189],{"class":182},[169,2470,2192],{"class":175},[169,2472,2473,2475,2477,2479,2481,2483,2485,2487,2489,2491,2493,2495,2497,2499,2501],{"class":171,"line":218},[169,2474,2458],{"class":175},[169,2476,2179],{"class":182},[169,2478,186],{"class":175},[169,2480,2203],{"class":189},[169,2482,78],{"class":175},[169,2484,2189],{"class":182},[169,2486,224],{"class":175},[169,2488,2212],{"class":182},[169,2490,186],{"class":175},[169,2492,2217],{"class":182},[169,2494,78],{"class":175},[169,2496,2222],{"class":182},[169,2498,186],{"class":175},[169,2500,2227],{"class":189},[169,2502,2230],{"class":175},[169,2504,2505,2507,2509,2511,2513,2515,2517],{"class":171,"line":238},[169,2506,2458],{"class":175},[169,2508,2179],{"class":182},[169,2510,186],{"class":175},[169,2512,2241],{"class":189},[169,2514,78],{"class":175},[169,2516,2189],{"class":182},[169,2518,2248],{"class":175},[169,2520,2521],{"class":171,"line":244},[169,2522,2523],{"class":175},"  ]\n",[169,2525,2526],{"class":171,"line":255},[169,2527,258],{"class":175},[11,2529,903],{"id":902},[905,2531,2532,2537],{},[908,2533,2534,2536],{},[31,2535,1000],{"href":999}," — why an element ends up plain vs. rich text in the first place.",[908,2538,2539,2542,2543,2545],{},[31,2540,2541],{"href":929},"Full API reference"," for ",[23,2544,660],{}," and every other render option.",[932,2547,2109],{},{"title":25,"searchDepth":179,"depth":179,"links":2549},[2550,2551,2552,2554,2555,2556],{"id":2141,"depth":179,"text":2142},{"id":2157,"depth":179,"text":2158},{"id":2276,"depth":179,"text":2553},"format fields",{"id":2400,"depth":179,"text":2401},{"id":2417,"depth":179,"text":2418},{"id":902,"depth":179,"text":903},"reference","The exact JSON shape textOverrides expects when a text element has mixed formatting inside it — fields, defaults, line breaks, and a full worked example.","\u002Fdocs-images\u002Frichtext-override-format.svg",{},{"title":1339,"description":2558},"docs\u002Frichtext-override-format","1Lq8iHTebQY8tSMd_g4AGRMqO2VOjO6qLQl38kQjslk",{"id":2565,"title":1000,"body":2566,"category":2557,"date":946,"description":2715,"extension":948,"heroImage":2716,"meta":2717,"navigation":951,"path":999,"readingMinutes":238,"seo":2718,"stem":2719,"tool":1867,"__hash__":2720},"docs\u002Fdocs\u002Ftext-frames-and-best-practices.md",{"type":8,"value":2567,"toc":2709},[2568,2571,2575,2590,2593,2603,2607,2617,2620,2636,2643,2648,2674,2682,2686,2692,2694],[27,2569,2570],{},"Overriding text (a translation, a name, a price) looks simple from the API side — you send a string, you get pixels back. Two things the engine does under the hood decide whether that string actually lands the way you expect: how big the text is allowed to get, and how many pieces your InDesign text frame turned into. Both are worth understanding before you build automation around a document.",[11,2572,2574],{"id":2573},"a-frames-size-is-the-maximum-bound-not-a-suggestion","A frame's size is the maximum bound, not a suggestion",[27,2576,2577,2578,807,2580,2582,2583,2585,2586,2589],{},"When an InDesign text frame is converted, it becomes a serial text element with a fixed ",[23,2579,380],{},[23,2581,384],{}," — captured once, at conversion time, from the original frame. Every render after that — including every ",[23,2584,660],{}," value you ever send — works ",[70,2587,2588],{},"inside that same box",". The engine has exactly two levers to make text fit: shrink the font size, and wrap into more lines. It never grows the box itself, no matter how long the replacement text is.",[27,2591,2592],{},"That means: if your English placeholder fits snugly and the German translation runs 30% longer, the frame doesn't expand to make room — the text shrinks (or wraps further) to stay inside the space you gave it in InDesign. This is precisely what makes the auto-fit engine useful (no manual resizing per language), but it also means the frame you draw is a real ceiling, not a hint.",[27,2594,2595,2598,2599,2602],{},[70,2596,2597],{},"Best practice:"," size your text frames with headroom for the ",[139,2600,2601],{},"longest"," value you'll ever send through them — the longest language, the longest name, the longest price string — not just the sample text you happened to design with. Auto-fit will shrink shorter values back down automatically; it can't invent space that was never there.",[11,2604,2606],{"id":2605},"one-text-frame-doesnt-always-mean-one-override-key","One text frame doesn't always mean one override key",[27,2608,2609,2610,2613,2614,2616],{},"The converter doesn't always turn one InDesign text frame into one serial element. Depending on what's inside it, a single frame can become ",[70,2611,2612],{},"several"," elements — and each one gets its own key in ",[23,2615,660],{},". This catches people off guard more than the bounds issue above, because it's invisible until you actually look at the converted result.",[27,2618,2619],{},"By default, a frame's content only splits into a new element at an existing paragraph break or forced line break, and only when:",[905,2621,2622,2628,2633],{},[908,2623,2624,2625],{},"the character formatting (font, size, weight, style, color, letter-spacing) or line spacing differs across that break, ",[70,2626,2627],{},"or",[908,2629,2630,2631],{},"it's a blank line, ",[70,2632,2627],{},[908,2634,2635],{},"InDesign paragraph spacing (space-before\u002Fspace-after) is set on either paragraph.",[27,2637,2638,2639,2642],{},"Consistently-formatted paragraphs with no blank line and no paragraph spacing between them are actually ",[70,2640,2641],{},"merged"," into one multi-line element — a subtlety worth knowing, since it means simply pressing Enter between two lines doesn't automatically split them.",[27,2644,2645],{},[70,2646,2647],{},"What this means in practice:",[905,2649,2650,2660,2667],{},[908,2651,2652,2653,2655,2656,2659],{},"If you want a single ",[23,2654,660],{}," key to control a whole heading or paragraph, keep its formatting uniform end to end and avoid paragraph spacing or blank lines inside it. A stray bold word or a different-colored phrase is fine to ",[139,2657,2658],{},"want",", but if it sits at a line break, it becomes a split point — what you meant as \"one sentence\" quietly becomes two override keys.",[908,2661,2662,2663,2666],{},"If two parts of what looks like one frame are conceptually different content — a headline and a caption, say — make them ",[70,2664,2665],{},"separate InDesign text frames"," from the start. It's cleaner to design that intent explicitly than to have the converter split a single frame for you and have to discover the extra key afterwards.",[908,2668,2669,2670,2673],{},"In short: ",[70,2671,2672],{},"one text frame per what is, in fact, one piece of text."," If it reads as one idea, keep it one frame with uniform formatting; if it's really two ideas, give it two frames.",[27,2675,2676,2677,2150,2679,2681],{},"You don't have to guess at any of this — load your file into the ",[31,2678,2149],{"href":2148},[31,2680,2153],{"href":929}," and open the text-overrides table. It shows exactly one row per element the conversion actually produced, with the key each one will use — check it before you wire up automation, not after.",[11,2683,2685],{"id":2684},"mixed-formatting-needs-a-different-override-shape","Mixed formatting needs a different override shape",[27,2687,2688,2689,2691],{},"If a text element does end up with mixed formatting inside it (a bold word, a linked phrase), it's in \"rich text\" mode, and overriding it takes a small structured array instead of a plain string — see ",[31,2690,1339],{"href":1338}," for the exact shape.",[11,2693,903],{"id":902},[905,2695,2696,2703],{},[908,2697,2698,807,2700,2702],{},[31,2699,1839],{"href":1838},[31,2701,671],{"href":670}," — put this into practice.",[908,2704,2705,2542,2707,2545],{},[31,2706,2541],{"href":929},[23,2708,660],{},{"title":25,"searchDepth":179,"depth":179,"links":2710},[2711,2712,2713,2714],{"id":2573,"depth":179,"text":2574},{"id":2605,"depth":179,"text":2606},{"id":2684,"depth":179,"text":2685},{"id":902,"depth":179,"text":903},"How the rendering engine and the InDesign→serial conversion actually interact — why a text frame's size is the hard ceiling for any override, and how to structure InDesign text so overrides stay clean and predictable.","\u002Fdocs-images\u002Ftext-frames-and-best-practices.svg",{},{"title":1000,"description":2715},"docs\u002Ftext-frames-and-best-practices","O_XOgD3GrmxSTOOGGE0TGDM5APg6oZbmytFCAWmu8-U",{"id":2722,"title":1319,"body":2723,"category":2882,"date":946,"description":2883,"extension":948,"heroImage":2884,"meta":2885,"navigation":951,"path":1318,"readingMinutes":238,"seo":2886,"stem":2887,"tool":1358,"__hash__":2888},"docs\u002Fdocs\u002Ftranslate-figma-photoshop-canva-illustrator.md",{"type":8,"value":2724,"toc":2873},[2725,2729,2735,2738,2742,2745,2776,2783,2787,2795,2800,2804,2807,2813,2825,2829,2840,2844,2847,2849],[11,2726,2728],{"id":2727},"the-honest-starting-point","The honest starting point",[27,2730,2731,2732],{},"Figma, Photoshop, Canva and Illustrator don't export IDML — that's an InDesign-only format, and Bluepic's translation engine works on IDML. So this isn't \"upload your Figma file and get eight languages back.\" It's something more useful once you know it exists: ",[70,2733,2734],{},"your artwork stays exactly as-is, in whatever tool you made it in — InDesign becomes a thin, one-time wrapper around it that carries the translatable text and does the auto-fitting.",[27,2736,2737],{},"This is not a workaround; it's the same production pattern print and marketing teams have used for decades. A poster's photography comes from Photoshop, its icon set from Illustrator, its background from Figma or Canva — and InDesign is the assembly layer that places all of it and adds the type on top. All this tutorial does is point that same assembly layer at Bluepic's API instead of a human's export button.",[11,2739,2741],{"id":2740},"step-1-export-your-artwork-as-a-flat-file","Step 1 — export your artwork as a flat file",[27,2743,2744],{},"From whichever tool made the graphic:",[905,2746,2747,2756,2764,2770],{},[908,2748,2749,88,2752,2755],{},[70,2750,2751],{},"Figma",[23,2753,2754],{},"Export"," → PNG, JPG or PDF.",[908,2757,2758,88,2761,2755],{},[70,2759,2760],{},"Canva",[23,2762,2763],{},"Share → Download",[908,2765,2766,2769],{},[70,2767,2768],{},"Photoshop"," — save as PSD (kept as layers) or export a flattened PNG\u002FJPG.",[908,2771,2772,2775],{},[70,2773,2774],{},"Illustrator"," — save as AI (kept as vector) or export a flattened PNG\u002FJPG\u002FPDF.",[27,2777,2778,2779,2782],{},"If you're not sure which to pick: ",[70,2780,2781],{},"PDF works from all four tools"," and is the simplest universal choice. Photoshop's native PSD and Illustrator's native AI also work directly — you don't have to flatten them first.",[11,2784,2786],{"id":2785},"step-2-place-it-in-a-lightweight-indesign-file","Step 2 — place it in a lightweight InDesign file",[27,2788,2789,2790,2792,2793,494],{},"Open (or create) an InDesign document, ",[23,2791,988],{}," your exported artwork, position it, and add your text frames on top — headline, body copy, call to action, whatever needs to vary per language. This InDesign file doesn't need to be a \"real\" layout in the traditional sense; its only job is to hold your artwork and your translatable text frames in one place. Export it: ",[23,2794,992],{},[27,2796,2797,2798,494],{},"Two things worth getting right while you're drawing those frames: size each one with headroom for your longest expected language (the frame's size becomes a hard ceiling, not a starting point), and keep one frame's formatting uniform if you want it to stay one overridable unit rather than silently splitting into several. Both are covered in ",[31,2799,1000],{"href":999},[11,2801,2803],{"id":2802},"step-3-send-it-to-bluepic-same-as-any-idml","Step 3 — send it to Bluepic, same as any IDML",[27,2805,2806],{},"This is where it stops being special-cased. Whether the file underneath is a native InDesign document or a thin wrapper around a Photoshop export, the API doesn't know the difference:",[16,2808,2811],{"className":2809,"code":2810,"language":21},[19],"POST https:\u002F\u002Fapi.bluepic.io\u002Fapi\u002Fidml\u002Frender\nAuthorization: \u003Cyour API key>\nContent-Type: multipart\u002Fform-data\n\nidml=@poster.idml\nassets=@background.pdf\ntextOverrides={\"0:TextFrame_headline\":\"Willkommen in Berlin\"}\n",[23,2812,2810],{"__ignoreMap":25},[27,2814,2815,2818,2819,2821,2822,2824],{},[70,2816,2817],{},"PDF, AI, EPS and PSD assets are rasterized automatically, server-side"," — you don't need Photoshop or Illustrator installed anywhere in your pipeline to handle a linked PSD or AI file; Bluepic converts it to a print-quality raster the same way it would if you'd flattened it yourself. Anything you don't mention in ",[23,2820,660],{}," keeps its source text, so this is the exact same mechanism used in ",[31,2823,1839],{"href":1838}," — the artwork's origin doesn't change how translation works at all.",[11,2826,2828],{"id":2827},"what-you-get-for-that-five-minutes-of-setup","What you get for that five minutes of setup",[905,2830,2831,2834,2837],{},[908,2832,2833],{},"Every language re-fits into the same text frames automatically — no manual resizing per locale, whether the underlying art came from Figma, Canva, Photoshop or Illustrator.",[908,2835,2836],{},"The artwork itself is never touched or re-generated — you keep full creative control in the tool you already use.",[908,2838,2839],{},"One API call per language, scriptable from wherever your translations already live (a CMS, a spreadsheet, a translation-memory export).",[11,2841,2843],{"id":2842},"what-this-doesnt-do","What this doesn't do",[27,2845,2846],{},"To be precise about the boundary: this doesn't give you live editing of a Figma or Canva design, and it doesn't reach into a PSD's individual layers to translate text baked into the artwork itself (a headline rendered as pixels inside Photoshop, for example, stays exactly as exported — only text frames you add in the InDesign wrapper are translatable). If your source text is baked into the graphic, pull it out into an InDesign text frame once; from then on it's automatable.",[11,2848,903],{"id":902},[905,2850,2851,2857,2862,2867],{},[908,2852,2853,2856],{},[31,2854,2855],{"href":929},"Try the interactive playground"," with a wrapper file built around your own artwork.",[908,2858,368,2859,2861],{},[31,2860,958],{"href":1355}," for the same pattern applied beyond translation — batch variants, personalization, sizes.",[908,2863,1322,2864,2866],{},[31,2865,1325],{"href":929}," for every render option.",[908,2868,2869,2870,2872],{},"If a text frame needs mixed formatting (part bold, a different color), see ",[31,2871,1339],{"href":1338}," for the value shape it needs.",{"title":25,"searchDepth":179,"depth":179,"links":2874},[2875,2876,2877,2878,2879,2880,2881],{"id":2727,"depth":179,"text":2728},{"id":2740,"depth":179,"text":2741},{"id":2785,"depth":179,"text":2786},{"id":2802,"depth":179,"text":2803},{"id":2827,"depth":179,"text":2828},{"id":2842,"depth":179,"text":2843},{"id":902,"depth":179,"text":903},"translate","None of these tools export a translatable, auto-fitting layout — but a thin InDesign wrapper around your existing artwork turns them into one, with zero design rework.","\u002Fdocs-images\u002Ftranslate-figma-photoshop-canva-illustrator.svg",{},{"title":1319,"description":2883},"docs\u002Ftranslate-figma-photoshop-canva-illustrator","f6elZd63ZAIX0wlRSM36INg9ahaOadPcCiLXAAeoPms",{"id":2890,"title":1839,"body":2891,"category":2882,"date":946,"description":3367,"extension":948,"heroImage":3368,"meta":3369,"navigation":951,"path":1838,"readingMinutes":244,"seo":3370,"stem":3371,"tool":1867,"__hash__":3372},"docs\u002Fdocs\u002Ftranslate-indesign-automatically.md",{"type":8,"value":2892,"toc":3357},[2893,2895,2898,2901,2911,2915,2925,2952,2958,2961,2965,2968,2974,2980,2986,2996,3001,3020,3026,3035,3038,3292,3299,3301,3308,3312,3315,3317,3354],[11,2894,964],{"id":963},[27,2896,2897],{},"You design a flyer, a social post, or a data sheet once, in InDesign. Then someone asks for the German version. Then French. Then Polish. German runs roughly 30% longer than English; Polish and French aren't far behind; Chinese often runs shorter. Every one of those languages either overflows the text frame or leaves an awkward gap — because the layout was only ever tuned for the source language.",[27,2899,2900],{},"The usual fixes are manual: a DTP agency rebuilds each language by hand, or someone eyeballs font sizes in InDesign for every locale, every time the copy changes. Neither scales past a handful of languages or a handful of updates.",[27,2902,2903,2904,1044,2907,2910],{},"Bluepic's IDML renderer takes a different approach: export your file as ",[70,2905,2906],{},"IDML",[23,2908,2909],{},"File → Export → InDesign Markup","), hand it to Bluepic, and swap the text per language. The layout engine re-fits every text frame to the size it was actually designed for — automatically, for each language, every time.",[11,2912,2914],{"id":2913},"option-1-do-it-by-hand-in-the-browser","Option 1 — do it by hand, in the browser",[27,2916,2917,2918,2921,2922,2924],{},"The fastest way to see this working is the free converter at ",[31,2919,2920],{"href":2148},"developers.bluepic.io\u002Fidml",". Drop your ",[23,2923,567],{}," (or the whole package folder, so linked images and fonts come along):",[2926,2927,2928,2935,2938,2941],"ol",{},[908,2929,2930,2931,2934],{},"Once it's parsed, the ",[70,2932,2933],{},"Text & overrides"," card shows every text element on the current page, pre-filled with your source copy.",[908,2936,2937],{},"Type your translation directly into any row — the preview on the left updates immediately, live, so you can see the frame re-fit in real time.",[908,2939,2940],{},"Switch pages with the picker in the card header if your document has more than one.",[908,2942,2943,2944,2947,2948,2951],{},"Download the page as PNG, JPEG, SVG or ",[23,2945,2946],{},".bluepic",", or hit ",[70,2949,2950],{},"PDF (all pages)"," once every page looks right.",[27,2953,2954],{},[1510,2955],{"alt":2956,"src":2957},"The Convert tool's Edit & export card, showing the live preview next to editable text rows for every element on the page","\u002Fscreenshots\u002Fconvert-edit-export.png",[27,2959,2960],{},"This is genuinely useful for a one-off translation, or for proving the concept before you wire up automation. But if you're translating the same document into eight languages every month, you want the API.",[11,2962,2964],{"id":2963},"option-2-automate-it-via-the-api","Option 2 — automate it via the API",[27,2966,2967],{},"The render API takes the exact same idea and makes it scriptable. One call:",[16,2969,2972],{"className":2970,"code":2971,"language":21},[19],"POST https:\u002F\u002Fapi.bluepic.io\u002Fapi\u002Fidml\u002Frender\nAuthorization: \u003Cyour API key>            (no \"Bearer \" prefix)\nContent-Type: multipart\u002Fform-data\n\nidml=@brochure.idml\nassets=@hero.jpg\nassets=@Inter.ttf\n",[23,2973,2971],{"__ignoreMap":25},[27,2975,2976,2977,2979],{},"That alone reproduces the source document. To translate it, add one field: ",[23,2978,660],{}," — a JSON object mapping each text element to its translated value:",[16,2981,2984],{"className":2982,"code":2983,"language":21},[19],"textOverrides={\"0:TextFrame_a1b2c3\":\"Willkommen in Berlin\",\"1:TextFrame_d4e5f6\":\"Jetzt entdecken\"}\n",[23,2985,2983],{"__ignoreMap":25},[27,2987,2988,2989,2992,2993,2995],{},"Keys are ",[23,2990,2991],{},"\"\u003CpageIndex>:\u003CelementId>\""," (0-based page index, matching the ",[23,2994,619],{}," you're rendering). Any element you don't mention keeps its source text — so a partial translation is a valid request, not an error.",[2997,2998,3000],"h3",{"id":2999},"where-the-keys-come-from","Where the keys come from",[27,3002,3003,3004,3009,3010,3013,3014,3016,3017,3019],{},"You don't hand-derive those element IDs. Load the same document into the ",[70,3005,3006],{},[31,3007,1289],{"href":3008},"\u002Fidml\u002Fapi#playground",", tick ",[139,3011,3012],{},"\"Override texts with custom values\"",", and it lists every text element on every page with an empty input next to each one. Type anything into a row and watch the generated ",[23,3015,1531],{}," command update live with the exact ",[23,3018,660],{}," JSON — copy that shape once, and you have the keys for every future request against that document.",[27,3021,3022],{},[1510,3023],{"alt":3024,"src":3025},"The API playground's override table — one row per text element, an empty box means \"keep source text\"","\u002Fscreenshots\u002Fapi-override-card.png",[27,3027,3028,3029,3031,3032,3034],{},"Two things worth knowing before you build a translation matrix on top of those keys: the frame's size in InDesign is the hard ceiling German\u002FPolish\u002FFrench get shrunk to fit inside (not just a starting point), and one InDesign text frame doesn't always map to exactly one key — see ",[31,3030,1000],{"href":999}," for both. If a row shows a formatting toolbar instead of a plain box, that element is rich text and needs the array shape from ",[31,3033,1339],{"href":1338}," rather than a plain string.",[27,3036,3037],{},"From there, automating a language is just: keep the keys, swap the values.",[16,3039,3041],{"className":425,"code":3040,"language":427,"meta":25,"style":25},"\u002F\u002F One render per language, same keys, translated values.\nconst translations = {\n  de: { '0:TextFrame_a1b2c3': 'Willkommen in Berlin', '1:TextFrame_d4e5f6': 'Jetzt entdecken' },\n  fr: { '0:TextFrame_a1b2c3': 'Bienvenue à Berlin', '1:TextFrame_d4e5f6': 'Découvrir maintenant' },\n};\n\nfor (const [lang, textOverrides] of Object.entries(translations)) {\n  const form = new FormData();\n  form.append('idml', idmlFile);\n  form.append('assets', heroImage, 'hero.jpg');\n  form.append('assets', interFont, 'Inter.ttf');\n\n  const res = await fetch(\n    `https:\u002F\u002Fapi.bluepic.io\u002Fapi\u002Fidml\u002Frender?format=pdf&textOverrides=${encodeURIComponent(JSON.stringify(textOverrides))}`,\n    { method: 'POST', headers: { Authorization: apiKey }, body: form },\n  );\n  const pdf = await res.blob();\n  \u002F\u002F save `pdf` as `brochure-${lang}.pdf`\n}\n",[23,3042,3043,3048,3059,3084,3107,3112,3116,3149,3163,3176,3194,3212,3216,3230,3254,3262,3266,3283,3288],{"__ignoreMap":25},[169,3044,3045],{"class":171,"line":172},[169,3046,3047],{"class":1030},"\u002F\u002F One render per language, same keys, translated values.\n",[169,3049,3050,3052,3055,3057],{"class":171,"line":179},[169,3051,435],{"class":434},[169,3053,3054],{"class":182}," translations",[169,3056,441],{"class":434},[169,3058,1068],{"class":175},[169,3060,3061,3064,3067,3069,3072,3074,3077,3079,3082],{"class":171,"line":196},[169,3062,3063],{"class":175},"  de: { ",[169,3065,3066],{"class":189},"'0:TextFrame_a1b2c3'",[169,3068,186],{"class":175},[169,3070,3071],{"class":189},"'Willkommen in Berlin'",[169,3073,78],{"class":175},[169,3075,3076],{"class":189},"'1:TextFrame_d4e5f6'",[169,3078,186],{"class":175},[169,3080,3081],{"class":189},"'Jetzt entdecken'",[169,3083,483],{"class":175},[169,3085,3086,3089,3091,3093,3096,3098,3100,3102,3105],{"class":171,"line":205},[169,3087,3088],{"class":175},"  fr: { ",[169,3090,3066],{"class":189},[169,3092,186],{"class":175},[169,3094,3095],{"class":189},"'Bienvenue à Berlin'",[169,3097,78],{"class":175},[169,3099,3076],{"class":189},[169,3101,186],{"class":175},[169,3103,3104],{"class":189},"'Découvrir maintenant'",[169,3106,483],{"class":175},[169,3108,3109],{"class":171,"line":218},[169,3110,3111],{"class":175},"};\n",[169,3113,3114],{"class":171,"line":238},[169,3115,1036],{"emptyLinePlaceholder":951},[169,3117,3118,3120,3122,3124,3127,3130,3132,3134,3137,3140,3143,3146],{"class":171,"line":244},[169,3119,1041],{"class":434},[169,3121,1044],{"class":175},[169,3123,435],{"class":434},[169,3125,3126],{"class":175}," [",[169,3128,3129],{"class":182},"lang",[169,3131,78],{"class":175},[169,3133,660],{"class":182},[169,3135,3136],{"class":175},"] ",[169,3138,3139],{"class":434},"of",[169,3141,3142],{"class":175}," Object.",[169,3144,3145],{"class":447},"entries",[169,3147,3148],{"class":175},"(translations)) {\n",[169,3150,3151,3153,3155,3157,3159,3161],{"class":171,"line":255},[169,3152,1060],{"class":434},[169,3154,1100],{"class":182},[169,3156,441],{"class":434},[169,3158,1105],{"class":434},[169,3160,1108],{"class":447},[169,3162,551],{"class":175},[169,3164,3165,3167,3169,3171,3173],{"class":171,"line":533},[169,3166,1116],{"class":175},[169,3168,1119],{"class":447},[169,3170,451],{"class":175},[169,3172,1124],{"class":189},[169,3174,3175],{"class":175},", idmlFile);\n",[169,3177,3178,3180,3182,3184,3186,3189,3192],{"class":171,"line":1113},[169,3179,1116],{"class":175},[169,3181,1119],{"class":447},[169,3183,451],{"class":175},[169,3185,1139],{"class":189},[169,3187,3188],{"class":175},", heroImage, ",[169,3190,3191],{"class":189},"'hero.jpg'",[169,3193,1692],{"class":175},[169,3195,3196,3198,3200,3202,3204,3207,3210],{"class":171,"line":1130},[169,3197,1116],{"class":175},[169,3199,1119],{"class":447},[169,3201,451],{"class":175},[169,3203,1139],{"class":189},[169,3205,3206],{"class":175},", interFont, ",[169,3208,3209],{"class":189},"'Inter.ttf'",[169,3211,1692],{"class":175},[169,3213,3214],{"class":171,"line":1154},[169,3215,1036],{"emptyLinePlaceholder":951},[169,3217,3218,3220,3222,3224,3226,3228],{"class":171,"line":1159},[169,3219,1060],{"class":434},[169,3221,438],{"class":182},[169,3223,441],{"class":434},[169,3225,444],{"class":434},[169,3227,448],{"class":447},[169,3229,1172],{"class":175},[169,3231,3232,3234,3236,3238,3240,3242,3244,3246,3248,3250,3252],{"class":171,"line":1175},[169,3233,1715],{"class":189},[169,3235,1181],{"class":447},[169,3237,451],{"class":189},[169,3239,491],{"class":182},[169,3241,494],{"class":189},[169,3243,497],{"class":447},[169,3245,451],{"class":189},[169,3247,660],{"class":175},[169,3249,1196],{"class":189},[169,3251,1199],{"class":189},[169,3253,193],{"class":175},[169,3255,3256,3258,3260],{"class":171,"line":1204},[169,3257,1207],{"class":175},[169,3259,465],{"class":189},[169,3261,1212],{"class":175},[169,3263,3264],{"class":171,"line":1215},[169,3265,1218],{"class":175},[169,3267,3268,3270,3273,3275,3277,3279,3281],{"class":171,"line":1221},[169,3269,1060],{"class":434},[169,3271,3272],{"class":182}," pdf",[169,3274,441],{"class":434},[169,3276,444],{"class":434},[169,3278,545],{"class":175},[169,3280,548],{"class":447},[169,3282,551],{"class":175},[169,3284,3285],{"class":171,"line":1226},[169,3286,3287],{"class":1030},"  \u002F\u002F save `pdf` as `brochure-${lang}.pdf`\n",[169,3289,3290],{"class":171,"line":1263},[169,3291,258],{"class":175},[27,3293,3294,3295,3298],{},"Pull the ",[23,3296,3297],{},"translations"," object from wherever your copy already lives — a spreadsheet, a CMS, a translation-memory export, or a machine-translation API you run once and review. Bluepic's job is the layout, not the translation itself; feed it whatever text you trust.",[2997,3300,34],{"id":796},[27,3302,799,3303,3305,3306,494],{},[70,3304,802],{}," — 1 credit per rendered page, regardless of how many text overrides you send. Six pages in five languages is 30 rendered outputs, i.e. 30 credits. Check your balance any time on the ",[31,3307,124],{"href":123},[11,3309,3311],{"id":3310},"what-auto-fit-actually-means","What \"auto-fit\" actually means",[27,3313,3314],{},"There's an honest caveat here worth stating plainly: there's no such thing as the \"correct\" InDesign rendering of your German copy — nobody ever laid that version out by hand. What Bluepic's engine does is re-run the same fit\u002Fshrink logic InDesign itself uses for auto-sizing text, against the real translated string, using real font metrics. It's layout-faithful to the ORIGINAL design's intent, not a pixel-for-pixel guess at what a human designer would have done differently for a 30%-longer string. For most marketing collateral — flyers, social posts, data sheets — that's exactly what you want: the master layout, honored, in every language.",[11,3316,903],{"id":902},[905,3318,3319,3324,3342,3347],{},[908,3320,3321,3323],{},[31,3322,2855],{"href":929}," and get your API key (issued automatically on first use).",[908,3325,1322,3326,3328,3329,78,3331,78,3333,78,3335,78,3337,1931,3339,3341],{},[31,3327,1325],{"href":929}," for every render option (",[23,3330,319],{},[23,3332,619],{},[23,3334,400],{},[23,3336,353],{},[23,3338,380],{},[23,3340,384],{},").",[908,3343,368,3344,3346],{},[31,3345,671],{"href":670}," for the same API used beyond translation — batch variants, dynamic fields, personalization.",[908,3348,3349,807,3351,3353],{},[31,3350,1000],{"href":999},[31,3352,1339],{"href":1338}," — the two things worth knowing before you scale this to a real translation matrix.",[932,3355,3356],{},"html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}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);}",{"title":25,"searchDepth":179,"depth":179,"links":3358},[3359,3360,3361,3365,3366],{"id":963,"depth":179,"text":964},{"id":2913,"depth":179,"text":2914},{"id":2963,"depth":179,"text":2964,"children":3362},[3363,3364],{"id":2999,"depth":196,"text":3000},{"id":796,"depth":196,"text":34},{"id":3310,"depth":179,"text":3311},{"id":902,"depth":179,"text":903},"Turn one InDesign master layout into every language you need, with the text re-fit automatically — by hand in the browser, or by API for real automation.","\u002Fdocs-images\u002Ftranslate-indesign-automatically.svg",{},{"title":1839,"description":3367},"docs\u002Ftranslate-indesign-automatically","8OtyQR6hx8WL1xqNnsqAuysFyKcRXP0Ipezhlwsiq1Y",1784233655087]