More AI build fun - creating a page from a functional specification

So in today's test of AI, I thought that I would step things up. Normally, I ask GitHub Copilot to do specific tasks, changes, etc. But this time, I wanted to see how easy it might be to create a "Functional Specification" and get the AI to build it. I usually build experimentally, starting from a basic idea and adding features as I go. But using a functional specification, you need to do it the other way around. You should try to be as specific as possible when describing what you want.

I had already previously created a "countdown" page which you may have seen: Fun little countdown page - track key dates/times. But that was purely a stand-alone web thing, while I did add something to notify Node-RED when something expired, everything else was pure browser-only.

So I wrote my spec using Markdown (around 120 lines). Then firstly asked Claude Sonnet 4.5 to review the spec and suggest improvements. Which it did and I mostly incorporated them.

Then I threw the spec at Claude Opus 4.5 (which is much stronger than Sonnet but also more expensive) and asked it to build the page.

Somewhat to my surprise, it did actually build a working page in fairly short order - first try. You can see the results below. You can also see that some tweaks will be needed but the basics including all of the uibuilder comms all work just fine.


The edit dialog leaves a little to be desired. Learning for next time is that you need to be quite specific when describing UI features. But fairly easy to tidy up.

I also asked it to build test scripts and documentation which, for some reason it didn't even try to do. Odd because it will often do so without being asked - possibly because it isn't picking up my usual overarching AI instruction file.

More impressive was that I started with 35% of my allowance of chargeable models used for the month and ended with 37% used. So just 2%. Nice. Note that I pay for the basic GitHub Copilot license at around ÂŁ100 per year. That gives you access to a certain amount of otherwise charged models each month.


Next will be to write some flows in Node-RED to manage the data including the data-cache for page load.

Further enhancements should include:

  • Allowing Node-RED to process the timers instead of the browser so the page doesn't have to be online all the time.
  • Adding a linked timer feature that would be well suited to pill timers. E.g. first pill at 9am, then 3 more spread evenly until midnight. With smart adjustments if you take one late or early.

Anyway, a bit of fun on a lazy Sunday.

Let me know if you want to see the code and/or the spec. The code, BTW, is just shy of 1600 lines but it has lots of comments added by the AI, just as I like things. The page file is actually an HTML fragment file for use with the UIBUILDER front-end router. Easily turned into a stand-alone page though.

4 Likes

Hi,
this is quite interesting (together with the other thread about ai assisted creation of uibuilder pages), as I am looking to do something similar for a personal project.
Could you share your specification file?
Did you have any more experiences with ai creating complete node red flows in the mean time?

# Functional specification for Timer route
This document outlines the functional specifications for the Timer route in the front-end application. The Timer route is responsible for managing and displaying timer functionalities to the user.

## Timer Route Overview
The timer route allows users to create and delete timers. Each timer has an end timestamp. The page displays a list of the active timers, showing the remaining time until each timer reaches its end timestamp. The timers should be updated every 10 seconds to reflect the remaining time accurately without overloading the system with too frequent updates. When a timer reaches its end timestamp, it should emit an event indicating that the timer has completed. The "remaining time" for expired timers should be shown with a minus prefix (e.g., '-2d 3h 15m'), indicating how much time has passed since the timer ended.

The user has the option to end a timer manually using a checkbox at the start of the timer entry. When the checkbox is selected, the timer should immediately emit an event indicating that it has been ended by the user. The timer display should then be moved to a separate section for ended timers which should be collapsed by default.

The timer route assumes that UIBUILDER for Node-RED is being used, and the implementation should adhere to the conventions and best practices of UIBUILDER.

## Timer Route Functional Requirements
There must be a button to create a new timer. Clicking this button opens a dialog where the user can input the timer details, including the description/name and end timestamp.

### The Timer route should display a list of timers, each showing the following information:
- A checkbox: Marks timer as manually ended but keeps it in the list (moved to ended section).
- The timer description or name.
- The remaining time until the timer ends (or time elapsed since it ended as a negative value), updated every 10 seconds. The 10-second update interval balances UI responsiveness with performance. This can be adjusted based on performance requirements
- The end timestamp of the timer. In the format "YYYY-MM-DD HH:MM DDD".
- Clear visual distinction between active and ended timers. Suitable for both dark and light modes.
  - Use background color changes, and text styles to differentiate between active and ended timers.
  - Active timers should have a normal appearance with a background colour that has a slight contrast to the page background.
  - Timers within 2 minutes of ending should be highlighted (e.g., with a warning background).
  - Overdue timers should be highlighgted (e.g., with a error background).
- A set of action buttons:
  - Delete: Permanently removes the timer from all lists.
  - Copy: Copies the timer to a new timer entry in an open dialog for further editing.
- Clicking anywhere on the timer entry (except for the checkbox and action buttons) opens a dialog to edit the timer details. Also allowing both keyboard and touch interactions.

A separate list inside a collapsible section should display the ended timers, with the same information and action buttons as active timers.

A vertical LED style chart indicator should be displayed next to the add button, this should have 10 segments. The display should count down the time untile the next 10-second update, with each segment representing 1 second. The segments should light up in sequence from bottom to top as time progresses, and reset when the timer updates. Since the 10-second update can be configurable, the segment duration should be dynamically calculated based on the update interval.

### The dialog for creating and editing timers should include:
- Input fields for:
  - Timer description/name. This input should be a single-line text input with a maximum length of 100 characters. It must not be empty.
  - End timestamp. The input for the end timestamp should use HTML date and time inputs (on the same line if possible), the input should be preceded by a button that sets the inputs to NOW. Excepting any other overrides (e.g. editing an existing entry), the inputs should default to NOW.
  - Noting that timestamps in the past are allowed.
- A Section containing Add/Subtract radio buttons and input fields for years, months, weeks, days, hours, minutes, and seconds to easily adjust the end timestamp relative to the current value.
- A Section showing the final calculated end timestamp based on the inputs above. and the remaining time until (or since) that timestamp.
- 2 action buttons:
  - Save: Saves the timer details and closes the dialog.
  - Cancel: Closes the dialog without saving changes.
- Upon opening, the description/name input field should be automatically focused for user convenience.
- The escape key should close the dialog without saving changes.
- The enter key should save the timer details if the dialog is open and the focus is not on a button.
- Clicking outside the dialog should close the dialog without saving changes.
- Trap focus within the dialog when it is open to enhance accessibility.

## Data Handling
Upon route initialization, the Timer route should request the current list of timers from node-red via UIBUILDER's messaging system. The timers should be stored in the front-end application state to allow for efficient rendering and updating.

When a timer is created, edited, deleted, or ended manually, the Timer route should send the appropriate message to node-red to update the backend data store accordingly. If uibuilder's comms channel is disconnected, the Timer route should queue each event and send them once the connection is re-established.

If a timer reaches its end timestamp, the Timer route should emit an event to node-red indicating that the timer has completed. If uibuilder's comms channel is disconnected, the Timer route should queue the event and send it once the connection is re-established.

Queued events should be stored in local storage to ensure they are not lost if the user refreshes the page or closes the browser. When comms becomes re-established, the Timer route should retrieve any queued events from local storage and send them to node-red in the order they were created (do not de-duplicate events). Once sent, the queued events should be removed from local storage.

Any localStorage data should be namespaced with `uib-timer-route-` to avoid conflicts with other data.

If server data conflicts with queued local changes, local changes take precedence until successfully synced.

## Timer Data Structure
Each timer should be represented by an object with the following properties:
- `id`: A unique identifier for the timer.
- `description`: A string representing the timer's description or name.
- `endTimestamp`: A timestamp indicating when the timer is set to end.
- `status`: A string indicating the timer's status, "active", "ended" or "expired".
- `endedBy`: A string indicating how the timer was ended, either "user" or "automatic" (if ended by reaching the end timestamp). Null if the timer is still active.

## UIBUILDER messages
The Timer route should handle the following UIBUILDER messages:
* `{ topic: 'timer:request' }` - Initial list request
* `{ topic: 'timer:create', payload: {...} }` - Create timer
* `{ topic: 'timer:update', payload: {...} }` - Edit timer
* `{ topic: 'timer:delete', id: string }` - Delete timer
* `{ topic: 'timer:ended', id: string, endedBy: 'user'|'auto' }` - Timer completed

## General Requirements
- The timer route should be contained in a single html fragment file in the same folder as this specification. The fragment file should be named `timers.html`. It should include all necessary HTML, CSS, and JavaScript to implement the specified functionality.
- The Timer route should be responsive and work well on various screen sizes, including mobile devices.
- The design should be consistent with the overall application theme, supporting both dark and light modes.
- Accessibility considerations should be taken into account, ensuring that all functionalities are usable via keyboard navigation and screen readers.
- Proper error handling should be implemented for invalid inputs in the timer creation/editing dialog.
- The application should maintain performance and not degrade with multiple active timers. 100 active timers should be handled smoothly.
- All timer-related events (creation, deletion, completion, manual ending) should be logged for auditing purposes.
- The Timer route should be tested thoroughly to ensure all functionalities work as expected.
- The implementation should follow best practices for code quality, maintainability, and scalability.
- The Timer route should be compatible with the latest versions of major web browsers.
- The latest standards for HTML, CSS, and JavaScript should be used in the implementation.
- CSS should prioritize:
  - Use of CSS variables for theming (dark/light mode). 
  - Flexbox or CSS Grid for layout.
  - Avoidance of deprecated or non-standard CSS properties.
  - Nested styles for better organization.
  - Comments to explain complex styling decisions.
- JavaScript should prioritize:
  - Use of ES6+ features for cleaner and more efficient code.
  - Use ES Modules as appropriate.
  - Modular code structure, separating concerns appropriately.
  - Clear and descriptive naming conventions for variables and functions.
  - Comments to explain complex logic or decisions.
  - Avoidance of global variables to prevent conflicts.
  - JSDoc comments for as needed.
- HTML should prioritize:
  - Semantic HTML5 elements for better accessibility and SEO.
  - Proper use of ARIA attributes where necessary.
  - Clear and descriptive IDs and classes for styling and scripting.
  - Comments to explain the structure and purpose of different sections.
- The implementation should include unit tests and integration tests to verify the functionality of the Timer route.
- Documentation should be provided for the Timer route, including usage instructions and any relevant technical details.

## Testing requirements
- Timer expiring while page is inactive
- Multiple timers expiring simultaneously
- Editing a timer while it's expiring
- Connection loss/recovery during timer operations

Think about everything you want. Be explicit, you need to think like you are explaining what you want to a person with very limited understanding.

No, I had a quick play with the FlowFuse AI thing but really, most flows are so simple, it would probably take you longer to explain it than to just do it.