Relatude Help

Skins

A skin is the interface's look: a value for each design token, the CSS variables (--r-*) that every component is drawn with, for the light theme and for the dark. Shared tokens (corners, fonts, text size, motion) have one value for both. A skin builds on a built-in skin, its base, and holds only the values it changes.

Each user picks a skin under Settings → Appearance, kept in their browser. Until they do, they get the installation's default: the CMS setting Skins.Default, else Default (windows). The built-in skins:

Skins Keys
Default, WCAG (high contrast), Neutral windows, wcag, neutral
Relatude, Relatude BW, Relatude Classic relatude, relatude-bw, relatude-classic
Forest, Winter, Synthwave, with moving backgrounds forest, winter, synthwave
Mac System 1, Windows NT, iOS, WordPress, Optimizely, Paper, Terminal mac, nt, ios, wordpress, optimizely, paper, terminal

The shared token themes says which themes a skin has: both, light or dark. A skin with one theme keeps the interface in it and hides the light and dark switch. A skin inherits themes from its base, so set it to both when you start from a skin with one theme, such as Windows NT.

Making a skin. Administrators open the skin designer with New skin under Settings → Appearance, or with Make a copy to edit in a skin's menu. The skin being designed is in force while the designer is open, so every change shows at once. Basic mode turns a few dials (accent, tint, wallpaper, moving background, transparency, corners, depth, font and motion), each setting many tokens. Advanced mode edits every token and shows the skin as JSON, to copy to another installation. Describe a skin asks an AI for a skin from a sentence, such as warm and calm, sand and terracotta. It uses the database's AI settings, else the Relatude AI service on the license.

Save keeps the skin in the CMS settings (Skins) for every user, and a skin's menu makes it the default or deletes it. The API's skins, skin-save, skin-delete, skin-default, skin-logo and skin-generate commands do the same from code (chapter 17). As JSON, a skin names its base and the values it sets in each theme, by token name without --r-. Shared tokens go in light:

{
  "name": "Harbour",
  "description": "Sea blue and sand.",
  "base": "windows",
  "light": {
    "accent": "#0b6e8a",
    "accent-strong": "#07495c",
    "bg": "#eef3f4",
    "radius": "10px",
    "font-ui": "Georgia, serif"
  },
  "dark": {
    "accent": "#5cc2de",
    "accent-strong": "#9be0f2",
    "bg": "#0d1b22"
  }
}
Group Main tokens
Ground bg and bg-paint (the window), login-paint, layer (the blades), surface (cards)
Text and lines ink, muted, faint, line
Accent and status accent, accent-strong, accent-contrast, accent-soft, danger, ok, warn
Controls and fields ctrl, ctrl-hover, focus, field, field-line, switch-on
Menu and top bar bar, bar-ink, nav-paint, nav-active, tab-selected
Blades blade-head, blade-line, blade-gap, layer-opacity, layer-blur
Shape and type radius, shadow-1, font-ui, font-mono, text-scale
Motion ease, dur

Further groups cover the selection, the preview, dialogs, logos and the moving background. skinTokens in @relatude/ui lists every token with its group, label and help.

Pictures and logos. Tokens ending in -image hold SVG source: bg-image (the wallpaper), layer-image (a texture on every blade) and nav-image (an illustration under the menu). Logos replace Relatude's on the login screen (logo-login), in the top bar (logo-bar) and in the top bar with the menu collapsed (logo-bar-collapsed). You upload them in the designer, as PNG, JPEG, WebP, GIF or SVG of up to 1 MB.

What a value can be. A skin changes the look and nothing else. Every value is checked when it is saved and again before it is drawn:

  • A CSS value is one value on one line, up to 400 characters: a colour, gradient, length, shadow, font-family list, time, timing function, or var(--r-name). It cannot contain ;, braces, <, >, \, !, @, comments or url().
  • A picture is one <svg> of up to 16,000 characters: shapes, gradients, patterns and filters, with no scripts, event attributes, styles or external files, and links only to its own parts (#id). It is drawn as an image, so it runs and loads nothing.
  • Fonts cannot be loaded from the web: use fonts on the computer, or IBM Plex Sans and IBM Plex Mono, which the interface loads.

Moving backgrounds

A skin can have a scene: an animation drawn with WebGL 2 behind the blades and the login screen, under the wallpaper. Without WebGL 2 the window's paint shows instead. The scene token is none (the default), peaks (a flight over faceted peaks), snow (snowfall over hills), aurora (northern lights), grid (a neon grid), stars (deep space), forest (a forest against the light), winter (a frozen lake), synthwave (a neon road toward a striped sun), graph (drifting linked rings) or shader (the skin's own, below).

Token Is
scene the scene, per theme
scene-sky, scene-horizon, scene-land, scene-shade, scene-snow, scene-accent its colours, per theme: the sky at the top and at the horizon, the land in light and in shadow, snow and stars, the glow
scene-veil a colour over the whole scene to quiet it, such as rgb(0 0 0 / 0.3)
scene-speed 1 as made, up to 4; 0 is a still picture
scene-work-speed the share of that speed once signed in: 1 the same, 0.1 barely moving
scene-work-opacity how much shows once signed in: 1 all, 0 none
scene-amount how much is in it (flakes, stars, lights): 0 to 3, 1 as made
scene-shader the GLSL of the shader scene

Choosing a scene in the designer's Basic mode fills in its own colours, which scenes in @relatude/ui lists. With scene-work-opacity at 0, a scene is for the login screen alone: it fades out at sign-in and is not drawn after that. Give the login screen a login-paint close to the scene's colours, since the scene fades in over it:

{
  "name": "Night watch",
  "base": "windows",
  "light": { "themes": "dark", "scene-work-opacity": "0" },
  "dark": {
    "scene": "aurora",
    "scene-sky": "#050b16", "scene-horizon": "#0f2233", "scene-land": "#18283a",
    "scene-shade": "#070d16", "scene-snow": "#dfe9f5", "scene-accent": "#4dffb0",
    "login-paint": "#050b16"
  }
}

To let a scene show through once signed in, set layer-opacity below 1 (down to 0.3) with layer-blur, and give nav-paint and bar translucent colours, blurred by nav-blur and bar-blur. Scenes ignore the system's reduce-motion setting: set scene-speed to 0 for a still one.

A shader of your own. With scene set to shader, the interface draws scene-shader, a GLSL ES 3.00 fragment shader in the style of Shadertoy:

void mainImage(out vec4 fragColor, in vec2 fragCoord) {
  vec2 uv = fragCoord / iResolution.xy;
  vec3 col = mix(uHorizon, uSky, uv.y);
  for (int i = 0; i < 5; i++) {
    float f = float(i);
    float y = 0.18 + f * 0.07 + 0.035 * sin(uv.x * (3.0 + f) + iTime * (0.25 + f * 0.07) + f * 1.7);
    col = mix(col, mix(uLand, uShade, f / 5.0), smoothstep(y + 0.004, y - 0.004, uv.y) * 0.55);
  }
  fragColor = vec4(col, 1.0);
}
  • iResolution, iTime, iTimeDelta, iFrame, the colours uSky, uHorizon, uLand, uShade, uSnow and uAccent (vec3), uAmount (scene-amount) and uNight (1 when the horizon is dark) are declared for you.
  • The source is plain ASCII, at most 12,000 characters, with no #version or #extension. Alpha is ignored.
  • It runs on the graphics card at half resolution and can read nothing: not the page, the network or anything of the user's. A shader that stops the graphics card is switched off.

The designer compiles the shader as you type and shows the errors. exampleShaders in @relatude/ui has more to start from.