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.github.io/xrfragment.media/gettingstarted2024.mp4#t=358]])","tags":"[[📡 by feature (heuristics)]]","title":"(non)positional audio","modified":"20240206123715235"},
{"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":"[[🧩 Object metadata]]","title":"#","modified":"20240228122206317","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.github.io/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 (''level2'': or queried object(s)).\n\n| fragment | type | functionality |\n| \u003Cb>#pos\u003C/b>=0,0,0 | [[vector3|vector]] |position camera |\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":"[[📜 XR Fragments]]","title":"#pos","modified":"20231128144134777","type":"text/vnd.tiddlywiki"},
{"created":"20230815160020110","text":"\n\nset the rotation of the camera (''level2'': or queried object(s)).\n\n| fragment | type | access | functionality |\n| \u003Cb>#rot\u003C/b>=0,90,0 | [[vector3|vector]] |🔓 🎲 💥 🔗| rotate camera (level2: or [[queried|#queries]] object(s)) |\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":"[[📜 XR Fragments]]","title":"#rot","modified":"20231128144235519","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.github.io/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.github.io/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.github.io/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]]","title":"#t","modified":"20240228121642698","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.github.io/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.github.io/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 (\u003Cb>pseudo-browser\u003C/b> using javascript libs like THREE/AFRAME)\n* thru the lens of hypermedia browsers (opening XR Documents (`.gltf`, `.obj` e.g) natively using URLs)\n\nThe [Godot XRF Library](#%F0%9F%A7%B0%20GODOT) is a suitable direction for making native XR hypermedia browsers.\n\n> in progress: integrating the XR Fragment parser on native browserlevel (Wolvic, Chromium-based browsers e.g.) for best performance.\n\nfor \u003Cb>pseudo-XR Fragment browsers\u003C/b> see the \u003Cb>AFRAME and THREEjs\u003C/b> libraries","tags":"[[🧰 Libaries & Tools]]","title":"🌎 Native hypermedia browsers","modified":"20240520080222957","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.github.io/xrfragment.media/media_uv_template_fragments.mp4\" type=\"video/mp4\"/>\n\u003C/$videojs>\n\u003C/div>\n\n","tags":"[[📜 XR Fragments]]","title":"🎞 Media Fragments","modified":"20240228122035043"},
{"created":"20230427172131986","text":"> [](https://github.com/coderofsalvation/xrfragment/actions)\u003Cbr>Bare minimum addressibility URI fragments for spatial browsers & apps. \u003Cbr>It allows users to share 4D (intent) URLs to eachother like:\u003Cbr>`https://linux.world/#pos=0,0,1&t=1,100`\u003Cbr>`linuxapp://conference/nixworkshop?newuser#pos=0,0,2&t=2,200`\u003Cbr>`androidapp://page1?tutorial#pos=0,0,1&t1,100`\u003Cbr>\n\n\u003Cbr>\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\u003Cbr>\u003Cbr>\n\n\u003Ciframe src=\"doc/RFC_XR_Fragments.html#list-of-uri-fragments\" frameborder=\"0\" class=\"spec\">\u003C/iframe>\n\nFor more info see [How it works](#How%20it%20works)\n","tags":"Reference","title":"📜 XR Fragments","modified":"20240208124144733","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>\nThanks to this, the XR Fragment specs stays small (just `src` + `href` + `href` metadata, controlled by URI Fragments)\n","tags":"Reference","title":"📡 by feature (heuristics)","modified":"20240206124341480"},
{"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":"[[🧰 Libaries & Tools]] [[🧰 libraries]]","title":"🔨 XR Fragments parser","modified":"20240416144439565","type":"text/markdown"},
{"created":"20240208102607476","text":"There are only 2 **static** XR Fragments (`#pos` and `#rot`) and the rest are **auto-generated scene-specific** fragments.\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\n> For more examples see \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":"[[📜 XR Fragments]]","title":"🖇 auto-generated fragments","modified":"20240208120851990","type":"text/markdown"},
{"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). Basically:\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| 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>\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.github.io/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":"[[📜 XR Fragments]]","title":"🧩 Object metadata","modified":"20240229160413143","type":"text/markdown"},
{"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\u003Cdiv>\n \u003Ctextarea class=\"sandboxify\"><script src=\"https://xrfragment.org/dist/xrfragment.aframe.js\"></script>\n<a-entity xrf=\"https://xrfragment.org/index.glb\"></a-entity>\n \u003C/textarea>\n\u003C/div>\n\n> for realtime fiddling and live example try [this codepen](https://codepen.io/coderofsalvation/pen/yLwedvX)\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\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.github.io/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 as [js/THREE.js](#js/THREE.js) (see for more info)","title":"🧰 AFRAME","modified":"20240416145109932","type":"text/markdown","tags":"[[🧰 libraries]] [[🧰 Libaries & Tools]]"},
{"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.github.io/xrfragment.media/xrfragment-godot.mp4\" type=\"video/mp4\"/>\n\u003C/$videojs>\n\u003C/div>","title":"🧰 GODOT","modified":"20240520080024474","type":"text/markdown","tags":"[[🧰 libraries]] [[🧰 Libaries & 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| **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 object |\n| **XRWG** | ⚠️emitted when XR Word Graph is being recalculated |\n| **predefinedView** | emitt
{"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":"20240105120105242","title":"$:/state/toc/Reference/🧰 libraries-XR Fragment parser--403145756","text":"open","modified":"20240105120105242"},
{"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|\u003C$link to=\\\"$:/themes/tiddl
{"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":"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":"[[📡 by feature (heuristics)]]","title":"changing object materials","modified":"20240208095728657","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":"[[📡 by feature (heuristics)]]","title":"collidable / walkable objects","modified":"20240206123715236"},
{"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":"[[📡 by feature (heuristics)]]","title":"create a button","modified":"20240208121551890"},
{"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.github.io/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":"[[📡 by feature (heuristics)]]","title":"creating a simple editor","modified":"20240319094523038","type":"text/vnd.tiddlywiki"},
{"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":"[[📡 by feature (heuristics)]]","title":"embed a 3D object (subtree)","modified":"20240223092757367"},
{"created":"20230808113746326","text":"Just get your hands on a 3D editor and follow the steps in the video:\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.github.io/xrfragment.media/gettingstarted2024.mp4\" type=\"video/mp4\"/>\n\u003C/$videojs>\n\u003C/div>\n\nHere are various ways to enhance your 3D assets/scenes with XR Fragments:\n\n| | ''scenario'' | ''how'' | ''notes'' |\n| 1 | easiest | the xrfragment.org \u003Ca href=\"/example/aframe/sandbox\" target=\"_blank\">Sandbox\u003C/a> | open 3D file (fbx/gltf) in \u003Ca href=\"https://blender.org\" target=\"_blank\">Blender\u003C/a>, add \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> |\n| 3 | easy #aframe #codepen| \u003Ca href=\"https://codepen.io/coderofsalvation/pen/yLwedvX\" target=\"_blank\">codepen\u003C/a> | press the 'fork'-button to clone the example |\n| 2 | 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| 4 | 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| 5 | 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| 6 | dev #polyglot | use the [[XR Fragment parser|https://github.com/coderofsalvation/xrfragment/tree/main/dist]] | lowlevel approach, more suitable for other scenarios |\n| 7 | dev #spec #browser | implement [[the spec|📜 XR fragments]] yourself | the spec is simple: parse URL and iterate over a scene |\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":"","title":"Getting started","modified":"20240416130943727","type":"text/vnd.tiddlywiki"},
{"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":"\u003Cb>Short explanation\u003C/b>: XR Fragments empowers designers to ship interactive 3D files without programming, simply by adding metadata.\u003Cbr>\nThis promotes ''Open Spatial Internet Features'' across ''existing'' authoring/viewing-software.\u003Cbr>\u003Cbr>\n\n[img[xrfragment.jpg]]\n\n\u003Cbr>\n\u003Cb>ChatGPT summary\u003C/b>: XR Fragments is a \u003Cb>Meta scene format\u003C/b> which leverages heuristic rules derived from any 3D scene or well-established 3D file formats, to extract meaningful features from scene hierarchies.\u003Cbr>\nThese heuristics, enable features that are both meaningful and consistent across different scene representations, allowing \u003Cb>higher interop\u003C/b> between fileformats, 3D editors, viewers and game-engines.\u003Cbr>\n\u003Cbr>\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\">0,0,0\u003C/span>\n\u003C/div>\n\u003Cbr>\n\n!! OK..so extra metadata is needed first?\n\nNO, manually entered metadata is optional, as [[#pos]] [[#rot]] [[🎞 W3C Media Fragments]] and [[🖇 auto-generated fragments]] work regardless of it.\n\u003Cbr>\u003Cb>URL addressibility\u003C/b> for objects inside your 3D file is generated ''automatically'' for you (this is very important to understand).\u003Cbr>\n\n!! How can I add more features to existing 3D assets/scenes?\n\nBy manually adding \u003Cb>metadata\u003C/b> inside 3D objects/asset/scene, which give scenes HTML-like powers:\n\n* [[href]] links to other assets/scenes + interactions (via \u003Ca href=\"#hashbus\">hashbus links\u003C/a>)\n* [[src]] the 3D version of the \u003Ca target=\"_blank\" href=\"https://www.w3.org/html/wiki/Elements/iframe\">iframe\u003C/a>\n* [[tag]] objects (to later toggle on/off, [[filters]] etc using [[href]]-values or [[predefined_view]]s)\n\n> There's two ways to add this metadata:\n\n* 3D editors: [[Blender|https://blender.org]], [[3DS Max|https://en.wikipedia.org/wiki/Autodesk_3ds_Max]], Maya etc (see \u003Ca target=\"_blank\" href=\"https://docs.blender.org/manual/en/2.79/data_system/custom_properties.html\">custom properties\u003C/a>). \n* Programmatically: frameworks like \u003Ca href=\"https://threejs.org\" target=\"_blank\">THREE.js\u003C/a> (`obj.userData`), \u003Ca href=\"https://godotengine.org\" target=\"_blank\">Godot\u003C/a>, Unity, Unreal etc.\n\n> \u003Cb>NOTE\u003C/b>: the [[AFRAME/THREE libraries|https://github.com/coderofsalvation/xrfragment/tree/main/dist]] automatically recognize and apply this metadata for you.\n\n!! Features\n\nHow do 3D viewers extract interactions from 3D models & scenes?\u003Cbr>\nBy extracting metadata from them, and controlling them using URLs:\n\n| ''feature'' | ''feature detection'' | ''URL-controllable'' |\n| [[buttons|create a button]] | any objects with [[href]] custom property | ✅ |\n| [[embed / instance local object|src]] | any objects with [[src]] custom property | ✅ |\n| [[embed / instance remote file (hypermedia: audio/video/image e.g.)|src]] | any objects with [[src]] custom property | ✅ |\n| [[navigation/teleporting|href]] | any objects with [[href]] custom property | ✅ |\n| [[referencing/selecting an object|🖇 auto-generated fragments]] | any objectname (`#myobject` e.g.) | ✅ |\n| [[referencing of objectgroups|tag]] | any object with
{"created":"20230522115709081","text":"\n\nhref metadata in 3D object allow navigation, portals & mutations\n\n| 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\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.github.io/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":"[[🧩 Object metadata]]","title":"href","modified":"20240416151041112","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.github.io/xrfragment.media/descriptive-metadata-implodes-3D-to-text.mp4\" type=\"video/mp4\"/>\n\u003C/$videojs>","tags":"[[📡 by feature (heuristics)]]","title":"Imploding 3D scene to Text","modified":"20240229160634900","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.github.io/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.github.io/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":"[[📡 by feature (heuristics)]]","title":"multiparty networking","modified":"20240206123715236"},
{"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.github.io/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.github.io/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.github.io/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":"[[📡 by feature (heuristics)]]","title"
{"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.github.io/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.github.io/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 interlinked
{"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":"[[📡 by feature (heuristics)]]","title":"positioning the user/camera","modified":"20240208123650964","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.github.io/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.github.io/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.github.io/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.github.io/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.github.io/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":"[[📡 by feature (heuristics)]]","title":"showing/hiding object(children)","modified":"20240223092242286","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.github.io/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.github.io/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":"[[🧩 Object metadata]]","title":"src","modified":"20240416151757910","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":"[[🧩 Object metadata]]","title":"tag","modified":"20240208094555851","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":"[[📡 by feature (heuristics)]]","title":"tagged objects","modified":"20240206123715238"},
{"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":"[[📡 by feature (heuristics)]]","title":"using shaders","modified":"20240319093237446","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":"[[📡 by feature (heuristics)]]","title":"uv and texture scrolling","modified":"20240328173629888"},
{"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":"A tiny specification for viewing 3D models as \u003Cb>linkable AR/VR websites\u003C/b>.\n\u003Cbr>\nAddress and Control ''anything inside a 3D model'' with \u003Ca href=\"https://www.w3.org/TR/media-frags/\">W3C Media Fragments\u003C/a> and \u003Ca href=\"https://www.rfc-editor.org/rfc/rfc6570\" target=\"_blank\">URI Templates\u003C/a>.\n\n\u003Cbr>\nSimply \u003Cb>SURF\u003C/b> a 3D file-verse and design for a \u003Cb>Spatial Open Internet\u003C/b> with the highest degree of \u003Cb>interoperability\u003C/b>:\u003Cbr>\n\u003Cbr>\u003Cbr>\n[img[xrfragment.jpg]]\n\u003Cbr>\u003Cbr>\n\n\u003Ca href=\"example/aframe/sandbox\" target=\"_blank\">» View \u003Cb>demo.glb\u003C/b>\u003C/a> or try \u003Ca href=\"https://codepen.io/coderofsalvation/pen/yLwedvX\" target=\"_blank\">this codepen\u003C/a>\n\u003Cbr>\u003Cbr>\nDiscover, share, link, navigate, animate & filter 3D content for 3D fileformats of today, yesterday, and tomorrow 💙\u003Cbr>\n\u003Cbr>\n\u003Ctable style=\"border:none\">\n \u003Ctr>\n\t \u003Ctd style=\"border:none;vertical-align:top\">\n\t\t\t\u003Ch3>⛔ no coding\u003C/h3>\n\t\t\t\u003Ch3>🎨 focus on designing\u003C/h3>\n\t\t\t\u003Ch3>🏄 surf 3D scenes in AR/VR\u003C/h3>\n\t \u003Ch3>📎 embeddable\u003C/h3>\n\t\t\t\u003Ch3>🤝 interoperable\u003C/h3>\n\t\t\u003C/td>\n\t\t\u003Ctd style=\"border:none;vertical-align:top\">\n\t\t \u003Ch3>💾 compatible with glTF FBX USDZ OBJ and more\u003C/h3>\n\t\t\t\u003Ch3>🔮 99% compatible with \u003Cb>future fileformats\u003C/b>\u003C/h3>\n \u003Ch3>🌱 friendly to opensource & corporations\u003C/h3>\n\t\t\t\u003Ch3>❤️ \u003Cb>no\u003C/b> fileformat or editor lock-in\u003C/h3>\n\t\t\t\u003Ch3>🧑🌾 #dontlearntocode #addmetadata\u003C/h3>\n\t\t\u003C/td>\n\t\u003C/tr>\n\u003C/table>\n\n\u003Cimg style=\"width:100%;max-width:900px;border-radius:15px;box-shadow:none;padding:20px\" class=\"border\" src=\"https://coderofsalvation.github.io/xrfragment.media/images/nocode.jpg\"/>\n\u003Cbr>\u003Cbr>\nIt's not an app or framework: \u003Cb>it's a spec\u003C/b> which aims to be compatible with any 3D scene(fileformat).\u003Cbr>\n\u003Cbr>\u003Cbr>\n\u003Cimg style=\"width:100%;max-width:900px;border-radius:15px;box-shadow:none;padding:20px\" class=\"border\" src=\"https://coderofsalvation.github.io/xrfragment.media/images/metadata.jpg\"/>\n\u003Cbr>\u003Cbr>\n\n\nSee [[How it works|How it works]] or \u003Ca href=\"example/aframe/sandbox\" target=\"_blank\">view a \u003Cb>demo.glb\u003C/b> scene right now\u003C/a>, or watch its 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.github.io/xrfragment.media/xrfragment.bumper2.mp4\" type=\"video/mp4\"/>\n\u003C/$videojs>\n\u003C/div>\n\n\u003Cbr>\nCheck [[How it works|How it works]], or \u003Ca href=\"example/aframe/sandbox\" target=\"_blank\">view a \u003Cb>demo.glb\u003C/b> scene right now\u003C/a>, or see the menu in the left corner for more.\n\u003Cbr>\u003Cbr>\n\u003Ciframe width=\"560\" height=\"315\" src=\"https://www.youtube.com/embed/bfxqm1q_GXw?start=1445\" title=\"YouTube video player\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" allowfullscreen>\u003C/iframe>\n","tags":"","title":"XR Fragments","modified":"20240416151920311"},
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.