⭐ If Reframe helped you, star the repo — it helps more people discover it!
💬 Have a question or idea? Head to Discussions instead of opening an issue.
🟢 Ready to contribute? Check out our Good First Issues — perfect for first-time contributors!
First off, thank you for considering contributing to Reframe! 🎉
Whether you're fixing a typo, adding a feature, improving accessibility, or writing a test — every contribution makes Reframe better for everyone.
If you have a bug or an idea, read this guide before opening an issue.
If you're ready to tackle some open issues, we've collected some good first issues for you.
- Getting Started
- Development Setup
- Project Structure
- Finding Issues
- Claiming Issues
- Making Changes
- Submitting a Pull Request
- Code Style
- Development Tips
- GSSoC'26 Participants
- Code of Conduct
# 1. Fork the repo by clicking 'Fork' on GitHub
# 2. Clone your fork
git clone https://github.com/<your-username>/reframe.git
cd reframe
# 3. Add the upstream remote
git remote add upstream https://github.com/magic-peach/reframe.git# Install dependencies
bun install
# Start the development server
bun run devOpen http://localhost:3000. Changes to components reflect instantly with Next.js Fast Refresh.
bun run build # Build for production (outputs to out/)
bun run lint # Run ESLint
bunx tsc --noEmit # Run TypeScript type checkingreframe/
├── src/
│ ├── app/
│ │ ├── layout.tsx # Root layout, metadata, fonts
│ │ ├── page.tsx # Home page
│ │ └── globals.css # Global styles
│ ├── components/
│ │ ├── VideoEditor.tsx # Root editor component
│ │ ├── FileUpload.tsx # Drag-drop file upload
│ │ ├── VideoPreview.tsx # HTML5 video player
│ │ ├── PresetSelector.tsx # 11 preset formats + custom
│ │ ├── FramingControl.tsx # Fit/Fill framing toggle
│ │ ├── TrimControl.tsx # Start/end time inputs
│ │ ├── RotateControl.tsx # Rotation buttons
│ │ ├── AudioSpeedControl.tsx # Audio + speed
│ │ ├── ExportSettings.tsx # Quality CRF slider
│ │ ├── ExportOverlay.tsx # Export progress modal
│ │ ├── DownloadResult.tsx # Success + download
│ │ └── LottiePlayer.tsx # Lottie animation wrapper
│ ├── hooks/
│ │ └── useVideoEditor.ts # Main state management hook
│ └── lib/
│ ├── ffmpeg.ts # FFmpeg wrapper & filter builders
│ ├── presets.ts # Preset definitions
│ └── types.ts # TypeScript types
├── public/ # Static assets
├── next.config.ts
├── tailwind.config.ts
└── tsconfig.json
This project uses Next.js Fast Refresh in development mode. Most changes to React components, hooks, and styles are reflected instantly in the browser without restarting the dev server.
- Component updates appear immediately
- State is often preserved during edits
- Restarting
npm run devis usually unnecessary for UI changes
Learn more: https://nextjs.org/docs/architecture/fast-refresh
Changes to ffmpeg.ts may not hot-reload correctly because FFmpeg initialization and WebAssembly modules can persist in memory.
If updates are not reflected:
- Perform a full browser page reload
- Clear cached worker instances if necessary
- Restart the development server only when required
FFmpeg WASM reference: https://ffmpegwasm.netlify.app/docs/overview
FFmpeg WebAssembly assets can be large and may take time to download during development.
Use the browser DevTools Network tab to:
- Verify FFmpeg assets are loading correctly
- Inspect caching behavior
- Detect failed
.wasmor worker requests - Measure initialization performance
Chrome DevTools: https://developer.chrome.com/docs/devtools/network
Install React DevTools for easier component inspection and debugging.
Helpful for:
- Inspecting component props and state
- Tracing re-renders
- Debugging hooks
- Monitoring React component trees
React DevTools: https://react.dev/learn/react-developer-tools
The browser console provides important runtime diagnostics for:
- FFmpeg initialization issues
- Hydration warnings
- API request failures
- WebAssembly loading errors
Filtering logs by warnings/errors can speed up debugging significantly.
Development builds include source maps, allowing you to debug original TypeScript/React source files directly from DevTools.
Tips:
- Set breakpoints in source files
- Use async stack traces
- Inspect runtime variables during rendering
JavaScript debugging guide: https://developer.chrome.com/docs/devtools/javascript
FFmpeg WebAssembly processing can consume significant browser memory during video operations.
Recommendations:
- Close unused tabs while testing
- Refresh the page after heavy processing tasks
- Monitor memory usage in browser performance tools
Performance tools: https://developer.chrome.com/docs/devtools/performance
After modifying .env.local, restart the Next.js development server because environment variables are loaded only during server startup.
Example:
npm run devEnvironment variables guide: https://nextjs.org/docs/app/guides/environment-variables
We have 300+ open issues across all skill levels:
| Level | Where to look |
|---|---|
| 🟢 Beginner | good first issue label — 100+ beginner tasks |
| 🟡 Intermediate | enhancement label |
| 🔴 Advanced | feature label |
| 🐛 Bug Fixes | bug label |
| ♿ Accessibility | accessibility label |
| 📝 Documentation | documentation label |
| 🔒 Security | security label |
| ⚡ Performance | performance label |
Before claiming an issue:
- Check if it already has an assignee — if so, pick a different one
- Comment
/assignon the issue to claim it instantly via our bot - If an issue has been idle and unassigned for a while, it's fair game
We use a bot to automatically manage issue assignments. Here's how it works:
Comment /assign on any open issue to claim it:
- The bot will assign it to you instantly
- You have 5 days to make progress before it is automatically unassigned
- You can only hold 5 issues at a time across the repo
If you can no longer work on an issue, comment /unassign to release it:
- This frees it up for other contributors immediately
- No hard feelings — we appreciate the honesty!
- ✅ First person to comment
/assigngets the issue - ✅ Only one contributor can be assigned per issue at a time
- ✅ Maximum 5 issues per contributor at once
⚠️ You will get a warning after 2 days of no activity⚠️ You will get a final warning after 4 days of no activity- ❌ Issue is automatically unassigned after 5 days of no activity
The bot will ping you if your assigned issue has no activity:
- Day 2 — friendly reminder to update your progress
- Day 4 — final warning, 24 hours left before unassignment
- Day 5 — automatic unassignment, issue reopens for others
- Leave a comment on your issue if you are stuck or need help — any comment resets the inactivity timer
- Link your PR to the issue using
Fixes #issue_numberin your PR description - If you see an issue already assigned, please pick a different one
git checkout -b feat/your-feature-name
# or
git checkout -b fix/bug-description
# or
git checkout -b docs/what-you-documented- Keep changes focused — one issue per PR
- Test your changes in the browser (test file upload, export, and download)
- Make sure
bun run lintpasses - Make sure
bunx tsc --noEmitpasses (no TypeScript errors)
git add <files>
git commit -m "feat: add aria-label to export button"Commit message format:
feat:— new featurefix:— bug fixdocs:— documentation changesrefactor:— code refactoring (no behavior change)test:— adding or fixing testsstyle:— formatting, whitespace changeschore:— build config, dependencies
- Push your branch:
git push origin feat/your-feature-name - Go to your fork on GitHub and click "Compare & pull request"
- Fill in the PR template:
- Describe what you changed and why
- Reference the issue:
Closes #<issue-number> - Attach a screen recording (required for UI/feature changes — see below)
- Submit the PR — maintainers will review within a few days
Any PR that adds or modifies a UI element, a user-facing feature, or any visual behaviour must include a screen recording of the working change running on your local machine.
This is a hard requirement — PRs without a recording will not be merged until one is added.
What to record:
- Run
bun run devand openhttp://localhost:3000 - Demonstrate the full working flow of your change (e.g. upload a video → use the new control → export → see the result)
- Show any edge cases your implementation handles (empty state, error state, etc.)
How to record:
- macOS:
Cmd + Shift + 5→ Record Selected Portion, or use QuickTime Player - Windows:
Win + G→ Xbox Game Bar → Capture - Linux: OBS Studio, GNOME Screenshot tool, or
kazam - Any OS: Loom (free, great for sharing)
Attach the recording directly to the PR by dragging the file into the GitHub comment box, or paste a Loom/shareable link.
- Code works in Chrome, Firefox, and Safari
- No new TypeScript errors (
bunx tsc --noEmit) - ESLint passes (
bun run lint) - UI changes tested on mobile (use browser DevTools)
- Accessibility: new interactive elements have ARIA labels
- Issue number referenced in PR description
- Screen recording attached (required for all UI/feature PRs)
- TypeScript: Strict types, no
anyunless absolutely necessary - React: Functional components only, use hooks
- Tailwind: Use utility classes; avoid inline
style={}for static styles - No comments: Code should be self-documenting via good naming; only add comments for non-obvious behavior
- No console.log: Remove debug logs before submitting
- Imports: Use relative imports within
src/
- Fast Refresh: Changes to React components update instantly without losing state
- FFmpeg changes: Changes to
src/lib/ffmpeg.tsmay require a full page reload - Testing exports: Keep a few small test videos (~5-10 MB) for quick export testing
- React DevTools: Install the React DevTools browser extension for component inspection
- Network throttling: Use Chrome DevTools Network tab → "Slow 3G" to test FFmpeg download behavior
- Mobile testing: Chrome DevTools → Device Toolbar to test responsive layouts
- Accessibility testing: Use axe DevTools browser extension
Reframe is an official GirlScript Summer of Code 2026 project!
- Browse issues labeled
gssoc'26 - Start with
good first issueif you're new to open source - Comment
/assignon the issue — our bot will assign it to you instantly, no maintainer needed - Submit your PR within 5 days and remember to link it with
Fixes #issue_number
- Read the issue fully before starting — ask questions in comments if anything is unclear
- Small, focused PRs are merged faster than large ones
- Quality over quantity — one well-implemented feature beats five half-done ones
- Be communicative — comment on your progress, especially if you're stuck
- Test thoroughly — check your changes work before submitting
- Found a bug? → Open a bug report
- Have a feature idea? → Open a feature request
- Stuck on an issue? → Comment on the issue and tag
@magic-peach
We expect all contributors to follow our Code of Conduct to create a safe, welcoming, and inclusive community.
- Be respectful and welcoming.
- Harassment and discrimination are strictly prohibited.
- Constructive feedback is encouraged.
Thank you for making Reframe better! 🎬
This project uses Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy
headers to enable cross-origin isolation, which allows FFmpeg.wasm to run in
multi-threaded mode for significantly faster video exports.
GitHub Pages does not support custom HTTP headers. If you are deploying to GitHub Pages, cross-origin isolation cannot be enabled and FFmpeg will automatically fall back to single-threaded mode.
For full multi-threading support, deploy to Vercel, Netlify, or Cloudflare Pages where custom headers are supported.