{"id":823,"date":"2025-08-07T21:43:30","date_gmt":"2025-08-08T04:43:30","guid":{"rendered":"https:\/\/lampwrite.com\/j\/?page_id=823"},"modified":"2025-08-13T14:36:06","modified_gmt":"2025-08-13T21:36:06","slug":"composite-layering-of-a-vector-drawing-application-with-glsl-and-a-high-fidelity-rip-ready-file-pipeline","status":"publish","type":"page","link":"https:\/\/lampwrite.com\/j\/composite-layering-of-a-vector-drawing-application-with-glsl-and-a-high-fidelity-rip-ready-file-pipeline\/","title":{"rendered":"Composite layering of a vector-drawing application with GLSL and a high fidelity RIP-ready pipeline"},"content":{"rendered":"\n<p>This article covers technical and architectural choices in modern web-based design tooling for applications requiring high fidelity, including print.<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"832\" height=\"444\" src=\"https:\/\/lampwrite.com\/j\/wp-content\/uploads\/2025\/08\/VSX_GoldFoil.gif\" alt=\"\" class=\"wp-image-803\"\/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>Geo\/GIS applications, light-sensing applications, medical imaging, and print applications handle data that cannot be accurately represented by static, 2D RGB screens.<\/p>\n\n\n\n<p>Within print, we have CMYK coloring that can fall outside of the sRGB gamut, spot colors, pantones, and specialty ink, including neon and UV reactive, foil masks, embossed and other surface-deforming alterations, and specular modifications including UV spot and other effects, like matte, semi-gloss and gloss finishes. These can be approximated for non-professional users.<\/p>\n\n\n\n<p>Shown above is the accompanying demo application, which shows an exaggerated gold foil effect written in OpenGL&#8217;s graphic shader language being composited over a Fabric.JS instance with a custom interface.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Demo Coverage<\/h2>\n\n\n\n<p>Supplied with the demo are three novel libraries created to demonstrate the principles behind composite applications with end-user friendly wizards.<\/p>\n\n\n\n<p>* <strong>Builder<\/strong>, an assembly for converting masked shapes and managing graphcs shaders),<br>\n* <strong>precision slider<\/strong> &#8211; a micro-ui element,<br>\n* <strong>Tiff-Writer<\/strong>, which exports high-fidelity TIFF files with embedded, editable multi-channel spot color channels.<\/p>\n\n\n\n<p>Not included: Spot Registry, allowing mapping to 5+ color digital presses with formatted asset bundles with uncompressed 300 DPI resolution and embedded ICC profiles for reproduction.<\/p>\n\n\n\n<p>&nbsp;<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">System Architecture<\/h2>\n\n\n\n<p>This is an interactive graph. Click any cell for more information. The bulk of the technical content of this article can be navigated within this graph. <\/p>\n\n\n\t<SECTION class=\"grapham-plugin\">\n\n\t\t<div\n\t\t\t\tclass=\"wp-block-grapham-diagram grapham-plugin\"\n\t\t\t\tdata-xml-b64=\"PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPG14ZmlsZSBob3N0PSJhcHAuZGlhZ3JhbXMubmV0IiBhZ2VudD0iTW96aWxsYS81LjAgKFgxMTsgTGludXggeDg2XzY0OyBydjoxMzQuMCkgR2Vja28vMjAxMDAxMDEgRmlyZWZveC8xMzQuMCIgdmVyc2lvbj0iMjguMC42Ij4KICA8ZGlhZ3JhbSBuYW1lPSJQYWdlLTEiIGlkPSJ3S3VpVDhqVzRNaEhobk8xM2wyeSI+CiAgICA8bXhHcmFwaE1vZGVsIGR4PSIxMDQzIiBkeT0iNTgzIiBncmlkPSIxIiBncmlkU2l6ZT0iMTAiIGd1aWRlcz0iMSIgdG9vbHRpcHM9IjEiIGNvbm5lY3Q9IjEiIGFycm93cz0iMSIgZm9sZD0iMSIgcGFnZT0iMSIgcGFnZVNjYWxlPSIxIiBwYWdlV2lkdGg9Ijg1MCIgcGFnZUhlaWdodD0iMTEwMCIgbWF0aD0iMCIgc2hhZG93PSIwIj4KICAgICAgPHJvb3Q+CiAgICAgICAgPG14Q2VsbCBpZD0iMCIgLz4KICAgICAgICA8bXhDZWxsIGlkPSIxIiBwYXJlbnQ9IjAiIC8+CiAgICAgICAgPG14Q2VsbCBpZD0iVEtwT25zS3phOWlvc1hTaGx4eWQtMzkiIHZhbHVlPSIiIHN0eWxlPSJ3aGl0ZVNwYWNlPXdyYXA7aHRtbD0xO3NoYXBlPW14Z3JhcGguYmFzaWMuZG9jdW1lbnQiIHZlcnRleD0iMSIgcGFyZW50PSIxIj4KICAgICAgICAgIDxteEdlb21ldHJ5IHg9IjU1MCIgeT0iMzM5IiB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgYXM9Imdlb21ldHJ5IiAvPgogICAgICAgIDwvbXhDZWxsPgogICAgICAgIDxteENlbGwgaWQ9IlRLcE9uc0t6YTlpb3NYU2hseHlkLTM1IiB2YWx1ZT0iIiBzdHlsZT0icm91bmRlZD0wO3doaXRlU3BhY2U9d3JhcDtodG1sPTE7IiB2ZXJ0ZXg9IjEiIHBhcmVudD0iMSI+CiAgICAgICAgICA8bXhHZW9tZXRyeSB4PSIzOTAiIHk9IjMwIiB3aWR0aD0iMjcwIiBoZWlnaHQ9IjI5MCIgYXM9Imdlb21ldHJ5IiAvPgogICAgICAgIDwvbXhDZWxsPgogICAgICAgIDxteENlbGwgaWQ9IlRLcE9uc0t6YTlpb3NYU2hseHlkLTMxIiB2YWx1ZT0iIiBzdHlsZT0id2hpdGVTcGFjZT13cmFwO2h0bWw9MTtzaGFwZT1teGdyYXBoLmJhc2ljLmRvY3VtZW50IiB2ZXJ0ZXg9IjEiIHBhcmVudD0iMSI+CiAgICAgICAgICA8bXhHZW9tZXRyeSB4PSI0MTIiIHk9IjMzOSIgd2lkdGg9IjEwMCIgaGVpZ2h0PSIxMDAiIGFzPSJnZW9tZXRyeSIgLz4KICAgICAgICA8L214Q2VsbD4KICAgICAgICA8bXhDZWxsIGlkPSJUS3BPbnNLemE5aW9zWFNobHh5ZC0xNSIgdmFsdWU9IiIgc3R5bGU9InJvdW5kZWQ9MDt3aGl0ZVNwYWNlPXdyYXA7aHRtbD0xOyIgdmVydGV4PSIxIiBwYXJlbnQ9IjEiPgogICAgICAgICAgPG14R2VvbWV0cnkgeD0iMTQwIiB5PSIzMCIgd2lkdGg9IjIwMCIgaGVpZ2h0PSIyMjgiIGFzPSJnZW9tZXRyeSIgLz4KICAgICAgICA8L214Q2VsbD4KICAgICAgICA8bXhDZWxsIGlkPSJUS3BPbnNLemE5aW9zWFNobHh5ZC0xIiB2YWx1ZT0iJmx0O2RpdiZndDtmYWJyaWMuanMgbG93ZXJDYW52YXMmbHQ7L2RpdiZndDsiIHN0eWxlPSJyb3VuZGVkPTA7d2hpdGVTcGFjZT13cmFwO2h0bWw9MTtmaWxsQ29sb3I9I2Q1ZThkNDtzdHJva2VDb2xvcj0jODJiMzY2OyIgdmVydGV4PSIxIiBwYXJlbnQ9IjEiPgogICAgICAgICAgPG14R2VvbWV0cnkgeD0iMTYwIiB5PSIxOTgiIHdpZHRoPSIxNjAiIGhlaWdodD0iNDAiIGFzPSJnZW9tZXRyeSIgLz4KICAgICAgICA8L214Q2VsbD4KICAgICAgICA8bXhDZWxsIGlkPSJUS3BPbnNLemE5aW9zWFNobHh5ZC0yIiB2YWx1ZT0iV2ViR0wyIENhbnZhcyIgc3R5bGU9InJvdW5kZWQ9MDt3aGl0ZVNwYWNlPXdyYXA7aHRtbD0xO2ZpbGxDb2xvcj0jZGFlOGZjO3N0cm9rZUNvbG9yPSM2YzhlYmY7IiB2ZXJ0ZXg9IjEiIHBhcmVudD0iMSI+CiAgICAgICAgICA8bXhHZW9tZXRyeSB4PSIxNjAiIHk9Ijc4IiB3aWR0aD0iMTYwIiBoZWlnaHQ9IjYyIiBhcz0iZ2VvbWV0cnkiIC8+CiAgICAgICAgPC9teENlbGw+CiAgICAgICAgPG14Q2VsbCBpZD0iVEtwT25zS3phOWlvc1hTaGx4eWQtMyIgdmFsdWU9IiZsdDtkaXYgYWxpZ249JnF1b3Q7bGVmdCZxdW90OyZndDtiaXRtYXNrIHN0YWNrIHgwJmx0Oy9kaXYmZ3Q7IiBzdHlsZT0icm91bmRlZD0wO3doaXRlU3BhY2U9d3JhcDtodG1sPTE7ZmlsbENvbG9yPSNmZmYyY2M7c3Ryb2tlQ29sb3I9I2Q2YjY1NjthbGlnbj1sZWZ0OyIgdmVydGV4PSIxIiBwYXJlbnQ9IjEiPgogICAgICAgICAgPG14R2VvbWV0cnkgeD0iNDAyIiB5PSIxNjkuNSIgd2lkdGg9IjEyMCIgaGVpZ2h0PSIzMiIgYXM9Imdlb21ldHJ5IiAvPgogICAgICAgIDwvbXhDZWxsPgogICAgICAgIDxteENlbGwgaWQ9IlRLcE9uc0t6YTlpb3NYU2hseHlkLTUiIHZhbHVlPSImbHQ7ZGl2IGFsaWduPSZxdW90O3JpZ2h0JnF1b3Q7Jmd0O2JpdG1hc2sgc3RhY2sgeE4tMSZsdDsvZGl2Jmd0OyIgc3R5bGU9InJvdW5kZWQ9MDt3aGl0ZVNwYWNlPXdyYXA7aHRtbD0xO2ZpbGxDb2xvcj0jZTFkNWU3O3N0cm9rZUNvbG9yPSM5NjczYTY7YWxpZ249cmlnaHQ7IiB2ZXJ0ZXg9IjEiIHBhcmVudD0iMSI+CiAgICAgICAgICA8bXhHZW9tZXRyeSB4PSI1MjIiIHk9IjE3MCIgd2lkdGg9IjEyMCIgaGVpZ2h0PSIzMS41IiBhcz0iZ2VvbWV0cnkiIC8+CiAgICAgICAgPC9teENlbGw+CiAgICAgICAgPG14Q2VsbCBpZD0iVEtwT25zS3phOWlvc1hTaGx4eWQtNiIgdmFsdWU9IiIgc3R5bGU9InNoYXBlPWZsZXhBcnJvdztlbmRBcnJvdz1jbGFzc2ljO2h0bWw9MTtyb3VuZGVkPTA7ZmlsbENvbG9yPSNmZmYyY2M7c3Ryb2tlQ29sb3I9I2Q2YjY1NjsiIGVkZ2U9IjEiIHBhcmVudD0iMSI+CiAgICAgICAgICA8bXhHZW9tZXRyeSB3aWR0aD0iNTAiIGhlaWdodD0iNTAiIHJlbGF0aXZlPSIxIiBhcz0iZ2VvbWV0cnkiPgogICAgICAgICAgICA8bXhQb2ludCB4PSIzMjAiIHk9IjE4Mi4zMSIgYXM9InNvdXJjZVBvaW50IiAvPgogICAgICAgICAgICA8bXhQb2ludCB4PSI0MDAiIHk9IjE4Mi4zMSIgYXM9InRhcmdldFBvaW50IiAvPgogICAgICAgICAgPC9teEdlb21ldHJ5PgogICAgICAgIDwvbXhDZWxsPgogICAgICAgIDxteENlbGwgaWQ9IlRLcE9uc0t6YTlpb3NYU2hseHlkLTgiIHZhbHVlPSImbHQ7YnImZ3Q7Jmx0O2JyJmd0OyZsdDticiZndDsmbHQ7YnImZ3Q7Jmx0O2JyJmd0OyZsdDtkaXYmZ3Q7cHJpdmF0ZSBUSUZGIFNWRyBDQU5WQVMgKHJlYWwgZGltZW5zaW9ucykmbHQ7L2RpdiZndDsiIHN0eWxlPSJyb3VuZGVkPTA7d2hpdGVTcGFjZT13cmFwO2h0bWw9MTtmaWxsQ29sb3I9I2Y1ZjVmNTtzdHJva2VDb2xvcj0jNjY2NjY2O2ZvbnRDb2xvcj0jMzMzMzMzOyIgdmVydGV4PSIxIiBwYXJlbnQ9IjEiPgogICAgICAgICAgPG14R2VvbWV0cnkgeD0iMTEwIiB5PSIyOTAiIHdpZHRoPSIyNTAiIGhlaWdodD0iMTIwIiBhcz0iZ2VvbWV0cnkiIC8+CiAgICAgICAgPC9teENlbGw+CiAgICAgICAgPG14Q2VsbCBpZD0iVEtwT25zS3phOWlvc1hTaGx4eWQtOSIgdmFsdWU9IiZsdDtkaXYgYWxpZ249JnF1b3Q7cmlnaHQmcXVvdDsmZ3Q7QnVpbGRlci5qcyBzaGFkZXIgcGlwZWxpbmUgJmx0O2JyJmd0OyZsdDsvZGl2Jmd0OyIgc3R5bGU9InJvdW5kZWQ9MDt3aGl0ZVNwYWNlPXdyYXA7aHRtbD0xO2ZpbGxDb2xvcj0jZTFkNWU3O3N0cm9rZUNvbG9yPSM5NjczYTY7YWxpZ249cmlnaHQ7IiB2ZXJ0ZXg9IjEiIHBhcmVudD0iMSI+CiAgICAgICAgICA8bXhHZW9tZXRyeSB4PSI0MDIiIHk9IjEzNi41IiB3aWR0aD0iMjQwIiBoZWlnaHQ9IjMzIiBhcz0iZ2VvbWV0cnkiIC8+CiAgICAgICAgPC9teENlbGw+CiAgICAgICAgPG14Q2VsbCBpZD0iVEtwT25zS3phOWlvc1hTaGx4eWQtMTAiIHZhbHVlPSIiIHN0eWxlPSJodG1sPTE7c2hhZG93PTA7ZGFzaGVkPTA7YWxpZ249Y2VudGVyO3ZlcnRpY2FsQWxpZ249bWlkZGxlO3NoYXBlPW14Z3JhcGguYXJyb3dzMi5iZW5kQXJyb3c7ZHk9Ny44ODtkeD0yNC41OTtub3RjaD0wO2Fycm93SGVhZD0zNS4yODtyb3VuZGVkPTA7ZmxpcEg9MTtyb3RhdGlvbj0tOTA7ZmlsbENvbG9yPSNmZmYyY2M7c3Ryb2tlQ29sb3I9I2Q2YjY1NjsiIHZlcnRleD0iMSIgcGFyZW50PSIxIj4KICAgICAgICAgIDxteEdlb21ldHJ5IHg9Ijg1IiB5PSIyMDgiIHdpZHRoPSIxMTAiIGhlaWdodD0iNTAiIGFzPSJnZW9tZXRyeSIgLz4KICAgICAgICA8L214Q2VsbD4KICAgICAgICA8bXhDZWxsIGlkPSJUS3BPbnNLemE5aW9zWFNobHh5ZC0xMiIgdmFsdWU9IiZsdDtkaXYgYWxpZ249JnF1b3Q7bGVmdCZxdW90OyZndDtGb2lsLCBzcG90LCBhbmQgZW1ib3NzIHpvbmVzIGdlbmVyYXRlIGJpdG1hc2sgY2xpcHMgZm9yIGVhY2ggc3BlY2lhbCBlZmZlY3QgY2xhc3MuJmx0O2JyJmd0OyZsdDticiZndDtBbGwgbWV0aG9kcyB0aGF0IG1vZGlmeSBvciBhbHRlciB0aGUgb3V0bGluZSBvciBwb3NpdGlvbiBvZiBhbiBlZmZlY3QgbWFyayB0aGUgY2FudmFzIG1hcHMgYXMgb3V0ZGF0ZWQuIEZhYnJpYyYjMzk7cyAmbHQ7c3BhbiBzdHlsZT0mcXVvdDtjb2xvcjogcmdiKDI1NSwgMTI1LCAxMjUpOyZxdW90OyZndDthZnRlcjpyZW5kZXImbHQ7L3NwYW4mZ3Q7IHJlc2FtcGxlcyB0aGUgbWFza3MgYW5kIHBhc3NlcyB0aGVtIGJhY2sgdG8gQnVpbGRlciAmYW1wO25ic3A7ICZsdDsvZGl2Jmd0OyIgc3R5bGU9InRleHQ7aHRtbD0xO2FsaWduPWxlZnQ7dmVydGljYWxBbGlnbj1taWRkbGU7d2hpdGVTcGFjZT13cmFwO3JvdW5kZWQ9MDsiIHZlcnRleD0iMSIgcGFyZW50PSIxIj4KICAgICAgICAgIDxteEdlb21ldHJ5IHg9IjQwMCIgeT0iMjA4IiB3aWR0aD0iMjUwIiBoZWlnaHQ9IjExMCIgYXM9Imdlb21ldHJ5IiAvPgogICAgICAgIDwvbXhDZWxsPgogICAgICAgIDxteENlbGwgaWQ9IlRLcE9uc0t6YTlpb3NYU2hseHlkLTEzIiB2YWx1ZT0iUmVuZGVyaW5nIFN0YWNrIiBzdHlsZT0idGV4dDtzdHJva2VDb2xvcj1ub25lO2ZpbGxDb2xvcj1ub25lO2h0bWw9MTtmb250U2l6ZT0yNDtmb250U3R5bGU9MTt2ZXJ0aWNhbEFsaWduPW1pZGRsZTthbGlnbj1jZW50ZXI7IiB2ZXJ0ZXg9IjEiIHBhcmVudD0iMSI+CiAgICAgICAgICA8bXhHZW9tZXRyeSB4PSIxOTAiIHk9IjM4IiB3aWR0aD0iMTAwIiBoZWlnaHQ9IjQwIiBhcz0iZ2VvbWV0cnkiIC8+CiAgICAgICAgPC9teENlbGw+CiAgICAgICAgPG14Q2VsbCBpZD0iVEtwT25zS3phOWlvc1hTaGx4eWQtMTYiIHZhbHVlPSJpbnZpc2libGUgbWFzayBvYmplY3RzIiBzdHlsZT0icm91bmRlZD0wO3doaXRlU3BhY2U9d3JhcDtodG1sPTE7ZmlsbENvbG9yPSNmZmYyY2M7c3Ryb2tlQ29sb3I9I2Q2YjY1NjsiIHZlcnRleD0iMSIgcGFyZW50PSIxIj4KICAgICAgICAgIDxteEdlb21ldHJ5IHg9IjE2MCIgeT0iMTY4IiB3aWR0aD0iMTYwIiBoZWlnaHQ9IjMwIiBhcz0iZ2VvbWV0cnkiIC8+CiAgICAgICAgPC9teENlbGw+CiAgICAgICAgPG14Q2VsbCBpZD0iVEtwT25zS3phOWlvc1hTaGx4eWQtMTkiIHZhbHVlPSJmYWJyaWMuanMgVUkgdXBwZXJDYW52YXMiIHN0eWxlPSJyb3VuZGVkPTA7d2hpdGVTcGFjZT13cmFwO2h0bWw9MTtmaWxsQ29sb3I9I2Q1ZThkNDtzdHJva2VDb2xvcj0jODJiMzY2OyIgdmVydGV4PSIxIiBwYXJlbnQ9IjEiPgogICAgICAgICAgPG14R2VvbWV0cnkgeD0iMTYwIiB5PSIxMzgiIHdpZHRoPSIxNjAiIGhlaWdodD0iMzAiIGFzPSJnZW9tZXRyeSIgLz4KICAgICAgICA8L214Q2VsbD4KICAgICAgICA8bXhDZWxsIGlkPSJUS3BPbnNLemE5aW9zWFNobHh5ZC0yMCIgdmFsdWU9IiIgc3R5bGU9Imh0bWw9MTtzaGFkb3c9MDtkYXNoZWQ9MDthbGlnbj1jZW50ZXI7dmVydGljYWxBbGlnbj1taWRkbGU7c2hhcGU9bXhncmFwaC5hcnJvd3MyLmJlbmRBcnJvdztkeT03Ljg4O2R4PTI0LjU5O25vdGNoPTA7YXJyb3dIZWFkPTM1LjI4O3JvdW5kZWQ9MDtmbGlwSD0xO3JvdGF0aW9uPTA7ZmlsbENvbG9yPSNlMWQ1ZTc7c3Ryb2tlQ29sb3I9Izk2NzNhNjsiIHZlcnRleD0iMSIgcGFyZW50PSIxIj4KICAgICAgICAgIDxteEdlb21ldHJ5IHg9IjMyMCIgeT0iODYuNSIgd2lkdGg9IjExMCIgaGVpZ2h0PSI1MCIgYXM9Imdlb21ldHJ5IiAvPgogICAgICAgIDwvbXhDZWxsPgogICAgICAgIDxteENlbGwgaWQ9IlRLcE9uc0t6YTlpb3NYU2hseHlkLTIyIiB2YWx1ZT0iUkdCIiBzdHlsZT0id2hpdGVTcGFjZT13cmFwO2h0bWw9MTthc3BlY3Q9Zml4ZWQ7IiB2ZXJ0ZXg9IjEiIHBhcmVudD0iMSI+CiAgICAgICAgICA8bXhHZW9tZXRyeSB4PSIxNjAiIHk9IjI5MCIgd2lkdGg9IjQwIiBoZWlnaHQ9IjQwIiBhcz0iZ2VvbWV0cnkiIC8+CiAgICAgICAgPC9teENlbGw+CiAgICAgICAgPG14Q2VsbCBpZD0iVEtwT25zS3phOWlvc1hTaGx4eWQtMjQiIHZhbHVlPSIiIHN0eWxlPSJzaGFwZT1mbGV4QXJyb3c7ZW5kQXJyb3c9Y2xhc3NpYztodG1sPTE7cm91bmRlZD0wO2ZpbGxDb2xvcj0jZDVlOGQ0O3N0cm9rZUNvbG9yPSM4MmIzNjY7ZW50cnlYPTAuNTtlbnRyeVk9MDtlbnRyeUR4PTA7ZW50cnlEeT0wO2V4aXRYPTAuMTI4O2V4aXRZPTAuOTkyO2V4aXREeD0wO2V4aXREeT0wO2V4aXRQZXJpbWV0ZXI9MDsiIGVkZ2U9IjEiIHBhcmVudD0iMSIgc291cmNlPSJUS3BPbnNLemE5aW9zWFNobHh5ZC0xIiB0YXJnZXQ9IlRLcE9uc0t6YTlpb3NYU2hseHlkLTIyIj4KICAgICAgICAgIDxteEdlb21ldHJ5IHdpZHRoPSI1MCIgaGVpZ2h0PSI1MCIgcmVsYXRpdmU9IjEiIGFzPSJnZW9tZXRyeSI+CiAgICAgICAgICAgIDxteFBvaW50IHg9IjI3MCIgeT0iMjgwIiBhcz0ic291cmNlUG9pbnQiIC8+CiAgICAgICAgICAgIDxteFBvaW50IHg9IjI3MCIgeT0iMjcwIiBhcz0idGFyZ2V0UG9pbnQiIC8+CiAgICAgICAgICA8L214R2VvbWV0cnk+CiAgICAgICAgPC9teENlbGw+CiAgICAgICAgPG14Q2VsbCBpZD0iVEtwT25zS3phOWlvc1hTaGx4eWQtMjUiIHZhbHVlPSJTcG90cyAmYW1wO2FtcDsgTWFza3MiIHN0eWxlPSJyb3VuZGVkPTA7d2hpdGVTcGFjZT13cmFwO2h0bWw9MTsiIHZlcnRleD0iMSIgcGFyZW50PSIxIj4KICAgICAgICAgIDxteEdlb21ldHJ5IHg9IjExMCIgeT0iMjkwIiB3aWR0aD0iNTAiIGhlaWdodD0iNDAiIGFzPSJnZW9tZXRyeSIgLz4KICAgICAgICA8L214Q2VsbD4KICAgICAgICA8bXhDZWxsIGlkPSJUS3BPbnNLemE5aW9zWFNobHh5ZC0yNyIgdmFsdWU9IiIgc3R5bGU9InNrZXRjaD0wO2FzcGVjdD1maXhlZDtwb2ludGVyRXZlbnRzPTE7c2hhZG93PTA7ZGFzaGVkPTA7aHRtbD0xO2xhYmVsUG9zaXRpb249Y2VudGVyO3ZlcnRpY2FsTGFiZWxQb3NpdGlvbj1ib3R0b207dmVydGljYWxBbGlnbj10b3A7YWxpZ249Y2VudGVyO3NoYXBlPW14Z3JhcGgubXNjYWUuZW50ZXJwcmlzZS5jb2RlX2ZpbGU7ZmlsbENvbG9yPSNlMWQ1ZTc7c3Ryb2tlQ29sb3I9Izk2NzNhNjsiIHZlcnRleD0iMSIgcGFyZW50PSIxIj4KICAgICAgICAgIDxteEdlb21ldHJ5IHg9IjQ1NC41NTk5OTk5OTk5OTk5NSIgeT0iOTguMzAwMDAwMDAwMDAwMDEiIHdpZHRoPSIzNy40NCIgaGVpZ2h0PSIzOC4yIiBhcz0iZ2VvbWV0cnkiIC8+CiAgICAgICAgPC9teENlbGw+CiAgICAgICAgPG14Q2VsbCBpZD0iVEtwT25zS3phOWlvc1hTaGx4eWQtMjgiIHZhbHVlPSJUaWZmV3JpdGVyIDo6ICZsdDtzcGFuIHN0eWxlPSZxdW90O2NvbG9yOiByZ2IoNzksIDMyLCAzMik7JnF1b3Q7Jmd0O2VuY29kZShvcHRzKSZsdDsvc3BhbiZndDsiIHN0eWxlPSJyb3VuZGVkPTA7d2hpdGVTcGFjZT13cmFwO2h0bWw9MTtmaWxsQ29sb3I9I2JhYzhkMztzdHJva2VDb2xvcj0jMjM0NDVkOyIgdmVydGV4PSIxIiBwYXJlbnQ9IjEiPgogICAgICAgICAgPG14R2VvbWV0cnkgeD0iMTEwIiB5PSI0MTAiIHdpZHRoPSIyNTAiIGhlaWdodD0iMzAiIGFzPSJnZW9tZXRyeSIgLz4KICAgICAgICA8L214Q2VsbD4KICAgICAgICA8bXhDZWxsIGlkPSJUS3BPbnNLemE5aW9zWFNobHh5ZC0yOSIgdmFsdWU9IiIgc3R5bGU9InNoYXBlPWZsZXhBcnJvdztlbmRBcnJvdz1jbGFzc2ljO2h0bWw9MTtyb3VuZGVkPTA7ZmlsbENvbG9yPSNiYWM4ZDM7c3Ryb2tlQ29sb3I9IzIzNDQ1ZDtleGl0WD0wLjEyODtleGl0WT0wLjk5MjtleGl0RHg9MDtleGl0RHk9MDtleGl0UGVyaW1ldGVyPTA7IiBlZGdlPSIxIiBwYXJlbnQ9IjEiPgogICAgICAgICAgPG14R2VvbWV0cnkgd2lkdGg9IjUwIiBoZWlnaHQ9IjUwIiByZWxhdGl2ZT0iMSIgYXM9Imdlb21ldHJ5Ij4KICAgICAgICAgICAgPG14UG9pbnQgeD0iMzYwIiB5PSI0MjQuNzYiIGFzPSJzb3VyY2VQb2ludCIgLz4KICAgICAgICAgICAgPG14UG9pbnQgeD0iNDAwIiB5PSI0MjUiIGFzPSJ0YXJnZXRQb2ludCIgLz4KICAgICAgICAgIDwvbXhHZW9tZXRyeT4KICAgICAgICA8L214Q2VsbD4KICAgICAgICA8bXhDZWxsIGlkPSJUS3BPbnNLemE5aW9zWFNobHh5ZC0zMCIgdmFsdWU9IlRJRkYgdy8gU2FtcGxlcyIgc3R5bGU9InJvdW5kZWQ9MDt3aGl0ZVNwYWNlPXdyYXA7aHRtbD0xO2ZpbGxDb2xvcj0jZmZmMmNjO3N0cm9rZUNvbG9yPSNkNmI2NTY7IiB2ZXJ0ZXg9IjEiIHBhcmVudD0iMSI+CiAgICAgICAgICA8bXhHZW9tZXRyeSB4PSI0MDAiIHk9IjQxMCIgd2lkdGg9IjEyMCIgaGVpZ2h0PSIzMCIgYXM9Imdlb21ldHJ5IiAvPgogICAgICAgIDwvbXhDZWxsPgogICAgICAgIDxteENlbGwgaWQ9IlRLcE9uc0t6YTlpb3NYU2hseHlkLTMzIiB2YWx1ZT0iIiBzdHlsZT0iZWRnZVN0eWxlPW9ydGhvZ29uYWxFZGdlU3R5bGU7cm91bmRlZD0wO29ydGhvZ29uYWxMb29wPTE7amV0dHlTaXplPWF1dG87aHRtbD0xOyIgZWRnZT0iMSIgcGFyZW50PSIxIiBzb3VyY2U9IlRLcE9uc0t6YTlpb3NYU2hseHlkLTMyIiB0YXJnZXQ9IlRLcE9uc0t6YTlpb3NYU2hseHlkLTI1Ij4KICAgICAgICAgIDxteEdlb21ldHJ5IHJlbGF0aXZlPSIxIiBhcz0iZ2VvbWV0cnkiIC8+CiAgICAgICAgPC9teENlbGw+CiAgICAgICAgPG14Q2VsbCBpZD0iVEtwT25zS3phOWlvc1hTaGx4eWQtMzIiIHZhbHVlPSJTcG90IFJlZ2lzdHJ5IiBzdHlsZT0ic2hhcGU9Y3lsaW5kZXIzO3doaXRlU3BhY2U9d3JhcDtodG1sPTE7Ym91bmRlZExibD0xO2JhY2tncm91bmRPdXRsaW5lPTE7c2l6ZT0xNTsiIHZlcnRleD0iMSIgcGFyZW50PSIxIj4KICAgICAgICAgIDxteEdlb21ldHJ5IHg9IjI1IiB5PSIyNzUiIHdpZHRoPSI2MCIgaGVpZ2h0PSI3MCIgYXM9Imdlb21ldHJ5IiAvPgogICAgICAgIDwvbXhDZWxsPgogICAgICAgIDxteENlbGwgaWQ9IlRLcE9uc0t6YTlpb3NYU2hseHlkLTM0IiB2YWx1ZT0iV2ViR0wgKyBVbmlmb3JtcyIgc3R5bGU9InRleHQ7c3Ryb2tlQ29sb3I9bm9uZTtmaWxsQ29sb3I9bm9uZTtodG1sPTE7Zm9udFNpemU9MjQ7Zm9udFN0eWxlPTE7dmVydGljYWxBbGlnbj1taWRkbGU7YWxpZ249Y2VudGVyOyIgdmVydGV4PSIxIiBwYXJlbnQ9IjEiPgogICAgICAgICAgPG14R2VvbWV0cnkgeD0iNDgwIiB5PSIzOCIgd2lkdGg9IjEwMCIgaGVpZ2h0PSI0MCIgYXM9Imdlb21ldHJ5IiAvPgogICAgICAgIDwvbXhDZWxsPgogICAgICAgIDxteENlbGwgaWQ9IlRLcE9uc0t6YTlpb3NYU2hseHlkLTM3IiB2YWx1ZT0iLnRpZiIgc3R5bGU9InRleHQ7c3Ryb2tlQ29sb3I9bm9uZTtmaWxsQ29sb3I9bm9uZTtodG1sPTE7Zm9udFNpemU9MjQ7Zm9udFN0eWxlPTE7dmVydGljYWxBbGlnbj1taWRkbGU7YWxpZ249Y2VudGVyOyIgdmVydGV4PSIxIiBwYXJlbnQ9IjEiPgogICAgICAgICAgPG14R2VvbWV0cnkgeD0iNDEwIiB5PSIzNjAiIHdpZHRoPSIxMDAiIGhlaWdodD0iNDAiIGFzPSJnZW9tZXRyeSIgLz4KICAgICAgICA8L214Q2VsbD4KICAgICAgICA8bXhDZWxsIGlkPSJUS3BPbnNLemE5aW9zWFNobHh5ZC0zOCIgdmFsdWU9IkFsdGVybmF0aXZlIE91dHB1dCIgc3R5bGU9InJvdW5kZWQ9MDt3aGl0ZVNwYWNlPXdyYXA7aHRtbD0xO2ZpbGxDb2xvcj0jZmZmMmNjO3N0cm9rZUNvbG9yPSNkNmI2NTY7IiB2ZXJ0ZXg9IjEiIHBhcmVudD0iMSI+CiAgICAgICAgICA8bXhHZW9tZXRyeSB4PSI1NDAiIHk9IjQxMCIgd2lkdGg9IjEyMCIgaGVpZ2h0PSIzMCIgYXM9Imdlb21ldHJ5IiAvPgogICAgICAgIDwvbXhDZWxsPgogICAgICAgIDxteENlbGwgaWQ9IlRLcE9uc0t6YTlpb3NYU2hseHlkLTQwIiB2YWx1ZT0iLnBkZiIgc3R5bGU9InRleHQ7c3Ryb2tlQ29sb3I9bm9uZTtmaWxsQ29sb3I9bm9uZTtodG1sPTE7Zm9udFNpemU9MjQ7Zm9udFN0eWxlPTE7dmVydGljYWxBbGlnbj1taWRkbGU7YWxpZ249Y2VudGVyOyIgdmVydGV4PSIxIiBwYXJlbnQ9IjEiPgogICAgICAgICAgPG14R2VvbWV0cnkgeD0iNTUwIiB5PSIzNjAiIHdpZHRoPSIxMDAiIGhlaWdodD0iNDAiIGFzPSJnZW9tZXRyeSIgLz4KICAgICAgICA8L214Q2VsbD4KICAgICAgICA8bXhDZWxsIGlkPSJUS3BPbnNLemE5aW9zWFNobHh5ZC00MSIgdmFsdWU9IlNoYWRlciBEZWZpbnRpb25zIChHTFNMKSIgc3R5bGU9InJvdW5kZWQ9MDt3aGl0ZVNwYWNlPXdyYXA7aHRtbD0xO2ZpbGxDb2xvcj0jZTFkNWU3O3N0cm9rZUNvbG9yPSM5NjczYTY7IiB2ZXJ0ZXg9IjEiIHBhcmVudD0iMSI+CiAgICAgICAgICA8bXhHZW9tZXRyeSB4PSI0OTIiIHk9IjEwMCIgd2lkdGg9IjE1MCIgaGVpZ2h0PSIzNi41IiBhcz0iZ2VvbWV0cnkiIC8+CiAgICAgICAgPC9teENlbGw+CiAgICAgICAgPG14Q2VsbCBpZD0iVEtwT25zS3phOWlvc1hTaGx4eWQtNDQiIHZhbHVlPSImbHQ7c3BhbiBzdHlsZT0mcXVvdDtjb2xvcjogcmdiKDEwNCwgMTA0LCAxMDQpOyZxdW90OyZndDsmbHQ7c3BhbiBzdHlsZT0mcXVvdDtjb2xvcjogcmdiKDM4LCAzOCwgMzgpOyZxdW90OyZndDszMzgmbHQ7L3NwYW4mZ3Q7Jmx0Oy9zcGFuJmd0OyIgc3R5bGU9InRleHQ7aHRtbD0xO2FsaWduPWNlbnRlcjt2ZXJ0aWNhbEFsaWduPW1pZGRsZTt3aGl0ZVNwYWNlPXdyYXA7cm91bmRlZD0wOyIgdmVydGV4PSIxIiBwYXJlbnQ9IjEiPgogICAgICAgICAgPG14R2VvbWV0cnkgeD0iMTEwIiB5PSIzMzAiIHdpZHRoPSI1MCIgaGVpZ2h0PSIzMCIgYXM9Imdlb21ldHJ5IiAvPgogICAgICAgIDwvbXhDZWxsPgogICAgICAgIDxteENlbGwgaWQ9IlRLcE9uc0t6YTlpb3NYU2hseHlkLTQ1IiB2YWx1ZT0iJmx0O3NwYW4gc3R5bGU9JnF1b3Q7Y29sb3I6IHJnYigxMDQsIDEwNCwgMTA0KTsmcXVvdDsmZ3Q7MjYyJmx0Oy9zcGFuJmd0OyIgc3R5bGU9InRleHQ7aHRtbD0xO2FsaWduPWNlbnRlcjt2ZXJ0aWNhbEFsaWduPW1pZGRsZTt3aGl0ZVNwYWNlPXdyYXA7cm91bmRlZD0wOyIgdmVydGV4PSIxIiBwYXJlbnQ9IjEiPgogICAgICAgICAgPG14R2VvbWV0cnkgeD0iMTYwIiB5PSIzMzAiIHdpZHRoPSI0MCIgaGVpZ2h0PSIzMCIgYXM9Imdlb21ldHJ5IiAvPgogICAgICAgIDwvbXhDZWxsPgogICAgICAgIDxteENlbGwgaWQ9IlRLcE9uc0t6YTlpb3NYU2hseHlkLTQ2IiB2YWx1ZT0iJmx0O3NwYW4gc3R5bGU9JnF1b3Q7Y29sb3I6IHJnYigxMDQsIDEwNCwgMTA0KTsmcXVvdDsmZ3Q7aWZkJmx0Oy9zcGFuJmd0OyIgc3R5bGU9InRleHQ7c3Ryb2tlQ29sb3I9bm9uZTtmaWxsQ29sb3I9bm9uZTtodG1sPTE7Zm9udFNpemU9MjQ7Zm9udFN0eWxlPTE7dmVydGljYWxBbGlnbj1taWRkbGU7YWxpZ249Y2VudGVyOyIgdmVydGV4PSIxIiBwYXJlbnQ9IjEiPgogICAgICAgICAgPG14R2VvbWV0cnkgeD0iMjkwIiB5PSIyOTAiIHdpZHRoPSIxMDAiIGhlaWdodD0iNDAiIGFzPSJnZW9tZXRyeSIgLz4KICAgICAgICA8L214Q2VsbD4KICAgICAgICA8bXhDZWxsIGlkPSJUS3BPbnNLemE5aW9zWFNobHh5ZC00NyIgdmFsdWU9IklDQyIgc3R5bGU9InJvdW5kZWQ9MDt3aGl0ZVNwYWNlPXdyYXA7aHRtbD0xOyIgdmVydGV4PSIxIiBwYXJlbnQ9IjEiPgogICAgICAgICAgPG14R2VvbWV0cnkgeD0iMjEwIiB5PSIyOTAiIHdpZHRoPSI0MCIgaGVpZ2h0PSI0MCIgYXM9Imdlb21ldHJ5IiAvPgogICAgICAgIDwvbXhDZWxsPgogICAgICAgIDxteENlbGwgaWQ9IlRLcE9uc0t6YTlpb3NYU2hseHlkLTQ4IiB2YWx1ZT0iJmx0O3NwYW4gc3R5bGU9JnF1b3Q7Y29sb3I6IHJnYigxMDQsIDEwNCwgMTA0KTsmcXVvdDsmZ3Q7MzQ2NzUmbHQ7L3NwYW4mZ3Q7IiBzdHlsZT0idGV4dDtodG1sPTE7YWxpZ249Y2VudGVyO3ZlcnRpY2FsQWxpZ249bWlkZGxlO3doaXRlU3BhY2U9d3JhcDtyb3VuZGVkPTA7IiB2ZXJ0ZXg9IjEiIHBhcmVudD0iMSI+CiAgICAgICAgICA8bXhHZW9tZXRyeSB4PSIyMTAiIHk9IjMzMCIgd2lkdGg9IjQwIiBoZWlnaHQ9IjMwIiBhcz0iZ2VvbWV0cnkiIC8+CiAgICAgICAgPC9teENlbGw+CiAgICAgIDwvcm9vdD4KICAgIDwvbXhHcmFwaE1vZGVsPgogIDwvZGlhZ3JhbT4KPC9teGZpbGU+\"\n\t\t\t\tdata-mappings='[\"TKpOnsKza9iosXShlxyd-41\",\"TKpOnsKza9iosXShlxyd-9\",\"TKpOnsKza9iosXShlxyd-3\",\"TKpOnsKza9iosXShlxyd-28\",\"TKpOnsKza9iosXShlxyd-32\",\"TKpOnsKza9iosXShlxyd-2\",\"TKpOnsKza9iosXShlxyd-1\",\"TKpOnsKza9iosXShlxyd-19\",\"TKpOnsKza9iosXShlxyd-25\",\"TKpOnsKza9iosXShlxyd-47\",\"TKpOnsKza9iosXShlxyd-22\",\"TKpOnsKza9iosXShlxyd-16\",\"TKpOnsKza9iosXShlxyd-8\"]'\n\t\t>\n\t\t\t\n<div class=\"wp-block-grapham-mapping grapham-mapping-block\" data-cell-id=\"TKpOnsKza9iosXShlxyd-41\" data-cell-label=\"Shader Defintions (GLSL)\"><div class=\"grapham-mapping-header\"><span class=\"grapham-mapping-label\">Shader Defintions (GLSL)<\/span><span class=\"grapham-mapping-cellid\">TKpOnsKza9iosXShlxyd-41<\/span><\/div><div class=\"grapham-mapping-content\">\n<p>Shaders for gold and silver effects in GLSL<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#EEFFFF;--cbp-line-number-width:calc(3 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 0 16px;font-size:0.8em;width:100%;text-align:left;background-color:#263238;font-style:italic;color:#EEFFFF\"><span style=\"border-bottom:1px solid rgba(238, 255, 255, 0.2)\">GLSL<\/span><\/span><span role=\"button\" tabindex=\"0\" style=\"color:#EEFFFF;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>#version 300 es\nprecision mediump float;\n\n\/\/ ================== UNIFORMS ====================\nuniform sampler2D u_maskGold;\nuniform sampler2D u_maskSilver;\nuniform sampler2D u_maskHolo;\nuniform sampler2D u_maskUV;\n\nuniform float   u_time;\nuniform float   u_foilIntensity;\nuniform float   u_foilSpecularity;\nuniform float   u_holoShimmerIntensity;\nuniform float   u_holoShimmerSpeed;\nuniform float   u_uvSpotStrength;\nuniform vec3    u_uvSpotColor;\n\nuniform float   u_wrinkleScale;\nuniform float   u_wrinkleStrength;\nuniform float   u_wrinkleSpeed;\nuniform float   u_sparkleIntensity;\nuniform float   u_sparkleFreq;\nuniform float   u_sparkleSpeed;\n\nin  vec2 v_uv;\nout vec4 fragColor;\n\n\/\/ ================== HELPERS ====================\nfloat hash(vec2 p) {\n  return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);\n}\nfloat noise(vec2 p) {\n  vec2 i = floor(p);\n  vec2 f = fract(p);\n  float a = hash(i + vec2(0.0,0.0));\n  float b = hash(i + vec2(1.0,0.0));\n  float c = hash(i + vec2(0.0,1.0));\n  float d = hash(i + vec2(1.0,1.0));\n  vec2 u = f*f*(3.0 - 2.0*f);\n  return mix(a, b, u.x)\n       + (c - a) * u.y * (1.0 - u.x)\n       + (d - b) * u.x * u.y;\n}\n\n\/\/ Simplified \u201cwrinkle\u201d normal\u2014no base image sampling\nvec3 calcNormal(vec2 uv) {\n  float wr = noise(uv * u_wrinkleScale + u_time * u_wrinkleSpeed) - 0.5;\n  return normalize(vec3(0.0, 0.0, 1.0) + vec3(wr) * u_wrinkleStrength);\n}\n\nfloat fresnelSchlick(float cosTheta, float F0) {\n  return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);\n}\n\n\/\/ ================== FOIL SHADE FUNCTIONS ====================\nvec3 shadeGold(float maskAlpha, vec2 uv) {\n  vec3 goldColor = vec3(1.0, 0.82, 0.36);\n  vec3 N = calcNormal(uv);\n  vec3 L = normalize(vec3(-0.3, 0.5, 1.0));\n  vec3 V = vec3(0.0, 0.0, 1.0);\n  vec3 H = normalize(L + V);\n\n  float spec    = pow(max(dot(N, H), 0.0), 8.0);\n  float reflect = fresnelSchlick(dot(N, V), u_foilSpecularity);\n  float sp      = noise(uv * u_sparkleFreq + u_time * u_sparkleSpeed);\n  float glint   = smoothstep(0.85, 0.98, sp);\n  vec3 sparkle  = vec3(1.0) * glint * u_sparkleIntensity;\n\n  return (goldColor + spec * reflect + sparkle) * maskAlpha;\n}\n\nvec3 shadeSilver(float maskAlpha, vec2 uv) {\n  vec3 silverColor = vec3(0.8, 0.8, 0.85);\n  vec3 N           = calcNormal(uv);\n  vec3 L           = normalize(vec3(0.3, 0.6, 1.0));\n  vec3 V           = vec3(0.0, 0.0, 1.0);\n  vec3 H           = normalize(L + V);\n\n  float spec    = pow(max(dot(N, H), 0.0), 12.0);\n  float reflect = fresnelSchlick(dot(N, V), u_foilSpecularity);\n\n  return (silverColor + spec * reflect) * maskAlpha;\n}\n\nvec3 shadeHolo(float maskAlpha, vec2 uv) {\n  float t       = sin((uv.x + uv.y) * 10.0 + u_time * u_holoShimmerSpeed);\n  float shimmer = smoothstep(0.2, 0.8, t) * u_holoShimmerIntensity;\n  return vec3(1.0) * shimmer * maskAlpha;\n}\n\nvec3 shadeUV(float maskAlpha, vec2 uv) {\n  return u_uvSpotColor * u_uvSpotStrength * maskAlpha;\n}\n\n\/\/ ================== MAIN FUNCTION ====================\nvoid main() {\n  \/\/ sample each mask\u2019s alpha channel\n  float mG = texture(u_maskGold,   v_uv).a;\n  float mS = texture(u_maskSilver, v_uv).a;\n  float mH = texture(u_maskHolo,   v_uv).a;\n  float mU = texture(u_maskUV,     v_uv).a;\n\n  \/\/ start from transparent black\n  vec3 outCol = vec3(0.0);\n\n  \/\/ accumulate foil colors\n  if (mG > 0.0) outCol += shadeGold( mG, v_uv) * u_foilIntensity;\n  if (mS > 0.0) outCol += shadeSilver(mS, v_uv) * u_foilIntensity;\n  if (mH > 0.0) outCol += shadeHolo(  mH, v_uv);\n  if (mU > 0.0) outCol += shadeUV(    mU, v_uv);\n\n  \/\/ final alpha is driven purely by the masks\n  float maskA = max(max(mG, mS), max(mH, mU));\n  fragColor = vec4(outCol, maskA);\n}<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki material-theme\" style=\"background-color: #263238\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #EEFFFF\">#version <\/span><span style=\"color: #F78C6C\">300<\/span><span style=\"color: #EEFFFF\"> es<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">precision mediump <\/span><span style=\"color: #C792EA\">float<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\">\/\/ ================== UNIFORMS ====================<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C792EA\">uniform<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #C792EA\">sampler2D<\/span><span style=\"color: #EEFFFF\"> u_maskGold<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C792EA\">uniform<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #C792EA\">sampler2D<\/span><span style=\"color: #EEFFFF\"> u_maskSilver<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C792EA\">uniform<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #C792EA\">sampler2D<\/span><span style=\"color: #EEFFFF\"> u_maskHolo<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C792EA\">uniform<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #C792EA\">sampler2D<\/span><span style=\"color: #EEFFFF\"> u_maskUV<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #C792EA\">uniform<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #C792EA\">float<\/span><span style=\"color: #EEFFFF\">   u_time<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C792EA\">uniform<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #C792EA\">float<\/span><span style=\"color: #EEFFFF\">   u_foilIntensity<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C792EA\">uniform<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #C792EA\">float<\/span><span style=\"color: #EEFFFF\">   u_foilSpecularity<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C792EA\">uniform<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #C792EA\">float<\/span><span style=\"color: #EEFFFF\">   u_holoShimmerIntensity<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C792EA\">uniform<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #C792EA\">float<\/span><span style=\"color: #EEFFFF\">   u_holoShimmerSpeed<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C792EA\">uniform<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #C792EA\">float<\/span><span style=\"color: #EEFFFF\">   u_uvSpotStrength<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C792EA\">uniform<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #C792EA\">vec3<\/span><span style=\"color: #EEFFFF\">    u_uvSpotColor<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #C792EA\">uniform<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #C792EA\">float<\/span><span style=\"color: #EEFFFF\">   u_wrinkleScale<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C792EA\">uniform<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #C792EA\">float<\/span><span style=\"color: #EEFFFF\">   u_wrinkleStrength<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C792EA\">uniform<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #C792EA\">float<\/span><span style=\"color: #EEFFFF\">   u_wrinkleSpeed<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C792EA\">uniform<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #C792EA\">float<\/span><span style=\"color: #EEFFFF\">   u_sparkleIntensity<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C792EA\">uniform<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #C792EA\">float<\/span><span style=\"color: #EEFFFF\">   u_sparkleFreq<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C792EA\">uniform<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #C792EA\">float<\/span><span style=\"color: #EEFFFF\">   u_sparkleSpeed<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #C792EA\">in<\/span><span style=\"color: #EEFFFF\">  <\/span><span style=\"color: #C792EA\">vec2<\/span><span style=\"color: #EEFFFF\"> v_uv<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C792EA\">out<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #C792EA\">vec4<\/span><span style=\"color: #EEFFFF\"> fragColor<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\">\/\/ ================== HELPERS ====================<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C792EA\">float<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #82AAFF\">hash<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #EEFFFF\">vec2 <\/span><span style=\"color: #EEFFFF; font-style: italic\">p<\/span><span style=\"color: #89DDFF\">)<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">  <\/span><span style=\"color: #89DDFF; font-style: italic\">return<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">fract<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #82AAFF\">sin<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #82AAFF\">dot<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F07178\">p<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">vec2<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F78C6C\">127.1<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">311.7<\/span><span style=\"color: #89DDFF\">)))<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">*<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">43758.5453123<\/span><span style=\"color: #89DDFF\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C792EA\">float<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #82AAFF\">noise<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #EEFFFF\">vec2 <\/span><span style=\"color: #EEFFFF; font-style: italic\">p<\/span><span style=\"color: #89DDFF\">)<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">  vec2 i <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">floor<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F07178\">p<\/span><span style=\"color: #89DDFF\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">  vec2 f <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">fract<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F07178\">p<\/span><span style=\"color: #89DDFF\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">  <\/span><span style=\"color: #C792EA\">float<\/span><span style=\"color: #F07178\"> a <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">hash<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F07178\">i <\/span><span style=\"color: #89DDFF\">+<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">vec2<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F78C6C\">0.0<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F78C6C\">0.0<\/span><span style=\"color: #89DDFF\">));<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">  <\/span><span style=\"color: #C792EA\">float<\/span><span style=\"color: #F07178\"> b <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">hash<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F07178\">i <\/span><span style=\"color: #89DDFF\">+<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">vec2<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F78C6C\">1.0<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F78C6C\">0.0<\/span><span style=\"color: #89DDFF\">));<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">  <\/span><span style=\"color: #C792EA\">float<\/span><span style=\"color: #F07178\"> c <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">hash<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F07178\">i <\/span><span style=\"color: #89DDFF\">+<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">vec2<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F78C6C\">0.0<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F78C6C\">1.0<\/span><span style=\"color: #89DDFF\">));<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">  <\/span><span style=\"color: #C792EA\">float<\/span><span style=\"color: #F07178\"> d <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">hash<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F07178\">i <\/span><span style=\"color: #89DDFF\">+<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">vec2<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F78C6C\">1.0<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F78C6C\">1.0<\/span><span style=\"color: #89DDFF\">));<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">  vec2 u <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> f<\/span><span style=\"color: #89DDFF\">*<\/span><span style=\"color: #F07178\">f<\/span><span style=\"color: #89DDFF\">*(<\/span><span style=\"color: #F78C6C\">3.0<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">-<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">2.0<\/span><span style=\"color: #89DDFF\">*<\/span><span style=\"color: #F07178\">f<\/span><span style=\"color: #89DDFF\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">  <\/span><span style=\"color: #89DDFF; font-style: italic\">return<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">mix<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F07178\">a<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> b<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">u<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">x<\/span><span style=\"color: #89DDFF\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">       <\/span><span style=\"color: #89DDFF\">+<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F07178\">c <\/span><span style=\"color: #89DDFF\">-<\/span><span style=\"color: #F07178\"> a<\/span><span style=\"color: #89DDFF\">)<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">*<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">u<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">y<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">*<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F78C6C\">1.0<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">-<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">u<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">x<\/span><span style=\"color: #89DDFF\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">       <\/span><span style=\"color: #89DDFF\">+<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F07178\">d <\/span><span style=\"color: #89DDFF\">-<\/span><span style=\"color: #F07178\"> b<\/span><span style=\"color: #89DDFF\">)<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">*<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">u<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">x<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">*<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">u<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">y<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\">\/\/ Simplified \u201cwrinkle\u201d normal\u2014no base image sampling<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C792EA\">vec3<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #82AAFF\">calcNormal<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #EEFFFF\">vec2 <\/span><span style=\"color: #EEFFFF; font-style: italic\">uv<\/span><span style=\"color: #89DDFF\">)<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">  <\/span><span style=\"color: #C792EA\">float<\/span><span style=\"color: #F07178\"> wr <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">noise<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F07178\">uv <\/span><span style=\"color: #89DDFF\">*<\/span><span style=\"color: #F07178\"> u_wrinkleScale <\/span><span style=\"color: #89DDFF\">+<\/span><span style=\"color: #F07178\"> u_time <\/span><span style=\"color: #89DDFF\">*<\/span><span style=\"color: #F07178\"> u_wrinkleSpeed<\/span><span style=\"color: #89DDFF\">)<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">-<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0.5<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">  <\/span><span style=\"color: #89DDFF; font-style: italic\">return<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">normalize<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #82AAFF\">vec3<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F78C6C\">0.0<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0.0<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">1.0<\/span><span style=\"color: #89DDFF\">)<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">+<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">vec3<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F07178\">wr<\/span><span style=\"color: #89DDFF\">)<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">*<\/span><span style=\"color: #F07178\"> u_wrinkleStrength<\/span><span style=\"color: #89DDFF\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #C792EA\">float<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #82AAFF\">fresnelSchlick<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #C792EA\">float<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #EEFFFF; font-style: italic\">cosTheta<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #C792EA\">float<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #EEFFFF; font-style: italic\">F0<\/span><span style=\"color: #89DDFF\">)<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">  <\/span><span style=\"color: #89DDFF; font-style: italic\">return<\/span><span style=\"color: #F07178\"> F0 <\/span><span style=\"color: #89DDFF\">+<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F78C6C\">1.0<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">-<\/span><span style=\"color: #F07178\"> F0<\/span><span style=\"color: #89DDFF\">)<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">*<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">pow<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F78C6C\">1.0<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">-<\/span><span style=\"color: #F07178\"> cosTheta<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">5.0<\/span><span style=\"color: #89DDFF\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\">\/\/ ================== FOIL SHADE FUNCTIONS ====================<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C792EA\">vec3<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #82AAFF\">shadeGold<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #C792EA\">float<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #EEFFFF; font-style: italic\">maskAlpha<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #EEFFFF\"> vec2 <\/span><span style=\"color: #EEFFFF; font-style: italic\">uv<\/span><span style=\"color: #89DDFF\">)<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">  vec3 goldColor <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">vec3<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F78C6C\">1.0<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0.82<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0.36<\/span><span style=\"color: #89DDFF\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">  vec3 N <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">calcNormal<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F07178\">uv<\/span><span style=\"color: #89DDFF\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">  vec3 L <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">normalize<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #82AAFF\">vec3<\/span><span style=\"color: #89DDFF\">(-<\/span><span style=\"color: #F78C6C\">0.3<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0.5<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">1.0<\/span><span style=\"color: #89DDFF\">));<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">  vec3 V <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">vec3<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F78C6C\">0.0<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0.0<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">1.0<\/span><span style=\"color: #89DDFF\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">  vec3 H <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">normalize<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F07178\">L <\/span><span style=\"color: #89DDFF\">+<\/span><span style=\"color: #F07178\"> V<\/span><span style=\"color: #89DDFF\">);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">  <\/span><span style=\"color: #C792EA\">float<\/span><span style=\"color: #F07178\"> spec    <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">pow<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #82AAFF\">max<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #82AAFF\">dot<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F07178\">N<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> H<\/span><span style=\"color: #89DDFF\">),<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0.0<\/span><span style=\"color: #89DDFF\">),<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">8.0<\/span><span style=\"color: #89DDFF\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">  <\/span><span style=\"color: #C792EA\">float<\/span><span style=\"color: #F07178\"> reflect <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">fresnelSchlick<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #82AAFF\">dot<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F07178\">N<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> V<\/span><span style=\"color: #89DDFF\">),<\/span><span style=\"color: #F07178\"> u_foilSpecularity<\/span><span style=\"color: #89DDFF\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">  <\/span><span style=\"color: #C792EA\">float<\/span><span style=\"color: #F07178\"> sp      <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">noise<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F07178\">uv <\/span><span style=\"color: #89DDFF\">*<\/span><span style=\"color: #F07178\"> u_sparkleFreq <\/span><span style=\"color: #89DDFF\">+<\/span><span style=\"color: #F07178\"> u_time <\/span><span style=\"color: #89DDFF\">*<\/span><span style=\"color: #F07178\"> u_sparkleSpeed<\/span><span style=\"color: #89DDFF\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">  <\/span><span style=\"color: #C792EA\">float<\/span><span style=\"color: #F07178\"> glint   <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">smoothstep<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F78C6C\">0.85<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0.98<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> sp<\/span><span style=\"color: #89DDFF\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">  vec3 sparkle  <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">vec3<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F78C6C\">1.0<\/span><span style=\"color: #89DDFF\">)<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">*<\/span><span style=\"color: #F07178\"> glint <\/span><span style=\"color: #89DDFF\">*<\/span><span style=\"color: #F07178\"> u_sparkleIntensity<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">  <\/span><span style=\"color: #89DDFF; font-style: italic\">return<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F07178\">goldColor <\/span><span style=\"color: #89DDFF\">+<\/span><span style=\"color: #F07178\"> spec <\/span><span style=\"color: #89DDFF\">*<\/span><span style=\"color: #F07178\"> reflect <\/span><span style=\"color: #89DDFF\">+<\/span><span style=\"color: #F07178\"> sparkle<\/span><span style=\"color: #89DDFF\">)<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">*<\/span><span style=\"color: #F07178\"> maskAlpha<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #C792EA\">vec3<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #82AAFF\">shadeSilver<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #C792EA\">float<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #EEFFFF; font-style: italic\">maskAlpha<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #EEFFFF\"> vec2 <\/span><span style=\"color: #EEFFFF; font-style: italic\">uv<\/span><span style=\"color: #89DDFF\">)<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">  vec3 silverColor <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">vec3<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F78C6C\">0.8<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0.8<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0.85<\/span><span style=\"color: #89DDFF\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">  vec3 N           <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">calcNormal<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F07178\">uv<\/span><span style=\"color: #89DDFF\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">  vec3 L           <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">normalize<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #82AAFF\">vec3<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F78C6C\">0.3<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0.6<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">1.0<\/span><span style=\"color: #89DDFF\">));<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">  vec3 V           <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">vec3<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F78C6C\">0.0<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0.0<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">1.0<\/span><span style=\"color: #89DDFF\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">  vec3 H           <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">normalize<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F07178\">L <\/span><span style=\"color: #89DDFF\">+<\/span><span style=\"color: #F07178\"> V<\/span><span style=\"color: #89DDFF\">);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">  <\/span><span style=\"color: #C792EA\">float<\/span><span style=\"color: #F07178\"> spec    <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">pow<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #82AAFF\">max<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #82AAFF\">dot<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F07178\">N<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> H<\/span><span style=\"color: #89DDFF\">),<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0.0<\/span><span style=\"color: #89DDFF\">),<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">12.0<\/span><span style=\"color: #89DDFF\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">  <\/span><span style=\"color: #C792EA\">float<\/span><span style=\"color: #F07178\"> reflect <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">fresnelSchlick<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #82AAFF\">dot<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F07178\">N<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> V<\/span><span style=\"color: #89DDFF\">),<\/span><span style=\"color: #F07178\"> u_foilSpecularity<\/span><span style=\"color: #89DDFF\">);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">  <\/span><span style=\"color: #89DDFF; font-style: italic\">return<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F07178\">silverColor <\/span><span style=\"color: #89DDFF\">+<\/span><span style=\"color: #F07178\"> spec <\/span><span style=\"color: #89DDFF\">*<\/span><span style=\"color: #F07178\"> reflect<\/span><span style=\"color: #89DDFF\">)<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">*<\/span><span style=\"color: #F07178\"> maskAlpha<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #C792EA\">vec3<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #82AAFF\">shadeHolo<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #C792EA\">float<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #EEFFFF; font-style: italic\">maskAlpha<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #EEFFFF\"> vec2 <\/span><span style=\"color: #EEFFFF; font-style: italic\">uv<\/span><span style=\"color: #89DDFF\">)<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">  <\/span><span style=\"color: #C792EA\">float<\/span><span style=\"color: #F07178\"> t       <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">sin<\/span><span style=\"color: #89DDFF\">((<\/span><span style=\"color: #EEFFFF\">uv<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">x<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">+<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">uv<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">y<\/span><span style=\"color: #89DDFF\">)<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">*<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">10.0<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">+<\/span><span style=\"color: #F07178\"> u_time <\/span><span style=\"color: #89DDFF\">*<\/span><span style=\"color: #F07178\"> u_holoShimmerSpeed<\/span><span style=\"color: #89DDFF\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">  <\/span><span style=\"color: #C792EA\">float<\/span><span style=\"color: #F07178\"> shimmer <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">smoothstep<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F78C6C\">0.2<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0.8<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> t<\/span><span style=\"color: #89DDFF\">)<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">*<\/span><span style=\"color: #F07178\"> u_holoShimmerIntensity<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">  <\/span><span style=\"color: #89DDFF; font-style: italic\">return<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">vec3<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F78C6C\">1.0<\/span><span style=\"color: #89DDFF\">)<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">*<\/span><span style=\"color: #F07178\"> shimmer <\/span><span style=\"color: #89DDFF\">*<\/span><span style=\"color: #F07178\"> maskAlpha<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #C792EA\">vec3<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #82AAFF\">shadeUV<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #C792EA\">float<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #EEFFFF; font-style: italic\">maskAlpha<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #EEFFFF\"> vec2 <\/span><span style=\"color: #EEFFFF; font-style: italic\">uv<\/span><span style=\"color: #89DDFF\">)<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">  <\/span><span style=\"color: #89DDFF; font-style: italic\">return<\/span><span style=\"color: #F07178\"> u_uvSpotColor <\/span><span style=\"color: #89DDFF\">*<\/span><span style=\"color: #F07178\"> u_uvSpotStrength <\/span><span style=\"color: #89DDFF\">*<\/span><span style=\"color: #F07178\"> maskAlpha<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\">\/\/ ================== MAIN FUNCTION ====================<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C792EA\">void<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #82AAFF\">main<\/span><span style=\"color: #89DDFF\">()<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">  <\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ sample each mask\u2019s alpha channel<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">  <\/span><span style=\"color: #C792EA\">float<\/span><span style=\"color: #F07178\"> mG <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">texture<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F07178\">u_maskGold<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\">   v_uv<\/span><span style=\"color: #89DDFF\">).<\/span><span style=\"color: #EEFFFF\">a<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">  <\/span><span style=\"color: #C792EA\">float<\/span><span style=\"color: #F07178\"> mS <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">texture<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F07178\">u_maskSilver<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> v_uv<\/span><span style=\"color: #89DDFF\">).<\/span><span style=\"color: #EEFFFF\">a<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">  <\/span><span style=\"color: #C792EA\">float<\/span><span style=\"color: #F07178\"> mH <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">texture<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F07178\">u_maskHolo<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\">   v_uv<\/span><span style=\"color: #89DDFF\">).<\/span><span style=\"color: #EEFFFF\">a<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">  <\/span><span style=\"color: #C792EA\">float<\/span><span style=\"color: #F07178\"> mU <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">texture<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F07178\">u_maskUV<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\">     v_uv<\/span><span style=\"color: #89DDFF\">).<\/span><span style=\"color: #EEFFFF\">a<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">  <\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ start from transparent black<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">  vec3 outCol <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">vec3<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F78C6C\">0.0<\/span><span style=\"color: #89DDFF\">);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">  <\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ accumulate foil colors<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">  <\/span><span style=\"color: #89DDFF; font-style: italic\">if<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F07178\">mG <\/span><span style=\"color: #89DDFF\">&gt;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0.0<\/span><span style=\"color: #89DDFF\">)<\/span><span style=\"color: #F07178\"> outCol <\/span><span style=\"color: #89DDFF\">+=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">shadeGold<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F07178\"> mG<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> v_uv<\/span><span style=\"color: #89DDFF\">)<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">*<\/span><span style=\"color: #F07178\"> u_foilIntensity<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">  <\/span><span style=\"color: #89DDFF; font-style: italic\">if<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F07178\">mS <\/span><span style=\"color: #89DDFF\">&gt;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0.0<\/span><span style=\"color: #89DDFF\">)<\/span><span style=\"color: #F07178\"> outCol <\/span><span style=\"color: #89DDFF\">+=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">shadeSilver<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F07178\">mS<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> v_uv<\/span><span style=\"color: #89DDFF\">)<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">*<\/span><span style=\"color: #F07178\"> u_foilIntensity<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">  <\/span><span style=\"color: #89DDFF; font-style: italic\">if<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F07178\">mH <\/span><span style=\"color: #89DDFF\">&gt;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0.0<\/span><span style=\"color: #89DDFF\">)<\/span><span style=\"color: #F07178\"> outCol <\/span><span style=\"color: #89DDFF\">+=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">shadeHolo<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F07178\">  mH<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> v_uv<\/span><span style=\"color: #89DDFF\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">  <\/span><span style=\"color: #89DDFF; font-style: italic\">if<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F07178\">mU <\/span><span style=\"color: #89DDFF\">&gt;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0.0<\/span><span style=\"color: #89DDFF\">)<\/span><span style=\"color: #F07178\"> outCol <\/span><span style=\"color: #89DDFF\">+=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">shadeUV<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F07178\">    mU<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> v_uv<\/span><span style=\"color: #89DDFF\">);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">  <\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ final alpha is driven purely by the masks<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">  <\/span><span style=\"color: #C792EA\">float<\/span><span style=\"color: #F07178\"> maskA <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">max<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #82AAFF\">max<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F07178\">mG<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> mS<\/span><span style=\"color: #89DDFF\">),<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">max<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F07178\">mH<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> mU<\/span><span style=\"color: #89DDFF\">));<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">  fragColor <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">vec4<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #F07178\">outCol<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> maskA<\/span><span style=\"color: #89DDFF\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>Foil shaders need only 1-bit texture masks. The spot and specular masks require sampling the base canvas.<\/p>\n<\/div><\/div>\n\n<div class=\"wp-block-grapham-mapping grapham-mapping-block\" data-cell-id=\"TKpOnsKza9iosXShlxyd-9\" data-cell-label=\"Builder.js shader pipeline\"><div class=\"grapham-mapping-header\"><span class=\"grapham-mapping-label\">Builder.js shader pipeline<\/span><span class=\"grapham-mapping-cellid\">TKpOnsKza9iosXShlxyd-9<\/span><\/div><div class=\"grapham-mapping-content\">\n<p>Builder is responsible for managing the shader pipeline. <\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#EEFFFF;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 0 16px;font-size:0.8em;width:100%;text-align:left;background-color:#263238;font-style:italic;color:#EEFFFF\"><span style=\"border-bottom:1px solid rgba(238, 255, 255, 0.2)\">JavaScript<\/span><\/span><span role=\"button\" tabindex=\"0\" style=\"color:#EEFFFF;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>\/\/ =======================================================\n\/\/ CONFIG &amp; HELPERS (in main.js)\n\/\/ =======================================================\nimport { shaders } from '.\/shaders.js';\n\nconst Builder             = {};\nwindow.Builder           = Builder;\nBuilder.layers           = {};\nBuilder.shaderConfig    = {\n\n\t\/\/ wrinkle and sparkle effects\n\tu_wrinkleScale:     10.0,   \/\/ noise frequency for micro-wrinkles\n\tu_wrinkleStrength:  0.9,   \/\/ how much noise bends normals\n\tu_wrinkleSpeed:     0.5,    \/\/ animation speed of subtle surface shifts\n\tu_sparkleIntensity: 1.0,    \/\/ brightness of sparkles\n\tu_sparkleFreq:      120.0,  \/\/ noise frequency for sparkle placement\n\tu_sparkleSpeed:     1.0,     \/\/ how fast glints flicker\n\n\t\/\/ foil effects\n\tu_foilIntensity:     0.3,\n\tu_foilSpecularity:   2.0,\n\tu_uvSpotStrength:    1.0,\n\tu_uvSpotColor:       &#91;1,1,1&#93;,\n\tu_holoShimmerIntensity: 0.8,\n\tu_holoShimmerSpeed:     10.0\n};\n\nBuilder.setConfig = cfg => Object.assign(Builder.shaderConfig, cfg);\n\n\n\/\/ -------------------------------------------------------------------\n\/\/ top-level constants &amp; debug helper\n\/\/ -------------------------------------------------------------------\nconst FOIL_CHANNELS = {\n\tgold_foil:   { uni: 'u_maskGold',   unit: 1 },\n\tsilver_foil: { uni: 'u_maskSilver', unit: 2 },\n\tholo_foil:   { uni: 'u_maskHolo',   unit: 3 },\n\tuv_spot:     { uni: 'u_maskUV',     unit: 4 }\n};\n\nBuilder.debug = false;\nfunction dbg(...args) { if (Builder.debug) console.log(...args); }\n\n\n\n\nBuilder.shaders = shaders;\n\n\/\/ -------------------------------------------------------------------\n\/\/ Shader compile\/link utilities\n\/\/ -------------------------------------------------------------------\n\nfunction compileShader(gl, type, src, name) {\n\tconst shader = gl.createShader(type);\n\tgl.shaderSource(shader, src);\n\tgl.compileShader(shader);\n\tif (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {\n\t\tconsole.error(`${name} compile failed:`, gl.getShaderInfoLog(shader));\n\t\tgl.deleteShader(shader);\n\t\treturn null;\n\t}\n\tconsole.log(`${name} compiled OK`);\n\treturn shader;\n}\n\nfunction createProgram(gl, vsSource, fsSource) {\n\tconst vs = compileShader(gl, gl.VERTEX_SHADER,   vsSource, \"vertex_shader\");\n\tconst fs = compileShader(gl, gl.FRAGMENT_SHADER, fsSource, \"fragment_shader\");\n\tif (!vs || !fs) return null;\n\n\tconst program = gl.createProgram();\n\tgl.attachShader(program, vs);\n\tgl.attachShader(program, fs);\n\tgl.linkProgram(program);\n\tif (!gl.getProgramParameter(program, gl.LINK_STATUS)) {\n\t\tconsole.error('Program link failed:', gl.getProgramInfoLog(program));\n\t\tgl.deleteProgram(program);\n\t\treturn null;\n\t}\n\tconsole.log(\"GL Shader program linked.\");\n\treturn program;\n}\n\nfunction getLayerShaderProgram(gl, shaderType) {\n\tif (!Builder.shaders&#91;shaderType&#93;) { console.warn(`Shader \"${shaderType}\" not found; falling back to \"multi_foil\".`); shaderType = 'multi_foil'; }\n\tconst { vertexSrc, fragmentSrc } = Builder.shaders&#91;shaderType&#93;;\n\tconsole.log(`Requesting ${shaderType} shader.`);\n\treturn createProgram(gl, vertexSrc, fragmentSrc);\n}\n\nfunction checkGLError(gl, op) {\n\tconst err = gl.getError();\n\tif (err !== gl.NO_ERROR) {\n\t\tconsole.error(`${op} \u2192 WebGL error 0x${err.toString(16)}`);\n\t}\n}\n<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki material-theme\" style=\"background-color: #263238\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #546E7A; font-style: italic\">\/\/ =======================================================<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\">\/\/ CONFIG &amp; HELPERS (in main.js)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\">\/\/ =======================================================<\/span><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF; font-style: italic\">import<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #89DDFF\">{<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">shaders<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">}<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #89DDFF; font-style: italic\">from<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">.\/shaders.js<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #C792EA\">const<\/span><span style=\"color: #EEFFFF\"> Builder             <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #89DDFF\">{};<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">window<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">Builder           <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #EEFFFF\"> Builder<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">Builder<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">layers           <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #89DDFF\">{};<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">Builder<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">shaderConfig    <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ wrinkle and sparkle effects<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">\t<\/span><span style=\"color: #F07178\">u_wrinkleScale<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\">     <\/span><span style=\"color: #F78C6C\">10.0<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #EEFFFF\">   <\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ noise frequency for micro-wrinkles<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">\t<\/span><span style=\"color: #F07178\">u_wrinkleStrength<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\">  <\/span><span style=\"color: #F78C6C\">0.9<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #EEFFFF\">   <\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ how much noise bends normals<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">\t<\/span><span style=\"color: #F07178\">u_wrinkleSpeed<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\">     <\/span><span style=\"color: #F78C6C\">0.5<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #EEFFFF\">    <\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ animation speed of subtle surface shifts<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">\t<\/span><span style=\"color: #F07178\">u_sparkleIntensity<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #F78C6C\">1.0<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #EEFFFF\">    <\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ brightness of sparkles<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">\t<\/span><span style=\"color: #F07178\">u_sparkleFreq<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\">      <\/span><span style=\"color: #F78C6C\">120.0<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #EEFFFF\">  <\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ noise frequency for sparkle placement<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">\t<\/span><span style=\"color: #F07178\">u_sparkleSpeed<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\">     <\/span><span style=\"color: #F78C6C\">1.0<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #EEFFFF\">     <\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ how fast glints flicker<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ foil effects<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">\t<\/span><span style=\"color: #F07178\">u_foilIntensity<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\">     <\/span><span style=\"color: #F78C6C\">0.3<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">\t<\/span><span style=\"color: #F07178\">u_foilSpecularity<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\">   <\/span><span style=\"color: #F78C6C\">2.0<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">\t<\/span><span style=\"color: #F07178\">u_uvSpotStrength<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\">    <\/span><span style=\"color: #F78C6C\">1.0<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">\t<\/span><span style=\"color: #F07178\">u_uvSpotColor<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\">       &#91;<\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #EEFFFF\">&#93;<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">\t<\/span><span style=\"color: #F07178\">u_holoShimmerIntensity<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #F78C6C\">0.8<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">\t<\/span><span style=\"color: #F07178\">u_holoShimmerSpeed<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\">     <\/span><span style=\"color: #F78C6C\">10.0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">};<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">Builder<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">setConfig<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #EEFFFF; font-style: italic\">cfg<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #C792EA\">=&gt;<\/span><span style=\"color: #EEFFFF\"> Object<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">assign<\/span><span style=\"color: #EEFFFF\">(Builder<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">shaderConfig<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #EEFFFF\"> cfg)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\">\/\/ -------------------------------------------------------------------<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\">\/\/ top-level constants &amp; debug helper<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\">\/\/ -------------------------------------------------------------------<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C792EA\">const<\/span><span style=\"color: #EEFFFF\"> FOIL_CHANNELS <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">\t<\/span><span style=\"color: #F07178\">gold_foil<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\">   <\/span><span style=\"color: #89DDFF\">{<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #F07178\">uni<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">u_maskGold<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #EEFFFF\">   <\/span><span style=\"color: #F07178\">unit<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #89DDFF\">},<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">\t<\/span><span style=\"color: #F07178\">silver_foil<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #89DDFF\">{<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #F07178\">uni<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">u_maskSilver<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #F07178\">unit<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #F78C6C\">2<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #89DDFF\">},<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">\t<\/span><span style=\"color: #F07178\">holo_foil<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\">   <\/span><span style=\"color: #89DDFF\">{<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #F07178\">uni<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">u_maskHolo<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #EEFFFF\">   <\/span><span style=\"color: #F07178\">unit<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #F78C6C\">3<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #89DDFF\">},<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">\t<\/span><span style=\"color: #F07178\">uv_spot<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\">     <\/span><span style=\"color: #89DDFF\">{<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #F07178\">uni<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">u_maskUV<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #EEFFFF\">     <\/span><span style=\"color: #F07178\">unit<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #F78C6C\">4<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">};<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">Builder<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">debug <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #FF9CAC\">false<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C792EA\">function<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #82AAFF\">dbg<\/span><span style=\"color: #89DDFF\">(...<\/span><span style=\"color: #EEFFFF; font-style: italic\">args<\/span><span style=\"color: #89DDFF\">)<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #89DDFF\">{<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF; font-style: italic\">if<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #EEFFFF\">Builder<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">debug<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #EEFFFF\">console<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">log<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">...<\/span><span style=\"color: #EEFFFF\">args<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">Builder<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">shaders <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #EEFFFF\"> shaders<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\">\/\/ -------------------------------------------------------------------<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\">\/\/ Shader compile\/link utilities<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\">\/\/ -------------------------------------------------------------------<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #C792EA\">function<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #82AAFF\">compileShader<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #EEFFFF; font-style: italic\">gl<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #EEFFFF; font-style: italic\">type<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #EEFFFF; font-style: italic\">src<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #EEFFFF; font-style: italic\">name<\/span><span style=\"color: #89DDFF\">)<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">shader<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">createShader<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">type<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">shaderSource<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">shader<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">src<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">compileShader<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">shader<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF; font-style: italic\">if<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #89DDFF\">!<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">getShaderParameter<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">shader<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">COMPILE_STATUS<\/span><span style=\"color: #F07178\">)) <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">console<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">error<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">`${<\/span><span style=\"color: #EEFFFF\">name<\/span><span style=\"color: #89DDFF\">}<\/span><span style=\"color: #C3E88D\"> compile failed:<\/span><span style=\"color: #89DDFF\">`<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">getShaderInfoLog<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">shader<\/span><span style=\"color: #F07178\">))<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">deleteShader<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">shader<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #89DDFF; font-style: italic\">return<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">null;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #EEFFFF\">console<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">log<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">`${<\/span><span style=\"color: #EEFFFF\">name<\/span><span style=\"color: #89DDFF\">}<\/span><span style=\"color: #C3E88D\"> compiled OK<\/span><span style=\"color: #89DDFF\">`<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF; font-style: italic\">return<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">shader<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #C792EA\">function<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #82AAFF\">createProgram<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #EEFFFF; font-style: italic\">gl<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #EEFFFF; font-style: italic\">vsSource<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #EEFFFF; font-style: italic\">fsSource<\/span><span style=\"color: #89DDFF\">)<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">vs<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">compileShader<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">VERTEX_SHADER<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\">   <\/span><span style=\"color: #EEFFFF\">vsSource<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #C3E88D\">vertex_shader<\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">fs<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">compileShader<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">FRAGMENT_SHADER<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">fsSource<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #C3E88D\">fragment_shader<\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF; font-style: italic\">if<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #89DDFF\">!<\/span><span style=\"color: #EEFFFF\">vs<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">||<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">!<\/span><span style=\"color: #EEFFFF\">fs<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF; font-style: italic\">return<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">null;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">program<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">createProgram<\/span><span style=\"color: #F07178\">()<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">attachShader<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">program<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">vs<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">attachShader<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">program<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">fs<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">linkProgram<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">program<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF; font-style: italic\">if<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #89DDFF\">!<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">getProgramParameter<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">program<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">LINK_STATUS<\/span><span style=\"color: #F07178\">)) <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">console<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">error<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">Program link failed:<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">getProgramInfoLog<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">program<\/span><span style=\"color: #F07178\">))<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">deleteProgram<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">program<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #89DDFF; font-style: italic\">return<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">null;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #EEFFFF\">console<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">log<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #C3E88D\">GL Shader program linked.<\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF; font-style: italic\">return<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">program<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #C792EA\">function<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #82AAFF\">getLayerShaderProgram<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #EEFFFF; font-style: italic\">gl<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #EEFFFF; font-style: italic\">shaderType<\/span><span style=\"color: #89DDFF\">)<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF; font-style: italic\">if<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #89DDFF\">!<\/span><span style=\"color: #EEFFFF\">Builder<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">shaders<\/span><span style=\"color: #F07178\">&#91;<\/span><span style=\"color: #EEFFFF\">shaderType<\/span><span style=\"color: #F07178\">&#93;) <\/span><span style=\"color: #89DDFF\">{<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">console<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">warn<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">`<\/span><span style=\"color: #C3E88D\">Shader &quot;<\/span><span style=\"color: #89DDFF\">${<\/span><span style=\"color: #EEFFFF\">shaderType<\/span><span style=\"color: #89DDFF\">}<\/span><span style=\"color: #C3E88D\">&quot; not found; falling back to &quot;multi_foil&quot;.<\/span><span style=\"color: #89DDFF\">`<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">shaderType<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">multi_foil<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">{<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">vertexSrc<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">fragmentSrc<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">}<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">Builder<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">shaders<\/span><span style=\"color: #F07178\">&#91;<\/span><span style=\"color: #EEFFFF\">shaderType<\/span><span style=\"color: #F07178\">&#93;<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #EEFFFF\">console<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">log<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">`<\/span><span style=\"color: #C3E88D\">Requesting <\/span><span style=\"color: #89DDFF\">${<\/span><span style=\"color: #EEFFFF\">shaderType<\/span><span style=\"color: #89DDFF\">}<\/span><span style=\"color: #C3E88D\"> shader.<\/span><span style=\"color: #89DDFF\">`<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF; font-style: italic\">return<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">createProgram<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">vertexSrc<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">fragmentSrc<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #C792EA\">function<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #82AAFF\">checkGLError<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #EEFFFF; font-style: italic\">gl<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #EEFFFF; font-style: italic\">op<\/span><span style=\"color: #89DDFF\">)<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">err<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">getError<\/span><span style=\"color: #F07178\">()<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF; font-style: italic\">if<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #EEFFFF\">err<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">!==<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">NO_ERROR<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">console<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">error<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">`${<\/span><span style=\"color: #EEFFFF\">op<\/span><span style=\"color: #89DDFF\">}<\/span><span style=\"color: #C3E88D\"> \u2192 WebGL error 0x<\/span><span style=\"color: #89DDFF\">${<\/span><span style=\"color: #EEFFFF\">err<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">toString<\/span><span style=\"color: #EEFFFF\">(<\/span><span style=\"color: #F78C6C\">16<\/span><span style=\"color: #EEFFFF\">)<\/span><span style=\"color: #89DDFF\">}`<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><\/span><\/code><\/pre><\/div>\n\n\n\n<p>GLSL fails silently on many operations, so linking, collating and attaching the WebGL effects requires some instrumentation. Your implementation should be capable of managing multiple layers, retrieving and surfacing GL layer errors, managing the default configurations and uniforms used in the rendering of the effect.<\/p>\n<\/div><\/div>\n\n<div class=\"wp-block-grapham-mapping grapham-mapping-block\" data-cell-id=\"TKpOnsKza9iosXShlxyd-3\" data-cell-label=\"bitmask stack x0\"><div class=\"grapham-mapping-header\"><span class=\"grapham-mapping-label\">bitmask stack x0<\/span><span class=\"grapham-mapping-cellid\">TKpOnsKza9iosXShlxyd-3<\/span><\/div><div class=\"grapham-mapping-content\">\n<p>Bitmasks, especially 1-bit bitmasks, given good performance and lend themselves well to tiling. <\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#EEFFFF;--cbp-line-number-width:calc(3 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 0 16px;font-size:0.8em;width:100%;text-align:left;background-color:#263238;font-style:italic;color:#EEFFFF\"><span style=\"border-bottom:1px solid rgba(238, 255, 255, 0.2)\">JavaScript<\/span><\/span><span role=\"button\" tabindex=\"0\" style=\"color:#EEFFFF;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>\/**\n * Uploads a source (canvas\/image\/video) into a given WebGL texture unit.\n * Re-allocates storage if dimensions change, otherwise performs a sub-image update.\n *\n * @param {Canvas|Image|Video|OffscreenCanvas} src\n *        The source element whose pixels will be uploaded.\n * @param {object|string|HTMLCanvasElement} layerRef\n *        The layer object (returned by initWebGLLayer),\n *        its ID string (glCanvas.id), or its gl-canvas element.\n * @param {number} &#91;unit=0&#93;\n *        Texture unit index: 0\u2192TEXTURE0, 1\u2192TEXTURE1, \u2026\n * @param {string} &#91;sampler='u_image'&#93;\n *        The sampler uniform key in layer.textures\n *        (e.g. 'u_image','u_maskGold','u_maskSilver',\u2026).\n *\/\nBuilder.updateTextureUnit = function(src, layerRef, unit = 0, sampler = 'u_image') {\n\n\tconsole.log(`Updating ${sampler} for ${unit}`);\n\n\t\/\/ Resolve layer object\n\tlet layer;\n\tif (typeof layerRef === 'string') {\n\t\tlayer = Builder.layers&#91;layerRef&#93;;\n\t} else if (layerRef instanceof HTMLCanvasElement) {\n\t\tlayer = Builder.layers&#91;layerRef.id&#93;;\n\t} else {\n\t\tlayer = layerRef;\n\t}\n\tif (!layer) { console.error('updateTextureUnit: missing layer', layerRef); return; }\n\n\tconst gl      = layer.gl;\n\tconst texture = layer.textures&#91;sampler&#93;;\n\tif (!gl || !texture) { console.error('updateTextureUnit: invalid sampler', sampler); return; }\n\n\t\/\/ Bind the texture to the chosen unit\n\tgl.activeTexture(gl.TEXTURE0 + unit);\n\tgl.bindTexture(gl.TEXTURE_2D, texture);\n\n\t\/\/ Determine if we must reallocate or do sub-image\n\tconst w = src.width, h = src.height;\n\tconst sizeKey = `__size_${sampler}`;\n\tconst last    = layer&#91;sizeKey&#93; || { w: -1, h: -1 };\n\n\tif (w !== last.w || h !== last.h) {\n\t\t\/\/ full allocate\n\t\tgl.texImage2D(\n\t\t\tgl.TEXTURE_2D, 0, gl.RGBA, w, h, 0,\n\t\t\tgl.RGBA, gl.UNSIGNED_BYTE, src\n\t\t);\n\t\tlayer&#91;sizeKey&#93; = { w, h };\n\n\t\t\/\/ if base image, update texelSize uniform immediately\n\t\tif (sampler === 'u_image' &amp;&amp; layer.uniforms.u_texelSize) {\n\t\t\tgl.useProgram(layer.program);\n\t\t\tgl.uniform2f(\n\t\t\t\tlayer.uniforms.u_texelSize,\n\t\t\t\t1 \/ w, 1 \/ h\n\t\t\t);\n\t\t}\n\t} else {\n\t\t\/\/ fast sub-image update\n\t\tgl.texSubImage2D(\n\t\t\tgl.TEXTURE_2D, 0, 0, 0, w, h,\n\t\t\tgl.RGBA, gl.UNSIGNED_BYTE, src\n\t\t);\n\t}\n\n\tcheckGLError(gl, `unit=${unit}, sampler=${sampler}`);\n};\n\n\n\n\n\/**\n * Starts the per-frame WebGL render loop.\n * This loop updates time\/config uniforms, handles resize,\n * and draws a full-screen quad using the textures already\n * bound by updateTextureUnit in your Fabric.js after:render.\n *\n * @param {object} layer\n *        The layer object returned by initWebGLLayer().\n *        Must have gl, program, attribs, vbo, uniforms,\n *        fabricCanvas, startTime, and lastW\/lastH fields.\n *\/\nBuilder.startRenderLoop = function(layer) {\n\tif (!layer || !layer.program) { throw new Error('startRenderLoop: invalid layer'); }\n\tconst { gl, program, vbo, attribs, uniforms, fabricCanvas, startTime } = layer;\n\n\t\/\/ bind samplers once (units 0\u20134)\n\tgl.useProgram(program);\n\tgl.uniform1i(uniforms.u_image,      0);\n\tgl.uniform1i(uniforms.u_maskGold,   1);\n\tgl.uniform1i(uniforms.u_maskSilver, 2);\n\tgl.uniform1i(uniforms.u_maskHolo,   3);\n\tgl.uniform1i(uniforms.u_maskUV,     4);\n\n\tfunction render(nowMs) {\n\t\tgl.useProgram(program);\n\n\t\t\/\/ time uniform\n\t\tif (uniforms.u_time) {\n\t\t\tconst t = (nowMs - startTime) * 0.001;\n\t\t\tgl.uniform1f(uniforms.u_time, t);\n\t\t}\n\n\t\t\/\/ shaderConfig uniforms\n\t\tconst C = Builder.shaderConfig;\n\t\tObject.entries(C).forEach((&#91;key, val&#93;) => {\n\t\t\tconst loc = uniforms&#91;key&#93;;\n\t\t\tif (!loc) return;\n\t\t\tif (Array.isArray(val) &amp;&amp; val.length === 3) {\n\t\t\t\tgl.uniform3fv(loc, val);\n\t\t\t} else if (typeof val === 'number') {\n\t\t\t\tgl.uniform1f(loc, val);\n\t\t\t}\n\t\t});\n\n\t\t\/\/ handle canvas resize \u2192 u_texelSize\n\t\tconst w = fabricCanvas.getWidth();\n\t\tconst h = fabricCanvas.getHeight();\n\t\tif (w !== layer.lastW || h !== layer.lastH) {\n\t\t\tlayer.lastW = w;\n\t\t\tlayer.lastH = h;\n\t\t\tif (uniforms.u_texelSize) {\n\t\t\t\tgl.uniform2f(uniforms.u_texelSize, 1 \/ w, 1 \/ h);\n\t\t\t}\n\t\t}\n\n\t\t\/\/ draw full-screen quad\n\t\tgl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);\n\t\tgl.clear(gl.COLOR_BUFFER_BIT);\n\t\tgl.bindBuffer(gl.ARRAY_BUFFER, vbo);\n\n\t\tgl.enableVertexAttribArray(attribs.a_position);\n\t\tgl.vertexAttribPointer(attribs.a_position, 2, gl.FLOAT, false, 16, 0);\n\t\tgl.enableVertexAttribArray(attribs.a_uv);\n\t\tgl.vertexAttribPointer(attribs.a_uv,       2, gl.FLOAT, false, 16, 8);\n\n\t\tgl.drawArrays(gl.TRIANGLES, 0, 6);\n\t\trequestAnimationFrame(render);\n\t}\n\n\trequestAnimationFrame(render);\n};<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki material-theme\" style=\"background-color: #263238\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #546E7A; font-style: italic\">\/**<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> * Uploads a source (canvas\/image\/video) into a given WebGL texture unit.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> * Re-allocates storage if dimensions change, otherwise performs a sub-image update.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> *<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> * <\/span><span style=\"color: #89DDFF; font-style: italic\">@<\/span><span style=\"color: #C792EA; font-style: italic\">param<\/span><span style=\"color: #546E7A; font-style: italic\"> <\/span><span style=\"color: #89DDFF; font-style: italic\">{<\/span><span style=\"color: #FFCB6B; font-style: italic\">Canvas|Image|Video|OffscreenCanvas<\/span><span style=\"color: #89DDFF; font-style: italic\">}<\/span><span style=\"color: #546E7A; font-style: italic\"> <\/span><span style=\"color: #EEFFFF; font-style: italic\">src<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> *        The source element whose pixels will be uploaded.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> * <\/span><span style=\"color: #89DDFF; font-style: italic\">@<\/span><span style=\"color: #C792EA; font-style: italic\">param<\/span><span style=\"color: #546E7A; font-style: italic\"> <\/span><span style=\"color: #89DDFF; font-style: italic\">{<\/span><span style=\"color: #FFCB6B; font-style: italic\">object|string|HTMLCanvasElement<\/span><span style=\"color: #89DDFF; font-style: italic\">}<\/span><span style=\"color: #546E7A; font-style: italic\"> <\/span><span style=\"color: #EEFFFF; font-style: italic\">layerRef<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> *        The layer object (returned by initWebGLLayer),<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> *        its ID string (glCanvas.id), or its gl-canvas element.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> * <\/span><span style=\"color: #89DDFF; font-style: italic\">@<\/span><span style=\"color: #C792EA; font-style: italic\">param<\/span><span style=\"color: #546E7A; font-style: italic\"> <\/span><span style=\"color: #89DDFF; font-style: italic\">{<\/span><span style=\"color: #FFCB6B; font-style: italic\">number<\/span><span style=\"color: #89DDFF; font-style: italic\">}<\/span><span style=\"color: #546E7A; font-style: italic\"> <\/span><span style=\"color: #89DDFF; font-style: italic\">&#91;<\/span><span style=\"color: #EEFFFF; font-style: italic\">unit<\/span><span style=\"color: #89DDFF; font-style: italic\">=<\/span><span style=\"color: #EEFFFF; font-style: italic\">0<\/span><span style=\"color: #89DDFF; font-style: italic\">&#93;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> *        Texture unit index: 0\u2192TEXTURE0, 1\u2192TEXTURE1, \u2026<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> * <\/span><span style=\"color: #89DDFF; font-style: italic\">@<\/span><span style=\"color: #C792EA; font-style: italic\">param<\/span><span style=\"color: #546E7A; font-style: italic\"> <\/span><span style=\"color: #89DDFF; font-style: italic\">{<\/span><span style=\"color: #FFCB6B; font-style: italic\">string<\/span><span style=\"color: #89DDFF; font-style: italic\">}<\/span><span style=\"color: #546E7A; font-style: italic\"> <\/span><span style=\"color: #89DDFF; font-style: italic\">&#91;<\/span><span style=\"color: #EEFFFF; font-style: italic\">sampler<\/span><span style=\"color: #89DDFF; font-style: italic\">=<\/span><span style=\"color: #EEFFFF; font-style: italic\">&#39;u_image&#39;<\/span><span style=\"color: #89DDFF; font-style: italic\">&#93;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> *        The sampler uniform key in layer.textures<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> *        (e.g. &#39;u_image&#39;,&#39;u_maskGold&#39;,&#39;u_maskSilver&#39;,\u2026).<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> *\/<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">Builder<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">updateTextureUnit<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #C792EA\">function<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #EEFFFF; font-style: italic\">src<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #EEFFFF; font-style: italic\">layerRef<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #EEFFFF; font-style: italic\">unit<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #EEFFFF; font-style: italic\">sampler<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">u_image<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">)<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #EEFFFF\">console<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">log<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">`<\/span><span style=\"color: #C3E88D\">Updating <\/span><span style=\"color: #89DDFF\">${<\/span><span style=\"color: #EEFFFF\">sampler<\/span><span style=\"color: #89DDFF\">}<\/span><span style=\"color: #C3E88D\"> for <\/span><span style=\"color: #89DDFF\">${<\/span><span style=\"color: #EEFFFF\">unit<\/span><span style=\"color: #89DDFF\">}`<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ Resolve layer object<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #C792EA\">let<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">layer<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF; font-style: italic\">if<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #89DDFF\">typeof<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">layerRef<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">===<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">string<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">layer<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">Builder<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">layers<\/span><span style=\"color: #F07178\">&#91;<\/span><span style=\"color: #EEFFFF\">layerRef<\/span><span style=\"color: #F07178\">&#93;<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF\">}<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF; font-style: italic\">else<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF; font-style: italic\">if<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #EEFFFF\">layerRef<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">instanceof<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #FFCB6B\">HTMLCanvasElement<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">layer<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">Builder<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">layers<\/span><span style=\"color: #F07178\">&#91;<\/span><span style=\"color: #EEFFFF\">layerRef<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">id<\/span><span style=\"color: #F07178\">&#93;<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF\">}<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF; font-style: italic\">else<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">layer<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">layerRef<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF; font-style: italic\">if<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #89DDFF\">!<\/span><span style=\"color: #EEFFFF\">layer<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">{<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">console<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">error<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">updateTextureUnit: missing layer<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">layerRef<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF; font-style: italic\">return<\/span><span style=\"color: #89DDFF\">;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #F07178\">      <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">layer<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">texture<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">layer<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">textures<\/span><span style=\"color: #F07178\">&#91;<\/span><span style=\"color: #EEFFFF\">sampler<\/span><span style=\"color: #F07178\">&#93;<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF; font-style: italic\">if<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #89DDFF\">!<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">||<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">!<\/span><span style=\"color: #EEFFFF\">texture<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">{<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">console<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">error<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">updateTextureUnit: invalid sampler<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">sampler<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF; font-style: italic\">return<\/span><span style=\"color: #89DDFF\">;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ Bind the texture to the chosen unit<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">activeTexture<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">TEXTURE0<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">+<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">unit<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">bindTexture<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">TEXTURE_2D<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">texture<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ Determine if we must reallocate or do sub-image<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">w<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">src<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">width<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">h<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">src<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">height<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">sizeKey<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">`<\/span><span style=\"color: #C3E88D\">__size_<\/span><span style=\"color: #89DDFF\">${<\/span><span style=\"color: #EEFFFF\">sampler<\/span><span style=\"color: #89DDFF\">}`<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">last<\/span><span style=\"color: #F07178\">    <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">layer<\/span><span style=\"color: #F07178\">&#91;<\/span><span style=\"color: #EEFFFF\">sizeKey<\/span><span style=\"color: #F07178\">&#93; <\/span><span style=\"color: #89DDFF\">||<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">{<\/span><span style=\"color: #F07178\"> w<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">-<\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> h<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">-<\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">};<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF; font-style: italic\">if<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #EEFFFF\">w<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">!==<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">last<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">w<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">||<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">h<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">!==<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">last<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">h<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ full allocate<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">texImage2D<\/span><span style=\"color: #F07178\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">TEXTURE_2D<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">RGBA<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">w<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">h<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">RGBA<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">UNSIGNED_BYTE<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">src<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">layer<\/span><span style=\"color: #F07178\">&#91;<\/span><span style=\"color: #EEFFFF\">sizeKey<\/span><span style=\"color: #F07178\">&#93; <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">{<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">w<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">h<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">};<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ if base image, update texelSize uniform immediately<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #89DDFF; font-style: italic\">if<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #EEFFFF\">sampler<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">===<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">u_image<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">&amp;&amp;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">layer<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">uniforms<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">u_texelSize<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">useProgram<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">layer<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">program<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">uniform2f<\/span><span style=\"color: #F07178\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t\t<\/span><span style=\"color: #EEFFFF\">layer<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">uniforms<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">u_texelSize<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t\t<\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">\/<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">w<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">\/<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">h<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF\">}<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF; font-style: italic\">else<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ fast sub-image update<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">texSubImage2D<\/span><span style=\"color: #F07178\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">TEXTURE_2D<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">w<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">h<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">RGBA<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">UNSIGNED_BYTE<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">src<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #82AAFF\">checkGLError<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">`<\/span><span style=\"color: #C3E88D\">unit=<\/span><span style=\"color: #89DDFF\">${<\/span><span style=\"color: #EEFFFF\">unit<\/span><span style=\"color: #89DDFF\">}<\/span><span style=\"color: #C3E88D\">, sampler=<\/span><span style=\"color: #89DDFF\">${<\/span><span style=\"color: #EEFFFF\">sampler<\/span><span style=\"color: #89DDFF\">}`<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">};<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\">\/**<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> * Starts the per-frame WebGL render loop.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> * This loop updates time\/config uniforms, handles resize,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> * and draws a full-screen quad using the textures already<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> * bound by updateTextureUnit in your Fabric.js after:render.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> *<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> * <\/span><span style=\"color: #89DDFF; font-style: italic\">@<\/span><span style=\"color: #C792EA; font-style: italic\">param<\/span><span style=\"color: #546E7A; font-style: italic\"> <\/span><span style=\"color: #89DDFF; font-style: italic\">{<\/span><span style=\"color: #FFCB6B; font-style: italic\">object<\/span><span style=\"color: #89DDFF; font-style: italic\">}<\/span><span style=\"color: #546E7A; font-style: italic\"> <\/span><span style=\"color: #EEFFFF; font-style: italic\">layer<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> *        The layer object returned by initWebGLLayer().<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> *        Must have gl, program, attribs, vbo, uniforms,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> *        fabricCanvas, startTime, and lastW\/lastH fields.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> *\/<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">Builder<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">startRenderLoop<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #C792EA\">function<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #EEFFFF; font-style: italic\">layer<\/span><span style=\"color: #89DDFF\">)<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF; font-style: italic\">if<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #89DDFF\">!<\/span><span style=\"color: #EEFFFF\">layer<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">||<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">!<\/span><span style=\"color: #EEFFFF\">layer<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">program<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">{<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF; font-style: italic\">throw<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">new<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">Error<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">startRenderLoop: invalid layer<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">{<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">program<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">vbo<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">attribs<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">uniforms<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">fabricCanvas<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">startTime<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">}<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">layer<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ bind samplers once (units 0\u20134)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">useProgram<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">program<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">uniform1i<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">uniforms<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">u_image<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\">      <\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">uniform1i<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">uniforms<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">u_maskGold<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\">   <\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">uniform1i<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">uniforms<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">u_maskSilver<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">2<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">uniform1i<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">uniforms<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">u_maskHolo<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\">   <\/span><span style=\"color: #F78C6C\">3<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">uniform1i<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">uniforms<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">u_maskUV<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\">     <\/span><span style=\"color: #F78C6C\">4<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #C792EA\">function<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">render<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #EEFFFF; font-style: italic\">nowMs<\/span><span style=\"color: #89DDFF\">)<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">useProgram<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">program<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ time uniform<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #89DDFF; font-style: italic\">if<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #EEFFFF\">uniforms<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">u_time<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">t<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #EEFFFF\">nowMs<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">-<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">startTime<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">*<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0.001<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">uniform1f<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">uniforms<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">u_time<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">t<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ shaderConfig uniforms<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">C<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">Builder<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">shaderConfig<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">Object<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">entries<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">C<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">forEach<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">(&#91;<\/span><span style=\"color: #EEFFFF; font-style: italic\">key<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF; font-style: italic\">val<\/span><span style=\"color: #89DDFF\">&#93;)<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #C792EA\">=&gt;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">loc<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">uniforms<\/span><span style=\"color: #F07178\">&#91;<\/span><span style=\"color: #EEFFFF\">key<\/span><span style=\"color: #F07178\">&#93;<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #89DDFF; font-style: italic\">if<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #89DDFF\">!<\/span><span style=\"color: #EEFFFF\">loc<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF; font-style: italic\">return<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #89DDFF; font-style: italic\">if<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #EEFFFF\">Array<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">isArray<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">val<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">&amp;&amp;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">val<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">length<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">===<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">3<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">uniform3fv<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">loc<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">val<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #89DDFF\">}<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF; font-style: italic\">else<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF; font-style: italic\">if<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #89DDFF\">typeof<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">val<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">===<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">number<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">uniform1f<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">loc<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">val<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #89DDFF\">}<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ handle canvas resize \u2192 u_texelSize<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">w<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">fabricCanvas<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">getWidth<\/span><span style=\"color: #F07178\">()<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">h<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">fabricCanvas<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">getHeight<\/span><span style=\"color: #F07178\">()<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #89DDFF; font-style: italic\">if<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #EEFFFF\">w<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">!==<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">layer<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">lastW<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">||<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">h<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">!==<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">layer<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">lastH<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #EEFFFF\">layer<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">lastW<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">w<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #EEFFFF\">layer<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">lastH<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">h<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #89DDFF; font-style: italic\">if<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #EEFFFF\">uniforms<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">u_texelSize<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">uniform2f<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">uniforms<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">u_texelSize<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">\/<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">w<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">\/<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">h<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ draw full-screen quad<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">viewport<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">drawingBufferWidth<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">drawingBufferHeight<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">clear<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">COLOR_BUFFER_BIT<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">bindBuffer<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">ARRAY_BUFFER<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">vbo<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">enableVertexAttribArray<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">attribs<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">a_position<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">vertexAttribPointer<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">attribs<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">a_position<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">2<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">FLOAT<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #FF9CAC\">false<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">16<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">enableVertexAttribArray<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">attribs<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">a_uv<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">vertexAttribPointer<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">attribs<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">a_uv<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\">       <\/span><span style=\"color: #F78C6C\">2<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">FLOAT<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #FF9CAC\">false<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">16<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">8<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">drawArrays<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">TRIANGLES<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">6<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #82AAFF\">requestAnimationFrame<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">render<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #82AAFF\">requestAnimationFrame<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">render<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">};<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>Builder.uploadTextureUnit provides our bitmasks from the base fabric.js layer. Our render loop is reasonably tight in this implementation for mobile performance reasons &#8211; a lot of the lifting is deferred to our init and upload functions, and this architecture allows us to throttle at the source of truth (changes initiated by a user through fabric.js).<\/p>\n\n\n\n<p>Additionally, we eschew tiling, because the design characteristics of a small, sub 800&#215;600 preview window offer diminishing returns in comparison to a fullscreen application. <\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>The key performance innovation is driven by the choice to introduce the separate file assets pipeline outside of fabric.js. E.g, By handling those larger print-ready textures with a fully separate export line, our 800&#215;600<\/p>\n<\/div><\/div>\n\n<div class=\"wp-block-grapham-mapping grapham-mapping-block\" data-cell-id=\"TKpOnsKza9iosXShlxyd-28\" data-cell-label=\"TiffWriter :: encode(opts)\"><div class=\"grapham-mapping-header\"><span class=\"grapham-mapping-label\">TiffWriter :: encode(opts)<\/span><span class=\"grapham-mapping-cellid\">TKpOnsKza9iosXShlxyd-28<\/span><\/div><div class=\"grapham-mapping-content\">\n<p>UTIF and other javascript-based TIFF libraries are not up to the task of complex TIFF operations, largely as a function of historical support for TIFF in web browsers. One library proudly states that it will &#8220;fail silently&#8221; because &#8220;it will encourage people to stop using Tiff.&#8221;<br><br>Consequently, most pipelines use a mixture of PDFs and other assets. But this need not be the case. While Spot Registry is the true heavy lifter (not showcased in this demo) and can handle the complexity of linking and producing packages of files and masks for today&#8217;s pipelines, there are good reasons to revisit Tiff in a web-fronted context.<br><br>Few image formats other than TIFF offer the ability to extend data beyond three to four 0-255 values per point, which is problematic (consider grayscale heightmaps from satellite data or medical imaging). And in print, all our additional processes, masks, spots and raster-based data can be packaged into a completely reproducible, archival-quality single package: one file per job. <\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>To take advantage of this, all we need to do is follow the Tiff spec as it already stands. For that, we&#8217;ll roll our own encoder and handle the IFD assembly and the binary data ourselves.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#EEFFFF;--cbp-line-number-width:calc(3 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 0 16px;font-size:0.8em;width:100%;text-align:left;background-color:#263238;font-style:italic;color:#EEFFFF\"><span style=\"border-bottom:1px solid rgba(238, 255, 255, 0.2)\">JavaScript<\/span><\/span><span role=\"button\" tabindex=\"0\" style=\"color:#EEFFFF;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>\n\/\/ ES Module for writing little-endian TIFFs with optional spot inks,\n\/\/ transparency, and ICC profiles. Leaves files in RGB so your RIP can handle the conversion.\n\n\/\/ want to check the exports?\n\/\/   # apt install libtiff-tools\n\/\/   tiffinfo -v export_spot\\(\\20\\).tif\n\nconst LE = true;  \/\/ little-endian flag for DataView\n\n\/\/ TIFF tag codes\nconst Tags = {\n\tImageWidth:                256,\n\tImageLength:               257,\n\tBitsPerSample:             258,\n\tCompression:               259,\n\tPhotometricInterpretation: 262,\n\tPlanarConfiguration:       284,\n\tSamplesPerPixel:           277,\n\tRowsPerStrip:              278,\n\tStripOffsets:              273,\n\tStripByteCounts:           279,\n\tXResolution:               282,\n\tYResolution:               283,\n\tResolutionUnit:            296,\n\tSoftware:                  305,\n\tInkNames:                  333,\n\tExtraSamples:              338,\n\tSampleFormat:              339,\n\tICCProfile:                34675,\n\n\t\/\/ Photoshop private tags\n\tAlphaChannelNames:         1006,  \/\/ 0x3EE\n\tDisplayInfo1:              1007,  \/\/ 0x3EF\n\tAlphaIdentifiers:          1053,  \/\/ 0x41D\n\tAlternateSpotColors:       1067,  \/\/ 0x42B\n\tDisplayInfo2:              1077   \/\/ 0x435\n};\n\n\/\/ Bytes per element for each TIFF field type\nconst TypeSize = {\n\t1: 1,   \/\/ BYTE\n\t2: 1,   \/\/ ASCII\n\t3: 2,   \/\/ SHORT\n\t4: 4,   \/\/ LONG\n\t5: 8,   \/\/ RATIONAL\n\t7: 1,   \/\/ UNDEFINED (ICC Profile &amp; Photoshop blobs)\n\t12: 8   \/\/ DOUBLE\n};\n\n\/\/ TIFF extra-sample codes (from the TIFF 6.0 spec)\n\/\/ 0 = unspecified (use InkNames to interpret spot colors)\n\/\/ 1 = associated alpha (premultiplied) \u2013 rarely used\n\/\/ 2 = unassociated alpha (straight alpha)\nconst ExtraSample = {\n\tUnspecified: 0,\n\tAssociatedAlpha: 1,\n\tUnassociatedAlpha: 2\n};\n\n\/**\n * Write a JS string as ASCII (plus trailing null) into a DataView.\n *\/\nfunction writeASCII(view, offset, str) {\n\tfor (let i = 0; i &lt; str.length; i++) {\n\t\tview.setUint8(offset + i, str.charCodeAt(i));\n\t}\n\tview.setUint8(offset + str.length, 0);\n}\n\n\/**\n * Encode raw RGB(A) + spot masks + ICC into a TIFF ArrayBuffer.\n *\n * opts: {\n *   width: number,\n *   height: number,\n *   baseImage: ArrayBuffer|TypedArray,       \/\/ interleaved RGB or RGBA\n *   colorOrder: 'RGB'|'RGBA',\n *   spotMasks?: {\n *     names: string[],                       \/\/ e.g. &#91;'Gold'&#93;\n *     buffers: ArrayBuffer[]                 \/\/ same length as names\n *   },\n *   iccProfile?: ArrayBuffer|Uint8Array,      \/\/ optional ICC profile\n *   photoshop?: {                             \/\/ optional Photoshop tags\n *     alphaChannelNames?: string[],\n *     alphaChannelIdentifiers?: number[],\n *     alternateSpotColors?: number[][],      \/\/ each &#91;C,M,Y,K&#93;\n *     displayInfo1?: ArrayBuffer|Uint8Array,\n *     displayInfo2?: ArrayBuffer|Uint8Array\n *   },\n *   xResolution?: number|&#91;number,number&#93;,\n *   yResolution?: number|&#91;number,number&#93;,\n *   resolutionUnit?: number\n * }\n *\n * Returns a little-endian TIFF file as an ArrayBuffer.\n *\/\nexport function encode(opts) {\n\tconst {\n\t\twidth,\n\t\theight,\n\t\tbaseImage,\n\t\tcolorOrder,\n\t\tspotMasks,\n\t\ticcProfile,\n\t\txResolution = 1,\n\t\tyResolution = 1,\n\t\tresolutionUnit = 2,\n\t\tphotoshop = {}\n\t} = opts;\n\n\tconst &#91;xResNum, xResDen&#93; = Array.isArray(xResolution) ? xResolution : &#91;xResolution, 1&#93;;\n\tconst &#91;yResNum, yResDen&#93; = Array.isArray(yResolution) ? yResolution : &#91;yResolution, 1&#93;;\n\n\tconst hasAlpha  = colorOrder === 'RGBA';\n\tconst spotCount = spotMasks?.buffers?.length || 0;\n\tconst channels  = 3 + (hasAlpha ? 1 : 0) + spotCount;\n\n\t\/\/ Normalize pixel data to Uint8Array\n\tconst buf = baseImage instanceof ArrayBuffer\n\t\t? new Uint8Array(baseImage)\n\t\t: new Uint8Array(baseImage.buffer || baseImage);\n\n\t\/\/ Split into per-channel planes (R, G, B, &#91;A&#93;, &#91;spots...&#93;)\n\tconst planeSize = width * height;\n\tconst planes = [];\n\tfor (let c = 0; c &lt; 3 + (hasAlpha ? 1 : 0); c++) {\n\t\tplanes.push(new Uint8Array(planeSize));\n\t}\n\tlet idx = 0;\n\tfor (let i = 0; i &lt; planeSize; i++) {\n\t\tplanes&#91;0&#93;&#91;i&#93; = buf&#91;idx++&#93;;\n\t\tplanes&#91;1&#93;&#91;i&#93; = buf&#91;idx++&#93;;\n\t\tplanes&#91;2&#93;&#91;i&#93; = buf&#91;idx++&#93;;\n\t\tif (hasAlpha) {\n\t\t\tplanes&#91;3&#93;&#91;i&#93; = buf&#91;idx++&#93;;\n\t\t}\n\t}\n\t\/\/ Spot-mask planes (one buffer per spot name)\n\tif (spotCount) {\n\t\tfor (let s = 0; s &lt; spotCount; s++) {\n\t\t\tplanes.push(new Uint8Array(spotMasks.buffers&#91;s&#93;));\n\t\t}\n\t}\n\n\t\/\/ Interleave all planes into one big pixel buffer\n\tconst pixelBuf = new Uint8Array(planeSize * channels);\n\tfor (let i = 0; i &lt; planeSize; i++) {\n\t\tfor (let c = 0; c &lt; channels; c++) {\n\t\t\tpixelBuf&#91;i * channels + c&#93; = planes&#91;c&#93;&#91;i&#93;;\n\t\t}\n\t}\n\n\t\/\/ Build IFD entries\n\tconst entries = [];\n\tfunction add(tagName, type, count, value) {\n\t\tentries.push({ tag: Tags&#91;tagName&#93;, type, count, value });\n\t}\n\n\t\/\/ Core TIFF tags\n\tadd('ImageWidth',          4, 1, &#91;width&#93;);\n\tadd('ImageLength',         4, 1, &#91;height&#93;);\n\tadd('BitsPerSample',       3, channels, new Array(channels).fill(8));\n\tadd('Compression',         3, 1, &#91;1&#93;);\n\tadd('SamplesPerPixel',     3, 1, &#91;channels&#93;);\n\tadd('RowsPerStrip',        4, 1, &#91;height&#93;);\n\tadd('StripByteCounts',     4, 1, &#91;pixelBuf.byteLength&#93;);\n\tadd('XResolution',         5, 1, &#91;xResNum, xResDen&#93;);\n\tadd('YResolution',         5, 1, &#91;yResNum, yResDen&#93;);\n\tadd('ResolutionUnit',      3, 1, &#91;resolutionUnit&#93;);\n\n\t\/\/ Software tag now stores a plain string, not an array\n\tadd('Software',            2, 'TIFFWriter'.length + 1, 'TIFFWriter');\n\n\t\/\/ Keep base as RGB\n\tadd('PhotometricInterpretation', 3, 1, &#91;2&#93;);\n\tadd('PlanarConfiguration',       3, 1, &#91;1&#93;);\n\n\t\/\/ ExtraSamples and SampleFormat\n\tif (hasAlpha || spotCount) {\n\t\tconst extraVals = [];\n\t\tif (hasAlpha) {\n\t\t\textraVals.push(ExtraSample.UnassociatedAlpha);\n\t\t}\n\t\tfor (let s = 0; s &lt; spotCount; s++) {\n\t\t\textraVals.push(ExtraSample.Unspecified);\n\t\t}\n\t\tadd('ExtraSamples',  3, extraVals.length, extraVals);\n\n\t\tadd('SampleFormat',  3, channels, new Array(channels).fill(1));\n\t}\n\n\t\/\/ InkNames \u2013 one null-separated string for R,G,B,&#91;Alpha&#93;,&#91;spot\u2026&#93;\n\tif (spotCount > 0) {\n\t\tconst names = [];\n\t\tnames.push('R', 'G', 'B');\n\t\tif (hasAlpha) { names.push('A'); }\n\t\tif (spotCount) { names.push(...spotMasks.names); }\n\n\t\tconst inkNamesStr = names.join('\\0') + '\\0';\n\t\tadd('InkNames', 2, inkNamesStr.length, inkNamesStr);\n\t}\n\n\t\/\/\n\t\/\/ === Photoshop private tags ===\n\t\/\/\n\t\/\/ AlphaChannelNames: null\u2010terminated names of each extra (spot) plane\n\tif (photoshop.alphaChannelNames?.length) {\n\t\tconst acn = photoshop.alphaChannelNames.join('\\0') + '\\0';\n\t\tadd('AlphaChannelNames', 2, acn.length, acn);\n\t}\n\n\t\/\/ AlphaIdentifiers: unique short IDs for each extra plane\n\tif (photoshop.alphaChannelIdentifiers?.length === spotCount) {\n\t\tadd(\n\t\t\t'AlphaIdentifiers',\n\t\t\t3,\n\t\t\tphotoshop.alphaChannelIdentifiers.length,\n\t\t\tphotoshop.alphaChannelIdentifiers\n\t\t);\n\t}\n\n\t\/\/ AlternateSpotColors: fallback CMYK for each spot\n\tif (photoshop.alternateSpotColors?.length === spotCount) {\n\t\tconst flat = photoshop.alternateSpotColors.flat();\n\t\tadd('AlternateSpotColors', 3, flat.length, flat);\n\t}\n\n\t\/\/ DisplayInfo1 &amp; DisplayInfo2: opaque Photoshop \u201cblob\u201d hints\n\tif (photoshop.displayInfo1) {\n\t\tconst blob = photoshop.displayInfo1 instanceof Uint8Array\n\t\t\t? photoshop.displayInfo1\n\t\t\t: new Uint8Array(photoshop.displayInfo1);\n\t\tadd('DisplayInfo1', 7, blob.length, &#91;blob&#93;);\n\t}\n\tif (photoshop.displayInfo2) {\n\t\tconst blob = photoshop.displayInfo2 instanceof Uint8Array\n\t\t\t? photoshop.displayInfo2\n\t\t\t: new Uint8Array(photoshop.displayInfo2);\n\t\tadd('DisplayInfo2', 7, blob.length, &#91;blob&#93;);\n\t}\n\n\t\/\/\n\t\/\/ === end Photoshop tags ===\n\t\/\/\n\n\t\/\/ Optional ICC profile\n\tif (iccProfile) {\n\t\tconst icc = iccProfile instanceof ArrayBuffer\n\t\t\t? new Uint8Array(iccProfile)\n\t\t\t: new Uint8Array(iccProfile.buffer || iccProfile);\n\t\tadd('ICCProfile', 7, icc.length, &#91;icc&#93;);\n\t}\n\n\t\/\/ Placeholder for StripOffsets\n\tadd('StripOffsets', 4, 1, &#91;0&#93;);\n\tentries.sort((a, b) => a.tag - b.tag);\n\n\t\/\/ Compute IFD size + overflow area\n\tconst ifdStart = 8;\n\tconst dirSize  = 2 + entries.length * 12 + 4;\n\tlet dataOff    = ifdStart + dirSize;\n\tconst overflow = [];\n\n\tfor (const e of entries) {\n\t\tconst len = TypeSize&#91;e.type&#93; * e.count;\n\t\tif (len > 4) {\n\t\t\te.offsetValue = dataOff;\n\t\t\toverflow.push(e);\n\t\t\tdataOff += len + (len &amp; 1);\n\t\t}\n\t}\n\n\t\/\/ Patch StripOffsets \u2192 pixel data\n\tconst pixelOffset = dataOff;\n\tconst stripEnt    = entries.find(e => e.tag === Tags.StripOffsets);\n\tstripEnt.value       = &#91;pixelOffset&#93;;\n\tstripEnt.offsetValue = pixelOffset;\n\tdataOff += pixelBuf.byteLength;\n\n\t\/\/ Allocate output buffer + DataView\n\tconst buffer = new ArrayBuffer(dataOff);\n\tconst view   = new DataView(buffer);\n\n\t\/\/ Write TIFF header\n\tview.setUint8(0, 0x49);\n\tview.setUint8(1, 0x49);\n\tview.setUint16(2, 42, LE);\n\tview.setUint32(4, ifdStart, LE);\n\n\t\/\/ Write IFD entries\n\tlet p = ifdStart;\n\tview.setUint16(p, entries.length, LE);\n\tp += 2;\n\n\tfor (const e of entries) {\n\t\tview.setUint16(p, e.tag, LE);   p += 2;\n\t\tview.setUint16(p, e.type, LE);  p += 2;\n\t\tview.setUint32(p, e.count, LE); p += 4;\n\n\t\tconst len = TypeSize&#91;e.type&#93; * e.count;\n\t\tif (len > 4) {\n\t\t\tview.setUint32(p, e.offsetValue, LE);\n\t\t} else {\n\t\t\tif (e.type === 3) {\n\t\t\t\tfor (let i = 0; i &lt; e.count; i++) {\n\t\t\t\t\tview.setUint16(p + 2 * i, e.value&#91;i&#93;, LE);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (e.type === 4) {\n\t\t\t\tview.setUint32(p, e.value&#91;0&#93;, LE);\n\t\t\t}\n\t\t}\n\t\tp += 4;\n\t}\n\n\t\/\/ next IFD pointer = 0\n\tview.setUint32(p, 0, LE);\n\n\t\/\/ Write overflow blocks (InkNames, Software, ICC, ExtraSamples arrays, etc.)\n\tfor (const e of overflow) {\n\t\tconst off = e.offsetValue;\n\t\tswitch (e.type) {\n\t\t\tcase 2: \/\/ ASCII\n\t\t\t\tconst str = Array.isArray(e.value) ? e.value.join('') : e.value;\n\t\t\t\twriteASCII(view, off, str);\n\t\t\t\tbreak;\n\t\t\tcase 3: \/\/ SHORT\n\t\t\t\tfor (let i = 0; i &lt; e.count; i++) {\n\t\t\t\t\tview.setUint16(off + 2 * i, e.value&#91;i&#93;, LE);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase 5: \/\/ RATIONAL\n\t\t\t\tfor (let i = 0; i &lt; e.count; i++) {\n\t\t\t\t\tconst num = e.value&#91;2 * i&#93;;\n\t\t\t\t\tconst den = e.value&#91;2 * i + 1&#93;;\n\t\t\t\t\tview.setUint32(off + 8 * i,     num, LE);\n\t\t\t\t\tview.setUint32(off + 8 * i + 4, den, LE);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase 7: \/\/ UNDEFINED (ICC profile or Photoshop blobs)\n\t\t\t\tnew Uint8Array(buffer, off, e.value&#91;0&#93;.length).set(e.value&#91;0&#93;);\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\t\/\/ Write pixel data into the file\n\tnew Uint8Array(buffer, pixelOffset, pixelBuf.byteLength).set(pixelBuf);\n\n\treturn buffer;\n}\n<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki material-theme\" style=\"background-color: #263238\" tabindex=\"0\"><code><span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\">\/\/ ES Module for writing little-endian TIFFs with optional spot inks,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\">\/\/ transparency, and ICC profiles. Leaves files in RGB so your RIP can handle the conversion.<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\">\/\/ want to check the exports?<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\">\/\/   # apt install libtiff-tools<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\">\/\/   tiffinfo -v export_spot\\(\\20\\).tif<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #C792EA\">const<\/span><span style=\"color: #EEFFFF\"> LE <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #FF9CAC\">true<\/span><span style=\"color: #89DDFF\">;<\/span><span style=\"color: #EEFFFF\">  <\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ little-endian flag for DataView<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\">\/\/ TIFF tag codes<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C792EA\">const<\/span><span style=\"color: #EEFFFF\"> Tags <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">\t<\/span><span style=\"color: #F07178\">ImageWidth<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\">                <\/span><span style=\"color: #F78C6C\">256<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">\t<\/span><span style=\"color: #F07178\">ImageLength<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\">               <\/span><span style=\"color: #F78C6C\">257<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">\t<\/span><span style=\"color: #F07178\">BitsPerSample<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\">             <\/span><span style=\"color: #F78C6C\">258<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">\t<\/span><span style=\"color: #F07178\">Compression<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\">               <\/span><span style=\"color: #F78C6C\">259<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">\t<\/span><span style=\"color: #F07178\">PhotometricInterpretation<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #F78C6C\">262<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">\t<\/span><span style=\"color: #F07178\">PlanarConfiguration<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\">       <\/span><span style=\"color: #F78C6C\">284<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">\t<\/span><span style=\"color: #F07178\">SamplesPerPixel<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\">           <\/span><span style=\"color: #F78C6C\">277<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">\t<\/span><span style=\"color: #F07178\">RowsPerStrip<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\">              <\/span><span style=\"color: #F78C6C\">278<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">\t<\/span><span style=\"color: #F07178\">StripOffsets<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\">              <\/span><span style=\"color: #F78C6C\">273<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">\t<\/span><span style=\"color: #F07178\">StripByteCounts<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\">           <\/span><span style=\"color: #F78C6C\">279<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">\t<\/span><span style=\"color: #F07178\">XResolution<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\">               <\/span><span style=\"color: #F78C6C\">282<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">\t<\/span><span style=\"color: #F07178\">YResolution<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\">               <\/span><span style=\"color: #F78C6C\">283<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">\t<\/span><span style=\"color: #F07178\">ResolutionUnit<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\">            <\/span><span style=\"color: #F78C6C\">296<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">\t<\/span><span style=\"color: #F07178\">Software<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\">                  <\/span><span style=\"color: #F78C6C\">305<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">\t<\/span><span style=\"color: #F07178\">InkNames<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\">                  <\/span><span style=\"color: #F78C6C\">333<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">\t<\/span><span style=\"color: #F07178\">ExtraSamples<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\">              <\/span><span style=\"color: #F78C6C\">338<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">\t<\/span><span style=\"color: #F07178\">SampleFormat<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\">              <\/span><span style=\"color: #F78C6C\">339<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">\t<\/span><span style=\"color: #F07178\">ICCProfile<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\">                <\/span><span style=\"color: #F78C6C\">34675<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ Photoshop private tags<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">\t<\/span><span style=\"color: #F07178\">AlphaChannelNames<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\">         <\/span><span style=\"color: #F78C6C\">1006<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #EEFFFF\">  <\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ 0x3EE<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">\t<\/span><span style=\"color: #F07178\">DisplayInfo1<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\">              <\/span><span style=\"color: #F78C6C\">1007<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #EEFFFF\">  <\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ 0x3EF<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">\t<\/span><span style=\"color: #F07178\">AlphaIdentifiers<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\">          <\/span><span style=\"color: #F78C6C\">1053<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #EEFFFF\">  <\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ 0x41D<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">\t<\/span><span style=\"color: #F07178\">AlternateSpotColors<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\">       <\/span><span style=\"color: #F78C6C\">1067<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #EEFFFF\">  <\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ 0x42B<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">\t<\/span><span style=\"color: #F07178\">DisplayInfo2<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\">              <\/span><span style=\"color: #F78C6C\">1077<\/span><span style=\"color: #EEFFFF\">   <\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ 0x435<\/span><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">};<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\">\/\/ Bytes per element for each TIFF field type<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C792EA\">const<\/span><span style=\"color: #EEFFFF\"> TypeSize <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">\t<\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #EEFFFF\">   <\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ BYTE<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">\t<\/span><span style=\"color: #F78C6C\">2<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #EEFFFF\">   <\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ ASCII<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">\t<\/span><span style=\"color: #F78C6C\">3<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #F78C6C\">2<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #EEFFFF\">   <\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ SHORT<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">\t<\/span><span style=\"color: #F78C6C\">4<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #F78C6C\">4<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #EEFFFF\">   <\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ LONG<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">\t<\/span><span style=\"color: #F78C6C\">5<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #F78C6C\">8<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #EEFFFF\">   <\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ RATIONAL<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">\t<\/span><span style=\"color: #F78C6C\">7<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #EEFFFF\">   <\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ UNDEFINED (ICC Profile &amp; Photoshop blobs)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">\t<\/span><span style=\"color: #F78C6C\">12<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #F78C6C\">8<\/span><span style=\"color: #EEFFFF\">   <\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ DOUBLE<\/span><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">};<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\">\/\/ TIFF extra-sample codes (from the TIFF 6.0 spec)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\">\/\/ 0 = unspecified (use InkNames to interpret spot colors)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\">\/\/ 1 = associated alpha (premultiplied) \u2013 rarely used<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\">\/\/ 2 = unassociated alpha (straight alpha)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C792EA\">const<\/span><span style=\"color: #EEFFFF\"> ExtraSample <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">\t<\/span><span style=\"color: #F07178\">Unspecified<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">\t<\/span><span style=\"color: #F07178\">AssociatedAlpha<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">\t<\/span><span style=\"color: #F07178\">UnassociatedAlpha<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #F78C6C\">2<\/span><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">};<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\">\/**<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> * Write a JS string as ASCII (plus trailing null) into a DataView.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> *\/<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C792EA\">function<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #82AAFF\">writeASCII<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #EEFFFF; font-style: italic\">view<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #EEFFFF; font-style: italic\">offset<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #EEFFFF; font-style: italic\">str<\/span><span style=\"color: #89DDFF\">)<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF; font-style: italic\">for<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #C792EA\">let<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">i<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #89DDFF\">;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">i<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">&lt;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">str<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">length<\/span><span style=\"color: #89DDFF\">;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">i<\/span><span style=\"color: #89DDFF\">++<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">view<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">setUint8<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">offset<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">+<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">i<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">str<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">charCodeAt<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">i<\/span><span style=\"color: #F07178\">))<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #EEFFFF\">view<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">setUint8<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">offset<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">+<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">str<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">length<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\">\/**<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> * Encode raw RGB(A) + spot masks + ICC into a TIFF ArrayBuffer.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> *<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> * opts: {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> *   width: number,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> *   height: number,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> *   baseImage: ArrayBuffer|TypedArray,       \/\/ interleaved RGB or RGBA<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> *   colorOrder: &#39;RGB&#39;|&#39;RGBA&#39;,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> *   spotMasks?: {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> *     names: string[],                       \/\/ e.g. &#91;&#39;Gold&#39;&#93;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> *     buffers: ArrayBuffer[]                 \/\/ same length as names<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> *   },<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> *   iccProfile?: ArrayBuffer|Uint8Array,      \/\/ optional ICC profile<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> *   photoshop?: {                             \/\/ optional Photoshop tags<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> *     alphaChannelNames?: string[],<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> *     alphaChannelIdentifiers?: number[],<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> *     alternateSpotColors?: number[][],      \/\/ each &#91;C,M,Y,K&#93;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> *     displayInfo1?: ArrayBuffer|Uint8Array,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> *     displayInfo2?: ArrayBuffer|Uint8Array<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> *   },<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> *   xResolution?: number|&#91;number,number&#93;,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> *   yResolution?: number|&#91;number,number&#93;,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> *   resolutionUnit?: number<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> * }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> *<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> * Returns a little-endian TIFF file as an ArrayBuffer.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> *\/<\/span><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF; font-style: italic\">export<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #C792EA\">function<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #82AAFF\">encode<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #EEFFFF; font-style: italic\">opts<\/span><span style=\"color: #89DDFF\">)<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">width<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">height<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">baseImage<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">colorOrder<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">spotMasks<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">iccProfile<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">xResolution<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">yResolution<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">resolutionUnit<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">2<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">photoshop<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">{}<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF\">}<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">opts<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">&#91;<\/span><span style=\"color: #EEFFFF\">xResNum<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">xResDen<\/span><span style=\"color: #89DDFF\">&#93;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">Array<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">isArray<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">xResolution<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">?<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">xResolution<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #F07178\"> &#91;<\/span><span style=\"color: #EEFFFF\">xResolution<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #F07178\">&#93;<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">&#91;<\/span><span style=\"color: #EEFFFF\">yResNum<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">yResDen<\/span><span style=\"color: #89DDFF\">&#93;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">Array<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">isArray<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">yResolution<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">?<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">yResolution<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #F07178\"> &#91;<\/span><span style=\"color: #EEFFFF\">yResolution<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #F07178\">&#93;<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">hasAlpha<\/span><span style=\"color: #F07178\">  <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">colorOrder<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">===<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">RGBA<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">spotCount<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">spotMasks<\/span><span style=\"color: #89DDFF\">?.<\/span><span style=\"color: #EEFFFF\">buffers<\/span><span style=\"color: #89DDFF\">?.<\/span><span style=\"color: #EEFFFF\">length<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">||<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">channels<\/span><span style=\"color: #F07178\">  <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">3<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">+<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #EEFFFF\">hasAlpha<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">?<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">+<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">spotCount<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ Normalize pixel data to Uint8Array<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">buf<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">baseImage<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">instanceof<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #FFCB6B\">ArrayBuffer<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #89DDFF\">?<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">new<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">Uint8Array<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">baseImage<\/span><span style=\"color: #F07178\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">new<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">Uint8Array<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">baseImage<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">buffer<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">||<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">baseImage<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ Split into per-channel planes (R, G, B, &#91;A&#93;, &#91;spots...&#93;)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">planeSize<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">width<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">*<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">height<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">planes<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> []<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF; font-style: italic\">for<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #C792EA\">let<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">c<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #89DDFF\">;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">c<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">&lt;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">3<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">+<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #EEFFFF\">hasAlpha<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">?<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">c<\/span><span style=\"color: #89DDFF\">++<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">planes<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">push<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">new<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">Uint8Array<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">planeSize<\/span><span style=\"color: #F07178\">))<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #C792EA\">let<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">idx<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF; font-style: italic\">for<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #C792EA\">let<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">i<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #89DDFF\">;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">i<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">&lt;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">planeSize<\/span><span style=\"color: #89DDFF\">;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">i<\/span><span style=\"color: #89DDFF\">++<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">planes<\/span><span style=\"color: #F07178\">&#91;<\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #F07178\">&#93;&#91;<\/span><span style=\"color: #EEFFFF\">i<\/span><span style=\"color: #F07178\">&#93; <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">buf<\/span><span style=\"color: #F07178\">&#91;<\/span><span style=\"color: #EEFFFF\">idx<\/span><span style=\"color: #89DDFF\">++<\/span><span style=\"color: #F07178\">&#93;<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">planes<\/span><span style=\"color: #F07178\">&#91;<\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #F07178\">&#93;&#91;<\/span><span style=\"color: #EEFFFF\">i<\/span><span style=\"color: #F07178\">&#93; <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">buf<\/span><span style=\"color: #F07178\">&#91;<\/span><span style=\"color: #EEFFFF\">idx<\/span><span style=\"color: #89DDFF\">++<\/span><span style=\"color: #F07178\">&#93;<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">planes<\/span><span style=\"color: #F07178\">&#91;<\/span><span style=\"color: #F78C6C\">2<\/span><span style=\"color: #F07178\">&#93;&#91;<\/span><span style=\"color: #EEFFFF\">i<\/span><span style=\"color: #F07178\">&#93; <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">buf<\/span><span style=\"color: #F07178\">&#91;<\/span><span style=\"color: #EEFFFF\">idx<\/span><span style=\"color: #89DDFF\">++<\/span><span style=\"color: #F07178\">&#93;<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #89DDFF; font-style: italic\">if<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #EEFFFF\">hasAlpha<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #EEFFFF\">planes<\/span><span style=\"color: #F07178\">&#91;<\/span><span style=\"color: #F78C6C\">3<\/span><span style=\"color: #F07178\">&#93;&#91;<\/span><span style=\"color: #EEFFFF\">i<\/span><span style=\"color: #F07178\">&#93; <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">buf<\/span><span style=\"color: #F07178\">&#91;<\/span><span style=\"color: #EEFFFF\">idx<\/span><span style=\"color: #89DDFF\">++<\/span><span style=\"color: #F07178\">&#93;<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ Spot-mask planes (one buffer per spot name)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF; font-style: italic\">if<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #EEFFFF\">spotCount<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #89DDFF; font-style: italic\">for<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #C792EA\">let<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">s<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #89DDFF\">;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">s<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">&lt;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">spotCount<\/span><span style=\"color: #89DDFF\">;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">s<\/span><span style=\"color: #89DDFF\">++<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #EEFFFF\">planes<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">push<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">new<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">Uint8Array<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">spotMasks<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">buffers<\/span><span style=\"color: #F07178\">&#91;<\/span><span style=\"color: #EEFFFF\">s<\/span><span style=\"color: #F07178\">&#93;))<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ Interleave all planes into one big pixel buffer<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">pixelBuf<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">new<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">Uint8Array<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">planeSize<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">*<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">channels<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF; font-style: italic\">for<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #C792EA\">let<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">i<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #89DDFF\">;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">i<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">&lt;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">planeSize<\/span><span style=\"color: #89DDFF\">;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">i<\/span><span style=\"color: #89DDFF\">++<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #89DDFF; font-style: italic\">for<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #C792EA\">let<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">c<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #89DDFF\">;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">c<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">&lt;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">channels<\/span><span style=\"color: #89DDFF\">;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">c<\/span><span style=\"color: #89DDFF\">++<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #EEFFFF\">pixelBuf<\/span><span style=\"color: #F07178\">&#91;<\/span><span style=\"color: #EEFFFF\">i<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">*<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">channels<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">+<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">c<\/span><span style=\"color: #F07178\">&#93; <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">planes<\/span><span style=\"color: #F07178\">&#91;<\/span><span style=\"color: #EEFFFF\">c<\/span><span style=\"color: #F07178\">&#93;&#91;<\/span><span style=\"color: #EEFFFF\">i<\/span><span style=\"color: #F07178\">&#93;<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ Build IFD entries<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">entries<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> []<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #C792EA\">function<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">add<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #EEFFFF; font-style: italic\">tagName<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF; font-style: italic\">type<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF; font-style: italic\">count<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF; font-style: italic\">value<\/span><span style=\"color: #89DDFF\">)<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">entries<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">push<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">{<\/span><span style=\"color: #F07178\"> tag<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">Tags<\/span><span style=\"color: #F07178\">&#91;<\/span><span style=\"color: #EEFFFF\">tagName<\/span><span style=\"color: #F07178\">&#93;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">type<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">count<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">value<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">}<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ Core TIFF tags<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #82AAFF\">add<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">ImageWidth<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\">          <\/span><span style=\"color: #F78C6C\">4<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> &#91;<\/span><span style=\"color: #EEFFFF\">width<\/span><span style=\"color: #F07178\">&#93;)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #82AAFF\">add<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">ImageLength<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\">         <\/span><span style=\"color: #F78C6C\">4<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> &#91;<\/span><span style=\"color: #EEFFFF\">height<\/span><span style=\"color: #F07178\">&#93;)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #82AAFF\">add<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">BitsPerSample<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\">       <\/span><span style=\"color: #F78C6C\">3<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">channels<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">new<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">Array<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">channels<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">fill<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #F78C6C\">8<\/span><span style=\"color: #F07178\">))<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #82AAFF\">add<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">Compression<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\">         <\/span><span style=\"color: #F78C6C\">3<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> &#91;<\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #F07178\">&#93;)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #82AAFF\">add<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">SamplesPerPixel<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\">     <\/span><span style=\"color: #F78C6C\">3<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> &#91;<\/span><span style=\"color: #EEFFFF\">channels<\/span><span style=\"color: #F07178\">&#93;)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #82AAFF\">add<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">RowsPerStrip<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\">        <\/span><span style=\"color: #F78C6C\">4<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> &#91;<\/span><span style=\"color: #EEFFFF\">height<\/span><span style=\"color: #F07178\">&#93;)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #82AAFF\">add<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">StripByteCounts<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\">     <\/span><span style=\"color: #F78C6C\">4<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> &#91;<\/span><span style=\"color: #EEFFFF\">pixelBuf<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">byteLength<\/span><span style=\"color: #F07178\">&#93;)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #82AAFF\">add<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">XResolution<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\">         <\/span><span style=\"color: #F78C6C\">5<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> &#91;<\/span><span style=\"color: #EEFFFF\">xResNum<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">xResDen<\/span><span style=\"color: #F07178\">&#93;)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #82AAFF\">add<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">YResolution<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\">         <\/span><span style=\"color: #F78C6C\">5<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> &#91;<\/span><span style=\"color: #EEFFFF\">yResNum<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">yResDen<\/span><span style=\"color: #F07178\">&#93;)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #82AAFF\">add<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">ResolutionUnit<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\">      <\/span><span style=\"color: #F78C6C\">3<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> &#91;<\/span><span style=\"color: #EEFFFF\">resolutionUnit<\/span><span style=\"color: #F07178\">&#93;)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ Software tag now stores a plain string, not an array<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #82AAFF\">add<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">Software<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\">            <\/span><span style=\"color: #F78C6C\">2<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">TIFFWriter<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">length<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">+<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">TIFFWriter<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ Keep base as RGB<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #82AAFF\">add<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">PhotometricInterpretation<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">3<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> &#91;<\/span><span style=\"color: #F78C6C\">2<\/span><span style=\"color: #F07178\">&#93;)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #82AAFF\">add<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">PlanarConfiguration<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\">       <\/span><span style=\"color: #F78C6C\">3<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> &#91;<\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #F07178\">&#93;)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ ExtraSamples and SampleFormat<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF; font-style: italic\">if<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #EEFFFF\">hasAlpha<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">||<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">spotCount<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">extraVals<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> []<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #89DDFF; font-style: italic\">if<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #EEFFFF\">hasAlpha<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #EEFFFF\">extraVals<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">push<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">ExtraSample<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">UnassociatedAlpha<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #89DDFF; font-style: italic\">for<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #C792EA\">let<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">s<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #89DDFF\">;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">s<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">&lt;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">spotCount<\/span><span style=\"color: #89DDFF\">;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">s<\/span><span style=\"color: #89DDFF\">++<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #EEFFFF\">extraVals<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">push<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">ExtraSample<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">Unspecified<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #82AAFF\">add<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">ExtraSamples<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\">  <\/span><span style=\"color: #F78C6C\">3<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">extraVals<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">length<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">extraVals<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #82AAFF\">add<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">SampleFormat<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\">  <\/span><span style=\"color: #F78C6C\">3<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">channels<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">new<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">Array<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">channels<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">fill<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #F07178\">))<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ InkNames \u2013 one null-separated string for R,G,B,&#91;Alpha&#93;,&#91;spot\u2026&#93;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF; font-style: italic\">if<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #EEFFFF\">spotCount<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">&gt;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">names<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> []<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">names<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">push<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">R<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">G<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">B<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #89DDFF; font-style: italic\">if<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #EEFFFF\">hasAlpha<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">{<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">names<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">push<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">A<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #89DDFF; font-style: italic\">if<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #EEFFFF\">spotCount<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">{<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">names<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">push<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">...<\/span><span style=\"color: #EEFFFF\">spotMasks<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">names<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">inkNamesStr<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">names<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">join<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #EEFFFF\">\\0<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">+<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #EEFFFF\">\\0<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #82AAFF\">add<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">InkNames<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">2<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">inkNamesStr<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">length<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">inkNamesStr<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/<\/span><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ === Photoshop private tags ===<\/span><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/<\/span><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ AlphaChannelNames: null\u2010terminated names of each extra (spot) plane<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF; font-style: italic\">if<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #EEFFFF\">photoshop<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">alphaChannelNames<\/span><span style=\"color: #89DDFF\">?.<\/span><span style=\"color: #EEFFFF\">length<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">acn<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">photoshop<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">alphaChannelNames<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">join<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #EEFFFF\">\\0<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">+<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #EEFFFF\">\\0<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #82AAFF\">add<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">AlphaChannelNames<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">2<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">acn<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">length<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">acn<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ AlphaIdentifiers: unique short IDs for each extra plane<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF; font-style: italic\">if<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #EEFFFF\">photoshop<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">alphaChannelIdentifiers<\/span><span style=\"color: #89DDFF\">?.<\/span><span style=\"color: #EEFFFF\">length<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">===<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">spotCount<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #82AAFF\">add<\/span><span style=\"color: #F07178\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">AlphaIdentifiers<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #F78C6C\">3<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #EEFFFF\">photoshop<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">alphaChannelIdentifiers<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">length<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #EEFFFF\">photoshop<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">alphaChannelIdentifiers<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ AlternateSpotColors: fallback CMYK for each spot<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF; font-style: italic\">if<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #EEFFFF\">photoshop<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">alternateSpotColors<\/span><span style=\"color: #89DDFF\">?.<\/span><span style=\"color: #EEFFFF\">length<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">===<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">spotCount<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">flat<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">photoshop<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">alternateSpotColors<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">flat<\/span><span style=\"color: #F07178\">()<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #82AAFF\">add<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">AlternateSpotColors<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">3<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">flat<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">length<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">flat<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ DisplayInfo1 &amp; DisplayInfo2: opaque Photoshop \u201cblob\u201d hints<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF; font-style: italic\">if<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #EEFFFF\">photoshop<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">displayInfo1<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">blob<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">photoshop<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">displayInfo1<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">instanceof<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #FFCB6B\">Uint8Array<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #89DDFF\">?<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">photoshop<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">displayInfo1<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">new<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">Uint8Array<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">photoshop<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">displayInfo1<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #82AAFF\">add<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">DisplayInfo1<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">7<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">blob<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">length<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> &#91;<\/span><span style=\"color: #EEFFFF\">blob<\/span><span style=\"color: #F07178\">&#93;)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF; font-style: italic\">if<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #EEFFFF\">photoshop<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">displayInfo2<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">blob<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">photoshop<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">displayInfo2<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">instanceof<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #FFCB6B\">Uint8Array<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #89DDFF\">?<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">photoshop<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">displayInfo2<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">new<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">Uint8Array<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">photoshop<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">displayInfo2<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #82AAFF\">add<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">DisplayInfo2<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">7<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">blob<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">length<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> &#91;<\/span><span style=\"color: #EEFFFF\">blob<\/span><span style=\"color: #F07178\">&#93;)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/<\/span><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ === end Photoshop tags ===<\/span><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ Optional ICC profile<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF; font-style: italic\">if<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #EEFFFF\">iccProfile<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">icc<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">iccProfile<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">instanceof<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #FFCB6B\">ArrayBuffer<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #89DDFF\">?<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">new<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">Uint8Array<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">iccProfile<\/span><span style=\"color: #F07178\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">new<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">Uint8Array<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">iccProfile<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">buffer<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">||<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">iccProfile<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #82AAFF\">add<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">ICCProfile<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">7<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">icc<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">length<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> &#91;<\/span><span style=\"color: #EEFFFF\">icc<\/span><span style=\"color: #F07178\">&#93;)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ Placeholder for StripOffsets<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #82AAFF\">add<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">StripOffsets<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">4<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> &#91;<\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #F07178\">&#93;)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #EEFFFF\">entries<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">sort<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #EEFFFF; font-style: italic\">a<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF; font-style: italic\">b<\/span><span style=\"color: #89DDFF\">)<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #C792EA\">=&gt;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">a<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">tag<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">-<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">b<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">tag<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ Compute IFD size + overflow area<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">ifdStart<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">8<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">dirSize<\/span><span style=\"color: #F07178\">  <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">2<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">+<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">entries<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">length<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">*<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">12<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">+<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">4<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #C792EA\">let<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">dataOff<\/span><span style=\"color: #F07178\">    <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">ifdStart<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">+<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">dirSize<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">overflow<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> []<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF; font-style: italic\">for<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">e<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">of<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">entries<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">len<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">TypeSize<\/span><span style=\"color: #F07178\">&#91;<\/span><span style=\"color: #EEFFFF\">e<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">type<\/span><span style=\"color: #F07178\">&#93; <\/span><span style=\"color: #89DDFF\">*<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">e<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">count<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #89DDFF; font-style: italic\">if<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #EEFFFF\">len<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">&gt;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">4<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #EEFFFF\">e<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">offsetValue<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">dataOff<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #EEFFFF\">overflow<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">push<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">e<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #EEFFFF\">dataOff<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">+=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">len<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">+<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #EEFFFF\">len<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">&amp;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ Patch StripOffsets \u2192 pixel data<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">pixelOffset<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">dataOff<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">stripEnt<\/span><span style=\"color: #F07178\">    <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">entries<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">find<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF; font-style: italic\">e<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #C792EA\">=&gt;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">e<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">tag<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">===<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">Tags<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">StripOffsets<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #EEFFFF\">stripEnt<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">value<\/span><span style=\"color: #F07178\">       <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> &#91;<\/span><span style=\"color: #EEFFFF\">pixelOffset<\/span><span style=\"color: #F07178\">&#93;<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #EEFFFF\">stripEnt<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">offsetValue<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">pixelOffset<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #EEFFFF\">dataOff<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">+=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">pixelBuf<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">byteLength<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ Allocate output buffer + DataView<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">buffer<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">new<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">ArrayBuffer<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">dataOff<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">view<\/span><span style=\"color: #F07178\">   <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">new<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">DataView<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">buffer<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ Write TIFF header<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #EEFFFF\">view<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">setUint8<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0x49<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #EEFFFF\">view<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">setUint8<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0x49<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #EEFFFF\">view<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">setUint16<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #F78C6C\">2<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">42<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">LE<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #EEFFFF\">view<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">setUint32<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #F78C6C\">4<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">ifdStart<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">LE<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ Write IFD entries<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #C792EA\">let<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">p<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">ifdStart<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #EEFFFF\">view<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">setUint16<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">p<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">entries<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">length<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">LE<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #EEFFFF\">p<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">+=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">2<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF; font-style: italic\">for<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">e<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">of<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">entries<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">view<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">setUint16<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">p<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">e<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">tag<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">LE<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><span style=\"color: #F07178\">   <\/span><span style=\"color: #EEFFFF\">p<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">+=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">2<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">view<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">setUint16<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">p<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">e<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">type<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">LE<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><span style=\"color: #F07178\">  <\/span><span style=\"color: #EEFFFF\">p<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">+=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">2<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">view<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">setUint32<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">p<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">e<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">count<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">LE<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">p<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">+=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">4<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">len<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">TypeSize<\/span><span style=\"color: #F07178\">&#91;<\/span><span style=\"color: #EEFFFF\">e<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">type<\/span><span style=\"color: #F07178\">&#93; <\/span><span style=\"color: #89DDFF\">*<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">e<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">count<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #89DDFF; font-style: italic\">if<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #EEFFFF\">len<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">&gt;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">4<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #EEFFFF\">view<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">setUint32<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">p<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">e<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">offsetValue<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">LE<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #89DDFF\">}<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF; font-style: italic\">else<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #89DDFF; font-style: italic\">if<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #EEFFFF\">e<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">type<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">===<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">3<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t\t<\/span><span style=\"color: #89DDFF; font-style: italic\">for<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #C792EA\">let<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">i<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #89DDFF\">;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">i<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">&lt;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">e<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">count<\/span><span style=\"color: #89DDFF\">;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">i<\/span><span style=\"color: #89DDFF\">++<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t\t\t<\/span><span style=\"color: #EEFFFF\">view<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">setUint16<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">p<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">+<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">2<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">*<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">i<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">e<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">value<\/span><span style=\"color: #F07178\">&#91;<\/span><span style=\"color: #EEFFFF\">i<\/span><span style=\"color: #F07178\">&#93;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">LE<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t\t<\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #89DDFF; font-style: italic\">if<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #EEFFFF\">e<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">type<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">===<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">4<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t\t<\/span><span style=\"color: #EEFFFF\">view<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">setUint32<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">p<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">e<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">value<\/span><span style=\"color: #F07178\">&#91;<\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #F07178\">&#93;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">LE<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">p<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">+=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">4<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ next IFD pointer = 0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #EEFFFF\">view<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">setUint32<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">p<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">LE<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ Write overflow blocks (InkNames, Software, ICC, ExtraSamples arrays, etc.)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF; font-style: italic\">for<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">e<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">of<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">overflow<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">off<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">e<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">offsetValue<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #89DDFF; font-style: italic\">switch<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #EEFFFF\">e<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">type<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #89DDFF; font-style: italic\">case<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">2<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ ASCII<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">str<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">Array<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">isArray<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">e<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">value<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">?<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">e<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">value<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">join<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">&#39;&#39;<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">e<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">value<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t\t<\/span><span style=\"color: #82AAFF\">writeASCII<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">view<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">off<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">str<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t\t<\/span><span style=\"color: #89DDFF; font-style: italic\">break<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #89DDFF; font-style: italic\">case<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">3<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ SHORT<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t\t<\/span><span style=\"color: #89DDFF; font-style: italic\">for<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #C792EA\">let<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">i<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #89DDFF\">;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">i<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">&lt;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">e<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">count<\/span><span style=\"color: #89DDFF\">;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">i<\/span><span style=\"color: #89DDFF\">++<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t\t\t<\/span><span style=\"color: #EEFFFF\">view<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">setUint16<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">off<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">+<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">2<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">*<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">i<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">e<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">value<\/span><span style=\"color: #F07178\">&#91;<\/span><span style=\"color: #EEFFFF\">i<\/span><span style=\"color: #F07178\">&#93;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">LE<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t\t<\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t\t<\/span><span style=\"color: #89DDFF; font-style: italic\">break<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #89DDFF; font-style: italic\">case<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">5<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ RATIONAL<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t\t<\/span><span style=\"color: #89DDFF; font-style: italic\">for<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #C792EA\">let<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">i<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #89DDFF\">;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">i<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">&lt;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">e<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">count<\/span><span style=\"color: #89DDFF\">;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">i<\/span><span style=\"color: #89DDFF\">++<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t\t\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">num<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">e<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">value<\/span><span style=\"color: #F07178\">&#91;<\/span><span style=\"color: #F78C6C\">2<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">*<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">i<\/span><span style=\"color: #F07178\">&#93;<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t\t\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">den<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">e<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">value<\/span><span style=\"color: #F07178\">&#91;<\/span><span style=\"color: #F78C6C\">2<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">*<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">i<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">+<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #F07178\">&#93;<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t\t\t<\/span><span style=\"color: #EEFFFF\">view<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">setUint32<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">off<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">+<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">8<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">*<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">i<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\">     <\/span><span style=\"color: #EEFFFF\">num<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">LE<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t\t\t<\/span><span style=\"color: #EEFFFF\">view<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">setUint32<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">off<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">+<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">8<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">*<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">i<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">+<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">4<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">den<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">LE<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t\t<\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t\t<\/span><span style=\"color: #89DDFF; font-style: italic\">break<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #89DDFF; font-style: italic\">case<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">7<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ UNDEFINED (ICC profile or Photoshop blobs)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t\t<\/span><span style=\"color: #89DDFF\">new<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">Uint8Array<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">buffer<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">off<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">e<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">value<\/span><span style=\"color: #F07178\">&#91;<\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #F07178\">&#93;<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">length<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">set<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">e<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">value<\/span><span style=\"color: #F07178\">&#91;<\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #F07178\">&#93;)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t\t<\/span><span style=\"color: #89DDFF; font-style: italic\">break<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ Write pixel data into the file<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF\">new<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">Uint8Array<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">buffer<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">pixelOffset<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">pixelBuf<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">byteLength<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">set<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">pixelBuf<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF; font-style: italic\">return<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">buffer<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><\/span><\/code><\/pre><\/div>\n<\/div><\/div>\n\n<div class=\"wp-block-grapham-mapping grapham-mapping-block\" data-cell-id=\"TKpOnsKza9iosXShlxyd-32\" data-cell-label=\"Spot Registry\"><div class=\"grapham-mapping-header\"><span class=\"grapham-mapping-label\">Spot Registry<\/span><span class=\"grapham-mapping-cellid\">TKpOnsKza9iosXShlxyd-32<\/span><\/div><div class=\"grapham-mapping-content\">\n<p>Spot Registry (outside of the scope of this demo) is the internal tool for managing the links between the front-end editor&#8217;s foils, spots and other effects layers and the final output your pipeline expects in the file format you need (whether tiff or pdf), seamlessly packaging the job.<\/p>\n<\/div><\/div>\n\n<div class=\"wp-block-grapham-mapping grapham-mapping-block\" data-cell-id=\"TKpOnsKza9iosXShlxyd-2\" data-cell-label=\"WebGL2 Canvas\"><div class=\"grapham-mapping-header\"><span class=\"grapham-mapping-label\">WebGL2 Canvas<\/span><span class=\"grapham-mapping-cellid\">TKpOnsKza9iosXShlxyd-2<\/span><\/div><div class=\"grapham-mapping-content\">\n<p>Our canvas is distinct from the fabric.js implementation for performance and stray effect iso<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#EEFFFF;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 0 16px;font-size:0.8em;width:100%;text-align:left;background-color:#263238;font-style:italic;color:#EEFFFF\"><span style=\"border-bottom:1px solid rgba(238, 255, 255, 0.2)\">HTML<\/span><\/span><span role=\"button\" tabindex=\"0\" style=\"color:#EEFFFF;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>\t\t\t&lt;canvas id=\"canvas\" class=\"fabric-canvas\" width=\"528\" height=\"672\">&lt;\/canvas>\n\t\t\t&lt;canvas id=\"gl-canvas\" class=\"gl-canvas\" data-alpha=\"true\" width=\"528\" height=\"672\">&lt;\/canvas><\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki material-theme\" style=\"background-color: #263238\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #EEFFFF\">\t\t\t<\/span><span style=\"color: #89DDFF\">&lt;<\/span><span style=\"color: #F07178\">canvas<\/span><span style=\"color: #89DDFF\"> <\/span><span style=\"color: #C792EA\">id<\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #C3E88D\">canvas<\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #89DDFF\"> <\/span><span style=\"color: #C792EA\">class<\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #C3E88D\">fabric-canvas<\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #89DDFF\"> <\/span><span style=\"color: #C792EA\">width<\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #C3E88D\">528<\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #89DDFF\"> <\/span><span style=\"color: #C792EA\">height<\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #C3E88D\">672<\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #89DDFF\">&gt;&lt;\/<\/span><span style=\"color: #F07178\">canvas<\/span><span style=\"color: #89DDFF\">&gt;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">\t\t\t<\/span><span style=\"color: #89DDFF\">&lt;<\/span><span style=\"color: #F07178\">canvas<\/span><span style=\"color: #89DDFF\"> <\/span><span style=\"color: #C792EA\">id<\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #C3E88D\">gl-canvas<\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #89DDFF\"> <\/span><span style=\"color: #C792EA\">class<\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #C3E88D\">gl-canvas<\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #89DDFF\"> <\/span><span style=\"color: #C792EA\">data-alpha<\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #C3E88D\">true<\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #89DDFF\"> <\/span><span style=\"color: #C792EA\">width<\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #C3E88D\">528<\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #89DDFF\"> <\/span><span style=\"color: #C792EA\">height<\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #C3E88D\">672<\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #89DDFF\">&gt;&lt;\/<\/span><span style=\"color: #F07178\">canvas<\/span><span style=\"color: #89DDFF\">&gt;<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>Builder.initWebGLLayer is responsible for setup and management of the GL Layer. <\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#EEFFFF;--cbp-line-number-width:calc(3 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 0 16px;font-size:0.8em;width:100%;text-align:left;background-color:#263238;font-style:italic;color:#EEFFFF\"><span style=\"border-bottom:1px solid rgba(238, 255, 255, 0.2)\">JavaScript<\/span><\/span><span role=\"button\" tabindex=\"0\" style=\"color:#EEFFFF;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>\/**\n * Initialize a WebGL2 layer over a Fabric.js canvas.\n * Compiles &amp; links the multi_foil shader, allocates one base\n * texture (u_image) and four mask textures, and binds samplers\n * to texture units 0\u20134.\n *\n * Foil channels (via FOIL_CHANNELS):\n *   gold_foil   \u2192 u_maskGold  @ unit 1\n *   silver_foil \u2192 u_maskSilver@ unit 2\n *   holo_foil   \u2192 u_maskHolo  @ unit 3\n *   uv_spot     \u2192 u_maskUV    @ unit 4\n *\n * @param {HTMLCanvasElement} glCanvasEl\n *        The WebGL &lt;canvas> element.\n * @param {HTMLCanvasElement} fabricCanvasEl\n *        The Fabric.js &lt;canvas> element.\n * @returns {object}\n *        The layer object, stored in Builder.layers by glCanvasEl.id.\n *\/\nBuilder.initWebGLLayer = function(glCanvasEl, fabricCanvasEl) {\n\t\/\/ validate\n\tif (!(glCanvasEl instanceof HTMLCanvasElement) || !(fabricCanvasEl instanceof HTMLCanvasElement)) {\n\t\tconsole.error('initWebGLLayer: both args must be &lt;canvas>');\n\t\treturn;\n\t}\n\n\t\/\/ create WebGL2 context\n\tconst wantAlpha = glCanvasEl.dataset.alpha === 'true';\n\tconst gl = glCanvasEl.getContext('webgl2', {\n\t\talpha: wantAlpha,\n\t\tpreserveDrawingBuffer: true,\n\t\tpremultipliedAlpha: false\n\t});\n\tif (!gl) { console.warn('initWebGLLayer: WebGL2 not supported'); return; }\n\tgl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);\n\tgl.clearColor(0, 0, 0, 0);\n\tgl.enable(gl.BLEND);\n\tgl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);\n\n\t\/\/ pick shader\n\tconst requestedType = glCanvasEl.dataset.shaderType || 'multi_foil';\t\t\t\t\t\t\/\/this is not how we should be initializing the requested shader types.\n\tconst program       = getLayerShaderProgram(gl, requestedType);\n\tif (!program) { console.error('initWebGLLayer: failed to get shader program'); return; }\n\tgl.useProgram(program);\n\n\t\/\/ attributes\n\tconst attribs = {\n\t\ta_position: gl.getAttribLocation(program, 'a_position'),\n\t\ta_uv:       gl.getAttribLocation(program, 'a_uv')\n\t};\n\n\t\/\/ uniforms\n\tconst uniformNames = &#91;\n\t\t'u_image', 'u_maskGold','u_maskSilver','u_maskHolo','u_maskUV',\n\t\t'u_time','u_texelSize',\n\t\t'u_wrinkleScale','u_wrinkleStrength','u_wrinkleSpeed',\n\t\t'u_sparkleIntensity','u_sparkleFreq','u_sparkleSpeed',\n\t\t'u_foilIntensity','u_foilSpecularity',\n\t\t'u_holoShimmerIntensity','u_holoShimmerSpeed',\n\t\t'u_uvSpotStrength','u_uvSpotColor'\n\t&#93;;\n\tconst uniforms = {};\n\tuniformNames.forEach(name => {\n\t\tuniforms&#91;name&#93; = gl.getUniformLocation(program, name);\n\t});\n\n\t\/\/ full-screen quad VBO\n\tconst quadVerts = new Float32Array(&#91;\n\t\t-1,-1, 0,0,   1,-1, 1,0,   -1,1, 0,1,\n\t\t1,1, 1,1,  -1,1, 0,1,    1,-1, 1,0\n\t&#93;);\n\tconst vbo = gl.createBuffer();\n\tgl.bindBuffer(gl.ARRAY_BUFFER, vbo);\n\tgl.bufferData(gl.ARRAY_BUFFER, quadVerts, gl.STATIC_DRAW);\n\tconst FSIZE = Float32Array.BYTES_PER_ELEMENT * 4;\n\tgl.enableVertexAttribArray(attribs.a_position);\n\tgl.vertexAttribPointer(attribs.a_position, 2, gl.FLOAT, false, FSIZE, 0);\n\tgl.enableVertexAttribArray(attribs.a_uv);\n\tgl.vertexAttribPointer(attribs.a_uv,       2, gl.FLOAT, false, FSIZE, 2 * Float32Array.BYTES_PER_ELEMENT);\n\n\t\/\/ helper: create &amp; configure RGBA texture\n\tfunction makeTex() {\n\t\tconst t = gl.createTexture();\n\t\tgl.bindTexture(gl.TEXTURE_2D, t);\n\t\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);\n\t\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);\n\t\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S,     gl.CLAMP_TO_EDGE);\n\t\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T,     gl.CLAMP_TO_EDGE);\n\t\treturn t;\n\t}\n\n\t\/\/ create textures\n\tconst texBase  = makeTex();\n\tconst texMasks = {};\n\tObject.values(FOIL_CHANNELS).forEach(({ uni }) => {\n\t\ttexMasks&#91;uni&#93; = makeTex();\n\t});\n\n\t\/\/ bind samplers&amp; units &amp; allocate empty masks\n\tgl.useProgram(program);\n\tgl.uniform1i(uniforms.u_image, 0);\n\tObject.entries(FOIL_CHANNELS).forEach((&#91;type, { uni, unit }&#93;) => {\n\t\tgl.uniform1i(uniforms&#91;uni&#93;, unit);\n\t\tgl.activeTexture(gl.TEXTURE0 + unit);\n\t\tgl.bindTexture(gl.TEXTURE_2D, texMasks&#91;uni&#93;);\n\t\tgl.texImage2D(\n\t\t\tgl.TEXTURE_2D, 0, gl.RGBA,\n\t\t\tfabricCanvasEl.width, fabricCanvasEl.height,\n\t\t\t0, gl.RGBA, gl.UNSIGNED_BYTE, null\n\t\t);\n\t});\n\n\t\/\/ set static shaderConfig uniforms\n\tObject.entries(Builder.shaderConfig).forEach((&#91;key, val&#93;) => {\n\t\tconst loc = uniforms&#91;key&#93;;\n\t\tif (!loc) return;\n\t\tif (typeof val === 'number')      gl.uniform1f(loc, val);\n\t\telse if (Array.isArray(val) &amp;&amp; val.length === 3) gl.uniform3fv(loc, val);\n\t});\n\n\t\/\/ assemble layer\n\tconst layer = {\n\t\tglCanvas:      glCanvasEl,\n\t\tfabricCanvas:  fabricCanvasEl,\n\t\tgl, program, attribs, uniforms, vbo,\n\t\ttextures:      { u_image: texBase, ...texMasks },\n\t\tshaderType:    requestedType,\n\t\tfoilChannels:  FOIL_CHANNELS,\n\t\tlastW:         -1,\n\t\tlastH:         -1,\n\t\tstartTime:     performance.now()\n\t};\n\n\tBuilder.layers&#91;glCanvasEl.id&#93; = layer;\n\treturn layer;\n};\n\n<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki material-theme\" style=\"background-color: #263238\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #546E7A; font-style: italic\">\/**<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> * Initialize a WebGL2 layer over a Fabric.js canvas.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> * Compiles &amp; links the multi_foil shader, allocates one base<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> * texture (u_image) and four mask textures, and binds samplers<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> * to texture units 0\u20134.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> *<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> * Foil channels (via FOIL_CHANNELS):<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> *   gold_foil   \u2192 u_maskGold  @ unit 1<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> *   silver_foil \u2192 u_maskSilver@ unit 2<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> *   holo_foil   \u2192 u_maskHolo  @ unit 3<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> *   uv_spot     \u2192 u_maskUV    @ unit 4<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> *<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> * <\/span><span style=\"color: #89DDFF; font-style: italic\">@<\/span><span style=\"color: #C792EA; font-style: italic\">param<\/span><span style=\"color: #546E7A; font-style: italic\"> <\/span><span style=\"color: #89DDFF; font-style: italic\">{<\/span><span style=\"color: #FFCB6B; font-style: italic\">HTMLCanvasElement<\/span><span style=\"color: #89DDFF; font-style: italic\">}<\/span><span style=\"color: #546E7A; font-style: italic\"> <\/span><span style=\"color: #EEFFFF; font-style: italic\">glCanvasEl<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> *        The WebGL &lt;canvas&gt; element.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> * <\/span><span style=\"color: #89DDFF; font-style: italic\">@<\/span><span style=\"color: #C792EA; font-style: italic\">param<\/span><span style=\"color: #546E7A; font-style: italic\"> <\/span><span style=\"color: #89DDFF; font-style: italic\">{<\/span><span style=\"color: #FFCB6B; font-style: italic\">HTMLCanvasElement<\/span><span style=\"color: #89DDFF; font-style: italic\">}<\/span><span style=\"color: #546E7A; font-style: italic\"> <\/span><span style=\"color: #EEFFFF; font-style: italic\">fabricCanvasEl<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> *        The Fabric.js &lt;canvas&gt; element.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> * <\/span><span style=\"color: #89DDFF; font-style: italic\">@<\/span><span style=\"color: #C792EA; font-style: italic\">returns<\/span><span style=\"color: #546E7A; font-style: italic\"> <\/span><span style=\"color: #89DDFF; font-style: italic\">{<\/span><span style=\"color: #FFCB6B; font-style: italic\">object<\/span><span style=\"color: #89DDFF; font-style: italic\">}<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> *        The layer object, stored in Builder.layers by glCanvasEl.id.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\"> *\/<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">Builder<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">initWebGLLayer<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #C792EA\">function<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #EEFFFF; font-style: italic\">glCanvasEl<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #EEFFFF; font-style: italic\">fabricCanvasEl<\/span><span style=\"color: #89DDFF\">)<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ validate<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF; font-style: italic\">if<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #89DDFF\">!<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">glCanvasEl<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">instanceof<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #FFCB6B\">HTMLCanvasElement<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">||<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">!<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">fabricCanvasEl<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">instanceof<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #FFCB6B\">HTMLCanvasElement<\/span><span style=\"color: #F07178\">)) <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">console<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">error<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">initWebGLLayer: both args must be &lt;canvas&gt;<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #89DDFF; font-style: italic\">return<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ create WebGL2 context<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">wantAlpha<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">glCanvasEl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">dataset<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">alpha<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">===<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">true<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">glCanvasEl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">getContext<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">webgl2<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\talpha<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">wantAlpha<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\tpreserveDrawingBuffer<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #FF9CAC\">true<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\tpremultipliedAlpha<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #FF9CAC\">false<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF\">}<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF; font-style: italic\">if<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #89DDFF\">!<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">{<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">console<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">warn<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">initWebGLLayer: WebGL2 not supported<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF; font-style: italic\">return<\/span><span style=\"color: #89DDFF\">;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">pixelStorei<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">UNPACK_FLIP_Y_WEBGL<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #FF9CAC\">true<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">clearColor<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">enable<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">BLEND<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">blendFunc<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">SRC_ALPHA<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">ONE_MINUS_SRC_ALPHA<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ pick shader<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">requestedType<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">glCanvasEl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">dataset<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">shaderType<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">||<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">multi_foil<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">;<\/span><span style=\"color: #F07178\">\t\t\t\t\t\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/this is not how we should be initializing the requested shader types.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">program<\/span><span style=\"color: #F07178\">       <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">getLayerShaderProgram<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">requestedType<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF; font-style: italic\">if<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #89DDFF\">!<\/span><span style=\"color: #EEFFFF\">program<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">{<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">console<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">error<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">initWebGLLayer: failed to get shader program<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF; font-style: italic\">return<\/span><span style=\"color: #89DDFF\">;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">useProgram<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">program<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ attributes<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">attribs<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\ta_position<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">getAttribLocation<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">program<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">a_position<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\ta_uv<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #F07178\">       <\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">getAttribLocation<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">program<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">a_uv<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #F07178\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF\">};<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ uniforms<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">uniformNames<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> &#91;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">u_image<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">u_maskGold<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">u_maskSilver<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">u_maskHolo<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">u_maskUV<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">u_time<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">u_texelSize<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">u_wrinkleScale<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">u_wrinkleStrength<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">u_wrinkleSpeed<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">u_sparkleIntensity<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">u_sparkleFreq<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">u_sparkleSpeed<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">u_foilIntensity<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">u_foilSpecularity<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">u_holoShimmerIntensity<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">u_holoShimmerSpeed<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">u_uvSpotStrength<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">u_uvSpotColor<\/span><span style=\"color: #89DDFF\">&#39;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t&#93;<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">uniforms<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">{};<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #EEFFFF\">uniformNames<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">forEach<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF; font-style: italic\">name<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #C792EA\">=&gt;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">uniforms<\/span><span style=\"color: #F07178\">&#91;<\/span><span style=\"color: #EEFFFF\">name<\/span><span style=\"color: #F07178\">&#93; <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">getUniformLocation<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">program<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">name<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF\">}<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ full-screen quad VBO<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">quadVerts<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">new<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">Float32Array<\/span><span style=\"color: #F07178\">(&#91;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #89DDFF\">-<\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #89DDFF\">,-<\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\">   <\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #89DDFF\">,-<\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\">   <\/span><span style=\"color: #89DDFF\">-<\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\">  <\/span><span style=\"color: #89DDFF\">-<\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\">    <\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #89DDFF\">,-<\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F78C6C\">0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t&#93;)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">vbo<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">createBuffer<\/span><span style=\"color: #F07178\">()<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">bindBuffer<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">ARRAY_BUFFER<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">vbo<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">bufferData<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">ARRAY_BUFFER<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">quadVerts<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">STATIC_DRAW<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">FSIZE<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">Float32Array<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">BYTES_PER_ELEMENT<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">*<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">4<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">enableVertexAttribArray<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">attribs<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">a_position<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">vertexAttribPointer<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">attribs<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">a_position<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">2<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">FLOAT<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #FF9CAC\">false<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">FSIZE<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">enableVertexAttribArray<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">attribs<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">a_uv<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">vertexAttribPointer<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">attribs<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">a_uv<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\">       <\/span><span style=\"color: #F78C6C\">2<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">FLOAT<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #FF9CAC\">false<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">FSIZE<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">2<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">*<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">Float32Array<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">BYTES_PER_ELEMENT<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ helper: create &amp; configure RGBA texture<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #C792EA\">function<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">makeTex<\/span><span style=\"color: #89DDFF\">()<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">t<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">createTexture<\/span><span style=\"color: #F07178\">()<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">bindTexture<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">TEXTURE_2D<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">t<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">texParameteri<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">TEXTURE_2D<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">TEXTURE_MIN_FILTER<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">LINEAR<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">texParameteri<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">TEXTURE_2D<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">TEXTURE_MAG_FILTER<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">LINEAR<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">texParameteri<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">TEXTURE_2D<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">TEXTURE_WRAP_S<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\">     <\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">CLAMP_TO_EDGE<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">texParameteri<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">TEXTURE_2D<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">TEXTURE_WRAP_T<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\">     <\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">CLAMP_TO_EDGE<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #89DDFF; font-style: italic\">return<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">t<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ create textures<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">texBase<\/span><span style=\"color: #F07178\">  <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">makeTex<\/span><span style=\"color: #F07178\">()<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">texMasks<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">{};<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #EEFFFF\">Object<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">values<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">FOIL_CHANNELS<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">forEach<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">({<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF; font-style: italic\">uni<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">})<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #C792EA\">=&gt;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">texMasks<\/span><span style=\"color: #F07178\">&#91;<\/span><span style=\"color: #EEFFFF\">uni<\/span><span style=\"color: #F07178\">&#93; <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">makeTex<\/span><span style=\"color: #F07178\">()<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF\">}<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ bind samplers&amp; units &amp; allocate empty masks<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">useProgram<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">program<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">uniform1i<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">uniforms<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">u_image<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #EEFFFF\">Object<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">entries<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">FOIL_CHANNELS<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">forEach<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">(&#91;<\/span><span style=\"color: #EEFFFF; font-style: italic\">type<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">{<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF; font-style: italic\">uni<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF; font-style: italic\">unit<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">}&#93;)<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #C792EA\">=&gt;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">uniform1i<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">uniforms<\/span><span style=\"color: #F07178\">&#91;<\/span><span style=\"color: #EEFFFF\">uni<\/span><span style=\"color: #F07178\">&#93;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">unit<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">activeTexture<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">TEXTURE0<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">+<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">unit<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">bindTexture<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">TEXTURE_2D<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">texMasks<\/span><span style=\"color: #F07178\">&#91;<\/span><span style=\"color: #EEFFFF\">uni<\/span><span style=\"color: #F07178\">&#93;)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">texImage2D<\/span><span style=\"color: #F07178\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">TEXTURE_2D<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">RGBA<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #EEFFFF\">fabricCanvasEl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">width<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">fabricCanvasEl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">height<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">RGBA<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">UNSIGNED_BYTE<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">null<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF\">}<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ set static shaderConfig uniforms<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #EEFFFF\">Object<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">entries<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">Builder<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">shaderConfig<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">forEach<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">(&#91;<\/span><span style=\"color: #EEFFFF; font-style: italic\">key<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF; font-style: italic\">val<\/span><span style=\"color: #89DDFF\">&#93;)<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #C792EA\">=&gt;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">loc<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">uniforms<\/span><span style=\"color: #F07178\">&#91;<\/span><span style=\"color: #EEFFFF\">key<\/span><span style=\"color: #F07178\">&#93;<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #89DDFF; font-style: italic\">if<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #89DDFF\">!<\/span><span style=\"color: #EEFFFF\">loc<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF; font-style: italic\">return<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #89DDFF; font-style: italic\">if<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #89DDFF\">typeof<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">val<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">===<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">number<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #F07178\">)      <\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">uniform1f<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">loc<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">val<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #89DDFF; font-style: italic\">else<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF; font-style: italic\">if<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #EEFFFF\">Array<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">isArray<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">val<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">&amp;&amp;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">val<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">length<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">===<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">3<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">uniform3fv<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">loc<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">val<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF\">}<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ assemble layer<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">layer<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\tglCanvas<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #F07178\">      <\/span><span style=\"color: #EEFFFF\">glCanvasEl<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\tfabricCanvas<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #F07178\">  <\/span><span style=\"color: #EEFFFF\">fabricCanvasEl<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">program<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">attribs<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">uniforms<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">vbo<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\ttextures<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #F07178\">      <\/span><span style=\"color: #89DDFF\">{<\/span><span style=\"color: #F07178\"> u_image<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">texBase<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">...<\/span><span style=\"color: #EEFFFF\">texMasks<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">},<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\tshaderType<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #F07178\">    <\/span><span style=\"color: #EEFFFF\">requestedType<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\tfoilChannels<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #F07178\">  <\/span><span style=\"color: #EEFFFF\">FOIL_CHANNELS<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\tlastW<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #F07178\">         <\/span><span style=\"color: #89DDFF\">-<\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\tlastH<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #F07178\">         <\/span><span style=\"color: #89DDFF\">-<\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\tstartTime<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #F07178\">     <\/span><span style=\"color: #EEFFFF\">performance<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">now<\/span><span style=\"color: #F07178\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF\">};<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #EEFFFF\">Builder<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">layers<\/span><span style=\"color: #F07178\">&#91;<\/span><span style=\"color: #EEFFFF\">glCanvasEl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">id<\/span><span style=\"color: #F07178\">&#93; <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">layer<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF; font-style: italic\">return<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">layer<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">};<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><\/span><\/code><\/pre><\/div>\n<\/div><\/div>\n\n<div class=\"wp-block-grapham-mapping grapham-mapping-block\" data-cell-id=\"TKpOnsKza9iosXShlxyd-1\" data-cell-label=\"fabric.js lowerCanvas\"><div class=\"grapham-mapping-header\"><span class=\"grapham-mapping-label\">fabric.js lowerCanvas<\/span><span class=\"grapham-mapping-cellid\">TKpOnsKza9iosXShlxyd-1<\/span><\/div><div class=\"grapham-mapping-content\">\n<p>The lowerCanvas is where our real SVG assets are pulled from. Our layer has to pay specific attention to lowerCanvas to drive change and bitmasks. We don&#8217;t want a fabric.js UI element from upperCanvas to trigger a texture reload or a mask movement, or worse, end up in the effects pipeline or the print export!<\/p>\n<\/div><\/div>\n\n<div class=\"wp-block-grapham-mapping grapham-mapping-block\" data-cell-id=\"TKpOnsKza9iosXShlxyd-19\" data-cell-label=\"fabric.js UI upperCanvas\"><div class=\"grapham-mapping-header\"><span class=\"grapham-mapping-label\">fabric.js UI upperCanvas<\/span><span class=\"grapham-mapping-cellid\">TKpOnsKza9iosXShlxyd-19<\/span><\/div><div class=\"grapham-mapping-content\">\n<p>While the outside interface is built outside of fabric.js (the text tool and letter kerning and foil selectors), leveraging the built-in handles is one of the big reasons to use fabric.js. Here, the editting of content should feel familiar and easy.<\/p>\n<\/div><\/div>\n\n<div class=\"wp-block-grapham-mapping grapham-mapping-block\" data-cell-id=\"TKpOnsKza9iosXShlxyd-25\" data-cell-label=\"Spots &amp; Masks\"><div class=\"grapham-mapping-header\"><span class=\"grapham-mapping-label\">Spots &amp; Masks<\/span><span class=\"grapham-mapping-cellid\">TKpOnsKza9iosXShlxyd-25<\/span><\/div><div class=\"grapham-mapping-content\">\n<p>Tiff (as a file format) stores extra samples at ExtraSamples (Tag 338). This is one of the areas we could choose to add our foil and spot effects in a tiff-only export.<\/p>\n<\/div><\/div>\n\n<div class=\"wp-block-grapham-mapping grapham-mapping-block\" data-cell-id=\"TKpOnsKza9iosXShlxyd-47\" data-cell-label=\"ICC\"><div class=\"grapham-mapping-header\"><span class=\"grapham-mapping-label\">ICC<\/span><span class=\"grapham-mapping-cellid\">TKpOnsKza9iosXShlxyd-47<\/span><\/div><div class=\"grapham-mapping-content\">\n<p>We can embed an ICC profile at ICC (Tag 34675).<\/p>\n<\/div><\/div>\n\n<div class=\"wp-block-grapham-mapping grapham-mapping-block\" data-cell-id=\"TKpOnsKza9iosXShlxyd-22\" data-cell-label=\"RGB\"><div class=\"grapham-mapping-header\"><span class=\"grapham-mapping-label\">RGB<\/span><span class=\"grapham-mapping-cellid\">TKpOnsKza9iosXShlxyd-22<\/span><\/div><div class=\"grapham-mapping-content\">\n<p>We&#8217;ve chosen to export in a photometric interpretation (e.g, RGB) in this demo. The type (RGB vs CMYK) is controlled at Tag 262. Other options include CMYK, YCbCr, CIELab, LogLuv, LogL, CFA.<\/p>\n<\/div><\/div>\n\n<div class=\"wp-block-grapham-mapping grapham-mapping-block\" data-cell-id=\"TKpOnsKza9iosXShlxyd-16\" data-cell-label=\"invisible mask objects\"><div class=\"grapham-mapping-header\"><span class=\"grapham-mapping-label\">invisible mask objects<\/span><span class=\"grapham-mapping-cellid\">TKpOnsKza9iosXShlxyd-16<\/span><\/div><div class=\"grapham-mapping-content\">\n<p>All mask texture updates are driven on the after:render flag by fabric.js and only update if there is a change. <\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#EEFFFF;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 0 16px;font-size:0.8em;width:100%;text-align:left;background-color:#263238;font-style:italic;color:#EEFFFF\"><span style=\"border-bottom:1px solid rgba(238, 255, 255, 0.2)\">JavaScript<\/span><\/span><span role=\"button\" tabindex=\"0\" style=\"color:#EEFFFF;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>fCanvas.on('after:render', () => {\n\n\t\t\tif (vsx.maskDirtyFlags) { vsx.updateMaskCanvases(); } \t\/\/ Rebuild all mask canvases\n\n\t\t\t\/\/ Upload only the dirty masks into their configured texture units\n\t\t\tconst foilChannels = Builder.layers&#91;glCanvas.id&#93;.foilChannels;\n\t\t\tif (typeof vsx.maskCanvases !== undefined) {\n\t\t\t\tObject.entries(vsx.maskCanvases).forEach((&#91;key, maskCanvas&#93;) => {\n\t\t\t\t\tif (!vsx.maskDirtyFlags&#91;key&#93;) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tconst {unit, uni} = foilChannels&#91;key&#93;;\n\t\t\t\t\tBuilder.updateTextureUnit(maskCanvas, glCanvas, unit, uni);\n\t\t\t\t\tvsx.maskDirtyFlags&#91;key&#93; = false;\n\t\t\t\t});\n\t\t\t}\n\n\t\t});<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki material-theme\" style=\"background-color: #263238\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #EEFFFF\">fCanvas<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">on<\/span><span style=\"color: #EEFFFF\">(<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">after:render<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #89DDFF\">()<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #C792EA\">=&gt;<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #89DDFF; font-style: italic\">if<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #EEFFFF\">vsx<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">maskDirtyFlags<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">{<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">vsx<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">updateMaskCanvases<\/span><span style=\"color: #F07178\">()<\/span><span style=\"color: #89DDFF\">;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">}<\/span><span style=\"color: #F07178\"> \t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ Rebuild all mask canvases<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t\t\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ Upload only the dirty masks into their configured texture units<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">foilChannels<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">Builder<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">layers<\/span><span style=\"color: #F07178\">&#91;<\/span><span style=\"color: #EEFFFF\">glCanvas<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">id<\/span><span style=\"color: #F07178\">&#93;<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">foilChannels<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #89DDFF; font-style: italic\">if<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #89DDFF\">typeof<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">vsx<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">maskCanvases<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">!==<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">undefined<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t\t<\/span><span style=\"color: #EEFFFF\">Object<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">entries<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">vsx<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">maskCanvases<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">forEach<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">(&#91;<\/span><span style=\"color: #EEFFFF; font-style: italic\">key<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF; font-style: italic\">maskCanvas<\/span><span style=\"color: #89DDFF\">&#93;)<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #C792EA\">=&gt;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t\t\t<\/span><span style=\"color: #89DDFF; font-style: italic\">if<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #89DDFF\">!<\/span><span style=\"color: #EEFFFF\">vsx<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">maskDirtyFlags<\/span><span style=\"color: #F07178\">&#91;<\/span><span style=\"color: #EEFFFF\">key<\/span><span style=\"color: #F07178\">&#93;) <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t\t\t\t<\/span><span style=\"color: #89DDFF; font-style: italic\">return<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t\t\t<\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t\t\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">{<\/span><span style=\"color: #EEFFFF\">unit<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">uni<\/span><span style=\"color: #89DDFF\">}<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">foilChannels<\/span><span style=\"color: #F07178\">&#91;<\/span><span style=\"color: #EEFFFF\">key<\/span><span style=\"color: #F07178\">&#93;<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t\t\t<\/span><span style=\"color: #EEFFFF\">Builder<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">updateTextureUnit<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">maskCanvas<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">glCanvas<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">unit<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">uni<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t\t\t<\/span><span style=\"color: #EEFFFF\">vsx<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">maskDirtyFlags<\/span><span style=\"color: #F07178\">&#91;<\/span><span style=\"color: #EEFFFF\">key<\/span><span style=\"color: #F07178\">&#93; <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #FF9CAC\">false<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t\t<\/span><span style=\"color: #89DDFF\">}<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #89DDFF\">}<\/span><span style=\"color: #EEFFFF\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span><\/code><\/pre><\/div>\n<\/div><\/div>\n\n<div class=\"wp-block-grapham-mapping grapham-mapping-block\" data-cell-id=\"TKpOnsKza9iosXShlxyd-8\" data-cell-label=\"private TIFF SVG CANVAS (real dimensions)\"><div class=\"grapham-mapping-header\"><span class=\"grapham-mapping-label\">private TIFF SVG CANVAS (real dimensions)<\/span><span class=\"grapham-mapping-cellid\">TKpOnsKza9iosXShlxyd-8<\/span><\/div><div class=\"grapham-mapping-content\">\n<p>This is a rough sketch-up of an export pipeline running on the &#8220;magic numbers&#8221; when SpotRegistry isn&#8217;t in use. <br><br>You&#8217;ll want to handle all of your spots and treatments within a central registry rather than as config values, and SpotRegistry should run as an internal service, to ensure you&#8217;re outputting a job package that your pipeline understands.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#EEFFFF;--cbp-line-number-width:calc(3 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 0 16px;font-size:0.8em;width:100%;text-align:left;background-color:#263238;font-style:italic;color:#EEFFFF\"><span style=\"border-bottom:1px solid rgba(238, 255, 255, 0.2)\">JavaScript<\/span><\/span><span role=\"button\" tabindex=\"0\" style=\"color:#EEFFFF;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>import { encode as encodeTiff } from \".\/libs\/tiff-writer\/tiff-writer.js\";\n\n\n\texportTIFF = async function() {\n\t\t\/\/ Data flow:\n\t\t\/\/ - Fabric lowerCanvasEl (#canvas): contains SVG\/vector\/text and raster assets; we re-render these at 300 dpi to preserve crispness.\n\t\t\/\/ - Fabric overlay and WebGL preview canvases: visual-only layers, excluded from TIFF export.\n\t\t\/\/ - For each foil type (gold_foil, silver_foil, holo_foil, uv_spot):\n\t\t\/\/     \u2022 Clone and re-render those objects at 300 dpi into their own offscreen canvas.\n\t\t\/\/     \u2022 Force\u2010white fill and stroke for pixel-perfect spot coverage.\n\t\t\/\/     \u2022 Extract and threshold into a binary Uint8Array mask.\n\n\t\t\/\/ compute scale from 96 ppi \u2192 300 dpi\n\t\tconst lowerCanvas = document.getElementById(\"canvas\");\n\t\tconst origW = lowerCanvas.width, origH = lowerCanvas.height;\n\t\tconst PPI = 96, DPI = 300;\n\t\tconst SCALE = DPI \/ PPI;\n\t\tconst w = Math.round(origW * SCALE), h = Math.round(origH * SCALE);\n\n\t\t\/\/ foil types and mask arrays\n\t\tconst foilTypes = &#91;\"gold_foil\", \"silver_foil\", \"holo_foil\", \"uv_spot\"&#93;;\n\t\tconst spotNames = [];\n\t\tconst spotMasks = [];\n\n\t\t\/\/ Render base image at 300 dpi by re-drawing non-foil objects\n\t\tconst baseCanvas = document.createElement(\"canvas\");\n\t\tbaseCanvas.width = w;\n\t\tbaseCanvas.height = h;\n\t\tconst bctx = baseCanvas.getContext(\"2d\");\n\t\tbctx.imageSmoothingEnabled = false;\n\n\t\tconst baseStatic = new fabric.StaticCanvas(baseCanvas, {\n\t\t\trenderOnAddRemove: false,\n\t\t\tbackgroundColor: window.fCanvas.backgroundColor || null,\n\t\t});\n\t\tbaseStatic.enableRetinaScaling = false;\n\t\tbaseStatic.setViewportTransform(&#91;SCALE, 0, 0, SCALE, 0, 0&#93;);\n\n\t\t\/\/ clone add every object that isn\u2019t a foil spot\n\t\tconst baseObjs = window.fCanvas.getObjects().filter(o => !foilTypes.includes(o.foilType));\n\t\tfor (const obj of baseObjs) {\n\t\t\tconst clone = await obj.clone();\n\t\t\tbaseStatic.add(clone);\n\t\t}\n\n\t\tbaseStatic.renderAll();\n\t\tconst rgbaBuffer = bctx.getImageData(0, 0, w, h).data.buffer;\n\n\n\t\t\/\/ For each foilType, build a pure-white 300 dpi mask offscreen\n\t\tfor (const type of foilTypes) {\n\t\t\t\/\/ grab original vector\/raster objects for this spot\n\t\t\tconst objs = window.fCanvas.getObjects().filter(o => o.foilType === type);\n\t\t\tif (objs.length === 0) continue;\n\n\t\t\t\/\/ set up high-res offscreen canvas\n\t\t\tconst offCanvas = document.createElement(\"canvas\");\n\t\t\toffCanvas.width = w;\n\t\t\toffCanvas.height = h;\n\t\t\tconst staticCanvas = new fabric.StaticCanvas(offCanvas, {\n\t\t\t\trenderOnAddRemove: false,\n\t\t\t\tbackgroundColor: \"black\",\n\t\t\t});\n\t\t\tstaticCanvas.enableRetinaScaling = false;\n\t\t\tstaticCanvas.setViewportTransform(&#91;SCALE, 0, 0, SCALE, 0, 0&#93;);\n\n\t\t\tconst offCtx = offCanvas.getContext(\"2d\");\n\t\t\toffCtx.imageSmoothingEnabled = false;\n\n\t\t\t\/\/ recursively force-white fill\/stroke on sub-objects\n\t\t\tfunction forceWhite(o) {\n\t\t\t\tif (o.type === \"group\" &amp;&amp; o._objects) {\n\t\t\t\t\to._objects.forEach(forceWhite);\n\t\t\t\t}\n\t\t\t\to.set({\n\t\t\t\t\tfill:          \"rgba(255,255,255,1)\",\n\t\t\t\t\tstroke:        \"rgba(255,255,255,1)\",\n\t\t\t\t\tstrokeUniform: true,\n\t\t\t\t\tobjectCaching: false,\n\t\t\t\t});\n\t\t\t\tif (o.left != null) o.left = Math.round(o.left);\n\t\t\t\tif (o.top  != null) o.top  = Math.round(o.top);\n\t\t\t}\n\n\t\t\t\/\/ clone + add each foil object at 300 dpi scale\n\t\t\tfor (const obj of objs) {\n\t\t\t\tconst cloned = await obj.clone();\n\t\t\t\tforceWhite(cloned);\n\t\t\t\tstaticCanvas.add(cloned);\n\t\t\t}\n\n\t\t\tstaticCanvas.renderAll();\n\n\t\t\t\/\/ threshold to binary mask\n\t\t\tconst maskData = offCtx.getImageData(0, 0, w, h).data;\n\t\t\tconst binary = new Uint8Array(w * h);\n\t\t\tfor (let p = 0, i = 0; p &lt; w * h; p++, i += 4) {\n\t\t\t\tbinary&#91;p&#93; = maskData&#91;i&#93; > 128 ? 255 : 0;\n\t\t\t}\n\n\t\t\tspotNames.push(type);\n\t\t\tspotMasks.push(binary.buffer);\n\t\t}\n\n\t\t\/\/ optional ICC profile\n\t\tlet iccProfile = null;\n\t\tif (document.getElementById(\"embed-icc\")?.checked) {\n\n\t\t\ticcProfile = window.vsx.iccProfileBuffer || null;\n\t\t}\n\n\t\t\/\/ encode &amp; download TIFF at 300 dpi\n\t\tconst opts = {\n\t\t\twidth:          w,\n\t\t\theight:         h,\n\t\t\tbaseImage:      rgbaBuffer,\n\t\t\tcolorOrder:     \"RGBA\",\n\t\t\tspotMasks:      spotNames.length ? { names: spotNames, buffers: spotMasks } : undefined,\n\t\t\ticcProfile:     iccProfile,\n\t\t\txResolution:    &#91;DPI,1&#93;,\n\t\t\tyResolution:    &#91;DPI,1&#93;,\n\t\t\tresolutionUnit: 2 \/\/inches\n\t\t};\n\n\n\t\tconst tiffBuffer = encodeTiff(opts);\n\t\tconst blob = new Blob(&#91;tiffBuffer&#93;, { type: \"image\/tiff\" });\n\t\tconst a = document.createElement(\"a\");\n\t\ta.href = URL.createObjectURL(blob);\n\t\ta.download = \"export_spot.tif\";\n\t\ta.click();<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki material-theme\" style=\"background-color: #263238\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #89DDFF; font-style: italic\">import<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #89DDFF\">{<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">encode<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF; font-style: italic\">as<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">encodeTiff<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">}<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #89DDFF; font-style: italic\">from<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #C3E88D\">.\/libs\/tiff-writer\/tiff-writer.js<\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">\t<\/span><span style=\"color: #82AAFF\">exportTIFF<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #C792EA\">async<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #C792EA\">function<\/span><span style=\"color: #89DDFF\">()<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ Data flow:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ - Fabric lowerCanvasEl (#canvas): contains SVG\/vector\/text and raster assets; we re-render these at 300 dpi to preserve crispness.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ - Fabric overlay and WebGL preview canvases: visual-only layers, excluded from TIFF export.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ - For each foil type (gold_foil, silver_foil, holo_foil, uv_spot):<\/span><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/     \u2022 Clone and re-render those objects at 300 dpi into their own offscreen canvas.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/     \u2022 Force\u2010white fill and stroke for pixel-perfect spot coverage.<\/span><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/     \u2022 Extract and threshold into a binary Uint8Array mask.<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ compute scale from 96 ppi \u2192 300 dpi<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">lowerCanvas<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">document<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">getElementById<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #C3E88D\">canvas<\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">origW<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">lowerCanvas<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">width<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">origH<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">lowerCanvas<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">height<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">PPI<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">96<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">DPI<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">300<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">SCALE<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">DPI<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">\/<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">PPI<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">w<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">Math<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">round<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">origW<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">*<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">SCALE<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">h<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">Math<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">round<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">origH<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">*<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">SCALE<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ foil types and mask arrays<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">foilTypes<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> &#91;<\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #C3E88D\">gold_foil<\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #C3E88D\">silver_foil<\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #C3E88D\">holo_foil<\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #C3E88D\">uv_spot<\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #F07178\">&#93;<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">spotNames<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> []<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">spotMasks<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> []<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ Render base image at 300 dpi by re-drawing non-foil objects<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">baseCanvas<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">document<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">createElement<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #C3E88D\">canvas<\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">baseCanvas<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">width<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">w<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">baseCanvas<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">height<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">h<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">bctx<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">baseCanvas<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">getContext<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #C3E88D\">2d<\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">bctx<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">imageSmoothingEnabled<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #FF9CAC\">false<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">baseStatic<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">new<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">fabric<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">StaticCanvas<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">baseCanvas<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\trenderOnAddRemove<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #FF9CAC\">false<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\tbackgroundColor<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">window<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">fCanvas<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">backgroundColor<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">||<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">null,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #89DDFF\">}<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">baseStatic<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">enableRetinaScaling<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #FF9CAC\">false<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">baseStatic<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">setViewportTransform<\/span><span style=\"color: #F07178\">(&#91;<\/span><span style=\"color: #EEFFFF\">SCALE<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">SCALE<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #F07178\">&#93;)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ clone add every object that isn\u2019t a foil spot<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">baseObjs<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">window<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">fCanvas<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">getObjects<\/span><span style=\"color: #F07178\">()<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">filter<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF; font-style: italic\">o<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #C792EA\">=&gt;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">!<\/span><span style=\"color: #EEFFFF\">foilTypes<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">includes<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">o<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">foilType<\/span><span style=\"color: #F07178\">))<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #89DDFF; font-style: italic\">for<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">obj<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">of<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">baseObjs<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">clone<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF; font-style: italic\">await<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">obj<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">clone<\/span><span style=\"color: #F07178\">()<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #EEFFFF\">baseStatic<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">add<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">clone<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">baseStatic<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">renderAll<\/span><span style=\"color: #F07178\">()<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">rgbaBuffer<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">bctx<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">getImageData<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">w<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">h<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">data<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">buffer<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ For each foilType, build a pure-white 300 dpi mask offscreen<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #89DDFF; font-style: italic\">for<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">type<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">of<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">foilTypes<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t\t\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ grab original vector\/raster objects for this spot<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">objs<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">window<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">fCanvas<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">getObjects<\/span><span style=\"color: #F07178\">()<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">filter<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF; font-style: italic\">o<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #C792EA\">=&gt;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">o<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">foilType<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">===<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">type<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #89DDFF; font-style: italic\">if<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #EEFFFF\">objs<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">length<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">===<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF; font-style: italic\">continue<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t\t\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ set up high-res offscreen canvas<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">offCanvas<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">document<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">createElement<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #C3E88D\">canvas<\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #EEFFFF\">offCanvas<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">width<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">w<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #EEFFFF\">offCanvas<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">height<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">h<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">staticCanvas<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">new<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">fabric<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">StaticCanvas<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">offCanvas<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t\trenderOnAddRemove<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #FF9CAC\">false<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t\tbackgroundColor<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #C3E88D\">black<\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #89DDFF\">}<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #EEFFFF\">staticCanvas<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">enableRetinaScaling<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #FF9CAC\">false<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #EEFFFF\">staticCanvas<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">setViewportTransform<\/span><span style=\"color: #F07178\">(&#91;<\/span><span style=\"color: #EEFFFF\">SCALE<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">SCALE<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #F07178\">&#93;)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">offCtx<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">offCanvas<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">getContext<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #C3E88D\">2d<\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #EEFFFF\">offCtx<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">imageSmoothingEnabled<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #FF9CAC\">false<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t\t\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ recursively force-white fill\/stroke on sub-objects<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #C792EA\">function<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">forceWhite<\/span><span style=\"color: #89DDFF\">(<\/span><span style=\"color: #EEFFFF; font-style: italic\">o<\/span><span style=\"color: #89DDFF\">)<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t\t<\/span><span style=\"color: #89DDFF; font-style: italic\">if<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #EEFFFF\">o<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">type<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">===<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #C3E88D\">group<\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">&amp;&amp;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">o<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">_objects<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t\t\t<\/span><span style=\"color: #EEFFFF\">o<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">_objects<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">forEach<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">forceWhite<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t\t<\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t\t<\/span><span style=\"color: #EEFFFF\">o<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">set<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t\t\tfill<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #F07178\">          <\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #C3E88D\">rgba(255,255,255,1)<\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t\t\tstroke<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #F07178\">        <\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #C3E88D\">rgba(255,255,255,1)<\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t\t\tstrokeUniform<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #FF9CAC\">true<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t\t\tobjectCaching<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #FF9CAC\">false<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t\t<\/span><span style=\"color: #89DDFF\">}<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t\t<\/span><span style=\"color: #89DDFF; font-style: italic\">if<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #EEFFFF\">o<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">left<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">!=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">null<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #EEFFFF\">o<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">left<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">Math<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">round<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">o<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">left<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t\t<\/span><span style=\"color: #89DDFF; font-style: italic\">if<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #EEFFFF\">o<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">top<\/span><span style=\"color: #F07178\">  <\/span><span style=\"color: #89DDFF\">!=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">null<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #EEFFFF\">o<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">top<\/span><span style=\"color: #F07178\">  <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">Math<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">round<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">o<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">top<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t\t\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ clone + add each foil object at 300 dpi scale<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #89DDFF; font-style: italic\">for<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">obj<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">of<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">objs<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">cloned<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF; font-style: italic\">await<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">obj<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">clone<\/span><span style=\"color: #F07178\">()<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t\t<\/span><span style=\"color: #82AAFF\">forceWhite<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">cloned<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t\t<\/span><span style=\"color: #EEFFFF\">staticCanvas<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">add<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">cloned<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #EEFFFF\">staticCanvas<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">renderAll<\/span><span style=\"color: #F07178\">()<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t\t\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ threshold to binary mask<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">maskData<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">offCtx<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">getImageData<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">w<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">h<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">data<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">binary<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">new<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">Uint8Array<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">w<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">*<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">h<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #89DDFF; font-style: italic\">for<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #C792EA\">let<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">p<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">i<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #89DDFF\">;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">p<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">&lt;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">w<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">*<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">h<\/span><span style=\"color: #89DDFF\">;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">p<\/span><span style=\"color: #89DDFF\">++,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">i<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">+=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">4<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t\t<\/span><span style=\"color: #EEFFFF\">binary<\/span><span style=\"color: #F07178\">&#91;<\/span><span style=\"color: #EEFFFF\">p<\/span><span style=\"color: #F07178\">&#93; <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">maskData<\/span><span style=\"color: #F07178\">&#91;<\/span><span style=\"color: #EEFFFF\">i<\/span><span style=\"color: #F07178\">&#93; <\/span><span style=\"color: #89DDFF\">&gt;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">128<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">?<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">255<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #EEFFFF\">spotNames<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">push<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">type<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #EEFFFF\">spotMasks<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">push<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">binary<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">buffer<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ optional ICC profile<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #C792EA\">let<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">iccProfile<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">null;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #89DDFF; font-style: italic\">if<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #EEFFFF\">document<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">getElementById<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #C3E88D\">embed-icc<\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">?.<\/span><span style=\"color: #EEFFFF\">checked<\/span><span style=\"color: #F07178\">) <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #EEFFFF\">iccProfile<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">window<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">vsx<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">iccProfileBuffer<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">||<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">null;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">\t\t<\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ encode &amp; download TIFF at 300 dpi<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">opts<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\twidth<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #F07178\">          <\/span><span style=\"color: #EEFFFF\">w<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\theight<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #F07178\">         <\/span><span style=\"color: #EEFFFF\">h<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\tbaseImage<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #F07178\">      <\/span><span style=\"color: #EEFFFF\">rgbaBuffer<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\tcolorOrder<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #F07178\">     <\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #C3E88D\">RGBA<\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\tspotMasks<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #F07178\">      <\/span><span style=\"color: #EEFFFF\">spotNames<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">length<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">?<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">{<\/span><span style=\"color: #F07178\"> names<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">spotNames<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> buffers<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">spotMasks<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">}<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">undefined,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\ticcProfile<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #F07178\">     <\/span><span style=\"color: #EEFFFF\">iccProfile<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\txResolution<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #F07178\">    &#91;<\/span><span style=\"color: #EEFFFF\">DPI<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #F07178\">&#93;<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\tyResolution<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #F07178\">    &#91;<\/span><span style=\"color: #EEFFFF\">DPI<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #F07178\">&#93;<\/span><span style=\"color: #89DDFF\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\tresolutionUnit<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">2<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #546E7A; font-style: italic\">\/\/inches<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #89DDFF\">};<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">tiffBuffer<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">encodeTiff<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">opts<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">blob<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">new<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #82AAFF\">Blob<\/span><span style=\"color: #F07178\">(&#91;<\/span><span style=\"color: #EEFFFF\">tiffBuffer<\/span><span style=\"color: #F07178\">&#93;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">{<\/span><span style=\"color: #F07178\"> type<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #C3E88D\">image\/tiff<\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">}<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">a<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">document<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">createElement<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #C3E88D\">a<\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">a<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">href<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">URL<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">createObjectURL<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">blob<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">a<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">download<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #C3E88D\">export_spot.tif<\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #EEFFFF\">a<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">click<\/span><span style=\"color: #F07178\">()<\/span><span style=\"color: #89DDFF\">;<\/span><\/span><\/code><\/pre><\/div>\n<\/div><\/div>\n\t\t<\/div>\n\n\t\t<div id=\"grapham-modal\" aria-hidden=\"true\">\n\t\t\t<div class=\"modal__overlay\" tabindex=\"-1\" data-micromodal-close><\/div>\n\t\t\t<div class=\"modal__container\" role=\"dialog\" aria-modal=\"true\">\n\t\t\t\t<header class=\"modal__header\">\n\t\t\t\t\t<button\n\t\t\t\t\t\t\tclass=\"modal__close\"\n\t\t\t\t\t\t\taria-label=\"Close modal\"\n\t\t\t\t\t\t\tdata-micromodal-close\n\t\t\t\t\t><\/button>\n\t\t\t\t<\/header>\n\t\t\t\t<main class=\"modal__content\" id=\"grapham-modal-content\"><\/main>\n\t\t\t<\/div>\n\t\t<\/div>\n\n\t<\/SECTION>\n\t\n\n\n<p>&nbsp;<\/p>\n\n\n\n<p>To preserve fidelity and image color accuracy, all WebGL2 &#8220;effects&#8221; are built and then displayed outside of Fabric.JS, using Builder. This prevents stray effects intended only for visual preview (such as emboss or foil previews) from affecting the working assets.<\/p>\n\n\n\n<p>The separation allows for the animations to be performance-optimized (important for mobile) with texture sampling occurring only during change events.<\/p>\n\n\n\n<p>For real dimensions without distortion, the base SVG files are then sampled at print DPI using the magic constants explored in &#8220;<a href=\"https:\/\/lampwrite.com\/j\/the-physiology-of-the-eye-and-the-user-experience\/#Fundamentals_of_Sizing_for_Web\">Fundamentals of Sizing for the Web.&#8221;<\/a><\/p>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Setting Up Fabric.js and WebGL Composition<\/h2>\n\n\n\n<p>We begin by initializing a standard Fabric.js canvas for layout and interaction. This canvas handles all user-driven edits, including text entry, font changes, kerning, and foil selection, while remaining agnostic to rendering effects. <br><br>Each object added to the canvas carries a custom <code>foilType<\/code> property, which we use to route it into the correct mask layer later.<\/p>\n\n\n\n<p>To render foil effects, we stack a second <code>&lt;canvas&gt;<\/code> element directly above the Fabric canvas. This WebGL canvas is initialized via <code>Builder.initWebGLLayer<\/code>(), which compiles the shaders, allocates textures, and binds samplers for each foil type. The two canvases are visually aligned but functionally independent: Fabric handles object state, while WebGL reads from offscreen masks to composite effects.<\/p>\n\n\n\n<p>We hook into Fabric\u2019s <code>after:render<\/code> event to rebuild foil masks and upload them to WebGL only when needed. Each mask canvas is redrawn with only the objects matching its <code>foilType<\/code>, rendered in solid white. These canvases are then uploaded to their respective texture units using <code>Builder.updateTextureUnit<\/code>(), ensuring the shader receives fresh data without redundant GPU calls:<code><br><\/code><\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#EEFFFF;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 0 16px;font-size:0.8em;width:100%;text-align:left;background-color:#263238;font-style:italic;color:#EEFFFF\"><span style=\"border-bottom:1px solid rgba(238, 255, 255, 0.2)\">JavaScript<\/span><\/span><span role=\"button\" tabindex=\"0\" style=\"color:#EEFFFF;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>fCanvas.on('after:render', () => {\n\n\tvsx.updateMaskCanvases(); \/\/ rebuild masks\n\tObject.entries(vsx.maskCanvases).forEach((&#91;type, maskCanvas&#93;) => {\n\t\t\n\t\tif (vsx.maskDirtyFlags&#91;type&#93;) {\n\t\t\tconst { unit, uni } = layer.foilChannels&#91;type&#93;;\n\t\t\tBuilder.updateTextureUnit(maskCanvas, layer, unit, uni);\n\t\t\tvsx.maskDirtyFlags&#91;type&#93; = false;\n\t\t}\n\t\n\t});\n\n});<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki material-theme\" style=\"background-color: #263238\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #EEFFFF\">fCanvas<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">on<\/span><span style=\"color: #EEFFFF\">(<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #C3E88D\">after:render<\/span><span style=\"color: #89DDFF\">&#39;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #89DDFF\">()<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #C792EA\">=&gt;<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #EEFFFF\">vsx<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">updateMaskCanvases<\/span><span style=\"color: #F07178\">()<\/span><span style=\"color: #89DDFF\">;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ rebuild masks<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #EEFFFF\">Object<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">entries<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">vsx<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">maskCanvases<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">forEach<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #89DDFF\">(&#91;<\/span><span style=\"color: #EEFFFF; font-style: italic\">type<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF; font-style: italic\">maskCanvas<\/span><span style=\"color: #89DDFF\">&#93;)<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #C792EA\">=&gt;<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #89DDFF; font-style: italic\">if<\/span><span style=\"color: #F07178\"> (<\/span><span style=\"color: #EEFFFF\">vsx<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">maskDirtyFlags<\/span><span style=\"color: #F07178\">&#91;<\/span><span style=\"color: #EEFFFF\">type<\/span><span style=\"color: #F07178\">&#93;) <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">{<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">unit<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">uni<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">}<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">layer<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">foilChannels<\/span><span style=\"color: #F07178\">&#91;<\/span><span style=\"color: #EEFFFF\">type<\/span><span style=\"color: #F07178\">&#93;<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #EEFFFF\">Builder<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">updateTextureUnit<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">maskCanvas<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">layer<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">unit<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">uni<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t\t<\/span><span style=\"color: #EEFFFF\">vsx<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">maskDirtyFlags<\/span><span style=\"color: #F07178\">&#91;<\/span><span style=\"color: #EEFFFF\">type<\/span><span style=\"color: #F07178\">&#93; <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #FF9CAC\">false<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t\t<\/span><span style=\"color: #89DDFF\">}<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #89DDFF\">}<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">}<\/span><span style=\"color: #EEFFFF\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Builder: WebGL Layer Initialization and Management<\/h2>\n\n\n\n<p>The <code>Builder<\/code> module encapsulates all WebGL setup and rendering logic. It\u2019s responsible for compiling the fragment shader, creating the rendering context, and managing texture units for each foil channel. When <code>Builder.initWebGLLayer<\/code> is called, it attaches a WebGL context to the foil canvas, sets up blending modes, and links uniform variables for each mask and foil texture.<\/p>\n\n\n\n<p>Each foil type is assigned a dedicated texture unit and uniform. These are stored under <code>layer<\/code>, which maps <code>foilType<\/code> and <code>spotName<\/code> to corresponding WebGL bindings. The shader samples from these textures and blends them using a custom compositing function that simulates foil reflectivity based on mask intensity and lighting angle.<\/p>\n\n\n\n<p>Texture updates are handled by <code>Builder.updateTextureUnit<\/code>(), which takes a mask canvas and uploads it to the GPU. This function ensures that only dirty textures are re-uploaded, minimizing performance overhead. It binds the texture, sets parameters, and transfers pixel data using <code>texImage2D<\/code>.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#EEFFFF;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 0 16px;font-size:0.8em;width:100%;text-align:left;background-color:#263238;font-style:italic;color:#EEFFFF\"><span style=\"border-bottom:1px solid rgba(238, 255, 255, 0.2)\">JavaScript<\/span><\/span><span role=\"button\" tabindex=\"0\" style=\"color:#EEFFFF;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>updateTextureUnit(canvas, layer, unit, uniform) {\n\t\n\tconst gl = layer.gl;\n\tgl.activeTexture(gl.TEXTURE0 + unit);\n\tgl.bindTexture(gl.TEXTURE_2D, layer.textures&#91;unit&#93;);\n\tgl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, canvas);\n\tgl.uniform1i(uniform, unit);\n\n}<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki material-theme\" style=\"background-color: #263238\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #82AAFF\">updateTextureUnit<\/span><span style=\"color: #EEFFFF\">(canvas<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #EEFFFF\"> layer<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #EEFFFF\"> unit<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #EEFFFF\"> uniform) <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #C792EA\">const<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">layer<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">activeTexture<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">TEXTURE0<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #89DDFF\">+<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">unit<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">bindTexture<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">TEXTURE_2D<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">layer<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">textures<\/span><span style=\"color: #F07178\">&#91;<\/span><span style=\"color: #EEFFFF\">unit<\/span><span style=\"color: #F07178\">&#93;)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">texImage2D<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">TEXTURE_2D<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #F78C6C\">0<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">RGBA<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">RGBA<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #EEFFFF\">UNSIGNED_BYTE<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">canvas<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F07178\">\t<\/span><span style=\"color: #EEFFFF\">gl<\/span><span style=\"color: #89DDFF\">.<\/span><span style=\"color: #82AAFF\">uniform1i<\/span><span style=\"color: #F07178\">(<\/span><span style=\"color: #EEFFFF\">uniform<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #F07178\"> <\/span><span style=\"color: #EEFFFF\">unit<\/span><span style=\"color: #F07178\">)<\/span><span style=\"color: #89DDFF\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">TiffWriter<\/h2>\n\n\n\n<p>The purpose of the <code>TiffWriter<\/code> module is to explore alternative export strategies using an extensible image format. In this case, we&#8217;ve designed it to export compositions into a TIFF file with multiple ink channels, each represented as a separate sample plane. Such a format could allow print workflows to treat each mask as a distinct spot color, but for a real pipeline, SpotRegistry needs to be active to split the spot colors and assets.<\/p>\n\n\n\n<p>Without photoshop in the pipeline, using tiff files is currently somewhat constrained as files created without correctly tagged IRB blocks have limited support, and programmatic or automated solutions are not always available, especially in browser (UTIF, TIFF, and many other libraries lack support). <\/p>\n\n\n\n<p>Regardless, .tif is an excellent, well documented and widely used extensible image format, so in principle there&#8217;s no reason we can&#8217;t automate processing Tiff files into RIP-ready packages.<\/p>\n\n\n\n<p>To bypass these limitations of current technology, we write the binary structure directly, ensuring full control over sample layout and ink metadata. <code>TiffWriter<\/code> manually constructs the IFD (Image File Directory), assigning each foil mask to a unique sample index and embedding metadata using tags like <code>InkSet<\/code>, <code>InkNames<\/code>, and <code>SampleFormat<\/code>.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#EEFFFF;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 0 16px;font-size:0.8em;width:100%;text-align:left;background-color:#263238;font-style:italic;color:#EEFFFF\"><span style=\"border-bottom:1px solid rgba(238, 255, 255, 0.2)\">JavaScript<\/span><\/span><span role=\"button\" tabindex=\"0\" style=\"color:#EEFFFF;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>const ifd = {\n\n\tt277: 4, \/\/ SamplesPerPixel\n\tt258: &#91;1, 1, 1, 1&#93;, \/\/ SampleFormat: unsigned int\n\tt339: &#91;16, 16, 16, 16&#93;, \/\/ BitsPerSample\n\tt334: 5, \/\/ InkSet: named inks\n\tt336: \"R\\0G\\0B\\0A\\0White\\0\\0\", \/\/ InkNames\n\n\/\/ Additional tags for tiling, compression, and resolution...\n\n};<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki material-theme\" style=\"background-color: #263238\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #C792EA\">const<\/span><span style=\"color: #EEFFFF\"> ifd <\/span><span style=\"color: #89DDFF\">=<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #89DDFF\">{<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">\t<\/span><span style=\"color: #F07178\">t277<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #F78C6C\">4<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ SamplesPerPixel<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">\t<\/span><span style=\"color: #F07178\">t258<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\"> &#91;<\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #F78C6C\">1<\/span><span style=\"color: #EEFFFF\">&#93;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ SampleFormat: unsigned int<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">\t<\/span><span style=\"color: #F07178\">t339<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\"> &#91;<\/span><span style=\"color: #F78C6C\">16<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #F78C6C\">16<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #F78C6C\">16<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #F78C6C\">16<\/span><span style=\"color: #EEFFFF\">&#93;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ BitsPerSample<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">\t<\/span><span style=\"color: #F07178\">t334<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #F78C6C\">5<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ InkSet: named inks<\/span><\/span>\n<span class=\"line\"><span style=\"color: #EEFFFF\">\t<\/span><span style=\"color: #F07178\">t336<\/span><span style=\"color: #89DDFF\">:<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #C3E88D\">R<\/span><span style=\"color: #EEFFFF\">\\0<\/span><span style=\"color: #C3E88D\">G<\/span><span style=\"color: #EEFFFF\">\\0<\/span><span style=\"color: #C3E88D\">B<\/span><span style=\"color: #EEFFFF\">\\0<\/span><span style=\"color: #C3E88D\">A<\/span><span style=\"color: #EEFFFF\">\\0<\/span><span style=\"color: #C3E88D\">White<\/span><span style=\"color: #EEFFFF\">\\0\\0<\/span><span style=\"color: #89DDFF\">&quot;<\/span><span style=\"color: #89DDFF\">,<\/span><span style=\"color: #EEFFFF\"> <\/span><span style=\"color: #546E7A; font-style: italic\">\/\/ InkNames<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #546E7A; font-style: italic\">\/\/ Additional tags for tiling, compression, and resolution...<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #89DDFF\">};<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>&nbsp;<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Demonstrations<\/h2>\n\n\n\n<p><\/p>\n\n\n\n<p>See this <a href=\"https:\/\/lampwrite.com\/examples\/vsx\/vsx.html\">visualization<\/a> for a more complete coverage of functionality. <br><br>This demonstration linked above is for discussion purposes. It concerns the investigation of novel techniques within a realworld-like case study. <br><br>That code is packaged in a reader-friendly manner in native javascript, and is not minified or abstracted away, so the techniques can be clearly understood. <\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This article covers technical and architectural choices in modern web-based design tooling for applications requiring high fidelity, including print. Geo\/GIS applications, light-sensing applications, medical imaging, and print applications handle data that cannot be accurately represented by static, 2D RGB screens. Within print, we have CMYK coloring that can fall outside of the sRGB gamut, spot [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-823","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/lampwrite.com\/j\/wp-json\/wp\/v2\/pages\/823","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/lampwrite.com\/j\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/lampwrite.com\/j\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/lampwrite.com\/j\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/lampwrite.com\/j\/wp-json\/wp\/v2\/comments?post=823"}],"version-history":[{"count":20,"href":"https:\/\/lampwrite.com\/j\/wp-json\/wp\/v2\/pages\/823\/revisions"}],"predecessor-version":[{"id":918,"href":"https:\/\/lampwrite.com\/j\/wp-json\/wp\/v2\/pages\/823\/revisions\/918"}],"wp:attachment":[{"href":"https:\/\/lampwrite.com\/j\/wp-json\/wp\/v2\/media?parent=823"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}