mirror of
https://github.com/bspeice/speice.io
synced 2025-01-03 06:19:36 -05:00
Start actually writing a post
This commit is contained in:
parent
582e03cff3
commit
1b4d190906
215
blog/2024-11-15-playing-with-fire/1-introduction.mdx
Normal file
215
blog/2024-11-15-playing-with-fire/1-introduction.mdx
Normal file
@ -0,0 +1,215 @@
|
||||
---
|
||||
slug: 2024/11/playing-with-fire
|
||||
title: "Playing with fire: Introduction"
|
||||
date: 2024-11-15 12:00:00
|
||||
authors: [bspeice]
|
||||
tags: []
|
||||
---
|
||||
|
||||
Wikipedia [describes](https://en.wikipedia.org/wiki/Fractal_flame) fractal flames as:
|
||||
|
||||
> a member of the iterated function system class of fractals
|
||||
|
||||
I think of them a different way: beauty in mathematics.
|
||||
|
||||
import isDarkMode from "@site/src/isDarkMode";
|
||||
import bannerDark from "./banner-dark.png"
|
||||
import bannerLight from "./banner-light.png"
|
||||
|
||||
<center>
|
||||
<!-- Why are these backwards? -->
|
||||
<img src={bannerLight} hidden={isDarkMode()}/>
|
||||
<img src={bannerDark} hidden={!isDarkMode()}/>
|
||||
</center>
|
||||
|
||||
<!-- truncate -->
|
||||
|
||||
I don't remember exactly when or how I originally came across fractal flames, but I do remember becoming entranced by the images they created.
|
||||
I also remember their unique appeal to my young engineering mind; this was an art form I could actively participate in.
|
||||
|
||||
The [paper](https://flam3.com/flame_draves.pdf) describing their mathematical structure was too much
|
||||
for me to handle at the time (I was ~12 years old), and I was content to play around and enjoy the pictures.
|
||||
But the desire to understand it stuck with me, so I wanted to try again. With a graduate degree in Financial Engineering under my belt,
|
||||
maybe it would be easier this time.
|
||||
|
||||
---
|
||||
|
||||
## Iterated function systems
|
||||
|
||||
Let's begin by defining an "[iterated function system](https://en.wikipedia.org/wiki/Iterated_function_system)" (IFS).
|
||||
We'll start at the end and work backwards to build a practical understanding. In mathematical notation, an IFS is:
|
||||
|
||||
$$
|
||||
S = \bigcup_{i=0}^{n-1} F_i(S) \\[0.6cm]
|
||||
S \in \mathbb{R}^2 \\
|
||||
F_i(S) \in \mathbb{R}^2 \rightarrow \mathbb{R}^2
|
||||
$$
|
||||
|
||||
### Stationary point
|
||||
|
||||
First, $S$. We're generating images, so everything is in two dimensions: $S \in \mathbb{R}^2$. The set $S$ is
|
||||
all points that are "in the system." To generate our final image, we just plot every point in the system
|
||||
like a coordinate chart.
|
||||
|
||||
For example, if we say $S = \{(0,0), (1, 1), (2, 2)\}$, there are three points to plot:
|
||||
|
||||
import Plot from "react-plotly.js"
|
||||
|
||||
<center>
|
||||
<Plot
|
||||
data={[
|
||||
{
|
||||
x: [0, 1, 2],
|
||||
y: [0, 1, 2],
|
||||
type: 'scatter',
|
||||
mode: 'markers',
|
||||
marker: { size: 15 }
|
||||
}
|
||||
]}
|
||||
layout={{
|
||||
plot_bgcolor: 'rgba(0,0,0,0)',
|
||||
paper_bgcolor: 'rgba(0,0,0,0)'
|
||||
}}
|
||||
config={{
|
||||
staticPlot: true
|
||||
}}
|
||||
/>
|
||||
</center>
|
||||
|
||||
For fractal flames, we just need to figure out which points are in $S$ and plot them. While there are
|
||||
technically an infinite number of points, if we find _enough_ points and plot them, we end up with a nice picture.
|
||||
|
||||
### Transformation functions
|
||||
|
||||
Second, $F_i(S)$. At their most basic, each $F_i$ is a function that takes in a 2-dimensional point and transforms
|
||||
it into a new 2-dimensional point: $F_i \in \mathbb{R}^2 \rightarrow \mathbb{R}^2$. It's worth discussing
|
||||
these functions, but not critical, so **this section is optional**.
|
||||
|
||||
In mathematical terms, each $F_i$ is a special kind of function called an [affine transformation](https://en.wikipedia.org/wiki/Affine_transformation).
|
||||
We can think of them like mapping from one coordinate system to another. For example, we can define a coordinate system
|
||||
where everything is shifted over:
|
||||
|
||||
$$
|
||||
F_{shift}(x, y) = (x + 1, y)
|
||||
$$
|
||||
|
||||
That is, for an input point $(x, y)$, the output point will be $(x + 1, y)$:
|
||||
|
||||
<center>
|
||||
<Plot
|
||||
data={[
|
||||
{
|
||||
x: [0, 1, 2],
|
||||
y: [0, 1, 2],
|
||||
type: 'scatter',
|
||||
mode: 'markers',
|
||||
marker: { size: 12 },
|
||||
name: "(x, y)"
|
||||
},
|
||||
{
|
||||
x: [1, 2, 3],
|
||||
y: [0, 1, 2],
|
||||
type: 'scatter',
|
||||
mode: 'markers',
|
||||
marker: { size: 12 },
|
||||
name: "(x+1, y)"
|
||||
},
|
||||
{
|
||||
x: [0, 1],
|
||||
y: [0, 0],
|
||||
mode: 'lines+markers',
|
||||
marker: {
|
||||
size: 12,
|
||||
symbol: 'arrow-bar-up',
|
||||
angleref: 'previous',
|
||||
color: 'rgb(0,0,0)'
|
||||
},
|
||||
type: 'scatter',
|
||||
showlegend: false
|
||||
},
|
||||
{
|
||||
x: [1, 2],
|
||||
y: [1, 1],
|
||||
mode: 'lines+markers',
|
||||
marker: {
|
||||
size: 12,
|
||||
symbol: 'arrow-bar-up',
|
||||
angleref: 'previous',
|
||||
color: 'rgb(0,0,0)'
|
||||
},
|
||||
type: 'scatter',
|
||||
showlegend: false
|
||||
},
|
||||
{
|
||||
x: [2, 3],
|
||||
y: [2, 2],
|
||||
mode: 'lines+markers',
|
||||
marker: {
|
||||
size: 12,
|
||||
symbol: 'arrow-bar-up',
|
||||
angleref: 'previous',
|
||||
color: 'rgb(0,0,0)'
|
||||
},
|
||||
type: 'scatter',
|
||||
showlegend: false
|
||||
}
|
||||
]}
|
||||
layout={{
|
||||
plot_bgcolor: 'rgba(0,0,0,0)',
|
||||
paper_bgcolor: 'rgba(0,0,0,0)'
|
||||
}}
|
||||
config={{
|
||||
staticPlot: true
|
||||
}}
|
||||
/>
|
||||
</center>
|
||||
|
||||
This is a simple example designed to illustrate the principle. In general, $F_i$ functions have the form:
|
||||
|
||||
$$
|
||||
F_i(x,y) = (a_i \cdot x + b_i \cdot y + c_i, \hspace{0.2cm} d_i \cdot x + e_i \cdot y + f_i)
|
||||
$$
|
||||
|
||||
The parameters ($a_i$, $b_i$, etc.) are values we get to choose. In the example above, we can represent our shift
|
||||
function using these parameters:
|
||||
|
||||
$$
|
||||
a_i = 1 \hspace{0.5cm} b_i = 0 \hspace{0.5cm} c_i = 1 \\
|
||||
d_i = 0 \hspace{0.5cm} e_i = 1 \hspace{0.5cm} f_i = 0 \\
|
||||
$$
|
||||
|
||||
$$
|
||||
\begin{align*}
|
||||
F_{shift}(x,y) &= (1 \cdot x + 0 \cdot y + 1, 0 \cdot x + 1 \cdot y + 0) \\
|
||||
F_{shift}(x,y) &= (x + 1, y)
|
||||
\end{align*}
|
||||
$$
|
||||
|
||||
Fractal flames use more complex functions to produce a wide variety of images, but all follow this same format.
|
||||
|
||||
## Sierpinski's gasket
|
||||
|
||||
Using these definitions, we can build the first image. The paper defines a function system we can use as-is:
|
||||
|
||||
$$
|
||||
F_0(x, y) = \left({x \over 2}, {y \over 2} \right)
|
||||
\hspace{0.8cm}
|
||||
F_1(x, y) = \left({{x + 1} \over 2}, {y \over 2} \right)
|
||||
\hspace{0.8cm}
|
||||
F_2(x, y) = \left({x \over 2}, {{y + 1} \over 2} \right)
|
||||
$$
|
||||
|
||||
### The chaos game
|
||||
|
||||
Next, how do we find out all the points in $S$? The paper lays out an algorithm called the "chaos game":
|
||||
|
||||
$$
|
||||
\begin{align*}
|
||||
&(x, y) = \text{a random point in the bi-unit square} \\
|
||||
&\text{iterate } \{ \\
|
||||
&\hspace{1cm} i = \text{a random integer from 0 to } n - 1 \text{ inclusive} \\
|
||||
&\hspace{1cm} (x,y) = F_i(x,y) \\
|
||||
&\hspace{1cm} \text{plot}(x,y) \text{ except during the first 20 iterations} \\
|
||||
\}
|
||||
\end{align*}
|
||||
$$
|
7
blog/2024-11-15-playing-with-fire/2-transforms.mdx
Normal file
7
blog/2024-11-15-playing-with-fire/2-transforms.mdx
Normal file
@ -0,0 +1,7 @@
|
||||
---
|
||||
slug: 2024/11/playing-with-fire-transforms
|
||||
title: "Playing with fire: Transforms and variations"
|
||||
date: 2024-11-15 13:00:00
|
||||
authors: [bspeice]
|
||||
tags: []
|
||||
---
|
9
blog/2024-11-15-playing-with-fire/3-log-density.mdx
Normal file
9
blog/2024-11-15-playing-with-fire/3-log-density.mdx
Normal file
@ -0,0 +1,9 @@
|
||||
---
|
||||
slug: 2024/11/playing-with-fire-log-density
|
||||
title: "Playing with fire: Log-density display"
|
||||
date: 2024-11-15 14:00:00
|
||||
authors: [bspeice]
|
||||
tags: []
|
||||
---
|
||||
|
||||
Testing
|
7
blog/2024-11-15-playing-with-fire/4-color.mdx
Normal file
7
blog/2024-11-15-playing-with-fire/4-color.mdx
Normal file
@ -0,0 +1,7 @@
|
||||
---
|
||||
slug: 2024/11/playing-with-fire-color
|
||||
title: "Playing with fire: Color"
|
||||
date: 2024-11-15 15:00:00
|
||||
authors: [bspeice]
|
||||
tags: []
|
||||
---
|
BIN
blog/2024-11-15-playing-with-fire/banner-dark.png
Normal file
BIN
blog/2024-11-15-playing-with-fire/banner-dark.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 557 KiB |
BIN
blog/2024-11-15-playing-with-fire/banner-light.png
Normal file
BIN
blog/2024-11-15-playing-with-fire/banner-light.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 558 KiB |
120
blog/2024-11-15-playing-with-fire/params.flame
Normal file
120
blog/2024-11-15-playing-with-fire/params.flame
Normal file
@ -0,0 +1,120 @@
|
||||
<Flames name="variations">
|
||||
<flame name="post xform" version="Apophysis 2.08 beta" size="600 600" center="0 0" scale="150" oversample="1" filter="0.2" quality="1" background="0 0 0" brightness="4" gamma="4" >
|
||||
<xform weight="0.422330042096567" color="0" pdj="1" coefs="1.51523 0.740356 -3.048677 -1.455964 0.724135 -0.362059" pdj_a="1.09358" pdj_b="2.13048" pdj_c="2.54127" pdj_d="2.37267" />
|
||||
<xform weight="0.564534951145298" color="0" julia="1" coefs="-1.381068 1.381068 -1.381068 -1.381068 0 0" />
|
||||
<xform weight="0.0131350067581356" color="0" linear="1" popcorn="1" coefs="0.031393 -0.031367 0.031367 0.031393 0 0" post="1 0 0 1 0.241352 0.271521" />
|
||||
<palette count="256" format="RGB">
|
||||
3A78875998AA5E9DAC78B1C2599BAB36798A2252601B3438
|
||||
1823270D1215080705010101000000000002080A090A0809
|
||||
0C070D0B090A030406010101000000000000000000000000
|
||||
0A00000B0A080E1213101B1F21202830243A6737357A3C31
|
||||
864424643A22452F1838251427190E1C12080E0F110E1213
|
||||
1014152110183720105D320FA0531F9144180409080A1312
|
||||
0C13140E13160E15160E17160F16171015180B161C0A1225
|
||||
0A0F2F101E37172E40294C5A3B6B7549798758879975A9BE
|
||||
79A7BF7EA6C0949FA2AA9985B7A27BC4AB72AC965A867654
|
||||
61574E4C4D48374343474141573F3F7C5C36B0914EC1DFF9
|
||||
C4E4FAC8E9FCBEE1F4B5DAEDB2D8EDB0D6ED5398A7386D78
|
||||
1D424A1B3B4219343B1B383E1D3C411D3B462155623D7C8B
|
||||
46747F4F6C74636454785C3584663E917047BEA467CEA86A
|
||||
DEAC6DC5975EAC834F916E41765A335F3D21431F21241625
|
||||
1F202B1A2B321A2D321B30331B323A1628360E1D220E1D21
|
||||
0F1D20101C1F111C1E111D1E121E1E2B21153B2B1B725432
|
||||
85542C9854279B63369F7346AD7C3AB2763AB18F4FB39453
|
||||
B69957B99B56BC9E56C19651CB9346AB6A2A9851254E341D
|
||||
2F261B10181A0E15160C12120D11120A10100D0D0D0C0E0E
|
||||
0B0F100B10120C11140F191A101F221829331A373B1E3D52
|
||||
1A40551744591D556420424C1E3B431D3C41112C33102328
|
||||
101B1D10191E111820101D2311242A1B33371B3A3F276476
|
||||
3E637D556284545F7D7759355C41261B30290E16180B0F0F
|
||||
0908060405030002010A0E0F12171A1C1B2B17343C3C7481
|
||||
467F8F508A9E528FA23E81923769722E69772248512B545E
|
||||
35616C688589807F85939FB5ABD6E6B3D6EA89B7CE5891A4
|
||||
467E92356C81194A6B1A373F132C310E1C1F050409020205
|
||||
0000020000000101010800000B0000170A000D0D0D0D1110
|
||||
0F0E14100F141F11082619082F1904210F05111717101919
|
||||
0F1B1B101F22182C2B252E2B282D311B2E321A2E2F162E30
|
||||
1325270E191B0F1314190D0F2E1211461A27552227612723
|
||||
6C303A56213D3033381C343619343B15383E193A431A4E5C
|
||||
</palette>
|
||||
</flame>
|
||||
<flame name="baseline" version="Apophysis 2.08 beta" size="600 600" center="0 0" scale="150" oversample="1" filter="0.2" quality="1" background="0 0 0" brightness="4" gamma="4" >
|
||||
<xform weight="0.422330042096567" color="0" pdj="1" coefs="1.51523 0.740356 -3.048677 -1.455964 0.724135 -0.362059" pdj_a="1.09358" pdj_b="2.13048" pdj_c="2.54127" pdj_d="2.37267" />
|
||||
<xform weight="0.564534951145298" color="0.13" julia="1" coefs="-1.381068 1.381068 -1.381068 -1.381068 0 0" />
|
||||
<xform weight="0.0131350067581356" color="0.844" linear="1" popcorn="1" coefs="0.031393 -0.031367 0.031367 0.031393 0 0" />
|
||||
<palette count="256" format="RGB">
|
||||
FF0000D31616BD2121A72C2C9137377C4242714747664D4D
|
||||
3A63631D7171008080008B8B00969600A1A100ACAC00B1B1
|
||||
00B7B700CCCC00D7D700E2E200EDED00F8F800FBFB00FFFF
|
||||
2CF0FF42E8FF58E0FF6DD8FF83D1FF8ECDFF99C9FFAFC2FF
|
||||
C5BAFFFFA6FFE9A2FFD39FFFBD9CFFA799FF9C97FF9196FF
|
||||
668FFF508CFF3A89FF2485FF0E82FF0781FF0080FF0B80FF
|
||||
1680FF2C80FF3780FF4280FF4D80FF5880FF5D80FF6380FF
|
||||
7980FF7785F4758BE96A96D35FA1BD59A6B254ACA749B791
|
||||
3EC17C28D7501DE23A12ED2409F61200FF0016E9002CD300
|
||||
58A7006D9100837C00996600AF5000BA4500C53A00DB2400
|
||||
F10E00E90B00D31600BD2100B22600A72C009137007C4200
|
||||
5058003A6300246E001973000E79000080000A7500146A00
|
||||
1E5F003249003C3E004633004B2D005028005A1D00651200
|
||||
8100008C00009800009E0000A40000AF0000BB0000C70000
|
||||
D20000EA0000F00000F60000FD0000F2160BE82C16DD4221
|
||||
C76E37BC8342B2994DACA452A7AF589CC56392DB6E87F179
|
||||
80FF8080E99680E39B80DEA180D3AC80C8B780BEC180B3CC
|
||||
809DE2808EF08080FF7A80F47580E96A80D35F80BD5480A7
|
||||
4980913380662D805B2880501D803A12802407800E008000
|
||||
2C841A3784204285265887336E8940838B4D998D5AAF8E66
|
||||
C59073FF9595FF9393FF9292FF9090FF8D8DFF8B8BFF8888
|
||||
FF8383FF8181FF8080FF7E7EFF7B7BFF7979FF7777FF7783
|
||||
FF768EFF769AFF75A6FF75B1FF74BDFF74C9FF73D4FF73E0
|
||||
FF72F8FF71FBFF71FFFF6BEDFF65DBFF5FC9FF5AB7FF54A5
|
||||
FF4E93FF4881FF426FFF3C5DFF374BFF2D2DFA293AF62548
|
||||
F12155ED1E63E81A70E4167EDF128BDB0E99D60AA6D106B4
|
||||
CD02C1CA00CACC00B9CE00A7CF0096D10085D30073D50062
|
||||
D70050D8003FDA002EDC001CDE000BDF0000D90C06D4180C
|
||||
CE2413C82F19C33B1FBD4725B7532BB25F32AC6B38A6773E
|
||||
9D8A489D7E429E723C9E66359F5B2FA04F29A04323A1371D
|
||||
A12B16A21F10A3130AA30804A40000A000009C0000980000
|
||||
9400009000008C00008800008400008000007C0000750000
|
||||
</palette>
|
||||
</flame>
|
||||
<flame name="final xform" version="Apophysis 2.08 beta" size="600 600" center="0 0" scale="150" oversample="1" filter="0.2" quality="1" background="1 1 1" brightness="4" gamma="4" >
|
||||
<xform weight="0.422330042096567" color="0.349" pdj="1" coefs="1.51523 0.740356 -3.048677 -1.455964 0.724135 -0.362059" pdj_a="1.09358" pdj_b="2.13048" pdj_c="2.54127" pdj_d="2.37267" />
|
||||
<xform weight="0.564534951145298" color="0" julia="1" coefs="-1.381068 1.381068 -1.381068 -1.381068 0 0" />
|
||||
<xform weight="0.0131350067581356" color="0.844" linear="1" popcorn="1" coefs="0.031393 -0.031367 0.031367 0.031393 0 0" post="1 0 0 1 0.241352 0.271521" />
|
||||
<finalxform color="0" symmetry="1" julia="1" coefs="2 0 0 2 0 0" />
|
||||
<palette count="256" format="RGB">
|
||||
7E3037762C45722B496E2A4E6A2950672853652754632656
|
||||
5C265C5724595322574D2155482153462050451F4E441E4D
|
||||
431E4C3F1E473F1E453F1E433F1E3F3F1E3B3E1E393E1E37
|
||||
421D36431C38451C3A471B3B491B3C4A1A3C4B1A3D4D1A3E
|
||||
4F19405318435517445817465A16475D15495E154960154A
|
||||
65134E6812506B12526E1153711055720F55740F55770E57
|
||||
7A0E59810C58840B58880A588B09588F0858910756930755
|
||||
9A05539D0451A1034FA5024BA90147AA0046AC0045B00242
|
||||
B4043DBB0634BE082EC20A29C30B27C50C26C90F1DCC1116
|
||||
D32110D6280EDA300CDC380ADF4109E04508E24A08E45106
|
||||
E75704EA6402EC6B01EE7300EE7600EF7A00F07E00F18300
|
||||
F29000F29300F39600F39900F39C00F3A000F3A100F3A201
|
||||
F2A502F1A805F0A906EFAA08EEA909EEA80AEDA60CEBA50F
|
||||
E5A313E1A113DD9F13DB9E13D99D14D49C15D09815CC9518
|
||||
C79318BE8B1ABB891BB9871DB4811FB07D1FAB7621A67123
|
||||
9C6227975C289256299053298E502A89482C853F2D803A2E
|
||||
7E3037762C45742B47722B496E2A4E6A2951672853632656
|
||||
5C265C5724595322575022564E2255482153452050451F4E
|
||||
431E4C3F1E473E1D463D1D453F1E43411E413F1E3B3E1E37
|
||||
421D36421D38431D3B451C3A471B3A491B3C4B1A3D4D1A3E
|
||||
4F19405318435418445518455817465A16475D154960154A
|
||||
65134E66124F6812506B12526E1153711055740F55770E57
|
||||
7A0E597E0D57810C58840B58880A588B09588F0858930755
|
||||
9A05539C04529E0452A1034FA5024BA90147AC0045B00242
|
||||
B4043DB7053ABB0634BE0831C20A29C50C26C90F1DCC1116
|
||||
D01711D32110D72A0EDA300CDD390ADF4109E24A08E45106
|
||||
E75704E95F03EA6402EC6C01EE7300EF7A00F07E00F18300
|
||||
F28900F29000F39300F39600F39C00F3A000F3A100F3A201
|
||||
F2A502F2A503F1A805F0A807EFAA08EEA80AEDA60CEBA50F
|
||||
E9A411E5A313E1A113DD9F13D99D14D49C15D09815CC9518
|
||||
C79318C38F1ABE8B1AB9871DB4811FB07D1FAB7621A67123
|
||||
A16A249C6227975E289256298E502A89482C853F2D803A2E
|
||||
</palette>
|
||||
</flame>
|
||||
</Flames>
|
95
blog/2024-11-15-playing-with-fire/params.ts
Normal file
95
blog/2024-11-15-playing-with-fire/params.ts
Normal file
@ -0,0 +1,95 @@
|
||||
/**
|
||||
* Parameters taken from the reference .flame file,
|
||||
* translated into something that's easier to work with.
|
||||
*/
|
||||
|
||||
import {Coefs, Transform} from "./types";
|
||||
import { julia, linear, pdj, popcorn } from "./variation";
|
||||
|
||||
export const identityCoefs: Coefs = {
|
||||
a: 1, b: 0, c: 0,
|
||||
d: 0, e: 1, f: 0,
|
||||
}
|
||||
|
||||
export const xform1Weight = 0.56453495;
|
||||
export const xform1: Transform = {
|
||||
coefs: {
|
||||
a: -1.381068, b: -1.381068, c: 0,
|
||||
d: 1.381068, e: -1.381068, f: 0,
|
||||
},
|
||||
coefsPost: identityCoefs,
|
||||
variations: [[1, julia]],
|
||||
color: 0
|
||||
}
|
||||
|
||||
const xform2Weight = 0.013135;
|
||||
export const xform2: Transform = {
|
||||
coefs: {
|
||||
a: 0.031393, b: 0.031367, c: 0,
|
||||
d: -0.031367, e: 0.031393, f: 0,
|
||||
},
|
||||
coefsPost: {
|
||||
a: 1, b: 0, c: 0.241352,
|
||||
d: 0, e: 1, f: 0.271521,
|
||||
},
|
||||
variations: [
|
||||
[1, linear],
|
||||
[1, popcorn]
|
||||
],
|
||||
color: 0.844
|
||||
}
|
||||
|
||||
export const xform3Weight = 0.42233;
|
||||
export const xform3: Transform = {
|
||||
coefs: {
|
||||
a: 1.51523, b: -3.048677, c: 0.724135,
|
||||
d: 0.740356, e: -1.455964, f: -0.362059,
|
||||
},
|
||||
coefsPost: identityCoefs,
|
||||
variations: [[1, pdj(1.09358, 2.13048, 2.54127, 2.37267)]],
|
||||
color: 0.349
|
||||
}
|
||||
|
||||
export const xformFinal: Transform = {
|
||||
coefs: {
|
||||
a: 2, b: 0, c: 0,
|
||||
d: 0, e: 2, f: 0
|
||||
},
|
||||
coefsPost: identityCoefs,
|
||||
variations: [[1, julia]],
|
||||
color: 0
|
||||
}
|
||||
|
||||
export const palette =
|
||||
"7E3037762C45722B496E2A4E6A2950672853652754632656" +
|
||||
"5C265C5724595322574D2155482153462050451F4E441E4D" +
|
||||
"431E4C3F1E473F1E453F1E433F1E3F3F1E3B3E1E393E1E37" +
|
||||
"421D36431C38451C3A471B3B491B3C4A1A3C4B1A3D4D1A3E" +
|
||||
"4F19405318435517445817465A16475D15495E154960154A" +
|
||||
"65134E6812506B12526E1153711055720F55740F55770E57" +
|
||||
"7A0E59810C58840B58880A588B09588F0858910756930755" +
|
||||
"9A05539D0451A1034FA5024BA90147AA0046AC0045B00242" +
|
||||
"B4043DBB0634BE082EC20A29C30B27C50C26C90F1DCC1116" +
|
||||
"D32110D6280EDA300CDC380ADF4109E04508E24A08E45106" +
|
||||
"E75704EA6402EC6B01EE7300EE7600EF7A00F07E00F18300" +
|
||||
"F29000F29300F39600F39900F39C00F3A000F3A100F3A201" +
|
||||
"F2A502F1A805F0A906EFAA08EEA909EEA80AEDA60CEBA50F" +
|
||||
"E5A313E1A113DD9F13DB9E13D99D14D49C15D09815CC9518" +
|
||||
"C79318BE8B1ABB891BB9871DB4811FB07D1FAB7621A67123" +
|
||||
"9C6227975C289256299053298E502A89482C853F2D803A2E" +
|
||||
"7E3037762C45742B47722B496E2A4E6A2951672853632656" +
|
||||
"5C265C5724595322575022564E2255482153452050451F4E" +
|
||||
"431E4C3F1E473E1D463D1D453F1E43411E413F1E3B3E1E37" +
|
||||
"421D36421D38431D3B451C3A471B3A491B3C4B1A3D4D1A3E" +
|
||||
"4F19405318435418445518455817465A16475D154960154A" +
|
||||
"65134E66124F6812506B12526E1153711055740F55770E57" +
|
||||
"7A0E597E0D57810C58840B58880A588B09588F0858930755" +
|
||||
"9A05539C04529E0452A1034FA5024BA90147AC0045B00242" +
|
||||
"B4043DB7053ABB0634BE0831C20A29C50C26C90F1DCC1116" +
|
||||
"D01711D32110D72A0EDA300CDD390ADF4109E24A08E45106" +
|
||||
"E75704E95F03EA6402EC6C01EE7300EF7A00F07E00F18300" +
|
||||
"F28900F29000F39300F39600F39C00F3A000F3A100F3A201" +
|
||||
"F2A502F2A503F1A805F0A807EFAA08EEA80AEDA60CEBA50F" +
|
||||
"E9A411E5A313E1A113DD9F13D99D14D49C15D09815CC9518" +
|
||||
"C79318C38F1ABE8B1AB9871DB4811FB07D1FAB7621A67123" +
|
||||
"A16A249C6227975E289256298E502A89482C853F2D803A2E"
|
24
blog/2024-11-15-playing-with-fire/types.ts
Normal file
24
blog/2024-11-15-playing-with-fire/types.ts
Normal file
@ -0,0 +1,24 @@
|
||||
/**
|
||||
* Affine transformation coefficients
|
||||
*/
|
||||
export type Coefs = {
|
||||
a: number;
|
||||
b: number;
|
||||
c: number;
|
||||
d: number;
|
||||
e: number;
|
||||
f: number;
|
||||
};
|
||||
|
||||
export type Variation = (
|
||||
x: number,
|
||||
y: number,
|
||||
coefs: Coefs
|
||||
) => [number, number];
|
||||
|
||||
export type Transform = {
|
||||
coefs: Coefs,
|
||||
coefsPost: Coefs,
|
||||
variations: [number, Variation][],
|
||||
color: number
|
||||
}
|
29
blog/2024-11-15-playing-with-fire/utility.ts
Normal file
29
blog/2024-11-15-playing-with-fire/utility.ts
Normal file
@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Generate a uniform random number in the range (-1, 1)
|
||||
*
|
||||
* @returns
|
||||
*/
|
||||
export function randomBiUnit() {
|
||||
return Math.random() * 2 - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a uniform random integer in the range [min, max)
|
||||
*
|
||||
* @param min
|
||||
* @param max
|
||||
* @returns
|
||||
*/
|
||||
export function randomInteger(min: number, max: number) {
|
||||
return Math.floor(Math.random() * (max - min)) + min;
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/a/34356351
|
||||
export function hexToBytes(hex: string) {
|
||||
var bytes = [];
|
||||
for (var i = 0; i < hex.length; i += 2) {
|
||||
bytes.push(parseInt(hex.substring(i, i + 2), 16));
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
40
blog/2024-11-15-playing-with-fire/variation.ts
Normal file
40
blog/2024-11-15-playing-with-fire/variation.ts
Normal file
@ -0,0 +1,40 @@
|
||||
import { Variation } from "./types";
|
||||
|
||||
export const linear: Variation = (x, y) => [x, y];
|
||||
|
||||
function r(x: number, y: number) {
|
||||
return Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
|
||||
}
|
||||
|
||||
function theta(x: number, y: number) {
|
||||
return Math.atan2(x, y);
|
||||
}
|
||||
|
||||
function omega(): number {
|
||||
return Math.random() > 0.5 ? Math.PI : 0;
|
||||
}
|
||||
|
||||
export const julia: Variation = (x, y) => {
|
||||
const sqrtR = Math.sqrt(r(x, y));
|
||||
const thetaVal = theta(x, y) / 2 + omega();
|
||||
return [sqrtR * Math.cos(thetaVal), sqrtR * Math.sin(thetaVal)];
|
||||
};
|
||||
|
||||
export const popcorn: Variation = (x, y, transformCoefs) => {
|
||||
return [
|
||||
x + transformCoefs.c * Math.sin(Math.tan(3 * y)),
|
||||
y + transformCoefs.f * Math.sin(Math.tan(3 * x)),
|
||||
];
|
||||
};
|
||||
|
||||
export const pdj: (
|
||||
pdjA: number,
|
||||
pdjB: number,
|
||||
pdjC: number,
|
||||
pdjD: number
|
||||
) => Variation = (pdjA, pdjB, pdjC, pdjD) => {
|
||||
return (x, y) => [
|
||||
Math.sin(pdjA * y) - Math.cos(pdjB * x),
|
||||
Math.sin(pdjC * x) - Math.cos(pdjD * y),
|
||||
];
|
||||
};
|
2231
package-lock.json
generated
2231
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -21,9 +21,11 @@
|
||||
"@mdx-js/react": "^3.0.0",
|
||||
"clsx": "^2.0.0",
|
||||
"docusaurus-lunr-search": "^3.5.0",
|
||||
"plotly.js": "^2.35.2",
|
||||
"prism-react-renderer": "^2.3.0",
|
||||
"react": "^18.0.0",
|
||||
"react-dom": "^18.0.0",
|
||||
"react-plotly.js": "^2.6.0",
|
||||
"rehype-katex": "^7.0.1",
|
||||
"remark-math": "^6.0.0"
|
||||
},
|
||||
|
13
src/DualImage/index.tsx
Normal file
13
src/DualImage/index.tsx
Normal file
@ -0,0 +1,13 @@
|
||||
import {useColorMode} from "@docusaurus/theme-common";
|
||||
import React from "react";
|
||||
|
||||
interface Props {
|
||||
srcLight: string;
|
||||
srcDark: string;
|
||||
alt: string;
|
||||
}
|
||||
const DualImage = ({srcLight, srcDark, alt}: Props) => {
|
||||
const {colorMode} = useColorMode();
|
||||
return <img src={colorMode === "dark" ? srcDark : srcLight} alt={alt} />
|
||||
}
|
||||
export default DualImage;
|
@ -22,3 +22,8 @@
|
||||
background: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='white' d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E")
|
||||
no-repeat;
|
||||
}
|
||||
|
||||
/* Dark mode for Plotly, copied from https://github.com/plotly/plotly.js/issues/2006#issuecomment-2081535168 */
|
||||
[data-theme='dark'] .plot-container {
|
||||
filter: invert(75%) hue-rotate(180deg);
|
||||
}
|
6
src/isDarkMode.ts
Normal file
6
src/isDarkMode.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import {useColorMode} from "@docusaurus/theme-common";
|
||||
|
||||
export default function isDarkMode() {
|
||||
const {colorMode} = useColorMode();
|
||||
return colorMode === "dark";
|
||||
}
|
Loading…
Reference in New Issue
Block a user