Vídeo (explicación de la app): https://youtu.be/swyhTpUhEL0
- Ficha del proyecto
- Descripción general del producto
- Arquitectura del sistema
- Modelo de datos
- Especificación de la API
- Historias de usuario
- Tickets de trabajo
- Pull requests
Javier Villarroel Freites (JVF).
CurateArtAI (en la interfaz: sketch.explorer).
Plataforma web que separa la capa de exploración de la capa de código: artistas exploran, editan y curan sketches generativos (p5.js / three.js) en lenguaje natural, asistidos por un agente de IA, con sus proyectos guardados en la nube.
- App: https://creative-code-ai.vercel.app
- Demo público (sin login): https://creative-code-ai.vercel.app/playground
https://github.com/JavierVLAB/AI4Devs-finalproject
El arte generativo de código tiene dos capas que hoy están enredadas. La capa de código define el sistema: el algoritmo, sus reglas, su estética. La capa de exploración es la búsqueda de la pieza concreta dentro de ese sistema —mover un radio, cambiar una paleta, subir el número de iteraciones— y la curación de las variaciones que merecen la pena. Programar obliga a mezclarlas: para probar una variante hay que volver al editor, editar un número, recargar y mirar. La exploración queda atrapada dentro del flujo de escribir código.
CurateArtAI separa ambas capas. Toma un sketch (p5.js / three.js) y lo convierte en una herramienta explorable y curable: expone sus parámetros como controles visuales, deja pedir cambios en lenguaje natural a un agente que edita el código, y permite guardar, comparar y curar las variaciones resultantes.
Resuelve tres problemas a la vez:
- Quien no programa queda fuera: un sketch es código, y sin saber editarlo no se puede tocar ni un color.
- Quien programa pierde tiempo en lo repetitivo: explorar variaciones es un bucle manual de editar-recargar-mirar.
- No existe una capa de curación: cuando una exploración da decenas de resultados, no hay forma cómoda de capturarlos, compararlos y quedarse con los mejores.
CurateArtAI vive entre escribir código y producir la pieza final, asistido por IA. No compite con el editor donde se escribe el algoritmo ni con la herramienta donde se publica el resultado: ocupa el hueco intermedio de explorar y curar.
Para quién: artistas generativos, creative technologists, diseñadores, educadores, estudiantes y curiosos que quieren explorar y curar variaciones de un sketch sin programar, o programando lo mínimo. Incluye tanto al artista que ya escribe su propio código y quiere acelerar la exploración, como al no-programador que quiere intervenir una pieza sin tocar una línea.
Qué no es: no es un IDE generalista, no es una herramienta de live-coding/VJ en tiempo real y no reemplaza al sketch. Lo envuelve: el código sigue siendo la fuente de verdad.
Agrupadas por área. La versión actual cubre un subconjunto; el resto marca la evolución del producto.
- Cuentas y biblioteca: registro/login con sesión persistente; biblioteca de proyectos en la nube (crear, abrir, guardar, borrar).
- Exploración: visor del sketch en iframe aislado; controles de parámetros generados automáticamente desde la configuración.
- Agente de IA: edición de configuración y código en lenguaje natural; generación de un sketch completo desde una descripción; historial de conversación por proyecto; memoria de proyecto que el agente lee y propone actualizar; editor de código y explorador de archivos como apoyo.
- Curación: snapshots de parámetros con preview visual; grid de comparación con selección múltiple y favoritos; (visión) generación por lotes de variaciones.
- Biblioteca de plantillas: plantillas publicadas variadas (creative coding: ruido Perlin, tramado/dithering, mosaicos geométricos, trazo para plotter), reutilizables desde el playground público y al crear un proyecto autenticado.
- Producción y export: exportación de sketch a SVG vectorial real (para pen plotter y patrones geométricos) vía addon
p5.js-svg; control de subida de imagen (type: image) para plantillas que procesan una imagen de origen (ej. tramado para serigrafía). (visión pendiente) alta resolución de exportación y separación de capas multicolor para serigrafía.
Objetivos del producto
- Separar la capa de exploración de la capa de código: parametrizar un sketch sin tocar el código.
- Editar el sketch (parámetros y código) con un agente de IA en lenguaje natural.
- Curar variaciones: capturarlas, compararlas y conservar las mejores.
- Guardar y recuperar proyectos por usuario, entre sesiones y dispositivos.
Métricas de éxito
- Un usuario sin conocimientos de código modifica visiblemente un sketch en menos de un minuto desde que abre un proyecto.
- Una instrucción típica al agente ("haz las líneas rojas", "añade un parámetro de velocidad") se resuelve en un solo turno y deja el sketch funcionando.
- El usuario captura al menos una variación como snapshot y la recupera intacta.
- El proyecto se recupera idéntico al reabrirlo en otra sesión.
El espacio de trabajo es de tema oscuro con paneles flotantes sobre un fondo de cuadrícula, apoyado en un sistema de diseño por tokens (ver §2). El flujo principal de extremo a extremo:
- El usuario inicia sesión.
- Crea un proyecto o abre uno de su biblioteca.
- Ve el sketch y sus controles, generados desde la configuración.
- Explora moviendo controles y/o pide un cambio al agente en lenguaje natural.
- El agente modifica el código o los parámetros y devuelve el resultado.
- La aplicación aplica el cambio, recarga el sketch y guarda el proyecto.
- El usuario investiga distintos parámetros para obtener variaciones y curar las mejores piezas.
- Guarda un snapshot de los resultados más interesantes.
- Al volver, encuentra su proyecto, parámetros, snapshots e historial intactos.
Vídeo (explicación de la app): https://youtu.be/swyhTpUhEL0
Capturas de pantalla:
Requisitos:
- Node.js 24.
- pnpm 11 (el proyecto fija
packageManager: pnpm@11.9.0enfront/ybackend/). - Proyecto Supabase con las migraciones de
supabase/migrations/aplicadas.
Instalación del frontend:
cd front
pnpm install
pnpm devVariables de entorno del frontend (front/.env):
VITE_SUPABASE_URL=...
VITE_SUPABASE_PUBLISHABLE_KEY=...
VITE_API_URL=http://localhost:4111Instalación del backend:
cd backend
pnpm install
pnpm devVariables de entorno del backend:
SUPABASE_URL=...
SUPABASE_SECRET_KEY=...
DATABASE_URL=...Las migraciones versionadas están en supabase/migrations/. El despliegue público (Vercel + Mastra Cloud), sus URLs y variables están documentados en §0.4 y §2.4.
Stack tecnológico
| Capa | Tecnología | Rol |
|---|---|---|
| Frontend | Vite + React 19 + TypeScript | Aplicación de página única (SPA) |
| Tailwind CSS 4 | Estilos | |
| CodeMirror 6 | Editor de código (JS / YAML / JSON) | |
js-yaml |
Parseo de la configuración (YAML) | |
@supabase/supabase-js |
Autenticación y acceso a datos desde el cliente | |
@mastra/client-js |
Cliente del agente sobre la API REST de Mastra | |
| Backend | Mastra (Node + Hono) | Servicio de agentes: Agents, Tools, Workflows, Memory |
@mastra/pg |
Memoria conversacional en Postgres | |
@mastra/auth-supabase |
Verificación del token de sesión | |
| Datos / Auth | Supabase | Postgres, Auth, Storage, RLS |
| Ejecución del arte | p5.js / three.js en <iframe> |
Renderizado aislado del sketch |
| Infraestructura | Vercel/Cloudflare Pages · Render · Supabase | Frontend · backend · datos |
| Proceso | OpenSpec · ESLint · Vitest · Playwright | Especificación, lint y tests |
El sistema se apoya en servicios gestionados para construir rápido y centrarse en lo propio del producto —la exploración y curación de sketches— en vez de reinventar infraestructura. De ahí tres planos: cliente, servicio de agentes (Mastra) y plataforma de datos (Supabase). El sketch corre en un <iframe> aislado porque ejecuta código arbitrario y no debe poder tocar la app ni los datos del usuario.
flowchart TB
subgraph Client["Cliente — Vite + React (SPA)"]
UI["UI: auth · biblioteca · canvas · editor · chat"]
SB["@supabase/supabase-js"]
MC["@mastra/client-js"]
Iframe["<iframe> aislado — sketch.js + p5/three"]
end
subgraph Backend["Servicio de agentes — Mastra (Node/Hono) · Render"]
Auth["@mastra/auth-supabase"]
Agent["Agent + Tools (edit_params · edit_sketch · update_memory)"]
WF["Workflow de guardrails"]
Mem["Memory (@mastra/pg)"]
Route["Model routing → LLM"]
end
subgraph Data["Plataforma de datos — Supabase"]
SAuth["Auth"]
PG["Postgres"]
Storage["Storage (assets)"]
end
LLM["Proveedor LLM"]
UI --> SB & MC
UI <-->|postMessage| Iframe
SB -->|login / CRUD con RLS| SAuth & PG
SB --> Storage
MC -->|HTTPS + Bearer token| Auth
Auth --> Agent --> WF & Mem & Route
Mem --> PG
Route --> LLM
Patrón. No es un monolito con API REST a medida, sino una composición de servicios gestionados: el cliente habla con Supabase (datos/auth) y con Mastra (agente) de forma independiente.
Beneficios. Menos código de infraestructura (auth, base de datos, memoria del agente y observabilidad vienen resueltos); secretos del LLM custodiados en el backend; el sketch aislado no compromete la app.
Sacrificios / déficits. Dependencia de servicios gestionados (acoplamiento a Supabase y Mastra); el backend en plan gratuito se suspende por inactividad y el primer acceso es lento; ejecutar código de sketch de terceros es una superficie de riesgo, mitigada con el <iframe> aislado; algunas funciones de exploración pueden depender de APIs solo disponibles en navegadores Chromium.
| Componente | Responsabilidad | Tecnología |
|---|---|---|
| Cliente | UI, estado de pantalla, render del sketch, acceso a datos y llamadas al agente. | Vite + React + TypeScript |
| Servicio de agentes | Aloja el agente, sus tools y el workflow de guardrails; verifica el token y ejecuta la inferencia. | Mastra (Node/Hono) |
| Plataforma de datos | Identidad, persistencia (proyectos/snapshots/assets), memoria del agente y control de acceso por RLS. | Supabase |
| iframe del sketch | Ejecuta el código del sketch de forma aislada, comunicándose por el protocolo postMessage. |
p5.js / three.js |
A alto nivel, el proyecto se organiza en dos servicios desplegables por separado:
front/— la SPA de React (UI, visor del sketch, controles, chat, editor).backend/— el servicio de agentes Mastra (Agent, tools, workflow, memoria).shared/— tipos TypeScript compartidos entre frontend y backend.supabase/migrations/— esquema SQL versionado, RLS y cambios de datos.openspec/— especificaciones, propuestas y cambios del proceso OpenSpec.
.
├── front/ # SPA Vite + React + TypeScript
│ ├── src/components/ # Componentes React por área
│ ├── src/hooks/ # Hooks de sesión, proyectos, sketch y agente
│ ├── src/lib/ # Lógica de dominio: YAML, Supabase, agente, sync del sketch
│ └── public/ # Assets estáticos
├── backend/ # Servicio Mastra
│ └── src/mastra/ # Agents, tools y workflows
├── shared/ # Tipos compartidos
├── supabase/migrations/ # Migraciones SQL
└── openspec/ # Especificaciones y cambios| Pieza | Plataforma | Project root |
|---|---|---|
| Frontend | Vercel (build estático de Vite, preset Vite) | front/ |
| Backend (Mastra) | Mastra Cloud (Server + Studio) | backend/ |
| Datos / Auth / Storage | Supabase (Postgres gestionado) | — |
Cada servicio se despliega en su propia nube; no se usan contenedores propios. Los secretos (clave de LLM, SUPABASE_SECRET_KEY y DATABASE_URL) viven solo en el backend; el cliente usa la clave publicable de Supabase.
Variables por servicio
| Servicio | Variables |
|---|---|
| Vercel (front) | VITE_SUPABASE_URL, VITE_SUPABASE_PUBLISHABLE_KEY, VITE_BACKEND_URL |
| Mastra Cloud (backend) | SUPABASE_URL, SUPABASE_SECRET_KEY, DATABASE_URL, OBSERVABILITY_DATABASE_URL, OBSERVABILITY_SCHEMA, ANTHROPIC_API_KEY, FRONTEND_ORIGIN |
DATABASE_URL debe usar el connection string del pooler de Supabase (*.pooler.supabase.com), no el directo (solo IPv6).
Despliegue del backend (CLI de Mastra, desde backend/):
npx mastra auth login
npx mastra server deploy --project curateartai-backend --env-file .env
npx mastra studio deploy --project curateartai-backend --env-file .env # opcional: StudioDespliegue del frontend: importar el repo en Vercel con project root front/, preset Vite y las tres variables VITE_* (con VITE_BACKEND_URL apuntando al Server de Mastra). El front/vercel.json añade el rewrite SPA para React Router.
Orden de despliegue (resuelve la dependencia mutua de URLs):
- Desplegar backend → obtener su URL estable.
- Desplegar frontend con
VITE_BACKEND_URL= URL del backend → obtener el dominio de Vercel. - Fijar
FRONTEND_ORIGINen el backend con el dominio de Vercel y redesplegar (restringe CORS). - Registrar el dominio de Vercel en Supabase Auth (Site URL / Redirect URLs).
- Aislamiento del sketch. Corre en un
<iframe>aislado; no puede acceder a la app, las claves ni los datos del usuario. La configuración se parsea, nunca se evalúa como código. - Secretos en el servidor. Las claves del LLM y la
service_rolede Supabase residen solo en el backend. El cliente usa laanon keypública. - Control de acceso por capas. Las tablas de aplicación se protegen con Row Level Security (un usuario solo accede a sus filas). Las tablas de memoria de Mastra se acceden solo desde el backend, que aísla por usuario tras verificar el token de sesión. (Detalle en §3.)
- Unitarios (Vitest): parseo de
config.yaml, generación de controles, sincronización del sketch, hook del agente y tools del backend. - Integración: CRUD con RLS y contrato del agente.
- E2E (Playwright,
front/e2e/): golden path — login → crear proyecto en blanco → workspace → mover un control → verificar reactividad del sketch (postMessage) → limpiar el proyecto creado. Se ejecuta a mano conpnpm test:e2e(requierepnpm devcorriendo y un usuario de test en Supabase); no está integrado en CI todavía.
La entidad central es el proyecto: un sketch con su código, configuración, parámetros e historial. Un usuario posee muchos proyectos; cada proyecto agrupa sus snapshots, variaciones y assets. Borrarlo arrastra todo lo suyo.
La persistencia se divide en dos grupos de tablas que conviven en la misma base de datos de Supabase: las de aplicación (las gestiona la app, se acceden desde el cliente con RLS) y las de memoria de Mastra (las gestiona Mastra, se acceden solo desde el backend).
erDiagram
AUTH_USERS ||--|| PROFILES : "1:1"
AUTH_USERS ||--o{ PROJECTS : "posee"
PROJECTS ||--o{ SNAPSHOTS : "agrupa"
PROJECTS ||--o{ VARIATIONS : "agrupa"
PROJECTS ||--o{ ASSETS : "agrupa"
AUTH_USERS ||--o{ MASTRA_THREADS : "resource"
MASTRA_THREADS ||--o{ MASTRA_MESSAGES : "contiene"
PROFILES {
uuid id PK
text display_name
timestamptz updated_at
}
PROJECTS {
uuid id PK
uuid user_id FK
text name
text description
text sketch_js
text config_yaml
text renderer
text memory
timestamptz created_at
timestamptz updated_at
}
SNAPSHOTS {
uuid id PK
uuid project_id FK
text label
jsonb values
text preview_url
boolean is_favorite
timestamptz created_at
}
VARIATIONS {
uuid id PK
uuid project_id FK
jsonb values
text preview_path
boolean is_favorite
timestamptz created_at
}
ASSETS {
uuid id PK
uuid project_id FK
text storage_path
text mime_type
text kind
timestamptz created_at
}
VARIATIONSy el campokinddeASSETSdan soporte a la visión de curación y producción; no forman parte de la versión actual.
Esquema en Postgres. El proyecto es el agregado raíz; snapshots, variations y assets se borran en cascada con él. El sketch se guarda como dos columnas de texto en projects (config_yaml y sketch_js), cuyo contenido sigue el contrato de §4.
-- Perfil 1:1 con el usuario de Supabase Auth.
create table profiles (
id uuid primary key references auth.users(id) on delete cascade,
display_name text,
updated_at timestamptz not null default now()
);
-- Agregado raíz. Guarda código y configuración como texto.
create table projects (
id uuid primary key default gen_random_uuid(),
user_id uuid not null references auth.users(id) on delete cascade,
name text not null,
description text,
sketch_js text not null default '',
config_yaml text not null default '',
renderer text not null default 'p5js' check (renderer in ('p5js', 'threejs')),
memory text,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now()
);
create index on projects (user_id);
-- Combinación de valores guardada y recuperable. values = { paramId: number|string }.
-- preview_url: miniatura del canvas en el momento del snapshot (bucket snapshot-previews).
create table snapshots (
id uuid primary key default gen_random_uuid(),
project_id uuid not null references projects(id) on delete cascade,
label text,
values jsonb not null,
preview_url text,
is_favorite boolean not null default false,
created_at timestamptz not null default now()
);
create index on snapshots (project_id);
-- Metadata de imágenes subidas por el usuario a un proyecto (ej. imagen de
-- origen de la plantilla de tramado para serigrafía). El binario vive en el
-- bucket de Storage `sketch-uploads`; esta fila solo guarda su URL pública.
create table assets (
id uuid primary key default gen_random_uuid(),
project_id uuid not null references projects(id) on delete cascade,
user_id uuid not null references profiles(id) on delete cascade,
name text not null,
url text not null,
mime_type text,
size_bytes bigint,
created_at timestamptz not null default now()
);
create index on assets (project_id);Plantillas publicadas. Tabla templates (slug, title, description, sketch_js, config_yaml, renderer, thumbnail_url, tags, is_published) — recurso independiente de projects, usado por el playground público y como origen al crear un proyecto autenticado.
Storage. Dos buckets públicos con RLS en storage.objects acotada por dueño del proyecto: snapshot-previews (miniaturas de snapshots) y sketch-uploads (imágenes de origen subidas por el usuario para un control type: image).
Memoria del agente. El historial de chat lo gestiona Mastra (@mastra/pg) en el mismo Postgres de Supabase. Organiza la conversación en resource (el usuario), thread (el proyecto, un hilo por proyecto) y message (cada turno). Mastra crea esas tablas automáticamente.
Seguridad (RLS). Las tablas de aplicación tienen RLS activado: un usuario solo accede a filas con user_id = auth.uid(); snapshots, variations y assets heredan el acceso por su project_id. Las tablas de memoria de Mastra no pasan por RLS: las consulta el backend con privilegios elevados, aislando por resourceId/threadId tras verificar el token.
El agente se expone desde el backend Mastra mediante una ruta custom que encapsula el contrato específico de CurateArtAI: autenticación con token de Supabase, contexto completo del sketch, threadId = projectId, resourceId = user.id, ejecución del workflow de guardrails y respuesta estructurada lista para el frontend.
Mastra también publica rutas built-in como POST /api/agents/{agentId}/generate, pero esta aplicación usa POST /agent para mantener un contrato más simple entre el workspace y el backend.
openapi: 3.0.0
info:
title: CurateArtAI — API del agente (Mastra)
version: 0.1.0
paths:
/agent:
post:
summary: Envía una instrucción en lenguaje natural y devuelve los archivos del sketch modificados.
security:
- bearerAuth: [] # token de sesión de Supabase
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [projectId, message, sketchJs, configYaml, renderer]
properties:
projectId: { type: string, format: uuid, description: "id del proyecto; también threadId del agente" }
message: { type: string, description: "instrucción del usuario" }
sketchJs: { type: string, description: "sketch.js actual completo" }
configYaml: { type: string, description: "config.yaml actual completo" }
renderer: { type: string, enum: [p5js, threejs] }
previousResponse: { type: string, description: "respuesta anterior, opcional, para detectar repeticiones" }
responses:
'200':
description: Respuesta del agente.
content:
application/json:
schema:
type: object
required: [response]
properties:
response: { type: string, description: "texto para el usuario" }
appliedConfigYaml: { type: string, description: "config.yaml completo, si cambió" }
appliedSketchJs: { type: string, description: "sketch.js completo, si cambió" }
memorySuggestion: { type: string, description: "propuesta de nota de memoria" }
pendingQuestion: { type: string, description: "si el agente necesita aclaración" }
'401':
description: Token de sesión ausente o inválido.
'400':
description: Body inválido o incompleto.
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearerOtros contratos del sistema, fuera de esta API REST:
- Datos y auth (Supabase). Acceso desde el cliente con
@supabase/supabase-js, gobernado por RLS (no son endpoints propios; ver §3). - Protocolo
postMessage(app ↔ iframe). Salientes:SKETCH_INIT,SKETCH_UPDATE,SKETCH_RESTARTcon{ config, values }. Entrantes:SKETCH_READY,SKETCH_ERROR { message }. - Contrato del sketch.
config.yaml(describe canvas y parámetros:range→ slider,select→ selector) ysketch.js(lee los valores dewindow.__SKETCH__.values, escuchapostMessage, emiteSKETCH_READY/SKETCH_ERROR). El renderer se infiere del código (THREE→threejs; si no,p5js).
Historias principales del producto, separando lo implementado en la versión actual de la visión pendiente.
Como artista, quiero crear una cuenta e iniciar sesión, para tener mis proyectos asociados a mí y accesibles desde cualquier dispositivo.
Criterios de aceptación
- Registro con email/contraseña.
- Sesión persistente entre recargas.
- Las acciones con cuenta son inaccesibles sin sesión.
- Los datos quedan aislados por usuario mediante RLS.
Como artista sin experiencia en código, quiero mover sliders y selectores, para explorar variaciones sin programar.
Criterios de aceptación
- Los controles se generan automáticamente desde
config.yaml. - Mover un control actualiza el sketch en tiempo real.
- Cambiar el canvas reinicia el sketch.
Como usuario, quiero pedir cambios en lenguaje natural, para que el agente edite el sketch por mí.
Criterios de aceptación
- La instrucción va al backend autenticado.
- El agente devuelve configuración o código validados.
- El cambio se aplica, el sketch se recarga y el proyecto se guarda.
- El historial se conserva por proyecto.
- Ante fallo, el usuario recibe un mensaje claro sin pérdida de trabajo.
- La memoria de proyecto se lee como contexto y solo se actualiza con aprobación.
Como usuario explorando variaciones, quiero guardar combinaciones de valores, para recuperarlas más tarde.
Criterios de aceptación
- Un snapshot captura los valores actuales con etiqueta y fecha.
- Cargar un snapshot restaura los valores y actualiza el sketch.
- Los snapshots quedan asociados al proyecto y se recuperan al reabrirlo.
Como usuario con muchos snapshots, quiero verlos en un grid lado a lado y marcar mis favoritos, para quedarme con las mejores piezas.
Criterios de aceptación
- El usuario ve un grid de snapshots del proyecto (con preview visual), alternable con la vista del sketch.
- Puede seleccionar varios, marcar/desmarcar favoritos y borrar con confirmación.
- Los favoritos se conservan y se recuperan al reabrir el proyecto.
Como artista, quiero partir de plantillas orientadas a técnicas de producción física (plotter, serigrafía) y exportar mi sketch a SVG, para poder llevarlo fuera de la pantalla.
Criterios de aceptación
- La biblioteca de plantillas incluye ejemplos variados de creative coding (ruido Perlin, tramado/dithering, mosaico geométrico, trazo para plotter).
- Un sketch puede declarar un control
type: image; el usuario sube una imagen o elige entre las ya subidas al proyecto. - Un sketch puede exponer exportación a SVG real (vectorial); el botón "Exportar SVG" solo aparece si el sketch actual la soporta.
- La descarga del SVG se dispara desde la aplicación, nunca desde dentro del iframe aislado del sketch.
Como artista, quiero elegir si mi sketch nuevo empieza en blanco, lo genera la IA a partir de una descripción, o parte de una plantilla existente, para no enfrentarme a un lienzo vacío cada vez que creo un proyecto.
Criterios de aceptación
- El modal de creación de proyecto pide el nombre y, en la misma vista (sin pasos), el origen del sketch: en blanco, IA o plantilla.
- El origen "en blanco" crea el proyecto con un sketch mínimo válido (no vacío ni roto).
- El origen "IA" permite describir el sketch deseado; esa descripción se envía sola como primer mensaje del chat al entrar al workspace.
- El origen "plantilla" permite elegir entre las plantillas publicadas y copia su contenido al proyecto nuevo.
Como artista explorando, quiero generar N variaciones barriendo rangos de parámetros, para ver muchas direcciones de golpe sin moverlas a mano una a una.
Criterios de aceptación
- El usuario elige qué parámetros varían y en qué rango.
- El sistema genera N variaciones.
- Cada variación guarda sus valores y una previsualización.
Como visitante sin cuenta, quiero abrir un playground público con ejemplos de sketches, para probar la experiencia de exploración antes de registrarme.
Criterios de aceptación
- El visitante accede a una ruta pública de playground sin iniciar sesión.
- El playground muestra una biblioteca de plantillas o ejemplos publicados.
- Al abrir una plantilla, el sketch se carga en un workspace efímero con sus controles visuales.
- Mover controles actualiza el sketch en tiempo real.
- Los cambios del visitante no se guardan en Supabase ni modifican la plantilla original.
- La IA aparece deshabilitada en el playground público, con una indicación clara de que estará disponible en demos invitadas.
- El playground ofrece una llamada a crear cuenta o iniciar sesión para guardar un proyecto propio desde una plantilla.
Tickets principales del desarrollo actual.
Ticket 1 (Base de datos) — Esquema Supabase + RLS
- Historias: H1, biblioteca y persistencia.
- Descripción: crear el proyecto Supabase y el esquema de datos de aplicación (
profiles,projects,snapshots,assets) con políticas RLS por usuario. - Tareas: escribir migraciones SQL versionadas (DDL de §3.2); activar RLS en todas las tablas; políticas con
auth.uid(); herencia de acceso porproject_id; índices poruser_id/project_id; borrado en cascada. - Criterios de aceptación: un usuario solo ve sus filas y el acceso cruzado queda bloqueado; borrar un proyecto arrastra sus snapshots y assets; las migraciones son reproducibles desde cero.
Ticket 2 (Backend) — Agente Mastra con salida estructurada
- Historia: H3 (edición con el agente).
- Descripción: agente que recibe una instrucción en lenguaje natural y devuelve
config.yaml/sketch.jsmodificados, con salida estructurada, tools y guardrails. - Tareas: definir el Agent y las tools
edit_params,edit_sketch,update_memory; schema Zod de salida (response,appliedConfigYaml?,appliedSketchJs?,memorySuggestion?,pendingQuestion?); workflow de guardrails A/B/C; verificación del token Supabase en la ruta customPOST /agent; memoria con@mastra/pg. - Criterios de aceptación: devuelve un objeto válido según el schema; cada tool valida su salida (YAML parseable / JS sin errores evidentes); los guardrails cortan bucles y fallos repetidos; una petición sin token válido devuelve 401; el historial se recupera al reabrir el proyecto.
Ticket 3 (Frontend) — Visor del sketch
- Historia: H2 (controles visuales).
- Descripción: componente que monta el sketch en un
<iframe>aislado, le inyecta los valores y gestiona la comunicación porpostMessage. - Tareas: iframe sandboxed con su HTML de arranque; inyección de
window.__SKETCH__(config + valores); manejo deSKETCH_READY/SKETCH_ERROR; ciclo de vida de las blob URLs (crear/revocar); recarga al cambiar el canvas; actualización en tiempo real al mover un control. - Criterios de aceptación: el sketch monta y renderiza; mover un control actualiza el sketch al instante; un error del sketch se muestra sin romper la app; no se filtran blob URLs entre recargas.
Ticket 4 (Frontend + Agente) — Chat del workspace conectado al agente
- Historia: H3 (edición con el agente).
- Descripción: conectar el panel de chat del workspace con
POST /agentpara enviar instrucciones en lenguaje natural, aplicar la respuesta estructurada del agente al sketch y persistir los cambios del proyecto. - Tareas: crear
useAgent; enviar{ projectId, message, sketchJs, configYaml, renderer, previousResponse? }con Bearer token; mantener historial local de la sesión; mostrar loading, errores ypendingQuestion; persistirappliedSketchJsenprojects.sketch_jsyappliedConfigYamlenprojects.config_yaml; regenerar controles o recargar iframe según qué cambió; guardarmemorySuggestionaprobado enprojects.memory; actualizarprojects.updated_at. - Criterios de aceptación: el usuario puede pedir un cambio desde el chat y verlo reflejado en el sketch; una respuesta conversacional no recarga el iframe; una configuración inválida no se persiste; las sugerencias de memoria solo se guardan con aprobación explícita; errores de red/auth se muestran sin romper el workspace.
Ticket 5 (Frontend + Datos) — Playground público de plantillas sin IA
- Historia: H7 (playground público de plantillas).
- Descripción: crear una experiencia pública para explorar sketches de ejemplo sin cuenta, usando plantillas publicadas como punto de partida y manteniendo todos los cambios en estado efímero.
- Tareas: definir el modelo mínimo de plantilla publicada (
title,description,sketch_js,config_yaml,renderer,thumbnail_url,tags,is_published); añadir la ruta pública/playground; listar plantillas publicadas; reutilizar el visor y los controles del workspace en modo no persistente; bloquear o deshabilitar el chat de IA en esta ruta; evitar escrituras enprojects,snapshots,memoryyupdated_at; añadir CTA para crear cuenta e iniciar un proyecto real desde una plantilla. - Criterios de aceptación: cualquier visitante puede abrir el playground y probar una plantilla; los controles modifican el sketch solo en la sesión actual; recargar la página restaura el estado original de la plantilla; no se realizan escrituras de usuario en Supabase; la IA queda claramente deshabilitada; el diseño deja preparado el camino para una demo futura con IA habilitada por token.
Ticket 6 (Frontend + Datos) — Plantillas de producción y exportación SVG
- Historia: H8 (plantillas de producción y exportación SVG).
- Descripción: reemplazar el contenido de la biblioteca de plantillas por cuatro plantillas orientadas a técnicas de producción (tramado para serigrafía, espiral para plotter, flow field de ruido Perlin, mosaico de arcos), y ampliar el runtime del sketch para soportar subida de imagen y exportación vectorial SVG.
- Tareas: cargar el addon
p5.js-svgen el iframe del sketch; nuevo tipo de controltype: imageenconfig.yaml(contrato) con componente de subida/selección en el sidebar; usar la tablaassetsya existente + nuevo bucketsketch-uploads(Storage, RLS por dueño del proyecto) para persistir imágenes subidas en proyectos autenticados, con fallback aFileReader/data URL en el playground efímero; protocoloEXPORT_SVG/EXPORTED_SVG(con chequeo previoHAS_SVG_EXPORT) para pedir el SVG al sketch y descargarlo desde fuera del iframe sandboxed; escribir y revisar las 4 plantillas nuevas; migraciones de borrado del contenido anterior sin revisar y de alta del contenido nuevo. - Criterios de aceptación: las 4 plantillas nuevas se ven y funcionan en el playground y en un proyecto; el botón "Exportar SVG" solo aparece en sketches que lo soportan; la imagen subida se ve reflejada en el sketch; ningún sketch existente sin controles de imagen o SVG se ve afectado.
Ticket 7 (Frontend + Backend) — Selección de origen al crear un proyecto
- Historia: H9 (selección de origen al crear un sketch).
- Descripción: el modal de creación de proyecto pasa a ofrecer 3 orígenes (en blanco / IA / plantilla) en una única vista sin pasos; de paso se corrige un bug preexistente que dejaba el chat del agente sin memoria configurada.
- Tareas: boilerplate mínimo válido para el origen "en blanco" (
front/src/lib/blankSketch.ts); extenderuseProjects.createProjectpara aceptar el origen elegido; rediseñarCreateProjectDialog(nombre → origen → sección inline según elección); enviar automáticamente la descripción del origen "IA" como primer mensaje de chat tras crear el proyecto y navegar al workspace; reutilizar la tablatemplatespara el origen "plantilla"; configurarmemoryensketch-agent.tscon@mastra/memory, compartiendo elLibSQLStorede la instancia de Mastra. - Criterios de aceptación: los 3 orígenes crean un proyecto usable; el origen "IA" deja el primer mensaje ya enviado al llegar al workspace; el origen "plantilla" copia el contenido elegido; el chat del agente responde sin el error de memoria no configurada.
Ticket 8 (Backend) — Observabilidad y evals locales del agente
- Descripción: trazas del agente visibles en Mastra Studio (tools, tiempos, fallos) y una batería de 5 evals representativas para validar comportamiento y guardrails en desarrollo.
- Criterios de aceptación: Studio muestra trazas reales de llamadas locales; las 5 evals son ejecutables y revisables; alcance solo local, no llega a producción.
Ticket 9 (Infraestructura) — Despliegue a Vercel + Mastra Cloud
- Descripción: desplegar el frontend en Vercel y el backend en Mastra Cloud, con CORS, variables de entorno y redirect URLs de Supabase Auth ajustados al dominio de producción.
- Criterios de aceptación: la app es accesible públicamente; login y agente funcionan en producción; orden de despliegue documentado en §2.4.
Ticket 10 (Frontend) — Landing pública redirige al demo
- Historia: H7 (playground público).
- Descripción: la raíz
/decide destino según sesión: sin sesión va a/playground, con sesión a/app. - Criterios de aceptación: un visitante sin cuenta llega al demo público desde
/; el flujo con sesión no cambia.
Ticket 11 (Backend) — Reducir CPU idle en Mastra Cloud
- Descripción: quitar observability y Postgres externo de la instancia Mastra para que el backend hiberne por inactividad, evitando coste sin tráfico.
- Criterios de aceptación: el backend hiberna sin uso; el consumo de CPU idle baja a niveles comparables con otros proyectos Mastra del usuario.
Ticket 12 (Frontend + Datos) — Grid de curación de snapshots con favoritos
- Historia: H6 (comparación y curación).
- Descripción: captura y guarda un preview del canvas al crear un snapshot; vista grid alternable con el sketch; selección múltiple, favoritos y borrado con confirmación.
- Criterios de aceptación: cada snapshot guarda su preview; el grid marca/desmarca favoritos y persiste el estado al reabrir; borrar pide confirmación.
Ticket 13 (Testing) — Primer test E2E golden path
- Descripción: Playwright configurado en
front/e2e/, con un test que cubre login → crear proyecto en blanco → workspace → mover un control → verificar reactividad del sketch. - Criterios de aceptación: el test pasa localmente con
pnpm test:e2e(requierepnpm devy usuario de test en Supabase).
En esta fase del proyecto no se ha seguido todavía un flujo formal de pull requests por ticket. Los cambios se han integrado directamente en main, así que la trazabilidad real de esta entrega queda mejor reflejada por commits.
-
Ticket 1 (Base de datos)
8fd850c4—feat: prepare changes for front and backend refactorin- Añade la migración inicial
20260623000000_initial_schema.sqly las specs base del refactor.
- Añade la migración inicial
91068683—feat: workspace UI flotante con design system tokenizado- Añade
20260627000000_add_snapshot_values.sqlpara snapshots.
- Añade
62bc4dfa—feat: playground public- Añade
20260702120000_add_public_templates.sqlpara plantillas públicas.
- Añade
-
Ticket 2 (Backend)
775c779c—feat: design system and agent api- Implementa el backend inicial del agente en Mastra:
POST /agent, tools, workflow de guardrails y tests.
- Implementa el backend inicial del agente en Mastra:
-
Ticket 3 (Frontend)
f45474ef—feat: Frontend base- Construye la base del visor del sketch, controles, autenticación y páginas principales.
91068683—feat: workspace UI flotante con design system tokenizado- Completa la UI del workspace, snapshots y componentes principales del editor.
-
Ticket 4 (Frontend + Agente)
daed879d—feat: frontend-agent- Conecta el workspace con el backend del agente, añade
useAgent, validación de respuestas y persistencia.
- Conecta el workspace con el backend del agente, añade
17159d6c—feat: frontend-agent 2- Ajusta y consolida las specs del chat y del workspace tras la integración.
-
Ticket 5 (Frontend + Datos)
62bc4dfa—feat: playground public- Implementa
/playground, biblioteca de plantillas, modo efímero y desactivación de IA en la demo pública.
- Implementa
-
Ticket 6 (Frontend + Datos)
f94fdd85—feat: refresco de biblioteca de plantillas + exportación SVG y subida de imagen- Reemplaza el contenido de la biblioteca de plantillas (tramado para serigrafía, espiral para plotter, flow field de Perlin, mosaico de arcos); añade control
type: imagey exportación SVG (p5.js-svg, protocoloEXPORT_SVG/HAS_SVG_EXPORT); usa la tablaassetsexistente + nuevo bucketsketch-uploads.
- Reemplaza el contenido de la biblioteca de plantillas (tramado para serigrafía, espiral para plotter, flow field de Perlin, mosaico de arcos); añade control
-
Ticket 7 (Frontend + Backend)
0b41d5dc—feat new sketches- Añade la selección de origen (en blanco / IA / plantilla) al crear un proyecto, boilerplate mínimo válido, envío automático del primer mensaje del chat para el origen "IA", y fix del bug de memoria del agente (
@mastra/memory).
- Añade la selección de origen (en blanco / IA / plantilla) al crear un proyecto, boilerplate mínimo válido, envío automático del primer mensaje del chat para el origen "IA", y fix del bug de memoria del agente (
-
Ticket 8 (Backend)
f0c6907d—feat: agents observability- Añade observabilidad local en Mastra Studio y la batería de 5 evals del agente.
-
Ticket 9 (Infraestructura)
98583a6f—preparando el despliegue431a745a—feat: landing pública al demo + documentación de despliegue- Configuran el despliegue a Vercel (frontend) y Mastra Cloud (backend), con CORS y documentación del proceso.
-
Ticket 10 (Frontend)
431a745a—feat: landing pública al demo + documentación de despliegue- Añade el redirect de
/según sesión (con sesión a/app, sin sesión a/playground).
- Añade el redirect de
-
Ticket 11 (Backend)
066512bd—fix: backend hiberna en Mastra Cloud (sin observability ni Postgres externo)- Elimina observability y Postgres externo de la instancia Mastra para permitir hibernación por inactividad.
-
Ticket 12 (Frontend + Datos)
e5f6de9b—feat: persistir favoritos + mejoras en grid de snapshotsc6dcb701—feat: persistir favoritos + mejoras en grid de snapshots vercel update- Añaden preview visual por snapshot, vista grid con selección múltiple, favoritos y borrado con confirmación.
-
Ticket 13 (Testing)
0f808c0c—test: primer E2E con Playwright — golden path de creación de proyecto- Configura Playwright en
front/e2e/y escribe el primer test del golden path.
- Configura Playwright en






