Logo refinement — V11
Superseded for the wordmark and motion timing by Logo refinement — V12 (2026-08-07). V12 replaces the synthesised-italic wordmark below with an explicit
skewX(-8deg)oblique and tightens the reveal and Journey timing this page documents. The mark geometry (ring, taper, dot) and everything else on this page — including the reveal/loading/Journey behaviour (single-emit contract, stall watchdog, forward-only loading) — is still current; only the specific timing constants and the wordmark'sitalicstyling are superseded. See V12 for the current numbers.
A refinement pass on the Objectuve mark. Cleans up the geometry, animations, and rendering performance of ObjectuveLogo.vue and ObjectuveLogoJourney.vue, and explores a set of candidate extensions for the brand system.
→ Open the live preview (standalone Vue 3 app — every refinement and every exploration is laid out as a replayable card)
Why
The pre-V11 implementation had six issues that surfaced once the mark was used at multiple sizes and inside animation.
- Taper overlap artifact — the arc path drew the blue gradient over the entire ring including the trailing wedge; the gold polygon was drawn on top of the same pixels. Subpixel AA gaps and gradient bleed showed up at certain scales and during opacity transitions.
- State-swap jump — the component swapped from a dynamic animated SVG to a separate static SVG when reveal finished. Subpixel rasterization differences between the two trees caused a visible jolt.
- Retracting loading spinner — the loop swept clockwise to 270° and then retracted counter-clockwise to 0°. Retracting a progress ring reads as losing progress — incompatible with the action-forward brand voice.
- Heavy
feGaussianBlurfilters in the Journey component caused frame drops on mobile. - RGB color interpolation (via per-frame string concatenation) muddied the blue→gold transition through grey.
- Static geometry treated 24 px and 300 px identically. The hero 10° taper degraded into anti-aliasing mush at favicon scale.
What we did
Geometry — single-path render
The arc path now stops cleanly at the taper's wide edge (a straight radial line). The gold taper attaches into the resulting notch without sharing any pixels with the arc beneath it. The same node tree is used for static, reveal, and loading — there is no v-if branch between an animated and a non-animated SVG, so there is no state-swap jump.
Reveal animation
- Ring fills clockwise to 270° with
easeOutCubic(1200 ms). - Wordmark stays hidden during the ring fill (the regression you caught — fixed).
- 80 ms after the ring locks, the gold dot pops in with spring overshoot.
- The wordmark unhides and animates in with a matching spring curve at the same instant — no flash between the unhide and the animation start.
Loading animation — forward only
The retraction is gone. Head sweeps to 270°, holds briefly, then the tail catches up to the head — the ring shortens by advancing its trailing edge clockwise, not by retreating its leading edge counter-clockwise. Every frame is forward; the ring never moves backward.
Taper geometry — hero & compact
| Mode | Offset | Curve | Use |
|---|---|---|---|
| Hero (default) | 10° | Concave (quadratic bezier) | ≥56 px — auth, splash, marketing, sidebar header |
| Compact | 14° | Straight | <40 px — favicon, nav, tab bar, app icon |
Selectable via the new compact prop. The wider straight compact shape survives the rasterizer at small sizes where 10° of angular span is only ~4 rendered pixels.
<ObjectuveLogo variant="integrated" /> <!-- hero default -->
<ObjectuveLogo variant="icon" :compact="true" /> <!-- below ~40 px -->Journey animation
- Premium burst — 16 dashed gold rays, two concentric expanding wave rings, soft radial bloom underneath the ring.
- Dot ignition — the taper now ignites the gold dot on impact instead of fading it: a sharp white flash plus gold particles fanning out.
- HSL color interpolation — blue → gold travels through cyan → green → yellow → gold (the warm route) instead of RGB-blending through grey. HSL strings cached and quantized.
- GPU-accelerated glow — replaced the heavy
feGaussianBlurwith a CSSdrop-shadowfilter applied via a class. Only engaged during the radiating phase; idle and reveal incur zero filter cost.
Exploratory candidates — what's shipped, what's still a proposal
The preview ships 13 candidate extensions. Three are now in production alongside the V11 refinement; ten remain proofs in the preview, waiting for sign-off.
Now in production
| Candidate | Where to find it | Production hook |
|---|---|---|
| Hero / compact taper | compact prop | Pick compact: true below ~40 px |
| F4 — Reveal breath | animate="reveal-breath" | Adds a 520 ms breath beat between the ring lock and the dot pop |
| F6 — Coach thinking | animate="coach-thinking" | Drop-in replacement for IonSpinner during Coach generation |
| F12 — Onboarding origin | animate="origin" | First-launch story: dot ignites → spark arcs to 12 o'clock → ring sweeps → wordmark settles |
Still proposals
| § | Name | What it needs |
|---|---|---|
| F10 | Day-complete beat | Wire to end-of-day check-in completion |
| G-A | Streak fire ladder | streakDays prop driving 5 tiers of dot embellishment |
| G-B | Streak break recovery | state="broken" plays the sympathetic-mourning sequence |
| G-C | Coach voice | Audio-reactive ring tied to TTS AnalyserNode.getFloatTimeDomainData() |
| H-D | Live session timer | New <ObjectuveLogoTimer> component for Pomodoro-style sessions |
| H-E | Session settle | animate="settle" mode for the app-close transition |
See the live preview — every card has a replay button.
Interruption & resume behaviour
The mark has exactly two resting states: collapsed-at-start (nothing drawn) and full-at-rest (270° ring, taper, dot, and wordmark all fully in). No intermediate combination — a collapsed ring with the dot or wordmark visible — is a reachable rest state.
This applies to the three terminating reveal modes: reveal, reveal-breath, and origin. loading and coach-thinking loop indefinitely and never arm the fail-safe described below.
If a reveal / reveal-breath / origin cycle is interrupted — a stalled requestAnimationFrame timeline, an auto-theme flip mid-animation, or the webview being backgrounded and resumed mid-reveal — the component snaps straight to full-at-rest rather than staying wherever the interruption caught it. A stall watchdog (armed at 2× the expected cycle duration) and a visibilitychange handler both trigger this; an auto-theme change no longer restarts (and re-collapses) a reveal that's already in flight.
animationComplete is guaranteed to fire exactly once per cycle, whether the cycle finished normally or was settled to rest by the fail-safe. SignIn.vue gates the entire sign-in form's visibility on this event — so an interrupted reveal can no longer leave the sign-in form hidden behind a broken logo.
API
<ObjectuveLogo>
interface Props {
variant?: 'integrated' | 'icon'; // default 'integrated'
theme?: 'auto' | 'light' | 'dark'; // default 'auto'
animate?:
| 'none'
| 'reveal' // V11 reveal
| 'reveal-breath' // F4: V11 + 520 ms breath beat
| 'loading' // forward-only spinner
| 'coach-thinking' // F6: looping gold→coach-purple dot pulse
| 'origin'; // F12: first-launch story (~2.95 s)
compact?: boolean; // set true for <40 px contexts
}
defineEmits<{ animationComplete: [] }>();<ObjectuveLogoJourney>
No API change in V11.
interface Props {
size?: number; // default 160
variant?: 'light' | 'dark'; // default 'light'
autoplay?: boolean; // default true
loop?: boolean; // default false
}
defineEmits<{ complete: [] }>();
defineExpose({ play }); // imperative replay handleVerification
The preview is the canonical verification surface — it loads Vue 3 from a CDN and runs the same algorithms as the production components.
- Section A — geometry before/after, with the path math annotated.
- Section B — reveal in light + dark.
- Section C — loading at 96 px and 48 px, light + dark.
- Section D — journey in light + dark, plus a size sweep.
- Section E — static sizes from 24 px (compact) to 300 px (hero).
- Sections F–I — exploratory candidates.
Last updated: 2026-09-11 (v4.8.3) — footer currency fix (OBJ-3649); no content change since 2026-08-06's V12-supersession note above.