You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Two related feature ideas from building Gnomputer (a Gno desktop-in-browser PWA that embeds mygnoscan via iframe). Posting as a proposal, not a request for immediate work — happy to help scope further.
1. Embeddable "widget mode" via URL flags
Right now embedding mygnoscan means iframing the full site (nav, theme, chrome and all). A URL flag (e.g. ?embed=1 or ?widget=graph) that strips the outer chrome and renders just one piece of content — a single graph, a single table, a single stat — would let a host app embed just the useful part instead of a whole page-in-a-page. Concretely useful pieces to expose this way: the per-realm dependency graph (/realm/:path?tab=graph), the gas/analytics leaderboards, a single block or tx detail view.
2. A realm interaction map
A visual "map" of realm activity: circles sized by request volume in a chosen timeframe, grouped by namespace (a big circle per address/org, smaller circles inside it for each realm that namespace owns), with arrows between realms for real dependency edges (sized/weighted by call volume, not just "exists"). A v2 could add arrows radiating in from outside the diagram to represent external callers/users hitting a realm, to visualize real traffic patterns, not just the static dependency graph mygnoscan's /realm/:path graph tab already shows.
This is a bigger, more novel feature than #1 — could live here (mygnoscan already has the indexer data and the existing d3-force graph to build on) or could be built directly in a consumer app; flagging it here first since mygnoscan's backend is the natural home for the aggregation query it'd need (activity-per-realm-per-timeframe, which isn't exposed by any current /api/* endpoint).
Context
Related tracking: moul/gnomputer#69 (a "see the impact of an action live" demo concept this map/embed mode would help support). Also see the existing backend/API feedback meta-issue for smaller, concrete bugs found during the same integration work.
Some implementation notes from reading the code (audit 2026-08-05), relevant to scoping both parts:
Part 1 (widget mode) is mostly mechanical but the frontend is a single 3315-line frontend/index.html with markup, CSS and JS inline, so "strip the chrome" means introducing a real render-mode branch rather than toggling a CSS class on an existing component boundary — there are not many boundaries yet. Worth doing after (or alongside) any frontend restructuring; landing it first means doing it twice.
Part 2 (realm interaction map) — the renderer is in better shape than the data layer:
The d3-force graph already exists and is good (index.html:2956). What is coupled to the dependency-graph shape is narrow: node radius (index.html:3088) and depthColor. Feeding it an activity-weighted graph is mostly a new data adapter, not a new renderer.
The blocker is the aggregation query, as you guessed. The data contract today is a dependency graph ({path: [imports]}) with no weights.
Per-realm timeframe aggregation exists, but only for storage: GetStorageTimeSeries (db.go:1387), exposed as /api/timeseries/storage?realm=. There is no per-realm activity series anywhere.
Closest path to what you want: mirror GetStorageTimeSeries with calls as the source plus AND pkg_path = ?, reusing the existing fillBuckets helper, and add an index on (network, pkg_path, block_time).
Namespace grouping (big circle per address/org, realms nested inside) can come straight from packages.creator, which is already stored and indexed.
For the dependency arrows weighted by call volume rather than mere existence, note that the existing analytics JOINs group calls/dependencies by path without network in the key (db.go:967) — so cross-network double-counting is a live risk for exactly this kind of aggregation. Worth fixing as part of the query work rather than after.
So: the map is realistically "one new aggregation endpoint + one adapter", with the network-scoping bug as a prerequisite. Filed #20 tracking the structural work; #14 covers tests for the multi-network query cases that this feature would otherwise trip over.
Status check against the deployed instance, 2026-09-22. Part 1 shipped, and most of part 2 shipped under a different name. What is genuinely left is one specific thing, and it is worth stating precisely rather than leaving this open as a whole feature.
Part 1: embed mode is live
?embed=1 works on every route, and the 2026-08-05 audit's worry about it — "the frontend is a single 3315-line index.html, so strip the chrome means introducing a real render-mode branch" — turned out to be answerable with a class instead. An inline script in <head> reads the flag before the body exists and sets html.embed; the rest is CSS.
Header, footer, rail, the section strips and the sanity subbar are hidden, the container loses its padding and the background goes transparent so a host page shows through. e2e/tests/embed.spec.js pins both halves: the chrome is gone and the content is still there (a blank iframe would satisfy the first assertion on its own), and that nothing changes without the flag.
Part 2: /contracts is the realm interaction map
Built as its own page rather than as a second mode of the dependency graph, which is why it did not read as an answer to this issue. Against this issue's description, item by item:
asked for
where it is
circles sized by request volume in a chosen timeframe
/api/contracts/map?window= with metric=calls; also importers, gas, unique_callers
grouped by namespace, a big circle per org with its realms inside
namespace on every node; the packed and bundled views nest by it
arrows for real dependency edges
/api/contracts/edges?kind=imports
weighted by call volume, not just "exists"
not done for import edges.kind=callers edges are weighted (shared callers, weight: 393 on wugnot -> gnoswap/router today), but an import edge is still binary
v2: arrows radiating in from outside for external callers
not done
Five layouts (orbit, packed, bundled, chord, treemap), and the realm page links straight into it centred on itself.
The 2026-08-05 audit's two prerequisites are both resolved. The network-scoping bug it flagged — analytics JOINs grouping calls/dependencies by path without network in the key — is fixed; singleNetwork makes /api/contracts/* refuse the all-chains case outright rather than blending it. And the per-realm aggregation it said was the blocker exists as /api/realm/usage/{path}, with a window filter, per-caller and per-function breakdowns.
Two things the map learned that this issue did not anticipate, both of which turn the picture to mud without them: an edge needs two addresses in common (one address touching two contracts once is a coincidence, and at min=1 the map is mostly coincidences), and an address that touched more than 30 contracts is excluded from edge generation, because one bot calling fifty contracts links all of them to each other. Its calls still count toward every node's size.
What is actually left
Weighted import edges. An import edge today says the import exists. Sizing it by the calling realm's traffic would say how much of the chain's activity actually flows through a given package, which is the question this issue asked and the one importers (a count of dependents, regardless of whether any of them is used) cannot answer. p/nt/ufmt/v0 has 103 dependents on mainnet and zero calls of its own, and there is currently no way to tell which of those 103 are live.
External-caller arrows. Genuinely not started. Worth deciding whether it is one node per caller (unreadable past a few dozen) or an aggregated inbound weight per realm drawn on the node itself, which is probably the same picture with none of the mud.
Leaving this open for those two. Everything else here is shipped.
Activity
moul commentedon Aug 5, 2026
Some implementation notes from reading the code (audit 2026-08-05), relevant to scoping both parts:
Part 1 (widget mode) is mostly mechanical but the frontend is a single 3315-line
frontend/index.htmlwith markup, CSS and JS inline, so "strip the chrome" means introducing a real render-mode branch rather than toggling a CSS class on an existing component boundary — there are not many boundaries yet. Worth doing after (or alongside) any frontend restructuring; landing it first means doing it twice.Part 2 (realm interaction map) — the renderer is in better shape than the data layer:
index.html:2956). What is coupled to the dependency-graph shape is narrow: node radius (index.html:3088) anddepthColor. Feeding it an activity-weighted graph is mostly a new data adapter, not a new renderer.{path: [imports]}) with no weights.GetStorageTimeSeries(db.go:1387), exposed as/api/timeseries/storage?realm=. There is no per-realm activity series anywhere.GetStorageTimeSerieswithcallsas the source plusAND pkg_path = ?, reusing the existingfillBucketshelper, and add an index on(network, pkg_path, block_time).packages.creator, which is already stored and indexed.calls/dependenciesby path without network in the key (db.go:967) — so cross-network double-counting is a live risk for exactly this kind of aggregation. Worth fixing as part of the query work rather than after.So: the map is realistically "one new aggregation endpoint + one adapter", with the network-scoping bug as a prerequisite. Filed #20 tracking the structural work; #14 covers tests for the multi-network query cases that this feature would otherwise trip over.
moul commentedon Sep 22, 2026
Status check against the deployed instance, 2026-09-22. Part 1 shipped, and most of part 2 shipped under a different name. What is genuinely left is one specific thing, and it is worth stating precisely rather than leaving this open as a whole feature.
Part 1: embed mode is live
?embed=1works on every route, and the 2026-08-05 audit's worry about it — "the frontend is a single 3315-line index.html, so strip the chrome means introducing a real render-mode branch" — turned out to be answerable with a class instead. An inline script in<head>reads the flag before the body exists and setshtml.embed; the rest is CSS.Header, footer, rail, the section strips and the sanity subbar are hidden, the container loses its padding and the background goes transparent so a host page shows through.
e2e/tests/embed.spec.jspins both halves: the chrome is gone and the content is still there (a blank iframe would satisfy the first assertion on its own), and that nothing changes without the flag.Part 2:
/contractsis the realm interaction mapBuilt as its own page rather than as a second mode of the dependency graph, which is why it did not read as an answer to this issue. Against this issue's description, item by item:
/api/contracts/map?window=withmetric=calls; alsoimporters,gas,unique_callersnamespaceon every node; thepackedandbundledviews nest by it/api/contracts/edges?kind=importskind=callersedges are weighted (shared callers,weight: 393on wugnot -> gnoswap/router today), but an import edge is still binaryFive layouts (
orbit,packed,bundled,chord,treemap), and the realm page links straight into it centred on itself.The 2026-08-05 audit's two prerequisites are both resolved. The network-scoping bug it flagged — analytics JOINs grouping
calls/dependenciesby path without network in the key — is fixed;singleNetworkmakes/api/contracts/*refuse the all-chains case outright rather than blending it. And the per-realm aggregation it said was the blocker exists as/api/realm/usage/{path}, with awindowfilter, per-caller and per-function breakdowns.Two things the map learned that this issue did not anticipate, both of which turn the picture to mud without them: an edge needs two addresses in common (one address touching two contracts once is a coincidence, and at min=1 the map is mostly coincidences), and an address that touched more than 30 contracts is excluded from edge generation, because one bot calling fifty contracts links all of them to each other. Its calls still count toward every node's size.
What is actually left
Weighted import edges. An import edge today says the import exists. Sizing it by the calling realm's traffic would say how much of the chain's activity actually flows through a given package, which is the question this issue asked and the one
importers(a count of dependents, regardless of whether any of them is used) cannot answer.p/nt/ufmt/v0has 103 dependents on mainnet and zero calls of its own, and there is currently no way to tell which of those 103 are live.External-caller arrows. Genuinely not started. Worth deciding whether it is one node per caller (unreadable past a few dozen) or an aggregated inbound weight per realm drawn on the node itself, which is probably the same picture with none of the mud.
Leaving this open for those two. Everything else here is shipped.