Skip to content

๐Ÿ› fix: contact ์บ”๋ฒ„์Šค ์˜คํ”„์Šคํฌ๋ฆฐ ๋ฏธ์ •์ง€ ์ˆ˜์ • + ์บ์‹œ ์žฌ๋งˆ์šดํŠธ ํŒ์ • - #100

Merged
pcwadarong merged 3 commits into
mainfrom
fix/render-when-visible-cache-remount
Sep 6, 2026

Conversation

@pcwadarong

@pcwadarong pcwadarong commented Sep 1, 2026 •

Copy link
Copy Markdown
Owner

๋ชฉ์ 

PR #97์ด ํ›„์†์œผ๋กœ ๋ถ„๋ฆฌํ•œ 2๊ฑด์„ ์ •๋ฆฌํ•œ๋‹ค.

(1) contact ์บ”๋ฒ„์Šค๊ฐ€ ํ•œ ๋ฒˆ ๋…ธ์ถœ๋œ ๋’ค ํ™”๋ฉด ๋ฐ–์œผ๋กœ ๋‚˜๊ฐ€๋„ ๊ณ„์† ๋ Œ๋”๋๋‹ค. RenderWhenVisible์ด setFrameloop('never')๋ฅผ ๋ช…๋ นํ˜•์œผ๋กœ ํ˜ธ์ถœํ•˜์ง€๋งŒ, R3F <Canvas>๊ฐ€ ๋ฆฌ๋ Œ๋”๋งˆ๋‹ค frameloop prop(๊ธฐ๋ณธ๊ฐ’ 'always')์„ ์Šคํ† ์–ด์— ์žฌ์ ์šฉํ•ด ๊ทธ ํ˜ธ์ถœ์„ ๊ณง๋ฐ”๋กœ ๋ฎ์–ด์ผ๋‹ค. (2) characterInstanceCache ์‹ฑ๊ธ€ํ„ด์ด sourceScene ๋™์ผ์„ฑ๋งŒ์œผ๋กœ ์บ์‹œ๋ฅผ ํŒ์ •ํ•˜๋Š” ๊ฒŒ ๋ผ์šฐํŠธ ์ด๋™ ํ›„ ์žฌ๋งˆ์šดํŠธ์—์„œ ์•ˆ์ „ํ•œ์ง€ ํ™•์ธ โ€” ๊ฒฐ๋ก ์€ ๋ฌธ์ œ ์—†์Œ, ๊ทผ๊ฑฐ๋ฅผ ์ฃผ์„ยทํ…Œ์ŠคํŠธ๋กœ ๋‚จ๊ฒผ๋‹ค.

์ „ ํ›„
contact ๋…ธ์ถœ ํ›„ ํ™”๋ฉด ๋ฐ– (useFrame/์ดˆ) โ‰ˆ60 (๊ณ„์† ๋”) 0 (์ •์ง€)
๊ฐ€์‹œ์„ฑ ํŒ๋‹จ ์ฃผ์ฒด Canvas ๋‚ด๋ถ€ ๋ช…๋ นํ˜• setFrameloop <Canvas frameloop> ์ œ์–ด prop
๋ฆฌ๋ Œ๋” ์‹œ frameloop configure๊ฐ€ 'always'๋กœ ๋˜๋Œ๋ฆผ ์˜๋„ํ•œ ๊ฐ’ ์œ ์ง€
์บ์‹œ ์žฌ๋งˆ์šดํŠธ ๊ทผ๊ฑฐ ์ฝ”๋“œ์— ์—†์Œ (์˜์‹ฌ ๋ฐ˜๋ณต) ์ฃผ์„ + ๊ณ„์•ฝ ํ…Œ์ŠคํŠธ๋กœ ๊ณ ์ •

์ ์šฉ ๋ฒ”์œ„: use-render-when-visible.ts(์ปดํฌ๋„ŒํŠธโ†’ํ›…), hero/contact ์บ”๋ฒ„์Šค 2๊ณณ์˜ ๋ฐฐ์„ , use-character-instance.ts ์ฃผ์„. ์• ๋‹ˆ๋ฉ”์ด์…˜ยท์ „ํ™˜ ๋กœ์งยท์—์…‹์€ ๊ฑด๋“œ๋ฆฌ์ง€ ์•Š์•˜๋‹ค.

์„ค๊ณ„

1. ์›์ธ์ด IO root๊ฐ€ ์•„๋‹ˆ๋ผ <Canvas frameloop> ์žฌ์ ์šฉ์ž„์„ ๊ณ„์ธก์œผ๋กœ ์ขํ˜”๋‹ค

๊ณผ์ œ์˜ ์œ ๋ ฅ ํ›„๋ณด๋Š” "IO์˜ root๊ฐ€ ๊ธฐ๋ณธ๊ฐ’(window)์ด๋ผ ์‹ค์ œ ์Šคํฌ๋กค ๋ฃจํŠธ([data-app-scroll-viewport])๋ฅผ ๋ชป ๋”ฐ๋ผ๊ฐ„๋‹ค"์˜€๋‹ค. ํ”„๋กœ๋•์…˜ ๋นŒ๋“œ + GPU Chromium(M3 Pro) ๊ณ„์ธก์œผ๋กœ ๋ฐ˜์ฆํ–ˆ๋‹ค.

์ขํžˆ๋Š” ์ˆœ์„œ ๊ฒฐ๊ณผ
โ‘ก contact ์บ”๋ฒ„์Šค์— root=nullยทroot=์•ฑ๋ทฐํฌํŠธ ๋‘ ์˜ต์ €๋ฒ„ ๋ถ€์ฐฉ, ์Šคํฌ๋กค in/out ๋‘˜ ๋‹ค ์ดํƒˆ ์‹œ isIntersecting:false ์ •ํ™• ๋ฐœํ™” โ†’ IO๋Š” ๋ฌด์ฃ„
โ‘ข RenderWhenVisible์— ๋กœ๊ทธ ์ฃผ์ž… ์ดํƒˆ ์‹œ setFrameloop('never') ํ˜ธ์ถœ๋จ, contact ์‹ค์ œ๋กœ ๋ฉˆ์ถค(tโ‰ˆ60ms)
โ‘ฃ ์ดํ›„ frameloop ํด๋ง ~1์ดˆ ๋’ค ํ˜ผ์ž always๋กœ ๋ณต๊ท€(RWV ํ˜ธ์ถœ ์—†์Œ). ์˜คํ”„์Šคํฌ๋ฆฐ์—์„œ resize 1๋ฐœ โ†’ neverโ†’always ์žฌํ˜„

R3F 9.5.0 ์†Œ์Šค์—์„œ ํ™•์ •:

// <Canvas>: deps ์—†๋Š” layout effect โ€” ๋งค ๋ Œ๋” ์‹คํ–‰
useIsomorphicLayoutEffect(() => { root.current.configure({ /* frameloop ๋“ฑ */ }) })

// configure(): frameloop ์ธ์ž ๊ธฐ๋ณธ๊ฐ’์ด 'always'
if (state.frameloop !== frameloop) state.setFrameloop(frameloop)

๋ช…๋ นํ˜• setFrameloop('never')๋Š” ๋‹ค์Œ ๋ฆฌ๋ Œ๋” ํ•œ ๋ฒˆ์— ๋ฎ์–ด์จ์ง„๋‹ค. ContactScene์˜ ๋ฆฌ์‚ฌ์ด์ฆˆยทavailableHeight ๋™๊ธฐํ™”ยท์Šคํฌ๋กค ๊ตฌ๋™ ๋ถ€๋ชจ ๋ Œ๋”๊ฐ€ ํ”ํ•˜๋ฏ€๋กœ ์˜คํ”„์Šคํฌ๋ฆฐ ํ›„ ๊ณง ํด๋กœ๋ฒ„๋œ๋‹ค. hero๊ฐ€ ๋ฉ€์ฉกํ•œ ๊ฑด IO ์šฐ์—ด์ด ์•„๋‹ˆ๋ผ **์ด ํŽ˜์ด์ง€์—์„œ ํ•ญ์ƒ ์ตœ์†Œ 93px ๋…ธ์ถœ(sticky ํ•€)**์ด๋ผ ์›ํ•˜๋Š” ์ƒํƒœ๊ฐ€ ์–ด์ฐจํ”ผ always๋ผ์„œ๋‹ค. contact๋งŒ ์™„์ „ํžˆ ์ดํƒˆํ•ด ๋“œ๋Ÿฌ๋‚œ๋‹ค.

์ด ๋ฉ”์ปค๋‹ˆ์ฆ˜์€ "ํ•œ ๋ฒˆ๋„ ๋…ธ์ถœ ์•ˆ ๋˜๋ฉด 0ํšŒ/์ดˆ"๋„ ์„ค๋ช…ํ•œ๋‹ค โ€” ์•ˆ ๋ณด์ด๋Š” ๋™์•ˆ ์Šคํฌ๋กค์ด ์—†์œผ๋ฉด Canvas ๋ฆฌ๋ Œ๋”๊ฐ€ ์—†์–ด never๊ฐ€ ์œ ์ง€๋˜๊ณ , ํ•œ ๋ฒˆ ๋ณด์ด๋ ค๊ณ  ์Šคํฌ๋กคํ•˜๋Š” ์ˆœ๊ฐ„ ๋ฆฌ๋ Œ๋”๊ฐ€ ๋‹ค๋ฐœ๋กœ ๋‚˜ ํด๋กœ๋ฒ„๋œ๋‹ค.

2. ์™œ controlled frameloop prop์ธ๊ฐ€

frameloop prop์ด R3F์˜ ์ง„์‹ค์ด๋ผ, ์›ํ•˜๋Š” ๊ฐ’์„ prop์œผ๋กœ ์ œ์–ดํ•˜๋ฉด ๋ฆฌ๋ Œ๋”๊ฐ€ ๋‚˜๋„ ๊ทธ ๊ฐ’์ด ์žฌ์ ์šฉ๋ผ ์œ ์ง€๋œ๋‹ค.

const [canvasElement, setCanvasElement] = useState<HTMLCanvasElement | null>(null);
const frameloop = useCanvasVisibilityFrameloop(canvasElement); // 'always' | 'never'
<Canvas frameloop={frameloop} onCreated={({ gl }) => setCanvasElement(gl.domElement)} />

๋ฒ„๋ฆฐ ๋Œ€์•ˆ

๋Œ€์•ˆ ์™œ ์•ˆ ๊ณจ๋ž๋‚˜
IO root๋ฅผ ์•ฑ ์Šคํฌ๋กค ๋ทฐํฌํŠธ๋กœ ๋ณ€๊ฒฝ ์›์ธ์ด ์•„๋‹ˆ๋ผ ์•ˆ ๊ณ ์ณ์ง„๋‹ค (์„ค๊ณ„ 1)
Canvas ๋‚ด๋ถ€์—์„œ store ๊ตฌ๋… ํ›„ 'never' ์žฌ-assert ๋งค ๋ฆฌ๋ Œ๋” configure๊ฐ€ 'always'๋กœ ์„ธํŒ… โ†’ ์šฐ๋ฆฌ๊ฐ€ 'never'๋กœ ๋˜๋Œ๋ฆฌ๋Š” ํ•‘ํ. ํ”„๋ ˆ์ž„ ๋ˆ„์ˆ˜๋Š” ์—†์ง€๋งŒ ํ”„๋ ˆ์ž„์›Œํฌ์™€ ์‹ธ์šฐ๊ณ  ํŒ๋‹จ ์ฃผ์ฒด๊ฐ€ ๋‘˜์ด ๋œ๋‹ค
frameloop="demand" ์บ๋ฆญํ„ฐ mixerยทgsapยทOrbitControls ๋Œํ•‘์ด ์ƒ์‹œ ๊ตฌ๋™๋ผ ๋งค ํ”„๋ ˆ์ž„ invalidate๋กœ ํ‡ดํ™” (๊ธฐ์กด JSDoc ๊ทผ๊ฑฐ)

3. resume ์‹œ ๋ช…์‹œ์  invalidate()๋ฅผ ๋‘์ง€ ์•Š์•˜๋‹ค

'never'โ†’'always' ๋ณต๊ท€ ์‹œ, hero๊ฐ€ ์ด ํŽ˜์ด์ง€์—์„œ ํ•ญ์ƒ always๋ผ ์ „์—ญ rAF ๋ฃจํ”„๊ฐ€ ๋ฉˆ์ถ”์ง€ ์•Š์œผ๋ฏ€๋กœ ๋‹ค์Œ ํ”„๋ ˆ์ž„์— contact๊ฐ€ ์ž๋™ ๋ Œ๋”๋œ๋‹ค(์‹ค์ธก ํ™•์ธ). ์ด ๋‘ ์บ”๋ฒ„์Šค๋Š” ํ™ˆ ๋ผ์šฐํŠธ์—๋งŒ ์กด์žฌํ•˜๋ฏ€๋กœ hero๊ฐ€ ๋ฃจํ”„๋ฅผ ์‚ด๋ ค๋‘๋Š” ์ „์ œ๊ฐ€ ํ•ญ์ƒ ์„ฑ๋ฆฝํ•œ๋‹ค. ์ „์—ญ invalidate()๋Š” ๋ชจ๋“  root๋ฅผ ๋ฌดํšจํ™”ํ•ด ๊ณผํ•˜๋ฏ€๋กœ ๋‘์ง€ ์•Š์•˜๋‹ค.

Changes

์ปค๋ฐ‹ ๋‚ด์šฉ
eb78ae5 ๐Ÿ› fix: contact ์˜คํ”„์Šคํฌ๋ฆฐ ๋ฏธ์ •์ง€ โ€” controlled frameloop prop
081f4df ๐Ÿงช test: characterInstanceCache ์žฌ๋งˆ์šดํŠธ ํŒ์ • ๊ทผ๊ฑฐ ๋ช…์‹œ
  • RenderWhenVisible ์ปดํฌ๋„ŒํŠธ โ†’ useCanvasVisibilityFrameloop(canvasElement) ํ›…. IO + visibilitychange ํŒ๋‹จ์€ ๊ทธ๋Œ€๋กœ, ๋ฐ˜ํ™˜๋งŒ 'always' | 'never'.
  • hero/contact ์บ”๋ฒ„์Šค๊ฐ€ onCreated์˜ gl.domElement๋ฅผ state๋กœ ์žก์•„ ํ›…์— ๋„˜๊ธฐ๊ณ  frameloop prop์œผ๋กœ ์†Œ๋น„. (hero๋Š” ์ด๋ฏธ canvasElement state๊ฐ€ ์žˆ์–ด ์žฌ์‚ฌ์šฉ.)
  • getOrCreateCharacterCache์— sourceScene ํ‚ค๊ฐ€ ์žฌ๋งˆ์šดํŠธ์— ์•ˆ์ „ํ•œ ๊ทผ๊ฑฐ ์ฃผ์„ + ๊ณ„์•ฝ ํ…Œ์ŠคํŠธ 2๊ฑด.

์˜๋„์ ์œผ๋กœ ์•ˆ ๋ฐ”๊พผ ๊ฒƒ

ํ•ญ๋ชฉ ์ด์œ 
MIXER_MAX_DELTA_SECONDS ์ƒํ•œ #93์˜ frameloop ์žฌ๊ฐœ ์•ˆ์ „์žฅ์น˜. ์ด๋ฒˆ ๋ฒ”์œ„ ๋ฐ–
#97์˜ instance๋ณ„ mixer ๋ถ„๋ฆฌ ์œ ์ง€
characterInstanceCache ์‹ฑ๊ธ€ํ„ด ๊ตฌ์กฐ ํŒ์ • ๊ฒฐ๊ณผ "๋ฌธ์ œ ์—†์Œ"์ด๋ผ ๊ตฌ์กฐ ๋ณ€๊ฒฝ ๋ถˆํ•„์š” (์„ค๊ณ„๋Š” ์บ์‹œ ์žฌ์‚ฌ์šฉ์ด ์˜คํžˆ๋ ค ์ด๋“)
๋น„ํ™ˆ ๋ผ์šฐํŠธ ํ”„๋ฆฌ๋กœ๋“œ(F-3) ๋ธŒ๋žœ์น˜ 02 ์†Œ์œ 

๋ฆฌ๋ทฐ ํฌ์ธํŠธ

  1. <Canvas> configure๊ฐ€ ๋งค ๋ Œ๋” frameloop์„ ์žฌ์ ์šฉํ•œ๋‹ค๋Š” ์ „์ œ (์„ค๊ณ„ 1) โ€” ์ด๊ฒŒ ํ‹€๋ฆฌ๋ฉด ์ง„๋‹จ์ด ๋ฌด๋„ˆ์ง„๋‹ค. ์„ค์น˜๋œ @react-three/fiber@9.5.0์˜ deps ์—†๋Š” layout effect + configure์˜ frameloop ๊ธฐ๋ณธ๊ฐ’ 'always'๊ฐ€ ๊ทผ๊ฑฐ๋‹ค.
  2. controlled prop ์ „ํ™˜์œผ๋กœ ํŒ๋‹จ ์ฃผ์ฒด๊ฐ€ ํ•˜๋‚˜๋กœ ์œ ์ง€๋˜๋Š”์ง€ โ€” ๊ฐ€์‹œ์„ฑ ํŒ๋‹จ์€ ํ›… ํ•œ ๊ณณ, <Canvas>๋Š” ๊ทธ ๊ฐ’์„ ๋ฐ›๊ธฐ๋งŒ ํ•œ๋‹ค.
  3. resume ์‹œ invalidate ์ƒ๋žต์ด ์•ˆ์ „ํ•œ์ง€ (์„ค๊ณ„ 3) โ€” hero๊ฐ€ ํ™ˆ์—์„œ ์ „์—ญ ๋ฃจํ”„๋ฅผ ํ•ญ์ƒ ์‚ด๋ ค๋‘๋Š” ์ „์ œ.
  4. ์บ์‹œ ์žฌ๋งˆ์šดํŠธ ํŒ์ • โ€” sourceScene ๋™์ผ์„ฑ์ด ์˜ณ์€ ํ‚ค๋ผ๋Š” ๊ทผ๊ฑฐ(drei useGLTF URL ์บ์‹œ๊ฐ€ ์–ธ๋งˆ์šดํŠธ๋กœ ์•ˆ ๋น„์›Œ์ง)์™€ ๊ณ„์•ฝ ํ…Œ์ŠคํŠธ.

Test plan

  • pnpm run check-types โ€” ํ†ต๊ณผ

  • pnpm run lint โ€” ํ†ต๊ณผ

  • pnpm run test:vitest โ€” ์ „ ๋ฒ„ํ‚ท ํ†ต๊ณผ (์‹ ๊ทœ: useCanvasVisibilityFrameloop 7๊ฑด, ์บ์‹œ ๊ณ„์•ฝ 2๊ฑด)

  • ์‹ค์ธก ์ „/ํ›„ โ€” ํ”„๋กœ๋•์…˜ ๋นŒ๋“œ + GPU Chromium(M3 Pro), 1600ร—1100, /ko. useFrame/์ดˆ ๊ณ„์ธก:

    ์ƒํƒœ ์ „ contact ํ›„ contact
    ๋ฏธ๋…ธ์ถœ 0 0
    ๋…ธ์ถœ์ค‘ โ‰ˆ60 โ‰ˆ77
    ๋…ธ์ถœํ›„ ํ™”๋ฉด๋ฐ– โ‰ˆ60 0
    resize 8๋ฐœ(์˜คํ”„์Šคํฌ๋ฆฐ) (60 ๋ณต๊ท€) 0 ์œ ์ง€
    ์žฌ๋…ธ์ถœ โ‰ˆ60 โ‰ˆ77
    SPA ๋ผ์šฐํŠธ ์™•๋ณต ํ›„ ์˜คํ”„์Šคํฌ๋ฆฐ โ€” 0

    hero(main)๋Š” ์ „ยทํ›„ ๋ชจ๋‘ ํ•ญ์ƒ running(ํ•ญ์ƒ ๋ถ€๋ถ„ ๋…ธ์ถœ์ด๋ผ ์ •์ƒ). ์ฝ˜์†” ์—๋Ÿฌ 0.

  • SPA ๋ผ์šฐํŠธ ์™•๋ณต(client-side) ํ›„ ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ •์ƒ ์žฌ๊ฐœ + ์บ์‹œ ์‹ฑ๊ธ€ํ„ด ์œ ์ง€ ํ™•์ธ (์บ์‹œ ํŒ์ • ๊ทผ๊ฑฐ)

  • ํƒญ ๋ฐฑ๊ทธ๋ผ์šด๋“œ/๋ณต๊ท€ ๋ผ์ด๋ธŒ ๊ณ„์ธก โ€” ๋ฏธ์‹คํ–‰. ๊ตฌ๋™ Chromium์ด document.visibilityState ์žฌ์ •์˜๋ฅผ ๋ง‰์•„ ๋ผ์ด๋ธŒ๋กœ๋Š” ๋ชป ๊ฑธ์—ˆ๋‹ค. ๋™์ผ applyVisibility ๊ฒฝ๋กœ๋ผ ์œ ๋‹› ํ…Œ์ŠคํŠธ๋กœ ์ปค๋ฒ„.

  • pnpm run test:browser โ€” 25 passed / 1 failed. ์‹คํŒจํ•œ home-hero-scene.spec.ts:39๋Š” ์ด ๋ณ€๊ฒฝ๊ณผ ๋ฌด๊ด€ํ•œ ๊ธฐ์กด flake: git stash๋กœ clean main์„ ๋ฆฌ๋นŒ๋“œํ•ด ๋Œ๋ ค๋„ ๋™์ผํ•˜๊ฒŒ ์‹คํŒจ(๊ฐ™์€ tabIndex 5s ํƒ€์ž„์•„์›ƒ). headless ์†Œํ”„ํŠธ์›จ์–ด ๋ Œ๋”๋ง(โ‰ˆ4fps)์—์„œ ์”ฌ ์ค€๋น„๊ฐ€ poll์„ ๋ชป ๋งž์ถ”๋Š” ํƒ€์ด๋ฐ ์ด์Šˆ๊ณ , ๋กœ์ปฌ retries:0์ด๋ผ ๋…ธ์ถœ๋œ๋‹ค. CI๋Š” retries:2๋ผ ๋งˆ์Šคํ‚น๋œ๋‹ค.

ํ›„์†

  • home-hero-scene.spec.ts:39์˜ headless ํƒ€์ด๋ฐ flake โ€” ์ด๋ฒˆ ๋ณ€๊ฒฝ๊ณผ ๋ฌด๊ด€ํ•˜๋‚˜ ๋กœ์ปฌ์—์„œ ์žฌํ˜„๋œ๋‹ค. 5s expect.poll ๋Œ€์‹  ๋ช…์‹œ์  ๋Œ€๊ธฐ ์กฐ๊ฑด์œผ๋กœ ์•ˆ์ •ํ™”ํ•˜๋Š” ๋ณ„๋„ ์ž‘์—…์ด ํ•„์š”ํ•˜๋‹ค. ์ด๋ฒˆ PR ๋ฒ”์œ„ ๋ฐ–(ํ…Œ์ŠคํŠธ ์ธํ”„๋ผ ์†Œ์œ ).

pcwadarong and others added 2 commits September 2, 2026 01:35
RenderWhenVisible์ด ์ดํƒˆ ์‹œ setFrameloop('never')๋ฅผ ๋ช…๋ นํ˜•์œผ๋กœ ํ˜ธ์ถœํ–ˆ์ง€๋งŒ,
R3F <Canvas>์˜ configure๊ฐ€ deps ์—†๋Š” layout effect๋ผ ๋งค ๋ฆฌ๋ Œ๋”๋งˆ๋‹ค frameloop
prop(๊ธฐ๋ณธ๊ฐ’ 'always')์„ ์Šคํ† ์–ด์— ์žฌ์ ์šฉํ•ด ๊ณง๋ฐ”๋กœ ๋ฎ์–ด์ผ๋‹ค. ๊ณ„์ธก์œผ๋กœ
IntersectionObserverยท๊ฐ€์‹œ์„ฑ ๋กœ์ง์€ ์ •์ƒ์ด๊ณ  ๋ฆฌ๋ Œ๋”๊ฐ€ ์›์ธ์ž„์„ ํ™•์ธํ–ˆ๋‹ค
(์˜คํ”„์Šคํฌ๋ฆฐ์—์„œ resize ํ•œ ๋ฒˆ์— neverโ†’always ์žฌํ˜„).

๊ฐ€์‹œ์„ฑ์„ React state๋กœ ์˜ฌ๋ ค <Canvas frameloop={visible?'always':'never'}>๋กœ
์ œ์–ดํ•œ๋‹ค. prop์ด ์ง„์‹ค์ด๋ฏ€๋กœ ๋ฆฌ๋ Œ๋”๊ฐ€ ๋‚˜๋„ ์˜๋„ํ•œ ๊ฐ’์ด ์œ ์ง€๋œ๋‹ค.
RenderWhenVisible ์ปดํฌ๋„ŒํŠธ๋ฅผ useCanvasVisibilityFrameloop ํ›…์œผ๋กœ ๋ฐ”๊พธ๊ณ 
heroยทcontact ์บ”๋ฒ„์Šค๊ฐ€ onCreated์˜ gl.domElement๋กœ ๊ตฌ๋…ํ•œ๋‹ค.

hero๋Š” ์ด ํŽ˜์ด์ง€์—์„œ ํ•ญ์ƒ ๋ถ€๋ถ„ ๋…ธ์ถœ์ด๋ผ ์ „ยทํ›„ ๋ชจ๋‘ always๋กœ ์ •์ƒ ๋™์ž‘ํ•œ๋‹ค.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
#97 ํ›„์†์œผ๋กœ sourceScene ๋™์ผ์„ฑ๋งŒ์œผ๋กœ ์บ์‹œ๋ฅผ ํŒ์ •ํ•˜๋Š” ๊ฒŒ ๋ผ์šฐํŠธ ์ด๋™ ํ›„
์žฌ๋งˆ์šดํŠธ์—์„œ ์•ˆ์ „ํ•œ์ง€ ํ™•์ธํ–ˆ๊ณ , ๊ฒฐ๋ก ์€ "๋ฌธ์ œ ์—†์Œ"์ด๋‹ค.

drei useGLTF ์บ์‹œ๊ฐ€ URL ๋‹จ์œ„๋กœ scene ๊ฐ์ฒด๋ฅผ ์œ ์ง€ํ•˜๊ณ  ๋ ˆํฌ ์–ด๋””์„œ๋„
clear/disposeํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ, client-side ์™•๋ณต์—๋„ ๊ฐ™์€ scene์ด ๋Œ์•„์™€
์ธ์Šคํ„ด์Šคยทmixer๊ฐ€ ๊ทธ๋Œ€๋กœ ์žฌ์‚ฌ์šฉ๋œ๋‹ค(ํด๋ก ยทmixer ์žฌ์ƒ์„ฑ ์—†์Œ). ์‹ค์ธก์œผ๋กœ๋„
SPA ๋ผ์šฐํŠธ ์™•๋ณต ํ›„ ์• ๋‹ˆ๋ฉ”์ด์…˜์ด ์ •์ƒ ์žฌ๊ฐœ๋จ์„ ํ™•์ธํ–ˆ๋‹ค. ๊ฐ’์ด ๋ฐ”๋€Œ๋Š” ๊ฒฝ์šฐ๋Š”
.vN ๊ฒฝ๋กœ ๋ณ€๊ฒฝยทuseGLTF.clear๋ฟ์ด๊ณ  ๋‘˜ ๋‹ค ์ „์ฒด ๋ฆฌ๋กœ๋“œ๋ผ ์˜ค๋ž˜๋œ ํด๋ก ์ด ๋‚จ์•„
๋ˆ„์ˆ˜๋  ๊ฒฝ๋กœ๊ฐ€ ์—†๋‹ค.

๋‹ค์Œ ์‚ฌ๋žŒ์ด ๊ฐ™์€ ์˜์‹ฌ์„ ๋ฐ˜๋ณตํ•˜์ง€ ์•Š๋„๋ก ํŒ์ • ๊ทผ๊ฑฐ๋ฅผ ์ฃผ์„์œผ๋กœ ๋‚จ๊ธฐ๊ณ ,
๊ฐ™์€ ๊ณ„์•ฝ์„ ํ…Œ์ŠคํŠธ๋กœ ๊ณ ์ •ํ•œ๋‹ค โ€” ๊ฐ™์€ scene ์žฌ๋งˆ์šดํŠธ๋Š” ์žฌ์‚ฌ์šฉ, ๋‹ค๋ฅธ scene์€ ์žฌ์ƒ์„ฑ.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Sep 1, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
chaen Ready Ready Preview Sep 6, 2026 10:26am UTC

@coderabbitai

coderabbitai Bot commented Sep 1, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 51 minutes.

Check out review usage here.

View limit details

Limit details: Youโ€™ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

โš™๏ธ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Team

Run ID: 92491f99-e37b-4425-bb06-68c957bea6e8

๐Ÿ“ฅ Commits

Reviewing files that changed from the base of the PR and between 9a4a938 and 701fcca.

๐Ÿ“’ Files selected for processing (10)
  • .claude/skills/article-writing/SKILL.md
  • .claude/skills/article-writing/references/capture-workflow.md
  • src/entities/character/model/use-character-instance.test.ts
  • src/entities/character/model/use-character-instance.ts
  • src/shared/lib/three/use-render-when-visible.test.tsx
  • src/shared/lib/three/use-render-when-visible.ts
  • src/widgets/contact-scene/ui/contact-scene-canvas.test.tsx
  • src/widgets/contact-scene/ui/contact-scene-canvas.tsx
  • src/widgets/home-hero-scene/ui/home-hero-stage-canvas.test.tsx
  • src/widgets/home-hero-scene/ui/home-hero-stage-canvas.tsx
โœจ Finishing Touches
๐Ÿ“ Generate docstrings
  • Create stacked PR
  • Commit on current branch
๐Ÿงช Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/render-when-visible-cache-remount

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

โค๏ธ Share

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

๐Ÿ’ก Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 081f4dfebd

โ„น๏ธ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with ๐Ÿ‘.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/shared/lib/three/use-render-when-visible.ts
Comment thread src/shared/lib/three/use-render-when-visible.ts
Comment thread src/widgets/contact-scene/ui/contact-scene-canvas.tsx
Comment thread src/entities/character/model/use-character-instance.ts
@pcwadarong pcwadarong changed the title ๐Ÿ› fix: contact ์˜คํ”„์Šคํฌ๋ฆฐ ๋ฏธ์ •์ง€ ์ˆ˜์ • โ€” frameloop ์ œ์–ด ์ „ํ™˜๊ณผ ์บ์‹œ ์žฌ๋งˆ์šดํŠธ ํŒ์ • ๐Ÿ› fix: contact ์บ”๋ฒ„์Šค ์˜คํ”„์Šคํฌ๋ฆฐ ๋ฏธ์ •์ง€ ์ˆ˜์ • + ์บ์‹œ ์žฌ๋งˆ์šดํŠธ ํŒ์ • Sep 6, 2026
๋ Œ๋” ๋ฃจํ”„ ๋””๋ฒ„๊น…์„ ๋ธ”๋กœ๊ทธ ์•„ํ‹ฐํด๋กœ ์ •๋ฆฌํ•˜๋ฉฐ ๋งŒ๋“  ์ ˆ์ฐจ๋ฅผ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ
์Šคํ‚ฌ๋กœ ๋‚จ๊ธด๋‹ค. ๊ธฐ์กด ๋ฐœํ–‰ ๊ธ€์„ ๋ฌธ์ฒด ๋‹จ์ผ ์ถœ์ฒ˜๋กœ ์‚ผ์•„ ์กด๋Œ“๋ง ํšŒ๊ณ  ํ†คยทTL;DRยท
์งˆ๋ฌธํ˜• ์†Œ์ œ๋ชฉยทbefore/after ์Œยท๊ตํ›ˆ ์ถ”์ƒํ™” ๊ฒฐ๋ง์„ ๊ฐ•์ œํ•˜๊ณ , ์„ฑ๋Šฅยทํƒ€์ด๋ฐ ๋ฒ„๊ทธ์˜
์ „/ํ›„๋ฅผ ์‹ค์ธก ์Šคํฌ๋ฆฐ์ƒท์œผ๋กœ ๋งŒ๋“œ๋Š” ์บก์ฒ˜ ์›Œํฌํ”Œ๋กœ(before/after ๋นŒ๋“œ +
GPU ๋ธŒ๋ผ์šฐ์ € HUD ์˜ค๋ฒ„๋ ˆ์ด + ์Šคํฌ๋ฆฐ์ƒท)๋ฅผ references๋กœ ๋ถ„๋ฆฌํ–ˆ๋‹ค.
headless ์†Œํ”„ํŠธ์›จ์–ด ๋ Œ๋”๋ง์ด ํ”„๋ ˆ์ž„๋ ˆ์ดํŠธ๋ฅผ ๋ญ‰๊ฐœ๋Š” ํ•จ์ •๋„ ๋ช…์‹œํ–ˆ๋‹ค.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@pcwadarong
pcwadarong merged commit c9394af into main Sep 6, 2026
6 checks passed

This branch was successfully deployed

1 active deployment
Preview โ€” 701fccac Deployed Sep 6, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant