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 X3Dthis 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

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.4. General flow:

sketchup-cge-workflow.png

1.1.5. Result

1.2. dtmf.ca org-publish architecture   org_mode plantuml org_publish spacemacs emacs

architecture.png
@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