[{"data":1,"prerenderedAt":509},["ShallowReactive",2],{"api:\u002Fapi\u002Fconfig:ru":3,"api:\u002Fapi\u002Fabout:ru":8,"api:\u002Fapi\u002Fprojects:ru":50},{"email":4,"lang":5,"name":6,"role":7},"hello@ewsirdev.example","ru","Ewsirdev","Веб-разработчик: сайты, лендинги и сервисы на Go",{"honest":9,"how":15,"intro":31,"lang":5,"principles":34},[10,11,12,13,14],"Почти все проекты учебно-демонстрационные; один сайт — реализованный клиентский, имя клиента не называется. Отзывы и цифры по заказам здесь не заявляются.","Race-детектор (go test -race) на моей рабочей машине не запускается из-за отсутствия C-компилятора; он выполняется в CI.","Свой слой WebSocket не проходил Autobahn Test Suite: корректность проверена собственными тестами. В продакшене разумнее брать проверенную библиотеку.","Демо-данные в проектах (история мониторинга, ссылки, задачи) сгенерированы и помечены в интерфейсах как демо.","Контакты: только почта. Телефон и соцсети намеренно не указаны.",[16,19,22,25,28],{"title":17,"text":18},"Разговор","Выясняем задачу, аудиторию и ограничения. Если сайт не нужен, скажу об этом сразу.",{"title":20,"text":21},"Договорённости","Состав работ, сроки и что считается готовым. Письменно, без сюрпризов.",{"title":23,"text":24},"Сборка","Короткие итерации: промежуточный результат можно открыть и потрогать.",{"title":26,"text":27},"Проверка","Тесты, мобильные экраны, доступность, нагрузка на форму и API.",{"title":29,"text":30},"Запуск","Docker-образ или статика, инструкция по запуску, передача кода.",[32,33],"Я веб-разработчик: делаю лендинги и небольшие сервисы на Go. Почти все проекты на этом сайте учебно-демонстрационные: бренды вымышленные, данные демо, код приватный и открывается по запросу. Исключение — один реализованный клиентский сайт (клиента не называю).","Здесь нет отзывов и цифр о заказах: показываю только то, что можно проверить, то есть работающий код, тесты и README с ограничениями.",[35,38,41,44,47],{"title":36,"text":37},"Просто и проверяемо","Стандартная библиотека Go, понятная структура пакетов, тесты на то, что действительно важно: конкурентный захват задач, двойная бронь, протокол WebSocket.",{"title":39,"text":40},"Честные ограничения","В каждом README есть раздел «Ограничения»: один токен вместо ролей, один процесс, at-least-once вместо exactly-once. Лучше сказать заранее, чем объяснять потом.",{"title":42,"text":43},"Доступность по умолчанию","Контраст по WCAG AA, видимый фокус, работа с клавиатуры, уважение к prefers-reduced-motion, mobile-first вёрстка.",{"title":45,"text":46},"Без секретов в коде","Настройки идут через переменные окружения, токены генерируются при старте, если не заданы.",{"title":48,"text":49},"Один бинарник","Фронтенд встроен в Go-сервис через embed, запуск не требует установки зависимостей; для SQLite используется драйвер без CGO.",[51,76,93,109,130,147,163,181,199,218,243,265,289,316,341,366,386,410,434,459,474,491],{"slug":52,"title":53,"type":54,"stack":55,"description":59,"highlights":60,"run":65,"hue":66,"og":67,"shots":68},"kanban-tasks","Янтарь: канбан-доска","backend",[56,57,58],"Go","SQLite","Docker","Многопользовательская канбан-доска: регистрация, доски, колонки, карточки с перетаскиванием. Go + SQLite без CGO, фронт встроен в бинарник.",[61,62,63,64],"PBKDF2 и сессии в HttpOnly-cookie","Изоляция данных пользователей","Тесты API","Docker multi-stage","cd kanban-tasks && go run .",344,"\u002Fog\u002Fkanban-tasks.jpg",{"desktop":69,"desktop_sm":70,"mobile":71,"dw":72,"dh":73,"mw":74,"mh":75},"\u002Fshots\u002Fkanban-tasks-desktop.webp","\u002Fshots\u002Fkanban-tasks-desktop-sm.webp","\u002Fshots\u002Fkanban-tasks-mobile.webp",1280,800,390,844,{"slug":77,"title":78,"type":54,"stack":79,"description":80,"highlights":81,"run":86,"hue":87,"og":88,"shots":89},"link-shortener","Короче: сократитель ссылок",[56,57,58],"Сокращение ссылок с алиасами и сроком жизни, статистика кликов по дням, браузерам и устройствам, дашборд под токеном. IP не хранятся.",[82,83,84,85],"Редирект и учёт кликов","Лимит запросов","Приватная статистика (хэш с солью)","Тесты и Docker","cd link-shortener && set SEED_DEMO=1&& go run .\u002Fcmd\u002Fserver",111,"\u002Fog\u002Flink-shortener.jpg",{"desktop":90,"desktop_sm":91,"mobile":92,"dw":72,"dh":73,"mw":74,"mh":75},"\u002Fshots\u002Flink-shortener-desktop.webp","\u002Fshots\u002Flink-shortener-desktop-sm.webp","\u002Fshots\u002Flink-shortener-mobile.webp",{"slug":94,"title":95,"type":54,"stack":96,"description":97,"highlights":98,"run":102,"hue":103,"og":104,"shots":105},"booking-slots","Запись на приём",[56,57,58],"Онлайн-запись на услуги: свободные слоты с учётом длительности и рабочих часов, защита от двойной записи, админ-панель. Вымышленная студия, демо.",[99,100,101,85],"Расчёт свободных слотов","Без двойных записей","Админка для услуг и расписания","cd booking-slots && go run .",65,"\u002Fog\u002Fbooking-slots.jpg",{"desktop":106,"desktop_sm":107,"mobile":108,"dw":72,"dh":73,"mw":74,"mh":75},"\u002Fshots\u002Fbooking-slots-desktop.webp","\u002Fshots\u002Fbooking-slots-desktop-sm.webp","\u002Fshots\u002Fbooking-slots-mobile.webp",{"slug":110,"title":111,"type":112,"stack":113,"description":117,"highlights":118,"run":123,"hue":124,"og":125,"shots":126},"landing-studio","Полутон: студия света","landing",[114,115,116],"HTML","CSS","JS","Лендинг вымышленной студии интерьерного света: тёплая палитра, засечный шрифт, SVG-иллюстрация, FAQ и демо-форма. Адаптивный, без внешних картинок.",[119,120,121,122],"Адаптив 390-1280","SVG вместо картинок","Доступные FAQ и форма","Честная демо-форма","cd landing-studio && python -m http.server 8091",212,"\u002Fog\u002Flanding-studio.jpg",{"desktop":127,"desktop_sm":128,"mobile":129,"dw":72,"dh":73,"mw":74,"mh":75},"\u002Fshots\u002Flanding-studio-desktop.webp","\u002Fshots\u002Flanding-studio-desktop-sm.webp","\u002Fshots\u002Flanding-studio-mobile.webp",{"slug":131,"title":132,"type":112,"stack":133,"description":134,"highlights":135,"run":140,"hue":141,"og":142,"shots":143},"landing-saas","Рубильник: трекер подписок",[114,115,116],"Лендинг вымышленного SaaS-продукта: тёмный градиентный hero, макет интерфейса на CSS, тарифы, FAQ, демо-форма. Все цены и названия придуманы.",[136,137,138,139],"Макет интерфейса на CSS","Тарифная сетка","Адаптив","Демо-форма без отправки данных","cd landing-saas && python -m http.server 8092",182,"\u002Fog\u002Flanding-saas.jpg",{"desktop":144,"desktop_sm":145,"mobile":146,"dw":72,"dh":73,"mw":74,"mh":75},"\u002Fshots\u002Flanding-saas-desktop.webp","\u002Fshots\u002Flanding-saas-desktop-sm.webp","\u002Fshots\u002Flanding-saas-mobile.webp",{"slug":148,"title":149,"type":112,"stack":150,"description":151,"highlights":152,"run":156,"hue":157,"og":158,"shots":159},"landing-event","Малый масштаб: конференция",[114,115,116],"Лендинг вымышленной однодневной конференции: плакатная типографика, расписание, спикеры-заглушки, условия, демо-форма записи.",[153,154,138,155],"Расписание дня","Плакатная типографика","Без выдуманных имён спикеров","cd landing-event && python -m http.server 8093",124,"\u002Fog\u002Flanding-event.jpg",{"desktop":160,"desktop_sm":161,"mobile":162,"dw":72,"dh":73,"mw":74,"mh":75},"\u002Fshots\u002Flanding-event-desktop.webp","\u002Fshots\u002Flanding-event-desktop-sm.webp","\u002Fshots\u002Flanding-event-mobile.webp",{"slug":164,"title":165,"type":54,"stack":166,"description":169,"highlights":170,"run":174,"hue":175,"og":176,"shots":177},"uptime-monitor","Пульс: монитор доступности",[56,57,167,168,58],"SSE","REST API","Монитор доступности: HTTP и TCP проверки по расписанию, аптайм, p50\u002Fp95, детектор инцидентов, живой дашборд на SSE и публичная статус-страница. Go + SQLite без CGO.",[171,172,173,85],"Горутина-воркер на каждую проверку","Инциденты после серии падений","Дашборд на SSE и публичный \u002Fstatus","cd uptime-monitor && set SEED_DEMO=1&& go run .\u002Fcmd\u002Fserver",101,"\u002Fog\u002Fuptime-monitor.jpg",{"desktop":178,"desktop_sm":179,"mobile":180,"dw":72,"dh":73,"mw":74,"mh":75},"\u002Fshots\u002Fuptime-monitor-desktop.webp","\u002Fshots\u002Fuptime-monitor-desktop-sm.webp","\u002Fshots\u002Fuptime-monitor-mobile.webp",{"slug":182,"title":183,"type":54,"stack":184,"description":186,"highlights":187,"run":192,"hue":193,"og":194,"shots":195},"job-queue","Конвейер: очередь задач",[56,57,168,167,185,58],"Prometheus","Очередь фоновых задач: приоритеты, отложенные и cron-задачи, ретраи с backoff и jitter, dead-letter, идемпотентные ключи, lease с fencing, метрики Prometheus.",[188,189,190,191],"At-least-once с lease и fencing","Ретраи с backoff и jitter + dead-letter","Собственный cron-парсер","Метрики Prometheus и graceful shutdown","cd job-queue && set API_TOKEN=demo&& set SEED_DEMO=1&& go run .\u002Fcmd\u002Fserver",249,"\u002Fog\u002Fjob-queue.jpg",{"desktop":196,"desktop_sm":197,"mobile":198,"dw":72,"dh":73,"mw":74,"mh":75},"\u002Fshots\u002Fjob-queue-desktop.webp","\u002Fshots\u002Fjob-queue-desktop-sm.webp","\u002Fshots\u002Fjob-queue-mobile.webp",{"slug":200,"title":201,"type":54,"stack":202,"description":205,"highlights":206,"run":211,"hue":212,"og":213,"shots":214},"realtime-rooms","Комнаты: чат и доска в реальном времени",[56,203,57,204,58],"WebSocket","Canvas","Комнаты в реальном времени: чат с историей в SQLite, список «кто онлайн», индикатор «печатает», общая доска со штрихами и курсорами, анонимные ники. WebSocket (RFC 6455) написан на stdlib.",[207,208,209,210],"Свой слой WebSocket (RFC 6455) на stdlib","Отключение медленных клиентов и лимиты частоты","Graceful shutdown с кодом 1001","Нагрузочный тест: 360 соединений в 6 комнатах","cd realtime-rooms && set SEED_DEMO=1&& go run .\u002Fcmd\u002Fserver",46,"\u002Fog\u002Frealtime-rooms.jpg",{"desktop":215,"desktop_sm":216,"mobile":217,"dw":72,"dh":73,"mw":74,"mh":75},"\u002Fshots\u002Frealtime-rooms-desktop.webp","\u002Fshots\u002Frealtime-rooms-desktop-sm.webp","\u002Fshots\u002Frealtime-rooms-mobile.webp",{"slug":219,"title":220,"type":54,"stack":221,"description":230,"highlights":231,"run":236,"hue":237,"og":238,"shots":239},"api-gateway","Шлюз: API-gateway",[56,222,223,224,225,167,185,226,227,228,58,229],"stdlib only","Reverse proxy","Circuit breaker","Token bucket","slog","Vanilla JS","embed","GitHub Actions","API-шлюз на чистой stdlib: маршруты по хосту\u002Fпрефиксу из JSON-конфига с горячей перезагрузкой без обрыва соединений, балансировка round-robin и least-conn, health-checks, circuit breaker на узел, ретраи идемпотентных запросов, rate limit, хэшированные API-ключи, метрики Prometheus, живой дашборд на SSE.",[232,233,234,235],"Ноль зависимостей: только stdlib","Горячая перезагрузка конфига без обрыва соединений","Circuit breaker на узел и ретраи идемпотентных запросов","Нагрузочный тест: 4000 запросов, 40 клиентов (демо-замер)","cd api-gateway && set SEED_DEMO=1&& go run .\u002Fcmd\u002Fgateway",200,"\u002Fog\u002Fapi-gateway.jpg",{"desktop":240,"desktop_sm":241,"mobile":242,"dw":72,"dh":73,"mw":74,"mh":75},"\u002Fshots\u002Fapi-gateway-desktop.webp","\u002Fshots\u002Fapi-gateway-desktop-sm.webp","\u002Fshots\u002Fapi-gateway-mobile.webp",{"slug":244,"title":245,"type":54,"stack":246,"description":252,"highlights":253,"run":258,"hue":259,"og":260,"shots":261},"notes-search","Картотека: заметки с поиском",[56,57,247,248,249,168,250,251,227,228,58,229],"FTS5","bm25","modernc.org\u002Fsqlite (без CGO)","Markdown (свой безопасный рендер)","SVG force-layout","База Markdown-заметок на Go и SQLite: вики-ссылки [[заметка]] с обратными ссылками и графом связей, полнотекстовый поиск FTS5 (bm25, подсветка, упрощённая русская морфология), история версий с собственным diff, автосохранение с разрешением конфликтов, экспорт и импорт .md.",[254,255,256,257],"Поиск FTS5 с bm25 и подсветкой","Вики-ссылки, backlinks и граф связей","История версий с собственным diff","Свой безопасный Markdown-рендер с тестом на XSS","cd notes-search && set SEED_DEMO=1&& go run .\u002Fcmd\u002Fserver",160,"\u002Fog\u002Fnotes-search.jpg",{"desktop":262,"desktop_sm":263,"mobile":264,"dw":72,"dh":73,"mw":74,"mh":75},"\u002Fshots\u002Fnotes-search-desktop.webp","\u002Fshots\u002Fnotes-search-desktop-sm.webp","\u002Fshots\u002Fnotes-search-mobile.webp",{"slug":266,"title":267,"type":112,"stack":268,"description":275,"highlights":276,"run":282,"hue":283,"og":284,"shots":285},"landing-3d","ОКСО Т1: 3D-лендинг",[269,270,227,271,272,273,274,229],"HTML5","CSS3","WebGL2","GLSL ES 3.00","Raymarching\u002FSDF","Scroll choreography","Лендинг вымышленного датчика воздуха (демо): объект рисуется одним фрагментным шейдером на чистом WebGL2 без библиотек, четыре SDF-формы перетекают по скроллу, есть SVG-фолбэк, reduced-motion и пауза вне экрана.",[277,278,279,280,281],"Один фрагментный шейдер","WebGL2 без библиотек","Четыре SDF-формы с морфингом по скроллу","SVG-фолбэк и prefers-reduced-motion","Пауза отрисовки вне экрана","cd landing-3d && python -m http.server 8094",90,"\u002Fog\u002Flanding-3d.jpg",{"desktop":286,"desktop_sm":287,"mobile":288,"dw":72,"dh":73,"mw":74,"mh":75},"\u002Fshots\u002Flanding-3d-desktop.webp","\u002Fshots\u002Flanding-3d-desktop-sm.webp","\u002Fshots\u002Flanding-3d-mobile.webp",{"slug":290,"title":291,"type":54,"stack":292,"description":301,"highlights":302,"run":309,"hue":310,"og":311,"shots":312},"raft-kv","Плот: KV на Raft",[56,293,294,295,222,296,167,297,298,299,300,227,58,229],"Raft","Distributed systems","Consensus","HTTP\u002FJSON","WAL + fsync","Snapshots","Linearizability","Deterministic simulation testing","Учебная реализация Raft с нуля на чистой stdlib: выборы лидера, репликация лога, коммит по кворуму, лог и term\u002Fvote на диске с fsync, снапшоты с компакцией, линеаризуемые чтения (read-index), редирект фолловера на лидера. Тестируется детерминированным симулятором сети и времени с проверкой линеаризуемости; дашборд умеет убивать лидера и рвать сеть (демо).",[303,304,305,306,307,308],"Raft с нуля на stdlib","без raft-библиотек","Детерминированный симулятор сети и времени + проверка линеаризуемости","Лог и term\u002Fvote с fsync","снапшоты и компакция","Дашборд: убить лидера и разорвать сеть (демо)","cd raft-kv && set SEED_DEMO=1&& go run .\u002Fcmd\u002Fraft-kv",290,"\u002Fog\u002Fraft-kv.jpg",{"desktop":313,"desktop_sm":314,"mobile":315,"dw":72,"dh":73,"mw":74,"mh":75},"\u002Fshots\u002Fraft-kv-desktop.webp","\u002Fshots\u002Fraft-kv-desktop-sm.webp","\u002Fshots\u002Fraft-kv-mobile.webp",{"slug":317,"title":318,"type":54,"stack":319,"description":328,"highlights":329,"run":334,"hue":335,"og":336,"shots":337},"auth-service","Ключница: сервис аутентификации",[56,320,57,249,321,322,323,324,325,326,327,227,228,58,229],"stdlib crypto","JWT EdDSA\u002FEd25519","JWKS","PBKDF2","TOTP","RBAC","REST","OpenAPI 3","Сервис аутентификации и авторизации на Go: EdDSA-JWT с ротацией ключей и JWKS, refresh-токены с ротацией и обнаружением кражи, TOTP-2FA (RFC 6238) с резервными кодами, RBAC, блокировка при переборе, сброс пароля по одноразовому токену, журнал аудита, список устройств, openapi.yaml. Не прошёл независимый аудит, не production-IdP.",[330,331,332,333],"JWT EdDSA и ротация ключей с JWKS","Refresh-токены с ротацией и reuse-detection","TOTP по RFC 6238 с проверкой на векторах RFC","Журнал аудита только на дозапись (триггеры БД)","cd auth-service && set SEED_DEMO=1&& go run .\u002Fcmd\u002Fserver",20,"\u002Fog\u002Fauth-service.jpg",{"desktop":338,"desktop_sm":339,"mobile":340,"dw":72,"dh":73,"mw":74,"mh":75},"\u002Fshots\u002Fauth-service-desktop.webp","\u002Fshots\u002Fauth-service-desktop-sm.webp","\u002Fshots\u002Fauth-service-mobile.webp",{"slug":342,"title":343,"type":54,"stack":344,"description":353,"highlights":354,"run":359,"hue":360,"og":361,"shots":362},"finance-tracker","Книга учёта: личные финансы",[56,57,249,168,345,346,347,348,349,350,351,58,229,323,352],"Nuxt 4","Vue 3","TypeScript","Pinia","SVG-графики","vitest","ESLint","CSV import\u002Fexport","Учёт личных финансов: счета в разных валютах с ручными курсами, доходы, расходы и переводы, бюджеты, платежи по cron-подобному расписанию, импорт CSV с превью, отчёты. Деньги только в целых минорных единицах, данные пользователей изолированы, графики нарисованы на SVG без библиотек. Go + SQLite и фронтенд на Nuxt 4.",[355,356,357,358],"Деньги только целыми минорными единицами","Мультивалютность с ручными курсами","Импорт CSV с превью и пробным прогоном","Свои SVG-графики без библиотек","cd finance-tracker && set SEED_DEMO=1&& go run .",140,"\u002Fog\u002Ffinance-tracker.jpg",{"desktop":363,"desktop_sm":364,"mobile":365,"dw":72,"dh":73,"mw":74,"mh":75},"\u002Fshots\u002Ffinance-tracker-desktop.webp","\u002Fshots\u002Ffinance-tracker-desktop-sm.webp","\u002Fshots\u002Ffinance-tracker-mobile.webp",{"slug":367,"title":368,"type":54,"stack":369,"description":373,"highlights":374,"run":379,"hue":380,"og":381,"shots":382},"pixel-wall","Пиксельная стена: общий холст",[56,222,203,370,227,228,371,372,58,229],"Canvas 2D","Binary protocol","Snapshot + journal","Совместный холст 256×256 в духе r\u002Fplace: 16 цветов, кулдаун на сессию и IP, свой WebSocket-слой на stdlib (RFC 6455) с бинарным протоколом (4 бита на пиксель), снимок и дельты, снапшот плюс журнал с восстановлением, таймлапс, зум и пан, мини-карта, экспорт PNG, админ-инструменты. Пет-проект.",[375,376,377,378],"Свой WebSocket (RFC 6455) на stdlib","Бинарный протокол: 4 бита на пиксель","Снапшот + журнал с восстановлением после падения","Таймлапс по журналу изменений","cd pixel-wall && set SEED_DEMO=1&& set ADMIN_TOKEN=secret&& go run .\u002Fcmd\u002Fserver",320,"\u002Fog\u002Fpixel-wall.jpg",{"desktop":383,"desktop_sm":384,"mobile":385,"dw":72,"dh":73,"mw":74,"mh":75},"\u002Fshots\u002Fpixel-wall-desktop.webp","\u002Fshots\u002Fpixel-wall-desktop-sm.webp","\u002Fshots\u002Fpixel-wall-mobile.webp",{"slug":387,"title":388,"type":389,"stack":390,"description":397,"highlights":398,"run":403,"hue":404,"og":405,"shots":406},"gitpulse","GitPulse: аналитика git-репозиториев","cli",[56,222,391,392,393,394,395,396,229,58],"CLI","git","html\u002Ftemplate","SVG","ANSI","os\u002Fexec","CLI на Go для анализа git-репозиториев без внешних зависимостей (нужен только git): stats с цветами и спарклайнами в терминале, report — самодостаточный HTML-отчёт с тепловой картой активности, churn и горячими файлами, вкладом авторов, bus factor по каталогам, ростом кода по языкам и периодами тишины (светлая и тёмная темы), diff-hotspots между ревизиями и локальный serve на 127.0.0.1. История читается потоком через git log -z --numstat -M. Пет-проект.",[399,400,401,402],"Только stdlib Go, внешний бинарник один: git","Поток git log -z --numstat -M с учётом .mailmap и переименований","Самодостаточный HTML-отчёт: тепловая карта, churn, bus factor, светлая и тёмная темы","Синтетическая история из 100 000 коммитов анализируется около 5 секунд","cd gitpulse && go run .\u002Fcmd\u002Fgitpulse stats .",7,"\u002Fog\u002Fgitpulse.jpg",{"desktop":407,"desktop_sm":408,"mobile":409,"dw":72,"dh":73,"mw":74,"mh":75},"\u002Fshots\u002Fgitpulse-desktop.webp","\u002Fshots\u002Fgitpulse-desktop-sm.webp","\u002Fshots\u002Fgitpulse-mobile.webp",{"slug":411,"title":412,"type":413,"stack":414,"description":419,"highlights":420,"run":427,"hue":428,"og":429,"shots":430},"legal-multipage-site","Многостраничный сайт юридической компании","site",[345,346,347,415,416,417,418,58,229],"Bootstrap 5","Zod","Vitest","Playwright","Реализованный сайт юридической и экспертной компании на Nuxt 4: 65 страниц с серверным рендерингом, JSON-LD разметка и 301-редиректы со старого сайта. Заявки уходят через серверный эндпоинт с проверкой Origin, лимитом размера тела и ограничением частоты запросов.",[421,422,423,424,425,426],"65 маршрутов с SSR, sitemap.xml и robots.txt; индексация включается явным флагом окружения","Форма заявок: серверный эндпоинт, проверка Origin, лимит тела 10 КБ, 3 запроса за 10 минут с одного IP, honeypot, опциональная капча","JSON-LD: LegalService, WebSite, BreadcrumbList","Одношаговые 301-редиректы со старых URL и со слешей на конце, заголовки безопасности (CSP, HSTS)","CI\u002FCD: lint, typecheck, Vitest, сборка, Playwright; затем Docker-образ и выкладка на сервер","210 модульных тестов в 13 файлах и 4 набора e2e-тестов","npm install && npm run build && node .output\u002Fserver\u002Findex.mjs",250,"\u002Fog\u002Flegal-multipage-site.jpg",{"desktop":431,"desktop_sm":432,"mobile":433,"dw":72,"dh":73,"mw":74,"mh":75},"\u002Fshots\u002Flegal-multipage-site-desktop.webp","\u002Fshots\u002Flegal-multipage-site-desktop-sm.webp","\u002Fshots\u002Flegal-multipage-site-mobile.webp",{"slug":435,"title":436,"type":437,"stack":438,"description":446,"highlights":447,"run":452,"hue":453,"og":454,"shots":455},"bad-club-booking-app","Bad Club: бронирование мест в игровом коворкинге","app",[346,439,348,440,441,442,443,444,445],"Vite","Vue Router","GSAP","Express","node:sqlite","JWT (httpOnly cookie)","Resend","Демо-приложение на Vue 3 и Express с SQLite: интерактивная карта зала с бронированием мест, личный кабинет и админ-панель с редактором расстановки. Вход без паролей, по одноразовому коду на e-mail.",[448,449,450,451],"Карта зала с зонами (обычные, тихая, VIP, два монитора), фильтром по типу и статусом мест","Админ-панель: обзор, брони, столы, компьютеры, пользователи и перетаскиваемая расстановка зала","Вход по OTP с ограничением попыток и частоты запросов, роль admin задаётся через переменную окружения","Данные для демо создаются сид-скриптом при первом запуске","npm install && npm run dev",150,"\u002Fog\u002Fbad-club-booking-app.jpg",{"desktop":456,"desktop_sm":457,"mobile":458,"dw":72,"dh":73,"mw":74,"mh":75},"\u002Fshots\u002Fbad-club-booking-app-desktop.webp","\u002Fshots\u002Fbad-club-booking-app-desktop-sm.webp","\u002Fshots\u002Fbad-club-booking-app-mobile.webp",{"slug":460,"title":461,"type":112,"stack":462,"description":463,"highlights":464,"run":452,"hue":468,"og":469,"shots":470},"dovod-concept","Довод: концепт лендинга экспертной организации",[345,346,347,115,229],"Концепт лендинга на Nuxt 4 для вымышленной экспертной организации: направления услуг, форма консультации с маской телефона, карусель отзывов и страница политики. Компания, отзывы, цифры и контакты придуманы; форма ничего не отправляет.",[465,466,467],"Форма с маской телефона, валидацией и подсказками по ошибкам; в демо показывает «данные не отправляются»","Бесконечная карусель отзывов со свайпом и автопрокруткой","Мобильная панель действий, адаптивная вёрстка, скелетон поверх серверного HTML",215,"\u002Fog\u002Fdovod-concept.jpg",{"desktop":471,"desktop_sm":472,"mobile":473,"dw":72,"dh":73,"mw":74,"mh":75},"\u002Fshots\u002Fdovod-concept-desktop.webp","\u002Fshots\u002Fdovod-concept-desktop-sm.webp","\u002Fshots\u002Fdovod-concept-mobile.webp",{"slug":475,"title":476,"type":413,"stack":477,"description":480,"highlights":481,"run":452,"hue":485,"og":486,"shots":487},"niche-landings","Каталог демо-лендингов под 10 ниш",[346,478,479,229],"Vue Router 4","Vite 8","Vue-каталог из десяти самостоятельных лендингов под разные ниши малого бизнеса: у каждого своя палитра, шрифты и структура секций. Каждый лендинг загружается отдельным чанком; весь контент демонстрационный.",[482,483,484],"10 ниш: медицина, мебель, ремонт, онлайн-школа, глэмпинг, юристы, автосервис, салон красоты, кафе, фитнес","Код-сплиттинг по маршрутам, общий набор SVG-иконок","Плашка «Демо-контент» на каталоге и каждом лендинге",32,"\u002Fog\u002Fniche-landings.jpg",{"desktop":488,"desktop_sm":489,"mobile":490,"dw":72,"dh":73,"mw":74,"mh":75},"\u002Fshots\u002Fniche-landings-desktop.webp","\u002Fshots\u002Fniche-landings-desktop-sm.webp","\u002Fshots\u002Fniche-landings-mobile.webp",{"slug":492,"title":493,"type":112,"stack":494,"description":497,"highlights":498,"run":502,"hue":503,"og":504,"shots":505},"dental-concept","Кварц: концепт лендинга стоматологии",[114,115,495,370,496,229],"JavaScript","htmlhint","Концепт одностраничного лендинга вымышленной стоматологии в стиле Liquid Chrome Dark: стеклянные карточки, хромированные заголовки и 3D-блоб в виде зуба на canvas. Один HTML-файл без сборки и зависимостей.",[499,500,501],"Анимированный блоб на canvas с учётом prefers-reduced-motion и видимости на экране","Форма записи с маской телефона и доступными сообщениями об ошибках","CI: htmlhint и проверка локальных ссылок и якорей","python -m http.server 8080",190,"\u002Fog\u002Fdental-concept.jpg",{"desktop":506,"desktop_sm":507,"mobile":508,"dw":72,"dh":73,"mw":74,"mh":75},"\u002Fshots\u002Fdental-concept-desktop.webp","\u002Fshots\u002Fdental-concept-desktop-sm.webp","\u002Fshots\u002Fdental-concept-mobile.webp",1792697892467]