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
| Mock | Purpose |
|---|---|
experimentStore.js | Experiment state and context |
socketClient.js | WebSocket communication |
dataServiceV3.js | Data collection service |
hlsPlayer.js | HLS video playback |
mediaPreloader.js | Media preloading |
firebaseConfig.js | Firebase services |
livekit-client.js | LiveKit video chat |
firebase-firestore.js | Firestore database |
firebase-auth.js | Firebase authentication |
notifications.js | Notification system |
variableManager.js | Experiment variables |
logger.js | Logging utilities |
Adding a New Mock
- Create
frontend/.storybook/mocks/myService.js:
// Mock implementation of myService
export function myFunction() {
console.log('[Mock] myFunction called');
return 'mocked value';
}
export default {
myFunction
};
- 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--defaultexperiment-multiplechoice--with-imageslivekit-videochat--default
Deployment
Storybook is automatically deployed when changes are pushed to:
.storybook/configurationsrc/stories/story files
The deployment workflow is in .github/workflows/deploy-storybook.yml.
Best Practices
- One story per variant - Create separate stories for different configurations
- Use defaultConfig - Start from schema defaults, override only what's needed
- Document variations - Add meaningful descriptions to each story
- Test interactions - Use stories to verify interactive behavior
- Keep mocks minimal - Only mock what's necessary for isolation
- 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.