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
| Section | What to touch |
|---|---|
| Hero | Swap 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 ticker | Names come from reviews.json → press. |
| Signature dishes | Dishes with featured = true (max 6). |
| On the menu now | Dishes of the current season, grouped by category. |
| A day at Ferro | Five stops: photo, time, title, text. data-stops holds the clock times (minutes). |
| Team, reviews, events, journal | All CMS lists: edit the collections, not the page. |
| Booking | Days 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
| Field | Type and use |
|---|---|
| slug | Slug. Unique, lowercase, used in the URL. |
| name | Plain text (EN/ES). Dish name as it reads on the menu. |
| ticket | Plain text (EN/ES). Short uppercase name the printer uses on kitchen tickets (max 12 characters). |
| category | Option: garden | sea | rice | sweet. |
| seasons | Multi-option: winter | spring | summer | autumn. The menu page shows the dishes of the selected season. |
| price | Number, euros, VAT included. |
| allergens | Numbers 1–14, EU Regulation 1169/2011 Annex II (1 gluten … 14 molluscs). Empty = no allergens. |
| photo | Image. Dish close-up; 4:5 or 1:1 crops best. |
| photoAlt | Plain text (EN/ES). Alt text for the photo. |
| focus | Plain text. CSS object-position for the crop, e.g. 50% 40%. |
| summary | Plain text (EN/ES). One line for lists and cards. |
| description | Formatted text (EN/ES). Two or three sentences for the detail page. |
| origin | Plain text (EN/ES). Where the main produce comes from. |
| cook | Reference → Team. Who cooks it (station). |
| pairing | Plain text (EN/ES). Suggested glass. |
| featured | Toggle. Shown in «This week at the pass» on the home page. |
| order | Number. Sort order inside its category. |
Team
| Field | Type and use |
|---|---|
| slug | Slug. Referenced by Dishes.cook, Journal.author and Events.host. |
| name | Plain text. Full name. |
| role | Plain text (EN/ES). Job title. |
| station | Plain text (EN/ES). Short uppercase station printed on the ticket stub (PASS, RICE…). |
| photo | Image. Portrait, 4:5. |
| photoAlt | Plain text (EN/ES). |
| focus | Plain text. CSS object-position. |
| bio | Plain text (EN/ES). Two sentences. |
| since | Number. Year they joined. |
| order | Number. |
Journal → post.html
| Field | Type and use |
|---|---|
| slug | Slug. |
| title | Plain text (EN/ES). |
| date | Date (YYYY-MM-DD). |
| category | Option (EN/ES): Market | Kitchen | Wine | Team. |
| cover | Image. 3:2 crop works everywhere. |
| coverAlt | Plain text (EN/ES). |
| focus | Plain text. CSS object-position. |
| excerpt | Plain text (EN/ES). One or two lines for cards. |
| body | Formatted text (EN/ES). Here as blocks: {type: p | h2 | quote | img, en, es, src, alt}. |
| author | Reference → Team. |
| dishes | Multi-reference → Dishes. Shown as «On the menu» at the end. |
| minutes | Number. Reading time. |
Events → event.html
| Field | Type and use |
|---|---|
| slug | Slug. |
| type | Option: event | private. |
| title | Plain text (EN/ES). |
| date | Date (YYYY-MM-DD). Empty for private formats that run all year. |
| time | Plain text, e.g. 20:30. |
| seats | Number. Seats available (events) or maximum guests (private). |
| price | Number, euros per person (events) or minimum spend (private, priceNote explains). |
| priceNote | Plain text (EN/ES). What the price includes. |
| cover | Image. 3:2. |
| coverAlt | Plain text (EN/ES). |
| focus | Plain text. CSS object-position. |
| summary | Plain text (EN/ES). One or two lines for cards. |
| body | Formatted text (EN/ES). Here as paragraphs. |
| host | Reference → Team. |
| dishes | Multi-reference → Dishes. What gets cooked. |
| order | Number. |
Reviews
| Field | Type and use |
|---|---|
| quote | Plain text (EN/ES). Keep it under 30 words. |
| author | Plain text. Guest name or critic. |
| source | Plain text. Publication or platform. |
| kind | Option: press | guest. |
| rating | Number 1–5 (guest reviews). |
| order | Number. |
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.
| Option | Default | What it does |
|---|---|---|
| enabled | true | Turns 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" · 5 | The 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. |
| services | lunch · dinner | Array 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 · lateAfter | 24 · 7 · 15 | Seconds 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. |
| motion | true | false = 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.