Skip to content

Tools

A tool is a small app that opens in a window of its own from the Tools page: a planner, a generator, a calculator. It’s a short JavaScript module with some HTML and CSS, like a custom dashboard widget, and it works with your library: it can browse and make collections, find models, read their files, and save the models it makes.

The Tools page, with the tools on shelves: Generators, Planners, Calculators and FilesThe Tools page, with the tools on shelves: Generators, Planners, Calculators and Files

Open Tools in the sidebar. Double-click a tool to open it, or press Enter on it; right-click it, or press the context menu key, for About, Its models and, on your own tools, Edit and Delete (an admin also gets Uninstall on an installed one). From anywhere, ⌘S (CtrlS) opens search, where !tool lists them: every tool you can open is there by name, and picking one opens its window. An admin can open an installed tool from Administration → Tools as well, with Open in its right-click menu or in its details.

The row above the icons sets the page up, and what you choose is kept on your account, so it opens the same way on every device:

  • Show as — Shelves, which the page starts on, splits the tools into Generators, Planners, Calculators, Files, Library and Other, with a heading each and empty shelves left out; One grid puts the installed tools first and then your own.
  • The order, on the right: by Name, Newest — where the page starts — or Author, as the models page orders its grid.
  • Where each tool sits: drag its icon onto another shelf, or right-click it and pick one under Move to. While a tool is in the air the empty shelves appear too, so it can be dropped on one. A tool starts on the shelf its own metadata names, and moving it is yours alone — an update to the tool won’t move it back.

Nine come with Thingport, for an admin to install:

Tool Shelf What it does
Multiboard plannerPlannersPlans a Multiboard wall and every tile and mount to print it. It draws the plates itself and brings the 13 joints.
Gridfinity drawer builderPlannersFits a Gridfinity baseplate and bins to a drawer, cut to your printer’s bed, and saves the set as one model.
Skadis plannerPlannersPlans a wall of 3D-printed IKEA Skadis boards sized to your bed, with the mounts and the print order. It brings its 21 boards, mounts and spacers from MakerWorld.
Enclosure generatorGeneratorsA case for electronics: box and lid with screws or snaps, PCB standoffs, port cutouts, vents and text.
QR code generatorGeneratorsA printable QR code for a link, text, a Wi-Fi network or a contact, as a 3MF with a part per filament.
Keyring generatorGeneratorsYour text as a keyring, with key rings and magnet pockets, in a 3MF that gives each piece its filament.
Script customizerGeneratorsGenerates a model again from an OpenSCAD script: the one a model in your library came with, or a .scad file.
Print cost estimatorCalculatorsA model’s print time, filament and real cost, and the price to charge for the margin you want.
MakerWorld 3MF normalizerFilesMakes Bambu Studio and MakerWorld 3MFs open in other slicers with their colours, plates and print settings.

A model that came with its script doesn’t need the Script customizer: Customize… on its own page opens its parameters whether the tool is installed or not.

The QR code generator in its window: what the code says on the left, the printable tile on the rightThe QR code generator in its window: what the code says on the left, the printable tile on the right

Administration → Tools has three parts.

Administration, Tools page: who sees tools, users' own tools switched off, and the nine repository tools installed, each marked LatestAdministration, Tools page: who sees tools, users' own tools switched off, and the nine repository tools installed, each marked Latest
  • Who sees tools: admins only, everyone, or admins and the users you pick; a new Thingport starts on everyone. Only they see Tools in the sidebar and get the models tools bring. Users’ own tools lets them also make their own, in the editor below; it’s off at first.
  • From the repository: the tools in the Thingport repository’s tools folder, none of them installed until you install it. Double-click one, or press Enter on it, for its details: what it does, how many models it brings, and screenshots to look through first (click one to see them large, and the arrow keys move between them). Install there makes it available to everyone who sees tools. Under each installed tool, a blue Update chip means the repository has a newer version, which one click takes, and a green Latest that it hasn’t; neither shows while the repository can’t be read. Right-click an installed tool to Open it, Fetch missing models when some haven’t come in, or Uninstall it.
  • Users’ own tools: the tools users made, and whose they are.

A tool may need models: a wall planner its mounts, for example. They come in a collection of their own, named Tool: and what the tool calls it, such as Tool: Multiboard models, in the library of everyone who sees tools, listed after their own collections. They open, download and go to a slicer like any other, but neither they nor the collection can be edited or deleted; they go, from every library, when you uninstall the tool. A user who loses access to tools loses them too, and gets them back with it.

The collection is where they are and the only place they are listed: a planner with two hundred parts would otherwise bury your own models under it, so they stay out of the models page and its categories. Search still finds them. Favourite one and it shows in Favourites, as anything you favourite does.

An admin may install a tool without them — they can run to gigabytes — by switching off Import its models as they install it, and import them later with Import its models in its details. An update, from its chip or its details, brings them only where this Thingport instance already has them, so a tool installed without them stays that way. Meanwhile a tool can fetch just the few that a piece of work needs, through fetchToolModels: one from a model page is imported then through this Thingport instance’s first admin account, with its connection to that site, while the tool’s own files come only with Import its models.

The files behind them are the tool’s, and are kept once for the instance however many people use the tool — parts that take a gigabyte take a gigabyte, not a gigabyte per person. Each user still has their own model, in their own collection and language; what they share is the bytes on disk.

A tool’s models are either files in its repository folder, such as the Multiboard planner’s joints, or model pages Thingport imports when you install it, as you: for designs that may be downloaded but not passed on, such as the Skadis planner’s boards from MakerWorld. For those, connect the provider first (Configuration → Providers). The tool’s details show how many have come in; a provider that limits daily downloads, or a sign-in that’s missing, stops the fetch, and Fetch missing models tries the rest again later.

With Users’ own tools on, the quickest way to get a tool is to describe it to an AI assistant connected to Thingport.

  1. Connect your assistant over MCP with your API token.
  2. A new token already allows Save a tool (save_tool) and Upload an icon (upload_icon). For the tool’s icon, the assistant searches Thingport’s own icons with list_icons, and uploads an SVG of its own when none fits.
  3. Ask for what you want, e.g. “Make me a Thingport tool that turns a few words into a printable label and saves it to my library.” The assistant reads the tool_guide tool first, which teaches it the format below, then saves the tool.
  4. Open it from Tools in the sidebar. To change it, ask again: list_tools lets the assistant read back the script, the HTML and the labels it wrote before.

Build with an AI assistant has more: the permissions it needs, example prompts, and checking what it made.

Use AI, beside the parts of the New tool editor, shows these steps as well, with three example prompts to copy. Its Connect an AI gives the command or settings for Claude Code, Claude, ChatGPT, Codex CLI, Cursor and VS Code.

A tool an assistant saves is one of your own, so the same warning applies: its script runs in your browser with your access to Thingport. Read what it wrote in the editor if you’re unsure, and remember that it can’t bring models of its own — only a tool from the repository does that.

With Users’ own tools on, New tool on the Tools page opens the editor:

  • Details: its name, folder name, description, icon, version, author, category, the size its window opens at, and the hosts it may reach. Saving one with the same folder name replaces it. The category is the shelf the Tools page starts it on; anyone using it can move it themselves.
  • Script: an ES module. The editor starts with a working tool, Cube maker, that uses most of what a tool can do; the SDK reference beside it lists the rest, and the full reference has each member in detail.
  • HTML & CSS: markup and a <style> block, put into the window before the script runs. Scope the styles to a class of your own so they stay in the tool. The theme is already on the window as CSS variables — --tp-accent, --tp-accent-ink, --tp-background, --tp-paper, --tp-text, --tp-text-muted, --tp-divider, --tp-error, --tp-warning, --tp-success and --tp-font — so a stylesheet can use them without the script copying anything. Text and icons on an accent-filled button take --tp-accent-ink, never the paper colour, which is dark in the dark theme. Watch the specificity while you’re at it: a reset written .yours button { color: inherit } outranks .yours-button { color: … } and quietly wins, so wrap such a reset in :where().
  • Labels: the words the tool shows, one file per language, so they aren’t buried in the script. The script asks for them by key with t("key"). English is the fallback, key by key, so a half-finished translation shows its own words where it has them and English where it doesn’t. + adds a language, starting from English’s keys with the words blanked.
  • Preview: the tool running alone, as its window will show it. Until it’s saved, what it keeps lasts only as long as the preview, and it can’t reach other hosts.

A tool you make is yours alone: other users don’t see it.

The default export is called with thingport when the window opens, and the function it returns is called when the window closes:

export default async function mount(thingport) {
const { root, theme, storage, models, collections, ui } = thingport;
root.querySelector("#save").addEventListener("click", async () => {
const collection = await ui.pickCollection({ title: "Save the bin to" });
if (!collection) return;
const model = await models.create({
name: "Bin 2×3",
collectionId: collection.id,
files: [{ name: "bin.stl", data: stl }],
});
ui.toast("Saved", "success", { openModel: model.id }); // with an Open button for the model
});
return () => {}; // stop timers and remove window listeners here
}

thingport has the window’s element and size, the theme, storage kept for the user, their models and collections, the dialog that asks which collection to save into, the models a repository tool brings, fetch through Thingport to the hosts the tool declares, Thingport’s own API, and the libraries below. Each is in the SDK reference, generated from the SDK itself, which also says what a widget has that a tool doesn’t and the other way round. Your first tool builds one step by step, and the recipes are complete tools to start from.

A tool’s labels don’t belong in its script. Buried there they can’t be read as text, handed to a translator, or added to without touching the logic. So they sit beside it, one file per language:

tools/bin-planner/
tool.json "locales": ["en", "lt"]
tool.js t("save.title")
locales/en.json { "save.title": "Save to Thingport", "rings.ring": "Ring {n}" }
locales/lt.json { "save.title": "Įrašyti į Thingport", "rings.ring": "Žiedas {n}" }

Each file is a flat map of key to sentence — flat, because a tool looks a label up by its whole key, and because nesting invites a file that is really a program. {name} in a sentence is filled in from what t is given. Thingport reads the file matching the user’s language, and hands the tool t:

export default async function mount({ t, labels }) {
labels(); // every data-t in tool.html, filled in
badge.textContent = t("rings.ring", { n: 2 }); // "Žiedas 2"
}

The markup carries the key where the sentence would be, so a panel’s words need no script at all:

<h2 data-t="wall.title">Wall size</h2>
<button data-t="parts.copy" data-t-title="parts.copyHint">Copy</button>

data-t sets the text; data-t-title, data-t-aria and data-t-placeholder fill those attributes. The English left in the markup is what a reviewer reads, and what shows if the labels never arrive. Call labels() again after adding more markup.

  • The metadata’s locales lists the languages the folder has; a language it names without a file is an error, not a shrug, so a missing translation can’t install quietly.
  • English is the fallback, key by key: a language that is half done shows its own words where it has them and English where it doesn’t. A tool with labels needs en.
  • A key with no words anywhere comes back as itself, so a label nobody wrote shows up in the window.
  • The user changing language runs the tool again, as changing the theme does, so t is read once at the top of mount rather than watched.
  • A table of labels a tool builds up front — the sections of a settings dialog, the names of the parts it makes — holds keys, and whatever shows them says them. A t() at the top of the file would run before there is a t.
  • A language Thingport doesn’t have is simply never asked for; a language the tool doesn’t have falls back to English. languages lists what Thingport has, if a tool wants to say so itself.
  • At most 128 KB a language and 1 MB in all.

A tool is one script with a size limit, and a reviewer reads it before it’s merged, so the big machinery lives in Thingport rather than in the tool: a font parser or a solid modelling kernel is most of a tool’s budget on its own, and one of them is a WebAssembly binary nobody could read. thingport.library(name) hands over Thingport’s own copy of Three.js, opentype.js, Manifold, its fonts or OpenSCAD, fetched the first time a tool asks and shared with every tool after that.

What each one hands over is in the SDK reference. OpenSCAD renders in a worker and entirely in the browser: the script, the parameters and the result go nowhere until the tool saves them. The libraries a script may include are in frontend/src/assets/scadLibraries. The fonts are all static faces, under the Open Font License, listed in frontend/src/assets/toolFonts: a variable font’s letters come back collapsed, as the parser doesn’t apply its deltas.

A tool in the repository is a folder under tools/, listed in its index.json. Tool development covers all of it — the fields and their limits, the models, the screenshots and the checks — and this is the shape of it:

  • tool.json (or tool.yml): the metadata, as the editor’s Details make it, plus author, and the models it brings, if any:

    {
    "name": "Bin planner",
    "version": "1.0.0",
    "author": "Your Name",
    "window": { "width": 1100, "height": 720 },
    "hosts": [],
    "category": "planners",
    "locales": ["en", "lt"],
    "collection": {
    "name": "Bin parts",
    "models": [
    { "key": "baseplate", "name": "Baseplate 1×1", "files": ["models/baseplate.stl"] },
    { "key": "tile-8x8", "name": "8×8 tile", "source": "https://thangs.com/m/974214" }
    ]
    }
    }

    Each model has a key the tool finds it by, a name, and either files from the tool’s folder, which the repository may carry only when the design’s licence allows it, or a source page Thingport imports when an admin installs the tool. screenshots lists up to eight PNG, JPEG or WebP pictures in its folder, each { "file", "caption" }, which admins look through before installing it. The iconUrl may also be an SVG as a data:image/svg+xml address, so the icon comes with the tool.

  • tool.js and, optionally, tool.html.

  • locales/<code>.json: the words it shows, for each language its metadata’s locales names. See the words a tool shows.

  • README.md: what it does, what it reaches, and where its models come from.

Open a pull request; a check validates the folder (npx tsx scripts/validateTools.ts in backend/ runs it locally), and a maintainer reads the code. The tools README lists what reviewers look for.

Administration → Tools says which of these it’s reading:

Thingport running Offers the tools from
From a checkout: npm run dev (development)The checkout’s own tools folder, read afresh each time: edit, then refresh
The local docker-compose.yml, which builds from the checkoutThe checkout’s tools folder, mounted into the backend
The :dev imageThe repository’s develop branch on GitHub
The :latest image, or a version’sThe repository’s main branch on GitHub

TOOLS_DIR points the backend at any folder instead, and TOOLS_URL at another repository’s tools folder as raw files, such as a fork’s (https://raw.githubusercontent.com/<you>/Thingport/<branch>/tools). From GitHub, the list is read again at most hourly; installing or updating a tool always reads it afresh.

Something unclear, wrong or missing on this page? Say so here, or react. It’s kept in GitHub Discussions. Something broken? Report it as a bug.