mirror of
https://github.com/Xevion/grain.git
synced 2025-12-06 01:15:10 -06:00
Noise & Gradient Generation
This commit is contained in:
124
src/App.tsx
Normal file
124
src/App.tsx
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
import Chance from "chance";
|
||||||
|
import ReactDOMServer from "react-dom/server";
|
||||||
|
import { useEventListener, useWindowSize } from "usehooks-ts";
|
||||||
|
import { useState } from "react";
|
||||||
|
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() {
|
||||||
|
const { width, height } = useWindowSize();
|
||||||
|
const [background, setBackground] = useState(generateBackground());
|
||||||
|
|
||||||
|
useEventListener("keydown", (e) => {
|
||||||
|
if (e.code != "Enter") return;
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
setBackground(generateBackground());
|
||||||
|
});
|
||||||
|
|
||||||
|
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 = {
|
||||||
|
background: [`url("${svg}")`, ...background].join(", "),
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={appStyle} className="gradient">
|
||||||
|
<div className="font-inter min-w-[100vw] min-h-[100vh] bg-zinc-800/50 bg-blend-overlay">
|
||||||
|
<div className="grid grid-cols-12 w-full">
|
||||||
|
<div className="col-span-1" />
|
||||||
|
<div className="flex col-span-10 md:col-span-8 lg:col-span-6 offset-1 bg-white w-full min-h-[100vh] text-zinc-800">
|
||||||
|
<div className="m-3 p-5 border-y-[1px] border-zinc-100">
|
||||||
|
<div className="mb-3">
|
||||||
|
<h2 className="text-4xl tracking-wide font-semibold drop-shadow-xl">
|
||||||
|
Ryan Walters
|
||||||
|
</h2>
|
||||||
|
<span className="py-1 text-zinc-500">
|
||||||
|
Published on {new Date().toLocaleDateString()}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-2">
|
||||||
|
<p>
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed
|
||||||
|
consequat lacus sit amet erat efficitur elementum. Fusce
|
||||||
|
hendrerit bibendum ipsum, sit amet volutpat augue egestas sed.
|
||||||
|
Curabitur ut blandit felis. Suspendisse euismod, orci quis
|
||||||
|
consectetur pretium, libero eros lobortis lacus, vel interdum
|
||||||
|
ex sem sed sapien. Aliquam erat volutpat. Curabitur tempus
|
||||||
|
faucibus lobortis. Nulla sodales ipsum sit amet ligula
|
||||||
|
elementum faucibus. Donec aliquam enim a arcu gravida tempus.
|
||||||
|
Etiam tempus lectus et mauris feugiat, vel imperdiet quam
|
||||||
|
mattis. Suspendisse urna enim, cursus quis nibh et, egestas
|
||||||
|
ultrices tortor. Quisque imperdiet elit molestie lorem
|
||||||
|
placerat posuere. Duis in dolor non elit tempor mattis. Proin
|
||||||
|
vehicula facilisis nibh.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Maecenas rhoncus, erat auctor scelerisque condimentum, nibh
|
||||||
|
magna tristique felis, vitae condimentum mi est quis dui.
|
||||||
|
Fusce non imperdiet massa. Sed varius ultrices odio non
|
||||||
|
faucibus. Pellentesque habitant morbi tristique senectus et
|
||||||
|
netus et malesuada fames ac turpis egestas. Pellentesque
|
||||||
|
semper pulvinar vehicula. Fusce vel convallis eros. Duis
|
||||||
|
cursus feugiat quam, quis sodales enim malesuada non.
|
||||||
|
Vestibulum ante ipsum primis in faucibus orci luctus et
|
||||||
|
ultrices posuere cubilia curae; Maecenas in efficitur elit,
|
||||||
|
sed suscipit magna. Duis finibus blandit leo vitae mollis. In
|
||||||
|
et est pulvinar, condimentum est sed, scelerisque nisl. Nunc
|
||||||
|
eleifend eros aliquet libero.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default App;
|
||||||
35
src/index.scss
Normal file
35
src/index.scss
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
@import url("https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;0,800;1,300;1,400;1,500;1,600;1,700;1,800&family=Raleway:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap");
|
||||||
|
@import url("https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap");
|
||||||
|
@import url('https://fonts.googleapis.com/css2?family=Roboto+Mono&display=swap');
|
||||||
|
|
||||||
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
||||||
|
|
||||||
|
:root {
|
||||||
|
font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 24px;
|
||||||
|
font-weight: 400;
|
||||||
|
|
||||||
|
color-scheme: light dark;
|
||||||
|
color: rgba(255, 255, 255, 0.87);
|
||||||
|
background-color: #242424;
|
||||||
|
|
||||||
|
font-synthesis: none;
|
||||||
|
text-rendering: optimizeLegibility;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
-webkit-text-size-adjust: 100%;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
min-width: 100vw;
|
||||||
|
min-height: 100vh;
|
||||||
|
|
||||||
|
background-color: #242424;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gradient {
|
||||||
|
filter: contrast(150%) brightness(90%);
|
||||||
|
background-blend-mode: overlay;
|
||||||
|
}
|
||||||
10
src/main.tsx
Normal file
10
src/main.tsx
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import ReactDOM from 'react-dom/client'
|
||||||
|
import App from './App'
|
||||||
|
import './index.scss'
|
||||||
|
|
||||||
|
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
|
||||||
|
<React.StrictMode>
|
||||||
|
<App />
|
||||||
|
</React.StrictMode>
|
||||||
|
)
|
||||||
14
src/utils.ts
Normal file
14
src/utils.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
export const getEdgePoint = (
|
||||||
|
n: number,
|
||||||
|
width: number,
|
||||||
|
height: number
|
||||||
|
): [number, number] => {
|
||||||
|
const full = 2 * width + 2 * height;
|
||||||
|
if (n > full) n %= full;
|
||||||
|
if (n < 0) n = full - n;
|
||||||
|
|
||||||
|
if (n < width) return [n, 0];
|
||||||
|
if (n < width + height) return [width, n - width];
|
||||||
|
if (n < 2 * width + height) return [n - (2 * width + height), height];
|
||||||
|
return [0, height - (n - (2 * width + height))];
|
||||||
|
};
|
||||||
1
src/vite-env.d.ts
vendored
Normal file
1
src/vite-env.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/// <reference types="vite/client" />
|
||||||
Reference in New Issue
Block a user