import Foundation
/// Whether the live render should pause: a covering sheet hides the canvas or
/// the scene isn't active (app switcher, background). The editor sheet stays
/// live on purpose — tuning needs visible feedback behind the half sheet.
func playerShouldPause(libraryVisible: Bool, sceneActive: Bool) -> Bool {
libraryVisible || !sceneActive
}
/// Ambient frame-rate policy: full 60 only while the device is cool (`.nominal`)
/// and not power-constrained; 30 from `.fair` upward (pre-empting the system's own
/// throttle) and in Low Power Mode. For an always-on visual, halving FPS early is
/// the gentlest lever before the OS throttles everything.
func preferredFPS(thermalState: ProcessInfo.ThermalState, lowPowerMode: Bool) -> Int {
if lowPowerMode || thermalState != .nominal { return 30 }
return 60
}
/// Drawable scale for the live composite: non-desktop tiers (phone/tablet) cap the
/// final pass at 2x. On phones this cuts ~55% composite fragment work vs 3x; on iPads
/// (already @2x) it is inert but keeps the policy consistent. Desktop keeps native scale.
/// (Capture/export is unaffected — it renders offscreen at the requested export size.)
func cappedDrawableScale(_ nativeScale: CGFloat, tier: FieldTier) -> CGFloat {
tier == .desktop ? nativeScale : min(nativeScale, 2.0)
}