Why it exists
Explore a small capability-based device system instead of tying every optic and effect to one controller script.
Input, deployment, battery lifetime, visual effects, view state, and audio each need a clear place in a reusable device prototype.
Based on the local ODS Experiment code.
How it works
- 01
Choose definitions
The registry selects BasicNightVision and one of three optic configurations.
- 02
Bind controls
ObservationDeviceController binds optic cycling, deployment, and power actions through ContextActionService.
- 03
Start capabilities
Powering on starts Battery drain, enables ImageIntensifier, starts device audio, and shows the view.
- 04
Switch or stop
Changing devices destroys prior capability instances; disabling stops the battery, visual effect, hum, and view.
Selected code
These excerpts are from the paths shown on each patch. Select an annotation for a focused note; copy code directly from each patch.
Battery.luau
src/shared/ObservationDevices/Capabilities/Battery.luau
Starts bounded battery drain, publishes percent changes, calls depletion once, and cancels the running task on stop.
function Battery:Start(): boolean
if self._depleted or self._drainTask then
return not self._depleted
end
self._drainTask = task.spawn(function()
while self._current > 0 do
local elapsed = task.wait(self._config.UpdateInterval)
self._current = math.max(0, self._current - self._config.DrainPerSecond * elapsed)
self._onChanged(self:GetPercent())
if self._current <= 0 then
self._depleted = true
self._drainTask = nil
self._onDepleted()
return
end
end
end)
return true
end
function Battery:Stop(): ()
if self._drainTask then
task.cancel(self._drainTask)
self._drainTask = nil
end
endImageIntensifier.luau
src/shared/ObservationDevices/Capabilities/ImageIntensifier.luau
Cancels earlier transitions, tweens Lighting and post-processing back to neutral, then disables effects after the power-down interval.
function ImageIntensifier:Disable(): ()
if not self._enabled then
return
end
self:_cancelTransitions()
self._enabled = false
local currentTransitionId = self._transitionId
local duration = self._config.Activation.PowerDownDuration
self:_tweenProperties(Lighting, duration, { ExposureCompensation = self._originalExposureCompensation })
self:_tweenProperties(self._colorCorrectionEffect, duration, NEUTRAL_COLOR_CORRECTION)
self:_tweenProperties(self._bloomEffect, duration, { Intensity = 0 })
self._shutdownTask = task.delay(duration, function()
if self._transitionId ~= currentTransitionId or self._enabled then
return
end
Lighting.ExposureCompensation = self._originalExposureCompensation
_applyProperties(self._colorCorrectionEffect, NEUTRAL_COLOR_CORRECTION)
self._bloomEffect.Intensity = 0
self._colorCorrectionEffect.Enabled = false
self._bloomEffect.Enabled = false
self._hasExposureBaseline = false
self._shutdownTask = nil
table.clear(self._transitionTweens)
end)
endEngineering decisions
Capability modules
- Reason
- Battery, DeviceAudio, ImageIntensifier, and view logic have separate lifetimes and configuration.
- Alternative
- Put every effect and timer in the controller.
- Tradeoff
- The controller coordinates construction and teardown between modules.
Restore Lighting state
- Reason
- ImageIntensifier captures the prior exposure and restores it during shutdown or reset.
- Alternative
- Leave global Lighting changes after power-off.
- Tradeoff
- Transitions need cancellation and baseline tracking.
Outcome & next steps
Outcome
The source implements one night-vision device definition, three optics, battery and audio capabilities, a view, and Lighting transitions.
What improved
Separate capability objects let the controller replace a device while cleaning up the previous battery, audio, view, and image effects.
Current limitations
- Only one device definition is present in the inspected registry.
- No Studio playtest or automated runtime test was available for this audit.
Future improvements
- Playtest power cycling, optic switching, battery depletion, and controller action cleanup in Studio.
What this demonstrates
Modular Luau configuration, capability lifetimes, delayed-task cancellation, and reversible visual effects.