mirror of
https://github.com/Xevion/grain.git
synced 2025-12-06 07:15:09 -06:00
Refactor gradient & noise gen. in useBackground.tsx
This commit is contained in:
60
src/App.tsx
60
src/App.tsx
@@ -1,69 +1,19 @@
|
|||||||
import Chance from "chance";
|
|
||||||
import ReactDOMServer from "react-dom/server";
|
|
||||||
import { useEventListener, useWindowSize } from "usehooks-ts";
|
import { useEventListener, useWindowSize } from "usehooks-ts";
|
||||||
import { useState } from "react";
|
import useBackground from "./useBackground";
|
||||||
import { getEdgePoint } from "@/utils";
|
|
||||||
|
|
||||||
const chance = Chance();
|
|
||||||
const colors = [
|
|
||||||
"#ed625d",
|
|
||||||
"#42b6c6",
|
|
||||||
"#f79f88",
|
|
||||||
"#446ba6",
|
|
||||||
"#4b95f0",
|
|
||||||
"#d16ba5",
|
|
||||||
];
|
|
||||||
|
|
||||||
const generateBackground = () => {
|
|
||||||
return chance.pickset(colors, 5).map((color) => {
|
|
||||||
const [x, y] = getEdgePoint(chance.integer({ min: 0, max: 100 }), 100, 100);
|
|
||||||
return `radial-gradient(farthest-corner at ${x}% ${y}%, ${chance.pickone(
|
|
||||||
colors
|
|
||||||
)}, ${chance.pickone(colors)}, transparent 100%)`;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const { width, height } = useWindowSize();
|
const { width, height } = useWindowSize();
|
||||||
const [background, setBackground] = useState(generateBackground());
|
const { svg, backgrounds, regenerate } = useBackground({ width, height, ratio: 0.3 });
|
||||||
|
|
||||||
useEventListener("keydown", (e) => {
|
useEventListener("keydown", (e) => {
|
||||||
if (e.code != "Enter") return;
|
if (e.code != "Enter") return;
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
setBackground(generateBackground());
|
e.preventDefault();
|
||||||
|
regenerate();
|
||||||
});
|
});
|
||||||
|
|
||||||
const ratio = 0.3;
|
|
||||||
const svgWidth = Math.ceil((width ?? 1920) * ratio);
|
|
||||||
const svgHeight = Math.ceil((height ?? 1080) * ratio);
|
|
||||||
console.log({ svgWidth, svgHeight });
|
|
||||||
|
|
||||||
const noise = (
|
|
||||||
<svg
|
|
||||||
viewBox={`0 0 ${svgWidth} ${svgHeight}`}
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<filter id="noiseFilter">
|
|
||||||
<feTurbulence
|
|
||||||
type="fractalNoise"
|
|
||||||
baseFrequency="2"
|
|
||||||
numOctaves="2"
|
|
||||||
stitchTiles="stitch"
|
|
||||||
/>
|
|
||||||
</filter>
|
|
||||||
<g opacity={0.9}>
|
|
||||||
<rect width="100%" height="100%" filter="url(#noiseFilter)" />
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
);
|
|
||||||
|
|
||||||
const svg = `data:image/svg+xml;base64,${window.btoa(
|
|
||||||
ReactDOMServer.renderToString(noise)
|
|
||||||
)}`;
|
|
||||||
|
|
||||||
const appStyle = {
|
const appStyle = {
|
||||||
background: [`url("${svg}")`, ...background].join(", "),
|
background: [`url("${svg}")`, ...backgrounds].join(", "),
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
81
src/useBackground.tsx
Normal file
81
src/useBackground.tsx
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
import { Chance } from "chance";
|
||||||
|
import { useEffect, useMemo, useState } from "react";
|
||||||
|
import ReactDOMServer from "react-dom/server";
|
||||||
|
import { getEdgePoint } from "./utils";
|
||||||
|
|
||||||
|
interface useBackgroundProps {
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
ratio: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface useBackgroundReturn {
|
||||||
|
regenerate: () => void;
|
||||||
|
backgrounds: string[];
|
||||||
|
svg: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const chance = Chance();
|
||||||
|
const palettes = [
|
||||||
|
// ["#5e1e1e", "#141414", "#400000", "#7a0000", "#2b0059", "#000c59", "#850082", "#850052"],
|
||||||
|
["#ed625d", "#42b6c6", "#f79f88", "#446ba6", "#4b95f0", "#d16ba5"],
|
||||||
|
];
|
||||||
|
|
||||||
|
const generateBackground = (): string[] => {
|
||||||
|
const palette = chance.pick(palettes);
|
||||||
|
return Array(5)
|
||||||
|
.fill(null)
|
||||||
|
.map(() => chance.pickone(palette))
|
||||||
|
.map((color) => {
|
||||||
|
const [x, y] = getEdgePoint(
|
||||||
|
chance.integer({ min: 0, max: 400 }),
|
||||||
|
100,
|
||||||
|
100
|
||||||
|
);
|
||||||
|
return `radial-gradient(farthest-corner at ${x}% ${y}%, ${color}, transparent 100%)`;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const useBackground = ({
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
ratio,
|
||||||
|
}: useBackgroundProps): useBackgroundReturn => {
|
||||||
|
const [background, setBackground] = useState(generateBackground());
|
||||||
|
|
||||||
|
const regenerate = () => {
|
||||||
|
setBackground(generateBackground());
|
||||||
|
};
|
||||||
|
|
||||||
|
const svgWidth = Math.ceil((width ?? 1920) * ratio);
|
||||||
|
const svgHeight = Math.ceil((height ?? 1080) * ratio);
|
||||||
|
const noise = (
|
||||||
|
<svg
|
||||||
|
viewBox={`0 0 ${svgWidth} ${svgHeight}`}
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<filter id="noiseFilter">
|
||||||
|
<feTurbulence
|
||||||
|
type="fractalNoise"
|
||||||
|
baseFrequency="2.1"
|
||||||
|
numOctaves="2"
|
||||||
|
seed={chance.natural()}
|
||||||
|
stitchTiles="stitch"
|
||||||
|
/>
|
||||||
|
</filter>
|
||||||
|
<g opacity={0.9}>
|
||||||
|
<rect width="100%" height="100%" filter="url(#noiseFilter)" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
regenerate,
|
||||||
|
svg: `data:image/svg+xml;base64,${window.btoa(
|
||||||
|
ReactDOMServer.renderToString(noise)
|
||||||
|
)}`,
|
||||||
|
backgrounds: background,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useBackground;
|
||||||
Reference in New Issue
Block a user