Uygulama Çekirdeği ve Yaşam Döngüsü

Core & Script Base

3D uygulamalar "sadece render loop" değildir; doğru kurulum, performans kadar sürdürülebilir mimari için de şarttır.
Bu sayfada, Three.js projesinin başlangıç iskeletini kurarken hangi parçayı neden nereye koyduğunu öğrenecek; iş mantığı ile render mantığını birbirinden ayıran bir düzen kuracaksın.

Ana Konu Temel Kurulum
Seviye 3

Entry Point (main.js) Uygulamanın Beyni ve Orkestrasyon Noktası

Başlangıç Noktası: "Kod Nereden Nefes Alır?"

Bir 3D uygulamanın entry point’i (çoğunlukla main.js), sadece ilk satırın yazıldığı dosya değildir.

Burada amaç, modüller arası iletişimi başlatmak ve uygulamanın yaşam döngüsünü "tek yerden" yönetebilecek bir orkestra şefliği kurmaktır.

İçerik Odağı: 3D uygulamada lifecycle yönetimi ( başlat, güncelle, durdur, yeniden boyutlandır ) HTML/CSS dünyasındaki sayfa akışından çok daha katıdır.

Modüler yapıda import hiyerarşisi önemlidir; çünkü bir modülün "yan etkisi" yanlış sırada çalışırsa, hata üretir ya da performansı gizlice düşürür.

Derinlik: İş mantığını ( input/state, sahneye obje ekleme kuralları ) render mantığından ayırmak, büyüyen projelerde kontrol edilebilirlik sağlar.

Bu ayrım için singleton yaklaşımı, uygulamanın tekil servislerini ( renderer, clock, input ) "tek kaynak" olarak sunabilir; class tabanlı yapı ise test ve yeniden kullanılabilirlik açısından daha temiz bir sınır çizer.

Uygulama Mimarisi: Class vs. Singleton

Entry point’i tasarlarken iki ana yaklaşım öne çıkar: class tabanlı bir "Experience" mimarisi ya da singleton / functional bir kurulum.

Bu farkı bilmek, okuyucunun sadece kodu "çalıştırmasını" değil, büyüyen bir 3D projede mimarinin nasıl evrildiğini de görmesini sağlar.

Orchestration Layer (Orkestrasyon Katmanı) main.js içinde modüllerin hangi sırayla ayağa kalktığı hayati önem taşır.

Yanlış sıra, undefined hatalarına veya "boş ekran" ile sonuçlanan sessiz başarısızlıklara yol açabilir.

Missing Link: Hata Yönetimi ve Fallback Üretim seviyesinde bir entry point, “her şey varmış gibi” başlamaz; önce minimum bir uyumluluk kontrolü yapar.

WebGL desteklenmiyorsa kullanıcıya anlaşılır bir uyarı gösterip render loop’u başlatmamak gerekir.

Basit bir kontrol: window.WebGLRenderingContext veya canvas üzerinden context alma denemesi ile yapılabilir.

Kritik Yükleme Sırası (Boot Sequence):

Core Services: Clock (zaman), Renderer (çizici) ve Camera (kamera) temelleri kurulmadan, uygulama "ölçülemez" ve "çizemez".

Resource Loader: Dokular, modeller, fontlar yüklenmeden sahneye bir şey eklemek; "sonradan düzeltirim" dediğin anda null referanslar üretir.

World / Scene Creation: Işık, zemin ve temel objeler sahneye alındığında artık dünya "yaşanabilir" hale gelir.

Interaction Layer: Mouse eventleri, raycaster ve kontroller ( OrbitControls vb.) en sonda aktive edilmelidir; çünkü etkileşim, dünyayı

"var kabul eder".

The Loop: requestAnimationFrame başlatılarak uygulamanın "kalbi" çalıştırılır.

Separation of Concerns (Sorumlulukların Ayrılması)

Entry point, iş mantığını doğrudan taşımamalıdır; onun görevi, doğru sınıfları çağırmak ve sistemleri "tetiklemek" olmalıdır.

Business Logic: Karaktere tıklanınca ne olacağı, puan sistemi, fizik kuralları gibi karar mekanizmalarıdır.

Render Logic: Gölgeler, post-processing, GPU’ya giden veriler, draw-call düzeni gibi çizim katmanıdır.

Derin Not: Entry point genelde sadece Experience.js veya World.js gibi bir çekirdek sınıfı çağırır; böylece "ne yapılacağı" ile

"nasıl çizileceği" ayrışır.

The Loop (Zaman ve Kare Yönetimi)

3D dünyada hareketler kare sayısına değil zamana bağlı olmalıdır.

Bu yüzden "frame-based" değil time-based düşünürsün.

Merkezi bir clock mekanizması ile her karede geçen süre (delta time) hesaplanır; böylece 144Hz ve 60Hz ekranlarda aynı animasyon "aynı hızda" akar.

\[ \text{Position}_{new} = \text{Position}_{old} + (\text{Velocity} \times \text{DeltaTime}) \]

Neden Önemli? FPS farklılıkları, delta time kullanılmadığında animasyonları hızlandırır veya yavaşlatır; bu da kullanıcılar arasında "fiziksel" tutarsızlık" üretir.

Global Access ve Debug Modu

Geliştirme aşamasında bazı araçlara hızlı erişim sağlamak hayat kurtarır (örn. lil-gui, profiler, debug overlay).

Buradaki kritik fikir şudur: Debug araçları production bundle’a zorla girmemelidir.

Bu nedenle "koşullu import" yaklaşımıyla sadece geliştirme modunda yüklenir.

Conditional Import: Tree-shaking mantığıyla, debug modülü yalnızca gerekli ortamda çağrılır; böylece production’da daha temiz ve küçük bir paket elde edilir.

Özellik
Class Tabanlı Yapı (Önerilen)
Singleton / Functional Yapı
Genişletilebilirlik

Çok yüksek. Miras ve kompozisyonla yapı büyütülebilir.

Kısıtlı. Global bağlar büyüdükçe karmaşıklık artar.

Test Edilebilirlik

Kolay. Her instance izole şekilde test edilebilir.

Zor. Global state bağımlılığı yüksektir.

Kapsülleme

Güçlü. private/public sınırlarıyla kontrol sağlanır.

Zayıf. Genelde her şey dışarıya açıktır.

Kullanım Senaryosu

Büyük ölçekli 3D motorlar (HoloDepth gibi).

Küçük demolar veya basit tool’lar.

Boot Sequence Görselleştirmesi Core → Resource → World → Interaction → Loop
1
Core
Clock • Renderer • Camera
WebGL context kontrolü (fallback kapısı)
PixelRatio + size ilk kez set edilir
Camera frustum başlangıç değerleri
2
Resource
Textures • Models • Fonts
Loader progress / state yönetimi
Sahneye ekleme: “yüklenmeden ekleme yok”
Cache stratejisi (reuse / dispose)
3
World
Lights • Ground • Objects
Scene graph kök düğümleri kurulur
Işık & gölge haritası stratejisi seçilir
İlk objeler: geometri + materyal yaşam döngüsü
4
Interaction
Raycaster • Controls • Events
Raycaster target list (pickable set)
Input → state → action zinciri
Event listener’lar: tek kayıt / tek kaldırma
5
Loop
requestAnimationFrame
DeltaTime hesapla → update() → render()
Frustum culling / visibility optimizasyonu
Debug overlay (dev) / kapalı (prod)
Seviye 3

Scene Bootstrap Karanlığa Koordinat Kazandırmak

Başlangıç Ortamı: Scene Graph’ın Doğuşu

Scene bootstrap, sahneyi "boş bir karanlık" olmaktan çıkarıp nesnelerin yaşayacağı bir uzaya dönüştürme sürecidir.

THREE.Scene nesnesini oluşturduğun anda, arka planda bir grafik ağacı mantığı çalışmaya başlar.

İçerik Odağı: Scene Graph = Dönüşümlerin Dolaştığı Ağaç Scene graph, nesnelerin ebeveyn-çocuk ilişkisini kurar; dönüşümler

( position/rotation/scale ) bu hiyerarşi üzerinden "aşağıya doğru" taşınır.

Bu nedenle sahneye ilk objeleri eklemek, sadece bir şey "göstermek" değildir: aslında update ve render sırasında dolaşılacak ağacın yapısını ve maliyetini de sen belirliyorsun.

Pratik sezgi: Bir objeyi "root" seviyesine eklemek ile, onu bir parent altında gruplayıp taşıtırmak arasında ciddi fark vardır; çünkü her frame’de hesaplanan world matrix zinciri değişir.

Büyük sahnelerde, gereksiz hiyerarşi "transform propagation" maliyetini artırabilir; aşırı düz (flat) yapı ise yönetilebilirliği düşürür.

Bootstrap aşamasında amaç, doğru derinlikte bir ağaç kurmaktır.

Derinlik: Fog • Background • Skydome (Aynı Şey Değiller)

Sis (fog), arka plan rengi (background) ve skydome ( gökyüzü kubbesi ) ilk anda "süs" gibi dursa da, sahnenin atmosferini ve okuma derinliğini belirleyen temel katmanlardır.

Fog çoğu zaman "mesafe tabanlı" bir degradedir ve özellikle büyük ölçekli sahnelerde depth algısını güçlendirir; background ise sahnenin "boşluk rengidir" ve render hedefi ile birlikte görünür.

Skydome ise fiziksel bir geometri/materyal yaklaşımıdır; doğru kurulursa atmosfer katar, yanlış kurulursa gereksiz draw-call ve texture yüküyle performansı düşürebilir.

Bellek ve Yaşam Döngüsü: Geometry / Material / Texture

İlk objeler eklenmeye başladığında bellek tarafında geometry, material ve texture referansları birikmeye başlar.

Buradaki kritik nokta şu: JavaScript tarafında bir objeyi referanssız bırakmak her zaman GPU tarafını boşaltmaz.

Çoğu kaynak için dispose disiplinine ihtiyaç duyarsın.

Derin Not: Yanlış kurulum, sahne büyüdükçe çöp toplayıcı baskısını artırır ve mikro takılmalar (stutter) üretir.

Bootstrap aşamasında "yeniden kullanılabilir" materyal/geometry havuzları tasarlamak, ileride performans borcunu düşürür.

Scene Bootstrap Katmanları Atmosfer → Sahne Ağacı → Kaynak Yaşam Döngüsü
A
Atmosfer & Okuma Derinliği
Fog • Background • Skydome
Fog: mesafe tabanlı degrade (depth okunabilirliği)
Background: boşluk rengi (clear color ile ilişkili)
Skydome: geometri + materyal (draw-call maliyeti)
B
Scene Graph (Dünya İskeleti)
Parent → Child • World Matrix zinciri
Root gruplar: World / Lights / Props / Helpers
Transform propagation: her frame güncellenen zincir
İlk ekleme sırası: ışık → zemin → içerik (okunabilirlik)
C
Kaynaklar & Bellek
Geometry • Material • Texture
Paylaşım: aynı geometry/material’i çoğaltma
Dispose: GPU belleğini gerçekten boşaltma
GC: referans döngüleri ve ani stutter riski
Seviye 3

Renderer Setup CPU ↔ GPU Köprüsü ve Context Yönetimi

Kritik Parça: Render Stratejisi Daha Başta Başlar

Renderer kurulumu, WebGL veya WebGPU üzerinde bir grafik bağlamı (context) oluşturmak ve GPU’ya "buradan sonra böyle çalış" diyecek temel parametreleri tek seferde kilitlemektir.

Pratikte bu, CPU ile GPU arasındaki köprüyü kurmak demektir: tarayıcı tarafında komut kuyruğu, bellek yerleşimi ve kare zamanlaması bu aşamada büyük ölçüde şekillenir.

WebGLRenderer (veya eşdeğeri) seçildiğinde, sahneyi "ne kadar keskin" ya da "ne kadar yumuşak" göreceğin kadar, her karede ödeyeceğin GPU faturası da seçilmiş olur.

Bağlam (Context): Canvas ile Birlikte Okunmalı

Context, bir canvas elementine bağlıdır; çözünürlük, alpha kanalı, stencil/depth tamponları ve örnekleme (MSAA) gibi seçeneklerin çoğu bağlam doğarken belirlenir; sonra değiştirmek ya pahalıdır ya da imkânsızdır.

Bu yüzden renderer’ı "sadece çizici" sanmak yanıltıcıdır: aslında setSize, setPixelRatio, renk çıkışı / tone mapping ve gölge haritası politikası birbirine kilitlenir; burada verilen bir tolerans, ileride materyal ağacına kadar uzanır.

Temel parametreler: antialias çoğu zaman ek bir MSAA yükü demektir; alpha ise canvas’ın sayfayla nasıl birleşeceğini (şeffaflık) belirler ve bazı arka plan kompozisyonlarında maliyeti görünür kılar.

powerPreference tarayıcıya GPU seçiminde ipucu verir: mobilde "yüksek performans" seçimi, termal sınıra yaklaştıkça FPS’in dalgalanmasına yol açabilir; masaüstünde ise tersine akıcılık kazandırabilir.

İçerik Odağı: Bu parametreler cihazın GPU kapasitesi, bellek bant genişliği ve batarya / termal yönetimiyle doğrudan ilişkilidir; özellikle mobilde tek bir "yüksek kalite" bayrağı, fark etmeden kare süresini bozabilir.

Aynı sahne iki cihazda farklı hissedilir; çünkü renderer başlangıcı, öncelik sırasını ( görüntü kalitesi mi, enerji mi, stabilite mi ) fiilen seçer.

Derinlik: Renk yönetimi ( sRGB çıkışı, doğrusal çalışma zinciri ve tone mapping ) ile gölge haritası ( shadow map ) türleri baştan doğru kurgulanmazsa, "biraz soluk / biraz gürültülü" giderilebilir; ama materyal ayarlarını ve post-processing zincirini baştan kurmak genelde daha pahalıdır.

Gölgelerde PCFSoft filtreleri çoğu senaryoda daha öngörülebilir bir maliyet sunar; VSM gibi teknikler ise kaliteyi artırırken bellek ve ek örnekleme yüküyle farklı bir denge kurar; başlangıç seçimi, sahnenin "temel fiziki hissini" değiştiren bir karar haline gelir.

WebGPU tarafına geçiş düşünülüyorsa, renderer köprüsü ve parametre seti yine başta netleşmelidir; çünkü burada yapılan varsayımlar, shader ve pipeline tarafındaki uyumluluk sınırı olur.

Seviye 3

Camera Setup Dünyaya Bakış Açısı ve Görsel Matematik

Görüş Alanı: Kamera Bir "Lens" Değildir, Bir Seçimdir

Kamera, kullanıcının dünyayı nasıl algılayacağını belirler; bu yüzden kurulum aşamasında verilen kararlar, sahnenin hissini doğrudan etkiler.

Aynı geometri ve ışıkla bile, kamera seçimi farklı bir görsel dil üretir: mesafe hissi, dramatik perspektif, "teknik çizim" düzlüğü veya arayüz üstüne bindirilen stabil bir sahne okuması gibi.

PerspectiveCamera ile OrthographicCamera arasında seçim, sadece "3D görünüm" değil; aynı zamanda ölçek algısı ve hareket hissi seçimidir.

Projeksiyon Türü: Derinlik mi, Düzlük mü?

Perspektif kamera, paralel çizgileri uzakta birleştiren klasik "insan gözü" modelidir; mimari gezinti, karakter takibi veya sinematik kadrajlar için doğal bir varsayılandır.

Ortografik kamera ise ölçekleri daha "ölçü tahtası" gibi okutur; grid tabanlı editörler, izometrik görünümler veya HUD / debug çizimlerinde sık tercih edilir.

İçerik Odağı: fov, aspect, near ve far değerleri matematiksel bir frustum tanımlar; bu sınırlar, GPU’nun hangi uzay hacmini

"görüş alanı" sayacağını ve dolayısıyla neyin çizileceğini belirleyen temel çerçevedir.

Bu dört parametre birlikte projectionMatrix üzerinden kilitlenir; yanlış kombinasyonlarda sahne "içeri çöker" ya da tersine gereksiz yere genişler ve hem derinlik çözünürlüğü hem seçim maliyeti bozulur.

Derinlik: Frustum culling, kameranın frustum dışında kalan nesneleri çizim yolundan düşürme fikridir; doğru kurgulandığında bu hem performans kazanımı hem de doğru sahne yönetimi sunar.

Three.js tarafında birçok yol otomatik frustum testine dayanır; yine de sahne ölçeği büyüdükçe, grupları ve LOD stratejilerini kamera mantığıyla hizalamak gerekir.

Z-fighting gibi bozulmalar, near / far aralığı kötü seçildiğinde derinlik tamponunun çözünürlüğünü zorlar ve yüzeyler aynı pikselde yarışır; bu yüzden "çok uzak göstersin" isteği çoğu zaman görüntüyü kırar; frustumu gerçekten ihtiyaç duyulan dünyaya sığdırmak daha sağlıklıdır.

Seviye 3

Resize Handling Ekran Değişince Dünyayı Yeniden Kurmak

Dinamik Boyut: Canvas Sabit Değildir

Resize handling, ekran boyutu değiştiğinde hem renderer çözünürlüğünü hem de kameranın oranlarını güncelleme disiplinidir.

Bu disiplin sadece "pencere küçüldü" demek değildir; layout, CSS ölçüleri, cihaz yönü ve hatta mobilde klavye açılıp kapanması gibi durumlarda çizim hedefinin gerçek boyutu değişebilir.

Event listener yönetimi önemlidir; yanlış yerleştirilmiş kayıtlar zamanla çoğalır ve hem bellek hem de gereksiz yeniden hesaplamalarla gizli performans borcu üretir.

Boyut Kaynağı: Pencere mi, Konteyner mi?

Tam ekran deneyimlerde window.innerWidth ve window.innerHeight sık kullanılır; ancak canvas bir layout içinde ölçekleniyorsa, gerçek çizim alanı çoğu zaman canvas.clientWidth / clientHeight ile daha doğru okunur.

Konteyner tabanlı arayüzlerde ResizeObserver, boyut değişimini "DOM gerçeğine" bağlı yakalamanın modern yoludur; tek bir global resize dinleyicisine göre daha deterministik bir akış kurar.

Event disiplini: Aynı handler’ı birden fazla kez bağlamamak, sayfa kapanırken veya route değişirken listener’ları kaldırmak ve mümkünse AbortController ile tek seferde iptal etmek, uzun ömürlü uygulamalarda kritik bir ayrıntıdır.

Aşırı sık tetiklenen resize akışlarında küçük bir debounce veya requestAnimationFrame ile birleştirme ( tek karede tek güncelleme ) jank’i azaltır.

İçerik Odağı: Ölçüyü yakaladıktan sonra Three.js tarafında tipik üçlü şudur: renderer.setSize, camera.aspect = genişlik / yükseklik ve ardından camera.updateProjectionMatrix().

innerWidth / innerHeight ile başlamak mümkündür; fakat canvas gerçekte daha küçükse, kamera oranı ile canvas çözünürlüğünün aynı gerçekliği paylaşması gerekir aksi halde sahne doğru çizilse bile "yanlış kadraj" hissi oluşur.

Derinlik: Kamera aspect oranını güncelledikten sonra updateProjectionMatrix() çağrısı, matematiksel olarak yeni frustum yapısının yeniden hesaplanması demektir.

Bu çağrı yapılmazsa, kamera eski projeksiyon ile render etmeye devam eder; sonuç olarak görüntü sıkışır, gerilir veya perspektif yanlış görünür.

devicePixelRatio tarafı ayrı bir başlıkta derinleşir; yine de resize ile aynı anda düşünülürse, netlik ve performans dengesi "tek seferde" kırılabilir bu yüzden boyut güncellemesini tek bir fonksiyonda toplamak pratik bir kuraldır.

Seviye 3

Pixel Ratio Yönetimi Netlik ↔ Performans Dengesi

DPI Gerçeği: "Bulanıklık" Bir Bug Değil

Yüksek DPI ekranlarda (Retina gibi) pixel ratio doğru yönetilmezse, sahne keskin görünmez; kenarlar yumuşar ve görüntü "bulanık" hissedilir.

Sebep çoğu zaman shader hatası değil, CSS pikseli ile fiziksel piksel arasındaki uyumsuzluktur: canvas mantıksal olarak küçük çizilip arka tampon geniş tutulmayınca, upscale edilen görüntü yumuşar.

Burada ana kavram, window.devicePixelRatio değeridir; bu oran büyüdükçe aynı sahne için üretilen piksel alanı kabaca kare oranında büyür ve GPU’ya düşen doldurma / örnekleme yükü hızla artar.

Çizim Tamponu: Netlik Bir "Çarpan" İşidir

Three.js tarafında renderer.setPixelRatio, çoğu kullanımda iç çözünürlüğü DPR ile ölçekler; bu da MSAA, gölge haritaları ve tam ekran post-processing maliyetini aynı çarpanla büyütür.

Bu yüzden DPR’yi "maksimuma sabitlemek", özellikle mobilde kısa süreli akıcılık verip sonra termal sınıra çarpan dalgalı FPS üretebilir.

İçerik Odağı: renderer.setPixelRatio() netliği artırır; ancak her zaman "sonuna kadar" açmak doğru değildir. Pratik kalıp, cihazın raporladığı oranı okuyup bir üst sınır ile kırpmaktır: Math.min.

MaxPR değerini sabit tutmak yerine; batarya modu, düşük güç profili veya kullanıcı tercihine göre ( prefers-reduced-motion gibi sinyaller ) adaptif kalite ile seçmek, üretim uygulamalarında daha sürdürülebilir olur.

Pixel ratio güncellemesi, Resize Handling’de anlatılan boyut güncellemesiyle aynı yeniden kurulum ritüeline bağlanmalıdır; aksi halde bir kez doğru görünüp pencere değişince tekrar bozulursun.

Derinlik: Genellikle pixel ratio’yu 2x ile sınırlandırmak, 3x ve üstü cihazlarda GPU yükünü kontrol altında tutar; çünkü her ekstra birim, hem rasterization hem de tam ekran geçişlerde maliyeti üstel hissettirebilir.

Bu strateji, görüntüyü "yeterince keskin" tutarken frame time’ı stabilize eder; özellikle gölgeler, post-processing veya yoğun geometri olan sahnelerde fark dramatik olur.

Özet kural: netlik ile performans arasında seçim yapmıyorsun; üst sınır + ölçüm ( basit bir FPS / frame time gözlemi ) ile DPR’yi gerçek cihaz verisine bağlıyorsun.

HoloDepth Engine • Infrastructure & Core Lab Sistem Terminali

Çekirdek Yapıyı Canlı Deneyimleyin

Anlatılan Viewport, Resize ve Dispose mekanizmalarının arka planda nasıl kusursuz çalıştığını görün. HoloDepth’in temiz sahne yapısını (Grid, Axes, Helpers) ve modüler mimarisini bizzat inceleyin.

Viewport/resize ritmini boz, geri topla; dispose ile bellek disiplinini gör. Çekirdeğin düzenli çalışmasının sahneyi nasıl stabilize ettiğini test et.