A browser for any linked-object resource — point it at a JSON-LD URL and get a usable UI.
The Linked Object Browser turns raw JSON-LD into interactive views: tasks, folders, profiles, playlists, markdown, and more. It plugs into any pod or server that can deliver linked data — Solid servers via JSS’ --mashlib-module, NosDav servers, plain static sites, anywhere.
The whole thing is ~1,100 lines of vanilla JavaScript. No dependencies. No framework. No build step.
Serve any directory of JSON-LD over HTTP and tell its host page to load this script — that’s it. There is nothing to install.
For a JSS-compatible server (Solid pods, NosDav, etc.), pass it as the mashlib module:
jss start --mashlib-module https://linkedobjects.org/browser/mashlib.js
Or, with nosdav-server:
nosdav --mashlib-module https://linkedobjects.org/browser/mashlib.js
Then visit any resource on the server — the browser renders the appropriate pane for the data’s @type.
To embed it directly in a static page:
<div id="losos"></div>
<script type="application/ld+json" src="data.jsonld"></script>
<script type="module" src="https://linkedobjects.org/browser/mashlib.js"></script>
Three layers, each standalone and replaceable:
┌─────────────────────────────────────────────────────────────┐
│ mashlib.js entry point: fetch → JSON-LD island │
├─────────────────────────────────────────────────────────────┤
│ losos/ shell: load panes, route by @type │
│ (~600 LOC, template renderer + boot) │
├─────────────────────────────────────────────────────────────┤
│ lion/ JSON-LD store, rdflib-compatible API │
│ (~175 LOC, replaces ~300 KB rdflib) │
└─────────────────────────────────────────────────────────────┘
mashlib.js fetches the current URL (JSON-LD, markdown, or playlist), injects it as an inline <script type="application/ld+json"> data island, registers pane modules, and imports the shell.
LOSOS (Linked Objects OS) loads every pane, finds the primary subject in the store, and renders a tab bar. Each pane decides for itself whether it can handle the subject. The first match wins.
LION (Linked Objects Notation) is a drop-in subset of rdflib: match, any, each, holds, statementsMatching — just enough for existing rdflib-based panes to work unchanged, without shipping 300 KB of triple-store code to the browser.
For each resource, the shell tries three sources in order:
canHandle(subject, store) returns true.ui:view — if the node itself declares a view URL, load it dynamically.@type → pane URL mapping (losos/registry.js).The active tab is persisted per path in localStorage, so the page remembers where you were.
A pane is a single ES module with two methods:
import { html, render } from '../losos/html.js'
export default {
label: 'Profile',
icon: '\u{1F464}', // optional
canHandle(subject, store) {
const type = store.type(subject.value)
return type && type.includes('Person')
},
render(subject, store, container, rawData) {
const name = store.prop(subject.value, 'name')
render(container, html`<h1>${name}</h1>`)
}
}
Register it in mashlib.js (or publish it anywhere and reference it via ui:view):
var panes = [
'panes/profile-pane.js',
// ...
]
That’s the whole contract.
mashlib.js entry point for --mashlib-module
mashlib.css minimal default styling
index.html standalone demo page
lion/
index.js JSON-LD store with rdflib-compatible methods
losos/
shell.js pane loader, tab bar, data resolution
html.js tagged-template → DOM renderer (no VDOM)
registry.js default @type → pane URL mappings
losos.js public API barrel
panes/
home-pane.js home screen: app grid, clock
todo-pane.js wf:Tracker / ical:Vtodo
profile-pane.js foaf:Person / schema:Person
folder-pane.js LDP containers
markdown-pane.js text/markdown documents
playlist-pane.js m3u / pls
pod-pane.js pod overview for Tracker docs
sharing-pane.js .acl editor (works on any resource)
source-pane.js raw JSON-LD view (catch-all)
schema-pane.js schema.org types
agent-pane.js, webledger-pane.js, terminal-pane.js, …
Clone and serve the directory over HTTP — there is nothing to install, compile, or bundle:
git clone https://github.com/linkedobjects/browser
cd browser
python3 -m http.server 8000
Then point a JSS instance at http://localhost:8000/mashlib.js, or open index.html directly.
The default branch is gh-pages, so pushing to it publishes immediately at https://linkedobjects.org/browser/.
rdflib.js + the original mashlib.js are ~300 KB and load N-Triples, Turtle, RDF/XML, SPARQL, patches, signing, pub-sub — a lot of surface for showing a to-do list. JSON-LD is now ubiquitous, browsers parse JSON natively, and most apps only need a handful of predicates. So:
ui:view. Data declares its own view.The result: pages stay small, boot fast, and anyone can fork a pane.