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