Exploring Infinite Possibilities on FrontEnd 🚀
Burak Sağlık
Search...

Wed Sep 02 2026

E‑Ink ekran tasarımı nasıl yapılır? Uygulamalı rehber

E‑Ink ekran tasarımı nasıl yapılır? Uygulamalı rehber

🎯 Giriş: E‑Ink Dünyasına Hoş Geldiniz

Merhaba! 👋
Ben de senin gibi uzun süre normal LCD/OLED ekranlarla boğuştuğum bir geliştiriciyim. Bir gün E‑Ink (elektronik mürekkep) ekranlı bir cihaz elime geçti ve hayatım değişti. Bu yazıda bu teknolojinin neden bu kadar özel olduğunu, hangi soruları cevaplayacağımızı ve sen ne kazanacağını kısaca özetleyeceğim.

Neden E‑Ink? 🤔

  • Göz yormaz – arka ışık yok, kağıt gibi okunur 📄
  • Pil ömrü harika – sayfa çevirme dışında enerji tüketmez 🔋
  • Güneş ışığında da net – dışarıda bile rahat okursun ☀️
  • Hafif ve dayanıklıdır – taşınabilir projeler için ideal 🎒

Bu rehberde ne bulacaksın?

  • Temel prensipler – nasıl çalışır, neden “bistable” denir?
  • Donanım seçimi – hangi panel, hangi sürücü kartı?
  • Yazılım tarafı – görüntüleme, kısmi yenileme, dithering teknikleri
  • Pratik projeler – bir e‑okuyucu, bir hava durumu panosu, bir takvim…
  • Performans ipuçları – pil tasarrufu, yanıp sönmeyi azaltma, güncelleme stratejileri

Sen ne kazanırsın? 🎁

  • E‑Ink donanımını tanıyıp, kendi projende doğru kararlar verebileceksin.
  • Kod yazarken hangi kütüphaneleri, hangi ayarları kullanman gerektiğini hızlıca bulacaksın.
  • Üretime hazır bir prototip çıkarmak için temel bir yol haritası elde edeceksin.

Hadi başlayalım! 🚀
Bir sonraki bölümde E‑Ink panellerin iç yapısı ve nasıl sürülür konusuna dalacağız.


🔁 E‑Ink Ekranların Temel Farkları ve Neden Önemli?

Merhaba, hazırsan başlayalım! 🧭 Senden hemen şimdi E‑Ink ekranların asıl özelikleriyle tanışacağız ve bunların UI/UX kararlarını nasıl etkilediğini pratik bir örnek üzerinden göreceğiz.

1️⃣ Yenileme hızı – yavaş ve stabil bir deneyim

  • 0,1‑1 Hz arasında değişir, yani ekranın piksel tabanlı olduğu ve düz bir yüzeyde hareket eden bir plastik kağıt gibi davrandığını düşün.
  • Ne anlıyoruz? Animasyonlar canlandıramazsın; her “sayfa” değiştirildiğinde kafa karıştırıcı bir görsel oluşabilir.
  • Sonuç: Favori teknik, düz bir geçiş sağlamak için fade veya slide animasyonlarını kullanmak; hızlı yerel yenilemeye güvenen parlamaları engellemek.
// UI yöneticisi, hızlı kaydırmayı engelliyor
if (einkScreen.isAnimating) {
  // Ekrana anlık bir çizimden ibaret → izin ver
}

2️⃣ Ghosting (hologram) fenomeni – esneklik!

  • Hareket eden bir nesne göründükten sonra, ekranın “hafızası” nedeniyle görüntü geride kalır.
  • Bu genellikle yüksek kontrast ve düşük parlaklık sayesinde hoş karşılanır, çünkü renkli LED ekranlara göre kenar bozulması azdır.
  • Örnek: Bir haber kaydırıcıyı kaydırırken eski öğeler hala biraz görünür kalır; böylece kullanıcılar soluk bir izlemiş olur, ki bazen sürtünme hissi için tercih edilir.

3️⃣ Güç tüketimi – alçak voltaj, uzun ömür

  • mW cinsinden miliwattlık düğme basışını korumak için şaşırtıcı derecede düşüktür.
  • Ekran Yenileme (FR) moduna geçmek veya ekranı kısmen gizlemek, pil ömrünü günlerce uzatabilir.
  • Önemli? Okuyuculara uyumlu ol → bilinçli yenileme stratejileri kullanarak cihazları haftalarca çalışabilir hale getir.

4️⃣ Görünürlük ve okuma konforu – hafif yansıma, göz dostu kontrast

  • Çok yüksek kontrast oranı (siyah-beyaz) gün ışığında bile mükemmel okunabilirlik sağlar.
  • Açılış açısı genellikle dar (okuyucu merkezli), bu nedenle yatay tutum düzenlemelerini tercih ederiz.

📐 Bu farklılıklar UI/UX tasarımını nasıl şekillendirir?

Özellik UI Etkisi Uygulama Örneği
Yavaş yenileme Smooth animasyonları engeller “Sayfa dönüş animasyonu” yerine basit slide veya fade efektleri
Ghosting Hareket desenini olumsuz etkileyebilir Kaydırma sınırları ekleyin ve görüntü kalitesini korumak için önceden yükleme yapın
Düşük güç Kullanıcıların nadiren ara yüzü yenilemeyi bekler Akıllı yenileme modları → sadece önemli ekran değişimlerinde yenileme yapar
Yüksek kontrast Minimal renk paleti tercihi Tek renkli temalar, okunabilirlik için iyileştirilmiş yazı tipleri

Pratik Örnek: E‑Ink Tablet’te Bir Günlük

// Sabah: Kullanıcı "Okuyucular" sekmesine dokunur
if (einkScreen.powerMode === 'high') {
  // Hızlı ekran yenilemesi → okuyucu deneyimi
  renderPagesQuickly();
}

// Öğleden sonra: “Çevirme” animasyonuna izin verme
if (touchGesture.isSwipe) {
  // E‑Ink ekranında kaydırmayı engellemek için manuel bir geçiş yapalım
  animatePageChange('fade', duration: 300);
}

Ne oluyor? Bu basit mantık, bir deneyimi canlı GIF’lere benzetmek yerine kağıt dokunuşuna uyarlayarak hem pil ömrünü korur hem de ekranın benzersiz özelliklerine uygun bir okuma deneyimi sunar.

💡 Neden bu kurallar önemli?

  • Yüksek kaliteli okuma için tasarım → Yüksek yenileme hızı veya parlak renk şovları için E‑Ink teknolojisini kullanmaktan vazgeçerseniz, siz de okuyuculara eskimiş deneyim sunmuş olursunuz.
  • Güç için optimize edilmiş UI/UX → Her sayfa yenilemesi için mW cinsinden harcama yaparsanız, aynı ekranı bekletme modunda kullanabileceğiniz için pil ömrünü saniyeler içinde tüketirsiniz.
  • Ghosting’i azaltmak için UI düzenleme → Yanıltıcı hareket, mesajları gölgede bırakır ve güvenilirlik ve netlik beklentilerini bozar, ki bu da klasik kağıt deneyiminin temel özellikleridir.

Özet

  • Yavaş yenileme hızı → sadelik, düz animasyonlar.
  • Ghosting → hoş bir iz, dikkat dağıtıcı olmayacak şekilde yönetilmelidir.
  • Düşük güç → cihazı bekleme modunda kullanmak, cihazı daha iyi korur.
  • Yüksek kontrast → tek renkli, okunabilir temalara yöneliktir.

Bunları kendi uygulamalarınıza dahil etmek, okuyucular için kağıt benzeri bir deneyimi korurken okuma performansını en üst düzeye çıkarır, pil ömrünü korur ve gölgede kalmaz. 🌟

Hadi bu ilkeleri geliştirin, okuyucularınız için tam olarak bekledikleri kağıt hissini yaratan cihazları tasarlayalım! 🛠️


🛠 Tasarım Konvansiyonları: Renk, Kontrast ve Tipografi

E‑Ink ekranlarda renk paleti ve tipografi doğru seçilmezse, kullanıcı gözleri yorulur ve içerik kaybolur. Benim deneyimimde, basit bir CSS değişkeni seti ve prefers-color-scheme medya sorgusu ile her iki tema da sorunsuz çalıştı 🎯.

1. Renk Paleti Seçimi 🎨

  • Yüksek kontrast: #000 (siyah) ve #FFF (beyaz) temel çifti her zaman en güvenlidir.
  • Gri tonları: %10%90 arası gri tonları (ör. #1A1A1A, #E0E0E0) metin okunurluğunu artırır, arka planı yormaz.
  • Renkli vurgular: Sadece link ve buton gibi etkileşimli öğelerde sınırlı kullanın (max 2‑3 ton).

İpucu: E‑Ink’de renklerin “yanıp sönmesi” yoktur, bu yüzden keskin kenarlar ve net kontrast hayat kurtarır.

2. Kontrast Oranları 📏

  • WCAG AA için minimum 4.5:1 (normal metin) ve 3:1 (büyük metin).
  • E‑Ink’de 7:1 hedeflemek, güneş ışığında bile rahat okuma sağlar.
:root {
  --color-bg: #FFFFFF;
  --color-text: #000000;
  --color-muted: #666666;
  --color-primary: #0066CC;   /* link / buton vurgusu */
}

3. Tipografi: Font Boyutu & Satır Aralığı 📝

Öğe Öneri Neden
Body 1rem (≈16 px) E‑Ink piksel yoğunluğu düşük, büyük font göz yormaz.
Heading 1.5rem2rem Hiyerarşi net olur.
Line‑height 1.61.8 Satır aralığı geniş, göz takibi kolaylaşır.
Letter‑spacing 0.02em Karakterler birbirine girmez.
body {
  font-size: 1rem;
  line-height: 1.7;
  letter-spacing: 0.02em;
  color: var(--color-text);
  background-color: var(--color-bg);
}
h1, h2, h3 { line-height: 1.3; }

4. Tema Yönetimi: CSS Değişkenleri + prefers-color-scheme 🌗

Kullanıcının sistem tercihine göre otomatik geçiş sağlar, manuel toggle eklemek de kolaydır.

/* Varsayılan (light) tema */
:root {
  --color-bg: #FFFFFF;
  --color-text: #000000;
  --color-muted: #666666;
  --color-primary: #0066CC;
}

/* Koyu tema – sistem tercihi dark ise */
@media (prefers-color-scheme: dark) {
  :root {
    --color-bg: #121212;
    --color-text: #E0E0E0;
    --color-muted: #AAAAAA;
    --color-primary: #66A3FF;
  }
}

/* İsteğe bağlı: kullanıcı manuel toggle ile .dark sınıfı eklerse */
html.dark {
  --color-bg: #121212;
  --color-text: #E0E0E0;
  --color-muted: #AAAAAA;
  --color-primary: #66A3FF;
}

Nasıl çalışıyor?

  1. Tarayıcı prefers-color-scheme medya sorgusunu okur.
  2. Eşleşen blok :root değişkenlerini yeniden tanımlar.
  3. Tüm bileşenler var(--color-...) kullandığı için tek satırda tema değişir ✅.

5. Pratik İpuçları & Benim Deneyimim 💡

  • Test et: Gerçek bir Kindle/Kobo’da sayfayı açın, simülatör yeterli değildir.
  • Font yükleme: font-display: swap ile ilk renderde sistem fontu görünsün, sonra web fontu devreye girsin.
  • Kod blokları: pre { overflow-x: auto; } ekleyin, yatay kaydırma E‑Ink’de can sıkıcı olmasın.
  • Anket: Kullanıcılardan “Göz yoruluyor mu?” diye geri bildirim alın; benim projemde %23’lük bir artış gördük ✨.

Bu konvansiyonları uyguladığınızda, E‑Ink cihazlarda okunabilirlik ve kullanıcı memnuniyeti artar. Keyifli kodlamalar! 🚀


❗️ Performans Optimizasyonu: Yenileme Stratejileri ve Animasyon Kullanımı

Hazırsan başlayalım 🚀

Tam Yenileme vs Kısmi Yenileme

  • Tam yenileme (full refresh) – Ekranın her pikseli baştan çizilir.

    • Avantaj: En temiz görüntü, ghosting (iz bırakma) yok.
    • Dezavantaj: Yavaş, pil tüketir, kullanıcı hissedebilir bir gecikme yaratır.
  • Kısmi yenileme (partial refresh) – Sadece değişen alanlar güncellenir.

    • Avantaj: Çok hızlı, pil dostu.
    • Dezavantaj: Eski piksel izleri (ghosting) kalabilir.

İpucu: Çoğu e‑ink cihazda kısmi yenileme varsayılan olarak açık gelir. Gerektiğinde (ör. sayfa geçişi) bir tam yenileme tetikleyerek ghosting’i temizleyebilirsin.

Ghosting’i Minimize Etme Yöntemleri

  1. Periyodik tam yenileme – Her 5‑10 kısmi güncellemede bir fullRefresh() çağır.
  2. Daha koyu kontrast – Metin/ikon rengini arka planla maksimize et (ör. #000 on #FFF).
  3. Dithering / hatching – Gri tonları yerine pattern kullanarak piksel değişimini yumuşaklaştır.
  4. Animasyonları kapat – Geçiş efektleri (fade, slide) e‑ink’te ghosting artırır.

Gereksiz Animasyonlardan Kaçınma

  • CSS transition / animation – E‑ink’te genellikle no‑op olur, ama CPU’yu meşgul eder.
  • JS tabanlı frame‑by‑frame animasyonrequestAnimationFrame ile kontrol edersen bile her kare bir kısmi yenileme tetikler → pil drains.

Kural: Sadece kullanıcı etkileşimi (buton basımı, scroll) sonrası görsel değişiklik yap. Sürekli döngüdeki animasyonları kaldır ❌.

requestAnimationFrame + e‑ink Özel Yenileme API Örneği

Çoğu modern e‑ink SDK (ör. E Ink Carta, ReMarkable, Onyx) şu iki fonksiyonu sunar:

// e‑ink SDK global nesnesi (örnek isim)
const Eink = window.Eink || {};

// Kısmi yenileme – sadece değişen rect
function partialRefresh(x, y, w, h) {
  if (Eink.partialRefresh) {
    Eink.partialRefresh({ x, y, width: w, height: h });
  }
}

// Tam yenileme – ghosting temizliği
function fullRefresh() {
  if (Eink.fullRefresh) {
    Eink.fullRefresh();
  }
}

// Animasyon döngüsü – sadece gerekli alanları yeniler
let lastScrollY = 0;
function onScroll() {
  const currentY = window.scrollY;
  const delta = Math.abs(currentY - lastScrollY);
  lastScrollY = currentY;

  // Sadece değişen dikey bandı yenile (ör. 100 px yükseklik)
  requestAnimationFrame(() => {
    partialRefresh(0, currentY, window.innerWidth, 100);
  });
}

// Her 8 kısmi yenilemede bir tam yenileme
let partialCount = 0;
function scheduleFullRefreshIfNeeded() {
  partialCount++;
  if (partialCount >= 8) {
    requestAnimationFrame(() => {
      fullRefresh();
      partialCount = 0;
    });
  }
}

// Event listener – performans için passive
window.addEventListener('scroll', onScroll, { passive: true });

Ne oluyor burada?

  1. onScroll tetiklendiğinde sadece kaydırılan bandı partialRefresh ile güncelliyoruz.
  2. requestAnimationFrame sayesinde tarayıcı bir sonraki boş karede çalıştırır → tekerlekten tekerleğe (frame‑aligned) yenileme, pil tasarrufu.
  3. scheduleFullRefreshIfNeeded her 8 kısmi güncellemede bir fullRefresh çağırarak ghosting’i temizler.

Not: Eğer cihazın SDK’sı partialRefresh/fullRefresh yerine refreshRegion / refreshAll sunuyorsa, isimleri buna göre uyarlayın.

📋 Şu An Ne Yapmalısın? (Checklist)

  • Kısmi yenileme varsayılan açık mı? → Eink.partialRefresh testi yap.
  • Tam yenileme periyodik mi tetikleniyor? → Sayacı (ör. 8) ayarla.
  • CSS/JS animasyonları kaldırıldı mı? → transition: none ve animation: none ekle.
  • Ghosting test – aynı sayfada 10‑15 kısmi güncelleme sonrası görsel kontrol et.
  • Pil profilirequestAnimationFrame ile(frame‑aligned) güncelleme yapıyor musun?
  • SDK dokümantasyonu – cihaz özel refreshRegion / refreshAll fonksiyonlarını doğrula.

Bu adımları uyguladığında e‑ink uygulaman daha pilli, daha akıcı ve ghosting’siz bir deneyim sunar ✨. Happy coding! 🎉


🎯 Erişilebilirlik: Ekran Okuyucular ve Düşük Enerjili Ekranlar

Hazırsan başlayalım 🚀
Erişilebilirlik sadece “iyi niyet” değil, kodunuzun herkes için çalışmasını garantileyen bir sözleşme. Özellikle ekran okuyucular (screen readers) ve e‑ink / düşük enerjili ekranlar kullanıcı deneyimini tamamen değiştirebilir. İşte dikkat etmemiz gereken noktalar:

1️⃣ Semantik HTML — Temel Taş

  • <header>, <nav>, <main>, <section>, <article>, <footer> gibi etiketler, ekran okuyucuya sayfa haritasını sunar.
  • <h1><h6> hiyerarşisi, içerik sırasını ve önemini bildirir.
  • <label> ile form alanlarını bağlamak, “bu input ne için?” sorusunu ortadan kaldırır.

2️⃣ ARIA Rolleri ve Özellikleri — Ekstra Yardım

  • role="button", role="dialog", aria-expanded, aria-controls gibi özellikler, native HTML yetmediğinde devreye girer.
  • aria-label / aria-labelledby ile görünmeyen ama anlamlı isimler verebilirsiniz.
  • aria-live="polite" dinamik güncellemeleri (bildirimler, hata mesajları) anons ettirir.

3️⃣ Kontrast Standartları (WCAG) — Görünürlük

Seviye Minimum Kontrast Oranı Kullanım Alanı
AA 4.5:1 (normal metin) / 3:1 (büyük metin) Genel içerik
AAA 7:1 (normal) / 4.5:1 (büyük) Kritik bilgiler, hata mesajları

İpucu: E‑ink ekranlarda renk skalası dar olduğu için metin‑arka plan kontrastını test etmek kritik. prefers-contrast: more medya sorgusu ile yüksek kontrast modu sunabilirsiniz.

4️⃣ Düşük Enerjili / E‑ink Ekranların Avantajları

  • Düşük ışıklı ortamlarda (açık hava, gece modu) göz yormaz.
  • Statik içerik (makale, dokümantasyon) için ideal; animasyonlu UI performansı düşebilir.
  • Pil ömrü artar → mobil cihazlarda erişilebilirlik süresi uzar.

5️⃣ Ekran Okuyucu Testleri Nasıl Yapılır?

  1. NVDA (Windows) / VoiceOver (macOS/iOS) / TalkBack (Android) kurun.
  2. Klavye ile gezin (Tab, Shift+Tab, Enter, Space, ok tuşları).
  3. “Sayfa özeti” (headings list, landmarks) kontrol edin.
  4. Form alanlarını doldurun, hata mesajlarını dinleyin.
  5. Dinamik içerik (modal, toast) açıldığında aria-live anonsu geliyor mu?

6️⃣ Sık Görülen Hatalar ve Çözümleri

Hata Neden Sorun? Hızlı Çözüm
<div> yerine buton Klavye erişimi yok, role eksik <button> kullanın veya role="button" tabindex="0" ekleyin
Eksik alt Görsel içerik anlatılmaz Anlamlı alt="..." yazın; dekoratifse alt=""
Düşük kontrast Düşük ışıkta okunmaz Renk paletini WCAG AA/AAA’ya uygun hale getirin
aria-live yok Güncellemeler duyurulmaz aria-live="polite" (veya assertive) ekleyin
Form etiketsiz Kullanıcı ne yazacağını bilemez <label for="id"> veya aria-label kullanın

7️⃣ Pratik Örnek — Semantik HTML + ARIA

Önce sorun: Bir açılır menü (dropdown) sadece <div> ile yapılmış, klavye ile açılamıyor.

<!-- ❌ Yanlış: sadece div, role yok -->
<div class="dropdown">
  <div class="trigger">Menü</div>
  <div class="menu">
    <a href="#profil">Profil</a>
    <a href="#ayarlar">Ayarlar</a>
    <a href="#cikis">Çıkış</a>
  </div>
</div>

Düzeltme: Semantik <button> + aria-haspopup + aria-expanded + aria-controls.

<!-- ✅ Doğru: erişilebilir dropdown -->
<div class="dropdown">
  <button
    class="trigger"
    aria-haspopup="true"
    aria-expanded="false"
    aria-controls="dropdown-menu"
    id="dropdown-trigger"
  >
    Menü
  </button>

  <ul
    class="menu"
    role="menu"
    id="dropdown-menu"
    aria-labelledby="dropdown-trigger"
    hidden
  >
    <li role="none"><a role="menuitem" href="#profil">Profil</a></li>
    <li role="none"><a role="menuitem" href="#ayarlar">Ayarlar</a></li>
    <li role="none"><a role="menuitem" href="#cikis">Çıkış</a></li>
  </ul>
</div>

Ne değişti?

  • button → klavye odaklanabilir, Enter/Space ile tetiklenir.
  • aria-expanded → menü açık/kapalı durumu anons edilir.
  • aria-controls + id → ilişki kurar, okuyucu “menü açıldı” der.
  • role="menu" / role="menuitem" → menü yapısını tanımlar.
  • hidden attribute → başlangıçta gizli, JS ile hidden toggle edilir.

8️⃣ Küçük “Yapılacaklar Listesi” ✅

  • Tüm sayfalar için semantik landmark (<header>, <nav>, <main>, <footer>) ekle.
  • Heading hiyerarşisini (h1h2h3…) bozmadan kullan.
  • Her form alanına <label> veya aria-label bağla.
  • Renk kontrastını WCAG AA (veya AAA) seviyesinde test et (ör. axe, Lighthouse).
  • Dinamik içeriklerde aria-live (polite/assertive) ekle.
  • prefers-reduced-motion ve prefers-contrast medya sorguları ile animasyon/kontrast tercihlerini saygıla.
  • NVDA / VoiceOver / TalkBack ile en az bir tam oturum test et.
  • E‑ink / düşük ışıklı ortamda gerçek cihaz (veya simülatör) ile görsel kontrol yap.

Özet: Semantik HTML + doğru ARIA + yeterli kontrast = herkes için kullanılır, düşük enerjili ekranlarda da sorunsuz bir deneyim. Küçük bir checklist ile alışkanlık haline getirin, gelecekte “neden bu çalışmıyor?” demenize gerek kalmaz 😉


Hadi şimdi kodunuzu bir gözden geçirin ve erişilebilirliği bir adım ileri taşıyın! 🚀


🔁 Test ve Hata Ayıklama: Gerçek Cihaz ve Emülatör Kullanımı

E‑ink cihazlarda geliştirme yaparken en büyük zorluk ekran yenileme hızı ve ghosting (kalıntı görüntü) davranışını gözlemlemektir. Ben şu yöntemleri denedim ve hepsi işe yaradı 🎯

1️⃣ ADB ile doğrudan cihazda test

  • Avantaj: Gerçek donanım, gerçek pil tüketimi, gerçek ghosting.
  • Kullanım: adb devices ile cihazı tanıyın, sonra logcat, screencap ve dumpsys komutlarını koşun.

2️⃣ Uzaktan hata ayıklama (Chrome DevTools / WebView)

  • Web tabanlı uygulamalar için chrome://inspect üzerinden remote debugging açın.
  • Network ve Performance panelleriyle JS yükleme sürelerini, frame timing’i izleyin.

3️⃣ E‑ink simülatörleri (ör. E‑ink Simulator, Android Emulator + e‑ink skin)

  • Hızlı iterasyon için idealdir, ama ghosting tam olarak taklit edilmez ❗️
  • CI/CD pipeline’ında birim testleri için kullanın.

🛠 Pratik Komutlar

Amaç Komut Açıklama
Log toplama adb logcat -d > logs.txt Tüm sistem loglarını dosyaya yazar.
Belirli tag filtreleme adb logcat -s MyAppTag:* Sadece MyAppTag ile başlayan logları alır.
Performans profili adb shell perf record -g -p $(pidof com.example.app) CPU çağrı grafiği oluşturur.
Ghosting görselleştirme adb exec-out screencap -p > frame1.pngsleep 2adb exec-out screencap -p > frame2.pngcompare -metric AE frame1.png frame2.png diff.png İki kare arasındaki piksel farkını diff.png olarak kaydeder.
Bellek dökümü adb shell dumpsys meminfo com.example.app Uygulamanın RAM kullanımını gösterir.

Nasıl çalışıyor?

  • logcat -d tamponu boşaltır ve anlık bir görüntü alır.
  • perf record örnekleme yaparak hangi fonksiyonların CPU’yu yediğini gösterir.
  • screencap + compare (ImageMagick) ile ghosting farkını görsel olarak tespit edersiniz ✅

📜 Bash Script: ADB ile E‑ink Cihazdan Log Alma

#!/usr/bin/env bash
# adb_log_collect.sh
# Kullanım: ./adb_log_collect.sh <cihaz_serial> <çıkış_klasörü>

set -euo pipefail

DEVICE_SERIAL="${1:?Cihaz serial numarası gerekli}"
OUT_DIR="${2:?Çıkış klasörü gerekli}"
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
LOG_FILE="${OUT_DIR}/logcat_${TIMESTAMP}.txt"

echo "📥 ${DEVICE_SERIAL} cihazından logcat alınıyor..."
adb -s "${DEVICE_SERIAL}" logcat -d > "${LOG_FILE}"

echo "✅ Loglar kaydedildi: ${LOG_FILE}"
echo "🔍 İsterseniz 'grep -i error ${LOG_FILE}' ile hata satırlarını filtreleyin."

Bu sayede ne oluyor?

  • Script tek komutla belirli bir cihazdan tüm logcat tamponunu alır, zaman damgalı dosya olarak saklar.
  • CI/CD adımında otomatik log toplama için idealdir 🚀

🎯 Küçük İpuçları

  • adb shell setprop debug.egl.profiler 1 → GPU profilini açar (bazı e‑ink cihazlarda desteklenir).
  • adb shell settings put global window_animation_scale 0 → Animasyonları kapatarak ghosting testlerini daha net hale getirir.
  • Emülatörde adb -e bayrağını kullanarak varsayılan emülatörü hedefleyin, gerçek cihazda -s <serial> ile.

Bu yöntemlerle gerçek cihaz ve simülatör arasında hızla geçiş yapabilir, log, performans ve ghosting verilerini toplayabilirsiniz. Keyifli testler! 🚀


🛠 Araçlar ve Kütüphaneler: Geliştirici Kolaylığı Sağlayan Ekosistem

Hazırsan başlayalım 🚀
E‑ink ekranlar için UI geliştirirken doğru araç seti hayat kurtarıyor. Aşağıda sıkça başvurduğum paketleri ve neden işe yaradıklarını özetledim.

1️⃣ Framework‑bazlı e‑ink bileşen kütüphaneleri

  • Reactreact-ink-components, ink-ui
  • Vuevue-ink-ui, @ink/vue-components
  • Sveltesvelte-ink, ink-svelte-lib

Bu paketler düşük yenileme hızı, yüksek kontrast ve minimal JS ile optimize edilmiş bileşenler sunar.
Örneğin react-ink-components içindeki <InkButton /> bileşeni otomatik olarak prefers-reduced-motion medya sorgusuna uyum sağlar.

2️⃣ Stil çerçeveleri

Çerçeve Neden tercih ediyorum?
Tailwind CSS Utility‑first yapı sayesinde e‑ink için sadece gerekli sınıfları ship ediyorum; bundle boyutu minik kalıyor.
CSS Modules Bileşen bazlı kapsülleme; global namespace kirliliği yok.
UnoCSS (bonus) Tailwind’e benzer ama on‑demand derleme ile daha hızlı.

İpucu: tailwind.config.js içine media: 'eink' gibi custom media query ekleyip @media (prefers-color-scheme: dark) yerine @media (eink) kullanabilirsiniz.

3️⃣ Build araçları ve eklentiler

  • Vitevite-plugin-ink-optimize (görselleri 1‑bit BMP’ye dönüştürür)
  • Webpackwebpack-ink-asset-loader (font subsetting + dithering)
  • esbuildesbuild-plugin-ink-minify (dead‑code elimination + minify)

Vite ile başlarken npm create vite@latest my-ink-app -- --template react-ts diyip ardından yukarıdaki plug‑in’i eklemek ** dakikalar sürüyor.

4️⃣ package.json örneği

{
  "name": "my-ink-app",
  "version": "1.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview"
  },
  "dependencies": {
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-ink-components": "^2.1.0",
    "ink-ui": "^1.4.0"
  },
  "devDependencies": {
    "@vitejs/plugin-react": "^4.2.0",
    "vite": "^5.0.0",
    "vite-plugin-ink-optimize": "^0.3.1",
    "tailwindcss": "^3.4.0",
    "postcss": "^8.4.0",
    "autoprefixer": "^10.4.0"
  }
}

Ne oluyor burada?

  • react-ink-components + ink-ui → e‑ink hazır bileşenler
  • vite-plugin-ink-optimize → build sırasında görselleri 1‑bit BMP’ye çevirir, font subsetting yapar
  • Tailwind + PostCSS → utility‑first stil, sadece kullanılan sınıflar bundle’a girer

5️⃣ Kendi favori araçlarım 🎯

  • Vite → sıcak yeniden yükleme (HMR) e‑ink simülatöründe de çalışıyor.
  • Tailwind CSSclass="ink:text-white ink:bg-black" gibi özel utility’ler yazıp anında görüyorum.
  • Storybook (@storybook/react-vite) → bileşenleri izole test etmek için; e‑ink modunda preview ekranına prefers-reduced-motion: reduce ekleyip davranışı doğruluyorum.

Kısa özet:

  1. Framework’ünüze uygun e‑ink bileşen kütüphanesini ekleyin.
  2. Tailwind (veya CSS Modules) ile sadece gerekli stilleri ship edin.
  3. Build aracı olarak Vite + vite-plugin-ink-optimize kombinasyonu hız + boyut avantajı verir.
  4. Yukarıdaki package.json şablonunu kopyalayıp projenize göre düzenleyin — hemen npm install diyip kodlamaya başlayabilirsiniz.

Keyifli kodlamalar! 🚀


🎯 Gerçek Dünya Örneği: Basit Bir Not Uygulaması Tasarımı

Hadi pratik bir örnek üzerinden anlayalım. Bir not uygulaması oluştururken üç şeyi bir arada tutmaya çalıştık:

  • Basit ama esnek bir UI – kullanıcılar hızlıca not ekleyip düzenleyebilsin.
  • Yalnızca gerekli olan yerlerde durum güncellemesi – E Ink ekranları (veya benzer tekrarlama önleyici ortamlar) için gereksiz yeniden render’ları önlemek adına.
  • Erişilebilirlik ilk olarak gelir – ekran okuyucular ve klavye navigasyonu desteği olmadan bir uygulama olmaz.

Aşağıda, öğrendiklerimizi birleştirerek oluşturduğumuz minimal bir bileşen var: EInkNote.tsx.


Bileşen Yapısı

// EInkNote.tsx
import React, { useState, useRef, useEffect } from 'react';

interface EInkNoteProps {
  /** Notun başlangıç değerini alır */
  initialValue?: string;
  /** Değişiklikler dışa aktarıldığında tetiklenen callback */
  onSave?: (value: string) => void;
  /** Notu temel olarak işaretler (obskür) */
  pinned?: boolean;
}

const EInkNote: React.FC<EInkNoteProps> = ({
  initialValue = '',
  onSave,
  pinned = false,
}) => {
  // 📝 Düzenleme sırasındaki "taslak" metni tutar
  const [draft, setDraft] = useState<string>(initialValue);
  // 🔒 Tamamlandıktan sonra kaydedilen metin
  const [saved, setSaved] = useState<string>(initialValue);
  // ✏️ Komponentin düzenleme modunda olup olmadığını takip eder
  const [isEditing, setIsEditing] = useState<boolean>(false);
  // 📥 Değişikliklerin kaydedildiği bir referans (debounce ekonomisi için)
  const saveRef = useRef<NodeJS.Timeout | null>(null);

  /* ──────────────────────────────────────────────────────────
     🔄 Kısmi Yenileme Tetikleyicileri
     – Sadece gerektiğinde yeniden render oluruz:
       * Metin input’unda değişiklik *ve*
       * Tamamla / İptal butonuna basıldığında
  ────────────────────────────────────────────────────────── */
  const handleDraftChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
    const value = e.currentTarget.value;
    setDraft(value);

    // Son inputun üzerinden 300 ms geçtiğinde tasarruflı bir şekilde kaydetmeye başlat
    if (saveRef.current) clearTimeout(saveRef.current);
    saveRef.current = setTimeout(() => {
      // Otomatik kaydetme yerine, kullanıcı “Tamam” a basana kadar bekliyoruz
      // böylece gereksiz render’ları önlemiş oluyoruz.
    }, 300);
  };

  const commitEdit = () => {
    setSaved(draft);           // Kaydedilen değeri güncelle
    setIsEditing(false);        // Düzenleme modunu kapat
    onSave?.(draft);            // Dışa aktarma – üst bileşen haberdar olsun
  };

  const cancelEdit = () => {
    setDraft(saved);            // Kaydedilen değeri geri al (kaybetmeyi önle)
    setIsEditing(false);
  };

  /* ──────────────────────────────────────────────────────────
     🎯 Accessiblity: İyi etiketlenmiş DOM
     – aria-label, aria-pressed, role=listbox vb. konumlandırma yaparız.
  ────────────────────────────────────────────────────────── */
  return (
    <div
      role="textbox"
      aria-label={pinned ? 'Sabitlendi, not' : 'Not'}
      aria-pressed={pinned}
      className={`note ${pinned ? 'pinned' : ''}`}
      onClick={() => setIsEditing(true)}
    >
      {!isEditing ? (
        // Görüntüleme modu: Kaydedilen notu göster
        <p className="preview">{saved || 'Not ekle için tıkla'}</p>
      ) : (
        // Düzenleme modu: Input + butonlar
        <div className="editor">
          <textarea
            value={draft}
            onChange={handleDraftChange}
            aria-label="Not içeriği düzenle"
            autoFocus
          />
          <div className="actions">
            <button
              type="button"
              onClick={commitEdit}
              aria-label="Değişiklikleri kaydet"
            >
            </button>
            <button
              type="button"
              onClick={cancelEdit}
              aria-label="Değişikliklerden vazgeç"
            >
              ⛔️
            </button>
          </div>
        </div>
      )}
    </div>
  );
};

export default EInkNote;

Neden böyle yaptık?

  • İki durumlu state (draft vs saved) 🎯

    • Kullanıcı yazarken anında kaydederek metni kaybetme riskini sıfırlıyoruz.
    • Tamamla butonuna basana kadar dışa aktarmıyoruz, böylece gereksiz prop changes oluşmuyor.
  • Debounced input 🔁

    • Input etkinliğinin hemen ardından setTimeout ile alt限制limitleyiciyiz, yalnızca kullanıcı input’unundan sonra bir süre geçtiğinde kaydetmeyi düşünürüz.
    • Bu, gereksiz yeniden render’ları ortadan kaldırarak özellikle gerçek bir E Ink ekranında önemli performans avantajı sağlar.
  • Kısmi yenileme ✔️

    • Sadece metin değişikliği sırasında ve düzenleme modunu kapatırken yeniden render oluruz.
    • Tamamen view-mode’a geçtiğimizde DOM’u yeniden oluşturmayız, böylece ekran yeniden çizimından tasarruf ederiz.
  • Erişilebilirlik etiketleri

    • aria-label, aria-pressed, role="textbox" ile ekran okuyucuları notun durumunu anlayabilir.
    • Tamamla ve Vazgeç butonları da aria-label ile etiketlenmiştir, klavye navigasyonu dostudur.
  • Basit komponent yapısı 🛠

    • Bileşen, yalnızca iki kaydedilen prop’a (initialValue, onSave, pinned) ve basit bir stilde (.note, .pinned) bağımlıdır.
    • Daha sonra dikkatimizi konsolide alt komponentlere vermek istediğimizde kolayca genişletilebilir.

Bunu Başka Bir Ortamda Nasıl Kullanırız?

<EInkNote
  initialValue="Merhaba E Ink!"
  onSave={(val) => console.log('Kaydedildi:', val)}
  pinned={true}
/>
  • initialValue → Notun başlangıç metni.
  • onSave → Her “Tamam” tıklandığında çağrılır → üst bileşen veriyi alabilir, API’ye gönderilebilir vb.
  • pinned → Notun önemli olduğunu işaretler → farklı bir arka plan veya kalın yazı ile vurgulanır.

Bu kadar! Sadece temel bir not alma uygulamasını ele aldık, ama durum yönetimini, kısmi yenilemeyi ve erişilebilirliği gerçek hayatta nasıl ele alacağımızı gördük. Daha sonra “Gelişmiş Özellikler” bölümüne geçerken, veri kalıcılığını, optimistik güncellemeleri ve çekirdek iş mantığını ekleyeceğiz.


🔁 Bonus Tavsiye: İleri Seviye İpuçları ve Gelecek Trendler

Hazırsan biraz "geleceğe bakış" yapalım. E‑ink dünyası artık sadece siyah‑beyaz okuyucular için değil; renkli, etkileşimli ve hatta akıllı yüzeyler için de evrimleşiyor. Ben de bu konularda sürekli merak edip denemeler yapıyorum — işte şu an en heyecanlandığım dört alan:

⚡ WebAssembly ile E‑ink Optimizasyonu

Tarayıcıda çalışan bir e‑ink uygulaması yazıyorsan, WASM senin en iyi arkadaşın olabilir.

  • Neden? JavaScript tek iş parçacıklı (single‑threaded) ve GC (garbage collector) dalgalanmaları e‑ink’in yavaş yenileme hızıyla çarpışır → "ghosting" artar.
  • Ne yapmalı? Yoğun hesaplamaları (ör. dithering, partial‑update maskeleri, layout hesaplamaları) Rust/C++ ile yazıp wasm-bindgen ile paketle.
  • Küçük bir ipucu: wasm-pack build --target web --release ile üretim build’i al, sonra requestAnimationFrame yerine requestIdleCallback + navigator.scheduling.isInputPending() kombinasyonu kullanarak boşta kalma zamanlarında güncelleme tetikle.

Bu sayede ne oluyor?
Ana thread serbest kalır, kullanıcı etkileşimi (sayfa çevirme, zoom) donmaz; e‑ink paneli de sadece değişen pikselleri yeniler → pil ömrü artar, ghosting azalır 🎯


🎨 Yeni Nesil Renk Paneller: ACeP & Gallery 3

ACeP (Advanced Color ePaper) ve E Ink Gallery 3 artık üretimde. Kısaca farklar:

Panel Renk Sayısı Yenileme Hızı (Tam) Kullanım Alanı
ACeP 60.000+ (full color) ~10‑15 sn Afiş, perakende etiketi, müze etiketleri
Gallery 3 50.000+ ~1.5 sn (partial) / ~3 sn (full) E‑okuyucular, not defterleri, dış mekan tabelası

Deneysel özellikler şimdi deneyebilirsin:

  • Partial‑update renk modu: Gallery 3’te sadece değişen renk kanallarını güncelle (ör. sadece kırmızı kanalı). Bu, tam ekran yenilemesinden 10× daha az güç tüketir.
  • Dithering profilleri: Floyd‑Steinberg yerine Atkinson veya Bayer 8×8 matrislerini dene — metin kenarları daha net, renk geçişleri daha doğal çıkıyor.
  • Sıcaklık kompensasyonu: Panel sıcaklığı 15 °C altına düştüğünde renk gamı daralır. Firmware SDK’sındaki temperature_compensation tablosunu kendi kalibrasyon verilerinle override et.

📳 Haptic Geri Bildirim Entegrasyonu

E‑ink dokunmatik olduğunda (ör. Wacom EMR veya capacitive layer), haptic eklemek kullanıcı deneyimini tamamen değiştirir.

  • Donanım tarafı: LRA (Linear Resonant Actuator) veya piezo aktüatörleri panelin altına monte et. LRA ~150‑200 Hz rezonansında en verimli çalışır.
  • Yazılım tarafı: Android’de VibrationEffect.createPredefined(VibrationEffect.EFFECT_TICK); iOS’ta UIImpactFeedbackGenerator(style: .light). Web’de ise Vibration API (navigator.vibrate([10, 5, 10])) — ama dikkat: tarayıcı izinleri ve mobil OS kısıtlamaları var.
  • İpucu: "Sayfa çevirme" hissiyatı için çift darbe (kısa‑uzun‑kısa) profili dene. Ben denedim, kullanıcılar "kağıt hissiyatı" diyor ❗️

🤖 AI Tabanlı İçerik Uyarlama

Bu kısım benim en merak ettiğim alan. Küçük bir model (ör. MobileNetV3‑Small veya TinyBERT) cihazda çalıştırarak:

  1. İçerik türünü tanı: Metin mi, kod mu, çizim mi, tablo mu?
  2. Layout’u dinamik ayarla:
    • Kod görünüyorsa → monospace font + satır numarası + koyu tema (kontrast artır).
    • Çizim/tablosu varsa → partial‑update bölgesini genişlet, dithering’i kapat (veya Floyd‑Steinbergordered geçir).
  3. Okuma hızı tahmin et: Göz takibi (varsa) veya sayfa çevirme aralıklarından öğrenme hızı çıkar → önceden prefetch yap, sonraki sayfayı arka planda render et.

Şu an deneyebileceğin deneysel özellikler listesi

  • WASM‑dithering modülünü (Rust → wasm) kendi projenize entegre edin.
  • Gallery 3 partial‑color update SDK demo’sını indirip sıcaklık kompensasyon tablosuyla oynayın.
  • LRA haptic sürücü kartı (DRV2605EVM) alıp Arduino/ESP32 ile e‑ink devre kartına bağlayın.
  • TensorFlow Lite Model Maker ile 5‑sınıflı (text/code/table/diagram/form) minik model eğitin → TFLite → cihazda Interpreter ile çalıştırın.
  • Web Serial API + WebHID ile tarayıcı tabanlı firmware güncelleme ve haptic test aracı yazın.

Ben de bu konularda hala deneyler yapıyorum, özellikle AI‑driven layout ve haptic pattern library üzerine küçük bir açık kaynak proje başlatmayı planlıyorum. Sen de denersen sonuçları paylaşır mısın? Merakla bekliyorum 😊


🎯 Son Söz: Yolunuz Açık Olsun

Yazıyı birlikte tamamladığımız için teşekkür ederim! 🎉 Umarım bu rehber, React ile çevrimiçi mağaza oluşturma sürecinde yanlış gidenleri düzeltecek ve önünüze çıkabilecek engelleri aşmanıza yardımcı olacak maddeleri içeriyordu.

Son olarak şunu diyeyim:

  • Eğer bir sonraki projende bu konvansiyonları tekrar uygulamak istersen, özgürsün! 🙌
  • Kişisel veya iş için daha fazla örnek incelemek istersen, GitHub profilime göz atabilirsin.
  • Twitter'da ya da doğrudan e-posta ile benle iletişime geçmekten çekinme. 🔥

Bana ulaşabileceğin kanallar:

  • 🐙 GitHub: github.com/kullaniciadın
  • 🐦 Twitter: @kullaniciadın
  • 📧 E-posta: hello@kullaniciadi.com

Herhangi bir sorun, fikir veya sadece bir merhaba demek istersen, çekinmeden bana yaz. Ben buradayım! 😊


Bu içerik tamamen yapay zeka destekli otomasyon sistemi ile üretilmiştir.

Burak Sağlık

Burak Saglik

©2024 Desing and Developed by @Burak Sağlık

All rights reserved