mirror of
https://github.com/bspeice/speice.io
synced 2025-07-03 23:05:17 -04:00
Mass formatting, fix mobile display, fix issues with image wrap-around
This commit is contained in:
@ -1,51 +1,52 @@
|
||||
import TeX from "@matejmazur/react-katex";
|
||||
import {Coefs} from "../src/coefs";
|
||||
import { Coefs } from "../src/transform";
|
||||
|
||||
import styles from "../src/css/styles.module.css";
|
||||
|
||||
export interface Props {
|
||||
title: String;
|
||||
isPost: boolean;
|
||||
coefs: Coefs;
|
||||
setCoefs: (coefs: Coefs) => void;
|
||||
resetCoefs: () => void;
|
||||
title: String;
|
||||
isPost: boolean;
|
||||
coefs: Coefs;
|
||||
setCoefs: (coefs: Coefs) => void;
|
||||
resetCoefs: () => void;
|
||||
}
|
||||
export const CoefEditor = ({title, isPost, coefs, setCoefs, resetCoefs}: Props) => {
|
||||
const resetButton = <button className={styles.inputReset} onClick={resetCoefs}>Reset</button>
|
||||
|
||||
return (
|
||||
<div className={styles.inputGroup} style={{display: 'grid', gridTemplateColumns: '1fr 1fr 1fr'}}>
|
||||
<p className={styles.inputTitle} style={{gridColumn: '1/-1'}}>{title} {resetButton}</p>
|
||||
<div className={styles.inputElement}>
|
||||
<p>{isPost ? <TeX>\alpha</TeX> : 'a'}: {coefs.a}</p>
|
||||
<input type={'range'} min={-2} max={2} step={0.01} value={coefs.a}
|
||||
onInput={e => setCoefs({...coefs, a: Number(e.currentTarget.value)})}/>
|
||||
</div>
|
||||
<div className={styles.inputElement}>
|
||||
<p>{isPost ? <TeX>\beta</TeX> : 'b'}: {coefs.b}</p>
|
||||
<input type={'range'} min={-2} max={2} step={0.01} value={coefs.b}
|
||||
onInput={e => setCoefs({...coefs, b: Number(e.currentTarget.value)})}/>
|
||||
</div>
|
||||
<div className={styles.inputElement}>
|
||||
<p>{isPost ? <TeX>\gamma</TeX> : 'c'}: {coefs.c}</p>
|
||||
<input type={'range'} min={-2} max={2} step={0.01} value={coefs.c}
|
||||
onInput={e => setCoefs({...coefs, c: Number(e.currentTarget.value)})}/>
|
||||
</div>
|
||||
<div className={styles.inputElement}>
|
||||
<p>{isPost ? <TeX>\delta</TeX> : 'd'}: {coefs.d}</p>
|
||||
<input type={'range'} min={-2} max={2} step={0.01} value={coefs.d}
|
||||
onInput={e => setCoefs({...coefs, d: Number(e.currentTarget.value)})}/>
|
||||
</div>
|
||||
<div className={styles.inputElement}>
|
||||
<p>{isPost ? <TeX>\epsilon</TeX> : 'e'}: {coefs.e}</p>
|
||||
<input type={'range'} min={-2} max={2} step={0.01} value={coefs.e}
|
||||
onInput={e => setCoefs({...coefs, e: Number(e.currentTarget.value)})}/>
|
||||
</div>
|
||||
<div className={styles.inputElement}>
|
||||
<p>{isPost ? <TeX>\zeta</TeX> : 'f'}: {coefs.f}</p>
|
||||
<input type={'range'} min={-2} max={2} step={0.01} value={coefs.f}
|
||||
onInput={e => setCoefs({...coefs, f: Number(e.currentTarget.value)})}/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export const CoefEditor = ({ title, isPost, coefs, setCoefs, resetCoefs }: Props) => {
|
||||
const resetButton = <button className={styles.inputReset} onClick={resetCoefs}>Reset</button>;
|
||||
|
||||
return (
|
||||
<div className={styles.inputGroup} style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr" }}>
|
||||
<p className={styles.inputTitle} style={{ gridColumn: "1/-1" }}>{title} {resetButton}</p>
|
||||
<div className={styles.inputElement}>
|
||||
<p>{isPost ? <TeX>\alpha</TeX> : "a"}: {coefs.a}</p>
|
||||
<input type={"range"} min={-2} max={2} step={0.01} value={coefs.a}
|
||||
onInput={e => setCoefs({ ...coefs, a: Number(e.currentTarget.value) })} />
|
||||
</div>
|
||||
<div className={styles.inputElement}>
|
||||
<p>{isPost ? <TeX>\beta</TeX> : "b"}: {coefs.b}</p>
|
||||
<input type={"range"} min={-2} max={2} step={0.01} value={coefs.b}
|
||||
onInput={e => setCoefs({ ...coefs, b: Number(e.currentTarget.value) })} />
|
||||
</div>
|
||||
<div className={styles.inputElement}>
|
||||
<p>{isPost ? <TeX>\gamma</TeX> : "c"}: {coefs.c}</p>
|
||||
<input type={"range"} min={-2} max={2} step={0.01} value={coefs.c}
|
||||
onInput={e => setCoefs({ ...coefs, c: Number(e.currentTarget.value) })} />
|
||||
</div>
|
||||
<div className={styles.inputElement}>
|
||||
<p>{isPost ? <TeX>\delta</TeX> : "d"}: {coefs.d}</p>
|
||||
<input type={"range"} min={-2} max={2} step={0.01} value={coefs.d}
|
||||
onInput={e => setCoefs({ ...coefs, d: Number(e.currentTarget.value) })} />
|
||||
</div>
|
||||
<div className={styles.inputElement}>
|
||||
<p>{isPost ? <TeX>\epsilon</TeX> : "e"}: {coefs.e}</p>
|
||||
<input type={"range"} min={-2} max={2} step={0.01} value={coefs.e}
|
||||
onInput={e => setCoefs({ ...coefs, e: Number(e.currentTarget.value) })} />
|
||||
</div>
|
||||
<div className={styles.inputElement}>
|
||||
<p>{isPost ? <TeX>\zeta</TeX> : "f"}: {coefs.f}</p>
|
||||
<input type={"range"} min={-2} max={2} step={0.01} value={coefs.f}
|
||||
onInput={e => setCoefs({ ...coefs, f: Number(e.currentTarget.value) })} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
@ -1,68 +1,68 @@
|
||||
import {useContext, useEffect, useState} from "react";
|
||||
import {Transform} from "../src/transform";
|
||||
import * as params from "../src/params"
|
||||
import {PainterContext} from "../src/Canvas"
|
||||
import {chaosGameFinal} from "./chaosGameFinal"
|
||||
import {VariationEditor, VariationProps} from "./VariationEditor"
|
||||
import {applyTransform} from "../src/applyTransform";
|
||||
import {buildBlend} from "./buildBlend";
|
||||
import { useContext, useEffect, useState } from "react";
|
||||
import { Transform } from "../src/transform";
|
||||
import * as params from "../src/params";
|
||||
import { PainterContext } from "../src/Canvas";
|
||||
import { chaosGameFinal } from "./chaosGameFinal";
|
||||
import { VariationEditor, VariationProps } from "./VariationEditor";
|
||||
import { applyTransform } from "../src/applyTransform";
|
||||
import { buildBlend } from "./buildBlend";
|
||||
|
||||
export default function FlameBlend() {
|
||||
const {width, height, setPainter} = useContext(PainterContext);
|
||||
const { width, height, setPainter } = useContext(PainterContext);
|
||||
|
||||
const xform1VariationsDefault: VariationProps = {
|
||||
linear: 0,
|
||||
julia: 1,
|
||||
popcorn: 0,
|
||||
pdj: 0,
|
||||
}
|
||||
const [xform1Variations, setXform1Variations] = useState(xform1VariationsDefault)
|
||||
const resetXform1Variations = () => setXform1Variations(xform1VariationsDefault);
|
||||
const xform1VariationsDefault: VariationProps = {
|
||||
linear: 0,
|
||||
julia: 1,
|
||||
popcorn: 0,
|
||||
pdj: 0
|
||||
};
|
||||
const [xform1Variations, setXform1Variations] = useState(xform1VariationsDefault);
|
||||
const resetXform1Variations = () => setXform1Variations(xform1VariationsDefault);
|
||||
|
||||
const xform2VariationsDefault: VariationProps = {
|
||||
linear: 1,
|
||||
julia: 0,
|
||||
popcorn: 1,
|
||||
pdj: 0
|
||||
}
|
||||
const [xform2Variations, setXform2Variations] = useState(xform2VariationsDefault)
|
||||
const resetXform2Variations = () => setXform2Variations(xform2VariationsDefault);
|
||||
const xform2VariationsDefault: VariationProps = {
|
||||
linear: 1,
|
||||
julia: 0,
|
||||
popcorn: 1,
|
||||
pdj: 0
|
||||
};
|
||||
const [xform2Variations, setXform2Variations] = useState(xform2VariationsDefault);
|
||||
const resetXform2Variations = () => setXform2Variations(xform2VariationsDefault);
|
||||
|
||||
const xform3VariationsDefault: VariationProps = {
|
||||
linear: 0,
|
||||
julia: 0,
|
||||
popcorn: 0,
|
||||
pdj: 1
|
||||
}
|
||||
const [xform3Variations, setXform3Variations] = useState(xform3VariationsDefault)
|
||||
const resetXform3Variations = () => setXform3Variations(xform3VariationsDefault);
|
||||
const xform3VariationsDefault: VariationProps = {
|
||||
linear: 0,
|
||||
julia: 0,
|
||||
popcorn: 0,
|
||||
pdj: 1
|
||||
};
|
||||
const [xform3Variations, setXform3Variations] = useState(xform3VariationsDefault);
|
||||
const resetXform3Variations = () => setXform3Variations(xform3VariationsDefault);
|
||||
|
||||
const identityXform: Transform = (x, y) => [x, y];
|
||||
const identityXform: Transform = (x, y) => [x, y];
|
||||
|
||||
useEffect(() => {
|
||||
const transforms: [number, Transform][] = [
|
||||
[params.xform1Weight, applyTransform(params.xform1Coefs, buildBlend(params.xform1Coefs, xform1Variations))],
|
||||
[params.xform2Weight, applyTransform(params.xform2Coefs, buildBlend(params.xform2Coefs, xform2Variations))],
|
||||
[params.xform3Weight, applyTransform(params.xform3Coefs, buildBlend(params.xform3Coefs, xform3Variations))]
|
||||
]
|
||||
useEffect(() => {
|
||||
const transforms: [number, Transform][] = [
|
||||
[params.xform1Weight, applyTransform(params.xform1Coefs, buildBlend(params.xform1Coefs, xform1Variations))],
|
||||
[params.xform2Weight, applyTransform(params.xform2Coefs, buildBlend(params.xform2Coefs, xform2Variations))],
|
||||
[params.xform3Weight, applyTransform(params.xform3Coefs, buildBlend(params.xform3Coefs, xform3Variations))]
|
||||
];
|
||||
|
||||
const gameParams = {
|
||||
width,
|
||||
height,
|
||||
transforms,
|
||||
final: identityXform
|
||||
}
|
||||
setPainter(chaosGameFinal(gameParams));
|
||||
}, [xform1Variations, xform2Variations, xform3Variations]);
|
||||
const gameParams = {
|
||||
width,
|
||||
height,
|
||||
transforms,
|
||||
final: identityXform
|
||||
};
|
||||
setPainter(chaosGameFinal(gameParams));
|
||||
}, [xform1Variations, xform2Variations, xform3Variations]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<VariationEditor title={"Transform 1"} variations={xform1Variations} setVariations={setXform1Variations}
|
||||
resetVariations={resetXform1Variations}/>
|
||||
<VariationEditor title={"Transform 2"} variations={xform2Variations} setVariations={setXform2Variations}
|
||||
resetVariations={resetXform2Variations}/>
|
||||
<VariationEditor title={"Transform 3"} variations={xform3Variations} setVariations={setXform3Variations}
|
||||
resetVariations={resetXform3Variations}/>
|
||||
</>
|
||||
)
|
||||
return (
|
||||
<>
|
||||
<VariationEditor title={"Transform 1"} variations={xform1Variations} setVariations={setXform1Variations}
|
||||
resetVariations={resetXform1Variations} />
|
||||
<VariationEditor title={"Transform 2"} variations={xform2Variations} setVariations={setXform2Variations}
|
||||
resetVariations={resetXform2Variations} />
|
||||
<VariationEditor title={"Transform 3"} variations={xform3Variations} setVariations={setXform3Variations}
|
||||
resetVariations={resetXform3Variations} />
|
||||
</>
|
||||
);
|
||||
}
|
@ -1,46 +1,46 @@
|
||||
import {useContext, useEffect, useState} from "react";
|
||||
import {Coefs} from "../src/coefs"
|
||||
import { useContext, useEffect, useState } from "react";
|
||||
import { Coefs } from "../src/transform";
|
||||
import * as params from "../src/params";
|
||||
import {PainterContext} from "../src/Canvas"
|
||||
import {buildBlend} from "./buildBlend";
|
||||
import {chaosGameFinal} from "./chaosGameFinal"
|
||||
import {VariationEditor, VariationProps} from "./VariationEditor";
|
||||
import {CoefEditor} from "./CoefEditor";
|
||||
import {applyPost, applyTransform} from "../src/applyTransform";
|
||||
import { PainterContext } from "../src/Canvas";
|
||||
import { buildBlend } from "./buildBlend";
|
||||
import { chaosGameFinal } from "./chaosGameFinal";
|
||||
import { VariationEditor, VariationProps } from "./VariationEditor";
|
||||
import { CoefEditor } from "./CoefEditor";
|
||||
import { applyPost, applyTransform } from "../src/applyTransform";
|
||||
|
||||
export default function FlameFinal() {
|
||||
const {width, height, setPainter} = useContext(PainterContext);
|
||||
const { width, height, setPainter } = useContext(PainterContext);
|
||||
|
||||
const [xformFinalCoefs, setXformFinalCoefs] = useState<Coefs>(params.xformFinalCoefs);
|
||||
const resetXformFinalCoefs = () => setXformFinalCoefs(params.xformFinalCoefs);
|
||||
const [xformFinalCoefs, setXformFinalCoefs] = useState<Coefs>(params.xformFinalCoefs);
|
||||
const resetXformFinalCoefs = () => setXformFinalCoefs(params.xformFinalCoefs);
|
||||
|
||||
const xformFinalVariationsDefault: VariationProps = {
|
||||
linear: 0,
|
||||
julia: 1,
|
||||
popcorn: 0,
|
||||
pdj: 0
|
||||
}
|
||||
const [xformFinalVariations, setXformFinalVariations] = useState<VariationProps>(xformFinalVariationsDefault);
|
||||
const resetXformFinalVariations = () => setXformFinalVariations(xformFinalVariationsDefault);
|
||||
const xformFinalVariationsDefault: VariationProps = {
|
||||
linear: 0,
|
||||
julia: 1,
|
||||
popcorn: 0,
|
||||
pdj: 0
|
||||
};
|
||||
const [xformFinalVariations, setXformFinalVariations] = useState<VariationProps>(xformFinalVariationsDefault);
|
||||
const resetXformFinalVariations = () => setXformFinalVariations(xformFinalVariationsDefault);
|
||||
|
||||
const [xformFinalCoefsPost, setXformFinalCoefsPost] = useState<Coefs>(params.xformFinalCoefsPost);
|
||||
const resetXformFinalCoefsPost = () => setXformFinalCoefsPost(params.xformFinalCoefsPost);
|
||||
const [xformFinalCoefsPost, setXformFinalCoefsPost] = useState<Coefs>(params.xformFinalCoefsPost);
|
||||
const resetXformFinalCoefsPost = () => setXformFinalCoefsPost(params.xformFinalCoefsPost);
|
||||
|
||||
useEffect(() => {
|
||||
const finalBlend = buildBlend(xformFinalCoefs, xformFinalVariations);
|
||||
const finalXform = applyPost(xformFinalCoefsPost, applyTransform(xformFinalCoefs, finalBlend));
|
||||
useEffect(() => {
|
||||
const finalBlend = buildBlend(xformFinalCoefs, xformFinalVariations);
|
||||
const finalXform = applyPost(xformFinalCoefsPost, applyTransform(xformFinalCoefs, finalBlend));
|
||||
|
||||
setPainter(chaosGameFinal({width, height, transforms: params.xforms, final: finalXform}));
|
||||
}, [xformFinalCoefs, xformFinalVariations, xformFinalCoefsPost]);
|
||||
setPainter(chaosGameFinal({ width, height, transforms: params.xforms, final: finalXform }));
|
||||
}, [xformFinalCoefs, xformFinalVariations, xformFinalCoefsPost]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<CoefEditor title={"Final Transform"} isPost={false} coefs={xformFinalCoefs} setCoefs={setXformFinalCoefs}
|
||||
resetCoefs={resetXformFinalCoefs}/>
|
||||
<VariationEditor title={"Final Transform Variations"} variations={xformFinalVariations}
|
||||
setVariations={setXformFinalVariations} resetVariations={resetXformFinalVariations}/>
|
||||
<CoefEditor title={"Final Transform Post"} isPost={true} coefs={xformFinalCoefsPost}
|
||||
setCoefs={setXformFinalCoefsPost} resetCoefs={resetXformFinalCoefsPost}/>
|
||||
</>
|
||||
)
|
||||
return (
|
||||
<>
|
||||
<CoefEditor title={"Final Transform"} isPost={false} coefs={xformFinalCoefs} setCoefs={setXformFinalCoefs}
|
||||
resetCoefs={resetXformFinalCoefs} />
|
||||
<VariationEditor title={"Final Transform Variations"} variations={xformFinalVariations}
|
||||
setVariations={setXformFinalVariations} resetVariations={resetXformFinalVariations} />
|
||||
<CoefEditor title={"Final Transform Post"} isPost={true} coefs={xformFinalCoefsPost}
|
||||
setCoefs={setXformFinalCoefsPost} resetCoefs={resetXformFinalCoefsPost} />
|
||||
</>
|
||||
);
|
||||
}
|
@ -1,46 +1,46 @@
|
||||
import {useContext, useEffect, useState} from "react";
|
||||
import {Coefs} from "../src/coefs"
|
||||
import {Transform} from "../src/transform";
|
||||
import { useContext, useEffect, useState } from "react";
|
||||
import { applyTransform } from "../src/applyTransform";
|
||||
import { Coefs, Transform } from "../src/transform";
|
||||
import * as params from "../src/params";
|
||||
import {PainterContext} from "../src/Canvas"
|
||||
import {chaosGameFinal, Props as ChaosGameFinalProps} from "./chaosGameFinal"
|
||||
import {CoefEditor} from "./CoefEditor"
|
||||
import {applyPost, applyTransform} from "@site/blog/2024-11-15-playing-with-fire/src/applyTransform";
|
||||
import { PainterContext } from "../src/Canvas";
|
||||
import { chaosGameFinal, Props as ChaosGameFinalProps } from "./chaosGameFinal";
|
||||
import { CoefEditor } from "./CoefEditor";
|
||||
import { transformPost } from "./post";
|
||||
|
||||
export default function FlamePost() {
|
||||
const {width, height, setPainter} = useContext(PainterContext);
|
||||
const { width, height, setPainter } = useContext(PainterContext);
|
||||
|
||||
const [xform1CoefsPost, setXform1CoefsPost] = useState<Coefs>(params.xform1CoefsPost);
|
||||
const resetXform1CoefsPost = () => setXform1CoefsPost(params.xform1CoefsPost);
|
||||
const [xform1CoefsPost, setXform1CoefsPost] = useState<Coefs>(params.xform1CoefsPost);
|
||||
const resetXform1CoefsPost = () => setXform1CoefsPost(params.xform1CoefsPost);
|
||||
|
||||
const [xform2CoefsPost, setXform2CoefsPost] = useState<Coefs>(params.xform2CoefsPost);
|
||||
const resetXform2CoefsPost = () => setXform2CoefsPost(params.xform2CoefsPost);
|
||||
const [xform2CoefsPost, setXform2CoefsPost] = useState<Coefs>(params.xform2CoefsPost);
|
||||
const resetXform2CoefsPost = () => setXform2CoefsPost(params.xform2CoefsPost);
|
||||
|
||||
const [xform3CoefsPost, setXform3CoefsPost] = useState<Coefs>(params.xform3CoefsPost);
|
||||
const resetXform3CoefsPost = () => setXform3CoefsPost(params.xform3CoefsPost);
|
||||
const [xform3CoefsPost, setXform3CoefsPost] = useState<Coefs>(params.xform3CoefsPost);
|
||||
const resetXform3CoefsPost = () => setXform3CoefsPost(params.xform3CoefsPost);
|
||||
|
||||
const identityXform: Transform = (x, y) => [x, y];
|
||||
const identityXform: Transform = (x, y) => [x, y];
|
||||
|
||||
const gameParams: ChaosGameFinalProps = {
|
||||
width,
|
||||
height,
|
||||
transforms: [
|
||||
[params.xform1Weight, applyPost(xform1CoefsPost, applyTransform(params.xform1Coefs, params.xform1Variations))],
|
||||
[params.xform2Weight, applyPost(xform2CoefsPost, applyTransform(params.xform2Coefs, params.xform2Variations))],
|
||||
[params.xform3Weight, applyPost(xform3CoefsPost, applyTransform(params.xform3Coefs, params.xform3Variations))],
|
||||
],
|
||||
final: identityXform
|
||||
}
|
||||
useEffect(() => setPainter(chaosGameFinal(gameParams)), [xform1CoefsPost, xform2CoefsPost, xform3CoefsPost]);
|
||||
const gameParams: ChaosGameFinalProps = {
|
||||
width,
|
||||
height,
|
||||
transforms: [
|
||||
[params.xform1Weight, transformPost(applyTransform(params.xform1Coefs, params.xform1Variations), xform1CoefsPost)],
|
||||
[params.xform2Weight, transformPost(applyTransform(params.xform2Coefs, params.xform2Variations), xform2CoefsPost)],
|
||||
[params.xform3Weight, transformPost(applyTransform(params.xform3Coefs, params.xform3Variations), xform3CoefsPost)]
|
||||
],
|
||||
final: identityXform
|
||||
};
|
||||
useEffect(() => setPainter(chaosGameFinal(gameParams)), [xform1CoefsPost, xform2CoefsPost, xform3CoefsPost]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<CoefEditor title={"Transform 1 Post"} isPost={true} coefs={xform1CoefsPost} setCoefs={setXform1CoefsPost}
|
||||
resetCoefs={resetXform1CoefsPost}/>
|
||||
<CoefEditor title={"Transform 2 Post"} isPost={true} coefs={xform2CoefsPost} setCoefs={setXform2CoefsPost}
|
||||
resetCoefs={resetXform2CoefsPost}/>
|
||||
<CoefEditor title={"Transform 3 Post"} isPost={true} coefs={xform3CoefsPost} setCoefs={setXform3CoefsPost}
|
||||
resetCoefs={resetXform3CoefsPost}/>
|
||||
</>
|
||||
)
|
||||
return (
|
||||
<>
|
||||
<CoefEditor title={"Transform 1 Post"} isPost={true} coefs={xform1CoefsPost} setCoefs={setXform1CoefsPost}
|
||||
resetCoefs={resetXform1CoefsPost} />
|
||||
<CoefEditor title={"Transform 2 Post"} isPost={true} coefs={xform2CoefsPost} setCoefs={setXform2CoefsPost}
|
||||
resetCoefs={resetXform2CoefsPost} />
|
||||
<CoefEditor title={"Transform 3 Post"} isPost={true} coefs={xform3CoefsPost} setCoefs={setXform3CoefsPost}
|
||||
resetCoefs={resetXform3CoefsPost} />
|
||||
</>
|
||||
);
|
||||
}
|
@ -1,45 +1,45 @@
|
||||
import styles from "../src/css/styles.module.css"
|
||||
import styles from "../src/css/styles.module.css";
|
||||
|
||||
export interface VariationProps {
|
||||
linear: number;
|
||||
julia: number;
|
||||
popcorn: number;
|
||||
pdj: number;
|
||||
linear: number;
|
||||
julia: number;
|
||||
popcorn: number;
|
||||
pdj: number;
|
||||
}
|
||||
|
||||
export interface Props {
|
||||
title: String;
|
||||
variations: VariationProps;
|
||||
setVariations: (variations: VariationProps) => void;
|
||||
resetVariations: () => void;
|
||||
title: String;
|
||||
variations: VariationProps;
|
||||
setVariations: (variations: VariationProps) => void;
|
||||
resetVariations: () => void;
|
||||
}
|
||||
|
||||
export const VariationEditor = ({title, variations, setVariations, resetVariations}: Props) => {
|
||||
const resetButton = <button className={styles.inputReset} onClick={resetVariations}>Reset</button>
|
||||
export const VariationEditor = ({ title, variations, setVariations, resetVariations }: Props) => {
|
||||
const resetButton = <button className={styles.inputReset} onClick={resetVariations}>Reset</button>;
|
||||
|
||||
return (
|
||||
<div className={styles.inputGroup} style={{display: 'grid', gridTemplateColumns: '1fr 1fr'}}>
|
||||
<p className={styles.inputTitle} style={{gridColumn: '1/-1'}}>{title} {resetButton}</p>
|
||||
<div className={styles.inputElement}>
|
||||
<span>Linear: {variations.linear}</span>
|
||||
<input type={'range'} min={0} max={1} step={0.01} style={{width: '100%'}} value={variations.linear}
|
||||
onInput={e => setVariations({...variations, linear: Number(e.currentTarget.value)})}/>
|
||||
</div>
|
||||
<div className={styles.inputElement}>
|
||||
<span>Julia: {variations.julia}</span>
|
||||
<input type={'range'} min={0} max={1} step={0.01} style={{width: '100%'}} value={variations.julia}
|
||||
onInput={e => setVariations({...variations, julia: Number(e.currentTarget.value)})}/>
|
||||
</div>
|
||||
<div className={styles.inputElement}>
|
||||
<span>Popcorn: {variations.popcorn}</span>
|
||||
<input type={'range'} min={0} max={1} step={0.01} style={{width: '100%'}} value={variations.popcorn}
|
||||
onInput={e => setVariations({...variations, popcorn: Number(e.currentTarget.value)})}/>
|
||||
</div>
|
||||
<div className={styles.inputElement}>
|
||||
<span>PDJ: {variations.pdj}</span>
|
||||
<input type={'range'} min={0} max={1} step={0.01} style={{width: '100%'}} value={variations.pdj}
|
||||
onInput={e => setVariations({...variations, pdj: Number(e.currentTarget.value)})}/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<div className={styles.inputGroup} style={{ display: "grid", gridTemplateColumns: "1fr 1fr" }}>
|
||||
<p className={styles.inputTitle} style={{ gridColumn: "1/-1" }}>{title} {resetButton}</p>
|
||||
<div className={styles.inputElement}>
|
||||
<span>Linear: {variations.linear}</span>
|
||||
<input type={"range"} min={0} max={1} step={0.01} style={{ width: "100%" }} value={variations.linear}
|
||||
onInput={e => setVariations({ ...variations, linear: Number(e.currentTarget.value) })} />
|
||||
</div>
|
||||
<div className={styles.inputElement}>
|
||||
<span>Julia: {variations.julia}</span>
|
||||
<input type={"range"} min={0} max={1} step={0.01} style={{ width: "100%" }} value={variations.julia}
|
||||
onInput={e => setVariations({ ...variations, julia: Number(e.currentTarget.value) })} />
|
||||
</div>
|
||||
<div className={styles.inputElement}>
|
||||
<span>Popcorn: {variations.popcorn}</span>
|
||||
<input type={"range"} min={0} max={1} step={0.01} style={{ width: "100%" }} value={variations.popcorn}
|
||||
onInput={e => setVariations({ ...variations, popcorn: Number(e.currentTarget.value) })} />
|
||||
</div>
|
||||
<div className={styles.inputElement}>
|
||||
<span>PDJ: {variations.pdj}</span>
|
||||
<input type={"range"} min={0} max={1} step={0.01} style={{ width: "100%" }} value={variations.pdj}
|
||||
onInput={e => setVariations({ ...variations, pdj: Number(e.currentTarget.value) })} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
@ -1,17 +1,17 @@
|
||||
import {Coefs} from "../src/coefs";
|
||||
import {VariationProps} from "./VariationEditor";
|
||||
import {linear} from "../src/linear";
|
||||
import {julia} from "../src/julia";
|
||||
import {popcorn} from "../src/popcorn";
|
||||
import {pdj} from "../src/pdj";
|
||||
import {pdjParams} from "../src/params";
|
||||
import {VariationBlend} from "../src/blend";
|
||||
import { Coefs } from "../src/transform";
|
||||
import { VariationProps } from "./VariationEditor";
|
||||
import { linear } from "../src/linear";
|
||||
import { julia } from "../src/julia";
|
||||
import { popcorn } from "../src/popcorn";
|
||||
import { pdj } from "../src/pdj";
|
||||
import { pdjParams } from "../src/params";
|
||||
import { Blend } from "../src/blend";
|
||||
|
||||
export function buildBlend(coefs: Coefs, variations: VariationProps): VariationBlend {
|
||||
return [
|
||||
[variations.linear, linear],
|
||||
[variations.julia, julia],
|
||||
[variations.popcorn, popcorn(coefs)],
|
||||
[variations.pdj, pdj(pdjParams)]
|
||||
]
|
||||
export function buildBlend(coefs: Coefs, variations: VariationProps): Blend {
|
||||
return [
|
||||
[variations.linear, linear],
|
||||
[variations.julia, julia],
|
||||
[variations.popcorn, popcorn(coefs)],
|
||||
[variations.pdj, pdj(pdjParams)]
|
||||
];
|
||||
}
|
@ -1,37 +1,51 @@
|
||||
// hidden-start
|
||||
import { randomBiUnit } from "../src/randomBiUnit";
|
||||
import { randomChoice } from "../src/randomChoice";
|
||||
import { plotBinary as plot } from "../src/plotBinary"
|
||||
import {Transform} from "../src/transform";
|
||||
import {Props as ChaosGameWeightedProps} from "../1-introduction/chaosGameWeighted";
|
||||
import { plotBinary as plot } from "../src/plotBinary";
|
||||
import { Transform } from "../src/transform";
|
||||
import { Props as WeightedProps } from "../1-introduction/chaosGameWeighted";
|
||||
|
||||
const quality = 0.5;
|
||||
const step = 1000;
|
||||
// hidden-end
|
||||
export type Props = ChaosGameWeightedProps & {
|
||||
final: Transform,
|
||||
export type Props = WeightedProps & {
|
||||
final: Transform,
|
||||
}
|
||||
export function* chaosGameFinal({width, height, transforms, final}: Props) {
|
||||
let image = new ImageData(width, height);
|
||||
let [x, y] = [randomBiUnit(), randomBiUnit()];
|
||||
|
||||
const iterations = width * height * quality;
|
||||
for (let i = 0; i < iterations; i++) {
|
||||
const [_, transform] = randomChoice(transforms);
|
||||
[x, y] = transform(x, y);
|
||||
export function* chaosGameFinal(
|
||||
{
|
||||
width,
|
||||
height,
|
||||
transforms,
|
||||
final
|
||||
}: Props
|
||||
) {
|
||||
let img =
|
||||
new ImageData(width, height);
|
||||
let [x, y] = [
|
||||
randomBiUnit(),
|
||||
randomBiUnit()
|
||||
];
|
||||
|
||||
// highlight-start
|
||||
const [finalX, finalY] = final(x, y);
|
||||
// highlight-end
|
||||
const pixels = width * height;
|
||||
const iterations = quality * pixels;
|
||||
for (let i = 0; i < iterations; i++) {
|
||||
const [_, transform] =
|
||||
randomChoice(transforms);
|
||||
[x, y] = transform(x, y);
|
||||
|
||||
if (i > 20)
|
||||
// highlight-start
|
||||
plot(finalX, finalY, image);
|
||||
// highlight-end
|
||||
// highlight-start
|
||||
const [finalX, finalY] = final(x, y);
|
||||
// highlight-end
|
||||
|
||||
if (i % step === 0)
|
||||
yield image;
|
||||
}
|
||||
if (i > 20)
|
||||
// highlight-start
|
||||
plot(finalX, finalY, img);
|
||||
// highlight-end
|
||||
|
||||
yield image;
|
||||
if (i % step === 0)
|
||||
yield img;
|
||||
}
|
||||
|
||||
yield img;
|
||||
}
|
@ -34,7 +34,7 @@ This leads us to the first big innovation of the Fractal Flame algorithm: adding
|
||||
after the affine transform. These functions are called "variations":
|
||||
|
||||
$$
|
||||
F_i(x, y) = V_j(a_i \cdot x + b_i \cdot y + c_i, d_i \cdot x + e_i \cdot y + f_i)
|
||||
F_i(x, y) = V_j(a_i x + b_i y + c_i, d_i x + e_i y + f_i)
|
||||
$$
|
||||
|
||||
import variationSource from '!!raw-loader!../src/variation'
|
||||
@ -96,7 +96,7 @@ Some variations rely on knowing the transform's affine coefficients; they're cal
|
||||
For the popcorn variation, we use $c$ and $f$:
|
||||
|
||||
$$
|
||||
V_{17}(x,y) = (x + c \cdot \text{sin}(\text{tan }3y), y + f \cdot \text{sin}(\text{tan }3x))
|
||||
V_{17}(x,y) = (x + c\ \text{sin}(\text{tan }3y), y + f\ \text{sin}(\text{tan }3x))
|
||||
$$
|
||||
|
||||
import popcornSrc from '!!raw-loader!../src/popcorn'
|
||||
@ -109,8 +109,8 @@ Some variations have extra parameters; they're called "parametric variations."
|
||||
For the PDJ variation, there are four extra parameters we can choose:
|
||||
|
||||
$$
|
||||
p_1 = \text{pdj.a} \hspace{0.2cm} p_2 = \text{pdj.b} \hspace{0.2cm} p_3 = \text{pdj.c} \hspace{0.2cm} p_4 = \text{pdj.d} \\
|
||||
V_{24} = (\text{sin}(p_1 \cdot y) - \text{cos}(p_2 \cdot x), \text{sin}(p_3 \cdot x) - \text{cos}(p_4 \cdot y))
|
||||
p_1 = \text{pdj.a} \hspace{0.1cm} p_2 = \text{pdj.b} \hspace{0.1cm} p_3 = \text{pdj.c} \hspace{0.1cm} p_4 = \text{pdj.d} \\
|
||||
V_{24} = (\text{sin}(p_1 y) - \text{cos}(p_2 x), \text{sin}(p_3 x) - \text{cos}(p_4 y))
|
||||
$$
|
||||
|
||||
import pdjSrc from '!!raw-loader!../src/pdj'
|
||||
@ -124,7 +124,7 @@ Each variation receives the same $x$ and $y$ inputs, and we add together each va
|
||||
We'll also give each variation a weight ($v_{ij}$) that changes how much it contributes to the result:
|
||||
|
||||
$$
|
||||
F_i(x,y) = \sum_{j} v_{ij} V_j(a_i \cdot x + b_i \cdot y + c_i, \hspace{0.2cm} d_i \cdot x + e_i \cdot y + f_i)
|
||||
F_i(x,y) = \sum_{j} v_{ij} V_j(x, y)
|
||||
$$
|
||||
|
||||
The formula looks intimidating, but it's not hard to implement:
|
||||
|
@ -1,7 +1,11 @@
|
||||
// hidden-start
|
||||
import {Coefs} from "../src/coefs";
|
||||
import {Transform} from "../src/transform";
|
||||
import {applyCoefs} from "../src/coefs";
|
||||
import { applyCoefs, Coefs, Transform } from "../src/transform";
|
||||
// hidden-end
|
||||
export const transformPost = (transform: Transform, coefs: Coefs): Transform =>
|
||||
(x, y) => applyCoefs(...transform(x, y), coefs)
|
||||
export const transformPost = (
|
||||
transform: Transform,
|
||||
coefs: Coefs
|
||||
): Transform =>
|
||||
(x, y) => {
|
||||
[x, y] = transform(x, y);
|
||||
return applyCoefs(x, y, coefs);
|
||||
}
|
Reference in New Issue
Block a user