@loworbitstudio/visor-theme-engine 0.15.1 → 0.17.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.
- package/dist/adapters/index.d.ts +1 -1
- package/dist/fowt.d.ts +46 -1
- package/dist/fowt.js +22 -1
- package/dist/index.d.ts +551 -4
- package/dist/index.js +649 -1
- package/dist/{types-zug1_eLX.d.ts → types-DqsWwFVZ.d.ts} +232 -1
- package/package.json +1 -1
- package/src/visor-theme.schema.json +225 -1
|
@@ -224,6 +224,228 @@ interface ThemeBrandResult {
|
|
|
224
224
|
warnings: string[];
|
|
225
225
|
}
|
|
226
226
|
|
|
227
|
+
/**
|
|
228
|
+
* Brand-strategy types for the Visor theme engine (VI-505).
|
|
229
|
+
*
|
|
230
|
+
* The Brand Record as validated, serializable, theme-aware data — a top-level
|
|
231
|
+
* `brand-strategy` block in `.visor.yaml`, SIBLING to the asset-only `brand`
|
|
232
|
+
* block (`packages/theme-engine/src/brand/`). The two have different lifecycles
|
|
233
|
+
* and consumers: `brand` declares logo/wordmark/etc. assets; `brand-strategy`
|
|
234
|
+
* declares positioning, personality, pillars, voice, and tone.
|
|
235
|
+
*
|
|
236
|
+
* Shape follows F1 — Visor's authored Brand Record
|
|
237
|
+
* (`docs/brand/visor-brand-record.yaml`) — itself derived from the VI-498
|
|
238
|
+
* research sketch (§5a).
|
|
239
|
+
*
|
|
240
|
+
* This module is deliberately self-contained and engine-decoupled (D4): the
|
|
241
|
+
* types, the pure validators (coherence context is injected, never imported),
|
|
242
|
+
* and the serializer lift cleanly into a future `@loworbitstudio/visor-brand`
|
|
243
|
+
* package. Engine-specific wiring (the known-token set, the comprehensive
|
|
244
|
+
* `validate()` pass, the manifest serialization call-site) lives outside.
|
|
245
|
+
*/
|
|
246
|
+
/** Positioning — the onliness, category, and differentiation wedge. */
|
|
247
|
+
interface BrandPositioning {
|
|
248
|
+
/** The single sentence that passes Neumeier's "only" test. */
|
|
249
|
+
onliness: string;
|
|
250
|
+
/** The category the brand competes in (e.g. "design system"). */
|
|
251
|
+
category: string;
|
|
252
|
+
/** What sets the brand apart within that category. */
|
|
253
|
+
differentiation: string;
|
|
254
|
+
}
|
|
255
|
+
/** A personality trait sharpened by its antonym (brand-as-person). */
|
|
256
|
+
interface BrandPersonalityTrait {
|
|
257
|
+
/** The trait (e.g. "precise"). */
|
|
258
|
+
trait: string;
|
|
259
|
+
/** What the trait is NOT — the antonym that earns it its keep (e.g. "fussy"). */
|
|
260
|
+
not: string;
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Brand archetype assignment (Pearson & Mark — twelve archetypes). Primary is
|
|
264
|
+
* required; secondary and tertiary are optional refinements.
|
|
265
|
+
*/
|
|
266
|
+
interface BrandArchetype {
|
|
267
|
+
primary: string;
|
|
268
|
+
secondary?: string;
|
|
269
|
+
tertiary?: string;
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* What a pillar governs — the link that turns a slogan into a checkable claim.
|
|
273
|
+
* Targets span three namespaces: design tokens, registry components, and
|
|
274
|
+
* meta-surfaces (the manifest, the CLI, component metadata). The `openness`
|
|
275
|
+
* pillar governs the last of these, which is why `governs` accepts more than
|
|
276
|
+
* tokens/components (F1 schema note). At least one target list is expected.
|
|
277
|
+
*/
|
|
278
|
+
interface BrandGoverns {
|
|
279
|
+
/** Semantic token refs (with or without the leading `--`), or `"*"` for all. */
|
|
280
|
+
tokens?: string[];
|
|
281
|
+
/** Registry component names, or `"*"` for all. */
|
|
282
|
+
components?: string[];
|
|
283
|
+
/** Meta-surfaces (e.g. `manifest`, `cli`, `component-metadata`). */
|
|
284
|
+
surfaces?: string[];
|
|
285
|
+
}
|
|
286
|
+
/** A strategic pillar — an essence word made operational. */
|
|
287
|
+
interface BrandPillar {
|
|
288
|
+
/** Stable id (e.g. "coherence"). */
|
|
289
|
+
id: string;
|
|
290
|
+
/** The pillar's claim in one line. */
|
|
291
|
+
statement: string;
|
|
292
|
+
/** What the pillar governs (coherence-checked against the live system). */
|
|
293
|
+
governs: BrandGoverns;
|
|
294
|
+
/**
|
|
295
|
+
* Reasons-to-believe — the message-house foundation (VI-541, Phase 2 wave-1).
|
|
296
|
+
* Concrete, checkable evidence backing this pillar's claim. Optional so a
|
|
297
|
+
* record can carry pillars without proof points.
|
|
298
|
+
*/
|
|
299
|
+
proof?: string[];
|
|
300
|
+
}
|
|
301
|
+
/** A fixed voice trait with a worked example. */
|
|
302
|
+
interface BrandVoiceTrait {
|
|
303
|
+
/** Trait name (e.g. "plainspoken"). */
|
|
304
|
+
name: string;
|
|
305
|
+
/** What to do. */
|
|
306
|
+
do: string;
|
|
307
|
+
/** What not to do. */
|
|
308
|
+
dont: string;
|
|
309
|
+
/** A worked example sentence (F1 carries one on every trait). */
|
|
310
|
+
example?: string;
|
|
311
|
+
}
|
|
312
|
+
/** Voice — fixed across the brand; never flexes. */
|
|
313
|
+
interface BrandVoice {
|
|
314
|
+
traits: BrandVoiceTrait[];
|
|
315
|
+
}
|
|
316
|
+
/** A single tone entry, keyed (in `tone`) to a recognized UI state. */
|
|
317
|
+
interface BrandToneEntry {
|
|
318
|
+
/** The feeling the copy should evoke in this state. */
|
|
319
|
+
feeling: string;
|
|
320
|
+
/** A worked example message for this state. */
|
|
321
|
+
example: string;
|
|
322
|
+
}
|
|
323
|
+
/** A lexicon pairing — the word to use and the one to avoid. */
|
|
324
|
+
interface BrandLexiconEntry {
|
|
325
|
+
use: string;
|
|
326
|
+
avoid: string;
|
|
327
|
+
}
|
|
328
|
+
/** Message-house roof — the single umbrella message above the pillars. */
|
|
329
|
+
interface BrandMessaging {
|
|
330
|
+
/** One overarching statement the pillars support (message-house roof). */
|
|
331
|
+
roof: string;
|
|
332
|
+
}
|
|
333
|
+
/** Reusable "about us" copy — short and long forms. */
|
|
334
|
+
interface BrandBoilerplate {
|
|
335
|
+
short: string;
|
|
336
|
+
long: string;
|
|
337
|
+
}
|
|
338
|
+
/** A color-pairing rule expressed as brand intent (not a computed value). */
|
|
339
|
+
interface BrandColorPairing {
|
|
340
|
+
/** The token or role being used (e.g. `--primary`). */
|
|
341
|
+
use: string;
|
|
342
|
+
/** What it pairs against (token, role, or surface). */
|
|
343
|
+
with: string;
|
|
344
|
+
/** The intent — when and how the pairing is allowed. */
|
|
345
|
+
rule: string;
|
|
346
|
+
}
|
|
347
|
+
/** Color-usage intent — the brand's allowed pairings. */
|
|
348
|
+
interface BrandColorUsage {
|
|
349
|
+
pairings: BrandColorPairing[];
|
|
350
|
+
}
|
|
351
|
+
/** A contrast target expressed as brand intent (a WCAG 2.1 AA threshold). */
|
|
352
|
+
interface BrandContrastTarget {
|
|
353
|
+
/** The text/UI context the target applies to. */
|
|
354
|
+
context: string;
|
|
355
|
+
/** The minimum contrast ratio (e.g. "4.5:1"). */
|
|
356
|
+
ratio: string;
|
|
357
|
+
}
|
|
358
|
+
/** Accessibility intent — the standard and its contrast targets. */
|
|
359
|
+
interface BrandAccessibility {
|
|
360
|
+
/** The conformance standard. Visor targets "WCAG 2.1 AA". */
|
|
361
|
+
standard: string;
|
|
362
|
+
/** WCAG 2.1 AA contrast targets, authored as intent (live computation is the render surface's concern). */
|
|
363
|
+
contrast: BrandContrastTarget[];
|
|
364
|
+
/** How the brand applies the standard (intent, not computed results). */
|
|
365
|
+
intent: string;
|
|
366
|
+
}
|
|
367
|
+
/** Visibility of a brand strategy. Client brands are `private`. */
|
|
368
|
+
type BrandVisibility = "public" | "private";
|
|
369
|
+
/**
|
|
370
|
+
* The `brand-strategy` block — strategy + verbal identity as data.
|
|
371
|
+
*
|
|
372
|
+
* `tone` is keyed by UI state (`error`, `success`, …); the keys are validated
|
|
373
|
+
* against the recognized UI states (coherence check D2). The ten Phase 1 fields
|
|
374
|
+
* are required in v1 — F1 authors the full record, and the downstream Workbench
|
|
375
|
+
* surfaces render each section. The Phase 2 wave-1 fields (`messaging`,
|
|
376
|
+
* `taglines`, `boilerplate`, `colorUsage`, `accessibility`; VI-541) are optional
|
|
377
|
+
* so a record — e.g. a private client brand — can omit them.
|
|
378
|
+
*/
|
|
379
|
+
interface BrandStrategy {
|
|
380
|
+
positioning: BrandPositioning;
|
|
381
|
+
/** 2–3 internal-facing core words (Aaker essence). */
|
|
382
|
+
essence: string[];
|
|
383
|
+
personality: BrandPersonalityTrait[];
|
|
384
|
+
archetype: BrandArchetype;
|
|
385
|
+
pillars: BrandPillar[];
|
|
386
|
+
voice: BrandVoice;
|
|
387
|
+
/** Voice flexed per UI state. Keys ∈ recognized UI states. */
|
|
388
|
+
tone: Record<string, BrandToneEntry>;
|
|
389
|
+
lexicon: BrandLexiconEntry[];
|
|
390
|
+
/** Aaker core/extended — the immutable subset, as section names. */
|
|
391
|
+
core: string[];
|
|
392
|
+
visibility: BrandVisibility;
|
|
393
|
+
/** Message-house roof — the umbrella message above the pillars. */
|
|
394
|
+
messaging?: BrandMessaging;
|
|
395
|
+
/** Permanent, brand-level signature line(s) — who the brand is, not what it sells this quarter. */
|
|
396
|
+
taglines?: string[];
|
|
397
|
+
/** Reusable "about us" copy — short and long forms. */
|
|
398
|
+
boilerplate?: BrandBoilerplate;
|
|
399
|
+
/** Color-usage intent — the brand's allowed pairings. */
|
|
400
|
+
colorUsage?: BrandColorUsage;
|
|
401
|
+
/** Accessibility intent — WCAG 2.1 AA standard + contrast targets. */
|
|
402
|
+
accessibility?: BrandAccessibility;
|
|
403
|
+
}
|
|
404
|
+
/**
|
|
405
|
+
* The agent-facing projection of a brand strategy, embedded in
|
|
406
|
+
* `visor-manifest.json` under `brand_strategy` (D3). Structurally identical to
|
|
407
|
+
* the authored shape so an agent reads `voice.traits` / `tone.error` the way it
|
|
408
|
+
* reads a component's `when_to_use`. Only PUBLIC strategies are serialized.
|
|
409
|
+
*/
|
|
410
|
+
type SerializedBrandStrategy = BrandStrategy;
|
|
411
|
+
/** Recognized UI states a `tone` key may target (coherence check D2). */
|
|
412
|
+
declare const DEFAULT_BRAND_STRATEGY_TONE_STATES: readonly string[];
|
|
413
|
+
/** Recognized meta-surfaces a pillar may govern (coherence check D2). */
|
|
414
|
+
declare const DEFAULT_BRAND_STRATEGY_SURFACES: readonly string[];
|
|
415
|
+
/** Valid `visibility` values. */
|
|
416
|
+
declare const BRAND_VISIBILITIES: readonly BrandVisibility[];
|
|
417
|
+
/** Wildcard accepted in any `governs` target list — matches all of that namespace. */
|
|
418
|
+
declare const GOVERNS_WILDCARD = "*";
|
|
419
|
+
type BrandStrategyIssueSeverity = "error" | "warning";
|
|
420
|
+
/** A single validation finding. Mirrors the engine's `ValidationIssue` shape. */
|
|
421
|
+
interface BrandStrategyIssue {
|
|
422
|
+
severity: BrandStrategyIssueSeverity;
|
|
423
|
+
code: string;
|
|
424
|
+
message: string;
|
|
425
|
+
path?: string;
|
|
426
|
+
}
|
|
427
|
+
/** Structured validation result for a brand-strategy block. */
|
|
428
|
+
interface BrandStrategyValidationResult {
|
|
429
|
+
valid: boolean;
|
|
430
|
+
errors: BrandStrategyIssue[];
|
|
431
|
+
warnings: BrandStrategyIssue[];
|
|
432
|
+
}
|
|
433
|
+
/**
|
|
434
|
+
* Coherence context — the real-world sets a strategy's links are checked
|
|
435
|
+
* against. Injected by the caller (the engine `validate()` pass, the manifest
|
|
436
|
+
* builder, or a test) so the validator stays pure and engine-decoupled (D4).
|
|
437
|
+
*/
|
|
438
|
+
interface BrandStrategyContext {
|
|
439
|
+
/** Known semantic token names WITHOUT the leading `--` (e.g. "primary", "surface-card"). When omitted, token coherence is skipped. */
|
|
440
|
+
tokens?: ReadonlySet<string>;
|
|
441
|
+
/** Known registry component names. When omitted, only `"*"` is accepted for components. */
|
|
442
|
+
components?: ReadonlySet<string>;
|
|
443
|
+
/** Recognized meta-surfaces. Defaults to {@link DEFAULT_BRAND_STRATEGY_SURFACES}. */
|
|
444
|
+
surfaces?: ReadonlySet<string>;
|
|
445
|
+
/** Recognized UI states for `tone` keys. Defaults to {@link DEFAULT_BRAND_STRATEGY_TONE_STATES}. */
|
|
446
|
+
states?: ReadonlySet<string>;
|
|
447
|
+
}
|
|
448
|
+
|
|
227
449
|
/**
|
|
228
450
|
* Types for the Visor Theme Engine
|
|
229
451
|
*
|
|
@@ -381,6 +603,15 @@ interface VisorThemeConfig {
|
|
|
381
603
|
* Omitted → the Visor default brand (stock themes are not logo-less).
|
|
382
604
|
*/
|
|
383
605
|
brand?: VisorBrand;
|
|
606
|
+
/**
|
|
607
|
+
* Brand-strategy block (VI-505) — positioning, personality, pillars, voice,
|
|
608
|
+
* and tone as validated, serializable data. SIBLING to `brand` (assets):
|
|
609
|
+
* different lifecycle and consumer. NOT expanded into derived CSS values;
|
|
610
|
+
* coherence-checked (pillars→tokens/components/surfaces; tone→UI states) and
|
|
611
|
+
* serialized to the agent manifest. Liftable into a future
|
|
612
|
+
* `@loworbitstudio/visor-brand` package (D4).
|
|
613
|
+
*/
|
|
614
|
+
"brand-strategy"?: BrandStrategy;
|
|
384
615
|
spacing?: {
|
|
385
616
|
base?: number;
|
|
386
617
|
};
|
|
@@ -605,4 +836,4 @@ interface ThemeData {
|
|
|
605
836
|
output: ThemeOutput;
|
|
606
837
|
}
|
|
607
838
|
|
|
608
|
-
export { type BrandSlot as B, type ColorRole as C, type FontResolveOptions as F, type GoogleFontEntry as G, type OKLCH as O, type ParsedColor as P, type ResolvedThemeConfig as R, type
|
|
839
|
+
export { GOVERNS_WILDCARD as $, type BrandContrastTarget as A, type BrandSlot as B, type ColorRole as C, type BrandGoverns as D, type BrandLexiconEntry as E, type FontResolveOptions as F, type GoogleFontEntry as G, type BrandMessaging as H, type BrandPersonalityTrait as I, type BrandPillar as J, type BrandPositioning as K, type BrandStrategyIssueSeverity as L, type BrandToneEntry as M, type BrandVariant as N, type OKLCH as O, type ParsedColor as P, type BrandVisibility as Q, type ResolvedThemeConfig as R, type SerializedBrandStrategy as S, type ThemeFontResult as T, type BrandVoice as U, type VisorTypography as V, type BrandVoiceTrait as W, type ColorFormat as X, DEFAULT_BRAND_STRATEGY_SURFACES as Y, DEFAULT_BRAND_STRATEGY_TONE_STATES as Z, type FontSource as _, type FontResolution as a, type RGBA as a0, type SemanticTokenValue as a1, type FontDisplayStrategy as b, type VisorBrand as c, type BrandSource as d, type BrandResolution as e, type ThemeBrandResult as f, type BrandStrategy as g, type BrandStrategyContext as h, type BrandStrategyIssue as i, type BrandStrategyValidationResult as j, type GeneratedPrimitives as k, type ThemeOutput as l, type ThemeData as m, type VisorThemeConfig as n, type FullShadeScale as o, type SelectiveShadeScale as p, type RGB as q, type SemanticTokens as r, type ShadeStep as s, BRAND_VARIANTS as t, BRAND_VISIBILITIES as u, type BrandAccessibility as v, type BrandArchetype as w, type BrandBoilerplate as x, type BrandColorPairing as y, type BrandColorUsage as z };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@loworbitstudio/visor-theme-engine",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.0",
|
|
4
4
|
"description": "Theme engine for the Visor design system — shade generation, token mapping, font resolution, and import/export for .visor.yaml themes.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
},
|
|
23
23
|
"label": {
|
|
24
24
|
"type": "string",
|
|
25
|
-
"description": "Human-readable display name for the theme (e.g. '
|
|
25
|
+
"description": "Human-readable display name for the theme (e.g. 'My Brand Pro'). Overrides the name-derived label in the docs theme switcher. Optional."
|
|
26
26
|
},
|
|
27
27
|
"default-mode": {
|
|
28
28
|
"type": "string",
|
|
@@ -293,6 +293,69 @@
|
|
|
293
293
|
]
|
|
294
294
|
}
|
|
295
295
|
},
|
|
296
|
+
"brand-strategy": {
|
|
297
|
+
"type": "object",
|
|
298
|
+
"description": "Brand-strategy block (VI-505) — positioning, personality, pillars, voice, and tone as validated, serializable data. Sibling to `brand` (assets): different lifecycle and consumer. NOT expanded into derived CSS values; coherence-checked (pillars govern real tokens/components/surfaces; tone keys map to real UI states) and serialized to the agent manifest under `brand_strategy`.",
|
|
299
|
+
"additionalProperties": false,
|
|
300
|
+
"required": ["positioning", "essence", "personality", "archetype", "pillars", "voice", "tone", "lexicon", "core", "visibility"],
|
|
301
|
+
"properties": {
|
|
302
|
+
"positioning": { "$ref": "#/$defs/brandPositioning" },
|
|
303
|
+
"essence": {
|
|
304
|
+
"type": "array",
|
|
305
|
+
"items": { "type": "string" },
|
|
306
|
+
"minItems": 1,
|
|
307
|
+
"description": "2–3 internal-facing core words (Aaker essence)."
|
|
308
|
+
},
|
|
309
|
+
"personality": {
|
|
310
|
+
"type": "array",
|
|
311
|
+
"items": { "$ref": "#/$defs/brandPersonalityTrait" },
|
|
312
|
+
"minItems": 1,
|
|
313
|
+
"description": "Brand-as-person traits, each sharpened by its antonym."
|
|
314
|
+
},
|
|
315
|
+
"archetype": { "$ref": "#/$defs/brandArchetype" },
|
|
316
|
+
"pillars": {
|
|
317
|
+
"type": "array",
|
|
318
|
+
"items": { "$ref": "#/$defs/brandPillar" },
|
|
319
|
+
"minItems": 1,
|
|
320
|
+
"description": "Strategic pillars — essence words made operational, each governing real tokens/components/surfaces."
|
|
321
|
+
},
|
|
322
|
+
"voice": { "$ref": "#/$defs/brandVoice" },
|
|
323
|
+
"tone": {
|
|
324
|
+
"type": "object",
|
|
325
|
+
"description": "Voice flexed per UI state. Keys must be recognized UI states.",
|
|
326
|
+
"minProperties": 1,
|
|
327
|
+
"propertyNames": { "enum": ["error", "success", "warning", "info", "empty", "loading", "validation-warning"] },
|
|
328
|
+
"additionalProperties": { "$ref": "#/$defs/brandToneEntry" }
|
|
329
|
+
},
|
|
330
|
+
"lexicon": {
|
|
331
|
+
"type": "array",
|
|
332
|
+
"items": { "$ref": "#/$defs/brandLexiconEntry" },
|
|
333
|
+
"minItems": 1,
|
|
334
|
+
"description": "Words to use and the ones to avoid."
|
|
335
|
+
},
|
|
336
|
+
"core": {
|
|
337
|
+
"type": "array",
|
|
338
|
+
"items": { "type": "string" },
|
|
339
|
+
"minItems": 1,
|
|
340
|
+
"description": "Aaker core/extended — the immutable subset, as section names."
|
|
341
|
+
},
|
|
342
|
+
"visibility": {
|
|
343
|
+
"type": "string",
|
|
344
|
+
"enum": ["public", "private"],
|
|
345
|
+
"description": "Client brands are private and are omitted from the public agent manifest."
|
|
346
|
+
},
|
|
347
|
+
"messaging": { "$ref": "#/$defs/brandMessaging" },
|
|
348
|
+
"taglines": {
|
|
349
|
+
"type": "array",
|
|
350
|
+
"items": { "type": "string", "minLength": 1 },
|
|
351
|
+
"minItems": 1,
|
|
352
|
+
"description": "Phase 2 wave-1 (VI-541). Permanent, brand-level signature line(s) — who the brand is, not what it sells this quarter."
|
|
353
|
+
},
|
|
354
|
+
"boilerplate": { "$ref": "#/$defs/brandBoilerplate" },
|
|
355
|
+
"colorUsage": { "$ref": "#/$defs/brandColorUsage" },
|
|
356
|
+
"accessibility": { "$ref": "#/$defs/brandAccessibility" }
|
|
357
|
+
}
|
|
358
|
+
},
|
|
296
359
|
"spacing": {
|
|
297
360
|
"type": "object",
|
|
298
361
|
"description": "Spacing configuration.",
|
|
@@ -460,6 +523,167 @@
|
|
|
460
523
|
"description": "Letter spacing in logical pixels (Flutter TextStyle.letterSpacing). Material defaults include negative values, e.g. -0.25 for displayLarge."
|
|
461
524
|
}
|
|
462
525
|
}
|
|
526
|
+
},
|
|
527
|
+
"brandPositioning": {
|
|
528
|
+
"type": "object",
|
|
529
|
+
"description": "Positioning — the onliness, category, and differentiation wedge.",
|
|
530
|
+
"additionalProperties": false,
|
|
531
|
+
"required": ["onliness", "category", "differentiation"],
|
|
532
|
+
"properties": {
|
|
533
|
+
"onliness": { "type": "string", "minLength": 1, "description": "The single sentence that passes Neumeier's \"only\" test." },
|
|
534
|
+
"category": { "type": "string", "minLength": 1, "description": "The category the brand competes in (e.g. \"design system\")." },
|
|
535
|
+
"differentiation": { "type": "string", "minLength": 1, "description": "What sets the brand apart within that category." }
|
|
536
|
+
}
|
|
537
|
+
},
|
|
538
|
+
"brandPersonalityTrait": {
|
|
539
|
+
"type": "object",
|
|
540
|
+
"description": "A personality trait sharpened by its antonym (brand-as-person).",
|
|
541
|
+
"additionalProperties": false,
|
|
542
|
+
"required": ["trait", "not"],
|
|
543
|
+
"properties": {
|
|
544
|
+
"trait": { "type": "string", "minLength": 1 },
|
|
545
|
+
"not": { "type": "string", "minLength": 1, "description": "The antonym — what the trait is not." }
|
|
546
|
+
}
|
|
547
|
+
},
|
|
548
|
+
"brandArchetype": {
|
|
549
|
+
"type": "object",
|
|
550
|
+
"description": "Brand archetype assignment (Pearson & Mark). Primary required; secondary/tertiary optional.",
|
|
551
|
+
"additionalProperties": false,
|
|
552
|
+
"required": ["primary"],
|
|
553
|
+
"properties": {
|
|
554
|
+
"primary": { "type": "string", "minLength": 1 },
|
|
555
|
+
"secondary": { "type": "string", "minLength": 1 },
|
|
556
|
+
"tertiary": { "type": "string", "minLength": 1 }
|
|
557
|
+
}
|
|
558
|
+
},
|
|
559
|
+
"brandGoverns": {
|
|
560
|
+
"type": "object",
|
|
561
|
+
"description": "What a pillar governs — design tokens, registry components, and/or meta-surfaces. At least one list is expected; use \"*\" for all of a namespace.",
|
|
562
|
+
"additionalProperties": false,
|
|
563
|
+
"minProperties": 1,
|
|
564
|
+
"properties": {
|
|
565
|
+
"tokens": { "type": "array", "items": { "type": "string" }, "minItems": 1, "description": "Semantic token refs (with or without the leading --), or \"*\"." },
|
|
566
|
+
"components": { "type": "array", "items": { "type": "string" }, "minItems": 1, "description": "Registry component names, or \"*\" for all." },
|
|
567
|
+
"surfaces": { "type": "array", "items": { "type": "string", "enum": ["manifest", "cli", "component-metadata"] }, "minItems": 1, "description": "Meta-surfaces a pillar may govern." }
|
|
568
|
+
}
|
|
569
|
+
},
|
|
570
|
+
"brandPillar": {
|
|
571
|
+
"type": "object",
|
|
572
|
+
"description": "A strategic pillar — an essence word made operational.",
|
|
573
|
+
"additionalProperties": false,
|
|
574
|
+
"required": ["id", "statement", "governs"],
|
|
575
|
+
"properties": {
|
|
576
|
+
"id": { "type": "string", "minLength": 1 },
|
|
577
|
+
"statement": { "type": "string", "minLength": 1, "description": "The pillar's claim in one line." },
|
|
578
|
+
"governs": { "$ref": "#/$defs/brandGoverns" },
|
|
579
|
+
"proof": {
|
|
580
|
+
"type": "array",
|
|
581
|
+
"items": { "type": "string", "minLength": 1 },
|
|
582
|
+
"minItems": 1,
|
|
583
|
+
"description": "Phase 2 wave-1 (VI-541). Reasons-to-believe — checkable evidence backing this pillar's claim (the message-house foundation)."
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
},
|
|
587
|
+
"brandVoice": {
|
|
588
|
+
"type": "object",
|
|
589
|
+
"description": "Voice — fixed across the brand; never flexes.",
|
|
590
|
+
"additionalProperties": false,
|
|
591
|
+
"required": ["traits"],
|
|
592
|
+
"properties": {
|
|
593
|
+
"traits": { "type": "array", "items": { "$ref": "#/$defs/brandVoiceTrait" }, "minItems": 1 }
|
|
594
|
+
}
|
|
595
|
+
},
|
|
596
|
+
"brandVoiceTrait": {
|
|
597
|
+
"type": "object",
|
|
598
|
+
"description": "A fixed voice trait with a worked example.",
|
|
599
|
+
"additionalProperties": false,
|
|
600
|
+
"required": ["name", "do", "dont"],
|
|
601
|
+
"properties": {
|
|
602
|
+
"name": { "type": "string", "minLength": 1 },
|
|
603
|
+
"do": { "type": "string", "minLength": 1, "description": "What to do." },
|
|
604
|
+
"dont": { "type": "string", "minLength": 1, "description": "What not to do." },
|
|
605
|
+
"example": { "type": "string", "minLength": 1, "description": "A worked example sentence." }
|
|
606
|
+
}
|
|
607
|
+
},
|
|
608
|
+
"brandToneEntry": {
|
|
609
|
+
"type": "object",
|
|
610
|
+
"description": "A single tone entry, keyed (in `tone`) to a recognized UI state.",
|
|
611
|
+
"additionalProperties": false,
|
|
612
|
+
"required": ["feeling", "example"],
|
|
613
|
+
"properties": {
|
|
614
|
+
"feeling": { "type": "string", "minLength": 1, "description": "The feeling the copy should evoke in this state." },
|
|
615
|
+
"example": { "type": "string", "minLength": 1, "description": "A worked example message for this state." }
|
|
616
|
+
}
|
|
617
|
+
},
|
|
618
|
+
"brandLexiconEntry": {
|
|
619
|
+
"type": "object",
|
|
620
|
+
"description": "A lexicon pairing — the word to use and the one to avoid.",
|
|
621
|
+
"additionalProperties": false,
|
|
622
|
+
"required": ["use", "avoid"],
|
|
623
|
+
"properties": {
|
|
624
|
+
"use": { "type": "string", "minLength": 1 },
|
|
625
|
+
"avoid": { "type": "string", "minLength": 1 }
|
|
626
|
+
}
|
|
627
|
+
},
|
|
628
|
+
"brandMessaging": {
|
|
629
|
+
"type": "object",
|
|
630
|
+
"description": "Phase 2 wave-1 (VI-541). Message-house roof — the single umbrella message above the pillars.",
|
|
631
|
+
"additionalProperties": false,
|
|
632
|
+
"required": ["roof"],
|
|
633
|
+
"properties": {
|
|
634
|
+
"roof": { "type": "string", "minLength": 1, "description": "One overarching statement the pillars support." }
|
|
635
|
+
}
|
|
636
|
+
},
|
|
637
|
+
"brandBoilerplate": {
|
|
638
|
+
"type": "object",
|
|
639
|
+
"description": "Phase 2 wave-1 (VI-541). Reusable \"about us\" copy — short and long forms.",
|
|
640
|
+
"additionalProperties": false,
|
|
641
|
+
"required": ["short", "long"],
|
|
642
|
+
"properties": {
|
|
643
|
+
"short": { "type": "string", "minLength": 1 },
|
|
644
|
+
"long": { "type": "string", "minLength": 1 }
|
|
645
|
+
}
|
|
646
|
+
},
|
|
647
|
+
"brandColorPairing": {
|
|
648
|
+
"type": "object",
|
|
649
|
+
"description": "A color-pairing rule expressed as brand intent (not a computed value).",
|
|
650
|
+
"additionalProperties": false,
|
|
651
|
+
"required": ["use", "with", "rule"],
|
|
652
|
+
"properties": {
|
|
653
|
+
"use": { "type": "string", "minLength": 1, "description": "The token or role being used (e.g. --primary)." },
|
|
654
|
+
"with": { "type": "string", "minLength": 1, "description": "What it pairs against (token, role, or surface)." },
|
|
655
|
+
"rule": { "type": "string", "minLength": 1, "description": "The intent — when and how the pairing is allowed." }
|
|
656
|
+
}
|
|
657
|
+
},
|
|
658
|
+
"brandColorUsage": {
|
|
659
|
+
"type": "object",
|
|
660
|
+
"description": "Phase 2 wave-1 (VI-541). Color-usage intent — the brand's allowed pairings.",
|
|
661
|
+
"additionalProperties": false,
|
|
662
|
+
"required": ["pairings"],
|
|
663
|
+
"properties": {
|
|
664
|
+
"pairings": { "type": "array", "items": { "$ref": "#/$defs/brandColorPairing" }, "minItems": 1 }
|
|
665
|
+
}
|
|
666
|
+
},
|
|
667
|
+
"brandContrastTarget": {
|
|
668
|
+
"type": "object",
|
|
669
|
+
"description": "A contrast target expressed as brand intent (a WCAG 2.1 AA threshold).",
|
|
670
|
+
"additionalProperties": false,
|
|
671
|
+
"required": ["context", "ratio"],
|
|
672
|
+
"properties": {
|
|
673
|
+
"context": { "type": "string", "minLength": 1, "description": "The text/UI context the target applies to." },
|
|
674
|
+
"ratio": { "type": "string", "minLength": 1, "description": "The minimum contrast ratio (e.g. \"4.5:1\")." }
|
|
675
|
+
}
|
|
676
|
+
},
|
|
677
|
+
"brandAccessibility": {
|
|
678
|
+
"type": "object",
|
|
679
|
+
"description": "Phase 2 wave-1 (VI-541). Accessibility intent — the standard and its contrast targets (authored as intent; live computation is the render surface's concern).",
|
|
680
|
+
"additionalProperties": false,
|
|
681
|
+
"required": ["standard", "contrast", "intent"],
|
|
682
|
+
"properties": {
|
|
683
|
+
"standard": { "type": "string", "minLength": 1, "description": "The conformance standard. Visor targets \"WCAG 2.1 AA\"." },
|
|
684
|
+
"contrast": { "type": "array", "items": { "$ref": "#/$defs/brandContrastTarget" }, "minItems": 1 },
|
|
685
|
+
"intent": { "type": "string", "minLength": 1, "description": "How the brand applies the standard (intent, not computed results)." }
|
|
686
|
+
}
|
|
463
687
|
}
|
|
464
688
|
}
|
|
465
689
|
}
|