Skip to main content

Storybook

HyperStudy uses Storybook for component development, documentation, and visual testing. Our Storybook is deployed at storybook.hyperstudy.io.

Overview

Storybook provides:

  • Live component demos for all experiment components
  • Interactive controls to test different configurations
  • Auto-generated documentation from component schemas
  • Visual regression testing baseline
  • Design token reference

Running Locally

cd frontend
npm run storybook

This starts Storybook at http://localhost:6006.

Story Structure

Stories are located in frontend/src/stories/ and organized by category:

src/stories/
├── experiment/ # Experiment components
│ ├── ShowText.stories.js
│ ├── ShowVideo.stories.js
│ ├── MultipleChoice.stories.js
│ ├── TextInput.stories.js
│ ├── VasRating.stories.js
│ └── ...
├── livekit/ # LiveKit components
│ ├── VideoChat.stories.js
│ └── TextChat.stories.js
├── shared/ # Shared UI components
│ └── MediaDeviceSetup.stories.js
└── utils/ # Story utilities
└── schemaToArgTypes.js

Creating Stories

Basic Story Template

/**
* ComponentName Component Stories
*
* Brief description of the component.
*/

import MyComponent from '../../components/experiment/MyComponent.svelte';
import { getDefaultConfig, componentTypes } from '../utils/schemaToArgTypes';

const componentType = componentTypes.MYCOMPONENT;
const defaultConfig = getDefaultConfig(componentType);

export default {
title: 'Experiment/MyComponent',
component: MyComponent,
tags: ['autodocs'],
argTypes: {
config: {
description: 'Component configuration object',
control: { type: 'object' }
}
},
parameters: {
docs: {
description: {
component: 'Detailed description for documentation.'
}
},
backgrounds: { default: 'dark' }
}
};

// Default story
export const Default = {
args: {
config: {
...defaultConfig,
// Override specific props
prompt: 'Example prompt text'
}
}
};

// Variation stories
export const WithCustomStyling = {
args: {
config: {
...defaultConfig,
backgroundColor: '#1a237e',
textColor: '#ffffff'
}
}
};

Using schemaToArgTypes

The schemaToArgTypes utility automatically generates Storybook controls from component config schemas:

import {
schemaToArgTypes,
getDefaultConfig,
getComponentInfo,
componentTypes
} from '../utils/schemaToArgTypes';

const componentType = componentTypes.TEXTINPUT;

// Get component metadata
const info = getComponentInfo(componentType);

// Get default configuration values
const defaultConfig = getDefaultConfig(componentType);

// Generate Storybook argTypes from schema
const argTypes = schemaToArgTypes(componentType);

This provides:

  • Automatic controls for all config properties
  • Correct control types (text, number, boolean, select, etc.)
  • Default values from the schema
  • Descriptions from schema documentation

Mock System

Storybook uses mocks to isolate components from runtime dependencies. Mocks are in frontend/.storybook/mocks/.

Available Mocks

MockPurpose
experimentStore.jsExperiment state and context
socketClient.jsWebSocket communication
dataServiceV3.jsData collection service
hlsPlayer.jsHLS video playback
mediaPreloader.jsMedia preloading
firebaseConfig.jsFirebase services
livekit-client.jsLiveKit video chat
firebase-firestore.jsFirestore database
firebase-auth.jsFirebase authentication
notifications.jsNotification system
variableManager.jsExperiment variables
logger.jsLogging utilities

Adding a New Mock

  1. Create frontend/.storybook/mocks/myService.js:
// Mock implementation of myService
export function myFunction() {
console.log('[Mock] myFunction called');
return 'mocked value';
}

export default {
myFunction
};
  1. Add alias in frontend/.storybook/main.js:
resolve: {
alias: {
'$lib/services/myService': resolve(__dirname, 'mocks/myService.js'),
'../../lib/services/myService': resolve(__dirname, 'mocks/myService.js'),
}
}

Storybook Addons

We use the following Storybook addons:

Essentials

Standard controls, actions, viewport, and docs panels.

Design Token Addon

Displays CSS custom properties (design tokens) in a dedicated panel:

  • Colors
  • Spacing
  • Typography
  • Z-index values

Embedding in Documentation

Stories can be embedded in Docusaurus docs using the StorybookEmbed component:

import StorybookEmbed from '@site/src/components/StorybookEmbed';

// Basic embed
<StorybookEmbed story="experiment-textinput--default" height="400px" />

// With controls panel
<StorybookEmbed story="experiment-vasrating--default" showControls height="600px" />

Story ID Format

Story IDs follow the pattern: category-componentname--storyname

Examples:

  • experiment-showtext--default
  • experiment-multiplechoice--with-images
  • livekit-videochat--default

Deployment

Storybook is automatically deployed when changes are pushed to:

  • .storybook/ configuration
  • src/stories/ story files

The deployment workflow is in .github/workflows/deploy-storybook.yml.

Best Practices

  1. One story per variant - Create separate stories for different configurations
  2. Use defaultConfig - Start from schema defaults, override only what's needed
  3. Document variations - Add meaningful descriptions to each story
  4. Test interactions - Use stories to verify interactive behavior
  5. Keep mocks minimal - Only mock what's necessary for isolation
  6. Tag with autodocs - Enable automatic documentation generation

Troubleshooting

Component Not Rendering

Check if a required module needs mocking. Look for import errors in the browser console.

Missing Controls

Ensure the component is using schemaToArgTypes or has explicit argTypes defined.

Styles Not Applied

Design tokens are loaded in preview.js. Verify the token file is imported correctly.