Skip to content
Documentation
Browse the library

LOGO.md · Simplified edition

On this page

PageHare logo — the pagehole system (binding)

Status: v1.1 — refined marks and four approved motion states. These brand rules apply to agents and people. If a request conflicts with a rule, stop and explain the conflict before making the change. Informative history lives in docs/design/brand-history.md (read-only).

The idea

One shape: a hole (an ellipse) with a hare's ears rising from it. The hare lives in the page. Everything in the system is a state of that one hole — emerging, spiraling, missed, or diving. The hole ellipse is the same shape in every mark; only what comes out of it changes.

Where the assets live

WhatWhere
Canonical currentColor SVG sourcespackages/app/src/lib/brand/*.svg
Mark component (inlines the sources)packages/app/src/lib/brand/BrandMark.svelte
Header lockup (responsive)packages/app/src/lib/brand/BrandLockup.svelte
Mode-1 tenant attributionpackages/app/src/lib/brand/PoweredBy.svelte
Motion family (CSS-only SVG)packages/app/src/lib/brand/BrandMotion.svelte
Accessible loading wrapperpackages/app/src/lib/components/PageholeLoader.svelte
Loader consumer rulespackages/app/src/lib/components/useDelayedLoading.svelte.ts
Favicons / PWA / apple-touchpackages/app/static/ (wired in app.html via %ph.icons%)
Empty-state artpackages/app/src/lib/brand/empty-state.svg (mark E)
Non-served exports (avatars, banners, motion)brand/exports/
Email lockupspackages/app/src/lib/email/assets/
Retired previous brandbrand/retired/

Usage, asset regeneration, and verification are documented in docs/design/brand-assets.md. The /styleguide brand section renders the actual components, including replayable one-shot motion.

Marks use currentColor. Include their SVG directly in Svelte components at build time. Do not import them as base64 or send SVG strings inside JavaScript. They use the surrounding text color, so they follow the active theme.

Variant table

VariantNameWhat it isUse for
AmasterEars rising from the hole, inside the page frameApp icon ≥ 32px, splash, hero
BbareEars + hole, no frameSmall sizes (< 32px), lockup fallback, powered-by, dense UI
DspiralConcentric ripples around the holeOccasional decoration only; never favicon, app icon, or status
EmissedHole with faint miss-arcs, ear half-sunk404 and empty states — "you fell too far"
—lockupMark + "PageHare" wordmark, one SVGHeader/nav when there is room

There is no static dive mark. The dive (ears sink, ripple, pop back) exists only as motion — BrandMotion, its PageholeLoader wrapper, and the brand/exports/motion/ files. Never render a frozen dive pose.

Handoff rules

  • Lockup ↔ mark B at 120px. The full lockup shows when it has ≥ 120px of inline space; below that it collapses to the bare mark B. Implemented as a container query in BrandLockup.svelte — it reacts to the space it is given, not the viewport.

  • Mark A ↔ mark B at 32px. The framed master mark loses legibility below 32px; hand off to the bare mark B at small sizes (Logo.svelte).

  • Favicons use B; app icons use A. Browser tabs must remain legible at their smallest size, so the scalable favicon and 16px raster use B; 32px and 48px raster favicons use A. The ICO contains those same raster sizes. PWA and apple-touch icons use A with safe padding. Never use the spiral D on either surface.

  • Keep the recognition cues. The refined A uses a lighter page frame and a modestly larger hare-and-hole group; canonical SVG sources own the geometry. Keep the bare B silhouette, serif wordmark, and existing theme palette.

  • Social introductions use the recognizable logo and name. Banners show the PageHare lockup and a short product promise, placed clear of common profile-image crops. E is supporting state art, not the brand introduction.

  • Dive is motion-only. See above.

  • Mode 1 (tenant custom domains): tenant surfaces get mark B "powered by" only. PageHare favicons and OG marks NEVER render on a tenant domain — the hooks.server.ts tenant branch serves the tenant's favicon or none (renderBrandHead in server/theme.ts).

Motion family

BrandMotion animates the existing ears around a fixed hole. Its SVG and CSS ship without a player, animation library, raster frames, or animation JavaScript. The hole's proportions stay canonical: the ears, ripple, and brief accent strokes carry the gesture; the hole itself does not stretch or bounce.

VariantNameUsePlayback and resting pose
diveQuiet diveDefault loading1.8s loop; sinks, makes one ripple, returns to B
earsCurious earsSmaller or quieter loading1.8s loop; ear flicks while the silhouette remains visible
missedWrong burrow404 and empty states2.8s once, then rests as E
successA small hooraySuccessful publishing1.4s once, then rests as B
  • One-shot means once per displayed state. Do not loop 404, empty-state, or success motion. The styleguide has an explicit replay control for review.

  • Success follows the completed publish. Never celebrate autosave, a pending request, or a failed publish. Preserve the ordinary text confirmation.

  • Motion carries no essential information. Use visible state text and appropriate status semantics alongside it. BrandMotion is always decorative; PageholeLoader supplies the accessible loading announcement.

  • Reduced motion is a deliberate resting pose. Disable all animation and show B for loading/success or E for missed. Do not freeze a diving frame or require JavaScript to reach the resting state.

  • Small brand gestures are the scoped exception to DS §7. The approved dive return and success stretch may overshoot modestly. Ordinary UI motion remains restrained; this is not permission to bounce controls or page content.

  • Reader output remains zero presentation JS. A CSS-only missed state may accompany an empty archive or reader error; it does not enable hydration.

Loader UX (consumer rules)

PageholeLoader accepts dive (default) or ears. The loader is a dumb visual; the timing rules live in useDelayedLoading:

  • Don't show for loads shorter than 300ms — a flash of the dive is worse than no loader.

  • Once shown, hold for at least one full cycle (~1.8s) — a half-swallowed hare reads as a glitch.

  • prefers-reduced-motion is honored inside BrandMotion: static B, no dive, ear flick, or ripple.

Themes

The brand ships three themes (repo packages/app/src/lib/styles/): Warren (default — near-white canvas, forest-green accent, baked into tokens.css), Burrow (terracotta) and Twilight (indigo) as [data-theme] files. Themes reassign Tier-1 tokens only; because marks are currentColor, they recolor for free. AA is enforced in both modes by scripts/check-theme-contrast.mjs.

The cold-read ritual (before shipping any new or edited mark)

One person, zero context, three checks: squint (does it still read as a hare in a hole?), upside-down (does the silhouette hold?), and at 24px (is it legible as a favicon?). If any fails, it is not ready.