Merge pull request #69 from bs-community/new-demo

new demo page & auto deploy to GitHub Pages
This commit is contained in:
yushijinhun 2020-08-18 12:58:46 +08:00
commit a1c4a2b576
No known key found for this signature in database
GPG Key ID: 5BC167F73EA558E4
19 changed files with 3440 additions and 12238 deletions

View File

@ -1,6 +1,6 @@
name: CI
on: [push]
on: [push, pull_request]
jobs:
test:
@ -9,8 +9,6 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: npm build & test
run: |
npm install
npm run build
npm test
- run: npm install
- run: npm run build
- run: npm test

31
.github/workflows/deploy-ghpages.yaml vendored Normal file
View File

@ -0,0 +1,31 @@
name: Deploy to GitHub Pages
on:
push:
branches:
- master
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: npm install
- run: npm run build
- run: npm test
- name: Prepare files
run: |
cp -r examples public
cp -r bundles public/js
build_commit="${{ github.sha }}"
build_time=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
sed -Ez \
-e 's#\.\./bundles/skinview3d\.bundle\.js#js/skinview3d.bundle.js#g' \
-e 's#\{\{build_commit\}\}#'$build_commit'#g' \
-e 's#\{\{build_time\}\}#'$build_time'#g' \
-e 's#<!--%%deploy_only%%(.*)-->#\1#g' \
-i public/index.html
- uses: crazy-max/ghaction-github-pages@v2
with:
target_branch: gh-pages
build_dir: public
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

1
.gitignore vendored
View File

@ -62,3 +62,4 @@ libs/
_ignore/
.DS_Store
.rpt2_cache
public/

View File

@ -1,4 +0,0 @@
module.exports = {
stories: ['../examples/stories/**/*.stories.js'],
addons: ['@storybook/addon-knobs/register']
};

View File

@ -1,3 +0,0 @@
{
"type": "commonjs"
}

View File

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

Before

Width:  |  Height:  |  Size: 689 B

After

Width:  |  Height:  |  Size: 689 B

View File

Before

Width:  |  Height:  |  Size: 589 B

After

Width:  |  Height:  |  Size: 589 B

View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

Before

Width:  |  Height:  |  Size: 278 KiB

After

Width:  |  Height:  |  Size: 278 KiB

View File

Before

Width:  |  Height:  |  Size: 109 KiB

After

Width:  |  Height:  |  Size: 109 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

415
examples/index.html Normal file
View File

@ -0,0 +1,415 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>skinview3d</title>
<style>
body {
font-family: "Helvetica Neue", "Helvetica", "Arial", "sans-serif";
width: max-content;
}
h1 {
font-size: 1.25em;
}
h2 {
font-size: 1em;
}
h1,
h2 {
margin-bottom: 0;
}
input[type="number"] {
width: 60px;
}
.control {
display: inline-block;
margin-right: 10px;
}
.control-section {
margin-left: 10px;
}
.control-section>h1,
.control-section>h2 {
margin-left: -10px;
}
table {
border-collapse: collapse;
}
table td,
table th {
border: 1px black dashed;
text-align: left;
width: 50px;
}
thead th {
border-top: unset;
}
tbody tr:last-child td,
tbody tr:last-child th {
border-bottom: unset;
}
table th:first-child,
table td:first-child {
border-left: unset;
}
table th:last-child,
table td:last-child {
border-right: unset;
}
table td input[type="checkbox"] {
vertical-align: middle;
margin: 0;
width: 100%;
}
footer {
margin-top: 10px;
padding-top: 10px;
border-top: 1px grey solid;
}
</style>
</head>
<body>
<div id="skin_container"></div>
<div class="controls">
<button id="reset_all" type="button" class="control">Reset All</button>
<div class="control-section">
<h1>Canvas Size</h1>
<div class="control">
<label for="canvas_width">Width:</label>
<input id="canvas_width" type="number" value="300">
</div>
<div class="control">
<label for="canvas_height">Height:</label>
<input id="canvas_height" type="number" value="300">
</div>
</div>
<div class="control-section">
<h1>Animation</h1>
<div class="control">
<label for="global_animation_speed">Global Speed:</label>
<input id="global_animation_speed" type="number" value="1" step="0.1">
</div>
<button id="animation_pause_resume" type="button" class="control">Pause / Resume</button>
<div>
<h2>Rotate</h2>
<div class="control">
<input id="rotate_animation" type="checkbox">
<label for="rotate_animation">Enable</label>
</div>
<div class="control">
<label for="rotate_animation_speed">Speed:</label>
<input id="rotate_animation_speed" type="number" value="1" step="0.1">
</div>
</div>
<div>
<h2>Walk / Run</h2>
<div class="control">
<input type="radio" id="primary_animation_none" name="primary_animation" value="" checked>
<label for="primary_animation_none">None</label>
<input type="radio" id="primary_animation_walk" name="primary_animation" value="walk">
<label for="primary_animation_walk">Walk</label>
<input type="radio" id="primary_animation_run" name="primary_animation" value="run">
<label for="primary_animation_run">Run</label>
</div>
<div class="control">
<label for="primary_animation_speed">Speed:</label>
<input id="primary_animation_speed" type="number" value="1" step="0.1">
</div>
</div>
</div>
<div class="control-section">
<h1>Mouse Control</h1>
<div class="control">
<input type="checkbox" id="control_rotate" checked>
<label for="control_rotate">Enable Rotate</label>
<input type="checkbox" id="control_zoom" checked>
<label for="control_zoom">Enable Zoom</label>
<input type="checkbox" id="control_pan">
<label for="control_pan">Enable Pan</label>
</div>
</div>
<div class="control-section">
<h1>Skin Layers</h1>
<table id="layers_table" class="control">
<!-- table contents are generated using javascript -->
</table>
</div>
<div class="control-section">
<h1>Textures</h1>
<div>
<div class="control">
<label for="skin_url">Skin URL:</label>
<input id="skin_url" type="text" value="img/1_8_texturemap_redux.png" placeholder="none"
list="default_skins">
<datalist id="default_skins">
<option value="img/1_8_texturemap_redux.png">
<option value="img/Hacksore.png">
<option value="img/haka.png">
<option value="img/hatsune_miku.png">
<option value="img/ironman_hd.png">
<option value="img/sethbling.png">
</datalist>
<input id="skin_url_upload" type="file" accept="image/*" style="display: none;">
<button type="button" class="control"
onclick="document.getElementById('skin_url_upload').click();">Browse...</button>
</div>
<div class="control">
<label for="skin_model">Model:</label>
<select id="skin_model" value="auto-detect">
<option value="auto-detect">Auto detect</option>
<option value="default">Default</option>
<option value="slim">Slim</option>
</select>
</div>
</div>
<div>
<div class="control">
<label for="cape_url">Cape URL:</label>
<input id="cape_url" type="text" value="" placeholder="none" list="default_capes">
<datalist id="default_capes">
<option value="">
<option value="img/cape.png">
<option value="img/mojang_cape.png">
<option value="img/hd_cape.png">
</datalist>
<input id="cape_url_upload" type="file" accept="image/*" style="display: none;">
<button type="button" class="control"
onclick="document.getElementById('cape_url_upload').click();">Browse...</button>
</div>
</div>
</div>
</div>
<footer>
<div>
GitHub: <a href="https://github.com/bs-community/skinview3d">bs-community/skinview3d</a>
</div>
<!--%%deploy_only%%
<div>
Built from
commit <a href="https://github.com/bs-community/skinview3d/commit/{{build_commit}}">{{build_commit}}</a>
at <time datetime="{{build_time}}">{{build_time}}</time>
</div>
-->
</footer>
<script src="../bundles/skinview3d.bundle.js"></script>
<script>
const skinParts = ["head", "body", "rightArm", "leftArm", "rightLeg", "leftLeg"];
const skinLayers = ["innerLayer", "outerLayer"];
const availableAnimations = {
walk: skinview3d.WalkingAnimation,
run: skinview3d.RunningAnimation
};
let skinViewer;
let oribitControl;
let rotateAnimation;
let primaryAnimation;
function reloadSkin() {
const input = document.getElementById("skin_url");
const url = input.value;
if (url === "") {
skinViewer.loadSkin(null);
input.setCustomValidity("");
} else {
skinViewer.loadSkin(url, document.getElementById("skin_model").value)
.then(() => input.setCustomValidity(""))
.catch(e => {
input.setCustomValidity("Image can't be loaded.");
console.error(e);
});
}
}
function reloadCape() {
const input = document.getElementById("cape_url");
const url = input.value;
if (url === "") {
skinViewer.loadCape(null);
input.setCustomValidity("");
} else {
skinViewer.loadCape(url)
.then(() => input.setCustomValidity(""))
.catch(e => {
input.setCustomValidity("Image can't be loaded.");
console.error(e);
});
}
}
function initializeLayersTable() {
const table = document.getElementById("layers_table");
const thead = document.createElement("thead");
table.appendChild(thead);
const rowHead = document.createElement("tr");
rowHead.appendChild(document.createElement("th"));
thead.appendChild(rowHead);
for (const part of skinParts) {
const cellHead = document.createElement("th");
cellHead.innerText = part;
rowHead.appendChild(cellHead);
}
const tbody = document.createElement("tbody");
table.appendChild(tbody);
for (const layer of skinLayers) {
const row = document.createElement("tr");
tbody.appendChild(row);
const cellLayer = document.createElement("th");
cellLayer.innerText = layer;
row.appendChild(cellLayer);
for (const part of skinParts) {
const cell = document.createElement("td");
row.appendChild(cell);
const checkbox = document.createElement("input");
checkbox.type = "checkbox";
checkbox.dataset.layer = layer;
checkbox.dataset.part = part;
checkbox.checked = true;
cell.appendChild(checkbox);
}
}
}
function initializeControls() {
document.getElementById("canvas_width").addEventListener("change", e => skinViewer.width = e.target.value);
document.getElementById("canvas_height").addEventListener("change", e => skinViewer.height = e.target.value);
document.getElementById("global_animation_speed").addEventListener("change", e => skinViewer.animations.speed = e.target.value);
document.getElementById("animation_pause_resume").addEventListener("click", () => skinViewer.animations.paused = !skinViewer.animations.paused);
document.getElementById("rotate_animation").addEventListener("change", e => {
if (e.target.checked && rotateAnimation === null) {
rotateAnimation = skinViewer.animations.add(skinview3d.RotatingAnimation);
rotateAnimation.speed = document.getElementById("rotate_animation_speed").value;
} else if (!e.target.checked && rotateAnimation !== null) {
rotateAnimation.resetAndRemove();
rotateAnimation = null;
}
});
document.getElementById("rotate_animation_speed").addEventListener("change", e => {
if (rotateAnimation !== null) {
rotateAnimation.speed = e.target.value;
}
});
for (const el of document.querySelectorAll('input[type="radio"][name="primary_animation"]')) {
el.addEventListener("change", e => {
if (primaryAnimation !== null) {
primaryAnimation.resetAndRemove();
primaryAnimation = null;
}
if (e.target.value !== "") {
primaryAnimation = skinViewer.animations.add(availableAnimations[e.target.value]);
primaryAnimation.speed = document.getElementById("primary_animation_speed").value;
}
});
}
document.getElementById("primary_animation_speed").addEventListener("change", e => {
if (primaryAnimation !== null) {
primaryAnimation.speed = e.target.value;
}
});
document.getElementById("control_rotate").addEventListener("change", e => oribitControl.enableRotate = e.target.checked);
document.getElementById("control_zoom").addEventListener("change", e => oribitControl.enableZoom = e.target.checked);
document.getElementById("control_pan").addEventListener("change", e => oribitControl.enablePan = e.target.checked);
for (const part of skinParts) {
for (const layer of skinLayers) {
document.querySelector(`#layers_table input[type="checkbox"][data-part="${part}"][data-layer="${layer}"]`)
.addEventListener("change", e => skinViewer.playerObject.skin[part][layer].visible = e.target.checked);
}
}
const skinReader = new FileReader();
skinReader.addEventListener("load", e => {
document.getElementById("skin_url").value = skinReader.result;
reloadSkin();
});
document.getElementById("skin_url_upload").addEventListener("change", e => {
const file = e.target.files[0];
if (file !== undefined) {
skinReader.readAsDataURL(file);
}
});
const capeReader = new FileReader();
capeReader.addEventListener("load", e => {
document.getElementById("cape_url").value = capeReader.result;
reloadCape();
});
document.getElementById("cape_url_upload").addEventListener("change", e => {
const file = e.target.files[0];
if (file !== undefined) {
capeReader.readAsDataURL(file);
}
});
document.getElementById("skin_url").addEventListener("change", () => reloadSkin());
document.getElementById("skin_model").addEventListener("change", () => reloadSkin());
document.getElementById("cape_url").addEventListener("change", () => reloadCape());
document.getElementById("reset_all").addEventListener("click", () => {
skinViewer.dispose();
initializeViewer();
});
}
function initializeViewer() {
skinViewer = new skinview3d.SkinViewer(document.getElementById("skin_container"));
oribitControl = skinview3d.createOrbitControls(skinViewer);
rotateAnimation = null;
primaryAnimation = null;
skinViewer.width = document.getElementById("canvas_width").value;
skinViewer.height = document.getElementById("canvas_height").value;
skinViewer.animations.speed = document.getElementById("global_animation_speed").value;
if (document.getElementById("rotate_animation").checked) {
rotateAnimation = skinViewer.animations.add(skinview3d.RotatingAnimation);
rotateAnimation.speed = document.getElementById("rotate_animation_speed").value;
}
const primaryAnimationName = document.querySelector('input[type="radio"][name="primary_animation"]:checked').value;
if (primaryAnimationName !== "") {
primaryAnimation = skinViewer.animations.add(availableAnimations[primaryAnimationName]);
primaryAnimation.speed = document.getElementById("primary_animation_speed").value;
}
oribitControl.enableRotate = document.getElementById("control_rotate").checked;
oribitControl.enableZoom = document.getElementById("control_zoom").checked;
oribitControl.enablePan = document.getElementById("control_pan").checked;
for (const part of skinParts) {
for (const layer of skinLayers) {
skinViewer.playerObject.skin[part][layer].visible =
document.querySelector(`#layers_table input[type="checkbox"][data-part="${part}"][data-layer="${layer}"]`).checked;
}
}
reloadSkin();
reloadCape();
}
initializeLayersTable();
initializeControls();
initializeViewer();
</script>
</body>
</html>

View File

@ -1,100 +0,0 @@
/* eslint-disable */
import * as skinview3d from "../..";
import { withKnobs, radios, number } from "@storybook/addon-knobs";
export default {
title: "Skinview3d",
decorators: [withKnobs],
};
let currentAnimation;
const createViewer = () => {
const element = document.createElement("div");
const viewer = new skinview3d.SkinViewer(element, {
width: 300,
height: 400,
skin: "textures/1_8_texturemap_redux.png",
});
console.log(viewer);
// Control objects with your mouse!
const control = skinview3d.createOrbitControls(viewer);
control.enableRotate = true;
control.enableZoom = false;
control.enablePan = false;
// Add an animation
currentAnimation = viewer.animations.add(skinview3d.WalkingAnimation);
return { viewer, element };
};
let { viewer, element } = createViewer();
export const Basic = () => {
// reset
let { viewer, element } = createViewer();
if (currentAnimation) {
currentAnimation.remove();
}
return element;
};
export const Animation = () => {
if (currentAnimation) {
currentAnimation.remove();
}
const animationMap = {
Walk: skinview3d.WalkingAnimation,
Run: skinview3d.RunningAnimation,
Rotate: skinview3d.RotatingAnimation,
};
const animationKey = radios("Animations", Object.keys(animationMap), "Run");
currentAnimation = viewer.animations.add(animationMap[animationKey]);
const label = "Speed";
const defaultValue = 0.5;
const options = {
range: true,
min: 0.1,
max: 2,
step: 0.01,
};
const value = number(label, defaultValue, options);
currentAnimation.speed = value;
return element;
};
export const Textures = () => {
const skinOptions = {
"1.8 Skin": "1_8_texturemap_redux",
"Classic Skin": "Hacksore",
"HD Skin": "ironman_hd",
};
const skinUrl = radios("Skin Textures", skinOptions, "1_8_texturemap_redux");
const capeOptions = {
None: "none",
"Classic Cape": "cape",
"HD Cape": "hd_cape",
};
const capeUrl = radios("Cape Textures", capeOptions, "none");
viewer.loadSkin(`textures/${skinUrl}.png`);
if (capeUrl === "none") {
viewer.loadCape(null);
} else {
viewer.loadCape(`textures/${capeUrl}.png`);
}
return element;
};

View File

@ -1,3 +0,0 @@
# Example textures
Assets in this directory are copyrighted by their original author(s), and are **OUTSIDE** the scope of skinview3d's license.
These files are intended for demo use. If you are the copyright owner and disagree with our use, please submit an issue and we will remove the related files.

15102
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -13,8 +13,8 @@
"test": "npm run test:lint",
"dev:watch:modules": "tsc -w --preserveWatchOutput --declaration --sourceMap --outDir libs -p .",
"dev:watch:bundles": "rollup -w --no-watch.clearScreen -c",
"dev:storybook": "start-storybook -s ./examples -p 6006",
"dev": "npm-run-all --parallel dev:watch:modules dev:storybook",
"dev:serve": "ws",
"dev": "npm-run-all --parallel dev:watch:modules dev:watch:bundles dev:serve",
"prepublishOnly": "npm run clean && npm run build"
},
"repository": {
@ -42,16 +42,13 @@
"three": "^0.118.3"
},
"devDependencies": {
"@babel/core": "^7.10.4",
"@rollup/plugin-node-resolve": "^8.4.0",
"@rollup/plugin-typescript": "^5.0.2",
"@storybook/addon-knobs": "^5.3.19",
"@storybook/html": "^5.3.19",
"@typescript-eslint/eslint-plugin": "^3.6.1",
"@typescript-eslint/parser": "^3.6.1",
"@yushijinhun/three-minifier-rollup": "^0.1.7",
"babel-loader": "^8.1.0",
"eslint": "^7.4.0",
"local-web-server": "^4.2.1",
"npm-run-all": "^4.1.5",
"rimraf": "^3.0.2",
"rollup": "^2.21.0",