src/scripts/
├── app.js ← Entry point (thin orchestrator)
├── filters.js ← All filter functions
├── canvas.js ← Canvas operations (load, draw, export)
├── ui.js ← DOM manipulation, event wiring
├── state.js ← Settings, filter state, persistence
└── utils.js ← clamp(), showToast(), generateExportName()
// filters.js
export function grayscale(r, g, b) { ... }
export function brightness(r, g, b, amount) { ... }
export function clamp(value) { ... }
Move each group of related functions into its own file. Add export in front of every function that other modules need.
import { grayscale, brightness, contrast, invert }
from './filters.js';
import { loadImageToCanvas, exportCanvas }
from './canvas.js';
import { setupEventListeners }
from './ui.js';
import { loadSettings, saveSettings }
from './state.js';
<script type="module" src="scripts/app.js"></script>
type="module" tells the browser this is an ES Module. Without it, import/export won't work. Modules are automatically deferred (no need for defer attribute).
Verify nothing broke — all features work as before.
If you find circular dependencies (A imports B, B imports A), extract the shared code into utils.js or a new shared module.
git switch -c refactor/PIXELCRAFT-019-modules
git add src/scripts/ src/index.html
git commit -m "Split app.js into ES Modules (PIXELCRAFT-019)"
git push origin refactor/PIXELCRAFT-019-modules
# PR → Review → Merge → Close ticket ✅
Modularity and separation of concerns.
Arguably the most important principle in software engineering.