holodepth

Framework entegrasyonları · Angular + Three

Host & Kök Sözleşmesi: Bileşenin Gümrük Masası

Angular'da WebGL sahnesi çoğu zaman bir host bileşenin tuvalinde açılır. Bu sayfa ElementRef / yaşam döngüsü / tek renderer sahipliği ile kök sözleşmeyi anlatır: Angular CLI veya RxJS 101 değil · Three ↔ host kapısı.

Holodepth bu yaprağı «Angular nedir?» turu veya R3F <Canvas> dersinin kopyası olarak yazmaz. R3F kök mührü Canvas & kök sözleşme yaprağındadır; mercek orada React/Fiber, burada bileşen host + DI ömrü. Mesh / buffer teorisi Three ve WebGL omurgasındadır. Kare + NgZone Kare döngüsü & NgZone yaprağındadır. Dispose derinliği Yükleme & OnDestroy yaprağındadır. glTF şema format izleklerindedir.

Sayfayı bitirdiğinizde şu cümleyi kurabilmelisiniz: «Host bileşen tuvali gümrük masasıdır. Renderer AfterViewInit'te açılır, OnDestroy'da kapanır. ElementRef CSS kutusu ile backing store'u ayırır. Tek canlı context varsayılandır. SSR'de tarayıcı kapısı zorunludur. Sonraki kapı şablon → Object3D haritasıdır.»

Bu sayfanın sınırı · komşu konularla ayrım

Bu sayfa Angular + Three'de host kök sözleşmesini anlatır:

  • Host bileşen / tuval sahipliği
  • AfterViewInit açılış · boyut / DPR
  • Tek context · SSR / platform kapısı
  • Üç host profili

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

Kısa ayrım: Bu sayfa «Angular host kapıyı nasıl mühürler?» · R3F Canvas «Fiber kapıyı nasıl mühürler?» · NgZone yaprağı «kapı açıkken tik nerede?» · Şablon haritası «kapının arkasında ağaç».

Gümrük masası: host bileşen

Imperatif demoda çoğu ekip index.html içine <canvas> koyup script'te renderer açar. Angular ürününde tuval bir component şablonuna aittir: stil, boyut, yaşam döngüsü ve enjekte servisler bu masadan geçer. Holodepth: mesh'i yanlış yazmak sahneyi bozar; host'u yanlış mühürlemek tüm oturumu bozar.

«angular-three» veya özel sarmalayıcı kütüphaneler bu masayı soyutlar; soyutlama yoksa da sözleşme aynıdır: kim canvas DOM'unu tutar, kim WebGLRenderer'ı yaratır, kim yok eder?

Şablon dekorasyonu taşımaz; host sözleşmeyi taşır.

AfterViewInit: kapı açılışı

Constructor veya ngOnInit içinde ViewChild canvas henüz garanti değildir. Holodepth kök kuralı: renderer ve ilk setSize tipik olarak AfterViewInit (veya eşdeğeri view hazır sinyali) sonrasındadır. Erken erişim «null canvas» veya 0×0 tampon üretir.

Kapanış: rota değişince bileşen ölür; GL kaynakları ngOnDestroy hattına yazılır. Derin dispose / loader sahipliği sonraki yapraktadır; burada mühür: açılış ve kapanış aynı host ömrüne bağlıdır.

ElementRef: iki defter bağlantısı

CSS kutusu (layout) ile backing store (piksel tamponu) yine ayrıdır. Host şablonunda width/height %100 ve min-height yoksa R3F'deki «siyah kutu»nu Angular'da da yaşarsınız. Holodepth: ViewChild ile canvas'ı alın; clientWidth/clientHeight ve devicePixelRatio tavanıyla setSize / setPixelRatio yazın.

Host defterleri · karıştırmayın
Defter Angular yüzü Kök kararı
Layout Host CSS / flex / min-height Tuval görünür alan
Backing store setSize + DPR tavanı Fill-rate bütçesi
Yaşam AfterViewInit ↔ OnDestroy Context ömrü

Resize: pencere veya yan panel açılınca host ölçüsü değişir. ResizeObserver (veya bilinçli host dinleyicisi) setSize yolunu tetikler. Her change detection'da setSize çağırmak thrashing üretir; seyreltin.

Tek renderer · servis tuzağı

Her host kartında yeni WebGLRenderer = yeni context. Dashboard'da üç küçük Angular bileşen üç GPU oturumu açabilir. Holodepth varsayılanı: mümkün olduğunca tek canlı renderer; paylaşım gerekiyorsa root-provided bir sahne servisi bilinçli tasarlanır, «her child kendi Three'si» alışkanlığı yapılmaz.

Servis tuzağı: singleton renderer'ı yanlışlıkla ikinci kez oluşturmak veya destroy sonrası kullanmak. Sahiplik cümlesi ticket'ta: renderer host'ta mı, shared service'te mi?

SSR ve platform kapısı

Angular Universal / SSR ortamında window, document ve WebGL yoktur. Holodepth: kök açılışı isPlatformBrowser (veya eşdeğeri) arkasındadır. Sunucuda renderer yaratmaya çalışmak build'i değil, runtime'ı kırar.

Hydration sonrası ilk frame: host boyutunun settle olmasını bekleyin; aksi 1×1 tampon riski. Bu Angular hydration dersi değil; Three host zamanlamasıdır.

Renderer imzası host'ta

Antialias, alpha, powerPreference, outputColorSpace, toneMapping ürün sabitleri host açılışında bir kez mühürlenir. Her child'da rastgele değiştirmek «neden renk kaydı?» tartışması üretir. R3F'de bu gl / onCreated yüzüdür; Angular'da aynı diplomatik karar host (veya shared factory) üzerindedir.

Kare metronom ve Zone politikası sonraki yapraktır. Burada yalnız: renderer varoluş sözleşmesi host ömrüne yazılır.

Güvenli host: simüle mühür

Örnekler öğretim amaçlı, güncel Angular + Three yüzeyine yaslanan simüle kalıplardır. CLI / standalone / NgModule ayrımı öğretilmez. Paket sürümlerinizi doğrulayın.

Simüle · vitrin hostu. Canvas ViewChild; açılış AfterViewInit; kapanış OnDestroy iskeleti.

import {
  AfterViewInit, Component, ElementRef, OnDestroy, ViewChild,
} from '@angular/core'
import * as THREE from 'three'

@Component({
  selector: 'app-stage-host',
  template: `
    <div class="stage-host" style="width:100%;height:100%;min-height:360px">
      <canvas #glCanvas style="display:block;width:100%;height:100%"></canvas>
    </div>
  `,
  // Eğitim: standalone / module seçimi ürün kararıdır.
})
export class StageHostComponent implements AfterViewInit, OnDestroy {
  @ViewChild('glCanvas', { static: false })
  private canvasRef!: ElementRef<HTMLCanvasElement>

  private renderer?: THREE.WebGLRenderer
  private resizeObs?: ResizeObserver

  ngAfterViewInit(): void {
    // SSR: burada isPlatformBrowser ile erken dönün (ürün kodunda).
    const canvas = this.canvasRef.nativeElement
    this.renderer = new THREE.WebGLRenderer({
      canvas,
      antialias: true,
      alpha: false,
      powerPreference: 'high-performance',
      preserveDrawingBuffer: false,
    })
    this.renderer.outputColorSpace = THREE.SRGBColorSpace
    this.renderer.toneMapping = THREE.ACESFilmicToneMapping
    this.applySize()

    this.resizeObs = new ResizeObserver(() => this.applySize())
    this.resizeObs.observe(canvas.parentElement ?? canvas)
  }

  private applySize(): void {
    const canvas = this.canvasRef?.nativeElement
    const renderer = this.renderer
    if (!canvas || !renderer) return
    const w = canvas.clientWidth
    const h = canvas.clientHeight
    if (w < 2 || h < 2) return
    const dpr = Math.min(window.devicePixelRatio || 1, 2)
    renderer.setPixelRatio(dpr)
    renderer.setSize(w, h, false)
  }

  ngOnDestroy(): void {
    this.resizeObs?.disconnect()
    this.renderer?.dispose()
    this.renderer = undefined
    // Scene/geometri dispose borusu Yükleme & OnDestroy yaprağında derinleşir.
  }
}

Simüle · paylaşımlı kök notu. Birden fazla host kartı varsa ikinci renderer'ı varsayılan yapmayın; sahiplik cümlesi yazın.

/** @typedef {'host-local' | 'app-shared'} RendererOwnership */

/**
 * Ürün ticket örneği — kod değil sözleşme.
 * host-local  → her StageHost kendi WebGLRenderer'ı (nadiren ≥2)
 * app-shared  → tek renderer; host'lar viewport / kamera dilimi paylaşır
 */
export const RENDERER_OWNERSHIP = /** @type {RendererOwnership} */ ('host-local')

export function assertSingleContext(liveRendererCount) {
  if (RENDERER_OWNERSHIP === 'host-local' && liveRendererCount > 1) {
    console.warn('[Holodepth] Birden fazla canlı context · mobil bütçeyi kontrol edin.')
  }
}

Güvenlik: kullanıcıdan gelen canvas boyutlarını sınırsız şişirmeyin; DPR tavanı zorunlu. SSR'de native DOM API çağrılarını platform kapısı olmadan çalıştırmayın.

Change detection notu (eşik)

Her Angular CD turunda setSize / render çağırmak sessiz jank üreticisidir. Holodepth eşiği: kök montaj host'ta; sürekli tik Zone / rAF yaprağında; ağır kaçış Zone kaçışı yaprağında. Bu sayfa CD'yi öğretmez; host'un CD'ye bağlanmaması gerektiğini mühürler.

Üç host profili

  • 01 · Host

    Ürün vitrini

    Sahiplik
    host-local renderer
    DPR
    Tavan 2 · keskinlik
    Risk
    İkinci kartta ikinci context
  • 02 · Host

    Dashboard paneli

    Sahiplik
    app-shared adayı
    Boyut
    Sabit min-height · ResizeObserver
    Risk
    Her widget kendi GL
  • 03 · Host

    SSR + client hydrate

    Kapı
    isPlatformBrowser
    Açılış
    AfterViewInit + settle
    Risk
    Sunucuda WebGL denemesi

Host tuzakları

  1. Erken ViewChild: ngOnInit'te canvas null.
  2. 0 yükseklik: flex child min-height yok.
  3. Çoklu context: kart başı renderer.
  4. SSR çağrısı: platform kapısız WebGL.
  5. CD thrash: her turda setSize.
  6. Destroy yok: rota sonrası context sızıntısı.
  7. R3F ezberi: frameloop prop'u aramak.

Holodepth perspektifleri

Ömür = context

Renderer host ömrüne yazılır. Orphan context mobilin sessiz düşmanıdır.

Bir context varsayılan

İkinci host ikinci gerekçe ister; kart ızgarası gerekçe değildir.

İki defteri ayırın

CSS kutusu ile DPR tamponu aynı satırda konuşulmamalı.

Teşhis maddeleri

  1. Renderer AfterViewInit'te mi açılıyor?
  2. Host min-height / boyut sözleşmesi var mı?
  3. DPR tavanı yazılı mı?
  4. Canlı context sayısı gerekçeli mi?
  5. SSR platform kapısı var mı?
  6. ResizeObserver thrash yapıyor mu?
  7. ngOnDestroy renderer'ı salıyor mu?
  8. R3F veya glTF şema bu sayfaya sızmış mı?

Holodepth içgörüsü

«Angular'da Three çalışmıyor» çoğu zaman mesh hatası değil; host zamanlaması, sıfır kutu veya çoklu context sorunudur. Önce gümrük masasını okuyun.

Sonraki kapı: şablon haritası

Kapı mühürlendikten sonra Angular şablonu (veya kütüphane yapı taşları) Object3D ağacına nasıl bağlanır? Sonraki sayfa Şablon → Object3D haritası bu eşlemeyi anlatır. NgZone döngüsü ve OnDestroy derinliği sonraki yapraklardadır.