Pular para o conteúdo
Folders to YTD

Folders to YTD

Drop folders of PNGs and get one .ytd texture dictionary per folder, compressed and mipmapped in the browser, ready to stream from a FiveM resource.

Por enquanto, esta documentação está em inglês.

Open the tool Last updated

Folders to YTD turns folders of images into the texture dictionaries GTA V streams. One folder in, one .ytd out. It runs entirely in your browser: nothing is uploaded and there is no converter to install.

Quick start

  1. Press Choose a folder, or drag folders onto the page. Every folder that has images in it becomes its own .ytd.
  2. Check the two names on each card: the dictionary name at the top (that is the file name) and the texture name on every row.
  3. Leave Compression on Auto unless you know you want something else.
  4. Press Build and download. You get a zip with a stream/ folder and an fxmanifest.lua, or the bare .ytd files if you switch the resource off.
  5. Unzip into resources, add ensure <your resource> to server.cfg and restart the whole server.

The two names

Everything in a texture dictionary is found by name, never by position, so both names matter.

Name Where it comes from What uses it
Dictionary The folder name, and the .ytd file name A .ytyp archetype’s textureDictionary field, and RequestStreamedTextureDict
Texture Each image file name The model’s own shader, which stores the name of the texture it wants

Important

If a model was built against mywall_01 and your file is called mywall01, that material draws untextured. There is no fallback and no warning in game. The page tells you whenever it has had to rename something.

Both names are lowercased, and anything that is not a letter, a number, an underscore or a dash becomes an underscore. You can edit either one on the page before you build.

Two textures with the same name inside one dictionary is refused, because they would hash to the same value and only one could exist. Two folders that would write the same .ytd is refused for the same reason.

Choosing a compression

Format Cost Use it for
DXT1 (BC1) 0.5 byte per pixel Almost everything, including normal maps
DXT5 (BC3) 1 byte per pixel Anything whose alpha fades rather than switches
ATI1 (BC4) 0.5 byte per pixel A single channel mask
ATI2 (BC5) 1 byte per pixel A two channel mask
A8R8G8B8 4 bytes per pixel Gradients and UI sheets where block artefacts show

Auto gives DXT5 to any image that has a pixel under alpha 255 and DXT1 to everything else. That matches what the game does: in a sample of 6,921 textures read straight out of a real game install, 82% are DXT1 and 16% are DXT5, and normal maps are DXT1 too (1,208 of the 1,231 in that sample).

Warning

DXT1 carries one bit of alpha. A pixel is fully solid or fully gone. It is fine for a leaf sheet or a cut out sign, and wrong for glass, smoke or a soft shadow. The page warns you when it spots alpha that is not already all or nothing.

Size and mipmaps

The default is to resize each image to the nearest power of two and cap the longest side at 2048.

That is not fussiness. A .ytd stores one stride and a level count, and every mip level is read as a quarter of the one before it. That quarter is only a real block count while both sides are powers of two, and it stops working once a side goes under 4 pixels, because a block compressed level can never be smaller than a single 4 x 4 block.

The game itself follows exactly that. In the same sample: 95.1% of textures carry the chain that halves down to 4 px, 5.7% carry one level, none carry a chain down to 1 px, and of the 46 textures that are not a power of two, not one has a second mip level.

So:

  • Resize to the nearest power of two (default) gives you a full chain.
  • Keep the original size is allowed, but any texture that is not a power of two is written with one level and the page says so. It will sparkle when the camera pulls back.
  • Build mipmaps off writes one level for everything. Only do that for something always drawn at a fixed size, like a UI sprite.

Nothing in the base game we sampled is larger than 2048 on a side.

Usage

Set usage from the file name marks each texture DIFFUSE, NORMAL or SPECULAR based on the GTA suffixes (_n, _nm, _nrm, _normal, _bump for normal; _s, _spec, _specular for specular). It also decides how the mip chain is filtered: colour textures are filtered in linear light, a normal map is renormalised, and a mask is left alone.

Turn it off if your file names use a different convention and you would rather everything said DIFFUSE.

Getting it into the game

A .ytd in a resource’s stream/ folder goes to the streamer on its own. It needs no files {} entry and no data_file line, which is why the generated manifest is three lines long.

fxmanifest.lua
fx_version 'cerulean'
game 'gta5'

name 'fivemad_textures'

Streamed assets are read once when the server starts, so restart myresource will not pick up a new dictionary. Restart the whole server. If the old texture is still showing, clear the server cache folder and have players clear their FiveM client cache.

A dictionary sitting in the streamer does nothing until something asks for it: a model through its archetype, or your own code.

client.lua
local txd = 'mypack'

CreateThread(function()
    RequestStreamedTextureDict(txd, false)
    while not HasStreamedTextureDictLoaded(txd) do
        Wait(0)
    end

    while true do
        DrawSprite(txd, 'mypack_logo', 0.5, 0.5, 0.2, 0.2, 0.0, 255, 255, 255, 255)
        Wait(0)
    end
end)

Limits

  • It writes DXT1, DXT5, ATI1, ATI2 and A8R8G8B8. BC7 is not written, even though the game ships a handful of BC7 textures.
  • It does not open existing .ytd files. To look inside one, replace a texture or shrink a whole stream folder, use the YTD Optimizer or the Texture Editor.
  • It cannot tell you what names your model wants. Those live in the model, not in your images.
  • Very large drops are read one image at a time in the browser, so a folder with hundreds of 4K PNGs takes a while and needs the memory for it.