refactor(desktop): drop leva from the chat backdrop

The backdrop shipped a leva control panel — a Shift+Y dev tweak surface
for opacity, blend mode, filters and a radius scalar — that has never
been touched since the app landed. Its hooks ran in every build, dev and
packaged alike: only the panel's visibility was gated on
`import.meta.env.DEV`, not the two `useControls` calls or the zustand
store behind them. Inline the values it was already rendering with and
delete the dependency; leva was the only thing importing it in the tree.

One of those controls was doing real damage. `--radius-scalar` shipped as
0.6 in styles.css, but the slider's 0.2 default was written onto the root
element on mount, so every window that mounts the backdrop rendered at
0.2 and every window that doesn't kept 0.6. The token now declares 0.2 —
the value the chat has actually rendered at all along.

The remaining static values (0.025 opacity, difference blend, 160dvh, top
left, invert) become classes; saturate(1)/brightness(1) were identity and
are dropped.
This commit is contained in:
Brooklyn Nicholson 2026-07-27 22:07:29 -05:00
parent 84858d76ba
commit 058c4376d2
4 changed files with 16 additions and 108 deletions

View file

@ -106,7 +106,6 @@
"hast-util-to-text": "^4.0.2",
"ignore": "^7.0.5",
"katex": "^0.16.45",
"leva": "^0.10.1",
"mermaid": "^11.15.0",
"motion": "^12.38.0",
"nanostores": "^1.3.0",

View file

@ -1,118 +1,24 @@
import { useStore } from '@nanostores/react'
import { Leva, useControls } from 'leva'
import { type CSSProperties, useEffect, useState } from 'react'
import { $backdrop } from '@/store/backdrop'
const BLEND_MODES = [
'normal',
'multiply',
'screen',
'overlay',
'darken',
'lighten',
'color-dodge',
'color-burn',
'hard-light',
'soft-light',
'difference',
'exclusion',
'hue',
'saturation',
'color',
'luminosity'
] as const
type BlendMode = (typeof BLEND_MODES)[number]
const assetPath = (path: string) => `${import.meta.env.BASE_URL}${path.replace(/^\/+/, '')}`
export function Backdrop() {
const [controlsOpen, setControlsOpen] = useState(false)
const on = useStore($backdrop)
useEffect(() => {
if (!import.meta.env.DEV) {
return
}
const onKeyDown = (event: KeyboardEvent) => {
const target = event.target as HTMLElement | null
const editing =
target?.isContentEditable ||
target instanceof HTMLInputElement ||
target instanceof HTMLTextAreaElement ||
target instanceof HTMLSelectElement
if (editing || event.repeat || event.altKey || event.ctrlKey || event.metaKey) {
return
}
if (event.shiftKey && event.code === 'KeyY') {
setControlsOpen(open => !open)
}
}
window.addEventListener('keydown', onKeyDown)
return () => window.removeEventListener('keydown', onKeyDown)
}, [])
const shape = useControls(
'UI / Shape',
{ radiusScalar: { value: 0.2, min: 0, max: 2, step: 0.1, label: 'radius scalar' } },
{ collapsed: true }
)
useEffect(() => {
document.documentElement.style.setProperty('--radius-scalar', String(shape.radiusScalar))
}, [shape.radiusScalar])
const statue = useControls(
'Backdrop / Statue',
{
enabled: { value: true, label: 'on' },
opacity: { value: 0.025, min: 0, max: 1, step: 0.005 },
blendMode: { value: 'difference' as BlendMode, options: BLEND_MODES, label: 'blend' },
invert: { value: true, label: 'invert color' },
saturate: { value: 1, min: 0, max: 3, step: 0.05, label: 'saturate' },
brightness: { value: 1, min: 0, max: 2, step: 0.05, label: 'brightness' },
objectPosition: {
value: 'top left',
options: ['top left', 'top right', 'bottom left', 'bottom right', 'center', 'top', 'bottom', 'left', 'right'],
label: 'position'
},
scale: { value: 160, min: 100, max: 300, step: 5, label: 'height (dvh)' }
},
{ collapsed: true }
)
if (!on) {
return null
}
return (
<>
<Leva collapsed hidden={!import.meta.env.DEV || !controlsOpen} titleBar={{ title: 'backdrop', drag: true }} />
{on && statue.enabled && (
<div
aria-hidden
className="pointer-events-none absolute inset-0 z-2"
style={{
mixBlendMode: statue.blendMode as CSSProperties['mixBlendMode'],
opacity: statue.opacity
}}
>
<img
alt=""
className="w-auto min-w-dvw object-cover"
fetchPriority="low"
src={assetPath('ds-assets/filler-bg0.jpg')}
style={{
height: `${statue.scale}dvh`,
objectPosition: statue.objectPosition,
filter: `invert(calc(${statue.invert ? 1 : 0} * var(--backdrop-invert-mul, 1))) saturate(${statue.saturate}) brightness(${statue.brightness})`
}}
/>
</div>
)}
</>
<div aria-hidden className="pointer-events-none absolute inset-0 z-2 opacity-[0.025] mix-blend-difference">
<img
alt=""
className="h-[160dvh] w-auto min-w-dvw object-cover object-left-top [filter:invert(var(--backdrop-invert-mul,1))]"
fetchPriority="low"
src={assetPath('ds-assets/filler-bg0.jpg')}
/>
</div>
)
}

View file

@ -387,7 +387,11 @@
--dt-spacing-mul: 1;
--radius: 0.75rem;
--radius-scalar: 0.6;
/* Effective value everywhere: the chat backdrop used to force 0.2 onto the
root element at runtime (an ungated leva slider default), so this 0.6
only ever applied to the windows that don't mount the backdrop. Pinned
to the value the app actually renders at. */
--radius-scalar: 0.2;
/* Space under last message vs overlay composer driven by the measured composer height (see composer/index.tsx)
plus the out-of-flow status stack's measured height (see status-stack/index.tsx) when one is showing.

1
package-lock.json generated
View file

@ -125,7 +125,6 @@
"hast-util-to-text": "^4.0.2",
"ignore": "^7.0.5",
"katex": "^0.16.45",
"leva": "^0.10.1",
"mermaid": "^11.15.0",
"motion": "^12.38.0",
"nanostores": "^1.3.0",