[{"data":1,"prerenderedAt":326},["ShallowReactive",2],{"work-en-room-n14":3},{"id":4,"title":5,"body":6,"category":305,"description":72,"extension":306,"featured":307,"links":308,"meta":310,"navigation":307,"order":297,"path":311,"period":312,"role":313,"seo":314,"slug":315,"stack":316,"stem":322,"subtitle":323,"summary":324,"__hash__":325},"projects_en\u002Fprojects\u002Fen\u002Froom-n14.md","Room N14",{"type":7,"value":8,"toc":296},"minimark",[9,14,23,45,48,52,55,59,65,76,79,83,89,119,135,168,174,198,209,227,233,243,247,285,289],[10,11,13],"h2",{"id":12},"the-problem","The problem",[15,16,17,18,22],"p",{},"A small Italian lodging business lives or dies by ",[19,20,21],"strong",{},"direct bookings",". Every night booked through an OTA (Booking, Airbnb) leaves 15-20% commission on the table. To capture organic traffic you need three things together:",[24,25,26,33,39],"ul",{},[27,28,29,32],"li",{},[19,30,31],{},"speed"," (decent Core Web Vitals, mobile-first)",[27,34,35,38],{},[19,36,37],{},"serious local SEO"," (structured data + hreflang + copy in multiple languages)",[27,40,41,44],{},[19,42,43],{},"credible aesthetics"," on a small budget, without a CMS to patch monthly",[15,46,47],{},"No WordPress to maintain, no servers to restart, no plugins breaking during high season.",[10,49,51],{"id":50},"why-i-built-it","Why I built it",[15,53,54],{},"I run a small B&B and I wanted full control over the direct channel. The vetrina site was the natural front door for organic traffic — and the perfect excuse to build everything from scratch with the right tools.",[10,56,58],{"id":57},"architecture","Architecture",[15,60,61,64],{},[19,62,63],{},"Nuxt 3 in pure SSG mode"," → HTML+CSS+JS output, no server-side runtime, hosted on a free global CDN.",[66,67,73],"pre",{"className":68,"code":70,"language":71,"meta":72},[69],"language-text","5 pages            ← home, services, location, gallery, contact\n4 components       ← navbar (with language switcher), footer,\n                     ContactIcon (booking channels), PoiIcon (points of interest)\n1 layout           ← default, with dynamic LodgingBusiness JSON-LD\n4 locales          ← IT (default), EN, ES, FR\n","text","",[74,75,70],"code",{"__ignoreMap":72},[15,77,78],{},"No Pinia, no stores, no data fetching: 5 content pages, minimal state (current language in a cookie).",[10,80,82],{"id":81},"key-technical-decisions","Key technical decisions",[15,84,85,88],{},[19,86,87],{},"1. Exhaustive, not decorative, structured data."," Every page emits targeted JSON-LD:",[24,90,91,101,107,113],{},[27,92,93,96,97,100],{},[74,94,95],{},"WebSite"," + ",[74,98,99],{},"Organization"," on the home page",[27,102,103,106],{},[74,104,105],{},"LodgingBusiness"," on every page (address, geo coordinates, amenities, check-in\u002Fout, price range)",[27,108,109,112],{},[74,110,111],{},"FAQPage"," on the services page (each amenity is a Q&A)",[27,114,115,118],{},[74,116,117],{},"BreadcrumbList"," on every subpage",[15,120,121,122,126,127,134],{},"Google reads the page without having to infer from the copy. Local ranking and rich results are ",[123,124,125],"em",{},"much"," more solid than ",[123,128,129,130,133],{},"\"I fill the ",[74,131,132],{},"meta description"," and hope\"",".",[15,136,137,140,141,144,145,148,149,148,152,155,156,159,160,163,164,167],{},[19,138,139],{},"2. Multi-language at zero cost."," 4 locales, ",[19,142,143],{},"one URL per page",": the navbar switcher swaps content client-side via cookie. No ",[74,146,147],{},"\u002Fen\u002F",", ",[74,150,151],{},"\u002Fes\u002F",[74,153,154],{},"\u002Ffr\u002F"," doubling the URLs to maintain. ",[74,157,158],{},"hreflang"," tags all point to the same canonical plus ",[74,161,162],{},"x-default",". Pros: simpler sitemap, copy centralised in ",[74,165,166],{},"locales\u002F*.json",". Cons: no SEO boost from localised URLs — trade-off accepted for a 5-page site.",[15,169,170,173],{},[19,171,172],{},"3. Image optimisation as a build step."," Custom Sharp script:",[24,175,176,179,185,192],{},[27,177,178],{},"resize to max 1920px (hero 2000px to keep visual impact)",[27,180,181,184],{},[123,182,183],{},"mozjpeg"," compression quality 78-82 (82 on heroes)",[27,186,187,188,191],{},"parallel ",[74,189,190],{},".webp"," generation for every source",[27,193,194,197],{},[74,195,196],{},".orig"," backup before overwriting — idempotent, safe to re-run",[15,199,200,201,204,205,208],{},"Total image folder ",[19,202,203],{},"~11 MB",", single images under 300 KB even on heroes. No external image CDN, no ",[74,206,207],{},"@nuxt\u002Fimage",": a build-time script is enough at this scale.",[15,210,211,214,215,218,219,222,223,226],{},[19,212,213],{},"4. Favicon automation."," One script produces the full suite from a parameterised SVG template: multi-res ",[74,216,217],{},"favicon.ico"," (16\u002F32\u002F48), ",[74,220,221],{},"apple-touch-icon"," 180, Android Chrome 192\u002F512, ",[74,224,225],{},"site.webmanifest",", a scalable SVG. Changing the brand colour = one-line edit.",[15,228,229,232],{},[19,230,231],{},"5. Centralised LodgingBusiness JSON-LD."," All property data (name, address, coordinates, amenities, hours, price range) lives in a single config file. The layout serialises the JSON-LD once at build time; every page inherits it. Zero duplication, one source of truth.",[15,234,235,238,239,242],{},[19,236,237],{},"6. No backend, no form engine."," The contact page uses ",[19,240,241],{},"mailto + WhatsApp + direct OTA channel links + Instagram",". No form persisting to a DB, no serverless function for submission. Less attack surface, less to break, zero GDPR overhead on form-submissions.",[10,244,246],{"id":245},"numbers","Numbers",[24,248,249,255,267,273,279],{},[27,250,251,254],{},[19,252,253],{},"~1,500 LOC"," total",[27,256,257,260,261,260,264],{},[19,258,259],{},"5 pages"," · ",[19,262,263],{},"4 components",[19,265,266],{},"1 layout",[27,268,269,272],{},[19,270,271],{},"4 locales"," synchronised (IT · EN · ES · FR)",[27,274,275,278],{},[19,276,277],{},"~30 image assets"," (14 sources + 16 derivatives and favicons)",[27,280,281,284],{},[19,282,283],{},"5 JSON-LD"," schema types emitted in total",[10,286,288],{"id":287},"takeaways","Takeaways",[15,290,291,292,295],{},"A well-built static site beats a poorly-built CMS nine times out of ten, especially for small businesses where content changes twice a year. The ",[123,293,294],{},"\"no runtime\""," constraint pushes toward simpler design decisions, not poorer ones. A Lighthouse score of 100 isn't a brag — it's the natural consequence of having nothing superfluous to execute.",{"title":72,"searchDepth":297,"depth":297,"links":298},2,[299,300,301,302,303,304],{"id":12,"depth":297,"text":13},{"id":50,"depth":297,"text":51},{"id":57,"depth":297,"text":58},{"id":81,"depth":297,"text":82},{"id":245,"depth":297,"text":246},{"id":287,"depth":297,"text":288},"work","md",true,{"live":309},"https:\u002F\u002Froomn14.it",{},"\u002Fprojects\u002Fen\u002Froom-n14","2025","Design · full-stack · SEO",{"title":5,"description":72},"room-n14",[317,318,319,320,321],"Nuxt 3 (SSG)","Tailwind CSS","Sharp","JSON-LD","Multi-language (4 locales)","projects\u002Fen\u002Froom-n14","A vetrina site for a small Italian lodging business. Nuxt SSG, multilingual, exhaustive structured data, build-time image optimisation — zero runtime.",null,"X9aAn__lH7PecZ5USxEJAlqjpJypyE-qw0-u9PXzKw0",1781346783479]