<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Hasan Yahşi · Notlar</title>
    <link>https://hasanyahsi.com/tr/notlar/</link>
    <atom:link href="https://hasanyahsi.com/tr/feed.xml" rel="self" type="application/rss+xml" />
    <description>Kısa teknik notlar: ne denendi, ne ölçüldü, ne yanlış gitti.</description>
    <language>tr-TR</language>
    <lastBuildDate>Tue, 15 Sep 2026 06:00:00 GMT</lastBuildDate>
    <item>
      <title>paintcheck: iki yanlış sürümün pikselden kontrast ölçmek üzerine öğrettikleri</title>
      <link>https://hasanyahsi.com/tr/notlar/paintcheck-yontem/</link>
      <guid isPermaLink="true">https://hasanyahsi.com/tr/notlar/paintcheck-yontem/</guid>
      <pubDate>Tue, 15 Sep 2026 06:00:00 GMT</pubDate>
      <description>Fikir basitti, sayfanın görüntüsünü al, renkleri oku. İlk iki uygulama iki zıt yönde kendinden emin biçimde yanlıştı. Test örneklerinin ortaya çıkardığı hatalar ve bunları nasıl düzelttiğim.</description>
      <content:encoded><![CDATA[<p><a href="https://github.com/hasanyahsitr/paintcheck">paintcheck</a> metin kontrastını CSS&#39;ten değil, Chrome&#39;un boyadığı piksellerden ölçüyor. Bu not README&#39;de olmayan kısım hakkında: yöntem doğru olmadan önce nasıl yanlış gitti. Aşağıdakiler hafızadan değil, deponun değişiklik günlüğü ve test fixture&#39;larından derlendi.</p>
<h2>CSS neden yetmedi</h2>
<p>axe-core gibi araçlar kontrastı <code>color</code> ve <code>background-color</code> değerlerinden hesaplar. Kendi sitemde metin, gradyan perde altındaki bir fotoğrafın üstündeydi; okunacak arka plan rengi yoktu, denetleyiciler ögeyi <em>incomplete</em> raporladı. En kötü noktadaki gerçek oran 4,5:1 gereksinime karşı 3:1 civarındaydı ve bunu bana kimse söylememişti.</p>
<h2>Birinci deneme: metnin yanından örnekle</h2>
<p>İlk sürüm bir ekran görüntüsü alıp arka plan rengini her harfin yanındaki piksellerden okudu. Düz zeminde çalışıyor. Gradyanda harfin yanındaki piksel altındakinden farklı renk; okumalar iki yönde de yanlıştı: geçen metne yanlış alarm, kalan metne temiz sonuç. Sayılar gördüğümle uyuşmadığı için fark ettim.</p>
<h2>İkinci deneme: kapsamayı değişimden tahmin et</h2>
<p>İkinci sürüm iki görüntü aldı, biri normal biri tüm metin gizli, ve her pikselin ne kadar harfle kaplandığını ne kadar değiştiğinden tahmin etti. Sonra renkleri en çok kaplanan piksellerden okudu.</p>
<p>Gradyanda iki görüntü arasındaki değişim zeminin koyuluğuyla büyür. Tahmin bu yüzden yalnızca en yüksek kontrastlı bölgenin piksellerini seçti ve açık uca hiç bakmadı. Zeminin metnin kendi renginden geçtiği <code>gradient.html</code> fixture&#39;ının en kötü noktası 1,1:1 civarında. Bu sürüm 4,47:1 raporladı ve geçirdi. Test başarısız oldu; ben olmamıştım.</p>
<h2>Dayanan yöntem</h2>
<p>Aynı görünümün beş ekran görüntüsü:</p>
<ul>
<li><strong>A</strong>: sayfanın kendisi</li>
<li><strong>A2</strong>: 300 ms sonra; değişen pikseller elenir (yüklenen yazı tipi, animasyon)</li>
<li><strong>B</strong>: tüm metin saydam</li>
<li><strong>C</strong>: tüm metin siyah</li>
<li><strong>D</strong>: tüm metin beyaz</li>
</ul>
<p>C ve D her pikselin kapsamasını tam olarak verir. Bir piksel <code>bg</code> zemini üstünde α oranında örtülüyse C = (1−α)·bg ve D = α·255 + (1−α)·bg, yani α = (D − C)/255; zeminden ve metnin gerçek renginden bağımsız. Ögenin en büyük α&#39;sına yakın pikseller harfin çekirdeği; kenar yumuşatma pikselleri atılır.</p>
<p>Sonra ön plan A&#39;dan, arka plan B&#39;den aynı piksellerden okunur. Hiçbir şey hesaplanmaz. Opaklık zincirleri, rgba renkler ve pseudo-element perdeler Chrome boyarken zaten uygulandı.</p>
<h2>Testlerin sonradan zorladığı iki düzeltme</h2>
<p><strong>Alt piksel yumuşatma.</strong> Windows&#39;ta ClearType her renk kanalına farklı kapsama verir. Tam kapalı sanılan pikseller hâlâ karışımdı ve her okuma yaklaşık yarım puan düşük çıkıyordu: beyaz üstünde <code>#777</code> için hesaplanan 4,48&#39;e karşı ölçülen 3,92. Chrome artık gri tonlamalı yumuşatmayla açılıyor (<code>--disable-lcd-text</code>).</p>
<p><strong>İnce harfler.</strong> Gövde bir pikselden inceyse hiçbir piksel tam kapanmaz, en yoğun olan bile karışımdır. α bilindiği için karışım geri alınabilir: E = B + (A − B)/α. Bu olmadan gerçekte 5,85:1 olan 12 px altbilgi bağlantıları 3,81:1 çıkıyordu. Bu düzeltmenin ilk sürümü rengin kendi alfasını da kapsamadan böldü, ki bu yanlış: siyah ve beyaz sondalar rengi değiştirir ama ögenin <code>opacity</code> değerini değil, dolayısıyla bölünmesi gereken tek şey opaklık. Geçmesi gereken rgba .68 satır ve 3,32:1&#39;de kalması gereken rgba .5 satır artık iki yönü de sabitliyor.</p>
<h2>Doğrulanan ve doğrulanmayan</h2>
<p>37bbe2a revizyonunda kayıtlı 57 test yerelde Windows 11 ve Chrome 152 ile geçti. Karşılaştırma betiği axe-core ile paintcheck’i aynı test sayfalarında çalıştırıyor; düz renklerde hesaplanan referans oranları kullanılıyor. Fotoğraf ve perde örneklerinin elle hesaplanmış referans değeri yok. Gösterilen sonuçlar yerel revizyona ait; bu revizyon henüz GitHub’da yayımlanmadı.</p>
<p>Güncelleme, 16 Eylül 2026: 37bbe2a revizyonu GitHub’da ve Ubuntu, Node 20/22 CI çalışması geçti. macOS hâlâ denenmedi. Yazı tiplerinin ekrana çizilmesi oranları değiştirebilir; bu iki ortam dışında aynı geçti/kaldı kararını vereceği doğrulanmış değil.</p>
<p>Araç henüz npm&#39;de değil. <code>npx github:hasanyahsitr/paintcheck</code> ile depodan çalışır ve yerel Chrome ister.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Kendi sitemdeki kontrast hatasını paintcheck ile yakaladım</title>
      <link>https://hasanyahsi.com/tr/notlar/kendi-sitemi-olctum/</link>
      <guid isPermaLink="true">https://hasanyahsi.com/tr/notlar/kendi-sitemi-olctum/</guid>
      <pubDate>Tue, 15 Sep 2026 06:00:00 GMT</pubDate>
      <description>paintcheck yeni ana sayfada 12 kontrast bulgusu verdi: tasarım referansından aldığım vurgu mavisi beyaz üstünde 4,09:1 ölçüldü. Lighthouse da Next.js 16 static export'tan kaynaklanan 26 ön yükleme 404'ü ortaya çıkardı. İkisi de düzeltildi, ikisi de yeniden ölçüldü.</description>
      <content:encoded><![CDATA[<p>Yeni hasanyahsi.com, beğendiğim bir portföy şablonunun düzenini örnek alan bento yerleşimiyle yayına girdi. Yayından önce başkalarına önerdiğim iki kontrolü çalıştırdım: paintcheck (kendi kontrast aracım) ve Lighthouse. İkisi de bir şey buldu.</p>
<h2>paintcheck: vurgu rengi</h2>
<p>Referans tasarım beyaz kartlar üstünde bağlantı ve düğmeler için parlak bir mavi kullanıyor: <code>#4770ff</code>. Gözle bakınca sorun yok. Boyanan piksellerden ölçünce var:</p>
<pre><code>! [contrast] section.hy-kart &gt; div.hy-kart-bas &gt; a.hy-ok
    &quot;More About Me&quot;
    16px — 4.09:1 — needs 4.5:1
    rgb(73,114,255) on rgb(255,255,255)
! [contrast] div.hy-profil-dugmeler &gt; a.hy-dugme
    &quot;Write to me&quot;
    16px — 4.16:1 — needs 4.5:1
    rgb(254,254,255) on rgb(71,112,255)
</code></pre>
<p>Ana sayfada on iki, hakkımda sayfasında altı, iletişim sayfasında altı bulgu. Hepsinin sebebi aynı: beyaz üstünde mavi metin ya da o mavi üstünde beyaz metin, 4,5:1 eşiğine karşı 4,09 ile 4,18 arasında. Bu düz zemin durumu; CSS aritmetiği burada kesindir, axe-core da yakalardı. Ben henüz hiçbir şey çalıştırmamıştım.</p>
<p>Düzeltme: açık temada metin ve düğme zemini için vurgu <code>#3457e8</code> oldu (beyazda 5,8:1), koyu temadaki siyah kartlarda metin için daha açık <code>#6b8cff</code>. Gözle fark küçük. Değişiklikten sonra paintcheck dört sayfada da sıfır kontrast bulgusu veriyor. Kalan bulgular, etiketli seçim çiplerinin içindeki görünmez radyo girdileri için <code>target-size</code> notları; tıklama hedefi etiketin kendisi, girdi bilerek 1×1.</p>
<h2>Lighthouse: var olmayan dosyalara 26 istek</h2>
<p>Ana sayfada masaüstü Lighthouse: performans 96, erişilebilirlik 96, en iyi uygulamalar 96, SEO 100. &quot;Konsolda hata&quot; denetimi çalışma sırasında on tane 404 listeledi; bağlantıların üstünde gezen bir puppeteer betiği tam bir ziyarette 26 saydı.</p>
<p>İstekler <code>/about/__next.!KGVuKQ.about.__PAGE__.txt</code> gibiydi. Next.js 16.2 static export, segment ön yükleme dosyalarını iç içe klasör olarak yazıyor (<code>out/about/__next.!KGVuKQ/about/__PAGE__.txt</code>), istemci ise noktalı düz adı istiyor. Her ön yükleme başarısız oluyor, her istemci tarafı geçiş tam sayfa yüklemeye düşüyordu.</p>
<p>Bunun için bir yapılandırma anahtarı bulamadım; derleme artık her iç içe dosyayı düz adıyla kopyalayan 30 satırlık bir betik çalıştırıyor. Sonrası: sıfır 404, istemci geçişlerinde sondaki eğik çizgi korunuyor, masaüstü Lighthouse 95 / 100 / 100 / 100, LCP 1,5 s, CLS 0.</p>
<h2>Lighthouse mobil: fotoğraf</h2>
<p>Mobil çalışma performansta 76 verdi; Lighthouse&#39;un benzetilmiş yavaş 4G&#39;sinde LCP 7,1 s. En büyük öğe kendi fotoğrafımdı: 800×800 WebP, üstelik <code>loading=&quot;lazy&quot;</code>. Ekrandaki ilk şeyi tembel yüklemek tam tersi bir hata; özniteliği sayfanın aşağısında da kullanılan bir bileşenden kopyalamıştım.</p>
<p>Düzeltme: profil fotoğrafı artık hemen yükleniyor, <code>fetchpriority=&quot;high&quot;</code> ile; telefon genişlikleri için <code>srcset</code> üzerinden 480 px sürüm sunuluyor. Yeniden ölçünce benzetilmiş mobil LCP 7,1 s&#39;den 6,2 s&#39;ye, puan 76&#39;dan 77&#39;ye geldi. Küçük bir hareket ve ayrıntı sebebini söylüyor: görselin kendisi yaklaşık 120 ms&#39;de yükleniyor; gecikme 173 KB&#39;lık HTML belgesinde ve öncesindeki çizim işinde, fotoğrafta değil.</p>
<p>Belgeyi de denedim. Logo yolları her logo için iki kez gömülüydü: bir kez işaretlemede, bir kez Next&#39;in satır içi veri yükünde. Onları tek bir dış SVG sprite dosyasına taşımak ana sayfayı 170 KB&#39;tan 82 KB&#39;a indirdi. Başka hiçbir şey çalışmazken iki kez ölçtüm: mobilde 78 ve 74, LCP 5,9 s ve 6,1 s. Belge yarıya indi, LCP aynı. Kaldıraç başka yerde; bu gece tahmin etmeyi bıraktım. Küçülen sayfa yine de kalmaya değer.</p>
<p><strong>Güncelleme, 16 Eylül 2026.</strong> Kaldıraç yerel sunucuymuş. Yukarıdaki mobil sayıların hepsi dizüstümdeki <code>serve</code> ile alındı; o da HTML&#39;i sıkıştırmadan ve önbellek başlığı olmadan gönderiyor. Aynı derleme Firebase Hosting&#39;de, canlı hasanyahsi.com üzerinde Lighthouse 12 ile: mobil 90 / 100 / 100 / 100, LCP 2,4 s; masaüstü 99 / 100 / 100 / 100, LCP 0,6 s. 6 saniye hiçbir zaman sayfa değildi, sunuş biçimiydi. Yayındaki siteyi ölçmek son adım değil ilk adım olmalıydı.</p>
<p>Mobildeki erişilebilirlik denetimi menü bağlantılarını da işaretledi: 1100 px altında etiket metnini <code>display: none</code> ile gizlemiştim, bu erişilebilir addan da siliyor. Artık yalnızca görsel olarak gizli; mobil erişilebilirlik puanı 100.</p>
<h2>Bu not ne değil</h2>
<p>Bu sayıların hiçbiri belge değil. Lighthouse tek makinede benzetilmiş kısıtlamayla çalışıyor; paintcheck tek bir anda tek bir görünümü ölçüyor. Mesele daha küçük: referanstan bir renk kopyaladım, kendi aracımın var olma sebebi olan eşikte kaldı ve bunu yalnızca aracı çalıştırdığım için öğrendim.</p>
]]></content:encoded>
    </item>
    <item>
      <title>İki hafta yapay zekâ görünürlüğü için çalıştım, Cloudflare botları kapıda çeviriyormuş</title>
      <link>https://hasanyahsi.com/tr/notlar/cloudflare-yz-botlari/</link>
      <guid isPermaLink="true">https://hasanyahsi.com/tr/notlar/cloudflare-yz-botlari/</guid>
      <pubDate>Mon, 14 Sep 2026 06:00:00 GMT</pubDate>
      <description>ChatGPT ve Perplexity'nin siteyi okuyabilmesi için hizmet sayfaları yazdım, şema ekledim. Sonra ölçtüm; botların hepsi 403 alıyordu. Sebep içerik değildi, bir tık ile açılmış bir kuraldı.</description>
      <content:encoded><![CDATA[<p>Ağustos sonunda DijitalOfisim için bir hedef koydum: birisi ChatGPT&#39;ye &quot;İzmir&#39;de hekim için WhatsApp asistanı kim yapıyor&quot; diye sorduğunda ilk cevaplardan biri biz olalım. İki hafta boyunca üç hizmet sayfası yazdım, Service ve FAQ şemaları ekledim, Google İşletme Profili&#39;ni doldurdum, Search Console&#39;a kaydettim.</p>
<p>Bugün, ölçüm günü, önce Cloudflare paneline baktım. Güvenlik kurallarında şu vardı:</p>
<blockquote>
<p>AI Crawl Control - Block AI bots by User Agent · Aktif</p>
</blockquote>
<p>Kural ChatGPT-User, OAI-SearchBot, Claude-SearchBot, PerplexityBot ve bingbot dahil 16 botu robots.txt dışında her yolda engelliyordu. Son 24 saatte 212 yapay zekâ tarayıcı isteğinin 163&#39;ü reddedilmişti. OpenAI, Anthropic, Perplexity ve Bing için izin verilen istek: sıfır.</p>
<h2>Nasıl ölçtüm</h2>
<p>Panele güvenmedim, dışarıdan denedim. Aynı sayfaya farklı User-Agent ile istek attım:</p>
<pre><code>Googlebot        200
ChatGPT-User     403
PerplexityBot    403
bingbot          403
</code></pre>
<p>Yani iki haftalık iş, botların okuyamadığı sayfalara gitmişti.</p>
<h2>Kural nereden gelmiş</h2>
<p>Cloudflare&#39;ın AI Crawl Control ekranında tek bir &quot;Block&quot; düğmesi bu kuralı üretiyor. Muhtemelen aylar önce &quot;yapay zekâ içeriğimi çalmasın&quot; refleksiyle basılmış. O gün mantıklıydı; bugün aynı düğme müşteriyi getirecek botu da kapı dışarı ediyor.</p>
<p>Bir de ikinci katman vardı: Güvenlik ayarlarındaki yönetilen &quot;Block AI bots&quot; kuralı. Özel kuralı düzelttikten sonra bile arama botları 403 almaya devam etti, bunu da kapatınca açıldı.</p>
<h2>Ne yaptım</h2>
<p>Kuralı silmedim, daralttım. Eğitim için tarayan botlar (GPTBot, ClaudeBot, CCBot, Bytespider) hâlâ engelli. Arama ve canlı çekim yapanlar (ChatGPT-User, OAI-SearchBot, Claude-SearchBot, PerplexityBot, bingbot) serbest. Sonra aynı testi tekrarladım:</p>
<pre><code>ChatGPT-User     200
OAI-SearchBot    200
PerplexityBot    200
bingbot          200
GPTBot           403
ClaudeBot        403
</code></pre>
<h2>Ders</h2>
<p>İçerik yazmadan önce kapıyı kontrol et. Sitenizde Cloudflare varsa Güvenlik &gt; Kurallar ve Güvenlik &gt; Ayarlar &gt; Bot trafiği bölümlerine bir kez bakın. &quot;AI&quot; kelimesi geçen her engel, arama botunu da engelliyor olabilir.</p>
<p>Bir hafta sonra tekrar ölçeceğim. Botların yeniden ne zaman geleceğini bilmiyorum; ilk sonuçlar düşük çıkarsa buraya onu da yazarım.</p>
]]></content:encoded>
    </item>
  </channel>
</rss>
