Loading a 3dm model and sending it to grasshopper using rhino3dm.js

I’ve gone through all the documentation I’ve found (js docs and api docs), but still can’t manage to figure out how to do it. I also haven’t found anything relevant on this forum.

To expand a bit on the title, I have a grasshopper file test.gh, and a 3dm model model.3dm. I’m trying to send the model as input to the grasshopper file.

What I’ve done so far:

const rhino = await rhino3dm()
const ghScript = await loadFileAsUint8Array('./path/to/test.gh')
const modelArray = await loadFileAsUint8Array('./path/to/model.3dm')
const file3dm = rhino.File3dm.fromByteArray(modelArray)

// here I'm lost. Not sure how to process `file3dm` to get the geometry

const trees = []
const inputModel = new RhinoCompute.Grasshopper.DataTree('RH_IN:MODEL')
inputModel.append([0], ???)

const result = await RhinoCompute.Grasshopper.evaluateDefinition(

The closest I’ve gotten is this code sample by @fraguada. I guess what I’m missing is how to get the whole geometry, instead of each object’s geometry one by one.

Any help will be highly appreciated. Thanks in advance!

What does your GH definition look like? I’ve sent serialized 3DMs then deserialize them in the gh definition.

Thanks for the super fast response!

My bad, I forgot to add the grasshopper script. Here it is (EDIT: I wanted to add it to the original post as well, but It seems I can’t edit the original post anymore).

When you mention serializing/deserializing, I have some questions:

  1. What should I serialize to send over, the File3dm item, the File3dmObjectTable, or something else?

  2. Is serialize a function that is available from the API, or is this just the ByteArray representation of the file?

  3. On the grasshopper definition, what kind of node should I use to deserialize the input?

Thank you again!

@fraguada I’ve tried a few different GH nodes to deserialize the file, but all of them seem to need a file path. Can you share an example code, even if just minimal, where I can see what part of the file I have to serialize on the JS side, and how to deserialize it on the GH side?

Thanks in advance.

Hello, I’m still blocked with this one.

The lack of documentation both on the JS and Python libraries makes this task way harder than it should be. Methods present in the docs but inexistent on the objects and the other way around. And the description in the docs is most of the time “…” or “[todo] add documentation”.

I’ve tried many things, like using the .encode() method in the JS side, but surprisingly there’s no .Decode() method on the python side, despite the documentation stating so.

I’ve also tried sending a string with the byte array created in JS, but the most I get on python is “expected Array[Byte] but got bytearray”.

When creating the bytearray in JS I’ve tried a couple of different ways. One with node APIs, and the other one using model3dm.toByteArray(). Both give a byte array representation, but they’re slightly different.

I’m completely in the dark here. Any help would be appreciated.

I will try to come up with an example for this in the next few days.

Thanks Luis :pray: I really appreciate it.

I’ve just pushed a sample which takes a 3dm file as input for a gh definition: rhino-developer-samples/compute/js/SampleGHDocInput at 7 · mcneel/rhino-developer-samples · GitHub

In js, we fetch the file and encode it as a base 64 string:

// in script.js

const file3dm = await fetch( data.fileName )
const buffer3dm = await file3dm.arrayBuffer()
const arr = new Uint8Array( buffer3dm )
const b64ba = base64ByteArray( arr )
data.inputs.encodedFile = b64ba

Here is the GH definition:

When we get the encoded file data, we actually need to save it to the local disk. That is what the C# component does:

// in SampleGHDocInput.gh

var tmp = Path.GetTempFileName();
tmp = Path.ChangeExtension(tmp, "3dm");
var b64 = System.Convert.FromBase64String( data );
File.WriteAllBytes(tmp, b64);
A = tmp;

Then you have your file path. I use an Import3dm component, but you could use RhinoDoc:

var doc = RhinoDoc.OpenHeadless(tmpFileName);

Hope this helps.