Skip to content

Synthesizer 7 axes

Laith0003 edited this page May 28, 2026 · 1 revision

The 7-Axis Synthesizer

The v3.0 flagship. Maps any brief to a fresh, deterministic design language by computing 7 continuous axis values and mixing brand vocabulary along them.

The axes

Axis Range Derived from Compiles to
warmth 0=cold ↔ 1=warm industry seed + tone tags RGB warmth shift on palette
contrast 0=flat ↔ 1=dramatic tone tags + attention need Modular scale ratio (1.200/1.250/1.333), weight curve
density 0=airy ↔ 1=dense data richness, must-have Spacing base (4/6/8/12px), line-height
geometry 0=sharp ↔ 1=soft emotional register Radius scale (2-18px), corner style
formality 0=playful ↔ 1=corporate audience Tracking, motion dampening, spacing override
motion 0=still ↔ 1=kinetic interactivity Animation timing (140-220ms), curve pick
type_personality 0=geometric ↔ 1=humanist voice Display family bias, weight curve

All seven are continuous floats in [0.0, 1.0]. Same brief → same values, every time. Pure Python math, no randomness, no LLM.

How a brief maps to axes

from engine.synthesizer import compute_axes

axes = compute_axes(brief)
# AxisValues(warmth=0.35, contrast=0.55, density=0.6, geometry=0.4,
#            formality=0.75, motion=0.45, type_personality=0.4)

Three-step derivation:

  1. Industry seed — 17 documented industries each have a 7-axis seed (fintech-payments, gaming, luxury, healthcare, etc.). Unknown industry → neutral 0.5 across the board.
  2. Tone nudges — 35+ documented tone tags push axes by ±0.10 to ±0.30 (warm → +0.20 warmth; bold → +0.25 contrast; minimal → −0.30 density).
  3. Forbidden clampsforbidden=["playful"] clamps formality to [0.6, 1.0]. forbidden=["dense"] clamps density to [0.0, 0.55].

All values clamped to [0.0, 1.0] after each step.

How axes compile to tokens

Palette

# Pick 8 axis-matching brand exemplars
# Distill palette anchors (canvas, ink, primary, accent)
# Weighted RGB mix + warmth-shift

The warmth axis pushes the mixed RGB warmer (more R+G) or cooler (more B). Distance from 0.5 sets intensity. Max shift ±18 units.

Spacing

Uses interactions.spacing_base_for(axes) for the conflict resolution:

density formality base px Why
dense (>0.65) any 4 Bloomberg-school: density wins
airy (<0.4) formal (>0.7) 12 Luxury: formality wins, breathing room
airy (<0.4) casual 8 Standard airy
balanced any 6 Mid-density default

Scale array follows Fibonacci-ish growth from the base.

Radius

Uses interactions.radius_base_px_for(axes, vocab_mean):

  • geometry < 0.3 + formality > 0.72px (sharp + corporate, NYT/Bloomberg)
  • geometry > 0.7 + formality < 0.418px (soft + playful, Glossier)
  • Otherwise weighted blend: 50% axis target + 30% vocab mean + 20% formality dampener

Motion

  • base_ms = int(220 - 80 * motion) — kinetic = snappier
  • High motion + corporate → +25% dampener (corporate slows kinetic axes)
  • Curve picked by motion axis: >0.7 spring-soft, >0.4 ease-cinema, else standard

Typography

Modular ratio from contrast: 1.200 / 1.250 / 1.333. 9-step ladder anchored at body=16px.

Weight curve from type_personality + contrast:

  • Geometric + loud → display 800
  • Geometric + quiet → display 700
  • Humanist + loud → display 700
  • Humanist + quiet → display 600
  • Body always 400; caption 500 (legibility)

Tracking: display tighter (−0.015 to −0.025em), caption wider (+0.04 to +0.06em). Formality tilts.

Line-heights: hero 1.02, display 1.05, h1 1.08, body 1.50-1.65 (density inverse), caption 1.45.

Three modes

Auto-dispatched based on what's in the brief:

# Mode 1: strict_brand — 100% brand verbatim
brief.reference_brands = ["stripe"]
brief.strict = True
# → SynthesizedSystem(mode="strict_brand", anchor_brand_id="stripe", ...)

# Mode 2: brand_anchor — 70/30
brief.reference_brands = ["stripe"]
# → SynthesizedSystem(mode="brand_anchor", anchor_brand_id="stripe", ...)

# Mode 3: pure_synthesis — infinity space
# (no reference_brands)
# → SynthesizedSystem(mode="pure_synthesis", ...)

In brand_anchor mode, the named brand is double-counted in the vocabulary distillation pool (so its weight is roughly 2× any other brand's, ~70% of the mixed result). The other 4 brands come from pick_exemplars_by_axes matching the brief's axes.

In pure_synthesis mode, 8 axis-matching brands are pulled and weighted equally.

Determinism guarantees

  • Same brief → same axes (no randomness, no clock)
  • Same axes → same exemplar set (deterministic sort by distance, tie-break by brand id alphabetical)
  • Same vocabulary → same output tokens (pure math, no LLM)
  • Same output → same evaluation (deterministic scorers)

Reproducible across machines, filesystems, Python versions.

Public API

from engine import synthesize, compute_axes
from engine.synthesizer.interactions import (
    spacing_base_for, radius_base_px_for,
    motion_timing_for, accent_register_for,
)

Related

Clone this wiki locally