How to Build a Dynamic Train Departure Time Digital Billboard Ad¶
Overview¶
This guide walks you through building a digital billboard ad that automatically calculates and displays the next scheduled train departure time based on the current time. You will create a custom JavaScript designer function that compares the current time against a list of hardcoded departure times, then expose that value on your canvas through a custom field — all without connecting to any external data feed.
How It Works¶
A Designer Function is a custom JavaScript function registered in your template that returns a single string value. That value is then bound to a Custom Field element on your canvas. Every time the ad renders, the function runs and returns the most relevant departure time for that moment.
In this guide, the function:
- Reads the current time in a configured timezone (e.g.,
Europe/London) - Compares it against a hardcoded list of scheduled departure times
- Returns the next upcoming departure, or the first departure of tomorrow if all trains for today have already departed
Objective¶
By the end of this guide, you will have:
- Created a new Billboard template in Lucit with a background and a departure time text element
- Registered a custom
fnNextDeparturedesigner function in the template's JavaScript editor - Created a Custom Field that calls this function and displays its result
- Placed and styled the departure time field on the canvas
- Tested the result using the POST AD workflow
Prerequisites¶
Before starting this guide, ensure you have:
- A Lucit account with appropriate permissions to create and edit templates
- An existing campaign with at least one screen attached
- Permission to access the Template Designer
- Background design assets for your billboard (images in the appropriate screen format sizes)
- The campaign's HTML Source Type set to Drive Template — this ensures the digital signage player receives a live HTML document rather than a pre-rendered snapshot, so
fnNextDeparturecan execute in real time on every render. You can set this underCampaign -> Settings -> HTML Source Type -> Drive Template. See the Campaign Page Navigation Guide for full details.
Example Scenario¶
Throughout this guide, we'll build a departure board ad for "Victoria Station" that displays messages like:
- "Next Departure at 11:25" (when a later train is still scheduled today)
- "Next Departure Tomorrow at 6:26" (when the last train of the day has passed)
Step 1: Create a New Template¶
Navigate to Templates¶
- Navigate to
Templates -> CREATE A NEW TEMPLATE - Choose
Data Connected Template - Select the Screen Formats that match your billboard screens (e.g., Widescreen, Bulletin)
- Click
NEXT - Select
New | Create a new template from scratch on a blank canvas - Click
CREATE
Name Your Template¶
- Click the
{PencilIcon}next to "Untitled" at the top of the page - Enter a descriptive name (e.g., "Victoria Station Departure Board")
- Click the
{CheckmarkIcon}or pressEnter
Step 2: Design the Canvas¶
This step sets up the visual layout of your billboard. You will add a background image and a placeholder text element where the departure time will appear.
Add a Background Image¶
- In the
Elements Panelon the left, expandUploaded Assets - Click or drag-and-drop your background image for the selected screen format
- When prompted, select
Background to stretch to fill the screen - Click
OK
Add a Static Title Element (Optional)¶
If your design includes a static headline such as "Victoria Station", add a Text element:
- In the
Elements Panel, expandStatic Elements - Click
Textto add a new text element to the canvas - Double-click the element and type your static label (e.g., "Victoria Station")
- Use the
Editpanel on the right to configure font, color, size, and alignment
Add a Placeholder for the Departure Time¶
The departure time will be filled in by your Custom Field later. For now, add a text element to reserve its position:
- In the
Elements Panel, expandStatic Elements - Click
Textto add a text element - Double-click and enter a placeholder value (e.g., "Next Departure at 11:25") so you can see how it looks while designing
- Position and style this element where you want the departure time to appear
- You will replace this static element with your Custom Field in Step 5
Tip: Use Auto font size under Font -> Size in the Edit panel to allow the text to scale within its bounding box as the message length varies (e.g., "Next Departure Tomorrow at 6:26" is longer than "Next Departure at 6:26").
Step 3: Register the fnNextDeparture Designer Function¶
This is where you add the JavaScript logic that calculates the next departure time.
Open the Code Editor¶
- In the Template Designer, in the
Actions Barat the bottom of the canvas, click the<>icon to open theCode Editordialog - Click on the
JStab
Add the Function¶
Copy and paste the following code into the JS editor:
registerDesignerFunction(
"fnNextDeparture",
() => {
const departureTimes = [
"6:26",
"8:26",
"11:25",
"15:26",
"19:20"
];
// Get current time in the configured timezone
const timezoneParts = new Intl.DateTimeFormat("en-GB", {
timeZone: "Europe/London",
hour: "2-digit",
minute: "2-digit",
hourCycle: "h23"
}).formatToParts(new Date());
const currentHour = Number(
timezoneParts.find((p) => p.type === "hour")?.value ?? 0
);
const currentMinute = Number(
timezoneParts.find((p) => p.type === "minute")?.value ?? 0
);
const currentTotalMinutes = (currentHour * 60) + currentMinute;
let nextDepartureTime = null;
let isTomorrow = false;
// Find the next departure today
for (const time of departureTimes) {
const [hour, minute] = time.split(":").map(Number);
const departureTotalMinutes = (hour * 60) + minute;
if (departureTotalMinutes >= currentTotalMinutes) {
nextDepartureTime = time;
break;
}
}
// If all departures for today have passed, use the first one tomorrow
if (!nextDepartureTime) {
nextDepartureTime = departureTimes[0];
isTomorrow = true;
}
return isTomorrow
? "Next Departure Tomorrow at " + nextDepartureTime
: "Next Departure at " + nextDepartureTime;
}
);
Customise the Function for Your Use Case¶
Before saving, update the two sections relevant to your schedule:
Update the departure times list — replace the example times with your real schedule:
- Times must be in
"H:MM"or"HH:MM"24-hour format - The list must be sorted in ascending chronological order
Update the timezone — replace "Europe/London" with the IANA timezone identifier for your station's location:
Common examples:
| Location | Timezone identifier |
|---|---|
| London, UK | Europe/London |
| New York, USA | America/New_York |
| Chicago, USA | America/Chicago |
| Los Angeles, USA | America/Los_Angeles |
| Paris, France | Europe/Paris |
| Sydney, Australia | Australia/Sydney |
| Tokyo, Japan | Asia/Tokyo |
A full list of valid timezone identifiers is available at Wikipedia — List of tz database time zones.
Understanding the Function¶
registerDesignerFunction: Registers the function with Lucit so it can be called from a Custom Field'sFIELD CODEdepartureTimes: A hardcoded list of scheduled departure times in 24-hour format, sorted earliest to latestIntl.DateTimeFormat: Reads the current time in the specified IANA timezone, ensuring the correct local time regardless of where the ad server is running- Loop logic: Iterates through the list to find the first departure that hasn't occurred yet
- Tomorrow fallback: When the last departure of the day has passed, the function wraps around to the first scheduled time and prefixes the message with "Tomorrow"
- Return value: A plain string — either
"Next Departure at HH:MM"or"Next Departure Tomorrow at HH:MM"— which becomes thedata-valueof the text element on your canvas
Save Your Changes¶
Click SAVE (or the save button) in the Code Editor before proceeding.
Step 4: Create the Custom Field¶
Now you will create the Custom Field that calls fnNextDeparture and makes its return value available as a canvas element.
Add a New Custom Field¶
- In the
Elements Panel, expandDynamic Data Elements - Scroll down to the
Custom Fieldssection - Click the
+icon next toCustom Field - The Custom Field dialog will open
Configure the Field¶
In the Custom Field dialog:
- Custom Field Name: Enter
Next Departure Time(or any descriptive name) - Placeholder: Enter
Next Departure at 11:25— this text is shown on the canvas when no data is present - Text / Image: Select
Text— this field returns a string, not an image URL
Add the Field Code¶
- Click on the
FIELD CODEtab - Enter the following:
This calls the designer function you registered in Step 3 with no arguments (the function reads the current time internally).
Save the Custom Field¶
Click SAVE or OK to save the Custom Field configuration.
Step 5: Place the Custom Field on the Canvas¶
Now that the Custom Field exists, you will replace the static placeholder text element you created in Step 2 with the live Custom Field.
Remove the Static Placeholder¶
- Click on the static departure time text element you added in Step 2
- Press
Deleteor use the element's context menu to remove it
Add the Custom Field to the Canvas¶
- In the
Elements Panel, underDynamic Data Elements -> Custom Fields, locateNext Departure Time - Click on it or drag it onto the canvas
- Position it in the same area where your static placeholder was
Style the Element¶
With the element selected, use the Edit panel to style it:
- Font Color:
Appearance -> {UnderlinedAIcon}— choose a high-contrast color appropriate for your billboard background - Font Family:
Font -> Family— select a clear, legible font - Font Size: Set to
AutounderFont -> Sizeto accommodate both the shorter "Next Departure at" and longer "Next Departure Tomorrow at" messages - Max Font Size: Set a maximum under
Font -> Max Sizeto prevent the text from growing too large on wide formats - Text Alignment: Set to centered or left-aligned depending on your design
Tip: Preview the element at its longest possible value. The string "Next Departure Tomorrow at 19:20" is the longest output this function can produce. Make sure your bounding box is wide enough to fit it at a readable size.
Step 6: Test with POST AD¶
Access POST AD¶
- In the Template Designer, click the
POST ADbutton (typically in the upper-right area) - Follow the POST AD workflow to post the ad to a screen in your campaign
What to Expect¶
Because fnNextDeparture takes no user inputs (all departure times are hardcoded in the function), no custom field form will appear during POST AD for this field. The departure time is computed automatically at render time.
After posting:
- Navigate to your campaign to see the newly posted creative
- The departure time text should display the correct next departure based on the current time
- The displayed value will update automatically each time the ad renders
Verify the Output¶
- If the current time is before the last scheduled departure of the day, you should see:
Next Departure at {HH:MM} - If the current time is after the last scheduled departure, you should see:
Next Departure Tomorrow at {HH:MM}
Tips & Best Practices¶
- Sort departure times ascending: The function iterates the list in order and stops at the first match. If your times are not sorted, it will return incorrect results.
- Use 24-hour time: The function compares total minutes in 24-hour format. Ensure all entries in
departureTimesuse 24-hour notation (e.g.,"15:26"not"3:26 PM"). - Set the correct timezone: Always use the IANA timezone identifier for the station's physical location, not your local timezone or UTC. This ensures the correct departure is shown regardless of where the ad server is running.
- Test across day boundaries: Manually set your device clock (or temporarily edit the function) to a time after the last departure to verify the "Tomorrow" fallback message renders correctly.
- Account for text length variation: "Next Departure Tomorrow at 6:26" is noticeably longer than "Next Departure at 6:26". Use Auto font sizing and test both outputs on each screen format to ensure neither is truncated.
- Seasonal schedule changes: Since departure times are hardcoded in the function, you will need to edit the
departureTimesarray in the template's JS editor whenever the schedule changes. Consider naming the function clearly (e.g.,fnNextDeparture_SummerSchedule) if you manage multiple timetables.
Common Questions¶
Why does the function not accept user inputs via Field Map? The departure times are embedded directly in the JavaScript function, so no user input is needed at POST AD time. The function computes the result dynamically each time the ad is rendered using the system clock.
Can I add more departure times?
Yes. Add any number of entries to the departureTimes array in the function, keeping them sorted in ascending 24-hour order.
What happens if I have weekend or holiday schedules?
The current function does not differentiate between days of the week. To handle different schedules per day, you would extend the registerDesignerFunction logic to check the current day of the week (e.g., using JavaScript's getDay() method in the appropriate timezone) and select from different departure time arrays accordingly.
The departure time is not updating on screen. What should I check?
* Verify the timeZone value in the function matches the station's actual timezone
* Confirm departureTimes is sorted in ascending order
* Check the browser console within the Template Designer preview for any JavaScript errors logged by the function
* Make sure the Custom Field's FIELD CODE tab contains exactly fnNextDeparture() with no typos
Can I display the departure time in a 12-hour format? Yes. Modify the return statement in the function to convert the 24-hour departure string to 12-hour format before returning it.
Related Resources¶
- Lucit Template Custom Fields Guide — Full reference for creating and configuring Custom Fields
- Lucit Template JavaScript Guide — Overview of all three function registration types and how to choose between them
- Template Designer General Navigation Guide — Reference for the Template Designer interface and tools
- Screen Format Reference — Billboard screen format specifications