diff --git a/bun.lock b/bun.lock
index fb8d4baf..86e2d3eb 100644
--- a/bun.lock
+++ b/bun.lock
@@ -7,6 +7,7 @@
"dependencies": {
"@iconify/react": "^6.0.2",
"@nsmr/pixelart-react": "^2.0.0",
+ "@paper-design/shaders-react": "0.0.71",
"@tailwindcss/vite": "^4.1.18",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
@@ -176,6 +177,10 @@
"@nsmr/pixelart-react": ["@nsmr/pixelart-react@2.0.0", "", { "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" } }, "sha512-hD9CeUZp10jemfnBQdN+mAMiIGnzcNDG8DoGcHUAvO6JgN1k7dbWscmY5HBqmWglnHliwcq4cY9ICQzjsaWeqQ=="],
+ "@paper-design/shaders": ["@paper-design/shaders@0.0.71", "", {}, "sha512-brCt05YxxyjBrhnE3l1wJJHcFXsM8aE4lmpd9TMQp+p0dMU3F+OWkJZL9m/RC1Tt7om5xr0Wg7d0HYm+b9NYZA=="],
+
+ "@paper-design/shaders-react": ["@paper-design/shaders-react@0.0.71", "", { "dependencies": { "@paper-design/shaders": "0.0.71" }, "peerDependencies": { "@types/react": "^18 || ^19", "react": "^18 || ^19" }, "optionalPeers": ["@types/react"] }, "sha512-kTqjIlyZcpkwqJie+3ldEDscTtx1oOi8eRBD5QgWKI21GaNn/SSg26092M5zzqr3e8dVANv0ktS2ICSjbMFKbw=="],
+
"@radix-ui/number": ["@radix-ui/number@1.1.1", "", {}, "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g=="],
"@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="],
diff --git a/package.json b/package.json
index e81792d6..76719d84 100644
--- a/package.json
+++ b/package.json
@@ -12,6 +12,7 @@
"dependencies": {
"@iconify/react": "^6.0.2",
"@nsmr/pixelart-react": "^2.0.0",
+ "@paper-design/shaders-react": "0.0.71",
"@tailwindcss/vite": "^4.1.18",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
diff --git a/src/components/paper-texture-overlay.tsx b/src/components/paper-texture-overlay.tsx
new file mode 100644
index 00000000..2399dd21
--- /dev/null
+++ b/src/components/paper-texture-overlay.tsx
@@ -0,0 +1,55 @@
+import { PaperTexture } from "@paper-design/shaders-react";
+import { useTheme } from "@/components/theme-provider";
+
+const lightTexture = {
+ colorFront: "#5f4a331a",
+ contrast: 0.22,
+ roughness: 0.24,
+ fiber: 0.2,
+ crumples: 0.2,
+ folds: 0.12,
+ drops: 0.08,
+};
+
+const darkTexture = {
+ colorFront: "#f6efe31a",
+ contrast: 0.18,
+ roughness: 0.2,
+ fiber: 0.18,
+ crumples: 0.16,
+ folds: 0.1,
+ drops: 0.06,
+};
+
+export function PaperTextureOverlay() {
+ const { resolvedTheme } = useTheme();
+ const isDark = resolvedTheme === "dark";
+ const texture = isDark ? darkTexture : lightTexture;
+
+ return (
+
+ );
+}
diff --git a/src/main.tsx b/src/main.tsx
index 409e6d93..5452fd05 100644
--- a/src/main.tsx
+++ b/src/main.tsx
@@ -1,15 +1,18 @@
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { BrowserRouter } from "react-router-dom";
+import { PaperTextureOverlay } from "@/components/paper-texture-overlay";
import { ThemeProvider } from "@/components/theme-provider";
import "./index.css";
import App from "./App.tsx";
const root = document.getElementById("root");
+const isTextureEnabled = import.meta.env.VITE_TEXTURE !== "0";
if (!root) throw new Error("Failed to find the root element");
createRoot(root).render(
+ {isTextureEnabled ? : null}