Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
package link.socket.phosphor.palette

import link.socket.phosphor.signal.AtmospherePattern
import link.socket.phosphor.signal.AtmosphereState

/**
* Canonical atmosphere presets for Lumos scene-global rendering.
*
* These presets use Socket-aligned default hues: 244-degree indigo,
* 197-degree cyan, 32-degree amber, and 280-degree purple. Consumers can
* construct their own [AtmosphereState] instances when a different palette or
* motion profile is needed.
*/
object AtmospherePresets {
val IDLE =
AtmosphereState(
primaryHue = 250f,
secondaryHue = 175f,
saturation = 0.85f,
lightness = 0.60f,
bipolarStrength = 0.0f,
pattern = AtmospherePattern.LONGITUDE,
patternSpeed = 0.25f,
pulseAmplitude = 0.025f,
pulseFrequency = 0.30f,
rotationY = 0.14f,
rotationX = 0.0f,
surfaceBump = 0.10f,
noise = 0.20f,
voxelGap = 0.05f,
ySquash = 0.95f,
resolution = 10,
glow = 1.0f,
)

val LISTENING =
AtmosphereState(
primaryHue = 195f,
secondaryHue = 270f,
saturation = 0.85f,
lightness = 0.60f,
bipolarStrength = 0.0f,
pattern = AtmospherePattern.PLASMA,
patternSpeed = 1.15f,
pulseAmplitude = 0.06f,
pulseFrequency = 0.5f,
rotationY = 0.16f,
rotationX = 0.10f,
surfaceBump = 0.10f,
noise = 0.20f,
voxelGap = 0.05f,
ySquash = 0.95f,
resolution = 10,
glow = 1.0f,
)

val THINKING =
AtmosphereState(
primaryHue = 244f,
secondaryHue = 185f,
saturation = 0.85f,
lightness = 0.60f,
bipolarStrength = 0.0f,
pattern = AtmospherePattern.SPIRAL,
patternSpeed = 0.7f,
pulseAmplitude = 0.025f,
pulseFrequency = 0.45f,
rotationY = 0.45f,
rotationX = 0.10f,
surfaceBump = 0.10f,
noise = 0.20f,
voxelGap = 0.05f,
ySquash = 0.95f,
resolution = 10,
glow = 1.0f,
)

val UNCERTAIN =
AtmosphereState(
primaryHue = 32f,
secondaryHue = 280f,
saturation = 0.85f,
lightness = 0.60f,
bipolarStrength = 0.45f,
pattern = AtmospherePattern.SPIRAL,
patternSpeed = 1.0f,
pulseAmplitude = 0.06f,
pulseFrequency = 0.16f,
rotationY = 0.10f,
rotationX = 0.10f,
surfaceBump = 0.10f,
noise = 0.20f,
voxelGap = 0.05f,
ySquash = 0.95f,
resolution = 10,
glow = 1.0f,
)

val READY =
AtmosphereState(
primaryHue = 249f,
secondaryHue = 197f,
saturation = 0.85f,
lightness = 0.60f,
bipolarStrength = 0.0f,
pattern = AtmospherePattern.PULSE,
patternSpeed = 1.3f,
pulseAmplitude = 0.04f,
pulseFrequency = 0.5f,
rotationY = 0.20f,
rotationX = -0.20f,
surfaceBump = 0.10f,
noise = 0.20f,
voxelGap = 0.05f,
ySquash = 0.95f,
resolution = 10,
glow = 1.0f,
)

val ALL: List<Pair<String, AtmosphereState>> =
listOf(
"idle" to IDLE,
"listening" to LISTENING,
"thinking" to THINKING,
"uncertain" to UNCERTAIN,
"ready" to READY,
)

/**
* Resolve a canonical preset by name, ignoring case.
*/
fun byName(name: String): AtmosphereState? =
ALL.firstOrNull { (presetName, _) -> presetName.equals(name, ignoreCase = true) }?.second
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package link.socket.phosphor.signal

import kotlinx.serialization.Serializable

/**
* Scene-global pattern families used by [AtmosphereState].
*
* Patterns describe spatial variation in the renderer's atmosphere. Surface
* adapters can interpret each family with renderer-specific math while keeping
* a stable signal contract in common code.
*/
@Serializable
enum class AtmospherePattern {
/** Horizontal-banded sine pattern around the vertical axis. */
LONGITUDE,

/** Vertical-banded sine pattern around the polar axis. */
LATITUDE,

/** Combined theta and phi sweep. */
SPIRAL,

/** Linear sweep along the Y axis. */
SCAN,

/** Three-axis noise sum. */
PLASMA,

/** Radial concentric rings from center. */
PULSE,

/** No pattern variation. */
SOLID,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package link.socket.phosphor.signal

import kotlinx.serialization.Serializable

/**
* Scene-global visual parameter for renderer atmosphere.
*
* AtmosphereState describes the global environment through which rendered
* light propagates. It is not a per-agent state; [AgentVisualState] remains the
* per-agent counterpart for position, activity, and phase progress.
*
* @property primaryHue Primary hue in degrees, expected in 0..360.
* @property secondaryHue Secondary hue in degrees, expected in 0..360.
* @property saturation Color saturation, expected in 0..1.
* @property lightness Color lightness, expected in 0..1.
* @property bipolarStrength Two-pole color strength; values greater than zero enable bipolar color mode.
* @property pattern Spatial pattern family.
* @property patternSpeed Temporal scale for pattern movement.
* @property pulseAmplitude Radial scale modulation amplitude.
* @property pulseFrequency Radial scale modulation rate in Hz.
* @property rotationY Continuous spin rate around the Y axis.
* @property rotationX Continuous spin rate around the X axis.
* @property surfaceBump Surface deformation amplitude.
* @property noise Per-voxel position jitter scale.
* @property voxelGap Voxel scale-down amount used by renderers that show lattice gaps.
* @property ySquash Vertical squash ratio.
* @property resolution Lattice resolution.
* @property glow Renderer-interpreted atmospheric glow intensity.
*/
@Serializable
data class AtmosphereState(
val primaryHue: Float,
val secondaryHue: Float,
val saturation: Float,
val lightness: Float,
val bipolarStrength: Float,
val pattern: AtmospherePattern,
val patternSpeed: Float,
val pulseAmplitude: Float,
val pulseFrequency: Float,
val rotationY: Float,
val rotationX: Float,
val surfaceBump: Float,
val noise: Float,
val voxelGap: Float,
val ySquash: Float,
val resolution: Int,
val glow: Float,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package link.socket.phosphor.signal

import kotlinx.serialization.Serializable

/**
* Diagnostic snapshot for a transition between two atmosphere states.
*
* The transition carries both raw time progress and eased progress so renderer
* integrations can report exactly which interpolation input produced the
* current state. Preset names are nullable because either endpoint may be a
* caller-constructed [AtmosphereState].
*
* Default preset transition table planned for AtmosphereChoreographer:
*
* | From -> To | Duration (s) | Easing |
* | --- | ---: | --- |
* | idle -> listening | 0.6 | eager |
* | idle -> thinking | 0.8 | easeOut |
* | idle -> uncertain | 1.4 | easeInOut |
* | idle -> ready | 1.1 | overshoot |
* | listening -> idle | 0.9 | easeInOut |
* | listening -> thinking | 0.75 | settled |
* | listening -> uncertain | 1.5 | easeInOut |
* | listening -> ready | 1.05 | overshoot |
* | thinking -> idle | 1.0 | easeInOut |
* | thinking -> listening | 0.65 | eager |
* | thinking -> uncertain | 1.65 | easeInOut |
* | thinking -> ready | 0.95 | overshoot |
* | uncertain -> idle | 1.15 | easeInOut |
* | uncertain -> listening | 0.6 | easeInOut |
* | uncertain -> thinking | 0.65 | easeInOut |
* | uncertain -> ready | 0.95 | easeInOut |
* | ready -> idle | 1.5 | easeInOut |
* | ready -> listening | 0.65 | eager |
* | ready -> thinking | 0.85 | settled |
* | ready -> uncertain | 1.7 | easeInOut |
* | default fallback | 1.1 | easeInOut |
*
* @property from Starting atmosphere state.
* @property to Target atmosphere state.
* @property fromPresetName Preset name for [from], or null when [from] is not a known preset.
* @property toPresetName Preset name for [to], or null when [to] is not a known preset.
* @property progressLinear Time-based progress, expected in 0..1.
* @property progressEased Easing-adjusted progress, expected in 0..1.
* @property easingName Easing identifier used for diagnostics.
* @property durationSeconds Transition duration in seconds.
*/
@Serializable
data class AtmosphereTransition(
val from: AtmosphereState,
val to: AtmosphereState,
val fromPresetName: String?,
val toPresetName: String?,
val progressLinear: Float,
val progressEased: Float,
val easingName: String,
val durationSeconds: Float,
)
Loading
Loading