[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"github-stars":3,"guide-nav":5,"doc-\u002Fdocs\u002Fguide\u002Fcustom-shaders":129},{"stars":4},5504,[6,11,15,19,23,27,31,35,39,43,47,51,55,59,63,67,72,76,80,84,88,93,97,101,105,109,113,117,121,125],{"path":7,"title":8,"description":9,"category":10},"\u002Fdocs\u002Fguide","Getting started","Shaders is a library of GPU effect components for Vue, React, Svelte, Solid, JavaScript and Framer, with a design editor for building with them.","code",{"path":12,"title":13,"description":14,"category":10},"\u002Fdocs\u002Fguide\u002Fquickstart","Quickstart","Install Shaders, render your first effect, and drive a prop from state.",{"path":16,"title":17,"description":18,"category":10},"\u002Fdocs\u002Fguide\u002Fcomposing-effects","Composing effects","Stack components as layers and nest them to control which layers an effect touches.",{"path":20,"title":21,"description":22,"category":10},"\u002Fdocs\u002Fguide\u002Fblending-masking","Blending and masking","Control how a layer mixes with the layers below it, and reveal one layer through another.",{"path":24,"title":25,"description":26,"category":10},"\u002Fdocs\u002Fguide\u002Fprops-reactivity","Props and reactivity","Bind props to your framework's state so effects update when it changes, and animate props with an animation library.",{"path":28,"title":29,"description":30,"category":10},"\u002Fdocs\u002Fguide\u002Fdynamic-props","Dynamic props","Drive any numeric or position prop from time, the cursor, or another layer, without writing animation code.",{"path":32,"title":33,"description":34,"category":10},"\u002Fdocs\u002Fguide\u002Flayout-positioning","Layout and positioning","Size and place a shader in your page with CSS, as a background, a fill, or an inline block.",{"path":36,"title":37,"description":38,"category":10},"\u002Fdocs\u002Fguide\u002Fsizing-and-units","Sizing and units","Size and place layers in CSS units (px, %, vw, rem, and canvas units) that stay correct as the canvas and window resize.",{"path":40,"title":41,"description":42,"category":10},"\u002Fdocs\u002Fguide\u002Ftransforms","Transforms","Position, size, and rotate any layer inside the canvas with a bounding box, in any CSS unit.",{"path":44,"title":45,"description":46,"category":10},"\u002Fdocs\u002Fguide\u002Fshape-effects","Shape effects","Pick the 2D, 3D or custom SVG shape that Glass, Neon, Emboss and other shape effects draw inside.",{"path":48,"title":49,"description":50,"category":10},"\u002Fdocs\u002Fguide\u002Fcolor-space","Color space","Match colors to your design tool with the output color space, and keep bright layers from clipping with tone mapping.",{"path":52,"title":53,"description":54,"category":10},"\u002Fdocs\u002Fguide\u002Fhooks-events","Hooks and events","Run code when an effect is ready to show, and show a fallback when the GPU can't run it.",{"path":56,"title":57,"description":58,"category":10},"\u002Fdocs\u002Fguide\u002Fperformance","Performance","Learn what makes an effect expensive on the GPU and how to keep it inside the frame budget.",{"path":60,"title":61,"description":62,"category":10},"\u002Fdocs\u002Fguide\u002Fcustom-shaders","Custom components","Write your own component in TypeScript, use it like any component in the library, and write WGSL by hand when you need to.",{"path":64,"title":65,"description":66,"category":10},"\u002Fdocs\u002Fguide\u002Ftelemetry","Telemetry","The `\u003CShader>` component occasionally sends an anonymous performance report to help us improve the engine over time.",{"path":68,"title":69,"description":70,"category":71},"\u002Fdocs\u002Fguide\u002Fmcp","Shaders MCP","Connect your AI coding agent to Shaders so it can find, install and edit effects in your codebase.","workflows",{"path":73,"title":74,"description":75,"category":71},"\u002Fdocs\u002Fguide\u002Fcli","Shaders CLI","Install your own shaders and Pro shaders into your codebase as component files, and keep them in sync with the design editor.",{"path":77,"title":78,"description":79,"category":71},"\u002Fdocs\u002Fguide\u002Fagent-skill","Agent skill","Give your coding agent a skill that teaches it to build with Shaders components, the CLI and Pro shaders.",{"path":81,"title":82,"description":83,"category":10},"\u002Fdocs\u002Fguide\u002Fvideo-rendering","Rendering to video","Turn a shader effect into a video file, from the design editor or from a frame-by-frame pipeline such as Remotion, Hyperframes or Puppeteer.",{"path":85,"title":86,"description":87,"category":10},"\u002Fdocs\u002Fguide\u002Fssr","Server rendering","Render Shaders in Next.js, Nuxt, SvelteKit, SolidStart and other SSR apps by keeping each shader on the client.",{"path":89,"title":90,"description":91,"category":92},"\u002Fdocs\u002Fguide\u002Fquick-tour-of-the-design-editor","Quick tour of the design editor","A short walkthrough of the full Shaders workflow, from designing on the infinite canvas to exporting code.","editor",{"path":94,"title":95,"description":96,"category":92},"\u002Fdocs\u002Fguide\u002Fintro-to-the-interface","Intro to the interface","A tour of the design editor interface: the canvas, layers, the Properties panel, and the ways to share and export.",{"path":98,"title":99,"description":100,"category":92},"\u002Fdocs\u002Fguide\u002Fcomposing-your-first-shader-effect","Composing your first shader effect","Building a first shader effect in the design editor by stacking and nesting components as layers.",{"path":102,"title":103,"description":104,"category":92},"\u002Fdocs\u002Fguide\u002Fmasking-and-blending","Masking and blending","How blend modes and masks combine components in the design editor.",{"path":106,"title":107,"description":108,"category":92},"\u002Fdocs\u002Fguide\u002Fdynamic-prop-mapping","Dynamic prop mapping","Turning static props into dynamic ones in the design editor: mapping one layer's output into another's prop, following the cursor, or animating automatically.",{"path":110,"title":111,"description":112,"category":92},"\u002Fdocs\u002Fguide\u002Fcustom-media-and-transformations","Custom media and transformations","Uploading images, videos, and SVG files to the media gallery, adding them to a composition, and placing them with transformations.",{"path":114,"title":115,"description":116,"category":92},"\u002Fdocs\u002Fguide\u002Finstalling-a-shader-via-mcp","Installing a shader via MCP","Installing a shader from the design editor into a hero section with the Shaders MCP.",{"path":118,"title":119,"description":120,"category":92},"\u002Fdocs\u002Fguide\u002Fexploring-shape-effects","Exploring shape effects","Applying shape effects such as liquid glass, liquid metal, and glowing edges to built-in shapes and your own SVG.",{"path":122,"title":123,"description":124,"category":92},"\u002Fdocs\u002Fguide\u002Fglass-component-spotlight","Component spotlight: Glass","A short look at the Glass component and the liquid-glass look it creates.",{"path":126,"title":127,"description":128,"category":92},"\u002Fdocs\u002Fguide\u002Fdigital-looks-component-spotlight","Component spotlight: Digital looks","A look at the digital stylization components for glitchy, futuristic, or technical effects.",{"id":130,"title":61,"body":131,"category":10,"description":62,"extension":1738,"icon":1739,"meta":1740,"navigation":227,"path":60,"seo":1741,"stem":1742,"__hash__":1743},"guide\u002Fdocs\u002Fguide\u002F13.custom-shaders.md",{"type":132,"value":133,"toc":1729},"minimark",[134,138,141,148,156,161,168,179,193,345,375,386,624,647,656,684,687,695,699,725,736,1285,1296,1300,1303,1352,1368,1372,1382,1404,1407,1546,1556,1618,1623,1697,1701,1725],[135,136,61],"h1",{"id":137},"custom-components",[139,140,62],"p",{},[139,142,143,144,147],{},"Every component in the library is a plain TypeScript object passed to ",[10,145,146],{},"defineShader",". Yours works the same way, with no build step.",[139,149,150,151,155],{},"A ",[152,153,154],"strong",{},"definition"," has two jobs: list the props someone can change, and say what color each pixel should be. Shaders handles the rest: blend modes, opacity, masks, transforms and code export.",[157,158,160],"h2",{"id":159},"building-a-component-from-primitives","Building a component from primitives",[162,163],"experimental-warning",{"link-label":164,"link-url":165,"message":166,"title":167},"Browse the primitives","\u002Fdocs\u002Fprimitives","The primitives API might change between releases while the vocabulary settles. A component written with them may need small edits when you upgrade.","Primitives are experimental",[139,169,170,171,174,175,178],{},"The ",[152,172,173],{},"primitives"," are the building blocks the library's own components are made of. Each one is a ",[152,176,177],{},"word",": a small function you combine with others, the way you combine CSS properties. This section builds a two-color gradient from them.",[139,180,181,184,185,188,189,192],{},[152,182,183],{},"1. Name it and list its props."," A prop is anything someone can change later, and each one needs a default. The ",[10,186,187],{},"transform"," says what kind of value it is, so a color string becomes a color and an ",[10,190,191],{},"{x, y}"," object becomes a point:",[194,195,200],"pre",{"className":196,"code":197,"language":198,"meta":199,"style":199},"language-ts shiki shiki-themes github-dark","import {defineShader, transformColor, transformPosition} from 'shaders\u002Fstd'\n\nexport const MyGradient = defineShader({\n  name: 'MyGradient',\n  props: {\n    from: {default: {x: 0, y: 0.5}, transform: transformPosition},\n    to: {default: {x: 1, y: 0.5}, transform: transformPosition},\n    colorA: {default: '#ff6b6b', transform: transformColor},\n    colorB: {default: '#4ecdc4', transform: transformColor},\n  },\n  \u002F\u002F paint: comes next\n})\n","ts","",[10,201,202,222,229,252,264,270,288,303,315,326,332,339],{"__ignoreMap":199},[203,204,207,211,215,218],"span",{"class":205,"line":206},"line",1,[203,208,210],{"class":209},"snl16","import",[203,212,214],{"class":213},"s95oV"," {defineShader, transformColor, transformPosition} ",[203,216,217],{"class":209},"from",[203,219,221],{"class":220},"sU2Wk"," 'shaders\u002Fstd'\n",[203,223,225],{"class":205,"line":224},2,[203,226,228],{"emptyLinePlaceholder":227},true,"\n",[203,230,232,235,238,242,245,249],{"class":205,"line":231},3,[203,233,234],{"class":209},"export",[203,236,237],{"class":209}," const",[203,239,241],{"class":240},"sDLfK"," MyGradient",[203,243,244],{"class":209}," =",[203,246,248],{"class":247},"svObZ"," defineShader",[203,250,251],{"class":213},"({\n",[203,253,255,258,261],{"class":205,"line":254},4,[203,256,257],{"class":213},"  name: ",[203,259,260],{"class":220},"'MyGradient'",[203,262,263],{"class":213},",\n",[203,265,267],{"class":205,"line":266},5,[203,268,269],{"class":213},"  props: {\n",[203,271,273,276,279,282,285],{"class":205,"line":272},6,[203,274,275],{"class":213},"    from: {default: {x: ",[203,277,278],{"class":240},"0",[203,280,281],{"class":213},", y: ",[203,283,284],{"class":240},"0.5",[203,286,287],{"class":213},"}, transform: transformPosition},\n",[203,289,291,294,297,299,301],{"class":205,"line":290},7,[203,292,293],{"class":213},"    to: {default: {x: ",[203,295,296],{"class":240},"1",[203,298,281],{"class":213},[203,300,284],{"class":240},[203,302,287],{"class":213},[203,304,306,309,312],{"class":205,"line":305},8,[203,307,308],{"class":213},"    colorA: {default: ",[203,310,311],{"class":220},"'#ff6b6b'",[203,313,314],{"class":213},", transform: transformColor},\n",[203,316,318,321,324],{"class":205,"line":317},9,[203,319,320],{"class":213},"    colorB: {default: ",[203,322,323],{"class":220},"'#4ecdc4'",[203,325,314],{"class":213},[203,327,329],{"class":205,"line":328},10,[203,330,331],{"class":213},"  },\n",[203,333,335],{"class":205,"line":334},11,[203,336,338],{"class":337},"sAwPA","  \u002F\u002F paint: comes next\n",[203,340,342],{"class":205,"line":341},12,[203,343,344],{"class":213},"})\n",[139,346,347,350,351,354,355,358,359,362,363,366,367,370,371,374],{},[152,348,349],{},"2. Say what to draw."," A gradient is two things. First, a ",[152,352,353],{},"field",": a number per pixel saying how far along the gradient that pixel sits. Second, a ",[152,356,357],{},"palette"," that turns that number into a color. ",[10,360,361],{},"dist.linear"," gives you the field, ",[10,364,365],{},"pair"," is the palette, and ",[10,368,369],{},"rampOver"," connects them. ",[10,372,373],{},"p('name')"," reads one of your props.",[139,376,377,378,381,382,385],{},"The finished definition adds a ",[10,379,380],{},"colorSpace"," prop and the ",[10,383,384],{},"paint:"," field:",[194,387,389],{"className":196,"code":388,"language":198,"meta":199,"style":199},"import {defineShader, p, paint, transformColor, transformColorSpace, transformPosition} from 'shaders\u002Fstd'\n\nconst {rampOver, dist, pair} = paint\n\nexport const MyGradient = defineShader({\n  name: 'MyGradient',\n  props: {\n    from: {default: {x: 0, y: 0.5}, transform: transformPosition},\n    to: {default: {x: 1, y: 0.5}, transform: transformPosition},\n    colorA: {default: '#ff6b6b', transform: transformColor},\n    colorB: {default: '#4ecdc4', transform: transformColor},\n    colorSpace: {default: 'oklch', transform: transformColorSpace, compileTime: true},\n  },\n  paint: rampOver(\n    dist.linear({from: p('from'), to: p('to'), angle: 0}),\n    pair(p('colorA'), p('colorB'), p('colorSpace')),\n  ),\n})\n",[10,390,391,402,406,435,439,453,461,465,477,489,497,505,522,527,538,576,613,619],{"__ignoreMap":199},[203,392,393,395,398,400],{"class":205,"line":206},[203,394,210],{"class":209},[203,396,397],{"class":213}," {defineShader, p, paint, transformColor, transformColorSpace, transformPosition} ",[203,399,217],{"class":209},[203,401,221],{"class":220},[203,403,404],{"class":205,"line":224},[203,405,228],{"emptyLinePlaceholder":227},[203,407,408,411,414,416,419,422,424,426,429,432],{"class":205,"line":231},[203,409,410],{"class":209},"const",[203,412,413],{"class":213}," {",[203,415,369],{"class":240},[203,417,418],{"class":213},", ",[203,420,421],{"class":240},"dist",[203,423,418],{"class":213},[203,425,365],{"class":240},[203,427,428],{"class":213},"} ",[203,430,431],{"class":209},"=",[203,433,434],{"class":213}," paint\n",[203,436,437],{"class":205,"line":254},[203,438,228],{"emptyLinePlaceholder":227},[203,440,441,443,445,447,449,451],{"class":205,"line":266},[203,442,234],{"class":209},[203,444,237],{"class":209},[203,446,241],{"class":240},[203,448,244],{"class":209},[203,450,248],{"class":247},[203,452,251],{"class":213},[203,454,455,457,459],{"class":205,"line":272},[203,456,257],{"class":213},[203,458,260],{"class":220},[203,460,263],{"class":213},[203,462,463],{"class":205,"line":290},[203,464,269],{"class":213},[203,466,467,469,471,473,475],{"class":205,"line":305},[203,468,275],{"class":213},[203,470,278],{"class":240},[203,472,281],{"class":213},[203,474,284],{"class":240},[203,476,287],{"class":213},[203,478,479,481,483,485,487],{"class":205,"line":317},[203,480,293],{"class":213},[203,482,296],{"class":240},[203,484,281],{"class":213},[203,486,284],{"class":240},[203,488,287],{"class":213},[203,490,491,493,495],{"class":205,"line":328},[203,492,308],{"class":213},[203,494,311],{"class":220},[203,496,314],{"class":213},[203,498,499,501,503],{"class":205,"line":334},[203,500,320],{"class":213},[203,502,323],{"class":220},[203,504,314],{"class":213},[203,506,507,510,513,516,519],{"class":205,"line":341},[203,508,509],{"class":213},"    colorSpace: {default: ",[203,511,512],{"class":220},"'oklch'",[203,514,515],{"class":213},", transform: transformColorSpace, compileTime: ",[203,517,518],{"class":240},"true",[203,520,521],{"class":213},"},\n",[203,523,525],{"class":205,"line":524},13,[203,526,331],{"class":213},[203,528,530,533,535],{"class":205,"line":529},14,[203,531,532],{"class":213},"  paint: ",[203,534,369],{"class":247},[203,536,537],{"class":213},"(\n",[203,539,541,544,547,550,552,555,558,561,563,565,568,571,573],{"class":205,"line":540},15,[203,542,543],{"class":213},"    dist.",[203,545,546],{"class":247},"linear",[203,548,549],{"class":213},"({from: ",[203,551,139],{"class":247},[203,553,554],{"class":213},"(",[203,556,557],{"class":220},"'from'",[203,559,560],{"class":213},"), to: ",[203,562,139],{"class":247},[203,564,554],{"class":213},[203,566,567],{"class":220},"'to'",[203,569,570],{"class":213},"), angle: ",[203,572,278],{"class":240},[203,574,575],{"class":213},"}),\n",[203,577,579,582,584,586,588,591,594,596,598,601,603,605,607,610],{"class":205,"line":578},16,[203,580,581],{"class":247},"    pair",[203,583,554],{"class":213},[203,585,139],{"class":247},[203,587,554],{"class":213},[203,589,590],{"class":220},"'colorA'",[203,592,593],{"class":213},"), ",[203,595,139],{"class":247},[203,597,554],{"class":213},[203,599,600],{"class":220},"'colorB'",[203,602,593],{"class":213},[203,604,139],{"class":247},[203,606,554],{"class":213},[203,608,609],{"class":220},"'colorSpace'",[203,611,612],{"class":213},")),\n",[203,614,616],{"class":205,"line":615},17,[203,617,618],{"class":213},"  ),\n",[203,620,622],{"class":205,"line":621},18,[203,623,344],{"class":213},[139,625,626,627,629,630,633,634,629,636,639,640,642,643,646],{},"That's the whole component. For a radial gradient, swap ",[10,628,361],{}," for ",[10,631,632],{},"dist.radial",", which takes a center and radius instead of two points. For more than two colors, swap ",[10,635,365],{},[10,637,638],{},"stops",", which reads a ",[10,641,638],{}," prop declared with ",[10,644,645],{},"colorStopsPropConfig()",".",[139,648,649,652,653,655],{},[152,650,651],{},"3. Pick the field that matches what you're making."," This example uses ",[10,654,384],{},", which draws from nothing. The other options:",[657,658,659,668,676],"ul",{},[660,661,662,667],"li",{},[152,663,664],{},[10,665,666],{},"effect:",": filters the layer nested inside it.",[660,669,670,675],{},[152,671,672],{},[10,673,674],{},"map:",": distorts the layer nested inside it.",[660,677,678,683],{},[152,679,680],{},[10,681,682],{},"shape:",": draws a 2D shape.",[139,685,686],{},"A definition uses exactly one of these.",[139,688,689,690,694],{},"To find a specific word, use the ",[691,692,693],"a",{"href":165},"primitives reference",". It's grouped by what you're trying to make, and each word shows an example of where it goes.",[157,696,698],{"id":697},"using-your-component","Using your component",[139,700,701,702,705,706,709,710,713,714,418,717,720,721,724],{},"Pass the definition to ",[10,703,704],{},"CustomShader"," from your framework's package. Your props become normal attributes, so ",[10,707,708],{},"colorA=\"#fff\""," sets the ",[10,711,712],{},"colorA"," prop from the example above. The layer props every component has, like ",[10,715,716],{},"blendMode",[10,718,719],{},"opacity"," and ",[10,722,723],{},"maskSource",", work the same as everywhere else.",[139,726,727,728,731,732,735],{},"Here ",[10,729,730],{},"MyGradient"," sits inside a ",[10,733,734],{},"\u003CBlur>",":",[737,738,740,888,986,1083,1173],"code-group",{":tabs":739},"[\"Vue\", \"React\", \"Svelte\", \"Solid\", \"JS\"]",[194,741,745],{"className":742,"code":743,"language":744,"meta":199,"style":199},"language-vue-html shiki shiki-themes github-dark","\u003Cscript setup>\nimport {Shader, CustomShader, Blur} from 'shaders\u002Fvue'\nimport {MyGradient} from '.\u002Fmy-gradient'\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003CShader>\n    \u003CBlur :intensity=\"8\">\n      \u003CCustomShader :src=\"MyGradient\" color-a=\"#ffffff\" \u002F>\n    \u003C\u002FBlur>\n  \u003C\u002FShader>\n\u003C\u002Ftemplate>\n","vue-html",[10,746,747,762,774,786,795,799,808,818,836,862,871,880],{"__ignoreMap":199},[203,748,749,752,756,759],{"class":205,"line":206},[203,750,751],{"class":213},"\u003C",[203,753,755],{"class":754},"s4JwU","script",[203,757,758],{"class":247}," setup",[203,760,761],{"class":213},">\n",[203,763,764,766,769,771],{"class":205,"line":224},[203,765,210],{"class":209},[203,767,768],{"class":213}," {Shader, CustomShader, Blur} ",[203,770,217],{"class":209},[203,772,773],{"class":220}," 'shaders\u002Fvue'\n",[203,775,776,778,781,783],{"class":205,"line":231},[203,777,210],{"class":209},[203,779,780],{"class":213}," {MyGradient} ",[203,782,217],{"class":209},[203,784,785],{"class":220}," '.\u002Fmy-gradient'\n",[203,787,788,791,793],{"class":205,"line":254},[203,789,790],{"class":213},"\u003C\u002F",[203,792,755],{"class":754},[203,794,761],{"class":213},[203,796,797],{"class":205,"line":266},[203,798,228],{"emptyLinePlaceholder":227},[203,800,801,803,806],{"class":205,"line":272},[203,802,751],{"class":213},[203,804,805],{"class":754},"template",[203,807,761],{"class":213},[203,809,810,813,816],{"class":205,"line":290},[203,811,812],{"class":213},"  \u003C",[203,814,815],{"class":754},"Shader",[203,817,761],{"class":213},[203,819,820,823,826,829,831,834],{"class":205,"line":305},[203,821,822],{"class":213},"    \u003C",[203,824,825],{"class":754},"Blur",[203,827,828],{"class":247}," :intensity",[203,830,431],{"class":213},[203,832,833],{"class":220},"\"8\"",[203,835,761],{"class":213},[203,837,838,841,843,846,848,851,854,856,859],{"class":205,"line":317},[203,839,840],{"class":213},"      \u003C",[203,842,704],{"class":754},[203,844,845],{"class":247}," :src",[203,847,431],{"class":213},[203,849,850],{"class":220},"\"MyGradient\"",[203,852,853],{"class":247}," color-a",[203,855,431],{"class":213},[203,857,858],{"class":220},"\"#ffffff\"",[203,860,861],{"class":213}," \u002F>\n",[203,863,864,867,869],{"class":205,"line":328},[203,865,866],{"class":213},"    \u003C\u002F",[203,868,825],{"class":754},[203,870,761],{"class":213},[203,872,873,876,878],{"class":205,"line":334},[203,874,875],{"class":213},"  \u003C\u002F",[203,877,815],{"class":754},[203,879,761],{"class":213},[203,881,882,884,886],{"class":205,"line":341},[203,883,790],{"class":213},[203,885,805],{"class":754},[203,887,761],{"class":213},[194,889,893],{"className":890,"code":891,"language":892,"meta":199,"style":199},"language-jsx shiki shiki-themes github-dark","import {Shader, CustomShader, Blur} from 'shaders\u002Freact'\nimport {MyGradient} from '.\u002Fmy-gradient'\n\n\u003CShader>\n  \u003CBlur intensity={8}>\n    \u003CCustomShader src={MyGradient} colorA=\"#ffffff\" \u002F>\n  \u003C\u002FBlur>\n\u003C\u002FShader>\n","jsx",[10,894,895,906,916,920,928,948,970,978],{"__ignoreMap":199},[203,896,897,899,901,903],{"class":205,"line":206},[203,898,210],{"class":209},[203,900,768],{"class":213},[203,902,217],{"class":209},[203,904,905],{"class":220}," 'shaders\u002Freact'\n",[203,907,908,910,912,914],{"class":205,"line":224},[203,909,210],{"class":209},[203,911,780],{"class":213},[203,913,217],{"class":209},[203,915,785],{"class":220},[203,917,918],{"class":205,"line":231},[203,919,228],{"emptyLinePlaceholder":227},[203,921,922,924,926],{"class":205,"line":254},[203,923,751],{"class":213},[203,925,815],{"class":240},[203,927,761],{"class":213},[203,929,930,932,934,937,939,942,945],{"class":205,"line":266},[203,931,812],{"class":213},[203,933,825],{"class":240},[203,935,936],{"class":247}," intensity",[203,938,431],{"class":209},[203,940,941],{"class":213},"{",[203,943,944],{"class":240},"8",[203,946,947],{"class":213},"}>\n",[203,949,950,952,954,957,959,962,964,966,968],{"class":205,"line":272},[203,951,822],{"class":213},[203,953,704],{"class":240},[203,955,956],{"class":247}," src",[203,958,431],{"class":209},[203,960,961],{"class":213},"{MyGradient} ",[203,963,712],{"class":247},[203,965,431],{"class":209},[203,967,858],{"class":220},[203,969,861],{"class":213},[203,971,972,974,976],{"class":205,"line":290},[203,973,875],{"class":213},[203,975,825],{"class":240},[203,977,761],{"class":213},[203,979,980,982,984],{"class":205,"line":305},[203,981,790],{"class":213},[203,983,815],{"class":240},[203,985,761],{"class":213},[194,987,991],{"className":988,"code":989,"language":990,"meta":199,"style":199},"language-tsx shiki shiki-themes github-dark","\u003Cscript>\n  import {Shader, CustomShader, Blur} from 'shaders\u002Fsvelte'\n  import {MyGradient} from '.\u002Fmy-gradient'\n\u003C\u002Fscript>\n\n\u003CShader>\n  \u003CBlur intensity={8}>\n    \u003CCustomShader src={MyGradient} colorA=\"#ffffff\" \u002F>\n  \u003C\u002FBlur>\n\u003C\u002FShader>\n","tsx",[10,992,993,1001,1006,1011,1019,1023,1031,1047,1067,1075],{"__ignoreMap":199},[203,994,995,997,999],{"class":205,"line":206},[203,996,751],{"class":213},[203,998,755],{"class":754},[203,1000,761],{"class":213},[203,1002,1003],{"class":205,"line":224},[203,1004,1005],{"class":213},"  import {Shader, CustomShader, Blur} from 'shaders\u002Fsvelte'\n",[203,1007,1008],{"class":205,"line":231},[203,1009,1010],{"class":213},"  import {MyGradient} from '.\u002Fmy-gradient'\n",[203,1012,1013,1015,1017],{"class":205,"line":254},[203,1014,790],{"class":213},[203,1016,755],{"class":754},[203,1018,761],{"class":213},[203,1020,1021],{"class":205,"line":266},[203,1022,228],{"emptyLinePlaceholder":227},[203,1024,1025,1027,1029],{"class":205,"line":272},[203,1026,751],{"class":213},[203,1028,815],{"class":240},[203,1030,761],{"class":213},[203,1032,1033,1035,1037,1039,1041,1043,1045],{"class":205,"line":290},[203,1034,812],{"class":213},[203,1036,825],{"class":240},[203,1038,936],{"class":247},[203,1040,431],{"class":209},[203,1042,941],{"class":213},[203,1044,944],{"class":240},[203,1046,947],{"class":213},[203,1048,1049,1051,1053,1055,1057,1059,1061,1063,1065],{"class":205,"line":305},[203,1050,822],{"class":213},[203,1052,704],{"class":240},[203,1054,956],{"class":247},[203,1056,431],{"class":209},[203,1058,961],{"class":213},[203,1060,712],{"class":247},[203,1062,431],{"class":209},[203,1064,858],{"class":220},[203,1066,861],{"class":213},[203,1068,1069,1071,1073],{"class":205,"line":317},[203,1070,875],{"class":213},[203,1072,825],{"class":240},[203,1074,761],{"class":213},[203,1076,1077,1079,1081],{"class":205,"line":328},[203,1078,790],{"class":213},[203,1080,815],{"class":240},[203,1082,761],{"class":213},[194,1084,1086],{"className":988,"code":1085,"language":990,"meta":199,"style":199},"import {Shader, CustomShader, Blur} from 'shaders\u002Fsolid'\nimport {MyGradient} from '.\u002Fmy-gradient'\n\n\u003CShader>\n  \u003CBlur intensity={8}>\n    \u003CCustomShader src={MyGradient} colorA=\"#ffffff\" \u002F>\n  \u003C\u002FBlur>\n\u003C\u002FShader>\n",[10,1087,1088,1099,1109,1113,1121,1137,1157,1165],{"__ignoreMap":199},[203,1089,1090,1092,1094,1096],{"class":205,"line":206},[203,1091,210],{"class":209},[203,1093,768],{"class":213},[203,1095,217],{"class":209},[203,1097,1098],{"class":220}," 'shaders\u002Fsolid'\n",[203,1100,1101,1103,1105,1107],{"class":205,"line":224},[203,1102,210],{"class":209},[203,1104,780],{"class":213},[203,1106,217],{"class":209},[203,1108,785],{"class":220},[203,1110,1111],{"class":205,"line":231},[203,1112,228],{"emptyLinePlaceholder":227},[203,1114,1115,1117,1119],{"class":205,"line":254},[203,1116,751],{"class":213},[203,1118,815],{"class":240},[203,1120,761],{"class":213},[203,1122,1123,1125,1127,1129,1131,1133,1135],{"class":205,"line":266},[203,1124,812],{"class":213},[203,1126,825],{"class":240},[203,1128,936],{"class":247},[203,1130,431],{"class":209},[203,1132,941],{"class":213},[203,1134,944],{"class":240},[203,1136,947],{"class":213},[203,1138,1139,1141,1143,1145,1147,1149,1151,1153,1155],{"class":205,"line":272},[203,1140,822],{"class":213},[203,1142,704],{"class":240},[203,1144,956],{"class":247},[203,1146,431],{"class":209},[203,1148,961],{"class":213},[203,1150,712],{"class":247},[203,1152,431],{"class":209},[203,1154,858],{"class":220},[203,1156,861],{"class":213},[203,1158,1159,1161,1163],{"class":205,"line":290},[203,1160,875],{"class":213},[203,1162,825],{"class":240},[203,1164,761],{"class":213},[203,1166,1167,1169,1171],{"class":205,"line":305},[203,1168,790],{"class":213},[203,1170,815],{"class":240},[203,1172,761],{"class":213},[194,1174,1178],{"className":1175,"code":1176,"language":1177,"meta":199,"style":199},"language-javascript shiki shiki-themes github-dark","import {createShader} from 'shaders\u002Fjs'\nimport {MyGradient} from '.\u002Fmy-gradient'\n\n\u002F\u002F Preset JSON names components by `type`; pass yours so the name resolves\nawait createShader(document.querySelector('canvas'), {\n  components: [\n    {type: 'Blur', props: {intensity: 8}, children: [\n      {type: 'MyGradient', props: {colorA: '#ffffff'}},\n    ]},\n  ],\n}, {components: [MyGradient]})\n","javascript",[10,1179,1180,1192,1202,1206,1211,1233,1238,1254,1270,1275,1280],{"__ignoreMap":199},[203,1181,1182,1184,1187,1189],{"class":205,"line":206},[203,1183,210],{"class":209},[203,1185,1186],{"class":213}," {createShader} ",[203,1188,217],{"class":209},[203,1190,1191],{"class":220}," 'shaders\u002Fjs'\n",[203,1193,1194,1196,1198,1200],{"class":205,"line":224},[203,1195,210],{"class":209},[203,1197,780],{"class":213},[203,1199,217],{"class":209},[203,1201,785],{"class":220},[203,1203,1204],{"class":205,"line":231},[203,1205,228],{"emptyLinePlaceholder":227},[203,1207,1208],{"class":205,"line":254},[203,1209,1210],{"class":337},"\u002F\u002F Preset JSON names components by `type`; pass yours so the name resolves\n",[203,1212,1213,1216,1219,1222,1225,1227,1230],{"class":205,"line":266},[203,1214,1215],{"class":209},"await",[203,1217,1218],{"class":247}," createShader",[203,1220,1221],{"class":213},"(document.",[203,1223,1224],{"class":247},"querySelector",[203,1226,554],{"class":213},[203,1228,1229],{"class":220},"'canvas'",[203,1231,1232],{"class":213},"), {\n",[203,1234,1235],{"class":205,"line":272},[203,1236,1237],{"class":213},"  components: [\n",[203,1239,1240,1243,1246,1249,1251],{"class":205,"line":290},[203,1241,1242],{"class":213},"    {type: ",[203,1244,1245],{"class":220},"'Blur'",[203,1247,1248],{"class":213},", props: {intensity: ",[203,1250,944],{"class":240},[203,1252,1253],{"class":213},"}, children: [\n",[203,1255,1256,1259,1261,1264,1267],{"class":205,"line":305},[203,1257,1258],{"class":213},"      {type: ",[203,1260,260],{"class":220},[203,1262,1263],{"class":213},", props: {colorA: ",[203,1265,1266],{"class":220},"'#ffffff'",[203,1268,1269],{"class":213},"}},\n",[203,1271,1272],{"class":205,"line":317},[203,1273,1274],{"class":213},"    ]},\n",[203,1276,1277],{"class":205,"line":328},[203,1278,1279],{"class":213},"  ],\n",[203,1281,1282],{"class":205,"line":334},[203,1283,1284],{"class":213},"}, {components: [MyGradient]})\n",[139,1286,1287,1288,1291,1292,1295],{},"To refer to your component by name in preset JSON without passing the definition each time, call ",[10,1289,1290],{},"registerShader(MyGradient)"," once when your app starts. After that, ",[10,1293,1294],{},"type: 'MyGradient'"," resolves.",[157,1297,1299],{"id":1298},"configuring-props","Configuring props",[139,1301,1302],{},"Each prop takes a few optional settings:",[657,1304,1305,1323,1331],{},[660,1306,1307,1311,1312,1315,1316,1319,1320,646],{},[152,1308,1309],{},[10,1310,187],{},": numbers and booleans don't need one. Colors use ",[10,1313,1314],{},"transformColor",", points use ",[10,1317,1318],{},"transformPosition",", and a color space name uses ",[10,1321,1322],{},"transformColorSpace",[660,1324,1325,1330],{},[152,1326,1327],{},[10,1328,1329],{},"compileTime: true",": recompiles the effect whenever the prop changes. Use it for a structural choice like a color space, not for anything someone drags, because each change rebuilds the effect.",[660,1332,1333,1338,1339,418,1342,418,1345,1348,1349,646],{},[152,1334,1335],{},[10,1336,1337],{},"ui",": tells an editor which control to show, for example ",[10,1340,1341],{},"{type: 'range', min: 0, max: 1, step: 0.01}",[10,1343,1344],{},"{type: 'color'}",[10,1346,1347],{},"{type: 'position'}"," or ",[10,1350,1351],{},"{type: 'select', options}",[139,1353,1354,1355,418,1357,418,1359,1348,1361,1364,1365,1367],{},"A prop can't share a name with a layer prop every component already has, such as ",[10,1356,719],{},[10,1358,716],{},[10,1360,187],{},[10,1362,1363],{},"children",". The component would consume it first, so ",[10,1366,146],{}," throws and names the prop.",[157,1369,1371],{"id":1370},"writing-wgsl-by-hand","Writing WGSL by hand",[139,1373,1374,1377,1378,1381],{},[152,1375,1376],{},"WGSL"," is the language WebGPU runs on the GPU. Build with primitives where you can. When the word you need doesn't exist yet, write the pixel math yourself in a ",[10,1379,1380],{},"wgsl"," body. Unlike the primitives, this path is stable, and it sits on the definition alongside everything else.",[139,1383,1384,1385,1388,1389,418,1392,418,1395,418,1398,720,1401,646],{},"A body is the inside of one WGSL function that returns a ",[10,1386,1387],{},"vec4f"," color. You don't declare anything: your props are available by name, and so are ",[10,1390,1391],{},"uv",[10,1393,1394],{},"time",[10,1396,1397],{},"aspect",[10,1399,1400],{},"viewport",[10,1402,1403],{},"pointer",[139,1405,1406],{},"This generator draws an animated ring:",[194,1408,1410],{"className":196,"code":1409,"language":198,"meta":199,"style":199},"import {defineShader, wgsl, transformColor, transformPosition} from 'shaders\u002Fstd'\n\nexport const Halo = defineShader({\n  name: 'Halo',\n  animatedTime: {speed: 'speed'},\n  props: {\n    color: {default: '#ffd166', transform: transformColor},\n    center: {default: {x: 0.5, y: 0.5}, transform: transformPosition},\n    radius: {default: 0.6},\n    speed: {default: 1},\n  },\n  paint: wgsl`\n    let d = length((uv - center) * vec2f(aspect, 1.0)) \u002F radius;\n    let ring = 0.5 + 0.5 * cos(d * 24.0 - time * 2.0);\n    return vec4f(color.rgb, ring * (1.0 - smoothstep(0.7, 1.0, d)));\n  `,\n})\n",[10,1411,1412,1423,1427,1442,1451,1461,1465,1475,1488,1498,1507,1511,1520,1525,1530,1535,1542],{"__ignoreMap":199},[203,1413,1414,1416,1419,1421],{"class":205,"line":206},[203,1415,210],{"class":209},[203,1417,1418],{"class":213}," {defineShader, wgsl, transformColor, transformPosition} ",[203,1420,217],{"class":209},[203,1422,221],{"class":220},[203,1424,1425],{"class":205,"line":224},[203,1426,228],{"emptyLinePlaceholder":227},[203,1428,1429,1431,1433,1436,1438,1440],{"class":205,"line":231},[203,1430,234],{"class":209},[203,1432,237],{"class":209},[203,1434,1435],{"class":240}," Halo",[203,1437,244],{"class":209},[203,1439,248],{"class":247},[203,1441,251],{"class":213},[203,1443,1444,1446,1449],{"class":205,"line":254},[203,1445,257],{"class":213},[203,1447,1448],{"class":220},"'Halo'",[203,1450,263],{"class":213},[203,1452,1453,1456,1459],{"class":205,"line":266},[203,1454,1455],{"class":213},"  animatedTime: {speed: ",[203,1457,1458],{"class":220},"'speed'",[203,1460,521],{"class":213},[203,1462,1463],{"class":205,"line":272},[203,1464,269],{"class":213},[203,1466,1467,1470,1473],{"class":205,"line":290},[203,1468,1469],{"class":213},"    color: {default: ",[203,1471,1472],{"class":220},"'#ffd166'",[203,1474,314],{"class":213},[203,1476,1477,1480,1482,1484,1486],{"class":205,"line":305},[203,1478,1479],{"class":213},"    center: {default: {x: ",[203,1481,284],{"class":240},[203,1483,281],{"class":213},[203,1485,284],{"class":240},[203,1487,287],{"class":213},[203,1489,1490,1493,1496],{"class":205,"line":317},[203,1491,1492],{"class":213},"    radius: {default: ",[203,1494,1495],{"class":240},"0.6",[203,1497,521],{"class":213},[203,1499,1500,1503,1505],{"class":205,"line":328},[203,1501,1502],{"class":213},"    speed: {default: ",[203,1504,296],{"class":240},[203,1506,521],{"class":213},[203,1508,1509],{"class":205,"line":334},[203,1510,331],{"class":213},[203,1512,1513,1515,1517],{"class":205,"line":341},[203,1514,532],{"class":213},[203,1516,1380],{"class":247},[203,1518,1519],{"class":220},"`\n",[203,1521,1522],{"class":205,"line":524},[203,1523,1524],{"class":220},"    let d = length((uv - center) * vec2f(aspect, 1.0)) \u002F radius;\n",[203,1526,1527],{"class":205,"line":529},[203,1528,1529],{"class":220},"    let ring = 0.5 + 0.5 * cos(d * 24.0 - time * 2.0);\n",[203,1531,1532],{"class":205,"line":540},[203,1533,1534],{"class":220},"    return vec4f(color.rgb, ring * (1.0 - smoothstep(0.7, 1.0, d)));\n",[203,1536,1537,1540],{"class":205,"line":578},[203,1538,1539],{"class":220},"  `",[203,1541,263],{"class":213},[203,1543,1544],{"class":205,"line":615},[203,1545,344],{"class":213},[139,1547,1548,1549,1551,1552,1555],{},"Inside an ",[10,1550,666],{},", the body can also read ",[10,1553,1554],{},"child",", the color of the nested layer at the current pixel:",[194,1557,1559],{"className":196,"code":1558,"language":198,"meta":199,"style":199},"export const Invert = defineShader({\n  name: 'Invert',\n  props: {amount: {default: 1}},\n  effect: wgsl`\n    return vec4f(mix(child.rgb, 1.0 - child.rgb, amount), child.a);\n  `,\n})\n",[10,1560,1561,1576,1585,1594,1603,1608,1614],{"__ignoreMap":199},[203,1562,1563,1565,1567,1570,1572,1574],{"class":205,"line":206},[203,1564,234],{"class":209},[203,1566,237],{"class":209},[203,1568,1569],{"class":240}," Invert",[203,1571,244],{"class":209},[203,1573,248],{"class":247},[203,1575,251],{"class":213},[203,1577,1578,1580,1583],{"class":205,"line":224},[203,1579,257],{"class":213},[203,1581,1582],{"class":220},"'Invert'",[203,1584,263],{"class":213},[203,1586,1587,1590,1592],{"class":205,"line":231},[203,1588,1589],{"class":213},"  props: {amount: {default: ",[203,1591,296],{"class":240},[203,1593,1269],{"class":213},[203,1595,1596,1599,1601],{"class":205,"line":254},[203,1597,1598],{"class":213},"  effect: ",[203,1600,1380],{"class":247},[203,1602,1519],{"class":220},[203,1604,1605],{"class":205,"line":266},[203,1606,1607],{"class":220},"    return vec4f(mix(child.rgb, 1.0 - child.rgb, amount), child.a);\n",[203,1609,1610,1612],{"class":205,"line":272},[203,1611,1539],{"class":220},[203,1613,263],{"class":213},[203,1615,1616],{"class":205,"line":290},[203,1617,344],{"class":213},[1619,1620,1622],"h3",{"id":1621},"what-a-body-receives","What a body receives",[657,1624,1625,1641,1655,1675,1691],{},[660,1626,1627,1630,1631,1633,1634,1637,1638,646],{},[152,1628,1629],{},"Types",": colors arrive as ",[10,1632,1387],{}," in linear RGB, positions as ",[10,1635,1636],{},"vec2f",", and numbers as ",[10,1639,1640],{},"f32",[660,1642,1643,1647,1648,1651,1652,1654],{},[152,1644,1645],{},[10,1646,1391],{},": runs 0–1 across the canvas, with ",[10,1649,1650],{},"y"," increasing downward. Multiply by ",[10,1653,1397],{}," to keep circles round.",[660,1656,1657,1661,1662,1665,1666,1669,1670,1672,1673,646],{},[152,1658,1659],{},[10,1660,1394],{},": the layer's own clock. Declare ",[10,1663,1664],{},"animatedTime: {speed: 'speed'}"," and add a ",[10,1667,1668],{},"speed"," prop, and setting ",[10,1671,1668],{}," slows the clock or stops it at ",[10,1674,278],{},[660,1676,1677,1680,1681,1684,1685,1688,1689,646],{},[152,1678,1679],{},"Neighbouring pixels",": a filter like a blur or a ripple samples ",[10,1682,1683],{},"childTexture"," with ",[10,1686,1687],{},"childSampler"," instead of reading ",[10,1690,1554],{},[660,1692,1693,1696],{},[152,1694,1695],{},"CPU-only props",": props that never reach the GPU, such as a URL string or a list, can't be used in a body.",[157,1698,1700],{"id":1699},"next-steps","Next steps",[657,1702,1703,1709,1716],{},[660,1704,1705,1708],{},[691,1706,1707],{"href":165},"Primitives reference",": every word, grouped by what you're trying to make.",[660,1710,1711,1715],{},[691,1712,1714],{"href":1713},"\u002Fdocs\u002Fprimitives\u002Fdefine","defineShader and wgsl",": the full definition contract.",[660,1717,1718,1724],{},[691,1719,1723],{"href":1720,"rel":1721},"https:\u002F\u002Fgithub.com\u002Fshader-effects-inc\u002Fshaders",[1722],"nofollow","Library source",": every library component, written as a definition like yours.",[1726,1727,1728],"style",{},"html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .s4JwU, html code.shiki .s4JwU{--shiki-default:#85E89D}",{"title":199,"searchDepth":224,"depth":224,"links":1730},[1731,1732,1733,1734,1737],{"id":159,"depth":224,"text":160},{"id":697,"depth":224,"text":698},{"id":1298,"depth":224,"text":1299},{"id":1370,"depth":224,"text":1371,"children":1735},[1736],{"id":1621,"depth":231,"text":1622},{"id":1699,"depth":224,"text":1700},"md","sparkles",{},{"title":61,"description":62},"docs\u002Fguide\u002F13.custom-shaders","eEDxyRjtKfcZk9Bxpe8Gf-tUvlIf0f96zAluY0VYPzQ"]