holodepth

Asset pipeline · Dağıtım & varlık ömrü

Manifest & Yükleme Önceliği: Kritik Yol ve Lazy

Tüm asset'ler aynı anda inmemeli. Manifest hangi dosyanın ne zaman yükleneceğini söyler — ilk kare, etkileşim ve arka plan yükü ayrılır.

Loader yüzeyi üretim izleğinde, CDN header politikası önceki yaprakta kuruldu. Burada bu ikisinin üzerine bir zaman çizelgesi eklenir: hangi asset'in saniye sıfırda, hangisinin ilk etkileşimden önce, hangisinin boşta kalan zamanda indirileceği.

Bant genişliği sınırlıdır ve kullanıcının dikkati de öyle. 20 MB'lık bir kahraman modeliyle 20 MB'lık arka plan dekorunu aynı anda indirmek, ikisinin de yarım saniyede gelmesini beklemek kadar anlamsızdır — ilk kare için gerekli olan öncelik kazanmalı, gerisi beklemelidir.

Sayfayı bitirdiğinizde şu cümleyi kurabilmelisiniz: «Manifest bir dosya listesi değil bir zaman çizelgesidir; P0/P1/P2 katmanları ilk kare, etkileşim ve arka planı ayırır; preload sadece gerçekten kritik yol için kullanılır; progressive yükleme düşük detaylı bir placeholder ile başlar.»

Bu sayfanın sınırı

Bu sayfa şunları anlatır:

  • Manifest şeması ve öncelik katmanları
  • Preload vs lazy vs idle yükleme
  • Kritik yol (hero asset) ve progressive strateji

Bilinçli olarak dışarıda bırakılan konular:

Kısa ayrım: Bu sayfa «ne zaman iner» · Platform LOD «hangi detay seviyesi var» · R3F «UI'da nasıl beklenir».

Öncelik katmanları: P0 / P1 / P2

P0 ilk kare için zorunludur (sky, zemin, hero silüet). P1 etkileşim öncesi gereklidir (pick edilebilir mesh, UI texture). P2 arka planda, kullanıcı fark etmeden yüklenir (dekor, uzak LOD, ses). Katman yazılmazsa her şey fiilen P0 olur ve ilk anlamlı boyama süresi şişer.

Katmanlama kararı, «bu asset olmadan sahne boş görünür mü» sorusuna verilen cevaptır. Estetik olarak hoş ama işlevsel olmayan detaylar hemen P2'ye düşer; bu ayrım genelde tasarım ile mühendislik arasında bir müzakere gerektirir.

Preload ve idle yükleme

requestIdleCallback veya ilk kare sonrası kurulan bir kuyruk ile P2 asset'leri indirilir. <link rel="preload"> yalnızca gerçekten P0 için kullanılmalıdır — aşırı preload, tarayıcının bant genişliğini P0'dan çalar ve «her şeyi öncelikli yapmak, hiçbir şeyi öncelikli yapmamak» sonucunu doğurur.

requestIdleCallback tüm tarayıcılarda garanti değildir; bir setTimeout fallback'i veya ilk render sonrası mikro-görev kuyruğu güvenli bir alternatiftir.

Progressive: düşük LOD önce

Platform LOD kararıyla uyumlu çalışır: önce düşük poligonlu bir placeholder, tam model P1'de yerini alır. Kullanıcı boş bir sahne görmez; bu, format şemasıyla ilgili değil tamamen yükleme sırasıyla ilgili bir karardır.

Geçiş anı (placeholder'dan tam modele) ani bir "pop" hissi vermemelidir — kısa bir crossfade veya opaklık geçişi bu sıçramayı yumuşatır.

Manifest şeması: versiyon + öncelik + bağımlılık

Bir manifest en az şu alanları taşımalıdır: asset kimliği, çözümlenmiş URL (versiyon mührüyle), öncelik katmanı ve varsa bağımlılık (bir sahne setinin birden fazla dosyaya ihtiyacı olduğunda). Bağımlılık bilgisi olmadan «bu asset yüklendi» ile «bu sahne gösterilebilir» arasındaki fark kaybolur.

Şema küçük tutulmalıdır — her yeni alan, manifest'i üreten otomasyonun ve okuyan runtime kodun birlikte güncellenmesi gereken bir sözleşme değişikliğidir.

Route/sahne bazlı manifest bölme

Tek bir dev manifest, küçük projelerde yeterlidir; ama çok sahneli bir uygulamada her route'un kendi manifest parçasına sahip olması, kullanıcının hiç ziyaret etmediği bir sahnenin asset listesini indirmesini önler. Ana manifest, alt manifest'lere işaret eden hafif bir dizin haline gelir.

Bu bölme, kod bölme (code splitting) ile aynı motivasyonu taşır: yalnızca gerekli olan indirilsin.

Kullanıcı etkileşimine göre öncelik değişimi

Statik P0/P1/P2 ataması bir başlangıç noktasıdır; bazı projelerde öncelik kullanıcı davranışına göre dinamik olarak değişir — örneğin bir envanter öğesinin üzerine gelindiğinde (hover) o öğenin yüksek detaylı versiyonu erken tetiklenebilir.

Bu dinamik önceliklendirme dikkatli kullanılmalıdır: her hover'da yeni bir yükleme tetiklemek, gereksiz ağ trafiği ve iptal edilen isteklerle sonuçlanabilir; bir debounce veya niyet tahmini (belirli bir süre hover kalması) makul bir denge sağlar.

Bant genişliği farkındalığı

Tarayıcının navigator.connection (Network Information API) desteği varsa, bağlantı tipi veya tahmini hız bilgisiyle P2 yüklemesi ertelenebilir veya daha düşük detaylı bir varyant seçilebilir. Bu API her tarayıcıda yoktur; yokluğunda varsayılan (orta) profile düşülmelidir.

Bant genişliği farkındalığı bir «her zaman doğru tahmin» aracı değildir — kaba bir sinyal olarak, aşırı yükleme riskini azaltan bir güvenlik önlemi olarak görülmelidir.

Yanlış öncelik kalıpları

  • 20 MB hero + 20 MB dekor aynı anda indirilir
  • Preload her dosya için körü körüne uygulanır
  • Manifest yok, URL'ler koda dağınık şekilde gömülü
  • P2'yi etkileşim öncesi zorunlu sanmak
  • Hover'da sınırsız yükleme tetiklenir, debounce yok
  • Bağlantı hızı hiç dikkate alınmaz

Simüle: öncelik kuyruğu

{
  "stages": [
    { "priority": "P0", "assets": ["env/sky.glb", "env/ground_lod0.glb"] },
    { "priority": "P1", "assets": ["characters/hero-scan.a8f3c2.glb"] },
    { "priority": "P2", "assets": ["decor/props_pack.glb"], "idle": true }
  ]
}
function isSlowConnection() {
  const c = navigator.connection
  if (!c) return false
  return c.saveData || /2g/.test(c.effectiveType || '')
}

export async function runLoadStages(stages, loadOne) {
  for (const stage of stages) {
    if (stage.idle) {
      if (isSlowConnection() && stage.priority === 'P2') continue // yavas baglantida P2 atlanir
      await new Promise((r) => requestIdleCallback ? requestIdleCallback(r) : setTimeout(r, 200))
    }
    await Promise.all(stage.assets.map((id) => loadOne(id)))
  }
}

Üç öncelik profili

  • 01 · Öncelik

    Vitrin (az asset)

    P0
    Tek hero model
    P2
    Yok denecek kadar az
    Risk
    Gereğinden fazla preload
  • 02 · Öncelik

    Oyun seviyesi (orta)

    P0
    Zemin + karakter
    P1
    Etkileşimli objeler
    Risk
    P1/P2 sınırı bulanık
  • 03 · Öncelik

    Açık dünya (çok asset)

    Manifest
    Route bazlı bölünmüş
    P2
    Bant genişliği duyarlı
    Risk
    Bağımlılık takibi karmaşık

Holodepth perspektifleri

Manifest bir zaman çizelgesidir

«Dosya listesi» değil «zaman çizelgesi»dir; ilk saniye deneyimi büyük ölçüde burada kazanılır veya kaybedilir.

Öncelik, tahmin değil karardır

P0/P1/P2 ataması «muhtemelen önemli» değil «ilk kare için zorunlu mu» sorusuna verilen açık bir cevap olmalıdır.

Dinamik öncelik dikkatli kullanılır

Kullanıcı etkileşimine göre önceliklendirme güçlü bir araçtır ama debounce ve bant genişliği farkındalığı olmadan geri teper.

  1. Her asset bir öncelik katmanına atanmış mı?
  2. Preload yalnızca gerçek P0 için mi kullanılıyor?
  3. Progressive geçiş (placeholder → tam model) yumuşak mı?
  4. Manifest şeması bağımlılığı ifade edebiliyor mu?
  5. Çok sahneli projede manifest route bazlı bölünmüş mü?
  6. Hover/etkileşim tetiklemesi debounce'lu mu?
  7. Yavaş bağlantıda P2 otomatik ertelenebiliyor mu?

Holodepth içgörüsü

Öncelik planı oturunca sıradaki ve son yaprak: registry ve dispose ile ömür borusunun tamamlanması.

Sonraki kapı

Yükleme sırası netse varlık yönetimi yaprağında registry, LRU ve dispose tamamlanır.