dtmf.ca
1. log
1.1. X3DOM iframe test x3d sketchup2018
1.1.1. Context
VRML has been an ISO standard since 1997, originally defined as early as 1994.
It has since been superseded by a new standard called X3D.1https://www.web3d.org
Why even bring up VRML at all, if it's out-of-date?
For one simple reason:
Sketchup 2018 is able to export VRML by default, exporting the scene to a .wrl file.
And with a well-structured .wrl/VRML file, it is possible to convert the geometry to X3D… this is where things begin to get interesting.
Did you know that X3D can be extended by a library called X3DOM? Which allows for native 3d model embedding in both commercial and non-commercial websites2"Free for non-commercial and commercial purposes.".
1.1.2. Materials Used
-
Sketchup 2018 - Ruby export script
-
castle-engine(forVRML>X3D) -
X3DOM
1.1.3. .RBZ
require 'sketchup.rb'
#=============================================================================
# This module encapsulates the exporter functionality to prevent conflicts with
# other extensions.
#
module CGE_X3D_Exporter
#===========================================================================
# The core logic for the export and conversion process.
#
def self.export_to_x3d
# --- 1. Get the active model and define file paths ---
model = Sketchup.active_model
model_path = model.path
# The model must be saved first to establish a base path for exports.
if model_path.empty?
UI.messagebox('Please save your model before exporting to X3D.')
return
end
# Check for SketchUp Pro, as VRML export is a Pro-only feature.
unless Sketchup.is_pro?
UI.messagebox('VRML export is a SketchUp Pro feature. This extension cannot proceed.')
return
end
# Define paths based on the saved model's location and name.
dir = File.dirname(model_path)
basename = File.basename(model_path, '.skp')
wrl_path = File.join(dir, "#{basename}.wrl")
x3d_path = File.join(dir, "#{basename}.x3d")
# --- 2. Define the path to the conversion utility ---
# This is the hardcoded path to your Castle Game Engine executable.
# If you move the engine, you must update this path.
converter_path = "/Applications/castle-engine/bin/castle-model-viewer.app/Contents/MacOS/castle-model-viewer"
# Verify that the converter executable actually exists at the specified path.
unless File.exist?(converter_path)
UI.messagebox("Conversion tool not found at:\n#{converter_path}\n\nPlease check your Castle Game Engine installation path.")
return
end
# --- 3. Export the model to VRML (.wrl) ---
# SketchUp's export method infers the format from the file extension.
# This will create the .wrl file and a folder with textures if they exist.
begin
puts "Exporting to VRML: #{wrl_path}"
export_status = model.export(wrl_path)
unless export_status
UI.messagebox("Failed to export model to VRML file.")
return
end
rescue => e
UI.messagebox("An error occurred during VRML export:\n#{e.message}")
return
end
# --- 4. Construct and execute the conversion command ---
# The command is built using the paths defined above.
# "castle-model-viewer ... --write --write-encoding xml > output.x3d"
# Using %Q{} allows for clean handling of paths that may contain spaces.
command = %Q{ "#{converter_path}" "#{wrl_path}" --write --write-encoding xml > "#{x3d_path}" }
puts "Executing conversion command:"
puts command
# Execute the command in the system's shell.
# The `system` command returns `true` on success, `false` on failure,
# or `nil` if the command could not be executed.
conversion_status = system(command)
# --- 5. Provide feedback to the user ---
if conversion_status
UI.messagebox("Successfully exported and converted to:\n#{x3d_path}")
# Optional: Open the containing folder after successful export.
# system("open \"#{dir}\"")
else
UI.messagebox("The conversion to X3D failed. Please check the Ruby Console for more details.")
puts "Conversion command failed. This could be an issue with Castle Game Engine or the exported VRML file."
end
# The intermediate .wrl file is kept for debugging purposes.
end # def self.export_to_x3d
#===========================================================================
# This block runs once when the script is loaded. It creates the menu item.
#
unless file_loaded?(__FILE__)
# Get the "File" menu. You could also use "Extensions".
menu = UI.menu('File')
# Add a separator and our menu item.
menu.add_separator
menu.add_item('Export to X3D (via CGE)') {
self.export_to_x3d
}
file_loaded(__FILE__)
end
end # module CGE_X3D_Exporter
1.1.5. Result
1.2. dtmf.ca org-publish architecture org_mode plantuml org_publish spacemacs emacs
@startuml !theme spacelab skinparam backgroundColor #FFFFFE ' Define actors and components actor "Author (dtmf)" as Author actor "Visitor (you)" as Visitor package "Emacs Environment" { ' The previous multi-line component syntax was causing a parse error. ' This version uses a single quoted string with newlines, which is more robust. component "==.spacemacs\n--\norg-publish-project-alist\ndtfm/new-log-post()" as SpacemacsConfig Author -- SpacemacsConfig } package "Source Directory" { node "~/org/dtmf.ca-src-tufte/" as SrcDir { artifact "<b>setup.org</b>\n<size:10>#+OPTIONS: publish:nil" as Setup artifact "<b>header.org</b>\n<size:10>#+OPTIONS: publish:nil" as Header artifact "<b>footer.org</b>\n<size:10>#+OPTIONS: publish:nil" as Footer artifact "<b>index.org</b>" as Index artifact "<b>log.org</b>" as Log folder "logs/" { artifact "<b>post-1.org</b>" as Post1 artifact "<b>post-2.org</b>" as Post2 } folder "assets/" { artifact "<b>model.x3d</b>" as Model artifact "<b>x3d-viewer.html</b>" as Viewer } artifact "<b>Static Files</b>\n<size:10>.css, .js" as Static } } package "Publishing & Deployment" { queue "<b>org-publish</b>\n<size:10>M-x org-publish" as OrgPublish node "~/dtmf.ca/" as PubDir node "Local Test Server" as LocalServer cloud "Live Web Server" as LiveServer } ' Define relationships SpacemacsConfig -> OrgPublish : "configures" OrgPublish -> SrcDir : "reads from" ' Source file relationships Index ..> Setup : "<<include>>" Index ..> Header : "<<include>>" Index ..> Footer : "<<include>>" Log ..> Setup Log ..> Header Log ..> Footer Post1 ..> Setup Post2 ..> Setup ' Log.org now transcludes the individual posts instead of linking to them. Log ..> Post1 : "<<transclude>>" Log ..> Post2 : "<<transclude>>" ' The custom function now just creates the post file. SpacemacsConfig ..> Post2 : "dtmf/new-log-post()\ncreates" ' Publishing flow OrgPublish -> PubDir : "writes to" PubDir -> LocalServer : "serves" PubDir -> LiveServer : "is deployed to" ' Visitor interaction LocalServer -- Author : "for testing" LiveServer -- Visitor : "serves site to" Visitor -> Index : "views" Visitor -> Post1 Visitor -> Viewer Viewer ..> Model : "<<loads>>" @enduml
1.3. domains in the membrane domains
| Domain Name | Expiry |
| moneyshirt.shop | Apr 26, 2026 |
| superordinate.space | Apr 24, 2026 |
| ph-dj.net | Apr 21, 2026 |
| escarpment.media | Apr 20, 2026 |
| concerted.systems | Apr 18, 2026 |
| dreammachine.icu | Apr 18, 2026 |
| touchdesigner.icu | Apr 18, 2026 |
| goldenhorseshoe.live | Apr 18, 2026 |
| selfreflectron.me | Apr 18, 2026 |
| didact.digital | Apr 18, 2026 |
| niagara.lol | Dec 21, 2025 |
| dingushead.com | Dec 21, 2025 |
| concrete.foundation | Dec 21, 2025 |
