From bce2623727de4fbc6cb24b670288661db94cf6d4 Mon Sep 17 00:00:00 2001 From: Oliver Bryan <04oliverbryan@gmail.com> Date: Wed, 7 Jan 2026 23:17:23 +0000 Subject: [PATCH] phase 1 complete --- DEVELOPMENT_PLAN.md | 8 ++++---- src/App.css | 2 +- src/Index.tsx | 47 ++++++++++++++++++++++++++++----------------- src/Layout.tsx | 32 ++++++++++++------------------ src/types/shape.ts | 14 ++++++++++++++ 5 files changed, 60 insertions(+), 43 deletions(-) create mode 100644 src/types/shape.ts diff --git a/DEVELOPMENT_PLAN.md b/DEVELOPMENT_PLAN.md index e6e723f..cbed17d 100644 --- a/DEVELOPMENT_PLAN.md +++ b/DEVELOPMENT_PLAN.md @@ -86,10 +86,10 @@ src/ - [x] Install `react-konva`, `konva`, `tone`, `simplex-noise` - [x] Initialize shadcn (neutral base, no CSS overwrite) - [x] Add shadcn components: `button`, `slider`, `toggle` -- [ ] Create `types/shape.ts` with `ShapeState` interface -- [ ] Create `Layout.tsx` - sidebar (fixed width) + canvas area (flex-1) -- [ ] Update `Index.tsx` to use Layout -- [ ] Verify existing dark theme still works +- [x] Create `types/shape.ts` with `ShapeState` interface +- [x] Create `Layout.tsx` - sidebar (fixed width) + canvas area (flex-1) +- [x] Update `Index.tsx` to use Layout +- [x] Verify existing dark theme still works ### Deliverables diff --git a/src/App.css b/src/App.css index 877e638..0c9be05 100644 --- a/src/App.css +++ b/src/App.css @@ -82,7 +82,7 @@ .dark { --background: oklch(0.145 0 0); --foreground: oklch(0.985 0 0); - --card: oklch(0.205 0 0); + --card: oklch(0.165 0 0); --card-foreground: oklch(0.985 0 0); --popover: oklch(0.205 0 0); --popover-foreground: oklch(0.985 0 0); diff --git a/src/Index.tsx b/src/Index.tsx index 4a72f50..fa5ee68 100644 --- a/src/Index.tsx +++ b/src/Index.tsx @@ -1,25 +1,36 @@ import { Stage, Layer, Circle } from "react-konva"; - -const STAGE_SIZE = 0.6; -const ASPECT_RATIO = 4 / 3; +import { useEffect, useState } from "react"; function Index() { + const [dimensions, setDimensions] = useState({ + width: window.innerWidth, + height: window.innerHeight, + }); + + useEffect(() => { + const handleResize = () => { + setDimensions({ + width: window.innerWidth, + height: window.innerHeight, + }); + }; + + window.addEventListener("resize", handleResize); + return () => window.removeEventListener("resize", handleResize); + }, []); + + // canvas fills the available space (accounting for sidebar width of 320px) + const canvasWidth = dimensions.width - 320; + const canvasHeight = dimensions.height; + return ( - - - - - + <> + + + + + + ); } diff --git a/src/Layout.tsx b/src/Layout.tsx index 180561c..8bfe866 100644 --- a/src/Layout.tsx +++ b/src/Layout.tsx @@ -1,27 +1,19 @@ import ThemeToggle from "@/components/theme-toggle"; -import { Link, useLocation } from "react-router-dom"; -import { Home, Settings } from "lucide-react"; export default function Layout({ children }: { children: React.ReactNode }) { - const router = useLocation(); - return ( -
-
- -

The Shape of Sound

- {router.pathname !== "/settings" && ( - - - - )} - {router.pathname !== "/" && ( - - - - )} -
-
{children}
+
+ {/* sidebar - fixed width */} + + + {/* canvas area - flex-1 */} +
{children}
); } diff --git a/src/types/shape.ts b/src/types/shape.ts new file mode 100644 index 0000000..511da57 --- /dev/null +++ b/src/types/shape.ts @@ -0,0 +1,14 @@ +export type Preset = "triangle" | "square" | "circle"; + +export interface ShapeState { + x: number; + y: number; + preset: Preset; + roundness: number; // 0-100, controls morph from preset to circle + size: number; // 0-100, controls volume + wobble: number; // 0-100, visual wobble amount + wobbleSpeed: number; // 0-100, wobble animation speed + grain: number; // 0-100, noise mix + color: string; // hex color from clavier keyboard + octave: number; // 1-8, frequency multiplier +}