@@ -2044,6 +2044,10 @@ <h2 data-bench-heading="Response Viewer">BullshitBench: Response Viewer</h2>
20442044 "openai/gpt-5.4-mini" : Object . freeze ( { input : 0.75 , cachedInput : 0.075 , output : 4.5 } ) ,
20452045 "openai/gpt-5.4-nano" : Object . freeze ( { input : 0.2 , cachedInput : 0.02 , output : 1.25 } ) ,
20462046} ) ;
2047+ const PREFERRED_LAUNCH_CHART_BASE_MODELS = Object . freeze ( [
2048+ "openai/gpt-5.4" ,
2049+ "google/gemini-3.1-pro-preview" ,
2050+ ] ) ;
20472051const PREFERRED_REASONING_SCATTER_BASE_MODELS = Object . freeze ( [
20482052 "openai/gpt-5.4-mini" ,
20492053 "openai/gpt-5.4-nano" ,
@@ -3198,6 +3202,12 @@ <h3 style="margin:0 0 6px;">${esc(prettyModel(sample))} -- ${esc(domLabel)}</h3>
31983202 const priorityFn = typeof opts . priorityFn === "function"
31993203 ? opts . priorityFn
32003204 : ( point => Number ( point ?. greenRate ) || 0 ) ;
3205+ const labelFormatter = typeof opts . labelFormatter === "function"
3206+ ? opts . labelFormatter
3207+ : ( point => launchChartModelLabel ( point ?. label ) ) ;
3208+ const pinnedLabelFormatter = typeof opts . pinnedLabelFormatter === "function"
3209+ ? opts . pinnedLabelFormatter
3210+ : ( point => String ( point ?. label || labelFormatter ( point ) ) ) ;
32013211
32023212 // Sort by configured priority descending (most important first)
32033213 const sorted = points . slice ( ) . sort ( ( a , b ) => {
@@ -3291,7 +3301,8 @@ <h3 style="margin:0 0 6px;">${esc(prettyModel(sample))} -- ${esc(domLabel)}</h3>
32913301 let autoLabelsPlaced = 0 ;
32923302 sorted . forEach ( pt => {
32933303 if ( ! pt ?. _pinnedLabel && autoLabelsPlaced >= maxLabels ) return ;
3294- const labelW = pt . label . length * charW + 2 ;
3304+ const labelText = String ( pt . _pinnedLabel ? pinnedLabelFormatter ( pt ) : labelFormatter ( pt ) || "" ) ;
3305+ const labelW = labelText . length * charW + 2 ;
32953306 const labelH = lineH ;
32963307 const cx = pt . _cx , cy = pt . _cy ;
32973308 const di = dotIdx . get ( pt ) ?? - 1 ;
@@ -3321,6 +3332,15 @@ <h3 style="margin:0 0 6px;">${esc(prettyModel(sample))} -- ${esc(domLabel)}</h3>
33213332 ] ;
33223333
33233334 if ( pt . _pinnedLabel ) {
3335+ for ( const o of offsets ) {
3336+ const box = { x : cx + o . dx , y : cy + o . dy , w : labelW , h : labelH } ;
3337+ if ( overlaps ( box , di ) ) continue ;
3338+ placed . push ( box ) ;
3339+ const anchor = o . dx < - labelW / 2 ? "end" : o . dx > 0 ? "start" : "middle" ;
3340+ const textX = anchor === "end" ? box . x + box . w : anchor === "middle" ? box . x + box . w / 2 : box . x ;
3341+ result . push ( { point : pt , x : textX , y : box . y + labelH - 2 , anchor } ) ;
3342+ return ;
3343+ }
33243344 for ( const o of offsets ) {
33253345 const box = { x : cx + o . dx , y : cy + o . dy , w : labelW , h : labelH } ;
33263346 if ( ! boxWithinPlot ( box ) ) continue ;
@@ -3413,6 +3433,17 @@ <h3 style="margin:0 0 6px;">${esc(prettyModel(sample))} -- ${esc(domLabel)}</h3>
34133433 } ) ;
34143434}
34153435
3436+ function primeDefaultScatterSelections ( chartId , points , preferredModels = [ ] ) {
3437+ const selected = selectedScatterPointSet ( chartId ) ;
3438+ if ( selected . size || ! preferredModels . length ) return ;
3439+ preferredModels . forEach ( ( baseModel ) => {
3440+ const preferredPoint = points
3441+ . filter ( point => scatterBaseModelKey ( point ) === baseModel )
3442+ . sort ( ( a , b ) => b . greenRate - a . greenRate || b . launchDate . getTime ( ) - a . launchDate . getTime ( ) ) [ 0 ] ;
3443+ if ( preferredPoint ) selected . add ( scatterPointKey ( preferredPoint ) ) ;
3444+ } ) ;
3445+ }
3446+
34163447function mergePinnedScatterLabelPoints ( points , autoCandidates ) {
34173448 const merged = [ ] ;
34183449 const seen = new Set ( ) ;
@@ -3434,6 +3465,10 @@ <h3 style="margin:0 0 6px;">${esc(prettyModel(sample))} -- ${esc(domLabel)}</h3>
34343465 return ( point ?. _pinnedLabel ? 100000 : 0 ) + ( Number ( point ?. greenRate ) || 0 ) ;
34353466}
34363467
3468+ function scatterBaseModelKey ( point ) {
3469+ return String ( point ?. mk || point ?. model || "" ) . replace ( / @ r e a s o n i n g = [ ^ @ ] + $ / i, "" ) ;
3470+ }
3471+
34373472function scatterToggleAriaLabel ( point ) {
34383473 return `${ point ?. _pinnedLabel ? "Hide" : "Show" } label for ${ point ?. label || "model" } ` ;
34393474}
@@ -3495,6 +3530,47 @@ <h3 style="margin:0 0 6px;">${esc(prettyModel(sample))} -- ${esc(domLabel)}</h3>
34953530 return selected . slice ( 0 , maxLabels ) ;
34963531}
34973532
3533+ function selectLaunchScatterLabelPoints ( points , maxLabels = 12 , preferredModels = [ ] ) {
3534+ const selected = [ ] ;
3535+ const seen = new Set ( ) ;
3536+ const add = p => {
3537+ if ( ! p ) return ;
3538+ const k = scatterPointKey ( p ) ;
3539+ if ( seen . has ( k ) ) return ;
3540+ seen . add ( k ) ;
3541+ selected . push ( p ) ;
3542+ } ;
3543+
3544+ preferredModels . forEach ( ( baseModel ) => {
3545+ const preferredPoint = points
3546+ . filter ( p => scatterBaseModelKey ( p ) === baseModel )
3547+ . sort ( ( a , b ) => b . greenRate - a . greenRate || b . launchDate . getTime ( ) - a . launchDate . getTime ( ) ) [ 0 ] ;
3548+ add ( preferredPoint ) ;
3549+ } ) ;
3550+
3551+ const byOrg = groupBy ( points , p => normOrg ( p . org ) ) ;
3552+ [ ...byOrg . values ( ) ] . forEach ( orgPts => {
3553+ add ( orgPts . slice ( ) . sort ( ( a , b ) => b . greenRate - a . greenRate || b . launchDate . getTime ( ) - a . launchDate . getTime ( ) ) [ 0 ] ) ;
3554+ add ( orgPts . slice ( ) . sort ( ( a , b ) => b . launchDate . getTime ( ) - a . launchDate . getTime ( ) || b . greenRate - a . greenRate ) [ 0 ] ) ;
3555+ } ) ;
3556+
3557+ const byDate = points . slice ( ) . sort ( ( a , b ) => a . launchDate . getTime ( ) - b . launchDate . getTime ( ) ) ;
3558+ const binCount = Math . min ( 5 , byDate . length ) ;
3559+ for ( let i = 0 ; i < binCount ; i ++ ) {
3560+ const start = Math . floor ( ( i * byDate . length ) / binCount ) ;
3561+ const end = Math . floor ( ( ( i + 1 ) * byDate . length ) / binCount ) ;
3562+ const bin = byDate . slice ( start , Math . max ( start + 1 , end ) ) ;
3563+ add ( bin . slice ( ) . sort ( ( a , b ) => b . greenRate - a . greenRate || b . launchDate . getTime ( ) - a . launchDate . getTime ( ) ) [ 0 ] ) ;
3564+ }
3565+
3566+ points . slice ( ) . sort ( ( a , b ) => b . greenRate - a . greenRate || b . launchDate . getTime ( ) - a . launchDate . getTime ( ) ) . slice ( 0 , maxLabels ) . forEach ( add ) ;
3567+ return selected . slice ( 0 , maxLabels ) ;
3568+ }
3569+
3570+ function launchScatterLabelPriority ( point ) {
3571+ return scatterLabelPriority ( point ) + ( PREFERRED_LAUNCH_CHART_BASE_MODELS . includes ( scatterBaseModelKey ( point ) ) ? 5000 : 0 ) ;
3572+ }
3573+
34983574function selectReasoningScatterLabelPoints ( points , maxLabels = 9 , metricKey = "avgReasoning" , preferredModels = [ ] ) {
34993575 const metricValue = p => Number ( p ?. [ metricKey ] || 0 ) ;
35003576 const selected = [ ] ;
@@ -3673,7 +3749,7 @@ <h3 style="margin:0 0 6px;">${esc(prettyModel(sample))} -- ${esc(domLabel)}</h3>
36733749 const RELEASE_WINDOW_DAYS = 0 ;
36743750 const RELEASE_WINDOW_MS = RELEASE_WINDOW_DAYS * 86400000 ;
36753751 const byModel2 = groupBy ( filtered , modelKey ) ;
3676- const rawPoints = [ ...byModel2 . entries ( ) ] . map ( ( [ , modelRows ] ) => {
3752+ const rawPoints = [ ...byModel2 . entries ( ) ] . map ( ( [ mk , modelRows ] ) => {
36773753 const sample = modelRows [ 0 ] || { } ;
36783754 const org = normOrg ( modelOrg ( sample ) ) ;
36793755 const targetOrgs = new Set ( [ "anthropic" , "openai" , "google" ] ) ;
@@ -3683,7 +3759,7 @@ <h3 style="margin:0 0 6px;">${esc(prettyModel(sample))} -- ${esc(domLabel)}</h3>
36833759 const launchDate = parseIsoDate ( launch . launch_date ) ;
36843760 if ( ! launchDate ) return null ;
36853761 const stats = summarizeRows ( modelRows ) ;
3686- return { label : prettyModel ( sample ) , org, launchDate, greenRate : stats . greenRate } ;
3762+ return { mk , label : prettyModel ( sample ) , org, launchDate, greenRate : stats . greenRate } ;
36873763 } ) . filter ( Boolean ) ;
36883764
36893765 if ( ! rawPoints . length ) {
@@ -3850,6 +3926,7 @@ <h3 style="margin:0 0 6px;">${esc(prettyModel(sample))} -- ${esc(domLabel)}</h3>
38503926
38513927 // Dots + labels
38523928 points . forEach ( p => { p . _cx = xFor ( p . launchDate . getTime ( ) ) ; p . _cy = yFor ( p . greenRate ) ; } ) ;
3929+ primeDefaultScatterSelections ( "launchAllOrgs" , points , PREFERRED_LAUNCH_CHART_BASE_MODELS ) ;
38533930 annotateScatterPoints ( "launchAllOrgs" , points ) ;
38543931 const dots = points . map ( p => renderScatterCircle ( p , "launchAllOrgs" , {
38553932 radius : 5 ,
@@ -3867,10 +3944,16 @@ <h3 style="margin:0 0 6px;">${esc(prettyModel(sample))} -- ${esc(domLabel)}</h3>
38673944 // Label placement — exclude the last point per org (already labeled at line end)
38683945 const lastPtSet = new Set ( [ ...lastPointPerOrg . values ( ) ] ) ;
38693946 const labelPoints = points . filter ( p => p . _pinnedLabel || ! lastPtSet . has ( p ) ) ;
3870- const labelPlacements = placeLabelsGreedy ( labelPoints , {
3947+ const labelCandidates = mergePinnedScatterLabelPoints (
3948+ labelPoints ,
3949+ selectLaunchScatterLabelPoints ( labelPoints , 12 , PREFERRED_LAUNCH_CHART_BASE_MODELS )
3950+ ) ;
3951+ const labelPlacements = placeLabelsGreedy ( labelCandidates , {
38713952 fontSize : 10 , svgW : W , svgH : H , ml, mr : mr + 120 , mt, mb,
38723953 lineSegments : allLineSegs , dotRadius : 6 , padding : 3 ,
3873- priorityFn : scatterLabelPriority ,
3954+ priorityFn : launchScatterLabelPriority ,
3955+ labelFormatter : point => launchChartModelLabel ( point . label ) ,
3956+ pinnedLabelFormatter : point => launchChartModelLabel ( point . label ) ,
38743957 } ) ;
38753958 const labelsHtml = labelPlacements . map ( lp => renderScatterTextLabel ( lp , "launchAllOrgs" , {
38763959 fontSize : "10" ,
@@ -3880,6 +3963,8 @@ <h3 style="margin:0 0 6px;">${esc(prettyModel(sample))} -- ${esc(domLabel)}</h3>
38803963 strokeWidth : "1.7" ,
38813964 pinnedStrokeWidth : "2.1" ,
38823965 opacity : "0.95" ,
3966+ labelFormatter : point => launchChartModelLabel ( point . label ) ,
3967+ pinnedLabelFormatter : point => launchChartModelLabel ( point . label ) ,
38833968 } ) ) . join ( "" ) ;
38843969
38853970 svg . innerHTML = `${ gridY } ${ gridX } ${ lines } ${ dots } ${ labelsHtml } ${ orgEndLabels }
0 commit comments