Volver al inicio

Roomify: renderizado de interiores con IA en React Puter

Roomify — aplicación web para generar renders de interiores 3D a partir de planos 2D usando React y Puter. Arquitectura en workers sin servidor elimina el backend. Código de workers proporcionado, hooks de frontend y soluciones de problemas.

Crea un visualizador de IA como Roomify en React+Puter
Advertisement 728x90

Roomify: Creando un Visualizador de Interiores con IA usando React y Puter Serverless

Roomify transforma un plano 2D en un renderizado 3D fotorrealista en segundos. La aplicación utiliza React 19 con TypeScript para el frontend y la plataforma Puter para la lógica serverless, almacenamiento y generación de IA. Sin un backend personalizado, el frontend interactúa directamente con la API de Puter a través del SDK puter.js.

La arquitectura elimina el servidor tradicional: las subidas de archivos, la creación de proyectos y las llamadas de IA ocurren en workers. Esto simplifica el despliegue y la escalabilidad para desarrolladores de nivel medio y senior.

Stack Tecnológico y sus Funciones

  • React 19 + TypeScript: Un frontend tipado con HMR a través de Vite.
  • React Router 7: Rutas para la página de inicio y el visualizador.
  • Tailwind CSS: Estilos con utilidades sin CSS personalizado.
  • Lucide React: Iconos para la interfaz de usuario.
  • Puter.js: Acceso al almacenamiento de archivos, KV, workers y modelos de IA desde el navegador.

Puter proporciona workers serverless, almacenamiento KV y almacenamiento persistente de archivos. Los workers se llaman mediante puter.action, y la IA mediante puter.ai.generate.

Google AdInline article slot

Arquitectura: Desde la Subida hasta el Renderizado

Flujo de procesamiento:

  • Subir el plano a puter.file.write.
  • Obtener una URL pública para el archivo.
  • Llamar al worker project.create para escribir metadatos en KV.
  • Generar mediante el worker ai.render3d: cargar la imagen, crear un prompt, llamar a Claude/Gemini, guardar el resultado.
  • Actualizar KV con la URL del renderizado y devolverlo al frontend.

El frontend muestra el plano original y el renderizado usando react-compare-slider para la comparación.

Funciones de Worker: Código y Lógica

Las funciones de worker en JavaScript se suben a través de la CLI de Puter.

Google AdInline article slot

Creando un proyecto:

// lib/puter.action.ts
export async function createProject({ item, visibility }) {
  const result = await puter.action('project.create', {
    item,
    visibility,
  });
  return result;
}

export async function getProjects() {
  return await puter.action('project.list');
}

export async function getProjectById({ id }) {
  return await puter.action('project.get', { id });
}

Generando un renderizado:

// worker: ai.render3d
export default async ({ sourceImage, style = 'fotorrealista' }) => {
  const imageUrl = typeof sourceImage === 'string' ? sourceImage : await puter.file.url(sourceImage);
  
  const prompt = `
    Transforma este plano de planta en un renderizado 3D de interior ${style}.
    La imagen muestra la distribución de una habitación con paredes, ventanas y puertas.
    Genera una vista realista desde una perspectiva que muestre mejor el espacio.
    Añade muebles, texturas, iluminación y sombras apropiadas.
    Haz que parezca una visualización arquitectónica profesional.
  `;
  
  const result = await puter.ai.generate({
    model: 'claude-3-sonnet',
    prompt,
    images: [imageUrl],
    responseFormat: 'image'
  });
  
  const renderedPath = `/projects/${projectId}/rendered.png`;
  await puter.file.write(renderedPath, result.image);
  
  const key = `project:${projectId}`;
  const project = JSON.parse(await puter.kv.get(key));
  project.renderedImage = puter.file.url(renderedPath);
  await puter.kv.set(key, JSON.stringify(project));
  
  return {
    renderedImage: project.renderedImage,
    renderedPath
  };
};

KV almacena metadatos: nombre del proyecto, propietario, privacidad y enlaces a archivos.

Google AdInline article slot

Frontend: Componentes y Hooks

La página de inicio (Home) muestra una lista de proyectos. El componente Upload convierte un archivo a base64:

// components/Upload.tsx
const handleFileChange = async (e) => {
  const file = e.target.files[0];
  if (!file) return;
  const base64 = await toBase64(file);
  onComplete(base64);
};

El visualizador (VisualizerId) usa useEffect para la generación automática:

useEffect(() => {
  if (isProjectLoading || hasInitialGenerated.current || !project?.sourceImage) return;
  if (project.renderedImage) {
    setCurrentImage(project.renderedImage);
    hasInitialGenerated.current = true;
    return;
  }
  hasInitialGenerated.current = true;
  void runGeneration(project);
}, [project, isProjectLoading]);

useRef evita llamadas duplicadas. El estado es local, sin Redux.

Solucionando Problemas Comunes

  • CORS: Proxy de Vite en desarrollo.
  • Tamaño de Base64: Guardar el archivo por separado, almacenar el enlace en KV.
  • Doble generación: useRef + verificaciones.
  • Asincronía: Estados de carga, esqueletos.
  • UI móvil: Responsividad de Tailwind, soporte táctil para el deslizador.

Validación: archivos de hasta 10 MB, JPG/PNG. Indicadores de carga para tiempos de generación de 10-15 segundos.

Conclusiones Clave

  • Puter reemplaza el backend: workers, KV, archivos e IA en un solo SDK.
  • Los hooks de React gestionan el estado sin bibliotecas externas.
  • Los prompts definen la calidad: detallar paredes, muebles e iluminación.
  • La arquitectura escala para producción sin DevOps.
  • El código es de código abierto, adecuado para bifurcaciones y experimentos.

— Editorial Team

Advertisement 728x90

Leer después