π¨π Transform images into audio that reveals the original picture when viewed as a spectrogram. Free, offline-capable PWA with no account required.
Try SpectroTrace Live | Documentation | Report Bug
- Features
- Requirements
- Quick Start
- Environment Variables
- Technical Architecture
- Modes
- Conversion Parameters
- File Limits
- Project Structure
- Scripts
- PWA & Offline Support
- Security & Privacy
- Support the Project
- Tech Stack
- License
- Image to audio spectrogram conversion via additive synthesis
- Basic and Advanced modes for different use cases
- Real-time waveform and dual spectrogram visualization (full spectrum + selected range)
- Offline-capable PWA with service worker caching
- No accounts, no data uploads
- Node.js: >= 24.12.0
- Browser: Modern browser with Web Audio API support (Chrome, Firefox, Safari, Edge)
# Clone the repository
git clone https://github.com/j-about/SpectroTrace.git
cd SpectroTrace
# Install dependencies
npm install
# Start development server
npm run devOpen http://localhost:3000 in your browser.
Copy .env.example to .env.local for local development:
cp .env.example .env.local| Variable | Required | Default | Description |
|---|---|---|---|
NODE_ENV |
No | development |
Node environment (development, production, test) |
NEXT_PUBLIC_BASE_URL |
No | http://localhost:3000 |
Canonical base URL for SEO metadata, sitemaps, and OpenGraph tags |
NEXT_PUBLIC_GTM_ID |
No | (empty) | Google Tag Manager container ID (format: GTM-XXXXXXXX) |
For production deployment, set NEXT_PUBLIC_BASE_URL to your domain (e.g., https://www.spectrotrace.org).
When NEXT_PUBLIC_GTM_ID is configured, additional CSP domains can be whitelisted via environment variables. These are useful for Google Analytics, Google Ads, or other third-party services added through GTM.
| Variable | Description |
|---|---|
NEXT_PUBLIC_CSP_CONNECT_SRC |
Additional connection sources (space-separated URLs) |
NEXT_PUBLIC_CSP_FONT_SRC |
Additional font sources (space-separated URLs) |
NEXT_PUBLIC_CSP_FRAME_SRC |
Additional frame sources (space-separated URLs) |
NEXT_PUBLIC_CSP_IMG_SRC |
Additional image sources (space-separated URLs) |
NEXT_PUBLIC_CSP_SCRIPT_SRC |
Additional script sources (space-separated URLs) |
NEXT_PUBLIC_CSP_STYLE_SRC |
Additional style sources (space-separated URLs) |
These variables also configure which external domains bypass service worker caching, ensuring analytics and tracking requests are never served from cache.
See Google's CSP guide for required domains per service.
Image Upload β Validation β Canvas Processing β Grayscale Conversion
β
Float32Array (0-1 per pixel)
β
Web Worker β Transfer ArrayBuffer β Main Thread
β
Additive Synthesis β PCM Generation β WAV Encoding β Blob
β
Main Thread β Transferable ArrayBuffer β WAV Result
β
Waveform Display + Dual Spectrograms + Download
Audio generation runs in a dedicated Web Worker to keep the UI responsive:
- Main Thread: UI rendering, image processing, playback controls
- Worker Thread: Additive synthesis, PCM generation, WAV encoding
- Communication: Typed messages with Transferable ArrayBuffer for zero-copy data transfer
- Cancellation: Job-based tracking with graceful cancellation support
The core algorithm (app/lib/audio/generateFromImage.ts) converts images to audio:
- Each image column becomes a time slice
- Each row maps to a frequency (configurable scale)
- Pixel brightness determines amplitude at that frequency
- Sinusoids are summed using additive synthesis
- Output is normalized with headroom to prevent clipping
Uses default parameters for quick one-click conversion. Best for users who want simple results without configuration.
Full control over all conversion parameters. Access via the mode toggle in the header.
| Parameter | Range | Default | Description |
|---|---|---|---|
| Duration | 1-60s | 8s | Length of generated audio |
| Min Frequency | 20-2000 Hz | 50 Hz | Lowest frequency in output |
| Max Frequency | 500-22000 Hz | 16000 Hz | Highest frequency in output |
| Sample Rate | 22050/44100/48000 Hz | 44100 Hz | Audio sample rate |
| Frequency Scale | logarithmic/linear | logarithmic | How rows map to frequencies |
| Brightness Curve | linear/exponential/logarithmic | linear | How brightness maps to amplitude |
| Smoothing | 0-100% | 15% | Reduces abrupt changes between frames |
| Invert Image | true/false | false | Swap bright/dark interpretation |
| Limit | Value |
|---|---|
| Max File Size | 50 MB |
| Max Resolution | 8192 x 8192 pixels |
| Supported Formats | PNG, JPG, WebP, BMP, SVG, TIFF, HEIC |
Images exceeding the resolution limit are automatically downscaled during processing.
app/
βββ page.tsx # Main application page
βββ how-it-works/ # How It Works educational page
βββ faq/ # FAQ page with accordion UI
βββ legal-notice/ # Legal Notice, Privacy Policy & Terms of Use
βββ layout.tsx # Root layout with PWA integration and JSON-LD
βββ manifest.ts # PWA manifest configuration
βββ sitemap.ts # Dynamic sitemap generation
βββ globals.css # Tailwind CSS theme
β
βββ config/
β βββ external-domains.mjs # Shared GTM/CSP domain configuration
β
βββ components/
β βββ ui/ # shadcn/ui component library
β βββ layout/ # Header, Footer
β βββ seo/ # JSON-LD structured data components
β βββ faq/ # FAQ accordion components
β βββ ImageUpload/ # Image upload with cropper
β βββ AudioControls/ # Advanced parameter controls
β βββ Visualizer/ # Waveform and Spectrogram
β βββ ExportButton/ # WAV download
β βββ TipPrompt/ # Optional tipping modal
β βββ pwa/ # Service worker and install prompt
β βββ analytics/ # Google Tag Manager integration
β
βββ lib/
β βββ audio/ # Audio generation and WAV encoding
β βββ image/ # Image processing utilities
β βββ seo/ # JSON-LD schema generators and FAQ data
β βββ utils.ts # Shared utilities
β
βββ hooks/ # Custom React hooks
β βββ useConversionParams.ts
β βββ useGeneration.ts
β βββ useAudioWorker.ts
β
βββ sw/
β βββ sw.ts # Service worker (Workbox, bundled via esbuild)
β
βββ workers/
βββ audioWorker.ts # Web Worker for audio generation
| Command | Description |
|---|---|
npm run dev |
Start development server |
npm run build |
Build for production |
npm run start |
Start production server |
npm run lint |
Run ESLint |
npm run lint:fix |
Run ESLint with auto-fix |
npm run type-check |
Run TypeScript type checking |
npm run format |
Format code with Prettier |
npm run format:check |
Check code formatting |
SpectroTrace works offline after the first visit:
- Service Worker: Caches application shell and assets
- Workbox: Provides caching strategies and precaching
- Install Prompt: Native app installation on supported platforms
- Standalone Mode: Full-screen experience when installed
The service worker is built separately using esbuild:
- Source:
app/sw/sw.ts - Output:
public/sw.js - Build script:
scripts/build-sw.mjs
The dev and build commands automatically rebuild the service worker. For manual rebuilds:
| Command | Purpose |
|---|---|
npm run build:sw |
Development build (with sourcemaps) |
npm run build:sw:prod |
Production build (minified) |
External domains that bypass service worker caching are configured via environment variables:
- When
NEXT_PUBLIC_GTM_IDis set, GTM script and connect domains automatically bypass caching - Additional domains from
NEXT_PUBLIC_CSP_CONNECT_SRCandNEXT_PUBLIC_CSP_SCRIPT_SRCalso bypass caching - This shared configuration (
app/config/external-domains.mjs) is used by both the CSP headers and service worker
- No user accounts: No registration or login required
- Client-side processing: All image and audio processing happens in your browser
- No data uploads: Images and generated audio never leave your device
- Legal Notice: French LCEN-compliant disclosures (website owner, hosting provider)
- Privacy Policy: GDPR-compliant data processing information
- Terms of Use: Service usage terms and conditions
All legal information is accessible at /legal-notice.
| Header | Value | Purpose |
|---|---|---|
| Strict-Transport-Security | max-age=31536000; includeSubDomains; preload |
Enforces HTTPS |
| Content-Security-Policy | Restrictive CSP | Limits resource loading |
| X-Content-Type-Options | nosniff |
Prevents MIME type sniffing |
| X-Frame-Options | DENY |
Prevents clickjacking |
| Referrer-Policy | strict-origin-when-cross-origin |
Controls referrer info |
| Permissions-Policy | camera=(), geolocation=(), microphone=(self) |
Restricts browser features |
| X-XSS-Protection | 1; mode=block |
Enables browser XSS filtering |
| X-DNS-Prefetch-Control | off |
Disables DNS prefetching |
| Resource | Domain | Purpose |
|---|---|---|
| Stripe (optional) | buy.stripe.com |
Tipping (opens in new tab) |
| Google Tag Manager | www.googletagmanager.com |
Analytics (optional, disabled by default) |
When GTM is enabled, only core GTM domains are whitelisted by default. Additional domains (Google Analytics, Google Ads, etc.) can be configured via NEXT_PUBLIC_CSP_* environment variables.
For self-hosted deployments:
- Configure HTTPS with valid certificates
- Enable HTTP to HTTPS redirects
- Use automated certificate renewal (Let's Encrypt)
Report vulnerabilities via GitHub Security Advisories. Do not open public issues for security vulnerabilities.
SpectroTrace is free and open source. If you find it useful, consider leaving a tip via the beer icon in the header. Tips are processed securely through Stripe Payment Links.
- Framework: Next.js 16 (App Router)
- Language: TypeScript 5.9 (strict mode)
- UI: React 19, Radix UI, shadcn/ui
- Styling: Tailwind CSS 4
- Audio: Web Audio API, wavesurfer.js
- PWA: Workbox