Thingy Kit.

Everything it takes to bring him into a project: his persona, his model and his code, behind one link.

This site is the source of Thingy. Every place he appears takes him from here, and a project that follows these addresses changes when he does.

  • Send a person this link

  • Or tell an agent this

    Read https://thingy.thingelstad.xyz/kit.md and bring Thingy into this project.

Thingy in the Workshop, showing a hammer

What is in the kit

PartWhat it isWhere
His personaWho he is, how he talks, and what he never does. The authority on himpersona.md, or as a page
His modelRigged glTF 2.0, in four scenes, with faces and accessoriescharacter/latest/, described by its manifest
His picturesTransparent stills, with no code to runhttps://thingy.thingelstad.xyz/character/latest/poses/<name>.webp
A frameAn iframe with him in it, with no code to runhttps://thingy.thingelstad.xyz/embed/
A componentThe <thingy-character> web component, for any frameworkhttps://thingy.thingelstad.xyz/thingy.js
His voiceThe one spoken voice he hasHow he sounds, in the persona
What he knowsJamie's published work, through the Librarian MCP serverConnect your AI on Ask Thingy
A model to printA 180 mm figure, as 3MF and zipped STLPrint Thingy
His illustrationThe original drawing, in the librarian's jacket. The authority on how he looks. A 220 KB PNG, for og:image and app iconshttps://thingy.thingelstad.xyz/thingy-original.png

To try him without writing anything, use the stage. Choose a scene and turn him, then Bring him along gives you the code, a picture or a link for exactly what you see.

Start with his job

Thingy is the same character everywhere, and each place gives him a job. The job picks the scene and how much of his personality comes through. The jobs he has today are in Where he works:

JobSceneUse scene=
LibrarianLibrarylibrary
Builder and record keeperWorkshopworkshop, with accessories for the job
Host of Supporting MembershipConcertconcert
Narrator of the audio editionNone, he is only heard

outdoors is a scene with no job yet.

If the project clearly fits one of those, use it, and keep to what the job says: builder and record keeper means the record of what Jamie has built. If you aren't sure it fits, ask Jamie. A new job is Jamie's to give, so ask Jamie what he does there before inventing a role, and add it to the persona first.

Each surface has its own register in the persona, and a new project has none until Jamie gives it one. Until then, borrow the nearest and write down that you did, as docs/THINGY.md does for Things I've Built. Settle whose name a page's entries carry at the same time, because he never writes as Jamie. That file settles it for its site.

Give him words

Whichever model writes as Thingy follows the persona. An agent writing pages or code for a project reads all of persona.md first. It is about 17 KB, and it is meant to be read whole.

  • A prompt that runs on every turn can carry less. Ask Thingy's chat keeps a condensed identity for its model. Take it from the persona and say so in the file, so the persona wins when they differ. Never fork him, and never add to him there.
  • Your surface adds mechanics, not character. Citations, lengths and formats belong to your project. Who he is does not.
  • Facts have owners. He reads a figure from where it lives and never states one from memory. The persona names each owner.

The lines that matter most, all from the persona, which wins if these ever differ:

  • He is never Jamie. He never writes as Jamie, and his words never pass as Jamie's.
  • He has his own name, byline or box, and his own face, so a reader can always tell it is him.
  • He invents nothing: no fact, figure, date, quotation, citation or feeling.
  • He is he/him, says "I" when talking with someone, and says plainly that he is an AI agent Jamie built when it matters.
  • He answers from Jamie's published work, and declines the rest in character.

To speak, he uses OpenAI tts-1-hd with the voice nova, for his own words only. The persona has the current voice and the hand-offs.

To answer from the archive, connect the Librarian MCP server at https://librarian.thingelstad.com/mcp. Its reference lists every tool. Readers sign in with an active Weekly Thing subscription. An agent can also use Ask Thingy's llms.txt.

Show him

You wantUseIt costs
A picture on a pageA stillUnder 60 KB, and no JavaScript
Him on a page, turnable by whoever visitsThe frameA model of about 2 MB, loaded inside the frame
Him inside an app, reacting to itThe componentthingy.js at about 820 KB, and a model of about 2 MB
Him in your own 3D sceneThe modelA model of about 2 MB, and your own renderer

Each of these follows the newest Thingy as written here. See Follow him or keep him to hold one still instead.

A still

<img
  src="https://thingy.thingelstad.xyz/character/latest/poses/workshop-hello.webp"
  alt="Thingy in the Workshop, waving hello"
  width="240"
  height="240"
/>

The name is <scene>-<pose>.webp, 1000 px square and transparent, with a tool or a face in it where the still has one: workshop-hammer-show.webp, library-rest-delighted.webp.

  • Every scene has present. Outdoors and Concert have only that, named by poster in the manifest, and they show the accessories the scene gives him. In workshop-present he holds the laptop.
  • The Library's stills also have faces, and the Workshop's have tools. stills for each scene in the manifest lists them. A still shows the original face unless its name gives another.
  • For anything with no still, use the frame or the component, which draw any scene, pose, accessory and face. Download picture on the stage also draws one, but that copy is yours to host and no longer follows latest.
  • Your policy and your background. A strict content security policy needs the host in img-src. He is made for a light page: on a very dark one, his legs and shadow sink into it.
  • If this site is ever down, the page loses the picture, so give it alt text or an empty alt that the page can stand without.

The frame

<iframe
  src="https://thingy.thingelstad.xyz/embed/?version=latest&scene=workshop&accessories=hammer&pose=show&face=proud&light=off&motion=off"
  title="Thingy in the Workshop"
  width="360"
  height="400"
  loading="lazy"
  style="border:0;background:transparent"
></iframe>

It is transparent, with no controls around him, and runs nothing on your page, so a strict content security policy needs only the host in frame-src. It takes version, scene, accessories, pose, face, light, motion and view. Anything version doesn't recognize means the newest model. view=<round>,<up>,<zoom> starts him at an angle, in degrees around him, degrees down from straight above, and zoom, as view=60,80,1.2.

The component

<script type="module" src="https://thingy.thingelstad.xyz/thingy.js"></script>
<thingy-character
  version="latest"
  scene="library"
  pose="hello"
  face="idle"
  light="off"
  motion="off"
  style="display:block;width:320px;height:380px"
></thingy-character>

It works in plain HTML or any framework. Change an attribute and he changes.

AttributeValues
versionlatest or v0.15, with the v. Anything else is the newest
scenelibrary, outdoors, workshop, concert
poseSee poses. Without one he stands in present, so set it
faceSee faces
accessoriesSee accessories. A comma list, or none
lighton or off. The antenna is lit when he is live, answering now or speaking
motionon or off. It obeys reduced motion even when on
blinkon blinks the faces that can, never under reduced motion
viewThe angle he starts at, written as the frame's view is
zoomoff leaves the mouse wheel to the page
posterAn image to show until the model is ready
view-labelThe canvas's accessible name
asset-baseAnother directory to load the models from, when hosting the files yourself
  • Events: thingy-ready, thingy-change, thingy-view as he turns, thingy-tap on a press that barely moves, and thingy-fallback when he falls back to a still because 3D could not start.
  • Methods: resetView(), hop({ height, direction, turns }) to jump and spin, and picture(size), which resolves to a square transparent PNG of him as he stands now.
  • Properties: view reads where he is now, and moves says whether the pose has motion to play.
  • Content security policy: the host needs to be in script-src and connect-src, with 'wasm-unsafe-eval' in script-src for the Meshopt decoder, and blob: in connect-src and img-src for the textures.

A still that becomes him

For a page that should stay light, show a still first and bring him in when the page is up. Skip the 3D for Save-Data or when WebGL 2 is missing, and the still stays if anything fails. Ask Thingy's front page does this, in thingy-3d.ts.

<div style="position:relative;width:240px;height:240px">
  <img
    id="thingy-still"
    src="https://thingy.thingelstad.xyz/character/latest/poses/library-hello.webp"
    alt="Thingy, waving"
    width="240"
    height="240"
  />
</div>
<script type="module">
  const still = document.querySelector("#thingy-still");
  const saving = navigator.connection?.saveData === true;
  const canDraw = !!document.createElement("canvas").getContext("webgl2");
  const later = window.requestIdleCallback ?? setTimeout;
  if (!saving && canDraw) {
    later(async () => {
      await import("https://thingy.thingelstad.xyz/thingy.js");
      const thingy = document.createElement("thingy-character");
      thingy.setAttribute("version", "latest");
      thingy.setAttribute("scene", "library");
      thingy.setAttribute("pose", "hello");
      thingy.setAttribute("zoom", "off");
      thingy.setAttribute("poster", still.src);
      thingy.style.cssText = "position:absolute;inset:0;width:100%;height:100%";
      thingy.addEventListener("thingy-ready", () => {
        still.style.visibility = "hidden";
      });
      thingy.addEventListener("thingy-fallback", () => {
        thingy.remove();
        still.style.visibility = "";
      });
      still.after(thingy);
    });
  }
</script>

The model

Load https://thingy.thingelstad.xyz/character/latest/<scene>.glb with Three.js GLTFLoader and its Meshopt decoder. Files are served with Access-Control-Allow-Origin: *. They are glTF 2.0 in meters, +Y up and +Z forward, with Meshopt compression and WebP textures, on a shared rig of 40 joints.

  • Poses are animation clips named for the pose, at 24 fps. The manifest gives each pose's stillFrame, the frame to hold for a still pose.
  • Accessories are skinned nodes named Thingy_Accessory_<id>, with tool clips named <tool>-<pose>. Show the ones he has and hide the rest. An accessory's absentNode in the manifest takes its place when it comes off: without headphones, Thingy_Accessory_ears gives him his ears.
  • The face is one cell of an atlas on the node Thingy_Screen: material Thingy_Face, emissive map, 4 columns by 5 rows. The manifest gives each face's cell, and a blink cell for the faces that can blink. faces.webp is the same atlas, small, for a page offering the faces.
  • The antenna is the material Thingy_Beacon.

Poses, faces and accessories

Poses

hello, present, thinking and rest, in every scene. On a page where people can turn him, hello makes the better first pose, since the present hand can read as a rude gesture from the side.

Faces

FaceWhat it means
originalThe illustration's wink
idleHe is ready and listening
thinkingHe is at work
found-itHe found something real, not merely that an answer finished
oopsSomething went wrong on his side
delightedA connection found
curiousA question he is turning over
proudShowing something Jamie built
eagerMaking the case for membership
sympatheticA hard subject
sheepishHe got something wrong and is fixing it

A face means what it says here, so show found-it only when he found something. There is also off, which is never shown to a reader.

Accessories

What he can have with him depends on the scene. A scene gives him what it gives him unless you say otherwise, so leave accessories off for that. Otherwise name what he has, separated by commas, or say none.

SceneAccessoriesWith noneUnless told otherwise
libraryNone
outdoorsbackpackOffbackpack
workshopscrewdriver, hammer, drillEmptyEmpty hands
workshoplaptopEmptylaptop in present
concertheadphonesOffheadphones

Some accessories keep to the poses they were made for:

In the WorkshopPoses
screwdriver, hammer, drillcarry, show, work
laptoppresent
nonehello, thinking, rest

carry holds the tool at his side, show holds it up, and work raises it to use it. With no accessories, a pose only a tool has brings that tool, so present in the Workshop holds the laptop. Asking for a pose the accessory does not have moves him to its first pose. Tool poses are single frames, so motion has nothing to play. An accessory a scene doesn't have is ignored. To read what he ended up with, use the accessories property or the thingy-change event.

The manifest describes each scene's slots, so a page can offer whatever a new scene brings without changing. A slot holds one accessory at a time.

Follow him or keep him

You wantUseChanges
The newest Thingy, alwaysversion="latest", character/latest/When this site does, within five minutes
One Thingy, for goodversion="v0.15", character/v0.15/Never
His personapersona.mdWhen Jamie approves a change, within a minute

Use latest unless a page needs one model forever.

Change him here, and this is how it reaches a project:

  • On its own: the model, the stills, the component and the frame, for anything following latest. Nothing to do.
  • By hand: words a project keeps of its own, such as a condensed prompt or a page in his voice. Each change to the persona opens an issue for Jamie, listing what to reread, drawn from surfaces.json.

Tell Jamie about a new project, so it can join surfaces.json with every still it names. A new model cannot ship without those stills, because this site's own checks fail first.

What this site keeps to:

  • Published addresses stay. A numbered version's files are never replaced, and an incompatible change gets a new version. The component draws v0.15 on. The older files, v0.10 and v0.14, stay published for anything loading them itself, with the outfit names they were made with.
  • Pose, scene and face names stay.
  • character/latest/ holds what the newest version holds, at the same names.
  • https://thingy.thingelstad.xyz/revision.json gives the commit and the time of the current build, for a project that wants to notice a change.

Where he works now

Two sites to read as examples:

  • Ask Thingy (code) follows latest with the component on its front page and a still on every other page. The rules it keeps are in its AGENTS.md.
  • Things I've Built (code) follows latest with stills alone, and keeps its job, scene and register in docs/THINGY.md, a good pattern for a new project to copy.

Terms

Everything here is licensed CC BY-NC 4.0: the persona, this kit, the model, the faces, the stills, the print files and the code. Use him, change him and share him, credit Jamie, and don't use him commercially. The whole licence is in LICENSE.

CC BY-NC 4.0

Credit him like this, linked where you can:

Thingy by Jamie Thingelstad, CC BY-NC 4.0

The code that Bring Thingy along gives you already carries that line. For a use the licence doesn't cover, ask Jamie.

Jamie has supported Creative Commons for years. His blog and the Weekly Thing carry its licences too, and the first donation from Weekly Thing Supporting Memberships went to it. In his words: "Copyright law can strangle creativity and culture. Creative Commons is doing good work to enable an alternative path."

A few things here have licences of their own, which NOTICE.md lists: the Inter fonts, Three.js inside the component, and the Creative Commons marks.

For agents

  • llms.txt indexes this site.
  • This page is kit.md, and it holds all of the kit but the persona. Read persona.md before writing anything in his voice.
  • manifest.json is the machine-readable list of scenes, poses, faces, accessories and stills. Trust it over this page if they ever differ.