initial commit
5
.gitignore
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
/_/
|
||||
/dist/
|
||||
__pycache__/
|
||||
*.osk
|
||||
.mypy_cache/
|
3
.vscode/extensions.json
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"recommendations": ["matangover.mypy"]
|
||||
}
|
16
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"cSpell.words": [
|
||||
"approachcircle",
|
||||
"chdir",
|
||||
"flyingtuna",
|
||||
"followpoint",
|
||||
"hitcircle",
|
||||
"lazer",
|
||||
"mypy",
|
||||
"scoreentry",
|
||||
"svgs",
|
||||
"vaxei"
|
||||
],
|
||||
"mypy.runUsingActiveInterpreter": true,
|
||||
"python.linting.mypyEnabled": true
|
||||
}
|
65
README.md
Normal file
|
@ -0,0 +1,65 @@
|
|||
# osu-pomp-skin
|
||||
|
||||
My custom skin for the game [osu!](osu.ppy.sh) (yes, the exclamation mark is part of the name).
|
||||
|
||||
## Characteristics
|
||||
|
||||
- semi-transparent approach circles to make reading high [AR](https://osu.ppy.sh/wiki/en/Beatmapping/Approach_rate) easier
|
||||
- minimalism
|
||||
- not even a health bar
|
||||
- osu!standard only
|
||||
- centered acc meter
|
||||
- made specifically for osu!lazer
|
||||
- `@2x` images only
|
||||
|
||||
## Commands
|
||||
|
||||
> Assumes that these commands are called from the project root
|
||||
|
||||
Build skin:
|
||||
|
||||
```bash
|
||||
python src
|
||||
```
|
||||
|
||||
## What's in it?
|
||||
|
||||
Since all images are [HD images](https://github.com/ppy/osu-wiki/blob/master/wiki/Skinning/FAQ/en.md#hd-images), `@2x` postfix is omitted and will be added automatically during the build process.
|
||||
|
||||
### approachcircle
|
||||
|
||||
### combo
|
||||
|
||||
### cursor
|
||||
|
||||
### followpoint
|
||||
|
||||
### hit
|
||||
|
||||
### hitcircle
|
||||
|
||||
### score
|
||||
|
||||
### scoreentry
|
||||
|
||||
### slider
|
||||
|
||||
### spinner
|
||||
|
||||
## Resources
|
||||
|
||||
- [osu! wiki page about skinning](https://osu.ppy.sh/wiki/en/Skinning)
|
||||
- some assets are from [vaxei's skin](https://drive.google.com/file/d/1JRDbxtEVFYMgt9ls4rvIRs2v0IfBddFO/view)
|
||||
- some assets are from [flyingtuna's skin](https://drive.google.com/file/d/1SVtUUvo4o2DUwQ1Pf2Xb0v4eDblvvovq/view)
|
||||
- some assets are from [whitecat's skin](https://drive.google.com/file/d/1A9Ktx7MY-UP5iOGTTHsyQP622zDOKqfe/view)
|
||||
|
||||
## License
|
||||
|
||||
The source code of this project\* is available under the MIT License.
|
||||
|
||||
\*: excluding files in the [`fonts`](./fonts) and the [`resource`](./resource) directory.
|
||||
|
||||
Fonts:
|
||||
|
||||
- [Source Code Pro](https://fonts.google.com/specimen/Source+Code+Pro): Open Font License (OFL)
|
||||
- [Noto Sans](https://fonts.google.com/noto/specimen/Noto+Sans): Open Font License (OFL)
|
BIN
fonts/NotoSans-Regular.ttf
Normal file
BIN
fonts/SourceCodePro-Light.ttf
Normal file
BIN
resource/approachcircle/approachcircle.png
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
resource/etc/1x1.png
Normal file
After Width: | Height: | Size: 73 B |
BIN
resource/hit/hit0.png
Normal file
After Width: | Height: | Size: 8.3 KiB |
BIN
resource/hit/hit100.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
resource/hit/hit50.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
resource/hitcircle/hitcircle.png
Normal file
After Width: | Height: | Size: 3.7 KiB |
BIN
resource/hitcircle/hitcircleoverlay.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
resource/hitcircle/hitcircleselect.png
Normal file
After Width: | Height: | Size: 71 KiB |
BIN
resource/slider/reversearrow@2x.png
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
resource/slider/sliderb.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
1
resource/slider/sliderendcircle.png
Symbolic link
|
@ -0,0 +1 @@
|
|||
../etc/1x1.png
|
BIN
resource/slider/sliderfollowcircle@2x.png
Normal file
After Width: | Height: | Size: 35 KiB |
BIN
resource/slider/sliderscorepoint.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
1
resource/spinner/spinner-approachcircle.png
Symbolic link
|
@ -0,0 +1 @@
|
|||
../etc/1x1.png
|
1
resource/spinner/spinner-background.png
Symbolic link
|
@ -0,0 +1 @@
|
|||
../etc/1x1.png
|
BIN
resource/spinner/spinner-bottom.png
Normal file
After Width: | Height: | Size: 3.7 KiB |
BIN
resource/spinner/spinner-circle.png
Normal file
After Width: | Height: | Size: 87 KiB |
1
resource/spinner/spinner-glow.png
Symbolic link
|
@ -0,0 +1 @@
|
|||
../etc/1x1.png
|
BIN
resource/spinner/spinner-middle.png
Normal file
After Width: | Height: | Size: 18 KiB |
1
resource/spinner/spinner-osu.png
Symbolic link
|
@ -0,0 +1 @@
|
|||
../etc/1x1.png
|
BIN
resource/spinner/spinner-rpm.png
Normal file
After Width: | Height: | Size: 4.6 KiB |
1
resource/spinner/spinner-spin.png
Symbolic link
|
@ -0,0 +1 @@
|
|||
../etc/1x1.png
|
1
resource/spinner/spinner-top.png
Symbolic link
|
@ -0,0 +1 @@
|
|||
../etc/1x1.png
|
41
resource/static/skin.ini
Normal file
|
@ -0,0 +1,41 @@
|
|||
[General]
|
||||
Name: POMP
|
||||
Author: developomp
|
||||
Profile: https://osu.ppy.sh/users/15691003
|
||||
Version: 2.7
|
||||
AnimationFramerate: 60
|
||||
|
||||
// Cursor
|
||||
|
||||
CursorExpand: 0
|
||||
CursorRotate: 0
|
||||
CursorTrailRotate: 0
|
||||
|
||||
// Slider
|
||||
|
||||
AllowSliderBallTint: 1
|
||||
|
||||
[Colours]
|
||||
|
||||
// Combo Colors
|
||||
|
||||
Combo1: 164, 100, 240 // #a464f0
|
||||
Combo2: 230, 110, 150 // #e66e96
|
||||
Combo3: 100, 200, 200 // #64c8c8
|
||||
Combo4: 130, 120, 255 // #8278ff
|
||||
SliderBorder: 85, 84, 102 // #555466
|
||||
SliderTrackOverride: 30, 30, 41 // #1e1e29
|
||||
|
||||
[Fonts]
|
||||
|
||||
// HitCircle
|
||||
|
||||
HitCircleOverlap: 15
|
||||
|
||||
// Score
|
||||
|
||||
ScoreOverlap: 5
|
||||
|
||||
// Combo
|
||||
|
||||
ComboOverlap: 10
|
35
src/__main__.py
Normal file
|
@ -0,0 +1,35 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
from os import chdir, getcwd
|
||||
from os.path import dirname, realpath, isdir, join, realpath
|
||||
|
||||
from log import BOLD, END, INVERSE, err
|
||||
import util
|
||||
|
||||
|
||||
def welcome():
|
||||
print(
|
||||
f"{BOLD}────────────────────{END}{INVERSE} POMP's osu! skin {END}{BOLD}────────────────────{END}"
|
||||
)
|
||||
|
||||
|
||||
def initialize():
|
||||
# move to project root
|
||||
chdir(realpath(join(dirname(realpath(__file__)), "..")))
|
||||
|
||||
print(f"working directory: {BOLD}{getcwd()}{END}")
|
||||
print()
|
||||
|
||||
# crete dist directory
|
||||
util.smart_make_dist_dir()
|
||||
|
||||
|
||||
def main():
|
||||
welcome()
|
||||
initialize()
|
||||
|
||||
# create POMP.osk
|
||||
util.make_osk()
|
||||
|
||||
|
||||
main()
|
13
src/log.py
Normal file
|
@ -0,0 +1,13 @@
|
|||
RED = "\033[91m"
|
||||
GREEN = "\033[92m"
|
||||
INVERSE = "\033[7m"
|
||||
BOLD = "\033[1m"
|
||||
END = "\033[0m"
|
||||
|
||||
|
||||
def log(message):
|
||||
print(f"{GREEN}{BOLD} LOG{END}{GREEN}: {message}{END}")
|
||||
|
||||
|
||||
def err(message):
|
||||
print(f"{RED}{BOLD} ERROR{END}{RED}: {message}{END}")
|
0
src/make.py
Normal file
85
src/osu_frames.py
Executable file
|
@ -0,0 +1,85 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
from argparse import ArgumentParser, RawDescriptionHelpFormatter
|
||||
from glob import glob
|
||||
from time import sleep
|
||||
from os import rename
|
||||
from os.path import basename, join
|
||||
from shutil import copyfile
|
||||
from re import search
|
||||
|
||||
|
||||
def increment_files(path, pattern, dry_run):
|
||||
deliminator = "-"
|
||||
files = sorted(glob(join(path, pattern)))
|
||||
print("Changing", len(files), "file names")
|
||||
|
||||
for index, file in enumerate(files):
|
||||
file_name = basename(file)
|
||||
|
||||
file_name_parts = file_name.split(deliminator)
|
||||
|
||||
prefix = file_name_parts[0]
|
||||
postfix = file_name_parts[1]
|
||||
number_regex = search(r"\d+", postfix)
|
||||
number_span = number_regex.span()
|
||||
|
||||
new_file_name = join(
|
||||
path, f"{prefix}{deliminator}{str(index)}{postfix[number_span[1]:]}"
|
||||
)
|
||||
|
||||
if dry_run:
|
||||
print(f"{file} -> {new_file_name}")
|
||||
else:
|
||||
rename(file, new_file_name)
|
||||
sleep(0.1)
|
||||
|
||||
|
||||
def make_100k_from_100(path, dry_run):
|
||||
files = sorted(glob(join(path, "hit100*")))
|
||||
print("Changing", len(files), "file names")
|
||||
|
||||
for file in files:
|
||||
file_name = basename(file)
|
||||
|
||||
new_file_name = join(path, f"hit100k{file_name[6:]}")
|
||||
|
||||
if dry_run:
|
||||
print(f"{file} -> {new_file_name}")
|
||||
else:
|
||||
copyfile(file, new_file_name)
|
||||
sleep(0.1)
|
||||
|
||||
|
||||
def parseargs():
|
||||
parser = ArgumentParser(
|
||||
formatter_class=RawDescriptionHelpFormatter,
|
||||
description="Increment file prefixes starting at a specific index.",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"path",
|
||||
help="where the files are located",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-p",
|
||||
"--pattern",
|
||||
help="glob pattern of files that will be affected",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-d",
|
||||
"--dry-run",
|
||||
action="store_true",
|
||||
help="print the results instead of renaming the files",
|
||||
)
|
||||
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
args = parseargs()
|
||||
|
||||
make_100k_from_100(args.path, args.dry_run)
|
||||
# increment_files(args.path, args.pattern, args.dry_run)
|
32
src/util.py
Executable file
|
@ -0,0 +1,32 @@
|
|||
import os
|
||||
import shutil
|
||||
|
||||
from log import log, BOLD, END, GREEN
|
||||
|
||||
DIST_DIR = "./dist"
|
||||
|
||||
|
||||
def smart_make_dist_dir():
|
||||
"""Create `dist` directory if it doesn't exist already"""
|
||||
|
||||
log(f"Creating empty {BOLD}dist{END}{GREEN} directory")
|
||||
|
||||
if os.path.isdir(DIST_DIR):
|
||||
try:
|
||||
shutil.rmtree(DIST_DIR)
|
||||
except OSError as err:
|
||||
print("Error: %s : %s" % (DIST_DIR, err.strerror))
|
||||
os.mkdir(DIST_DIR)
|
||||
|
||||
|
||||
def make_osk():
|
||||
"""zip the `dist` directory and save it to `POMP.osk`"""
|
||||
|
||||
log(f"Creating {BOLD}POMP.osk")
|
||||
|
||||
shutil.make_archive("POMP", "zip", DIST_DIR)
|
||||
|
||||
if os.path.isfile("POMP.zip"):
|
||||
os.rename("POMP.zip", "POMP.osk")
|
||||
else:
|
||||
print_error("cannot find zip file to convert to osk file :(")
|