vt-c-visitrans-design-system¶
Apply VisiTrans Corporate Design to prototypes and implementations. Generate PrimeNG presets, validate CD compliance, and provide component templates.
Plugin: core-standards
Category: Design
Command: /vt-c-visitrans-design-system
VisiTrans Design System¶
Apply VisiTrans Corporate Design (CD) consistently across prototypes and implementations.
Token Source¶
Canonical design tokens: TOOLKIT_ROOT/configs/visitrans-cd-tokens.yaml
All colors, typography, spacing, radii, and product themes are defined in this single YAML file. Skills and generators should reference this file rather than hardcoding values.
Generators¶
Generate framework-specific presets from the canonical tokens:
# PrimeNG preset (Angular)
python3 TOOLKIT_ROOT/scripts/design_system/generate_primeng_preset.py --product visitrans --output src/app/core/theme/vt-preset.ts
# CSS custom properties (any framework)
python3 TOOLKIT_ROOT/scripts/design_system/generate_css_variables.py --product visitrans --output src/styles/vt-variables.css
Python access¶
from scripts.design_system.tokens import load_tokens, get_product_theme
tokens = load_tokens()
orange = tokens['colors']['primary']['orange'] # '#FC9E00'
theme = get_product_theme('visimatch') # resolved hex values
Source Reference¶
Official CD Manual: ONEDRIVE_ROOT/03-Corporate Design/03-cd-manual/VisiTrans_CD_*.pdf
Invocation¶
/vt-c-visitrans-design-system --init # Generate PrimeNG preset + CSS variables
/vt-c-visitrans-design-system --validate # Check files for CD compliance
/vt-c-visitrans-design-system --components # Generate Angular component templates
Brand Overview¶
VisiTrans Family¶
| Brand | Purpose | Primary Color |
|---|---|---|
| VisiTrans | Parent company | Orange #FC9E00 |
| VisiMatch | Matching platform | Orange (inherit) |
| VisiFair | Trade fair management | Orange (inherit) |
| VisiArea | Venue management | Orange (inherit) |
Color Palette¶
Primary Colors¶
| Color | Hex | RGB | CMYK | Usage |
|---|---|---|---|---|
| Black | #1F1F1F | 31, 31, 31 | 0, 0, 0, 88 | Text, headers |
| Orange | #FC9E00 | 252, 158, 0 | 0, 38, 100, 0 | Brand accent, CTA |
| White | #FFFFFF | 255, 255, 255 | 0, 0, 0, 0 | Background |
Secondary - Gray Scale¶
| Color | Hex | Usage |
|---|---|---|
| Gray 90 | #2D2D2D | Secondary text |
| Gray 70 | #5C5C5C | Subtle text |
| Gray 50 | #8A8A8A | Placeholders |
| Gray 30 | #B8B8B8 | Borders |
| Gray 10 | #E6E6E6 | Backgrounds |
Secondary - Orange Scale¶
| Color | Hex | Usage |
|---|---|---|
| Orange Dark | #CC5200 | Hover states |
| Orange Light | #FF944D | Highlights |
Action Color¶
| Color | Hex | Usage |
|---|---|---|
| Magenta | #E6007E | Special actions, notifications |
Typography¶
Font Family¶
Inter - All weights available (Thin to Black)
Font Weights¶
| Weight | Value | Usage |
|---|---|---|
| Thin | 100 | Decorative |
| Extra Light | 200 | Light text |
| Light | 300 | Body text (alternative) |
| Regular | 400 | Body text (primary) |
| Medium | 500 | Emphasized text |
| Semi Bold | 600 | Subheadings |
| Bold | 700 | Headings |
| Extra Bold | 800 | Hero text |
| Black | 900 | Special emphasis |
Type Scale¶
| Element | Size | Weight | Line Height |
|---|---|---|---|
| H1 | 2.5rem (40px) | Bold | 1.2 |
| H2 | 2rem (32px) | Bold | 1.25 |
| H3 | 1.5rem (24px) | Semi Bold | 1.3 |
| H4 | 1.25rem (20px) | Semi Bold | 1.4 |
| Body | 1rem (16px) | Regular | 1.5 |
| Small | 0.875rem (14px) | Regular | 1.5 |
| Caption | 0.75rem (12px) | Regular | 1.4 |
Mode 1: Initialize (--init)¶
Generate design system files for a project.
PrimeNG Preset¶
Generate src/app/core/theme/vt-preset.ts using definePreset() from @primeuix/themes based on Aura, mapping VisiTrans colors to PrimeNG's three-tier model:
// src/app/core/theme/vt-preset.ts
import { definePreset } from '@primeuix/themes';
import Aura from '@primeuix/themes/aura';
export const vtPreset = definePreset(Aura, {
primitive: {
vtOrange: {
50: '#FFF8E6', 100: '#FFECB3', 200: '#FFE080', 300: '#FFD44D',
400: '#FFC826', 500: '#FC9E00', 600: '#E08C00', 700: '#CC5200',
800: '#993D00', 900: '#662900', 950: '#331400',
},
vtGray: {
50: '#F5F5F5', 100: '#E6E6E6', 200: '#D4D4D4', 300: '#B8B8B8',
400: '#A1A1A1', 500: '#8A8A8A', 600: '#737373', 700: '#5C5C5C',
800: '#454545', 900: '#2D2D2D', 950: '#1F1F1F',
},
vtMagenta: {
50: '#FFF0F7', 100: '#FFD6EA', 200: '#FFADD5', 300: '#FF85C0',
400: '#FF5CAB', 500: '#E6007E', 600: '#CC0070', 700: '#B30063',
800: '#990055', 900: '#660039', 950: '#33001D',
},
},
semantic: {
primary: {
50: '{vtOrange.50}', 100: '{vtOrange.100}', 200: '{vtOrange.200}',
300: '{vtOrange.300}', 400: '{vtOrange.400}', 500: '{vtOrange.500}',
600: '{vtOrange.600}', 700: '{vtOrange.700}', 800: '{vtOrange.800}',
900: '{vtOrange.900}', 950: '{vtOrange.950}',
},
colorScheme: {
light: {
surface: {
0: '#FFFFFF', 50: '{vtGray.50}', 100: '{vtGray.100}',
200: '{vtGray.200}', 300: '{vtGray.300}', 400: '{vtGray.400}',
500: '{vtGray.500}', 600: '{vtGray.600}', 700: '{vtGray.700}',
800: '{vtGray.800}', 900: '{vtGray.900}', 950: '{vtGray.950}',
},
formField: {
background: '#FFFFFF',
disabledBackground: '{vtGray.100}',
filledBackground: '{vtGray.50}',
borderColor: '{vtGray.300}',
hoverBorderColor: '{vtOrange.500}',
focusBorderColor: '{vtOrange.500}',
color: '{vtGray.950}',
disabledColor: '{vtGray.500}',
placeholderColor: '{vtGray.500}',
},
},
},
},
components: {
button: { borderRadius: '8px' },
card: { borderRadius: '12px' },
inputtext: { borderRadius: '8px' },
},
});
CSS Variables¶
/* src/styles.css */
/* GDPR: Self-host Inter font in production. Google Fonts CDN used here for prototyping only. */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@100;200;300;400;500;600;700;800;900&display=swap');
:root {
/* Primary Colors (for non-PrimeNG contexts) */
--vt-black: #1F1F1F;
--vt-orange: #FC9E00;
--vt-white: #FFFFFF;
/* Gray Scale */
--vt-gray-90: #2D2D2D;
--vt-gray-70: #5C5C5C;
--vt-gray-50: #8A8A8A;
--vt-gray-30: #B8B8B8;
--vt-gray-10: #E6E6E6;
/* Orange Scale */
--vt-orange-dark: #CC5200;
--vt-orange-light: #FF944D;
/* Action */
--vt-magenta: #E6007E;
/* Typography */
--vt-font-family: 'Inter', sans-serif;
/* Spacing */
--vt-space-xs: 4px;
--vt-space-sm: 8px;
--vt-space-md: 16px;
--vt-space-lg: 24px;
--vt-space-xl: 32px;
--vt-space-2xl: 48px;
/* Radii */
--vt-radius-sm: 4px;
--vt-radius-md: 8px;
--vt-radius-lg: 12px;
--vt-radius-xl: 16px;
}
body {
font-family: var(--vt-font-family);
color: var(--vt-black);
background-color: var(--vt-white);
}
Mode 2: Validate (--validate)¶
Check files for CD compliance issues.
Validation Rules¶
- Color Compliance
- No hardcoded hex colors outside palette
- Orange must be #FC9E00 (not close variants)
-
Action buttons use orange or magenta only
-
Typography Compliance
- Font family must be Inter
- No unapproved font weights
-
Headings follow type scale
-
Spacing Compliance
- Use design system spacing tokens
-
Consistent padding/margins
-
Component Compliance
- Buttons follow CD patterns
- Forms use approved styling
- Cards follow elevation rules
Validation Output¶
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
VisiTrans CD Validation
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Scanning: src/**/*.{tsx,css}
Issues Found: N
ERRORS (Must Fix):
─────────────────────────────────────────────────────────────────
• [file:line] Hardcoded color #FF5500 should be vt-orange (#FC9E00)
• [file:line] Font "Roboto" not in CD - use Inter
WARNINGS (Should Fix):
─────────────────────────────────────────────────────────────────
• [file:line] Consider using vt-gray-30 instead of #BBBBBB
• [file:line] Non-standard spacing 20px - use vt-md (16px) or vt-lg (24px)
PASSED:
─────────────────────────────────────────────────────────────────
✓ 45 files checked
✓ All buttons use approved variants
✓ Typography follows type scale
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Mode 3: Components (--components)¶
Generate VisiTrans-compliant Angular standalone component templates wrapping PrimeNG.
VtButtonComponent¶
// shared/components/vt-button/vt-button.component.ts
import { Component, input } from '@angular/core';
import { Button } from 'primeng/button';
@Component({
selector: 'vt-button',
standalone: true,
imports: [Button],
template: `
<p-button
[label]="label()"
[severity]="severityMap[variant()] ?? 'primary'"
[size]="size()"
[outlined]="variant() === 'outline'"
[text]="variant() === 'ghost'"
[styleClass]="variant() === 'action' ? 'vt-btn-action' : ''"
/>
`,
styles: [`
:host ::ng-deep .vt-btn-action.p-button {
background: var(--vt-magenta, #E6007E) !important;
border-color: var(--vt-magenta, #E6007E) !important;
color: #fff !important;
&:hover { opacity: 0.9; }
}
`],
})
export class VtButtonComponent {
label = input.required<string>();
variant = input<'primary' | 'secondary' | 'outline' | 'action' | 'ghost'>('primary');
size = input<'small' | 'large' | undefined>(undefined);
readonly severityMap: Record<string, string> = {
primary: 'primary',
secondary: 'secondary',
outline: 'primary',
ghost: 'secondary',
};
}
VtCardComponent¶
// shared/components/vt-card/vt-card.component.ts
import { Component, computed, input } from '@angular/core';
import { Card } from 'primeng/card';
@Component({
selector: 'vt-card',
standalone: true,
imports: [Card],
template: `
<p-card [styleClass]="elevationClass()">
<ng-content />
</p-card>
`,
})
export class VtCardComponent {
elevation = input<'flat' | 'raised' | 'elevated'>('raised');
elevationClass = computed(() => {
const map = { flat: 'border-1 surface-border shadow-none', raised: 'shadow-2', elevated: 'shadow-4' };
return map[this.elevation()];
});
}
VtInputComponent¶
// shared/components/vt-input/vt-input.component.ts
import { Component, input, model } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { InputText } from 'primeng/inputtext';
import { FloatLabel } from 'primeng/floatlabel';
@Component({
selector: 'vt-input',
standalone: true,
imports: [FormsModule, InputText, FloatLabel],
template: `
<div class="w-full">
<p-floatlabel>
<input pInputText [id]="inputId()" [(ngModel)]="value" [class.ng-invalid]="!!error()" class="w-full" />
<label [for]="inputId()">{{ label() }}</label>
</p-floatlabel>
@if (error()) {
<small class="p-error mt-1 block">{{ error() }}</small>
}
</div>
`,
})
export class VtInputComponent {
label = input.required<string>();
inputId = input.required<string>();
error = input<string | null>(null);
value = model<string>('');
}
VtNavigationComponent¶
// shared/components/vt-navigation/vt-navigation.component.ts
import { Component, input } from '@angular/core';
import { Menubar } from 'primeng/menubar';
import { MenuItem } from 'primeng/api';
@Component({
selector: 'vt-navigation',
standalone: true,
imports: [Menubar],
template: `
<p-menubar [model]="items()">
<ng-template pTemplate="start">
<img [src]="logoSrc()" [alt]="logoAlt()" [class]="'mr-3 ' + logoClass()" />
</ng-template>
</p-menubar>
`,
})
export class VtNavigationComponent {
items = input.required<MenuItem[]>();
logoSrc = input('/images/logo.svg');
logoAlt = input('VisiTrans');
logoClass = input('h-2rem');
}
Logo Usage¶
Logo Variants¶
- Primary: Full color on white background
- Inverted: White on dark/orange background
- Monochrome: Black for special cases
Clear Space¶
Minimum clear space around logo: Height of the "V" in VisiTrans
Minimum Sizes¶
- Digital: 80px width minimum
- Print: 25mm width minimum
Best Practices¶
Do's¶
- Use design tokens (not hardcoded values)
- Maintain consistent spacing
- Follow the type scale
- Use Orange for primary CTAs
- Use Magenta sparingly for special actions
Don'ts¶
- Don't modify the brand colors
- Don't use fonts other than Inter
- Don't stretch or distort the logo
- Don't use orange backgrounds with white text (contrast)
- Don't override default button styles without reason
Integration¶
This skill integrates with:
- /vt-c-kw-prototype - Applied during prototype creation
- /vt-c-pd-3-prototype - Applied during product design prototype creation
- /vt-c-visitrans-cd - Full CD document checker
- Design agents - For implementation review