From 67b9b91af60eba4321bd34cac39444806e4298ef Mon Sep 17 00:00:00 2001 From: Kyle McDowell Date: Thu, 11 Jun 2026 10:50:56 -0500 Subject: [PATCH 01/12] p3-polish: delete 156KB of orphaned HUD-era focus PNGs and their dead CSS hook Co-Authored-By: Claude Fable 5 --- web/public/dualsense/focus/focus_L1.png | Bin 5877 -> 0 bytes web/public/dualsense/focus/focus_L2.png | Bin 6421 -> 0 bytes web/public/dualsense/focus/focus_Lstick.png | Bin 8822 -> 0 bytes web/public/dualsense/focus/focus_PS.png | Bin 3919 -> 0 bytes web/public/dualsense/focus/focus_R1.png | Bin 6129 -> 0 bytes web/public/dualsense/focus/focus_R2.png | Bin 6579 -> 0 bytes web/public/dualsense/focus/focus_Rstick.png | Bin 8742 -> 0 bytes web/public/dualsense/focus/focus_circle.png | Bin 5083 -> 0 bytes web/public/dualsense/focus/focus_create.png | Bin 4630 -> 0 bytes web/public/dualsense/focus/focus_cross.png | Bin 5384 -> 0 bytes web/public/dualsense/focus/focus_down.png | Bin 5202 -> 0 bytes web/public/dualsense/focus/focus_left.png | Bin 4748 -> 0 bytes web/public/dualsense/focus/focus_options.png | Bin 4765 -> 0 bytes web/public/dualsense/focus/focus_rear_L.png | Bin 3024 -> 0 bytes web/public/dualsense/focus/focus_rear_R.png | Bin 3009 -> 0 bytes web/public/dualsense/focus/focus_right.png | Bin 6062 -> 0 bytes web/public/dualsense/focus/focus_square.png | Bin 5702 -> 0 bytes web/public/dualsense/focus/focus_touchpad.png | Bin 6357 -> 0 bytes web/public/dualsense/focus/focus_triangle.png | Bin 4777 -> 0 bytes web/public/dualsense/focus/focus_up.png | Bin 4552 -> 0 bytes .../button-mapping/layout/controller-art.css | 16 +--------------- 21 files changed, 1 insertion(+), 15 deletions(-) delete mode 100644 web/public/dualsense/focus/focus_L1.png delete mode 100644 web/public/dualsense/focus/focus_L2.png delete mode 100644 web/public/dualsense/focus/focus_Lstick.png delete mode 100644 web/public/dualsense/focus/focus_PS.png delete mode 100644 web/public/dualsense/focus/focus_R1.png delete mode 100644 web/public/dualsense/focus/focus_R2.png delete mode 100644 web/public/dualsense/focus/focus_Rstick.png delete mode 100644 web/public/dualsense/focus/focus_circle.png delete mode 100644 web/public/dualsense/focus/focus_create.png delete mode 100644 web/public/dualsense/focus/focus_cross.png delete mode 100644 web/public/dualsense/focus/focus_down.png delete mode 100644 web/public/dualsense/focus/focus_left.png delete mode 100644 web/public/dualsense/focus/focus_options.png delete mode 100644 web/public/dualsense/focus/focus_rear_L.png delete mode 100644 web/public/dualsense/focus/focus_rear_R.png delete mode 100644 web/public/dualsense/focus/focus_right.png delete mode 100644 web/public/dualsense/focus/focus_square.png delete mode 100644 web/public/dualsense/focus/focus_touchpad.png delete mode 100644 web/public/dualsense/focus/focus_triangle.png delete mode 100644 web/public/dualsense/focus/focus_up.png diff --git a/web/public/dualsense/focus/focus_L1.png b/web/public/dualsense/focus/focus_L1.png deleted file mode 100644 index b6a6c163dd9ad99630ea075850d82347d1c10c10..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5877 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 M*b`E*J?^Lf03rU{hyVZp diff --git a/web/public/dualsense/focus/focus_L2.png b/web/public/dualsense/focus/focus_L2.png deleted file mode 100644 index 656cda1443e3fcf649e3f561d415ee4cbcc44368..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6421 zcmeHMSy)rqmfit0pp8+vUMd!Z5&}3fMPv#@>LM6L@K%)|3QCI@6=W0=2!<$Hs6^02 zArK+jv{+scP%P#lD1(t9Vw&L=85klEBZSc~(>qjuefz23s-Aqvch1>+pSAz}uYaw* z_Q|cIULLyZwypyJ=n@aQ{Q!U_1ptks+G}BpXsGEiyy!$6^os`IucqoBg7^b=9Dr|{ ziEgexQ67$py>AA~1DYmCuNy8Om4DxW&Lv6%u?W2nIyXzSPt@PI_K4pe;5hO+yGGde zdR=9NiO>G`H<()^@0GtWG3Fcpr-sFUZ2v+}(OD+ima}huZ;L&<_WR!&sfA^EmGj;) zzB3i73NC8z@J~1&pb^4wr_*Dz#(ls0QAio zC;%Q^{{x#Frif#0HQL)_?D)p~iB<&wfrr_B^&cy;WJ979_(a8%l{pBE|FtyJIR#^f zWCrU|Qn(h-p9fw;W(@i;i_UpYd>IOW%=f<5LRkpHm_?o{qeD^D+9v=M>w1p&O&XZR z#Z^kVk%n-sI(qnW{}im0Jx0jdbOnHj9dJaHq3PW8Hsh-jACpRz*n#8wh3nkQwhrvt3qo;#FAdA#YPot?U8QJg89o8a@1R zRLW}4)3eu*ivI2V7U7a4p#@UU%IvG3k5HrYZq!0`HOt=!5TMUr3saD>1WijhYIZ`m zrk#I1UvW=XLL566S{sEQJ_AWKFryUHHZZH16BZIl!7c;{%!OW!|Lu<2guOYO)H``~ z-NWihLpCLIH9^D%_)=}^z&H$&_IfyBuQ7j=q3i3CBkL;2hbEpwJn>HNJ{jVb0|+pF zR0Guo9hFIej(Qlk2Y>==2<2S)s9P3wTK9?bvsHv>JrGp7g?_I@*f^>06zvEjAU&DK>Hj_3|iZi`1G+K~E zEi(%(OlaOH?+rgXzT{`{FLFjnAwUTJpfACI+)AHv2#tAS2`FYnjo-+-RGJN zg_1Ld8afHnOY~;S`!{OXC%yVy(^f&Gs97#eFgg?w)X_<0eX}f<-Po0I^~r>C)KR#l;>kzpLEKD=zP+^Y2ZjM;sNZq{PUWul=^(ed#|5urKMA~@`bMZ~JiGArhn1~OqOeeH*AQS31 z^cy{V->cQ&3^d8?Lp(KHMf5FS3uWID=JR7UD%b#SAG|DFy=Hq98+s`fW`mxMW)xo1 zZe~JI<;r>YX#^;4f+&yEm=^%>193 z;V^RXw|SbFV8RB7xJO$9MKQ4R_SeT1Y65!lMhb7R{6XaGT&FrS1YUA5Ls0yy)XL|b zfG{xK|E^YcaTlC&>i8;`AuSMY+G_qf0tME^fQvl!Kk18Q&|2{g06yx`j_nuY%k_%qd{SoR1>KxJcfJ+O%ul$m111_-KRTCvf8CNN4^X#xDzf zCbTbiutnMPk_T8zeBW^0-A(ajHfC@qz;AcF@7U}&mf9T9S zgC%_J?alqzaRkttzk|}c-q}Kw*j~9}9%OPqH#(u|0k-a*^{s_Z(<*L*arg#kBkh)p zd>BdzQu^6^u1&ri#%?wbbPR=u8%JDu=OP|4gBr_8RUIRs@vNuwn;Dh;}yzksqhnS>UW z3P=q-!lr=O}@Ll@+$2@&h&{U2P)sby?=fUZ6Dw@mGIYvCX>+Q!@hZhjL4tGuqZ&T znDD6<{ZlaDm^zs0lVj;~y9X_V%JKrucj2aUr@Np5u?&TqV`d-Z@rg%SQf7m5MW?rpN^o)6pr&gr*eX zOs{o~CYVjsK*ftZCwB>#T)W84t%DDjC_|BBs5+$IT1le$+zb2lDDd4akG+o@XRwKT z#fduMj;w*fC(*cT3Ip$u{M@iM~WO!jXsRzGRT9cD6N93=ue7V z`Fy;Oav*!lKb*{I&31YDWVjHx71Tdx9646&AST>7;M4KtjC*ka^_?K$u8_O%NIK>2 zKC;JXG~vShvY4?lbaqjt3HQaTNX{k8!M9iKAOm=%xQ5-?WM(Ai#qro|LzjU)oZ+M@;cc%dtk9PBCbsw0=Nte;SKsOmVe z=0QKi-hV2+FcmIx6SRnNu8^Dr_twKL$*AP+rv!89F{(-aBdTp0;qk&VEP=i0Hh<@b96{q!Rb*G*&K9X^y>MoR(d@S3 z%qIkEjb2dL$7lie4PH{)%Y!co;zU~$S}ZOv#$5VrA>RGH^UhC_2QqV3HO^$9)^ga% zXi9eV;|fPs2RTXfo-BG=t6Ih?9cF4&=c+?gr3GeJTiSe2c~0KLN)Jtj6PJe?q$ihE zd)i-w0s0}hLSvKHKkXhE5)I_F{_oOCj&RN=a^I5Ju+S~oN zWzFUG0}BV4rw>i0peIyc7`BPq`AFvC#H-Sexp^t1R~CT&tLb=PwCF7-&F!E&J%E3+ zvLyB~Osd%-MA`^~TP3oc;^K_Q{MLwa7ni1oe-w5b5hoXjw0(op!ZebW@&jM98x}qv zqE%yJ4poYt$b92%P+3VkP%pmUXErls3{~mjcsA%>fAoN(mL6FDz(hq6PH1?F=t1sI|KX7xBHL7XoSpMF)9&~!NrO_m;+941P# ztlN6i%TJ!b^p58+bk8# z53I?~Ik@D(B$GTpmx?E=Ys=0WJh%&MAa$`>AAhp;$5_jtpnIyb3z)_P_Mm(|RSv6j zC}SP`@o*>NDdJ>5mYWr~M==snS!)%r1_O#a;mXSfu~m_!y-5jSl@?^J;mS>CyB2lEg=d~(d8+r7OSxM>V2BPrP*?-^A=q()r@2r3Tu((Fym9~p zrl@`&@Nv#N75 zp-jSd!hhr;`>X9g_oK#FzQ6MQ wr+q>DDz>j;`zp4tTl63Nq5l6(GZTsV?&8^Bo|n$5|3@Gm@Nz5sKJeOq1AO{rC;$Ke diff --git a/web/public/dualsense/focus/focus_Lstick.png b/web/public/dualsense/focus/focus_Lstick.png deleted file mode 100644 index b411de37a48c84697d3f0671ac8c150c7def7a4d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8822 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 I2hXej11~9&jsO4v diff --git a/web/public/dualsense/focus/focus_PS.png b/web/public/dualsense/focus/focus_PS.png deleted file mode 100644 index b68ca143458b16ea7cc09db7689b38b58f375ea5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3919 zcmeAS@N?(olHy`uVBq!ia0y~yV6I?bU<%-11B%>vc5ES#;w1zQemaSlBNfIZ}4w{iK;s#dSb!Xd zmIKTT3>^YM7cmGj@iQ@8^Jm5SV8#Qo zn_Pt(jz4>PX3xBt_UX^&&-_`N#uqk+oguIH0P};5KaKI|lVf7Y^LoH|AoToo zU=sksOwR^Z{^qJ57#(<#Hv@U*}BQ@cWu^#dF8X-WzeBw;ETtZ_e3m!@n!s_;XrX-JWN*^||YJ zzAI)-C}rYrXn&V7t;71py3e~y*607IWZ%s4u+;JU&%3q^H#mXPu^$S7j{kY=b^rRG zcUS++zq5D#YRB&%tJ|0x+JW8;D6#QgA$#WN_Pn@zk2GH}c-*?3W0rlMf#G{%{qN5? zMX;j@Ope3D1CqCWEJ| KpUXO@geCwjc}Ii* diff --git a/web/public/dualsense/focus/focus_R1.png b/web/public/dualsense/focus/focus_R1.png deleted file mode 100644 index bfb8160859723bcf86651c9fd137132f70f2916d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6129 zcmeHKX;f2Lw!RD{U{O#OrHD+Tfjk94KnX|yOXN z&c3%Ukleo5xo;-~L0`aUTrWb9N&*BaUr^rxB%`992jEYGdd4Rfg7%nVKPC7gZXSYk zAHlBQTuLaP6ZmIUD6a5igSAieKOT7G7k& z)uN)qP!!JnH-Ksy~E}HrtmQ5vU zQEVLXC2)wmk1-(rEOWfTmJ*YK2+E`jAD%kWB&raURv?xALI4OmC%*)!AyZW&2s){8 zT@8XRoSIOApdYuz+noF#2~k;`qyj$ly1HW;88~*zPbLlJ*(FM+utP|CSk^%PZSOqgJaEAxP`{ zgUAey|4iL!q8Q7*S^njWPWOx%LuwzUUJA4A`Y7pzElF)U0UnZv8c=6SACu!?)Nx1n z&mc#oBAe$bP=JdaZ!zYjp@FX%urNBe_lGV*A^%zQbe>~hUt`6-fk%F+plHY5(A0pjR;)0VVy>g4-?WI^TdQ zslT@X4}=ttMF>_Obw-0?C&e5=y00}W8{F&!$EzAO zuivw%eXc@M$9N)@={=_13rteO=kah5bd=yO7bUEnV!9X1sV3~lAoWG$iKnw1?eCrg z=Fc!=;r3%j9R#FMV_BKFA9I7*9k|Qy7C_Xi3T|A)Mdk23@b4%q7(zR-^LuOF7ja#c&ILuTnYd^ zz!>yCQidiuOlkd53>d7=+X5^-9~0bG1GzoNK*ojViOqM>E+E+Acs0eEOFw}ufe7d2 zfT(na7Q6hm1{nD{7=Zt~l)?NQjtp+e7WE$@s2CUmM$%Hs(6-&tYHvVKJK3Czqu8F4 zHc1wICT_;wHiJ&qHEQxlDoFB+%xurd9rj5W$y_^|mx9JDM{f;mRS{2;I+qLIz%&)& zS6hN6paxfZ>tU|N^>P<;NfqaSC@2YpMmAcDS*eOe7rYC!BHH7&DZ5v9(w=#wLD66?) zEit|U7nR4e!nOV?6(~0XMmslZOce@TN3oDsutsG{Q(VW_8!cW)W8oAtgk8X}KJBdx z$~7%{B^TFG+Wk{xvpyV|Ungd##M?%tS_%{9nAK`*HKcnceCaat}r^eeetu`oVprmn+3uVROYuqKwNMNF)p=m z@}tN7VI9vX2%6YC^6G%3z5MElCdc0ga_bav@gBKiT_&f}q$dQWQ+R`dlr(O5zStuB z{%V8aYDsWbhb<}&&lqy!^Z3R=>MuHA`Q?nVXR~4zFRGA4YJNH3*H5L1h>#dVn^rZ)%P5==*Ttp`0E4vrPH5QN>i84F)2NK zPdFu>apjEs1H6Hg^l0EqL8T3kD5ANQLc`^iQQ~M*Lrc%xr9IYhaSUk)Gt9^6_UcpT zTGn8Cg~&m>-5qtVL=Nn8v1#A1MR*Gn{GG}=F$KG!G_IhJS~H?su;!ZKdBAE;)|%Ki z7uVd^^=qY2fooqZwvM0ZJ#>kkMtg=uc+ld-FZGN>Ezh@7g&p32NnOpEe$e9D7I^C)>%0n-Zi#HMq$khcxq^KEaM_D#yf5EB@g^P8Is+_^Mifm(??9%miV%6`E#t;T%^`M}&uIPh zccmU5+fQsL_yvq3$SQvLbE+{2$wZ_WO^V>rqjJSxdve~j_?1quKSbgcKQISz3NH|T zhDp~K-f4kY0*po^lWC-0ktgSna+LXL?+A~10sG2%`7NBk@#dN%+|HaK`F|F_3)C9T z*O)(NDD78~mbkSQ{Phs2pDc>cpa_%Ax`Gy*WYiz*?XdEBVUaDC)=Cpn>Ex=N9Q60l zjK9;(kp>^)UZdhWSU>eP=7+JzI!Y(+Dpk=K874QZa(VhX5|zDJef)JXS}=xE7Tmrj zvL?+AYKjJ@>2|f<>ByFHIZwP~Otj?CeS!PzWexY*ZS9*D{oO<9Rf zr~8N{CUSBCVc3Wt>lvwxb?#W>SJbXMQIz7dbHOQUNTP5(hN*4lu&BO7EALNFNPc}D z!tzB;NR(nx z#rOwlQ)|hj5$5!TG|L6m@Qco-*Yi66;grNnjc9S(QKN)=wF+ zV?PZ1Mu#AK%dM8Xd9=5#d!+Xl&F_}Ud!82H{QIdp(Kng}wO;yqW+kb2h4;+HKCiX_ z<724wvY`w4s$k?D9TM0-Wg%KeB+q9PL-qB>>zmrZJQgIul!8Gt`_2yrM?7qR`~CYHrUN5G5i{?z;yP)nRNXrAFx%FhYqN z7re~nTA@Zadn4t_2G*D&wWCN_C|fzL7s*kk&bDCqQU~(IJSJm5l8;mHN7t(z(qOE_ z)*V@scQwlNDwmh?aN~_)TYgU*op%_z?)D<^D=@-F9yvXmd<-Gjj$R6K;aBt%`7TaMlIP;a zU1WX%rr4!!6r)rz`e_3veZ7ua>5|05S=lR(kkObIZDY#NLEm`p$q`v>)C|#fvVwQi3YBxFt zd6+ubrYv7xY8TBHY7$uQw2taw))kGZ^w#m*z*^J9XM6stD%pTad z44uU$`?RmNG}wF${m-^|o0IK?fbMTs!*(m!Zjak<19&pGTfzTtD|or7Vokcc!#JSE R2aG5X{3nuY?Wuqp{{k}2TYvxn diff --git a/web/public/dualsense/focus/focus_R2.png b/web/public/dualsense/focus/focus_R2.png deleted file mode 100644 index 7b5f18b94070a062c2cda8b9cfe5cd2aa267e036..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6579 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 Ty9oS_fFM{G+>Qs^15f`SyJcVg diff --git a/web/public/dualsense/focus/focus_Rstick.png b/web/public/dualsense/focus/focus_Rstick.png deleted file mode 100644 index 18aab0718e77e1ccd3346e1f1fd594f6cd102f4e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8742 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 diff --git a/web/public/dualsense/focus/focus_left.png b/web/public/dualsense/focus/focus_left.png deleted file mode 100644 index a43684bdbc271b6566319a0ec85dfb9d579cbeb6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4748 zcmeHK`%{x=7Cv0spcMfbaakbB?^+CJ0k!5OLauGc?$o_0iBz*}<6?QtnDzNMd&M!~XOn7rjT28TUA;o#>pM zgCqPwo%{F`+HqG=@(#rz!i8`Dbza>%_QMIoP*HJN_*yYxv2}YJYn zWrP8&NMbni5?g6-b2HfhyQ4p!!MOR9#x~5K;)W)ywvl-f?5Cc<;kj=%oiHj1Os&*$hK zjbGpY4ZRyDo!#1+=)3MSnW0U_BLJ;Fd}g3&K~MO&fys1`j33TOJOJz) zzNp%pv*ZC(b${$_1?AFWDt@|QJi`y*IHK7slZ#pE4HG#FE#7nkKC#8vz6ju7FRC;R z2-2%7&PZ!!6!8VLwK_w64bPBxWC@j+h8WzF6{`!uvl8{GoVO0v7A_^Pni%GHJ5t{G zw|XJ}N|wBrU$9ilP2ufk2L@d8F^L bw9Mfc@6Z-;|w39+A$PInUwGbh ztv*aQOAwAa(&>T2{F^qglYrQqj?<45wvnnPC^-aX_(+0uyf@H)B|}IC_8}w)P3Wxd z%lXi4d45CYe!p3oVF@*(RiQR5EH{ghqmSgsWYn-N}f$V3-)Sa)s&m)ceNxJ$f1?#-+#{*d4h$?^S=X?HG>ztjS|A;&3 znvqK#Nv(1RQ6FkGQwYhQ^IgN^(~9BJ_KQ8Cc$)XKFFEJ>6@3w&h}1}x_|&5V`gl%Q z(WGhqavPFWRMNew%%QIF)l z_xJJBZ_6A=PX*{N^)>C>)*~KdY%P%gdS^%g4perif)Sl{(seE<6;6~R4gaMLV z%{HL5i_xYnyDMBGr>sC5XYG(A$Z-PL>r#%poa5KCA3)V?i@(ydz56|D0O=Pf_^0Ic zci%Kyhop%b-Jerz0cvmC;jgqS{^Mc=Z0EoV++`Z+{yp-f7eIbCiaCB`(>s@cb?Uw* zUTM5aDDxOEbM>QHL%uZvaO1;N+4pY}_-3J?()jFZ01@eZ6zB86Q^urWcYuyJ>4tKD z^`H!6p#$&zxO|!n5Ra+EdRcCD{_L&^q{Gjd`<)w)``yoRD&>BW_m>1@dPG9&gVFlw zEdn&Dt+#EqSBu|WE#+2bQW5w?nH}C=xn7>u@@j0i|4T#+Fp6T(2?YLVM?q(UE!GZz v#454@*y(98TWVqvgryrSqu_sgJnE<|9bt_L9O}Q(90zQFe01jrX%+tkY`QN; diff --git a/web/public/dualsense/focus/focus_options.png b/web/public/dualsense/focus/focus_options.png deleted file mode 100644 index ad5658c03fb2bc4b0deee700020b9d2ee099775c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4765 zcmeHI`B&3d9(@U5WLMl830T@d9fCq(1ab&OtO}8}(1uto24ra+M0SD*1n8g^lh}la zk!`F8osKBc0?HD=f@VU2ID^PhLJ*UNDrAGf5ZUH^=^ruY%*hWq-;;Yj@4frE?|$yP z7#$g6Yqiq~0ANcAJs1Ok83O=x^u`Skk*S_shaby~(4*M^Y4KhMVNC*l5 z`a+=3f;pse)wUD^K=grE5Ukn+nF3dHX8`tFnqZSACPVz+O+$U%Su_9{mX4IXoAu@% zHAo)BO5yPDJ>@AGkBvfKVfC5;`e>S~k>1tKS1K&0(P4*RItWj_;~fv1E9TCOL|R;_ z{EP|!&DGDlf8qvXgMH9vNQJwvH>t2XlT@4TF04)ampPz+DT|z=axvKYKC@vYT$;+% zc*Bz!KX1}`Ol?A?8vwUoG5(^eyAZH=0BsML$q#tSQGc36{SjopL0{f1d#qDG9KiTU zx(;aEj1+FUjdThX^&!km8g-mVr2W>4H{7bRYT9t@&nO5z5bLS^PPLUt8(6hl`?V=L ze}a;VCiHKQ0N~0{3fEpd)l?j6zSjphCe?NVL|1r z7d$@9g-}Yr)A6f+{Ez28;E@J(IOmMub=E?@vRwb3gzN zkGR>!Q+`#EFIR_?cF?|U`vwiX8d)~yf9krbtgCHOqN?c@u=zi!lP`2)Hs|Xak3NFj z-Nz{!)|ef&6e~oCeZh{K)f|*P3g3uqD6Co6DP>)!Z)%7aJL>SeqWre~{t+Tei=zBX zJFcug&;99R7XoDS@4QGmYQY}K%A1?$q9#Pj-Hybg_d2&_VthV9R#esD<6uh}|FrTt ziSV0A^Wl)q+DcSw1|E*RwwUG1JLezYBT#B`VoT$tk%1_{yr^#IkO$?8eo#)}{Z6)i zyFHzw2<~?pWFaD{)MvTyrmIgL+NyeD7c(e;K6yR?^;z@3w4+A)iyD8%wczp;kwg!M5229l>z(EzlL!ZLo(ES{ z*JwS{kL+vX$sC)Vn$Xs6I>5~RnLqWEqrKFyR;S!W35v*am5jztiuf*QVo#q<&-F<= zH)vI6?tOkjuI8`!wXiw9)HpoJT_#BK#nSxOmoLx19Lk6ux?wXOFZ$4VdpNwEnItl& zr=NsPR4Q!7eWT8dEf;dnTpDZJ88nf?UBVXkH6%0a>}g)`jc%%(p~wRkj8g26>gHRk z@6K_@#3fQ!V-&a9&A40Qxx@R{(bhVbdi%M>+n+Ek92lUtWAW<>{=+232JPyW?xmQD z(*o&GK_n~wS6<06IvZ(vZ&1WsIG5~Z93po22&VqNb~38+K*i*=<{6Kf`)>Bx7U&pe zL&}9tyirZm5(kB>`9j6?64q`riuRS1v;r+h&`v8BrTB*9uewJFdFOpWAe=hUB8QfH8dYH&ymvY8^7zgPClZQ%r83${{uNZO)tce2Xw=om5gK@XOfQ* zK0{E=dw=Kn*Ycsvma~{9bJ%~&(v<(|8wW#i5w7IZ8|`3_5AXBZX;)(&cTM%0z?j@6 zzJc$lpQ;6_!%*3wHnCm@tFv)yUOWNtU?SB{fh_i z3_%Ubw~V5E>K61>KjgfZJH?zVeH<>0ttbzZS$kpEL1%Gan5=MlwR7cYxHA>dcq{5rMW>hvpS+tMctWq{kpGYD|I8SCK7=dVE*@GY4KX>)Mi&?m;D~>c1pt5h4jvA6|A8Pu#B_iQO|VH5 r#3Cj`n5My$5TfyM0suC2 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 A`v3p{ diff --git a/web/public/dualsense/focus/focus_right.png b/web/public/dualsense/focus/focus_right.png deleted file mode 100644 index 8a6743d629d1064598c7edbb73fdd9a6563d9c67..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6062 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 diff --git a/web/public/dualsense/focus/focus_triangle.png b/web/public/dualsense/focus/focus_triangle.png deleted file mode 100644 index 804d8be57979c53d94612b8af570830fd0f07733..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4777 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 diff --git a/web/src/styles/button-mapping/layout/controller-art.css b/web/src/styles/button-mapping/layout/controller-art.css index 5532ca6..4357df9 100644 --- a/web/src/styles/button-mapping/layout/controller-art.css +++ b/web/src/styles/button-mapping/layout/controller-art.css @@ -64,8 +64,7 @@ z-index: 1; } -.dm-controller-base, -.dm-controller-focus { +.dm-controller-base { position: absolute; inset: 4% 4% 6%; width: 92%; @@ -85,19 +84,6 @@ opacity: 0.46; } -.dm-controller-focus { - z-index: 3; - opacity: 0; - filter: - drop-shadow(0 0 6px rgba(0, 112, 204, 0.55)) - drop-shadow(0 0 18px rgba(0, 112, 204, 0.4)); - transition: opacity 200ms ease-out, filter 220ms ease-out; -} - -.dm-controller-focus.visible { - opacity: 1; -} - .dm-controller-focus-card { position: absolute; left: 50%; From 94b7608d1403e325167b7007fe0a6569dc781c90 Mon Sep 17 00:00:00 2001 From: Kyle McDowell Date: Thu, 11 Jun 2026 10:54:13 -0500 Subject: [PATCH 02/12] p3-polish: saved rail 12px rows, 10px title, AA-passing muted ink on raised surfaces --- web/src/styles/tokens.css | 4 ++++ web/src/styles/tuning.css | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/web/src/styles/tokens.css b/web/src/styles/tokens.css index 8f9bd53..92daa68 100644 --- a/web/src/styles/tokens.css +++ b/web/src/styles/tokens.css @@ -8,6 +8,10 @@ --hairline-strong: #2e2e36; --ink: #d6d6dc; --ink-muted: #8b8b96; /* secondary text only; not body-sized prose */ + /* Brighter muted ink for small text needing AA headroom: #8b8b96 computes + โ‰ˆ4.46:1 on --surface-raised (a marginal fail); #93939d clears 4.5:1 on + every app surface. */ + --ink-muted-raised: #93939d; /* accent โ€” PlayStation blue */ --accent: #0070cc; /* primary buttons */ diff --git a/web/src/styles/tuning.css b/web/src/styles/tuning.css index c1a2473..8246255 100644 --- a/web/src/styles/tuning.css +++ b/web/src/styles/tuning.css @@ -503,11 +503,11 @@ } .saved-rail-title { - font-size: 9px; + font-size: 10px; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; - color: var(--ink-muted); + color: var(--ink-muted-raised); } .saved-rail-rows { @@ -523,7 +523,7 @@ gap: 10px; padding: 4px 0; border-bottom: 1px solid var(--hairline); - font-size: 11px; + font-size: 12px; } .saved-row:last-child { @@ -545,7 +545,7 @@ .saved-row-saved, .saved-row-was { - color: var(--ink-muted); + color: var(--ink-muted-raised); } .saved-row-now { @@ -588,7 +588,7 @@ .saved-preview-note { font-size: 9px; - color: var(--ink-muted); + color: var(--ink-muted-raised); white-space: nowrap; } @@ -614,7 +614,7 @@ .saved-discard-button { flex: 0 0 auto; background: var(--surface-raised); - color: var(--ink-muted); + color: var(--ink-muted-raised); border: 0; border-radius: var(--radius-s); padding: 5px 12px; @@ -671,7 +671,7 @@ padding: 0; font-family: inherit; font-size: 11px; - color: var(--ink-muted); + color: var(--ink-muted-raised); cursor: pointer; min-width: 0; text-align: left; From 8aec75bc1fa9c0357c26f63eda491baa9fdfc11f Mon Sep 17 00:00:00 2001 From: Kyle McDowell Date: Thu, 11 Jun 2026 11:01:30 -0500 Subject: [PATCH 03/12] =?UTF-8?q?p3-polish:=20Edge=20slots=20speak=20produ?= =?UTF-8?q?ct=20=E2=80=94=20friendly=20agent-missing=20error=20(note=20+?= =?UTF-8?q?=20toast),=20empty=20state=20teaches=20Fn=20slots?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/src/App.svelte | 9 +++++++-- web/src/app/edgeOnboardProfiles.ts | 10 ++++++++++ web/src/lib/features/controllers/EdgeSlotsView.svelte | 10 +++++++--- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/web/src/App.svelte b/web/src/App.svelte index ae35f9e..79fef5a 100644 --- a/web/src/App.svelte +++ b/web/src/App.svelte @@ -26,6 +26,7 @@ edgeSlotWriteLabel as edgeOnboardSlotWriteLabel, edgeSlotWriteTooltip as edgeOnboardSlotWriteTooltip, emptyEdgeOnboardProfileState, + friendlyEdgeSlotsError, isEdgeTargetController, shouldReadEdgeOnboardProfiles, shouldResetEdgeOnboardProfiles @@ -1495,7 +1496,9 @@ edgeProfiles = await getEdgeProfiles(controllerId); } catch (caught) { edgeProfiles = null; - edgeProfilesError = caught instanceof Error ? caught.message : 'Unable to read Edge onboard slots.'; + edgeProfilesError = friendlyEdgeSlotsError( + caught instanceof Error ? caught.message : 'Unable to read Edge onboard slots.' + ); } finally { edgeProfilesLoading = false; } @@ -1534,7 +1537,9 @@ showToast(response.message, response.accepted ? 'success' : 'error'); await loadEdgeProfiles(controller.id, true); } catch (caught) { - edgeProfilesError = caught instanceof Error ? caught.message : 'Unable to write Edge onboard slot.'; + edgeProfilesError = friendlyEdgeSlotsError( + caught instanceof Error ? caught.message : 'Unable to write Edge onboard slot.' + ); showToast(edgeProfilesError, 'error'); } finally { edgeProfilesBusySlot = ''; diff --git a/web/src/app/edgeOnboardProfiles.ts b/web/src/app/edgeOnboardProfiles.ts index bb6f65e..e3d7f24 100644 --- a/web/src/app/edgeOnboardProfiles.ts +++ b/web/src/app/edgeOnboardProfiles.ts @@ -90,6 +90,16 @@ export function edgeSlotWriteLabel(edgeProfiles: EdgeProfilesResponse | null): s return edgeProfiles?.supportState === 'read_write' ? 'Write' : 'Stage'; } +/** + * The missing-agent failure arrives as dev-voiced API text (thrown by + * getEdgeProfiles/writeEdgeProfile when no real agent is serving); speak + * product before it reaches a note or toast. + */ +export const friendlyEdgeSlotsError = (message: string): string => + message.includes('requires the real DSCC agent') + ? 'Reading onboard slots needs DSCC running.' + : message; + export function edgeProfileNameForSlot(slot: EdgeProfileSlot, profileName: string): string { const sourceName = profileName || 'DSCC Profile'; return `${sourceName} ${slot.shortcut.replace('Fn + ', '')}`.trim().slice(0, 64); diff --git a/web/src/lib/features/controllers/EdgeSlotsView.svelte b/web/src/lib/features/controllers/EdgeSlotsView.svelte index a3d6eed..0026f82 100644 --- a/web/src/lib/features/controllers/EdgeSlotsView.svelte +++ b/web/src/lib/features/controllers/EdgeSlotsView.svelte @@ -82,9 +82,13 @@ {:else}
- Fn Slots - {edgeProfilesLoading ? 'Reading slots' : 'No slot data'} - {edgeProfilesLoading ? 'controller scan' : 'unavailable'} + Fn slots + {edgeProfilesLoading ? 'Reading slots' : 'Nothing read yet'} + {edgeProfilesLoading + ? 'checking the controller' + : 'Fn slots are shortcuts stored on the controller โ€” hold Fn and press an action button to switch. Press Read to see what each slot holds.'}
{/if} From 682cf37334f6ea1add1f571d4184c16c012d59f7 Mon Sep 17 00:00:00 2001 From: Kyle McDowell Date: Thu, 11 Jun 2026 11:09:54 -0500 Subject: [PATCH 04/12] =?UTF-8?q?p3-polish:=20replace=20status=20?= =?UTF-8?q?=F0=9F=8E=AE=20emoji=20with=20the=20brand=20controller=20glyph?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/src/lib/features/status/StatusView.svelte | 4 +++- web/src/styles/status.css | 6 +++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/web/src/lib/features/status/StatusView.svelte b/web/src/lib/features/status/StatusView.svelte index ff3ec65..a678914 100644 --- a/web/src/lib/features/status/StatusView.svelte +++ b/web/src/lib/features/status/StatusView.svelte @@ -138,7 +138,9 @@
{#each controllers as item (item.id)}
- +
{#if renameActiveId === item.id}
diff --git a/web/src/styles/status.css b/web/src/styles/status.css index 8088646..2e0d006 100644 --- a/web/src/styles/status.css +++ b/web/src/styles/status.css @@ -110,11 +110,15 @@ display: flex; align-items: center; justify-content: center; - font-size: 16px; border-radius: var(--radius-m); background: var(--surface-raised); } +.status-controller-glyph { + width: 30px; + height: 22px; +} + .status-controller-main { flex: 1; min-width: 0; From 1993d68d15b4ff9bc0dc29d04405d4b8c290d47e Mon Sep 17 00:00:00 2001 From: Kyle McDowell Date: Thu, 11 Jun 2026 11:15:18 -0500 Subject: [PATCH 05/12] p3-polish: render color swatches beside hex values in the saved rail --- web/src/lib/features/tuning/SavedRail.svelte | 16 ++++++++++++---- web/src/styles/tuning.css | 13 +++++++++++++ 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/web/src/lib/features/tuning/SavedRail.svelte b/web/src/lib/features/tuning/SavedRail.svelte index d7da522..a55c564 100644 --- a/web/src/lib/features/tuning/SavedRail.svelte +++ b/web/src/lib/features/tuning/SavedRail.svelte @@ -59,21 +59,29 @@ const changeSummary = $derived( outsideOnly ? 'Unsaved changes' : `${dirtyCount} unsaved change${dirtyCount === 1 ? '' : 's'}` ); + + // Lightbar/redline rows carry raw hex strings; pair them with a swatch. + const swatchColor = (value: string): string | null => + /^#[0-9a-f]{6}$/i.test(value.trim()) ? value.trim() : null; +{#snippet rowValue(value: string)} + {#if swatchColor(value)}{/if}{value} +{/snippet} + {#snippet diffRows()} {#each rows as item (item.id)}
{item.label} {#if item.dirty && item.savedValue !== item.currentValue} - {item.savedValue} - โ†’ {item.currentValue} + {@render rowValue(item.savedValue)} + โ†’ {@render rowValue(item.currentValue)} {:else if item.dirty} - {item.currentValue} + {@render rowValue(item.currentValue)} {:else} - {item.savedValue} + {@render rowValue(item.savedValue)} {/if}
diff --git a/web/src/styles/tuning.css b/web/src/styles/tuning.css index 8246255..e99b5de 100644 --- a/web/src/styles/tuning.css +++ b/web/src/styles/tuning.css @@ -553,6 +553,19 @@ font-weight: 600; } +/* Hex color values get a swatch so the color is readable at a glance. + (Atomic inline boxes don't inherit the strikethrough line, so the saved + swatch stays clean inside .) */ +.saved-swatch { + display: inline-block; + width: 10px; + height: 10px; + margin-right: 5px; + border-radius: 3px; + border: 1px solid var(--hairline-strong); + vertical-align: -1px; +} + .saved-rail-foot { margin-top: 12px; padding-top: 10px; From c6a9a42e771cdfb3380eeb40a7a44f4f1dcfd93b Mon Sep 17 00:00:00 2001 From: Kyle McDowell Date: Thu, 11 Jun 2026 11:21:29 -0500 Subject: [PATCH 06/12] p3-polish: reserve scroll room under the tuning canvas while the mobile save bar is shown --- web/src/styles/tuning.css | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/web/src/styles/tuning.css b/web/src/styles/tuning.css index e99b5de..fedc5cd 100644 --- a/web/src/styles/tuning.css +++ b/web/src/styles/tuning.css @@ -718,6 +718,12 @@ .saved-mobile-bar { display: block; } + + /* The fixed bar floats over the document; reserve room beneath the canvas + only while it's shown so the last row stays reachable. */ + body:has(.saved-mobile-bar) .canvas-grid { + padding-bottom: 84px; + } } /* Content parked below the grid until Tasks 8-10 re-home it. */ From e624b9c9d81784c93749e99479d5dc454fba36db Mon Sep 17 00:00:00 2001 From: Kyle McDowell Date: Thu, 11 Jun 2026 11:23:39 -0500 Subject: [PATCH 07/12] =?UTF-8?q?p3-polish:=20toolbar=20readout=20says=20T?= =?UTF-8?q?uning=20Scope=20=C2=B7=20Everyday,=20matching=20the=20vocabular?= =?UTF-8?q?y=20law?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/src/App.svelte | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/web/src/App.svelte b/web/src/App.svelte index 79fef5a..586fc33 100644 --- a/web/src/App.svelte +++ b/web/src/App.svelte @@ -632,11 +632,14 @@ }; $: telemetryRateText = `${telemetryPacketRate >= 100 ? telemetryPacketRate.toFixed(0) : telemetryPacketRate.toFixed(1)} Hz`; $: telemetryRateDetail = telemetryRateStatusText(adapter); - $: systemReadoutTitle = selectedTuningScope === 'global' ? 'Profile Scope' : 'Telemetry Rate'; - $: systemReadoutValue = selectedTuningScope === 'global' ? 'Global' : telemetryRateText; + // "Tuning Scope", not "Profile Scope": this readout tracks what the tuning + // view edits, while Status's sentence tracks profile resolution โ€” the two can + // legitimately differ, so the label must not claim to be the same thing. + $: systemReadoutTitle = selectedTuningScope === 'global' ? 'Tuning Scope' : 'Telemetry Rate'; + $: systemReadoutValue = selectedTuningScope === 'global' ? 'Everyday' : telemetryRateText; $: systemReadoutDetail = selectedTuningScope === 'global' - ? 'Controller-only tuning' + ? 'Global Profile ยท controller-only tuning' : telemetryRateDetail; $: overrideScope = profileWorkspace.overrideScope; // Sync the override dropdown when the ACTIVE profile changes (server-side From 1687bd2d42a471551e9921b3585002e4dfe63339 Mon Sep 17 00:00:00 2001 From: Kyle McDowell Date: Thu, 11 Jun 2026 11:26:44 -0500 Subject: [PATCH 08/12] p3-polish: stale telemetry reads as no press on the live trigger readouts --- web/src/App.svelte | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/web/src/App.svelte b/web/src/App.svelte index 586fc33..1c88b20 100644 --- a/web/src/App.svelte +++ b/web/src/App.svelte @@ -465,8 +465,11 @@ $: telemetry = snapshot?.telemetry ?? []; $: telemetryByName = new Map(telemetry.map((item) => [item.name, item])); $: effectState = snapshot?.effectState; - $: l2LivePress = controllerInputFresh ? l2ControllerPress : selectedTuningScope === 'global' ? 0 : telemetryUnitValue('input.brake'); - $: r2LivePress = controllerInputFresh ? r2ControllerPress : selectedTuningScope === 'global' ? 0 : telemetryUnitValue('input.throttle'); + // Stale telemetry must read as "no press", not as the last frozen value: + // telemetryUnitValue keeps returning the last packet's value, so without the + // freshness gate the readout freezes non-zero when packets stop. + $: l2LivePress = controllerInputFresh ? l2ControllerPress : selectedTuningScope === 'global' || !selectedGameTelemetryFresh ? 0 : telemetryUnitValue('input.brake'); + $: r2LivePress = controllerInputFresh ? r2ControllerPress : selectedTuningScope === 'global' || !selectedGameTelemetryFresh ? 0 : telemetryUnitValue('input.throttle'); $: triggerCurveDisplayMode = selectedTuningScope === 'game' && usesForzaRuntimeProfile(selectedTuningGame) ? 'forza' : 'base'; $: appSettings = snapshot?.appSettings; $: forzaGlyphs = appSettings?.settings.forzaPlaystationGlyphs; From 811139693dbaed71b094e3207d4355f3b8f453c8 Mon Sep 17 00:00:00 2001 From: Kyle McDowell Date: Thu, 11 Jun 2026 11:32:22 -0500 Subject: [PATCH 09/12] docs: add p3-polish implementation plan --- .../superpowers/plans/2026-06-11-p3-polish.md | 669 ++++++++++++++++++ 1 file changed, 669 insertions(+) create mode 100644 docs/superpowers/plans/2026-06-11-p3-polish.md diff --git a/docs/superpowers/plans/2026-06-11-p3-polish.md b/docs/superpowers/plans/2026-06-11-p3-polish.md new file mode 100644 index 0000000..f6d898a --- /dev/null +++ b/docs/superpowers/plans/2026-06-11-p3-polish.md @@ -0,0 +1,669 @@ +# P3 Polish Backlog Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Land the ten deliberately-deferred P3 items from the 2026-06-11 critique (`.impeccable/critique/2026-06-11T05-34-28Z__web-src.md`): orphaned asset cleanup, saved-rail typography/contrast, Edge-slots plain-words copy, status-page desktop layout, emojiโ†’glyph swap, color swatches, mobile-bar occlusion, toolbar scope readout, and the two `$:` hidden-dep smells (only if cheap). + +**Architecture:** All work is in `web/` except one read-only grep already done (crates/ has zero asset-path references to the focus PNGs โ€” confirmed). Every change is small and local; the one M-effort item (status desktop layout) is prepared as two screenshot-able treatments and decided at a single batched user CHECKPOINT together with the other visual items. `cd web && npm run check` is the regression rail after every task. + +**Tech Stack:** Svelte 5 (App.svelte and tuning panels are LEGACY `$:` mode โ€” do not introduce runes there; SavedRail.svelte is already runes mode), Vite, Playwright (devDep). + +**Hard rules (user-enforced; violations failed prior reviews):** +- Never touch `web/src/lib/api/*`, `web/src/lib/mock/*`, `web/src/lib/types.ts` (the Edge-slots dev-voiced error string lives in `web/src/lib/api/controllers.ts` โ€” map it in the VIEW, do not edit the api file). +- Copy law: no Device/HID/gamepad/plugin/backend/bus in user copy; "Everyday" always pairs with "Global Profile"; `/legacy/i` must not match anything in production source (source-audit enforces). +- Never commit to `main`. This plan's branch: `p3-polish` off `main`. +- No local Rust toolchain; nothing here touches `crates/`. +- Gates: `cd web && npm run check` green at every commit. +- Visual items (Tasks 2, 4, 5, 7, 8) get ONE batched user CHECKPOINT (Task 10) before the PR โ€” the user reviews in dev:mock; commits before the checkpoint are fine (branch is unpushed and amendable). + +--- + +### Task 0: Branch + baseline + +**Files:** none (git + gates only) + +- [ ] **Step 0.1: Create the branch** + +```bash +cd /Users/kmcdowell/Documents/repos/dualsense-command +git checkout main && git pull +git checkout -b p3-polish +``` + +- [ ] **Step 0.2: Confirm the gate baseline** + +Run: `cd web && npm run check` +Expected: all gates green (typecheck, source-audit, button-map, snapshot-map, haptics-graph, build, release-size, visual-smoke). If anything is red, STOP and report. + +--- + +### Task 1: Delete the orphaned HUD-era focus PNGs (+ their dead CSS hook) + +20 PNGs (156KB) in `web/public/dualsense/focus/` have zero references anywhere in `web/` or `crates/` (verified by exhaustive grep: the only image lookups are `ButtonMappingView.svelte:316` โ†’ `/dualsense/controller_front.png` and `buttonMapping.ts:251` โ†’ `/dualsense/icons/iconid_controller_key_*.png`). The companion CSS class `.dm-controller-focus` (`web/src/styles/button-mapping/layout/controller-art.css:88-99`) is defined but never applied to any element. + +**Files:** +- Delete: `web/public/dualsense/focus/` (entire directory, 20 PNGs) +- Modify: `web/src/styles/button-mapping/layout/controller-art.css:88-99` + +- [ ] **Step 1.1: Re-verify zero references (cheap insurance)** + +```bash +cd /Users/kmcdowell/Documents/repos/dualsense-command +grep -rn "dualsense/focus\|focus_" web/src web/scripts web/index.html web/vite.config.ts crates/ || echo "ZERO REFS" +``` +Expected: `ZERO REFS` (or only hits that are clearly not asset paths, e.g. `focus-visible`, `focus_` absent). If a real asset reference appears, STOP and report. + +- [ ] **Step 1.2: Delete the directory and the dead CSS block** + +```bash +git rm -r web/public/dualsense/focus +``` + +Then in `web/src/styles/button-mapping/layout/controller-art.css` delete the entire `.dm-controller-focus { ... }` rule block (lines 88โ€“99: opacity/filter/transition styling for a focus overlay image that is never rendered). Verify nothing else references the class first: + +```bash +grep -rn "dm-controller-focus" web/src || echo "only the css rule" +``` +Expected: only the rule being deleted (in controller-art.css). If a Svelte file uses it, STOP โ€” leave the CSS and report. + +- [ ] **Step 1.3: Verify build + size gate** + +Run: `cd web && npm run build && npm run test:release-size && (grep -r "focus_" dist/ && echo "FAIL: focus refs in dist" || echo "clean")` +Expected: build green, release-size green (smaller), `clean`. + +- [ ] **Step 1.4: Commit** + +```bash +git add -A web/public/dualsense web/src/styles/button-mapping/layout/controller-art.css +git commit -m "p3-polish: delete 156KB of orphaned HUD-era focus PNGs and their dead CSS hook" +``` + +--- + +### Task 2: Saved rail typography + raised-surface contrast โ€” **CHECKPOINT (batched, Task 10)** + +The rail title is 9px and rows are 11px; `--ink-muted` (#8b8b96) on `--surface-raised` (#26262c) computes โ‰ˆ4.46:1 โ€” a marginal AA fail. Raise rows to 12px, title to 10px, and add a one-step-brighter muted token for raised surfaces. + +**Files:** +- Modify: `web/src/styles/tokens.css` (after `--ink-muted`, line ~10) +- Modify: `web/src/styles/tuning.css` (`.saved-rail-title` ~505, `.saved-row` ~519, `.saved-row-saved`/`.saved-row-was` ~546) + +- [ ] **Step 2.1: Add the raised-surface muted token** + +In `tokens.css`, directly after the `--ink-muted: #8b8b96;` line, add: + +```css + /* Muted ink for raised surfaces: #8b8b96 on --surface-raised is โ‰ˆ4.46:1 + (marginal AA fail); this lands โ‰ˆ4.9:1. */ + --ink-muted-raised: #93939d; +``` + +- [ ] **Step 2.2: Apply in tuning.css** + +Change `.saved-rail-title` from: +```css +.saved-rail-title { + font-size: 9px; + font-weight: 600; + letter-spacing: 0.08em; + text-transform: uppercase; + color: var(--ink-muted); +} +``` +to: +```css +.saved-rail-title { + font-size: 10px; + font-weight: 600; + letter-spacing: 0.08em; + text-transform: uppercase; + color: var(--ink-muted-raised); +} +``` + +In `.saved-row`, change `font-size: 11px;` to `font-size: 12px;` (rest of the rule unchanged). + +Change: +```css +.saved-row-saved, +.saved-row-was { + color: var(--ink-muted); +} +``` +to: +```css +.saved-row-saved, +.saved-row-was { + color: var(--ink-muted-raised); +} +``` + +- [ ] **Step 2.3: Verify** + +Run: `cd web && npm run check` +Expected: green (visual-smoke covers 1366/1440/390; the rail is fixed-width furniture so +1px text must not break layout โ€” if visual-smoke fails on rail overflow, report rather than shrinking the font back). + +- [ ] **Step 2.4: Commit** + +```bash +git add web/src/styles/tokens.css web/src/styles/tuning.css +git commit -m "p3-polish: saved rail 12px rows, 10px title, AA-passing muted ink on raised surfaces" +``` + +--- + +### Task 3: Edge onboard slots โ€” plain words, teach Fn slots + +The error state renders the raw API message "DualSense Edge onboard profile read/write requires the real DSCC agent." (thrown in `web/src/lib/api/controllers.ts` โ€” FORBIDDEN file, map in the view). The empty state says "No slot data / unavailable". Both are dev register. + +**Files:** +- Modify: `web/src/lib/features/controllers/EdgeSlotsView.svelte` (script + error note + empty-state block) + +- [ ] **Step 3.1: Map the dev-voiced error in the view's script** + +In the ` -{#snippet rowValue(value: string)} - {#if swatchColor(value)}{/if}{value} +{#snippet rowValue(value: string, isColor: boolean)} + {#if isColor && value.startsWith('#')}{/if}{value} {/snippet} {#snippet diffRows()} @@ -75,13 +71,13 @@ {item.label} {#if item.dirty && item.savedValue !== item.currentValue} - {@render rowValue(item.savedValue)} - โ†’ {@render rowValue(item.currentValue)} + {@render rowValue(item.savedValue, item.kind === 'color')} + โ†’ {@render rowValue(item.currentValue, item.kind === 'color')} {:else if item.dirty} - {@render rowValue(item.currentValue)} + {@render rowValue(item.currentValue, item.kind === 'color')} {:else} - {@render rowValue(item.savedValue)} + {@render rowValue(item.savedValue, item.kind === 'color')} {/if}
diff --git a/web/src/lib/features/tuning/savedDiff.ts b/web/src/lib/features/tuning/savedDiff.ts index fc379eb..d228de5 100644 --- a/web/src/lib/features/tuning/savedDiff.ts +++ b/web/src/lib/features/tuning/savedDiff.ts @@ -41,6 +41,8 @@ export type SavedDiffRow = { savedValue: string; currentValue: string; dirty: boolean; + /** 'color' rows carry raw hex values; the rail pairs them with a swatch. */ + kind?: 'color'; }; /** The saved baseline: the editable slice of a controller configuration. */ @@ -135,8 +137,9 @@ const row = ( label: string, savedValue: string, currentValue: string, - dirty = savedValue !== currentValue -): SavedDiffRow => ({ id, label, savedValue, currentValue, dirty }); + dirty = savedValue !== currentValue, + kind?: 'color' +): SavedDiffRow => ({ id, label, savedValue, currentValue, dirty, kind }); /** A generic per-field comparison for the deep telemetry tuning groups. */ const tuningGroupRow = ( @@ -249,13 +252,17 @@ export const savedDiffRows = ( 'lightbar-color', 'Lightbar color', (saved.lightbar?.color ?? DEFAULT_LIGHTBAR_COLOR).toLowerCase(), - draft.lightbarColor.toLowerCase() + draft.lightbarColor.toLowerCase(), + undefined, + 'color' ), row( 'redline-color', 'Redline color', (saved.lightbar?.rpmColor ?? DEFAULT_REDLINE_COLOR).toLowerCase(), - draft.rpmColor.toLowerCase() + draft.rpmColor.toLowerCase(), + undefined, + 'color' ), row( 'left-deadzone', diff --git a/web/src/styles/status.css b/web/src/styles/status.css index 4ef2a83..8d8defa 100644 --- a/web/src/styles/status.css +++ b/web/src/styles/status.css @@ -114,9 +114,16 @@ background: var(--surface-raised); } -.status-controller-glyph { +/* Two-class selector to out-specify .dm-controller-glyph's `mask` shorthand + (which would otherwise reset mask-size back to `contain`, same as the + sidebar brand glyph does in shell-v2.css). */ +.dm-controller-glyph.status-controller-glyph { width: 30px; height: 22px; + /* Square SVG canvas with the artwork in a central band โ€” zoom the mask + past the box so the controller renders at ~22px tall (see shell-v2.css). */ + mask-size: 36px 36px; + -webkit-mask-size: 36px 36px; } .status-controller-main { diff --git a/web/src/styles/tuning.css b/web/src/styles/tuning.css index fedc5cd..f99ca39 100644 --- a/web/src/styles/tuning.css +++ b/web/src/styles/tuning.css @@ -720,8 +720,9 @@ } /* The fixed bar floats over the document; reserve room beneath the canvas - only while it's shown so the last row stays reachable. */ - body:has(.saved-mobile-bar) .canvas-grid { + only while it's shown so the last row stays reachable. Anchored at the + tuning wrapper to keep :has() invalidation local. */ + .work-and-rail:has(.saved-mobile-bar) .canvas-grid { padding-bottom: 84px; } }