Thank you for your interest in contributing to MetaHuman Engine!
Found a bug? Please create an issue with:
- Clear description of the problem
- Steps to reproduce
- Expected vs actual behavior
- Environment details (OS, browser, versions)
- Screenshots/recordings if applicable
Have an idea? Open an issue with:
- Use case description
- Proposed solution
- Alternatives considered
Want to fix a bug or add a feature? Follow the workflow below.
Improvements to docs, README, or code comments are always welcome.
# Fork the repository on GitHub, then:
git clone https://github.com/your-username/meta-human.git
cd meta-human
git remote add upstream https://github.com/LessUp/meta-human.git# Frontend
npm install
# Backend (optional)
cd examples/backend-python
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt
cd ..git checkout master
git pull --ff-only origin master- Do not add AI workflow frameworks, generated skill systems, or repository-scoped agent control files
- Keep the product surface focused on the landing page, the
/appruntime, and the localized docs site - Record user-visible history only in the root
CHANGELOG.md
Follow Conventional Commits:
<type>(<scope>): <subject>
<body>
<footer>
Types:
| Type | Description |
|---|---|
feat |
New feature |
fix |
Bug fix |
docs |
Documentation changes |
style |
Code style (formatting, semicolons, etc.) |
refactor |
Code refactoring |
perf |
Performance improvements |
test |
Adding or updating tests |
chore |
Maintenance tasks |
Examples:
feat(avatar): add wave animation trigger
docs(api): update WebSocket documentation
fix(dialogue): resolve memory leak in streamNaming:
PascalCasefor components, types, interfacescamelCasefor functions, variablesSCREAMING_SNAKE_CASEfor constants
Imports:
// 1. External imports
import React from 'react';
// 2. Internal absolute imports
import { Button } from '@/components/ui/Button';
// 3. Internal relative imports
import { helper } from './utils';Comments:
// Good: Explains why, not what
// Retry with exponential backoff for network resilience
await retry(operation, { delay: 1000 * attempts });
// Bad: Restates the code
// Multiply delay by attempts
delay = 1000 * attempts;The project uses automated formatting:
# Format code
npm run format
# Check formatting
npm run format:check
# Lint
npm run lint
# Fix lint issues
npm run lint:fix# Watch mode
npm run test
# Single run
npm run test:run
# With coverage
npm run test:coverageComponent Example:
import { render, screen } from '@testing-library/react';
import { ChatDock } from './ChatDock';
describe('ChatDock', () => {
it('renders input field', () => {
render(<ChatDock />);
expect(screen.getByPlaceholderText('Type a message...')).toBeInTheDocument();
});
});Hook Example:
import { renderHook } from '@testing-library/react';
import { useChatStream } from './useChatStream';
describe('useChatStream', () => {
it('sends message successfully', async () => {
const { result } = renderHook(() => useChatStream());
await result.current.sendMessage('Hello');
expect(result.current.messages).toHaveLength(1);
});
});- Code follows style guidelines
- Tests pass:
npm run test:run - Linting passes:
npm run lint - TypeScript compiles:
npm run typecheck - Commits follow conventional format
- Documentation updated if needed
- Push branch to your fork
- Open PR against
masterbranch - Fill out PR template
- Link related issues
- Maintainers will review within 48 hours
- Address review comments
- Keep PR focused on single concern
Once approved, a maintainer will merge your PR.
src/
├── components/ # UI, landing, viewer, and shared primitives
├── core/ # Runtime services without React imports
│ ├── avatar/ # 3D avatar engine
│ ├── audio/ # TTS/ASR services
│ ├── dialogue/ # Dialogue orchestration and transports
│ ├── performance/ # Device capability handling
│ ├── vision/ # Face and pose processing
│ └── voiceCommand/ # Voice command execution
├── hooks/ # UI orchestration hooks
├── lib/ # Shared utilities
├── pages/ # Route-level pages
├── store/ # Zustand stores
└── __tests__/ # Tests
- Create file:
components/ComponentName.tsx - Add styles (Tailwind classes)
- Add types if complex props
- Write tests
- Export from
components/index.ts
- Create file:
hooks/useHookName.ts - Follow existing hook patterns
- Add JSDoc comments
- Write tests
- Export from
hooks/index.ts
- Create file:
store/storeName.ts - Use Zustand pattern
- Define TypeScript interfaces
- Add persistence if needed
- Document public API
Use JSDoc for public APIs:
/**
* Send a chat message and receive streaming response
* @param message - User's message text
* @param options - Streaming callbacks
* @returns Promise that resolves when stream completes
* @throws {ChatError} When transport fails
*/
async function streamMessage(message: string, options: StreamOptions): Promise<void>;When adding features:
- Update main README.md if user-facing
- Update
docs/en/anddocs/zh/if product or API behavior changes - Update the root
CHANGELOG.mdwhen the change is user-visible
- Issues: Bug reports, feature requests
- Discussions: Questions, ideas, show-and-tell
- Pull Requests: Code contributions
- Be respectful and inclusive
- Welcome newcomers
- Focus on constructive feedback
- Respect differing viewpoints
- Check existing issues
- Start a discussion
- Ask in your PR/issue
Thank you for contributing to MetaHuman Engine! 🎉