gora.
BRUNO Tbilisis

Verslo logika

Koncepcija „Midnight Cellar“, paletė ir šriftai, 16 animacijos sluoksnių grynu CSS, GEO optimizacija LLM, turinio pipeline'as 200+ nuotraukų, technologijų stekas.

~14 min skaityti · 2850 žodžių
Pilna apžvalga: pagrindinis puslapis (Hero → About → Signatures → Reels → Gallery → Reviews → Visit → Footer) + puslapis /reels su autoplay vaizdo įrašais. Desktop ir mobiliosios versijos apžvalgos — naršyklė pasirenka šaltinį pagal viewport plotį.

TL;DR

BRUNO Tbilisi — modern European fusion Vake rajone. Svetainė sukurta kaip editorial žurnalas: gilus ink-juodas fonas („Midnight Cellar"), kreminis teksto popierius, fire-orange žvakės akcentas, Fraunces Variable display su italic intarpais, IBM Plex Serif body tekstui. 16 animacijos sluoksnių realizuoti grynu CSS + IntersectionObserver — be framer-motion, be animacijų bibliotekų. Multi-page architektūra: 9 pagrindinio puslapio sekcijos + 8 routes. Built for GEO: JSON-LD Restaurant + Menu + FAQPage, llms.txt su answer-first santrauka, robots.txt su eksplicitiniu Allow GPTBot, ClaudeBot, PerplexityBot, Google-Extended botams. Turinio pipeline'as surenka 200+ nuotraukų iš 5 šaltinių (Instagram, Yandex Maps, Restaurant Guru, TripAdvisor, Google Business), apdorojimas per sharp + blurhash + pHash deduplikaciją. Diegimas — VPS + nginx + Cloudflare, domenas brunotbilisi.com.

Kontekstas ir auditorija

BRUNO — restoranas Vake rajone, premium Tbilisio kvartale. Tikslinis svečias: tarptautinis turistas 30–45 metų (vizitas 2–4 dienoms) arba ekspatas, ieškantis geros vietos su biodynamic wine ir padoriu brunch. Konkurencija Vake intensyvi: dešimtys vietų 500 m spinduliu, kiekviena su savo Instagram ir Resos puslapiu.

Užsakovas norėjo svetainės-parduotuvės, ne vizitinės kortelės. Tikslas — paversti organinę paiešką į rezervacijas ir Wolt pristatymo užsakymus. Tai reiškia:

  1. Atrandamumas LLM asistentuose — kai turistas klausia ChatGPT „where to get good brunch in Tbilisi", BRUNO turi patekti į top-3.
  2. Editorial tankis — mažai teksto, daug nuotraukų, viskas ritmiška. Ne „apie mus / meniu / kontaktai", o scena-nuotaika, kaip vyno žurnale.
  3. Adaptyvumas visiems trims svečių tipams — užsiėmęs verslo pietūs (reikia kainos + laiko + telefono), suplanuota vakarienė (reikia viso meniu + biodinaminių vynų), brunch savaitgaliais (reikia patiekalų nuotraukų ir darbo valandų).

Vaizdo apžvalga viršuje rodo tikrą puslapio ritmą: pauzė hero (žvakė mirga viršutiniame dešiniame kampe), išryškėjančios signature patiekalų kortelės su 3D tilt, /reels su įtaisytomis vaizdo kilpomis, masonry galerija su blurhash placeholder, ilgos žurnalinės citatos reviews skiltyje.

Koncepcija: Midnight Cellar

Užeiti į vyno restoraną vakare — tai įžengti į pustamsę salę, kur žvakės ant stalų, plytinės arkos, buteliai už stiklo ir prislopintas jazz. Aš perkėliau tai į digital — tiesiogine prasme. Paletė priešinga įprastam „restoraninės" svetainės stiliui (kur paprastai baltas fonas su pasteliniais akcentais): čia gilus ink-juodas su šiltai kreminiu teksto popieriumi. Žvakės ugnis — vienintelis dalykas, kuris šviečia.

Trys koncepcijos raktai:

  1. Ne skeuomorfizmas, o aliuzija. Aš nepiešiu žvakės — aš statau radialinį gradientą radial-gradient(ellipse 55% 42% at 18% 15%, rgba(201,101,31,0.28) 0%, transparent 55%) su keyframe mirgėjimo animacija (6s ease-in-out infinite). Efektas — tarsi viršuje dešinėje degtų šiltos šviesos šaltinis, ir jis šiek tiek pulsuoja. To pakanka — smegenys pačios užbaigia žvakę.
  2. Žurnalinis ritmas, ne lendinginis. Sekcijos plačios, hairline skirtukai 1px gradientu į skaidrumą (linear-gradient(to right, transparent, rgba(245,238,224,0.16), transparent)), daug oro. Antraštės stambios, body 16-17px, line-height 1.7. Ne „parduodantis lendingas", o ilgas atvartas žurnale.
  3. Editorial > marketing. Jokių „Užsakyk stalą dabar pat!" huge-buttons. Rezervacijos mygtukas ramus, mini-mono caps. Svarbiausia — nuotraukos ir tekstai.

Paletė

app/globals.css :root — tokenai:

TokenasHEXVaidmuo
--ink-base#0D0A07gilus ink-juodas, body fonas — tarp juodos ir tamsiai rudos
--ink-raised#15110Bpakeltas sluoksnis — kortelės, hover-state
--ink-inset#080605giliau už base — fokusinės sekcijos (Hero, Reviews)
--ink-linergba(245,238,224,0.08)ploni brūkšniai — skirtukai, borders
--ink-line-strongrgba(245,238,224,0.16)hairline divider gradiento centras
--cream#F5EEE0pagrindinis tekstas — šiltas popierius, ne grynas baltas
--cream-muted#9A8E78antrinis tekstas — caption, meta
--fire#C9651Fugninis oranžinis — žvakė, akcentas, single CTA
--fire-glowrgba(201,101,31,0.12)švelnus pašvaitis candle-glow utilitams
--fire-glow-strongrgba(201,101,31,0.22)sustiprintas pašvaitis hero
--wine#6B1E2Aretas emocinis akcentas (brunch, atsiliepimai)
--wine-muted#3A1419tamsus vynas, giliosioms sekcijoms

Tik dvi akcento spalvos — fire ir wine. Žalios nėra, mėlynos nėra, violetinės nėra. Tai suteikia vizualinį monolitiškumą — net be logotipo svetainė atpažįstamai „BRUNO".

Tipografija

Trys šriftai, visi per next/font/google:

const fraunces = Fraunces({
  subsets: ['latin'],
  variable: '--font-fraunces',
  axes: ['SOFT', 'WONK', 'opsz'],
  display: 'swap',
});
const plexSerif = IBM_Plex_Serif({ ..., weight: ['400'] });
const plexMono  = IBM_Plex_Mono({ ..., weight: ['400', '500'] });
  • Fraunces Variable display antraštėms. Aktyvios trys ašys: SOFT (serifų minkštumas 0–100), WONK (charakteringos „keistos" formos 0–1), opsz (optinis dydis 9–144). Italic variantas su WONK 1 ir SOFT 100 atrodo kaip rankų raižinys — ne kaip įprastas pasvirimas. Tai suteikia retą charakterį, kurį sunku pakartoti.
  • IBM Plex Serif body tekstui — neutralus modernus serif, weight 400. Gerai skaitomas ant tamsaus fono ilgose ištraukose.
  • IBM Plex Mono meta — caption, kainos, darbo valandos, telefonas. Mono editorial kontekste — užuomina į „etiketę", į rankų darbą.

Pagrindinės utilities:

.display {
  font-family: var(--font-fraunces);
  font-variation-settings: 'SOFT' 30, 'WONK' 0, 'opsz' 144;
  letter-spacing: -0.035em;
  line-height: 0.92;
}
.display-italic {
  font-style: italic;
  font-variation-settings: 'SOFT' 100, 'WONK' 1, 'opsz' 144;
}

Letter-spacing -0.035em ir line-height 0.92 display antraštėms — labai tankios, tai „grūdas". Body tekste — įprasti 1.7 line-height, patogu skaityti ilgose ištraukose.

16 animacijos sluoksnių

Pagrindinis skirtumas nuo kitų portfelio kazusų — čia animacijos gryname CSS + IntersectionObserver, be framer-motion, be animacijų bibliotekų. Tai reiškia:

  • Bundle mažesnis ~80 KB gzipped
  • SSR veikia idealiai (niekas „nešokinėja" per hidrataciją)
  • Performance — visos animacijos GPU compositor, neperskaičiuojamos kiekviename rAF

Vaizdo įraše viršuje matomi 9 iš 16. Pilnas sąrašas:

Globalūs sluoksniai

  1. Film grain per body::before. SVG-noise per feTurbulence, opacity 0.04, mix-blend-mode: screen. Nuolatinė plėvelės tekstūra — momentinis foto-spaudos pojūtis, ne „makeup'o".
  2. Scroll progress bar — fixed top, fire-orange juostelė, plotis = scrollY / scrollHeight. Realizuota per Element.animate({ width: '...%' }) su rAF-throttle.
  3. Scroll velocity blur — esant greitam scroll body gauna filter: blur(0..1.8px) per --scroll-blur CSS kintamąjį. Lerp glotninimas (current += (target - current) * 0.3) pašalina trūkčiojimą. Lėto scrollinimo metu blur = 0.

Hero

  1. Candle flicker — radial-gradient viršutiniame dešiniame kampe su keyframe candleFlicker 6s ease-in-out infinite, keičiantis opacity į 0.85 → 1.0 → 0.92 → 1.0 nereguliariais intervalais. Panašu į tikrą žvakės liepsną.
  2. Hero parallax per JS apvalkalą HeroParallax: fonas slenka 0.3× nuo scrollY per CSS kintamąjį --parallax-y.
  3. Gyro-drift mobilėje: pakreipus įrenginį fonas slenka ±2-3° pagal kampą. Per DeviceOrientationEvent API — ten, kur iOS suteikia permission. Viena iš nedaugelio Tbilisio svetainių, naudojančių gyroscope.

Sekcijos

  1. Scroll-reveal per [data-reveal] atributą ir IntersectionObserver. Elementas turi opacity: 0; transform: translateY(24px), patekęs į viewport gauna data-reveal-in="true" → opacity ir transform į nulį, transition 600ms cubic-bezier(0.22, 1, 0.36, 1). Stagger per --reveal-delay CSS kintamąjį.
  2. Menu category stagger + 3D tilt. Puslapyje /menu ir Signatures pagrindiniame — kortelės reaguoja į mouse-over: transform: perspective(1000px) rotateX(...) rotateY(...) priklausomai nuo žymeklio padėties. Subtilu, bet daro korteles „gyvas". Stagger atsiradimo metu — 80ms tarp kortelių.
  3. Gallery wave — masonry blokai gauna reveal-delay pagal diagonal-bangą: delay = (col * 50 + row * 80)ms. Sukuria „užplūstančios bangos" efektą vietoj nuobodaus vienalaikio atsiradimo.
  4. Amber panel breathe — Brunch & Bar sekcija (atskirame puslapyje /brunch) kvėpuoja: šiltas gintarinis švytėjimas pulsuoja 8s alternate. Negalima pamatyti pagrindinio puslapio apžvalgoje — reikia užeiti į /brunch.
  5. Sunrise sweep — one-shot animacija /brunch panelėje. Pirmą kartą patekus į viewport (sessionStorage flag) panelė gauna class sunrise-sweep, ir šviesos gradientas „prariedi" iš kairės į dešinę per 1.5s. „Saulėtekio" efektas.

Touch / Mobile

  1. Touch ripple — pasirinktinis prisilietimo feedback: per touchstart atsiranda apskritimas su opacity-fade-out per 600ms. Geriau nei default tap-highlight.
  2. Swipe hints — mobiliojoje Signatures karuselėje: plona rodyklė „pravažiuoja" pirmą kartą lankant sekciją, užsimindama apie swipe.
  3. Music note ping — užvedus pelę ant „cocktails" sekcijos desktop'e maža music-note ikona pingina su tiny scale 1.0 → 1.15 → 1.0.

Reels

  1. Autoplay-on-scroll videos /reels puslapyje: 8 vaizdo kilpos su interjeru ir patiekalais. Naudojamas IntersectionObserver su threshold 0.5 — jei vaizdas viewport centre, jis groja, kitaip pauzuojamas. Be garso. Optimizacija — preload="metadata" visiems, vaizdas atsisiunčiamas tik scrollinant prie jo.

CountUp

  1. CountUp About sekcijoje: reitingai 4.9★, 4.8★, 4.6★, 4.7★ iš keturių šaltinių (Google/Yandex/TripAdvisor/Restaurant Guru) — animuojami nuo 0 iki tikslinės reikšmės per 1.2s patekus į viewport. Subtilu, bet suteikia „gyvą" atspalvį skaičiams.

Visi 16 sluoksnių gerbia prefers-reduced-motion: reduce. CSS:

@media (prefers-reduced-motion: reduce) {
  .candle-glow::before { animation: none; }
  [data-reveal] { transition: opacity 200ms; transform: none !important; }
  /* ... */
}

JS — window.matchMedia('(prefers-reduced-motion: reduce)').matches patikra kiekvieno komponento-provaiderio starte, fallback į no-op.

Puslapio architektūra

Pagrindinis (app/page.tsx) — 9 sekcijos:

  1. Hero (#top) — full-bleed salės nuotrauka + display antraštė „Bruno · Vake", paantraštė „Modern European fusion", hours + tel mini-mono caps
  2. HomeQuoteStrip — trumpa citata iš gourmet apžvalgos, fire-orange wonk-italic
  3. HomeTriad — trys vertikalūs blokai: „Eat", „Drink", „Visit" su nuotraukomis
  4. Signatures (#signatures) — 9 signature patiekalai su preview + 3D tilt grid
  5. Reels (#reels) — 4 įtaisytos vaizdo kilpos su autoplay-on-scroll
  6. Gallery (#gallery) — 57 nuotraukos masonry, blurhash placeholder
  7. Reviews (#reviews) — ilgos žurnalinės citatos iš 4 šaltinių (Google/Yandex/TripAdvisor/Guru)
  8. HomeVisitCompact — žemėlapis + adresas + valandos + telefonas + booking link
  9. Footer — socialiniai tinklai, jur. informacija (BBB Restogroup LLC, 402360404)

Sticky Nav viršuje — fade-in po pirmo scrollinimo, blur backdrop, semi-transparent ink. Gilaus lygio puslapiuose (pvz. /menu/pasta) pridedamas Breadcrumb. Paslėpta ScrollProgress — fire-orange juostelė pačioje viršuje.

Vidiniai puslapiai

8 routes už pagrindinio ribų:

  • /menu + /menu/{category} — 11 kategorijų (starters, salads, pasta, pizza, mains, desserts, brunch, brunch-extras, kids, drinks, wine). Kiekviena subkategorija turi savo puslapį su full-bleed nuotrauka ir stagger patiekalų kortelėmis.
  • /brunch — atskiras nusileidimo puslapis tikslinei auditorijai „brunch iki 16:00 kasdien". Jame gyvena sunrise sweep — lėčiausia ir emocingiausia svetainės animacija.
  • /cocktails — atskiras puslapis su CocktailsPanel + muzikinis ping efektas ant ikonos.
  • /reels — autoplay-on-scroll režimas: 8 vaizdo kilpos, scrollini ir matai viską, kas vyksta salėje.
  • /reviews — pilni 127 atsiliepimai, 4 filtrai pagal šaltinį.
  • /visit — žemėlapis + trys būdai pasiekti + parkavimas + dress code.
  • /about — ilgas tekstas apie restorano filosofiją + reitingai CountUp.

GEO: built for LLM-discoverability

Svetainė buvo daroma antrajam paieškos kontūrui — LLM asistentams (ChatGPT, Claude, Perplexity). Surinkimo metu Tbilisyje niekas tuo neužsiėmė. Kas padaryta:

public/llms.txt

Answer-first santrauka plain-text formatu: 600 žodžių su atsakymais į 8 pagrindinius klausimus („where is BRUNO", „what's the cuisine", „opening hours", „brunch menu", „cocktail program", „vegan options", „booking", „address"). Sustruktūrinta kaip Q&A. LLM botai indeksuodami gauna koncentratą — nereikia parsinti HTML.

public/robots.txt

Eksplicitinis Allow: šiems botams:

User-agent: GPTBot
Allow: /
User-agent: ClaudeBot
Allow: /
User-agent: PerplexityBot
Allow: /
User-agent: Google-Extended
Allow: /
User-agent: Applebot-Extended
Allow: /
User-agent: Bytespider
Allow: /

Daugelis restoranų svetainių Tbilisyje blokuoja šiuos botus pagal nutylėjimą (per default CMS robots.txt). Mes — priešingai.

JSON-LD

app/layout.tsx įdiegta pilna schema:

  • Restaurant — name, address, geo, phone, hours, priceRange, servesCuisine, acceptsReservations
  • Menu — visos 11 kategorijų su MenuSection ir MenuItem (pavadinimas, aprašymas, kaina, allergen, image)
  • FAQPage — 8 klausimai su answer-first atsakymais

Semantic HTML

<article>, <section>, <dl>/<dt>/<dd>, <figure>/<figcaption> — visur, kur tinka. LLM botai geriau ištraukia esybes iš teisingai sumarkuoto turinio.

Answer-first proza About / Visit / FAQ

Ne „BRUNO — tai vieta, kur...", o „BRUNO is a modern European fusion restaurant in Vake, Tbilisi. Address: Zakaria Paliashvili 11a. Phone: +995 551 07 78 49. Hours: Sun–Thu 11:00–23:00, Fri–Sat 11:00–02:00." — plikas atsakymas pirmame sakinyje, toliau detalės.

Rezultatas

Per 2 mėnesius po publikacijos BRUNO patenka į ChatGPT ir Perplexity esant užklausoms „brunch in Tbilisi", „european fusion Vake", „truffle pasta Tbilisi". Tai organinis kanalas, kurio nenupirksi ir kuris nepriklauso nuo mokamų kanalų.

Turinio pipeline'as 200+ nuotraukų

Pagrindinis restorano svetainės skausmas — nuotraukos. Užsakovas suteikė prieigą prie Instagram ir bendrą Yandex Maps aplanką. Surinkau pipeline'ą iš 5 šaltinių:

ŠaltinisĮrankisNuotraukos
Instagram @brunotbilisiinstaloader (be login, viešas profilis)242 postai
Yandex MapsPlaywright headless chromium → /gallery/ → orig65+
Google Business ProfilePlaywright per g.page/r/...~30
TripAdvisorPlaywright per review URL~40
Restaurant GuruPlaywright per profile45

Po surinkimo — vieningas pipeline scripts/process-gallery.mjs:

  1. Resize per sharp: long edge max 1600px (daugiau webui nereikia).
  2. Convert į du formatus: WebP q=82 + AVIF q=70. Front-ende — <picture> su <source type="image/avif"> + WebP fallback. AVIF sunkesnis CPU, bet dydis mažesnis 20-30%.
  3. Blurhash kiekvienai nuotraukai — 32 simbolių placeholder, renderinamas iš karto į <canvas> kol kraunamas galutinis vaizdas. Jokių „šokimų" layout, jokių grey rectangles.
  4. pHash deduplikacija — tos pačios nuotraukos yra IG ir Yandex (restorano foto aplankas). pHash distance < 5 — laikomas dublikatu, paliekama tik geriausia pagal raišką.
  5. Manifestpublic/gallery/manifest.json su metaduomenimis:
    [{
      "src": "/gallery/2025-03-15_001.webp",
      "srcAvif": "/gallery/2025-03-15_001.avif",
      "blurhash": "L9AS}j%M00%M~q%M00%M",
      "width": 1600, "height": 2000,
      "caption": "...", "date": "2025-03-15",
      "source": "instagram",
      "tags": ["food", "interior", "drinks"]
    }]
    
  6. Curation manifest.curated.json faile — hero kandidatų atranka (nuotraukos su luminosity ~0.48 — ne per tamsios, ne pereksponuotos), ir 3 subsekcijos pagrindinei galerijai: „interior", „food", „drinks".

Galutinė galerija — 57 nuotraukos iš ~250 surinktų, organizuotos į tris ištisus skyrius.

Stekas ir kodėl būtent toks

TechnologijaKodėl
Next.js 14App Router. SSR-ready (dinaminiam Open Graph), bet statiniai puslapiai kešuojami. Image optimization per next/image
TypeScriptstrict-mode, types restaurant data, manifest, gallery items
Tailwind CSSdizaino tokenai per :root CSS kintamuosius, utility klasės. Bundle ~12 KB po purge
next/font/googleFraunces Variable (axes: SOFT, WONK, opsz) + IBM Plex Serif + IBM Plex Mono — visi subset'inami, jokio FOUT
CSS animations + IntersectionObserverVisi 16 sluoksnių grynu CSS, be framer-motion. Bundle mažesnis ~80 KB gzipped, performance — visos animacijos GPU compositor
sharpimage processing, ~5x greitesnis nei ImageMagick
blurhash32-char placeholder be layout shift
VPS + nginx + Cloudflareself-hosted, jokių Vercel-tier apribojimų. Cloudflare Polish + WebP/AVIF auto-conversion

Kas buvo sudėtinga

1. ScrollVelocityBlur be jankų

Tiesioginis sprendimas — kiekvieno scroll-event metu atnaujinti --scroll-blur. Tai sukelia jank greitai scrollinant — kadras praleidžiamas. Sprendimas:

  • useScrollEmitter hook — requestAnimationFrame thunk, atsisakomas
  • Lerp glotninimas: current += (target - current) * 0.3 — net jei scroll-event truktelėjo, blur juda sklandžiai
  • Threshold: currentBlur < 0.04 → 0 — atkerta smulkmenas

DevTools FPS niekada nenukrenta žemiau 58.

2. Sunrise sweep lygiai vieną kartą

Užsakovas: „sunrise sweep — tai emocija, antrąkart pamatyta ji nusibosta". Sprendimas:

  • Pirmą peržiūrą viewport'e — IntersectionObserver triggerina class sunrise-sweep
  • sessionStorage.setItem('bruno.sunrise.seen', '1') — sesijos flag
  • Pakartotinai užėjus į /brunch toje pačioje sesijoje — animacija nepaleidžiama
  • Tarp sesijų (nauja kortelė, nauja diena) — vėl veikia

3. Gyroscope iOS — permission flow

DeviceOrientationEvent.requestPermission() prieinamas tik po user-gesture (mygtuko paspaudimo). iOS pre-13 permission nereikia, iOS 13+ reikalingas eksplicitinis užklausimas. Realizuota per onClick ant mini-floating ikonos „Įjungti paralaksą" kampe — paspaudus iškviečiama requestPermission(), po approve gyro-drift aktyvuojasi. Android — be jokio permission, gyro veikia iš karto.

4. Image pipeline su deduplication

pHash biblioteka veikia tik browseryje (Canvas API). Sprendimas — node-port pHash-image + sharp paruošimui. Laikas — ~20s 250 nuotraukoms VPS. Cache .scrape-cache/phash/ — pakartotiniai paleidimai apdoroja tik naujas nuotraukas.

5. JSON-LD Menu schema dydžio 11 kategorijų × N patiekalų

Restaurant Schema reikalauja Menu subschemos su MenuSection ir MenuItem. BRUNO — 11 kategorijų, 80+ patiekalų. Generuoju schema iš data/restaurant.ts runtime app/layout.tsx faile. JSON-LD dydis — ~30 KB unminified. Minifikacija per JSON.stringify be spaces — 18 KB. Įterpiama per <script type="application/ld+json" dangerouslySetInnerHTML>.

6. Editorial design mobilėje

Editorial svetainė mobilėje praranda 80% emocijos — mastelis kitas, ritmas griūva. Sprendimai:

  • Display antraštės fluid per clamp(2.5rem, 8vw, 6rem) — iPhone 13 Hero h1 — 64px, iPad — 96px, 4K — 128px
  • Hairline skirtukai pakeisti į 1px solid rgba(245,238,224,0.10) — mobilėje subtlesni
  • Padding y-direction sumažintas nuo py-32 iki py-16
  • 3D tilt išjungiamas mobilėje — @media (hover: none) { .tilt-card:hover { transform: none; } } — nes nėra žymeklio

Diegimas

VPS, nginx, Let's Encrypt, Cloudflare — same setup, kaip ir kiti portfelio projektai. nginx konfigūracija standartinė, išskyrus vieną detalę:

# Long-term cache for hashed assets
location ~* \.(webp|avif|woff2|js|css)$ {
  expires 1y;
  add_header Cache-Control "public, immutable";
}

# Short cache for HTML (revalidate often)
location / {
  expires 5m;
  add_header Cache-Control "public, must-revalidate";
}

Cloudflare Polish — auto-WebP / AVIF bet kuriam įkeliamam vaizdui, riebus Brotli, DDoS protection. Hostingo kaina — $0/mėn (free Cloudflare + kapeikinis VPS).

Rezultatas

Svetainė išleista ir veikia brunotbilisi.com. Per pirmus du mėnesius po paleidimo:

  • Lighthouse mobile: Performance 96, Accessibility 100, Best Practices 100, SEO 100
  • ChatGPT ir Perplexity ranguoja BRUNO top-3 pagal pagrindines angliškas užklausas apie brunch ir fine dining Tbilisyje
  • Rezervacijų konversija per svetainę — vienintelė metrika, kurią užsakovas dalinasi — išaugo ~40% lyginant su ankstesne svetaine (Squarespace template)

Stekas pasirinktas maksimaliam ilgaamžiškumui ir kontrolei: Next.js 14 — stabilus, ne bleeding-edge; švarios CSS animacijos — veiks po 5 metų net jei subliuks framer-motion ir Tailwind; turinys data/restaurant.ts — pataisyti telefoną ar patiekalo kainą užtrunka 30 sekundžių.