Files
lanspread/design/design_reference/logo/INTEGRATION.md
T
2026-06-20 19:49:42 +02:00

150 lines
6.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# SoftLAN — Logo handoff
The SoftLAN mark is a pixelated **“S”** (5×5 grid) that, at rest, is a static
icon — but periodically and on hover it **comes alive**: it dissolves into a
single segment that slithers across the board like the game *Snake*, then
re-lays itself back into the S. Two shorter “glitch” flickers add variety.
This folder is everything an engineer/agent needs to ship it.
```
logo_handoff/
├── pixel-live.jsx ← the live React component (the deliverable)
├── demo.html ← open in a browser to see it in motion + in context
├── INTEGRATION.md ← this file
└── assets/
├── softlan-mark.svg static S, fill="currentColor" (inline use)
├── softlan-mark-blue.svg static S, fixed #3b82f6 (img/favicon use)
├── softlan-tile.svg rounded app-icon tile, gradient + white S
└── favicon.svg = tile (drop-in favicon)
```
---
## 1. The live component — `pixel-live.jsx`
A single React component, `LiveLogo`. No build step assumed in the demo (its
loaded via Babel-in-browser), but the source is plain JSX — drop it into your
normal React/TS toolchain and it compiles as-is.
### Props
| prop | type | default | notes |
|-------------|----------|-------------|-------|
| `accent` | string | `#3b82f6` | the S color (any CSS color). Wire this to your theme accent. |
| `size` | number | `140` | rendered width/height in px (its a square SVG). |
| `idleAuto` | boolean | `true` | when true, plays a random trick by itself every `idleMin``idleMax` ms. |
| `idleMin` | number | `5000` | min ms between idle auto-plays. |
| `idleMax` | number | `11000` | max ms between idle auto-plays. |
### Behavior (built in)
- **Rest:** renders the static pixel S in `accent`.
- **Hover:** plays a random trick (snake-weighted).
- **Click:** plays the snake trick.
- **Idle:** if `idleAuto`, fires a random trick on a 511s jitter — but only
while the tab is visible (`document.hidden` guard), so background tabs stay quiet.
- It never overlaps plays (a `playing` guard ignores triggers mid-animation).
### Imperative API (ref)
```jsx
const logo = useRef(null);
// ...
<LiveLogo ref={logo} accent="#3b82f6" size={32} />
// trigger a specific trick on demand:
logo.current.play('snake'); // 'snake' | 'rgb' | 'glitch'
logo.current.isPlaying(); // boolean
```
### Tricks
- `snake` (~2.6s) — the headline animation. S → slither across the 5×5 board → S.
- `rgb` (~1.35s) — chromatic-aberration split that settles back to clean.
- `glitch` (~1.1s) — rows tear/kick sideways, then snap back.
Edit the `POOL` array near the bottom of the file to change which tricks the
random picker uses (and their weighting), and `TRICK_DUR` to retune durations.
---
## 2. Wiring it into the launcher
The current brand mark in `launcher.jsx` is a placeholder div:
```jsx
// BEFORE — both the 'single' and 'two' topbar variants:
<div className="brand-mark" style={{ background: accent }}>S</div>
```
Replace each with the live component:
```jsx
// AFTER:
<LiveLogo accent={accent} size={28} />
```
- Pass the existing `accent` tweak straight through — the mark recolors live.
- `size={28}` matches the current 28px brand-mark box; adjust to taste.
- Drop the old `.brand-mark` background/letter CSS (the SVG is self-contained).
- The component is small and animates only on hover/idle, so its fine to mount
one instance per topbar. If you want the whole header to react to a single
event, share one `ref` and call `.play()`.
Import at the top of the file (or via your bundler):
```jsx
import { LiveLogo } from './pixel-live'; // if you convert exports to ES modules
```
The file currently attaches `LiveLogo` to `window` for the no-build demo —
swap the final `Object.assign(window, …)` line for `export { LiveLogo }` in a
module build.
---
## 3. Static assets (`assets/`)
For places that must be static — favicons, OS app icons, store listings,
loading splash, OG images, anywhere JS isnt running:
- **`softlan-tile.svg`** — the rounded app-icon tile (gradient + white S). Use
this for the favicon, dock/taskbar icon, and installer art. `favicon.svg` is
an identical copy for convenient `<link rel="icon">`.
- **`softlan-mark-blue.svg`** — just the S in brand blue, transparent bg. Use in
`<img>` tags and anywhere you need a fixed color.
- **`softlan-mark.svg`** — the S with `fill="currentColor"`. **Only inherits
color when inlined into the DOM** (inline `<svg>` or an SVG-as-component); via
`<img src>` it wont pick up `currentColor`. Best for inline React/JSX use
where you want it to follow text/theme color.
Geometry note: all static marks use the exact same grid as the live component
(viewBox `0 0 100 100`, cell 17, offset 7.5, gap 2.4, radius 3), so the static
and animated S are pixel-identical — no jump when the live one mounts.
### Generating raster PNGs (if your pipeline needs them)
```bash
# requires librsvg (rsvg-convert) or Inkscape
rsvg-convert -w 512 -h 512 assets/softlan-tile.svg > icon-512.png
rsvg-convert -w 256 -h 256 assets/softlan-tile.svg > icon-256.png
rsvg-convert -w 32 -h 32 assets/favicon.svg > favicon-32.png
```
---
## 4. Accessibility & motion
- The static SVGs carry `role="img"` + `aria-label="SoftLAN"`. Give the live
component an accessible label in its host (e.g. wrap with `aria-label`), since
its decorative motion over a brand mark.
- The idle auto-play already pauses in hidden tabs. If you want to fully respect
`prefers-reduced-motion`, gate the triggers:
```jsx
const reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
<LiveLogo idleAuto={!reduce} /* and skip the hover/click play when reduce */ />
```
At rest its a clean static S, so reduced-motion users simply get the icon.
---
## 5. Quick check
Open `demo.html` in any browser: hover the big mark (or wait), use the trick
buttons, and try the accent swatches. The small mark in the mock top bar is the
same component at `size={30}` — thats exactly how it looks in the launcher.