An .osk file is how osu! skins are shared. If you write tools around skins, or just want to send your edited skin to a friend, it helps to know exactly what the game expects.
It's just a zip
An .osk is a normal ZIP archive with a different extension. You can open it with any archive tool, and you can create one by zipping a folder and renaming .zip to .osk.
cd "My Skin" zip -r "../My Skin.osk" . The one rule people break: no nested folder
The files must be at the root of the archive:
My Skin.osk ├── skin.ini ├── hitcircle.png ├── hitcircle@2x.png ├── cursor.png └── ... If you zip the folder instead of its contents you get My Skin.osk/My Skin/skin.ini. Depending on the client this imports as an empty skin or the default skin with a strange name. Zip from inside the folder.
Naming
When imported, the skin folder name is taken from the archive file name, not from the Name: key in skin.ini. Keep both the same to avoid confusion in the skin selector.
What to leave out
- Editor leftovers:
.psd,.kra,Thumbs.db,.DS_Store. - Duplicate copies such as
hitcircle (1).png. - Unused animation frames — osu! loads every numbered frame it finds, which can make a skin feel heavy.
Quick validation script
import zipfile, sys z = zipfile.ZipFile(sys.argv[1]) names = z.namelist() if any('/' in n.rstrip('/') for n in names if n.lower().endswith('skin.ini')): print('skin.ini is inside a subfolder - repack from inside the folder') if not any(n.lower() == 'skin.ini' for n in names): print('no skin.ini at root') junk = [n for n in names if n.endswith(('.psd', '.DS_Store', 'Thumbs.db'))] print('junk files:', junk or 'none') Importing
Double-click the .osk or drag it onto the osu! window; both stable and lazer accept it. Step-by-step instructions with screenshots are on the osuskins.org install guide. If you're looking for skins to test your tooling with, the osuskins.org library and its best skins list have hundreds of real-world archives — including messy ones.

