Kiri:Moto Frame Message API

Hi. I’m trying to embed the slicer in my website, but I’m having some issues and I hope you could give me some light.

I embedded the slicer using an iframe, and I was wondering if it’s possible to listen to the “export” event, so I can send the generated g-code to my server for processing. Tried with window.addEventListener(“message”, …) with no results.

Thanks in advance.

using the example on Kiri:Moto Frame Message API try:

let api = kiri.frame;
api.setMode('FDM');
api.clear();
api.load('/obj/cube.stl');
api.on('loaded', () => {
    api.slice();
});
api.on('slice.done', () => {
  api.prepare();
});
api.on('prepare.done', () => {
    api.export(true);
});
api.on('export.done', gcode => {
    console.log(gcode);
})

and when you run code open the javascript console and the gcode will be there

Hi, thanks for the quick reply. I’m really lost here. But can that code only be executed here Kiri:Moto Frame Message API ?, or is there a script source I should include first?

This is what I have done so far with postMessage (sorry I didn’t include this in my question):

<div wire:init="init">
    <div class="px-4 py-20">
        <div class="max-w-screen-xl mx-auto">
            <iframe wire:ignore class="w-full h-40r" id="{{ $iframeId }}" src="https://grid.space/kiri/" frameborder="0" allowfullscreen></iframe>
        </div>
    </div>

    <script>
        document.addEventListener('livewire:load', () => {
            console.log('Livewire component loaded.');

            @this.on('set-iframe', (iframeId, fileUrl) => {
                console.log('set-iframe event executed.', 'iframeId: ' + iframeId, 'fileUrl: ' + fileUrl);

                const kiriFrame = document.getElementById(iframeId);
        
                kiriFrame.onload = () => {
                    console.log('kiriFrame onload executed.');

                    kiriFrame.contentWindow.postMessage({ command: 'setFrame', id_obj: iframeId }, 'https://grid.space');
                    kiriFrame.contentWindow.postMessage({ command: 'clear' }, 'https://grid.space');
                    kiriFrame.contentWindow.postMessage({ command: 'load', url: fileUrl }, 'https://grid.space');
                    kiriFrame.contentWindow.postMessage({ command: 'setMode', mode: 'FDM' }, 'https://grid.space');
                    
                    window.addEventListener('message', function (event) {
                        console.log('Message received.');

                        if (event.origin !== 'https://grid.space') return;

                        console.log(event);
                    }, false);
                }
            });
        });
    </script>
</div>

It’s a Laravel + Livewire website.

I’m trying to communicate with the iframe using postMessage, but it’s not working. The onload function is being called, though.

Note:

I was hoping to receive a message in the window event listener when the user clicks “Export” inside the iframe.

if you inspect the example page, you’ll notice it loads this:

Screenshot 2024-11-05 at 9.33.27 AM

the original code for this is here so you can see what’s happening with the api wrapper.

I had not anticipated sending the gcode as an event when the user initiates an export, but this is not hard to do.

Hi stewart. Thank you for your patience. I included the script, and copied my code to a plain html file to see if it was my Laravel implementation messing with it, but it’s still not working. Here’s my attempt to communicate with the iframe:

<div>
        <div class="px-4 py-20">
            <div class="max-w-screen-xl mx-auto">
                <iframe class="w-full h-40r" width="800" height="600" id="kiri-frame" src="https://grid.space/kiri/" frameborder="0" allowfullscreen></iframe>
            </div>
        </div>
        
        <script src="https://grid.space/code/frame.js"></script>
        <script>
            const kiriFrame = document.getElementById('kiri-frame');
            let api = kiri.frame;

            kiriFrame.onload = function () {
                api.setFrame('kiri-frame');
                api.clear();
            }
        </script>
</div>

I also tried moving the code outside from the onload function, and checked the console for errors, but there’s nothing.

kiri.frame is defined, I checked with console.log.

I’ll try to reproduce and let you know what I find

I have the same issue using firefox (chrome seems is worse)

After lot of trying different things, the following is working best for me, for loading a file using the api does nothing in the console. Last log:
“Sending data to Kiri:Moto…”

Also onmessage is never fired…

Code:
jQuery(document).ready(function ($) {

const iframe = document.getElementById('kiri-moto-frame');
const iframeOrigin = 'https://grid.space'; 

// Initialize the Kiri:Moto API
kiri.frame.setFrame(iframe, iframeOrigin);

// Handle messages from the iframe
kiri.frame.onmessage = (data, rawMsg) => {
    console.log('Message received from iframe:', data);

    if (data.event === 'ready') {
        console.log('Kiri:Moto is ready.');

        // Example commands
        kiri.frame.setMode('FDM'); // Set slicing mode
        kiri.frame.clear();       // Clear the workspace
    }
};

// Add your additional interactions here
iframe.onload = function () {
    console.log('Iframe loaded.');

    // Confirm initialization by sending a simple command
    kiri.frame.send({ ping: true });

    if (typeof kiri === 'undefined' || !kiri.frame) {
        console.error('Kiri:Moto API is not available. Please check the iframe source or initialization timing.');
        return;
    } else {
        console.log('Kiri:Moto API loaded:', kiri.frame);
    }

    const api = kiri.frame;
    api.setMode('FDM');
    api.clear();

    // Handle the 'loaded' event
    api.on('loaded', () => {
        console.log('File loaded into Kiri:Moto.');
        // api.slice(); // Start slicing the loaded object
    });

    // Handle the 'slice.done' event
    api.on('slice.done', () => {
        console.log('Slicing complete.');
        api.prepare(); // Start preparing sliced paths
    });

    // Handle the 'prepare.done' event
    api.on('prepare.done', () => {
        console.log('Preparation complete.');
        api.export(); // Export G-code
    });

    // Optional: Handle export completion
    api.on('export.done', (data) => {
        console.log('Export complete.');
        console.log('Exported Data:', data);
        // You can download the exported file or handle it as needed
    });
};

// Handle file upload
$('#kubify-file-upload').on('change', function (event) {
    console.log('file change event');
    const file = event.target.files[0];
    if (!file) return;

    const reader = new FileReader();

    reader.onload = function (e) {
        const data = e.target.result;
        console.log('reader onload event');
        console.log('File content (first 100 bytes):', new Uint8Array(data).slice(0, 100));

        // Parse and load the uploaded file into Kiri:Moto
        const api = kiri.frame;
        console.log('Sending data to Kiri:Moto...');
        api.parse(data);
        
    };

    // Read the file as an ArrayBuffer
    reader.readAsArrayBuffer(file);
});

it looks like CORS headers required to allow shared arrays to work in Onshape is interfering with cross frame messaging. I’m not entirely sure how to resolve this at the moment. it’s complicated.