From 39959246cd454b7f18866fecadac26be7802b490 Mon Sep 17 00:00:00 2001 From: metacryst Date: Mon, 29 Dec 2025 06:03:50 -0600 Subject: [PATCH] solid canvas prototpye --- cave/components/DownloadsPanel.js | 94 ------------------- cave/components/Home.js | 34 ------- cave/components/HomePanel.js | 7 -- cave/components/NavMenu.js | 37 -------- cave/index.html | 14 +++ cave/index.js | 148 +++++++++++++++++++++++++++++- 6 files changed, 160 insertions(+), 174 deletions(-) delete mode 100644 cave/components/DownloadsPanel.js delete mode 100644 cave/components/Home.js delete mode 100644 cave/components/HomePanel.js delete mode 100644 cave/components/NavMenu.js diff --git a/cave/components/DownloadsPanel.js b/cave/components/DownloadsPanel.js deleted file mode 100644 index 302ab29..0000000 --- a/cave/components/DownloadsPanel.js +++ /dev/null @@ -1,94 +0,0 @@ -class DownloadsPanel extends Shadow { - render() { - ZStack(() => { - input("", "60vw") - .backgroundColor("var(--accent3)") - .color("var(--accent)") - .border("none") - .borderTop("1px solid var(--accent)") - .borderBottom("1px solid var(--accent)") - .outline("0.5px solid black") - .borderRadius(7, px) - .transition("padding .2s") - .padding(0.5, em) - .position("absolute") - .x(50, vw).y(7, em) - .transform("translate(-50%, -50%)") - .onInput(() => { - console.log('typing') - }) - .onFocus(function (focusing) { - if(focusing) { - this.style.padding = "1em" - this.style.borderColor = "var(--darkred)" - } else { - this.style.padding = "0.5em" - this.style.borderColor = "var(--accent)" - } - }) - - // VStack(() => { - // const json = this.getJSONData() - - // p(json.length + " Entries") - // .marginBottom(2, em) - - // // Split into two alternating columns - // const left = [] - // const right = [] - - // for (let i = 0; i < 200; i++) { - // if (i % 2 === 0) { - // left.push(json[i]) - // } else { - // right.push(json[i]) - // } - // } - - // console.log(left) - // HStack(() => { - // // LEFT COLUMN - // VStack(() => { - // for (let item of left) { - // p(item.name) - // .marginLeft(0, em) - // .marginBottom(0.1, em) - // } - // }) - - // // RIGHT COLUMN - // VStack(() => { - // for (let item of right) { - // p(item.name) - // .marginLeft(0, em) - // .marginBottom(0.1, em) - // } - // }) - // .marginLeft(3, em) // spacing between columns - // }) - // }) - // .paddingLeft(5, em) - // .paddingTop(10, em) - }) - } - - getJSONData() { - const script = document.getElementById('jsonData'); - if (!script) { - console.warn('initial-data script not found'); - return null; - } - - try { - // script.textContent is the raw JSON string - const data = JSON.parse(script.textContent); - console.log(data) - return data; - } catch (err) { - console.error('Failed to parse initial-data JSON:', err); - return null; - } - } -} - -register(DownloadsPanel) \ No newline at end of file diff --git a/cave/components/Home.js b/cave/components/Home.js deleted file mode 100644 index 07eb939..0000000 --- a/cave/components/Home.js +++ /dev/null @@ -1,34 +0,0 @@ -import "./NavMenu.js" -import "./HomePanel.js" -import "./DownloadsPanel.js" - -class Home extends Shadow { - - render() { - ZStack(() => { - - switch(window.location.pathname) { - case "/": - HomePanel() - break; - case "/downloads": - DownloadsPanel() - break; - } - }) - .backgroundColor("var(--main)") - .display("block") - .width(100, vw).height("auto") - .color("var(--accent)") - .fontFamily("Arial") - .onAppear(() => { - document.body.style.backgroundColor = "var(--main)" - }) - .onNavigate(() => { - console.log("navved") - this.rerender() - }) - } -} - -register(Home) \ No newline at end of file diff --git a/cave/components/HomePanel.js b/cave/components/HomePanel.js deleted file mode 100644 index 5e08913..0000000 --- a/cave/components/HomePanel.js +++ /dev/null @@ -1,7 +0,0 @@ -class HomePanel extends Shadow { - render() { - - } -} - -register(HomePanel) \ No newline at end of file diff --git a/cave/components/NavMenu.js b/cave/components/NavMenu.js deleted file mode 100644 index 82b14c5..0000000 --- a/cave/components/NavMenu.js +++ /dev/null @@ -1,37 +0,0 @@ -class NavMenu extends Shadow { - - NavButton(text) { - return p(text) - .cursor("default") - .onAppear(function () { - console.log(window.location.pathname, "/" + this.innerText.toLowerCase()) - if(window.location.pathname === ("/" + this.innerText.toLowerCase())) { - this.style.textDecoration = "underline" - } - }) - .onHover(function (hovering) { - if(hovering) { - this.style.textDecoration = "underline" - } else { - this.style.textDecoration = "" - } - }) - .onClick(function (done) { - if(done) { - window.navigateTo(this.innerText === "Home" ? "/" : this.innerText.toLowerCase()) - } - }) - } - - render() { - HStack(() => { - this.NavButton("Home") - this.NavButton("Downloads") - }) - .gap(2, em) - .x(50, vw).y(5, vh) - .center() - } -} - -register(NavMenu) \ No newline at end of file diff --git a/cave/index.html b/cave/index.html index d5c9356..dcf80f6 100644 --- a/cave/index.html +++ b/cave/index.html @@ -7,7 +7,21 @@ + + \ No newline at end of file diff --git a/cave/index.js b/cave/index.js index b14af88..74b5940 100644 --- a/cave/index.js +++ b/cave/index.js @@ -1,2 +1,146 @@ -import "./components/Home.js" -Home() \ No newline at end of file +/* +Samuel Russell +Captured Sun +12.29.2025 +*/ + +class Canvas { + STROKE_COLOR = getComputedStyle(document.documentElement).getPropertyValue("--accent").trim(); + c = document.createElement("canvas") + ctx; + + /* ----------------------------- + Camera + ----------------------------- */ + camera = { + x: 0, + y: 0, + scale: 1, + ZOOM_SPEED: 0.016, + PAN_SPEED: 1.5, + FOCUS_THRESHOLD: 4.0 + } + + /* ----------------------------- + Rectangle + ----------------------------- */ + rect = { + x: -300, + y: -200, + w: 600, + h: 400 + }; + + resize = () => { + // Make Canvas Fill Screen + this.c.style.width = window.innerWidth + "px"; + this.c.style.height = window.innerHeight + "px"; + + // Set Internal Render Size by DPR + const dpr = window.devicePixelRatio || 1; + this.c.width = window.innerWidth * dpr; + this.c.height = window.innerHeight * dpr; + this.ctx.scale(dpr, dpr); + } + + onWheel = (e) => { + e.preventDefault(); + let camera = this.camera + + const rectCanvas = this.c.getBoundingClientRect(); + const mouseX = e.clientX - rectCanvas.left; + const mouseY = e.clientY - rectCanvas.top; + + if (!e.ctrlKey) { + const dpr = window.devicePixelRatio || 1; + + // Two-finger pan in world coordinates + camera.x += (e.deltaX * dpr) * camera.PAN_SPEED / camera.scale; + camera.y += (e.deltaY * dpr) * camera.PAN_SPEED / camera.scale; + return; + } + + const dpr = window.devicePixelRatio || 1; + + const worldX = ( + mouseX - + (this.c.width / dpr) / 2 // X coordinate of canvas center in CSS pixels + ) // Mouse offset from canvas center in CSS pixels + / camera.scale // Account for Zoom: shift by camera's zoom position + + camera.x; // Account for Pan: shift by camera’s world X position + + const worldY = ( + mouseY - + (this.c.height / dpr) / 2 + ) + / camera.scale + + camera.y; + + // Apply zoom + const zoomFactor = Math.exp(-e.deltaY * camera.ZOOM_SPEED); + camera.scale *= zoomFactor; + camera.scale = Math.max(0.04, Math.min(10, camera.scale)); + + // Adjust camera to keep cursor fixed + camera.x = worldX - (mouseX - (this.c.width / dpr) / 2) / camera.scale; + camera.y = worldY - (mouseY - (this.c.height / dpr) / 2) / camera.scale; + } + + draw = () => { + let ctx = this.ctx + let rect = this.rect + let camera = this.camera + let scale = camera.scale + requestAnimationFrame(this.draw); + + ctx.setTransform(1, 0, 0, 1, 0, 0); + ctx.clearRect(0, 0, this.c.width, this.c.height); + + let drawMenus = () => { + + ctx.setTransform(1, 0, 0, 1, 0, 0); // reset transform for UI + ctx.fillStyle = "rgba(30,30,30,0.8)"; + ctx.fillRect(10,10,150,100); + + ctx.fillStyle = "#FEB279"; + ctx.fillRect(20,20,120,30); + ctx.fillRect(20,60,120,30); + + ctx.fillStyle = "#000"; + ctx.font = "60px arial"; + ctx.fillText("Button 1", 20, 40); + ctx.fillText("Button 2", 20, 80); + } + + let drawSpace = () => { + ctx.translate(this.c.width / 2, this.c.height / 2); + ctx.scale(scale, scale); + ctx.translate(-camera.x, -camera.y); + + ctx.strokeStyle = this.STROKE_COLOR; + ctx.lineWidth = 0.5 / scale; + ctx.strokeRect(rect.x, rect.y, rect.w, rect.h); + } + + ctx.save() + + drawSpace() + + ctx.restore() + + drawMenus(ctx); + } + + constructor() { + document.body.appendChild(this.c) + this.ctx = this.c.getContext("2d"); + + window.addEventListener("resize", this.resize); + this.resize(); + + this.c.addEventListener("wheel", this.onWheel, { passive: false }); + this.draw() + } +} + +new Canvas() \ No newline at end of file