From 7732a302cd936645577fb20fc037d0c6779b8567 Mon Sep 17 00:00:00 2001 From: Mark Date: Tue, 19 May 2026 22:30:23 +0200 Subject: [PATCH] =?UTF-8?q?feat(01-12):=20wave-2=20task-1=20=E2=80=94=20ra?= =?UTF-8?q?sterize=20Loom=20mark=20to=20icons/icon{16,48,128}.png=20(overw?= =?UTF-8?q?rites=20Bug=20A=20placeholders)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit scripts/rasterize-icons.sh (80 lines) is the one-off rasterization recipe. It reads src/shared/brand/mokosh-mark.svg and emits the three toolbar icon sizes via rsvg-convert, with assets-spec.md size FLOOR sanity checks embedded. Before: icons/icon16.png 574 B 16-bit/color RGB (Bug A placeholder) icons/icon48.png 1153 B 16-bit/color RGB (Bug A placeholder) icons/icon128.png 2615 B 16-bit/color RGB (Bug A placeholder) After: icons/icon16.png 406 B 8-bit/color RGBA (Loom mark — D-01) icons/icon48.png 784 B 8-bit/color RGBA (Loom mark — D-01) icons/icon128.png 1952 B 8-bit/color RGBA (Loom mark — D-01) All three clear assets-spec.md Chrome imageUtil silent-rejection floors (16≥200B, 48≥500B, 128≥1024B). Sizes match RESEARCH §3 verification. Per D-06 (Neutral mark + dynamic badge): single neutral mark per size; no per-state PNG sets. The dynamic chrome.action.setBadgeBackgroundColor in src/background/index.ts does state communication via colored badge. Per RESEARCH §3 anti-pattern: PNGs are COMMITTED as static artifacts; not regenerated at build time. scripts/rasterize-icons.sh is the documented re-run recipe (for when src/shared/brand/mokosh-mark.svg changes). Verification: - tests/build/icons-present.test.ts: 15/15 GREEN (existence, FLOOR, PNG signature, dimensions, color-type byte === 6 RGBA) - Bug A regression check: file content differs from prior placeholders (verified via git diff binary status); the placeholder fingerprint used by harness A19 (Wave 6) will distinguish on first 32 bytes. Co-Authored-By: Claude Opus 4.7 (1M context) --- icons/icon128.png | Bin 2615 -> 1952 bytes icons/icon16.png | Bin 574 -> 406 bytes icons/icon48.png | Bin 1153 -> 784 bytes scripts/rasterize-icons.sh | 79 +++++++++++++++++++++++++++++++++++++ 4 files changed, 79 insertions(+) create mode 100755 scripts/rasterize-icons.sh diff --git a/icons/icon128.png b/icons/icon128.png index a599bd27a2430ca724b0b0b4f8bab0cfb936ccb3..6b84581c3705094d11699155cfc9af383654bab9 100644 GIT binary patch literal 1952 zcmbVNXHXOP68{qjARIMtNCF-NX$M9;6+}wt^$c7DgP@3to?t|bNZ=wQ1f>X41P|%G z6GXZfgE>)AiXajZ2mwQrB0(@wK$8b=-k0~~KHTi={$_V}cec%Jq9?{#P6jRm0FZNa zalmdNWt*iXw`8aF>7Ff+Jmc={07TnV#Hh>wK+424SHIx^My)FE-Zgn^=( zn)1U(L}@ipU+%cQcKi9?8Dleccpateb-tpfc+SX|=N9ygneWzZy+Y2W)wz!B?EIx4 ziZZcohUJes>-6*L`+gefGN6S1_~ee_W>bzI#ZQaiK7m~QC8p;%zn6}N;&e(b?raHv z)=Z+cv^C}+ULZkI5^SbV0W-LwBGCin9}Q4YYn^flvhI_L_SSS_-i`) z9Bcm<;j{!)b)ThVdhXF=w#SM(AeQv=Z6-iw>_c9~*BX7`Z%j#ze?N*?UJS!kvpnoK zctF`GzaesC?HyWrwnM1YTUy5E9hy$rnp1#2-m=guKsg?T!lYei(-bD8u3X--nbhUq zr-akjecKoUO`8rV_tsRyekPWS{`?eVnxcImq3^8G6Kb&W@t}jzi|twmi!kr5>r&S% z&Pu0b)-qtOKj}#_ccLtQMHN{NMYTn~EIxMb!(*DeNO_+EeF&a@G_g<@uP>1pTfasX z_Vjz0Jqp7lWZ|#bvEy%CzWzY$-qvx%b<+HGzCNTm$>Fr`6q;vh8uy`|3eCdtK!zJu zNM?+Ol>No4Ya9+SJ0-rJLVNWhWKTGW?WE*|hhbOLHdlvSq*1=^C3cE!R;J*F7Yzn) z{%CZxRJ)i)Rrvy#lN9@5&3O1hnWwGxeO~O@X@qUJEFAO)0n19Ul{`u2)qklxLz@~~ z29mqdjJ<>TZ`AL1jlL0LGfvkV@q{m}Xp73bZjEVJ)L?V{ZmvvIYO!X@-Rqdzho49K z{*YP8`>1JahU$)_)D8=^+;z}rX2#JvQwR{+@+LS>(mI-`V8Yc*BZ}}J44GHYUYBSW z29M1wd|P{qMob|n7w6ci3Uu>tGjm%}TiH%LxvkYC?;=Xd@i+-hz17JQcn;qsigwE{ zDmU$FGq(nr*EV~ei^!^$KZoGPI{k2*?-_?^NsYVOj(dm|ya5py@kw(z%G?3)Ps$wR zc@3H15rwkhSN21z4oz+5G9Qt%3W=iR*&a^Asc?@+Ryt3ZQyYDr( ze9eafrxHva{}3>8%y|Vr_W<=pIj_m-Pu8o}OiZmjkDuU}k6wNR&{vUgHK zd=4v2UWy+{l6(!dQclL0-#cZRCab7&sYOCKzN2#Q?kLWj)4)P~f+e>ZX{$8(kYFO> z_V&_}FlW7j_czH-+^c4tLe3Zmh?W%q#1c}stQQqRYTIGN+HeHKG9P_Vm$5qRGN66L zZ04N}kx9o$ToSvmy>-fL>~aKYqYEE)Kw$AA^ihbw33O z4V%1M{aZvM!j$|T`#}YOcbtXq(TzSoW9>srNsTbmXqnALj@Z(BC~<$wMkg}jN2c0f zinl$#SUP&>l3DcK^J!~Jldv(|AD1zl0}Q)KQ^0DTVtJmp@jiCE;gj2Fj5veasL@Lv z^NcoR;-s>jKaP+=WF5@3Fm_5?)bvY4*Zg1yp@sM)Ay1jBGDyaG&)2~$5n_9Zo%3h` z{pA#LEsOop@KP=0#o>?uhnc!ry-*XRf}nOE5&^*nvi9?YW%Ewd6r~_X*iDmp fGXKBNER!HWqi@H&7NmdN{=dN05#vyA7eM_F+@PUF literal 2615 zcmcImc{JPE7ypJ@YHd}jb{(TtYtUGNMB1jPE|wY;v1V*lTRO;yq>L)s>4Kn$Z75AO zXjL^L)SzuzbhK0nRg6?)4=IA*SO55(^E+#EjTpInjgWImf*~NC%Jc#0Ll9afqN;94G)& zn5nrT3~p#*ao*%80%nFVGt-B`5HOe-mLBvU29Z(0VLvDSv%xV@rJXJ7{@VjSED{%o z4~UHZXB+5#bI@eBlH&>V`Gk+N9FE(0fqM7iBl(a3d1*Gp=jy%O^h4K`D|YJ|_QNL5 zsAlvRhUy;5es|xjpgp|2#w2s)2ko$HvX2p$yOhoDpi8!= z$XJavVv8b2Cts6Hld7zmCZSwRik9ROjZ>C!vw=akPxbR!`XOCmxJ*e|RBXXnVLZj{ z34Hu~cEwYaO4y6n8z%g6iI~Y%{j!LLzJ0|P>t0Lw|iDCEmQhW;DLm7*B!=l(>fa5*%%iDya>5g0(JS41QY`+=pJgDSk}@ z@?qI`wN##|!^xeRD}Gk%|4jzcsZAb@unwRu>#2{~yp>{h9%xxs_d~_(>afP>ibxL3 z8%68aJoSv2Baa5k)FjsTj3_@C^W{?0M;lr!<+ZBb^Q{Jh65`^l>MTwNg}-s1cI)$| zNH;;acN8E0NyH*ie_e0{k8fP>k&z?BNsYk%Yr>qo@MsvROMno>P|pk3Y|hDv`j_x} z@JA`lEq&hKOqP=?hNo~L(oEcum;-j6p|OgBh|#2o8hPey*h z7pGEF*r!J+V^4ePm%-?xugcrSJ7}=gHV6{@{XVWSF%`|(#V9@{%`6GHK#O?2dX5WC z2&*-^dAoOP0a8sH>0dp-mufkmXB|4ZY>^BQr~FRM+tJ&ye3umoozIm~WZ5~TS&K4{ zPn82I8$wx4yU$b4EzBnU3A90fg@-|Qf z%m{EZNx&0GuVxMcBpwpC)znu7V=r114OROU@yjlP81_k5{k`i+TV3*P^DjMq+*u{0 z+Gy`^?->?Og~P$Ht|xC@m2XqKk*lNQR<&xed6{eYw9d@JK4|VoTM_csE|Y@=`*^mK zV`8>qc}4#7#+%kRlG&FgB(x+`v@G?a@aZl-leR=~=CfP%6SY9T%Ml2?DGDinZLBD2wGtoV&L=Dmr{{G}iHSY4dQ*Erjv0u}h2^es)m5?~d)Zjvex3=+X(>Bz@ zO_2Pc`jp_G1HSB@zIFvwdUk2{`k+E}>$bGol0^j^ARzo4iV~S>0>*RHttb^Rs^!&BA%eVJl@4$oc#UD z_P+U8-5G0hg8i#db(+fnI?Bt6E8=hJJ*QE;QMB2ZIx0f{_I$iModH5mdWhf`sXQo4 z4j|3$c#P7ol9`=fPv&Cu(}~4twu8MONhjZ9n^h)94k%G$utt23K8ALvR`Ejc@^eNS zA2X+$x0=v=qrQ%;Fn9@KaHB;++g-eMt#|W-{e>hJeY;wh998M$+NL0nV${;A!>TIk z|AfmiLl4G|a#aO+uRM(BTLwG6-fPZ6Lu?dRm5*7z&+#46ym2(RN>I#I?@2b~7hIgl zIE_4hE>`2ZNJ8-Uyl|V7izHrp^QN^jmqWBw5oQvNMF_V|oPn(8bCieh+~h!%x_T`M zt5NWBY^n9DPdN60HuZ}F1b>cXN}XRbZO0PcHhmoy_$ zmyudI6PrG3veLig{TKcH1%cCQA@89%Z$RODc7)+VMb{xtKYTu?)<_jJc29sGs{52W zV?mp-e)q%QbZ6So(4X`@a)Nk$a*|s|&#z32?-mJ@N3E Hf6BiAj6uO1 diff --git a/icons/icon16.png b/icons/icon16.png index 09f0c04bd62251b122c95fc7131782ca4f99e5d9..e2bb08c8581312d29e75d3fad79e65516fa2081d 100644 GIT binary patch delta 392 zcmV;30eAks1eODk7=H)`0000V^Z#K0000JJOGiWi{{a60|De66lK=n#OG!jQR5*>r zlfOy>K@f+(nM*=SQ<->rUcky25d2dMHok$rf}M}zYlyvR#3zU#XwpfJ#ArG#k2`P2 zB6nhOVjzV-ScY$5W_M@yC(I?y_09oin>h!09G9|6G@A_ifPV=fO@I3uI6@=>z}T3V zWm3)-0(Z0N@Kl=XokPrS>ebp-6g_+ZwEWH`z}s|iQO04oyAr3#Gb$&l&aD|tisVHU zMGqeaW6hkeizfZ1im7@6UKsAK6q|99){3i^F+lv8dM4sk$ZQ{_8>h+pcUiFrAWoC> zQZD4!S3Kz>@_$&b)*8jaw1;W$H?CJ}4MZOCq`!O*{{0CRaV~Qr+0TE_@;eF4=Uv7C ztNwPTX4%p`P^bDT5d56+UkZY5Lm)8EdnwFx1so$X0v0h-8@QcKhi8%(mDa}2o;lYp m4#{Jwokex@HhH=S>tQnQWj24Y&;@nYpROC5gEOxb_?_CMKF!ljm#?aS75iNKTjklgrrQ}DKT6K;b=8^t`KjeG zfBPLedagB(6tp_*WH^JS&hV^>sJ9SW(&=mK$6e>PGXLpJzdfw>%~#id)KNLe^exr= z@4ghle8%6eX0yc$d2VnxP<3~$_{$^F3JJU4z3Mg*(s{6HhsfW~$^N#pt;H0p3jG958SQ#+d>mQ_FYM-F&1PomUPgg&ebxsLQ04f3Br~m)} diff --git a/icons/icon48.png b/icons/icon48.png index f07eff6f489c1cc9c681cbf22e82dff116f0934f..b2b141d57aae7925e996dd1437ec7f78a1c07ef5 100644 GIT binary patch delta 772 zcmV+f1N;1e36KVm7=H)`000120{Mpk000JJOGiWi{{a60|De66lK=n$#Ysd#RA_QKcI;l?j|lS2G~qY*mX0}KY-NeM3@PK zF}8_?>M~P_imB?3be17_gQ*+d+zD?``+!luYWy-h;WhP28V~Q561d> zo`7Z)XI#*Wbqe&W(hDHMzQV5tZ`gFcBEJRwE=cxZkJnpUxt)dvMiZ&K0`Gy#^@M~# zS&@h3Vs6PEtTIp${}H?+)P?LTGHsji4OEuRI@L#h1(gpt{Ha}2AETry)$$;3>uYEs z-=z=H3@{l?r+;*~FXLu8#mu<3<}LBcY-uAuS6>W_B~!N*PmsXcW+C_TH1mP^crrDI z@&a#CJaU;)4h^5lUvX{8zQouX98&!W0&o-68WwG8OhAeL-rq&1Bm(R9rOj+HTB zV!{2{Az@7;qT41`7&NhSeEQiTG7vVAfv|}TgiS06wSULl8i`0Ekx1WcrhuyqfmTY$ zP@{RR=KJbI6RNgW5C3K^ekJ81$A3R)grK_sikxpp{y!*M+Q>Ulbp}qv^UC8woAPV& z|C|98-4SFEz!6@F%DZN2xv-!x zmP~D%&wnJM+r>itd9CLA^Ab0vf&~+3J@c2*$UxXc8<|(63ofH4B-+SYBHG9-qK)i? zL6?Ws&gqEIki!hArlMuzn8Zhf7u+PAv zl`t7kre^656Ed1e&!c+FA3zs_xI(4Lw+4**Q+-ueL9#fqTf2T6n|$a6kc=%J*gV{m z3De{|(q>KH5%d#X+-60bd!@qHWiwE96)G2VONvaRlsYc0F`FRwZShcJjgO3^2V&=# zQ8WWg0R6S9w)3wBc&~jEH0vJpzA2Z#)U6#627dvdfom$6%7Ib<0000I(3)EF2VS{N990fib~ zFffz?6~0PfV6d9Oz#v{QXIG#NP=YPV+uh|q7;r{>zXKFuFY)wsWq-vg$j7W`HpMv- zD5P5A8c~vxSdwa$T$Bo=7>o>z%ybP*bq&o!3{9*IjIE4~wG9lc3=E9p)+eKA$jwj5 zOsmAL!HHS?K2U=O+=i0O+|=Td#M}bhdPK#{fLfRnJzX3_GVZ;d>FY1-DARs=lP-7e z!ws$r#C(!hsO^!l_#iadRIyE5TV=0?+JppwgOevtmS?Pacw`}`i0_jH;(-gcB=szt zxMI56HG#?B5?)PHx?q~Qee2TLFn(vA$Yi&hH`n<-`^m8X=hKt#&Yi38S`)VVYSz_+ ze+&!D8vo1ca4?CnFmg9FusR-SQb=$V*r31>A;1C_ZVbszY&5=m-L$sfO#1Zw<*%c> zw2Ef7Z`)io`$m3^OPHYdpN0+2ylnTEG%a0YFROm~45Qsew@VuzzByj=P3P3}MAOe( z=3NOtme=dxl5}xzdrmgxj_m50U(}DXN zW_hX9>gcv{Io9zRIX+mhV40BTeAejY|F(eTCB1xAC)t%fHs0h0l0PD3uaL8PrOT!C znfqH7@dGtHSqsvz@Im(#^`Dj}Sf+0JR}!-vB;@;ld&NeO8K*!&y$U4ss$s&53Go;hT(_s~?VK(BnPu|V1#)|yWvkg*U5b0{S0yQZ zXlBXw_r~SD^NQDQe$J`(IxJ0X?)~WAqg8A737yFa|RR$rGN+1FgX@$?}+Q;8UVR&Vpa8!ZCEWKXDC1?1ji mRag;lApAUXx&2 + return 1 + fi + if ! command -v rsvg-convert >/dev/null 2>&1; then + echo "ERROR: rsvg-convert not found on PATH (install librsvg)" >&2 + return 1 + fi + + mkdir -p "${ICONS_DIR}" + + local size + for size in 16 48 128; do + local out="${ICONS_DIR}/icon${size}.png" + rsvg-convert -w "${size}" -h "${size}" "${MARK_SVG}" -o "${out}" + + local bytes + bytes="$(stat -c%s "${out}")" + local floor="${FLOORS[${size}]}" + + if (( bytes < floor )); then + echo "FAIL: ${out} (${bytes} bytes) is below Chrome imageUtil floor ${floor} B" >&2 + return 1 + fi + echo " rasterized: ${out} (${bytes} bytes; floor ${floor} B)" + done + + echo + echo "==> Done. PNGs are at ${ICONS_DIR}/icon{16,48,128}.png." +} + +main "$@"