Как я создал Roomify — AI-визуализатор интерьеров на React и Puter

Как я создал Roomify — AI-визуализатор интерьеров на React и Puter

Привет! Я фулл-стек-разработчик, и недавно я запустил свой pet-проект — Roomify, веб-приложение, которое превращает обычный план помещения в фотореалистичный 3D-рендер за несколько секунд. В этой статье я расскажу, как всё устроено: от выбора технологий до интеграции с AI и облачной платформой Puter.

Зачем это нужно?

Представьте, что вы архитектор или дизайнер интерьеров. Клиент приносит чертёж и просит показать, как это будет выглядеть в реальности. Обычно приходится часами настраивать 3D-сцену в Blender или SketchUp. А что, если это может сделать нейросеть за пару секунд?

Roomify — это попытка ответить на этот вопрос. Кроме того, я хотел:

  • Изучить интеграцию с AI-моделями (Claude, Gemini) без развёртывания собственного бэкенда.
  • Попробовать платформу Puter как альтернативу традиционному серверу.
  • Создать удобный и красивый интерфейс на React.

В итоге получилось то, чем я горжусь — и теперь делюсь опытом.

Выбор стека

Вот основные технологии, которые я использовал:

  • React 19 + TypeScript — современный фронтенд с типизацией.
  • React Router 7 — маршрутизация между страницами.
  • Vite — быстрая сборка и горячая замена модулей (HMR).
  • Tailwind CSS — утилитарный подход к стилям, без лишних CSS-файлов.
  • Lucide React — лаконичные иконки.
  • Puter.js — SDK для работы с облачной платформой Puter.

Почему Puter? Это «интернет-ОС», которая предоставляет serverless-воркеры, KV-хранилище, постоянное файловое хранилище и доступ к AI-моделям прямо из браузера. Мне не понадобился отдельный бэкенд — разработка стала проще и быстрее.

Как Puter работает в проекте

Вся логика хранения проектов и вызова AI построена на Puter. Я использую три ключевые возможности:

  1. Файловое хранилище — загруженные планы и сгенерированные рендеры сохраняются как файлы. Puter автоматически создаёт публичные URL, которые можно использовать в теге img.
  2. KV-хранилище — хранение метаданных проекта: название, дата создания, владелец, приватность. Это быстрый key-value доступ, идеальный для таких данных.
  3. Serverless Workers — я написал несколько воркеров, которые вызываются через puter.action. Они обрабатывают загрузку, взаимодействие с AI и возвращают результат.

Все воркеры написаны на JavaScript и загружены в Puter через CLI. В результате я получил полноценный API без DevOps.

AI-генерация: из 2D-плана в 3D-рендер

Сердце приложения — функция generate3DView. Она отправляет изображение плана в AI-модель (Claude или Gemini) и получает обратно фотореалистичный рендер интерьера.

На стороне воркера формируется промпт:

«Преобразуй данный план помещения в фотореалистичное 3D-изображение интерьера. Учти расположение стен, окон, дверей. Добавь текстуры, мебель, освещение в современном стиле.»

Модель генерирует изображение, воркер сохраняет его в хранилище и возвращает base64 и публичную ссылку.

Проблемы, с которыми я столкнулся:

  • Ограничение размера изображения. Puter и модели не принимают большие файлы. Пришлось добавить валидацию: максимум 10 МБ, форматы JPG или PNG.
  • Время генерации. Иногда модель работает 10–15 секунд. На фронте я добавил анимированный лоадер, чтобы пользователь не нервничал.
  • Качество результата. Не всегда получается идеально, особенно при сложных планах. Планирую улучшать промпты и добавлять выбор стиля.

Фронтенд: компоненты и логика

Приложение состоит из двух страниц: главной (Home) и визуализатора (VisualizerId).

Главная страница

Пользователь видит список своих проектов и может загрузить новый план. Компонент Upload читает файл и преобразует его в base64.

После загрузки вызывается handleUploadComplete, который создаёт проект через createProject, сохраняет его в Puter и перенаправляет на страницу визуализатора с передачей изображения.

Важно: я использую isCreatingProjectRef.current, чтобы предотвратить повторную отправку при быстрых кликах.

Страница визуализатора

Здесь происходит основное действие. Компонент получает id из URL, загружает проект через getProjectById и, если рендер ещё не сгенерирован, запускает генерацию.

Чтобы генерация срабатывала только один раз, я использую useRef с флагом hasInitialGenerated.

Для сравнения «до и после» применяется библиотека react-compare-slider. Пользователь может перетаскивать ползунок и видеть разницу между исходным планом и рендером.

Также есть кнопки экспорта (скачать рендер) и «Поделиться» (в разработке).

Управление состоянием

Состояние проектов на главной странице хранится в локальном стейте. Redux не понадобился — React и хуки справляются отлично.

Основные сложности

  1. CORS при работе с Puter. SDK требует правильной настройки origin. В dev-режиме я использовал прокси Vite.
  2. Обработка base64. Puter ограничивает объём передаваемых данных. Решение: сначала сохраняю файл отдельно, а в KV-хранилище кладу только ссылку.
  3. Двойная генерация. Из-за строгого режима React в dev-сборке эффект мог срабатывать дважды. Исправил с помощью useRef и проверки наличия рендера.
  4. Асинхронная загрузка. При быстром переходе на страницу проект мог ещё не загрузиться. Добавил состояние isProjectLoading и планирую внедрить скелетон-интерфейс.
  5. Мобильный UI. Tailwind помог с адаптивом, но с react-compare-slider на мобильных пришлось поработать: уменьшил высоту и добавил поддержку touch-событий.

Что дальше?

  • Выбор стиля интерьера. Пользователь сможет указать «минимализм», «лофт», «скандинавский» и другие.
  • Редактирование после генерации. Возможность менять материалы, добавлять или удалять объекты.
  • Поддержка векторных форматов. Планирую добавить SVG и DXF для более точного распознавания.
  • Мобильное приложение. Разработка на React Native.
  • Интеграция с BIM-системами. Например, экспорт в IFC.

Заключение

Roomify показал, что современные технологии позволяют решать сложные творческие задачи с минимальными усилиями. Благодаря React и Puter я создал полноценный сервис всего за пару недель. Главное — не бояться экспериментировать и делиться результатами.

Читать оригинал