UJG / Editor's Draft /
GitHub
Table of Contents
  • 1Overview
  • 2Normative Artifacts
  • 3Terminology
  • 4Attachment Model
  • 5Ontology
  • 6JSON-LD Context
  • 7Validation
  • 8State Surface Example
  • 9Transition Surface Example
  • 10Outgoing Transition Surface Example
  • 11Graph Node Instance Example
  • 12Appendix: Private Extension Payloads
W3C Community Group Draft Report

Surface

draft

Status of this Document

This report was published by the User Journal Graph Community Group . It is not a W3C Standard nor is it on the W3C Standards Track. Please note that under the W3C Community Contributor License Agreement (CLA) there is a limited opt-out and other conditions apply. Learn more about W3C Community and Business Groups .

Last Update
2026-07-10
Editors
  • Seva Dolgopolov
Group
User Journal Graph Community Group
Repository
View Source
License
W3C-Software-and-Document

1. Overview

This core-family layer defines a graph-successor vocabulary for assigning an addressable Surface to a Graph subject and, when needed, to the Touchpoint that presents that surface.

A Surface identifies a design-system-agnostic materialized boundary for one graph subject. Supported graph subjects are State, CompositeState, Transition, and OutgoingTransition. A surface may represent a page, screen, dialog, prompt, frame, application shell, transition affordance, action bar, repeated card, repeated slide, or other user-facing boundary. A single Surface is stable surface identity, not one runtime occurrence. Concrete runtime-visible occurrences are represented by SurfaceInstance.

A Touchpoint identifies the system, channel, origin, or service boundary through which a surface is presented to a human. Touchpoints are optional: a surface can be addressable without declaring its touchpoint, and a document can model graph topology without using Surface at all.

SurfaceInstance identifies a concrete runtime-visible occurrence of one Surface. GraphNodeInstance identifies a concrete occurrence of a graph node. It is useful when the same graph node is repeated with different content or under different parent occurrences, such as slides inside one image slider occurrence inside one blog post occurrence.

Surface annotates the shared graph with materialized boundary identity from the Surface layer. Graph subjects do not carry Surface references and do not depend on this module. Surface does not change graph topology, traversal rules, import resolution, rendering behavior, or runtime semantics. It also does not define how a surface is realized by a design system.

2. Normative Artifacts

Surface is published through the following artifacts:

  • surface.ttl: ontology, published at https://ujg.specs.openuji.org/ed/ns/surface

  • surface.context.jsonld: JSON-LD term mappings, published at https://ujg.specs.openuji.org/ed/ns/surface.context.jsonld

  • surface.shape.ttl: SHACL validation rules, published at https://ujg.specs.openuji.org/ed/ns/surface.shape

Examples in this page compose the shared baseline context https://ujg.specs.openuji.org/ed/ns/context.jsonld with the Surface context.

Non-goals:

  • Surface does not define rendering engines, widget libraries, styling systems, hydration behavior, component trees, region trees, layout semantics, or presentation semantics.

  • Surface does not define references from Surface to DesignSystem, Component, Template, Slot, SlotBinding, TokenSource, or SurfaceRealization resources.

  • Surface does not introduce new traversal semantics beyond UJG Graph.

  • Touchpoint does not define actor responsibility, authorization, runtime attribution, server truth, queue state, or protocol state.

  • Surface does not replace opaque vendor-private hints carried in UJG Core extensions.

3. Terminology

  • Surface: An addressable, design-system-agnostic materialized boundary for exactly one Graph subject.

  • SurfaceInstance: An addressable concrete occurrence of one Surface.

  • Touchpoint: An addressable system, channel, origin, or service boundary through which a surface is presented to a human.

  • GraphNodeInstance: An addressable concrete occurrence of one supported Graph node.

  • Surface attachment: The relation that assigns a surface to the graph node it exposes.

  • Touchpoint attachment: The relation that assigns a surface to its presenting touchpoint.

  • Instance attachment: The relation that assigns a surface instance to the graph-node occurrence it materializes.

4. Attachment Model

Surface introduces canonical interoperable attachments:

  • surface:graphNodeRef links a Surface to a Graph subject.

  • surface:touchpointRef links a Surface to a Touchpoint.

  • surface:surfaceRef links a SurfaceInstance to a Surface.

  • surface:graphNodeInstanceRef links a SurfaceInstance to a GraphNodeInstance.

Allowed graph subjects are:

  • State

  • CompositeState

  • Transition

  • OutgoingTransition

graphNodeRef is the canonical assignment form from Surface to Graph subject. To resolve surfaces for a graph subject, consumers find Surface nodes whose graphNodeRef value is that graph subject.

A graph subject without a referencing Surface remains fully valid and traversable. A surface without a SurfaceInstance remains a valid stable design, UXR, observability, or distributed-journey reference. Consumers MAY ignore this module and still process the graph.

A Surface MUST reference exactly one Graph subject in the validated document set using graphNodeRef. A graph subject MAY be referenced by more than one Surface when it has multiple visible occurrences.

A Surface MAY reference at most one Touchpoint using touchpointRef. The touchpoint identifies the presenting system, channel, origin, or service boundary for that surface. touchpointRef MUST NOT be interpreted as graph traversal, actor responsibility, runtime attribution, or ownership truth. A Touchpoint MAY be referenced by many surfaces.

A SurfaceInstance MUST reference exactly one Surface using surfaceRef. A SurfaceInstance MAY reference at most one GraphNodeInstance using graphNodeInstanceRef. GraphNodeInstance.graphNodeRef MUST reference exactly one supported Graph node. Producers SHOULD use matching graph-node values on the SurfaceInstance's referenced Surface and its referenced GraphNodeInstance when the surface instance is a direct visible occurrence of that graph node. A GraphNodeInstance MAY reference a parent GraphNodeInstance using parentInstanceRef, allowing consumers to derive occurrence trees.

A CompositeState MAY have its own Surface when the composite state has a user-facing material boundary as a whole, such as a shell, frame, scaffold, wizard frame, dashboard region, checkout shell, kiosk session frame, or settings layout. A composite-state surface does not replace child state surfaces and does not define containment beyond Graph semantics.

Transition and outgoing-transition surfaces represent user-facing transition affordances or invocation boundaries. They MUST NOT imply transition execution, transition availability, traversal, state activation, ordering, or lifecycle semantics.

An OutgoingTransitionGroup MUST NOT have its own Surface. Each child OutgoingTransition MAY have its own Surface. Group membership remains Graph-only: consumers use OutgoingTransitionGroup.outgoingTransitionRefs to determine which child outgoing transitions are effectively available, while surfaces identify the individual child affordances.

Multi-platform, multi-renderer, or multi-design-system output SHOULD NOT be represented by assigning multiple surfaces to the same graph subject merely to select implementations. Such alternatives belong in realization resources defined by modules that depend on Surface. Multiple surfaces are for distinct visible occurrences, not component or renderer variants.

5. Ontology

The normative Surface ontology is defined below and is published at https://ujg.specs.openuji.org/ed/ns/surface. It is the authoritative structural definition for Surface, SurfaceInstance, Touchpoint, GraphNodeInstance, graphNodeRef, surfaceRef, touchpointRef, and graphNodeInstanceRef.

turtle
@prefix ujg: <https://ujg.specs.openuji.org/ed/ns/core#> .
@prefix ujggraph: <https://ujg.specs.openuji.org/ed/ns/graph#> .
@prefix ujgsurface: <https://ujg.specs.openuji.org/ed/ns/surface#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix dct: <http://purl.org/dc/terms/> .

<https://ujg.specs.openuji.org/ed/ns/surface#> a owl:Ontology ;
  rdfs:label "UJG Surface Editor's Draft Vocabulary"@en ;
  dct:description "UJG Surface ontology declaration" .

### Classes

ujgsurface:Surface a owl:Class ;
  rdfs:subClassOf ujg:Node .

ujgsurface:SurfaceInstance a owl:Class ;
  rdfs:subClassOf ujg:Node .

ujgsurface:Touchpoint a owl:Class ;
  rdfs:subClassOf ujg:Node .

ujgsurface:GraphNodeInstance a owl:Class ;
  rdfs:subClassOf ujg:Node .

### Properties

ujgsurface:graphNodeRef a owl:ObjectProperty ;
  rdfs:domain [
    a owl:Class ;
    owl:unionOf (
      ujgsurface:Surface
      ujgsurface:GraphNodeInstance
    )
  ] ;
  rdfs:range [
    a owl:Class ;
    owl:unionOf (
      ujggraph:State
      ujggraph:CompositeState
      ujggraph:Transition
      ujggraph:OutgoingTransition
    )
  ] .

ujgsurface:touchpointRef a owl:ObjectProperty ;
  rdfs:domain ujgsurface:Surface ;
  rdfs:range ujgsurface:Touchpoint .

ujgsurface:surfaceRef a owl:ObjectProperty ;
  rdfs:domain ujgsurface:SurfaceInstance ;
  rdfs:range ujgsurface:Surface .

ujgsurface:graphNodeInstanceRef a owl:ObjectProperty ;
  rdfs:domain ujgsurface:SurfaceInstance ;
  rdfs:range ujgsurface:GraphNodeInstance .

ujgsurface:parentInstanceRef a owl:ObjectProperty ;
  rdfs:domain ujgsurface:GraphNodeInstance ;
  rdfs:range ujgsurface:GraphNodeInstance .

ujgsurface:channel a owl:DatatypeProperty ;
  rdfs:domain ujgsurface:Touchpoint ;
  rdfs:range xsd:string .

ujgsurface:origin a owl:ObjectProperty ;
  rdfs:domain ujgsurface:Touchpoint ;
  rdfs:range rdfs:Resource .
@prefix ujg: <https://ujg.specs.openuji.org/ed/ns/core#> .
@prefix ujggraph: <https://ujg.specs.openuji.org/ed/ns/graph#> .
@prefix ujgsurface: <https://ujg.specs.openuji.org/ed/ns/surface#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix dct: <http://purl.org/dc/terms/> .

<https://ujg.specs.openuji.org/ed/ns/surface#> a owl:Ontology ;
  rdfs:label "UJG Surface Editor's Draft Vocabulary"@en ;
  dct:description "UJG Surface ontology declaration" .

### Classes

ujgsurface:Surface a owl:Class ;
  rdfs:subClassOf ujg:Node .

ujgsurface:SurfaceInstance a owl:Class ;
  rdfs:subClassOf ujg:Node .

ujgsurface:Touchpoint a owl:Class ;
  rdfs:subClassOf ujg:Node .

ujgsurface:GraphNodeInstance a owl:Class ;
  rdfs:subClassOf ujg:Node .

### Properties

ujgsurface:graphNodeRef a owl:ObjectProperty ;
  rdfs:domain [
    a owl:Class ;
    owl:unionOf (
      ujgsurface:Surface
      ujgsurface:GraphNodeInstance
    )
  ] ;
  rdfs:range [
    a owl:Class ;
    owl:unionOf (
      ujggraph:State
      ujggraph:CompositeState
      ujggraph:Transition
      ujggraph:OutgoingTransition
    )
  ] .

ujgsurface:touchpointRef a owl:ObjectProperty ;
  rdfs:domain ujgsurface:Surface ;
  rdfs:range ujgsurface:Touchpoint .

ujgsurface:surfaceRef a owl:ObjectProperty ;
  rdfs:domain ujgsurface:SurfaceInstance ;
  rdfs:range ujgsurface:Surface .

ujgsurface:graphNodeInstanceRef a owl:ObjectProperty ;
  rdfs:domain ujgsurface:SurfaceInstance ;
  rdfs:range ujgsurface:GraphNodeInstance .

ujgsurface:parentInstanceRef a owl:ObjectProperty ;
  rdfs:domain ujgsurface:GraphNodeInstance ;
  rdfs:range ujgsurface:GraphNodeInstance .

ujgsurface:channel a owl:DatatypeProperty ;
  rdfs:domain ujgsurface:Touchpoint ;
  rdfs:range xsd:string .

ujgsurface:origin a owl:ObjectProperty ;
  rdfs:domain ujgsurface:Touchpoint ;
  rdfs:range rdfs:Resource .

6. JSON-LD Context

The normative Surface JSON-LD context is defined below and is published at https://ujg.specs.openuji.org/ed/ns/surface.context.jsonld. It provides the compact JSON-LD term mappings and coercions for Surface-specific properties and classes.

json-ld
{
  "@context": {
    "@version": 1.1,

    "ujgsurface": "https://ujg.specs.openuji.org/ed/ns/surface#",
    "surface": "https://ujg.specs.openuji.org/ed/ns/surface#",
    "xsd": "http://www.w3.org/2001/XMLSchema#",

    "Surface": "ujgsurface:Surface",
    "SurfaceInstance": "ujgsurface:SurfaceInstance",
    "Touchpoint": "ujgsurface:Touchpoint",
    "GraphNodeInstance": "ujgsurface:GraphNodeInstance",

    "graphNodeRef": {
      "@id": "ujgsurface:graphNodeRef",
      "@type": "@id"
    },
    "touchpointRef": {
      "@id": "ujgsurface:touchpointRef",
      "@type": "@id"
    },
    "surfaceRef": {
      "@id": "ujgsurface:surfaceRef",
      "@type": "@id"
    },
    "graphNodeInstanceRef": {
      "@id": "ujgsurface:graphNodeInstanceRef",
      "@type": "@id"
    },
    "parentInstanceRef": {
      "@id": "ujgsurface:parentInstanceRef",
      "@type": "@id"
    },
    "channel": "ujgsurface:channel",
    "origin": {
      "@id": "ujgsurface:origin",
      "@type": "@id"
    }
  }
}
{
  "@context": {
    "@version": 1.1,

    "ujgsurface": "https://ujg.specs.openuji.org/ed/ns/surface#",
    "surface": "https://ujg.specs.openuji.org/ed/ns/surface#",
    "xsd": "http://www.w3.org/2001/XMLSchema#",

    "Surface": "ujgsurface:Surface",
    "SurfaceInstance": "ujgsurface:SurfaceInstance",
    "Touchpoint": "ujgsurface:Touchpoint",
    "GraphNodeInstance": "ujgsurface:GraphNodeInstance",

    "graphNodeRef": {
      "@id": "ujgsurface:graphNodeRef",
      "@type": "@id"
    },
    "touchpointRef": {
      "@id": "ujgsurface:touchpointRef",
      "@type": "@id"
    },
    "surfaceRef": {
      "@id": "ujgsurface:surfaceRef",
      "@type": "@id"
    },
    "graphNodeInstanceRef": {
      "@id": "ujgsurface:graphNodeInstanceRef",
      "@type": "@id"
    },
    "parentInstanceRef": {
      "@id": "ujgsurface:parentInstanceRef",
      "@type": "@id"
    },
    "channel": "ujgsurface:channel",
    "origin": {
      "@id": "ujgsurface:origin",
      "@type": "@id"
    }
  }
}

7. Validation

The normative Surface SHACL shape is defined below and is published at https://ujg.specs.openuji.org/ed/ns/surface.shape. It is the authoritative validation artifact for Surface structural constraints.

turtle
@prefix ujggraph: <https://ujg.specs.openuji.org/ed/ns/graph#> .
@prefix ujgsurface: <https://ujg.specs.openuji.org/ed/ns/surface#> .
@prefix ujgsurfaceshape: <https://ujg.specs.openuji.org/ed/ns/surface.shape#> .
@prefix sh: <http://www.w3.org/ns/shacl#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .

ujgsurfaceshape:GraphSubjectShape a sh:NodeShape ;
  sh:nodeKind sh:IRI ;
  sh:or (
    [ sh:class ujggraph:State ]
    [ sh:class ujggraph:CompositeState ]
    [ sh:class ujggraph:Transition ]
    [ sh:class ujggraph:OutgoingTransition ]
  ) .

ujgsurfaceshape:SurfaceShape a sh:NodeShape ;
  sh:targetClass ujgsurface:Surface ;
  sh:nodeKind sh:IRI ;

  sh:property [
    sh:path ujgsurface:graphNodeRef ;
    sh:node ujgsurfaceshape:GraphSubjectShape ;
    sh:nodeKind sh:IRI ;
    sh:minCount 1 ;
    sh:maxCount 1 ;
  ] ;

  sh:property [
    sh:path ujgsurface:touchpointRef ;
    sh:class ujgsurface:Touchpoint ;
    sh:nodeKind sh:IRI ;
    sh:maxCount 1 ;
  ] .

ujgsurfaceshape:SurfaceInstanceShape a sh:NodeShape ;
  sh:targetClass ujgsurface:SurfaceInstance ;
  sh:nodeKind sh:IRI ;

  sh:property [
    sh:path ujgsurface:surfaceRef ;
    sh:class ujgsurface:Surface ;
    sh:nodeKind sh:IRI ;
    sh:minCount 1 ;
    sh:maxCount 1 ;
  ] ;

  sh:property [
    sh:path ujgsurface:graphNodeInstanceRef ;
    sh:class ujgsurface:GraphNodeInstance ;
    sh:nodeKind sh:IRI ;
    sh:maxCount 1 ;
  ] .

ujgsurfaceshape:GraphNodeInstanceShape a sh:NodeShape ;
  sh:targetClass ujgsurface:GraphNodeInstance ;
  sh:nodeKind sh:IRI ;

  sh:property [
    sh:path ujgsurface:graphNodeRef ;
    sh:node ujgsurfaceshape:GraphSubjectShape ;
    sh:nodeKind sh:IRI ;
    sh:minCount 1 ;
    sh:maxCount 1 ;
  ] ;

  sh:property [
    sh:path ujgsurface:parentInstanceRef ;
    sh:class ujgsurface:GraphNodeInstance ;
    sh:nodeKind sh:IRI ;
    sh:maxCount 1 ;
  ] .

ujgsurfaceshape:TouchpointShape a sh:NodeShape ;
  sh:targetClass ujgsurface:Touchpoint ;
  sh:nodeKind sh:IRI ;

  sh:property [
    sh:path ujggraph:label ;
    sh:datatype xsd:string ;
    sh:minCount 1 ;
    sh:maxCount 1 ;
  ] ;

  sh:property [
    sh:path ujgsurface:channel ;
    sh:datatype xsd:string ;
    sh:maxCount 1 ;
  ] ;

  sh:property [
    sh:path ujgsurface:origin ;
    sh:nodeKind sh:IRI ;
    sh:maxCount 1 ;
  ] .
@prefix ujggraph: <https://ujg.specs.openuji.org/ed/ns/graph#> .
@prefix ujgsurface: <https://ujg.specs.openuji.org/ed/ns/surface#> .
@prefix ujgsurfaceshape: <https://ujg.specs.openuji.org/ed/ns/surface.shape#> .
@prefix sh: <http://www.w3.org/ns/shacl#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .

ujgsurfaceshape:GraphSubjectShape a sh:NodeShape ;
  sh:nodeKind sh:IRI ;
  sh:or (
    [ sh:class ujggraph:State ]
    [ sh:class ujggraph:CompositeState ]
    [ sh:class ujggraph:Transition ]
    [ sh:class ujggraph:OutgoingTransition ]
  ) .

ujgsurfaceshape:SurfaceShape a sh:NodeShape ;
  sh:targetClass ujgsurface:Surface ;
  sh:nodeKind sh:IRI ;

  sh:property [
    sh:path ujgsurface:graphNodeRef ;
    sh:node ujgsurfaceshape:GraphSubjectShape ;
    sh:nodeKind sh:IRI ;
    sh:minCount 1 ;
    sh:maxCount 1 ;
  ] ;

  sh:property [
    sh:path ujgsurface:touchpointRef ;
    sh:class ujgsurface:Touchpoint ;
    sh:nodeKind sh:IRI ;
    sh:maxCount 1 ;
  ] .

ujgsurfaceshape:SurfaceInstanceShape a sh:NodeShape ;
  sh:targetClass ujgsurface:SurfaceInstance ;
  sh:nodeKind sh:IRI ;

  sh:property [
    sh:path ujgsurface:surfaceRef ;
    sh:class ujgsurface:Surface ;
    sh:nodeKind sh:IRI ;
    sh:minCount 1 ;
    sh:maxCount 1 ;
  ] ;

  sh:property [
    sh:path ujgsurface:graphNodeInstanceRef ;
    sh:class ujgsurface:GraphNodeInstance ;
    sh:nodeKind sh:IRI ;
    sh:maxCount 1 ;
  ] .

ujgsurfaceshape:GraphNodeInstanceShape a sh:NodeShape ;
  sh:targetClass ujgsurface:GraphNodeInstance ;
  sh:nodeKind sh:IRI ;

  sh:property [
    sh:path ujgsurface:graphNodeRef ;
    sh:node ujgsurfaceshape:GraphSubjectShape ;
    sh:nodeKind sh:IRI ;
    sh:minCount 1 ;
    sh:maxCount 1 ;
  ] ;

  sh:property [
    sh:path ujgsurface:parentInstanceRef ;
    sh:class ujgsurface:GraphNodeInstance ;
    sh:nodeKind sh:IRI ;
    sh:maxCount 1 ;
  ] .

ujgsurfaceshape:TouchpointShape a sh:NodeShape ;
  sh:targetClass ujgsurface:Touchpoint ;
  sh:nodeKind sh:IRI ;

  sh:property [
    sh:path ujggraph:label ;
    sh:datatype xsd:string ;
    sh:minCount 1 ;
    sh:maxCount 1 ;
  ] ;

  sh:property [
    sh:path ujgsurface:channel ;
    sh:datatype xsd:string ;
    sh:maxCount 1 ;
  ] ;

  sh:property [
    sh:path ujgsurface:origin ;
    sh:nodeKind sh:IRI ;
    sh:maxCount 1 ;
  ] .

The rules below define the remaining module semantics beyond the structural constraints captured by the SHACL shape.

  1. Attachment only: Surface properties MUST NOT change Graph validity, graph traversal behavior, import resolution, or core node identity.

  2. Single exposed graph node: A Surface MUST identify exactly one Graph subject. A graph subject MAY be referenced by more than one Surface.

  3. Canonical direction: graphNodeRef is the canonical assignment from Surface to Graph subject.

  4. Surface instance: A SurfaceInstance MUST identify exactly one Surface using surfaceRef.

  5. Optional graph-node instance: SurfaceInstance.graphNodeInstanceRef MAY identify the concrete graph-node occurrence that a surface instance materializes.

  6. Optional touchpoint: touchpointRef MAY identify the touchpoint that presents a surface. Missing touchpointRef means the presenting touchpoint is not stated.

  7. Touchpoint boundary only: Touchpoint MUST NOT be interpreted as an Actor, as authorization data, as runtime evidence, or as server-internal truth.

  8. Graceful degradation: A consumer that does not implement Surface semantics MAY ignore Surface data, but it SHOULD preserve recognized JSON-LD data during read-transform-write when possible.

  9. Design-system agnostic: Surface properties MUST NOT define or imply design-system realization, component selection, template selection, slot binding, token-source selection, or rendering behavior.

  10. Interoperable realization: Component, template, slot, slot-binding, token-source, and surface-realization relationships intended for interoperability SHOULD be expressed by an optional module that depends on Surface.

8. State Surface Example

json
{
  "@context": [
    "https://ujg.specs.openuji.org/ed/ns/context.jsonld",
    "https://ujg.specs.openuji.org/ed/ns/surface.context.jsonld"
  ],
  "@id": "https://example.com/ujg/surface/checkout.jsonld",
  "@type": "UJGDocument",
  "nodes": [
    {
      "@id": "urn:state:cart",
      "@type": "State",
      "label": "Cart"
    },
    {
      "@id": "urn:surface:cart",
      "@type": "Surface",
      "graphNodeRef": "urn:state:cart",
      "touchpointRef": "urn:touchpoint:web"
    },
    {
      "@id": "urn:touchpoint:web",
      "@type": "Touchpoint",
      "label": "Web",
      "channel": "web",
      "origin": "https://shop.example"
    }
  ]
}
{
  "@context": [
    "https://ujg.specs.openuji.org/ed/ns/context.jsonld",
    "https://ujg.specs.openuji.org/ed/ns/surface.context.jsonld"
  ],
  "@id": "https://example.com/ujg/surface/checkout.jsonld",
  "@type": "UJGDocument",
  "nodes": [
    {
      "@id": "urn:state:cart",
      "@type": "State",
      "label": "Cart"
    },
    {
      "@id": "urn:surface:cart",
      "@type": "Surface",
      "graphNodeRef": "urn:state:cart",
      "touchpointRef": "urn:touchpoint:web"
    },
    {
      "@id": "urn:touchpoint:web",
      "@type": "Touchpoint",
      "label": "Web",
      "channel": "web",
      "origin": "https://shop.example"
    }
  ]
}

This example means:

  • urn:surface:cart identifies the addressable surface for cart.

  • urn:surface:cart is not a reusable template for other states.

  • urn:touchpoint:web identifies the system/channel boundary that presents the cart surface.

  • the graph remains the only source of truth for state and transition behavior.

9. Transition Surface Example

json
{
  "@context": [
    "https://ujg.specs.openuji.org/ed/ns/context.jsonld",
    "https://ujg.specs.openuji.org/ed/ns/surface.context.jsonld"
  ],
  "@id": "https://example.com/ujg/surface/transition.jsonld",
  "@type": "UJGDocument",
  "nodes": [
    {
      "@id": "urn:state:cart",
      "@type": "State",
      "label": "Cart"
    },
    {
      "@id": "urn:state:checkout",
      "@type": "State",
      "label": "Checkout"
    },
    {
      "@id": "urn:transition:checkout",
      "@type": "Transition",
      "from": "urn:state:cart",
      "to": "urn:state:checkout"
    },
    {
      "@id": "urn:surface:checkout-action",
      "@type": "Surface",
      "graphNodeRef": "urn:transition:checkout"
    }
  ]
}
{
  "@context": [
    "https://ujg.specs.openuji.org/ed/ns/context.jsonld",
    "https://ujg.specs.openuji.org/ed/ns/surface.context.jsonld"
  ],
  "@id": "https://example.com/ujg/surface/transition.jsonld",
  "@type": "UJGDocument",
  "nodes": [
    {
      "@id": "urn:state:cart",
      "@type": "State",
      "label": "Cart"
    },
    {
      "@id": "urn:state:checkout",
      "@type": "State",
      "label": "Checkout"
    },
    {
      "@id": "urn:transition:checkout",
      "@type": "Transition",
      "from": "urn:state:cart",
      "to": "urn:state:checkout"
    },
    {
      "@id": "urn:surface:checkout-action",
      "@type": "Surface",
      "graphNodeRef": "urn:transition:checkout"
    }
  ]
}

This example assigns a surface to the user-facing affordance for a transition. It does not execute the transition or change traversal semantics.

10. Outgoing Transition Surface Example

json
{
  "@context": [
    "https://ujg.specs.openuji.org/ed/ns/context.jsonld",
    "https://ujg.specs.openuji.org/ed/ns/surface.context.jsonld"
  ],
  "@id": "https://example.com/ujg/surface/outgoing.jsonld",
  "@type": "UJGDocument",
  "nodes": [
    {
      "@id": "urn:outgoing:home",
      "@type": "OutgoingTransition",
      "to": "urn:state:home"
    },
    {
      "@id": "urn:outgoing:profile",
      "@type": "OutgoingTransition",
      "to": "urn:state:profile"
    },
    {
      "@id": "urn:outgoing-group:global-nav",
      "@type": "OutgoingTransitionGroup",
      "outgoingTransitionRefs": ["urn:outgoing:home", "urn:outgoing:profile"]
    },
    {
      "@id": "urn:surface:home-action",
      "@type": "Surface",
      "graphNodeRef": "urn:outgoing:home"
    }
  ]
}
{
  "@context": [
    "https://ujg.specs.openuji.org/ed/ns/context.jsonld",
    "https://ujg.specs.openuji.org/ed/ns/surface.context.jsonld"
  ],
  "@id": "https://example.com/ujg/surface/outgoing.jsonld",
  "@type": "UJGDocument",
  "nodes": [
    {
      "@id": "urn:outgoing:home",
      "@type": "OutgoingTransition",
      "to": "urn:state:home"
    },
    {
      "@id": "urn:outgoing:profile",
      "@type": "OutgoingTransition",
      "to": "urn:state:profile"
    },
    {
      "@id": "urn:outgoing-group:global-nav",
      "@type": "OutgoingTransitionGroup",
      "outgoingTransitionRefs": ["urn:outgoing:home", "urn:outgoing:profile"]
    },
    {
      "@id": "urn:surface:home-action",
      "@type": "Surface",
      "graphNodeRef": "urn:outgoing:home"
    }
  ]
}

The OutgoingTransitionGroup remains a Graph construct only. The child outgoing-transition surface represents that outgoing transition's own affordance and can be used for observation or design-system realization without surfacing the group itself.

11. Graph Node Instance Example

json
{
  "@context": [
    "https://ujg.specs.openuji.org/ed/ns/context.jsonld",
    "https://ujg.specs.openuji.org/ed/ns/surface.context.jsonld"
  ],
  "@id": "https://example.com/ujg/surface/repeated-slide.jsonld",
  "@type": "UJGDocument",
  "nodes": [
    {
      "@id": "urn:state:blog-post",
      "@type": "CompositeState",
      "label": "Blog post",
      "subjourneyId": "urn:journey:blog-post"
    },
    {
      "@id": "urn:state:image-slide",
      "@type": "State",
      "label": "Image slide"
    },
    {
      "@id": "urn:graph-node-instance:blog-post:123",
      "@type": "GraphNodeInstance",
      "graphNodeRef": "urn:state:blog-post"
    },
    {
      "@id": "urn:graph-node-instance:blog-post:123:slide-1",
      "@type": "GraphNodeInstance",
      "graphNodeRef": "urn:state:image-slide",
      "parentInstanceRef": "urn:graph-node-instance:blog-post:123"
    },
    {
      "@id": "urn:surface:image-slide",
      "@type": "Surface",
      "graphNodeRef": "urn:state:image-slide"
    },
    {
      "@id": "urn:surface-instance:image-slide:post-123:slide-1",
      "@type": "SurfaceInstance",
      "surfaceRef": "urn:surface:image-slide",
      "graphNodeInstanceRef": "urn:graph-node-instance:blog-post:123:slide-1"
    }
  ]
}
{
  "@context": [
    "https://ujg.specs.openuji.org/ed/ns/context.jsonld",
    "https://ujg.specs.openuji.org/ed/ns/surface.context.jsonld"
  ],
  "@id": "https://example.com/ujg/surface/repeated-slide.jsonld",
  "@type": "UJGDocument",
  "nodes": [
    {
      "@id": "urn:state:blog-post",
      "@type": "CompositeState",
      "label": "Blog post",
      "subjourneyId": "urn:journey:blog-post"
    },
    {
      "@id": "urn:state:image-slide",
      "@type": "State",
      "label": "Image slide"
    },
    {
      "@id": "urn:graph-node-instance:blog-post:123",
      "@type": "GraphNodeInstance",
      "graphNodeRef": "urn:state:blog-post"
    },
    {
      "@id": "urn:graph-node-instance:blog-post:123:slide-1",
      "@type": "GraphNodeInstance",
      "graphNodeRef": "urn:state:image-slide",
      "parentInstanceRef": "urn:graph-node-instance:blog-post:123"
    },
    {
      "@id": "urn:surface:image-slide",
      "@type": "Surface",
      "graphNodeRef": "urn:state:image-slide"
    },
    {
      "@id": "urn:surface-instance:image-slide:post-123:slide-1",
      "@type": "SurfaceInstance",
      "surfaceRef": "urn:surface:image-slide",
      "graphNodeInstanceRef": "urn:graph-node-instance:blog-post:123:slide-1"
    }
  ]
}

This example models one concrete image-slide occurrence inside one concrete blog-post occurrence. The graph still defines the reusable state semantics; the instance nodes identify visible occurrences of those graph nodes.

12. Appendix: Private Extension Payloads

Core extensions remains available for private data that is not intended to participate in interoperable Surface semantics.

json
{
  "@id": "urn:surface:cart",
  "@type": "Surface",
  "graphNodeRef": "urn:state:cart",
  "extensions": {
    "com.acme.audit": {
      "reviewTicket": "ACME-1234"
    }
  }
}
{
  "@id": "urn:surface:cart",
  "@type": "Surface",
  "graphNodeRef": "urn:state:cart",
  "extensions": {
    "com.acme.audit": {
      "reviewTicket": "ACME-1234"
    }
  }
}

Copyright © 2026 the Contributors to the ujg/surface, published by the User Journal Graph Community Group under the W3C Community Contributor License Agreement (CLA) . A human-readable summary is available.

generated by Speculator