Music Composer is a compact, demo-grade music sketching app that generates short musical ideas and lets you edit, play and export them using a piano-roll UI. It focuses on performance, small initial bundles (lazy-loading), and workerized heavy work so the UI stays snappy on mobile and desktop.
This README explains everything a new visitor or contributor needs to know: features, pages/routes, setup, development workflow, exports, CI/tests, and how to fork & contribute.
Place these files in the repository assets/ folder (project root) so GitHub can render them in the README:
assets/demo.gif— short animated demo (recommended: 600×340 GIF)assets/home.png— Home page screenshot (recommended: 1280×720 PNG)assets/composer.png— Composer page screenshot (recommended: 1280×720 PNG)assets/notfound.png— 404 / NotFound screenshot (recommended: 800×400 PNG)
Example embed (relative paths used for GitHub rendering):
If images don't appear, ensure they are committed and pushed, use relative paths, and check filename case.
- Emotion-driven generators: dynamic, emotion-based melody and chord generation (uses
src/engine/generators/*). - Piano-roll editor: 16-step grid with note toggling, responsive layout and touch gestures (drag-to-scroll and pinch-to-zoom) implemented in
src/features/composer/PianoRoll.tsx. - Playback: lazy-loaded Tone.js playback via
src/lib/audio.tsandplayComposition()with tempo, quantize and swing controls. - Exporters: MIDI exporter (
src/engine/exporters/midi.exporter.ts) and WAV exporter with worker-based renderer and main-thread fallback (src/engine/exporters/wav.exporter.ts,src/workers/render.worker.ts,src/engine/exporters/wav.render.fallback.ts). - Batch exports and presets: preset list in
src/engine/presets.tsand batch export workflow insrc/features/composer/ComposerControls.tsx. - Web Workers: generator worker (
src/workers/generator.worker.ts) for async generation and a renderer worker for offline WAV rendering. - Undo/redo history: snapshot-based history persisted to
localStoragewith trimming to limit size (src/features/composer/composer.store.ts). - UI helpers: mobile bottom sheet (
src/components/MobileBottomSheet.tsx), history panel (src/components/HistoryPanel.tsx), and toast notifications (src/components/Toast.tsx). - Tests: example unit tests using Vitest (see
src/engine/generators/emotion.generator.test.ts). - Performance-minded: dynamic imports and workerization are used to keep the initial bundle small and keep heavy work off the main thread.
- Framework: React (TypeScript) with Vite
- Audio: Tone.js (lazy-loaded) and WebAudio API
- State: Zustand for composer store
- Build & dev: Vite
- Testing: Vitest (unit tests)
- Export/Workers: Custom Web Workers (
src/workers), WAV renderer and simple MIDI exporter - Styling: Tailwind CSS (utility-first) and small global CSS helpers
/— Home page (src/pages/HomePage.tsx)/composer— Composer editor (piano-roll, controls) (src/pages/ComposerPage.tsx)- Any other path — NotFound page (src/pages/NotFoundPage.tsx)
Routes are configured in src/app/router.tsx and mounted in the main app shell.
src/engine/generators/— Melody/chord/rhythm/emotion generatorssrc/engine/exporters/— MIDI and WAV exporterssrc/workers/— Generator and renderer web workerssrc/features/composer/— Composer UI,PianoRoll.tsx,ComposerControls.tsx, andcomposer.store.tssrc/lib/audio.ts— audio playback helpers (lazy-load Tone.js)src/components/— shared UI (Header, Toasts, HistoryPanel, MobileBottomSheet)
Prerequisites: Node.js >= 20.19.0 (Node 20 LTS recommended) and npm or pnpm.
Run the following to get started locally (copy/paste):
# check node version (must be >= 20.19.0)
node -v
# install dependencies (use --legacy-peer-deps if you hit peer conflicts on npm)
npm install
# or: npm install --legacy-peer-deps
# start dev server (HMR)
npm run dev
# run tests once
npm test
# run linter
npm run lint
# build production bundle
npm run build
# preview built app locally
npm run previewIf you're using pnpm replace npm with pnpm for the above commands.
- Open
/composer. - Choose an emotion or preset and hit Generate.
- Edit notes directly on the piano-roll (tap/click to toggle). Mobile supports drag-to-scroll and pinch-to-zoom for the note rows.
- Adjust quantize, swing and tempo from the advanced controls (bottom sheet on mobile).
- Play the composition (Tone.js loads on first play).
- Export as MIDI or WAV using the Export buttons — WAV rendering happens in a worker for offline export.
- MIDI: simple single-track MIDI exporter at
src/engine/exporters/midi.exporter.ts. - WAV: offline renderer with a Web Worker (
src/workers/render.worker.ts) and a main-thread fallback (src/engine/exporters/wav.render.fallback.ts). - MP3: not included by default due to encoder dependencies; to add MP3, consider
lamejsor server-side encoding.
Batch export presets are provided (see src/engine/presets.ts) and can be exported in sequence with progress UI and ZIP packaging (if enabled).
- Generation and offline rendering are moved to Web Workers to avoid blocking the UI. Generators are also dynamically imported to keep the initial bundle small.
- Tone.js is lazy-loaded at playback time to reduce initial download.
- A GitHub Actions workflow is configured to run build, lint and tests on push/PR (.github/workflows/ci.yml).
- Unit tests use
vitestand can be executed withnpm test.
- Fork the repo on GitHub using the Fork button.
- Clone your fork:
git clone https://github.com/Haseeb-MernStack/Emotion-Based-Music-Generator-Piano-Roll-Sequencer.git
cd music-composer
npm install- Create a feature branch:
git checkout -b feat/your-feature- Implement your change and add tests where applicable.
- Run the dev server and tests locally.
- Commit and push your branch:
git add .
git commit -m "feat: short description"
git push --set-upstream origin feat/your-feature- Open a Pull Request in the original repository and describe your changes. Link an issue if one exists.
Contribution guidelines: see CONTRIBUTING.md for code style and PR expectations.
- Add screenshots and
assets/demo.gifto the top-levelassets/folder. - Ensure
npm run buildcompletes without warnings. Use dynamic imports for heavy code paths when adding features. - If packaging many exports, use a ZIP step (e.g.,
jszip) in a batch-export flow.
You can create a web-friendly demo GIF from a short screen recording (MP4/WebM) using ffmpeg. This repository includes a small helper script scripts/generate-demo.js that wraps a palette-based ffmpeg flow for better GIF quality.
- Install
ffmpegon your machine and ensure it is available in yourPATH. - Place a short screen recording at
assets/raw-demo.mp4(or use your own path). - Run the helper script via npm:
npm run generate:demoOr run the script directly with options:
node scripts/generate-demo.js assets/raw-demo.mp4 assets/demo.gif --fps 12 --scale 600:-1 --duration 6--fpssets the output frame-rate (12 is a good default for demo GIFs).--scaleacceptsWxHwhere-1preserves aspect ratio for one dimension.--durationlimits the extracted segment in seconds.
The script uses a two-step palette generation for higher quality GIF output and will overwrite assets/demo.gif.
- No audio: interact with the page (user gesture) to unlock Tone.js. If still no sound, check the browser's autoplay policy and console for errors.
- Large bundle: verify dynamic imports and workerization for heavy modules like generators and Tone.js.
- Worker issues: ensure worker files are referenced with
new Worker(new URL('./worker.ts', import.meta.url))(Vite recommended pattern).
- This app runs entirely in the browser; no user data is sent to a server by default. If you add analytics or remote sync, document data flows and obtain consent.
This project is licensed under the MIT License — see LICENSE.
- I can add MP3 export, ZIP batch packaging, more unit tests, or a step-by-step demo video/GIF. Open an issue or request a PR and I can implement it.
This repository includes a GitHub Action that will:
- Convert any SVG placeholders placed in
assets/into PNG (and GIF fordemo.svg) using ImageMagick. - Generate
assets/demo.giffromassets/raw-demo.mp4usingffmpegand thescripts/generate-demo.jshelper if a raw recording exists.
The workflow runs on push and can be triggered manually via the Actions tab. It commits generated assets back to the repository so forks can benefit from generated previews when allowed by branch permissions.
-
Live demo: https://music-composer-xi.vercel.app/
-
Quick setup on Vercel:
- In Vercel, click "New Project" → Import from GitHub and select this repository.
- Set Build Command to
npm run buildand Output Directory todist. - Under Project Settings → General, set Node.js Version to
20.x(or20.19+). Vercel will respectengines.nodeinpackage.jsonbut setting it explicitly avoids mismatch. - Add any required Environment Variables in the Vercel dashboard (never commit secrets to Git).
- Enable Preview Deployments to get per-PR preview URLs.
-
Production checklist / recommendations:
- CI gates: require
build,lint, andtestchecks on PRs before merging. - Source maps + error reporting: upload source maps to Sentry/Bugsnag and configure release tracking.
- Performance budgets: add bundle-size checks (e.g.,
rollup-plugin-visualizerorsource-map-explorer) in CI. - Cache policy: configure
vercel.jsonor Vercel headers to serve hashed assets with long cache TTLs. - Security headers: add CSP, HSTS and other headers via
vercel.jsonor Vercel dashboard. - Secrets: put API keys and analytics IDs into Vercel Environment Variables.
- Monitoring: enable uptime checks and performance/error monitoring for production.
- Assets: use Vercel Image Optimization or pre-optimize large images/GIFs; keep
assets/demo.gifweb-friendly. - Offline support: test your service-worker and
public/offline.htmlin production. - Dependency security: enable Dependabot/renovate and run audits regularly.
- Releases & changelog: use
semantic-releaseor a changelog workflow for releases. - Accessibility: run Lighthouse audits and automate basic accessibility checks.
- CI gates: require
