Anton Indicator

Orbit · Morph — Implementation Guide

A single-component thinking indicator: a satellite orbits a center that morphs through chaos → pyramid → dot → cube while the AI is working, then resolves to a futurist A when done. Vanilla HTML, CSS, and a small JS animator. No frameworks, no build step.


Preview

Light · thinking
Dark · thinking

States

The component takes one of three states: idle, thinking, done. Idle shows just the moon orbiting a faded ring (use it as a presence cue when Anton is awake but waiting). Thinking runs the full morph cycle. Done freezes into the futurist A with a confirming ring.

idle
thinking
done
idle
thinking
done

Sizes

The indicator is a scalable SVG. Set its rendered size with the --om-size CSS variable (defaults to 18px). Recommended sizes: 16–18px inline next to text, 24–32px in compact UI affordances, 72–200px+ for hero/loading states.

16px
18px
24px
32px
48px
72px

Color tokens

Two themes only. The accent is the only animated color; the orbit ring sits at low opacity in the faded color.

Light
  • ink   #0E0F10
  • faded   #6B6F73
  • accent   #1F9CB0
Dark
  • ink   #F2F6FF
  • faded   #8A97AE
  • accent   rgb(34 211 238)

Animation spec

Cycle

The thinking state runs two clocks in lockstep:

Geometry

All paths are authored in a 0 0 24 24 viewBox so the indicator scales cleanly to any size. Center is (12, 12). Orbit radius is 8.5. Pyramid + cube rotate to "face" the satellite — they share the orbit angle so the composition feels physically connected.


HTML

Drop a span anywhere. Set theme + state via data attributes; size via the --om-size CSS variable. The animator script (below) will fill in the SVG on load and on attribute changes.

<span class="orbit-morph"
      data-theme="light"     <!-- light | dark -->
      data-state="thinking"  <!-- idle | thinking | done -->
      style="--om-size: 24px"></span>

To switch states at runtime, just toggle the attribute:

const el = document.querySelector('.orbit-morph');
el.dataset.state = 'thinking';   // start working
// …later…
el.dataset.state = 'done';       // resolve to the A

CSS

Three rules. The dark-theme glow is a CSS filter so it runs on the GPU and scales with size.

/* size variable + base layout */
.orbit-morph { display: inline-block; }

/* dark-theme accent glow when active */
.orbit-morph[data-theme="dark"][data-state="thinking"],
.orbit-morph[data-theme="dark"][data-state="done"] {
  filter: drop-shadow(0 0 calc(var(--om-size, 18px) * 0.18) rgba(34, 211, 238, 0.55));
}

/* idle is quieter */
.orbit-morph[data-state="idle"] svg { opacity: 0.7; }

JS animator

One requestAnimationFrame loop per indicator. The SVG is rebuilt each frame from the current (angle, phase). The full implementation is below — drop it in a <script> tag at the end of the page (it auto-mounts every .orbit-morph on the page and watches for attribute changes).

Note: the same script is what's powering the live previews on this page — view source to inspect.


Files

Everything you need is in this single HTML file. Copy the three sections (HTML markup, CSS rule block, and the <script> at the end) into your app. No npm install. No external assets.