Compare commits
No commits in common. "fc063b6b4b98d48633f07153da3f950df44f7865" and "746762e0a8cb121d8efe8e94fc16a65d28a832ff" have entirely different histories.
fc063b6b4b
...
746762e0a8
19 changed files with 48507 additions and 0 deletions
BIN
doc/RF6_XR_Fragments.png
Normal file
BIN
doc/RF6_XR_Fragments.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 31 KiB |
1634
doc/RFC_XR_Fragments.html
Normal file
1634
doc/RFC_XR_Fragments.html
Normal file
File diff suppressed because it is too large
Load diff
999
doc/RFC_XR_Fragments.md
Normal file
999
doc/RFC_XR_Fragments.md
Normal file
|
|
@ -0,0 +1,999 @@
|
|||
%%%
|
||||
Title = "XR Fragments"
|
||||
area = "Internet"
|
||||
workgroup = "Jens & Leon Internet Engineering Task Force"
|
||||
|
||||
[seriesInfo]
|
||||
name = "XR-Fragments"
|
||||
value = "draft-XRFRAGMENTS-leonvankammen-00"
|
||||
stream = "IETF"
|
||||
status = "informational"
|
||||
|
||||
date = 2023-04-12T00:00:00Z
|
||||
|
||||
[[author]]
|
||||
initials="L.R."
|
||||
surname="van Kammen"
|
||||
fullname="L.R. van Kammen"
|
||||
|
||||
%%%
|
||||
|
||||
<!-- for annotated version see: https://raw.githubusercontent.com/ietf-tools/rfcxml-templates-and-schemas/main/draft-rfcxml-general-template-annotated-00.xml -->
|
||||
|
||||
<!--{
|
||||
|
||||
<style type="text/css">
|
||||
body{
|
||||
font-family: monospace;
|
||||
max-width: 1000px;
|
||||
font-size: 15px;
|
||||
padding: 0% 10%;
|
||||
line-height: 30px;
|
||||
color:#555;
|
||||
background:#F7F7F7;
|
||||
}
|
||||
h1 { margin-top:40px; }
|
||||
pre{ line-height:18px; }
|
||||
a,a:visited,a:active{ color: #70f; }
|
||||
code{
|
||||
border: 1px solid #AAA;
|
||||
border-radius: 3px;
|
||||
padding: 0px 5px 2px 5px;
|
||||
}
|
||||
|
||||
pre{
|
||||
line-height: 18px;
|
||||
overflow: auto;
|
||||
padding: 12px;
|
||||
}
|
||||
pre + code {
|
||||
background:#DDD;
|
||||
}
|
||||
pre>code{
|
||||
border:none;
|
||||
border-radius:0px;
|
||||
padding:0;
|
||||
}
|
||||
blockquote{
|
||||
padding-left: 30px;
|
||||
margin: 0;
|
||||
border-left: 5px solid #CCC;
|
||||
}
|
||||
th {
|
||||
border-bottom: 1px solid #000;
|
||||
text-align: left;
|
||||
padding-right:45px;
|
||||
padding-left:7px;
|
||||
background: #DDD;
|
||||
}
|
||||
|
||||
td {
|
||||
border-bottom: 1px solid #CCC;
|
||||
font-size:13px;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<br>
|
||||
<h1>XR Fragments</h1>
|
||||
<br>
|
||||
|
||||
<pre>
|
||||
stream: IETF
|
||||
area: Internet
|
||||
status: informational
|
||||
author: Leon van Kammen
|
||||
date: 2023-04-12T00:00:00Z
|
||||
workgroup: Internet Engineering Task Force
|
||||
value: draft-XRFRAGMENTS-leonvankammen-00
|
||||
</pre>
|
||||
|
||||
|
||||
}-->
|
||||
|
||||
.# Abstract
|
||||
|
||||
> Version: 0.5
|
||||
|
||||
An open specification for hyperlinking & deeplinking 3D fileformats.
|
||||
This draft is a specification for interactive URI-controllable 3D files, enabling [hypermediatic](https://github.com/coderofsalvation/hypermediatic) navigation, to enable a spatial web for hypermedia browsers with- or without a network-connection.<br>
|
||||
XR Fragments allows us to better use implicit metadata inside 3D scene(files), by mapping it to proven technologies like [URI Fragments](https://en.wikipedia.org/wiki/URI_fragment).<br>
|
||||
|
||||
> Almost every idea in this document is demonstrated at [https://xrfragment.org](https://xrfragment.org)
|
||||
|
||||
{mainmatter}
|
||||
|
||||
# Quick reference
|
||||
|
||||
1. [Abstract](#abstract)
|
||||
1. [Index](#index)
|
||||
1. [Introduction](#introduction)
|
||||
1. [How does it work](#how-does-it-work)
|
||||
1. [What does it solve](#what-does-it-solve)
|
||||
1. [HFL (Hypermediatic Feedback Loop) for XR Browsers](#hfl-hypermediatic-feedback-loop-for-xr-browsers)
|
||||
1. [Conventions and Definitions](#conventions-and-definitions)
|
||||
1. [XR Fragment URL Grammar](#xr-fragment-url-grammar)
|
||||
1. [Spatial Referencing 3D](#spatial-referencing-3d)
|
||||
1. [Level0: Files](#level0-files)
|
||||
1. [via href metadata](#via-href-metadata)
|
||||
1. [via chained extension](#via-chained-extension)
|
||||
1. [via subdocuments/xattr](#via-subdocuments-xattr)
|
||||
1. [JSON sidecar-file](#json-sidecar-file)
|
||||
1. [Level1: URI](#level1-uri)
|
||||
1. [List of URI Fragments](#list-of-uri-fragments)
|
||||
1. [List of explicit metadata](#list-of-explicit-metadata)
|
||||
1. [Level2: href links](#level2-href-links)
|
||||
1. [Interaction behaviour](#interaction-behaviour)
|
||||
1. [XR Viewer implementation](#xr-viewer-implementation)
|
||||
1. [Level3: Media Fragments](#level3-media-fragments)
|
||||
1. [Animation(s) timeline](#animation-s-timeline)
|
||||
1. [Specify playback loopmode](#specify-playback-loopmode)
|
||||
1. [Controlling embedded content](#controlling-embedded-content)
|
||||
1. [Level4: prefix operators](#level4-prefix-operators)
|
||||
1. [Object teleports](#object-teleports)
|
||||
1. [Object multipliers](#object-multipliers)
|
||||
1. [De/selectors (+ and -)](#de-selectors-and)
|
||||
1. [Sharing object or file (#|)](#sharing-object-or-file)
|
||||
1. [xrf:// URI scheme](#xrf-uri-scheme)
|
||||
1. [Level5: URI Templates (RFC6570)](#level5-uri-templates-rfc6570)
|
||||
1. [Top-level URL processing](#top-level-url-processing)
|
||||
1. [UX](#ux)
|
||||
1. [Example: Navigating content href portals](#example-navigating-content-href-portals)
|
||||
1. [Walking surfaces](#walking-surfaces)
|
||||
1. [Example: Virtual world rings](#example-virtual-world-rings)
|
||||
1. [Additional scene metadata](#additional-scene-metadata)
|
||||
1. [Accessibility interface](#accessibility-interface)
|
||||
1. [Two-button navigation](#two-button-navigation)
|
||||
1. [Overlap with fileformat-specific extensions](#overlap-with-fileformat-specific-extensions)
|
||||
1. [Vendor Prefixes](#vendor-prefixes)
|
||||
1. [Security Considerations](#security-considerations)
|
||||
1. [FAQ](#faq)
|
||||
1. [Authors](#authors)
|
||||
1. [IANA Considerations](#iana-considerations)
|
||||
1. [Acknowledgments](#acknowledgments)
|
||||
1. [Appendix: Definitions](#appendix-definitions)
|
||||
|
||||
# Introduction
|
||||
(!Introduction)
|
||||
|
||||
How can we add more control to existing text and 3D scenes, without introducing new dataformats?<br>
|
||||
Historically, there's many attempts to create the ultimate 3D fileformat.<br>
|
||||
The lowest common denominator is: designers describing/tagging/naming things using **plain text**.<br>
|
||||
XR Fragments exploits the fact that all 3D models already contain such metadata:
|
||||
|
||||
**XR Fragments allows deeplinking of 3D objects by mapping objectnames to URI fragments**
|
||||
|
||||
# How does it work
|
||||
(!What is XR Fragments )
|
||||
|
||||
XR Fragments utilizes URLs:
|
||||
|
||||
1. for 3D viewers/browser to manipulate the camera or objects (via URI fragments)
|
||||
2. implicitly: by mapping 3D objectnames (of a 3D scene/file) to URI fragments (3D deeplinking)
|
||||
3. explicitly: by scanning `href` metadata **inside** 3D scene-files to enable interactions
|
||||
4. externally: progressively enhance a 3D (file) into an experience via [sidecarfiles](https://en.wikipedia.org/wiki/Sidecar_file)
|
||||
|
||||
# What does it solve
|
||||
|
||||
It solves:
|
||||
|
||||
1. addressibility and [hypermediatic](https://github.com/coderofsalvation/hypermediatic) navigation of 3D scenes/objects: [URI Fragments](https://en.wikipedia.org/wiki/URI_fragment) using src/href spatial metadata
|
||||
1. Interlinking text & spatial objects by collapsing space into a Word Graph (XRWG) to show [visible links](#visible-links)
|
||||
1. unlocking spatial potential of the (originally 2D) hashtag (which jumps to a chapter) for navigating XR documents
|
||||
1. refraining from introducing scripting-engines for mundane tasks (and preventing its inevitable security-headaches)
|
||||
1. the gap between text an 3d objects: object-names directly map to hashtags (=fragments), which allows 3D to text transcription.
|
||||
|
||||
> NOTE: The chapters in this document are ordered from highlevel to lowlevel (technical) as much as possible
|
||||
|
||||
XR Fragments views XR experiences through the lens of 3D deeplinked URI's, rather than thru code(frameworks) or protocol-specific browsers (webbrowser e.g.).
|
||||
To aid adoption, the standard comprises of various (optional) support-levels, which incorporate existing standards like [W3C Media Fragments](https://www.w3.org/TR/media-frags/) and [URI Templates (RFC6570)](https://www.rfc-editor.org/rfc/rfc6570) to promote spatial addressibility, sharing, navigation, filtering and databinding objects for (XR) Browsers.<br>
|
||||
|
||||
> XR Fragments is in a sense, a <b>heuristical 3D format</b> or meta-format, which leverages heuristic rules derived from any 3D scene or well-established 3D file formats, to extract meaningful features from scene hierarchies.<br>
|
||||
These heuristics, enable features that are both meaningful and consistent across different scene representations, allowing <b>higher interop</b> between fileformats, 3D editors, viewers and game-engines.
|
||||
|
||||
# HFL (Hypermediatic Feedback Loop) for XR Browsers
|
||||
(!HFL (Hypermediatic Feedback Loop) for XR Browsers)
|
||||
|
||||
`href` metadata traditionally implies **click** AND **navigate**, however XR Fragments adds stateless **click** (`xrf://....`) via the `xrf://` scheme, which does not change the top-level URL-adress (of the browser).
|
||||
This allows for many extra interactions via URLs, which otherwise needs a scripting language.
|
||||
These are called **hashbus**-only events/
|
||||
|
||||
> Being able to use the same URI Fragment DSL for navigation (`href: #foo`) as well as interactions (`href: xrf://#foo`) greatly simplifies implementation, increases HFL, and reduces need for scripting languages.
|
||||
|
||||
This opens up the following benefits for traditional & future webbrowsers:
|
||||
|
||||
* [hypermediatic](https://github.com/coderofsalvation/hypermediatic) loading/clicking 3D assets (gltf/fbx e.g.) natively (with or without using HTML).
|
||||
* potentially allowing 3D assets/nodes to publish XR Fragments to themselves/eachother using the `xrf://` hashbus (`xrf://#person=walk` to trigger `walk`-animation for object `person`)
|
||||
* potentially collapsing the 3D scene to an wordgraph (for essential navigation purposes) controllable thru a hash(tag)bus
|
||||
* completely bypassing the security-trap of loading external scripts (by loading 3D model-files, not HTML-javascriptable resources)
|
||||
|
||||
|
||||
XR Fragments itself are [hypermediatic](https://github.com/coderofsalvation/hypermediatic) and HTML-agnostic, though pseudo-XR Fragment browsers **can** be implemented on top of HTML/Javascript.
|
||||
|
||||
| principle | 3D URL | HTML 2D URL |
|
||||
|-----------------------------|-------------------------------------------------|---------------------------------------|
|
||||
| the XRWG | wordgraph (collapses 3D scene to tags) | Ctrl-F (find) |
|
||||
| the hashbus | hashtags alter camera/scene/object-projections | hashtags alter document positions |
|
||||
| src metadata | renders content and offers sourceportation | renders content |
|
||||
| href metadata | teleports to other XR document | jumps to other HTML document |
|
||||
| href metadata | triggers predefined view | Media fragments |
|
||||
| href metadata | triggers camera/scene/object/projections | n/a |
|
||||
| href metadata | draws visible connection(s) for XRWG 'tag' | n/a |
|
||||
| href metadata | filters certain (in)visible objects | n/a |
|
||||
| href metadata | href="xrf://#-foo&bar" | href="javascript:hideFooAndShowBar()` |
|
||||
| | (this does not update topLevel URI) | (this is non-standard, non-hypermediatic) |
|
||||
|
||||
> An important aspect of HFL is that URI Fragments can be triggered without updating the top-level URI (default href-behaviour) thru their own 'bus' (`xrf://#.....`). This decoupling between navigation and interaction prevents non-standard things like (`href`:`javascript:dosomething()`).
|
||||
|
||||
# Conventions and Definitions
|
||||
(!Conventions and Definitions)
|
||||
|
||||
See appendix below in case certain terms are not clear.
|
||||
|
||||
## XR Fragment URL Grammar
|
||||
(! XR Fragment URL Grammar )
|
||||
|
||||
For typical HTTP-like browsers/applications:
|
||||
|
||||
```
|
||||
reserved = gen-delims / sub-delims
|
||||
gen-delims = "#" / "&"
|
||||
sub-delims = "," / "="
|
||||
```
|
||||
|
||||
> Example: `://foo.com/my3d.gltf#room1&prio=-5&t=0,100`
|
||||
|
||||
| Demo | Explanation |
|
||||
|-------------------------------|---------------------------------|
|
||||
| `room1` | vector/coordinate argument e.g. |
|
||||
| `room1&cam1` | combinators |
|
||||
|
||||
> this is already implemented in all browsers
|
||||
|
||||
Pseudo (non-native) browser-implementations (supporting XR Fragments using HTML+JS e.g.) can use the `?` search-operator to address outbound content.<br>
|
||||
In other words, the URL updates to: `https://me.com?https://me.com/other.glb` when navigating to `https://me.com/other.glb` from inside a `https://me.com` WebXR experience e.g.<br>
|
||||
That way, if the link gets shared, the XR Fragments implementation at `https://me.com` can load the latter (and still indicates which XR Fragments entrypoint-experience/client was used).
|
||||
|
||||
# Spatial Referencing 3D
|
||||
(!Spatial Referencing 3D )
|
||||
|
||||
3D files contain an hierarchy of objects.<br>
|
||||
XR Fragments assumes the following objectname-to-URI-Fragment mapping, in order to deeplink 3D objects:
|
||||
|
||||
```
|
||||
|
||||
my.io/scene.fbx
|
||||
+─────────────────────────────+
|
||||
│ sky │ src: http://my.io/scene.fbx#sky (includes building,mainobject,floor)
|
||||
│ +─────────────────────────+ │
|
||||
│ │ building │ │ src: http://my.io/scene.fbx#building (includes mainobject,floor)
|
||||
│ │ +─────────────────────+ │ │
|
||||
│ │ │ mainobject │ │ │ src: http://my.io/scene.fbx#mainobject (includes floor)
|
||||
│ │ │ +─────────────────+ │ │ │
|
||||
│ │ │ │ floor │ │ │ │ src: http://my.io/scene.fbx#floor (just floor object)
|
||||
│ │ │ │ │ │ │ │
|
||||
│ │ │ +─────────────────+ │ │ │
|
||||
│ │ +─────────────────────+ │ │
|
||||
│ +─────────────────────────+ │
|
||||
+─────────────────────────────+
|
||||
|
||||
```
|
||||
|
||||
> Every 3D fileformat supports named 3D object, and this name allows URLs (fragments) to reference them (and their children objects).
|
||||
|
||||
Clever nested design of 3D scenes allow great ways for re-using content, and/or previewing scenes.<br>
|
||||
For example, to render a portal with a preview-version of the scene, create an 3D object with:
|
||||
|
||||
* href: `https://scene.fbx`
|
||||
|
||||
> It also allows **sourceportation**, which basically means the enduser can teleport to the original XR Document of an `src` embedded object, and see a visible connection to the particular embedded object. Basically an embedded link becoming an outbound link by activating it.
|
||||
|
||||
# Level0: Files
|
||||
(!Level0: Files )
|
||||
(!Level0: Files)
|
||||
|
||||
Compatible 3D fileformats: [glTF](https://www.khronos.org/gltf/), [usdz](https://openusd.org/release/spec_usdz.html), [obj](https://en.wikipedia.org/wiki/Wavefront_.obj_file), [collada](https://www.khronos.org/collada), [THREE.json](https://github.com/mrdoob/three.js/wiki/JSON-Object-Scene-format-4), [X3D](https://en.wikipedia.org/wiki/X3D) e.g.
|
||||
<br>
|
||||
|
||||
A 3D scene-file can be considered <b>XR Fragment-compatible</b> when it contains metadata:
|
||||
1. implicit: there's at least one object with a name (*)
|
||||
2. explicit: (optional) object(s) have (level2) href extras.
|
||||
|
||||
> \* = last wins in case of non-unique names
|
||||
|
||||
There are **optional** auto-loaded [side-car files]() to enable hasslefree [XR Movies](#XR%20Movies).<br>
|
||||
they can accomodate developers or applications who (for whatever reason) must not modify the 3D scene-file (a `.glb` e.g.).
|
||||
|
||||
## via href metadata
|
||||
|
||||
```
|
||||
scene.glb <--- 'href' extra [heuristic] detected inside!
|
||||
scene.png (preview thumbnail)
|
||||
scene.ogg (soundtrack to plays when global 3D animation starts)
|
||||
scene.vtt (subtitles for accessibility or screenreaders)
|
||||
scene.json (sidecar JSON-file with explicit metadata)
|
||||
```
|
||||
|
||||
**heuristics**:
|
||||
|
||||
* if at least one `href` custom property/extra is found in a 3D scene
|
||||
* The viewer should poll for the above mentioned sidecar-file extensions (and present accordingly)
|
||||
|
||||
## via chained extension
|
||||
|
||||
```
|
||||
scene.xrf.glb <--- '.xrf.' sidecar file heuristic detected!
|
||||
scene.xrf.png (preview thumbnail)
|
||||
scene.xrf.ogg (soundtrack to plays when global 3D animation starts)
|
||||
scene.xrf.vtt (subtitles for accessibility or screenreaders)
|
||||
scene.xrf.json (sidecar JSON-file with explicit metadata)
|
||||
```
|
||||
|
||||
> A fallback-mechanism to turn 3D files into [XR Movies](#XR%20Movies) without editing them.
|
||||
|
||||
**heuristics**:
|
||||
|
||||
* the chained-extension heuristic `.xrf.` should be present in the filename (`scene.xrf.glb` e.g.)
|
||||
|
||||
## via subdocuments/xattr
|
||||
|
||||
More secure protocols (Nextgraph e.g.) don't allow for simply polling files.
|
||||
In such case, subdocuments or extended attributes should be polled:
|
||||
|
||||
> NOTE: in the examples below we use the href-heuristic, but also the `.xrf.` chained-extension applies here.
|
||||
|
||||
```
|
||||
myspreadsheet.ods
|
||||
└── explainer.glb <--- 'href' extra [heuristic] detected inside!
|
||||
├── explainer.ogg (soundtrack to play when global 3D animation starts)
|
||||
├── explainer.png (preview thumnbnail)
|
||||
├── explainer.json (sidecar JSON-file with explicit metadata)
|
||||
└── explainer.vtt (subtitles for accessibility or screenreaders)
|
||||
```
|
||||
|
||||
If only extended attributes (xattr) are available, the respective referenced file can be embedded:
|
||||
|
||||
```
|
||||
$ setfattr -n explainer.ogg -v "soundtrack.ogg" explainer.glb
|
||||
$ setfattr -n explainer.png -v "thumbnail.png" explainer.glb
|
||||
$ setfattr -n explainer.vtt -v "subtitles.vtt" explainer.glb
|
||||
```
|
||||
|
||||
> NOTE: Linux's `setfattr/getfattr` is `xattr` on mac, and `Set-Content/Get-content` on Windows. See [pxattr](https://www.lesbonscomptes.com/pxattr/index.html) for lowlevel access.
|
||||
|
||||
## JSON sidecar-file
|
||||
|
||||
For developers, sidecar-file can allow for defining **explicit** XR Fragments links (>level1), outside of the 3D file.<br>
|
||||
This can be done via (objectname/metadata) key/value-pairs in a JSON [sidecar-file](https://en.wikipedia.org/wiki/Sidecar_file):
|
||||
|
||||
* experience.glb
|
||||
* experience.json `<----`
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"aria-description": "description of scene",
|
||||
"button": {
|
||||
"href": "#roomB",
|
||||
"aria-description": "description of room"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> This will make object `button` clickable, and teleport the user to object `roomB`.
|
||||
|
||||
So after loading `experience.glb` the existence of `experience.json` is detected, to apply the explicit metadata.<br>
|
||||
The sidecar will define (or **override** already existing) extras, which can be handy for multi-user platforms (offer 3D scene customization/personalization to users).
|
||||
|
||||
> In THREE.js-code this would boil down to:
|
||||
|
||||
```javascript
|
||||
scene.userData['aria-description'] = "description of scene"
|
||||
scene.getObjectByName("button").userData.href = "#roomB"
|
||||
|
||||
// now the XR Fragments parser can process the XR Fragments userData 'extras' in the scene
|
||||
```
|
||||
|
||||
# Level1: URI
|
||||
(!Level1: URI)
|
||||
|
||||
> **XR Fragments allows deeplinking of 3D objects by mapping objectnames to URI fragments**
|
||||
|
||||
XR Fragments tries to seek to connect the world of text (semantical web / RDF), and the world of pixels.<br>
|
||||
Instead of forcing authors to combine 3D/2D objects programmatically (publishing thru a game-editor e.g.), XR Fragments **integrates all** which allows a universal viewing experience.<br>
|
||||
|
||||
```
|
||||
+───────────────────────────────────────────────────────────────────────────────────────────────+
|
||||
│ │
|
||||
│ U R N │
|
||||
│ U R L | │
|
||||
│ | |-----------------+--------| │
|
||||
│ +--------------------------------------------------| │
|
||||
│ | │
|
||||
│ + https://foo.com/some/foo/scene.glb#someview <-- http URI (=URL and has URN) │
|
||||
│ | │
|
||||
│ + ipfs://cfe0987ec9r9098ecr/cats.fbx#someview <-- an IPFS URI (=URL and has URN) │
|
||||
│ │
|
||||
│ ec09f7e9cf8e7f09c8e7f98e79c09ef89e000efece8f7ecfe9fe <-- an interpeer URI │
|
||||
│ │
|
||||
│ │
|
||||
│ |------------------------+-------------------------| │
|
||||
│ | │
|
||||
│ U R I │
|
||||
│ │
|
||||
+───────────────────────────────────────────────────────────────────────────────────────────────+
|
||||
|
||||
```
|
||||
|
||||
Fact: our typical browser URL's are just **a possible implementation** of URI's (for untapped humancentric potential of URI's [see interpeer.io](https://interpeer.io) or [NextGraph](https://nextgraph.org) )
|
||||
|
||||
> XR Fragments does not look at XR (or the web) thru the lens of HTML or URLs.<br>But approaches things from a higherlevel local-first 3D hypermedia browser-perspective.
|
||||
|
||||
Below you can see how this translates back into good-old URLs:
|
||||
|
||||
```
|
||||
+───────────────────────────────────────────────────────────────────────────────────────────────+
|
||||
│ │
|
||||
│ the soul of any URL: ://macro /meso ?micro #nano │
|
||||
│ │
|
||||
│ 2D URL: ://library.com /document ?search #chapter │
|
||||
│ xrf:// │
|
||||
│ 4D URL: ://park.com /4Dscene.fbx ─> ?other.glb ─> #object ─> hashbus │
|
||||
│ │ #filter │ │
|
||||
│ │ #tag │ │
|
||||
│ │ (hypermediatic) #material │ │
|
||||
│ │ ( feedback ) #animation │ │
|
||||
│ │ ( loop ) #texture │ │
|
||||
│ │ #variable │ │
|
||||
│ │ │ │
|
||||
│ XRWG <─────────────────────<─────────────+ │
|
||||
│ │ │ │
|
||||
│ └─ objects ──────────────>─────────────+ │
|
||||
│ │
|
||||
│ │
|
||||
+───────────────────────────────────────────────────────────────────────────────────────────────+
|
||||
|
||||
```
|
||||
|
||||
> ?-linked and #-linked navigation are JUST one possible way to implement XR Fragments: the essential goal is to allow a Hypermediatic FeedbackLoop (HFL) between external and internal 4D navigation.
|
||||
|
||||
## List of URI Fragments
|
||||
|
||||
| fragment | type | example | info |
|
||||
|-------------------|------------|--------------------|----------------------------------------------------------------------|
|
||||
| `#......` | vector3 | `#room1` `#room2` `#cam2` | positions/parents camera(rig) (or XR floor) to xyz-coord/object/camera and upvector |
|
||||
| [Media Fragments](https://www.w3.org/TR/media-frags/) | [media fragment](#media%20fragments%20and%20datatypes) | `#t=0,2&loop` | play (and loop) 3D animation from 0 seconds till 2 seconds|
|
||||
|
||||
|
||||
## List of **explicit* metadata
|
||||
|
||||
These are the possible 'extras' for 3D nodes and sidecar-files
|
||||
|
||||
| key | type | example (JSON) | function | existing compatibility |
|
||||
|--------------|----------|------------------------|---------------------|----------------------------------------|
|
||||
| `href` | string | `"href": "b.gltf"` | XR teleport | custom property in 3D fileformats |
|
||||
|
||||
|
||||
# Level2: href links
|
||||
(!Level2: href links)
|
||||
|
||||
Explicit href metadata ('extras') in a 3D object (of a 3D file), hint the viewer that the user ''can interact'' with that object :
|
||||
|
||||
| fragment | type | example value |
|
||||
|`href`| string (uri or predefined view) | `#pyramid`<br>`#lastvisit`<br>`xrf://#-someobject`<br>`://somefile.gltf#foo`<br> |
|
||||
|
||||
## Interaction behaviour
|
||||
|
||||
When clicking an ''href''-value, the user(camera) is teleport to the referenced object.
|
||||
|
||||
The imported/teleported destination can be another object in the same scene-file, or a different file.
|
||||
|
||||
## XR Viewer implementation
|
||||
|
||||
| **spec** | **action** | **feature** |
|
||||
|-|-|-|
|
||||
| level0+1 | hover 3D file [href](#via-href-metadata) | show the preview PNG thumbnail (if any). |
|
||||
| level0+1 | launch 3D file [href](#via-href-metadata) | replace the current scene with a new 3D file (`href: other.glb` e.g.) |
|
||||
| level2 | click internal 3D file [href](#via-href-metadata) (`#roomB` e.g.) | teleport the camera to the origin of object(name `roomB`). See [[teleport camera]].|
|
||||
| level2 | click external 3D file [href](#via-href-metadata) (`foo.glb` e.g.) | replace the current scene with a new 3D file (`href: other.glb` e.g.) |
|
||||
| level2 | hover external 3D file [href](#via-href-metadata) | show the preview PNG thumbnail (if any sidecar, see level0) |
|
||||
| level2 | click [href](#via-href-metadata) | hashbus: execute without changing the toplevel URL location (`href: xrf://#someObjectName` e.g.) |
|
||||
| level3 | click [href](#via-href-metadata) | set the global 3D animation timeline to its Media Fragment value (`#t=2,3` e.g.) |
|
||||
|
||||
> NOTE: hashbus links (`xrf://#foo&bar`) don't change the toplevel URL, which makes it ideal for interactions (in contrast to typical `#roomC` navigation, which benefit back/forward browser-buttons), see <a href="#hashbus">hashbus</a> for more info.
|
||||
|
||||
# Level3: Media Fragments
|
||||
(!Level3: Media Fragments )
|
||||
|
||||
> these allow for XR Movies with a controllable timeline using `href` URI's with Media Fragments
|
||||
|
||||
Just like with 2D media-files, W3C mediafragments (`#t=1,2`) can be used to control a timeline via the [#t](##t) primitive.
|
||||
XR Fragments Level3 makes the 3D timeline, as well as URL-referenced files **controllable** via Media Fragments like:
|
||||
|
||||
* level2 hrefs (`href: #t=4` e.g. to control 3D timeline)
|
||||
* level4: `xrf:` URI scheme:
|
||||
* `href: xrf:foo.wav#t=0` to play a wav
|
||||
* `href: xrf:news.glb?clone#t=0` to instance and play another experience
|
||||
|
||||
## Animation(s) timeline
|
||||
|
||||
controls the animation(s) of the scene (or `src` resource which contains a timeline)
|
||||
|
||||
| fragment | type | functionality |
|
||||
| <b>#t</b>=start,stop | [[vector2]] (default:`#t=0`) | start,stop (in seconds |
|
||||
|
||||
|
||||
| Example Value | Explanation |
|
||||
| `#t=1` | play (3D) animations from 1 seconds till end (and stop) |
|
||||
| `#t=1,100` | play (3D) animations from 1 till 100 seconds (and stop) |
|
||||
|
||||
## Specify playback loopmode
|
||||
|
||||
This compensates a missing element from Media Fragments to enable/disable temporal looping. .
|
||||
|
||||
| fragment | type | functionality |
|
||||
| <b>#loop</b> | string | enables animation/video/audio loop |
|
||||
| <b>#-loop</b> | string | disables animation/video/audio loop |
|
||||
|
||||
|
||||
## Controlling embedded content
|
||||
|
||||
use [[URI Templates]] to control embedded media, for example a simple video-player:
|
||||
|
||||
```
|
||||
foo.usdz
|
||||
│
|
||||
├── ◻ loopbutton_enable
|
||||
│ └ href: #loop <-- enable global loop
|
||||
│
|
||||
├── ◻ loopbutton_enable
|
||||
│ └ href: #-loop <-- disable global loop
|
||||
│
|
||||
├── ◻ playbutton
|
||||
│ └ href: #t=10&loop <-- play global 3D timeline (all anims) (looped)
|
||||
│
|
||||
└── ◻ playbutton_external
|
||||
└ href: https://my.org/animation.glb#!&t=3,10 <-- import & play external anim
|
||||
|
||||
```
|
||||
|
||||
# Level4: prefix operators
|
||||
(!Level4: prefix operators)
|
||||
|
||||
Prefixing objectnames with the following simple operators allow for **extremely powerful** XR interactions:
|
||||
|
||||
* #!
|
||||
* #*
|
||||
* #+ or #-
|
||||
* #|
|
||||
* xrf: URI scheme
|
||||
|
||||
> **Examples:** `#+menu` to show a object, `#-menu` to hide a menu, `#!menu` to teleport a menu, `#*block` to clone a grabbable block, `#|object` to share an object
|
||||
|
||||
|
||||
## Object teleports (!)
|
||||
|
||||
Prefixing an object with an exclamation-symbol, will teleport a (local or remote) referenced object from/to its original/usercamera location.<br>
|
||||
|
||||
[img[objecteleport.png]]
|
||||
|
||||
Usecases:
|
||||
* show/hide objects/buttons (menu e.g.) in front of user
|
||||
* embed remote (object within) 3D file via remote URL
|
||||
* instance an interactive object near the user regardless of location
|
||||
* instance HUD or semi-transparent-textured-sphere (LUT) around the user
|
||||
|
||||
<div class="border padding" style="border:4px solid #888">
|
||||
<span class="big hi1">#!menu</span>
|
||||
</div>
|
||||
<br>
|
||||
|
||||
Clicking the [href](#via-href-metadata)-value above will:
|
||||
|
||||
1. **reposition the referenced object** (menu) to the usercamera's-coordinates.
|
||||
2. **zoom** in case of (non-empty) mesh-object: rescale to 1 m³, and position 1m in front of the camera
|
||||
3. toggle behaviour: revert values if 1/2 were already applied
|
||||
4. `#+` is always implied (objects are always made visible)
|
||||
|
||||
This tiny but powerful symbol allows incredible interactive possibilities, by carefully positioning re-usable objects outside of a scene (below the usercamera's floor e.g.).
|
||||
|
||||
* href: `#whiteroom&!explainer&!exitmenu`
|
||||
|
||||
> This will teleport the user to `whiteroom` and moves object `explainer` and `exitmenu` in front of the user.
|
||||
|
||||
* href: `https://my.org/foo.glb#!
|
||||
|
||||
Clicking the [href](#via-href-metadata)-value above will:
|
||||
|
||||
1. import `foo.glb` from `my.org`'s webserver
|
||||
2. show it in front of the user (because `#!` indicates object teleport)
|
||||
|
||||
* href: `https://foo.glb#roomB&!bar`
|
||||
|
||||
Clicking the [href](#via-href-metadata)-value above will:
|
||||
|
||||
1. replace the current scene with `foo.glb`
|
||||
2. teleport the user to #roomB inside `foo.glb`
|
||||
3. **instance the referenced object** (bar inside foo.glb) in front of the user.
|
||||
4. it will update the top-Level URL (because `xrf:` was not used)
|
||||
5. hide the **instanced object** when clicked again (toggle visibility)
|
||||
|
||||
> **NOTE**: level2 teleportation links, as well as instancing mitigates the 'broken embedded image'-issue of HTML: **always** attaching the href-values to **a 3D (preview) object** (that way broken links will not break the design).
|
||||
|
||||
**Example:** clicking a 3D button with title 'menu' and [href](#href)-value `xrf:menu.glb?instance#t=4,5` would instance a 3D menu (`menu.glb`) in front of the user, and loop its animation between from 4-5 seconds (`t=4,5`)
|
||||
|
||||
> **NOTE**: combining instance-operators allows dynamic construction of 3D scenes (`#london&!welcomeMenu&!fadeBox` e.g.)
|
||||
|
||||
## Object multipliers (*)
|
||||
|
||||
The star-prefix will clone a (local or remote) referenced object to the usercamera's location, and make it grabbable.<br>
|
||||
Usecases:
|
||||
* object-picker (build stuff with objects)
|
||||
|
||||
> **NOTE**: this is basically the [#! operator](#%23%21) which infinitely **clones** the referenced object (instead of repositioning the object).
|
||||
|
||||
## De/selectors (+ and -)
|
||||
|
||||
* href: `#-welcome` (or `#+welcome`)
|
||||
|
||||
Clicking href-value above will do:
|
||||
|
||||
1. show/hide the target object (and children)
|
||||
|
||||
* href: `#https://my.org/foo.glb/#bar&-welcome`
|
||||
|
||||
> **NOTE:** the latter shows that (de)selectors can also be with regular [href](#href)-values
|
||||
|
||||
## Sharing object or file (#|)
|
||||
|
||||
The pipe-symbol (`|`) sends a (targeted) object to the OS.
|
||||
Clicking the href-value below will:
|
||||
|
||||
1. share the (targeted object in the) file to a another application
|
||||
|
||||
> This URL can be fed straight into [Web Share API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Share_API) or [xdg-open](https://www.freedesktop.org/wiki/Software/xdg-utils/)
|
||||
|
||||
* href: `xrf://#|bar`
|
||||
|
||||
> **NOTE**: sharing is limited to (internal objects) via `xrf:` scheme-only
|
||||
|
||||
## xrf:// URI scheme
|
||||
|
||||
Prefixing the `xrf:` to [href](#href)-values **will prevent** [level2](#📜%20level2:%20explicit%20links) [href](#href)-values from changing the top-Level URL.
|
||||
|
||||
> **Usecase**: for non-shareable URLs like `href: xrf:#t=4,5`, to display a stateful msg e.g.).
|
||||
|
||||
**Reason:** XR Fragments is inspired by HTML's [href-attribute](https://en.wikipedia.org/wiki/Hyperlink), which does various things:
|
||||
|
||||
1. it updates the browser-location
|
||||
2. it makes something clickable
|
||||
3. it jumps to another document / elsewhere in the same document
|
||||
4. and more
|
||||
|
||||
The `xrf:` scheme will just do 2 & 3 (so the URL-values will not leak into the top-level URL).
|
||||
|
||||
> **compliance with RFC 3986**: unimplemented/unknown URI schemes (`xrf:...` e.g.) will not update the top-level URL
|
||||
|
||||
# Level5: URI Templates (RFC6570)
|
||||
(!Level5: URI Templates (RFC6570))
|
||||
|
||||
XR Fragments adopts Level1 URI **Fragment** expansion to provide safe interactivity.<br>
|
||||
This is non-normative, and the draft spec is available on request.
|
||||
|
||||
|
||||
# Top-level URL processing
|
||||
(!Top-level URL processing)
|
||||
|
||||
> Example URL: `://foo/world.gltf#room1&t=10&cam`
|
||||
|
||||
The URL-processing-flow for hypermedia browsers goes like this:
|
||||
|
||||
1. IF scene operators and/or animation operator (`t`) are present in the URL then (re)position the camera (to `room1`) and/or animation-range (`10`) accordingly.
|
||||
2. IF no camera-position has been set in <b>step 1 or 2</b> assume `0,0,0` as camera coordinate (XR: add user-height) ([example](https://github.com/coderofsalvation/xrfragment/blob/main/src/3rd/js/three/navigator.js#L31]]))
|
||||
3. IF a camera-object exists with name `cam` assume that user(camera) position
|
||||
|
||||
## UX
|
||||
|
||||
End-users should always have read/write access to:
|
||||
|
||||
1. the current (toplevel) <b>URL</b> (an URLbar etc)
|
||||
2. URL-history (a <b>back/forward</b> button e.g.)
|
||||
3. Clicking/Touching an `href` navigates (and updates the URL) to another scene/file (and coordinate e.g. in case the URL contains XR Fragments).
|
||||
|
||||
|
||||
# Example: Navigating content href portals
|
||||
(!Example: Navigating content href portals)
|
||||
|
||||
navigation, portals & mutations
|
||||
|
||||
| fragment | type | example value |
|
||||
|----------|---------------------------------|---------------------------------------------------------------------------------------------------------------------------|
|
||||
|`href` | string (uri or predefined view) | `#room1`<br>`#room1`<br>`://somefile.gltf#room1`<br> |
|
||||
|
||||
1. clicking an outbound ''external''- or ''file URI'' fully replaces the current scene and assumes `room2` by default (unless specified)
|
||||
|
||||
2. relocation/reorientation should happen locally for local URI's (`#....`)
|
||||
|
||||
3. navigation should not happen ''immediately'' when user is more than 5 meter away from the portal/object containing the href (to prevent accidental navigation e.g.)
|
||||
|
||||
4. URL navigation should always be reflected in the client URL-bar (in case of javascript: see [[here](https://github.com/coderofsalvation/xrfragment/blob/dev/src/3rd/js/three/navigator.js) for an example navigator), and only update the URL-bar after the scene (default fragment `#`) has been loaded.
|
||||
|
||||
5. In immersive XR mode, the navigator back/forward-buttons should be always visible (using a wearable e.g., see [[here](https://github.com/coderofsalvation/xrfragment/blob/dev/example/aframe/sandbox/index.html#L26-L29) for an example wearable)
|
||||
|
||||
6. make sure that the ''back-button'' of the ''browser-history'' always refers to the previous position (see [[here](https://github.com/coderofsalvation/xrfragment/blob/main/src/3rd/js/three/xrf/href.js#L97))
|
||||
|
||||
7. ignore previous rule in special cases, like clicking an `href` using camera-portal collision (the back-button could cause a teleport-loop if the previous position is too close)
|
||||
|
||||
8. href-events should bubble upward the node-tree (from children to ancestors, so that ancestors can also conain an href), however only 1 href can be executed at the same time.
|
||||
|
||||
9. the end-user navigator back/forward buttons should repeat a back/forward action until a `#...` primitive is found (the stateless xrf:// href-values should not be pushed to the url-history)
|
||||
|
||||
[» example implementation](https://github.com/coderofsalvation/xrfragment/blob/main/src/3rd/js/three/xrf/href.js)<br>
|
||||
[» example 3D asset](https://github.com/coderofsalvation/xrfragment/blob/main/example/assets/href.gltf#L192)<br>
|
||||
[» discussion](https://github.com/coderofsalvation/xrfragment/issues/1)<br>
|
||||
|
||||
## Walking surfaces
|
||||
|
||||
> By default position `0,0,0` of the 3D scene represents the walkable plane, however this is overridden when the following applies:
|
||||
|
||||
XR Fragment-compatible viewers can infer this data based scanning the scene for:
|
||||
|
||||
1. materialless (nameless & textureless) mesh-objects (without `href` and >0 faces)
|
||||
|
||||
> optionally the viewer can offer thumbstick, mouse or joystick teleport-tools for non-roomscale VR/AR setups.
|
||||
|
||||
# Example: Virtual world rings
|
||||
(!Example: Virtual world rings )
|
||||
|
||||
Consider 3D scenes linking to eachother using these `href` values, attached to 3D button-objects:
|
||||
|
||||
* `href: schoolA.edu/projects.gltf#math`
|
||||
* `href: schoolB.edu/projects.gltf#math`
|
||||
* `href: university.edu/projects.gltf#math`
|
||||
|
||||
This would teleport users to the math-projects of those universities.<br>
|
||||
Now consider adding a 'webring index'-button to each file, with this href-value:
|
||||
|
||||
|
||||
* href: workgroup.edu/webrings.glb#!webringmenu
|
||||
|
||||
This would allow displaying the (remote 3D file) webring menu with various href-buttons inside, all centrally curated by the workgroup.
|
||||
|
||||
# Additional scene metadata
|
||||
(!Additional scene metadata )
|
||||
|
||||
XR Fragments does not aim to redefine the metadata-space or accessibility-space by introducing its own cataloging-metadata fields.
|
||||
Instead, it encourages browsers to scan nodes for the following custom properties:
|
||||
|
||||
* [SPDX](https://spdx.dev/) license information
|
||||
* [ARIA](https://www.w3.org/WAI/standards-guidelines/aria/) attributes (`aria-*: .....`)
|
||||
* [datapackage.json](https://datapackage.org) findability, accessibility, interoperability, and reusability of data
|
||||
|
||||
ARIA's `aria-description`-metadata is normative, to aid accessibility and scene transcripts
|
||||
|
||||
> **NOTE**: please always start `aria-description` with a verb to aid transcripts.
|
||||
|
||||
The following metadata are non-normative but encouraged, since they are popular and cheap to parse:
|
||||
|
||||
* [RDF/JSON-LD](https://json-ld.org) like [this example](https://mvmd.org/standards/gltf/) or via glTF's [KHR_xmp_json_ld extension](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_xmp_json_ld)
|
||||
* [Open Graph](https://ogp.me) attributes (`og:*: .....`)
|
||||
* [Dublin-Core](https://www.dublincore.org/specifications/dublin-core/application-profile-guidelines/) attributes(`dc:*: .....`)
|
||||
* [BibTex](https://bibtex.eu/fields) when known bibtex-keys exist with values enclosed in `{` and `},`
|
||||
|
||||
|
||||
> Example: object 'tryceratops' with `aria-description: is a huge dinosaurus standing on a #mountain` generates transcript `#tryceratops is a huge dinosaurus standing on a #mountain`, where the hashtags are clickable XR Fragments (activating the visible-links in the XR browser).
|
||||
|
||||
Individual nodes can be enriched with such metadata, but most importantly the scene node:
|
||||
|
||||
| metadata key | example value |
|
||||
|--------------------------------------------------------|-------------------------------------------------|
|
||||
| `aria-description`, `og:description`, `dc:description` | `An immersive experience about Triceratops` (*) |
|
||||
| `SPDX` | `CC0-1.0` |
|
||||
| `dc:creator` | `John Doe` |
|
||||
| `dc:title`, `og:title` | 'Triceratops` (*) |
|
||||
| `og:site_name` | `https://xrfragment.org` |
|
||||
| `dc.publisher` | `NLNET` |
|
||||
| `dc.date` | `2024-01-01` |
|
||||
| `dc.identifier` | `XRFRAGMENT-001` |
|
||||
| `journal` (bibTeX) | `{Future Of Text Vol 3},` |
|
||||
|
||||
> \* = these are interchangable (only one needs to be defined)
|
||||
|
||||
There's no silver bullet when it comes to metadata, so XR Fragment-implementations should support where the metadata is/goes.
|
||||
|
||||
> These attributes can be scanned and presented during an `href` or `src` eye/mouse-over.
|
||||
|
||||
# Accessibility interface
|
||||
(!Accessibility interface)
|
||||
|
||||
The addressibility of XR Fragments allows for unique 3D-to-text transcripts, as well as an textual interface to navigate 3D content.<br>
|
||||
Spec:<br><Br>
|
||||
|
||||
1. The enduser must be able to enable an accessibility-mode (which persists across application/webpage restarts)
|
||||
2. Accessibility-mode must contain a text-input for the user to enter text
|
||||
3. Accessibility-mode must contain a flexible textlog for the user to read (via screenreader, screen, or TTS e.g.)
|
||||
4. the textlog contains `aria-descriptions`, and its narration (Screenreader e.g.) can be skipped (via 2-button navigation)
|
||||
5. The `back` command should navigate back to the previous URL (alias for browser-backbutton)
|
||||
6. The `forward` command should navigate back to the next URL (alias for browser-nextbutton)
|
||||
7. A destination is a 3D node containing an `href` with a `#...` XR fragment (which matches a 3d object name)
|
||||
8. The `go` command should list all possible destinations
|
||||
9. The `go left` command should move the camera around 0.3 meters to the left
|
||||
10. The `go right` command should move the camera around 0.3 meters to the right
|
||||
11. The `go forward` command should move the camera 0.3 meters forward (direction of current rotation).
|
||||
12. The `rotate left` command should rotate the camera 0.3 to the left
|
||||
13. The `rotate left` command should rotate the camera 0.3 to the right
|
||||
14. The (dynamic) `go abc` command should navigate to `#scene2` in case there's a 3D node with name `abc` and `href` value `#scene2`
|
||||
15. The `look` command should give an (contextual) 3D-to-text transcript, by scanning the `aria-description` values of the current `#...` (3D object) value (including its children)
|
||||
16. The `do` command should list all possible `href` values which don't contain an `#...` XR Fragment
|
||||
17. The (dynamic) `do abc` command should navigate/execute `https://.../...` in case a 3D node exist with name `abc` and `href` value `https://.../...`
|
||||
|
||||
## Two-button navigation
|
||||
|
||||
For specific user-profiles, gyroscope/mouse/keyboard/audio/visuals will not be available.<br>
|
||||
Therefore a 2-button navigation-interface is the bare minimum interface:
|
||||
|
||||
1. objects with href metadata can be cycled via a key (tab on a keyboard)
|
||||
2. objects with href metadata can be activated via a key (enter on a keyboard)
|
||||
3. the TTS reads the href-value (and/or aria-description if available)
|
||||
|
||||
## Overlap with fileformat-specific extensions
|
||||
|
||||
Some 3D scene-fileformats have support for extensions.
|
||||
What if the functionality of those overlap?
|
||||
For example, GLTF has the `OMI_LINK` extension which might overlap with XR Fragment's `href`:
|
||||
|
||||
> Priority Order and Precedence, otherwise fallback applies
|
||||
|
||||
1.**Extensions Take Precedence**: Since glTF-specific extensions are designed with the format’s
|
||||
specific needs and optimizations in mind, they should take precedence over extras metadata
|
||||
in cases where both contain overlapping functionality.
|
||||
This approach aligns with the idea that extensions are more likely to be interpreted uniformly by glTF-compatible software.
|
||||
|
||||
2. **Fallback Fall-through Mechanism**:
|
||||
If a glTF implementation does not support a particular extension, the (XRF) extras field can serve as a fallback. This way, metadata provided in extras can still be useful for applications that don't handle certain extensions.
|
||||
|
||||
> **Example 1** In case of the OMI_LINK glTF extension (`href: https://nlnet.nl`) and an XR Fragment (`href: #otherroom` or `href: otherplanet.glb`), it is clear that `https://nlnet.nl` should open in a browsertab, whereas the XR Fragment links should teleport the user. If the OMI_LINK contains an XR Fragment (`#room1` e.g.) a teleport should be performed only (and other [overlapping] metadata should be ignored).
|
||||
|
||||
> **Example 2** If an Extensions uses XR Fragments in URI's (`href: #otherroom` or `href: xrf://-walls` in OMI_LINK e.g.), then perform them according to XR Fragment spec (teleport user). But only once: ignore further overlapping metadata for that usecase.
|
||||
|
||||
# Vendor Prefixes
|
||||
(!Vendor Prefixes )
|
||||
|
||||
Vendor-specific metadata in a 3D scenefiles, are similar to vendor-specific [CSS-prefixes](https://en.wikipedia.org/wiki/CSS#Vendor_prefixes) (`-moz-opacity: 0.2` e.g.).
|
||||
This allows popular 3D engines/frameworks, to initialize specific features when loading a scene/object, in a progressive enhanced way.
|
||||
|
||||
Vendor Prefixes allows embedding 3D engines/framework-specific features a 3D file via metadata:
|
||||
|
||||
| what | XR metadata | Lowest common denominator |
|
||||
|------------------|---------------------|-------------------------------------------------------|
|
||||
| CSS | vendor-agnostic | 2D canvas + object referencing/styling |
|
||||
| XR Fragments | vendor-agnostic | 3D camera + object(file) load/embed/click/referencing |
|
||||
| Vendor prefixs | vendor-**specific** | Specialized Entity-Component implementation |
|
||||
|
||||
> Why? Because not all XR interactions can/should be solved/standardized by embedding XR Fragments into any 3D file.
|
||||
The lowest common denominator between 3D engines is the 'entity'-part of their entity-component-system (ECS). The 'component'-part can be progressively enhanced via vendor prefixes.
|
||||
|
||||
For example, the following metadata can be added to a .glb file, to make an object grabbable in AFRAME:
|
||||
|
||||
```
|
||||
+────────────────────────────────────────────────────────────────────────────────────────────────────────+
|
||||
│ http://y.io/z.glb | AFRAME app │
|
||||
│-----------------------------------------------+--------------------------------------------------------│
|
||||
│ | │
|
||||
│ | after loading the glb, john can be placed into the │
|
||||
│ +-[3D mesh]-+ | castle via hands, because the author added metadata to │
|
||||
│ | / \ | | john via either: │
|
||||
│ | / \ | | │
|
||||
│ | / \ | | 1. Blender (custom property-box, no plugins needed) │
|
||||
│ | |_____| | | │
|
||||
│ +-----│-----+ | 2. javascript-code: │
|
||||
│ │ | │
|
||||
│ ├─ name: castle | for( var com in this.el.components ){ │
|
||||
│ └─ tag: house baroque | this.el.object3D.userData[`-AFRAME-${com}`] = '' │
|
||||
│ | } │
|
||||
│ [3D mesh-+ | // save to z.glb in AFRAME inspector │
|
||||
│ | ├─ name: john | │
|
||||
│ | O ├─ age: 23 | │
|
||||
│ | /|\ ├─ -aframe-grabbable: '' | > inits 'grabbable' component on object john │
|
||||
│ | / \ ├─ -aframe-material.color: '#F0A' | > inits 'material' component on object john │
|
||||
│ | ├─ -aframe-text.value: '{name}{age}'| > inits 'text' component (*) with value 'john' │
|
||||
│ | ├─ -three-material.fog: false | > changes material settings in THREE.js app │
|
||||
│ | ├─ -godot-Label3D.text: '{name}{age}'| > inits 'Label3D' component (*) in Godot │
|
||||
│ +--------+ | │
|
||||
│ | │
|
||||
├─ -GODOT-version: '4.3' | > exporters/authors can report targeted version │
|
||||
├─ -AFRAME-version: '1.6.0' | and (optionally) hint component-repo│
|
||||
├─ -AFRAME-info: 'https://git.benetou.fr/comps' │
|
||||
│ | │
|
||||
+────────────────────────────────────────────────────────────────────────────────────────────────────────+
|
||||
```
|
||||
|
||||
* key/value syntax: -`<vendorname>`-`<component|version>`.`<key>` `[string/boolean/float/int]`-value
|
||||
|
||||
String-templatevalues are evaluated as per [URI Templates (RFC6570)](https://www.rfc-editor.org/rfc/rfc6570) Level 1.
|
||||
|
||||
> This 'separating of mechanism from policy' (unix rule) does **somewhat** break portability of an XR experience, but still prevents (E-waste of) handcoded virtual worlds. It allows for (XR experience) metadata to survive in future 3D engines and scene-fileformats.
|
||||
|
||||
|
||||
# Security Considerations
|
||||
(!Security Considerations)
|
||||
|
||||
The only dynamic parts are [W3C Media Fragments](https://www.w3.org/TR/media-frags/) and [URI Templates (RFC6570)](https://www.rfc-editor.org/rfc/rfc6570).<br>
|
||||
The use of URI Templates is limited to pre-defined variables and Level0 fragments-expansion only, which makes it quite safe.<br>
|
||||
n fact, it is much safer than relying on a scripting language (javascript) which can change URN too.
|
||||
|
||||
# FAQ
|
||||
(!FAQ )
|
||||
|
||||
**Q:** Why is everything HTTP GET-based, what about POST/PUT/DELETE HATEOS<br>
|
||||
**A:** Because it's out of scope: XR Fragment specifies a read-only way to surf XR documents. These things belong in the application layer (for example, an XR Hypermedia browser can decide to support POST/PUT/DELETE requests for embedded HTML thru `src` values)
|
||||
|
||||
---
|
||||
|
||||
**Q:** Why isn't there support for scripting, URI Template Fragments are so limited compared to WASM & javascript
|
||||
**A:** This is out of scope as it unhyperifies hypermedia, and this is up to XR hypermedia browser-extensions.<br> Historically scripting/Javascript seems to been able to turn webpages from hypermedia documents into its opposite (hyperscripted nonhypermedia documents).<br>In order to prevent this backward-movement (hypermedia tends to liberate people from finnicky scripting) XR Fragment uses [W3C Media Fragments](https://www.w3.org/TR/media-frags/) and [URI Templates (RFC6570)](https://www.rfc-editor.org/rfc/rfc6570), to prevent unhyperifying itself by hardcoupling to a particular markup or scripting language. <br>
|
||||
XR Fragments supports filtering objects in a scene only, because in the history of the javascript-powered web, showing/hiding document-entities seems to be one of the most popular basic usecases.<br>
|
||||
Doing advanced scripting & networkrequests under the hood are obviously interesting endavours, but this is something which should not be hardcoupled with XR Fragments or hypermedia.<br>This perhaps belongs more to browser extensions.<br>
|
||||
Non-HTML Hypermedia browsers should make browser extensions the right place, to 'extend' experiences, in contrast to code/javascript inside hypermedia documents (this turned out as a hypermedia antipattern).
|
||||
|
||||
# authors
|
||||
(!authors)
|
||||
|
||||
* Leon van Kammen (@lvk@mastodon.online)
|
||||
* Jens Finkhäuser (@jens@social.finkhaeuser.de)
|
||||
|
||||
# IANA Considerations
|
||||
(!IANA Considerations)
|
||||
|
||||
This document has no IANA actions.
|
||||
|
||||
# Acknowledgments
|
||||
(!Acknowledgments)
|
||||
|
||||
* [NLNET](https://nlnet.nl)
|
||||
* [Future of Text](https://futureoftext.org)
|
||||
* [visual-meta.info](https://visual-meta.info)
|
||||
* Michiel Leenaars
|
||||
* Gerben van der Broeke
|
||||
* Mauve
|
||||
* Jens Finkhäuser
|
||||
* Marc Belmont
|
||||
* Tim Gerritsen
|
||||
* Frode Hegland
|
||||
* Brandel Zackernuk
|
||||
* Mark Anderson
|
||||
|
||||
# Appendix: Definitions
|
||||
(!Appendix: Definitions )
|
||||
|
||||
|definition | explanation |
|
||||
|----------------------|--------------------------------------------------------------------------------------------------------------------------------------|
|
||||
|human | a sentient being who thinks fuzzy, absorbs, and shares thought (by plain text, not markuplanguage) |
|
||||
|scene | a (local/remote) 3D scene or 3D file (index.gltf e.g.) |
|
||||
|3D object | an object inside a scene characterized by vertex-, face- and customproperty data. |
|
||||
|URI | some resource at something somewhere via someprotocol (`http://me.com/foo.glb#foo` or `e76f8efec8efce98e6f` [see interpeer.io](https://interpeer.io))|
|
||||
|URL | something somewhere via someprotocol (`http://me.com/foo.glb`) |
|
||||
|URN | something at some domain (`me.com/foo.glb`) |
|
||||
|metadata | custom properties of text, 3D Scene or Object(nodes), relevant to machines and a human minority (academics/developers) |
|
||||
|XR fragment | URI Fragment with spatial hints (which match the name of a 3D object-, camera-, animation-object) |
|
||||
|the XRWG | wordgraph (collapses 3D scene to tags) |
|
||||
|the hashbus | hashtags map to camera/scene-projections |
|
||||
|spacetime hashtags | positions camera, triggers scene-preset/time |
|
||||
|teleportation | repositioning the enduser to a different position (or 3D scene/file) |
|
||||
|sourceportation | teleporting the enduser to the original XR Document of an `src` embedded object. |
|
||||
|placeholder object | a 3D object which with src-metadata (which will be replaced by the src-data.) |
|
||||
|src | (HTML-piggybacked) metadata of a 3D object which instances content |
|
||||
|href | (HTML-piggybacked) metadata of a 3D object which links to content |
|
||||
|filter | URI Fragment(s) which show/hide object(s) in a scene based on name/tag/property (`#cube&-price=>3`) |
|
||||
|visual-meta | [visual-meta](https://visual.meta.info) data appended to text/books/papers which is indirectly visible/editable in XR. |
|
||||
|requestless metadata | metadata which never spawns new requests (unlike RDF/HTML, which can cause framerate-dropping, hence not used a lot in games) |
|
||||
|FPS | frames per second in spatial experiences (games,VR,AR e.g.), should be as high as possible |
|
||||
|introspective | inward sensemaking ("I feel this belongs to that") |
|
||||
|extrospective | outward sensemaking ("I'm fairly sure John is a person who lives in oklahoma") |
|
||||
|`◻` | ascii representation of an 3D object/mesh |
|
||||
|(un)obtrusive | obtrusive: wrapping human text/thought in XML/HTML/JSON obfuscates human text into a salad of machine-symbols and words |
|
||||
|flat 3D object | a 3D object of which all verticies share a plane |
|
||||
|BibTeX | simple tagging/citing/referencing standard for plaintext |
|
||||
|BibTag | a BibTeX tag |
|
||||
|(hashtag)bibs | an easy to speak/type/scan tagging SDL ([see here](https://github.com/coderofsalvation/hashtagbibs) which expands to BibTex/JSON/XML |
|
||||
|
||||
614
doc/RFC_XR_Fragments.md.bak
Normal file
614
doc/RFC_XR_Fragments.md.bak
Normal file
|
|
@ -0,0 +1,614 @@
|
|||
%%%
|
||||
Title = "XR Fragments"
|
||||
area = "Internet"
|
||||
workgroup = "Internet Engineering Task Force"
|
||||
|
||||
[seriesInfo]
|
||||
name = "XR-Fragments"
|
||||
value = "draft-XRFRAGMENTS-leonvankammen-00"
|
||||
stream = "IETF"
|
||||
status = "informational"
|
||||
|
||||
date = 2023-04-12T00:00:00Z
|
||||
|
||||
[[author]]
|
||||
initials="L.R."
|
||||
surname="van Kammen"
|
||||
fullname="L.R. van Kammen"
|
||||
|
||||
%%%
|
||||
|
||||
<!-- for annotated version see: https://raw.githubusercontent.com/ietf-tools/rfcxml-templates-and-schemas/main/draft-rfcxml-general-template-annotated-00.xml -->
|
||||
|
||||
<!--{
|
||||
|
||||
<style type="text/css">
|
||||
body{
|
||||
font-family: monospace;
|
||||
max-width: 1000px;
|
||||
font-size: 15px;
|
||||
padding: 0% 20%;
|
||||
line-height: 30px;
|
||||
color:#555;
|
||||
background:#F0F0F3
|
||||
}
|
||||
h1 { margin-top:40px; }
|
||||
pre{ line-height:18px; }
|
||||
a,a:visited,a:active{ color: #70f; }
|
||||
code{
|
||||
border: 1px solid #AAA;
|
||||
border-radius: 3px;
|
||||
padding: 0px 5px 2px 5px;
|
||||
}
|
||||
|
||||
pre{
|
||||
line-height: 18px;
|
||||
overflow: auto;
|
||||
padding: 12px;
|
||||
}
|
||||
pre + code {
|
||||
background:#DDD;
|
||||
}
|
||||
pre>code{
|
||||
border:none;
|
||||
border-radius:0px;
|
||||
padding:0;
|
||||
}
|
||||
blockquote{
|
||||
padding-left: 30px;
|
||||
margin: 0;
|
||||
border-left: 5px solid #CCC;
|
||||
}
|
||||
th {
|
||||
border-bottom: 1px solid #000;
|
||||
text-align: left;
|
||||
padding-right:45px;
|
||||
padding-left:7px;
|
||||
background: #DDD;
|
||||
}
|
||||
|
||||
td {
|
||||
border-bottom: 1px solid #CCC;
|
||||
font-size:13px;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<br>
|
||||
<h1>XR Fragments</h1>
|
||||
<br>
|
||||
|
||||
<pre>
|
||||
stream: IETF
|
||||
area: Internet
|
||||
status: informational
|
||||
author: Leon van Kammen
|
||||
date: 2023-04-12T00:00:00Z
|
||||
workgroup: Internet Engineering Task Force
|
||||
value: draft-XRFRAGMENTS-leonvankammen-00
|
||||
</pre>
|
||||
|
||||
|
||||
}-->
|
||||
|
||||
.# Abstract
|
||||
|
||||
This draft offers a specification for 4D URLs & navigation, to link 3D scenes and text together with- or without a network-connection.<br>
|
||||
The specification promotes spatial addressibility, sharing, navigation, query-ing and tagging interactive (text)objects across for (XR) Browsers.<br>
|
||||
XR Fragments allows us to enrich existing dataformats, by recursive use of existing proven technologies like [URI Fragments](https://en.wikipedia.org/wiki/URI_fragment) and BibTags notation.<br>
|
||||
|
||||
> Almost every idea in this document is demonstrated at [https://xrfragment.org](https://xrfragment.org)
|
||||
|
||||
{mainmatter}
|
||||
|
||||
# Introduction
|
||||
|
||||
How can we add more features to existing text & 3D scenes, without introducing new dataformats?<br>
|
||||
Historically, there's many attempts to create the ultimate markuplanguage or 3D fileformat.<br>
|
||||
However, thru the lens of authoring, their lowest common denominator is still: plain text.<br>
|
||||
XR Fragments allows us to enrich/connect existing dataformats, by recursive use of existing technologies:<br>
|
||||
|
||||
1. addressibility and navigation of 3D scenes/objects: [URI Fragments](https://en.wikipedia.org/wiki/URI_fragment) + src/href spatial metadata
|
||||
1. hasslefree tagging across text and spatial objects using [BibTags](https://en.wikipedia.org/wiki/BibTeX) as appendix (see [visual-meta](https://visual-meta.info) e.g.)
|
||||
|
||||
> NOTE: The chapters in this document are ordered from highlevel to lowlevel (technical) as much as possible
|
||||
|
||||
# Core principle
|
||||
|
||||
XR Fragments strives to serve (nontechnical/fuzzy) humans first, and machine(implementations) later, by ensuring hasslefree text-vs-thought feedback loops.<br>
|
||||
This also means that the repair-ability of machine-matters should be human friendly too (not too complex).<br>
|
||||
|
||||
> "When a car breaks down, the ones **without** turbosupercharger are easier to fix"
|
||||
|
||||
Let's always focus on average humans: the 'fuzzy symbolical mind' must be served first, before serving the greater ['categorized typesafe RDF hive mind'](https://en.wikipedia.org/wiki/Borg)).
|
||||
|
||||
> Humans first, machines (AI) later.
|
||||
|
||||
# Conventions and Definitions
|
||||
|
||||
|definition | explanation |
|
||||
|----------------------|-------------------------------------------------------------------------------------------------------------------------------|
|
||||
|human | a sentient being who thinks fuzzy, absorbs, and shares thought (by plain text, not markuplanguage) |
|
||||
|scene | a (local/remote) 3D scene or 3D file (index.gltf e.g.) |
|
||||
|3D object | an object inside a scene characterized by vertex-, face- and customproperty data. |
|
||||
|metadata | custom properties of text, 3D Scene or Object(nodes), relevant to machines and a human minority (academics/developers) |
|
||||
|XR fragment | URI Fragment with spatial hints like `#pos=0,0,0&t=1,100` e.g. |
|
||||
|src | (HTML-piggybacked) metadata of a 3D object which instances content |
|
||||
|href | (HTML-piggybacked) metadata of a 3D object which links to content |
|
||||
|query | an URI Fragment-operator which queries object(s) from a scene like `#q=cube` |
|
||||
|visual-meta | [visual-meta](https://visual.meta.info) data appended to text/books/papers which is indirectly visible/editable in XR. |
|
||||
|requestless metadata | opposite of networked metadata (RDF/HTML requests can easily fan out into framerate-dropping, hence not used a lot in games). |
|
||||
|FPS | frames per second in spatial experiences (games,VR,AR e.g.), should be as high as possible |
|
||||
|introspective | inward sensemaking ("I feel this belongs to that") |
|
||||
|extrospective | outward sensemaking ("I'm fairly sure John is a person who lives in oklahoma") |
|
||||
|`◻` | ascii representation of an 3D object/mesh |
|
||||
|(un)obtrusive | obtrusive: wrapping human text/thought in XML/HTML/JSON obfuscates human text into a salad of machine-symbols and words |
|
||||
|BibTeX | simple tagging/citing/referencing standard for plaintext |
|
||||
|BibTag | a BibTeX tag |
|
||||
|
||||
# List of URI Fragments
|
||||
|
||||
| fragment | type | example | info |
|
||||
|--------------|----------|-------------------|-------------------------------------------------------------------|
|
||||
| `#pos` | vector3 | `#pos=0.5,0,0` | positions camera to xyz-coord 0.5,0,0 |
|
||||
| `#rot` | vector3 | `#rot=0,90,0` | rotates camera to xyz-coord 0.5,0,0 |
|
||||
| `#t` | vector2 | `#t=500,1000` | sets animation-loop range between frame 500 and 1000 |
|
||||
| `#......` | string | `#.cubes` `#cube` | object(s) of interest (fragment to object name or class mapping) |
|
||||
|
||||
> xyz coordinates are similar to ones found in SVG Media Fragments
|
||||
|
||||
# List of metadata for 3D nodes
|
||||
|
||||
| key | type | example (JSON) | info |
|
||||
|--------------|----------|--------------------|--------------------------------------------------------|
|
||||
| `name` | string | `"name": "cube"` | available in all 3D fileformats & scenes |
|
||||
| `class` | string | `"class": "cubes"` | available through custom property in 3D fileformats |
|
||||
| `href` | string | `"href": "b.gltf"` | available through custom property in 3D fileformats |
|
||||
| `src` | string | `"src": "#q=cube"` | available through custom property in 3D fileformats |
|
||||
|
||||
Popular compatible 3D fileformats: `.gltf`, `.obj`, `.fbx`, `.usdz`, `.json` (THREEjs), `COLLADA` and so on.
|
||||
|
||||
> NOTE: XR Fragments are file-agnostic, which means that the metadata exist in programmatic 3D scene(nodes) too.
|
||||
|
||||
# Navigating 3D
|
||||
|
||||
Here's an ascii representation of a 3D scene-graph which contains 3D objects `◻` and their metadata:
|
||||
|
||||
```
|
||||
+--------------------------------------------------------+
|
||||
| |
|
||||
| index.gltf |
|
||||
| │ |
|
||||
| ├── ◻ buttonA |
|
||||
| │ └ href: #pos=1,0,1&t=100,200 |
|
||||
| │ |
|
||||
| └── ◻ buttonB |
|
||||
| └ href: other.fbx | <-- file-agnostic (can be .gltf .obj etc)
|
||||
| |
|
||||
+--------------------------------------------------------+
|
||||
|
||||
```
|
||||
|
||||
An XR Fragment-compatible browser viewing this scene, allows the end-user to interact with the `buttonA` and `buttonB`.<br>
|
||||
In case of `buttonA` the end-user will be teleported to another location and time in the **current loaded scene**, but `buttonB` will
|
||||
**replace the current scene** with a new one, like `other.fbx`.
|
||||
|
||||
# Embedding 3D content
|
||||
|
||||
Here's an ascii representation of a 3D scene-graph with 3D objects `◻` which embeds remote & local 3D objects `◻` (without) using queries:
|
||||
|
||||
```
|
||||
+--------------------------------------------------------+ +-------------------------+
|
||||
| | | |
|
||||
| index.gltf | | ocean.com/aquarium.fbx |
|
||||
| │ | | │ |
|
||||
| ├── ◻ canvas | | └── ◻ fishbowl |
|
||||
| │ └ src: painting.png | | ├─ ◻ bass |
|
||||
| │ | | └─ ◻ tuna |
|
||||
| ├── ◻ aquariumcube | | |
|
||||
| │ └ src: ://rescue.com/fish.gltf#q=bass%20tuna | +-------------------------+
|
||||
| │ |
|
||||
| ├── ◻ bedroom |
|
||||
| │ └ src: #q=canvas |
|
||||
| │ |
|
||||
| └── ◻ livingroom |
|
||||
| └ src: #q=canvas |
|
||||
| |
|
||||
+--------------------------------------------------------+
|
||||
```
|
||||
|
||||
An XR Fragment-compatible browser viewing this scene, lazy-loads and projects `painting.png` onto the (plane) object called `canvas` (which is copy-instanced in the bed and livingroom).<br>
|
||||
Also, after lazy-loading `ocean.com/aquarium.gltf`, only the queried objects `bass` and `tuna` will be instanced inside `aquariumcube`.<br>
|
||||
Resizing will be happen accordingly to its placeholder object `aquariumcube`, see chapter Scaling.<br>
|
||||
|
||||
# XR Fragment queries
|
||||
|
||||
Include, exclude, hide/shows objects using space-separated strings:
|
||||
|
||||
* `#q=cube`
|
||||
* `#q=cube -ball_inside_cube`
|
||||
* `#q=* -sky`
|
||||
* `#q=-.language .english`
|
||||
* `#q=cube&rot=0,90,0`
|
||||
* `#q=price:>2 price:<5`
|
||||
|
||||
It's simple but powerful syntax which allows <b>css</b>-like class/id-selectors with a searchengine prompt-style feeling:
|
||||
|
||||
1. queries are showing/hiding objects **only** when defined as `src` value (prevents sharing of scene-tampered URL's).
|
||||
1. queries are highlighting objects when defined in the top-Level (browser) URL (bar).
|
||||
1. search words like `cube` and `foo` in `#q=cube foo` are matched against 3D object names or custom metadata-key(values)
|
||||
1. search words like `cube` and `foo` in `#q=cube foo` are matched against tags (BibTeX) inside plaintext `src` values like `@cube{redcube, ...` e.g.
|
||||
1. `#` equals `#q=*`
|
||||
1. words starting with `.` like `.german` match class-metadata of 3D objects like `"class":"german"`
|
||||
1. words starting with `.` like `.german` match class-metadata of (BibTeX) tags in XR Text objects like `@german{KarlHeinz, ...` e.g.
|
||||
|
||||
> **For example**: `#q=.foo` is a shorthand for `#q=class:foo`, which will select objects with custom property `class`:`foo`. Just a simple `#q=cube` will simply select an object named `cube`.
|
||||
|
||||
* see [an example video here](https://coderofsalvation.github.io/xrfragment.media/queries.mp4)
|
||||
|
||||
## including/excluding
|
||||
|
||||
| operator | info |
|
||||
|----------|-------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `*` | select all objects (only useful in `src` custom property) |
|
||||
| `-` | removes/hides object(s) |
|
||||
| `:` | indicates an object-embedded custom property key/value |
|
||||
| `.` | alias for `"class" :".foo"` equals `class:foo` |
|
||||
| `>` `<` | compare float or int number |
|
||||
| `/` | reference to root-scene.<br>Useful in case of (preventing) showing/hiding objects in nested scenes (instanced by `src`) (*) |
|
||||
|
||||
> \* = `#q=-/cube` hides object `cube` only in the root-scene (not nested `cube` objects)<br> `#q=-cube` hides both object `cube` in the root-scene <b>AND</b> nested `skybox` objects |
|
||||
|
||||
[» example implementation](https://github.com/coderofsalvation/xrfragment/blob/main/src/3rd/js/three/xrf/q.js)
|
||||
[» example 3D asset](https://github.com/coderofsalvation/xrfragment/blob/main/example/assets/query.gltf#L192)
|
||||
[» discussion](https://github.com/coderofsalvation/xrfragment/issues/3)
|
||||
|
||||
## Query Parser
|
||||
|
||||
Here's how to write a query parser:
|
||||
|
||||
1. create an associative array/object to store query-arguments as objects
|
||||
1. detect object id's & properties `foo:1` and `foo` (reference regex: `/^.*:[><=!]?/` )
|
||||
1. detect excluders like `-foo`,`-foo:1`,`-.foo`,`-/foo` (reference regex: `/^-/` )
|
||||
1. detect root selectors like `/foo` (reference regex: `/^[-]?\//` )
|
||||
1. detect class selectors like `.foo` (reference regex: `/^[-]?class$/` )
|
||||
1. detect number values like `foo:1` (reference regex: `/^[0-9\.]+$/` )
|
||||
1. expand aliases like `.foo` into `class:foo`
|
||||
1. for every query token split string on `:`
|
||||
1. create an empty array `rules`
|
||||
1. then strip key-operator: convert "-foo" into "foo"
|
||||
1. add operator and value to rule-array
|
||||
1. therefore we we set `id` to `true` or `false` (false=excluder `-`)
|
||||
1. and we set `root` to `true` or `false` (true=`/` root selector is present)
|
||||
1. we convert key '/foo' into 'foo'
|
||||
1. finally we add the key/value to the store like `store.foo = {id:false,root:true}` e.g.
|
||||
|
||||
> An example query-parser (which compiles to many languages) can be [found here](https://github.com/coderofsalvation/xrfragment/blob/main/src/xrfragment/Query.hx)
|
||||
|
||||
## XR Fragment URI Grammar
|
||||
|
||||
```
|
||||
reserved = gen-delims / sub-delims
|
||||
gen-delims = "#" / "&"
|
||||
sub-delims = "," / "="
|
||||
```
|
||||
|
||||
> Example: `://foo.com/my3d.gltf#pos=1,0,0&prio=-5&t=0,100`
|
||||
|
||||
| Demo | Explanation |
|
||||
|-------------------------------|---------------------------------|
|
||||
| `pos=1,2,3` | vector/coordinate argument e.g. |
|
||||
| `pos=1,2,3&rot=0,90,0&q=.foo` | combinators |
|
||||
|
||||
|
||||
# Text in XR (tagging,linking to spatial objects)
|
||||
|
||||
We still think and speak in simple text, not in HTML or RDF.<br>
|
||||
The most advanced human will probably not shout `<h1>FIRE!</h1>` in case of emergency.<br>
|
||||
Given the new dawn of (non-keyboard) XR interfaces, keeping text as is (not obscuring with markup) is preferred.<br>
|
||||
Ideally metadata must come **later with** text, but not **obfuscate** the text, or **in another** file.<br>
|
||||
|
||||
> Humans first, machines (AI) later ([core principle](#core-principle)
|
||||
|
||||
This way:
|
||||
|
||||
1. XR Fragments allows <b id="tagging-text">hasslefree XR text tagging</b>, using BibTeX metadata **at the end of content** (like [visual-meta](https://visual.meta.info)).
|
||||
1. XR Fragments allows hasslefree <a href="#textual-tag">textual tagging</a>, <a href="#spatial-tag">spatial tagging</a>, and <a href="#supra-tagging">supra tagging</a>, by mapping 3D/text object (class)names using BibTeX 'tags'
|
||||
1. Bibs/BibTeX-appendices is first-choice **requestless metadata**-layer for XR text, HTML/RDF/JSON is great (but fits better in the application-layer)
|
||||
1. Default font (unless specified otherwise) is a modern monospace font, for maximized tabular expressiveness (see [the core principle](#core-principle)).
|
||||
1. anti-pattern: hardcoupling a mandatory **obtrusive markuplanguage** or framework with an XR browsers (HTML/VRML/Javascript) (see [the core principle](#core-principle))
|
||||
1. anti-pattern: limiting human introspection, by immediately funneling human thought into typesafe, precise, pre-categorized metadata like RDF (see [the core principle](#core-principle))
|
||||
|
||||
This allows recursive connections between text itself, as well as 3D objects and vice versa, using **BibTags** :
|
||||
|
||||
```
|
||||
+---------------------------------------------+ +------------------+
|
||||
| My Notes | | / \ |
|
||||
| | | / \ |
|
||||
| The houses here are built in baroque style. | | /house\ |
|
||||
| | | |_____| |
|
||||
| | +---------|--------+
|
||||
| @house{houses, >----'house'--------| class/name match?
|
||||
| url = {#.house} >----'houses'-------` class/name match?
|
||||
| } |
|
||||
+---------------------------------------------+
|
||||
```
|
||||
|
||||
> The enduser can add connections by speaking/typing/scanning [hashtagbibs](https://github.com/coderofsalvation/hashtagbibs) which the XR Browser can expand to BibTags.
|
||||
|
||||
This allows instant realtime tagging of objects at various scopes:
|
||||
|
||||
| scope | matching algo |
|
||||
|---------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| <b id="textual-tagging">textual</b> | text containing 'houses' is now automatically tagged with 'house' (incl. plaintext `src` child nodes) |
|
||||
| <b id="spatial-tagging">spatial</b> | spatial object(s) with `"class":"house"` (because of `{#.house}`) are now automatically tagged with 'house' (incl. child nodes) |
|
||||
| <b id="supra-tagging">supra</b> | text- or spatial-object(s) (non-descendant nodes) elsewhere, named 'house', are automatically tagged with 'house' (current node to root node) |
|
||||
| <b id="omni-tagging">omni</b> | text- or spatial-object(s) (non-descendant nodes) elsewhere, containing class/name 'house', are automatically tagged with 'house' (too node to all nodes) |
|
||||
| <b id="infinite-tagging">infinite</b> | text- or spatial-object(s) (non-descendant nodes) elsewhere, containing class/name 'house' or 'houses', are automatically tagged with 'house' (too node to all nodes) |
|
||||
|
||||
This empowers the enduser spatial expressiveness (see [the core principle](#core-principle)): spatial wires can be rendered, words can be highlighted, spatial objects can be highlighted/moved/scaled, links can be manipulated by the user.<br>
|
||||
The simplicity of appending BibTeX 'tags' (humans first, machines later) is also demonstrated by [visual-meta](https://visual-meta.info) in greater detail.
|
||||
|
||||
1. The XR Browser needs to adjust tag-scope based on the endusers needs/focus (infinite tagging only makes sense when environment is scaled down significantly)
|
||||
1. The XR Browser should always allow the human to view/edit the metadata, by clicking 'toggle metadata' on the 'back' (contextmenu e.g.) of any XR text, anywhere anytime.
|
||||
|
||||
> NOTE: infinite matches both 'house' and 'houses' in text, as well as spatial objects with `"class":"house"` or name "house". This multiplexing of id/category is deliberate because of [the core principle](#core-principle).
|
||||
|
||||
## Default Data URI mimetype
|
||||
|
||||
The `src`-values work as expected (respecting mime-types), however:
|
||||
|
||||
The XR Fragment specification bumps the traditional default browser-mimetype
|
||||
|
||||
`text/plain;charset=US-ASCII`
|
||||
|
||||
to a hashtagbib(tex)-friendly one:
|
||||
|
||||
`text/plain;charset=utf-8;bib=^@`
|
||||
|
||||
This indicates that:
|
||||
|
||||
* utf-8 is supported by default
|
||||
* [hashtagbibs](https://github.com/coderofsalvation/hashtagbibs) are expanded to [bibtags](https://en.wikipedia.org/wiki/BibTeX)
|
||||
* lines matching regex `^@` will automatically get filtered out, in order to:
|
||||
* links between textual/spatial objects can automatically be detected
|
||||
* bibtag appendices ([visual-meta](https://visual-meta.info) can be interpreted e.g.
|
||||
|
||||
> for more info on this mimetype see [bibs](https://github.com/coderofsalvation/hashtagbibs)
|
||||
|
||||
Advantages:
|
||||
|
||||
* out-of-the-box (de)multiplex human text and metadata in one go (see [the core principle](#core-principle))
|
||||
* no network-overhead for metadata (see [the core principle](#core-principle))
|
||||
* ensuring high FPS: HTML/RDF historically is too 'requesty'/'parsy' for game studios
|
||||
* rich send/receive/copy-paste everywhere by default, metadata being retained (see [the core principle](#core-principle))
|
||||
* netto result: less webservices, therefore less servers, and overall better FPS in XR
|
||||
|
||||
> This significantly expands expressiveness and portability of human tagged text, by **postponing machine-concerns to the end of the human text** in contrast to literal interweaving of content and markupsymbols (or extra network requests, webservices e.g.).
|
||||
|
||||
For all other purposes, regular mimetypes can be used (but are not required by the spec).<br>
|
||||
|
||||
## URL and Data URI
|
||||
|
||||
```
|
||||
+--------------------------------------------------------------+ +------------------------+
|
||||
| | | author.com/article.txt |
|
||||
| index.gltf | +------------------------+
|
||||
| │ | | |
|
||||
| ├── ◻ article_canvas | | Hello friends. |
|
||||
| │ └ src: ://author.com/article.txt | | |
|
||||
| │ | | @friend{friends |
|
||||
| └── ◻ note_canvas | | ... |
|
||||
| └ src:`data:welcome human\n@...` | | } |
|
||||
| | +------------------------+
|
||||
| |
|
||||
+--------------------------------------------------------------+
|
||||
```
|
||||
|
||||
The enduser will only see `welcome human` and `Hello friends` rendered spatially.
|
||||
The beauty is that text (AND visual-meta) in Data URI promotes rich copy-paste.
|
||||
In both cases, the text gets rendered immediately (onto a plane geometry, hence the name '_canvas').
|
||||
The XR Fragment-compatible browser can let the enduser access visual-meta(data)-fields after interacting with the object (contextmenu e.g.).
|
||||
|
||||
> additional tagging using [bibs](https://github.com/coderofsalvation/hashtagbibs): to tag spatial object `note_canvas` with 'todo', the enduser can type or speak `@note_canvas@todo`
|
||||
|
||||
The mapping between 3D objects and text (src-data) is simple (the :
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
+------------------------------------------------+
|
||||
| |
|
||||
| index.gltf |
|
||||
| │ |
|
||||
| └── ◻ rentalhouse |
|
||||
| └ class: house <----------------- matches -------+
|
||||
| └ ◻ note | |
|
||||
| └ src:`data: todo: call owner | hashtagbib |
|
||||
| #owner@house@todo | ----> expands to @house{owner,
|
||||
| | bibtex: }
|
||||
| ` | @contact{
|
||||
+------------------------------------------------+ }
|
||||
```
|
||||
|
||||
Bi-directional mapping between 3D object names and/or classnames and text using bibs,BibTags & XR Fragments, allows for rich interlinking between text and 3D objects:
|
||||
|
||||
1. When the user surfs to https://.../index.gltf#rentalhouse the XR Fragments-parser points the enduser to the rentalhouse object, and can show contextual info about it.
|
||||
2. When (partial) remote content is embedded thru XR Fragment queries (see XR Fragment queries), indirectly related metadata can be embedded along.
|
||||
|
||||
## Bibs & BibTeX: lowest common denominator for linking data
|
||||
|
||||
> "When a car breaks down, the ones **without** turbosupercharger are easier to fix"
|
||||
|
||||
Unlike XML or JSON, BibTex is typeless, unnested, and uncomplicated, hence a great advantage for introspection.<br>
|
||||
It's a missing sensemaking precursor to extrospective RDF.<br>
|
||||
BibTeX-appendices are already used in the digital AND physical world (academic books, [visual-meta](https://visual-meta.info)), perhaps due to its terseness & simplicity.<br>
|
||||
In that sense, it's one step up from the `.ini` fileformat (which has never leaked into the physical world like BibTex):
|
||||
|
||||
1. <b id="frictionless-copy-paste">frictionless copy/pasting</b> (by humans) of (unobtrusive) content AND metadata
|
||||
1. an introspective 'sketchpad' for metadata, which can (optionally) mature into RDF later
|
||||
|
||||
| characteristic | UTF8 Plain Text (with BibTeX) | RDF |
|
||||
|------------------------------------|-------------------------------|---------------------------|
|
||||
| perspective | introspective | extrospective |
|
||||
| structure | fuzzy (sensemaking) | precise |
|
||||
| space/scope | local | world |
|
||||
| everything is text (string) | yes | no |
|
||||
| voice/paper-friendly | [bibs](https://github.com/coderofsalvation/hashtagbibs) | no |
|
||||
| leaves (dictated) text intact | yes | no |
|
||||
| markup language | just an appendix | ~4 different |
|
||||
| polyglot format | no | yes |
|
||||
| easy to copy/paste content+metadata| yes | up to application |
|
||||
| easy to write/repair for layman | yes | depends |
|
||||
| easy to (de)serialize | yes (fits on A4 paper) | depends |
|
||||
| infrastructure | selfcontained (plain text) | (semi)networked |
|
||||
| freeform tagging/annotation | yes, terse | yes, verbose |
|
||||
| can be appended to text-content | yes | up to application |
|
||||
| copy-paste text preserves metadata | yes | up to application |
|
||||
| emoji | yes | depends on encoding |
|
||||
| predicates | free | semi pre-determined |
|
||||
| implementation/network overhead | no | depends |
|
||||
| used in (physical) books/PDF | yes (visual-meta) | no |
|
||||
| terse non-verb predicates | yes | no |
|
||||
| nested structures | no (but: BibTex rulers) | yes |
|
||||
|
||||
> To keep XR Fragments a lightweight spec, BibTeX is used for rudimentary text/spatial tagging (not JSON, RDF or a scripting language because they're harder to write/speak/repair.).
|
||||
|
||||
Applications are also free to attach any JSON(LD / RDF) to spatial objects using custom properties (but is not interpreted by this spec).
|
||||
|
||||
## XR Text example parser
|
||||
|
||||
|
||||
1. The XR Fragments spec does not aim to harden the BiBTeX format
|
||||
2. respect multi-line BibTex values because of [the core principle](#core-principle)
|
||||
3. Expand hashtag(bibs) and rulers (like `${visual-meta-start}`) according to the [hashtagbibs spec](https://github.com/coderofsalvation/hashtagbibs)
|
||||
4. BibTeX snippets should always start in the beginning of a line (regex: ^@), hence mimetype `text/plain;charset=utf-8;bib=^@`
|
||||
|
||||
Here's an XR Text (de)multiplexer in javascript, which ticks all the above boxes:
|
||||
|
||||
```
|
||||
xrtext = {
|
||||
|
||||
expandBibs: (text) => {
|
||||
let bibs = { regex: /(#[a-zA-Z0-9_+@\-]+(#)?)/g, tags: {}}
|
||||
text.replace( bibs.regex , (m,k,v) => {
|
||||
tok = m.substr(1).split("@")
|
||||
match = tok.shift()
|
||||
if( tok.length ) tok.map( (t) => bibs.tags[t] = `@${t}{${match},\n}` )
|
||||
else if( match.substr(-1) == '#' )
|
||||
bibs.tags[match] = `@{${match.replace(/#/,'')}}`
|
||||
else bibs.tags[match] = `@${match}{${match},\n}`
|
||||
})
|
||||
return text.replace( bibs.regex, '') + Object.values(bibs.tags).join('\n')
|
||||
},
|
||||
|
||||
decode: (str) => {
|
||||
// bibtex: ↓@ ↓<tag|tag{phrase,|{ruler}> ↓property ↓end
|
||||
let pat = [ /@/, /^\S+[,{}]/, /},/, /}/ ]
|
||||
let tags = [], text='', i=0, prop=''
|
||||
let lines = xrtext.expandBibs(str).replace(/\r?\n/g,'\n').split(/\n/)
|
||||
for( let i = 0; i < lines.length && !String(lines[i]).match( /^@/ ); i++ )
|
||||
text += lines[i]+'\n'
|
||||
|
||||
bibtex = lines.join('\n').substr( text.length )
|
||||
bibtex.split( pat[0] ).map( (t) => {
|
||||
try{
|
||||
let v = {}
|
||||
if( !(t = t.trim()) ) return
|
||||
if( tag = t.match( pat[1] ) ) tag = tag[0]
|
||||
if( tag.match( /^{.*}$/ ) ) return tags.push({ruler:tag})
|
||||
t = t.substr( tag.length )
|
||||
t.split( pat[2] )
|
||||
.map( kv => {
|
||||
if( !(kv = kv.trim()) || kv == "}" ) return
|
||||
v[ kv.match(/\s?(\S+)\s?=/)[1] ] = kv.substr( kv.indexOf("{")+1 )
|
||||
})
|
||||
tags.push( { k:tag, v } )
|
||||
}catch(e){ console.error(e) }
|
||||
})
|
||||
return {text, tags}
|
||||
},
|
||||
|
||||
encode: (text,tags) => {
|
||||
let str = text+"\n"
|
||||
for( let i in tags ){
|
||||
let item = tags[i]
|
||||
if( item.ruler ){
|
||||
str += `@${item.ruler}\n`
|
||||
continue;
|
||||
}
|
||||
str += `@${item.k}\n`
|
||||
for( let j in item.v ) str += ` ${j} = {${item.v[j]}}\n`
|
||||
str += `}\n`
|
||||
}
|
||||
return str
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The above functions (de)multiplexe text/metadata, expands bibs, (de)serialize bibtex (and all fits more or less on one A4 paper)
|
||||
|
||||
> above can be used as a startingpoint for LLVM's to translate/steelman to a more formal form/language.
|
||||
|
||||
```
|
||||
str = `
|
||||
hello world
|
||||
here are some hashtagbibs followed by bibtex:
|
||||
|
||||
#world
|
||||
#hello@greeting
|
||||
#another-section#
|
||||
|
||||
@{some-section}
|
||||
@flap{
|
||||
asdf = {23423}
|
||||
}`
|
||||
|
||||
var {tags,text} = xrtext.decode(str) // demultiplex text & bibtex
|
||||
tags.find( (t) => t.k == 'flap{' ).v.asdf = 1 // edit tag
|
||||
tags.push({ k:'bar{', v:{abc:123} }) // add tag
|
||||
console.log( xrtext.encode(text,tags) ) // multiplex text & bibtex back together
|
||||
```
|
||||
This expands to the following (hidden by default) BibTex appendix:
|
||||
|
||||
```
|
||||
hello world
|
||||
here are some hashtagbibs followed by bibtex:
|
||||
|
||||
@{some-section}
|
||||
@flap{
|
||||
asdf = {1}
|
||||
}
|
||||
@world{world,
|
||||
}
|
||||
@greeting{hello,
|
||||
}
|
||||
@{another-section}
|
||||
@bar{
|
||||
abc = {123}
|
||||
}
|
||||
```
|
||||
|
||||
# HYPER copy/paste
|
||||
|
||||
The previous example, offers something exciting compared to simple copy/paste of 3D objects or text.
|
||||
XR Text according to the XR Fragment spec, allows HYPER-copy/paste: time, space and text interlinked.
|
||||
Therefore, the enduser in an XR Fragment-compatible browser can copy/paste/share data in these ways:
|
||||
|
||||
1. time/space: 3D object (current animation-loop)
|
||||
1. text: TeXt object (including BibTeX/visual-meta if any)
|
||||
1. interlinked: Collected objects by visual-meta tag
|
||||
|
||||
# Security Considerations
|
||||
|
||||
Since XR Text contains metadata too, the user should be able to set up tagging-rules, so the copy-paste feature can :
|
||||
|
||||
* filter out sensitive data when copy/pasting (XR text with `class:secret` e.g.)
|
||||
|
||||
# IANA Considerations
|
||||
|
||||
This document has no IANA actions.
|
||||
|
||||
# Acknowledgments
|
||||
|
||||
TODO acknowledge.
|
||||
BIN
doc/RFC_XR_Fragments.png
Normal file
BIN
doc/RFC_XR_Fragments.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
35994
doc/RFC_XR_Fragments.svg
Normal file
35994
doc/RFC_XR_Fragments.svg
Normal file
File diff suppressed because it is too large
Load diff
|
After Width: | Height: | Size: 1,002 KiB |
1736
doc/RFC_XR_Fragments.txt
Normal file
1736
doc/RFC_XR_Fragments.txt
Normal file
File diff suppressed because it is too large
Load diff
1257
doc/RFC_XR_Fragments.xml
Normal file
1257
doc/RFC_XR_Fragments.xml
Normal file
File diff suppressed because it is too large
Load diff
465
doc/RFC_XR_Macros.html
Normal file
465
doc/RFC_XR_Macros.html
Normal file
|
|
@ -0,0 +1,465 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>XR Macros</title>
|
||||
<meta name="GENERATOR" content="github.com/mmarkdown/mmark Mmark Markdown Processor - mmark.miek.nl">
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- for annotated version see: https://raw.githubusercontent.com/ietf-tools/rfcxml-templates-and-schemas/main/draft-rfcxml-general-template-annotated-00.xml -->
|
||||
|
||||
|
||||
<style type="text/css">
|
||||
body{
|
||||
font-family: monospace;
|
||||
max-width: 1000px;
|
||||
font-size: 15px;
|
||||
padding: 0% 20%;
|
||||
line-height: 30px;
|
||||
color:#555;
|
||||
background:#F0F0F3
|
||||
}
|
||||
h1 { margin-top:40px; }
|
||||
pre{ line-height:18px; }
|
||||
a,a:visited,a:active{ color: #70f; }
|
||||
code{
|
||||
border: 1px solid #AAA;
|
||||
border-radius: 3px;
|
||||
padding: 0px 5px 2px 5px;
|
||||
}
|
||||
|
||||
pre{
|
||||
line-height: 18px;
|
||||
overflow: auto;
|
||||
padding: 12px;
|
||||
}
|
||||
pre + code {
|
||||
background:#DDD;
|
||||
}
|
||||
pre>code{
|
||||
border:none;
|
||||
border-radius:0px;
|
||||
padding:0;
|
||||
}
|
||||
blockquote{
|
||||
padding-left: 30px;
|
||||
margin: 0;
|
||||
border-left: 5px solid #CCC;
|
||||
}
|
||||
th {
|
||||
border-bottom: 1px solid #000;
|
||||
text-align: left;
|
||||
padding-right:45px;
|
||||
padding-left:7px;
|
||||
background: #DDD;
|
||||
}
|
||||
|
||||
td {
|
||||
border-bottom: 1px solid #CCC;
|
||||
font-size:13px;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<br>
|
||||
<h1>XR Macros</h1>
|
||||
<br>
|
||||
|
||||
<pre>
|
||||
stream: IETF
|
||||
area: Internet
|
||||
status: informational
|
||||
author: Leon van Kammen
|
||||
date: 2023-04-12T00:00:00Z
|
||||
workgroup: Internet Engineering Task Force
|
||||
value: draft-XRMACROS-leonvankammen-00
|
||||
</pre>
|
||||
|
||||
|
||||
|
||||
<h1 class="special" id="abstract">Abstract</h1>
|
||||
|
||||
<p>This draft offers a specification for embedding macros in existing 3D scenes/assets, to offer simple interactions and configure the renderer further.<br>
|
||||
Together with URI Fragments, it allows for rich immersive experiences without the need of a complicated sandboxed scripting languages.</p>
|
||||
|
||||
<blockquote>
|
||||
<p>Almost every idea in this document is demonstrated at <a href="https://xrfragment.org">https://xrfragment.org</a>, as this spec was created during the <a href="https://xrfragment.org">XR Fragments</a> spec.</p>
|
||||
</blockquote>
|
||||
<section data-matter="main">
|
||||
<h1 id="introduction">Introduction</h1>
|
||||
|
||||
<p>How can we add more features to existing text & 3D scenes, without introducing new dataformats?<br>
|
||||
Historically, there’s many attempts to create the ultimate markuplanguage or 3D fileformat.<br>
|
||||
Their lowest common denominator is: (co)authoring using plain text.<br>
|
||||
Therefore, XR Macros allows us to enrich/connect existing dataformats, by offering a polyglot notation based on existing notations:<br></p>
|
||||
|
||||
<ol>
|
||||
<li>getting/setting common used 3D properties using querystring- or JSON-notation</li>
|
||||
<li>targeting 3D properties using the lightweight query notation present in <a href="https://xrfragment.org">XR Fragments</a></li>
|
||||
</ol>
|
||||
|
||||
<blockquote>
|
||||
<p>NOTE: The chapters in this document are ordered from highlevel to lowlevel (technical) as much as possible</p>
|
||||
</blockquote>
|
||||
|
||||
<h1 id="core-principle">Core principle</h1>
|
||||
|
||||
<ol>
|
||||
<li>XR Macros use querystrings, but are HTML-agnostic (though pseudo-XR Fragment browsers <strong>can</strong> be implemented on top of HTML/Javascript).</li>
|
||||
<li>An XR Macro is 3D metadata which starts with ‘!’ (<code>!clickme: fog=0,10</code> e.g.)</li>
|
||||
<li>Metadata-values can contain the <code>|</code> symbol to 🎲 roundrobin variable values (<code>!toggleme: fog=0,10|fog=0,1000</code> e.g.)</li>
|
||||
<li>XR Macros acts as simple eventhandlers for URI Fragments: they are automatically published on the (<a href="https://xrfragment.org">XR Fragments</a>) hashbus, to act as events (so more serious scripting languages can react to them as well).</li>
|
||||
<li>XR Macros can assign object metadata (<code>!setlocal: foo=1</code> writes <code>foo:1</code> metadata to the object containing the <code>!setlocal</code> metadata)</li>
|
||||
<li>XR Macros can assign global metadata (<code>!setfoo: #foo=1</code> writes <code>foo:1</code> metadata to the root scene-node)</li>
|
||||
</ol>
|
||||
|
||||
<blockquote>
|
||||
<p>These very simple principles allow for rich interactions and dynamic querying</p>
|
||||
</blockquote>
|
||||
|
||||
<h1 id="conventions-and-definitions">Conventions and Definitions</h1>
|
||||
|
||||
<p>See appendix below in case certain terms are not clear.</p>
|
||||
|
||||
<h1 id="list-of-xr-macros">List of XR Macros</h1>
|
||||
|
||||
<p>(XR) Macros can be embedded in 3D assets/scenes.<br>
|
||||
Macros enrich existing spatial content with a lowcode, limited logic-layer, by recursive (economic) use of the querystring syntax (which search engines and <a href="https://xrfragment.org">XR Fragments</a> already uses.<br>
|
||||
This is done by allowing string/integer variables, and the <code>|</code> symbol to roundrobin variable values.<br>
|
||||
Macros also act as events, so more serious scripting languages can react to them as well.<br></p>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>key</th>
|
||||
<th>type</th>
|
||||
<th>example (JSON)</th>
|
||||
<th>function</th>
|
||||
<th>existing compatibility</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>@bg</code></td>
|
||||
<td>string</td>
|
||||
<td><code>"@bg":"#cube"</code></td>
|
||||
<td>bg: binds fog near/far based to cube x/y/z (anim) values</td>
|
||||
<td>custom property in 3D fileformats</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><code>@fog</code></td>
|
||||
<td>string</td>
|
||||
<td><code>"@fog":"#cube"</code></td>
|
||||
<td>fog: binds fog near/far based to cube x/y (anim) values</td>
|
||||
<td>custom property in 3D fileformats</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><code>@scroll</code></td>
|
||||
<td>string</td>
|
||||
<td><code>"@scroll":"#cube"</code></td>
|
||||
<td>texturescrolling: binds texture x/y/rot based to cube x/y/z (anim) values</td>
|
||||
<td>custom property in 3D fileformats</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><code>@emissive</code></td>
|
||||
<td>string</td>
|
||||
<td><code>"@emissive":"#cube"</code></td>
|
||||
<td>day/night/mood: binds material’s emissive value to cube x/y/z (anim) values</td>
|
||||
<td>custom property in 3D fileformats</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h2 id="usecase-click-object">Usecase: click object</h2>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>custom property</th>
|
||||
<th>value</th>
|
||||
<th>trigger when</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>!clickme</td>
|
||||
<td>bg=1,1,1&foo=2</td>
|
||||
<td>object clicked</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h2 id="usecase-conditional-click-object">Usecase: conditional click object</h2>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>custom property</th>
|
||||
<th>value</th>
|
||||
<th>trigger when</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>#</td>
|
||||
<td>foo=1</td>
|
||||
<td>scene</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>!clickme</td>
|
||||
<td>q=foo>2&bg=1,1,1</td>
|
||||
<td>object clicked and foo > 2</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<blockquote>
|
||||
<p>when a user clicks an object with the custom properties above, it should set the backgroundcolor to <code>1,1,1</code> when <code>foo</code> is greater than <code>2</code> (see previous example)</p>
|
||||
</blockquote>
|
||||
|
||||
<h2 id="usecase-click-object-roundrobin">Usecase: click object (roundrobin)</h2>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>custom property</th>
|
||||
<th>value</th>
|
||||
<th>trigger when</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>!cycleme</td>
|
||||
<td>day|noon|night</td>
|
||||
<td>object clicked</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>day</td>
|
||||
<td>bg=1,1,1</td>
|
||||
<td>roundrobin</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>noon</td>
|
||||
<td>bg=0.5,0.5,0.5</td>
|
||||
<td>roundrobin</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>night</td>
|
||||
<td>bg=0,0,0&foo=2</td>
|
||||
<td>roundrobin</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<blockquote>
|
||||
<p>when a user clicks an object with the custom properties above, it should trigger either <code>day</code> <code>noon</code> or <code>night</code> in roundrobin fashion.</p>
|
||||
</blockquote>
|
||||
|
||||
<h2 id="usecase-click-object-or-uri-fragment-and-scene-load-trigger">Usecase: click object or URI fragment, and scene load trigger</h2>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>custom property</th>
|
||||
<th>value</th>
|
||||
<th>trigger when</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>#</td>
|
||||
<td>random</td>
|
||||
<td>scene loaded</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>#random</td>
|
||||
<td>random</td>
|
||||
<td>URL contains #random</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>!random</td>
|
||||
<td>day|noon|night</td>
|
||||
<td>#random, # or click</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>day</td>
|
||||
<td>bg=1,1,1</td>
|
||||
<td>roundrobin</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>noon</td>
|
||||
<td>bg=0.5,0.5,0.5</td>
|
||||
<td>roundrobin</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>night</td>
|
||||
<td>bg=0,0,0&foo=2</td>
|
||||
<td>roundrobin</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h2 id="usecase-present-context-menu-with-options">Usecase: present context menu with options</h2>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>custom property</th>
|
||||
<th>value</th>
|
||||
<th>trigger when</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>!random</td>
|
||||
<td>!day</td>
|
||||
<td>!noon</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>!day</td>
|
||||
<td>bg=1,1,1</td>
|
||||
<td>clicked in contextmenu</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>!noon</td>
|
||||
<td>bg=0.5,0.5,0.5</td>
|
||||
<td>clicked in contextmenu</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>!night</td>
|
||||
<td>bg=0,0,0&foo=2</td>
|
||||
<td>clicked in contextmenu</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<blockquote>
|
||||
<p>When interacting with an object with more than one <code>!</code>-macro, the XR Browser should offer a contextmenu to execute a macro.</p>
|
||||
</blockquote>
|
||||
|
||||
<p>In a similar way, when <strong>any</strong> <code>!</code>-macro is present on the sceneroot, the XR Browser should offer a context-menu to execute those macro’s.</p>
|
||||
|
||||
<h2 id="event-bubble-flow">Event Bubble-flow</h2>
|
||||
|
||||
<p>click object with (<code>!clickme</code>:<code>AR</code> or <code>!clickme</code>: <code>!reset</code> e.g.)</p>
|
||||
|
||||
<pre><code> ◻
|
||||
│
|
||||
└── does current object contain this property-key (`AR` or `!reset` e.g.)?
|
||||
└── no: is there any (root)object containing property `AR`
|
||||
└── yes: evaluate its (roundrobin) XR macro-value(s) (and exit)
|
||||
└── no: trigger URL: #AR
|
||||
</code></pre>
|
||||
|
||||
<p>click object with (<code>!clickme</code>:<code>#AR|#VR</code> e.g.)</p>
|
||||
|
||||
<pre><code> ◻
|
||||
│
|
||||
└── apply the roundrobin (rotate the options, value `#AR` becomes `#VR` upon next click)
|
||||
└── is there any object with property-key (`#AR` e.g.)?
|
||||
└── no: just update the URL to `#AR`
|
||||
└── yes: apply its value to the scene, and update the URL to `#AR`
|
||||
|
||||
click object with (`!clickme`:`!foo|!bar|!flop` e.g.)
|
||||
</code></pre>
|
||||
|
||||
<p>◻
|
||||
│<br>
|
||||
└── apply the roundrobin (rotate the options, value <code>!foo</code> becomes <code>!bar</code> upon next click)
|
||||
└── is there any object with property-key (<code>!foo</code> e.g.)?
|
||||
└── no: do nothing
|
||||
└── yes: apply its value to the scene
|
||||
“`</p>
|
||||
|
||||
<blockquote>
|
||||
<p>Note that only macro’s can trigger roundrobin values or contextmenu’s, as well as roundrobin values never ending up in the toplevel URL.</p>
|
||||
</blockquote>
|
||||
|
||||
<h1 id="security-considerations">Security Considerations</h1>
|
||||
|
||||
<h1 id="iana-considerations">IANA Considerations</h1>
|
||||
|
||||
<p>This document has no IANA actions.</p>
|
||||
|
||||
<h1 id="acknowledgments">Acknowledgments</h1>
|
||||
|
||||
<ul>
|
||||
<li><a href="https://nlnet.nl">NLNET</a></li>
|
||||
<li><a href="https://futureoftext.org">Future of Text</a></li>
|
||||
<li><a href="https://visual-meta.info">visual-meta.info</a></li>
|
||||
</ul>
|
||||
|
||||
<h1 id="appendix-definitions">Appendix: Definitions</h1>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>definition</th>
|
||||
<th>explanation</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>scene</td>
|
||||
<td>a (local/remote) 3D scene or 3D file (index.gltf e.g.)</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>3D object</td>
|
||||
<td>an object inside a scene characterized by vertex-, face- and customproperty data.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>XR fragments</td>
|
||||
<td>URI Fragment with spatial hints like <code>#pos=0,0,0&t=1,100</code> e.g.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>query</td>
|
||||
<td>an URI Fragment-operator which queries object(s) from a scene like <code>#q=cube</code></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>FPS</td>
|
||||
<td>frames per second in spatial experiences (games,VR,AR e.g.), should be as high as possible</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><code>◻</code></td>
|
||||
<td>ascii representation of an 3D object/mesh</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>(un)obtrusive</td>
|
||||
<td>obtrusive: wrapping human text/thought in XML/HTML/JSON obfuscates human text into a salad of machine-symbols and words</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
251
doc/RFC_XR_Macros.md
Normal file
251
doc/RFC_XR_Macros.md
Normal file
|
|
@ -0,0 +1,251 @@
|
|||
%%%
|
||||
Title = "XR Macros"
|
||||
area = "Internet"
|
||||
workgroup = "Internet Engineering Task Force"
|
||||
|
||||
[seriesInfo]
|
||||
name = "XR-Macros"
|
||||
value = "draft-XRMACROS-leonvankammen-00"
|
||||
stream = "IETF"
|
||||
status = "informational"
|
||||
|
||||
date = 2023-04-12T00:00:00Z
|
||||
|
||||
[[author]]
|
||||
initials="L.R."
|
||||
surname="van Kammen"
|
||||
fullname="L.R. van Kammen"
|
||||
|
||||
%%%
|
||||
|
||||
<!-- for annotated version see: https://raw.githubusercontent.com/ietf-tools/rfcxml-templates-and-schemas/main/draft-rfcxml-general-template-annotated-00.xml -->
|
||||
|
||||
<!--{
|
||||
|
||||
<style type="text/css">
|
||||
body{
|
||||
font-family: monospace;
|
||||
max-width: 1000px;
|
||||
font-size: 15px;
|
||||
padding: 0% 20%;
|
||||
line-height: 30px;
|
||||
color:#555;
|
||||
background:#F0F0F3
|
||||
}
|
||||
h1 { margin-top:40px; }
|
||||
pre{ line-height:18px; }
|
||||
a,a:visited,a:active{ color: #70f; }
|
||||
code{
|
||||
border: 1px solid #AAA;
|
||||
border-radius: 3px;
|
||||
padding: 0px 5px 2px 5px;
|
||||
}
|
||||
|
||||
pre{
|
||||
line-height: 18px;
|
||||
overflow: auto;
|
||||
padding: 12px;
|
||||
}
|
||||
pre + code {
|
||||
background:#DDD;
|
||||
}
|
||||
pre>code{
|
||||
border:none;
|
||||
border-radius:0px;
|
||||
padding:0;
|
||||
}
|
||||
blockquote{
|
||||
padding-left: 30px;
|
||||
margin: 0;
|
||||
border-left: 5px solid #CCC;
|
||||
}
|
||||
th {
|
||||
border-bottom: 1px solid #000;
|
||||
text-align: left;
|
||||
padding-right:45px;
|
||||
padding-left:7px;
|
||||
background: #DDD;
|
||||
}
|
||||
|
||||
td {
|
||||
border-bottom: 1px solid #CCC;
|
||||
font-size:13px;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<br>
|
||||
<h1>XR Macros</h1>
|
||||
<br>
|
||||
|
||||
<pre>
|
||||
stream: IETF
|
||||
area: Internet
|
||||
status: informational
|
||||
author: Leon van Kammen
|
||||
date: 2023-04-12T00:00:00Z
|
||||
workgroup: Internet Engineering Task Force
|
||||
value: draft-XRMACROS-leonvankammen-00
|
||||
</pre>
|
||||
|
||||
|
||||
}-->
|
||||
|
||||
.# Abstract
|
||||
|
||||
This draft offers a specification for embedding macros in existing 3D scenes/assets, to offer simple interactions and configure the renderer further.<br>
|
||||
Together with URI Fragments, it allows for rich immersive experiences without the need of a complicated sandboxed scripting languages.
|
||||
|
||||
> Almost every idea in this document is demonstrated at [https://xrfragment.org](https://xrfragment.org), as this spec was created during the [XR Fragments](https://xrfragment.org) spec.
|
||||
|
||||
{mainmatter}
|
||||
|
||||
# Introduction
|
||||
|
||||
How can we add more features to existing text & 3D scenes, without introducing new dataformats?<br>
|
||||
Historically, there's many attempts to create the ultimate markuplanguage or 3D fileformat.<br>
|
||||
Their lowest common denominator is: (co)authoring using plain text.<br>
|
||||
Therefore, XR Macros allows us to enrich/connect existing dataformats, by offering a polyglot notation based on existing notations:<br>
|
||||
|
||||
1. getting/setting common used 3D properties using querystring- or JSON-notation
|
||||
1. targeting 3D properties using the lightweight query notation present in [XR Fragments](https://xrfragment.org)
|
||||
|
||||
> NOTE: The chapters in this document are ordered from highlevel to lowlevel (technical) as much as possible
|
||||
|
||||
# Core principle
|
||||
|
||||
1. XR Macros use querystrings, but are HTML-agnostic (though pseudo-XR Fragment browsers **can** be implemented on top of HTML/Javascript).
|
||||
1. An XR Macro is 3D metadata which starts with '!' (`!clickme: fog=0,10` e.g.)
|
||||
1. Metadata-values can contain the `|` symbol to 🎲 roundrobin variable values (`!toggleme: fog=0,10|fog=0,1000` e.g.)
|
||||
1. XR Macros acts as simple eventhandlers for URI Fragments: they are automatically published on the ([XR Fragments](https://xrfragment.org)) hashbus, to act as events (so more serious scripting languages can react to them as well).
|
||||
1. XR Macros can assign object metadata (`!setlocal: foo=1` writes `foo:1` metadata to the object containing the `!setlocal` metadata)
|
||||
1. XR Macros can assign global metadata (`!setfoo: #foo=1` writes `foo:1` metadata to the root scene-node)
|
||||
|
||||
> These very simple principles allow for rich interactions and dynamic querying
|
||||
|
||||
# Conventions and Definitions
|
||||
|
||||
See appendix below in case certain terms are not clear.
|
||||
|
||||
# List of XR Macros
|
||||
|
||||
(XR) Macros can be embedded in 3D assets/scenes.<br>
|
||||
Macros enrich existing spatial content with a lowcode, limited logic-layer, by recursive (economic) use of the querystring syntax (which search engines and [XR Fragments](https://xrfragment.org) already uses.<br>
|
||||
This is done by allowing string/integer variables, and the `|` symbol to roundrobin variable values.<br>
|
||||
Macros also act as events, so more serious scripting languages can react to them as well.<br>
|
||||
|
||||
| key | type | example (JSON) | function | existing compatibility |
|
||||
|--------------|----------|------------------------|---------------------|----------------------------------------|
|
||||
| `@bg` | string | `"@bg":"#cube"` | bg: binds fog near/far based to cube x/y/z (anim) values | custom property in 3D fileformats |
|
||||
| `@fog` | string | `"@fog":"#cube"` | fog: binds fog near/far based to cube x/y (anim) values | custom property in 3D fileformats |
|
||||
| `@scroll` | string | `"@scroll":"#cube"` | texturescrolling: binds texture x/y/rot based to cube x/y/z (anim) values | custom property in 3D fileformats |
|
||||
| `@emissive` | string | `"@emissive":"#cube"` | day/night/mood: binds material's emissive value to cube x/y/z (anim) values | custom property in 3D fileformats |
|
||||
|
||||
## Usecase: click object
|
||||
|
||||
| custom property | value | trigger when |
|
||||
|-----------------|--------------------------|------------------------|
|
||||
| !clickme | bg=1,1,1&foo=2 | object clicked |
|
||||
|
||||
## Usecase: conditional click object
|
||||
|
||||
| custom property | value | trigger when |
|
||||
|-----------------|--------------------------|-----------------------------|
|
||||
| # | foo=1 | scene |
|
||||
| !clickme | q=foo>2&bg=1,1,1 | object clicked and foo > 2 |
|
||||
|
||||
> when a user clicks an object with the custom properties above, it should set the backgroundcolor to `1,1,1` when `foo` is greater than `2` (see previous example)
|
||||
|
||||
## Usecase: click object (roundrobin)
|
||||
|
||||
| custom property | value | trigger when |
|
||||
|-----------------|--------------------------|------------------------|
|
||||
| !cycleme | day|noon|night | object clicked |
|
||||
| day | bg=1,1,1 | roundrobin |
|
||||
| noon | bg=0.5,0.5,0.5 | roundrobin |
|
||||
| night | bg=0,0,0&foo=2 | roundrobin |
|
||||
|
||||
> when a user clicks an object with the custom properties above, it should trigger either `day` `noon` or `night` in roundrobin fashion.
|
||||
|
||||
## Usecase: click object or URI fragment, and scene load trigger
|
||||
|
||||
| custom property | value | trigger when |
|
||||
|-----------------|--------------------------|------------------------|
|
||||
| # | random | scene loaded |
|
||||
| #random | random | URL contains #random |
|
||||
| !random | day|noon|night | #random, # or click |
|
||||
| day | bg=1,1,1 | roundrobin |
|
||||
| noon | bg=0.5,0.5,0.5 | roundrobin |
|
||||
| night | bg=0,0,0&foo=2 | roundrobin |
|
||||
|
||||
## Usecase: present context menu with options
|
||||
|
||||
| custom property | value | trigger when |
|
||||
|-----------------|--------------------------|------------------------|
|
||||
| !random | !day|!noon|!night | clicked in contextmenu |
|
||||
| !day | bg=1,1,1 | clicked in contextmenu |
|
||||
| !noon | bg=0.5,0.5,0.5 | clicked in contextmenu |
|
||||
| !night | bg=0,0,0&foo=2 | clicked in contextmenu |
|
||||
|
||||
> When interacting with an object with more than one `!`-macro, the XR Browser should offer a contextmenu to execute a macro.
|
||||
|
||||
In a similar way, when **any** `!`-macro is present on the sceneroot, the XR Browser should offer a context-menu to execute those macro's.
|
||||
|
||||
## Event Bubble-flow
|
||||
|
||||
click object with (`!clickme`:`AR` or `!clickme`: `!reset` e.g.)
|
||||
```
|
||||
◻
|
||||
│
|
||||
└── does current object contain this property-key (`AR` or `!reset` e.g.)?
|
||||
└── no: is there any (root)object containing property `AR`
|
||||
└── yes: evaluate its (roundrobin) XR macro-value(s) (and exit)
|
||||
└── no: trigger URL: #AR
|
||||
```
|
||||
|
||||
click object with (`!clickme`:`#AR|#VR` e.g.)
|
||||
```
|
||||
◻
|
||||
│
|
||||
└── apply the roundrobin (rotate the options, value `#AR` becomes `#VR` upon next click)
|
||||
└── is there any object with property-key (`#AR` e.g.)?
|
||||
└── no: just update the URL to `#AR`
|
||||
└── yes: apply its value to the scene, and update the URL to `#AR`
|
||||
|
||||
click object with (`!clickme`:`!foo|!bar|!flop` e.g.)
|
||||
```
|
||||
◻
|
||||
│
|
||||
└── apply the roundrobin (rotate the options, value `!foo` becomes `!bar` upon next click)
|
||||
└── is there any object with property-key (`!foo` e.g.)?
|
||||
└── no: do nothing
|
||||
└── yes: apply its value to the scene
|
||||
```
|
||||
|
||||
> Note that only macro's can trigger roundrobin values or contextmenu's, as well as roundrobin values never ending up in the toplevel URL.
|
||||
|
||||
# Security Considerations
|
||||
|
||||
|
||||
# IANA Considerations
|
||||
|
||||
This document has no IANA actions.
|
||||
|
||||
# Acknowledgments
|
||||
|
||||
* [NLNET](https://nlnet.nl)
|
||||
* [Future of Text](https://futureoftext.org)
|
||||
* [visual-meta.info](https://visual-meta.info)
|
||||
|
||||
# Appendix: Definitions
|
||||
|
||||
|definition | explanation |
|
||||
|----------------------|-------------------------------------------------------------------------------------------------------------------------------|
|
||||
|scene | a (local/remote) 3D scene or 3D file (index.gltf e.g.) |
|
||||
|3D object | an object inside a scene characterized by vertex-, face- and customproperty data. |
|
||||
|XR fragments | URI Fragment with spatial hints like `#pos=0,0,0&t=1,100` e.g. |
|
||||
|query | an URI Fragment-operator which queries object(s) from a scene like `#q=cube` |
|
||||
|FPS | frames per second in spatial experiences (games,VR,AR e.g.), should be as high as possible |
|
||||
|`◻` | ascii representation of an 3D object/mesh |
|
||||
|(un)obtrusive | obtrusive: wrapping human text/thought in XML/HTML/JSON obfuscates human text into a salad of machine-symbols and words |
|
||||
|
||||
392
doc/RFC_XR_Macros.txt
Normal file
392
doc/RFC_XR_Macros.txt
Normal file
|
|
@ -0,0 +1,392 @@
|
|||
|
||||
|
||||
|
||||
|
||||
Internet Engineering Task Force L.R. van Kammen
|
||||
Internet-Draft 1 September 2025
|
||||
Intended status: Informational
|
||||
|
||||
|
||||
|
||||
XR Macros
|
||||
draft-XRMACROS-leonvankammen-00
|
||||
|
||||
Abstract
|
||||
|
||||
This draft offers a specification for embedding macros in existing 3D
|
||||
scenes/assets, to offer simple interactions and configure the
|
||||
renderer further.
|
||||
Together with URI Fragments, it allows for rich immersive experiences
|
||||
without the need of a complicated sandboxed scripting languages.
|
||||
|
||||
Almost every idea in this document is demonstrated at
|
||||
https://xrfragment.org (https://xrfragment.org), as this spec was
|
||||
created during the XR Fragments (https://xrfragment.org) spec.
|
||||
|
||||
Status of This Memo
|
||||
|
||||
This Internet-Draft is submitted in full conformance with the
|
||||
provisions of BCP 78 and BCP 79.
|
||||
|
||||
Internet-Drafts are working documents of the Internet Engineering
|
||||
Task Force (IETF). Note that other groups may also distribute
|
||||
working documents as Internet-Drafts. The list of current Internet-
|
||||
Drafts is at https://datatracker.ietf.org/drafts/current/.
|
||||
|
||||
Internet-Drafts are draft documents valid for a maximum of six months
|
||||
and may be updated, replaced, or obsoleted by other documents at any
|
||||
time. It is inappropriate to use Internet-Drafts as reference
|
||||
material or to cite them other than as "work in progress."
|
||||
|
||||
This Internet-Draft will expire on 5 March 2026.
|
||||
|
||||
Copyright Notice
|
||||
|
||||
Copyright (c) 2025 IETF Trust and the persons identified as the
|
||||
document authors. All rights reserved.
|
||||
|
||||
This document is subject to BCP 78 and the IETF Trust's Legal
|
||||
Provisions Relating to IETF Documents (https://trustee.ietf.org/
|
||||
license-info) in effect on the date of publication of this document.
|
||||
Please review these documents carefully, as they describe your rights
|
||||
and restrictions with respect to this document. Code Components
|
||||
|
||||
|
||||
|
||||
van Kammen Expires 5 March 2026 [Page 1]
|
||||
|
||||
Internet-Draft XR Macros September 2025
|
||||
|
||||
|
||||
extracted from this document must include Revised BSD License text as
|
||||
described in Section 4.e of the Trust Legal Provisions and are
|
||||
provided without warranty as described in the Revised BSD License.
|
||||
|
||||
Table of Contents
|
||||
|
||||
1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 2
|
||||
2. Core principle . . . . . . . . . . . . . . . . . . . . . . . 2
|
||||
3. Conventions and Definitions . . . . . . . . . . . . . . . . . 3
|
||||
4. List of XR Macros . . . . . . . . . . . . . . . . . . . . . . 3
|
||||
4.1. Usecase: click object . . . . . . . . . . . . . . . . . . 4
|
||||
4.2. Usecase: conditional click object . . . . . . . . . . . . 4
|
||||
4.3. Usecase: click object (roundrobin) . . . . . . . . . . . 5
|
||||
4.4. Usecase: click object or URI fragment, and scene load
|
||||
trigger . . . . . . . . . . . . . . . . . . . . . . . . . 5
|
||||
4.5. Usecase: present context menu with options . . . . . . . 6
|
||||
4.6. Event Bubble-flow . . . . . . . . . . . . . . . . . . . . 6
|
||||
5. Security Considerations . . . . . . . . . . . . . . . . . . . 7
|
||||
6. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 7
|
||||
7. Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . 7
|
||||
8. Appendix: Definitions . . . . . . . . . . . . . . . . . . . . 7
|
||||
|
||||
1. Introduction
|
||||
|
||||
How can we add more features to existing text & 3D scenes, without
|
||||
introducing new dataformats?
|
||||
Historically, there's many attempts to create the ultimate
|
||||
markuplanguage or 3D fileformat.
|
||||
Their lowest common denominator is: (co)authoring using plain text.
|
||||
Therefore, XR Macros allows us to enrich/connect existing
|
||||
dataformats, by offering a polyglot notation based on existing
|
||||
notations:
|
||||
|
||||
1. getting/setting common used 3D properties using querystring- or
|
||||
JSON-notation
|
||||
2. targeting 3D properties using the lightweight query notation
|
||||
present in XR Fragments (https://xrfragment.org)
|
||||
|
||||
| NOTE: The chapters in this document are ordered from highlevel to
|
||||
| lowlevel (technical) as much as possible
|
||||
|
||||
2. Core principle
|
||||
|
||||
1. XR Macros use querystrings, but are HTML-agnostic (though pseudo-
|
||||
XR Fragment browsers *can* be implemented on top of HTML/
|
||||
Javascript).
|
||||
2. An XR Macro is 3D metadata which starts with '!' (!clickme:
|
||||
fog=0,10 e.g.)
|
||||
|
||||
|
||||
|
||||
van Kammen Expires 5 March 2026 [Page 2]
|
||||
|
||||
Internet-Draft XR Macros September 2025
|
||||
|
||||
|
||||
3. Metadata-values can contain the | symbol to 🎲 roundrobin variable
|
||||
values (!toggleme: fog=0,10|fog=0,1000 e.g.)
|
||||
4. XR Macros acts as simple eventhandlers for URI Fragments: they
|
||||
are automatically published on the (XR Fragments
|
||||
(https://xrfragment.org)) hashbus, to act as events (so more
|
||||
serious scripting languages can react to them as well).
|
||||
5. XR Macros can assign object metadata (!setlocal: foo=1 writes
|
||||
foo:1 metadata to the object containing the !setlocal metadata)
|
||||
6. XR Macros can assign global metadata (!setfoo: #foo=1 writes
|
||||
foo:1 metadata to the root scene-node)
|
||||
|
||||
| These very simple principles allow for rich interactions and
|
||||
| dynamic querying
|
||||
|
||||
3. Conventions and Definitions
|
||||
|
||||
See appendix below in case certain terms are not clear.
|
||||
|
||||
4. List of XR Macros
|
||||
|
||||
(XR) Macros can be embedded in 3D assets/scenes.
|
||||
Macros enrich existing spatial content with a lowcode, limited logic-
|
||||
layer, by recursive (economic) use of the querystring syntax (which
|
||||
search engines and XR Fragments (https://xrfragment.org) already
|
||||
uses.
|
||||
This is done by allowing string/integer variables, and the | symbol
|
||||
to roundrobin variable values.
|
||||
Macros also act as events, so more serious scripting languages can
|
||||
react to them as well.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
van Kammen Expires 5 March 2026 [Page 3]
|
||||
|
||||
Internet-Draft XR Macros September 2025
|
||||
|
||||
|
||||
+=========+======+===================+=================+=============+
|
||||
|key |type |example (JSON) |function |existing |
|
||||
| | | | |compatibility|
|
||||
+=========+======+===================+=================+=============+
|
||||
|@bg |string|"@bg":"#cube" |bg: binds fog |custom |
|
||||
| | | |near/far based to|property in |
|
||||
| | | |cube x/y/z (anim)|3D |
|
||||
| | | |values |fileformats |
|
||||
+---------+------+-------------------+-----------------+-------------+
|
||||
|@fog |string|"@fog":"#cube" |fog: binds fog |custom |
|
||||
| | | |near/far based to|property in |
|
||||
| | | |cube x/y (anim) |3D |
|
||||
| | | |values |fileformats |
|
||||
+---------+------+-------------------+-----------------+-------------+
|
||||
|@scroll |string|"@scroll":"#cube" |texturescrolling:|custom |
|
||||
| | | |binds texture |property in |
|
||||
| | | |x/y/rot based to |3D |
|
||||
| | | |cube x/y/z (anim)|fileformats |
|
||||
| | | |values | |
|
||||
+---------+------+-------------------+-----------------+-------------+
|
||||
|@emissive|string|"@emissive":"#cube"|day/night/mood: |custom |
|
||||
| | | |binds material's |property in |
|
||||
| | | |emissive value to|3D |
|
||||
| | | |cube x/y/z (anim)|fileformats |
|
||||
| | | |values | |
|
||||
+---------+------+-------------------+-----------------+-------------+
|
||||
|
||||
Table 1
|
||||
|
||||
4.1. Usecase: click object
|
||||
|
||||
+=================+================+================+
|
||||
| custom property | value | trigger when |
|
||||
+=================+================+================+
|
||||
| !clickme | bg=1,1,1&foo=2 | object clicked |
|
||||
+-----------------+----------------+----------------+
|
||||
|
||||
Table 2
|
||||
|
||||
4.2. Usecase: conditional click object
|
||||
|
||||
+=================+==================+============================+
|
||||
| custom property | value | trigger when |
|
||||
+=================+==================+============================+
|
||||
| # | foo=1 | scene |
|
||||
+-----------------+------------------+----------------------------+
|
||||
| !clickme | q=foo>2&bg=1,1,1 | object clicked and foo > 2 |
|
||||
+-----------------+------------------+----------------------------+
|
||||
|
||||
|
||||
|
||||
van Kammen Expires 5 March 2026 [Page 4]
|
||||
|
||||
Internet-Draft XR Macros September 2025
|
||||
|
||||
|
||||
Table 3
|
||||
|
||||
| when a user clicks an object with the custom properties above, it
|
||||
| should set the backgroundcolor to 1,1,1 when foo is greater than 2
|
||||
| (see previous example)
|
||||
|
||||
4.3. Usecase: click object (roundrobin)
|
||||
|
||||
+=================+================+================+
|
||||
| custom property | value | trigger when |
|
||||
+=================+================+================+
|
||||
| !cycleme | day|noon|night | object clicked |
|
||||
+-----------------+----------------+----------------+
|
||||
| day | bg=1,1,1 | roundrobin |
|
||||
+-----------------+----------------+----------------+
|
||||
| noon | bg=0.5,0.5,0.5 | roundrobin |
|
||||
+-----------------+----------------+----------------+
|
||||
| night | bg=0,0,0&foo=2 | roundrobin |
|
||||
+-----------------+----------------+----------------+
|
||||
|
||||
Table 4
|
||||
|
||||
| when a user clicks an object with the custom properties above, it
|
||||
| should trigger either day noon or night in roundrobin fashion.
|
||||
|
||||
4.4. Usecase: click object or URI fragment, and scene load trigger
|
||||
|
||||
+=================+================+======================+
|
||||
| custom property | value | trigger when |
|
||||
+=================+================+======================+
|
||||
| # | random | scene loaded |
|
||||
+-----------------+----------------+----------------------+
|
||||
| #random | random | URL contains #random |
|
||||
+-----------------+----------------+----------------------+
|
||||
| !random | day|noon|night | #random, # or click |
|
||||
+-----------------+----------------+----------------------+
|
||||
| day | bg=1,1,1 | roundrobin |
|
||||
+-----------------+----------------+----------------------+
|
||||
| noon | bg=0.5,0.5,0.5 | roundrobin |
|
||||
+-----------------+----------------+----------------------+
|
||||
| night | bg=0,0,0&foo=2 | roundrobin |
|
||||
+-----------------+----------------+----------------------+
|
||||
|
||||
Table 5
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
van Kammen Expires 5 March 2026 [Page 5]
|
||||
|
||||
Internet-Draft XR Macros September 2025
|
||||
|
||||
|
||||
4.5. Usecase: present context menu with options
|
||||
|
||||
+=================+================+========================+
|
||||
| custom property | value | trigger when |
|
||||
+=================+================+========================+
|
||||
| !random | !day | !noon |
|
||||
+-----------------+----------------+------------------------+
|
||||
| !day | bg=1,1,1 | clicked in contextmenu |
|
||||
+-----------------+----------------+------------------------+
|
||||
| !noon | bg=0.5,0.5,0.5 | clicked in contextmenu |
|
||||
+-----------------+----------------+------------------------+
|
||||
| !night | bg=0,0,0&foo=2 | clicked in contextmenu |
|
||||
+-----------------+----------------+------------------------+
|
||||
|
||||
Table 6
|
||||
|
||||
| When interacting with an object with more than one !-macro, the XR
|
||||
| Browser should offer a contextmenu to execute a macro.
|
||||
|
||||
In a similar way, when *any* !-macro is present on the sceneroot, the
|
||||
XR Browser should offer a context-menu to execute those macro's.
|
||||
|
||||
4.6. Event Bubble-flow
|
||||
|
||||
click object with (!clickme:AR or !clickme: !reset e.g.)
|
||||
|
||||
◻
|
||||
│
|
||||
└── does current object contain this property-key (`AR` or `!reset` e.g.)?
|
||||
└── no: is there any (root)object containing property `AR`
|
||||
└── yes: evaluate its (roundrobin) XR macro-value(s) (and exit)
|
||||
└── no: trigger URL: #AR
|
||||
|
||||
click object with (!clickme:#AR|#VR e.g.)
|
||||
|
||||
◻
|
||||
│
|
||||
└── apply the roundrobin (rotate the options, value `#AR` becomes `#VR` upon next click)
|
||||
└── is there any object with property-key (`#AR` e.g.)?
|
||||
└── no: just update the URL to `#AR`
|
||||
└── yes: apply its value to the scene, and update the URL to `#AR`
|
||||
|
||||
click object with (`!clickme`:`!foo|!bar|!flop` e.g.)
|
||||
|
||||
◻ │
|
||||
└── apply the roundrobin (rotate the options, value !foo becomes !bar
|
||||
upon next click) └── is there any object with property-key (!foo
|
||||
e.g.)? └── no: do nothing └── yes: apply its value to the scene ```
|
||||
|
||||
|
||||
|
||||
van Kammen Expires 5 March 2026 [Page 6]
|
||||
|
||||
Internet-Draft XR Macros September 2025
|
||||
|
||||
|
||||
| Note that only macro's can trigger roundrobin values or
|
||||
| contextmenu's, as well as roundrobin values never ending up in the
|
||||
| toplevel URL.
|
||||
|
||||
5. Security Considerations
|
||||
|
||||
6. IANA Considerations
|
||||
|
||||
This document has no IANA actions.
|
||||
|
||||
7. Acknowledgments
|
||||
|
||||
* NLNET (https://nlnet.nl)
|
||||
* Future of Text (https://futureoftext.org)
|
||||
* visual-meta.info (https://visual-meta.info)
|
||||
|
||||
8. Appendix: Definitions
|
||||
|
||||
+===============+===================================================+
|
||||
| definition | explanation |
|
||||
+===============+===================================================+
|
||||
| scene | a (local/remote) 3D scene or 3D file |
|
||||
| | (index.gltf e.g.) |
|
||||
+---------------+---------------------------------------------------+
|
||||
| 3D object | an object inside a scene characterized by |
|
||||
| | vertex-, face- and customproperty data. |
|
||||
+---------------+---------------------------------------------------+
|
||||
| XR fragments | URI Fragment with spatial hints like |
|
||||
| | #pos=0,0,0&t=1,100 e.g. |
|
||||
+---------------+---------------------------------------------------+
|
||||
| query | an URI Fragment-operator which queries |
|
||||
| | object(s) from a scene like #q=cube |
|
||||
+---------------+---------------------------------------------------+
|
||||
| FPS | frames per second in spatial experiences |
|
||||
| | (games,VR,AR e.g.), should be as high as |
|
||||
| | possible |
|
||||
+---------------+---------------------------------------------------+
|
||||
| ◻ | ascii representation of an 3D object/mesh |
|
||||
+---------------+---------------------------------------------------+
|
||||
| (un)obtrusive | obtrusive: wrapping human text/thought in |
|
||||
| | XML/HTML/JSON obfuscates human text into |
|
||||
| | a salad of machine-symbols and words |
|
||||
+---------------+---------------------------------------------------+
|
||||
|
||||
Table 7
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
van Kammen Expires 5 March 2026 [Page 7]
|
||||
381
doc/RFC_XR_Macros.xml
Normal file
381
doc/RFC_XR_Macros.xml
Normal file
|
|
@ -0,0 +1,381 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- name="GENERATOR" content="github.com/mmarkdown/mmark Mmark Markdown Processor - mmark.miek.nl" -->
|
||||
<rfc version="3" ipr="trust200902" docName="draft-XRMACROS-leonvankammen-00" submissionType="IETF" category="info" xml:lang="en" xmlns:xi="http://www.w3.org/2001/XInclude" indexInclude="true" consensus="true">
|
||||
|
||||
<front>
|
||||
<title>XR Macros</title><seriesInfo value="draft-XRMACROS-leonvankammen-00" stream="IETF" status="informational" name="XR-Macros"></seriesInfo>
|
||||
<author initials="L.R." surname="van Kammen" fullname="L.R. van Kammen"><organization></organization><address><postal><street></street>
|
||||
</postal></address></author><date/>
|
||||
<area>Internet</area>
|
||||
<workgroup>Internet Engineering Task Force</workgroup>
|
||||
|
||||
<abstract>
|
||||
<t>This draft offers a specification for embedding macros in existing 3D scenes/assets, to offer simple interactions and configure the renderer further.<br />
|
||||
|
||||
Together with URI Fragments, it allows for rich immersive experiences without the need of a complicated sandboxed scripting languages.</t>
|
||||
<t>Almost every idea in this document is demonstrated at <eref target="https://xrfragment.org">https://xrfragment.org</eref>, as this spec was created during the <eref target="https://xrfragment.org">XR Fragments</eref> spec.</t>
|
||||
</abstract>
|
||||
|
||||
</front>
|
||||
|
||||
<middle>
|
||||
|
||||
<section anchor="introduction"><name>Introduction</name>
|
||||
<t>How can we add more features to existing text & 3D scenes, without introducing new dataformats?<br />
|
||||
|
||||
Historically, there's many attempts to create the ultimate markuplanguage or 3D fileformat.<br />
|
||||
|
||||
Their lowest common denominator is: (co)authoring using plain text.<br />
|
||||
|
||||
Therefore, XR Macros allows us to enrich/connect existing dataformats, by offering a polyglot notation based on existing notations:<br />
|
||||
</t>
|
||||
|
||||
<ol spacing="compact">
|
||||
<li>getting/setting common used 3D properties using querystring- or JSON-notation</li>
|
||||
<li>targeting 3D properties using the lightweight query notation present in <eref target="https://xrfragment.org">XR Fragments</eref></li>
|
||||
</ol>
|
||||
<blockquote><t>NOTE: The chapters in this document are ordered from highlevel to lowlevel (technical) as much as possible</t>
|
||||
</blockquote></section>
|
||||
|
||||
<section anchor="core-principle"><name>Core principle</name>
|
||||
|
||||
<ol spacing="compact">
|
||||
<li>XR Macros use querystrings, but are HTML-agnostic (though pseudo-XR Fragment browsers <strong>can</strong> be implemented on top of HTML/Javascript).</li>
|
||||
<li>An XR Macro is 3D metadata which starts with '!' (<tt>!clickme: fog=0,10</tt> e.g.)</li>
|
||||
<li>Metadata-values can contain the <tt>|</tt> symbol to 🎲 roundrobin variable values (<tt>!toggleme: fog=0,10|fog=0,1000</tt> e.g.)</li>
|
||||
<li>XR Macros acts as simple eventhandlers for URI Fragments: they are automatically published on the (<eref target="https://xrfragment.org">XR Fragments</eref>) hashbus, to act as events (so more serious scripting languages can react to them as well).</li>
|
||||
<li>XR Macros can assign object metadata (<tt>!setlocal: foo=1</tt> writes <tt>foo:1</tt> metadata to the object containing the <tt>!setlocal</tt> metadata)</li>
|
||||
<li>XR Macros can assign global metadata (<tt>!setfoo: #foo=1</tt> writes <tt>foo:1</tt> metadata to the root scene-node)</li>
|
||||
</ol>
|
||||
<blockquote><t>These very simple principles allow for rich interactions and dynamic querying</t>
|
||||
</blockquote></section>
|
||||
|
||||
<section anchor="conventions-and-definitions"><name>Conventions and Definitions</name>
|
||||
<t>See appendix below in case certain terms are not clear.</t>
|
||||
</section>
|
||||
|
||||
<section anchor="list-of-xr-macros"><name>List of XR Macros</name>
|
||||
<t>(XR) Macros can be embedded in 3D assets/scenes.<br />
|
||||
|
||||
Macros enrich existing spatial content with a lowcode, limited logic-layer, by recursive (economic) use of the querystring syntax (which search engines and <eref target="https://xrfragment.org">XR Fragments</eref> already uses.<br />
|
||||
|
||||
This is done by allowing string/integer variables, and the <tt>|</tt> symbol to roundrobin variable values.<br />
|
||||
|
||||
Macros also act as events, so more serious scripting languages can react to them as well.<br />
|
||||
</t>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>key</th>
|
||||
<th>type</th>
|
||||
<th>example (JSON)</th>
|
||||
<th>function</th>
|
||||
<th>existing compatibility</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><tt>@bg</tt></td>
|
||||
<td>string</td>
|
||||
<td><tt>"@bg":"#cube"</tt></td>
|
||||
<td>bg: binds fog near/far based to cube x/y/z (anim) values</td>
|
||||
<td>custom property in 3D fileformats</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><tt>@fog</tt></td>
|
||||
<td>string</td>
|
||||
<td><tt>"@fog":"#cube"</tt></td>
|
||||
<td>fog: binds fog near/far based to cube x/y (anim) values</td>
|
||||
<td>custom property in 3D fileformats</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><tt>@scroll</tt></td>
|
||||
<td>string</td>
|
||||
<td><tt>"@scroll":"#cube"</tt></td>
|
||||
<td>texturescrolling: binds texture x/y/rot based to cube x/y/z (anim) values</td>
|
||||
<td>custom property in 3D fileformats</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><tt>@emissive</tt></td>
|
||||
<td>string</td>
|
||||
<td><tt>"@emissive":"#cube"</tt></td>
|
||||
<td>day/night/mood: binds material's emissive value to cube x/y/z (anim) values</td>
|
||||
<td>custom property in 3D fileformats</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<section anchor="usecase-click-object"><name>Usecase: click object</name>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>custom property</th>
|
||||
<th>value</th>
|
||||
<th>trigger when</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>!clickme</td>
|
||||
<td>bg=1,1,1&foo=2</td>
|
||||
<td>object clicked</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table></section>
|
||||
|
||||
<section anchor="usecase-conditional-click-object"><name>Usecase: conditional click object</name>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>custom property</th>
|
||||
<th>value</th>
|
||||
<th>trigger when</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>#</td>
|
||||
<td>foo=1</td>
|
||||
<td>scene</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>!clickme</td>
|
||||
<td>q=foo>2&bg=1,1,1</td>
|
||||
<td>object clicked and foo > 2</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table><blockquote><t>when a user clicks an object with the custom properties above, it should set the backgroundcolor to <tt>1,1,1</tt> when <tt>foo</tt> is greater than <tt>2</tt> (see previous example)</t>
|
||||
</blockquote></section>
|
||||
|
||||
<section anchor="usecase-click-object-roundrobin"><name>Usecase: click object (roundrobin)</name>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>custom property</th>
|
||||
<th>value</th>
|
||||
<th>trigger when</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>!cycleme</td>
|
||||
<td>day|noon|night</td>
|
||||
<td>object clicked</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>day</td>
|
||||
<td>bg=1,1,1</td>
|
||||
<td>roundrobin</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>noon</td>
|
||||
<td>bg=0.5,0.5,0.5</td>
|
||||
<td>roundrobin</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>night</td>
|
||||
<td>bg=0,0,0&foo=2</td>
|
||||
<td>roundrobin</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table><blockquote><t>when a user clicks an object with the custom properties above, it should trigger either <tt>day</tt> <tt>noon</tt> or <tt>night</tt> in roundrobin fashion.</t>
|
||||
</blockquote></section>
|
||||
|
||||
<section anchor="usecase-click-object-or-uri-fragment-and-scene-load-trigger"><name>Usecase: click object or URI fragment, and scene load trigger</name>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>custom property</th>
|
||||
<th>value</th>
|
||||
<th>trigger when</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>#</td>
|
||||
<td>random</td>
|
||||
<td>scene loaded</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>#random</td>
|
||||
<td>random</td>
|
||||
<td>URL contains #random</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>!random</td>
|
||||
<td>day|noon|night</td>
|
||||
<td>#random, # or click</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>day</td>
|
||||
<td>bg=1,1,1</td>
|
||||
<td>roundrobin</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>noon</td>
|
||||
<td>bg=0.5,0.5,0.5</td>
|
||||
<td>roundrobin</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>night</td>
|
||||
<td>bg=0,0,0&foo=2</td>
|
||||
<td>roundrobin</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table></section>
|
||||
|
||||
<section anchor="usecase-present-context-menu-with-options"><name>Usecase: present context menu with options</name>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>custom property</th>
|
||||
<th>value</th>
|
||||
<th>trigger when</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>!random</td>
|
||||
<td>!day</td>
|
||||
<td>!noon</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>!day</td>
|
||||
<td>bg=1,1,1</td>
|
||||
<td>clicked in contextmenu</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>!noon</td>
|
||||
<td>bg=0.5,0.5,0.5</td>
|
||||
<td>clicked in contextmenu</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>!night</td>
|
||||
<td>bg=0,0,0&foo=2</td>
|
||||
<td>clicked in contextmenu</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table><blockquote><t>When interacting with an object with more than one <tt>!</tt>-macro, the XR Browser should offer a contextmenu to execute a macro.</t>
|
||||
</blockquote><t>In a similar way, when <strong>any</strong> <tt>!</tt>-macro is present on the sceneroot, the XR Browser should offer a context-menu to execute those macro's.</t>
|
||||
</section>
|
||||
|
||||
<section anchor="event-bubble-flow"><name>Event Bubble-flow</name>
|
||||
<t>click object with (<tt>!clickme</tt>:<tt>AR</tt> or <tt>!clickme</tt>: <tt>!reset</tt> e.g.)</t>
|
||||
|
||||
<artwork><![CDATA[ ◻
|
||||
│
|
||||
└── does current object contain this property-key (`AR` or `!reset` e.g.)?
|
||||
└── no: is there any (root)object containing property `AR`
|
||||
└── yes: evaluate its (roundrobin) XR macro-value(s) (and exit)
|
||||
└── no: trigger URL: #AR
|
||||
]]>
|
||||
</artwork>
|
||||
<t>click object with (<tt>!clickme</tt>:<tt>#AR|#VR</tt> e.g.)</t>
|
||||
|
||||
<artwork><![CDATA[ ◻
|
||||
│
|
||||
└── apply the roundrobin (rotate the options, value `#AR` becomes `#VR` upon next click)
|
||||
└── is there any object with property-key (`#AR` e.g.)?
|
||||
└── no: just update the URL to `#AR`
|
||||
└── yes: apply its value to the scene, and update the URL to `#AR`
|
||||
|
||||
click object with (`!clickme`:`!foo|!bar|!flop` e.g.)
|
||||
]]>
|
||||
</artwork>
|
||||
<t>◻
|
||||
│<br />
|
||||
└── apply the roundrobin (rotate the options, value <tt>!foo</tt> becomes <tt>!bar</tt> upon next click)
|
||||
└── is there any object with property-key (<tt>!foo</tt> e.g.)?
|
||||
└── no: do nothing
|
||||
└── yes: apply its value to the scene
|
||||
```</t>
|
||||
<blockquote><t>Note that only macro's can trigger roundrobin values or contextmenu's, as well as roundrobin values never ending up in the toplevel URL.</t>
|
||||
</blockquote></section>
|
||||
</section>
|
||||
|
||||
<section anchor="security-considerations"><name>Security Considerations</name>
|
||||
</section>
|
||||
|
||||
<section anchor="iana-considerations"><name>IANA Considerations</name>
|
||||
<t>This document has no IANA actions.</t>
|
||||
</section>
|
||||
|
||||
<section anchor="acknowledgments"><name>Acknowledgments</name>
|
||||
|
||||
<ul spacing="compact">
|
||||
<li><eref target="https://nlnet.nl">NLNET</eref></li>
|
||||
<li><eref target="https://futureoftext.org">Future of Text</eref></li>
|
||||
<li><eref target="https://visual-meta.info">visual-meta.info</eref></li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section anchor="appendix-definitions"><name>Appendix: Definitions</name>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>definition</th>
|
||||
<th>explanation</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>scene</td>
|
||||
<td>a (local/remote) 3D scene or 3D file (index.gltf e.g.)</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>3D object</td>
|
||||
<td>an object inside a scene characterized by vertex-, face- and customproperty data.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>XR fragments</td>
|
||||
<td>URI Fragment with spatial hints like <tt>#pos=0,0,0&t=1,100</tt> e.g.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>query</td>
|
||||
<td>an URI Fragment-operator which queries object(s) from a scene like <tt>#q=cube</tt></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>FPS</td>
|
||||
<td>frames per second in spatial experiences (games,VR,AR e.g.), should be as high as possible</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td><tt>◻</tt></td>
|
||||
<td>ascii representation of an 3D object/mesh</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>(un)obtrusive</td>
|
||||
<td>obtrusive: wrapping human text/thought in XML/HTML/JSON obfuscates human text into a salad of machine-symbols and words</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table></section>
|
||||
|
||||
</middle>
|
||||
|
||||
</rfc>
|
||||
53
doc/fragments.awk
Normal file
53
doc/fragments.awk
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
BEGIN{
|
||||
ROUNDROBIN="🎲"
|
||||
ASSET="🔒"
|
||||
OVERRIDE="🔓"
|
||||
PV_OVERRIDE="💥"
|
||||
NAVIGATOR="👩"
|
||||
PROMPT="✋?"
|
||||
EMBEDDED="🔗"
|
||||
print "| fragment | type | access | scope |"
|
||||
print "|----------|------|--------------|-------|"
|
||||
}
|
||||
|
||||
END{
|
||||
print ""
|
||||
print ASSET" = value(s) can only defined in 3D asset (immutable)<br>"
|
||||
print OVERRIDE" = value(s) can be overwritten in certain context<br>"
|
||||
print ROUNDROBIN" = multiple values will be roundrobin'ed (`#pos=0,0,0|1,0,0` e.g.)<br>"
|
||||
print PV_OVERRIDE" = value(s) can be overwritten by [predefined_view](#predefined_view)<br>"
|
||||
print NAVIGATOR" = value(s) can be overwritten when user clicks `href` (value) or top-level URL change(see [How it works](#How%20it%20works))<br>"
|
||||
print EMBEDDED" = value(s) can be overwritten when 3D asset is embedded/linked as `src` value<br>"
|
||||
print PROMPT" = value(s) can be overwritten by offering confirmation/undo to user<br><br>"
|
||||
print ""
|
||||
print "for more info see [How it works](#How%20it%20works)"
|
||||
}
|
||||
|
||||
/category:/ {
|
||||
$1=$2=""
|
||||
sub(/^[[:space:]]+/, "", $0 ) # remove leading spaces
|
||||
sub(/[[:space:]]+$/, "", $0 ) # remove trailing spaces
|
||||
scope=$0
|
||||
}
|
||||
|
||||
|
||||
/Frag.*XRF\.*/ {
|
||||
gsub(/.*\("/,"",$1)
|
||||
gsub(/".*/,"",$1)
|
||||
type="string"
|
||||
perms = $0 ~ /OVERRIDE/ ? OVERRIDE : ASSET
|
||||
frag=$1
|
||||
$1=""
|
||||
if( $0 ~ /T_INT/ ) type="int"
|
||||
if( $0 ~ /T_STRING_OBJ/ ) type="[string object](string object ) "
|
||||
if( $0 ~ /T_VECTOR2/ ) type="[vector2](#vector ) "
|
||||
if( $0 ~ /T_VECTOR3/ ) type="[vector3](#vector ) "
|
||||
if( $0 ~ /T_URL/ ) type="[url](#url ) "
|
||||
if( $0 ~ /T_PREDEFINED_VIEW/ ) type="[predefined view](#predefined_view ) "
|
||||
if( $0 ~ /ROUNDROBIN/ ) perms=perms" "ROUNDROBIN
|
||||
if( $0 ~ /PV_OVERRIDE/ ) perms=perms" "PV_OVERRIDE
|
||||
if( $0 ~ /NAVIGATOR/ ) perms=perms" "NAVIGATOR
|
||||
if( $0 ~ /EMBEDDED/ ) perms=perms" "EMBEDDED
|
||||
if( $0 ~ /PROMPT/ ) perms=perms" "PROMPT
|
||||
print "| **"frag"** |" type "|" perms "|" scope "|"
|
||||
}
|
||||
33
doc/generate.awk
Normal file
33
doc/generate.awk
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
# a no-nonsense source-to-markdown generator which scans for:
|
||||
#
|
||||
# /**
|
||||
# * # foo
|
||||
# *
|
||||
# * this is markdown $(cat bar.md)
|
||||
# */
|
||||
#
|
||||
# var foo; // comment with 2 leading spaces is markdown too $(date)
|
||||
#
|
||||
# easily refactorable to hash-based languages (py/bash/perl/lua e.g.)
|
||||
# by changing the regexes
|
||||
#
|
||||
/\$\(/ { cmd=$0;
|
||||
gsub(/^.*\$\(/,"",cmd);
|
||||
gsub(/\).*/,"",cmd);
|
||||
cmd | getline stdout; close(cmd);
|
||||
sub(/\$\(.*\)/,stdout);
|
||||
}
|
||||
/\/\*\*/ { doc=1; sub(/^.*\/\*/,""); }
|
||||
doc && /\*\// { doc=0;
|
||||
sub(/[[:space:]]*\*\/.*/,"");
|
||||
sub(/^[[:space:]]*\*[[:space:]]?/,"");
|
||||
print
|
||||
}
|
||||
doc && /^[[:space:]]*\*/ { sub(/^[[:space:]]*\*[[:space:]]?/,"");
|
||||
print
|
||||
}
|
||||
!doc && /\/\/ / { sub(".*// ","");
|
||||
sub("# ","\n# ");
|
||||
sub("> ","\n> ");
|
||||
print
|
||||
}
|
||||
10
doc/generate.sh
Executable file
10
doc/generate.sh
Executable file
|
|
@ -0,0 +1,10 @@
|
|||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
for topic in Fragments Macros; do
|
||||
mmark RFC_XR_$topic.md > RFC_XR_$topic.xml
|
||||
mmark --html RFC_XR_$topic.md | grep -vE '(<!--{|}-->)' > RFC_XR_$topic.html
|
||||
xml2rfc --v3 RFC_XR_$topic.xml # RFC_XR_$topic.txt
|
||||
sed -i 's/Expires: .*//g' RFC_XR_$topic.txt
|
||||
convert -size 700x2400 xc:white -font "FreeMono" +antialias -pointsize 12 -fill black -annotate +15+15 "@RFC_XR_Fragments.txt" -colorspace gray +dither -posterize 6 RF6_XR_Fragments.png
|
||||
done
|
||||
3
doc/notes/prio.md
Normal file
3
doc/notes/prio.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
\#static allow client to ignore lower-prio objects in the renderloop, to compensate frame-drop/cpu/gpu-overload scenario’s
|
||||
|
||||
Q: should `-` be used to indicate 'lowering' priority (css's `z-index` 0-??? range is a bit confusing in that sense)
|
||||
25
doc/shell.nix
Normal file
25
doc/shell.nix
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
{ pkgs ? import <nixos-unstable> {} } :
|
||||
{
|
||||
|
||||
pkgs = import (builtins.fetchGit {
|
||||
name = "nixos-23.05";
|
||||
url = "https://github.com/nixos/nixpkgs/";
|
||||
ref = "refs/heads/nixos-unstable";
|
||||
rev = "ef99fa5c5ed624460217c31ac4271cfb5cb2502c";
|
||||
});
|
||||
|
||||
foo = pkgs.mkShell {
|
||||
# nativeBuildInputs is usually what you want -- tools you need to run
|
||||
nativeBuildInputs = with pkgs.buildPackages; [
|
||||
|
||||
mmark
|
||||
xml2rfc
|
||||
python312Packages.lxml
|
||||
wkhtmltopdf-bin
|
||||
imagemagick
|
||||
|
||||
];
|
||||
};
|
||||
|
||||
# to create [markdown] table of contents use LLM with this input: awk '/id="/ { print $0 }' RFC_XR_Fragments.html | grep -v idx
|
||||
}
|
||||
489
doc/style.css
Normal file
489
doc/style.css
Normal file
|
|
@ -0,0 +1,489 @@
|
|||
:root {
|
||||
--color-a: black;
|
||||
--color-at: #000000CC;
|
||||
--color-b: #222;
|
||||
--color-c: #444;
|
||||
--color-d: #888;
|
||||
--color-e: #FF0;
|
||||
--color-f: #CCC;
|
||||
--color-g: #FFF;
|
||||
--color-gt: #FFF5;
|
||||
--params-width: 320px;
|
||||
--font-1: 'Montserrat', sans-serif;
|
||||
--font-2: monospace, courier;
|
||||
--font-size-1: 57px;
|
||||
--font-size-2: 26px;
|
||||
--font-size-3: 18px;
|
||||
--font-size-4: 15px;
|
||||
--gutter-1: 10%;
|
||||
--gradient-1: linear-gradient(45deg, #dc2454 0%, #944a9d 51%, #4824dc 100%);
|
||||
--gradient-2: linear-gradient(45deg, #dc2454 0%, #944a9d 21%, #4824dc 50%,#dc2454 70%, #944a9d 88%, #4824dc 100%);
|
||||
}
|
||||
|
||||
body>h1:nth-child(1) {
|
||||
display:none;
|
||||
}
|
||||
|
||||
body{
|
||||
position:relative;
|
||||
width:100%;
|
||||
height:100vh;
|
||||
color: var(--color-d);
|
||||
line-height: 38px;
|
||||
margin:0;
|
||||
padding:0;
|
||||
font-size: var(--font-size-3);
|
||||
}
|
||||
|
||||
* {
|
||||
font-family: var(--font-1);
|
||||
font-size: var(--font-size-3);
|
||||
font-weight:500;
|
||||
color: var(--color-c);
|
||||
}
|
||||
|
||||
img,
|
||||
.img{
|
||||
image-rendering: -webkit-optimize-contrast;
|
||||
}
|
||||
|
||||
#jumbotron{
|
||||
margin-top:50px;
|
||||
}
|
||||
|
||||
b{
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: var(--color-c);
|
||||
font-size: var(--font-size-1);
|
||||
font-weight:700;
|
||||
margin: 0;
|
||||
line-height: 11vh;
|
||||
padding-right:40px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: var(--font-size-2);
|
||||
font-weight:400;
|
||||
padding-right:40px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
background-image: var(--gradient-1);
|
||||
color: var(--color-g);
|
||||
display:inline;
|
||||
border-radius: 5px;
|
||||
padding: 2px 10px 2px 10px;
|
||||
font-weight: 600;
|
||||
font-size: var(--font-size-4);
|
||||
text-transform:uppercase;
|
||||
white-space:nowrap;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 700px) {
|
||||
body {
|
||||
font-size: var(--font-size-3);
|
||||
line-height: 40px;
|
||||
}
|
||||
svg.img{
|
||||
transform: scale(0.8);
|
||||
}
|
||||
.content{
|
||||
padding-top: 60px;
|
||||
margin-left: 27px !important;
|
||||
padding-right: 54px !important;
|
||||
}
|
||||
.heading{
|
||||
transform:scale(0.7);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
table {
|
||||
border:none;
|
||||
box-shadow: 0px 0px 10px #0005;
|
||||
padding:20px;
|
||||
background: transparent !important;
|
||||
border-radius:4px;
|
||||
}
|
||||
table tr td,
|
||||
table tr th {
|
||||
vertical-align:top;
|
||||
text-align:left;
|
||||
border-bottom:1px solid #555;
|
||||
color: var(--color-d);
|
||||
}
|
||||
table tr td a:visited,
|
||||
table tr td a:active,
|
||||
table tr td a{
|
||||
color: var(--color-e);
|
||||
}
|
||||
table tr:last-child td{
|
||||
border:none;
|
||||
}
|
||||
table tr th {
|
||||
border-bottom:2px solid var(--color-d);
|
||||
}
|
||||
|
||||
code{
|
||||
display: inline-block;
|
||||
unicode-bidi: embed;
|
||||
font-family: monospace;
|
||||
white-space: pre;
|
||||
background: var(--color-c);
|
||||
margin-bottom: 5px;
|
||||
padding: 0px 5px;
|
||||
font-size:16px;
|
||||
}
|
||||
|
||||
.content {
|
||||
height:99vh;
|
||||
max-width: 50em;
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
padding-top:25px;
|
||||
box-sizing:border-box;
|
||||
}
|
||||
|
||||
a,a:visited,a:active{
|
||||
color: var(--color-a);
|
||||
display:inline-block;
|
||||
text-decoration:none;
|
||||
}
|
||||
a:hover{
|
||||
opacity:0.9;
|
||||
}
|
||||
|
||||
/* lato-regular - latin */
|
||||
@font-face {
|
||||
font-family: 'Lato';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: url('/assets/font/lato-v17-latin-regular.eot'); /* IE9 Compat Modes */
|
||||
src: local(''),
|
||||
url('/assets/font/lato-v17-latin-regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
|
||||
url('/assets/font/lato-v17-latin-regular.woff2') format('woff2'), /* Super Modern Browsers */
|
||||
url('/assets/font/lato-v17-latin-regular.woff') format('woff'), /* Modern Browsers */
|
||||
url('/assets/font/lato-v17-latin-regular.ttf') format('truetype'), /* Safari, Android, iOS */
|
||||
url('/assets/font/lato-v17-latin-regular.svg#Lato') format('svg'); /* Legacy iOS */
|
||||
}
|
||||
|
||||
#sidemenu {
|
||||
position:absolute;
|
||||
top:0;
|
||||
left:0;
|
||||
}
|
||||
|
||||
#sidemenu nav {
|
||||
width: 300px;
|
||||
box-shadow: 0px 0px 8px #0005;
|
||||
background:#FFF;
|
||||
z-index:10;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 99;
|
||||
height:100vh;
|
||||
}
|
||||
#sidemenu .sidemenu__btn {
|
||||
display: block;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
top:20px;
|
||||
left:20px;
|
||||
background: transparent;
|
||||
border: none;
|
||||
position: fixed;
|
||||
z-index: 100;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
}
|
||||
#sidemenu .sidemenu__btn span {
|
||||
display: block;
|
||||
width: 30px;
|
||||
height: 3px;
|
||||
margin: auto;
|
||||
background:var(--color-d);
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
-webkit-transition: all .4s ease;
|
||||
transition: all .4s ease;
|
||||
}
|
||||
#sidemenu .sidemenu__btn span.top {
|
||||
-webkit-transform: translateY(-8px);
|
||||
transform: translateY(-8px);
|
||||
}
|
||||
#sidemenu .sidemenu__btn span.bottom {
|
||||
-webkit-transform: translateY(8px);
|
||||
transform: translateY(8px);
|
||||
}
|
||||
#sidemenu .sidemenu__btn.active .top {
|
||||
-webkit-transform: rotate(-45deg);
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
#sidemenu .sidemenu__btn.active .mid {
|
||||
-webkit-transform: translateX(-20px) rotate(360deg);
|
||||
transform: translateX(-20px) rotate(360deg);
|
||||
opacity: 0;
|
||||
}
|
||||
#sidemenu .sidemenu__btn.active .bottom {
|
||||
-webkit-transform: rotate(45deg);
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
#sidemenu .sidemenu__wrapper {
|
||||
padding-top: 70px;
|
||||
margin-left:20px;
|
||||
}
|
||||
#sidemenu .sidemenu__list {
|
||||
overflow-y: scroll;
|
||||
max-height: 73vh;
|
||||
padding-top: 50px;
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
#sidemenu .sidemenu__item {
|
||||
padding: 0;
|
||||
}
|
||||
#sidemenu li > a {
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
-webkit-transition: .4s ease;
|
||||
transition: .4s ease;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
nav {
|
||||
-webkit-transition: .2s ease;
|
||||
transition: .2s ease;
|
||||
-webkit-transform: translateX(0px);
|
||||
transform: translateX(0px);
|
||||
opacity:1;
|
||||
}
|
||||
|
||||
nav.hide {
|
||||
-webkit-transform: translateX(-300px);
|
||||
transform: translateX(-300px);
|
||||
opacity:0;
|
||||
}
|
||||
|
||||
ul, ol {
|
||||
margin-left:30px !important;
|
||||
margin-top: 35px !important;
|
||||
margin-bottom: 35px !important;
|
||||
}
|
||||
ul:nth-child(1){
|
||||
margin:0;
|
||||
}
|
||||
|
||||
ul,li{
|
||||
text-decoration:none !important;
|
||||
/*list-style:none;*/
|
||||
padding-left:10px;
|
||||
padding-right:10px;
|
||||
}
|
||||
|
||||
li > a,
|
||||
li > a.visited,
|
||||
li > a.active{
|
||||
color:#555;
|
||||
padding:5px;
|
||||
}
|
||||
li > b {
|
||||
background:#FFF;
|
||||
padding:5px;
|
||||
}
|
||||
|
||||
.sidemenu__list > li,
|
||||
.sidemenu__list > ul > li{
|
||||
display:inline-block;
|
||||
}
|
||||
|
||||
ul > li {
|
||||
display:block;
|
||||
}
|
||||
|
||||
.content ul > li::before {content: "•"; padding-right:10px;color: #54F;}
|
||||
|
||||
li > b {
|
||||
font-weight:100;
|
||||
}
|
||||
|
||||
.touchscreen {
|
||||
border:30px solid #aab5bb;
|
||||
border-radius:20px;
|
||||
position:relative;
|
||||
}
|
||||
.touchscreen:after {
|
||||
content:"";
|
||||
display:block;
|
||||
position:absolute;
|
||||
border-radius:50%;
|
||||
width:15px;
|
||||
height:15px;
|
||||
background:#FFF;
|
||||
top:136px;
|
||||
right:-22px;
|
||||
|
||||
}
|
||||
|
||||
div.pretty{
|
||||
border-radius: 4px;
|
||||
display: block;
|
||||
background: #372e42;
|
||||
overflow-x: scroll;
|
||||
white-space:pre-wrap;
|
||||
color:#65e;
|
||||
}
|
||||
|
||||
code.pretty,
|
||||
div.pretty > pre > code{
|
||||
background: -webkit-linear-gradient(-70deg,#98a7f0,#0d4e50);
|
||||
background-clip: border-box;
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
border: none;
|
||||
text-shadow: 0px 0px 5px #fff9;
|
||||
filter: brightness(1.8);
|
||||
font-size:14px;
|
||||
width:98%;
|
||||
padding:0px 15px;
|
||||
margin:0;
|
||||
box-sizing:border-box;
|
||||
line-height:20px;
|
||||
}
|
||||
|
||||
blockquote{
|
||||
box-sizing: border-box;
|
||||
background: transparent !important;
|
||||
border-radius: 7px;
|
||||
padding: 20px;
|
||||
width: 100%;
|
||||
margin: 30px 0px 20px 0px;
|
||||
color: var(--color-f) !important;
|
||||
font-weight: bold;
|
||||
}
|
||||
blockquote a {
|
||||
color:#000 !important;
|
||||
}
|
||||
blockquote a:hover {
|
||||
color:#FFF !important;
|
||||
background:#000;
|
||||
}
|
||||
|
||||
img {
|
||||
width:100%;
|
||||
filter: brightness(0.97)
|
||||
}
|
||||
|
||||
/* GRID SYSTEM */
|
||||
.block{
|
||||
display: block;
|
||||
text-align: left;
|
||||
margin-bottom: var(--gutter-1);
|
||||
min-height:55vh;
|
||||
}
|
||||
|
||||
.block .img{
|
||||
border-radius:15px;
|
||||
width:100%;
|
||||
height:35vh;
|
||||
margin-bottom:15px;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
p{ margin:0; padding:0; }
|
||||
|
||||
//the grid:
|
||||
|
||||
.grid{
|
||||
width: 90%;
|
||||
max-width: 900px;
|
||||
margin: 0 auto;
|
||||
background-color: $grid-color;
|
||||
//just for styling:
|
||||
padding-top: var(--gutter-1);
|
||||
}
|
||||
|
||||
.gutter{
|
||||
/*
|
||||
margin-left: calc( var(--gutter-1) /2 );
|
||||
margin-right: calc( var(--gutter-1) /2 );
|
||||
*/
|
||||
margin-right: var(--gutter-1);
|
||||
}
|
||||
|
||||
.col-33{
|
||||
width: 33.3%;
|
||||
float: left;
|
||||
}
|
||||
.col-50{
|
||||
width: 50%;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.clear{
|
||||
clear: both;
|
||||
display: block;
|
||||
}
|
||||
|
||||
//responsive
|
||||
|
||||
@media all and (max-width:800px) {
|
||||
.col-33{
|
||||
width: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (max-width:600px) {
|
||||
.col-50, .col-33{
|
||||
width: 100%;
|
||||
float: none;
|
||||
}
|
||||
h1 {
|
||||
font-size: 50px;
|
||||
line-height:70px;
|
||||
}
|
||||
h2{
|
||||
font-size: var(--font-size-3);
|
||||
}
|
||||
.block.gutter{
|
||||
margin-right:0;
|
||||
}
|
||||
}
|
||||
|
||||
.darken{
|
||||
filter: brightness(0.8);
|
||||
}
|
||||
|
||||
button{
|
||||
cursor:pointer;
|
||||
padding: 10px;
|
||||
border-radius: 6px;
|
||||
background-image: var(--gradient-1);
|
||||
border: none;
|
||||
border-radius: 20px;
|
||||
display:inline-block;
|
||||
color: #FFF;
|
||||
border: none;
|
||||
opacity:1.0;
|
||||
font-size: var(--font-size-4);
|
||||
font-weight:600;
|
||||
}
|
||||
button:hover{
|
||||
opacity:0.8;
|
||||
}
|
||||
|
||||
.gradient{
|
||||
background-image: var(--gradient-2);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
4171
index.html
Normal file
4171
index.html
Normal file
File diff suppressed because one or more lines are too long
Loading…
Add table
Reference in a new issue