diff options
| author | Craig Jennings <c@cjennings.net> | 2026-06-13 18:19:25 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-06-13 18:19:25 -0500 |
| commit | 749cb0885872571b36d9b3174067911a47fd5e3b (patch) | |
| tree | 4253b675c96dcdf78639611e4b57f66813929b7a /scripts/theme-studio/theme-studio.html | |
| parent | d0cf30bfa37864db12009c2f561c87f96bd66989 (diff) | |
| download | dotemacs-749cb0885872571b36d9b3174067911a47fd5e3b.tar.gz dotemacs-749cb0885872571b36d9b3174067911a47fd5e3b.zip | |
Fix theme studio span endpoint tiles
Diffstat (limited to 'scripts/theme-studio/theme-studio.html')
| -rw-r--r-- | scripts/theme-studio/theme-studio.html | 30 |
1 files changed, 20 insertions, 10 deletions
diff --git a/scripts/theme-studio/theme-studio.html b/scripts/theme-studio/theme-studio.html index 70726afa..72cb2022 100644 --- a/scripts/theme-studio/theme-studio.html +++ b/scripts/theme-studio/theme-studio.html @@ -557,6 +557,7 @@ function lMax(hue,chroma,fgSet,target){ function oklchOf(hex){return oklab2oklch(srgb2oklab(hex));} function isReservedGroundLikeName(name){return /^(bg|fg)(?:[-_+].+|\d.*)$/i.test(name||'');} +function isPureEndpointHex(hex){const h=(hex||'').toLowerCase();return h==='#ffffff'||h==='#000000';} function columnStem(name){name=name||'color';if(/^color-\d+$/.test(name))return name;name=name.replace(/[+-]\d+$/,'');return name.replace(/\d+$/,'')||'color';} function columnOffset(name){const m=(name||'').match(/([+-]\d+)$/);return m?parseInt(m[1],10):0;} function legacyColumnStem(name){return isReservedGroundLikeName(name)?name:columnStem(name);} @@ -566,7 +567,7 @@ function groundRoleOfEntry(entry,ground){ if(!entry)return null; const [hex,name]=entry,col=entry[2],n=(name||'').toLowerCase(),h=(hex||'').toLowerCase(); const bg=(ground&&ground.bg||'').toLowerCase(),fg=(ground&&ground.fg||'').toLowerCase(); - if(/^ground-\d+$/i.test(name||''))return 'step'; + if(/^ground[+-]\d+$/i.test(name||''))return 'step'; if(col==='ground'){ if(bg&&h===bg)return 'bg'; if(fg&&h===fg)return 'fg'; @@ -593,7 +594,7 @@ function groundColumnMembersFromPalette(palette,ground){ if(role==='bg'||role==='fg')byRole[role]={hex:entry[0],name:entry[1]}; else if(role==='step')byRole.steps.push({hex:entry[0],name:entry[1]}); } - const stepIndex=m=>{const x=(m.name||'').match(/^ground-(\d+)$/i);return x?parseInt(x[1],10):Infinity;}; + const stepIndex=m=>{const x=(m.name||'').match(/^ground[+-](\d+)$/i);return x?parseInt(x[1],10):Infinity;}; byRole.steps.sort((a,b)=>stepIndex(a)-stepIndex(b)); return [byRole.bg||{hex:ground&&ground.bg,name:'bg'},...byRole.steps,byRole.fg||{hex:ground&&ground.fg,name:'fg'}].filter(m=>m.hex); } @@ -632,7 +633,7 @@ function toggleLockSet(keys,locked){ // Group a flat palette into the ground strip plus structural columns. ground is // {bg,fg}; those endpoint hexes form the pinned ground column even when absent -// from the palette, and ground-N entries are reserved for that column. Everything +// from the palette, and ground+N entries are reserved for that column. Everything // else groups by its stable column id, not by OKLCH hue/chroma or display name. // Legacy two-field entries fall back to their generated-name stem until edited. function columnsFromPalette(palette,ground){ @@ -664,7 +665,7 @@ function regenColumn(baseHex,n,opts){ if(k===0)return {members:[{hex,offset:0,clamped:false}]}; const r=ramp(hex,Object.assign({},opts,{n:k})); if(r.error)return {members:[],error:r.error}; - const members=[...r.steps,{hex,offset:0,clamped:false}].sort((a,b)=>a.offset-b.offset); + const members=[...r.steps.filter(s=>!isPureEndpointHex(s.hex)),{hex,offset:0,clamped:false}].sort((a,b)=>a.offset-b.offset); return {members}; } // Rank a column's current member hexes by lightness and give each a signed offset @@ -905,7 +906,7 @@ function ensureGroundEndpoints(){ } function normalizePalette(){PALETTE=PALETTE.map(normalizePaletteEntry);ensureGroundEndpoints();} // The ground column is explicit: bg pins the top endpoint, fg pins the bottom -// endpoint, and generated ground-N steps live between them. +// endpoint, and generated ground+N steps live between them. function groundColumnMembers(){ return groundColumnMembersFromPalette(PALETTE,{bg:MAP['bg'],fg:MAP['p']}); } @@ -920,10 +921,13 @@ function setGroundSpan(n){ const old=PALETTE.filter(entry=>groundRoleOfEntry(entry,{bg:MAP['bg'],fg:MAP['p']})==='step'); const bg=srgb2oklab(MAP['bg']),fg=srgb2oklab(MAP['p']); const entries=[]; + let step=1; for(let i=1;i<=n;i++){ const t=i/(n+1); const lab={L:bg.L+(fg.L-bg.L)*t,a:bg.a+(fg.a-bg.a)*t,b:bg.b+(fg.b-bg.b)*t}; - entries.push([lrgb2hex(oklab2lrgb(lab.L,lab.a,lab.b)),'ground-'+i,'ground']); + const hex=lrgb2hex(oklab2lrgb(lab.L,lab.a,lab.b)); + if(hex.toLowerCase()==='#ffffff'||hex.toLowerCase()==='#000000')continue; + entries.push([hex,'ground+'+(step++),'ground']); } for(const [oldHex,oldName] of old){ const next=entries.find(([,name])=>name===oldName); @@ -2144,16 +2148,22 @@ if(location.hash==='#counttest'){let ok=true;const notes=[];const A=(c,n)=>{if(! PALETTE=[['#204060','bg'],['#f0fef0','fg']]; setGroundSpan(2); A(MAP['bg']==='#204060'&&MAP['p']==='#f0fef0','spanning ground keeps bg/fg assignments on endpoints'); - A(PALETTE.some(p=>p[1]==='ground-1')&&PALETTE.some(p=>p[1]==='ground-2'),'spanning ground adds interior ground-N entries'); + A(PALETTE.some(p=>p[1]==='ground+1')&&PALETTE.some(p=>p[1]==='ground+2'),'spanning ground adds interior ground+N entries'); A(document.querySelector('#pals .fstrip[data-column="ground"] .fhead + .fcount + .pchip'),'ground span control renders before tiles'); MAP['bg']='#ffffff';MAP['p']='#000000'; - PALETTE=[['#ffffff','bg'],['#bbbbbb','ground-1','ground'],['#777777','ground-2','ground'],['#000000','fg']]; + PALETTE=[['#ffffff','bg'],['#bbbbbb','ground+1','ground'],['#777777','ground+2','ground'],['#000000','fg']]; renderPalette(); const groundNames=[...document.querySelectorAll('#pals .fstrip[data-column="ground"] .pchip .nm')].map(e=>e.value); - A(groundNames.join('|')==='bg|ground-1|ground-2|fg','ground column order is bg, ground steps, fg even when bg is lighter: '+groundNames.join('|')); + A(groundNames.join('|')==='bg|ground+1|ground+2|fg','ground column order is bg, ground steps, fg even when bg is lighter: '+groundNames.join('|')); MAP['bg']='#204060';MAP['p']='#f0fef0'; setGroundSpan(1); - A(!PALETTE.some(p=>p[1]==='ground-2'),'lowering ground span removes dropped interior steps'); + A(!PALETTE.some(p=>p[1]==='ground+2'),'lowering ground span removes dropped interior steps'); + PALETTE=[['#204060','bg'],['#f0fef0','fg'],['#e0e0e0','near-white','near-white']]; + setColumnCount('#e0e0e0',4); + A(!PALETTE.some(p=>p[0].toLowerCase()==='#ffffff'&&p[1]!=='fg'),'spanning a near-white base skips generated pure-white tiles'); + PALETTE=[['#204060','bg'],['#f0fef0','fg'],['#101010','near-black','near-black']]; + setColumnCount('#101010',4); + A(!PALETTE.some(p=>p[0].toLowerCase()==='#000000'&&p[1]!=='bg'),'spanning a near-black base skips generated pure-black tiles'); PALETTE=[['#204060','bg'],['#f0fef0','fg']]; regenColumn('#67809c',2).members.forEach(m=>PALETTE.push([m.hex,m.offset===0?'blue':'blue'+(m.offset>0?'+'+m.offset:m.offset)])); const innerOld=regenColumn('#67809c',2).members.find(m=>m.offset===1).hex; // survives a count change |
