mirror of
https://github.com/bspeice/speice.io
synced 2024-12-22 16:48:10 -05:00
1 line
71 KiB
JavaScript
1 line
71 KiB
JavaScript
"use strict";(self.webpackChunkspeice_io=self.webpackChunkspeice_io||[]).push([["7618"],{43766:function(s,e,n){n.r(e),n.d(e,{metadata:()=>a,contentTitle:()=>E,default:()=>D,assets:()=>A,toc:()=>R,frontMatter:()=>C});var a=n("36613"),t=n("85893"),l=n("50065"),i=n("67"),r=n("87320"),m=n("67294"),c=n("1905"),h=n("42974"),o=n("37955"),d=n("5886");function p(s){let{paint:e,children:n}=s,{width:a,height:t,setPainter:l}=(0,m.useContext)(r.wn);return(0,m.useEffect)(()=>{l(function*(s){let{width:e,height:n,transforms:a,final:t,paint:l}=s,i=e*n,r=10*i,m=Array(i).fill(0),c=(s,a)=>{let[t,l]=(0,d.n)(s,a,e);if(t<0||t>=e||l<0||l>=n)return;let i=(0,d.j)(t,l,e,1);m[i]+=1},[p,x]=[(0,h.J)(),(0,h.J)()];for(let s=0;s<r;s++){let[i,r]=(0,o.m)(a);[p,x]=r(p,x);let[h,d]=t(p,x);s>20&&c(h,d),s%1e5==0&&(yield l(e,n,m))}yield l(e,n,m)}({width:a,height:t,transforms:c.y7,final:c.SV,paint:e}))},[a,t]),n}function x(s,e,n){let a=new ImageData(s,e),t=0;for(let s of n)t=Math.max(t,s);for(let s=0;s<n.length;s++){let e=4*s;a.data[e]=0,a.data[e+1]=0,a.data[e+2]=0;let l=n[s]/t*255;a.data[e+3]=l}return a}function j(s,e,n){let a=new ImageData(s,e),t=n.map(Math.log),l=-1/0;for(let s of t)l=Math.max(l,s);for(let s=0;s<n.length;s++){let e=4*s;a.data[e]=0,a.data[e+1]=0,a.data[e+2]=0;let n=t[s]/l*255;a.data[e+3]=n}return a}function g(s,e){let n=3*Math.floor(e*(s.length/3));return[s[n],s[n+1],s[n+2]]}function u(s,e,n){return s*(1-n)+e*n}function N(s,e,n,a,t,l){let i=s*e,r=new ImageData(s,e);for(let s=0;s<i;s++){let e=Math.log10(l[s])/(1.5*l[s]),i=4*s,m=n[s]*e*255;r.data[i]=m;let c=a[s]*e*255;r.data[i+1]=c;let h=t[s]*e*255;r.data[i+2]=h;let o=l[s]*e*255;r.data[i+3]=o}return r}var f=n("57037"),y=n("84239");let v=s=>{let{height:e,palette:n,children:a}=s,l=(0,m.useRef)(null),[i,r]=(0,m.useState)(0);(0,m.useEffect)(()=>{l&&r(l.current.offsetWidth)},[l]);let c=(0,m.useRef)(null),h=(0,m.useMemo)(()=>{if(0===i)return;let s=new ImageData(i,e);for(let a=0;a<i;a++){let[t,l,r]=g(n,a/i);for(let n=0;n<e;n++){let e=(0,d.j)(a,n,i,4);s.data[e]=255*t,s.data[e+1]=255*l,s.data[e+2]=255*r,s.data[e+3]=255}}return s},[i,e,n]);(0,m.useEffect)(()=>{c&&h&&c.current.getContext("2d").putImageData(h,0,0)},[c,h]);let o={filter:"dark"===(0,y.I)().colorMode?"invert(1)":""};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)("div",{ref:l,style:{width:"100%",height:e},children:i>0?(0,t.jsx)("canvas",{ref:c,width:i,height:e,style:o}):null}),a]})},w=s=>{let{title:e,palette:n,transformColor:a,setTransformColor:l,resetTransformColor:i,children:r}=s,m=(0,t.jsx)("button",{className:f.Z.inputReset,onClick:i,children:"Reset"}),[c,h,o]=g(n,a.color),d=`rgb(${Math.floor(255*c)},${Math.floor(255*h)},${Math.floor(255*o)})`,{colorMode:p}=(0,y.I)();return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)("div",{className:f.Z.inputGroup,style:{display:"grid",gridTemplateColumns:"2fr 2fr 1fr"},children:[(0,t.jsxs)("p",{className:f.Z.inputTitle,style:{gridColumn:"1/-1"},children:[e," ",m]}),(0,t.jsxs)("div",{className:f.Z.inputElement,children:[(0,t.jsxs)("p",{children:["Color: ",a.color]}),(0,t.jsx)("input",{type:"range",min:0,max:1,step:.001,value:a.color,onInput:s=>l({...a,color:Number(s.currentTarget.value)})})]}),(0,t.jsxs)("div",{className:f.Z.inputElement,children:[(0,t.jsxs)("p",{children:["Speed: ",a.colorSpeed]}),(0,t.jsx)("input",{type:"range",min:0,max:1,step:.001,value:a.colorSpeed,onInput:s=>l({...a,colorSpeed:Number(s.currentTarget.value)})})]}),(0,t.jsx)("div",{className:f.Z.inputElement,style:{width:"100%",height:"100%",backgroundColor:d,filter:"dark"===p?"invert(1)":""}})]}),r]})};function b(s){let{children:e}=s,{width:n,height:a,setPainter:l}=(0,m.useContext)(r.wn),i={color:c.N3,colorSpeed:.5},[p,x]=(0,m.useState)(i),j={color:c.yV,colorSpeed:.5},[u,f]=(0,m.useState)(j),y={color:c.iD,colorSpeed:.5},[b,C]=(0,m.useState)(y),E={color:c.sB,colorSpeed:0},[A,R]=(0,m.useState)(E);return(0,m.useEffect)(()=>{l(function*(s){let{width:e,height:n,transforms:a,final:t,palette:l,colors:i,finalColor:r}=s,m=e*n,c=Array(m).fill(0),p=Array(m).fill(0),x=Array(m).fill(0),j=Array(m).fill(0),u=(s,n,a)=>{let[t,i]=(0,d.n)(s,n,e);if(t<0||t>=e||i<0||i>=e)return;let r=(0,d.j)(t,i,e,1),[m,h,o]=g(l,a);c[r]+=m,p[r]+=h,x[r]+=o,j[r]+=1},[f,y]=[(0,h.J)(),(0,h.J)()],v=Math.random(),w=15*m;for(let s=0;s<w;s++){var b,C,E,A,R,B;let[l,m]=(0,o.m)(a);[f,y]=m(f,y);let h=i[l];b=v,C=h.color,v=b*(1-(E=h.colorSpeed))+C*E;let[d,g]=t(f,y);let w=(A=v,R=r.color,A*(1-(B=r.colorSpeed))+R*B);s>20&&u(d,g,w),s%1e5==0&&(yield N(e,n,c,p,x,j))}yield N(e,n,c,p,x,j)}({width:n,height:a,transforms:c.y7,final:c.SV,palette:c.DG,colors:[p,u,b],finalColor:A}))},[p,u,b,A]),(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(v,{height:40,palette:c.DG}),(0,t.jsx)(w,{title:"Transform 1",palette:c.DG,transformColor:p,setTransformColor:x,resetTransformColor:()=>x(i)}),(0,t.jsx)(w,{title:"Transform 2",palette:c.DG,transformColor:u,setTransformColor:f,resetTransformColor:()=>f(j)}),(0,t.jsx)(w,{title:"Transform 3",palette:c.DG,transformColor:b,setTransformColor:C,resetTransformColor:()=>C(y)}),(0,t.jsx)(w,{title:"Transform Final",palette:c.DG,transformColor:A,setTransformColor:R,resetTransformColor:()=>R(E)}),e]})}let C={slug:"2024/11/playing-with-fire-log-density",title:"Playing with fire: Tone mapping and color",date:new Date("2024-12-16T21:32:00.000Z"),authors:["bspeice"],tags:[]},E=void 0,A={authorsImageUrls:[void 0]},R=[{value:"Image histograms",id:"image-histograms",level:2},{value:"Tone mapping",id:"tone-mapping",level:2},{value:"Color",id:"color",level:2},{value:"Color coordinate",id:"color-coordinate",level:3},{value:"Color speed",id:"color-speed",level:3},{value:"Palette",id:"palette",level:3},{value:"Plotting",id:"plotting",level:3},{value:"Summary",id:"summary",level:2}];function B(s){let e={a:"a",admonition:"admonition",annotation:"annotation",blockquote:"blockquote",code:"code",em:"em",h2:"h2",h3:"h3",li:"li",math:"math",mi:"mi",mn:"mn",mo:"mo",mrow:"mrow",mspace:"mspace",mstyle:"mstyle",msub:"msub",mtable:"mtable",mtd:"mtd",mtext:"mtext",mtr:"mtr",p:"p",semantics:"semantics",span:"span",ul:"ul",...(0,l.a)(),...s.components},{Details:n}=e;return!n&&function(s,e){throw Error("Expected "+(e?"component":"object")+" `"+s+"` to be defined: you likely forgot to import, pass, or provide it.")}("Details",!0),(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)(e.p,{children:["So far, our ",(0,t.jsx)(e.code,{children:"plot()"})," function has been fairly simple: map a fractal flame coordinate to a specific pixel,\nand color in that pixel. This works well for simple function systems (like Sierpinski's Gasket),\nbut more complex systems (like the reference parameters) produce grainy images."]}),"\n",(0,t.jsx)(e.p,{children:"In this post, we'll refine the image quality and add color to really make things shine."}),"\n",(0,t.jsx)(e.h2,{id:"image-histograms",children:"Image histograms"}),"\n",(0,t.jsx)(e.admonition,{type:"note",children:(0,t.jsx)(e.p,{children:"This post covers sections 4 and 5 of the Fractal Flame Algorithm paper"})}),"\n",(0,t.jsx)(e.p,{children:'One problem with the current chaos game algorithm is that we waste work\nbecause pixels are either "on" (opaque) or "off" (transparent).\nIf the chaos game encounters the same pixel twice, nothing changes.'}),"\n",(0,t.jsx)(e.p,{children:'To demonstrate how much work is wasted, we\'ll count each time the chaos game\nvisits a pixel while iterating. This gives us a kind of image "histogram":'}),"\n","\n",(0,t.jsx)(i.Z,{language:"typescript",children:'// hidden-start\nimport { randomBiUnit } from "../src/randomBiUnit";\nimport { randomChoice } from "../src/randomChoice";\nimport { Props as ChaosGameFinalProps } from "../2-transforms/chaosGameFinal";\nimport { camera, histIndex } from "../src/camera";\n\nconst quality = 10;\nconst step = 100_000;\n// hidden-end\ntype Props = ChaosGameFinalProps & {\n paint: (\n width: number,\n height: number,\n histogram: number[]\n ) => ImageData;\n}\n\nexport function* chaosGameHistogram(\n {\n width,\n height,\n transforms,\n final,\n paint\n }: Props\n) {\n const pixels = width * height;\n const iterations = quality * pixels;\n\n // highlight-start\n const hist = Array<number>(pixels)\n .fill(0);\n\n const plotHist = (\n x: number,\n y: number\n ) => {\n const [pixelX, pixelY] =\n camera(x, y, width);\n\n if (\n pixelX < 0 ||\n pixelX >= width ||\n pixelY < 0 ||\n pixelY >= height\n )\n return;\n\n const hIndex =\n histIndex(pixelX, pixelY, width, 1);\n\n hist[hIndex] += 1;\n };\n // highlight-end\n\n let [x, y] = [\n randomBiUnit(),\n randomBiUnit()\n ];\n\n for (let i = 0; i < iterations; i++) {\n const [_, transform] =\n randomChoice(transforms);\n [x, y] = transform(x, y);\n const [finalX, finalY] = final(x, y);\n\n if (i > 20) {\n // highlight-start\n plotHist(finalX, finalY);\n // highlight-end\n }\n\n if (i % step === 0)\n yield paint(width, height, hist);\n }\n\n yield paint(width, height, hist);\n}'}),"\n",(0,t.jsx)(e.p,{children:'When the chaos game finishes, we find the pixel encountered most often.\nFinally, we "paint" the image by setting each pixel\'s alpha (transparency) value\nto the ratio of times visited divided by the maximum:'}),"\n","\n","\n",(0,t.jsx)(i.Z,{language:"typescript",children:"export function paintLinear(\n width: number,\n height: number,\n hist: number[]\n) {\n const img =\n new ImageData(width, height);\n\n let hMax = 0;\n for (let value of hist) {\n hMax = Math.max(hMax, value);\n }\n\n for (let i = 0; i < hist.length; i++) {\n const pixelIndex = i * 4;\n\n img.data[pixelIndex] = 0;\n img.data[pixelIndex + 1] = 0;\n img.data[pixelIndex + 2] = 0;\n\n const alpha = hist[i] / hMax * 0xff;\n img.data[pixelIndex + 3] = alpha;\n }\n\n return img;\n}"}),"\n","\n",(0,t.jsx)(r.ke,{children:(0,t.jsx)(p,{paint:x})}),"\n",(0,t.jsx)(e.h2,{id:"tone-mapping",children:"Tone mapping"}),"\n",(0,t.jsx)(e.p,{children:'While using a histogram reduces the "graining," it also leads to some parts vanishing entirely.\nIn the reference parameters, the outer circle is still there, but the interior is gone!'}),"\n",(0,t.jsxs)(e.p,{children:["To fix this, we'll introduce the second major innovation of the fractal flame algorithm: ",(0,t.jsx)(e.a,{href:"https://en.wikipedia.org/wiki/Tone_mapping",children:"tone mapping"}),".\nThis is a technique used in computer graphics to compensate for differences in how\ncomputers represent brightness, and how people actually see brightness."]}),"\n",(0,t.jsx)(e.p,{children:'As a concrete example, high-dynamic-range (HDR) photography uses this technique to capture\nscenes with a wide range of brightnesses. To take a picture of something dark,\nyou need a long exposure time. However, long exposures lead to "hot spots" (sections that are pure white).\nBy taking multiple pictures with different exposure times, we can combine them to create\na final image where everything is visible.'}),"\n",(0,t.jsxs)(e.p,{children:['In fractal flames, this "tone map" is accomplished by scaling brightness according to the ',(0,t.jsx)(e.em,{children:"logarithm"}),'\nof how many times we encounter a pixel. This way, "cold spots" (pixels the chaos game visits infrequently)\nare still visible, and "hot spots" (pixels the chaos game visits frequently) won\'t wash out.']}),"\n",(0,t.jsxs)(n,{children:[(0,t.jsx)("summary",{children:"Log-scale vibrancy also explains fractal flames appear to be 3D..."}),(0,t.jsx)(e.p,{children:"As mentioned in the paper:"}),(0,t.jsxs)(e.blockquote,{children:["\n",(0,t.jsx)(e.p,{children:"Where one branch of the fractal crosses another, one may appear to occlude the other\nif their densities are different enough because the lesser density is inconsequential in sum.\nFor example, branches of densities 1000 and 100 might have brightnesses of 30 and 20.\nWhere they cross the density is 1100, whose brightness is 30.4, which is\nhardly distinguishable from 30."}),"\n"]})]}),"\n","\n",(0,t.jsx)(i.Z,{language:"typescript",children:"export function paintLogarithmic(\n width: number,\n height: number,\n hist: number[]\n) {\n const img =\n new ImageData(width, height);\n\n const histLog = hist.map(Math.log);\n\n let hLogMax = -Infinity;\n for (let value of histLog) {\n hLogMax = Math.max(hLogMax, value);\n }\n\n for (let i = 0; i < hist.length; i++) {\n const pixelIndex = i * 4;\n\n img.data[pixelIndex] = 0; // red\n img.data[pixelIndex + 1] = 0; // green\n img.data[pixelIndex + 2] = 0; // blue\n\n const alpha =\n histLog[i] / hLogMax * 0xff;\n img.data[pixelIndex + 3] = alpha;\n }\n\n return img;\n}"}),"\n","\n",(0,t.jsx)(r.ke,{children:(0,t.jsx)(p,{paint:j})}),"\n",(0,t.jsx)(e.h2,{id:"color",children:"Color"}),"\n",(0,t.jsxs)(e.p,{children:["Now we'll introduce the last innovation of the fractal flame algorithm: color.\nBy including a third coordinate (",(0,t.jsxs)(e.span,{className:"katex",children:[(0,t.jsx)(e.span,{className:"katex-mathml",children:(0,t.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,t.jsxs)(e.semantics,{children:[(0,t.jsx)(e.mrow,{children:(0,t.jsx)(e.mi,{children:"c"})}),(0,t.jsx)(e.annotation,{encoding:"application/x-tex",children:"c"})]})})}),(0,t.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,t.jsxs)(e.span,{className:"base",children:[(0,t.jsx)(e.span,{className:"strut",style:{height:"0.4306em"}}),(0,t.jsx)(e.span,{className:"mord mathnormal",children:"c"})]})})]}),") in the chaos game, we can illustrate the transforms\nresponsible for the image."]}),"\n",(0,t.jsx)(e.h3,{id:"color-coordinate",children:"Color coordinate"}),"\n",(0,t.jsxs)(e.p,{children:["Color in a fractal flame is continuous on the range ",(0,t.jsxs)(e.span,{className:"katex",children:[(0,t.jsx)(e.span,{className:"katex-mathml",children:(0,t.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,t.jsxs)(e.semantics,{children:[(0,t.jsxs)(e.mrow,{children:[(0,t.jsx)(e.mo,{stretchy:"false",children:"["}),(0,t.jsx)(e.mn,{children:"0"}),(0,t.jsx)(e.mo,{separator:"true",children:","}),(0,t.jsx)(e.mn,{children:"1"}),(0,t.jsx)(e.mo,{stretchy:"false",children:"]"})]}),(0,t.jsx)(e.annotation,{encoding:"application/x-tex",children:"[0, 1]"})]})})}),(0,t.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,t.jsxs)(e.span,{className:"base",children:[(0,t.jsx)(e.span,{className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,t.jsx)(e.span,{className:"mopen",children:"["}),(0,t.jsx)(e.span,{className:"mord",children:"0"}),(0,t.jsx)(e.span,{className:"mpunct",children:","}),(0,t.jsx)(e.span,{className:"mspace",style:{marginRight:"0.1667em"}}),(0,t.jsx)(e.span,{className:"mord",children:"1"}),(0,t.jsx)(e.span,{className:"mclose",children:"]"})]})})]}),". This is important for two reasons:"]}),"\n",(0,t.jsxs)(e.ul,{children:["\n",(0,t.jsx)(e.li,{children:"It helps blend colors together in the final image. Slight changes in the color value lead to\nslight changes in the actual color"}),"\n",(0,t.jsx)(e.li,{children:"It allows us to swap in new color palettes easily. We're free to choose what actual colors\neach value represents"}),"\n"]}),"\n",(0,t.jsxs)(e.p,{children:["We'll give each transform a color value (",(0,t.jsxs)(e.span,{className:"katex",children:[(0,t.jsx)(e.span,{className:"katex-mathml",children:(0,t.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,t.jsxs)(e.semantics,{children:[(0,t.jsx)(e.mrow,{children:(0,t.jsxs)(e.msub,{children:[(0,t.jsx)(e.mi,{children:"c"}),(0,t.jsx)(e.mi,{children:"i"})]})}),(0,t.jsx)(e.annotation,{encoding:"application/x-tex",children:"c_i"})]})})}),(0,t.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,t.jsxs)(e.span,{className:"base",children:[(0,t.jsx)(e.span,{className:"strut",style:{height:"0.5806em",verticalAlign:"-0.15em"}}),(0,t.jsxs)(e.span,{className:"mord",children:[(0,t.jsx)(e.span,{className:"mord mathnormal",children:"c"}),(0,t.jsx)(e.span,{className:"msupsub",children:(0,t.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,t.jsxs)(e.span,{className:"vlist-r",children:[(0,t.jsx)(e.span,{className:"vlist",style:{height:"0.3117em"},children:(0,t.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"},children:[(0,t.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,t.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,t.jsx)(e.span,{className:"mord mathnormal mtight",children:"i"})})]})}),(0,t.jsx)(e.span,{className:"vlist-s",children:"\u200B"})]}),(0,t.jsx)(e.span,{className:"vlist-r",children:(0,t.jsx)(e.span,{className:"vlist",style:{height:"0.15em"},children:(0,t.jsx)(e.span,{})})})]})})]})]})})]}),") in the ",(0,t.jsxs)(e.span,{className:"katex",children:[(0,t.jsx)(e.span,{className:"katex-mathml",children:(0,t.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,t.jsxs)(e.semantics,{children:[(0,t.jsxs)(e.mrow,{children:[(0,t.jsx)(e.mo,{stretchy:"false",children:"["}),(0,t.jsx)(e.mn,{children:"0"}),(0,t.jsx)(e.mo,{separator:"true",children:","}),(0,t.jsx)(e.mn,{children:"1"}),(0,t.jsx)(e.mo,{stretchy:"false",children:"]"})]}),(0,t.jsx)(e.annotation,{encoding:"application/x-tex",children:"[0, 1]"})]})})}),(0,t.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,t.jsxs)(e.span,{className:"base",children:[(0,t.jsx)(e.span,{className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,t.jsx)(e.span,{className:"mopen",children:"["}),(0,t.jsx)(e.span,{className:"mord",children:"0"}),(0,t.jsx)(e.span,{className:"mpunct",children:","}),(0,t.jsx)(e.span,{className:"mspace",style:{marginRight:"0.1667em"}}),(0,t.jsx)(e.span,{className:"mord",children:"1"}),(0,t.jsx)(e.span,{className:"mclose",children:"]"})]})})]})," range.\nThe final transform gets a value too (",(0,t.jsxs)(e.span,{className:"katex",children:[(0,t.jsx)(e.span,{className:"katex-mathml",children:(0,t.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,t.jsxs)(e.semantics,{children:[(0,t.jsx)(e.mrow,{children:(0,t.jsxs)(e.msub,{children:[(0,t.jsx)(e.mi,{children:"c"}),(0,t.jsx)(e.mi,{children:"f"})]})}),(0,t.jsx)(e.annotation,{encoding:"application/x-tex",children:"c_f"})]})})}),(0,t.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,t.jsxs)(e.span,{className:"base",children:[(0,t.jsx)(e.span,{className:"strut",style:{height:"0.7167em",verticalAlign:"-0.2861em"}}),(0,t.jsxs)(e.span,{className:"mord",children:[(0,t.jsx)(e.span,{className:"mord mathnormal",children:"c"}),(0,t.jsx)(e.span,{className:"msupsub",children:(0,t.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,t.jsxs)(e.span,{className:"vlist-r",children:[(0,t.jsx)(e.span,{className:"vlist",style:{height:"0.3361em"},children:(0,t.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"},children:[(0,t.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,t.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,t.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.10764em"},children:"f"})})]})}),(0,t.jsx)(e.span,{className:"vlist-s",children:"\u200B"})]}),(0,t.jsx)(e.span,{className:"vlist-r",children:(0,t.jsx)(e.span,{className:"vlist",style:{height:"0.2861em"},children:(0,t.jsx)(e.span,{})})})]})})]})]})})]}),").\nThen, at each step in the chaos game, we'll set the current color\nby blending it with the previous color:"]}),"\n",(0,t.jsx)(e.span,{className:"katex-display",children:(0,t.jsxs)(e.span,{className:"katex",children:[(0,t.jsx)(e.span,{className:"katex-mathml",children:(0,t.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block",children:(0,t.jsxs)(e.semantics,{children:[(0,t.jsxs)(e.mtable,{rowspacing:"0.25em",columnalign:"right left",columnspacing:"0em",children:[(0,t.jsxs)(e.mtr,{children:[(0,t.jsx)(e.mtd,{children:(0,t.jsx)(e.mstyle,{scriptlevel:"0",displaystyle:"true",children:(0,t.jsx)(e.mrow,{})})}),(0,t.jsx)(e.mtd,{children:(0,t.jsx)(e.mstyle,{scriptlevel:"0",displaystyle:"true",children:(0,t.jsxs)(e.mrow,{children:[(0,t.jsx)(e.mrow,{}),(0,t.jsx)(e.mo,{stretchy:"false",children:"("}),(0,t.jsx)(e.mi,{children:"x"}),(0,t.jsx)(e.mo,{separator:"true",children:","}),(0,t.jsx)(e.mi,{children:"y"}),(0,t.jsx)(e.mo,{stretchy:"false",children:")"}),(0,t.jsx)(e.mo,{children:"="}),(0,t.jsx)(e.mtext,{children:"random\xa0point\xa0in\xa0the\xa0bi-unit\xa0square"})]})})})]}),(0,t.jsxs)(e.mtr,{children:[(0,t.jsx)(e.mtd,{children:(0,t.jsx)(e.mstyle,{scriptlevel:"0",displaystyle:"true",children:(0,t.jsx)(e.mrow,{})})}),(0,t.jsx)(e.mtd,{children:(0,t.jsx)(e.mstyle,{scriptlevel:"0",displaystyle:"true",children:(0,t.jsxs)(e.mrow,{children:[(0,t.jsx)(e.mrow,{}),(0,t.jsx)(e.mi,{children:"c"}),(0,t.jsx)(e.mo,{children:"="}),(0,t.jsx)(e.mtext,{children:"random\xa0point\xa0from\xa0[0,1]"})]})})})]}),(0,t.jsxs)(e.mtr,{children:[(0,t.jsx)(e.mtd,{children:(0,t.jsx)(e.mstyle,{scriptlevel:"0",displaystyle:"true",children:(0,t.jsx)(e.mrow,{})})}),(0,t.jsx)(e.mtd,{children:(0,t.jsx)(e.mstyle,{scriptlevel:"0",displaystyle:"true",children:(0,t.jsxs)(e.mrow,{children:[(0,t.jsx)(e.mrow,{}),(0,t.jsx)(e.mtext,{children:"iterate\xa0"}),(0,t.jsx)(e.mo,{stretchy:"false",children:"{"})]})})})]}),(0,t.jsxs)(e.mtr,{children:[(0,t.jsx)(e.mtd,{children:(0,t.jsx)(e.mstyle,{scriptlevel:"0",displaystyle:"true",children:(0,t.jsx)(e.mrow,{})})}),(0,t.jsx)(e.mtd,{children:(0,t.jsx)(e.mstyle,{scriptlevel:"0",displaystyle:"true",children:(0,t.jsxs)(e.mrow,{children:[(0,t.jsx)(e.mrow,{}),(0,t.jsx)(e.mspace,{width:"2.8453em"}),(0,t.jsx)(e.mi,{children:"i"}),(0,t.jsx)(e.mo,{children:"="}),(0,t.jsx)(e.mtext,{children:"random\xa0integer\xa0from\xa00\xa0to\xa0"}),(0,t.jsx)(e.mi,{children:"n"}),(0,t.jsx)(e.mo,{children:"\u2212"}),(0,t.jsx)(e.mn,{children:"1"})]})})})]}),(0,t.jsxs)(e.mtr,{children:[(0,t.jsx)(e.mtd,{children:(0,t.jsx)(e.mstyle,{scriptlevel:"0",displaystyle:"true",children:(0,t.jsx)(e.mrow,{})})}),(0,t.jsx)(e.mtd,{children:(0,t.jsx)(e.mstyle,{scriptlevel:"0",displaystyle:"true",children:(0,t.jsxs)(e.mrow,{children:[(0,t.jsx)(e.mrow,{}),(0,t.jsx)(e.mspace,{width:"2.8453em"}),(0,t.jsx)(e.mo,{stretchy:"false",children:"("}),(0,t.jsx)(e.mi,{children:"x"}),(0,t.jsx)(e.mo,{separator:"true",children:","}),(0,t.jsx)(e.mi,{children:"y"}),(0,t.jsx)(e.mo,{stretchy:"false",children:")"}),(0,t.jsx)(e.mo,{children:"="}),(0,t.jsxs)(e.msub,{children:[(0,t.jsx)(e.mi,{children:"F"}),(0,t.jsx)(e.mi,{children:"i"})]}),(0,t.jsx)(e.mo,{stretchy:"false",children:"("}),(0,t.jsx)(e.mi,{children:"x"}),(0,t.jsx)(e.mo,{separator:"true",children:","}),(0,t.jsx)(e.mi,{children:"y"}),(0,t.jsx)(e.mo,{stretchy:"false",children:")"})]})})})]}),(0,t.jsxs)(e.mtr,{children:[(0,t.jsx)(e.mtd,{children:(0,t.jsx)(e.mstyle,{scriptlevel:"0",displaystyle:"true",children:(0,t.jsx)(e.mrow,{})})}),(0,t.jsx)(e.mtd,{children:(0,t.jsx)(e.mstyle,{scriptlevel:"0",displaystyle:"true",children:(0,t.jsxs)(e.mrow,{children:[(0,t.jsx)(e.mrow,{}),(0,t.jsx)(e.mspace,{width:"2.8453em"}),(0,t.jsx)(e.mo,{stretchy:"false",children:"("}),(0,t.jsxs)(e.msub,{children:[(0,t.jsx)(e.mi,{children:"x"}),(0,t.jsx)(e.mi,{children:"f"})]}),(0,t.jsx)(e.mo,{separator:"true",children:","}),(0,t.jsxs)(e.msub,{children:[(0,t.jsx)(e.mi,{children:"y"}),(0,t.jsx)(e.mi,{children:"f"})]}),(0,t.jsx)(e.mo,{stretchy:"false",children:")"}),(0,t.jsx)(e.mo,{children:"="}),(0,t.jsxs)(e.msub,{children:[(0,t.jsx)(e.mi,{children:"F"}),(0,t.jsxs)(e.mrow,{children:[(0,t.jsx)(e.mi,{children:"f"}),(0,t.jsx)(e.mi,{children:"i"}),(0,t.jsx)(e.mi,{children:"n"}),(0,t.jsx)(e.mi,{children:"a"}),(0,t.jsx)(e.mi,{children:"l"})]})]}),(0,t.jsx)(e.mo,{stretchy:"false",children:"("}),(0,t.jsx)(e.mi,{children:"x"}),(0,t.jsx)(e.mo,{separator:"true",children:","}),(0,t.jsx)(e.mi,{children:"y"}),(0,t.jsx)(e.mo,{stretchy:"false",children:")"})]})})})]}),(0,t.jsxs)(e.mtr,{children:[(0,t.jsx)(e.mtd,{children:(0,t.jsx)(e.mstyle,{scriptlevel:"0",displaystyle:"true",children:(0,t.jsx)(e.mrow,{})})}),(0,t.jsx)(e.mtd,{children:(0,t.jsx)(e.mstyle,{scriptlevel:"0",displaystyle:"true",children:(0,t.jsxs)(e.mrow,{children:[(0,t.jsx)(e.mrow,{}),(0,t.jsx)(e.mspace,{width:"2.8453em"}),(0,t.jsx)(e.mi,{children:"c"}),(0,t.jsx)(e.mo,{children:"="}),(0,t.jsx)(e.mo,{stretchy:"false",children:"("}),(0,t.jsx)(e.mi,{children:"c"}),(0,t.jsx)(e.mo,{children:"+"}),(0,t.jsxs)(e.msub,{children:[(0,t.jsx)(e.mi,{children:"c"}),(0,t.jsx)(e.mi,{children:"i"})]}),(0,t.jsx)(e.mo,{stretchy:"false",children:")"}),(0,t.jsx)(e.mi,{mathvariant:"normal",children:"/"}),(0,t.jsx)(e.mn,{children:"2"})]})})})]}),(0,t.jsxs)(e.mtr,{children:[(0,t.jsx)(e.mtd,{children:(0,t.jsx)(e.mstyle,{scriptlevel:"0",displaystyle:"true",children:(0,t.jsx)(e.mrow,{})})}),(0,t.jsx)(e.mtd,{children:(0,t.jsx)(e.mstyle,{scriptlevel:"0",displaystyle:"true",children:(0,t.jsxs)(e.mrow,{children:[(0,t.jsx)(e.mrow,{}),(0,t.jsx)(e.mspace,{width:"2.8453em"}),(0,t.jsx)(e.mtext,{children:"plot"}),(0,t.jsx)(e.mo,{stretchy:"false",children:"("}),(0,t.jsxs)(e.msub,{children:[(0,t.jsx)(e.mi,{children:"x"}),(0,t.jsx)(e.mi,{children:"f"})]}),(0,t.jsx)(e.mo,{separator:"true",children:","}),(0,t.jsxs)(e.msub,{children:[(0,t.jsx)(e.mi,{children:"y"}),(0,t.jsx)(e.mi,{children:"f"})]}),(0,t.jsx)(e.mo,{separator:"true",children:","}),(0,t.jsxs)(e.msub,{children:[(0,t.jsx)(e.mi,{children:"c"}),(0,t.jsx)(e.mi,{children:"f"})]}),(0,t.jsx)(e.mo,{stretchy:"false",children:")"}),(0,t.jsx)(e.mtext,{children:"\xa0if\xa0iterations"}),(0,t.jsx)(e.mo,{children:">"}),(0,t.jsx)(e.mn,{children:"20"})]})})})]}),(0,t.jsx)(e.mtr,{children:(0,t.jsx)(e.mtd,{children:(0,t.jsx)(e.mstyle,{scriptlevel:"0",displaystyle:"true",children:(0,t.jsx)(e.mo,{stretchy:"false",lspace:"0em",rspace:"0em",children:"}"})})})})]}),(0,t.jsx)(e.annotation,{encoding:"application/x-tex",children:"\\begin{align*}\n&(x, y) = \\text{random point in the bi-unit square} \\\\\n&c = \\text{random point from [0,1]} \\\\\n&\\text{iterate } \\{ \\\\\n&\\hspace{1cm} i = \\text{random integer from 0 to } n - 1 \\\\\n&\\hspace{1cm} (x,y) = F_i(x,y) \\\\\n&\\hspace{1cm} (x_f,y_f) = F_{final}(x,y) \\\\\n&\\hspace{1cm} c = (c + c_i) / 2 \\\\\n&\\hspace{1cm} \\text{plot}(x_f,y_f,c_f) \\text{ if iterations} > 20 \\\\\n\\}\n\\end{align*}"})]})})}),(0,t.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,t.jsxs)(e.span,{className:"base",children:[(0,t.jsx)(e.span,{className:"strut",style:{height:"13.5em",verticalAlign:"-6.5em"}}),(0,t.jsx)(e.span,{className:"mord",children:(0,t.jsxs)(e.span,{className:"mtable",children:[(0,t.jsx)(e.span,{className:"col-align-r",children:(0,t.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,t.jsxs)(e.span,{className:"vlist-r",children:[(0,t.jsxs)(e.span,{className:"vlist",style:{height:"7em"},children:[(0,t.jsxs)(e.span,{style:{top:"-9.16em"},children:[(0,t.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,t.jsx)(e.span,{className:"mord"})]}),(0,t.jsxs)(e.span,{style:{top:"-7.66em"},children:[(0,t.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,t.jsx)(e.span,{className:"mord"})]}),(0,t.jsxs)(e.span,{style:{top:"-6.16em"},children:[(0,t.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,t.jsx)(e.span,{className:"mord"})]}),(0,t.jsxs)(e.span,{style:{top:"-4.66em"},children:[(0,t.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,t.jsx)(e.span,{className:"mord"})]}),(0,t.jsxs)(e.span,{style:{top:"-3.16em"},children:[(0,t.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,t.jsx)(e.span,{className:"mord"})]}),(0,t.jsxs)(e.span,{style:{top:"-1.66em"},children:[(0,t.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,t.jsx)(e.span,{className:"mord"})]}),(0,t.jsxs)(e.span,{style:{top:"-0.16em"},children:[(0,t.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,t.jsx)(e.span,{className:"mord"})]}),(0,t.jsxs)(e.span,{style:{top:"1.34em"},children:[(0,t.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,t.jsx)(e.span,{className:"mord"})]}),(0,t.jsxs)(e.span,{style:{top:"2.84em"},children:[(0,t.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,t.jsx)(e.span,{className:"mord",children:(0,t.jsx)(e.span,{className:"mclose",children:"}"})})]})]}),(0,t.jsx)(e.span,{className:"vlist-s",children:"\u200B"})]}),(0,t.jsx)(e.span,{className:"vlist-r",children:(0,t.jsx)(e.span,{className:"vlist",style:{height:"6.5em"},children:(0,t.jsx)(e.span,{})})})]})}),(0,t.jsx)(e.span,{className:"col-align-l",children:(0,t.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,t.jsxs)(e.span,{className:"vlist-r",children:[(0,t.jsxs)(e.span,{className:"vlist",style:{height:"7em"},children:[(0,t.jsxs)(e.span,{style:{top:"-9.16em"},children:[(0,t.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,t.jsxs)(e.span,{className:"mord",children:[(0,t.jsx)(e.span,{className:"mord"}),(0,t.jsx)(e.span,{className:"mopen",children:"("}),(0,t.jsx)(e.span,{className:"mord mathnormal",children:"x"}),(0,t.jsx)(e.span,{className:"mpunct",children:","}),(0,t.jsx)(e.span,{className:"mspace",style:{marginRight:"0.1667em"}}),(0,t.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.03588em"},children:"y"}),(0,t.jsx)(e.span,{className:"mclose",children:")"}),(0,t.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}}),(0,t.jsx)(e.span,{className:"mrel",children:"="}),(0,t.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}}),(0,t.jsx)(e.span,{className:"mord text",children:(0,t.jsx)(e.span,{className:"mord",children:"random\xa0point\xa0in\xa0the\xa0bi-unit\xa0square"})})]})]}),(0,t.jsxs)(e.span,{style:{top:"-7.66em"},children:[(0,t.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,t.jsxs)(e.span,{className:"mord",children:[(0,t.jsx)(e.span,{className:"mord"}),(0,t.jsx)(e.span,{className:"mord mathnormal",children:"c"}),(0,t.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}}),(0,t.jsx)(e.span,{className:"mrel",children:"="}),(0,t.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}}),(0,t.jsx)(e.span,{className:"mord text",children:(0,t.jsx)(e.span,{className:"mord",children:"random\xa0point\xa0from\xa0[0,1]"})})]})]}),(0,t.jsxs)(e.span,{style:{top:"-6.16em"},children:[(0,t.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,t.jsxs)(e.span,{className:"mord",children:[(0,t.jsx)(e.span,{className:"mord"}),(0,t.jsx)(e.span,{className:"mord text",children:(0,t.jsx)(e.span,{className:"mord",children:"iterate\xa0"})}),(0,t.jsx)(e.span,{className:"mopen",children:"{"})]})]}),(0,t.jsxs)(e.span,{style:{top:"-4.66em"},children:[(0,t.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,t.jsxs)(e.span,{className:"mord",children:[(0,t.jsx)(e.span,{className:"mord"}),(0,t.jsx)(e.span,{className:"mspace",style:{marginRight:"2.8453em"}}),(0,t.jsx)(e.span,{className:"mord mathnormal",children:"i"}),(0,t.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}}),(0,t.jsx)(e.span,{className:"mrel",children:"="}),(0,t.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}}),(0,t.jsx)(e.span,{className:"mord text",children:(0,t.jsx)(e.span,{className:"mord",children:"random\xa0integer\xa0from\xa00\xa0to\xa0"})}),(0,t.jsx)(e.span,{className:"mord mathnormal",children:"n"}),(0,t.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}}),(0,t.jsx)(e.span,{className:"mbin",children:"\u2212"}),(0,t.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}}),(0,t.jsx)(e.span,{className:"mord",children:"1"})]})]}),(0,t.jsxs)(e.span,{style:{top:"-3.16em"},children:[(0,t.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,t.jsxs)(e.span,{className:"mord",children:[(0,t.jsx)(e.span,{className:"mord"}),(0,t.jsx)(e.span,{className:"mspace",style:{marginRight:"2.8453em"}}),(0,t.jsx)(e.span,{className:"mopen",children:"("}),(0,t.jsx)(e.span,{className:"mord mathnormal",children:"x"}),(0,t.jsx)(e.span,{className:"mpunct",children:","}),(0,t.jsx)(e.span,{className:"mspace",style:{marginRight:"0.1667em"}}),(0,t.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.03588em"},children:"y"}),(0,t.jsx)(e.span,{className:"mclose",children:")"}),(0,t.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}}),(0,t.jsx)(e.span,{className:"mrel",children:"="}),(0,t.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}}),(0,t.jsxs)(e.span,{className:"mord",children:[(0,t.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.13889em"},children:"F"}),(0,t.jsx)(e.span,{className:"msupsub",children:(0,t.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,t.jsxs)(e.span,{className:"vlist-r",children:[(0,t.jsx)(e.span,{className:"vlist",style:{height:"0.3117em"},children:(0,t.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"-0.1389em",marginRight:"0.05em"},children:[(0,t.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,t.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,t.jsx)(e.span,{className:"mord mathnormal mtight",children:"i"})})]})}),(0,t.jsx)(e.span,{className:"vlist-s",children:"\u200B"})]}),(0,t.jsx)(e.span,{className:"vlist-r",children:(0,t.jsx)(e.span,{className:"vlist",style:{height:"0.15em"},children:(0,t.jsx)(e.span,{})})})]})})]}),(0,t.jsx)(e.span,{className:"mopen",children:"("}),(0,t.jsx)(e.span,{className:"mord mathnormal",children:"x"}),(0,t.jsx)(e.span,{className:"mpunct",children:","}),(0,t.jsx)(e.span,{className:"mspace",style:{marginRight:"0.1667em"}}),(0,t.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.03588em"},children:"y"}),(0,t.jsx)(e.span,{className:"mclose",children:")"})]})]}),(0,t.jsxs)(e.span,{style:{top:"-1.66em"},children:[(0,t.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,t.jsxs)(e.span,{className:"mord",children:[(0,t.jsx)(e.span,{className:"mord"}),(0,t.jsx)(e.span,{className:"mspace",style:{marginRight:"2.8453em"}}),(0,t.jsx)(e.span,{className:"mopen",children:"("}),(0,t.jsxs)(e.span,{className:"mord",children:[(0,t.jsx)(e.span,{className:"mord mathnormal",children:"x"}),(0,t.jsx)(e.span,{className:"msupsub",children:(0,t.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,t.jsxs)(e.span,{className:"vlist-r",children:[(0,t.jsx)(e.span,{className:"vlist",style:{height:"0.3361em"},children:(0,t.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"},children:[(0,t.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,t.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,t.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.10764em"},children:"f"})})]})}),(0,t.jsx)(e.span,{className:"vlist-s",children:"\u200B"})]}),(0,t.jsx)(e.span,{className:"vlist-r",children:(0,t.jsx)(e.span,{className:"vlist",style:{height:"0.2861em"},children:(0,t.jsx)(e.span,{})})})]})})]}),(0,t.jsx)(e.span,{className:"mpunct",children:","}),(0,t.jsx)(e.span,{className:"mspace",style:{marginRight:"0.1667em"}}),(0,t.jsxs)(e.span,{className:"mord",children:[(0,t.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.03588em"},children:"y"}),(0,t.jsx)(e.span,{className:"msupsub",children:(0,t.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,t.jsxs)(e.span,{className:"vlist-r",children:[(0,t.jsx)(e.span,{className:"vlist",style:{height:"0.3361em"},children:(0,t.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"-0.0359em",marginRight:"0.05em"},children:[(0,t.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,t.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,t.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.10764em"},children:"f"})})]})}),(0,t.jsx)(e.span,{className:"vlist-s",children:"\u200B"})]}),(0,t.jsx)(e.span,{className:"vlist-r",children:(0,t.jsx)(e.span,{className:"vlist",style:{height:"0.2861em"},children:(0,t.jsx)(e.span,{})})})]})})]}),(0,t.jsx)(e.span,{className:"mclose",children:")"}),(0,t.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}}),(0,t.jsx)(e.span,{className:"mrel",children:"="}),(0,t.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}}),(0,t.jsxs)(e.span,{className:"mord",children:[(0,t.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.13889em"},children:"F"}),(0,t.jsx)(e.span,{className:"msupsub",children:(0,t.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,t.jsxs)(e.span,{className:"vlist-r",children:[(0,t.jsx)(e.span,{className:"vlist",style:{height:"0.3361em"},children:(0,t.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"-0.1389em",marginRight:"0.05em"},children:[(0,t.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,t.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,t.jsxs)(e.span,{className:"mord mtight",children:[(0,t.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.10764em"},children:"f"}),(0,t.jsx)(e.span,{className:"mord mathnormal mtight",children:"ina"}),(0,t.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.01968em"},children:"l"})]})})]})}),(0,t.jsx)(e.span,{className:"vlist-s",children:"\u200B"})]}),(0,t.jsx)(e.span,{className:"vlist-r",children:(0,t.jsx)(e.span,{className:"vlist",style:{height:"0.2861em"},children:(0,t.jsx)(e.span,{})})})]})})]}),(0,t.jsx)(e.span,{className:"mopen",children:"("}),(0,t.jsx)(e.span,{className:"mord mathnormal",children:"x"}),(0,t.jsx)(e.span,{className:"mpunct",children:","}),(0,t.jsx)(e.span,{className:"mspace",style:{marginRight:"0.1667em"}}),(0,t.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.03588em"},children:"y"}),(0,t.jsx)(e.span,{className:"mclose",children:")"})]})]}),(0,t.jsxs)(e.span,{style:{top:"-0.16em"},children:[(0,t.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,t.jsxs)(e.span,{className:"mord",children:[(0,t.jsx)(e.span,{className:"mord"}),(0,t.jsx)(e.span,{className:"mspace",style:{marginRight:"2.8453em"}}),(0,t.jsx)(e.span,{className:"mord mathnormal",children:"c"}),(0,t.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}}),(0,t.jsx)(e.span,{className:"mrel",children:"="}),(0,t.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}}),(0,t.jsx)(e.span,{className:"mopen",children:"("}),(0,t.jsx)(e.span,{className:"mord mathnormal",children:"c"}),(0,t.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}}),(0,t.jsx)(e.span,{className:"mbin",children:"+"}),(0,t.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}}),(0,t.jsxs)(e.span,{className:"mord",children:[(0,t.jsx)(e.span,{className:"mord mathnormal",children:"c"}),(0,t.jsx)(e.span,{className:"msupsub",children:(0,t.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,t.jsxs)(e.span,{className:"vlist-r",children:[(0,t.jsx)(e.span,{className:"vlist",style:{height:"0.3117em"},children:(0,t.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"},children:[(0,t.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,t.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,t.jsx)(e.span,{className:"mord mathnormal mtight",children:"i"})})]})}),(0,t.jsx)(e.span,{className:"vlist-s",children:"\u200B"})]}),(0,t.jsx)(e.span,{className:"vlist-r",children:(0,t.jsx)(e.span,{className:"vlist",style:{height:"0.15em"},children:(0,t.jsx)(e.span,{})})})]})})]}),(0,t.jsx)(e.span,{className:"mclose",children:")"}),(0,t.jsx)(e.span,{className:"mord",children:"/2"})]})]}),(0,t.jsxs)(e.span,{style:{top:"1.34em"},children:[(0,t.jsx)(e.span,{className:"pstrut",style:{height:"3em"}}),(0,t.jsxs)(e.span,{className:"mord",children:[(0,t.jsx)(e.span,{className:"mord"}),(0,t.jsx)(e.span,{className:"mspace",style:{marginRight:"2.8453em"}}),(0,t.jsx)(e.span,{className:"mord text",children:(0,t.jsx)(e.span,{className:"mord",children:"plot"})}),(0,t.jsx)(e.span,{className:"mopen",children:"("}),(0,t.jsxs)(e.span,{className:"mord",children:[(0,t.jsx)(e.span,{className:"mord mathnormal",children:"x"}),(0,t.jsx)(e.span,{className:"msupsub",children:(0,t.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,t.jsxs)(e.span,{className:"vlist-r",children:[(0,t.jsx)(e.span,{className:"vlist",style:{height:"0.3361em"},children:(0,t.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"},children:[(0,t.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,t.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,t.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.10764em"},children:"f"})})]})}),(0,t.jsx)(e.span,{className:"vlist-s",children:"\u200B"})]}),(0,t.jsx)(e.span,{className:"vlist-r",children:(0,t.jsx)(e.span,{className:"vlist",style:{height:"0.2861em"},children:(0,t.jsx)(e.span,{})})})]})})]}),(0,t.jsx)(e.span,{className:"mpunct",children:","}),(0,t.jsx)(e.span,{className:"mspace",style:{marginRight:"0.1667em"}}),(0,t.jsxs)(e.span,{className:"mord",children:[(0,t.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.03588em"},children:"y"}),(0,t.jsx)(e.span,{className:"msupsub",children:(0,t.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,t.jsxs)(e.span,{className:"vlist-r",children:[(0,t.jsx)(e.span,{className:"vlist",style:{height:"0.3361em"},children:(0,t.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"-0.0359em",marginRight:"0.05em"},children:[(0,t.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,t.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,t.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.10764em"},children:"f"})})]})}),(0,t.jsx)(e.span,{className:"vlist-s",children:"\u200B"})]}),(0,t.jsx)(e.span,{className:"vlist-r",children:(0,t.jsx)(e.span,{className:"vlist",style:{height:"0.2861em"},children:(0,t.jsx)(e.span,{})})})]})})]}),(0,t.jsx)(e.span,{className:"mpunct",children:","}),(0,t.jsx)(e.span,{className:"mspace",style:{marginRight:"0.1667em"}}),(0,t.jsxs)(e.span,{className:"mord",children:[(0,t.jsx)(e.span,{className:"mord mathnormal",children:"c"}),(0,t.jsx)(e.span,{className:"msupsub",children:(0,t.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,t.jsxs)(e.span,{className:"vlist-r",children:[(0,t.jsx)(e.span,{className:"vlist",style:{height:"0.3361em"},children:(0,t.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"},children:[(0,t.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,t.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,t.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.10764em"},children:"f"})})]})}),(0,t.jsx)(e.span,{className:"vlist-s",children:"\u200B"})]}),(0,t.jsx)(e.span,{className:"vlist-r",children:(0,t.jsx)(e.span,{className:"vlist",style:{height:"0.2861em"},children:(0,t.jsx)(e.span,{})})})]})})]}),(0,t.jsx)(e.span,{className:"mclose",children:")"}),(0,t.jsx)(e.span,{className:"mord text",children:(0,t.jsx)(e.span,{className:"mord",children:"\xa0if\xa0iterations"})}),(0,t.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}}),(0,t.jsx)(e.span,{className:"mrel",children:">"}),(0,t.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}}),(0,t.jsx)(e.span,{className:"mord",children:"20"})]})]})]}),(0,t.jsx)(e.span,{className:"vlist-s",children:"\u200B"})]}),(0,t.jsx)(e.span,{className:"vlist-r",children:(0,t.jsx)(e.span,{className:"vlist",style:{height:"5em"},children:(0,t.jsx)(e.span,{})})})]})})]})})]})})]})}),"\n",(0,t.jsx)(e.h3,{id:"color-speed",children:"Color speed"}),"\n",(0,t.jsxs)(e.admonition,{type:"warning",children:[(0,t.jsx)(e.p,{children:"Color speed isn't introduced in the Fractal Flame Algorithm paper."}),(0,t.jsxs)(e.p,{children:["It is included here because ",(0,t.jsxs)(e.a,{href:"https://github.com/scottdraves/flam3/blob/7fb50c82e90e051f00efcc3123d0e06de26594b2/variations.c#L2140",children:[(0,t.jsx)(e.code,{children:"flam3"})," implements it"]}),",\nand because it's fun to play with."]})]}),"\n",(0,t.jsxs)(e.p,{children:['Next, we\'ll add a parameter to each transform that controls how much it changes the current color.\nThis is known as the "color speed" (',(0,t.jsxs)(e.span,{className:"katex",children:[(0,t.jsx)(e.span,{className:"katex-mathml",children:(0,t.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,t.jsxs)(e.semantics,{children:[(0,t.jsx)(e.mrow,{children:(0,t.jsxs)(e.msub,{children:[(0,t.jsx)(e.mi,{children:"s"}),(0,t.jsx)(e.mi,{children:"i"})]})}),(0,t.jsx)(e.annotation,{encoding:"application/x-tex",children:"s_i"})]})})}),(0,t.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,t.jsxs)(e.span,{className:"base",children:[(0,t.jsx)(e.span,{className:"strut",style:{height:"0.5806em",verticalAlign:"-0.15em"}}),(0,t.jsxs)(e.span,{className:"mord",children:[(0,t.jsx)(e.span,{className:"mord mathnormal",children:"s"}),(0,t.jsx)(e.span,{className:"msupsub",children:(0,t.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,t.jsxs)(e.span,{className:"vlist-r",children:[(0,t.jsx)(e.span,{className:"vlist",style:{height:"0.3117em"},children:(0,t.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"},children:[(0,t.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,t.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,t.jsx)(e.span,{className:"mord mathnormal mtight",children:"i"})})]})}),(0,t.jsx)(e.span,{className:"vlist-s",children:"\u200B"})]}),(0,t.jsx)(e.span,{className:"vlist-r",children:(0,t.jsx)(e.span,{className:"vlist",style:{height:"0.15em"},children:(0,t.jsx)(e.span,{})})})]})})]})]})})]}),"):"]}),"\n",(0,t.jsx)(e.span,{className:"katex-display",children:(0,t.jsxs)(e.span,{className:"katex",children:[(0,t.jsx)(e.span,{className:"katex-mathml",children:(0,t.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",display:"block",children:(0,t.jsxs)(e.semantics,{children:[(0,t.jsxs)(e.mrow,{children:[(0,t.jsx)(e.mi,{children:"c"}),(0,t.jsx)(e.mo,{children:"="}),(0,t.jsx)(e.mi,{children:"c"}),(0,t.jsx)(e.mo,{children:"\u22C5"}),(0,t.jsx)(e.mo,{stretchy:"false",children:"("}),(0,t.jsx)(e.mn,{children:"1"}),(0,t.jsx)(e.mo,{children:"\u2212"}),(0,t.jsxs)(e.msub,{children:[(0,t.jsx)(e.mi,{children:"s"}),(0,t.jsx)(e.mi,{children:"i"})]}),(0,t.jsx)(e.mo,{stretchy:"false",children:")"}),(0,t.jsx)(e.mo,{children:"+"}),(0,t.jsxs)(e.msub,{children:[(0,t.jsx)(e.mi,{children:"c"}),(0,t.jsx)(e.mi,{children:"i"})]}),(0,t.jsx)(e.mo,{children:"\u22C5"}),(0,t.jsxs)(e.msub,{children:[(0,t.jsx)(e.mi,{children:"s"}),(0,t.jsx)(e.mi,{children:"i"})]})]}),(0,t.jsx)(e.annotation,{encoding:"application/x-tex",children:"c = c \\cdot (1 - s_i) + c_i \\cdot s_i"})]})})}),(0,t.jsxs)(e.span,{className:"katex-html","aria-hidden":"true",children:[(0,t.jsxs)(e.span,{className:"base",children:[(0,t.jsx)(e.span,{className:"strut",style:{height:"0.4306em"}}),(0,t.jsx)(e.span,{className:"mord mathnormal",children:"c"}),(0,t.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}}),(0,t.jsx)(e.span,{className:"mrel",children:"="}),(0,t.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2778em"}})]}),(0,t.jsxs)(e.span,{className:"base",children:[(0,t.jsx)(e.span,{className:"strut",style:{height:"0.4445em"}}),(0,t.jsx)(e.span,{className:"mord mathnormal",children:"c"}),(0,t.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}}),(0,t.jsx)(e.span,{className:"mbin",children:"\u22C5"}),(0,t.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}})]}),(0,t.jsxs)(e.span,{className:"base",children:[(0,t.jsx)(e.span,{className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,t.jsx)(e.span,{className:"mopen",children:"("}),(0,t.jsx)(e.span,{className:"mord",children:"1"}),(0,t.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}}),(0,t.jsx)(e.span,{className:"mbin",children:"\u2212"}),(0,t.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}})]}),(0,t.jsxs)(e.span,{className:"base",children:[(0,t.jsx)(e.span,{className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,t.jsxs)(e.span,{className:"mord",children:[(0,t.jsx)(e.span,{className:"mord mathnormal",children:"s"}),(0,t.jsx)(e.span,{className:"msupsub",children:(0,t.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,t.jsxs)(e.span,{className:"vlist-r",children:[(0,t.jsx)(e.span,{className:"vlist",style:{height:"0.3117em"},children:(0,t.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"},children:[(0,t.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,t.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,t.jsx)(e.span,{className:"mord mathnormal mtight",children:"i"})})]})}),(0,t.jsx)(e.span,{className:"vlist-s",children:"\u200B"})]}),(0,t.jsx)(e.span,{className:"vlist-r",children:(0,t.jsx)(e.span,{className:"vlist",style:{height:"0.15em"},children:(0,t.jsx)(e.span,{})})})]})})]}),(0,t.jsx)(e.span,{className:"mclose",children:")"}),(0,t.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}}),(0,t.jsx)(e.span,{className:"mbin",children:"+"}),(0,t.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}})]}),(0,t.jsxs)(e.span,{className:"base",children:[(0,t.jsx)(e.span,{className:"strut",style:{height:"0.5945em",verticalAlign:"-0.15em"}}),(0,t.jsxs)(e.span,{className:"mord",children:[(0,t.jsx)(e.span,{className:"mord mathnormal",children:"c"}),(0,t.jsx)(e.span,{className:"msupsub",children:(0,t.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,t.jsxs)(e.span,{className:"vlist-r",children:[(0,t.jsx)(e.span,{className:"vlist",style:{height:"0.3117em"},children:(0,t.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"},children:[(0,t.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,t.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,t.jsx)(e.span,{className:"mord mathnormal mtight",children:"i"})})]})}),(0,t.jsx)(e.span,{className:"vlist-s",children:"\u200B"})]}),(0,t.jsx)(e.span,{className:"vlist-r",children:(0,t.jsx)(e.span,{className:"vlist",style:{height:"0.15em"},children:(0,t.jsx)(e.span,{})})})]})})]}),(0,t.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}}),(0,t.jsx)(e.span,{className:"mbin",children:"\u22C5"}),(0,t.jsx)(e.span,{className:"mspace",style:{marginRight:"0.2222em"}})]}),(0,t.jsxs)(e.span,{className:"base",children:[(0,t.jsx)(e.span,{className:"strut",style:{height:"0.5806em",verticalAlign:"-0.15em"}}),(0,t.jsxs)(e.span,{className:"mord",children:[(0,t.jsx)(e.span,{className:"mord mathnormal",children:"s"}),(0,t.jsx)(e.span,{className:"msupsub",children:(0,t.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,t.jsxs)(e.span,{className:"vlist-r",children:[(0,t.jsx)(e.span,{className:"vlist",style:{height:"0.3117em"},children:(0,t.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"},children:[(0,t.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,t.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,t.jsx)(e.span,{className:"mord mathnormal mtight",children:"i"})})]})}),(0,t.jsx)(e.span,{className:"vlist-s",children:"\u200B"})]}),(0,t.jsx)(e.span,{className:"vlist-r",children:(0,t.jsx)(e.span,{className:"vlist",style:{height:"0.15em"},children:(0,t.jsx)(e.span,{})})})]})})]})]})]})]})}),"\n","\n",(0,t.jsx)(i.Z,{language:"typescript",children:"export function mixColor(\n color1: number,\n color2: number,\n colorSpeed: number\n) {\n return color1 * (1 - colorSpeed) +\n color2 * colorSpeed;\n}"}),"\n",(0,t.jsx)(e.p,{children:"Color speed values work just like transform weights. A value of 1\nmeans we take the transform color and ignore the previous color state.\nA value of 0 means we keep the current color state and ignore the\ntransform color."}),"\n",(0,t.jsx)(e.h3,{id:"palette",children:"Palette"}),"\n",(0,t.jsx)(e.p,{children:"Now, we need to map the color coordinate to a pixel color. Fractal flames typically use\n256 colors (each color has 3 values - red, green, blue) to define a palette.\nThe color coordinate then becomes an index into the palette."}),"\n",(0,t.jsx)(e.p,{children:'There\'s one small complication: the color coordinate is continuous, but the palette\nuses discrete colors. How do we handle situations where the color coordinate is\n"in between" the colors of our palette?'}),"\n",(0,t.jsx)(e.p,{children:"One way to handle this is a step function. In the code below, we multiply the color coordinate\nby the number of colors in the palette, then truncate that value. This gives us a discrete index:"}),"\n","\n",(0,t.jsx)(i.Z,{language:"typescript",children:"export function colorFromPalette(\n palette: number[],\n colorIndex: number\n): [number, number, number] {\n const numColors = palette.length / 3;\n const paletteIndex = Math.floor(\n colorIndex * (numColors)\n ) * 3;\n return [\n palette[paletteIndex], // red\n palette[paletteIndex + 1], // green\n palette[paletteIndex + 2] // blue\n ];\n}"}),"\n",(0,t.jsxs)(n,{children:[(0,t.jsx)("summary",{children:"As an alternative..."}),(0,t.jsxs)(e.p,{children:["...you could interpolate between colors in the palette.\nFor example, ",(0,t.jsx)(e.code,{children:"flam3"})," uses ",(0,t.jsx)(e.a,{href:"https://github.com/scottdraves/flam3/blob/7fb50c82e90e051f00efcc3123d0e06de26594b2/rect.c#L483-L486",children:"linear interpolation"})]})]}),"\n",(0,t.jsx)(e.p,{children:"In the diagram below, each color in the palette is plotted on a small vertical strip.\nPutting the strips side by side shows the full palette used by the reference parameters:"}),"\n","\n",(0,t.jsx)(v,{height:"40",palette:c.DG}),"\n",(0,t.jsx)(e.h3,{id:"plotting",children:"Plotting"}),"\n",(0,t.jsxs)(e.p,{children:["We're now ready to plot our ",(0,t.jsxs)(e.span,{className:"katex",children:[(0,t.jsx)(e.span,{className:"katex-mathml",children:(0,t.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,t.jsxs)(e.semantics,{children:[(0,t.jsxs)(e.mrow,{children:[(0,t.jsx)(e.mo,{stretchy:"false",children:"("}),(0,t.jsxs)(e.msub,{children:[(0,t.jsx)(e.mi,{children:"x"}),(0,t.jsx)(e.mi,{children:"f"})]}),(0,t.jsx)(e.mo,{separator:"true",children:","}),(0,t.jsxs)(e.msub,{children:[(0,t.jsx)(e.mi,{children:"y"}),(0,t.jsx)(e.mi,{children:"f"})]}),(0,t.jsx)(e.mo,{separator:"true",children:","}),(0,t.jsxs)(e.msub,{children:[(0,t.jsx)(e.mi,{children:"c"}),(0,t.jsx)(e.mi,{children:"f"})]}),(0,t.jsx)(e.mo,{stretchy:"false",children:")"})]}),(0,t.jsx)(e.annotation,{encoding:"application/x-tex",children:"(x_f,y_f,c_f)"})]})})}),(0,t.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,t.jsxs)(e.span,{className:"base",children:[(0,t.jsx)(e.span,{className:"strut",style:{height:"1.0361em",verticalAlign:"-0.2861em"}}),(0,t.jsx)(e.span,{className:"mopen",children:"("}),(0,t.jsxs)(e.span,{className:"mord",children:[(0,t.jsx)(e.span,{className:"mord mathnormal",children:"x"}),(0,t.jsx)(e.span,{className:"msupsub",children:(0,t.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,t.jsxs)(e.span,{className:"vlist-r",children:[(0,t.jsx)(e.span,{className:"vlist",style:{height:"0.3361em"},children:(0,t.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"},children:[(0,t.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,t.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,t.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.10764em"},children:"f"})})]})}),(0,t.jsx)(e.span,{className:"vlist-s",children:"\u200B"})]}),(0,t.jsx)(e.span,{className:"vlist-r",children:(0,t.jsx)(e.span,{className:"vlist",style:{height:"0.2861em"},children:(0,t.jsx)(e.span,{})})})]})})]}),(0,t.jsx)(e.span,{className:"mpunct",children:","}),(0,t.jsx)(e.span,{className:"mspace",style:{marginRight:"0.1667em"}}),(0,t.jsxs)(e.span,{className:"mord",children:[(0,t.jsx)(e.span,{className:"mord mathnormal",style:{marginRight:"0.03588em"},children:"y"}),(0,t.jsx)(e.span,{className:"msupsub",children:(0,t.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,t.jsxs)(e.span,{className:"vlist-r",children:[(0,t.jsx)(e.span,{className:"vlist",style:{height:"0.3361em"},children:(0,t.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"-0.0359em",marginRight:"0.05em"},children:[(0,t.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,t.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,t.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.10764em"},children:"f"})})]})}),(0,t.jsx)(e.span,{className:"vlist-s",children:"\u200B"})]}),(0,t.jsx)(e.span,{className:"vlist-r",children:(0,t.jsx)(e.span,{className:"vlist",style:{height:"0.2861em"},children:(0,t.jsx)(e.span,{})})})]})})]}),(0,t.jsx)(e.span,{className:"mpunct",children:","}),(0,t.jsx)(e.span,{className:"mspace",style:{marginRight:"0.1667em"}}),(0,t.jsxs)(e.span,{className:"mord",children:[(0,t.jsx)(e.span,{className:"mord mathnormal",children:"c"}),(0,t.jsx)(e.span,{className:"msupsub",children:(0,t.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,t.jsxs)(e.span,{className:"vlist-r",children:[(0,t.jsx)(e.span,{className:"vlist",style:{height:"0.3361em"},children:(0,t.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"},children:[(0,t.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,t.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,t.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.10764em"},children:"f"})})]})}),(0,t.jsx)(e.span,{className:"vlist-s",children:"\u200B"})]}),(0,t.jsx)(e.span,{className:"vlist-r",children:(0,t.jsx)(e.span,{className:"vlist",style:{height:"0.2861em"},children:(0,t.jsx)(e.span,{})})})]})})]}),(0,t.jsx)(e.span,{className:"mclose",children:")"})]})})]})," coordinates. This time, we'll use a histogram\nfor each color channel (red, green, blue, alpha). After translating from color coordinate (",(0,t.jsxs)(e.span,{className:"katex",children:[(0,t.jsx)(e.span,{className:"katex-mathml",children:(0,t.jsx)(e.math,{xmlns:"http://www.w3.org/1998/Math/MathML",children:(0,t.jsxs)(e.semantics,{children:[(0,t.jsx)(e.mrow,{children:(0,t.jsxs)(e.msub,{children:[(0,t.jsx)(e.mi,{children:"c"}),(0,t.jsx)(e.mi,{children:"f"})]})}),(0,t.jsx)(e.annotation,{encoding:"application/x-tex",children:"c_f"})]})})}),(0,t.jsx)(e.span,{className:"katex-html","aria-hidden":"true",children:(0,t.jsxs)(e.span,{className:"base",children:[(0,t.jsx)(e.span,{className:"strut",style:{height:"0.7167em",verticalAlign:"-0.2861em"}}),(0,t.jsxs)(e.span,{className:"mord",children:[(0,t.jsx)(e.span,{className:"mord mathnormal",children:"c"}),(0,t.jsx)(e.span,{className:"msupsub",children:(0,t.jsxs)(e.span,{className:"vlist-t vlist-t2",children:[(0,t.jsxs)(e.span,{className:"vlist-r",children:[(0,t.jsx)(e.span,{className:"vlist",style:{height:"0.3361em"},children:(0,t.jsxs)(e.span,{style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"},children:[(0,t.jsx)(e.span,{className:"pstrut",style:{height:"2.7em"}}),(0,t.jsx)(e.span,{className:"sizing reset-size6 size3 mtight",children:(0,t.jsx)(e.span,{className:"mord mathnormal mtight",style:{marginRight:"0.10764em"},children:"f"})})]})}),(0,t.jsx)(e.span,{className:"vlist-s",children:"\u200B"})]}),(0,t.jsx)(e.span,{className:"vlist-r",children:(0,t.jsx)(e.span,{className:"vlist",style:{height:"0.2861em"},children:(0,t.jsx)(e.span,{})})})]})})]})]})})]}),")\nto RGB value, add that to the histogram:"]}),"\n","\n",(0,t.jsx)(i.Z,{language:"typescript",children:'// hidden-start\nimport { Props as ChaosGameFinalProps } from "../2-transforms/chaosGameFinal";\nimport { randomBiUnit } from "../src/randomBiUnit";\nimport { randomChoice } from "../src/randomChoice";\nimport { camera, histIndex } from "../src/camera";\nimport { colorFromPalette } from "./colorFromPalette";\nimport { mixColor } from "./mixColor";\nimport { paintColor } from "./paintColor";\n\nconst quality = 15;\nconst step = 100_000;\n// hidden-end\nexport type TransformColor = {\n color: number;\n colorSpeed: number;\n}\n\nexport type Props = ChaosGameFinalProps & {\n palette: number[];\n colors: TransformColor[];\n finalColor: TransformColor;\n}\n\nexport function* chaosGameColor(\n {\n width,\n height,\n transforms,\n final,\n palette,\n colors,\n finalColor\n }: Props\n) {\n const pixels = width * height;\n\n // highlight-start\n const imgRed = Array<number>(pixels)\n .fill(0);\n const imgGreen = Array<number>(pixels)\n .fill(0);\n const imgBlue = Array<number>(pixels)\n .fill(0);\n const imgAlpha = Array<number>(pixels)\n .fill(0);\n\n const plotColor = (\n x: number,\n y: number,\n c: number\n ) => {\n const [pixelX, pixelY] =\n camera(x, y, width);\n\n if (\n pixelX < 0 ||\n pixelX >= width ||\n pixelY < 0 ||\n pixelY >= width\n )\n return;\n\n const hIndex =\n histIndex(pixelX, pixelY, width, 1);\n\n const [r, g, b] =\n colorFromPalette(palette, c);\n\n imgRed[hIndex] += r;\n imgGreen[hIndex] += g;\n imgBlue[hIndex] += b;\n imgAlpha[hIndex] += 1;\n }\n // highlight-end\n\n let [x, y] = [\n randomBiUnit(),\n randomBiUnit()\n ];\n let c = Math.random();\n\n const iterations = quality * pixels;\n for (let i = 0; i < iterations; i++) {\n const [transformIndex, transform] =\n randomChoice(transforms);\n [x, y] = transform(x, y);\n\n // highlight-start\n const transformColor =\n colors[transformIndex];\n\n c = mixColor(\n c,\n transformColor.color,\n transformColor.colorSpeed\n );\n // highlight-end\n\n const [finalX, finalY] = final(x, y);\n\n // highlight-start\n const finalC = mixColor(\n c,\n finalColor.color,\n finalColor.colorSpeed\n );\n // highlight-end\n\n if (i > 20)\n plotColor(\n finalX,\n finalY,\n finalC\n )\n\n if (i % step === 0)\n yield paintColor(\n width,\n height,\n imgRed,\n imgGreen,\n imgBlue,\n imgAlpha\n );\n }\n\n yield paintColor(\n width,\n height,\n imgRed,\n imgGreen,\n imgBlue,\n imgAlpha\n );\n}'}),"\n",(0,t.jsx)(e.p,{children:"Finally, painting the image. With tone mapping, logarithms scale the image brightness to match\nhow it is perceived. With color, we use a similar method, but scale each color channel\nby the alpha channel:"}),"\n","\n",(0,t.jsx)(i.Z,{language:"typescript",children:"export function paintColor(\n width: number,\n height: number,\n red: number[],\n green: number[],\n blue: number[],\n alpha: number[]\n): ImageData {\n const pixels = width * height;\n const img =\n new ImageData(width, height);\n\n for (let i = 0; i < pixels; i++) {\n const scale =\n Math.log10(alpha[i]) /\n (alpha[i] * 1.5);\n\n const pixelIndex = i * 4;\n\n const rVal = red[i] * scale * 0xff;\n img.data[pixelIndex] = rVal;\n\n const gVal = green[i] * scale * 0xff;\n img.data[pixelIndex + 1] = gVal;\n\n const bVal = blue[i] * scale * 0xff;\n img.data[pixelIndex + 2] = bVal;\n\n const aVal = alpha[i] * scale * 0xff;\n img.data[pixelIndex + 3] = aVal;\n }\n\n return img;\n}"}),"\n",(0,t.jsx)(e.p,{children:"And now, at long last, a full-color fractal flame:"}),"\n","\n",(0,t.jsx)(r.ke,{children:(0,t.jsx)(b,{})}),"\n",(0,t.jsx)(e.h2,{id:"summary",children:"Summary"}),"\n",(0,t.jsx)(e.p,{children:'Tone mapping is the second major innovation of the fractal flame algorithm.\nBy tracking how often the chaos game encounters each pixel, we can adjust\nbrightness/transparency to reduce the visual "graining" of previous images.'}),"\n",(0,t.jsx)(e.p,{children:"Next, introducing a third coordinate to the chaos game makes color images possible,\nthe third major innovation of the fractal flame algorithm. Using a continuous\ncolor scale and color palette adds a splash of excitement to the image."}),"\n",(0,t.jsx)(e.p,{children:'The Fractal Flame Algorithm paper goes on to describe more techniques\nnot covered here. For example, image quality can be improved with density estimation\nand filtering. New parameters can be generated by "mutating" existing\nfractal flames. And fractal flames can even be animated to produce videos!'}),"\n",(0,t.jsx)(e.p,{children:"That said, I think this is a good place to wrap up. We went from\nan introduction to the mathematics of fractal systems all the way to\ngenerating full-color images. Fractal flames are a challenging topic,\nbut it's extremely rewarding to learn about how they work."})]})}function D(s={}){let{wrapper:e}={...(0,l.a)(),...s.components};return e?(0,t.jsx)(e,{...s,children:(0,t.jsx)(B,{...s})}):B(s)}},57037:function(s,e,n){n.d(e,{Z:function(){return a}});let a={inputGroup:"inputGroup_aXxM",inputTitle:"inputTitle_L5pB",inputElement:"inputElement_lfVV",inputReset:"inputReset_vh8n"}},87320:function(s,e,n){n.d(e,{ke:function(){return c},wn:function(){return i}});var a=n(85893),t=n(67294),l=n(84239);let i=(0,t.createContext)(null),r=s=>e=>{let n=document.createElement("a");n.download=`${s}.png`,n.href=e.target.toDataURL("image/png"),n.click()},m=s=>{let{name:e,style:n,children:m}=s,c=(0,t.useRef)(null),[h,o]=(0,t.useState)(0),[d,p]=(0,t.useState)(0);(0,t.useEffect)(()=>{c.current&&(o(c.current.offsetWidth),p(c.current.offsetHeight))},[c]);let x=(0,t.useRef)(null),[j,g]=(0,t.useState)(!1);(0,t.useEffect)(()=>{if(!x.current)return;let s=new IntersectionObserver(s=>{let[e]=s;e.isIntersecting&&g(!0)});return s.observe(x.current),()=>{x.current&&s.unobserve(x.current)}},[x.current]);let[u,N]=(0,t.useState)(null);(0,t.useEffect)(()=>{x.current&&u&&x.current.getContext("2d").putImageData(u[0],0,0)},[x,u]);let[f,y]=(0,t.useState)(null);(0,t.useEffect)(()=>{if(!j||!f)return;let s=f[0],e=s.next().value;e?(N([e]),y([s])):y(null)},[j,f]);let[v,w]=(0,t.useState)(null);(0,t.useEffect)(()=>{v&&y([v])},[v]);let b={ref:x,width:h,height:d,style:{filter:"dark"===(0,l.I)().colorMode?"invert(1)":""}};return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)("center",{children:(0,a.jsx)("div",{ref:c,style:n,children:h>0?(0,a.jsx)("canvas",{...b,onDoubleClick:r(e)}):null})}),(0,a.jsx)(i.Provider,{value:{width:h,height:d,setPainter:w},children:h>0?m:null})]})},c=s=>{let{name:e,style:n,children:t}=s;return(0,a.jsx)("center",{children:(0,a.jsx)(m,{name:e,style:{width:"75%",aspectRatio:"1/1",...n},children:t})})}},58611:function(s,e,n){n.d(e,{g:()=>l,N:()=>t});var a=n("86861");let t=(s,e)=>(n,t)=>(function(s,e,n){let[a,t]=[0,0];for(let[l,i]of n){let[n,r]=i(s,e);a+=l*n,t+=l*r}return[a,t]})(...(0,a.z)(n,t,s),e),l=(s,e)=>(n,t)=>(0,a.z)(...e(n,t),s)},5886:function(s,e,n){function a(s,e,n){return[Math.floor((s+2)*n/4),Math.floor((e+2)*n/4)]}function t(s,e,n,a){return n*a*e+s*a}n.d(e,{j:function(){return t},n:function(){return a}})},64814:function(s,e,n){n.d(e,{e:function(){return t}});let a=()=>Math.random()>.5?0:Math.PI,t=(s,e)=>{let n=Math.sqrt(Math.sqrt(Math.pow(s,2)+Math.pow(e,2))),t=Math.atan2(s,e)/2+a();return[n*Math.cos(t),n*Math.sin(t)]}},27729:function(s,e,n){n.d(e,{G:function(){return a}});let a=(s,e)=>[s,e]},1905:function(s,e,n){n.d(e,{DG:function(){return F},DO:function(){return j},EW:function(){return w},L4:function(){return A},N3:function(){return x},Qt:function(){return u},SV:function(){return k},Ue:function(){return d},Ux:function(){return E},ZU:function(){return b},aI:function(){return h},d3:function(){return v},fm:function(){return c},iD:function(){return C},kO:function(){return N},qR:function(){return y},rK:function(){return p},sB:function(){return B},v$:function(){return g},xN:function(){return o},y7:function(){return D},yV:function(){return f}});var a=n(27729),t=n(64814),l=n(62025),i=n(56089),r=n(58611);let m={a:1,b:0,c:0,d:0,e:1,f:0},c={a:1.09358,b:2.13048,c:2.54127,d:2.37267},h=.56453495,o={a:-1.381068,b:-1.381068,c:0,d:1.381068,e:-1.381068,f:0},d=m,p=[[1,t.e]],x=0,j=.013135,g={a:.031393,b:.031367,c:0,d:-.031367,e:.031393,f:0},u={a:1,b:0,c:.24,d:0,e:1,f:.27},N=[[1,a.G],[1,(0,l.X)(g)]],f=.844,y=.42233,v={a:1.51523,b:-3.048677,c:.724135,d:.740356,e:-1.455964,f:-.362059},w=m,b=[[1,(0,i.i)(c)]],C=.349,E={a:2,b:0,c:0,d:0,e:2,f:0},A=m,R=[[1,t.e]],B=0,D=[[h,(0,r.g)(d,(0,r.N)(o,p))],[j,(0,r.g)(u,(0,r.N)(g,N))],[y,(0,r.g)(w,(0,r.N)(v,b))]],k=(0,r.g)(A,(0,r.N)(E,R)),F=(function(s){let e=[];for(let n=0;n<s.length;n+=2)e.push(parseInt(s.substring(n,n+2),16));return e})("3130323635383B3A3D403F424644484B494D504E525653585B585D605D626562686B676D706C737571787B767D807B838580888A858D908A93958F989A949DA099A3A59EA8AAA3ADAFA8B3B5ADB8BAB2BEBFB7C3C5BCC8CAC1CECFC6D3D4CBD8DAD0DEDFD5E3DFD2E0DFCEDDE0CBDAE0C8D7E0C4D3E0C1D0E1BECDE1BBCAE1B7C7E1B4C4E1B1C1E2ADBEE2AABAE2A7B7E2A3B4E2A0B1E39DAEE399ABE396A8E393A5E490A1E48C9EE4899BE48698E48295E57F92E57C8FE5788CE57589E57285E66E82E66B7FE6687CE66479E76176E75E73E75B70E7576CE75469E85166E84D63E84A60E4495EE0485CDC475BD84659D44557D04455CB4353C74252C34150BF404EBB3F4CB73E4BB33D49AF3C47AB3B45A73A43A339429F38409B373E97363C92353A8E34398A33378632358231337E30327A2F30762E2E722D2C6E2C2A6A2B29662A276229255E282359272155262051251E4D241C49231A4522194121173D20153C1F153A1F14391E14381E14361D14351C13341C13321B13311B132F1A122E19122D19122B18122A181129171127161126161125151023151022141021140F1F130F1E120F1C120F1B110E1A110E18100E170F0E160F0D140E0D130E0D120D0D100C0C0F0C0C0E0B0C0C0B0C0B0A0B09090B08090B07080B05080A04070A0606090804090A03088C46728A457087446D85436B8243698042667D41647B4061793F5F763E5D743D5A713D586F3C566C3B536A3A5168394F65384C63374A6037485E36455B354359344057333E54323C5231394F31374D30354A2F32482E30462D2E432C2B412B293E2B273C2A2439292237281F35271D32261B3025182D25162B241428231126220F25210F24210E23200E221F0E221E0D211E0D201D0D1F1C0D1E1B0C1D1B0C1C1A0C1B190B1B180B1A180B19170A18160A17150A1615091514091413091413081312081211081110081010070F0F070E0E070D0D060C0D060C0C060B0B050A0A05090A050809040708040607040507040506030405030304030204020103020608070C0D0D1112121617171B1C1D2121222626272B2B2D").map(s=>s/255)},56089:function(s,e,n){n.d(e,{i:function(){return a}});let a=s=>{let{a:e,b:n,c:a,d:t}=s;return(s,l)=>[Math.sin(e*l)-Math.cos(n*s),Math.sin(a*s)-Math.cos(t*l)]}},62025:function(s,e,n){n.d(e,{X:function(){return a}});let a=s=>{let{c:e,f:n}=s;return(s,a)=>[s+e*Math.sin(Math.tan(3*a)),a+n*Math.sin(Math.tan(3*s))]}},42974:function(s,e,n){n.d(e,{J:function(){return a}});function a(){return 2*Math.random()-1}},37955:function(s,e,n){n.d(e,{m:function(){return a}});function a(s){let e=Math.random()*s.reduce((s,e)=>{let[n,a]=e;return s+n},0);for(let n of s.entries()){let[s,a]=n,[t,l]=a;if(e<t)return[s,l];e-=t}let n=s.length-1;return[n,s[n][1]]}},86861:function(s,e,n){n.d(e,{z:function(){return a}});function a(s,e,n){return[s*n.a+e*n.b+n.c,s*n.d+e*n.e+n.f]}},40653:function(s,e,n){n.d(e,{Z:()=>C});var a=n("85893");n("67294");var t=n("67026"),l=n("7227"),i=n("34550"),r=n("96025"),m=n("2933"),c=n("70144"),h=n("78720"),o=n("66856"),d=n("16893");let p="playgroundContainer_TGbA",x="playgroundHeader_qwyd",j="playgroundEditor_PvJ1",g="playgroundPreview_bb8I";function u(s){let{children:e}=s;return(0,a.jsx)("div",{className:(0,t.Z)(x),children:e})}function N(){return(0,a.jsx)("div",{children:"Loading..."})}function f(){return(0,a.jsx)(c.Z,{fallback:(0,a.jsx)(N,{}),children:()=>(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(d.Z,{fallback:s=>(0,a.jsx)(h.Ac,{...s}),children:(0,a.jsx)(i.i5,{})}),(0,a.jsx)(i.IF,{})]})})}function y(){return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(u,{children:(0,a.jsx)(r.Z,{id:"theme.Playground.result",description:"The result label of the live codeblocks",children:"Result"})}),(0,a.jsx)("div",{className:g,children:(0,a.jsx)(f,{})})]})}function v(){let s=(0,l.Z)();return(0,a.jsx)(i.uz,{className:j},String(s))}function w(){return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(u,{children:(0,a.jsx)(r.Z,{id:"theme.Playground.liveEditor",description:"The live editor label of the live codeblocks",children:"Live Editor"})}),(0,a.jsx)(v,{})]})}let b=s=>`${s};`;function C(s){let{children:e,transformCode:n,...t}=s,{siteConfig:{themeConfig:l}}=(0,m.Z)(),{liveCodeBlock:{playgroundPosition:r}}=l,c=(0,o.p)(),h=t.metastring?.includes("noInline")??!1;return(0,a.jsx)("div",{className:p,children:(0,a.jsx)(i.nu,{code:e?.replace(/\n$/,""),noInline:h,transformCode:n??b,theme:c,...t,children:"top"===r?(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(y,{}),(0,a.jsx)(w,{})]}):(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(w,{}),(0,a.jsx)(y,{})]})})})}},36613:function(s){s.exports=JSON.parse('{"permalink":"/2024/11/playing-with-fire-log-density","source":"@site/blog/2024-11-15-playing-with-fire/3-log-density/index.mdx","title":"Playing with fire: Tone mapping and color","description":"So far, our plot() function has been fairly simple: map a fractal flame coordinate to a specific pixel,","date":"2024-12-16T21:32:00.000Z","tags":[],"readingTime":6.245,"hasTruncateMarker":true,"authors":[{"name":"Bradlee Speice","socials":{"github":"https://github.com/bspeice"},"key":"bspeice","page":null}],"frontMatter":{"slug":"2024/11/playing-with-fire-log-density","title":"Playing with fire: Tone mapping and color","date":"2024-12-16T21:32:00.000Z","authors":["bspeice"],"tags":[]},"unlisted":false,"lastUpdatedAt":1734402605000,"nextItem":{"title":"Playing with fire: Transforms and variations","permalink":"/2024/11/playing-with-fire-transforms"}}')}}]); |