diff --git a/.gitignore b/.gitignore
index 2386917..7eaaf84 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,3 @@
-assets/backups/*
-node_modules/*
+node_modules
+backups
package*.json
\ No newline at end of file
diff --git a/README.md b/README.md
index 3389399..3d9d2ba 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,8 @@
# Low cost sprite based V-Tubing
-A lightweight script, that uses sprites and allows you to have a VTube character you can control with Stream Deck and Touch Portal buttons.
-Working on a video demo.
+A lightweight Sprite based VTube environment, that you can control with Stream Deck and Touch Portal buttons.
+
+If you like de content, consider [buying me a ☕](https://www.buymeacoffee.com/mazeakin).
## Requirements
@@ -11,12 +12,19 @@ Working on a video demo.
## Instalation/Usage
+#### If you don't want to fiddle with any of the manual parts, here is a [Windows version](https://github.com/Mazeakin/Maze-Static-VTube/releases) you can just download and use.
+
First, install the required Node dependencies in the project folder:
`npm i ws socket.io express`
Then, run the main script:
`node app.js`
+## Making it visible on OBS
+
+Simply add the `http://127.0.0.1:3000/` address as OBS Browser source.
+That's all.
+
## Using with Stream Deck
1. Point to the (running) webservice;
@@ -38,17 +46,9 @@ Then, run the main script:
- Use `last` to jump to the last frame recorded in the `frames.json` file.
- Use `random` to jump to a random frame recorded in the `frames.json` file.
-## Making it visible on OBS
-
-Simply add the `http://127.0.0.1:3000/` address as OBS Browser source.
-That's all.
-
## Character editor.
-By opening the `http://127.0.0.1:3000/map` URL (after starting the server), you'll find a character editor.
-
-> I am still working on a way to streamline the process of changing your spritesheet image (with an "upload" button).
-> But, for now, you need to replace the `assets/character.png` file by hand.
+By opening the `http://127.0.0.1:3000/map` URL (after starting the server) or by opening the [APP](https://github.com/Mazeakin/Maze-Static-VTube/releases), you'll find a character editor.
![map-1.png](tutorial/map-1.png)
@@ -61,25 +61,29 @@ By opening the `http://127.0.0.1:3000/map` URL (after starting the server), you'
- Reorganize frames (drag and drop).
- Click sprites in the timeline to quickly navigate and preview.
- Toggle the timeline.
-- Save (replaces your current `frames.json` file, but makes a backup once a day inside the `assets/backups` folder).
+- Save (replaces your current `frames.json` file, but makes a backup once a day inside the `backups` folder).
## Mapping the character by hand
-1. You'll need the `X` and `Y` coordinates, plus the `width` and `height` of each frame, in order to map it correctly (use CSS background-position as reference);
-2. Then, proceed to fill the `frames` array inside the `assets/frames.json` file.
+_First, you are brave._
+
+- You'll need the `X` and `Y` coordinates, plus the `width` and `height` of each frame, in order to map it correctly (use CSS background-position as reference, top left is `X-0` and `Y-0`);
+- Then, proceed to fill the `frames` array inside the `assets/frames.json` file.
-## Replacing a spritesheet
+## Replacing a spritesheet by hand
Just replace the `assets/character.png` file.
## Todo
-- ⬜ Support uploading new spritesheet to the editor.
+- 🟨 Code cleanup.
- ⬜ Make replacing a frame in the editor less annoying.
- ⬜ Support for small movement when microphone is detected.
- ⬜ Support for loop through predefined frames when microphone is detected.
- ⬜ Support for second set of frames for mouth movement when microphone is detected.
- ⬜ Support for idle set of frames.
+- ✅ Support for uploading new spritesheet to the editor.
+- ✅ Character preview inside the editor.
- ✅ Character editor.
- ✅ "first", "last" and "random" actions.
- ✅ "flip" and "unflip" actions.
@@ -110,7 +114,7 @@ A: Yes. But I'd appreciate if you shared your customization with everyone else.
Q: _I see a lot of unused code. Are you adding new stuff?_
A: Yes. I may send commits with placeholder code I am working on.
-Q: _Can I message you on if I have issues or suggestions?_
+Q: _Can I message you if I have issues or suggestions?_
A: Sure. You can open an issue here, or message me on [Discord](https://discord.gg/eYfSNQT) or [Twitter](https://twitter.com/Mazeakin).
## Credits
@@ -120,6 +124,5 @@ A: Sure. You can open an issue here, or message me on [Discord](https://discord.
## Known bugs
-- One to two pixels as margin error are randomly added/removed when saving from the editor.
+- One to two pixels as margin error are randomly added/removed when saving from the editor. That means you need to fiddle with positions, till you get the perfect frame.
- The sprite frame actually working flawless (despite the item above) in the animation screen is actually a bug.
-- That means you need to fidget with positions, till you get the perfect frame.
diff --git a/app.js b/app.js
index e593a51..efd0ba9 100644
--- a/app.js
+++ b/app.js
@@ -6,14 +6,17 @@ const { Server } = require("socket.io")
const io = new Server(server)
const WebSocket = require("ws")
const fs = require("fs")
+const bodyParser = require("body-parser")
+app.use(bodyParser.json({ limit: "50mb" }))
+app.use(bodyParser.urlencoded({ limit: "50mb", extended: true }))
app.use(express.json())
app.use(express.urlencoded({ extended: true }))
app.use("/assets", express.static("assets"))
app.get("/", (req, res) => {
- res.sendFile(__dirname + "/pages/index.htm")
+ res.sendFile(__dirname + "/pages/player.htm")
})
app.get("/character", (req, res) => {
@@ -27,8 +30,8 @@ app.get("/map", (req, res) => {
app.post("/map", (req, res) => {
try {
- if (!fs.existsSync("assets/backups")) {
- fs.mkdirSync("assets/backups")
+ if (!fs.existsSync("backups")) {
+ fs.mkdirSync("backups")
}
var d = new Date()
@@ -36,10 +39,16 @@ app.post("/map", (req, res) => {
"0" + d.getDate()
).slice(-2)}`
- if (!fs.existsSync(`assets/backups/frames-${date}.json`)) {
+ if (!fs.existsSync(`backups/${date}-frames.json`)) {
fs.copyFile(
"assets/frames.json",
- `assets/backups/frames-${date}.json`,
+ `backups/${date}-frames.json`,
+ (err) => {}
+ )
+
+ fs.copyFile(
+ "assets/character.png",
+ `backups/${date}-character.png`,
(err) => {}
)
}
@@ -47,13 +56,32 @@ app.post("/map", (req, res) => {
console.error(err)
}
- fs.writeFile("assets/frames.json", JSON.stringify(req.body), (err) => {
- if (err) {
- console.error(err)
- res.send("err")
- return
+ if (req.body.spritesheet) {
+ const spritesheet = req.body.spritesheet.replace(
+ /^data:image\/png;base64,/,
+ ""
+ )
+
+ fs.writeFile("assets/character.png", spritesheet, "base64", function (err) {
+ if (err) {
+ console.error(err)
+ res.send("err")
+ return
+ }
+ })
+ }
+
+ fs.writeFile(
+ "assets/frames.json",
+ JSON.stringify({ frames: req.body.frames }),
+ (err) => {
+ if (err) {
+ console.error(err)
+ res.send("err")
+ return
+ }
}
- })
+ )
res.json({ ok: true })
})
diff --git a/assets/character-demo.png b/assets/character-demo.png
new file mode 100644
index 0000000..373ec88
Binary files /dev/null and b/assets/character-demo.png differ
diff --git a/assets/frames.json b/assets/frames.json
index 9abc158..1fc1181 100644
--- a/assets/frames.json
+++ b/assets/frames.json
@@ -1 +1,8 @@
-{"frames":[{"w":"258px","h":"437px","p":"-56px -76.99999237060547px"},{"w":"268px","h":"437px","p":"-314px -76.99999237060547px"},{"w":"360px","h":"437px","p":"-573px -77.99999237060547px"}]}
\ No newline at end of file
+{
+ "frames": [
+ { "w": "260px", "h": "439px", "p": "-56px -76.99999237060547px" },
+ { "w": "270px", "h": "439px", "p": "-314px -76.99999237060547px" },
+ { "w": "362px", "h": "439px", "p": "-573px -77.99999237060547px" },
+ { "w": "253px", "h": "132px", "p": "-971.5px -206.50000762939453px" }
+ ]
+}
diff --git a/pages/character-map.htm b/pages/character-map.htm
index 51acf65..0f24bdb 100644
--- a/pages/character-map.htm
+++ b/pages/character-map.htm
@@ -1,13 +1,10 @@