This commit is contained in:
Leon van Kammen 2025-11-10 15:05:01 +01:00
parent d725c9c73a
commit 0ace214070
7 changed files with 534 additions and 367 deletions

View file

@ -1,5 +0,0 @@
#!/bin/sh
dir="$(dirname $1)"
cd "$dir"
echo "[package_experience.sh] zipping experience.zip"
zip -D ".xrforge/experience.zip * | tee -a .xrforge/log.txt

View file

View file

@ -19,6 +19,8 @@ begin
# Read and parse the JSON file # Read and parse the JSON file
data = JSON.parse( File.read( "datapackage.json" ) ) data = JSON.parse( File.read( "datapackage.json" ) )
if data['keywords'].empty? || data['keywords'].include?('janusxr')
logfile = File.join( File.dirname(filename), ".xrforge/log.txt" ) logfile = File.join( File.dirname(filename), ".xrforge/log.txt" )
XRForge.log("✅ starting build janusXR XR scene", logfile) XRForge.log("✅ starting build janusXR XR scene", logfile)
@ -61,15 +63,7 @@ begin
# Define the HTML content using a multi-line string (heredoc) # Define the HTML content using a multi-line string (heredoc)
# Ruby's heredoc allows for variable interpolation (using #{}) # Ruby's heredoc allows for variable interpolation (using #{})
jml = <<~HTML jml = <<~JML
<!DOCTYPE html>
<html>
<head>
<title>janusxr room</title>
</head>
<body>
<script src="https://web.janusvr.com/janusweb.js"></script>
<janus-viewer>
<FireBoxRoom> <FireBoxRoom>
<Assets> <Assets>
<assetobject id="experience" src="#{federate_drive_host}/#{model_file.gsub("#","%23")}"/> <assetobject id="experience" src="#{federate_drive_host}/#{model_file.gsub("#","%23")}"/>
@ -78,19 +72,37 @@ begin
<object pos="0 0 0" collision_id="experience" id="experience" /> <object pos="0 0 0" collision_id="experience" id="experience" />
</Room> </Room>
</FireBoxRoom> </FireBoxRoom>
JML
html = <<~HTML
<!DOCTYPE html>
<html>
<head>
<title>janusxr room</title>
</head>
<body>
<script src="https://web.janusvr.com/janusweb.js"></script>
<janus-viewer>
#{jml}
</janus-viewer> </janus-viewer>
</body> </body>
</html> </html>
HTML HTML
# Write the content to the specified file File.write('.xrforge/janusxr.html', html)
# File.write is the concise equivalent of 'echo "$jml" > filename' File.write('.xrforge/scene.jml', jml)
File.write('.xrforge/janusxr.html', jml)
XRForge.log("✅ written janusxr.html", logfile)
XRForge.log("✅ generated scene.jml", logfile)
XRForge.log("✅ generated janusxr.html", logfile)
XRForge.log(" ", logfile) XRForge.log(" ", logfile)
# tag it!
if ! data['keywords'].include?('janusxr')
data['keywords'].push('janusxr')
File.write(file_path, JSON.pretty_generate(data) )
end
end
rescue Errno::ENOENT rescue Errno::ENOENT
puts "File #{filename} not found" puts "File #{filename} not found"
rescue JSON::ParserError rescue JSON::ParserError

View file

@ -0,0 +1,87 @@
#!/usr/bin/env ruby
require 'json'
require_relative './../../xrforge.rb'
# Check if a filename is provided
if ARGV.length != 1
puts "Usage: #{$0} <path/to/experience/somefile.xxx>"
exit 1
end
filename = ARGV[0]
begin
# Change the directory
dir = File.dirname(filename)
Dir.chdir( File.dirname(filename) )
# Read and parse the JSON file
data = JSON.parse( File.read( "datapackage.json" ) )
if data['keywords'].empty? || data['keywords'].include?('mml')
logfile = File.join( File.dirname(filename), ".xrforge/log.txt" )
XRForge.log("✅ starting build mml XR scene", logfile)
# Extract the desired field (assuming the field is named 'model_file')
thumb_file = data['image']
XRForge.log("✅ thumbnail sidecar-file '#{thumb_file}' detected", logfile)
# Get the base name of the thumbnail file without its extension
base_name = File.basename(thumb_file, File.extname(thumb_file))
model_file = nil # Initialize model_file to nil
# Loop over the list of extensions
XRForge::MODEL_EXT.each do |ext|
# Construct the filename with the current extension
filename = "#{base_name}#{ext}"
# Check if the file exists
if File.exist?(filename)
XRForge.log("✅ 3D file '#{filename}' detected", logfile)
model_file = "#{dir.gsub("/mnt/","")}/#{filename}" # Store the found filename
break # Stop the loop once a file is found
else
# Log a message for the file that was not found, but don't stop
XRForge.log("⚠️ 3D file '#{filename}' not detected", logfile)
end
end
# Check if a model file was found after the loop
if model_file
XRForge.log("✅ Final model file: '#{model_file}'", logfile)
else
XRForge.log("❌ No suitable 3D file found for XR Fragments- / MML-compatible experience", logfile)
end
# Get the value of the environment variable FEDERATE_DRIVE_HOST
federate_drive_host = ENV['FEDERATE_DRIVE_HOST']
# https://viewer.mml.io/main/v1/?url=https%3A%2F%2Ffoo.org%2Fbar.mml
mml = <<~MML
<m-model src="#{federate_drive_host}/#{model_file.gsub("#","%23")}" anim-loop="true" anim-enabled="true"></m-model>
MML
File.write('.xrforge/scene.mml', mml)
XRForge.log("✅ generated scene.mml", logfile)
XRForge.log(" ", logfile)
# tag it!
if ! data['keywords'].include?('mml')
data['keywords'].push('mml')
File.write(file_path, JSON.pretty_generate(data) )
end
end
rescue Errno::ENOENT
puts "File #{filename} not found"
rescue JSON::ParserError
puts "Error parsing JSON from #{filename}"
rescue => e
puts "An error occurred: #{e.message}"
end

View file

@ -0,0 +1,32 @@
Features can be toggled via tags:<br>
<br>
<table class="table">
<tr>
<td>
<a class="badge rounded-pill bg-secondary tag">menu</a>
</td>
<td>
This will generate a navigator-menu <b>into</b> your main 3D file.<br>
The links can be edited <%= link_to "here", edit_model_path(@model) %>
</td>
</tr>
<tr>
<td>
<a class="badge rounded-pill bg-secondary tag">janusxr</a>
</td>
<td>
This generates an JanusXR address.<br>
<a href="https://janusxr.org/" target="_blank">JanusXR</a> is an Open Immersive Web-layer since 2015, which allows existing webpages to become spatial.<br>
It is Free and Opensource, and allows you to meet others in this experience (avatars, chat and voice etc).<br>
</td>
</tr>
<tr>
<td>
<a class="badge rounded-pill bg-secondary tag">mml</a>
</td>
<td>
This generates an MML address.<br>
Metaverse Markup Language (<a href="https://mml.io" target="_blank">MML</a>) is an open markup language used to define experiences.
</td>
</tr>
</table>

View file

@ -81,12 +81,18 @@
</tr> </tr>
<% end %> <% end %>
<% if ENV['FEDERATE_DRIVE_HOST'].present? %> <% if ENV['FEDERATE_DRIVE_HOST'].present? %>
<% if @model.tags.where(name: "janusxr" ).any? %>
<tr> <tr>
<td> <td>
<i class="bi bi-people" role="img"></i> <i class="bi bi-eye-fill" role="img"></i>
</td> </td>
<td> <td>
<%= link_to "JanusXR Metaverse", ENV['FEDERATE_DRIVE_HOST']+"/"+@model.library.name+"/"+@model.path.gsub("#","%23")+"/.xrforge/janusxr.html" %> <%
fediURL = ENV['FEDERATE_DRIVE_HOST']+"/"+@model.library.name+"/"+@model.path.gsub("#","%23")+"/.xrforge/janusxr.html"
%>
<%= link_to "JanusXR address", fediURL, target:"_blank" %>
<a href="" target="_blank"><i class="bi bi-link-45deg"></i></a>
<label for="toggle_janusxr"><i class="bi bi-info-circle"></i></label> <label for="toggle_janusxr"><i class="bi bi-info-circle"></i></label>
<div class="toggle-box"> <div class="toggle-box">
<input type="checkbox" id="toggle_janusxr" hidden> <input type="checkbox" id="toggle_janusxr" hidden>
@ -94,19 +100,53 @@
<i class="bi bi-arrow-90deg-up"></i>&nbsp; <i class="bi bi-arrow-90deg-up"></i>&nbsp;
<small> <small>
This is the JanusXR address.<br> This is the JanusXR address.<br>
<a href="https://janusxr.org/" target="_blank">JanusXR</a> is an established Metaverse since 2015.<br> <a href="https://janusxr.org/" target="_blank">JanusXR</a> is an Open Immersive Web-layer since 2015, which allows existing webpages to become spatial.<br>
It is Free and Opensource, and allows you to meet others in this experience (avatars, chat and voice etc). It is Free and Opensource, and allows you to meet others in this experience (avatars, chat and voice etc).<br>
</small> </small>
</div> </div>
</div> </div>
</td> </td>
</tr> </tr>
<%
# lets generate a JanusXR spatial layer for the current scene
jmlfile = @model.library.path+"/"+@model.path+"/.xrforge/scene.jml"
jml = ""
if File.exist?(jmlfile)
jml = File.read(jmlfile)
end
%>
<!-- JML (https://janusxr.org) spatial markup
<%== jml %>
-->
<% end %>
<% if @model.tags.where(name: "mml" ).any? %>
<tr> <tr>
<td> <td>
<i class="bi bi-file-zip" role="img"></i> <i class="bi bi-eye-fill" role="img"></i>
</td>
<td>
<%= link_to "MML address", "https://viewer.mml.io/main/v1/?url="+URI.encode_www_form_component(ENV['FEDERATE_DRIVE_HOST']+"/"+@model.library.name+"/"+@model.path.gsub("#","%23")+"/.xrforge/scene.mml"), target:"_blank" %>
<a href="<%= ENV['FEDERATE_DRIVE_HOST']+"/"+@model.library.name+"/"+@model.path.gsub("#","%23")+"/.xrforge/scene.mml" %>" target="_blank"><i class="bi bi-link-45deg"></i></a>
<label for="toggle_mml"><i class="bi bi-info-circle"></i></label>
<div class="toggle-box">
<input type="checkbox" id="toggle_mml" hidden>
<div class="hidden-tooltip">
<i class="bi bi-arrow-90deg-up"></i>&nbsp;
<small>
This is the MML address.<br>
Metaverse Markup Language (<a href="https://mml.io" target="_blank">MML</a>) is an open markup language used to define experiences.
</small>
</div>
</div>
</td> </td>
<td><%= link_to "zip archive", "/"+@model.library.name+"/"+@model.path.gsub("#","%23")+"/.xrforge/experience.zip" %></td>
</tr> </tr>
<% end %>
<tr> <tr>
<td> <td>
<i class="bi bi-journal-check" role="img"></i> <i class="bi bi-journal-check" role="img"></i>
@ -121,19 +161,7 @@
<small> <small>
This is the build log of XR Forge.<br> This is the build log of XR Forge.<br>
When you add files, they are processed, validated (for <a href="https://xrfragment.org" target="_blank">XR Fragment</a> compliance).<br> When you add files, they are processed, validated (for <a href="https://xrfragment.org" target="_blank">XR Fragment</a> compliance).<br>
But also features can be toggled via tags:<br> <% render 'models/tags_info' %>
<br>
<table class="table">
<tr>
<td>
<a class="badge rounded-pill bg-secondary tag">menu</a>
</td>
<td>
This will generate a navigator-menu <b>into</b> your main 3D file.<br>
The links can be edited <%= link_to "here", edit_model_path(@model) %>
</td>
</tr>
</table>
</small> </small>
</div> </div>
</div> </div>
@ -161,6 +189,7 @@
</td> </td>
</tr> </tr>
<% end %> <% end %>
<% if @model.collection %> <% if @model.collection %>
<tr> <tr>
<td><%= icon "collection", Collection.model_name.human(count: 100) %></td> <td><%= icon "collection", Collection.model_name.human(count: 100) %></td>
@ -202,7 +231,18 @@
</tr> </tr>
<tr> <tr>
<td><%= icon "tag", t(".tags") %></td> <td><%= icon "tag", t(".tags") %></td>
<td><%= render "tag_list", tags: @model.tags.order(taggings_count: :desc, name: :asc), filter: @filter %></td> <td><%= render "tag_list", tags: @model.tags.order(taggings_count: :desc, name: :asc), filter: @filter %>
<label for="toggle_tags"><i class="bi bi-info-circle"></i></label>
<div class="toggle-box">
<input type="checkbox" id="toggle_tags" hidden>
<div class="hidden-tooltip" style="max-height:400px">
<i class="bi bi-arrow-90deg-up"></i>&nbsp;
<small>
<% render 'models/tags_info' %>
</small>
</div>
</div>
</td>
</tr> </tr>
<% if SiteSettings.social_enabled? %> <% if SiteSettings.social_enabled? %>
<tr> <tr>

View file

@ -76,6 +76,7 @@ rec
pkgs.pkgsStatic.inotify-tools # inotifywait e.g. pkgs.pkgsStatic.inotify-tools # inotifywait e.g.
pkgs.pkgsStatic.zip # inotifywait e.g. pkgs.pkgsStatic.zip # inotifywait e.g.
pkgs.pkgsStatic.ts # job management pkgs.pkgsStatic.ts # job management
pkgs.janus-gateway # webrtc server
myAssimp # cli 3D editing/conversion myAssimp # cli 3D editing/conversion
./.. ./..
]; ];