Two ANSI bugs, both found by running fastfetch rather than by reading the parser, and both invisible to anything that spells its escapes out in full. ESC[m with no parameters means ESC[0m. ECMA-48 is explicit that an omitted parameter takes its default and SGR's default is 0, and sgr() iterated its parameter list -- which is empty in exactly that case, so the loop body never ran and the reset was silently dropped. Programs emit the bare form constantly. fastfetch writes "\x1b[32m1%\x1b[m", so everything after the first coloured character stayed green forever. With a background colour it is much worse: its palette swatch sets a white background and resets, the reset did nothing, and the console went white-on-white and stayed there -- filling the screen with white rectangles as it scrolled, which looks like a corrupted framebuffer rather than one missing branch. OSC sequences were not a state at all, so ESC ] fell through and the payload printed as text: a hyperlinked path arrived as "Disk (]8;;file:///\]8;;\)". Nothing here acts on an operating-system command -- there is no window title and no hyperlink to follow -- but *discarding* one is not optional, because the alternative is printing somebody's URL into the middle of their output. ESC \ ends it, and an ESC followed by anything else is handed back to the escape state rather than eaten, so a malformed OSC does not swallow the sequence after it. Verified by screendumping the framebuffer after two consecutive fastfetch runs: identical output both times, near-white coverage down from most of the screen to 2% (the palette swatch's own white cell), and the disk line reading "Disk (/)". Also installs docs/branding/Ascii/ascii_50.txt as /usr/share/schos/logo.txt -- Shift as characters, at the width that leaves room for an info block on an 80-column console. Installed from the branding directory rather than copied into sysroot by hand, so there is one source. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VQ7Qx8E1q1M1bbCq8QLHS2
216 lines
9.2 KiB
Markdown
216 lines
9.2 KiB
Markdown
# Branding
|
||
|
||
Three marks, three different jobs. They are not interchangeable and the
|
||
difference is not stylistic.
|
||
|
||
| | | |
|
||
|---|---|---|
|
||
| **Shift** | *the logo* | An abstract mark. Non-human, non-animal. Signs the system. |
|
||
| **Guru** | *the icon* | A pictogram. Denotes one state. Has a face; has no body. |
|
||
| **SchCotie** | *the mascot* | A character. Has a body, poses and expressions. |
|
||
|
||
The distinction that decides everything else: **a mascot has to be able to
|
||
do things.** An icon works once, at one size, in one state. A character has to
|
||
work confused, pleased, asleep and from behind — which is why it costs more and
|
||
why it is drawn last.
|
||
|
||
---
|
||
|
||
## The one constraint everything answers to
|
||
|
||
**The kernel draws its mark as a 128×128 single-channel coverage mask.**
|
||
`include/logo.h` holds no colour at all — two pixels per byte, sixteen levels of
|
||
ink — and the kernel composites it in whatever `include/theme.h` says.
|
||
|
||
So any mark that will end up there has to survive as **a solid shape in one
|
||
colour at 128 px, and be recognisable at 24**. That rules out hairlines, thin
|
||
rings and anything that depends on a gradient to read. The mark this replaced
|
||
failed on all three counts.
|
||
|
||
Colour is therefore the *last* decision, never the first. Design the silhouette,
|
||
then colour it.
|
||
|
||
---
|
||
|
||
## Shift — the logo
|
||
|
||
`shift.svg`
|
||
|
||
Three slabs, displaced: the layer diagram in
|
||
[../architecture/README.md](../architecture/README.md) as a solid object, and
|
||
the kernel's name (**SchIFT**) as a shape.
|
||
|
||
- **Any colour.** This is a fact about the pipeline, not a preference — the
|
||
coverage mask carries none, so the loader draws it in metal and the kernel in
|
||
the theme accent, from the same bytes.
|
||
- **With or without a wordmark.** Set "SchOS" beside it in **Roboto Bold**,
|
||
which is already in the tree (`ports/Roboto`), already Apache-2.0, and already
|
||
in `NOTICE`.
|
||
- Non-human and non-animal, permanently. The character work belongs to
|
||
SchCotie; a logo that starts growing a face has taken the mascot's job.
|
||
|
||
## Guru — the icon
|
||
|
||
`guru.svg`
|
||
|
||
The crash face. Mythic rather than cartoon — closer to a temple carving than a
|
||
character — square or nearly so, with an expression that stays in the
|
||
`:(` / `:|` register.
|
||
|
||
**Purple, and only purple, and only here.** `theme.h` states the rule it
|
||
enforces:
|
||
|
||
> normal states are calm and dark; only failure is loud. PSOGM keeps the
|
||
> full-bleed purple entirely to itself, which is what makes it mean something.
|
||
|
||
That purple is `PSOGM_BG #4B1D9A`, and it is deliberately **not** the accent
|
||
`#7C5CFF`. If Guru ever appears in accent violet on a splash, a sticker or a
|
||
README header, the deep purple stops meaning *the machine stopped* — and it is
|
||
the only colour in the system that means anything at all.
|
||
|
||
So: Guru does not leave the crash screen.
|
||
|
||
## SchCotie — the mascot
|
||
|
||
*Not drawn yet.*
|
||
|
||
A daemon: **the process that works while nobody is watching.** The horns are a
|
||
pun on the word; the meaning is the background job that keeps running after you
|
||
have walked away — which is `schinit` supervising, restarting what dies, awake
|
||
at 3am. Patient and watchful rather than mischievous.
|
||
|
||
Horns carry **X** — POSIX, Unix, X11 — one substitution reading three ways.
|
||
|
||
Two constraints that follow from the section above. A thin X is two diagonal
|
||
strokes and dissolves at small sizes, so it wants to be **solid wedges with the
|
||
X notched out as negative space**: the horn silhouette survives downscaling and
|
||
the X appears as you get closer. And it needs a **turnaround** — front, side,
|
||
three-quarter, matching heights on shared construction lines — because a
|
||
character drawn once at one angle only ever works at that angle.
|
||
|
||
### The licensing point, which is not optional here
|
||
|
||
**The BSD daemon is copyrighted.** Marshall Kirk McKusick holds it and the terms
|
||
are not a free licence. A character that reads as "Beastie, but purple, with X
|
||
horns" is a derivative-work argument, and this mark would be in every image
|
||
SchOS ships, beside a `NOTICE` file this project has been careful about.
|
||
|
||
The concept is not the problem. A daemon is a Greek *daimon* and a Unix
|
||
background process — neither is ownable. What belongs to Beastie is the
|
||
execution: the pitchfork, the sneakers, that red, that face, that pose. Horns, a
|
||
tail and a small imp are generic and thousands of years old.
|
||
|
||
**Draw from the idea. Do not have a picture of Beastie open while you do it.**
|
||
|
||
---
|
||
|
||
## Colour
|
||
|
||
From `include/theme.h`, which is the source of truth. Nothing here restates a
|
||
value it does not already define.
|
||
|
||
| | | |
|
||
|---|---|---|
|
||
| `SCH_BG` | `#0C0E13` | Ground. Near-black with a blue cast, because pure black reads as "switched off". |
|
||
| `SCH_FG` | `#E6E8EC` | Primary text |
|
||
| `SCH_DIM` | `#707784` | Secondary |
|
||
| `SCH_ACCENT` | `#7C5CFF` | The one accent. Shift, SchCotie, anything calm. |
|
||
| `PSOGM_BG` | `#4B1D9A` | **Failure only.** Guru's ground and nothing else's. |
|
||
|
||
## File formats
|
||
|
||
**SVG, or PNG at high resolution with no lossy compression.** Nothing else.
|
||
|
||
No JPEG anywhere — a mark is flat colour with hard edges, which is the exact
|
||
case JPEG is worst at, and the ringing it leaves around an edge is permanent.
|
||
No screenshots of marks. No re-exports of re-exports: go back to the SVG.
|
||
|
||
**SVG is the source of truth for every mark.** A raster is something generated
|
||
from it, never edited.
|
||
|
||
## The mark as characters
|
||
|
||
`Ascii/ascii_{50,68,100,150}.txt` — Shift rendered in text at four widths, named
|
||
for the column count they fit in.
|
||
|
||
`make` installs the 50-column one as `/usr/share/schos/logo.txt`, because 50 is
|
||
what leaves room for an info block beside it on an 80-column console:
|
||
|
||
```sh
|
||
fastfetch --file-raw /usr/share/schos/logo.txt
|
||
```
|
||
|
||
Installed from here rather than copied into `sysroot/` by hand, so there is one
|
||
source and the build keeps them in step.
|
||
|
||
These are a *rendering* of the mark, not a second mark. If Shift changes they
|
||
are regenerated from it; they are not edited to taste, or the two drift and the
|
||
text one wins by being the one people see in a terminal.
|
||
|
||
## What is in here, and why a raster is committed
|
||
|
||
```
|
||
shift.svg the logo, in colour
|
||
shift-mask.svg the same geometry in greys -- see below
|
||
shift-mask.png rasterised from it, committed on purpose
|
||
uberblock.svg SchFS
|
||
guru.svg the crash icon
|
||
superseded-*.png the old wordmark, kept for reference only
|
||
```
|
||
|
||
The pipeline is three stages:
|
||
|
||
```
|
||
shift-mask.svg --(inkscape)--> shift-mask.png --(make logo)--> include/logo.h
|
||
```
|
||
|
||
**Both intermediates are committed, and that is deliberate.** `inkscape` is not
|
||
a build prerequisite — see [../guides/building.md](../guides/building.md) — so a
|
||
build that required a vector rasteriser would stop working on most hosts for the
|
||
sake of a file that changes about once a year. The PNG is regenerated by hand
|
||
when the SVG changes, and `make logo` turns it into the header.
|
||
|
||
### Why the mask is a separate file from the logo
|
||
|
||
`tools/python/mklogo.py` reads ink as `(255 - luminance) * alpha`, so **tones
|
||
survive as coverage** rather than being flattened — and the relationship
|
||
inverts: *darkest here is brightest on screen*. Copying the violet fills from
|
||
`shift.svg` would light the object from below.
|
||
|
||
So `shift-mask.svg` is the same geometry in greys chosen for how the mask reads.
|
||
Two files sharing one geometry is a drift hazard; the `<desc>` in both says so.
|
||
If either is edited, edit both.
|
||
|
||
---
|
||
|
||
## Where each mark is actually drawn
|
||
|
||
| | |
|
||
|---|---|
|
||
| Loader splash | Shift, from `include/logo.h`, shaded per row by `metal()` in `boot/common/ui.c` — silver, not accent. |
|
||
| Kernel console / early boot | Shift, same mask, composited flat in a theme colour by `gfx_draw_logo`. |
|
||
| PSOGM | Guru, drawn from primitives by `draw_guru()` in `kernel/core/panic.c`. Never a bitmap: it scales with the display and costs nothing in the kernel image. |
|
||
| Serial crash report | `:(`, as text. Guru cannot be drawn in ASCII, and a mood marker in a log is not the icon. |
|
||
| SchFS | **Nowhere yet.** `uberblock.svg` has no consumer; it is waiting for `projects/schfs-linux/` to have a README worth heading. |
|
||
|
||
One trap, since it has already been stepped in: `boot/common/ui.c` includes
|
||
`logo.h`, `theme.h` and `font.h`, and the Makefile rule for the loader did not
|
||
list them. A new logo therefore did not rebuild the loader — `make` reported
|
||
nothing to do and the splash kept drawing a mask compiled months earlier. The
|
||
kernel half never showed the problem because those objects are built with
|
||
`-MD -MP` and track their own headers. **Changing anything in here means the
|
||
loader must actually relink**, and that needs `clang` and `lld-link`.
|
||
|
||
## What this does not cover
|
||
|
||
- **No trademark position.** These are marks the project uses, not marks anyone
|
||
has registered or defended.
|
||
- **No usage rules for third parties** — nothing says what someone else may do
|
||
with them. Worth writing before anything is published.
|
||
- **SchCotie does not exist.** Everything above it is a brief, not a
|
||
description.
|
||
- **Guru is drawn but not wired in.** `panic.c` still renders `:(` from
|
||
primitives, and there is a real argument for keeping it — see the note in that
|
||
file about being "legible as a mood without being a picture of anything".
|
||
- **No wordmark lockup is specified.** "Roboto Bold beside it" is not a spacing
|
||
rule, a size ratio or a clear-space margin, and it will want to be.
|