Skip to content

[Preview] OpenROAD web server as new GUI#9753

Merged
maliberty merged 129 commits intoThe-OpenROAD-Project:masterfrom
The-OpenROAD-Project-staging:web
Mar 23, 2026
Merged

[Preview] OpenROAD web server as new GUI#9753
maliberty merged 129 commits intoThe-OpenROAD-Project:masterfrom
The-OpenROAD-Project-staging:web

Conversation

@openroad-ci
Copy link
Copy Markdown
Collaborator

@openroad-ci openroad-ci commented Mar 13, 2026

This is initial work toward replacing the Qt gui with OpenROAD acting as a web server and using a standard browser as the display. It is known to be incomplete but is far enough along for feedback on the general approach.

Especially I'd like feedback on

  • The bazel handling of javascript and npm dependencies and tests (@hzeller @QuantamHD )
  • Does it work for other people (portability), particularly on MacOS.

To run it you load a design as usual and then

web_server -dir <prefix>/src/web/src

maliberty added 30 commits March 8, 2026 03:22
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Don't draw right/top highlight borders when the instance extends
beyond the tile, which was causing yellow lines at every tile seam.

Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Add a menu bar (File, View, Tools, Windows, Help) matching the GUI's
menu structure. File > Open DB opens a server-side file browser dialog
(LIST_DIR WebSocket request) instead of a bare text input. File > Save DB
uses the same browser. Menu items are dynamically enabled/disabled based
on whether a design is loaded.

Allow the web server to start without a loaded design by removing the
WEB-0099 error and adding null-chip/null-block guards throughout
TileGenerator, Search, and WebSocketSession. The client detects empty
bounds and skips map setup, letting the user load a design via the menu.
After read_db, the client reloads to run the full init flow.

Add shapes_ready to the BOUNDS response so the client can skip the
loading overlay on browser reload when shapes are already built.

Add keyboard shortcuts for zoom in (z) and zoom out (Shift+Z), with
an input field guard to avoid triggering shortcuts while typing.

Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
@maliberty
Copy link
Copy Markdown
Member

/gemini review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a significant new feature: a web-based GUI for OpenROAD, intended as a modern replacement for the Qt-based GUI. The changes are extensive and well-structured, primarily consisting of two major parts: a substantial refactoring of the gui module to decouple it from Qt, and the implementation of a new web module that provides the server backend and frontend assets.

The refactoring of the gui module is impressive, introducing patterns like a DescriptorRegistry and a factory system for HeatMapDataSource which greatly improve modularity and enable the new web viewer to reuse core visualization logic. The new web module itself is well-architected, using standard and robust technologies like Boost.Asio/Beast for the C++ backend and Leaflet/GoldenLayout for the JavaScript frontend.

My feedback focuses on improving the robustness of the server's request handling and enhancing configuration flexibility for better portability and deployment options. Overall, this is an excellent preview of a major new capability for OpenROAD.

set def_file [make_result_file "rdl_route_45.def"]
write_def $def_file
diff_files $def_file "rdl_route_45.defok"
web_server -dir /workspace/w6/tools/OpenROAD/src/web/src
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The path /workspace/w6/tools/OpenROAD/src/web/src is hardcoded. This will likely cause the test to fail on machines with different directory structures. It would be more portable to use a path relative to the test file or the project root, or to use an environment variable. This also applies to src/pad/test/rdl_route_bump_to_bump_only.tcl.

References
  1. Define tunable parameters as named constants instead of using hardcoded magic numbers. This principle extends to hardcoded paths which should be configurable or relative for portability.

Comment on lines +21 to +54
#include <vector>

#include "clock_tree_report.h"
#include "color.h"
#include "gui/descriptor_registry.h"
#include "gui/gui.h"
#include "gui/heatMap.h"
#include "hierarchy_report.h"
#include "json_builder.h"
#include "odb/db.h"
#include "odb/geom.h"
#include "tile_generator.h"
#include "timing_report.h"
#include "utl/Logger.h"

namespace web {

//------------------------------------------------------------------------------
// ShapeCollector — a gui::Painter that collects rectangles from
// descriptor->highlight() calls for use in tile rendering.
//------------------------------------------------------------------------------

class ShapeCollector : public gui::Painter
{
public:
ShapeCollector() : Painter(nullptr, odb::Rect(), 1.0) {}

std::vector<odb::Rect> rects;
std::vector<odb::Polygon> polys;

void drawRect(const odb::Rect& rect, int, int) override
{
rects.push_back(rect);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The extract_string function is a hand-rolled JSON string parser. It handles common escape sequences but misses some from the JSON standard, such as \b (backspace) and \f (form feed). The default case for an unknown escape sequence is also incorrect, as it just appends the character following the backslash.

While this may work for the current client implementation, it's not fully compliant and could lead to parsing errors with other clients or future changes. Consider using a lightweight JSON library for more robust and maintainable JSON parsing. This would also simplify the request parsing logic in web.cpp.

Comment on lines +1568 to +1633
try {
fs::path dir_path
= req.dir_path.empty() ? fs::current_path() : fs::path(req.dir_path);
dir_path = fs::canonical(dir_path);

struct Entry
{
std::string name;
bool is_dir;
std::uintmax_t size;
};
std::vector<Entry> entries;

for (const auto& entry : fs::directory_iterator(
dir_path, fs::directory_options::skip_permission_denied)) {
const auto& name = entry.path().filename().string();
// Skip hidden files/directories.
if (!name.empty() && name[0] == '.') {
continue;
}
bool is_dir = entry.is_directory();
std::uintmax_t size = 0;
if (!is_dir) {
std::error_code ec;
size = entry.file_size(ec);
if (ec) {
size = 0;
}
}
entries.push_back({name, is_dir, size});
}

// Sort: directories first, then alphabetical within each group.
std::ranges::sort(entries, [](const Entry& a, const Entry& b) {
if (a.is_dir != b.is_dir) {
return a.is_dir > b.is_dir;
}
return a.name < b.name;
});

JsonBuilder builder;
builder.beginObject();
builder.field("path", dir_path.string());
builder.field("parent", dir_path.parent_path().string());
builder.beginArray("entries");
for (const auto& entry : entries) {
builder.beginObject();
builder.field("name", entry.name);
builder.field("is_dir", entry.is_dir);
if (!entry.is_dir) {
builder.field("size", static_cast<int>(entry.size));
}
builder.endObject();
}
builder.endArray();
builder.endObject();

const std::string& json = builder.str();
resp.payload.assign(json.begin(), json.end());
} catch (const std::exception& e) {
resp.type = 2;
std::string err = std::string("list_dir error: ") + e.what();
resp.payload.assign(err.begin(), err.end());
}
return resp;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-medium medium

The list_dir handler allows browsing the server's filesystem starting from the current working directory. While this is convenient for a local desktop tool, it could become a security concern if OpenROAD is ever run as a shared or remote service, as it might expose more of the filesystem than intended. For future hardening, you might consider adding an option to restrict file browsing to a specific root directory or a set of allowed directories.

Comment on lines +921 to +923
auto const address = net::ip::make_address("127.0.0.1");
uint16_t const port = 8080;
int const num_threads = 32;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The server address, port, and number of threads are hardcoded. It would be beneficial to make these configurable, for example, through arguments to the web_server Tcl command or environment variables. This would improve flexibility, allowing users to avoid port conflicts or bind to different interfaces (e.g., 0.0.0.0 to allow remote access).

References
  1. Define tunable parameters as named constants instead of using hardcoded magic numbers. Server address, port, and number of threads are tunable parameters that should not be hardcoded.

Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
@maliberty
Copy link
Copy Markdown
Member

I'm going to merge this to keep this PR from getting bigger but the module remains not feature complete. I'm glad to have people try it and give feedback, issues, or PRs.

Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
@maliberty maliberty merged commit 07be495 into The-OpenROAD-Project:master Mar 23, 2026
14 of 15 checks passed
@maliberty maliberty deleted the web branch March 23, 2026 02:46
gudeh pushed a commit to gudeh/OpenROAD that referenced this pull request Apr 3, 2026
…t-staging/web

[Preview] OpenROAD web server as new GUI
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants