During my training as a Software Developer, I worked on developing a web application that interacts with our SCTX API.
This project serves as a learning opportunity to enhance my knowledge and skills in web technologies and API integration.
The web application provides an intuitive interface for querying API data using a tile-based layout:
- The top tile displays an overview of system data collected and returned by the API. This section can be expanded or collapsed using a toggle button.
- For each connected monitor, a tile is dynamically generated, displaying a preview image of the corresponding stream.
- Clicking on a tile opens the stream in fullscreen mode.
- Clicking on the stream again returns the user to the overview and exits fullscreen mode.
- SCTX: An integrated web application providing data via the FastCGI protocol. The API sends various events with parameters that need to be processed.
- HTML, CSS, JavaScript: Implemented without additional frameworks or libraries.
- Nginx as the web server.
- When accessed via
127.0.0.1
, the webpage should display an overview page with system data and stream previews for each monitor. - Users should be able to select a stream from the overview, which will then open in fullscreen mode.
- System data (e.g., RAM size) is provided in bytes and must be converted to appropriate units with the correct unit prefix.
- If the API returns a 410 error, the overview should be removed, and a proper error message must be displayed.
The API provides multiple endpoints for retrieving data:
fetch('/api/init.sctx');
Returns a session key along with the same system data provided by api/overview.sctx
.
fetch('/api/overview.sctx', { method: 'POST', body: `session=${session}` });
Returns system information (memory, processor, displays, etc.) and an array of stream previews.
fetch('/api/select.sctx', { method: 'POST', body: `session=${session}&stream=${(streamNumber)}`});
Selects a stream and returns a status. If status 200 is received, the event handler can be bound.
fetch('/api/event.sctx', { method: 'POST', body: `session=${session}` });
Retrieves events along with their respective parameters.
- geometry: The stream's resolution or aspect ratio has changed. The display must be updated accordingly. The screen will turn black until a new image is loaded.
- image: A new image segment or a full image is provided. Includes a PNG URL with X/Y coordinates, width, and height.
- overlay: The overlay becomes visible or hidden.
- overlayImage: Updates the overlay image (68x68px JPEG), which must be rendered on top of the stream.
- overlayPosition: Updates the overlay’s position. If the overlay is hidden, it should reappear at the last known position when reactivated.
- terminated: The stream has been closed. This should be reflected in the UI, and the event handler must be deactivated.
Important:
A single API request may return multiple events at once.
Event-provided image URLs are valid for only 5 seconds—after that, they will return a 404 error.
As mentioned earlier and shown in the example image, I chose a tile-based layout for better visual organization and usability.
Static tile: Displays system data using an HTML table and is created only once.
Dynamic tiles: Created for each monitor and updated every 5 seconds.
Clicking on a dynamic tile hides the overview and activates fullscreen mode to display the selected stream.
To optimize performance, the stream is displayed using three separate canvas elements:
- Overlay Canvas: Displays the mouse cursor separately to ensure smoother movement.
- Buffer Canvas: Aggregates image fragments from API responses before rendering.
- Stream Canvas: The final image is drawn here, using data collected in the buffer canvas.
This method enables efficient rendering of 5-15 image fragments per update with just one draw call.
One of the key challenges was the API's JSON structure, which lacked a clear hierarchy.
Instead of simple nested objects, it contained a mix of objects, wrapper objects, and top-level key-value pairs.
To solve this issue, I developed two helper functions:
- Detects wrapper objects and extracts all nested objects into an array.
- Collects all top-level key-value pairs for structured processing.
With these methods, any JSON response (excluding arrays) can be dynamically parsed and displayed within the static tile’s table.
If a fetch request fails, a dedicated error page is displayed.
- The error page reads the error code from the URL and provides a detailed explanation from a JSON file.
- A "Retry" button allows users to return to index.html
, where the overview will attempt to reload.
This project was a valuable exercise in API integration, real-time rendering, and UI optimization.
By structuring the data efficiently and handling API responses dynamically, the application ensures smooth performance and a clean user experience. 🚀