Dial Examples

Real-world examples demonstrating various use cases of the Dial system.

3D Object Controller

A complete example for controlling 3D objects with transform, appearance, and physics properties.

// Box3D.tsx
type Vector3 = [number, number, number];
type Quaternion = [number, number, number, number];

interface Box3DProps {
  /**
   * Position in world space
   * @dial transform
   * @dial-dtype vector3
   * @dial-min -100
   * @dial-max 100
   * @dial-step 0.1
   * @dial-icon Move3d
   * @dial-label World Position
   */
  position: Vector3;

  /**
   * Rotation (Euler angles in degrees)
   * @dial transform
   * @dial-dtype euler
   * @dial-min -180
   * @dial-max 180
   * @dial-step 1
   * @dial-icon RotateCw
   */
  rotation: Vector3;

  /**
   * Scale factor
   * @dial transform
   * @dial-dtype vector3
   * @dial-min 0.1
   * @dial-max 10
   * @dial-step 0.1
   * @dial-icon Scaling
   */
  scale: Vector3;

  /**
   * Box dimensions
   * @dial geometry
   * @dial-layout grid
   * @dial-cols 3
   * @dial-dtype vector
   * @dial-mins [0.1, 0.1, 0.1]
   * @dial-maxs [20, 20, 20]
   * @dial-steps [0.1, 0.1, 0.1]
   * @dial-placeholders ["Width", "Height", "Depth"]
   * @dial-icon Box
   */
  size: Vector3;

  /**
   * Number of segments
   * @dial geometry
   * @dial-dtype vector
   * @dial-mins [1, 1, 1]
   * @dial-maxs [32, 32, 32]
   * @dial-steps [1, 1, 1]
   * @dial-dtypes ["int", "int", "int"]
   * @dial-placeholders ["W Segments", "H Segments", "D Segments"]
   * @dial-icon Grid3x3
   */
  segments: [number, number, number];

  /**
   * Base color
   * @dial appearance
   * @dial-dtype color
   * @dial-icon Palette
   * @dial-label Base Color
   */
  color: string;

  /**
   * Emissive color
   * @dial appearance
   * @dial-dtype color
   * @dial-icon Lightbulb
   * @dial-label Emissive
   */
  emissive: string;

  /**
   * Material type
   * @dial appearance
   * @dial-dtype select
   * @dial-options ["standard", "physical", "lambert", "phong", "toon"]
   * @dial-icon Sparkles
   */
  material: string;

  /**
   * Metalness (for physical material)
   * @dial appearance
   * @dial-min 0
   * @dial-max 1
   * @dial-step 0.01
   * @dial-icon Gem
   */
  metalness: number;

  /**
   * Roughness (for physical material)
   * @dial appearance
   * @dial-min 0
   * @dial-max 1
   * @dial-step 0.01
   * @dial-icon Brush
   */
  roughness: number;

  /**
   * Opacity
   * @dial appearance
   * @dial-min 0
   * @dial-max 1
   * @dial-step 0.01
   * @dial-icon Opacity
   */
  opacity: number;

  /**
   * Cast shadows
   * @dial rendering
   * @dial-dtype boolean
   * @dial-icon Moon
   */
  castShadow: boolean;

  /**
   * Receive shadows
   * @dial rendering
   * @dial-dtype boolean
   * @dial-icon Sun
   */
  receiveShadow: boolean;

  /**
   * Visible
   * @dial rendering
   * @dial-dtype boolean
   * @dial-icon Eye
   */
  visible: boolean;

  /**
   * Enable physics
   * @dial physics
   * @dial-dtype boolean
   * @dial-icon Zap
   * @dial-label Enable Physics
   */
  usePhysics: boolean;

  /**
   * Mass (kg)
   * @dial physics
   * @dial-min 0.1
   * @dial-max 1000
   * @dial-step 0.1
   * @dial-icon Weight
   */
  mass: number;

  /**
   * Friction coefficient
   * @dial physics
   * @dial-min 0
   * @dial-max 1
   * @dial-step 0.01
   * @dial-icon Grip
   */
  friction: number;

  /**
   * Restitution (bounciness)
   * @dial physics
   * @dial-min 0
   * @dial-max 1
   * @dial-step 0.01
   * @dial-icon ArrowBounce
   */
  restitution: number;
}

export const Box3D: React.FC<Box3DProps> = (props) => {
  // Your 3D rendering logic here
  return <mesh {...props} />;
};

UI Theme Editor

Control theme variables for a design system.

// ThemeEditor.tsx
type ColorRGB = [
  // @dial-min 0 @dial-max 255 @dial-step 1 @dial-dtype int
  r: number,
  // @dial-min 0 @dial-max 255 @dial-step 1 @dial-dtype int
  g: number,
  // @dial-min 0 @dial-max 255 @dial-step 1 @dial-dtype int
  b: number,
];

interface ThemeProps {
  /**
   * Primary brand color
   * @dial colors
   * @dial-dtype color
   * @dial-icon Palette
   * @dial-label Primary Color
   */
  primaryColor: string;

  /**
   * Secondary brand color
   * @dial colors
   * @dial-dtype color
   * @dial-icon Palette
   * @dial-label Secondary Color
   */
  secondaryColor: string;

  /**
   * Accent color
   * @dial colors
   * @dial-dtype color
   * @dial-icon Star
   * @dial-label Accent Color
   */
  accentColor: string;

  /**
   * Background color (RGB values)
   * @dial colors
   * @dial-icon PaintBucket
   * @dial-label Background RGB
   */
  backgroundColor: ColorRGB;

  /**
   * Base font size
   * @dial typography
   * @dial-dtype int
   * @dial-min 12
   * @dial-max 24
   * @dial-step 1
   * @dial-icon Type
   * @dial-label Base Font Size
   */
  baseFontSize: number;

  /**
   * Line height multiplier
   * @dial typography
   * @dial-min 1
   * @dial-max 2
   * @dial-step 0.1
   * @dial-icon AlignJustify
   */
  lineHeight: number;

  /**
   * Font weight
   * @dial typography
   * @dial-dtype select
   * @dial-options ["100", "200", "300", "400", "500", "600", "700", "800", "900"]
   * @dial-icon Bold
   */
  fontWeight: string;

  /**
   * Border radius
   * @dial layout
   * @dial-layout grid
   * @dial-cols 2
   * @dial-dtype int
   * @dial-min 0
   * @dial-max 32
   * @dial-step 1
   * @dial-icon RoundedCorner
   * @dial-label Corner Radius
   */
  borderRadius: number;

  /**
   * Spacing unit
   * @dial layout
   * @dial-dtype int
   * @dial-min 2
   * @dial-max 16
   * @dial-step 1
   * @dial-icon Ruler
   * @dial-label Spacing Unit
   */
  spacingUnit: number;

  /**
   * Enable dark mode
   * @dial preferences
   * @dial-dtype boolean
   * @dial-icon Moon
   */
  darkMode: boolean;

  /**
   * Enable animations
   * @dial preferences
   * @dial-dtype boolean
   * @dial-icon Sparkles
   */
  enableAnimations: boolean;

  /**
   * Animation duration (ms)
   * @dial preferences
   * @dial-dtype int
   * @dial-min 100
   * @dial-max 2000
   * @dial-step 50
   * @dial-icon Clock
   */
  animationDuration: number;
}

Data Visualization Controls

Configure chart and graph properties.

// ChartControls.tsx
interface ChartProps {
  /**
   * Chart type
   * @dial chart
   * @dial-dtype select
   * @dial-options ["line", "bar", "pie", "scatter", "area", "bubble"]
   * @dial-icon BarChart
   * @dial-label Chart Type
   */
  type: string;

  /**
   * Chart title
   * @dial chart
   * @dial-dtype string
   * @dial-icon Type
   */
  title: string;

  /**
   * Show legend
   * @dial chart
   * @dial-dtype boolean
   * @dial-icon List
   */
  showLegend: boolean;

  /**
   * X-axis range
   * @dial axes
   * @dial-layout grid
   * @dial-cols 2
   * @dial-dtype vector2
   * @dial-mins [-1000, -1000]
   * @dial-maxs [1000, 1000]
   * @dial-steps [1, 1]
   * @dial-placeholders ["Min", "Max"]
   * @dial-icon ArrowLeftRight
   * @dial-label X-Axis Range
   */
  xRange: [number, number];

  /**
   * Y-axis range
   * @dial axes
   * @dial-dtype vector2
   * @dial-mins [-1000, -1000]
   * @dial-maxs [1000, 1000]
   * @dial-steps [1, 1]
   * @dial-placeholders ["Min", "Max"]
   * @dial-icon ArrowUpDown
   * @dial-label Y-Axis Range
   */
  yRange: [number, number];

  /**
   * Grid color
   * @dial styling
   * @dial-dtype color
   * @dial-icon Grid3x3
   */
  gridColor: string;

  /**
   * Line thickness
   * @dial styling
   * @dial-dtype int
   * @dial-min 1
   * @dial-max 10
   * @dial-step 1
   * @dial-icon Minus
   */
  lineWidth: number;

  /**
   * Point size
   * @dial styling
   * @dial-dtype int
   * @dial-min 1
   * @dial-max 20
   * @dial-step 1
   * @dial-icon Circle
   */
  pointSize: number;

  /**
   * Animation enabled
   * @dial animation
   * @dial-dtype boolean
   * @dial-icon Play
   */
  animated: boolean;

  /**
   * Animation duration (seconds)
   * @dial animation
   * @dial-min 0.1
   * @dial-max 5
   * @dial-step 0.1
   * @dial-icon Timer
   */
  animationDuration: number;
}

Game Settings Panel

Configure game parameters and difficulty settings.

// GameSettings.tsx
interface GameSettingsProps {
  /**
   * Difficulty level
   * @dial gameplay
   * @dial-dtype select
   * @dial-options ["easy", "normal", "hard", "extreme"]
   * @dial-icon Gamepad2
   * @dial-label Difficulty
   */
  difficulty: string;

  /**
   * Player speed
   * @dial player
   * @dial-min 1
   * @dial-max 20
   * @dial-step 0.5
   * @dial-icon Zap
   */
  playerSpeed: number;

  /**
   * Jump height
   * @dial player
   * @dial-min 1
   * @dial-max 10
   * @dial-step 0.5
   * @dial-icon ArrowUp
   */
  jumpHeight: number;

  /**
   * Health points
   * @dial player
   * @dial-dtype int
   * @dial-min 1
   * @dial-max 200
   * @dial-step 1
   * @dial-icon Heart
   */
  health: number;

  /**
   * Master volume
   * @dial audio
   * @dial-layout grid
   * @dial-cols 2
   * @dial-min 0
   * @dial-max 100
   * @dial-step 1
   * @dial-icon Volume2
   */
  masterVolume: number;

  /**
   * Music volume
   * @dial audio
   * @dial-min 0
   * @dial-max 100
   * @dial-step 1
   * @dial-icon Music
   */
  musicVolume: number;

  /**
   * SFX volume
   * @dial audio
   * @dial-min 0
   * @dial-max 100
   * @dial-step 1
   * @dial-icon AudioWaveform
   */
  sfxVolume: number;

  /**
   * Enable voice chat
   * @dial audio
   * @dial-dtype boolean
   * @dial-icon Mic
   */
  voiceChat: boolean;

  /**
   * Graphics quality
   * @dial graphics
   * @dial-dtype select
   * @dial-options ["low", "medium", "high", "ultra"]
   * @dial-icon Monitor
   */
  graphicsQuality: string;

  /**
   * Resolution scale
   * @dial graphics
   * @dial-min 50
   * @dial-max 200
   * @dial-step 10
   * @dial-icon Maximize
   */
  resolutionScale: number;

  /**
   * Enable shadows
   * @dial graphics
   * @dial-dtype boolean
   * @dial-icon Moon
   */
  shadows: boolean;

  /**
   * Anti-aliasing
   * @dial graphics
   * @dial-dtype select
   * @dial-options ["none", "FXAA", "TAA", "MSAA x2", "MSAA x4", "MSAA x8"]
   * @dial-icon Brush
   */
  antiAliasing: string;
}

Usage with Generated Schema

After generating schemas with the CLI, integrate them into your application:

// App.tsx
import React, { useState } from 'react';
import { DialProvider, DialPanel } from '@vuer-ai/vuer-uikit';
import { Box3D } from './Box3D';
import dialSchemas from './metadata/schema.dial';

// Extract the Box3D schema
const box3DSchema = dialSchemas.find(s => s.component === 'Box3D');

function App() {
  const [box3DProps, setBox3DProps] = useState({
    position: [0, 0, 0],
    rotation: [0, 0, 0],
    scale: [1, 1, 1],
    size: [1, 1, 1],
    segments: [1, 1, 1],
    color: '#3b82f6',
    emissive: '#000000',
    material: 'standard',
    metalness: 0,
    roughness: 0.5,
    opacity: 1,
    castShadow: true,
    receiveShadow: true,
    visible: true,
    usePhysics: false,
    mass: 1,
    friction: 0.5,
    restitution: 0.5
  });

  const handleValueChange = (name: string, value: any) => {
    setBox3DProps(prev => ({ ...prev, [name]: value }));
  };

  return (
    <div className="flex">
      <div className="w-1/3 p-4">
        <h2>3D Box Controls</h2>
        <DialProvider
          schemas={box3DSchema.schemas}
          onValueChange={handleValueChange}
        >
          <DialPanel
            schemas={box3DSchema.schemas}
            groups={box3DSchema.groups}
          />
        </DialProvider>
      </div>
      <div className="w-2/3 p-4">
        <h2>3D Preview</h2>
        <Box3D {...box3DProps} />
      </div>
    </div>
  );
}

Best Practices

Organize properties into logical groups for better UX:

// Good: Grouped by concern
interface Props {
  /** @dial transform */
  x: number;
  /** @dial transform */
  y: number;

  /** @dial appearance */
  color: string;
  /** @dial appearance */
  opacity: number;
}

2. Use Descriptive Labels

Provide clear labels for better understanding:

interface Props {
  /**
   * @dial settings
   * @dial-label "Maximum Retry Attempts"
   */
  maxRetries: number;

  /**
   * @dial settings
   * @dial-label "Connection Timeout (seconds)"
   */
  timeout: number;
}

3. Set Appropriate Constraints

Define sensible min/max values:

interface Props {
  /**
   * @dial performance
   * @dial-min 1
   * @dial-max 120
   * @dial-step 1
   * @dial-label "Target FPS"
   */
  targetFPS: number;
}

4. Use Icons for Visual Clarity

Add icons to improve visual recognition:

interface Props {
  /** @dial controls @dial-icon Play */
  play: boolean;

  /** @dial controls @dial-icon Pause */
  pause: boolean;

  /** @dial controls @dial-icon SkipForward */
  next: boolean;
}

Next Steps