Version: v0.1
Last Updated: 2026-01-23
Purpose: Complete reference for the current AceForge UI architecture, framework, and features for future UI rewrites.
- Architecture Overview
- Framework & Technology Stack
- UI Structure & Components
- JavaScript Architecture
- API Endpoints
- State Management
- Styling & CSS
- Data Flow & Communication
- Features & Functionality
- Key Implementation Details
AceForge uses a Flask + pywebview hybrid architecture:
┌─────────────────────────────────────────────────────────┐
│ aceforge_app.py │
│ (Main Entry Point - PyInstaller Bundle) │
│ - Monkey-patches webview.start() as singleton │
│ - Starts Flask server in background thread │
│ - Creates pywebview window pointing to Flask server │
│ - Handles window lifecycle and cleanup │
└──────────────────┬──────────────────────────────────────┘
│
│ imports
▼
┌─────────────────────────────────────────────────────────┐
│ music_forge_ui.py │
│ (Flask Application) │
│ - Flask app initialization │
│ - Blueprint registration │
│ - Log streaming infrastructure │
│ - Static file serving │
└──────────────────┬──────────────────────────────────────┘
│
│ serves HTML/CSS/JS
▼
┌─────────────────────────────────────────────────────────┐
│ cdmf_template.py (HTML) │
│ - Single-page application template │
│ - Jinja2 template with embedded structure │
│ - Loads external CSS/JS files │
└──────────────────┬──────────────────────────────────────┘
│
│ loads
▼
┌─────────────────────────────────────────────────────────┐
│ static/scripts/*.js (JavaScript Modules) │
│ - Modular JavaScript architecture │
│ - Each module handles specific UI concerns │
│ - Communicates via window.CDMF global object │
└─────────────────────────────────────────────────────────┘
Frozen App Mode (Production):
- Entry point:
aceforge_app.py - Flask server runs in background thread
- pywebview provides native macOS window
- No terminal window (console=False in PyInstaller spec)
- Window close triggers cleanup and exit
Development Mode:
- Entry point:
music_forge_ui.py(when run directly) - Can use pywebview OR browser fallback
- Terminal window shows server logs
- Useful for development and debugging
-
Flask Backend → Frontend:
- Server-Sent Events (SSE) for log streaming (
/logs/stream) - JSON API endpoints for data (
/tracks.json,/progress, etc.) - HTML form submissions for generation/training
- Server-Sent Events (SSE) for log streaming (
-
Frontend → Flask Backend:
fetch()calls to REST endpoints- Form submissions (POST) for generation/training
- Hidden iframes for form submissions (legacy pattern)
-
pywebview Bridge:
pywebview_bridge.jsinterceptsfetch()calls- Maps to
window.pywebview.apimethods (serverless mode) - Falls back to real
fetch()if pywebview API unavailable
Flask (Python Web Framework)
- Version: Latest (from requirements)
- Purpose: HTTP server, routing, template rendering
- Server: Waitress (WSGI server) - production-ready, multi-threaded
- Port: 5056 (hardcoded)
- Host: 127.0.0.1 (localhost only)
Key Flask Components:
- Blueprints: Modular route organization
cdmf_generation- Generation endpointscdmf_tracks- Track managementcdmf_training- LoRA trainingcdmf_models- Model download/managementcdmf_mufun- MuFun analyzercdmf_lyrics- Lyrics generation
Vanilla JavaScript (No Framework)
- Architecture: Modular, namespace-based
- Global Object:
window.CDMF- main namespace - State Management: Shared state object in
window.CDMF.state - No Build Step: Direct script includes in HTML
pywebview Integration:
- Library:
pywebview(Python package) - Version: 5.1
- Purpose: Native macOS window wrapper
- Bridge:
pywebview_bridge.js- shims fetch() to pywebview API
Jinja2 (via Flask)
- Template File:
cdmf_template.py(contains HTML string) - Rendering:
render_template_string()in Flask - Variables: Passed from Flask routes to template
- Static Files: Served via Flask's
url_for('static', ...)
CSS (Vanilla, No Preprocessor)
- File:
static/scripts/cdmf.css - Approach: Utility classes, component-based
- Theme: Dark mode (color-scheme: dark)
- Design System: Custom, not using external framework
The UI is a single-page application with the following structure:
<body>
<div class="page">
<!-- 1. Titlebar -->
<div class="cd-titlebar">
- Logo + "AceForge" title (gradient text)
- Version badge (v0.1)
- Exit button
</div>
<!-- 2. Tagline -->
<p class="tagline">Description text</p>
<!-- 3. Console Panel (Collapsible) -->
<div class="card" id="consoleCard">
- Collapsible server console logs
- Real-time log streaming
</div>
<!-- 4. Settings Panel (Collapsible) -->
<div class="card" id="settingsCard">
- Models folder configuration
</div>
<!-- 5. Music Player Card -->
<div class="card">
- Track list (sortable, filterable)
- Category filter chips
- Player controls (play, pause, stop, loop, mute)
- Progress slider
- Volume slider
- Audio element (<audio id="audioPlayer">)
</div>
<!-- 6. Mode Tabs -->
<div class="tab-row">
- "Generate" tab (active by default)
- "Training" tab
</div>
<!-- 7. Generation Form (mode: generate) -->
<form id="generateForm" class="card card-mode" data-mode="generate">
- Loading bar
- Model status notice
- Core/Advanced tab switcher
- Core knobs (prompt, lyrics, presets, sliders)
- Advanced knobs (scheduler, CFG, LoRA, etc.)
- Saved presets section
- Output directory
- Generate button
</form>
<!-- 8. Training Form (mode: train) -->
<form id="trainForm" class="card card-mode" data-mode="train">
- Training status banner
- Dataset selection
- LoRA config selection
- Training parameters
- Start/Pause/Resume/Cancel buttons
</form>
<!-- 9. Dataset Tagging Card (mode: train) -->
<div id="datasetTagCard" class="card card-mode" data-mode="train">
- Mass tagging tools
</div>
<!-- 10. MuFun Card (mode: train) -->
<div id="mufunCard" class="card card-mode" data-mode="train">
- MuFun analyzer controls
</div>
<!-- 11. Modals -->
- Auto prompt/lyrics modal
- LoRA config help modal
- Lyrics generation overlay
<!-- 12. Hidden Elements -->
- <iframe> elements for form submissions (legacy)
- <select id="trackList"> for audio player
</div>
</body>page
├── cd-titlebar (header)
├── tagline (description)
├── consoleCard (collapsible)
├── settingsCard (collapsible)
├── Music Player Card
│ ├── Track list header (sortable)
│ ├── Track list panel (filterable)
│ ├── Progress controls
│ └── Player controls
├── Mode Tabs (Generate/Training)
├── generateForm (card-mode, data-mode="generate")
│ ├── Core/Advanced tabs
│ ├── Core knobs section
│ └── Advanced knobs section
├── trainForm (card-mode, data-mode="train")
├── datasetTagCard (card-mode, data-mode="train")
└── mufunCard (card-mode, data-mode="train")
Cards:
.card- Main container component.card-header-row- Card title and actions.card-mode- Mode-specific cards (show/hide based on mode)
Form Rows:
.row- Horizontal form row (label + input).slider-row- Row with range slider + number input.row-progress- Progress bar container
Buttons:
.btn- Base button style.btn.primary- Primary action button.btn.secondary- Secondary action.btn.danger- Destructive action.btn:disabled- Disabled state
Tabs:
.tab-row- Tab container.tab-btn- Tab button.tab-btn-active- Active tab
Presets:
.preset-buttons- Container for preset buttons- Preset buttons use icons + labels
Track List:
.track-list-header- Sortable column headers.track-list-panel- Track rows container.track-row- Individual track row.track-fav-btn- Favorite button.track-delete-btn- Delete button
JavaScript is organized into modular files, each handling specific UI concerns:
Core Modules:
cdmf_main.js- Main orchestration, knob tabs, training controlscdmf_generation_ui.js- Generation form logic, progress updatescdmf_player_ui.js- Audio player controls and track managementcdmf_tracks_ui.js- Track list rendering, sorting, filteringcdmf_presets_ui.js- Preset management (load/save/delete)cdmf_mode_ui.js- Mode switching (Generate/Training)cdmf_training_ui.js- Training form logic and status updatescdmf_lora_ui.js- LoRA selection and managementcdmf_mufun_ui.js- MuFun analyzer UIcdmf_console.js- Console log streaming and displaypywebview_bridge.js- pywebview API bridge (fetch shim)
All modules use a shared global namespace:
const CDMF = (window.CDMF = window.CDMF || {});Shared State Object:
CDMF.state = {
candyModelsReady: boolean,
candyModelStatusState: string,
candyModelStatusMessage: string,
candyIsGenerating: boolean,
candyGenerationCounter: number,
candyActiveGenerationToken: number,
candyTrackSortKey: string | null,
candyTrackSortDir: "asc" | "desc",
candyTrackFilterCategories: Set,
progressTimer: Timer | null,
// ... more state
};Function Exposure:
CDMF.switchKnobTab = function(which) { ... };
CDMF.onSubmitForm = function(event) { ... };
CDMF.setPreset = function(presetId) { ... };
// ... more functionscdmf_main.js:
- Initializes shared state
- Handles Core/Advanced tab switching
- Training pause/resume/cancel controls
- Global utility functions
cdmf_generation_ui.js:
- Generation form submission
- Progress bar updates (via polling
/progress) - Loading bar animation
- Model status polling
- Lyrics generation UI
- Form validation
cdmf_player_ui.js:
- HTML5 audio element management
- Play/pause/stop/rewind/loop controls
- Volume control
- Time display formatting
- Progress slider synchronization
- Track selection from list
cdmf_tracks_ui.js:
- Track list rendering
- Sorting (by name, length, category, created)
- Filtering by category
- Favorite toggling
- Track deletion
- Category editing (right-click context menu)
- Metadata loading (length, category)
cdmf_presets_ui.js:
- Preset button click handlers
- Preset application (fills form fields)
- Random preset selection
- Instrumental/vocal preset group switching
cdmf_mode_ui.js:
- Mode tab switching (Generate/Training)
- Shows/hides mode-specific cards
- Updates active tab styling
cdmf_training_ui.js:
- Training form submission
- Training status polling
- Progress bar updates
- Pause/resume/cancel handlers
- LoRA config loading
cdmf_lora_ui.js:
- LoRA selection dropdown
- LoRA file browser
- LoRA weight input
- LoRA application to form
cdmf_mufun_ui.js:
- MuFun model status
- Dataset folder selection
- Analysis progress
- Results display
cdmf_console.js:
- Server-Sent Events (SSE) connection to
/logs/stream - Log message parsing and filtering
- Console panel show/hide
- Progress bar extraction from tqdm output
pywebview_bridge.js:
- Detects pywebview environment
- Intercepts
fetch()calls - Maps endpoints to
window.pywebview.apimethods - Provides Response-like objects for compatibility
- HTML loads → Scripts load in order (see template)
- cdmf_main.js → Initializes
window.CDMFand shared state - Other modules → Attach functions to
window.CDMF - DOMContentLoaded → Modules initialize event listeners
- Bootstrap data →
window.CDMF_BOOTprovides initial state - Polling starts → Model status, progress, training status
Inline Handlers (Template):
<button onclick="CDMF.switchMode('generate')">Generate</button>DOM Listeners (JavaScript):
document.getElementById('btnPlay').addEventListener('click', function() { ... });Form Submission:
<form onsubmit="return CDMF.onSubmitForm(event)">Custom Events:
- None currently used (could be added for decoupling)
| Method | Endpoint | Purpose |
|---|---|---|
| GET | / |
Main UI page (renders template) |
| GET | /healthz |
Health check endpoint |
| GET | /loading |
Loading page (splash screen) |
| GET | /logs/stream |
Server-Sent Events log stream |
| POST | /shutdown |
Gracefully shutdown server |
| Method | Endpoint | Purpose |
|---|---|---|
| GET | / |
Index page (same as main /) |
| POST | /generate |
Start ACE-Step generation |
| POST | /prompt_lyrics/generate |
Generate prompt/lyrics from concept |
Generation Request (POST /generate):
Form data:
- prompt: str (genre/style description)
- lyrics: str (optional, with [verse], [chorus] markers)
- instrumental: bool (checkbox)
- target_seconds: float
- fade_in: float
- fade_out: float
- steps: int
- guidance_scale: float
- seed: int
- seed_random: bool
- bpm: int | None
- vocal_gain_db: float
- instrumental_gain_db: float
- scheduler_type: str ("euler" | "heun" | "pingpong")
- cfg_type: str ("apg" | "cfg" | "cfg_star")
- omega_scale: float
- lora_name_or_path: str
- lora_weight: float
- ref_audio_file: File (optional)
- ref_audio_strength: float
- # ... more advanced params| Method | Endpoint | Purpose |
|---|---|---|
| GET | /music/<filename> |
Serve audio file |
| GET | /progress |
Get generation progress (JSON) |
| GET | /tracks.json |
List all tracks (JSON) |
| GET/POST | /tracks/meta |
Get/set track metadata |
| GET/POST | /user_presets |
Get/save user presets |
| POST | /tracks/rename |
Rename track file |
| POST | /tracks/delete |
Delete track file |
Progress Response (GET /progress):
{
"stage": "generating" | "ace_load" | "done" | "error",
"current": 0.0-1.0,
"total": 1.0,
"done": boolean,
"error": boolean,
"message": string
}Tracks Response (GET /tracks.json):
{
"tracks": [
{
"name": "filename.wav",
"path": "/path/to/file.wav",
"url": "/music/filename.wav"
}
]
}| Method | Endpoint | Purpose |
|---|---|---|
| POST | /train_lora |
Start LoRA training |
| GET | /train_lora/status |
Get training status |
| GET | /train_lora/configs |
List LoRA config files |
| POST | /train_lora/pause |
Pause training |
| POST | /train_lora/resume |
Resume training |
| POST | /train_lora/cancel |
Cancel training |
| POST | /dataset_mass_tag |
Mass-create prompt/lyrics files |
| Method | Endpoint | Purpose |
|---|---|---|
| GET | /models/status |
Get model download status |
| POST | /models/ensure |
Download/verify ACE-Step models |
| GET/POST | /models/folder |
Get/set models folder path |
| Method | Endpoint | Purpose |
|---|---|---|
| GET | /mufun/status |
Get MuFun model status |
| POST | /mufun/ensure |
Download/verify MuFun model |
| POST | /mufun/analyze_dataset |
Analyze dataset folder |
| Method | Endpoint | Purpose |
|---|---|---|
| GET | /lyrics/status |
Get lyrics model status |
| POST | /lyrics/ensure |
Download/verify lyrics model |
| POST | /lyrics/generate |
Generate lyrics from concept |
Global State Object (window.CDMF.state):
{
// Model status
candyModelsReady: boolean,
candyModelStatusState: "unknown" | "absent" | "downloading" | "ready" | "error",
candyModelStatusMessage: string,
candyModelStatusTimer: Timer | null,
// Generation state
candyIsGenerating: boolean,
candyGenerationCounter: number,
candyActiveGenerationToken: number,
candyHasSeenWork: boolean,
progressTimer: Timer | null,
// Track list state
candyTrackSortKey: string | null,
candyTrackSortDir: "asc" | "desc",
candyTrackFilterCategories: Set<string>,
// Lyrics model state
lyricsModelState: "unknown" | "absent" | "downloading" | "ready" | "error",
lyricsModelMessage: string,
lyricsModelStatusTimer: Timer | null,
// UI state
candyGenerateButtonDefaultHTML: string | null,
candyTrainButtonDefaultHTML: string | null,
autoPromptLyricsDefaultHTML: string | null
}Backward Compatibility Globals:
window.candyModelsReady = CDMF.state.candyModelsReady;
window.candyModelStatusState = CDMF.state.candyModelStatusState;
window.candyIsGenerating = CDMF.state.candyIsGenerating;Module: cdmf_state.py
Shared State Objects:
# Model status
MODEL_STATUS = {
"state": "unknown" | "absent" | "downloading" | "ready" | "error",
"message": string
}
MODEL_LOCK = threading.Lock()
# Generation progress
GENERATION_PROGRESS = {
"stage": string,
"current": float,
"total": float,
"done": boolean,
"error": boolean,
"message": string
}
PROGRESS_LOCK = threading.Lock()
# Training status
TRAINING_STATUS = {
"state": "idle" | "running" | "paused" | "cancelled" | "error",
"message": string,
"progress": float
}
TRAINING_LOCK = threading.Lock()Client → Server:
- Form submissions (POST)
- Polling (GET requests every N seconds)
- Server-Sent Events (SSE) for logs
Server → Client:
- JSON responses to polling requests
- Server-Sent Events for real-time logs
- Progress updates via
/progressendpoint
Polling Intervals:
- Model status: ~2-3 seconds
- Generation progress: ~0.5-1 second (during generation)
- Training status: ~1-2 seconds (during training)
Color Palette:
:root {
--cd-accent: #f97316; /* Orange accent */
--cd-text-dim: #cbd5e1; /* Dimmed text */
--cd-border: #334155; /* Border color */
}
Background: #020617 (very dark blue-black)
Text: #e5e7eb (light gray)
Cards: #020617 with border #111827Typography:
- Font:
system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif - Title: Gradient text (orange → purple → blue → cyan)
- Body: Light gray (#e5e7eb)
- Small text: #6b7280 (muted gray)
Cards:
.card- Main container (dark background, rounded, border, shadow).card-header-row- Flex row for title + actions.card-mode- Mode-specific visibility
Form Elements:
.row- Horizontal form row (label + input).slider-row- Row with range slider.row label- Form label (min-width: 120px).row input[type="text"]- Text input styling.row textarea- Textarea styling
Buttons:
.btn- Base button (padding, border-radius, cursor).btn.primary- Primary action (accent color).btn.secondary- Secondary action.btn.danger- Destructive action (red).btn:disabled- Disabled state (opacity, no pointer).btn:hover:not(:disabled)- Hover effect
Tabs:
.tab-row- Tab container (flex, gap).tab-btn- Tab button (padding, border, background).tab-btn-active- Active tab (accent border)
Track List:
.track-list-header- Sortable header row.track-list-panel- Track rows container.track-row- Individual track (hover effects).track-row.active- Currently playing track.track-fav-btn- Favorite button (star).track-delete-btn- Delete button (trash)
Loading/Progress:
.loading-bar- Progress bar container.loading-bar-inner- Animated inner bar (candystripe).loading-bar.active- Active state (shows animation)
Presets:
.preset-buttons- Container for preset buttons- Preset buttons use
.btnclass with icons
Current State:
- Fixed max-width: 960px (centered)
- Not fully responsive (designed for desktop)
- Flexbox for layout
- No mobile breakpoints
Layout:
- Single column
- Cards stack vertically
- Form rows wrap on smaller screens
Loading Bar:
- Candystripe animation (rainbow gradient moving)
- CSS keyframes:
@keyframes cdmf-candystripe - Used during generation and model downloads
Spinner:
- CSS animation:
cdmf-spin(rotation) - Used in lyrics generation overlay
User clicks "Generate"
↓
cdmf_generation_ui.js: onSubmitForm()
↓
Form submission (POST /generate)
↓
cdmf_generation.py: generate()
↓
generate_ace.py: generate_track_ace()
↓
Progress callbacks → cdmf_state.GENERATION_PROGRESS
↓
Client polls /progress endpoint
↓
cdmf_generation_ui.js: updateLoadingBarFraction()
↓
UI updates progress bar
Server logs → QueueHandler → LOG_QUEUE
↓
SSE endpoint (/logs/stream)
↓
cdmf_console.js: EventSource connection
↓
Parse log messages
↓
Filter noisy messages (task queue, client disconnected)
↓
Extract tqdm progress bars
↓
Display in console panel
User action (favorite, delete, etc.)
↓
cdmf_tracks_ui.js: Event handler
↓
fetch() to /tracks/meta or /tracks/delete
↓
cdmf_tracks.py: Route handler
↓
Update file system / metadata
↓
Return JSON response
↓
cdmf_tracks_ui.js: Refresh track list
↓
fetch() to /tracks.json
↓
Re-render track list
User clicks preset button
↓
cdmf_presets_ui.js: setPreset()
↓
Fills form fields from preset data
↓
User clicks "Save" preset
↓
fetch() POST /user_presets
↓
cdmf_tracks.py: save_user_preset()
↓
Stores in JSON file
↓
Returns updated preset list
↓
cdmf_presets_ui.js: Updates preset dropdown
Core Features:
- Text prompt input (genre/style description)
- Lyrics input (optional, with structure markers)
- Instrumental mode toggle
- Preset buttons (quick style selection)
- Target length slider (15-240 seconds)
- Fade in/out controls
- Inference steps control
- Guidance scale control
- Seed control (random or fixed)
- BPM hint (optional)
Advanced Features:
- Scheduler selection (Euler, Heun, Ping-pong)
- CFG mode (APG, CFG, CFG★)
- Omega scale
- Guidance interval/decay
- ERG switches (Tag, Lyric, Diffusion)
- Custom steps (OSS)
- Repaint/extend tasks
- Audio2Audio (reference track)
- LoRA adapter selection
- Vocal/instrumental gain adjustment (post-process)
Presets:
- Built-in presets (instrumental and vocal)
- User-saved presets
- Random preset selection
- Preset categories
Features:
- Track list with metadata (name, length, category, created date)
- Sortable columns (favorite, name, length, category, created)
- Category filtering (chips)
- Favorite toggling (★ button)
- Track deletion
- Category editing (right-click context menu)
- Play/pause/stop controls
- Rewind button
- Loop toggle
- Mute toggle
- Volume slider
- Progress slider (seek)
- Time display (current/total)
Track Management:
- Automatic discovery of .wav files in output directory
- Metadata stored in JSON files (favorites, categories)
- Track renaming
- Category assignment
Features:
- Dataset folder selection
- Experiment name input
- LoRA config selection (JSON presets)
- Training parameters:
- Max steps
- Max epochs
- Learning rate
- Max clip seconds
- SSL loss weight
- Instrumental-only toggle
- Save frequency
- Advanced trainer settings:
- Precision (32-bit, 16-mixed, bf16-mixed)
- Gradient accumulation
- Gradient clipping
- DataLoader reload frequency
- Validation check interval
- Device count
- Training controls:
- Start training
- Pause training
- Resume training
- Cancel training
- Progress indication (candystripe bar)
Mass Tagging:
- Dataset folder selection
- Base tags input
- Create prompt files
- Create [inst] lyrics files
- Overwrite existing files option
MuFun Analyzer:
- MuFun model status/installation
- Dataset folder selection
- Base tags input
- Instrumental-only toggle
- Analyze folder (auto-creates prompt/lyrics files)
- Results display
ACE-Step Models:
- Model status display
- Download models button
- Models folder configuration
- Progress indication during download
MuFun Model:
- Model status display
- Install/check button
- Large download (~16.5GB)
Lyrics Model:
- Model status display
- Install/check button
- Used for prompt/lyrics generation
Features:
- Modal dialog for concept input
- Generate mode selection:
- Prompt only
- Lyrics only
- Prompt + lyrics
- Auto-fills form fields
- Loading overlay during generation
Features:
- Collapsible console panel
- Real-time log streaming (SSE)
- Filtered messages (removes noise)
- Progress bar extraction from tqdm
- Useful for troubleshooting
Legacy Pattern (Hidden Iframes):
<form target="generation_frame" onsubmit="return CDMF.onSubmitForm(event)">
<!-- form fields -->
</form>
<iframe id="generation_frame" name="generation_frame" style="display:none;"></iframe>Why Iframes:
- Prevents page navigation on form submit
- Allows server to return HTML response (for errors)
- Legacy pattern, could be modernized to fetch()
Polling Pattern:
function pollProgress() {
fetch('/progress')
.then(r => r.json())
.then(data => {
updateLoadingBarFraction(data.current / data.total);
if (!data.done) {
setTimeout(pollProgress, 500);
}
});
}Server-Side:
- Progress stored in
cdmf_state.GENERATION_PROGRESS - Updated via callbacks from
generate_ace.py - Thread-safe (uses locks)
Storage:
- JSON files in output directory:
{trackname}.meta.json - Contains:
favorite,category,created, etc. - Loaded on track list refresh
File Structure:
output_dir/
├── track1.wav
├── track1.meta.json
├── track2.wav
├── track2.meta.json
└── ...
Built-in Presets:
- Defined in
presets.json(loaded bycdmf_tracks.load_presets()) - Two groups:
instrumentalandvocal - Each preset has:
id,label,icon,prompt,seed_vibe, etc.
User Presets:
- Stored in
user_presets.json(in output directory) - Saved via
/user_presetsPOST endpoint - Loaded on page load
Implementation:
CDMF.switchMode = function(mode) {
// Hide all mode-specific cards
document.querySelectorAll('.card-mode').forEach(card => {
card.style.display = 'none';
});
// Show cards for selected mode
document.querySelectorAll(`.card-mode[data-mode="${mode}"]`).forEach(card => {
card.style.display = '';
});
// Update tab styling
document.querySelectorAll('.mode-tab-btn').forEach(btn => {
btn.classList.toggle('tab-btn-active', btn.dataset.mode === mode);
});
};Bridge Pattern:
pywebview_bridge.jsinterceptsfetch()calls- Maps to
window.pywebview.apimethods - Provides Response-like objects for compatibility
- Falls back to real
fetch()if pywebview unavailable
Window Control API:
WindowControlAPIclass inaceforge_app.py- Exposed via
js_apiparameter towebview.create_window() - Methods:
minimize(),restore(),maximize() - Called from JavaScript via
window.pywebview.api.minimize()
Frozen App:
if getattr(sys, 'frozen', False):
static_folder = Path(sys._MEIPASS) / 'static'
app = Flask(__name__, static_folder=str(static_folder))Development:
else:
app = Flask(__name__) # Uses default 'static' folderURL Generation:
<link rel="stylesheet" href="{{ url_for('static', filename='scripts/cdmf.css') }}">
<script src="{{ url_for('static', filename='scripts/cdmf_main.js') }}"></script>Server-Side:
LOG_QUEUE = queue.Queue(maxsize=1000)
class QueueHandler(logging.Handler):
def emit(self, record):
LOG_QUEUE.put_nowait(self.format(record))
@app.route("/logs/stream")
def stream_logs():
def generate():
while True:
try:
msg = LOG_QUEUE.get(timeout=1)
yield f"data: {json.dumps({'message': msg})}\n\n"
except queue.Empty:
yield "data: {}\n\n" # Keep-alive
return Response(generate(), mimetype='text/event-stream')Client-Side:
const eventSource = new EventSource('/logs/stream');
eventSource.onmessage = function(event) {
const data = JSON.parse(event.data);
if (data.message) {
appendLogMessage(data.message);
}
};Form Validation:
- Client-side: Basic checks in
onSubmitForm() - Server-side: Parameter validation in route handlers
- Error messages displayed in toast notifications
Error Display:
<div class="toast error">
{{ short_message }}
<button onclick="CDMF.toggleDetails()">Details</button>
</div>
<div id="detailsPanel" class="details-panel">
{{ details }}
</div>Template Injection:
<script>
window.CDMF_BOOT = {
presets: {{ presets | tojson | safe }},
modelsReady: {{ models_ready | tojson | safe }},
modelState: {{ model_state | tojson | safe }},
modelMessage: {{ model_message | tojson | safe }},
autoplayUrl: {{ autoplay_url or '' | tojson | safe }},
urls: {
trainStatus: "{{ url_for('cdmf_training.train_lora_status') }}",
mufunStatus: "{{ url_for('cdmf_mufun.mufun_status') }}",
// ...
}
};
</script>Backward Compatibility:
window.CANDY_PRESETS = window.CDMF_BOOT.presets;
window.CANDY_MODELS_READY = window.CDMF_BOOT.modelsReady;
// ...aceforge_app.py # Main entry point (PyInstaller bundle)
music_forge_ui.py # Flask app initialization
cdmf_template.py # HTML template (Jinja2 string)
cdmf_generation.py # Generation blueprint
cdmf_tracks.py # Track management blueprint
cdmf_training.py # Training blueprint
cdmf_models.py # Model management blueprint
cdmf_mufun.py # MuFun analyzer blueprint
cdmf_lyrics.py # Lyrics generation blueprint
cdmf_state.py # Shared state management
cdmf_paths.py # Path configuration
generate_ace.py # ACE-Step generation logic
static/
├── scripts/
│ ├── cdmf_main.js # Main orchestration
│ ├── cdmf_generation_ui.js # Generation form
│ ├── cdmf_player_ui.js # Audio player
│ ├── cdmf_tracks_ui.js # Track list
│ ├── cdmf_presets_ui.js # Preset management
│ ├── cdmf_mode_ui.js # Mode switching
│ ├── cdmf_training_ui.js # Training form
│ ├── cdmf_lora_ui.js # LoRA selection
│ ├── cdmf_mufun_ui.js # MuFun analyzer
│ ├── cdmf_console.js # Console logs
│ ├── pywebview_bridge.js # pywebview bridge
│ └── cdmf.css # Stylesheet
├── aceforge_logo.png # App logo
├── aceforge.ico # Windows icon
└── loading.html # Splash screen
presets.json # Built-in presets
user_presets.json # User-saved presets (in output dir)
CDMF.spec # PyInstaller spec file
requirements_ace_macos.txt # Python dependencies
-
No Build Step:
- JavaScript files loaded directly (no bundling/minification)
- No TypeScript or modern JS features
- No module system (uses global namespace)
-
Legacy Patterns:
- Hidden iframes for form submission
- Polling instead of WebSockets
- Inline event handlers in HTML
-
Responsive Design:
- Fixed width (960px max)
- No mobile breakpoints
- Not optimized for small screens
-
State Management:
- Global state object (not reactive)
- Manual synchronization between modules
- No state persistence (except presets)
-
Error Handling:
- Basic error display
- No error recovery mechanisms
- Limited user feedback on failures
-
Code Organization:
- Large HTML template (1700+ lines)
- JavaScript modules could be more modular
- Some duplicate code between modules
-
Performance:
- Polling intervals could be optimized
- No request debouncing
- Large track lists not virtualized
-
Accessibility:
- Limited ARIA labels
- Keyboard navigation not fully implemented
- Screen reader support minimal
-
Testing:
- No unit tests
- No integration tests
- Manual testing only
Core Functionality:
- All generation parameters and controls
- Track management features
- Preset system
- Training workflow
- Model management
User Experience:
- Collapsible panels (console, settings)
- Mode switching (Generate/Training)
- Core/Advanced tab pattern
- Progress indication
- Real-time log streaming
API Compatibility:
- Keep existing Flask routes (or provide migration path)
- Maintain JSON response formats
- Preserve form parameter names
Architecture:
- Modern JavaScript framework (React, Vue, Svelte)
- Build system (Vite, Webpack, etc.)
- TypeScript for type safety
- Component-based architecture
State Management:
- Reactive state (Redux, Zustand, Pinia)
- Proper state persistence
- Optimistic updates
Communication:
- WebSockets instead of polling
- GraphQL or REST API
- Better error handling
UI/UX:
- Modern design system
- Responsive layout
- Better accessibility
- Improved animations
- Dark/light theme toggle
Performance:
- Code splitting
- Lazy loading
- Virtual scrolling for track lists
- Request debouncing
-
Run Flask server:
python music_forge_ui.py
-
Edit files:
- HTML: Edit
cdmf_template.py - CSS: Edit
static/scripts/cdmf.css - JS: Edit
static/scripts/*.js - Python: Edit
*.pyfiles
- HTML: Edit
-
Reload browser:
- Hard refresh (Cmd+Shift+R) to clear cache
-
Build app:
bash build_local.sh
-
Run app:
open dist/AceForge.app
-
Check logs:
- Console logs in UI (if console panel open)
- System logs (Console.app on macOS)
Client-Side:
- Browser DevTools (F12)
console.log()in JavaScript- Network tab for API calls
Server-Side:
- Terminal output (if running from source)
- Console panel in UI (log streaming)
- Python debugger (pdb)
This document provides a comprehensive reference for the current AceForge UI architecture. When rewriting the UI, use this as a guide to:
- Understand the current implementation - How things work now
- Preserve functionality - What features must be maintained
- Identify improvements - What can be modernized
- Plan migration - How to transition from old to new
The current UI is functional but uses older patterns. A modern rewrite should:
- Use a modern JavaScript framework
- Implement proper state management
- Improve responsive design
- Enhance accessibility
- Optimize performance
- Maintain API compatibility (or provide migration)
Key Files to Reference:
cdmf_template.py- HTML structurestatic/scripts/cdmf_*.js- JavaScript modulesstatic/scripts/cdmf.css- Stylingmusic_forge_ui.py- Flask routescdmf_*.py- Blueprint implementations
End of Document