toString=String,"string"==typeof code||code instanceof String||(code=toString(code)),source=code,index=0,lineNumber=source.length>0?1:0,lineStart=0,length=source.length,buffer=null,state={allowIn:!0,labelSet:{},inFunctionBody:!1,inIteration:!1,inSwitch:!1},extra={},options!==void 0&&(extra.range="boolean"==typeof options.range&&options.range,extra.loc="boolean"==typeof options.loc&&options.loc,extra.raw="boolean"==typeof options.raw&&options.raw,"boolean"==typeof options.tokens&&options.tokens&&(extra.tokens=[]),"boolean"==typeof options.comment&&options.comment&&(extra.comments=[]),"boolean"==typeof options.tolerant&&options.tolerant&&(extra.errors=[])),length>0&&source[0]===void 0&&(code instanceof String&&(source=code.valueOf()),source[0]===void 0&&(source=stringToArray(code))),patch();try{program=parseProgram(),extra.comments!==void 0&&(filterCommentLocation(),program.comments=extra.comments),extra.tokens!==void 0&&(filterTokenLocation(),program.tokens=extra.tokens),extra.errors!==void 0&&(program.errors=extra.errors),(extra.range||extra.loc)&&(program.body=filterGroup(program.body))}catch(e){throw e}finally{unpatch(),extra={}}return program}var Token,TokenName,Syntax,PropertyKind,Messages,Regex,source,strict,index,lineNumber,lineStart,length,buffer,state,extra;Token={BooleanLiteral:1,EOF:2,Identifier:3,Keyword:4,NullLiteral:5,NumericLiteral:6,Punctuator:7,StringLiteral:8},TokenName={},TokenName[Token.BooleanLiteral]="Boolean",TokenName[Token.EOF]="<end>",TokenName[Token.Identifier]="Identifier",TokenName[Token.Keyword]="Keyword",TokenName[Token.NullLiteral]="Null",TokenName[Token.NumericLiteral]="Numeric",TokenName[Token.Punctuator]="Punctuator",TokenName[Token.StringLiteral]="String",Syntax={AssignmentExpression:"AssignmentExpression",ArrayExpression:"ArrayExpression",BlockStatement:"BlockStatement",BinaryExpression:"BinaryExpression",BreakStatement:"BreakStatement",CallExpression:"CallExpression",CatchClause:"CatchClause",ConditionalExpression:"ConditionalExpression",ContinueStatement:"ContinueStatement",DoWhileStatement:"DoWhileStatement",DebuggerStatement:"DebuggerStatement",EmptyStatement:"EmptyStatement",ExpressionStatement:"ExpressionStatement",ForStatement:"ForStatement",ForInStatement:"ForInStatement",FunctionDeclaration:"FunctionDeclaration",FunctionExpression:"FunctionExpression",Identifier:"Identifier",IfStatement:"IfStatement",Literal:"Literal",LabeledStatement:"LabeledStatement",LogicalExpression:"LogicalExpression",MemberExpression:"MemberExpression",NewExpression:"NewExpression",ObjectExpression:"ObjectExpression",Program:"Program",Property:"Property",ReturnStatement:"ReturnStatement",SequenceExpression:"SequenceExpression",SwitchStatement:"SwitchStatement",SwitchCase:"SwitchCase",ThisExpression:"ThisExpression",ThrowStatement:"ThrowStatement",TryStatement:"TryStatement",UnaryExpression:"UnaryExpression",UpdateExpression:"UpdateExpression",VariableDeclaration:"VariableDeclaration",VariableDeclarator:"VariableDeclarator",WhileStatement:"WhileStatement",WithStatement:"WithStatement"},PropertyKind={Data:1,Get:2,Set:4},Messages={UnexpectedToken:"Unexpected token %0",UnexpectedNumber:"Unexpected number",UnexpectedString:"Unexpected string",UnexpectedIdentifier:"Unexpected identifier",UnexpectedReserved:"Unexpected reserved word",UnexpectedEOS:"Unexpected end of input",NewlineAfterThrow:"Illegal newline after throw",InvalidRegExp:"Invalid regular expression",UnterminatedRegExp:"Invalid regular expression: missing /",InvalidLHSInAssignment:"Invalid left-hand side in assignment",InvalidLHSInForIn:"Invalid left-hand side in for-in",MultipleDefaultsInSwitch:"More than one default clause in switch statement",NoCatchOrFinally:"Missing catch or finally after try",UnknownLabel:"Undefined label '%0'",Redeclaration:"%0 '%1' has already been declared",IllegalContinue:"Illegal continue statement",IllegalBreak:"Illegal break statement",IllegalReturn:"Illegal return statement",StrictModeWith:"Strict mode code may not include a with statement",StrictCatchVariable:"Catch variable may not be eval or arguments in strict mo
case"utf8":case"utf-8":ret=this.parent.utf8Write(string,this.offset+offset,length);break;case"ascii":ret=this.parent.asciiWrite(string,this.offset+offset,length);break;case"binary":ret=this.parent.binaryWrite(string,this.offset+offset,length);break;case"base64":ret=this.parent.base64Write(string,this.offset+offset,length);break;case"ucs2":case"ucs-2":ret=this.parent.ucs2Write(string,this.offset+offset,length);break;default:throw Error("Unknown encoding")}return Buffer._charsWritten=SlowBuffer._charsWritten,ret},Buffer.prototype.toString=function(encoding,start,end){switch(encoding=((encoding||"utf8")+"").toLowerCase(),start===void 0||0>start?start=0:start>this.length&&(start=this.length),end===void 0||end>this.length?end=this.length:0>end&&(end=0),start+=this.offset,end+=this.offset,encoding){case"hex":return this.parent.hexSlice(start,end);case"utf8":case"utf-8":return this.parent.utf8Slice(start,end);case"ascii":return this.parent.asciiSlice(start,end);case"binary":return this.parent.binarySlice(start,end);case"base64":return this.parent.base64Slice(start,end);case"ucs2":case"ucs-2":return this.parent.ucs2Slice(start,end);default:throw Error("Unknown encoding")}},Buffer.byteLength=SlowBuffer.byteLength,Buffer.prototype.fill=function(value,start,end){if(value||(value=0),start||(start=0),end||(end=this.length),"string"==typeof value&&(value=value.charCodeAt(0)),"number"!=typeof value||isNaN(value))throw Error("value is not a number");if(start>end)throw Error("end <start");if(end===start)return0;if(0==this.length)return0;if(0>start||start>=this.length)throw Error("start out of bounds");if(0>end||end>this.length)throw Error("end out of bounds");return this.parent.fill(value,start+this.offset,end+this.offset)},Buffer.prototype.copy=function(target,target_start,start,end){var source=this;if(start||(start=0),end||(end=this.length),target_start||(target_start=0),start>end)throw Error("sourceEnd <sourceStart");if(end===start)return0;if(0==target.length||0==source.length)return0;if(0>target_start||target_start>=target.length)throw Error("targetStart out of bounds");if(0>start||start>=source.length)throw Error("sourceStart out of bounds");if(0>end||end>source.length)throw Error("sourceEnd out of bounds");return end>this.length&&(end=this.length),end-start>target.length-target_start&&(end=target.length-target_start+start),this.parent.copy(target.parent,target_start+target.offset,start+this.offset,end+this.offset)},Buffer.prototype.slice=function(start,end){if(void 0===end&&(end=this.length),end>this.length)throw Error("oob");if(start>end)throw Error("oob");return new Buffer(this.parent,end-start,+start+this.offset)},Buffer.prototype.utf8Slice=function(start,end){return this.toString("utf8",start,end)},Buffer.prototype.binarySlice=function(start,end){return this.toString("binary",start,end)},Buffer.prototype.asciiSlice=function(start,end){return this.toString("ascii",start,end)},Buffer.prototype.utf8Write=function(string,offset){return this.write(string,offset,"utf8")},Buffer.prototype.binaryWrite=function(string,offset){return this.write(string,offset,"binary")},Buffer.prototype.asciiWrite=function(string,offset){return this.write(string,offset,"ascii")},Buffer.prototype.readUInt8=function(offset,noAssert){var buffer=this;return noAssert||(assert.ok(void 0!==offset&&null!==offset,"missing offset"),assert.ok(buffer.length>offset,"Trying to read beyond buffer length")),offset>=buffer.length?void 0:buffer.parent[buffer.offset+offset]},Buffer.prototype.readUInt16LE=function(offset,noAssert){return readUInt16(this,offset,!1,noAssert)},Buffer.prototype.readUInt16BE=function(offset,noAssert){return readUInt16(this,offset,!0,noAssert)},Buffer.prototype.readUInt32LE=function(offset,noAssert){return readUInt32(this,offset,!1,noAssert)},Buffer.prototype.readUInt32BE=function(offset,noAssert){return readUInt32(this,offset,!0,noAssert)},Buffer.prototype.readInt8=function(offset,noAssert){var neg,buffer=this;return noAssert||(assert.ok(void 0!==offset&&null!==offset,"missing offset"),assert.ok(buffer.length>offset,"Trying to read beyond
a.TEXTURE_WRAP_S,a.CLAMP_TO_EDGE);a.texParameteri(a.TEXTURE_2D,a.TEXTURE_WRAP_T,a.CLAMP_TO_EDGE);a.texParameteri(a.TEXTURE_2D,a.TEXTURE_MIN_FILTER,b?a.NEAREST:a.LINEAR);a.texParameteri(a.TEXTURE_2D,a.TEXTURE_MAG_FILTER,b?a.NEAREST:a.LINEAR)}let d,c,f=a.createFramebuffer();a.bindFramebuffer(a.FRAMEBUFFER,f);let e=a.createTexture();if(!e)throw Error("createTexture returned null");a.bindTexture(a.TEXTURE_2D,e);b(!0);a.framebufferTexture2D(a.FRAMEBUFFER,a.COLOR_ATTACHMENT0,a.TEXTURE_2D,e,0);return{get handle(){return f},
get texture(){return e},updateTexture:b,bind:function(){a.bindFramebuffer(a.FRAMEBUFFER,f);a.viewport(0,0,d,c)},updateResolution:function(b,f){if(b!==d||f!==c)d=b,c=f,a.bindTexture(a.TEXTURE_2D,e),a.texImage2D(a.TEXTURE_2D,0,a.RGBA,b,f,0,a.RGBA,a.FLOAT,null)},dispose:function(){a.deleteFramebuffer(f);a.deleteTexture(e)}}}function O(a,b,d){b=a.createShader(b);a.shaderSource(b,d);a.compileShader(b);if(!a.getShaderParameter(b,a.COMPILE_STATUS)){let c=a.getShaderInfoLog(b);a.deleteShader(b);console.warn(c,
b,d={}){function c(){a.getParameter(a.ACTIVE_TEXTURE)!==b&&a.activeTexture(a["TEXTURE".concat(b)])}function f(){h.forEach(b=>{a.texParameteri(p,b[0],b[1])})}function e(b){if("object"===typeof b){Object.assign(n,b);c();a.bindTexture(p,v);var {level:d,internalFormat:e,offsetX:h,offsetY:r,width:g,height:t,border:m,format:B,type:D,flipY:z,buffer:y,pixels:A}=n;f();a.pixelStorei(a.UNPACK_FLIP_Y_WEBGL,z);if(A){let [c,d]=Q(A);if(0===c||0===d){console.warn("Texture size is invalid ".concat(c," x ").concat(d,
". Update is skipped;"));return}{({pixels:b}=n);var J=a.getTexParameter(p,a.TEXTURE_WRAP_S);let c=a.getTexParameter(p,a.TEXTURE_WRAP_T),d=a.getTexParameter(p,a.TEXTURE_MIN_FILTER),f=G(b.width)&&G(b.height);(J=J!==a.CLAMP_TO_EDGE||c!==a.CLAMP_TO_EDGE||d!==a.LINEAR&&d!==a.NEAREST)&&!f&&(l||(l=document.createElement("canvas"),l.width=2**Math.floor(Math.log(b.width)/Math.LN2),l.height=2**Math.floor(Math.log(b.height)/Math.LN2),console.warn("Texture is not power of two ".concat(b.width," x ").concat(b.height,
". Resized to ").concat(l.width," x ").concat(l.height,";"))),l.getContext("2d").drawImage(b,0,0,l.width,l.height));q=J&&l||b}}"number"===typeof h&&"number"===typeof r?q?a.texSubImage2D(p,d,h,r,B,D,q):a.texSubImage2D(p,d,h,r,g,t,B,D,y):q?a.texImage2D(p,d,e,B,D,q):a.texImage2D(p,d,e,g,t,m,B,D,y);q&&G(q.width)&&G(q.height)&&(b=a.getTexParameter(p,a.TEXTURE_MIN_FILTER),b!==a.LINEAR&&b!==a.NEAREST&&a.generateMipmap(p))}}let p=a.TEXTURE_2D,v=a.createTexture(),n={},h=[],q,l;e(Object.assign({level:0,internalFormat:a.RGBA,
offsetX:null,offsetY:null,width:1,height:1,border:0,format:a.RGBA,type:a.UNSIGNED_BYTE,flipY:!0,buffer:ta,pixels:null},"object"===typeof d?d:{}));return{setParameters:function(b){c();h.length=0;b.forEach(b=>{h.push(b);a.texParameteri(p,b[0],b[1])})},shallow:function(){c();a.bindTexture(p,v);f()},update:e,dispose:function(){a.deleteTexture(v)}}}function ua(a){return new Promise((b,d)=>{let c=new XMLHttpRequest;c.open("GET",a,!0);c.responseType="arraybuffer";c.onreadystatechange=()=>{c.readyState===
XMLHttpRequest.DONE&&(200===c.status||206===c.status?b(c.response):(console.log(c),d(c.status)))};c.send()})}function va(a,b){return new Promise((d,c)=>{b.decodeAudioData(a,d,c)})}function wa(a,b,d,c,f,e,p,v){async function n(){g=l.createBufferSource();g.buffer=await va(await ua(c),l);g.loop=e;g.start();t=!0}function h(){let a=document.querySelector(c);a&&a instanceof HTMLAudioElement&&(r=a,g=l.createMediaElementSource(a))}function q(a,b){a.connect(m);m.connect(b)}f=a.gl;let l=a.wa,m=l.createAnalyser();
K?(g=g.surface.dom,t=3,l()):console.warn("src: ".concat(c,": element is not a valid texture source")):console.warn("src: ".concat(c,": no element could be selected"))}return{dispose:function(){r.dispose()},update:function(a){x.forEach(a);h||w()&&g.readyState===g.HAVE_ENOUGH_DATA?(w()&&(B||(B=!0,k(),r.setParameters([[u.TEXTURE_WRAP_S,u.CLAMP_TO_EDGE],[u.TEXTURE_WRAP_T,u.CLAMP_TO_EDGE],[u.TEXTURE_MIN_FILTER,u.LINEAR]]))),r.update({pixels:g})):r.shallow()}}}function Aa(a){function b(a){n.forEach(a=>
"y","z","w"]}attributeChangedCallback(a,b,d){switch(a){case "x":case "y":case "z":case "w":null!=d&&this.renderer.setUniform(this.name,this.getValue())}}init(a){this.name?(this.program=a,this.renderer.addUniform(this.name,this.getValue(),this.type)):console.warn("sd-uniform created without a name.")}}customElements.get("sd-uniform")||customElements.define("sd-uniform",Ia);let Ja=new Set(["touchstart","touchmove","touchend"]);var U=a=>{a=Ja.has(a.type)&&"object"===typeof a.touches[0]?a.touches[0]:
a;return[a.clientX||0,a.clientY||0]};class K extends Z{static get observedAttributes(){return["height","width"]}constructor(){super();this.shadow=this.attachShadow({mode:"open"})}connectedCallback(){this.shadow.innerHTML=W.render(this.width,this.height);this.canvas=W.map(this.shadow).canvas;setTimeout(()=>{try{this.init()}catch(a){console.error(a&&a.message||"Error in shader-doodle.")}})}disconnectedCallback(){super.disconnectedCallback();this.renderer.removeSurface(this.surface);this.surface.dispose();
<!--~~ Static content for Google and browsers without JavaScript ~~-->
<noscript>
<divid="splashArea">
<p>This <aclass="tc-tiddlylink-external"href="https://tiddlywiki.com"rel="noopener noreferrer"target="_blank">TiddlyWiki</a> contains the following tiddlers:</p><p><ul>
{"created":"20240131104509452","text":"Create an empty mesh object (in Blender it's called an 'Empty') and add an [[src]] custom property with an OGG/MP3/WAV URL. For example:\n\u003Cbr>\u003Cbr>\n`src` : `https://foo.com/podcast.mp3`\n\u003Cbr>\u003Cbr>\n1. ''IF'' the empty is positioned at 0,0,0 the audio is nonpositional (like music e.g.)\u003Cbr>\u003Cbr>\n2. ''IF'' the empty is ''not'' positioned at 0,0,0, then it'll be positional audio\u003Cbr>\u003Cbr>\n3. the ''scale'' of the audio object will determine the amplitude/reach of the positional audio.\u003Cbr>\u003Cbr>\n\u003Cbr>\n\n> NOTE: audio does not play unless [[#t|`#t=1`]] triggers it. For auto-play try adding `#t=1` to the default fragment `#` on the scene ([[see this video|https://coderofsalvation.codeberg.page/xrfragment.media/gettingstarted2024.mp4#t=358]])","tags":"[[📡 implicit scene features]]","title":"(non)positional audio","modified":"20241007083525196"},
{"created":"20240208125917539","text":"`#` indicates a default fragment to execute during scene-load.\n\n| fragment | type | example value | info |\n|`#`| string (& separated) | `#-cube&t=0` | hide object with name `cube` and start 3D animations (implies `xrf://-cube&t=0`)|\n\n> NOTE: this only gets publish to the [[hashbus]] and does not update the top-Level URL\n\n[[» discussion|https://github.com/coderofsalvation/xrfragment/issues/12]]\u003Cbr>\n","tags":"[[📜 level2: metadata extras]]","title":"#","modified":"20241007085507403","type":"text/vnd.tiddlywiki"},
{"created":"20241007083043404","text":"reference object(s) within a scene (by name)\n\n| fragment | type | functionality |\n| \u003Cb>#car&room\u003C/b> | string | reference object(s) with name `car` (and `room`) |\n\nIt is up to the implementation what to do with it (import objects from a remote scene-file, or [[highlight them|Selection of interest]] in the current scene)","tags":"level1 [[🖇 implicit URI fragments]]","title":"#\u003Cobjectname>","modified":"20241007083412151","type":"text/vnd.tiddlywiki"},
{"created":"20240207131001873","text":"!! Specify playback loopmode\n\nThe missing element from Media Fragments.\n\n| fragment | type | functionality |\n| \u003Cb>#loop\u003C/b> | string | enables animation/video/audio loop |\n| \u003Cb>#-loop\u003C/b> | string | disables animation/video/audio loop |\n\n> `#loop` is fully functional, but not part of the official W3C Media Fragments (yet?)\n\n\u003Cbr>\n\u003Cdiv style=\"max-width:600px\">\n\u003C$videojs controls=\"controls\" aspectratio=\"16:9\" preload=\"auto\" poster=\"\" fluid=\"fluid\" class=\"vjs-big-play-centered\">\n \u003Csource src=\"https://coderofsalvation.codeberg.page/xrfragment.media/media_uv_template_fragments.mp4\" type=\"video/mp4\"/>\n\u003C/$videojs>\n\u003C/div>\n\n!Spec\n\nBelow is the related section of the spec (full spec here: \u003Ca href=\"doc/RFC_XR_Fragments.html\" target=\"_blank\">HTML\u003C/a>, \u003Ca href=\"doc/RFC_XR_Fragments.txt\" target=\"_blank\">TXT\u003C/a>)\n\n\u003Ciframe src=\"doc/RFC_XR_Fragments.html#list-of-uri-fragments\" frameborder=\"0\" class=\"spec\">\u003C/iframe>\n\n\u003Cbr>\u003CBr>\n[[» discussion|https://github.com/coderofsalvation/xrfragment/issues/14]]\u003Cbr>\n","tags":"[[🎞 Media Fragments]]","title":"#loop 🌱","modified":"20240228121548299","type":"text/vnd.tiddlywiki"},
{"created":"20230815155307052","text":"\n\nset the position of the camera ([[filtered|filters]] object(s)).\n\n| fragment | type | functionality |\n| \u003Cb>#pos\u003C/b>=0,0,0 | [[vector3|vector]] |position camera |\n| \u003Cb>#pos\u003C/b>=roomB | string |position camera to position of object with name `roomB` |\n| \u003Cb>#pos\u003C/b>=cam2 | string | position camera to position of camera with name `cam02`, and make it active camera [follow animation e.g.] |\n\n> in case of referencing an object, attach/parent the camera to that object (so it animates along with the object)\n\nYou can add this URI Fragment to the top-level URLbar, or as [[href]] value (to trigger via click) in a 3D model Editor (Blender e.g.):\u003Cbr>\u003Cbr>\n\n\u003Cdiv style=\"max-width:600px\">\n\u003C$videojs controls=\"controls\" aspectratio=\"16:9\" preload=\"auto\" poster=\"\" fluid=\"fluid\" class=\"vjs-big-play-centered\">\n \u003Csource src=\"https://coderofsalvation.codeberg.page/xrfragment.media/gettingstarted2024.mp4#t=295\" type=\"video/mp4\"/>\n\u003C/$videojs>\n\u003C/div>\n\n\u003Ch2>Developers only:\u003C/h2>\n\n[[» example implementation|https://github.com/coderofsalvation/xrfragment/blob/main/src/3rd/js/three/xrf/pos.js]]\u003Cbr>\n[[» discussion|https://github.com/coderofsalvation/xrfragment/issues/5]]\u003Cbr>\n\n!Spec\n\nBelow is the related section of the spec (full spec here: \u003Ca href=\"doc/RFC_XR_Fragments.html\" target=\"_blank\">HTML\u003C/a>, \u003Ca href=\"doc/RFC_XR_Fragments.txt\" target=\"_blank\">TXT\u003C/a>)\n\n\u003Ciframe src=\"doc/RFC_XR_Fragments.html#navigating-3d\" frameborder=\"0\" class=\"spec\">\u003C/iframe>\n","tags":"[[🔗 URL]] level1","title":"#pos","modified":"20241007190128830","type":"text/vnd.tiddlywiki"},
{"created":"20230815160020110","text":"\n\nset the rotation of the camera (or queried object(s)).\n\n| fragment | type | access | functionality |\n| \u003Cb>#rot\u003C/b>=0,90,0 | [[vector3|vector]] |🔓 🎲 💥 🔗| rotate camera (or [[filtered|#filters]] object(s)) |\n\nYou can add this URI Fragment to the top-level URLbar, or as [[href]] value (to trigger via click) in a 3D model Editor (Blender e.g.):\u003Cbr>\u003Cbr>\n\n\u003Cdiv style=\"max-width:600px\">\n\u003C$videojs controls=\"controls\" aspectratio=\"16:9\" preload=\"auto\" poster=\"\" fluid=\"fluid\" class=\"vjs-big-play-centered\">\n \u003Csource src=\"https://coderofsalvation.codeberg.page/xrfragment.media/gettingstarted2024.mp4#t=295\" type=\"video/mp4\"/>\n\u003C/$videojs>\n\u003C/div>\n\n\u003Ch2>Developers only:\u003C/h2>\n\n[[» example implementation|https://github.com/coderofsalvation/xrfragment/blob/main/src/3rd/js/three/xrf/rot.js]]\u003Cbr>\n[[» discussion|https://github.com/coderofsalvation/xrfragment/issues/7]]\u003Cbr>\n\n!Spec\n\nBelow is the related section of the spec (full spec here: \u003Ca href=\"doc/RFC_XR_Fragments.html\" target=\"_blank\">HTML\u003C/a>, \u003Ca href=\"doc/RFC_XR_Fragments.txt\" target=\"_blank\">TXT\u003C/a>)\n\n\u003Ciframe src=\"doc/RFC_XR_Fragments.html#navigating-3d\" frameborder=\"0\" class=\"spec\">\u003C/iframe>\n","tags":"[[🔗 URL]] level1","title":"#rot","modified":"20241007083021800","type":"text/vnd.tiddlywiki"},
{"created":"20240207130807055","text":"!! Play back speed\n\ncontrols the animation(s) of the scene (or `src` resource which contains a timeline)\n\n| fragment | type | functionality |\n| \u003Cb>#s\u003C/b>=1 | `[-]float` | set playback speed |\n\n> 🌱 = fully functional, but not part of the official W3C Media Fragments (yet?)\n\n\u003Cbr>\n\u003Cdiv style=\"max-width:600px\">\n\u003C$videojs controls=\"controls\" aspectratio=\"16:9\" preload=\"auto\" poster=\"\" fluid=\"fluid\" class=\"vjs-big-play-centered\">\n \u003Csource src=\"https://coderofsalvation.codeberg.page/xrfragment.media/media_uv_template_fragments.mp4\" type=\"video/mp4\"/>\n\u003C/$videojs>\n\u003C/div>\n\n!Spec\n\nBelow is the related section of the spec (full spec here: \u003Ca href=\"doc/RFC_XR_Fragments.html\" target=\"_blank\">HTML\u003C/a>, \u003Ca href=\"doc/RFC_XR_Fragments.txt\" target=\"_blank\">TXT\u003C/a>)\n\n\u003Ciframe src=\"doc/RFC_XR_Fragments.html#media-fragments-and-datatypes\" frameborder=\"0\" class=\"spec\">\u003C/iframe>\n\n\u003Cbr>\u003CBr>\n[[» discussion|https://github.com/coderofsalvation/xrfragment/issues/13]]\u003Cbr>\n","tags":"[[🎞 Media Fragments]]","title":"#s 🌱","modified":"20240228121853616","type":"text/vnd.tiddlywiki"},
{"created":"20231012145307424","text":"!!Animation(s) timeline\n\ncontrols the animation(s) of the scene (or `src` resource which contains a timeline)\n\n| fragment | type | functionality |\n| \u003Cb>#t\u003C/b>=start,stop | [[vector2]] (default:`#t=0,0`) | start,stop (in seconds |\n\n\n| Example Value | Explanation |\n| `#t=1` | play (3D) animations from 1 seconds till end (and stop) |\n| `#t=1,100` | play (3D) animations from 1 till 100 seconds (and stop) |\n| `#t=0,0` | stop (3D) animations at frame 0 |\n| `src`:`https://f.io/cat.mp4#t=0` | play video starting from `0` seconds till end (and stop) |\n| `src`:`https://f.io/cat.mp3#t=0` | play audio starting from `0` seconds till end (and stop) |\n| `src`:`https://f.io/cat.usdz3#t=2,3` | play 3D anim starting between `2` seconds and `3` (and loop) |\n\n> Use [[#s 🌱]] to control playback speed\n\n[[» example implementation|https://github.com/coderofsalvation/xrfragment/blob/main/src/3rd/js/three/xrf/t.js]]\u003Cbr>\n[[» discussion|https://github.com/coderofsalvation/xrfragment/issues/10]]\u003Cbr>\n\n\u003Cbr>\n\u003Cdiv style=\"max-width:600px\">\n\u003C$videojs controls=\"controls\" aspectratio=\"16:9\" preload=\"auto\" poster=\"\" fluid=\"fluid\" class=\"vjs-big-play-centered\">\n \u003Csource src=\"https://coderofsalvation.codeberg.page/xrfragment.media/media_uv_template_fragments.mp4\" type=\"video/mp4\"/>\n\u003C/$videojs>\n\u003C/div>\n\n\u003Cbr>\n\u003Cdiv style=\"max-width:600px\">\n\u003C$videojs controls=\"controls\" aspectratio=\"16:9\" preload=\"auto\" poster=\"\" fluid=\"fluid\" class=\"vjs-big-play-centered\">\n \u003Csource src=\"https://coderofsalvation.codeberg.page/xrfragment.media/animation.mp4\" type=\"video/mp4\"/>\n\u003C/$videojs>\n\u003C/div>\n\n!Spec\n\nBelow is the related section of the spec (full spec here: \u003Ca href=\"doc/RFC_XR_Fragments.html\" target=\"_blank\">HTML\u003C/a>, \u003Ca href=\"doc/RFC_XR_Fragments.txt\" target=\"_blank\">TXT\u003C/a>)\n\n\u003Ciframe src=\"doc/RFC_XR_Fragments.html#list-of-uri-fragments\" frameborder=\"0\" class=\"spec\">\u003C/iframe>\n\n!! Controlling embedded content\n\nuse [[URI Templates]] to control embedded media, for example a simple video-player:\n\n```\n\n foo.usdz \n │ \n │ \n ├── ◻ stopbutton \n │ ├ #: #-stopbutton\n │ └ href: #player=stop&-stopbutton (stop and hide stop-button)\n │ \n └── ◻ plane \n ├ play: #t=0,10\n ├ stop: #t=0,0\n ├ href: #player=play&stopbutton (play and show stop-button)\n └ src: cat.mp4#{player}\n\n\n```\n\n\u003Cbr>\u003CBr>\n[[» discussion|https://github.com/coderofsalvation/xrfragment/issues/10]]\u003Cbr>\n\n","tags":"[[🎞 Media Fragments]] level1","title":"#t","modified":"20241007083033780","type":"text/vnd.tiddlywiki"},
{"created":"20240207130824258","text":"!! UV offset\n\nsets the uv-coordinates of polygons/texture\n\n| fragment | type | functionality |\n| \u003Cb>#uv\u003C/b>=u,v,uspeed,vspeed | [[vector2]] | set/scroll to uv coordinate |\n\n> 🌱 means that this is an optional element of the XR Fragments spec (you can position the default uv-coordinates in your 3D editor)\n\n\u003Cbr>\n\u003Cdiv style=\"max-width:600px\">\n\u003C$videojs controls=\"controls\" aspectratio=\"16:9\" preload=\"auto\" poster=\"\" fluid=\"fluid\" class=\"vjs-big-play-centered\">\n \u003Csource src=\"https://coderofsalvation.codeberg.page/xrfragment.media/media_uv_template_fragments.mp4\" type=\"video/mp4\"/>\n\u003C/$videojs>\n\u003C/div>\n\n!Spec\n\nBelow is the related section of the spec (full spec here: \u003Ca href=\"doc/RFC_XR_Fragments.html\" target=\"_blank\">HTML\u003C/a>, \u003Ca href=\"doc/RFC_XR_Fragments.txt\" target=\"_blank\">TXT\u003C/a>)\n\n\u003Ciframe src=\"doc/RFC_XR_Fragments.html#media-fragments-and-datatypes\" frameborder=\"0\" class=\"spec\">\u003C/iframe>\n\n\u003Cbr>\u003CBr>\n[[» discussion|https://github.com/coderofsalvation/xrfragment/issues/15]]\u003Cbr>\n","tags":"[[🎞 Media Fragments]]","title":"#uv 🌱","modified":"20240228121656916","type":"text/vnd.tiddlywiki"},
{"created":"20230427174739986","text":"> in \u003Ca href=\"./dist/xrfragment.js\" target=\"_blank\">xrfragment.js\u003C/a>, and \u003Ca href=\"./dist/xrfragment.module.js\" target=\"_blank\">xrfragment.module.js\u003C/a>\n\nParse a fragment (key/value) and add it to an object store (if valid).\n\n> **NOTE**: You probably want to use the higher-level [URI.parse(url,filter)](#%E2%86%AA%20URI.parse%28url%2Cfilter%29) which calls this function\n\n| args | type | example | comment |\n|-|-|-|-|\n| key | string | `pos` | |\n| value | string | `1.2,3,4` | datatype must comply with [spec](#List%20of%20fragments) |\n| store | object | {} | will not be touched if validation failed, |\n\n> returns true if validated, otherwise false \n\nhere are some interactive examples:\n\n\u003Cdiv>\n \u003Ctextarea spellcheck=\"false\" autofocus class=\"sandboxify\">frags = {}\nok = xrfragment.Parser.parse('pos','1.2,2,3',frags)\nconsole.log( frags.pos )\n\n\u003C/textarea>\n\t\u003Cpre class=\"result\">\u003C/pre>\n\u003C/div>\n\n\u003Cbr>\n\nUnknown or fragments with wrong type will be rejected:\n\n\u003Cdiv>\n \u003Ctextarea spellcheck=\"false\" autofocus class=\"sandboxify\">frags = {}\nok = xrfragment.Parser.parse('pos','true',frags)\nconsole.log( frags.pos )\n\n\u003C/textarea>\n\t\u003Cpre class=\"result\">\u003C/pre>\n\u003C/div>\n\n# Spec \n\n> version 0.2 @ 2023-06-27T11:10:08+0200 [](https://github.com/coderofsalvation/xrfragment/actions)\n\nIn case your programming language has no parser ([check here](https://github.com/coderofsalvation/xrfragment/tree/main/dist)) you can [crosscompile it](https://github.com/coderofsalvation/xrfragment/blob/main/build.hxml), or roll your own `Parser.parse(k,v,store)` using the spec:\n\n1. requirement: receive arguments: key (string), value (string), store (writable associative array/object)\n1. add keys without values to store as [predefined view](predefined_view)\n1. check if fragment is official XR Fragment\n1. guess the type of the value (string,int,float,x,y,z,color,args,query)\n1. don't add to store if value-type is incorrect\n1. if valid, add to store\n1. prefix non-offical fragment key's with underscore (and add to store)\n\n> icanhazcode? yes, see [Parser.hx](https://github.com/coderofsalvation/xrfragment/blob/main/src/xrfragment/Parser.hx)\n\n# Tests\n \nthe spec is tested with [JSON unittests](./../src/spec) consumed by [Test.hx](./../src/Test.hx) to cross-test all languages.\n\n","tags":"[[🔨 XR Fragments parser]]","title":"↪ Parser.parse(k,v,store)","modified":"20240105120217927","type":"text/markdown"},
{"created":"20230427150948872","text":"> in \u003Ca href=\"./dist/xrfragment.js\" target=\"_blank\">xrfragment.js\u003C/a>, and \u003Ca href=\"./dist/xrfragment.module.js\" target=\"_blank\">xrfragment.module.js\u003C/a>\n\nValidates and turns a XR fragment string (`document.location.hash` in javascript e.g.) into objectform using [Parser.parse(k,v,store)](#↪%20Parser.parse(k,v,store)).\n\n| args | type | example | comment |\n|-|-|-|-|\n| url | string | `#pos=1.2,3,4`\u003Cbr>`#pos=1.2,3,4&t=1,2`| |\n| filter | integer\u003Cbr>(bitmask) | `0` = no filter\u003Cbr>`XRF.NAVIGATOR` (default)\u003Cbr>`XRF.EMBEDDED`\u003Cbr>`XRF.PV_OVERRIDE` | filter out fragments which are not flagged with this flag.\u003Cbr>\u003Cbr>For example, parsing with `XRF.NAVIGATOR` will ignore any fragments which are not flagged as such (like `scale` in case of top-level URI navigation).\u003Cbr>On the other hand, `XRF.EMBEDDED` makes sense when parsing an embedded URI (`src: other.gltf#scale=2,2,2` e.g.)\u003Cbr> |\n\n> returns an object with validated fragment(values) as key(objects)\n\nhere are some interactive examples:\n\n\u003Cdiv>\n \u003Ctextarea spellcheck=\"false\" autofocus class=\"sandboxify\">frags = xrfragment.URI.parse('#pos=1.0,2.0,3.0')\nconsole.log( frags.pos )\u003C/textarea>\n\t\u003Cpre class=\"result\">\u003C/pre>\n\u003C/div>\n\n\u003Cbr>\n\nYou can combine them with the `&` character:\u003Cbr>\n\n\u003Cdiv>\n \u003Ctextarea spellcheck=\"false\" autofocus class=\"sandboxify\">frags = xrfragment.URI.parse('#t=1,100&pos=1,2,3.1')\nconsole.log( frags.t )\u003C/textarea>\n\t\u003Cpre class=\"result\">\u003C/pre>\n\u003C/div>\n\nUnallowed fragments can be filtered out:\u003Cbr>\n\n\u003Cdiv>\n \u003Ctextarea spellcheck=\"false\" autofocus class=\"sandboxify\">XRF = xrfragment.XRF\nfrags = xrfragment.URI.parse('#scale=1,2,3', XRF.NAVIGATOR )\nconsole.log( frags )\u003C/textarea>\n\t\u003Cpre class=\"result\">\u003C/pre>\n\u003C/div>\n\n> The above is perfect for top-level browser navigation (which should not parse \u003Cb>embedded-only\u003C/b> XR Fragments like `scale` or [queries](#queries))\n\nAnother example for parsing embedded assets\n\n\u003Cdiv>\n \u003Ctextarea spellcheck=\"false\" autofocus class=\"sandboxify\">XRF = xrfragment.XRF\nmymodel = {userData:{src: \"other.gltf#scale=2,2,2\"}} // mock THREE.js\nfrags = xrfragment.URI.parse( mymodel.userData.src, XRF.EMBEDDED )\nconsole.log( frags.scale.x )\u003C/textarea>\n\t\u003Cpre class=\"result\">\u003C/pre>\n\u003C/div>\n\n> The above is perfect for embedded content (`scale` fragment is allowed here)\n\nFinally, parsing \u003Cb>custom\u003C/b> framework-specific fragments is also possible (they are prefixed with `_`)\u003Cbr>\n\n\u003Cdiv>\n \u003Ctextarea spellcheck=\"false\" autofocus class=\"sandboxify\">frags = xrfragment.URI.parse(\"#pos=0,0,1&foo=123&bar=flop\")\nconsole.log(frags._foo.int)\u003C/textarea>\n\t\u003Cpre class=\"result\">\u003C/pre>\n\u003C/div>\n\n> The above is perfect for embedded content (`scale` fragment is allowed here)\n\n# Spec\n\n> version 0.2 [](https://github.com/coderofsalvation/xrfragment/actions) generated by `make doc` @ 2023-06-27T11:18:12+0200\n\n### XR Fragment URI Grammar \n\n```\n reserved = gen-delims / sub-delims\n gen-delims = \"#\" / \"&\" \n sub-delims = \",\" / \"=\"\n```\n\n> Example: `://foo.com/my3d.asset#pos=1,0,0&prio=-5&t=0,100`\n\n| Explanation | |\n|-|-|\n| `pos=1,2,3` | vector/coordinate argument e.g. |\n| `pos=1,2,3&rot=0,90,0&q=.foo` | combinators |\n\nIn case your programming language has no parser ([check here](https://github.com/coderofsalvation/xrfragment/tree/main/dist)) you can [crosscompile it](https://github.com/coderofsalvation/xrfragment/blob/main/build.hxml), or roll your own `Parser.parse(k,v,store)` using the spec:\n\n1. store key/values into a associative array or dynamic object\n1. fragment URI starts with `#`\n1. fragments are split by `&`\n1. loop thru each fragmen
{"created":"20230830155016049","text":"\n> **DISCLAIMER**: XR Macros is a tiny logic-layer which falls outside of the scope of the XR Fragment spec (for now). \u003Cbr>They currently demonstrate features beyond the addressibility/navigation/embedding-focus of XR Fragments, and fall more into the demo/authoring-side of things. Every XR macro demonstration should potentially be replaced by piggybacking \u003Ca href=\"https://github.com/omigroup/gltf-extensions\" target=\"_blank\">OMI extensions\u003C/a> (when they support the usecase).\n\u003Cbr>\n\nXR Macros are a tiny roundrobin logic-layer **defined inside** 3D assets/scenes. \u003Cbr>\nMacros introduce a lowest-common-denominator logic-layer, by recursive, economic re-use of the querystring syntax (which the XR Fragment parser already uses).\u003Cbr>\n\u003Cbr>\nThe example XR macro's are based on common usecases & features found in 3D engines, to offer an lowcode alternative to basic experiences without requiring a scripting language.\u003Cbr>\n(Sometimes a spreadsheet will do instead of a programming language).\u003Cbr>\n\n# Spec\n\nBelow is the related section of the spec (full spec here: [[HTML|doc/RFC_XR_Macros.html]], [[TXT|doc/RFC_XR_Fragments.txt]], [[XML|doc/RFC_XR_Fragments.xml]])\n\n\u003Ciframe src=\"doc/RFC_XR_Macros.html#core-principle\" frameborder=\"0\" class=\"spec\">\u003C/iframe>\n\n# Example macros\n\n| XR macro | type | access | supported\u003Cbr>in\u003Cbr>sandbox |info |\n|----------|------|--------------|-|------|\n| **fov** |int 1..360|🔓 💥 👩 🔗|✔| hints field of view to renderer|\n| **clip** |[vector2](#vector) |🔓 💥 👩 🔗|✔| hints camera clipping to renderer |\n| **bg** |[vector3](#vector)|🔓 💥 👩 🔗|✔| hints background rgb values (0..255) to renderer\n| **fog** |[vector2](#vector)|🔓 💥 👩 🔗|✔| hints fog settings to renderer |\n| **env** |string|🔓 💥 🔗|✔|query selector / object manipulation|\n| [show](#show) |integer [0-1] |🔒 🎲 💥 🔗| ✔|show/hide [queried](#queries) object(s)|\n| [mov](#mov) |[vector3](#vector ) |🔒 🎲 💥 🔗| ✔|move [queried](#queries) object(s) \u003Cb>relatively\u003C/b> (instead of \u003Cb>absolute\u003C/b> using `#pos=`)|\n| [scale](#scale) |[vector3](#vector ) |🔓 🎲 💥 🔗| ✔|scale [queried](#queries) object(s) |\n| **prio** |int|🔒||asset loading linking|\n| **gravity** |[vector3](#vector) |🔓 💥 🔗||animation|\n| **physics** |[vector3](#vector) |🔓 💥 🔗||animation|\n| **namespace** |string|🔒||author / metadata|\n| **SPDX** |string|🔒||author / metadata|\n| **unit** |string|🔒||author / metadata|\n| **description** |string|🔒||author / metadata|\n| **session** |[url](#url ) |🔓 💥 👩 🔗 ✋?||multiparty|\n\n🔒 = value(s) can only be defined in 3D asset (immutable)\u003Cbr>\n🔓 = value(s) can be overwritten in certain context (by url)\u003Cbr>\n🎲 = multiple values will be roundrobin'ed (`#pos=0,0,0|1,0,0` e.g.)\u003Cbr>\n💥 = value(s) can be overwritten by [predefined_view](#predefined_view)\u003Cbr>\n👩 = value(s) can be overwritten when user clicks `href` (value) or top-level URL change(see [How it works](#How%20it%20works))\u003Cbr>\n🔗 = value(s) can be overwritten when 3D asset is embedded/linked as `src` value\u003Cbr>\n✋? = value(s) can be overwritten by offering confirmation/undo to user\u003Cbr>\u003Cbr>\n\n\u003Cdiv style=\"max-width:600px\">\n\u003C$videojs controls=\"controls\" aspectratio=\"16:9\" preload=\"auto\" poster=\"\" fluid=\"fluid\" class=\"vjs-big-play-centered\">\n \u003Csource src=\"https://coderofsalvation.codeberg.page/xrfragment.media/fovfogclip.mp4\" type=\"video/mp4\"/>\n\u003C/$videojs>\n\u003C/div>\n\nfor more info see [How it works](#How%20it%20works)","tags":"","title":"⏯️ XR Macros","modified":"20231122145951626","type":"text/markdown"},
{"created":"20230921095138812","text":"Hypermedia browsers supporting XR Fragments can be implemented on various levels:\n\n* thru the lens of HTML (a \u003Cb>pseudo-browser\u003C/b> using javascript like \u003Ca href=\"/example/aframe/sandbox\" target=\"_blank\">the sandbox\u003C/a> which uses the [THREE](#🧰%20THREE.js) or [AFRAME](#🧰%20AFRAME) javascript library)\n* the [Godot XRF Library](#%F0%9F%A7%B0%20GODOT) is also suitable direction for making native XR hypermedia browsers.\n* thru the lens of hypermedia browsers (opening XR Documents (`.gltf`, `.obj` e.g) natively using URLs, these don't exist (yet))\n> in progress: integrating the XR Fragment parser on native browserlevel (Wolvic, Chromium-based browsers e.g.) for best performance.","tags":"[[🧰 Libraries & Tools]]","title":"🌎 3D hypermedia browsers","modified":"20241209132308842","type":"text/markdown"},
{"created":"20240207122728580","text":"The current scene and [[src]] media (including the 3D timeline) can be further manipulated using [[Media Fragment URIs|https://www.w3.org/TR/media-frags/]].\n\nSo far `#t=` has been standardized by W3C.\u003Cbr>\nThough not being part of the XR Fragments standard, the demos suggest extra media fragments like `#loop`, `#s` and `#uv` to compensate for the lack of loop/speed/uv control.\n\u003Cbr>\u003Cbr>\n\nXR Fragments is endorsing W3C Media Fragments for media-control, as well as [[URI Templates|https://www.rfc-editor.org/rfc/rfc6570]] for text-templating.\n\n\u003Cbr>\n\u003Cdiv style=\"max-width:600px\">\n\u003C$videojs controls=\"controls\" aspectratio=\"16:9\" preload=\"auto\" poster=\"\" fluid=\"fluid\" class=\"vjs-big-play-centered\">\n \u003Csource src=\"https://coderofsalvation.codeberg.page/xrfragment.media/media_uv_template_fragments.mp4\" type=\"video/mp4\"/>\n\u003C/$videojs>\n\u003C/div>\n\n","tags":"[[🖇 implicit URI fragments]]","title":"🎞 Media Fragments","modified":"20241007082930415"},
{"created":"20240206123412197","text":"All modern 3D editors allow embedding metadata in objects of an exported 3D file.\u003Cbr>\n\n> An Easy **nocode** way to add metadata is [by adding custom properties in blender e.g.](https://docs.blender.org/manual/en/2.79/data_system/custom_properties.html). This is demonstrated in the getting started video: \n\n\u003Cdiv style=\"max-width:300px\">\n\u003C$videojs controls=\"controls\" aspectratio=\"16:9\" preload=\"auto\" poster=\"\" fluid=\"fluid\" class=\"vjs-big-play-centered\">\n \u003Csource src=\"https://coderofsalvation.codeberg.page/xrfragment.media/gettingstarted2024.mp4#t=200\" type=\"video/mp4\"/>\n\u003C/$videojs>\n\u003C/div>\n\u003Cbr>\u003Cbr>\n\n* [href](#href) for clickable links\n* [src](#src) for embedding content\n* [tag](#tag) to tag things\n\n\u003Cbr>\n\n\n\n| custom property | type | functionality |\n|----------|------|--------------|\n| [href](#href) | string (uri or [predefined view](#predefined_view)) | href navigation / portals / teleporting to other XR documents|\n| [src](#src) |string (uri or [predefined view](#predefined_view) or [query](#queries)) | lazyloading of (partial) local/external assets/scenes (3D iframes) |\n| [tag](#tag) |string|space-separated tagging of objects (like CSS class) for XRWG and or queries|\n\n\u003Cbr>\n> In Editors like \u003Ca href=\"https://blender.org\" target=\"_blank\">blender.org\u003C/a> these are called ''custom properties''.\n\u003Cbr>\u003Cbr>\n\n\u003Cb>Object metadata\u003C/b> can also be added programmatically, for example in \u003Ca href=\"https://threejs.org\" target=\"_blank\">AFRAME/THREE.js\u003C/a> can export GLB/USDZ/OBJ/COLLADA-files with them, after setting `myobject.userData.href = \"#pos=nameofplane\"` e.g.\n\n## Descriptive Metadata\n\nXR Fragments does not re-invent **descriptive metadata**, but encourages adding existing standards to 3D nodes, most notably:\n\n* [ARIA](https://www.w3.org/WAI/standards-guidelines/aria/) attributes (`aria-*: .....`)\n\n> **ARIA** (`aria-description`) is the most important to support, as it promotes accessibility and allows scene transcripts. Please start `aria-description` with a verb to aid transcripts.\n \nExample: object 'tryceratops' with `aria-description: is a huge dinosaurus standing on a #mountain` generates transcript `#tryceratops is a huge dinosaurus standing on a #mountain`.\u003Cbr>\nThese hashtags are clickable XR Fragments (activating the visible-\n\u003Cbr>\n\u003Cdiv style=\"max-width:300px\">\n\u003C$videojs controls=\"controls\" aspectratio=\"16:9\" preload=\"auto\" poster=\"\" fluid=\"fluid\" class=\"vjs-big-play-centered\">\n \u003Csource src=\"https://coderofsalvation.codeberg.page/xrfragment.media/xrf-xrsh-aria.mp4\" type=\"video/mp4\"/>\n\u003C/$videojs>\n\u003C/div>\n\u003Cbr>\n\nbut also the following attributes are encouraged:\n\n* [SPDX](https://spdx.dev/) license information\n* [Open Graph](https://ogp.me) attributes (`og:*: .....`)\n* [Dublin-Core](https://www.dublincore.org/specifications/dublin-core/application-profile-guidelines/) attributes(`dc:*: .....`)\n* [BibTex](https://bibtex.eu/fields) when known bibtex-keys exist with values enclosed in `{` and `},`\n\nThese attributes can be scanned and presented during an `href` or `src` eye/mouse-over.\n\n\n\u003C$videojs controls=\"controls\" aspectratio=\"16:9\" preload=\"auto\" poster=\"\" fluid=\"fluid\" class=\"vjs-big-play-centered\">\n \u003Csource src=\"https://coderofsalvation.codeberg.page/xrfragment.media/descriptive-metadata-implodes-3D-to-text.mp4\" type=\"video/mp4\"/>\n\u003C/$videojs>\n\n## Spec\n\nBelow is the related section of the spec (full spec here: \u003Ca href=\"doc/RFC_XR_Fragments.html\" target=\"_blank\">HTML\u003C/a>, \u003Ca href=\"doc/RFC_XR_Fragments.txt\" target=\"_blank\">TXT\u003C/a>)\n\n\u003Ciframe src=\"doc/RFC_XR_Fragments.html#additional-scene-metadata\" frameborder=\"0\" class=\"spec\">\u003C/iframe>\n","tags":"Reference","title":"📜 level2: metadata extras","modified":"20250211165852492","type":"text/markdown"},
{"created":"20240130111558609","text":"\nfeature heuristics are basically features which can be inferred from absense or presence of certain metadata.\n\u003Cbr>\u003Cbr>\n\nFor example, 3D objects always have a name, and are (not) children of certain 3D objects.\nAll this indirect information can be used to activate certain viewer-features.\n\u003Cbr>\u003Cbr>\nAll feature heuristics have been with care, to ensure they can be extracted from both new/legacy 3D fileformats.\n\u003Cbr>\u003Cbr>\n","tags":"Reference","title":"📡 implicit scene features","modified":"20241007083525195"},
{"created":"20240626095757672","text":"URLs are the heart of XR Fragment-based 3D Hypermedia:\n\n* they allow navigating the XR browser to a model\n* they allow position/rotating the camera in front of something somewhere (see [[#pos]] and [[#rot]])\n* they allow back/forward navigation \n* they allow adressing other 3D models, images, files (see [[src]])\n* they allow [[controlling media files|🎞 Media Fragments]]\n* they allow adressing parts of a 3D model (see [[🖇 implicit URI fragments]])\n\n> To see more, please unfold the Reference > URL menu","tags":"[[📜 level1: URL]]","title":"🔗 URL","modified":"20241007085518868"},
{"created":"20230622104423767","text":"The parser is the heart ❤ of XR Fragments, and used by XR Fragment browsers.\u003Cbr>\nIt's available as \u003Ca href=\"https://github.com/coderofsalvation/xrfragment\" target=\"_blank\">git repository\u003C/a> and directly below:\n\n| language | link |\n|-|-|\n| python | \u003Ca href=\"./dist/xrfragment.py\" target=\"_blank\">xrfragment.py\u003C/a> |\n| lua | \u003Ca href=\"./dist/xrfragment.lua\" target=\"_blank\">xrfragment.lua\u003C/a> |\n| javascript | \u003Ca href=\"./dist/xrfragment.js\" target=\"_blank\">xrfragment.js\u003C/a> |\n| javascript | \u003Ca href=\"./dist/xrfragment.module.js\" target=\"_blank\">xrfragment.module.js\u003C/a> |\n| any language | \u003Ca href=\"https://github.com/coderofsalvation/xrfragment/blob/main/build.hxml\" target=\"_blank\">using HaXe\u003C/a> |\n| spec | you can literally write a parser yourself, the spec is kept very easy intentionally |\n\n\u003Cbr>\nWith that, you can immediately add 4D \u003Cb>addressibility\u003C/b> to your app like this:\n\u003Cbr>\u003Cbr>\n\n\u003Cdiv>\n \u003Ctextarea spellcheck=\"false\" autofocus class=\"sandboxify noresult\" style=\"min-height:205px;width:100%;max-width:800px;\">import xrfragment from './dist/xrfragment.module.js';\n// read URL\nlet url = `mysite.com/#pos=0,0,1&rot=0,90,34&t=500,100&mycustom=123` // replace with document.location.href\nlet spatialAddress = xrfragment.URI.parse(url)\n \n// share URL\nlet player = {pos:[0,0,1],rot:[0,90,45],t:[500,100]} // position 0,0,1 rot 0,90,45 animationrange frame 500-100\nlet {protocol,host,path,search} = document.location\nalert(`${protocol}//${host}${path}${search}#pos=${player.pos.join(',')}&rot=${player.rot.join(',')}&t=${player.t.join(',')}`)\n\u003C/textarea>\n\u003C/div> \n\n> Congrats! After connecting `pos` and `rot` to your camera, and providing back/forward navigation, you have a \u003Cb>XR Fragments navigator\u003C/b>-compliant client.\n\n\u003Cbr>\n\nFor example, the [AFRAME](#%F0%9F%A7%B0%20AFRAME) / [THREE.js](#%F0%9F%A7%B0%20THREE.js) client-libraries use it like this:\n\u003Cbr>\n\n\u003Cdiv>\n \u003Ctextarea style=\"min-height:130px\" spellcheck=\"false\" autofocus class=\"sandboxify\">let out = {}\nout.uri = xrfragment.URI.parse(\"http://abc.com/a?foo.glb#pos=0,0,1&nonspec=1&-foo&bar\")\nconsole.log(out)\n\u003C/textarea>\n\t\u003Cpre class=\"result\" style=\"min-height:300px\">\u003C/pre>\n\u003C/div>\n\n> If you want to build your own client/browser, see the documentation for these functions in the sidemenu\n\n| function | info |\n|-|-|\n| `xrfragment.URI.parse( str, flag )` | see [URI.parse](#↪%20URI.parse(url%2Cfilter)) |\n| `xrfragment.Parser.parse(k,v,store)` | see [Parser.parse](#↪%20Parser.parse(k%2Cv%2Cstore)) |\n","tags":"[[🧰 Libraries & Tools]] [[🧰 libraries]]","title":"🔨 XR Fragments parser","modified":"20241209132308848","type":"text/markdown"},
{"created":"20240208102607476","text":"Besides the only 2 **static** XR URI Fragments (`#pos` and `#rot`), every 3D object, material or camera can be \u003Cb>adressed\u003C/b> by URI fragments (`#myobject` e.g.) which are **auto-generated from the 3D scene** (implicit metadata).\u003Cbr>\nThese are inferred at runtime from the 3D scene-nodes (object names, object metadata etc).\u003Cbr>\u003Cbr>\nFree fragments and features generated for you..How great is that? 🎉\n\u003Cbr>\n\u003Cbr>\n\u003Cpre>\n\u003Ccode>\n my.io/scene.usdz Embeddable as:\n +─────────────────────────────+\n │ sky │ src: http://my.io/scene.udsz#sky (includes building,mainobject,floor)\n │ +─────────────────────────+ │ \n │ │ building │ │ src: http://my.io/scene.udsz#building (includes mainobject,floor)\n │ │ +─────────────────────+ │ │\n │ │ │ mainobject │ │ │ src: http://my.io/scene.udsz#mainobject (includes floor)\n │ │ │ +─────────────────+ │ │ │\n │ │ │ │ floor │ │ │ │ src: http://my.io/scene.udsz#floor (just floor object)\n │ │ │ │ │ │ │ │\n │ │ │ +─────────────────+ │ │ │ href: http://my.io/scene.udsz#-mainobject (hides mainobject when clicked)\n │ │ +─────────────────────+ │ │\n │ +─────────────────────────+ │\n +─────────────────────────────+\n\u003C/code>\n\u003C/pre>\n\n\n> Fragments (`#building` e.g.) allow for very convenient, guess-able [filters](#filters) to reference/show/hide objects within a 3D scene.\n\n\nFor more examples see [filters](#filters) and \u003Ca href=\"#📡 by feature (heuristics)\">the reference-menu (by feature)\u003C/a>\n\n> Below is the related section of the spec (full spec here: \u003Ca href=\"doc/RFC_XR_Fragments.html\" target=\"_blank\">HTML\u003C/a>, \u003Ca href=\"doc/RFC_XR_Fragments.txt\" target=\"_blank\">TXT\u003C/a>)\n\n\u003Cbr>\n\u003Ciframe src=\"doc/RFC_XR_Fragments.html#fragment-to-metadata-mapping\" frameborder=\"0\" class=\"spec\">\u003C/iframe>\n","tags":"[[🔗 URL]]","title":"🖇 implicit URI fragments","modified":"20241007082732186","type":"text/markdown"},
{"created":"20240626145227798","text":"\u003Cdiv style=\"max-width:600px\">\n\u003C$videojs controls=\"controls\" aspectratio=\"16:9\" preload=\"auto\" poster=\"\" fluid=\"fluid\" class=\"vjs-big-play-centered\">\n \u003Csource src=\"https://coderofsalvation.codeberg.page/xrfragment.media/gettingstarted2024.mp4\" type=\"video/mp4\"/>\n\u003C/$videojs>\n\u003C/div>\n\n* download and install \u003Ca href=\"https://blender.org\" target=\"_blank\">Blender\u003C/a> here (for desktop)\n* export 3D files (File > Export > glTF 2.0) after adding [[href]], [[src]] and [[tag]] \u003Cb>metadata\u003C/b> as \u003Ca href=\"https://docs.blender.org/manual/en/2.79/data_system/custom_properties.html\" target=\"_blank\">custom properties\u003C/a>\n* in the export dialog, set extension to `.glb` (=easiest)\n* in the export dialog, check these checkboxes (Include dropdown):\n\n```\n\n✅ custom properties (=XR fragment metadata)\n\n✅ cameras\n\n✅ lights\n\n```\n* click export-button and save the file (`example.glb) somewhere\n* load the 3D file (`example.glb` e.g.) into the \u003Ca href=\"example/aframe/sandbox\" target=\"_blank\">sandbox\u003C/a> by clicking the hamburger-menu: `load 3D file`-button\n* see [getting started video](#Getting%20started) to see the above steps in detail\n\n> This is the easiest route which don't involves coding, you can load the \u003Ca href=\"example.glb\" target=\"_blank\">example.glb\u003C/a> \u003Ca href=\"index.glb\" target=\"_blank\">index.glb\u003C/a> as an example, and inspect the \u003Ca href=\"https://docs.blender.org/manual/en/2.79/data_system/custom_properties.html\" target=\"_blank\">custom properties\u003C/a>","title":"🖥 Blender ✅🔥","modified":"20241209132308877","type":"text/markdown","tags":"[[🧰 libraries]] [[🧰 Libraries & Tools]]"},
{"created":"20240717141500750","text":"\u003Ca href=\"https://modelviewer.dev\" target=\"_blank\"><model-viewer>\u003C/a> is a way to easily embed glTF 3D files into webpages.\u003Cbr>\n\u003Cbr>\nThere's a xrfragment overlay, which will \n\u003Cu tabindex=\"0\">turboboost\n \u003Cspan>it with XR Fragment support, allowing \u003C/span>\n\t\u003Cu tabindex=\"0\">minimum viable interactions \n\t \u003Cspan>like navigation, teleportation, showing/hiding objects, portals, lenses, loading and embedding scenes, hypermedia files and URLs.\u003C/span>\n\t\u003C/u>\n\u003C/u> it, by turning it into\n\u003Cu tabindex=\"0\">immersive experiences\n \u003Cspan>, allowing interactive story telling, elearnings, basically 3D hypermedia\u003C/span>\n\u003C/u> for \n\u003Cu tabindex=\"0\">all devices\n \u003Cspan>, like VR/AR devices, laptop, tablet and mobile (VR)\u003C/span>\n\u003C/u>\n\n\u003Ccenter>\n \u003Ca class=\"btn\" href=\"example/model-viewer\" target=\"_blank\" style=\"padding:10px 30px\">See example\u003C/a>\n\u003C/center>\n\nHere's the example snippet using the \u003Ca href=\"https://xrfragment.org/dist/xrfragment.model-viewer.js\" target=\"_blank\">xrfragment.model-viewer.js\u003C/a> overlay\n\u003Cbr>\n\n\u003Cdiv>\n \u003Ctextarea spellcheck=\"false\" autofocus class=\"sandboxify noresult\" style=\"min-height:205px;width:100%;max-width:800px;\"><model-viewer
      src="https://xrfragment.org/example/assets/index.glb"
      ar alt="XR Fragments demo scene"camera-controls touch-action="none" disable-tap
      field-of-view="80deg" min-field-of-view="25deg" max-field-of-view="100deg" 
      interpolation-decay="200" camera-target="0m 0m 0m" min-camera-orbit="0.1% 0.1% 0.1%" 
      style="width:66vw; height: 66vh; border-radius:5px; border:1px solid #CCC"
    >
</model-viewer>

<script src="./.
{"created":"20230602135111711","text":"The \u003Ca href=\"https://aframe.io\">AFRAME\u003C/a> wraps the THREE.js library, to enable a hypermedia browser-experience in just 2 lines:\n\n```\n\u003Cscript src=\"https://xrfragment.org/dist/xrfragment.aframe.js\">\u003C/script>\n\u003Ca-entity xrf=\"https://xrfragment.org/index.glb\">\u003C/a-entity> \n```\n\nIt enables:\n\n* linking together of space, time & (text)objects\n* with- or without a network-connection.\n* discover, share, link, navigate & query 4D experiences using URLs\n\n> Basically navigation automatically happens via [href](#href) values embedded in 3D models (glb e.g.) or programmaticaly: `xrf.navigator.to('https://xrfragment.org/index.glb#pos=start')` e.g. \n\n\u003Cbr>\nThe snippet above can be found \u003Ca href=\"https://github.com/coderofsalvation/xrfragment/blob/main/example/three/sandbox/index.html#L92-L112\" target=\"_blank\">in this source-example\u003C/a> or see it in action here:\n\u003Cbr>\u003Cbr>\n\n\u003Cbr>\n\u003Cdiv style=\"max-width:600px\">\n\u003C$videojs controls=\"controls\" aspectratio=\"16:9\" preload=\"auto\" poster=\"\" fluid=\"fluid\" class=\"vjs-big-play-centered\">\n \u003Csource src=\"https://coderofsalvation.codeberg.page/xrfragment.media/xrf-searxr.mp4\" type=\"video/mp4\"/>\n\u003C/$videojs>\n\u003C/div>\n\n## Getting started\n\n1. use the code from the codepen above as a startingpoint \n2. add your own 3D model (`index.glb` in the example)\n\n> This setup automatically launches the (THREE.js) `xrf.init()` which injects xrf-capabilities into THREE.js loaders. It'll automatically detect any XR Fragments in 3D assets (loaded afterwards). \u003Cbr>On top of that, it'll reflect changes in the URL-bar.\n\nAlso note that `xrf-get` allows converting objects inside assets into AFRAME `\u003Ca-entity>`, and `xrf-button` allows for simple interactions.\n\u003Cbr>\u003Cbr>\nSee the above in action below:\n\u003Cbr>\u003Cbr>\n\u003Ciframe class=\"border\" src=\"./example/aframe/sandbox?index.gltf#pos=0,0,0\" frameborder=\"0\" style=\"width:100%; height:70%; min-height:500px;\"/>\n\nThe xrfragment library lives at `window.AFRAME.XRF` so you can call `AFRAME.XRF.navigator.to('foo.hltf#pos=1,1,2')` e.g.\n\u003Cbr>\u003Cbr>\nEverything else works the same (and can be extended via) as the [THREE.js library](#%F0%9F%A7%B0%20THREE.js) (see for more info)\n\n## The navigator\n\nAll (clicked/requested) links will go through the navigator, which lives at `xrf.navigator` and can be replaced/extended with your own [navigator.js](https://codeberg.org/coderofsalvation/xrfragment/src/branch/main/src/3rd/js/three/navigator.js)\n\nBy default it opens unknown links (like an HTML/PDF link in a new tab, however that can be disabled:\n\n```\ndocument.querySelector('a-scene', function(){\n xrf.navigator.opts.openInNewTab = false\n})\n```\n\n## plugins\n\nThere are various optional plugins which add a small 2D overlay interface, add network features etc:\n\n```\n\n\u003Cscript src=\"dist/xrfragment.plugin.p2p.js\">\u003C/script> \u003C!-- serverless p2p connectivity -->\n\u003Cscript src=\"dist/xrfragment.plugin.matrix.js\">\u003C/script> \u003C!-- matrix connectivity -->\n\u003Cscript src=\"dist/xrfragment.plugin.network.js\">\u003C/script> \u003C!-- matrix and webrtc chat/scene examples --> \n\u003Cscript src=\"dist/xrfragment.plugin.editor.js\">\u003C/script> \u003C!-- basic editor example --> \n\u003Cscript src=\"dist/xrfragment.plugin.frontend.css.js\">\u003C/script> \u003C!-- basic menu interface css -->\n\u003Cscript src=\"dist/xrfragment.plugin.frontend.js\">\u003C/script> \u003C!-- basic menu interface -->\n\n```\n\nsee \u003Ca href=\"example/aframe/sandbox\" target=\"_blank\">here\u003C/a> for an example and [index.html](https://codeberg.org/coderofsalvation/xrfragment/src/branch/main/example/aframe/sandbox/index.html) for its code\n\n> While these are not part of the spec, you can use/modify them to your own likings.\n\n## plugin: frontend\n\nThis creates a hamburger menu and popu
{"created":"20240517153232783","text":"[Godot](https://godotengine.org/) is a Game/XR multi-platform builder environment.\u003Cbr>\n\u003Cbr>\nGodot developers can use the \u003Ca href=\"https://codeberg.org/coderofsalvation/xrfragment-godot/src/branch/main/xrfragment.gd\" target=\"_blank\">xrfragment.gd\u003C/a> library to build their own XR browser.\u003Cbr>\u003Cbr>\nThere's an \u003Ca href=\"https://codeberg.org/coderofsalvation/xrfragment-godot\" target=\"_blank\">Example Godot Project\u003C/a> included which uses it using this simple \u003Ca href=\"https://codeberg.org/coderofsalvation/xrfragment-godot/src/branch/main/main.gd\" target=\"_blank\">main.gd\u003C/a> script.\n\u003Cbr>\u003Cbr>\n\u003Cb>NOTE:\u003C/b> the XR Fragment support is not as mature as the AFRAME library (see Example Model Browser in sidemenu)\n\n\u003Cbr>\n\u003Cdiv style=\"max-width:600px\">\n\u003C$videojs controls=\"controls\" aspectratio=\"16:9\" preload=\"auto\" poster=\"\" fluid=\"fluid\" class=\"vjs-big-play-centered\">\n \u003Csource src=\"https://coderofsalvation.codeberg.page/xrfragment.media/xrfragment-godot.mp4\" type=\"video/mp4\"/>\n\u003C/$videojs>\n\u003C/div>","title":"🧰 GODOT","modified":"20241209132308938","type":"text/markdown","tags":"[[🧰 libraries]] [[🧰 Libraries & Tools]]"},
{"created":"20230508095631417","text":"> \u003Cb>NOTE\u003C/b>: Expect just THREE.js boilerplate here, for a more mature demo see the [AFRAME](#%F0%9F%A7%B0%20AFRAME) wrapper (contains better UX).\n\nHere you can download \u003Ca href=\"./dist/xrfragment.three.js\" target=\"_blank\">xrfragment.three.js\u003C/a> or \u003Ca href=\"./dist/xrfragment.three.module.js\" target=\"_blank\">xrfragment.three.module.js\u003C/a>, and here's how to empower your [THREE.js app](https://threejs.org) with XR Fragments:\n\u003Cbr>\n\n\u003Cdiv>\n \u003Ctextarea spellcheck=\"false\" autofocus class=\"sandboxify noresult\" style=\"min-height:205px;width:100%;max-width:800px;\">import xrfragment from './dist/xrfragment.three.js';\n \n/* enable XR fragments */\nlet XRF = xrf.init({ \n\tTHREE,\n\tcamera,\n\tscene,\n\trenderer,\n\tdebug: true,\n\tloaders: [ GLTFLoader, FBXLoader ], // specify 3D assets to scan for embedded XR fragments \n})\n\u003C/textarea>\n\u003C/div> \n\n> [`xrf.init()`](https://github.com/coderofsalvation/xrfragment/blob/main/src/3rd/js/three/index.js#L4) injects itself into THREE.js. It'll automatically detect any XR Fragments in 3D assets (loaded afterwards). \u003Cbr>On top of that, it'll reflect changes in the URL-bar.\n\n\nFrom here you will want to use `xrf.navigator.to('index.glb#pos=start')` e.g. to navigate scenes via javascript, or \u003Cb>preferrably\u003C/b> simply by embedding [href](#href) metadata into your 3D files.\n\u003Cbr>\nThe snippet above can be found \u003Ca href=\"https://github.com/coderofsalvation/xrfragment/blob/main/example/three/sandbox/index.html#L92-L112\" target=\"_blank\">in this source-example\u003C/a> or see it in action here:\n\u003Cbr>\u003Cbr>\n\n\u003Ciframe class=\"border\" src=\"./example/three/sandbox\" frameborder=\"0\" style=\"width:100%; height:70vh\"/>\n\n\u003Cbr>\nThe example above loads a gltf-scene which contains \u003Cb>embedded XR fragments\u003C/b> which:\n\n* replaces certain objects with \u003Cb>tiny clones of itself\u003C/b> by instancing `src` selfreferences (`src: #cube` or `src: #-sky&-cube`)\n\nFor all XR fragments see [the list](#📜%20XR%20fragments)\n\n\u003Ch2>Events / Customizing \u003C/h2>\n\nThere are various ways to customize the behaviour of xrfragments.\n \nThere's the `addEventListener` which allows promise-ification of events:\n\n\u003Cdiv>\n \u003Ctextarea spellcheck=\"false\" autofocus class=\"sandboxify noresult\" style=\"min-height:240px;width:100%;max-width:800px;\">\nXRF.addEventListener('href',(e) => {\n if( e.click ){\n const promise = e.promise() // optional promisify event\n promise.resolve() // teleport\n promise.reject('nope') // do not teleport\n }\n})\n \nXRF.addEventListener('foobar', console.log ) \nXRF.emit('foobar',{x:1}) // emit custom event\n .then( () => alert('hello') ) // optional\n\u003C/textarea>\n\u003C/div>\n\u003Cbr>\n\n> Above you can see how [XR Macro's](#⏯%EF%B8%8F%20XR%20Macros) extend the XR Fragments parser with custom behaviour.\n\n| event | info |\n|-------|------|\n| **init** | emitted when xrf.init() is being called |\n| **href** | emitted when user interacts with [href](#href) ('hover' or click) |\n| **hashbus** | ⚠️ emitted when hashbus is processing (XR) fragments |\n| **reset** | emitted when current scene is emptied (and next model is loaded) |\n| **parseModel** | ⚠️ emitted when global or embedded 3D model is being parsed |\n| **navigate** | emitted when new scene is going to be loaded via `xrf.navigator.to(...)` or back/forward button |\n| **navigateLoading** | emitted when new scene is loading via `xrf.navigator.to(...)` or back/forward button |\n| **navigateLoaded** | emitted when new scene is loaded via `xrf.navigator.to(...)` or back/forward button |\n| **navigateError** | emitted when new scene is not able to get loaded |\n| **focus** | emitted when user hovers over an object |\n| **play** | emitted when media fragment is being activated on an object |\n| **stop** | emitted when media fragment is being activated on an
{"created":"20240701124206254","text":"> Unity is partly closed/open technology, in contrast to [Godot](https://godotengine.org/) as an open alternative to foster an \u003Ca href=\"https://twitter.com/coderofsalvatio/status/1813552757988843524\" target=\"_blank\">inclusive future\u003C/a>.\n\nUnity can load various 3D models, but the following [glTFast plugin](https://github.com/atteneder/glTFast) is adviced for XR Fragments:\n\n* realtime import/export of glTF/glb 3D models\n* support for reading custom metadata via `extras` [event](https://github.com/atteneder/glTFast/issues/90)\n\n\u003Cb>NOTE:\u003C/b> the XR Fragment metadata is not detected out of the box, so you have to do that manually by parsing `extras`.\n\nYou can use the parser library using the [C#, javascript, python or lua version](https://github.com/coderofsalvation/xrfragment/tree/main/dist)\n\n> please do a PR upstream in case you've managed to come up with a demo (to help other people using Unity)","title":"🧰 Unity ⚠️","modified":"20241209132309043","type":"text/markdown","tags":"[[🧰 libraries]] [[🧰 Libraries & Tools]]"},
{"created":"20230424124659851","text":"{\"tiddlers\":{\"$:/Acknowledgements\":{\"title\":\"$:/Acknowledgements\",\"text\":\"TiddlyWiki incorporates code from these fine OpenSource projects:\\n\\n* [[The Stanford Javascript Crypto Library|http://bitwiseshiftleft.github.io/sjcl/]]\\n* [[The Jasmine JavaScript Test Framework|http://pivotal.github.io/jasmine/]]\\n* [[Normalize.css by Nicolas Gallagher|http://necolas.github.io/normalize.css/]]\\n\\nAnd media from these projects:\\n\\n* World flag icons from [[Wikipedia|http://commons.wikimedia.org/wiki/Category:SVG_flags_by_country]]\\n\"},\"$:/core/copyright.txt\":{\"title\":\"$:/core/copyright.txt\",\"type\":\"text/plain\",\"text\":\"TiddlyWiki created by Jeremy Ruston, (jeremy [at] jermolene [dot] com)\\n\\nCopyright (c) 2004-2007, Jeremy Ruston\\nCopyright (c) 2007-2023, UnaMesa Association\\nAll rights reserved.\\n\\nRedistribution and use in source and binary forms, with or without\\nmodification, are permitted provided that the following conditions are met:\\n\\n* Redistributions of source code must retain the above copyright notice, this\\n list of conditions and the following disclaimer.\\n\\n* Redistributions in binary form must reproduce the above copyright notice,\\n this list of conditions and the following disclaimer in the documentation\\n and/or other materials provided with the distribution.\\n\\n* Neither the name of the copyright holder nor the names of its\\n contributors may be used to endorse or promote products derived from\\n this software without specific prior written permission.\\n\\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS'\\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\"},\"$:/core/icon\":{\"title\":\"$:/core/icon\",\"tags\":\"$:/tags/Image\",\"text\":\"\u003Csvg width=\\\"22pt\\\" height=\\\"22pt\\\" viewBox=\\\"0 0 128 128\\\">\u003Cpath d=\\\"M64 0l54.56 32v64L64 128 9.44 96V32L64 0zm21.127 95.408c-3.578-.103-5.15-.094-6.974-3.152l-1.42.042c-1.653-.075-.964-.04-2.067-.097-1.844-.07-1.548-1.86-1.873-2.8-.52-3.202.687-6.43.65-9.632-.014-1.14-1.593-5.17-2.157-6.61-1.768.34-3.546.406-5.34.497-4.134-.01-8.24-.527-12.317-1.183-.8 3.35-3.16 8.036-1.21 11.44 2.37 3.52 4.03 4.495 6.61 4.707 2.572.212 3.16 3.18 2.53 4.242-.55.73-1.52.864-2.346 1.04l-1.65.08c-1.296-.046-2.455-.404-3.61-.955-1.93-1.097-3.925-3.383-5.406-5.024.345.658.55 1.938.24 2.53-.878 1.27-4.665 1.26-6.4.47-1.97-.89-6.73-7.162-7.468-11.86 1.96-3.78 4.812-7.07 6.255-11.186-3.146-2.05-4.83-5.384-4.61-9.16l.08-.44c-3.097.59-1.49.37-4.82.628-10.608-.032-19.935-7.37-14.68-18.774.34-.673.664-1.287 1.243-.994.466.237.4 1.18.166 2.227-3.005 13.627 11.67 13.732 20.69 11.21.89-.25 2.67-1.936 3.905-2.495 2.016-.91 4.205-1.282 6.376-1.55 5.4-.63 11.893 2.276 15.19 2.37 3.3.096 7.99-.805 10.87-.615 2.09.098 4.143.483 6.16 1.03 1.306-6.49 1.4-11.27 4.492-12.38 1.814.293 3.213 2.818 4.25 4.167 2.112-.086 4.12.46 6.115 1.066 3.61-.522 6.642-2.593 9.833-4.203-3.234 2.69-3.673 7.075-3.303 11.127.138 2.103-.444 4.386-1.164 6.54-1.348 3.507-3.95 7.204-6.97 7.014-1.14-.036-1.805-.695-2.653-1.4-.164 1.427-.81 2.7-1.434 3.96-1.44 2.797-5.203 4.03-8.687 7.016-3.484 2.985 1.114 13.65 2.23 15.594 1.114 1.94 4.226 2.652 3.02 4.406-.37.58-.936.785-1.54 1.01l-.82.11zm-40.097-8.85l.553.14c.694-.27 2.09.15 2.83.353-1.363-1.31-3.417-3.24-4.897-4.46-.485-1.47-.278-2.96-.174-4.46l.02-.123c-.582 1.205-1.322 2.376-1.72 3.645-.465 1.71 2.07 3.5
{"text":"{\n \"tiddlers\": {\n \"$:/plugins/ihm/tidgraph/changelog\": {\n \"created\": \"20151024161547099\",\n \"creator\": \"ihm4u\",\n \"modified\": \"20151031061347109\",\n \"modifier\": \"ihm4u\",\n \"tags\": \"\",\n \"title\": \"$:/plugins/ihm/tidgraph/changelog\",\n \"text\": \"For the complete changelog see\\n\\nhttps://ihm4u.github.io/tw5plugs/#Tidgraph%20-%20Changelog\\n\"\n },\n \"$:/plugins/ihm/tidgraph/documentation\": {\n \"title\": \"$:/plugins/ihm/tidgraph/documentation\",\n \"text\": \"!!Example\\nThe following example shows a tiddler which tags 7 children:\\n\\n``\u003C$tidgraph start=\\\"Virtues\\\" />``\\n\\nlooks like this:\\n\\n{{$:/plugins/ihm/tidgraph/tidgraph.png}}\\n\\n!!Usage\\nSimple usage:\\n\\n``\u003C$tidgraph start=\\\"MyRootTiddler\\\" />``\\n\\nThe map will start with MyRootTiddler on the left, and show all its children recursively. The default maximum depth is 10 levels, it can be changed with the `maxdepth` attribute.\\n\\nAll options:\\n\\n|!Attribute |!Description|!Default |\\n|`start` |Initial tiddler that starts the map | none |\\n|`startat` |First level to display. 0 is the root tiddler named in the `start` attribute. 1 is the next level, etc. | 0 |\\n|`maxdepth` |Maximum depth to display.| 10 |\\n|`mode` |//tagging// or //linking// or custom. This is how to identify the children of a node. With //tagging// Tiddlers that tag other tiddlers become their parent. With //linking// tiddlers that link to other tiddlers become their parent. A custom mode can be specified by a `$:/config/tidgraph/modes/MyMode` tiddler where `MyMode` is the name of the mode. The subfilter can be also specified directly; e.g. `mode=\\\"fields[]\\\"`. See [[Custom Mode Demo|https://ihm4u.github.io/tw5plugs/#Custom%20Mode%20Demo]] for an example | //tagging// |\\n|`nodetitle` |Field to use as title for the node. | //title// (or //caption// if present) |\\n|`tooltip` |List of fields to use for node tooltip. The first field with a non empty value is used. | //summary// |\\n|`filter` |Only tiddlers matching filter will be used | none |\\n|`nocollapse` |Disable ability to collapse nodes. The graph allows node collapsing by default. | false |\\n|`nodetemplate` |One or mode node templates to make node look like you want. See the [[Node Templates Demo|https://ihm4u.github.io/tw5plugs/#Node%20Templates%20Demo]] for examples of how to use them. | none |\\n|`layout` |`E` for East (Vertical) or `S` for south (Horizontal) layout. | E |\\n\\n!CSS classes\\nYou can also change colors, and other styles with the following CSS classes.\\n\\n|!Class |!Description |\\n|tgr-node|Style for each node. If you want to change the color of the links inside the node use the `.tgr-node a` selector. |\\n|tgr-edge |Style for the SVG path that connects the nodes. The old name was tgr-link. |\\n|tgr-arrow |Style for the SVG polyline that draws the arrow at the end of the link |\\n\"\n },\n \"$:/plugins/ihm/tidgraph/readme\": {\n \"created\": \"20151024054526558\",\n \"modified\": \"20151024065317719\",\n \"tags\": \"\",\n \"title\": \"$:/plugins/ihm/tidgraph/readme\",\n \"text\": \"!!How\\nSimply put this in your tiddler:\\n\\n``\u003C$tidgraph start=\\\"MyRootTiddler\\\" />``\\n\\nThere are other options covered in the [[documentation|$:/plugins/ihm/tidgraph/documentation]].\\n\\n!!Features\\n* No third-party libraries\\n* Light weight\\n* Rendering of map/graph with HTML5 and SVG (no heavy png or jpg images)\\n* Automatic map/graph creation, no need for dragging/connecting/etc\\n* Figures out tree-graph by means of tags or links, or custom modes \\n* Collapse/expand nodes\\n* User defined Node Templates!!\\n\\n!!Limitations\\n* Layout is horizontal from left to right, if needed a vertical layout will be added later\\n\"\n },\n \"$:/plugins/ihm/tidgraph/stylesheet\": {\n \"tags\": \"$:/tags/Stylesheet\",\n
{"text":"{\n \"tiddlers\": {\n \"$:/plugins/nico/notebook-mobile/js/notebookSidebarNav.js\": {\n \"title\": \"$:/plugins/nico/notebook-mobile/js/notebookSidebarNav.js\",\n \"text\": \"/*\\\\\\ntitle: $:/themes/nico/notebook-mobile/js/notebookSidebarNav.js\\ntype: application/javascript\\nmodule-type: global\\n\\nCloses the notebook sidebar on mobile when navigating\\n\\n\\\\*/\\n(function(){\\n\\n /*jslint node: true, browser: true */\\n /*global $tw: false */\\n \\\"use strict\\\";\\n\\n const isOnMobile = () => {\\n\\t\\tlet bottombar = document.querySelector('.nc-bottombar');\\n\\t\\treturn bottombar && bottombar.getClientRects().length > 0;\\n };\\n\\n const closeSidebar = () => {\\n\\t\\t$tw.wiki.setText(\\\"$:/state/notebook-sidebar\\\", \\\"text\\\", undefined, \\\"no\\\");\\n };\\n\\n const closeSidebarOnMobile = () => {\\n\\t\\tif (isOnMobile()) {\\n console.log(\\\"closing sidebar\\\");\\n\\t\\t\\tcloseSidebar();\\n\\t\\t};\\n };\\n\\n const setup = () => {\\n\\t\\t$tw.hooks.addHook(\\\"th-navigating\\\",function(event) {\\n\\t\\t\\tcloseSidebarOnMobile();\\n\\t\\t\\treturn event;\\n\\t\\t});\\n };\\n\\n setup();\\n\\n exports.closeNotebookSidebar = closeSidebar;\\n})();\\n\",\n \"type\": \"application/javascript\",\n \"module-type\": \"global\",\n \"created\": \"20200430151329085\",\n \"modified\": \"20201210200127495\",\n \"tags\": \"\"\n }\n }\n}","bag":"default","revision":"0","version":"1.0.0","type":"application/json","title":"$:/plugins/nico/notebook-mobile","source":"https://github.com/NicolasPetton/Notebook","plugin-type":"plugin","name":"Mobile support for the Notebook theme","list":"","description":"JavaScript hooks for mobile devices support of the Notebook theme","dependents":"","core-version":">=5.1.22","author":"NicolasPetton"},
{"created":"20230423163535033","text":"A tiny specification for controlling any 3D model using URLs\n{{$:/xrfragment/topmenu}}\n\u003C$action-setfield $tiddler=\"$:/state/sidebar\" text=“no” />","title":"$:/SiteSubtitle","modified":"20231206154359154","tags":"$:/tags/StartupAction"},
{"created":"20230424093627704","title":"$:/state/plugin-info-833095967-Draft of '$:/core'---1604322978","text":"readme","modified":"20230424093629208"},
{"created":"20240207130427889","title":"$:/state/toc/Reference/📜 XR Fragments-🎞 Media Fragments--403145756","text":"close","modified":"20240416130958570"},
{"created":"20241007082934855","title":"$:/state/toc/Reference/📜 XR Fragments/🔗 URL-🖇 implicit URI fragments--403145756","text":"close","modified":"20241007085106374"},
{"created":"20241007083025154","title":"$:/state/toc/Reference/📜 XR Fragments/🔗 URL/🖇 implicit URI fragments-🎞 Media Fragments--403145756","text":"close","modified":"20241007085040766"},
{"created":"20240105120105242","title":"$:/state/toc/Reference/🧰 libraries-XR Fragment parser--403145756","text":"open","modified":"20240105120105242"},
{"created":"20240627122947980","text":"{\n \"tiddlers\": {\n \"$:/themes/nico/notebook/LICENSE\": {\n \"title\": \"$:/themes/nico/notebook/LICENSE\",\n \"created\": \"20200419141443144\",\n \"modified\": \"20210118213330307\",\n \"tags\": \"\",\n \"type\": \"text/vnd.tiddlywiki\",\n \"text\": \"\\nMIT License Copyright (c) 2020 [[Nicolas Petton|https://nicolas.petton.fr]] nicolas@petton.fr\\n\\nPermission is hereby granted, free of charge, to any person obtaining a copy\\nof this software and associated documentation files (the \\\"Software\\\"), to deal\\nin the Software without restriction, including without limitation the rights\\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\\ncopies of the Software, and to permit persons to whom the Software is furnished\\nto do so, subject to the following conditions:\\n\\nThe above copyright notice and this permission notice (including the next\\nparagraph) shall be included in all copies or substantial portions of the\\nSoftware.\\n\\nTHE SOFTWARE IS PROVIDED \\\"AS IS\\\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS\\nOR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\\nWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF\\nOR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\\n\"\n },\n \"$:/themes/nico/notebook/themetweaks\": {\n \"title\": \"$:/themes/nico/notebook/themetweaks\",\n \"created\": \"20201217172915960\",\n \"modified\": \"20210123211851680\",\n \"tags\": \"$:/tags/ControlPanel/Appearance\",\n \"caption\": \"{{$:/language/ThemeTweaks/ThemeTweaks}}\",\n \"text\": \"\\\\define lingo-base() $:/language/ThemeTweaks/\\n\\nYou can tweak certain aspects of the ''Notebook'' theme.\\n\\n! \u003C\u003Clingo Options>>\\n\\n|\u003C$link to=\\\"$:/themes/nico/notebook/options/stickytitles\\\">\u003C\u003Clingo Options/StickyTitles>>\u003C/$link>\u003Cbr>//\u003C\u003Clingo Options/StickyTitles/Hint>>// |\u003C$select tiddler=\\\"$:/themes/nico/notebook/options/stickytitles\\\">\u003Coption value=\\\"no\\\">{{$:/language/No}}\u003C/option>\u003Coption value=\\\"yes\\\">{{$:/language/Yes}}\u003C/option>\u003C/$select> |\\n|\u003C$link to=\\\"$:/themes/tiddlywiki/vanilla/options/codewrapping\\\">\u003C\u003Clingo Options/CodeWrapping>>\u003C/$link> |\u003C$select tiddler=\\\"$:/themes/tiddlywiki/vanilla/options/codewrapping\\\">\u003Coption value=\\\"pre\\\">{{$:/language/No}}\u003C/option>\u003Coption value=\\\"pre-wrap\\\">{{$:/language/Yes}}\u003C/option>\u003C/$select> |\\n|\u003C$link to=\\\"$:/themes/nico/notebook/options/reveal-tiddler-controls-on-hover\\\">Reveal tiddler controls on mouseover\u003C/$link> |\u003C$select tiddler=\\\"$:/themes/nico/notebook/options/reveal-tiddler-controls-on-hover\\\">\u003Coption value=\\\"no\\\">{{$:/language/No}}\u003C/option>\u003Coption value=\\\"yes\\\">{{$:/language/Yes}}\u003C/option>\u003C/$select> |\\n\\n! \u003C\u003Clingo Settings>>\\n\\n|\u003C$link to=\\\"$:/themes/nico/notebook/settings/fontfamily\\\">\u003C\u003Clingo Settings/FontFamily>>\u003C/$link> |\u003C$edit-text tiddler=\\\"$:/themes/nico/notebook/settings/fontfamily\\\" default=\\\"\\\" tag=\\\"input\\\"/> | |\\n|\u003C$link to=\\\"$:/themes/nico/notebook/settings/codefontfamily\\\">\u003C\u003Clingo Settings/CodeFontFamily>>\u003C/$link> |\u003C$edit-text tiddler=\\\"$:/themes/nico/notebook/settings/codefontfamily\\\" default=\\\"\\\" tag=\\\"input\\\"/> | |\\n|\u003C$link to=\\\"$:/themes/nico/notebook/settings/editorfontfamily\\\">\u003C\u003Clingo Settings/EditorFontFamily>>\u003C/$link> |\u003C$edit-text tiddler=\\\"$:/themes/nico/notebook/settings/editorfontfamily\\\" default=\\\"\\\" tag=\\\"input\\\"/> | |\\n\\n! \u003C\u003Clingo Metrics>>\\n\\n|\u00
{"created":"20230530121012871","text":"16:04:16 From Leon van Kammen : https://xrf.isvery.ninja/example/aframe/sandbox\n16:04:51 From Frode Hegland : https://futuretextlab.info\n16:04:54 From Leon van Kammen : https://xrf.isvery.ninja\n16:05:21 From Frode Hegland : https://futuretextlab.info/category/vr-resource/\n16:15:08 From Peter Wasilko : What is MR in the center of the diagram?\n16:15:28 From Brandel Zachernuk : “Mixed Reality”\n16:15:54 From Peter Wasilko : How is it distinguished from AR?\n16:17:09 From Brandel Zachernuk : It’s a term that people use to encompass the lot. Many people claimed that Google Glass-style AR with no ‘world registration’ as AR, which drove people to coining an additional term\n16:17:30 From Frode Hegland : Ah… thanks Brandel\n16:19:05 From Patrick Lichty : MR, XR, AR, VR, it seems these are used rather fungible, it’d be good to have a small discussion about the Venn diagram here after the talk.\n16:19:24 From Frode Hegland : Yes exactly http://community.cim3.net/wiki/PurpleNumbers.html\n16:19:39 From Frode Hegland : Doug’s paragraph level addressing made live on the web through this\n16:19:52 From Karl Hebenstreit, Jr. : Reacted to “MR, XR, AR, VR, it s…” with 👍\n16:22:14 From Peter Wasilko : I particularly loved Doug’s deep linking distinction between a location in a document whose content might change vs. content in a document whose location might change. We need anchors to both.\n16:22:43 From Frode Hegland : Reacted to “I particularly loved…” with 👍\n16:24:17 From Frode Hegland : Hi Dene\n16:24:36 From Patrick Lichty : Reacted to “I particularly loved…” with 👏\n16:25:08 From Dene Grigar To Frode Hegland(privately) : Good moring\n16:25:12 From Dene Grigar To Frode Hegland(privately) : morning\n16:25:27 From Frode Hegland To Dene Grigar(privately) : 🙂\n16:30:25 From Frode Hegland : Hi Matthias\n16:31:40 From Patrick Lichty : This is amazing, actually.\n16:31:51 From Peter Wasilko : It looked like the image on the surface of the portal object was changing with one’s relative position to it.\n16:33:09 From Dene Grigar : Is there an example of how this has been used for art?\n16:33:25 From Patrick Lichty : Yes.\n16:36:22 From Karl Hebenstreit, Jr. : Future of Interface Workshop (February 15-16), https://futureofinterface.org/info-center/accessibility/ and there’s an XR Accessibility community, https://xraccess.org/\n16:40:15 From Peter Wasilko : https://en.wikipedia.org/wiki/TouchDesigner\n16:40:47 From Peter Wasilko : https://derivative.ca\n16:45:25 From Fabien : addressability of the known universe with infinite resolution\n16:47:49 From Frode Hegland : Fabien, infinite resolution depends on stated context, so cool\n16:47:50 From Frode Hegland : Can this generate a link to a specific location and view by the user performing an action in that location and sharing it? Like a GPS coordinate maybe.\n16:50:22 From Brandel Zachernuk : This is the W3C TPAC: https://www.w3.org/2023/09/TPAC/, and the IW WG (webXR etc) is here: https://www.w3.org/immersive-web/\n16:50:28 From Fabien : Reacted to “This is the W3C TP…” with 👍\n16:51:33 From Matthias mprove : The TPAC link says ”Sorry, Insufficient Access Privileges”\n16:51:34 From Karl Hebenstreit, Jr. : I see XR accessibility as one of the most complex challenges. How can we make it accessible so people with disabilities are not excluded from virtual worlds?\n16:52:22 From Matthias mprove : Oh, the comma was playing a trick on me: https://www.w3.org/2023/09/TPAC/\n16:53:45 From Peter Wasilko : De Bruijn Indices! https://en.wikipedia.org/wiki/De_Bruijn_index\n17:01:36 From Dene Grigar : Yes, I do\n17:02:14 From Dene Grigar : VR poses a challenge for conservation\n17:02:39 From Frode Hegland : 1 second sorry\n17:02:49 From Fabien : indeed, participated to Not Time To Wait specifically for that https://mediaarea.net/NoTimeToWait6\n17:03:13 From Fabien : (for conservation, in art or not)\n17:03:28 From Daveed Benjamin : Love it Peter! Bit.ly for XR fragments\n17:03:55 From Matthias mpro
{"created":"20240619094946365","text":"XR Fragment-capable clients offer increased XR Accessibility via the so-called 2-button navigation:\n\n> TAB and ENTER actions allow for cycling/executing objects with `href` metadata \u003Cb>contextually\u003C/b>, meaning that only relevant objects are candidates for this (allowing comfortable tab-navigation inside huge worlds with large amounts of buttons). The buttons are remappable, and can also be triggered via speech.\n\n\u003Cdiv style=\"max-width:600px\">\n\u003C$videojs _autoplay controls=\"controls\" aspectratio=\"16:9\" preload=\"auto\" poster=\"\" fluid=\"fluid\" class=\"vjs-big-play-centered\">\n \u003Csource src=\"https://coderofsalvation.codeberg.page/xrfragment.media/accessibility-2buttonnav.mp4\" type=\"video/mp4\"/>\n\u003C/$videojs>\n\u003C/div>\n\nHere's the relevant part of the spec:\n\u003Cbr>\u003Cbr>\n\u003Ciframe src=\"doc/RFC_XR_Fragments.html#two-button-navigation\" frameborder=\"0\" class=\"spec\">\u003C/iframe>\n\nThe spec also defines a simple text-input interface which allows navigation via speech or text-input:\n\n\u003Ciframe src=\"doc/RFC_XR_Fragments.html#accessibility-interface\" frameborder=\"0\" class=\"spec\">\u003C/iframe>\n","tags":"[[📡 implicit scene features]]","title":"accessibility via commands","modified":"20241007083525196","type":"text/markdown"},
{"created":"20240712161508821","text":"\u003Ca href=\"https://en.wikipedia.org/wiki/Reflection_mapping\" target=\"_blank\">reflection mapping\u003C/a> enhances the realism of 3D objects by reflecting their surroundings.\u003Cbr>\nTo make sure each object uses the right environment map, in your 3D editor (blender e.g.) set it based on the closest parent object with a (seamless) texture.\n\n> This way, objects automatically inherit the appropriate reflections and lighting from their nearest parent, ensuring a consistent and realistic look across the scene.\n\n\u003Cbr>\nBelow is the related section of the spec (full spec here: \u003Ca href=\"doc/RFC_XR_Fragments.html\" target=\"_blank\">HTML\u003C/a>, \u003Ca href=\"doc/RFC_XR_Fragments.txt\" target=\"_blank\">TXT\u003C/a>)\n\n\u003Ciframe src=\"doc/RFC_XR_Fragments.html#reflection-mapping\" frameborder=\"0\" class=\"spec\">\u003C/iframe>\n\n\n","tags":"[[📡 implicit scene features]]","title":"automatic reflection mapping","modified":"20241014092343457","type":"text/markdown"},
{"created":"20240208094644929","text":"XR Fragment-capable clients can show/hide objects with a certain name or [tag](#tag) in various ways:\n\n`#\u003Ctag_or_objectname>[*]=\u003Cmaterialname>`\n\n| example | including children | info |\n|---------|--------------------|------|\n| `#foo=dark` | no | **changed material** of object with `foo` as name or part of [tag](#tag) (space-separated) to material (with name `dark`)|\n| `#foo*=dark` | yes | **changes material** of object with `foo` as name or part of [tag](#tag) (space-separated) to material (with name `dark`)|\n| `#!foo` | no | **resets material** of object with `foo` as name or part of [tag](#tag) back to original material |\n| `#!foo*` | yes | **resets material** of object with `foo` as name or part of [tag](#tag) back to original material |\n\n> NOTE: if a material does not exist, the update does not happen.","tags":"[[📡 implicit scene features]]","title":"changing object materials","modified":"20241007083525199","type":"text/markdown"},
{"created":"20240130111910059","text":"> NOTE: the following is adviced but also non-mandatory for clients: the default floor is assumed to be at coordinate 0,0,0\n\nXR Fragment-capable clients can sense walkable meshes, by scanning all objects in a scene for:\n\n1. non-existence of `href`-attribute \n\u003Cbr>\n2. non-existence of `src`-attribute \n\u003Cbr>\n3. non-existance of material \n\u003Cbr>\u003Cbr>\n\nIf all conditions are met, the mesh can be considered collidable/walkable (to teleport to e.g.)\n","tags":"[[📡 implicit scene features]]","title":"collidable / walkable objects","modified":"20241007083525204"},
{"created":"20240208121110799","text":"> An Easy ''nocode'' way to add metadata is [[by adding custom properties in blender e.g.|https://docs.blender.org/manual/en/2.79/data_system/custom_properties.html]]. Basically:\n\u003Cbr>\u003Cbr>\nCreate a plane or box-object, and add the following metadata:\n\n* `href`:`https://xrfragment.org` (to open a website in a new tab)\n* `href`:`https://me.com/model.glb` (to surf to a new 3D model)\n* `href`:`#.....` (interactivity: execute some fragments, see [[🖇 auto-generated fragments]] )","tags":"[[📡 implicit scene features]]","title":"create a button","modified":"20241007083525204"},
{"created":"20240319093241402","text":"The best environment for editing 3D models are...3D editors (like [[blender|https://blender.org]]).\n\u003Cbr>\u003Cbr>\nHowever, since XR Fragment browsers use URI (Fragments) for interactivity, a simple metadata-editor can easily be implemented.\u003Cbr>\nBelow is a demonstration of a [[editor.js|https://github.com/coderofsalvation/xrfragment/tree/main/src/3rd/js/plugin/frontend/$editor.js]] vanilla javascript-plugin, which adds a button to \nthe example viewer:\n\n\u003Cbr>\n\u003Cdiv style=\"max-width:600px\">\n\u003C$videojs controls=\"controls\" aspectratio=\"16:9\" preload=\"auto\" poster=\"\" fluid=\"fluid\" class=\"vjs-big-play-centered\">\n \u003Csource src=\"https://coderofsalvation.codeberg.page/xrfragment.media/xrfragment-editing-metadata.mp4\" type=\"video/mp4\"/>\n\u003C/$videojs>\n\u003C/div>\n\nBasically, a simple metadata editor allows for:\n\n!!! updating `href` values\n\n* to change teleportation destinations (internal links, external links)\n* to show hide certain objects when clicking a button\n* to open a certain website when clicking a button\n* to change networking adresses (Matrix room, WebRTC P2P roomname e.g.)\n\n!!! updating `src` values\n\n* to link to different (internal/external) 3D objects\n\n!!! updating `tag` values\n\n* to create/modify groups of object (for group-hiding/showing via `#-mygroup` and `#mygroup` in `href`-values)\n\n> Beyond this, you can choose to allow the enduser to edit any metadata.","tags":"[[📡 implicit scene features]]","title":"creating a simple editor","modified":"20241007083525205","type":"text/vnd.tiddlywiki"},
{"created":"20240731153010378","text":"> An Easy ''nocode'' way to add metadata is [[by adding custom properties in blender e.g.|https://docs.blender.org/manual/en/2.79/data_system/custom_properties.html]]. Basically:\n\u003Cbr>\n\n[Create a button](#create%20a%20button), but add the following metadata for HTTP-links:\n\n## server-backend redirect\n\n1. add to your button the metadata `href`:`https://yourserver.io/a?b`\n2. make your server return `Location: /final/link/here` based on `a` or `?b`, together with statuscode 302 (=temporary redirect).\n\n> Please refer to your server documentation on how to do a 302 redirect.\n\nThis allows for flexible server-controllable URLs inside a model. Keep in mind that this obviously reduces the portability of the model, which may (not) be a problem depending on the usecase.\n\n## nginx static redirect\n\n```\nlocation ~ /a\\?b$ {\n return 302 https://foobar.com;\n}\n```\n\n## apache static redirect\n\n```\nRewriteEngine On\nRewriteCond %{QUERY_STRING} ^a?b$\nRewriteRule ^(.*)$ https://foobar.com? [R=302,L]\n```\n","tags":"[[📡 implicit scene features]]","title":"dynamic buttons via server","modified":"20241007083525205","type":"text/markdown"},
{"created":"20240223092012710","text":"Create an empty mesh object (in Blender it's called an 'Empty') and add an [[src]] custom property with an local/external URL.\n\n* `src`: `#building`\n* `src`: `https://foo.com/world.fbx#building&-floor`\n\n> NOTE: remember that [[showing/hiding object(children)]] in an [[src]] will allow **spatial referencing** (reparenting the target object to the root of the scene).\u003Cbr>See the spec below:\n\n!Spec\n\nBelow is the related section of the spec (full spec here: \u003Ca href=\"doc/RFC_XR_Fragments.html\" target=\"_blank\">HTML\u003C/a>, \u003Ca href=\"doc/RFC_XR_Fragments.txt\" target=\"_blank\">TXT\u003C/a>)\n\n\u003Ciframe src=\"doc/RFC_XR_Fragments.html#spatial-referencing-3d\" frameborder=\"0\" class=\"spec\">\u003C/iframe>\n","tags":"[[📡 implicit scene features]]","title":"embed a 3D object (subtree)","modified":"20241007083525207"},
{"created":"20240722085406030","text":"Since 2020, Next Generation Internet (NGI) programmes, part of European Commission's Horizon programme, fund free software in Europe using a cascade funding mechanism (see for example NLnet's calls). This year, according to the Horizon Europe working draft detailing funding programmes for 2025, we notice that Next Generation Internet is not mentioned any more as part of Cluster 4.\n\nNGI programmes have shown their strength and importance to support the European software infrastructure, as a generic funding instrument to fund digital commons and ensure their long-term sustainability. We find this transformation incomprehensible, moreover when NGI has proven efficient and ecomomical to support free software as a whole, from the smallest to the most established initiatives. This ecosystem diversity backs the strength of European technological innovation, and maintaining the NGI initiative to provide structural support to software projects at the heart of worldwide innovation is key to enforce the sovereignty of a European infrastructure.\nContrary to common perception, technical innovations often originate from European rather than North American programming communities, and are mostly initiated by small-scaled organizations.\n\nPrevious Cluster 4 allocated 27 millions euros to:\n\n \"Human centric Internet aligned with values and principles commonly shared in Europe\" ;\n \"A flourishing internet, based on common building blocks created within NGI, that enables better control of our digital life\" ;\n \"A structured eco-system of talented contributors driving the creation of new internet commons and the evolution of existing internet commons\" .\n\nIn the name of these challenges, more than 500 projects received NGI funding in the first 5 years, backed by 18 organisations managing these European funding consortia.\n\nNGI contributes to a vast ecosystem, as most of its budget is allocated to fund third parties by the means of open calls, to structure commons that cover the whole Internet scope - from hardware to application, operating systems, digital identities or data traffic supervision. This third-party funding is not renewed in the current program, leaving many projects short on resources for research and innovation in Europe.\n\nMoreover, NGI allows exchanges and collaborations across all the Euro zone countries as well as \"widening countries\"¹, currently both a success and and an ongoing progress, likewise the Erasmus programme before us. NGI also contributes to opening and supporting longer relationships than strict project funding does. It encourages to implement projects funded as pilots, backing collaboration, identification and reuse of common elements across projects, interoperability in identification systems and beyond, and setting up development models that mix diverse scales and types of European funding schemes.\n\nWhile the USA, China or Russia deploy huge public and private resources to develop software and infrastructure that massively capture private consumer data, the EU can't afford this renunciation.\nFree and open source software, as supported by NGI since 2020, is by design the opposite of potential vectors for foreign interference. It lets us keep our data local and favors a community-wide economy and know-how, while allowing an international collaboration.\nThis is all the more essential in the current geopolitical context: the challenge of technological sovereignty is central, and free software allows to address it while acting for peace and sovereignty in the digital world as a whole.\n\nL’Union Européenne doit poursuivre le financement des logiciels libres\nDepuis 2020, les programmes Next Generation Internet (NGI), sous-branche du programme Horizon Europe de la Commission Européenne financent en cascade (via les appels de NLnet) le logiciel libre en Europe. Cette année, à la lecture du brouillon du Programme de Travail de Horizon Europe détaillant les programmes de financement de la commission européenne pour 2025, nous nous aperce
{"created":"20240619105321821","text":"3D Objects inside a 3D model can be referenced/shown/hidden via URI filters:\n\u003Cbr>\n\n\u003Cimg src=\"https://coderofsalvation.codeberg.page/xrfragment.media/images/filters.gif\" style=\"width:100%\"/>\n\nThis allows high re-usability of 3D modes for remote-, local- and recursive (embedded `src`) usecases:\n\u003Cbr>\u003Cbr>\n\n\u003Cpre>\n\u003Ccode>\n my.io/scene.usdz Embeddable as:\n +─────────────────────────────+\n │ sky │ src: http://my.io/scene.udsz#sky (includes building,mainobject,floor)\n │ +─────────────────────────+ │ \n │ │ building │ │ src: http://my.io/scene.udsz#building (includes mainobject,floor)\n │ │ +─────────────────────+ │ │\n │ │ │ mainobject │ │ │ src: http://my.io/scene.udsz#mainobject (includes floor)\n │ │ │ +─────────────────+ │ │ │\n │ │ │ │ floor │ │ │ │ src: http://my.io/scene.udsz#floor (just floor object)\n │ │ │ │ │ │ │ │\n │ │ │ +─────────────────+ │ │ │ href: http://my.io/scene.udsz#-mainobject (hides mainobject when clicked)\n │ │ +─────────────────────+ │ │\n │ +─────────────────────────+ │\n +─────────────────────────────+\n\u003C/code>\n\u003C/pre>\n\nThe [[href]] and [[src]] documentation show various examples, but the full syntax is explained in the spec below.\u003Cbr>\nOn top of that, [[tagged objects]] allow using `tag` metadata to group objects to trigger grouped features\n\n\u003Ch2>What does \"&-interactions*\" do in the demo scene?\u003C/h2>\n\nThe scene-node (3D root) of the [[demo scene|example/assets/index.glb]] indeed contains (startup) [[#]] metadata (`#pos=start&rot=0,40,0&t=0&-interactions*`).\n\u003Cbr>\nIts hiding all 3D objects (and their children) which are tagged with 'interactions'.\u003Cbr>\nFor example: you can see all the menu-items in Blender, but not in the browser.\u003Cbr>\n\n* `&` is just a separator ('AND do the following:')\n* `-` means 'hide'\n* `interactions` selects all objects with name 'interactions' or tag: interactions metadata\n* `*` selects all objects inside those selected objects too (text-objects etc)\n\n> For more on syntax see the spec below\n\n\u003Cbr>\u003Cbr>\n\u003Ciframe src=\"doc/RFC_XR_Fragments.html#xr-fragment-filters\" frameborder=\"0\" class=\"spec\">\u003C/iframe>\n\nFragment identifiers are derived from \u003Cb>metadata\u003C/b> inside the loaded 3D Model.\u003Cbr>More specific: \u003Cb>object-\u003C/b>, \u003Cb>material-\u003C/b>, and \u003Cb>camera-\u003C/b>names via a strategy called 'Fragment-to-metadata mapping':\n\n\u003Cbr>\u003Cbr>\n\u003Ciframe src=\"doc/RFC_XR_Fragments.html#fragment-to-metadata-mapping\" frameborder=\"0\" class=\"spec\">\u003C/iframe>\n\n","tags":"[[📡 implicit scene features]]","title":"filters","modified":"20241007083525208"},
{"created":"20230808113746326","text":"Just get your hands on a 3D editor (see this [[🖥 Blender ✅🔥]] guide) and follow the steps in the video:\n\u003Cbr>\u003Cbr>\n\u003Cdiv style=\"max-width:600px\">\n\u003C$videojs controls=\"controls\" aspectratio=\"16:9\" preload=\"auto\" poster=\"\" fluid=\"fluid\" class=\"vjs-big-play-centered\">\n \u003Csource src=\"https://coderofsalvation.codeberg.page/xrfragment.media/gettingstarted2024.mp4\" type=\"video/mp4\"/>\n\u003C/$videojs>\n\u003C/div>\n\n\n\u003Ccenter>\n \u003Ca class=\"btn\" href=\"https://matrix.to/#/#xrfragments:matrix.org\" target=\"_blank\" style=\"padding:10px 30px\">Join Matrix Community\u003C/a>\n\u003C/center>\n\nHere are various ways to create/test 3D files with XR Fragments:\n\n| ''scenario'' | ''how'' | ''notes'' |\n| easiest | see the [[🖥 Blender ✅🔥]] workflow using the \u003Ca href=\"/example/aframe/sandbox\" target=\"_blank\">Sandbox\u003C/a> on xrfragment.org | export 3D file (.glb) in \u003Ca href=\"https://blender.org\" target=\"_blank\">Blender\u003C/a>, after adding [[href]], [[src]] and [[tag]] \u003Cb>metadata\u003C/b> as \u003Ca href=\"https://docs.blender.org/manual/en/2.79/data_system/custom_properties.html\" target=\"_blank\">custom properties\u003C/a>, and load exported files into \u003Ca href=\"/example/aframe/sandbox\" target=\"_blank\">the sandbox\u003C/a> (see video above)|\n\n\u003Cbr>\n\n\u003Ch2>Developers\u003C/h2>\n\nFor developers wanting to integrate or build your own 3D hypermedia browser, the easiest is WebXR:\n\n\u003Ca href=\"example/aframe/sandbox\" target=\"_blank\">» View \u003Cb>index.glb\u003C/b> online\u003C/a> or \u003Ca href=\"index.glb\" target=\"_blank\">download \u003Cb>index.glb\u003C/b> and open\u003C/a> it in \u003Ca href=\"https://blender.org\" target=\"_blank\">Blender\u003C/a>.\u003Cbr>\n(developers can extend a 3D model viewer here \u003Ca href=\"https://codepen.io/coderofsalvation/pen/yLwedvX\" target=\"_blank\">this codepen\u003C/a>)\n\u003Cbr>\u003Cbr>\n\nBut there are also other approaches, as XR Fragments is not tied to any XR-technology or fileformat:\n\n| ''scenario'' | ''how'' | ''notes'' |\n| dev #godot | load the \u003Ca href=\"#%F0%9F%A7%B0%20GODOT\">example project\u003C/a> | |\n| dev #threejs #github #modular | fork \u003Ca href=\"https://github.com/coderofsalvation/xrfragment-three-helloworld\">xfragment-three-helloworld\u003C/a> | requires javascript- and \u003Ca href=\"https://threejs.org\" target=\"_blank\">threejs\u003C/a> developer-knowledge |\n| dev #polyglot | use the [[XR Fragment parser|https://github.com/coderofsalvation/xrfragment/tree/main/dist]] | lowlevel approach, more suitable for other scenarios |\n| dev #spec #browser | implement [[the spec|📜 XR fragments]] yourself | the spec is simple: parse URL and iterate over a scene |\n| dev #aframe #github | hosted sandbox by \u003Ca href=\"https://github.com/coderofsalvation/xrfragment-helloworld\" target=\"_blank\">forking xrfragment-helloworld\u003C/a> | Basically #1 but it will be hosted for free at your own github URL |\n| dev #aframe #github #modular | fork \u003Ca href=\"https://github.com/coderofsalvation/xrfragment-aframe-helloworld\">xfragment-aframe-helloworld\u003C/a> | requires javascript- and \u003Ca href=\"https://aframe.io\" target=\"_blank\">aframe.io\u003C/a> developer-knowledge |\n\nNext to that, familiarize yourself with XR Fragments by checking these videos: \n\n1. \u003Ca href=\"https://github.com/coderofsalvation/xrfragment.media\" target=\"_blank\">All videos on github\u003C/a> (tip: star the repo)\u003Cbr>\n2. \u003Ca href=\"https://www.youtube.com/playlist?list=PLctjJGlTmeE64XPSQER2BSbjmqVGaWM4J\" target=\"_blank\">All videos on Youtube\u003C/a> (tip: subscribe or add to 'Watch-later' list)","tags":"Home","title":"Getting started","modified":"20250211170414759","type":"text/vnd.tiddlywiki","list-before":"Philosophy & FAQ"},
{"created":"20240924135721168","text":"XR Fragments is \u003Cb>not a\u003C/b> fileformat-specific extension, it's a spec for so-called \u003Cb>embedded 'extras' in 3D assets.\u003C/b>\u003Cbr>\nThese are easier to use in any 3D editor (not only blender) than it would be to support new GLTF extensions.\u003Cbr>\nThis is not to say extensions are bad (they are superior in certain cases).\u003Cbr>\n\n> Just like URLs allow fileformat-agnostic navigation, 3D asset 'extras' are fileformat-agnostic too, which together allow for XR Fragments.\n\n# How to deal with overlapping functionality?\n\u003Cbr>\nWell, \u003Cb>extensions take precende, otherwise 'fallback' applies\u003C/b>.\n\u003Cbr>\nBelow is the related section of the spec (full spec here: \u003Ca href=\"doc/RFC_XR_Fragments.html\" target=\"_blank\">HTML\u003C/a>, \u003Ca href=\"doc/RFC_XR_Fragments.txt\" target=\"_blank\">TXT\u003C/a>)\n\n\u003Cbr>\u003Cbr>\n\n\u003Ciframe src=\"doc/RFC_XR_Fragments.html#overlap-with-fileformat-specific-extensions\" frameborder=\"0\" class=\"spec\">\u003C/iframe>\n\nFor more info see [How it works](#How%20it%20works)\n","tags":"Reference","title":"glTF extensions","modified":"20240925080534370","type":"text/markdown"},
{"created":"20240226111559175","text":"The hashbus sits inbetween HTML's traditional `href` and the toplevel URL.\u003Cbr>\nSay what?\u003Cbr>\n\u003Cbr>\n> Because of historical reasons the `href` bundles interaction (a click) and navigation (replacing the viewport with another resource).\n\nXR Fragments also allows separating these historicially merged actions, by introducing a hashbus:\n\n| href value | updates top-level URL |\n|-|-|\n| `#foo` | yes |\n|`xrf://#foo` | no |\n\nThis allows much more document interactions, with the following benefits:\n\n* interactions don't clutter URLs for back/forward button navigation\n* many usecases don't require a scripting language anymore (hiding/scrolling via [#uv](#uv) e.g.)\n* use same URI Fragment DSL for navigation and interactions\n* re-use URI Templates across 3D nodes\n* allow 3D nodes publish updates to other 3D nodes (via hashbus)\n\nIn short, a complete **hypermediatic feedback loop** (HFL).\n\n\u003Cbr>\nBelow is the related section of the spec (full spec here: \u003Ca href=\"doc/RFC_XR_Fragments.html\" target=\"_blank\">HTML\u003C/a>, \u003Ca href=\"doc/RFC_XR_Fragments.txt\" target=\"_blank\">TXT\u003C/a>)\n\n\u003Ciframe src=\"doc/RFC_XR_Fragments.html#hypermediatic-feedbackloop-for-xr-browsers\" frameborder=\"0\" class=\"spec\">\u003C/iframe>\n\n","tags":"","title":"hashbus","modified":"20240228122229072","type":"text/markdown"},
{"created":"20230428150217784","text":"\u003Cdiv class=\"border\" style=\"padding:15px\">\n \u003Cb>NOTE:\u003C/b> This is a \u003Cb>technical\u003C/b> page about \u003Ca href=\"doc/RFC_XR_Fragments.html\" target=\"_blank\">the spec\u003C/a>\u003Cbr>You might want to check out \u003Ca href=\"#Getting%20started\">Getting Started\u003C/a> instead.\n\u003C/div>\n\n\u003Cb>Short explanation\u003C/b>: XR Fragments empowers designers to navigate and ship portable interactive 3D files without programming, simply by using URLs:\u003Cbr>\n\u003Col>\n\u003Cli>as \u003Cb>implicit\u003C/b> navigational means for 3D viewers/browser (via the URL bar)\u003C/li>\n\u003Cli>as \u003Cb>explicit\u003C/b> [[metadata extras]] (metadata) in 3D scene-files (or \u003Ca href=\"https://xrfragment.org/doc/RFC_XR_Fragments.html#sidecar-file\" target=\"_blank\">sidecar-file\u003C/a> for nonportable decorative usecases)\u003C/li>\n\u003C/ol>\n\n\u003Cdiv style=\"text-align:center\">\n\u003Cb style=\"font-size:11px\">~10min podcast deepdive\u003C/b>\u003Cbr>\n\u003Caudio controls>\n \u003Csource src=\"https://coderofsalvation.codeberg.page/xrfragment.media/podcast-xrfragments-spec-xrwg.mp3\" type=\"audio/mpeg\" />\n\u003C/audio>\n\u003C/div>\n\u003Cbr>\nBoth URL-[[notation|🔗 URL]] and [[metadata extras]] are described \u003Ca href=\"doc/RFC_XR_Fragments.html\" target=\"_blank\">the spec\u003C/a>, but see the menubar for more practical documentation.\n\u003Cbr>\nThis URL/extras combi promotes ''Open Spatial Internet Features'' across ''existing'' authoring/viewing-software.\u003Cbr>\n\u003Cbr>It also allows fallback-features for 3D assets (FBX e.g.) which don't support certain (glTF e.g.) extensions.\n\u003Cbr>\u003Cbr>\n\u003Ccenter>\n \u003Ca class=\"btn\" href=\"https://matrix.to/#/#xrfragments:matrix.org\" target=\"_blank\" style=\"padding:10px 30px\">Join Matrix Community\u003C/a>\n\u003C/center>\n\u003Cbr>\n\n[img[xrfragment.jpg]]\n\n!! How are URLs embedded in 3D assets?\n\nXR Fragments is \u003Cb>not a\u003C/b> fileformat-specific extension, it's a spec for so-called \u003Cb>embedded 'extras' in 3D assets.\u003C/b>\u003Cbr>\nThese are easier to use in any 3D editor (not only blender) than it would be to support new fileformat-specific (glTF e.g.) extensions.\u003Cbr>\nThis is not to say extensions are bad (they are superior in certain cases, and can be side-by-side, see [[glTF extensions]] ).\u003Cbr>\n\n> Just like URLs allow fileformat-agnostic navigation, 3D asset 'extras' are fileformat-agnostic too. These lowest common denominators for interop, are the focus for XR Fragments.\n\nSo the outside world (browsers) can use URLs to reference content inside 3D assets, and 3D assets themselves can also embed 'extras' with URL-references to other objects (interaction/navigation).\n\n!! How can XR Browsers surf these worlds?\n\nUsing an \u003Cb>URL-bar\u003C/b> in your browser, app or OS.\u003Cbr>\nWhich points to an 3D scene or file ([[glTF|https://en.wikipedia.org/wiki/GlTF]], [[USDZ|https://en.wikipedia.org/wiki/Universal_Scene_Description]], [[OBJ|https://en.wikipedia.org/wiki/Wavefront_.obj_file]], [[COLLADA|https://en.wikipedia.org/wiki/COLLADA]], [[FBX|https://en.wikipedia.org/wiki/FBX]] e.g.):\n\u003Cbr>\u003Cbr>\u003Cbr>\n\u003Cdiv class=\"border padding\">\n\t\u003Cspan class=\"big\">://\u003C/span>\n\t\u003Cspan class=\"big hi2\">foo/world.gltf\u003C/span>\n\t\u003Cspan class=\"big hi1\">#cube\u003C/span>\n\t\u003Cspan class=\"big hi3\">&\u003C/span>\n\t\u003Cspan class=\"big hi1\">pos\u003C/span>\n\t\u003Cspan class=\"big hi3\">=\u003C/span>\n\t\u003Cspan class=\"big hi1\">otherroom\u003C/span>\n\u003C/div>\n\u003Cbr>\n\n> This basically instructs the browser: show (if hidden) object named 'cube' and teleport (move the camera) to object named 'otherroom'. \n\n!! OK..so extra metadata is needed first?\n\nNo, \u003Cb>explicit\u003C/b> [[metadata extras]] are optional, as [[#pos]] [[#rot]] [[🎞 Media Fragments]] and [[🖇 auto-generated fragments]] work regardless of it (they use implicit metadata based on the scene).\n\u00
{"created":"20230522115709081","text":"| fragment | type | example value |\n|`href`| string (uri or predefined view) | `#pos=1,1,0`\u003Cbr>`#pos=1,1,0&rot=90,0,0`\u003Cbr>`#pos=pyramid`\u003Cbr>`#pos=lastvisit`\u003Cbr>`xrf://#-someobject`\u003Cbr>`://somefile.gltf#pos=1,1,0`\u003Cbr> |\n\nhref metadata ('extras') in a 3D object, hint the viewer that the user can interact with that object :\n\n| sepc | feature |\n|-|-|\n| level1 | replace the current scene with a new 3D file (`href: other.glb` e.g.) |\n| level1 | teleport the user to another location within the current scene (`href: #pos=roomC` e.g.) |\n| level1 | highlight an object within a scene (`href: #someObjectName` e.g.) |\n| level2 | do a level1 feature without changing the URLbar location (`href: xrf://#someObjectName` e.g.) |\n| level2 | change a material of an object |\n| level2 | start or specify an animation of the scene or object (`href: #t=0`, `href: #car=drive` e.g.) |\n\n\n> NOTE: hashbus links (`xrf://#foo&bar`) don't change the toplevel URL, which makes it ideal for interactions (in contrast to typical `pos=` navigation, which benefit back/forward browser-buttons), see \u003Ca href=\"#hashbus\">hashbus\u003C/a> for more info.\n\n[[» example implementation|https://github.com/coderofsalvation/xrfragment/blob/main/src/3rd/js/three/xrf/href.js]]\u003Cbr>\n[[» example 3D asset|https://github.com/coderofsalvation/xrfragment/blob/main/example/assets/href.gltf#L192]]\u003Cbr>\n[[» discussion|https://github.com/coderofsalvation/xrfragment/issues/1]]\u003Cbr>\n\n[img[xrfragment.jpg]]\n\n\n!Spec\n\nBelow is the related section of the spec (full spec here: \u003Ca href=\"doc/RFC_XR_Fragments.html\" target=\"_blank\">HTML\u003C/a>, \u003Ca href=\"doc/RFC_XR_Fragments.txt\" target=\"_blank\">TXT\u003C/a>)\n\n\u003Ciframe src=\"doc/RFC_XR_Fragments.html#navigating-content-href-portals\" frameborder=\"0\" class=\"spec\">\u003C/iframe>\n\n> solutions in the spec were abducted from [[this|https://i.imgur.com/E3En0gJ.png]] and [[this|https://i.imgur.com/lpnTz3A.png]] survey result\n\n!!!Demo\n\n\u003C$videojs controls=\"controls\" aspectratio=\"16:9\" preload=\"auto\" poster=\"\" fluid=\"fluid\" class=\"vjs-big-play-centered\">\n \u003Csource src=\"https://coderofsalvation.codeberg.page/xrfragment.media/href.mp4\" type=\"video/mp4\"/>\n\u003C/$videojs>\n\n> capture of \u003Ca href=\"./example/aframe/sandbox\" target=\"_blank\">aframe/sandbox\u003C/a>\n\n","tags":"[[📜 level2: metadata extras]] level1","title":"href","modified":"20241007085507404","type":"text/vnd.tiddlywiki"},
{"created":"20230706161915394","text":"> Let's look at the browser thru the lens of XR, and not the other way around (it's a trap).\n\n* a \u003Cb>2D hyperlink\u003C/b> navigates/replaces the current document (or opens a tab)\n* a \u003Cb>hyperpreview\u003C/b> simply links/shows/summarizes an 2D/3D object/document/image\n\nA \u003Cb>hyperpreview\u003C/b> promotes \u003Cb>approximated summaries\u003C/b> of text documents, instead of fully supporting/rendering them.\u003Cbr>\nThat way, opening the content (spatially) will be offloaded to (other applications) on the client or operating system.\u003Cbr>\nThis is in contrast with traditional 2D (space-restricted) way of opening hyperlinks in new tabs (or replacing the current document).\n\n\n> Basically: the moment you want to implement HTML iframes into your spatial experience, you're looking at XR thru the lens of 2D (a common trap). The higher-dimensional recursive nature of XR Fragments \u003Cb>already allows\u003C/b> recursive (spatial i)frames.\n\n## Spec 0.5\n\n1. mimetype `text/html` instanced by [src](#src) should should be \u003Cb>hyperpreviewable\u003C/b> (a non-interactive 2D image-texture).\n\n2. When interacting with a \u003Cb>hyperpreview\u003C/b>, the XR Fragment host/client should offer copy/share of the adress (to clipboard and optionally other applications which can handle the mimetype).\n\n3. \u003Cb>hyperpreviews\u003C/b> should not aim for achieving 100% render-compatibility of all mimetypes. The goal is \u003Cb>addressbility\u003C/b> and \u003Cb>approximated summarization\u003C/b>, not embedding javascript-supported browser-iframes.\n\n4. Designers can solve unsupported mimetypes by using `src` for an image-thumbnail and `href` for the content (which should be offloaded to the (applications on) the operatingsystem)\n\nmimetype behaviour when user interacts with `src`:\n\n| mimetype | render | hyperpreview | action | update URL fragment | clipboard contents after clicking |\n|-|-|-|-|-|-|\n|\u003Cb>unknown mimetypes\u003C/b>| no | \n|text/html| no | yes |\u003Cb>summarize\u003C/b> HTML-text (first paragraph hinted by a fragment identifier e.g.) using crude html-to-image | name of object (`#website`) |\n|\u003Cb>3d objects\u003C/b>\u003Cbr>model/gltf+json\u003Cbr>model/glb\u003Cbr>model/obj\u003Cbr>..and so on | yes | no | highlight \u003Cbr>(draw boundingbox e.g.) | name of object (`#cube` e.g.) | `src`-value + linebreak + url with fragment: `http://other.com/other.gltf`\u003Cbr>`https://foo.com/#cube`\u003Cbr>Sharing such 'trail' (with the clipboardmanager) promotes backwards-reasoning (`other.gltf` is a cube in `scene.gltf` e.g.)\n|\u003Cb>images\u003C/b>\u003Cbr>image/png\u003Cbr>image/jpg\u003Cbr>image/gif\u003Cbr>..and so on | yes | no | highlight \u003Cbr>(draw border/boundingbox e.g.) | name of object (`#poster` e.g.) | object url with fragment (`https://foo.com/#cube` e.g.)\n\n\u003Chr>\n\n\u003Cb>Example\u003C/b>: embed an HTML document into your scene\n\n* create a plane with custom property [src](#src) and value `https://mysite.com/foo.html#summary` or `https://mysite.com/foo.html#chapter1`. \n* add custom property [\nso that the XR Fragment client can easily render a html-to-image conversion to a texture.\u003Cbr>\nThis is perfect for simple text.\u003Cbr>\nCRUD/scripting/animations don't belong in \u003Cb>hyperpreviews\u003C/b> and can partially be re-used in the 3D assets (using [src](#src) or fbx/gltf animations).\u003Cbr>\n\n\u003Chr>\n\n\u003Cb>Q\u003C/b>: How can I embed text from a textfile on a server?\n\n\u003Cb>A\u003C/b>: create an [src](#src) with value `https://mysite.com/foo.txt` so that the XR Fragment client can easily render a html-to-image conversion to a (non)scrolling texture.\u003Cbr>\n\n\u003Cbr>\n\n## Why are hyperpreviews so limited?\n\nBecause \u003Cb>hyperpreviews\u003C/b> separate the following concerns of hyperlinks: navigation, addressibility, interaction and rendering.\n\u003Cbr>\nIn \u003Cb>2D hyperlinks\u003C/b> we click links, which \u003Cb>navigates us to\u003C/b> AND \u003Cb>renders\u003C/b> the destinati
{"created":"20240229160427482","text":"This can be done using ''Descriptive metadata'' and ARIA descriptions (see [[🧩 Object metadata]])\n\n! Demo\n\n\u003C$videojs controls=\"controls\" aspectratio=\"16:9\" preload=\"auto\" poster=\"\" fluid=\"fluid\" class=\"vjs-big-play-centered\">\n \u003Csource src=\"https://coderofsalvation.codeberg.page/xrfragment.media/descriptive-metadata-implodes-3D-to-text.mp4\" type=\"video/mp4\"/>\n\u003C/$videojs>","tags":"[[📡 implicit scene features]]","title":"Imploding 3D scene to Text","modified":"20241007083525209","type":"text/vnd.tiddlywiki"},
{"created":"20230817073753245","text":"\n\nupdates the position of queried object(s)) relative to its original position\n\n| fragment | type | access | functionality |\n| \u003Cb>#mov\u003C/b>=0,0,0 | [[vector3|vector]] |🔓 🎲 💥 🔗| translate position |\n\n[[» example implementation|https://github.com/coderofsalvation/xrfragment/blob/main/src/3rd/js/three/xrf/mov.js]]\u003Cbr>\n[[» discussion|https://github.com/coderofsalvation/xrfragment/issues/9]]\u003Cbr>\n\n\n!!!spec\n\n> version 0.2\n\n1. translate the object(s) by adding the vector on top of its current position\n\n!!!Demo\n\n\u003C$videojs controls=\"controls\" aspectratio=\"16:9\" preload=\"auto\" poster=\"\" fluid=\"fluid\" class=\"vjs-big-play-centered\">\n \u003Csource src=\"https://coderofsalvation.codeberg.page/xrfragment.media/interactivity.mp4\" type=\"video/mp4\"/>\n\u003C/$videojs>\n\n> example of interactions using mov\n\n","tags":"","title":"mov","modified":"20230817075908855","type":"text/vnd.tiddlywiki"},
{"created":"20240130112528793","text":"XR Fragment-capable clients promotes \u003Cb>network-agnostic-or-a-la-carte\u003C/b> philosophy. Therefore, networking can be hinted using the [[href]] metadata.\n\nThis \u003Ca href=\"example/aframe/sandbox\" target=\"_blank\">\u003Cb>demoviewer\u003C/b>\u003C/a> basically detects `href` metadata with values:\n\n`matrix://r/myroom:matrix.org`\u003Cbr>\n`trystero://r/myroom:bittorent`\u003Cbr>\n`\u003Csomeprotocol>://\u003Cresource>`\u003Cbr>\n\n\u003Cbr>\n\u003Cdiv style=\"max-width:600px\">\n\u003C$videojs controls=\"controls\" aspectratio=\"16:9\" preload=\"auto\" poster=\"\" fluid=\"fluid\" class=\"vjs-big-play-centered\">\n \u003Csource src=\"https://coderofsalvation.codeberg.page/xrfragment.media/multiparty-matrix.mp4\" type=\"video/mp4\"/>\n\u003C/$videojs>\n\u003C/div>\n\nIn the demoviewer, just click the 'meeting link' or '[matrix]' button to see that it triggers a connection popup.\u003Cbr>\nAn important detail is that the user can always decide what (not) to connect (webcam/chat/scene events/avatar) e.g.\n\n> Important to notice: there's no compelling reason for why a networked experienced should go all-in (with avatars & scene-sync), just as there's no reason for websites to show all the mousecursors of all active visitors.\n\nTechnically, any XR Fragment-compatible client can support as much protocols as they want (natively, thru extensions, or using a viewer scriptinglanguage).\u003Cbr>\nThis is why XR Fragments is ready for future networks too.","tags":"[[📡 implicit scene features]]","title":"multiparty networking","modified":"20241007083525209"},
{"created":"20231128145723311","text":"> NOTE: the following is adviced but also non-mandatory for clients: offering buttons (with `href` or filters) next to portals/lenses makes things accessible for euclidian-only clients.\n\nA mesh ''without a material'' with an `src` value (referencing an object or URL reference) will turn into:\n\n1. ''Portals'': will render a referenced object (outside) of the portal \u003Cb>ALSO\u003C/b> inside of the object (portal)\u003Cbr>\n\u003Cbr>\n2. ''Lenses'': will render referenced \u003Cb>children\u003C/b> object \u003Cb>ONLY\u003C/b> inside of the parent object (the lens).\n\n> NOTE: the origin of the flat object, will correlate to `0,0,0` or the origin of the referenced object (the origin of object `bar` in case of `src: foo.usdz#bar` e.g.). So you can be creative with the origin of the portal/lens object, to reposition the referenced object. \n\nYou can see this demonstrated in \u003Ca href=\"/example/assets/index.glb\" target=\"_blank\">index.glb\u003C/a> or the demo-video & viewer below:\n\n\u003Cbr>\n\u003Cdiv style=\"max-width:600px\">\n\u003C$videojs controls=\"controls\" aspectratio=\"16:9\" preload=\"auto\" poster=\"\" fluid=\"fluid\" class=\"vjs-big-play-centered\">\n \u003Csource src=\"https://coderofsalvation.codeberg.page/xrfragment.media/portals-and-lenses.mp4\" type=\"video/mp4\"/>\n\u003C/$videojs>\n\u003C/div>\n\n! Portals\n\nWill render objects outside of the portal \u003Cb>ALSO\u003C/b> inside of the portal\n\n\u003Cimg style=\"width:100%;border-radius:5px;box-shadow:none;padding:20px\" class=\"border\" src=\"https://coderofsalvation.codeberg.page/xrfragment.media/images/portal.jpg\"/>\n\nExample scene hierarchy:\n\n```\n\n\n my.io/scene.usdz\n +─────────────────────────────+\n │ world1 │ \n │ +─────────────────────────+ │ \n │ │ myportal +-------+ src: #world2 \n | | | | + href: #pos=world2\n │ +─────────────────────────+ │\n │ world2 │ \n │ +─────────────────────────+ │ \n │ │ cube │ │ \n │ +─────────────────────────+ │\t\n +─────────────────────────────+\n\n\n```\n\n! Lenses\n\nWill render objects inside of the portal (children) \u003Cb>ONLY\u003C/b> inside of the portal.\n\n\u003Cimg style=\"width:100%;border-radius:5px;box-shadow:none;padding:20px\" class=\"border\" src=\"https://coderofsalvation.codeberg.page/xrfragment.media/images/xrlens.png\"/>\n\nExample scene hierarchy:\n\n```\n\n\n my.io/scene.usdz\n +─────────────────────────────+\n │ world1 │ \n │ +─────────────────────────+ │ \n │ │ myportal +-------+ src: #someinfo\n | | +──────────+ | | \n | | | someinfo | | |\n | | +──────────+ | |\n │ +─────────────────────────+ │\n │ world2 │ \n │ +─────────────────────────+ │ \n │ │ cube │ │ \n │ +─────────────────────────+ │\t\n +─────────────────────────────+\n\n\n```\n\n!Demo viewer\n\nPress the 'Teleport down there'-button (in the lens) and witness the portals afterwards yourself:\n\n\u003Ciframe class=\"border\" src=\"./example/aframe/sandbox/?index.glb\" frameborder=\"0\" style=\"width:100%;max-width:1000px; height:70%; min-height:500px;\"/>","tags":"[[📡 implicit scene feature
{"created":"20230508143700790","text":"Sit back and watch this ''#convergence-not-metaverse'' appstore-agnostic-but-symbiotic philosophy below:\u003Cbr>\u003Cbr>\u003Cbr>\n\n\u003Cdiv style=\"max-width:600px\">\n\u003C$videojs _autoplay controls=\"controls\" aspectratio=\"16:9\" preload=\"auto\" poster=\"\" fluid=\"fluid\" class=\"vjs-big-play-centered\">\n \u003Csource src=\"https://coderofsalvation.codeberg.page/xrfragment.media/xrfragment.bumper2.mp4\" type=\"video/mp4\"/>\n\u003C/$videojs>\n\u003C/div>\n\n!!FAQ\n\n\u003Cb>Q: Why is X not possible / so limited?\u003C/b>\u003Cbr/>\n\u003Cb>A:\u003C/b> You're probably referring to the \u003Cb>Example Model Browser\u003C/b> while XR Fragments is \u003Cb>a code-less framework-less language-less SPEC\u003C/b> for navigating and linking 3D models. This is important to realize. The spec is about parsing spatial hints in URI's from the URL-bar and metadata inside 3D models. Developers can decide to build anything on top of this paradigm which falls outside the spec.\n\n\u003Chr>\n\n\u003Cb>Q: How can XR Fragments support all 3D files ever made?\u003C/b>\u003Cbr>\n\u003Cb>A:\u003C/b> By targeting the lowest common denominator of all 3D fileformats: objectnames, positions, rotations (and metadata called `custom properties`/`extras`)\n\n\u003Chr>\n\n\u003Cb>Q: Do my 3D files need a specific (metadata) layout/format?\u003C/b>\u003Cbr>\n\u003Cb>A:\u003C/b> No, XR Fragments are file-agnostic and metadata is optional.\u003Cbr>\nThe objectnames inside the 3D file are used as URL references.\n\n\u003Chr>\n\n\u003Cb>Q: Do I need complex infrastructure?\u003C/b>\u003Cbr>\n\u003Cb>A:\u003C/b> No, XR Fragments are protocol-agnostic, you can host your files on a USB-stick, wordpress webserver, ftp-directory, ipfs, blockchain etc!\n\n\u003Chr>\n\n\u003Cb>Q: How will this enable the metaverse?\u003C/b>\u003Cbr>\n\u003Cb>A:\u003C/b> The metaverse is a fantasy sci-fi concept from a book. XR fragments deals with real people creating 3D interlinked content & storytelling.\n \n\u003Chr>\n\n\u003Cb>Q: Why not attach a programming language to XR Fragments\u003C/b>\u003Cbr>\n\u003Cb>A:\u003C/b> The intention is understandable, but it is out of scope. Programming languages & frameworks come and go. Hence XR Fragments is a spec for interactive metadata for 3D viewers. Hypermedia viewers based on metadata outsurvive programminglanguages in general.\u003Cbr>However, you are free to build programming language \u003Cb>to extend\u003C/b> experiences, or build a viewer or parser in your favorite language.\n\n\u003Chr>\n\u003Cb>Q: Why don't you add feature X from game Y?\u003C/b>\u003Cbr>\n\u003Cb>A:\u003C/b> To keep the spec simple, it is limited to 3 primitives and 3 fragments (`href`+`src`+`tag` and `#pos`+`#rot`+`#t`) which allows myriads of URL-controllable experiences (including the metadata already present in 3D files like object names and hierarchy).\u003Cbr>It's a pragmatic approach after witnessing many metaverse-inspired do-it-all complex technology-stacks.\n\n\n\n\u003Cbr>\u003Cbr>\n\n!!Philosophy\n\n\u003Cbr>\n\u003Cdiv style=\"max-width:600px\">\n\u003C$videojs controls=\"controls\" aspectratio=\"16:9\" preload=\"auto\" poster=\"\" fluid=\"fluid\" class=\"vjs-big-play-centered\">\n \u003Csource src=\"https://coderofsalvation.codeberg.page/xrfragment.media/philosophy.mp4\" type=\"video/mp4\"/>\n\u003C/$videojs>\n\u003C/div>\n\nWe have plenty of wellcrafted, amazing 3D assets on the web.\u003Cbr>\nWhat's missing? Hyperlinked no-code storytelling ❤\u003Cbr>\n\u003Cbr>\nWhat else is missing? adressibility of XR experiences.\u003Cbr>\nLess boilerplate code = productive XR design ❤\u003Cbr>\n\n> \u003Cb>do ask yourself\u003C/b>: why do Code-heavy XR applications tend to break over time due to browser/OS/dependency updates?\n\n!!Solution: XR Fragments\n\nLets invite some old battle-proof friends (`src`, `href`, `class`, `queries`, URL's and protocols), and connect our 3D assets \u003Cb>directly\u003C/b>:\n\n[img[interlinked.png]]\n\nMany meaningful experiences can be achieved using solely int
{"created":"20240208123050293","text":"> An Easy ''nocode'' way to add metadata is [[by adding custom properties in blender e.g.|https://docs.blender.org/manual/en/2.79/data_system/custom_properties.html]]. Basically:\n\u003Cbr>\u003Cbr>\n* create a plane object with a name (`scene1` e.g.)\n* create a plane object elsewhere with a name (`scene2` e.g.)\n* add metadata `#`:`pos=scene1` (to position the user during scene load)\n* now create a button object, and add metadata `href`:`#pos=scene2` to teleport the user (after clicking)\n\n> NOTE: teleportations focus on the **origin** of an object, so you might need to adjust them in case of a box e.g. (the origin is usually in the middle, which might not be what you want in case you want to teleport on top of the box).\n","tags":"[[📡 implicit scene features]]","title":"positioning the user/camera","modified":"20241007083525212","type":"text/markdown"},
{"created":"20230427205533684","text":"Just like with SVG fragments, predefined views are settings embedded in the asset.\u003Cbr>\nThey are basically an alias for a (bundle of) XR Fragments.\n\n## When are they triggered?\n\n* upon load by default (the `#` custom property, embedded in the asset)\n* when occuring in an url top-level change \n* on-demand (by clicking a `href`-property with value `#my_view` e.g.)\n\nBasically, a custom property-key in a 3D file/scene needs to match this, in order to have its value executed as XR Fragments URI.\u003Cbr>\n\n\u003Cbr>\n\u003Cdiv style=\"max-width:600px\">\n\u003C$videojs controls=\"controls\" aspectratio=\"16:9\" preload=\"auto\" poster=\"\" fluid=\"fluid\" class=\"vjs-big-play-centered\">\n \u003Csource src=\"https://coderofsalvation.codeberg.page/xrfragment.media/predefinedviews.mp4\" type=\"video/mp4\"/>\n\u003C/$videojs>\n\u003C/div>\n\u003Cbr>\n\n## Example scene\n\n```\n \n 🌎\n ├ #: #q=-sphere\n ├ #hide: #q=-.foo\n ├ #show: #q=.foo\n │\n ├── ◻ sphere\n │ └ href: #show|hide\n │\n └── ◻ cube\n └ class: foo\n \t\n```\n\nUpon load `#` will hide a mesh with name `sphere` by default, but when triggering `#hide` or `#show` (*) it will show/hide any object with class `foo` (in other words: the `cube` mesh) in [roundrobin fashion using `|`](#roundrobin).\n\n> \\* = by navigating the browser to `#hide` or clicking the sphere's `href` e.g. \n\n\n[» example implementation](https://github.com/coderofsalvation/xrfragment/blob/main/src/3rd/js/three/xrf/predefinedView.js#L41)\u003Cbr>\n\n## Spec\n\n> version 0.2\n\n1. upon scene-load, the XR Fragment parser should look for metadata (a unique custom property) in the scene with key `#` (and value `#presetA&english` e.g.)\n2. upon scene-load, the XR Fragment parser should look for predefined views in the top-level URL (basically keys without values, like `#foo&bar`)\n3. after collecting the predefined views, their respective string-values should be evaluated by searching thru the scene again (like step 1). A predefined view `#foo` will be defined somewhere as `#foo`:`#q=cube&scale=1,1,1` e.g.)\n4. the final XR Fragment strings (`#q=cube&scale=1,1,1` e.g.) should be applied to the scene.\n5. Recursion is OK (`#foo` -> `#bar` -> `#flop`) but the XR Fragment parser should protect against cyclic dynamics (`#foo` -> `#bar` -> `#foo` e.g.) by not evaluating the originating predefined view (`#foo`) twice during the same evaluation.\n\n# DIY Parsing\n\nThe AFRAME/THREE libraries do this for you, but here's how you would parse an top-level browser URI (`document.location.href` in javascript e.g.) using the [parser for other languages](https://github.com/coderofsalvation/xrfragment/tree/main/dist):\n\n\u003Cdiv>\n \u003Ctextarea spellcheck=\"false\" autofocus class=\"sandboxify\">frags = xrfragment.URI.parse('#my_view&t=1,2')\nconsole.log({\n frags,\n is_predefined_view: frags.my_view.is( xrfragment.XRF.PV_EXECUTE)\n})\n\n\u003C/textarea>\n\t\u003Cpre class=\"result\">\u003C/pre>\n\u003C/div>\n","tags":"","title":"predefined_view","modified":"20230815095750918","type":"text/markdown"},
{"created":"20230622092234442","text":"\u003Cb>RoundRobin\u003C/b> cycles thru a list of options (separated by `|`).\nIt is a very basic way to cycle thru [[predefined views or object-selections|predefined_view]]\n\n\u003Cbr>\n\u003Cdiv style=\"max-width:600px\">\n\u003C$videojs controls=\"controls\" aspectratio=\"16:9\" preload=\"auto\" poster=\"\" fluid=\"fluid\" class=\"vjs-big-play-centered\">\n \u003Csource src=\"https://coderofsalvation.codeberg.page/xrfragment.media/roundrobin.mp4\" type=\"video/mp4\"/>\n\u003C/$videojs>\n\u003C/div>\n\u003Cbr>\n\nFor example, when the user interacts with an embedded [[href]]:`#foo|bar` it will update the top-URL to:\n\n\u003Cbr>\u003Cbr>\n\u003Cdiv class=\"border\" style=\"border-radius:5px; padding:35px 30px 20px 20px; display:inline\">\n\u003Cspan class=\"big\">://\u003C/span>\n\u003Cspan class=\"big hi2\">url\u003C/span>\n\u003Cspan class=\"big hi1\">#foo\u003C/span>\n\u003C/div>\n\u003Cbr>\u003Cbr>\n\nBut after clicking it the second time:\n\n\u003Cbr>\u003Cbr>\n\u003Cdiv class=\"border\" style=\"border-radius:5px; padding:35px 30px 20px 20px; display:inline\">\n\u003Cspan class=\"big\">://\u003C/span>\n\u003Cspan class=\"big hi2\">url\u003C/span>\n\u003Cspan class=\"big hi1\">#bar\u003C/span>\n\u003C/div>\n\u003Cbr>\u003Cbr>\n\nAnd after clicking it the third time:\n\n\u003Cbr>\u003Cbr>\n\u003Cdiv class=\"border\" style=\"border-radius:5px; padding:35px 30px 20px 20px; display:inline\">\n\u003Cspan class=\"big\">://\u003C/span>\n\u003Cspan class=\"big hi2\">url\u003C/span>\n\u003Cspan class=\"big hi1\">#foo\u003C/span>\n\u003C/div>\n\u003Cbr>\u003Cbr>\n\n> And so on..\n\nYou can add as many `|` options as you want, you're simply restricted to the maximum-length limitations of URLs.\n","tags":"","title":"roundrobin","modified":"20230622093304383"},
{"created":"20230817075156856","text":"\n\nupdates the scale of [[queried|queries]] object(s))\n\n| fragment | type | access | functionality |\n| \u003Cb>#scale\u003C/b>=0,0,0 | [[vector3|vector]] |🔓 🎲 💥 🔗| scale [[queried|queries]] objects |\n\n[[» example implementation|https://github.com/coderofsalvation/xrfragment/blob/main/src/3rd/js/three/xrf/scale.js]]\u003Cbr>\n[[» discussion|https://github.com/coderofsalvation/xrfragment/issues/6]]\u003Cbr>\n\n!!!spec\n\n> version 0.2\n\n1. scale the object(s) by overwriting the scale-vector of the object(s) with the vector3 value of `scale`\n\n!!!Demo\n\n\u003C$videojs controls=\"controls\" aspectratio=\"16:9\" preload=\"auto\" poster=\"\" fluid=\"fluid\" class=\"vjs-big-play-centered\">\n \u003Csource src=\"https://coderofsalvation.codeberg.page/xrfragment.media/interactivity.mp4\" type=\"video/mp4\"/>\n\u003C/$videojs>\n\n> example of interactions using `mov`, `pos` (`scale` can be used as well)\n\n","tags":"","title":"scale","modified":"20230817075725779","type":"text/vnd.tiddlywiki"},
{"created":"20230706125411297","text":"Sometimes embedded properties (like [[href|href]] or [[src|src]]) instance new objects.\u003Cbr>\nBut what about their scale?\u003Cbr>\nHow does the scale of the object (with the embedded properties) impact the scale of the referenced content?\u003Cbr>\n\n> Rule of thumb: visible placeholder objects act as a '3D canvas' for the referenced scene (a plane acts like a 2D canvas for images e, a cube as a 3D canvas e.g.).\n\n!! Spec\n\n> version 0.2\n\n!!!! 1. \u003Cb>IF\u003C/b> an embedded property (`src` e.g.) is set on an non-empty placeholder object (geometry of >2 vertices):\n\n* calculate the \u003Cb>bounding box\u003C/b> of the ''placeholder'' object (maxsize=1.4 e.g.)\n* hide the ''placeholder'' object (material e.g.)\n* instance the `src` scene as a child of the existing object\n* calculate the \u003Cb>bounding box\u003C/b> of the instanced scene, and scale it accordingly (to 1.4 e.g.)\n\n> REASON: non-empty placeholder object can act as a protective bounding-box (for remote content of which might grow over time e.g.)\n\nTODO: needs intermediate visuals to make things more obvious\n\n!!!! 2. ELSE multiply the scale-vector of the instanced scene with the scale-vector of the \u003Cb>placeholder\u003C/b> object. \n","tags":"","title":"scaling of instanced objects","modified":"20230804104522801","type":"text/vnd.tiddlywiki"},
{"created":"20230607121914968","text":"A \u003Cb>Selection of Interest\u003C/b> (SoI) adheres to spirit of the original URI fragment, and it's rationale is further explained by Fabien Benetou's [[in this video|https://youtu.be/bfxqm1q_GXw?t=6407]].\u003Cbr>\nLet's have a look at this url:\n\n\u003Cbr>\u003Cbr>\n\u003Cdiv class=\"border\" style=\"border-radius:5px; padding:35px 30px 20px 20px; display:inline\">\n\u003Cspan class=\"big\">://\u003C/span>\n\u003Cspan class=\"big hi2\">url\u003C/span>\n\u003Cspan class=\"big hi1\">#cube\u003C/span>\n\u003Cspan class=\"big hi3\">&\u003C/span>\n\u003Cspan class=\"big hi1\">pos\u003C/span>\n\u003Cspan class=\"big hi3\">=\u003C/span>\n\u003Cspan class=\"big hi1\">0,0,0\u003C/span>\n\u003C/div>\n\n\u003Cbr>\nThis allows link-sharing and referencing on a macrolevel (`pos` positions the camera) and microlevel (`#cube`):\n\n\u003Cb>IF\u003C/b> the scene or file contains an object with name `cube` then the camera should \u003Cb>look at that object\u003C/b> and highlight it (draw a wire-frame bounding box e.g.).\n\nAnother example:\n\n\u003Cbr>\u003Cbr>\n\u003Cdiv class=\"border\" style=\"border-radius:5px; padding:35px 30px 20px 20px; display:inline\">\n\u003Cspan class=\"big\">://\u003C/span>\n\u003Cspan class=\"big hi2\">url\u003C/span>\n\u003Cspan class=\"big hi1\">#.cubes\u003C/span>\n\u003Cspan class=\"big hi3\">&\u003C/span>\n\u003Cspan class=\"big hi1\">pos\u003C/span>\n\u003Cspan class=\"big hi3\">=\u003C/span>\n\u003Cspan class=\"big hi1\">0,0,0\u003C/span>\n\u003C/div>\n\n\u003Cbr>\n\n\u003Cb>IF\u003C/b> the scene or file contains objects with custom property `class`: `cubes` then the camera should \u003Cb>look at that at least one object\u003C/b> and highlight them (draw a wire-frame bounding boxes e.g.).\n\n> NOTE: it is up to the end-user/client to not create links which contain a `pos` which makes it impossible to see the Selection of interest.\n\n\u003Cbr>\n\u003Cdiv style=\"max-width:600px\">\n\u003C$videojs controls=\"controls\" aspectratio=\"16:9\" preload=\"auto\" poster=\"\" fluid=\"fluid\" class=\"vjs-big-play-centered\">\n \u003Csource src=\"https://coderofsalvation.codeberg.page/xrfragment.media/selections.mp4\" type=\"video/mp4\"/>\n\u003C/$videojs>\n\u003C/div>","tags":"","title":"Selection of interest","modified":"20230622092212964"},
{"created":"20230817074913778","text":"\n\ntoggles the visibility of [[queried|queries]] objects\n\n| fragment | type | access | functionality |\n| \u003Cb>#show\u003C/b>=1 | integer [0-1] |🔓 🎲 💥 🔗| show (1) or hide (0) [[queried|queries]] objects |\n\n[[» example implementation|https://github.com/coderofsalvation/xrfragment/blob/main/src/3rd/js/three/xrf/show.js]]\u003Cbr>\n[[» discussion|https://github.com/coderofsalvation/xrfragment/issues/8]]\u003Cbr>\n\n\n!!!spec\n\n> version 0.2\n\n1. hide the object (material e.g.) when `show` has value 0\n\n2. show the object (material e.g.) when `show` has value 1\n\n3. not supported in [[src|src]] values (there plain [[queries|queries]] are used to hide/show object)\n\n!!!Demo\n\n\u003C$videojs controls=\"controls\" aspectratio=\"16:9\" preload=\"auto\" poster=\"\" fluid=\"fluid\" class=\"vjs-big-play-centered\">\n \u003Csource src=\"https://coderofsalvation.codeberg.page/xrfragment.media/interactivity.mp4\" type=\"video/mp4\"/>\n\u003C/$videojs>\n\n> example of interactions using show\n\n","tags":"","title":"show","modified":"20230817080230232","type":"text/vnd.tiddlywiki"},
{"created":"20240208094034099","text":"XR Fragment-capable clients can show/hide objects with a certain name or [tag](#tag) in various ways:\n\n`#[-]\u003Ctag_or_objectname>[*]`\n\n| example | including children | info |\n|---------|--------------------|------|\n| `#foo` | no | **shows** object with `foo` as name or part of [tag](#tag) (space-separated)|\n| `#foo*` | yes | **shows** object with `foo` as name or part of [tag](#tag) (space-separated)|\n| `#-foo` | no | **hides** object with `foo` as name or part of [tag](#tag) (space-separated)|\n| `#-foo*` | yes | **hides** object with `foo` as name or part of [tag](#tag) (space-separated)|\n","tags":"[[📡 implicit scene features]]","title":"showing/hiding object(children)","modified":"20241007083525216","type":"text/markdown"},
{"created":"20230526124859519","text":"!About me\n\nWorking for the internet (+vice versa).\u003Cbr>\nObserving internet & text (with a smile) thru the lens of Karl Popper & Neil Postman.\n\n[img[aboutleon.png]]","tags":"Slide_FutureOfText","title":"Slide_FutureOfText/03","modified":"20230527141610247"},
{"created":"20230527152525909","text":"!!Fragment\n\n\u003Cmedium>\na piece of information that is smaller than the whole\n\u003C/medium>\n\n\u003C\u003C\u003C\nXR Fragment adds: ''teleporting friends to specific (nested) experiences (at a certain time)''\n\u003C\u003C\u003C\n","tags":"Slide_FutureOfText","title":"Slide_FutureOfText/06","modified":"20230528161741263"},
{"created":"20230526182426315","text":"!!!Bold statement\n\nText keeps inviting itself to every party\n\u003C$image source=\"q.png\" width=\"500\"/>","tags":"Slide_FutureOfText","title":"Slide_FutureOfText/06.01","modified":"20230529094432565"},
{"created":"20230528125412620","text":"\u003Cdiv style=\"text-align:left\">\n \u003Cdiv class=\"jumbo\">2D\u003C/div>\n \u003Cspan>Fragment\u003C/span>\n\t\u003Cbr>\n\t\u003Cspan class=\"big hi1\">://\u003C/span>\n\t\u003Cspan class=\"big hi2\">experience.html\u003C/span>\n\t\u003Cspan class=\"big hi1\">#something\u003C/span>\n\u003Cbr>\u003Cbr>\u003Cbr>\n\t\u003Cspan class=\"hi3\">a friend\u003C/span> teleports me to \u003Cspan class=\"hi1\">something\u003C/span> somewhere at sometime\n\n\u003C/div>\n","tags":"Slide_FutureOfText","title":"Slide_FutureOfText/06.3","modified":"20230530130744096"},
{"created":"20230527153040161","text":"!!!Many projections of 4D XR\n\n[img[conflict.jpg]]","tags":"Slide_FutureOfText","title":"Slide_FutureOfText/07","modified":"20230529095429758"},
{"created":"20230528125440503","text":"\u003Cdiv style=\"text-align:left\">\n \u003Cdiv class=\"jumbo\">4D\u003C/div>\n \u003Cspan>URL\u003C/span>\n\t\u003Cbr>\n\t\u003Cspan class=\"big hi1\">://\u003C/span>\u003Cspan class=\"big hi2\">experience\u003C/span>\u003Cspan class=\"big hi1\">#pos=0,0,1&rot=0,90,0\u003C/span>&\u003Cspan class=\"big hi3\">t=100,500\u003C/span>\n\u003Cbr>\u003Cbr>\u003Cbr>\n\u003Cspan class=\"hi3\">a friend\u003C/span> teleports me to \u003Cspan class=\"hi1\">something\u003C/span> \u003Cspan class=\"hi2\">somewhere\u003C/span> at \u003Cspan class=\"hi3\">sometime\u003C/span>\n\n\u003C/div>\n","tags":"Slide_FutureOfText","title":"Slide_FutureOfText/07.46","modified":"20230530131933205"},
{"created":"20230527172507136","text":"!!!Metadata\n\nText keeps inviting itself to every party\n\u003C$image source=\"q.png\" width=\"500\"/>","tags":"Slide_FutureOfText","title":"Slide_FutureOfText/07.473","modified":"20230528164508207"},
{"created":"20230528145409844","text":"!!!src & href inviting themselves to the party (again)\n\n[img[xrfragment.jpg]]","tags":"Slide_FutureOfText","title":"Slide_FutureOfText/07.48","modified":"20230529095313152"},
{"created":"20230528134334366","text":"!!!URL is the teleport\n\n[img[interlinked.png]]\n\noffline-friendly","tags":"Slide_FutureOfText","title":"Slide_FutureOfText/07.5","modified":"20230528154146751"},
{"created":"20230527161553676","text":"\"URLs? been there done that.\"\n\n\u003Cbr>\n\u003C$image source=\"popper.png\" width=\"500\"/>","tags":"Slide_FutureOfText","title":"Slide_FutureOfText/09","modified":"20230528135511606"},
{"created":"20230527171212961","text":"!!Bold redefinition of URLs\nMultidimensional Cognitive Transformers (MCT)\n\n\u003C$image source=\"feedback.png\" width=\"300\"/>\n\u003Cbr>\n\u003Cmedium>\n\"//an interesting feedbackloop of experiences becoming metadata of text and/or vice-versa//\"\n\u003C/medium>\n\u003Cbr>\n","tags":"Slide_FutureOfText","title":"Slide_FutureOfText/16","modified":"20230528181858689"},
{"created":"20230620103309687","text":"`src` is the 3D version of the \u003Ca target=\"_blank\" href=\"https://www.w3.org/html/wiki/Elements/iframe\">iframe\u003C/a>.\u003Cbr>\nIt instances content (in objects) in the current scene/asset.\n\n| fragment | type | example value |\n|`src`| string (uri or [[predefined view|predefined_view]] or [[query|queries]]) | `#cube`\u003Cbr>`#-ball_inside_cube`\u003Cbr>`#-/sky&-rain`\u003Cbr>`#-language&english`\u003Cbr>`#price:>2&price:\u003C5`\u003Cbr>`https://linux.org/penguin.png`\u003Cbr>`https://linux.world/distrowatch.gltf#t=1,100`\u003Cbr>`linuxapp://conference/nixworkshop/apply.gltf#q=flyer`\u003Cbr>`androidapp://page1?tutorial#pos=0,0,1&t1,100`\u003Cbr>foo.mp3#t=0,0,0|\n\n> NOTE: when the enduser clicks `href: #cube` while object `cube` has a timeline-supported `src` set (`src: foo.mp3` `src: bar.mp4#t=0,0,0` e.g.), then `#t=1,1,0` (play oneshot) will be executed for that `src`(see [[#t|t]]).\n\n[[» example implementation|https://github.com/coderofsalvation/xrfragment/blob/main/src/3rd/js/three/xrf/src.js]]\u003Cbr>\n[[» example 3D asset|https://github.com/coderofsalvation/xrfragment/blob/main/example/assets/query.gltf#L192]]\u003Cbr>\n[[» discussion|https://github.com/coderofsalvation/xrfragment/issues/4]]\u003Cbr>\n\u003Cbr>\u003Cbr>\n\n!!Non-euclidian portals / lenses\n\n\u003Cimg style=\"width:100%;max-width:800px;border-radius:5px;box-shadow:none;padding:20px\" class=\"border\" src=\"https://coderofsalvation.codeberg.page/xrfragment.media/images/xrlens.png\"/>\n\nWhen `src` values are projected on flat 3D objects, they will be project [[non-euclidian]] as:\n\n1. \u003Cb>A portal\u003C/b>: render objects ALSO inside portal (which the enduser can walk into)\n2. \u003Cb>A lens\u003C/b>: render objects ONLY visible inside lens\n\n> Read more on the [[non-euclidian portals & lenses]] page\n\n!!XR audio/video integration\n\n* add a `src: foo.mp3` or `src: bar.mp4` metadata to a 3D object (`cube` e.g.)\n* to disable auto-play: add `#t=0,0,0` (`src: bar.mp3#t=0,0,0` e.g.)\n* to play it, add `href: #cube` somewhere else \n* when the enduser clicks the `href`, `#t=1,0,0` (play) will be applied to the `src` value\n\n> for more info see [[#t|t]].\n\n\u003Cbr>\n\u003Ciframe class=\"border\" src=\"./example/aframe/sandbox?./assets/src.gltf#pos=0,0,0&embed=1\" frameborder=\"0\" style=\"width:100%; height:70%; min-height:500px; max-width:1000px\"/>\n\u003Cbr>\n\u003Cbr>\n\u003Cdiv style=\"max-width:600px\">\n\u003C$videojs controls=\"controls\" aspectratio=\"16:9\" preload=\"auto\" poster=\"\" fluid=\"fluid\" class=\"vjs-big-play-centered\">\n \u003Csource src=\"https://coderofsalvation.codeberg.page/xrfragment.media/src.mp4\" type=\"video/mp4\"/>\n\u003C/$videojs>\n\u003C/div>\n\u003Cbr>\n\n!Spec\n\nBelow is the related section of the spec (full spec here: \u003Ca href=\"doc/RFC_XR_Fragments.html\" target=\"_blank\">HTML\u003C/a>, \u003Ca href=\"doc/RFC_XR_Fragments.txt\" target=\"_blank\">TXT\u003C/a>)\n\n\u003Ciframe src=\"doc/RFC_XR_Fragments.html#embedding-xr-content-src-instancing\" frameborder=\"0\" class=\"spec\">\u003C/iframe>\n","tags":"[[📜 level2: metadata extras]]","title":"src","modified":"20241007085507406","type":"text/vnd.tiddlywiki"},
{"created":"20231128144347734","text":"`tag` metadata allows tagging objects with strings (similar to `id` and `class` in HTML).\u003Cbr>\nIt is used by [[filters]] to reference groups of objects, and the [[XRWG]] to associate things with eachother.\u003Cbr>\n\n| fragment | type | example value |\n|`tag`| string (space separated) | `#cube`\u003Cbr>`#cubes`\u003Cbr>`#-sky&rain`\u003Cbr>`#-language&english`\u003Cbr>`#price=>2&price=\u003C5`|\n\n[[» discussion|https://github.com/coderofsalvation/xrfragment/issues/11]]\u003Cbr>\n","tags":"[[📜 level2: metadata extras]]","title":"tag","modified":"20241007085507407","type":"text/vnd.tiddlywiki"},
{"created":"20240130113718711","text":"XR Fragment-capable clients can reference objects with a certain `name` or `tag`, take for example this URL:\n\n`https://foo.com/index.glb#cubes`\n\nAfter loading the scene, all [[tags]] and object-names will be loaded into the XRWG, so that:\n\n1. objects with name `cubes` will be matched\n\u003Cbr>\n2. objects with [[tag]] `cubes` will be matched\n\u003Cbr>\n\u003Cbr>\nIf objects are matched, the client can draw visible links to/from the objects/visitor to 'point' to those objects of interest.\u003Cbr>\u003CBr>\n\nsee [[predefined_view]] for more info\n","tags":"[[📡 implicit scene features]]","title":"tagged objects","modified":"20241007083525221"},
{"created":"20240319091757152","text":"Shaders can be applied to meshes by adding [[src]] metadata, which supports [[sidecar loading|https://en.wikipedia.org/wiki/Sidecar_file]] of fragment/vertex shaderfiles.\n\u003Cbr>\nthe following fileformats are encouraged:\n\n* [[GLSL|https://www.khronos.org/opengl/wiki/Core_Language_(GLSL)]] (`.frag`/`.vert` are automatically sidecar loaded)\n* [[ISF|https://editor.isf.video/]]\n\n> at the moment [[GLSL|https://www.khronos.org/opengl/wiki/Core_Language_(GLSL)]] is supported in the XR Fragment demo-viewer:\n\n`src`: `https://foo.com/my.frag`\n\n> this will sidecar-load `https://foo.com/my.vert` (if exist)\n\n! Uniforms\n\nAs per the XR Fragment spec, these can be modified using the `u:\u003Cname>` fragment, for example:\n\u003Cbr>\u003Cbr>\n* `src`: `https://foo.com/my.frag#u:speed=0.2,0.4`\n\n> these can be manipulated via href-clicks and [[URI Fragment Templates|https://www.rfc-editor.org/rfc/rfc6570]]:\n\n* `src`: `https://foo.com/my.frag#{uspeed}`\n* `uspeed_slow`: `0.2,0.4`\n* `uspeed_fast`: `0.2,0.4`\n* `href`: `xrf://uspeed=uspeed_slow`\n","tags":"[[📡 implicit scene features]]","title":"using shaders","modified":"20241007083525221","type":"text/vnd.tiddlywiki"},
{"created":"20240328173212858","text":"> An Easy ''nocode'' way to add metadata is [[by adding custom properties in blender e.g.|https://docs.blender.org/manual/en/2.79/data_system/custom_properties.html]]. Basically:\n\u003Cbr>\u003Cbr>\nCreate a plane or box-object with a texture-material, and add the following metadata:\n\n* `#`:`#uv=0,0,0.1,0.1`\n\n> Profit! this will position the uv-coords initially at `0,0` and scroll `0.1` in the `u` and `v` direction.\n\nRead more about [[#uv|#uv 🌱]]\n\n> NOTE: combine it with [[Reactivity / URI templating]] if you want the user to control/change presets.","tags":"[[📡 implicit scene features]]","title":"uv and texture scrolling","modified":"20241007083525222"},
{"created":"20230427204906096","text":"comma-separated coordinates e.g. which after parsing can be accessed using `.x`, `.y`, `.z` etc.\n\n| type | example |\n|-|-|\n| vector2 | `1.2,3` or `0.4,0.6` | \n| vector3 | `1.2,3,4` or `0.4,0.6,5` | \n\nhere are some interactive examples:\n\n\u003Cdiv>\n \u003Ctextarea spellcheck=\"false\" autofocus class=\"sandboxify\">frags = {}\nok = xrfragment.Parser.parse('pos','1.2,2,3',frags)\nconsole.log( frags.pos.z )\n\n\u003C/textarea>\n\t\u003Cpre class=\"result\">\u003C/pre>\n\u003C/div>\n","tags":"","title":"vector","modified":"20230427205327718","type":"text/markdown"},
{"created":"20230424092557827","text":"An open \n\u003Cu tabindex=\"0\">specification\n \u003Cspan>which uses\u003C/span> \n \u003Cu tabindex=\"0\">implicit\n\t \u003Cspan>metadata, derived from the inherent structure, relationship, or patterns within 3D files.\u003Cbr> By using this \u003C/span>\n \u003C/u>\n\t\u003Cspan>metadata and\u003C/span>\n \t\u003Cu tabindex=\"0\">open standards\n\t \u003Cspan>, because many problems have been solved already via \n\t \u003Cu tabindex=\"0\">FOSS\n\t\t\t \u003Cspan>, which stands for Free Open Source Software, basically Global Commons \u003C/span>\n\t\t \u003C/u>\n\t\t\t\u003Cspan>, online indie innovation, and \u003Ca href=\"https://datatracker.ietf.org\" target=\"_blank\">RFCs\u003C/a>\u003C/span>\n\t\t\t. XR Fragments allows\n\t \u003C/span>\n\t\u003C/u>\t\t\n\u003C/u> for unifying 3D\n\u003Cu tabindex=\"0\">fileformats\n \u003Cspan>like \u003Cb>glTF\u003C/b>, \u003Cb>usdz\u003C/b>, \u003Cb>obj\u003C/b>, \u003Cb>collada\u003C/b> which are used in websites, Game Engines, and 3D editors like \u003Ca href=\"https://blender.org\" target=\"_blank\">Blender\u003C/a>.\u003Cbr>XR Fragments makes 3D files\u003C/span>\n\u003C/u>.\n\u003Cbr>\nTurn 3D files into \n\u003Cu tabindex=\"0\">linkable AR/VR websites\n \u003Cspan>, by embedding links in 3D files, using any \n \u003Cu tabindex=\"0\">protocol\n \u003Cspan>, not necessarily served via HTTP, but also \u003Ca href=\"https://ipfs.com\" target=\"_blank\">IPFS\u003C/a>, \u003Ca href=\"https://hypercore-protocol.github.io/new-website/guides/getting-started/\" target=\"_blank\">hypercore\u003C/a>, \u003Ca href=\"https://github.com/webtorrent/webtorrent\" target=\"_blank\">webtorrent\u003C/a> e.g. \u003C/span>\n\t \u003C/u>\n\t\u003C/span>\n\u003C/u>.\n\u003Cbr>3D files with XR Fragments enable interoperable,\n\u003Cu tabindex=\"0\">networkable\n \u003Cspan> by embedding URL metadata\u003C/span>\n\u003C/u>\nand\n \u003Cu tabindex=\"0\">interactions \n\t \u003Cspan>, like navigation, teleportation, showing/hiding objects, portals, lenses, loading and embedding scenes, hypermedia files and URLs, allowing useful immersive\u003C/span>\n\t\t\u003Cu tabindex=\"0\">experiences\n\t\t \u003Cspan>like e-learnings, quiz, realtime-rendered 3D movies, and audiovisual storytelling\u003C/span>\n\t\t\u003C/u>\n\t\u003C/u>\nvia so-called\n\u003Cu tabindex=\"0\">extras\n\u003Cspan>which is extra metadata exported to 3D asset-files,\u003C/span>\n\u003C/u>\nand promotes URL\n\u003Cu tabindex=\"0\">standards\n \u003Cspan>like \u003Ca href=\"https://en.wikipedia.org/wiki/URI_fragment\" target=\"_blank\">URI Fragments\u003C/a>, \u003Ca href=\"https://www.w3.org/TR/media-frags/\" target=\"_blank\">Media Fragments\u003C/a>, \u003Ca href=\"https://www.rfc-editor.org/rfc/rfc7111\" target=\"_blank\">CSV Fragments\u003C/a>, \u003Ca href=\"https://web.dev/articles/text-fragments\" target=\"_blank\">Text Fragments\u003C/a>.\n\t\u003Cbr>It decentralizes and aids \n\u003Cu tabindex=\"0\">DMA and GDPR-compliant\n \u003Cspan>solo 3D experiences, which are portable and don't save data or track user (network effects)\u003C/span>\n\u003Ca href=\"https://localfirstweb.dev\" target=\"_blank\">local-first\u003C/a> XR experiences.\u003Cbr>\n\u003C/u>\n\u003C/span>\n\u003C/u>.\u003Cbr>\n\n\u003Cbr>\nAvoid \u003Cb>cloudlock-in\u003C/b>, and make your 3D experiences \u003Cb>outlast\u003C/b> current technologies.\n\n\u003Cdiv style=\"text-align:center\">\n\u003Cb style=\"font-size:11px\">~10 mins podcast introduction\u003C/b>\u003Cbr>\n\u003Caudio controls src=\"https://coderofsalvation.codeberg.page/xrfragment.media/podcast-xrfragments-intro.mp3\" type=\"audio/mpeg\">\n\u003C/audio>\n\u003C/div>\n\n\u003Ccenter>\n \u003Ca class=\"btn\" href=\"example/aframe/sandbox\" target=\"_blank\" style=\"padding:10px 30px\">See example 3D file + viewer\u003C/a>\n\u003C/center>\n\n\u003Cbr>\n\u003Cdiv style=\"max-width:800px;box-shadow:none\" class=\"border\">\n\u003C$videojs _autoplay controls=\"controls\" aspectratio=\"16:9\" preload=\"auto\" poster=\"\" fluid=\"f
function t(a,b,c){if(4!==b.length)throw new sjcl.exception.invalid("invalid aes block size");var d=a.b[c],e=b[0]^d[0],f=b[c?3:1]^d[1],g=b[2]^d[2];b=b[c?1:3]^d[3];var h,k,l,n=d.length/4-2,m,p=4,r=[0,0,0,0];h=a.s[c];a=h[0];var q=h[1],v=h[2],w=h[3],x=h[4];for(m=0;m<n;m++)h=a[e>>>24]^q[f>>16&255]^v[g>>8&255]^w[b&255]^d[p],k=a[f>>>24]^q[g>>16&255]^v[b>>8&255]^w[e&255]^d[p+1],l=a[g>>>24]^q[b>>16&255]^v[e>>8&255]^w[f&255]^d[p+2],b=a[b>>>24]^q[e>>16&255]^v[f>>8&255]^w[g&255]^d[p+3],p+=4,e=h,f=k,g=l;for(m=
if(0>h)throw new sjcl.exception.invalid("this isn't base64!");26<e?(e-=26,c.push(g^h>>>e),g=h<<32-e):(e+=6,g^=h<<32-e)}e&56&&c.push(sjcl.bitArray.partial(e&56,g,1));returnc}};sjcl.codec.base64url={fromBits:function(a){returnsjcl.codec.base64.fromBits(a,1,1)},toBits:function(a){returnsjcl.codec.base64.toBits(a,1)}};sjcl.hash.sha256=function(a){this.b[0]||this.O();a?(this.F=a.F.slice(0),this.A=a.A.slice(0),this.l=a.l):this.reset()};sjcl.hash.sha256.hash=function(a){return(newsjcl.hash.sha256).update(a).finalize()};
function u(a,b){var c,d,e,f=a.F,g=a.b,h=f[0],k=f[1],l=f[2],n=f[3],m=f[4],p=f[5],r=f[6],q=f[7];for(c=0;64>c;c++)16>c?d=b[c]:(d=b[c+1&15],e=b[c+14&15],d=b[c&15]=(d>>>7^d>>>18^d>>>3^d<<25^d<<14)+(e>>>17^e>>>19^e>>>10^e<<15^e<<13)+b[c&15]+b[c+9&15]|0),d=d+q+(m>>>6^m>>>11^m>>>25^m<<26^m<<21^m<<7)+(r^m&(p^r))+g[c],q=r,r=p,p=m,m=n+d|0,n=l,l=k,k=h,h=d+(k&l^n&(k^l))+(k>>>2^k>>>13^k>>>22^k<<30^k<<19^k<<10)|0;f[0]=f[0]+h|0;f[1]=f[1]+k|0;f[2]=f[2]+l|0;f[3]=f[3]+n|0;f[4]=f[4]+m|0;f[5]=f[5]+p|0;f[6]=f[6]+r|0;f[7]=
f[7]+q|0}
sjcl.mode.ccm={name:"ccm",G:[],listenProgress:function(a){sjcl.mode.ccm.G.push(a)},unListenProgress:function(a){a=sjcl.mode.ccm.G.indexOf(a);-1<a&&sjcl.mode.ccm.G.splice(a,1)},fa:function(a){varb=sjcl.mode.ccm.G.slice(),c;for(c=0;c<b.length;c+=1)b[c](a)},encrypt:function(a,b,c,d,e){varf,g=b.slice(0),h=sjcl.bitArray,k=h.bitLength(c)/8,l=h.bitLength(g)/8;e=e||64;d=d||[];if(7>k)throw new sjcl.exception.invalid("ccm: iv must be at least 7 bytes");for(f=2;4>f&&l>>>8*f;f++);f<15-k&&(f=15-k);c=h.clamp(c,
8*(15-f));b=sjcl.mode.ccm.V(a,b,c,d,e,f);g=sjcl.mode.ccm.C(a,g,c,b,e,f);return h.concat(g.data,g.tag)},decrypt:function(a,b,c,d,e){e=e||64;d=d||[];var f=sjcl.bitArray,g=f.bitLength(c)/8,h=f.bitLength(b),k=f.clamp(b,h-e),l=f.bitSlice(b,h-e),h=(h-e)/8;if(7>g)throw new sjcl.exception.invalid("ccm: iv must be at least 7 bytes");for(b=2;4>b&&h>>>8*b;b++);b<15-g&&(b=15-g);c=f.clamp(c,8*(15-b));k=sjcl.mode.ccm.C(a,k,c,l,e,b);a=sjcl.mode.ccm.V(a,k.data,c,d,e,b);if(!f.equal(k.tag,a))thrownewsjcl.exception.corrupt("ccm:tagdoesn'tmatch");
sjcl.mode.ocb2={name:"ocb2",encrypt:function(a,b,c,d,e,f){if(128!==sjcl.bitArray.bitLength(c))throw new sjcl.exception.invalid("ocb iv must be 128 bits");var g,h=sjcl.mode.ocb2.S,k=sjcl.bitArray,l=k.i,n=[0,0,0,0];c=h(a.encrypt(c));var m,p=[];d=d||[];e=e||64;for(g=0;g+4<b.length;g+=4)m=b.slice(g,g+4),n=l(n,m),p=p.concat(l(c,a.encrypt(l(c,m)))),c=h(c);m=b.slice(g);b=k.bitLength(m);g=a.encrypt(l(c,[0,0,0,b]));m=k.clamp(l(m.concat([0,0,0]),g),b);n=l(n,l(m.concat([0,0,0]),g));n=a.encrypt(l(n,l(c,h(c))));
d.length&&(n=l(n,f?d:sjcl.mode.ocb2.pmac(a,d)));return p.concat(k.concat(m,k.clamp(n,e)))},decrypt:function(a,b,c,d,e,f){if(128!==sjcl.bitArray.bitLength(c))throw new sjcl.exception.invalid("ocb iv must be 128 bits");e=e||64;var g=sjcl.mode.ocb2.S,h=sjcl.bitArray,k=h.i,l=[0,0,0,0],n=g(a.encrypt(c)),m,p,r=sjcl.bitArray.bitLength(b)-e,q=[];d=d||[];for(c=0;c+4<r/32;c+=4)m=k(n,a.decrypt(k(n,b.slice(c,c+4)))),l=k(l,m),q=q.concat(m),n=g(n);p=r-32*c;m=a.encrypt(k(n,[0,0,0,p]));m=k(m,h.clamp(b.slice(c),p).concat([0,
0,0]));l=k(l,m);l=a.encrypt(k(l,k(n,g(n))));d.length&&(l=k(l,f?d:sjcl.mode.ocb2.pmac(a,d)));if(!h.equal(h.clamp(l,e),h.bitSlice(b,r)))throw new sjcl.exception.corrupt("ocb: tag doesn't match");return q.concat(h.clamp(m,p))},pmac:function(a,b){var c,d=sjcl.mode.ocb2.S,e=sjcl.bitArray,f=e.i,g=[0,0,0,0],h=a.encrypt([0,0,0,0]),h=f(h,d(d(h)));for(c=0;c+4<b.length;c+=4)h=d(h),g=f(g,a.encrypt(f(h,b.slice(c,c+4))));c=b.slice(c);128>e.bitLength(c)&&(h=f(h,d(h)),c=e.concat(c,[-2147483648,0,0,0]));g=f(g,c);
sjcl.misc.hmac.prototype.encrypt=sjcl.misc.hmac.prototype.mac=function(a){if(this.aa)throw new sjcl.exception.invalid("encrypt on already updated hmac called!");this.update(a);return this.digest(a)};sjcl.misc.hmac.prototype.reset=function(){this.R=new this.W(this.w[0]);this.aa=!1};sjcl.misc.hmac.prototype.update=function(a){this.aa=!0;this.R.update(a)};sjcl.misc.hmac.prototype.digest=function(){var a=this.R.finalize(),a=(new this.W(this.w[1])).update(a).finalize();this.reset();return a};
sjcl.misc.pbkdf2=function(a,b,c,d,e){c=c||1E4;if(0>d||0>c)throw new sjcl.exception.invalid("invalid params to pbkdf2");"string"===typeof a&&(a=sjcl.codec.utf8String.toBits(a));"string"===typeof b&&(b=sjcl.codec.utf8String.toBits(b));e=e||sjcl.misc.hmac;a=new e(a);var f,g,h,k,l=[],n=sjcl.bitArray;for(k=1;32*l.length<(d||1);k++){e=f=a.encrypt(n.concat(b,[k]));for(g=1;g<c;g++)for(f=a.encrypt(f),h=0;h<f.length;h++)e[h]^=f[h];l=l.concat(e)}d&&(l=n.clamp(l,d));returnl};
(k=1);if(!k){if(void 0===b)for(c=b=0;c<a.length;c++)for(e=a[c];0<e;)b++,e=e>>>1;this.c[g].update([d,this.N++,2,b,f,a.length].concat(a))}break;case "string":void 0===b&&(b=a.length);this.c[g].update([d,this.N++,3,b,f,a.length]);this.c[g].update(a);break;default:k=1}if(k)throw new sjcl.exception.bug("random: addEntropy only supports number, array of numbers or string");this.m[g]+=b;this.f+=b;h===this.u&&(this.isReady()!==this.u&&A("seeded",Math.max(this.o,this.f)),A("progress",this.getProgress()))},
this.a.mouseCollector),document.detachEvent("keypress",this.a.keyboardCollector)),this.D=!1)},addEventListener:function(a,b){this.K[a][this.ga++]=b},removeEventListener:function(a,b){var c,d,e=this.K[a],f=[];for(d in e)e.hasOwnProperty(d)&&e[d]===b&&f.push(d);for(c=0;c<f.length;c++)d=f[c],deletee[d]},la:function(){C(this,1)},oa:function(a){varb,c;try{b=a.x||a.clientX||a.offsetX||0,c=a.y||a.clientY||a.offsetY||0}catch(d){c=b=0}0!=b&&0!=c&&this.addEntropy([b,c],2,"mouse");C(this,0)},qa:function(a){a=
function A(a,b){var c,d=sjcl.random.K[a],e=[];for(c in d)d.hasOwnProperty(c)&&e.push(d[c]);for(c=0;c<e.length;c++)e[c](b)}functionC(a,b){"undefined"!==typeofwindow&&window.performance&&"function"===typeofwindow.performance.now?a.addEntropy(window.performance.now(),b,"loadtime"):a.addEntropy((newDate).valueOf(),b,"loadtime")}functiony(a){a.b=z(a).concat(z(a));a.L=newsjcl.cipher.aes(a.b)}functionz(a){for(varb=0;4>b&&(a.h[b]=a.h[b]+1|0,!a.h[b]);b++);return a.L.encrypt(a.h)}
function B(a,b){return function(){b.apply(a,arguments)}}sjcl.random=new sjcl.prng(6);
else break a;sjcl.random.addEntropy(F,1024,"crypto['getRandomValues']")}}catch(a){"undefined"!==typeof window&&window.console&&(console.log("There was an error collecting entropy from the browser:"),console.log(a))}
b.mode&&sjcl.arrayBuffer&&sjcl.arrayBuffer.ccm&&b.ct instanceof ArrayBuffer?sjcl.arrayBuffer.ccm.decrypt(g,b.ct,b.iv,b.tag,f,b.ts):sjcl.mode[b.mode].decrypt(g,b.ct,b.iv,f,b.ts);e.g(d,b);d.key=a;return 1===c.raw?f:sjcl.codec.utf8String.fromBits(f)},decrypt:function(a,b,c,d){var e=sjcl.json;return e.ia(a,e.decode(b),c,d)},encode:function(a){var b,c="{",d="";for(b in a)if(a.hasOwnProperty(b)){if(!b.match(/^[a-z0-9]+$/i))throw new sjcl.exception.invalid("json encode: invalid property name");c+=d+'"'+
b+'":';d=",";switch(typeof a[b]){case "number":case "boolean":c+=a[b];break;case "string":c+='"'+escape(a[b])+'"';break;case "object":c+='"'+sjcl.codec.base64.fromBits(a[b],0)+'"';break;default:throw new sjcl.exception.bug("json encode: unsupported type");}}return c+"}"},decode:function(a){a=a.replace(/\s/g,"");if(!a.match(/^\{.*\}$/))throw new sjcl.exception.invalid("json decode: this isn't json!");a=a.replace(/^\{|\}$/g,"").split(/,/);var b={},c,d;for(c=0;c<a.length;c++){if(!(d=a[c].match(/^\s*(?:(["']?)([a-z][a-z0-9]*)\1)\s*:\s*(?:(-?\d+)|"([a-z0-9+\/%*_.@=\-]*)"|(true|false))$/i)))thrownewsjcl.exception.invalid("jsondecode:thisisn'tjson!");
null!=d[3]?b[d[2]]=parseInt(d[3],10):null!=d[4]?b[d[2]]=d[2].match(/^(ct|adata|salt|iv)$/)?sjcl.codec.base64.toBits(d[4]):unescape(d[4]):null!=d[5]&&(b[d[2]]="true"===d[5])}return b},g:function(a,b,c){void 0===a&&(a={});if(void 0===b)return a;for(var d in b)if(b.hasOwnProperty(d)){if(c&&void 0!==a[d]&&a[d]!==b[d])throw new sjcl.exception.invalid("required parameter overridden");a[d]=b[d]}return a},sa:function(a,b){var c={},d;for(d in a)a.hasOwnProperty(d)&&a[d]!==b[d]&&(c[d]=a[d]);return c},ra:function(a,
Information about each module is kept in an object with these members:
moduleType: type of module
definition: object, function or string defining the module; see below
exports: exports of the module, filled in after execution
The `definition` can be of several types:
* An object can be used to directly specify the exports of the module
* A function with the arguments `module,require,exports` that returns `exports`
* A string function body with the same arguments
Each moduleInfo object is stored in two hashmaps: $tw.modules.titles and $tw.modules.types. The first is indexed by title and the second is indexed by type and then title
*/
$tw.modules = {
titles: {}, // hashmap by module name of moduleInfo
types: {} // hashmap by module type and then name of moduleInfo
};
/*
Define a JavaScript tiddler module for later execution
moduleName: name of module being defined
moduleType: type of module
definition: module definition; see discussion above
The main boot kernel for TiddlyWiki. This single file creates a barebones TW environment that is just sufficient to bootstrap the modules containing the main logic of the application.
On the server this file is executed directly to boot TiddlyWiki. In the browser, this file is packed into a single HTML file.
\*/
var _boot = (function($tw) {
/*jslint node: true, browser: true */
/*global modules: false, $tw: false */
"use strict";
// Include bootprefix if we're not given module data
if(!$tw) {
$tw = require("./bootprefix.js").bootprefix();
}
$tw.utils = $tw.utils || Object.create(null);
/////////////////////////// Standard node.js libraries
promptMsg = ( $tw.language == undefined ? "Well, this is embarrassing. It is recommended that you restart TiddlyWiki by refreshing your browser" : $tw.language.getString("InternalJavaScriptError/Hint") );
Fill in any null or undefined properties of an object with the properties from a list of source objects. Each property that is an object is called recursively
Get the browser location.hash. We don't use location.hash because of the way that Firefox auto-urldecodes it (see http://stackoverflow.com/questions/1703552/encoding-of-window-location-hash)
submitText: text to use for submit button (defaults to "Login")
serviceName: text of the human readable service name
noUserName: set true to disable username prompt
canCancel: set true to enable a cancel button (callback called with null)
repeatPassword: set true to prompt for the password twice
callback: function to be called on submission with parameter of object {username:,password:}. Callback must return `true` to remove the password prompt
Return an array of classes created from the modules of a specified type. Each module should export the properties to be added to those of the optional base class
Wiki constructor. State is stored in private members that only a small number of privileged accessor methods have direct access. Methods added via the prototype have to use these accessors and cannot access the state data directly.
options include:
enableIndexers - Array of indexer names to enable, or null to use all available indexers
*/
$tw.Wiki = function(options) {
options = options || {};
var self = this,
tiddlers = Object.create(null), // Hashmap of tiddlers
// Register the plugin tiddlers of a particular type, or null/undefined for any type, optionally restricting registration to an array of tiddler titles. Return the array of titles affected
self.unregisterPluginTiddlers(null,[title]); // Unregister the plugin if it's already registered
pluginTiddlers.push(tiddler);
registeredTitles.push(tiddler.fields.title);
}
}
};
if(titles) {
$tw.utils.each(titles,function(title) {
checkTiddler(self.getTiddler(title),title);
});
} else {
this.each(function(tiddler,title) {
checkTiddler(tiddler,title);
});
}
return registeredTitles;
};
// Unregister the plugin tiddlers of a particular type, or null/undefined for any type, optionally restricting unregistering to an array of tiddler titles. Returns an array of the titles affected
Enable safe mode by deleting any tiddlers that override a shadow tiddler
*/
$tw.Wiki.prototype.processSafeMode = function() {
var self = this,
overrides = [];
// Find the overriding tiddlers
this.each(function(tiddler,title) {
if(self.isShadowTiddler(title)) {
console.log(title);
overrides.push(title);
}
});
// Assemble a report tiddler
var titleReportTiddler = "TiddlyWiki Safe Mode",
report = [];
report.push("TiddlyWiki has been started in [[safe mode|https://tiddlywiki.com/static/SafeMode.html]]. All plugins are temporarily disabled. Most customisations have been disabled by renaming the following tiddlers:")
Decrypt any tiddlers stored within the element with the ID "encryptedArea". The function is asynchronous to allow the user to be prompted for a password
callback: function to be called the decryption is complete
// Storing encrypted tiddlers on the server isn't supported yet
callback();
};
} // End of if($tw.browser && !$tw.node)
/////////////////////////// Node definitions
if($tw.node) {
/*
Load the tiddlers contained in a particular file (and optionally extract fields from the accompanying .meta file) returned as {filepath:,type:,tiddlers:[],hasMetaFile:}
Load all the tiddlers recursively from a directory, including honouring `tiddlywiki.files` files for drawing in external files. Returns an array of {filepath:,type:,tiddlers: [{..fields...}],hasMetaFile:}. Note that no file information is returned for externally loaded tiddlers, just the `tiddlers` property.