From da91d4fd0fa4ae7c1e305abf85cc8bba78ba0840 Mon Sep 17 00:00:00 2001 From: Charles Vien Date: Thu, 15 Jan 2026 19:02:00 -0800 Subject: [PATCH 1/2] Implement real torch --- .../src/renderer/components/CursorGlow.tsx | 50 +++++++++++++++++-- .../src/renderer/components/StatusBar.tsx | 2 + .../src/renderer/components/TorchToggle.tsx | 27 ++++++++++ 3 files changed, 74 insertions(+), 5 deletions(-) create mode 100644 apps/array/src/renderer/components/TorchToggle.tsx diff --git a/apps/array/src/renderer/components/CursorGlow.tsx b/apps/array/src/renderer/components/CursorGlow.tsx index 59051f920..015af206f 100644 --- a/apps/array/src/renderer/components/CursorGlow.tsx +++ b/apps/array/src/renderer/components/CursorGlow.tsx @@ -1,6 +1,6 @@ import { useSettingsStore } from "@features/settings/stores/settingsStore"; import { useThemeStore } from "@stores/themeStore"; -import { useEffect, useState } from "react"; +import { useEffect, useRef, useState } from "react"; export function CursorGlow() { const isDarkMode = useThemeStore((state) => state.isDarkMode); @@ -8,6 +8,9 @@ export function CursorGlow() { const [mousePos, setMousePos] = useState<{ x: number; y: number } | null>( null, ); + const [flicker, setFlicker] = useState({ scale: 1, opacity: 0.6 }); + const animationRef = useRef(null); + const lastUpdateRef = useRef(0); useEffect(() => { const handleMouseMove = (e: MouseEvent) => { @@ -18,20 +21,57 @@ export function CursorGlow() { return () => window.removeEventListener("mousemove", handleMouseMove); }, []); + // Torch flicker animation - slow breathing with subtle opacity flicker + useEffect(() => { + if (!isDarkMode || !cursorGlow) return; + + const animate = (timestamp: number) => { + // Slow breathing for size (4 second cycle) + const breathCycle = (timestamp / 4000) * Math.PI * 2; + const breath = Math.sin(breathCycle); + + // Faster subtle opacity flicker (update every ~150ms) + if (timestamp - lastUpdateRef.current > 150) { + lastUpdateRef.current = timestamp; + } + const flickerAmount = 0.75 + Math.random() * 0.25; // 0.75 to 1.0 + + setFlicker({ + scale: 1 + breath * 0.02, + opacity: flickerAmount, + }); + animationRef.current = requestAnimationFrame(animate); + }; + + animationRef.current = requestAnimationFrame(animate); + + return () => { + if (animationRef.current) { + cancelAnimationFrame(animationRef.current); + } + }; + }, [isDarkMode, cursorGlow]); + if (!isDarkMode || !cursorGlow || !mousePos) return null; + const baseSize = 200; + const size = baseSize * flicker.scale; + const offset = size / 2; + return (
); diff --git a/apps/array/src/renderer/components/StatusBar.tsx b/apps/array/src/renderer/components/StatusBar.tsx index 4286dd0c8..3037bcfe0 100644 --- a/apps/array/src/renderer/components/StatusBar.tsx +++ b/apps/array/src/renderer/components/StatusBar.tsx @@ -1,5 +1,6 @@ import { CampfireToggle } from "@components/CampfireToggle"; import { StatusBarMenu } from "@components/StatusBarMenu"; +import { TorchToggle } from "@components/TorchToggle"; import { Badge, Box, Code, Flex, Kbd } from "@radix-ui/themes"; import { useStatusBarStore } from "@stores/statusBarStore"; @@ -44,6 +45,7 @@ export function StatusBar({ showKeyHints = true }: StatusBarProps) { )} + {IS_DEV && ( diff --git a/apps/array/src/renderer/components/TorchToggle.tsx b/apps/array/src/renderer/components/TorchToggle.tsx new file mode 100644 index 000000000..d0c2b87a3 --- /dev/null +++ b/apps/array/src/renderer/components/TorchToggle.tsx @@ -0,0 +1,27 @@ +import { useSettingsStore } from "@features/settings/stores/settingsStore"; +import { Fire } from "@phosphor-icons/react"; +import { IconButton, Tooltip } from "@radix-ui/themes"; +import { useThemeStore } from "@stores/themeStore"; + +export function TorchToggle() { + const isDarkMode = useThemeStore((state) => state.isDarkMode); + const { cursorGlow, setCursorGlow } = useSettingsStore(); + + // Only show torch toggle in dark mode + if (!isDarkMode) return null; + + return ( + + setCursorGlow(!cursorGlow)} + style={{ + color: cursorGlow ? "var(--orange-9)" : "var(--gray-9)", + }} + > + + + + ); +} From 5288e353373fd6f7cadd8fcbf2888c0388acf853 Mon Sep 17 00:00:00 2001 From: Charles Vien Date: Thu, 15 Jan 2026 19:05:53 -0800 Subject: [PATCH 2/2] lint --- apps/array/src/renderer/components/CursorGlow.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/array/src/renderer/components/CursorGlow.tsx b/apps/array/src/renderer/components/CursorGlow.tsx index 015af206f..5a79065fe 100644 --- a/apps/array/src/renderer/components/CursorGlow.tsx +++ b/apps/array/src/renderer/components/CursorGlow.tsx @@ -71,7 +71,8 @@ export function CursorGlow() { "radial-gradient(circle at center, var(--fire-glow) 0%, transparent 70%)", opacity: flicker.opacity, zIndex: 9999, - transition: "opacity 0.1s ease-out, width 0.1s ease-out, height 0.1s ease-out", + transition: + "opacity 0.1s ease-out, width 0.1s ease-out, height 0.1s ease-out", }} /> );