## title: Teeworlds utilities
## date: "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.
(HTM) teedata.net
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
utilities code.
(HTM) TeeAssembler 2.0
/fokkonaut_bridge.png
(IMG) /fokkonaut_bridge.png
## 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)
/render_default.png
/render_color.png
(IMG) /render_default.png
(IMG) /render_color.png
### 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
/scene.png
(IMG) /scene.png
### Merge asset parts
Here we are going to merge specific parts from a skin
(right) to another (left).
Any Teeworlds asset should works.
/teedata_skin.png
/alien_skin.png
(IMG) /teedata_skin.png
(IMG) /alien_skin.png
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
/render_new_skin.png
/new_skin.png
(IMG) /render_new_skin.png
(IMG) /new_skin.png
### 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
/skin_with_weapon_and_emote.png
(IMG) /skin_with_weapon_and_emote.png
### Other possible result
/board.png
(IMG) /board.png
## Links
https://github.com/teeworlds-utilities/teeworlds-utilities
(HTM) https://github.com/teeworlds-utilities/teeworlds-utilities