char-slop/berry
multipurpose self-modifiable agentic harness
git clone https://git.t4t.associates/char-slop/berry
b3a4fb7
main
1import type { Rgb } from "./ghostty.ts" ; 2import { TERMINAL_PALETTE } from "@berry/util/palette.ts" ; 3 4const rgb = ( hex :string ) :Rgb => [ 5parseInt ( hex . slice ( 1 , 3 ), 16 ), 6parseInt ( hex . slice ( 3 , 5 ), 16 ), 7parseInt ( hex . slice ( 5 , 7 ), 16 ), 8]; 9 10/** berry's colors, as programs see them when they ask, and as the view draws their defaults. */ 11export const COLORS = { 12foreground :rgb ( "#f3eef2" ), 13background :rgb ( "#100e11" ), 14cursor :rgb ( "#ff9df5" ), 15palette :TERMINAL_PALETTE . map ( rgb ), 16}; 17 18/** Below this, text is hard to read on its background: ghostty's suggestion for a `minimum-contrast` that ensures it. */ 19const MINIMUM_CONTRAST = 3 ; 20 21const luminance = ( color :Rgb ) => { 22const [ r , g , b ] = color . map (( c ) => { 23const s = c / 255 ; 24return s <= 0.03928 ?s / 12.92 :(( s + 0.055 ) / 1.055 ) ** 2.4 ; 25}); 26return 0.2126 * r + 0.7152 * g + 0.0722 * b ; 27}; 28 29/** WCAG 2's contrast ratio between two colors, from 1 for none to 21. */ 30export function contrast ( a :Rgb , b :Rgb ) :number { 31const [ lighter , darker ] = [ luminance ( a ), luminance ( b )]. sort (( x , y ) => y - x ); 32return ( lighter + 0.05 ) / ( darker + 0.05 ); 33} 34 35/** 36* The color to draw text of `color` in on `background`: itself if it reads there, else moved toward white or black, 37* whichever stands out more there, just far enough that it does, so black on a dark background is a dark gray. 38*/ 39export function readable ( color :Rgb , background :Rgb ) :Rgb { 40if ( contrast ( color , background ) >= MINIMUM_CONTRAST ) return color ; 41const toward = contrast ([ 255 , 255 , 255 ], background ) >= contrast ([ 0 , 0 , 0 ], background ) ?255 :0 ; 42const mixed = ( t :number ) :Rgb => color . map (( c ) => Math . round ( c + ( toward - c ) * t )) as never ; 43// the least mix that reads, found by halving 44let [ low , high ] = [ 0 , 1 ]; 45for ( let i = 0 ; i < 16 ; i ++ ) { 46const middle = ( low + high ) / 2 ; 47if ( contrast ( mixed ( middle ), background ) >= MINIMUM_CONTRAST ) high = middle ; 48else low = middle ; 49} 50return mixed ( high ); 51}