browser

Linked Object Browser

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.


Try it

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>

How it works

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.

Pane resolution

For each resource, the shell tries three sources in order:

  1. Local panes — any pane whose canHandle(subject, store) returns true.
  2. ui:view — if the node itself declares a view URL, load it dynamically.
  3. Registry@type → pane URL mapping (losos/registry.js).

The active tab is persisted per path in localStorage, so the page remembers where you were.


Writing a pane

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.


Project layout

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, …

Development

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/.


Why

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:

The result: pages stay small, boot fast, and anyone can fork a pane.


License

AGPL-3.0