💾 Archived View for tilde.pink › ~nagi › teeworlds-utilities.gmi captured on 2024-05-10 at 12:24:31. Gemini links have been rewritten to link to archived content

View Raw

More Information

⬅️ Previous capture (2024-03-21)

-=-=-=-=-=-=-

Teeworlds utilities

2023-07-26

This idea came to me when I was looking for a Teeworlds skin renderer.

The ones that existed didn't suit me, as they didn't really respect the in-game rendering. Either the feet were too far out or the colors were wrong.

So I decided to make my own toolbox to manipulate Teeworlds assets, which we use on

teedata.net

and for the Teedata Discord bot.

Indirectly, other people use it, for example, to render skins in a Discord channel that displays messages in real time (fokkonaut's Discord server) or in other projects like

TeeAssembler 2.0

that used some part of the **teeworlds-utilites** code.

Use case examples

Teeworlds skin rendering

Render a Teeworlds 4K skin with default and custom colors.

import {
  Skin,
  ColorCode,
  ColorRGB
} from 'teeworlds-utilities';

const renderTest = async () => {
  const skin = new Skin();

  await skin.load('https://api.skins.tw/database/skins/96AATxN3DEzcGww4QhmduFCsPzaxhZO7Tq6Lh9OI.png');

  skin
    .render()
    .saveRenderAs('default.png', true)
    .colorTee(
      new ColorCode(6619008),
      new ColorRGB(136, 113, 255),
    )
    .render()
    .saveRenderAs('color.png', true);
}

try {
  renderTest();
} catch (err) {
  console.error(err);
}

Result (4K)

Scene

A custom scene including a rendered skin.

import { Scene } from 'teeworlds-utilities';

const sceneTest = async () => {
  const scene = new Scene(
    'data/scenes/schemes/example.json'
  ).preprocess();

  await scene.renderScene();
  scene.saveScene('scene.png')
}

sceneTest();

Result

Merge asset parts

Here we are going to merge specific parts from a skin (right) to another (left). Any Teeworlds asset should works.

import {
  Skin,
  SkinPart
} from 'teeworlds-utilities';

const mergeTest = async () => {
  const teedata = new Skin();
  await teedata.load('https://teedata.net/databasev2/skins/teedata/teedata.png');

  const sunny = new Skin();
  await sunny.load('https://teedata.net/databasev2/skins/irradiated%20sunny/irradiated%20sunny.png');

  teedata
    .copyParts(
      sunny,
      SkinPart.FOOT,
      SkinPart.FOOT_SHADOW,
      SkinPart.DEFAULT_EYE,
      SkinPart.ANGRY_EYE,
      SkinPart.BLINK_EYE,
      SkinPart.CROSS_EYE,
      SkinPart.HAPPY_EYE,
      SkinPart.SCARY_EYE,
      SkinPart.HAND_SHADOW,
      SkinPart.HAND,
    )
    .setEyeAssetPart(SkinPart.ANGRY_EYE)
    .render()
    .saveAs('skin.png')
    .saveRenderAs('rendered_skin.png', true)
}

try {
  mergeTest();
} catch (err) {
  console.error(err);
}

Result

More skin configuration

Here we are using the SkinFull object to render some in-game feature like the weapon, hands and emote.

import {
  Skin,
  Gameskin,
  ColorRGB,
  Emoticon,
  SkinFull,
  GameskinPart,
  EmoticonPart
} from 'teeworlds-utilities';

const fullSkinRenderConfiguration = async () => {
  const teedataSunny = new Skin();
  await teedataSunny.load('skin.png');

  const napolitano = new Gameskin();
  await napolitano.load('https://teedata.net/databasev2/gameskins/napolitano/napolitano.png');

  const emoticon = new Emoticon();
  await emoticon.load('https://teedata.net/databasev2/emoticons/default/default.png');

  teedataSunny
    .colorTee(
      new ColorRGB(255, 255, 255),
      new ColorRGB(255, 255, 255),
    )
    .setOrientation(345);

  new SkinFull()
    .setSkin(teedataSunny)
    .setGameskin(napolitano, GameskinPart.HAMMER)
    .setEmoticon(emoticon, EmoticonPart.PART_1_2)
    .process()
    .saveAs('skin_with_weapon_and_emote.png', true);
}

try {
  fullSkinRenderConfiguration();
} catch (err) {
  console.error(err);
}

Result

Other possible result

Links

https://github.com/teeworlds-utilities/teeworlds-utilities