Help

Make it your restaurant

Change the brand, the photos and the copy in an afternoon. Everything that repeats lives in five CMS collections; the ticket rail is one component with options.

Quick start (about 2 hours)

  • Brand: rename «Ferro» in the header, footer wordmark and meta tags.
  • Colours and type: edit the tokens in the style guide (colour and text styles).
  • Photos: replace the files in img/ keeping the names, or change the Image field in the CMS. One grade for all: see img/CREDITOS.md.
  • Menu: edit cms/dishes.json (the Dishes collection).
  • Hours: set services in the rail options; the hours table, the status line and the booking form follow.

Pages (17)

index · menu · dish (CMS) · about · private-dining · event (CMS) · gift-cards · journal · post (CMS) · reservations · contact · careers · legal · 404 · style-guide · help · licenses

Home, section by section

SectionWhat to touch
HeroSwap img/hero-rice.jpg (3:2 or wider), its three .webp sizes and the 2:3 phone crop hero-rice-portrait.webp (one image field per breakpoint). Edit the h1, the lead and the two buttons. The proof card reads the rating from the Reviews collection settings.
The pass (signature)ComandaRail code component. Set the options below, or turn it off; the static tickets in the markup stay as a fallback.
Press tickerNames come from reviews.json → press.
Signature dishesDishes with featured = true (max 6).
On the menu nowDishes of the current season, grouped by category.
A day at FerroFive stops: photo, time, title, text. data-stops holds the clock times (minutes).
Team, reviews, events, journalAll CMS lists: edit the collections, not the page.
BookingDays and times come from the rail’s services. Replace the submit handler with your booking tool (CoverManager, TheFork, OpenTable).

CMS collections (5)

The JSON files in cms/ are the source (one file per collection). python3 build.py bundles them into js/cms-data.js for the preview. Lists use data-cms, detail pages data-cms-item; bindings map one-to-one to «connect to field».

Dishes → dish.html

dishes
FieldType and use
slugSlug. Unique, lowercase, used in the URL.
namePlain text (EN/ES). Dish name as it reads on the menu.
ticketPlain text (EN/ES). Short uppercase name the printer uses on kitchen tickets (max 12 characters).
categoryOption: garden | sea | rice | sweet.
seasonsMulti-option: winter | spring | summer | autumn. The menu page shows the dishes of the selected season.
priceNumber, euros, VAT included.
allergensNumbers 1–14, EU Regulation 1169/2011 Annex II (1 gluten … 14 molluscs). Empty = no allergens.
photoImage. Dish close-up; 4:5 or 1:1 crops best.
photoAltPlain text (EN/ES). Alt text for the photo.
focusPlain text. CSS object-position for the crop, e.g. 50% 40%.
summaryPlain text (EN/ES). One line for lists and cards.
descriptionFormatted text (EN/ES). Two or three sentences for the detail page.
originPlain text (EN/ES). Where the main produce comes from.
cookReference → Team. Who cooks it (station).
pairingPlain text (EN/ES). Suggested glass.
featuredToggle. Shown in «This week at the pass» on the home page.
orderNumber. Sort order inside its category.

Team

team
FieldType and use
slugSlug. Referenced by Dishes.cook, Journal.author and Events.host.
namePlain text. Full name.
rolePlain text (EN/ES). Job title.
stationPlain text (EN/ES). Short uppercase station printed on the ticket stub (PASS, RICE…).
photoImage. Portrait, 4:5.
photoAltPlain text (EN/ES).
focusPlain text. CSS object-position.
bioPlain text (EN/ES). Two sentences.
sinceNumber. Year they joined.
orderNumber.

Journal → post.html

journal
FieldType and use
slugSlug.
titlePlain text (EN/ES).
dateDate (YYYY-MM-DD).
categoryOption (EN/ES): Market | Kitchen | Wine | Team.
coverImage. 3:2 crop works everywhere.
coverAltPlain text (EN/ES).
focusPlain text. CSS object-position.
excerptPlain text (EN/ES). One or two lines for cards.
bodyFormatted text (EN/ES). Here as blocks: {type: p | h2 | quote | img, en, es, src, alt}.
authorReference → Team.
dishesMulti-reference → Dishes. Shown as «On the menu» at the end.
minutesNumber. Reading time.

Events → event.html

events
FieldType and use
slugSlug.
typeOption: event | private.
titlePlain text (EN/ES).
dateDate (YYYY-MM-DD). Empty for private formats that run all year.
timePlain text, e.g. 20:30.
seatsNumber. Seats available (events) or maximum guests (private).
priceNumber, euros per person (events) or minimum spend (private, priceNote explains).
priceNotePlain text (EN/ES). What the price includes.
coverImage. 3:2.
coverAltPlain text (EN/ES).
focusPlain text. CSS object-position.
summaryPlain text (EN/ES). One or two lines for cards.
bodyFormatted text (EN/ES). Here as paragraphs.
hostReference → Team.
dishesMulti-reference → Dishes. What gets cooked.
orderNumber.

Reviews

reviews
FieldType and use
quotePlain text (EN/ES). Keep it under 30 words.
authorPlain text. Guest name or critic.
sourcePlain text. Publication or platform.
kindOption: press | guest.
ratingNumber 1–5 (guest reviews).
orderNumber.

The ticket rail (ComandaRail)

One code component (js/rail.js). Its options are property controls; in this prototype they are the JSON in data-options on the section. Preview any moment with ?t=21:10&d=5.

OptionDefaultWhat it does
enabledtrueTurns the signature on or off. Off hides the rail band; the live status line keeps working.
variant"live""live" follows the clock; "static" freezes it at staticAt/staticDay with no timers or motion.
staticAt · staticDay"21:10" · 5The moment the static variant shows (0 = Sunday).
timezone"Europe/Madrid"IANA time zone of the restaurant.
city"València"Shown after the time in every status line.
serviceslunch · dinnerArray of {id, label, short, open, close, last, days}. Add a breakfast, drop a dinner: the rail, the status line and the booking times follow.
marketFrom · prepFrom · marketDays"07:45" · "10:00" · [2–6]When the morning «market» and «mise en place» states start.
interval · maxTickets · lateAfter24 · 7 · 15Seconds between new tickets, tickets on the rail, minutes before a timer turns red.
colors{paper, ink, ribbon, heat, steel}CSS colours for the thermal paper, the print, the allergen ribbon, the lamps and the band.
tickets{dishes:"cms", cook, tables, counterSeats, mods, alerts, bookings}Ticket data. dishes:"cms" uses the current season’s Dishes (field «ticket»); or pass a list of names.
labels{market:{en,es}, …}Override the name of any state.
motiontruefalse = no sway, slide or print. Reduced motion always forces false.

Motion

All motion is plain CSS/JS (see the style guide): appear, text by line, image reveal, sticky run, parallax, hover preview and a wipe page transition. Nothing else needs code.

Languages

English and Spanish ship as two full language versions. In this template, add ?lang=es to any page.

Changelog

  • 2.0 · 26 Sep 2026 · Multi-page (17 page templates), 5 CMS collections, 43 photos in one grade, native motion system, the rail as a component with options.
  • 1.0 · 26 Sep 2026 · One-page prototype.