Deterministic color generation with SplitMix64, GF(3) trits, and MCP
Scanned 9/6/2026
Install to Claude Code
npx -y skills add plurigrid/asi --skill gay-mcp --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Gay Mcp?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/plurigrid-gay-mcp-d66080e2)More formats (shields.io, HTML) on the badges page.
---
name: gay-mcp
description: Deterministic color generation with SplitMix64, GF(3) trits, and MCP
tools for palettes and threads.
license: UNLICENSED
metadata:
source: local
---
<!-- Propagated to codex | Trit: 0 | Source: .ruler/skills/gay-mcp -->
# Gay-MCP Skill: Deterministic Color Generation
**Status**: ✅ Production Ready
**Trit**: +1 (PLUS - optimistic/generative)
**Principle**: Same seed → Same colors (SPI guarantee)
**Implementation**: Gay.jl (Julia) + SplitMixTernary (Ruby)
---
## Overview
**Gay-MCP** provides deterministic color generation via SplitMix64 + golden angle. Every invocation with the same seed produces identical colors, enabling:
1. **Parallel computation**: Fork generators, get same results
2. **Reproducibility**: Colors are functions of (seed, index)
3. **GF(3) trits**: Each color maps to {-1, 0, +1}
## Core Algorithm
```
SplitMix64:
state = (state + γ) mod 2⁶⁴
z = state
z = (z ⊕ (z >> 30)) × 0xBF58476D1CE4E5B9
z = (z ⊕ (z >> 27)) × 0x94D049BB133111EB
return z ⊕ (z >> 31)
Color Generation:
L = 10 + random() × 85 # Lightness: 10-95
C = random() × 100 # Chroma: 0-100
H = random() × 360 # Hue: 0-360
trit = hue_to_trit(H) # GF(3) mapping
```
## Constants
```ruby
GOLDEN = 0x9E3779B97F4A7C15 # φ⁻¹ × 2⁶⁴
MIX1 = 0xBF58476D1CE4E5B9
MIX2 = 0x94D049BB133111EB
MASK64 = 0xFFFFFFFFFFFFFFFF
```
## MCP Server
The Gay MCP server provides these tools:
| Tool | Description |
|------|-------------|
| `color_at` | Get color at specific index |
| `palette` | Generate N-color palette |
| `golden_thread` | Golden angle spiral |
| `reafference` | Self-recognition loop |
| `loopy_strange` | Generator ≡ Observer |
## Commands
```bash
# Start MCP server
julia --project=@gay -e "using Gay; Gay.serve_mcp()"
# Generate palette
just gay-palette seed=1069 n=12
# Test determinism
just gay-test
```
## API (Ruby)
```ruby
require 'splitmix_ternary'
# Create generator
gen = SplitMixTernary.new(1069)
# Get color at index
color = gen.color_at(42)
# => { L: 45.2, C: 67.8, H: 234.5, trit: -1, index: 42 }
# Generate trits
gen.next_trit # => -1, 0, or +1
# Split for parallelism
child = gen.split(7) # Independent child generator
```
## API (Julia)
```julia
using Gay
# Set seed
Gay.gay_seed(1069)
# Get color
color = Gay.color_at(42)
# Generate palette
palette = Gay.palette(12)
# Golden thread
colors = Gay.golden_thread(steps=10)
```
## API (Python)
```python
from gay import SplitMixTernary, TripartiteStreams
# Create generator
gen = SplitMixTernary(seed=1069)
# Get color at index (returns dict with L, C, H, trit, hex)
color = gen.color_at(42)
# => {'L': 45.2, 'C': 67.8, 'H': 234.5, 'trit': -1, 'index': 42, 'hex': '#2E5FA3'}
# Generate hex color directly
hex_color = gen.hex_at(42) # => '#2E5FA3'
# Generate palette as hex list
palette = gen.palette_hex(n=12)
# => ['#D8267F', '#2CD826', '#4FD826', ...]
# Generate trits
trit = gen.next_trit() # => -1, 0, or +1
# Split for parallelism (deterministic child)
child = gen.split(offset=7)
# Tripartite streams (GF(3) = 0 guaranteed)
streams = TripartiteStreams(seed=1069)
triplet = streams.next_triplet()
# => {'minus': -1, 'ergodic': 0, 'plus': 1, 'gf3_sum': 0, 'conserved': True}
```
## Hex Color Output (#RRGGBB)
Convert OkLCH to hex for CSS/web usage:
```python
def oklch_to_hex(L: float, C: float, H: float) -> str:
"""Convert OkLCH to #RRGGBB hex string."""
import math
# OkLCH -> OkLab
a = C * math.cos(math.radians(H))
b = C * math.sin(math.radians(H))
# OkLab -> Linear RGB (simplified)
l_ = L/100 + 0.3963377774 * a + 0.2158037573 * b
m_ = L/100 - 0.1055613458 * a - 0.0638541728 * b
s_ = L/100 - 0.0894841775 * a - 1.2914855480 * b
l, m, s = l_**3, m_**3, s_**3
r = +4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s
g = -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s
b = -0.0041960863 * l - 0.7034186147 * m + 1.7076147010 * s
# Clamp and convert to 0-255
def to_byte(x): return max(0, min(255, int(x * 255)))
return f"#{to_byte(r):02X}{to_byte(g):02X}{to_byte(b):02X}"
```
## Integration with discrete_backprop
Color learning via gradient-free optimization:
```python
from gay import SplitMixTernary
from discrete_backprop import DiscreteBackprop
class ColorLearner:
"""Learn optimal color sequences via trit-based backprop."""
def __init__(self, seed: int, target_palette: list):
self.gen = SplitMixTernary(seed)
self.target = target_palette
self.backprop = DiscreteBackprop(dims=3) # L, C, H
def loss(self, index: int) -> float:
"""Compute color distance to target."""
color = self.gen.color_at(index)
target = self.target[index % len(self.target)]
return sum((color[k] - target[k])**2 for k in ['L', 'C', 'H'])
def step(self, indices: list) -> dict:
"""Discrete gradient step via trit perturbation."""
losses = [self.loss(i) for i in indices]
# Compute trit-based gradient (Δtrit per dimension)
gradients = self.backprop.discrete_gradient(
params=[self.gen.state],
losses=losses,
perturbation='trit' # Use {-1, 0, +1} perturbations
)
# Chain seed based on gradient direction
direction_trit = sum(g for g in gradients) % 3 - 1 # Map to {-1, 0, +1}
self.gen.chain_seed(direction_trit)
return {
'loss': sum(losses) / len(losses),
'gradient_trit': direction_trit,
'new_seed': hex(self.gen.seed)
}
# Usage
learner = ColorLearner(seed=0x42D, target_palette=[
{'L': 50, 'C': 80, 'H': 30}, # Target warm
{'L': 70, 'C': 60, 'H': 150}, # Target neutral
{'L': 40, 'C': 90, 'H': 240}, # Target cold
])
for epoch in range(100):
result = learner.step(indices=[0, 1, 2])
if result['loss'] < 0.01:
break
```
## Tripartite Streams
Three independent streams with GF(3) = 0:
```ruby
streams = SplitMixTernary::TripartiteStreams.new(seed)
triplet = streams.next_triplet
# => { minus: -1, ergodic: 0, plus: 1, gf3_sum: 0, conserved: true }
```
## Trit Mapping
```
Hue 0-60°, 300-360° → +1 (PLUS, warm)
Hue 60-180° → 0 (ERGODIC, neutral)
Hue 180-300° → -1 (MINUS, cold)
```
## Out-of-Order Proof
```ruby
proof = SplitMixTernary.prove_out_of_order(seed)
# => {
# ordered_equals_reversed: true,
# ordered_equals_shuffled: true,
# proof: "QED: Math is doable out of order"
# }
```
## Integration with Langevin Dynamics (NEW)
Track which colors affect which noise calls in Langevin training:
```julia
# Instrument Langevin noise via color tracking
function instrument_langevin_noise(sde, step_id)
color = color_at(rng, step_id)
noise = randn_from_color(color)
return (color, noise, step_id)
end
# Export audit trail showing cause-effect
audit_log = export_color_trace(
trajectory=sde_solution,
seed=base_seed
)
# Shows: step_47 → color_0xD8267F → noise_0.342 → parameter_update
# Verify GF(3) conservation across trajectory
gf3_check(color_sequence, balance_threshold=0.1)
```
## Integration with Unworld
Colors are derived, not temporal:
```ruby
# Seed chaining
next_seed = Unworld.chain_seed(current_seed, color[:trit])
# Derive color
color = Unworld.derive_color(seed, index)
```
## Example Output
```
╔═══════════════════════════════════════════════════════════════════╗
║ GAY.JL: Deterministic Color Generation ║
╚═══════════════════════════════════════════════════════════════════╝
Seed: 0x42D
─── Palette (12 colors) ───
1: #D8267F (trit=+1)
2: #2CD826 (trit=0)
3: #4FD826 (trit=0)
...
─── Out-of-Order Proof ───
Indices: [1, 5, 10, 20, 50]
Ordered = Reversed: true
Ordered = Shuffled: true
QED: Math is doable out of order
```
---
**Skill Name**: gay-mcp
**Type**: Deterministic Color Generation
**Trit**: +1 (PLUS)
**GF(3)**: Conserved via tripartite streams
**SPI**: Guaranteed (same seed → same output)
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!