@signal9/era-ui 3.5.1 → 3.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,181 @@
1
+ /**
2
+ * SIGNALNINE dish — the logo, in one self-contained file.
3
+ *
4
+ * Zero imports and zero dependencies, deliberately: this file is the mark's
5
+ * portable master copy, so it stays droppable into any Svelte 5 project
6
+ * unchanged. It is the one component in the library that does NOT consume
7
+ * --era-* tokens — a logo has fixed brand geometry and colour, and must
8
+ * render identically whatever density, surface, or theme surrounds it.
9
+ * Do not "fix" that by tokenising it.
10
+ *
11
+ * A nonagon satellite dish modeled as a true closed shell (inner bowl, outer
12
+ * underside cone, rim wall), orthographically projected to plain SVG polygons
13
+ * with painter depth-sorting, backface culling, and Lambert shading in oklch.
14
+ * No rendering library — the math below is the product.
15
+ *
16
+ * The render math and physics tables are exported from this module block, so
17
+ * tooling (labs, exporters, tests) can reuse them without duplicating
18
+ * geometry:
19
+ * import { Logo, renderLogoMarkup, PAL } from './index.js';
20
+ *
21
+ * Colors, geometry constants, and defaults are final brand decisions.
22
+ *
23
+ * Ported from blog.signalnine.dev (src/lib/SignalnineDish.svelte); era-ui is
24
+ * now the canonical home. Public types/functions were renamed Dish* -> Logo*;
25
+ * the geometry and physics are untouched.
26
+ */
27
+ export type LogoPalette = 'amber' | 'chrome' | 'steel';
28
+ export type LogoState = 'manual' | 'idle' | 'loading' | 'search' | 'transmit' | 'success' | 'error' | 'sleep';
29
+ export type HueOverride = {
30
+ hD: number;
31
+ hL: number;
32
+ C: number;
33
+ };
34
+ export type Ring = {
35
+ r: number;
36
+ rise: number;
37
+ a: number;
38
+ w: number;
39
+ };
40
+ export interface LogoParams {
41
+ /** 0 flat plate → 100 deepest dish (mouth always full width). */
42
+ depth?: number;
43
+ /** Core-inlay dilate, 40–240 (%). */
44
+ inset?: number;
45
+ /** View elevation, 0 flat 2D face-on → 100 edge-on/underside. */
46
+ tilt?: number;
47
+ /** Screen-plane rotation, degrees. */
48
+ aim?: number;
49
+ /** Key-light orbit around the dish axis, degrees. */
50
+ light?: number;
51
+ palette?: LogoPalette;
52
+ /** Global luminance multiplier (sleep dims to 0.5). */
53
+ dim?: number;
54
+ /** Rotor spin, degrees (loading preset). */
55
+ spin?: number;
56
+ /** Core opacity multiplier (error blink). */
57
+ feedBlink?: number;
58
+ /** Core radius multiplier (transmit pulse). */
59
+ feedPulse?: number;
60
+ /** Rising transmit/success rings. */
61
+ rings?: Ring[] | null;
62
+ /** State recolor (error red, success green). */
63
+ hueOv?: HueOverride | null;
64
+ }
65
+ export declare const LOGO_STATES: LogoState[];
66
+ export declare const wrap: (d: number) => number;
67
+ export declare const clamp: (v: number, a: number, b: number) => number;
68
+ export declare const norm360: (v: number) => number;
69
+ export declare const PAL: Record<LogoPalette, {
70
+ Cm: number;
71
+ hD: number;
72
+ hL: number;
73
+ loI: number;
74
+ hiI: number;
75
+ loO: number;
76
+ hiO: number;
77
+ dot: string;
78
+ tile: string;
79
+ }>;
80
+ export declare const PALETTES: LogoPalette[];
81
+ /** oklch → sRGB hex, for portable export. */
82
+ export declare function oklchToHex(Lc: number, C: number, H: number): string;
83
+ /** One frame of the dish, as inner SVG markup for a -100 -100 200 200 canvas. */
84
+ export declare function renderLogoMarkup(params?: LogoParams): string;
85
+ /** Standalone portable SVG of a pose — oklch converted to sRGB hex. */
86
+ export declare function logoSvgDocument(params?: LogoParams, size?: number): string;
87
+ export declare const SPR: {
88
+ readonly depth: {
89
+ readonly k: 70;
90
+ readonly c: 12;
91
+ };
92
+ readonly inset: {
93
+ readonly k: 80;
94
+ readonly c: 13;
95
+ };
96
+ readonly tilt: {
97
+ readonly k: 34;
98
+ readonly c: 7;
99
+ };
100
+ readonly aim: {
101
+ readonly k: 26;
102
+ readonly c: 5.2;
103
+ };
104
+ readonly light: {
105
+ readonly k: 90;
106
+ readonly c: 17;
107
+ };
108
+ };
109
+ export type Dof = keyof typeof SPR;
110
+ export type LogoSim = Record<Dof, {
111
+ v: number;
112
+ vel: number;
113
+ }> & {
114
+ /** Where a spinning light has committed to stop. Always AHEAD of the
115
+ * current angle, so the sweep never reverses to get home. */
116
+ light: {
117
+ v: number;
118
+ vel: number;
119
+ park?: number | null;
120
+ };
121
+ };
122
+ export type Fx = {
123
+ spinV: number;
124
+ dim: number;
125
+ feedBlink: number;
126
+ feedPulse: number;
127
+ rings: Ring[] | null;
128
+ hueOv: HueOverride | null;
129
+ };
130
+ export declare function createSim(p: Required<Pick<LogoParams, Dof>>): LogoSim;
131
+ /** Where the key light parks at rest. Every preset targets this (or an offset
132
+ * from it), so moving it re-lights the mark everywhere at once. */
133
+ export declare const REST_LIGHT = 250;
134
+ /** Fixed physics step. Long frames are sub-stepped rather than integrated in
135
+ * one huge leap — a stalled frame (e.g. the main thread finishing a
136
+ * navigation) would otherwise blow the spring up and snap the pose. */
137
+ export declare const FIXED_STEP: number;
138
+ /**
139
+ * Advance every spring one step toward its target.
140
+ *
141
+ * `coastLight` cuts the light's spring drive while it is still orbiting fast,
142
+ * leaving only drag — the sweep spins down like a motor losing power instead
143
+ * of being yanked to the nearest rest angle (which reverses it) or whipped to
144
+ * one a full turn ahead (which speeds it up). Once it drops below SPIN_CARRY
145
+ * the spring takes over and parks it.
146
+ */
147
+ export declare function integrate(sim: LogoSim, tgt: Record<Dof, number>, dt: number, coastLight?: boolean): void;
148
+ /**
149
+ * Per-state spring targets and visual effects. Mutates `sim` for impulses.
150
+ *
151
+ * Tilt targets are expressed RELATIVE to `baseTilt` (the mark's resting
152
+ * elevation), so a mark parked at a different tilt keeps its silhouette
153
+ * through every preset instead of springing back to the stock 55. At the
154
+ * default 55 the numbers are identical to the original absolute table.
155
+ */
156
+ export declare function stateFrame(st: LogoState, t: number, scl: number, sim: LogoSim, jolt: {
157
+ last: number;
158
+ sign: number;
159
+ }, baseTilt?: number): {
160
+ tgt: Record<Dof, number>;
161
+ fx: Fx;
162
+ };
163
+ type $$ComponentProps = {
164
+ depth?: number;
165
+ tilt?: number;
166
+ aim?: number;
167
+ light?: number;
168
+ inset?: number;
169
+ palette?: LogoPalette;
170
+ /** 'manual' renders a static pose; any other state animates its preset. */
171
+ state?: LogoState;
172
+ size?: number;
173
+ /** Deepen the bowl while held, then spring back on release. */
174
+ pressable?: boolean;
175
+ class?: string;
176
+ };
177
+ declare const Logo: import("svelte").Component<$$ComponentProps, {
178
+ exportSVG: () => string;
179
+ }, "">;
180
+ type Logo = ReturnType<typeof Logo>;
181
+ export default Logo;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@signal9/era-ui",
3
- "version": "3.5.1",
3
+ "version": "3.7.0",
4
4
  "scripts": {
5
5
  "dev": "vite dev --host",
6
6
  "build": "vite build && npm run prepack",