Website Development Skill
Trigger
Activate when working on:
- •JavaScript modules in
js/ - •Journal entries in
journal/ - •Website pages in
content/ - •Any frontend development
Commands
# Local development (required for ES6 modules) python3 -m http.server 8001 # Generate journal manifest after adding entries node scripts/generate-journal-manifest.js
No build step — vanilla JavaScript with ES6 modules.
Architecture: EventBus + Dependency Injection
All components communicate via central pub/sub EventBus. Components receive dependencies through constructor injection.
// Event naming: category:action (lowercase, colon separator)
// Examples: player:play, nav:pageChanged, journal:loaded
constructor(container, eventBus, featureDetector) {
this.container = container;
this.eventBus = eventBus;
}
Module Organization
js/ ├── core/ # EventBus, FeatureDetector, ScriptLoader ├── audio/ # MusicPlayer (SOLID pattern) ├── navigation/ # PageNavigator, DropdownController ├── journal/ # JournalManager, MarkdownParser, TimelineRenderer ├── viewers/ # ViewerBase, ThreeDViewer, PointCloudViewer ├── animations/ # AnimationController, FloatingAnimation ├── media/ # LazyLoader, ImageGallery └── app.js # Main orchestrator
Viewer Pattern
All viewers extend ViewerBase:
async checkSupport() // Verify device capabilities async loadDependencies() // Lazy load libraries async initialize() // Setup viewer async render() // Display content showFallback() // Static image fallback dispose() // Cleanup
Existing viewers: ThreeDViewer, PointCloudViewer, AudioViewer
Embedding Viewers in Journal Markdown
Use data attributes for viewer configuration:
<div data-audio-viewer
data-prompt="Description of what was requested"
data-artist="Artist Name"
data-tracks='[{"src": "path/to/file.mp3", "title": "Track", "description": "..."}]'>
</div>
EntryRenderer auto-initializes viewers via dynamic import.
Grid Reflow Pattern (ResizeObserver)
When a component's height changes during CSS transitions, use ResizeObserver to trigger GridLayoutOptimizer.optimize() continuously — not just after transition ends.
// In component that changes height:
if (!this.resizeObserver) {
const bubble = this.container.closest('.content-bubble');
if (bubble) {
let lastHeight = bubble.offsetHeight;
this.resizeObserver = new ResizeObserver(() => {
const currentHeight = bubble.offsetHeight;
if (Math.abs(currentHeight - lastHeight) > 1) {
lastHeight = currentHeight;
this.emitEvent('component:resized', {});
}
});
this.resizeObserver.observe(bubble);
}
}
// In dispose():
if (this.resizeObserver) {
this.resizeObserver.disconnect();
this.resizeObserver = null;
}
Why: CSS Grid doesn't automatically reflow sibling elements when one element's height changes via transition. ResizeObserver fires during the transition, allowing continuous layout updates.
Code Conventions
- •One class per file (PascalCase classes, camelCase utilities)
- •Every component must have
dispose()for cleanup - •Error format:
console.error('[ComponentName] Message:', error) - •Use
requestAnimationFramefor visual updates - •Debounce expensive operations
- •Respect
prefers-reduced-motion
Testing
Manual browser testing before commits:
- •DevTools Console + Network tabs
- •Test feature manually
- •Verify no console errors
- •Check EventBus debug logs (localhost)
- •Test mobile viewport
Journal Entries
Template: journal/TEMPLATE.md
- •Kontext: Tool/Workflow, intention
- •Prozess: Input, iterations, output
- •Erkenntnisse: Surprises, errors as features
- •Weiterentwicklung: Workflow changes, next steps