diff --git a/packages/client/src/components/Workshop.jsx b/packages/client/src/components/Workshop.jsx index 3596ede..f39abac 100644 --- a/packages/client/src/components/Workshop.jsx +++ b/packages/client/src/components/Workshop.jsx @@ -1,9 +1,9 @@ import React, { useState, useEffect, useCallback } from 'react'; import { workshop as workshopApi } from '../services/api.js'; import { useAuth } from '../services/AuthContext.jsx'; -import { state, deserialize } from '../engine/state.js'; -import { serialize } from '../engine/state.js'; -import { rebuildGraph } from '../engine/audioEngine.js'; +import { state, deserialize, emit } from '../engine/state.js'; +import { stopAudio, rebuildGraph } from '../engine/audioEngine.js'; +import { getPresets } from '../engine/presets.js'; const TAGS = ['ambient', 'bass', 'drums', 'pad', 'lead', 'fx', 'chiptune', 'experimental']; @@ -11,17 +11,27 @@ function ShareModal({ onClose, onShared }) { const [title, setTitle] = useState(''); const [description, setDescription] = useState(''); const [selectedTags, setSelectedTags] = useState([]); + const [selectedPreset, setSelectedPreset] = useState(null); const [loading, setLoading] = useState(false); const [error, setError] = useState(''); + const presets = getPresets(); + const handleShare = async () => { if (!title.trim()) { setError('Titulo requerido'); return; } - if (state.modules.length === 0) { setError('No hay modulos en el canvas'); return; } + if (!selectedPreset) { setError('Selecciona un preset para compartir'); return; } setLoading(true); setError(''); try { - const patchData = serialize(); + // Use the preset data directly (already serialized correctly) + const patchData = { + modules: selectedPreset.modules || [], + connections: selectedPreset.connections || [], + camera: selectedPreset.camera || { camX: 0, camY: 0, zoom: 1 }, + masterVolume: selectedPreset.masterVolume ?? -6, + }; + await workshopApi.share({ title: title.trim(), description: description.trim(), @@ -38,10 +48,36 @@ function ShareModal({ onClose, onShared }) { return (
-
e.stopPropagation()} style={{ gap: 14 }}> +
e.stopPropagation()} style={{ gap: 14, maxHeight: '80vh', overflow: 'auto' }}>

Compartir Patch

+ + {presets.length === 0 ? ( +

+ No tienes presets guardados. Ve al Sandbox, crea algo y guardalo con "Save" primero. +

+ ) : ( +
+ {presets.map((p, i) => ( + + ))} +
+ )} + setTitle(e.target.value)} /> @@ -65,7 +101,8 @@ function ShareModal({ onClose, onShared }) { {error &&
{error}
} -
@@ -132,11 +169,18 @@ export default function Workshop({ onSwitchToSandbox, onSwitchToGame }) { useEffect(() => { loadPatches(); }, [loadPatches]); const handleLoad = (patch) => { - if (patch.data) { - deserialize(patch.data); - if (state.isRunning) rebuildGraph(); - onSwitchToSandbox?.(); - } + if (!patch.data) return; + + // Stop audio, clean state, then load + if (state.isRunning) stopAudio(); + + // Deep clone to avoid reference issues + const cleanData = JSON.parse(JSON.stringify(patch.data)); + deserialize(cleanData); + rebuildGraph(); + emit(); + + onSwitchToSandbox?.(); }; const handleLike = async (patchId) => {