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
10 changes: 5 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@ jobs:
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4

- name: Run tests
run: ./gradlew :phosphor-core:jvmTest
- name: Run JVM tests
run: ./gradlew :phosphor-core:jvmTest :phosphor-lumos:jvmTest

- name: Check formatting
run: ./gradlew :phosphor-core:ktlintCheck
run: ./gradlew :phosphor-core:ktlintCheck :phosphor-lumos:ktlintCheck

ios_compile:
name: iOS Compile
Expand All @@ -54,8 +54,8 @@ jobs:
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4

- name: Compile iOS target
run: ./gradlew :phosphor-core:compileKotlinIosArm64
- name: Compile iOS targets
run: ./gradlew :phosphor-core:compileKotlinIosArm64 :phosphor-lumos:compileKotlinIosArm64

test:
name: Tests
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ jobs:
uses: gradle/actions/setup-gradle@v4

- name: Run tests before publish
run: ./gradlew :phosphor-core:jvmTest :phosphor-core:compileKotlinIosArm64
run: ./gradlew :phosphor-core:jvmTest :phosphor-lumos:jvmTest :phosphor-core:compileKotlinIosArm64 :phosphor-lumos:compileKotlinIosArm64

- name: Decode signing key
if: ${{ github.event.inputs.dry_run != 'true' }}
Expand All @@ -64,13 +64,13 @@ jobs:
ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.SIGNING_PASSWORD }}
run: |
export ORG_GRADLE_PROJECT_signingInMemoryKey="$(cat /tmp/signing-key.asc)"
./gradlew :phosphor-core:publishAllPublicationsToMavenCentralRepository
./gradlew :phosphor-core:publishAllPublicationsToMavenCentralRepository :phosphor-lumos:publishAllPublicationsToMavenCentralRepository

- name: Dry run publish
if: ${{ github.event.inputs.dry_run == 'true' }}
run: |
echo "Dry run mode - publishing to Maven Local only"
./gradlew :phosphor-core:publishToMavenLocal
./gradlew :phosphor-core:publishToMavenLocal :phosphor-lumos:publishToMavenLocal

- name: Create GitHub Release
if: startsWith(github.ref, 'refs/tags/v') && github.event.inputs.dry_run != 'true'
Expand Down
25 changes: 13 additions & 12 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# AGENTS.md

Phosphor is a Kotlin Multiplatform rendering library that translates cognitive state into visible light — ASCII luminance, color ramps, particle physics, and 3D waveform surfaces. Read [SOUL.md](SOUL.md) for project philosophy and values.
Phosphor is a Kotlin Multiplatform rendering library that translates cognitive state into visible light — ASCII luminance, color ramps, particle physics, 3D waveform surfaces, and the Lumos voxel-orb companion visualization. Read [SOUL.md](SOUL.md) for project philosophy and values.

## Development Commands

Expand All @@ -20,12 +20,6 @@ Phosphor is a Kotlin Multiplatform rendering library that translates cognitive s
./gradlew dokkaHtml # Generate API documentation
```

### Demo
```bash
./gradlew :phosphor-demo:run # Run the desktop demo application
./gradlew :phosphor-demo-cli:installDist && ./phosphor-demo-cli/phosphor-demo # Run the terminal demo
```

### Publishing
```bash
./gradlew publishToMavenLocal # Publish to local Maven for integration testing
Expand All @@ -45,24 +39,31 @@ Phosphor is a layered rendering pipeline: cognitive signals flow in, visible cha
| Emitter | `emitter/` | EmitterEffect sealed hierarchy — transient visual events (SparkBurst, HeightPulse, Turbulence, ColorWash) |
| Bridge | `bridge/` | Adapters connecting live runtime state to the animation field |

### Rendering Surface Adapters (separate modules)
### Active Modules

| Module | Purpose |
|--------|---------|
| `phosphor-core/` | Shared rendering pipeline — signals, fields, palettes, cells, choreography, emitters, and runtime bridges |
| `phosphor-lumos/` | Framework-free voxel-orb companion visualization for cognitive state, built as a sibling output module over `phosphor-core` |

### Future / Aspirational Modules

| Module | Purpose |
|--------|---------|
| `phosphor-mosaic/` | Mosaic (Compose-for-terminal) adapter — AnnotatedString output |
| `phosphor-compose/` | Compose Multiplatform Canvas adapter — DrawScope rendering |
| `phosphor-ansi/` | Raw ANSI escape code output for non-Compose terminals |
| `phosphor-demo/` | Desktop demo app (Compose Desktop) |
| `phosphor-demo-cli/` | Terminal demo app |

## Key Paths

| Module | Purpose |
|--------|---------|
| `phosphor-core/src/commonMain/` | Shared rendering pipeline — signals, fields, palettes, cells |
| `phosphor-core/src/commonTest/` | Unit tests for palette mapping, projection math, particle physics |
| `phosphor-mosaic/src/jvmMain/` | Terminal rendering via Mosaic AnnotatedString |
| `phosphor-compose/src/commonMain/` | Compose Canvas rendering via DrawScope |
| `phosphor-demo/` | Desktop demo app (Compose Desktop) |
| `phosphor-demo-cli/` | Terminal demo app |
| `phosphor-lumos/src/commonMain/` | Lumos module boundary for framework-free voxel-orb visualization data |
| `phosphor-lumos/src/commonTest/` | Lumos smoke tests and future voxel-frame API tests |

## Before You Change Anything

Expand Down
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ Phosphor is a Kotlin Multiplatform rendering library that transduces cognitive s

Just as CRT phosphor converts electron energy into visible light, this library converts an AI agent's internal state into something you can see: sparse floating dots coalescing into dense bright strokes as cognition shifts from perception to execution.

Phosphor ships `:phosphor-core` alongside `:phosphor-lumos`, its first separate output module. Lumos is a framework-free voxel-orb companion visualization for cognitive state; it complements the CRT-phosphor terminal aesthetic and does not replace it.

---

## The Pipeline
Expand All @@ -34,7 +36,14 @@ Signal → Field → Palette → Render → Choreography → Emitter → Surface
| **Emitter** | `emitter/` | Transient effects — spark bursts, height pulses, turbulence — that decay naturally |
| **Bridge** | `bridge/` | Connects runtime cognitive state to the animation field |

`phosphor-core` has zero UI framework dependencies. Surface adapters (phosphor-mosaic, phosphor-compose, phosphor-ansi) live in separate modules.
`phosphor-core` has zero UI framework dependencies. Platform-specific rendering belongs in separate surface modules; `:phosphor-lumos` is the first concrete sibling module and establishes the boundary for framework-free voxel-orb frame data.

## Modules

| Module | Purpose |
|--------|---------|
| `:phosphor-core` | Shared rendering pipeline — signals, fields, palettes, cells, choreography, emitters, and runtime bridges |
| `:phosphor-lumos` | Voxel-orb companion visualization module for cognitive state, scaffolded for downstream Lumos frame APIs |

---

Expand Down
32 changes: 32 additions & 0 deletions phosphor-core/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import com.vanniktech.maven.publish.JavadocJar
import com.vanniktech.maven.publish.KotlinMultiplatform
import com.vanniktech.maven.publish.SonatypeHost
import org.gradle.plugins.signing.Sign
import org.gradle.plugins.signing.SigningExtension
import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.plugin.mpp.apple.XCFramework
Expand All @@ -18,6 +20,24 @@ val phosphorVersion: String by project
group = "link.socket"
version = phosphorVersion

val hasInMemorySigningCredentials =
providers.gradleProperty("signingInMemoryKey").isPresent &&
providers.gradleProperty("signingInMemoryKeyId").isPresent &&
providers.gradleProperty("signingInMemoryKeyPassword").isPresent
val hasFileSigningCredentials =
providers.gradleProperty("signing.secretKeyRingFile").isPresent &&
providers.gradleProperty("signing.keyId").isPresent &&
providers.gradleProperty("signing.password").isPresent
val hasGpgSigningCredentials = providers.gradleProperty("signing.gnupg.keyName").isPresent
val hasSigningCredentials =
hasInMemorySigningCredentials ||
hasFileSigningCredentials ||
hasGpgSigningCredentials
val isPublishingToMavenLocal =
gradle.startParameter.taskNames.any {
it == "publishToMavenLocal" || it.endsWith(":publishToMavenLocal")
}

kotlin {
applyDefaultHierarchyTemplate()

Expand Down Expand Up @@ -111,3 +131,15 @@ mavenPublishing {
}
}
}

plugins.withId("signing") {
extensions.configure<SigningExtension>("signing") {
if (hasGpgSigningCredentials) {
useGpgCmd()
}
}
}

tasks.withType<Sign>().configureEach {
enabled = hasSigningCredentials && !isPublishingToMavenLocal
}
141 changes: 141 additions & 0 deletions phosphor-lumos/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import com.vanniktech.maven.publish.JavadocJar
import com.vanniktech.maven.publish.KotlinMultiplatform
import com.vanniktech.maven.publish.SonatypeHost
import org.gradle.plugins.signing.Sign
import org.gradle.plugins.signing.SigningExtension
import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.plugin.mpp.apple.XCFramework

plugins {
kotlin("multiplatform")
kotlin("plugin.serialization")
id("org.jlleitschuh.gradle.ktlint")
id("org.jetbrains.dokka")
id("com.vanniktech.maven.publish")
}

val phosphorVersion: String by project

group = "link.socket"
version = phosphorVersion

val hasInMemorySigningCredentials =
providers.gradleProperty("signingInMemoryKey").isPresent &&
providers.gradleProperty("signingInMemoryKeyId").isPresent &&
providers.gradleProperty("signingInMemoryKeyPassword").isPresent
val hasFileSigningCredentials =
providers.gradleProperty("signing.secretKeyRingFile").isPresent &&
providers.gradleProperty("signing.keyId").isPresent &&
providers.gradleProperty("signing.password").isPresent
val hasGpgSigningCredentials = providers.gradleProperty("signing.gnupg.keyName").isPresent
val hasSigningCredentials =
hasInMemorySigningCredentials ||
hasFileSigningCredentials ||
hasGpgSigningCredentials
val isPublishingToMavenLocal =
gradle.startParameter.taskNames.any {
it == "publishToMavenLocal" || it.endsWith(":publishToMavenLocal")
}

kotlin {
applyDefaultHierarchyTemplate()

jvm {
compilerOptions {
jvmTarget.set(JvmTarget.JVM_21)
}
}

js(IR) {
browser()
binaries.executable()
}

@OptIn(ExperimentalWasmDsl::class)
wasmJs {
browser()
binaries.executable()
}

val xcf = XCFramework()
val iosTargets = listOf(iosX64(), iosArm64(), iosSimulatorArm64())

iosTargets.forEach {
it.binaries.framework {
baseName = "phosphor-lumos"
xcf.add(this)
}
}

sourceSets {
val commonMain by getting {
dependencies {
implementation(project(":phosphor-core"))
}
}
val commonTest by getting {
dependencies {
implementation(kotlin("test"))
}
}
}
}

mavenPublishing {
publishToMavenCentral(SonatypeHost.CENTRAL_PORTAL)
signAllPublications()

configure(KotlinMultiplatform(javadocJar = JavadocJar.Dokka("dokkaGeneratePublicationHtml")))

coordinates("link.socket", "phosphor-lumos", version.toString())

pom {
name.set("Phosphor Lumos")
description.set(
"Kotlin Multiplatform voxel-orb companion visualization for cognitive state, " +
"built on the Phosphor core signal and rendering substrate.",
)
url.set("https://github.com/socket-link/phosphor")
inceptionYear.set("2025")

licenses {
license {
name.set("The Apache Software License, Version 2.0")
url.set("https://www.apache.org/licenses/LICENSE-2.0.txt")
distribution.set("repo")
}
}

developers {
developer {
id.set("socket-link")
name.set("Socket Link")
url.set("https://github.com/socket-link")
}
}

scm {
connection.set("scm:git:git://github.com/socket-link/phosphor.git")
developerConnection.set("scm:git:ssh://git@github.com:socket-link/phosphor.git")
url.set("https://github.com/socket-link/phosphor")
}

issueManagement {
system.set("GitHub Issues")
url.set("https://github.com/socket-link/phosphor/issues")
}
}
}

plugins.withId("signing") {
extensions.configure<SigningExtension>("signing") {
if (hasGpgSigningCredentials) {
useGpgCmd()
}
}
}

tasks.withType<Sign>().configureEach {
enabled = hasSigningCredentials && !isPublishingToMavenLocal
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
@file:Suppress("ktlint:standard:no-empty-file")

/**
* Lumos provides framework-free voxel-orb visualization data for cognitive state,
* complementing Phosphor's CRT-terminal rendering pipeline without replacing it.
*/

package link.socket.phosphor.lumos
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package link.socket.phosphor.lumos

import kotlin.test.Test
import kotlin.test.assertEquals
import link.socket.phosphor.signal.CognitivePhase

class LumosSmokeTest {
@Test
fun `lumos package compiles with core dependency`() {
assertEquals(CognitivePhase.NONE, CognitivePhase.valueOf("NONE"))
}
}
1 change: 1 addition & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
rootProject.name = "Phosphor"

include(":phosphor-core")
include(":phosphor-lumos")

pluginManagement {
repositories {
Expand Down
Loading