Creative Multimedia Workshop — idea capture and organization, multi-source asset search with circuit breaker, layered soundscape design, interactive narrative building, and MadLibs-style creative writing. The most complex integration in the AP ecosystem, crossing the language boundary between a Python REST backend (stock-art-collector) and a TypeScript/React frontend.
Zone: staging/ (active development, v0.1). Part of Phase 2 Wave C.
Key Decisions
Decision
Rationale
Date
ADR-001: TypeScript circuit breaker over Python dependency
Avoids cross-language runtime dependency — AssetManager follows same interface patterns as stock-art-collector’s SourceAdapter ABC; actual API calls go through the REST API on port 3070
2026-02-06
ADR-002: Declarative soundscape layers
Stores layer configs as data (preset name, volume, playback rate, loop flag); React UI creates the Web Audio graph from declarative config — same pattern as Tavern’s SoundEffects, keeps core logic testable in Node.js
2026-02-06
ADR-003: DJB2-variant string hash for deduplication
Bundle 3 templates (adventure-hook, character-intro, scene-setter) with {key} interpolation; simpler than @ap/narrative-engine’s InterpolationEngine, matches creative writing context
2026-02-06
ADR-005: Tab-based React UI with view-per-module pattern
4 views (Creative Dashboard, Idea Workspace, Soundscape Mixer, Story Builder) map to 5 core TypeScript modules; MadLibs integrated into Story Builder rather than standalone
2026-02-12
Patterns Established
Pattern
Description
Reusable
Declarative audio layer config
Store soundscape layers as plain data objects; let the UI layer create the Web Audio graph
Yes
TypeScript circuit breaker wrapping Python REST API
AssetManager mirrors Python SourceAdapter interface; all external calls go through REST port boundary
Yes
View-per-module tab layout
One tab per primary workflow, backed by one or more modules; compound features (e.g., MadLibs) colocated with their closest workflow
Yes
Lessons Learned
Lesson
Context
Impact
Cross-language boundary via REST is cleaner than shared types
Python stock-art-collector provides Unsplash/Pexels/Pixabay search — exposing it as a REST API on port 3070 allows the TypeScript frontend to treat it as any HTTP service
Adopted as the integration pattern for all Python→TypeScript boundaries
MadLibs content depth matters
Web port started with 3 templates vs 20+ in iOS original — content regression is a real risk on rewrites
Carry over content breadth explicitly; don’t assume feature parity without counting
@ap/audio import in Node.js tests requires aliasing
AudioService singleton needs window — use @ap/audio-presets alias to SoundGenerator.ts for test compatibility
Test infra pattern for any web-audio module
Technical Debt
Item
Priority
Notes
stock-art-collector cross-language dependency
High
AssetManager requires Python REST API on port 3070 — build asset features last; graceful degradation when service unavailable
MadLibs content regression
Medium
3 templates vs 20+ in iOS source — target 10+ templates to match original content depth
Ghost Writer features not ported
Medium
Dexie persistence, TemplateGenerator, IdeaEvolver not ported — re-evaluate after core UI is built
Hash dedup is simplistic
Low
DJB2 string hash on URLs — adequate for MVP; replace with true perceptual hashing if quality issues arise
Tech Stack
Layer
Technology
Version
Runtime
Node.js
>=18.0.0
Language
TypeScript
^5.6.0
Framework
React
^19.0.0
Build
Vite
^7.3.1
Test
Vitest
^4.0.18
Internal Dependencies
Package
Purpose
@ap/narrative-engine
Interactive story graph building and preview
@ap/audio
Soundscape layer presets (SOUND_PRESETS)
Source Apps
App
Contribution
gw
Idea Catcher, Outline Builder, Template Generator, MadLibs, Idea Evolver