Project code

The open text format for truss models. The Project code panel, the format, and every field.

Last updated 2026-10-11

Open format · MIT

Project code is your truss written as text (JSON). It's what you get when you copy on the canvas, and what the Project code panel shows. This guide explains the panel and the format. For what to do with it, see:

The Project code panel

Open Project code from the panel on the right. It shows your whole model as text, and follows your changes on the canvas.

  • Edit right in the text: change a number, add a line, then press Apply — the canvas updates. If something's wrong, Apply stays disabled and the problem is shown under the text, e.g. "member 3 references node 9, which doesn't exist".
  • Apply replaces the whole truss with what's in the text. Anything not in the text is removed from the canvas. This is the difference from pasting on the canvas, which adds.
  • Copy minified (fewer AI tokens), in the ⋮ menu: copies the code with no spaces or line breaks. Useful for a big model, so the AI has less text to read.

Schema reference

The document is one JSON object with these keys: units, nodes, members, supports, nodalLoads, materials, sections, and an optional dimensions. Nothing else is allowed — Truzme keeps more than this behind the scenes (view settings, background images, uploaded assets), but none of that appears here.

A document may also start with an optional $schema key: the link to this format, so the text says what it is wherever it's pasted. Code copied from the canvas starts with it. Truzme ignores it when you press Apply, and drops it when you paste into the Project code panel.

Writing AI prompts with your own instructions, for a course or a research study? Link the format itself. Unlike the format guide, it has no instructions for the AI — only a description of every field below:

Referencing entities — always by id

Every entity has a small integer id. Anything that points to another entity — a member's endpoints, a support's or load's node, the section and material assigned to a member — does so with that id. Ids only need to be unique within their own array, so a node id: 1 and a section id: 1 don't collide.

units

Every category the document uses, all required:

  • length — node coordinates: m, cm, mm, ft, in
  • sectionLength — section dimensions: mm, cm, in
  • force — loads: kN, N, kg, kip, lbf
  • materialStrength — modulus and strength: MPa, N/mm², GPa, ksi, psi
  • area — section area and, indirectly, its moment of inertia: mm², cm², in², ft²
  • density — material density: kg/m³, lb/ft³

This block is authoritative on import: Apply reads the units declared here — not whatever Truzme is currently displaying — and converts every number accordingly. length and sectionLength are different categories on purpose: a node coordinate and a section dimension are rarely the same scale.

nodes

{ id, x, y } — x/y are coordinates in units.length. x increases to the right, y increases upward — the standard math convention, not screen coordinates. A node above and to the right of the origin has positive x and positive y.

members

{ id, from, to, section, material } — from/to are node ids for the member's two ends; section/material are ids into the sections/materials arrays.

supports

{ id, node, x, y, angle } — node is the restrained node's id; x/y are booleans, true meaning translation is fixed in that direction.

angle is optional: it turns the support, in degrees, counterclockwise, and its x and y directions turn with it. A roller with "y": true and "angle": 30 stands on a surface tilted 30°, so it holds the node only across that surface. On a pin it only changes how the support is drawn. Leave it out for 0.

nodalLoads

{ id, node, x, y, mode } — node is the id of the loaded node; x/y are signed force components in units.force. mode is optional and only changes how the arrow is drawn, not the analysis. Leave it out for "push", where the arrow points at the node. Use "pull" for a load hanging from the truss, e.g. on a bottom chord node: the arrow then starts at the node and points away, so it isn't drawn across the members.

materials

{ id, name, EModulus, fMax, density, color } — modulus and max stress, both in units.materialStrength; density in units.density. color is optional (a hex string, e.g. "#1D4ED8") — leave it out and an existing material keeps its current color, a new one gets a default. Include it to set or change a material's color.

materials and sections can't be empty arrays — every model needs at least one of each, even one with no members yet. Apply rejects a paste that has none of either.

sections — a union of five shapes

Every section has id, name, sectionType (which decides which other fields are required), and an optional color — same rule as a material's color: leave it out to keep whatever a matching id already has, include it to set one.

  • solid_round — d (diameter)
  • pipe — outerDiameter, thickness
  • rectangle — w, h
  • hollow_rectangle — w, h, thickness
  • custom — area, Imin (nothing to derive these from, so they're given directly)

All dimensions are in units.sectionLength; area and Imin on a custom section are in units.area and its matching inertia unit (mm² area → mm⁴ inertia, in² → in⁴, and so on).

For the four standard shapes, Truzme computes area and Imin on import from the input dimensions — you only ever provide those dimensions, never the derived values, so there's one source of truth. The exported text doesn't show computed area or inertia for standard shapes; check the Utilization panel in Truzme for those.

dimensions — optional

The measurement lines you draw with the Dimension tool (not to be confused with a section's own w/h/d dimensions above). Leaving the key out is the same as an empty list: no dimension lines.

{ id, from, to, kind, anchor } — from/to are node ids, same convention as a member's from/to. kind is "horizontal", "vertical", or "angle". anchor is a point ({ x, y }, in units.length) the line is drawn through — it's the point you click when placing a dimension with the tool.

When you ask an AI for a design with a specific span or height, it's worth asking it to add a dimension line confirming that measurement — the format guide tells it to do this on its own whenever a prompt states one.

Excluded on purpose

Your display preferences (not to be confused with the units block above, which is part of the public document), background images, uploaded asset files, and Truzme's internal bookkeeping don't appear here — none of it describes the structure, so none of it needs to go through an AI.

Worked example

A three-node, three-member truss: a pin support and a roller, one downward load at the apex, a custom color on the material and section, and a dimension line confirming the 4 m base span.

{
    "units": {
        "length": "m",
        "sectionLength": "mm",
        "force": "kN",
        "materialStrength": "MPa",
        "area": "mm²",
        "density": "kg/m³"
    },
    "nodes": [
        { "id": 1, "x": 0, "y": 0 },
        { "id": 2, "x": 4, "y": 0 },
        { "id": 3, "x": 2, "y": 3 }
    ],
    "members": [
        { "id": 1, "from": 1, "to": 2, "section": 1, "material": 1 },
        { "id": 2, "from": 1, "to": 3, "section": 1, "material": 1 },
        { "id": 3, "from": 2, "to": 3, "section": 1, "material": 1 }
    ],
    "supports": [
        { "id": 1, "node": 1, "x": true, "y": true },
        { "id": 2, "node": 2, "x": false, "y": true }
    ],
    "nodalLoads": [{ "id": 1, "node": 3, "x": 0, "y": -10 }],
    "materials": [{ "id": 1, "name": "Steel", "EModulus": 210000, "fMax": 235, "density": 7850, "color": "#1D4ED8" }],
    "sections": [
        {
            "id": 1,
            "name": "40×40×3",
            "sectionType": "hollow_rectangle",
            "w": 40,
            "h": 40,
            "thickness": 3,
            "color": "#9D57DE"
        }
    ],
    "dimensions": [{ "id": 1, "from": 1, "to": 2, "kind": "horizontal", "anchor": { "x": 2, "y": -0.75 } }]
}

color and dimensions are both optional — see the schema reference above if you want to leave them out.

Ask an AI to move node 3, add a fourth node, or swap the section on member 2 — it only has to keep ids consistent and never invent an id that isn't defined.

Behavior notes

Apply matches ids. When you press Apply in the panel, an id that already existed in your model keeps the same entity across the round-trip — its place in undo history, its selection state, and its color unless the pasted entity sets a new one. Only ids you didn't have before get created as new entities, and ids that are missing from the pasted code are removed. This is why an AI editing your project code should send back the whole model, keep existing ids stable, and only introduce new ones for things it's actually adding.

Units convert automatically. The numbers you paste are read in whatever units the pasted units block declares, then converted to Truzme's internal representation — you don't need to match your current display units before pasting.

Where it came from

Project code was developed in collaboration with a research team at Penn State University, USA, who needed a text format an AI could read and write — so a truss design could be generated and revised in a chat and then loaded straight back into Truzme.

See Who uses Truzme for more about their work with Truzme.

Thanks to Ali Tarlani Beris for starting the conversation.

Use it in your own tool

Free to implement in any tool. Please name it "Truzme Project code" and link to this page. How to do it: Connect your app. Details: License.

Text and figures: CC BY-NC-ND 4.0. Free to use in class with a link to this page. Details: License.

Previous

Teaching with Truzme

Next

Connect your app

Back to guides