Skip to content

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-family: 'Inter', sans-serif;

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

  1. Color Compliance
  2. No hardcoded hex colors outside palette
  3. Orange must be #FC9E00 (not close variants)
  4. Action buttons use orange or magenta only

  5. Typography Compliance

  6. Font family must be Inter
  7. No unapproved font weights
  8. Headings follow type scale

  9. Spacing Compliance

  10. Use design system spacing tokens
  11. Consistent padding/margins

  12. Component Compliance

  13. Buttons follow CD patterns
  14. Forms use approved styling
  15. 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