@@ -32,12 +32,16 @@ function normalizeRuntimeExtensionEntry(entry) {
3232 const panelWidth = Number . isFinite ( panelWidthRaw ) && panelWidthRaw > 0 ? panelWidthRaw : 260 ;
3333 const panelHeight = Number . isFinite ( panelHeightRaw ) && panelHeightRaw > 0 ? panelHeightRaw : 96 ;
3434 const resolvePanelSize = typeof entry . resolvePanelSize === 'function' ? entry . resolvePanelSize : null ;
35+ const resolveContextBehavior = typeof entry . resolveContextBehavior === 'function'
36+ ? entry . resolveContextBehavior
37+ : null ;
3538
3639 return Object . freeze ( {
3740 overlayId,
3841 onStep,
3942 onRender,
4043 resolvePanelSize,
44+ resolveContextBehavior,
4145 compose,
4246 layerOrder,
4347 visualPriority,
@@ -140,7 +144,81 @@ function rectsOverlap(a, b) {
140144 return a . x < b . x + b . width && a . x + a . width > b . x && a . y < b . y + b . height && a . y + a . height > b . y ;
141145}
142146
143- function getComposedRuntimeFrames ( runtime , activeOverlayId ) {
147+ function resolveOverlayGameplayState ( context = { } ) {
148+ if ( ! context || typeof context !== 'object' ) {
149+ return null ;
150+ }
151+
152+ if ( context . gameplayState && typeof context . gameplayState === 'object' ) {
153+ return context . gameplayState ;
154+ }
155+
156+ const scene = context . scene ;
157+ if ( ! scene || typeof scene !== 'object' ) {
158+ return null ;
159+ }
160+
161+ if ( typeof scene . getOverlayGameplayState === 'function' ) {
162+ const value = scene . getOverlayGameplayState ( ) ;
163+ if ( value && typeof value === 'object' ) {
164+ return value ;
165+ }
166+ }
167+
168+ if ( typeof scene . getGameplayState === 'function' ) {
169+ const value = scene . getGameplayState ( ) ;
170+ if ( value && typeof value === 'object' ) {
171+ return value ;
172+ }
173+ }
174+
175+ if ( scene . gameplayState && typeof scene . gameplayState === 'object' ) {
176+ return scene . gameplayState ;
177+ }
178+
179+ if ( scene . state && typeof scene . state === 'object' ) {
180+ return scene . state ;
181+ }
182+
183+ return null ;
184+ }
185+
186+ function resolveRuntimeExtensionContextBehavior ( extension , context = { } ) {
187+ const defaultBehavior = {
188+ visible : true ,
189+ compose : extension ?. compose === true ,
190+ panelWidth : Number ( extension ?. panelWidth ) || 260 ,
191+ panelHeight : Number ( extension ?. panelHeight ) || 96 ,
192+ } ;
193+
194+ if ( ! extension || typeof extension . resolveContextBehavior !== 'function' ) {
195+ return defaultBehavior ;
196+ }
197+
198+ try {
199+ const gameplayState = resolveOverlayGameplayState ( context ) ;
200+ const resolved = extension . resolveContextBehavior ( {
201+ ...context ,
202+ gameplayState,
203+ } ) ;
204+ return {
205+ visible : resolved ?. visible !== false ,
206+ compose : resolved ?. compose === true || resolved ?. compose === false
207+ ? resolved . compose
208+ : defaultBehavior . compose ,
209+ panelWidth : Number . isFinite ( Number ( resolved ?. panelWidth ) )
210+ ? Number ( resolved . panelWidth )
211+ : defaultBehavior . panelWidth ,
212+ panelHeight : Number . isFinite ( Number ( resolved ?. panelHeight ) )
213+ ? Number ( resolved . panelHeight )
214+ : defaultBehavior . panelHeight ,
215+ } ;
216+ } catch {
217+ return defaultBehavior ;
218+ }
219+ }
220+
221+ function getComposedRuntimeFrames ( runtime , activeOverlayId , context = { } ) {
144222 if ( ! runtime || ! Array . isArray ( runtime . runtimeExtensions ) || runtime . runtimeExtensions . length === 0 ) {
145223 return [ ] ;
146224 }
@@ -151,8 +229,12 @@ function getComposedRuntimeFrames(runtime, activeOverlayId) {
151229
152230 for ( let i = 0 ; i < runtime . runtimeExtensions . length ; i += 1 ) {
153231 const extension = runtime . runtimeExtensions [ i ] ;
232+ const contextBehavior = resolveRuntimeExtensionContextBehavior ( extension , context ) ;
233+ if ( contextBehavior . visible === false ) {
234+ continue ;
235+ }
154236 const isActive = i === activeIndex ;
155- if ( ! isActive && extension . compose !== true ) {
237+ if ( ! isActive && contextBehavior . compose !== true ) {
156238 continue ;
157239 }
158240 if ( ! shouldRunRuntimeExtension ( extension , normalizedActiveOverlayId ) ) {
@@ -163,6 +245,7 @@ function getComposedRuntimeFrames(runtime, activeOverlayId) {
163245 extension,
164246 registrationIndex : i ,
165247 isActive,
248+ contextBehavior,
166249 } ) ;
167250 }
168251
@@ -362,12 +445,19 @@ function attachCompositionSlots(frames, renderer, safeZones = [], layoutContext
362445
363446 for ( let i = 0 ; i < frames . length ; i += 1 ) {
364447 const frame = frames [ i ] ;
365- const fallbackWidth = Math . max ( 120 , Number ( frame . extension . panelWidth ) || 260 ) ;
366- const fallbackHeight = Math . max ( 32 , Number ( frame . extension . panelHeight ) || 96 ) ;
448+ const fallbackWidth = Math . max (
449+ 120 ,
450+ Number ( frame . contextBehavior ?. panelWidth ) || Number ( frame . extension . panelWidth ) || 260
451+ ) ;
452+ const fallbackHeight = Math . max (
453+ 32 ,
454+ Number ( frame . contextBehavior ?. panelHeight ) || Number ( frame . extension . panelHeight ) || 96
455+ ) ;
367456 const dynamicPanelSize = resolveDynamicPanelSize ( frame . extension , {
368457 ...layoutContext ,
369458 renderer,
370459 canvasSize : { width, height } ,
460+ gameplayState : resolveOverlayGameplayState ( layoutContext ) ,
371461 frameIndex : i ,
372462 frameCount : frames . length ,
373463 safeZones,
@@ -499,7 +589,7 @@ export function getOverlayGameplayRuntimeCompositionSnapshot(runtime, context =
499589 const activeOverlayId = String ( context ?. activeOverlayId || '' ) . trim ( ) ;
500590 const safeZones = resolveLayoutSafeZones ( context ) ;
501591 const frames = deriveRenderHierarchy ( attachCompositionSlots (
502- getComposedRuntimeFrames ( runtime , activeOverlayId ) ,
592+ getComposedRuntimeFrames ( runtime , activeOverlayId , context ) ,
503593 context ?. renderer ,
504594 safeZones ,
505595 context
@@ -517,7 +607,7 @@ export function getOverlayGameplayRuntimeCompositionSnapshot(runtime, context =
517607 visualTier : frame . visualTier ,
518608 readabilityOpacity : frame . readabilityOpacity ,
519609 hiddenByClutter : ! visibleSet . has ( frame ) ,
520- compose : frame . extension . compose === true ,
610+ compose : frame . contextBehavior ? .compose === true ,
521611 isActive : frame . isActive === true ,
522612 overlayId : frame . extension . overlayId ,
523613 slot : frame . slot ,
@@ -614,7 +704,7 @@ export function stepOverlayGameplayRuntime(runtime, context = {}) {
614704 }
615705
616706 const activeOverlayId = String ( context . activeOverlayId || '' ) . trim ( ) ;
617- const frames = getComposedRuntimeFrames ( runtime , activeOverlayId ) ;
707+ const frames = getComposedRuntimeFrames ( runtime , activeOverlayId , context ) ;
618708 if ( frames . length === 0 ) {
619709 return 0 ;
620710 }
@@ -633,7 +723,7 @@ export function stepOverlayGameplayRuntime(runtime, context = {}) {
633723 count : frames . length ,
634724 registrationIndex : frame . registrationIndex ,
635725 layerOrder : frame . extension . layerOrder ,
636- compose : frame . extension . compose === true ,
726+ compose : frame . contextBehavior ? .compose === true ,
637727 isActive : frame . isActive === true ,
638728 slot : frame . slot || null ,
639729 } ,
@@ -661,7 +751,7 @@ export function renderOverlayGameplayRuntime(runtime, context = {}) {
661751 const frames = applyCompositionReadabilityLimits (
662752 deriveRenderHierarchy (
663753 attachCompositionSlots (
664- getComposedRuntimeFrames ( runtime , activeOverlayId ) ,
754+ getComposedRuntimeFrames ( runtime , activeOverlayId , context ) ,
665755 context . renderer ,
666756 safeZones ,
667757 context
@@ -692,7 +782,7 @@ export function renderOverlayGameplayRuntime(runtime, context = {}) {
692782 visualTier : frame . visualTier ,
693783 readabilityOpacity : frame . readabilityOpacity ,
694784 hiddenByClutter : frame . hiddenByClutter === true ,
695- compose : frame . extension . compose === true ,
785+ compose : frame . contextBehavior ? .compose === true ,
696786 isActive : frame . isActive === true ,
697787 slot : frame . slot ,
698788 } ,
0 commit comments