Converting text input from user into pre-made number models

I need to be able to enter 4 digits of a year and have those years show up as custom objects - in this case a diamond-covered year on a piece of jewelry.

We would need models for each number 0 1 2 3 4 5 6 7 8 9 and a text attribute would let customers enter a year like 2 0 2 0 and the numbers would be replaced with the corresponding models. How can we achieve this?

Hi Bartosz,

To be clear, it sounds like you are trying to represent each text character (i.e. 0-9) with a pre-made 3D model instead of using Text Shapes to build a model from text. Correct?

Here are instructions on how you can accomplish this. A demo of the final result can be found here.

Step 0: Create Assets & Get Asset Ids

First, upload the 3D assets for each character (i.e. 3D models representing 0 - 9).

Then, create an empty placeholder model (i.e. create a Model asset on Threekit with no nodes).

Finally, get the ID of each asset, which can be retrieved from the URL of the asset detail page. We will need these later.

Step 1: Setup Anchors

In the parent asset (i.e. the asset we’re configuring), import four (i.e. one for each character) models. These will be used as anchors for the character models. It does not matter what models are imported or where they are placed. Those properties will be controlled by Asset Rules. However, it would be easiest to import 1, 2, 3, & 4 as a memory aid.

Step 2: Create Attributes

Create 4 Part Reference attributes (one for each character) and a String attribute (for the text input).

Step 3: Create Rule to Set Models

Create a rule with no conditions (i.e. one that always fires) and add actions to set each Anchor Node (i.e. the models we imported in Step 1) to it’s corresponding attribute.

Step 4: Create Rules to Update Placement (optional)

We may want to move the Anchors (change the transform) depending on how many characters are entered. For example, if the user enters 20 instead of 2020, we would want the letters aligned in the center instead of the first 2 anchor positions.

To do this, we create one rule for each character length that controls where each anchor is placed. NOTE: This can be done with a script as well and that may be the preferred approach if there were many characters.

Each rule should have conditions that detect how many Anchors have been set (i.e. the number of characters) and actions that set the position to each Anchor.

Here is a finished rule

To set the position, create an Set Property Action

Set the Translation property of the Anchor

Step 5: Add Configuration Script

Now that we have the rules setup, we need to add a script that will set the Anchors according to the text input. This can be done by adding a Custom Script action to the rule that always fires.

Here is a script to use as a template.

// Store the assetId for each number in an array
const numberAssets = [

// Use the Placeholder Model to set Anchors w/no value.
const placeholder = { assetId: "1f4eaa40-a788-4773-b1a5-30a04e0f7463" };

const anchorReset = {
  Anchor1: placeholder,
  Anchor2: placeholder,
  Anchor3: placeholder,
  Anchor4: placeholder,

let player;

async function onChange() {
  if (!player)
    if (/(preview|admin)$/gi.test(window?.location?.origin))
      // Find player on platform
      player = window.api._store.getIn(["player", "players"]).first().api;
    else if (window.player)
      // Find player on embed
      player = window.player;
    else return console.warn("Cannot find player");

  // Get the configurator
  if (!window.configurator)
    window.configurator = await player.getConfigurator();

  // Only fire if the Text has changed
  const nextConfig = window.configurator.getConfiguration();
  if (window.prevConfig?.Text === nextConfig.Text) return;
  window.prevConfig = nextConfig;

  const update = nextConfig.Text.split("")
    .map((int) => numberAssets[int]) // Map the input character to the assetId
    .map((assetId, index) => ({ [`Anchor${index + 1}`]: { assetId } })) // Create the config updates
      (acc, cur) => ({ ...acc, ...cur }), // Reduce attribute values to a single object
      anchorReset // Use anchorReset as the initial value to ensure empty Anchors are cleared

  return window.configurator.setConfiguration(update);

// onChange is an async function, meaning it returns a Promise
// Returning this to the config script ensures other rules are fired w/a consistent order of operations
return onChange();

On Embed: Assign Player to Window

The script needs to access the Player API. On initialization, assign the player to the window.

      assetId: "00000000-0000-0000-0000-000000000000",
      authToken: "00000000-0000-0000-0000-000000000000",
      el: document.getElementById("player-el"),
    .then((player) => {
      window.player = player;

Hello Phil,
Thank you so much for taking the time to create this demo.
Tomorrow I will be checking it based on our case.
Thank you very much.

@bartosz.stepien FYI, I updated the script to reflect the change I made.

let player;

async function onChange() {
  if (!player)
    if (/(preview|admin)
      player = window.api._store.getIn(["player", "players"]).first().api;
    else player = window.player;
  if (!player) return;

1 Like


I have a question about deformers. There is a way to do some deforms on top of this 3d inputed models?bend

Some latice or bend? Why I’m asking is that the numbers are bended a litle bit. In attachment I put some references on this effect (it is for 2018).

I know how deformers are woring in profesional 3D software and I wondering if is possible do this in here?

This will be helpful for me if we can do that. I was see that some deformers are under operators but I cant put this on “anchor” I think because this is not yet a model 3d but only null in the space.


I have one idea about this.I can put a “bend modifier” on each number with default 0 value.

And in final model asset add some hidden attributes that will be drivig this bend angle regarding input position.

Please give me some fresh ideas how can I achieve this effect.


Hi Bartosz,

That’s an interesting problem. Normally, if we were using a Text Shape to define all characters, then we could easily apply a Bend Deformer (or some operator) to all characters. In this case, since each character is a model, we will have to coordinate the deformation across the children.

I don’t have a clean answer off the top of my head. Maybe try combining a Bend Deformers & a Stretch operator.

If you can get it working w/out configuration (i.e. just the 3D side), I can probably help you figure out how to hook it up to the configurator.

Hi Bartosz,

Another option that might work is the “UV Warp” operator for meshes. It is an operator that lets you warp geometry around a source piece of geometry.

Firstly, create a source piece of the geometry of the desired deformed shape. This can be created in the platform or imported and make sure it has plenty of segments. The segements help the “UV Warp” operator work more accurately.

Then apply the “UV Warp” operator to the indivual meshes you want warped. Use the Dimension and Justification for each letter to adjust the placement. Change Ridgity to Component. Vertex Ridgity can give a messy result. Input your source geoemtry and use the world cordinates. I attached my settings below.

Let me know if you have any more questions.

1 Like

Is this method performant enough to handle 27 different letters? Or should I leave it up to the website to handle all of this assetID swapping?

This is being used in projects for the entire alphabet, Threekit is performant enough to handle it but is up to the implementers to make sure the assets, textures, etc are all optimized for the web.