skinview3d
Advanced tools
Comparing version 2.2.1 to 2.3.0-alpha.1
@@ -41,2 +41,7 @@ import { ModelType } from "skinview-utils"; | ||
} | ||
export declare class EarsObject extends Group { | ||
readonly rightEar: Mesh; | ||
readonly leftEar: Mesh; | ||
constructor(texture: Texture); | ||
} | ||
export declare type BackEquipment = "cape" | "elytra"; | ||
@@ -47,5 +52,6 @@ export declare class PlayerObject extends Group { | ||
readonly elytra: ElytraObject; | ||
constructor(skinTexture: Texture, capeTexture: Texture); | ||
readonly ears: EarsObject; | ||
constructor(skinTexture: Texture, capeTexture: Texture, earsTexture: Texture); | ||
get backEquipment(): BackEquipment | null; | ||
set backEquipment(value: BackEquipment | null); | ||
} |
@@ -268,4 +268,23 @@ import { BoxGeometry, DoubleSide, FrontSide, Group, Mesh, MeshStandardMaterial, Vector2 } from "three"; | ||
} | ||
export class EarsObject extends Group { | ||
constructor(texture) { | ||
super(); | ||
const material = new MeshStandardMaterial({ | ||
map: texture, | ||
side: FrontSide | ||
}); | ||
const earBox = new BoxGeometry(8, 8, 4 / 3); | ||
setUVs(earBox, 0, 0, 6, 6, 1, 14, 7); | ||
this.rightEar = new Mesh(earBox, material); | ||
this.rightEar.name = "rightEar"; | ||
this.rightEar.position.x = -6; | ||
this.add(this.rightEar); | ||
this.leftEar = new Mesh(earBox, material); | ||
this.leftEar.name = "leftEar"; | ||
this.leftEar.position.x = 6; | ||
this.add(this.leftEar); | ||
} | ||
} | ||
export class PlayerObject extends Group { | ||
constructor(skinTexture, capeTexture) { | ||
constructor(skinTexture, capeTexture, earsTexture) { | ||
super(); | ||
@@ -289,2 +308,8 @@ this.skin = new SkinObject(skinTexture); | ||
this.add(this.elytra); | ||
this.ears = new EarsObject(earsTexture); | ||
this.ears.name = "ears"; | ||
this.ears.position.y = 10; | ||
this.ears.position.z = 2 / 3; | ||
this.ears.visible = false; | ||
this.skin.head.add(this.ears); | ||
} | ||
@@ -291,0 +316,0 @@ get backEquipment() { |
@@ -11,2 +11,15 @@ import { ModelType, RemoteImage, TextureSource } from "skinview-utils"; | ||
} | ||
export interface SkinLoadOptions extends LoadOptions { | ||
/** | ||
* The model type of skin. Default is "auto-detect". | ||
*/ | ||
model?: ModelType | "auto-detect"; | ||
/** | ||
* true: Loads the ears drawn on the skin texture, and show it. | ||
* "load-only": Loads the ears drawn on the skin texture, but do not make it visible. | ||
* false: Do not load ears from the skin texture. | ||
* Default is false. | ||
*/ | ||
ears?: boolean | "load-only"; | ||
} | ||
export interface CapeLoadOptions extends LoadOptions { | ||
@@ -19,2 +32,10 @@ /** | ||
} | ||
export interface EarsLoadOptions extends LoadOptions { | ||
/** | ||
* "standalone": The texture is a 14x7 image that only contains the ears; | ||
* "skin": The texture is a skin that contains ears, and we only show its ear part. | ||
* Default is "standalone". | ||
*/ | ||
textureType?: "standalone" | "skin"; | ||
} | ||
export interface SkinViewerOptions { | ||
@@ -27,2 +48,12 @@ width?: number; | ||
/** | ||
* If you want to show the ears drawn on the current skin, set this to "current-skin". | ||
* To show ears that come from a separate texture, you have to specify 'textureType' ("standalone" or "skin") and 'source'. | ||
* "standalone" means the provided texture is a 14x7 image that only contains the ears. | ||
* "skin" means the provided texture is a skin that contains ears, and we only show its ear part. | ||
*/ | ||
ears?: "current-skin" | { | ||
textureType: "standalone" | "skin"; | ||
source: RemoteImage | TextureSource; | ||
}; | ||
/** | ||
* Whether the canvas contains an alpha buffer. Default is true. | ||
@@ -78,4 +109,6 @@ * This option can be turned off if you use an opaque background. | ||
readonly capeCanvas: HTMLCanvasElement; | ||
readonly earsCanvas: HTMLCanvasElement; | ||
private readonly skinTexture; | ||
private readonly capeTexture; | ||
private readonly earsTexture; | ||
private backgroundTexture; | ||
@@ -90,3 +123,3 @@ private _disposed; | ||
loadSkin(empty: null): void; | ||
loadSkin<S extends TextureSource | RemoteImage>(source: S, model?: ModelType | "auto-detect", options?: LoadOptions): S extends TextureSource ? void : Promise<void>; | ||
loadSkin<S extends TextureSource | RemoteImage>(source: S, options?: SkinLoadOptions): S extends TextureSource ? void : Promise<void>; | ||
resetSkin(): void; | ||
@@ -96,2 +129,5 @@ loadCape(empty: null): void; | ||
resetCape(): void; | ||
loadEars(empty: null): void; | ||
loadEars<S extends TextureSource | RemoteImage>(source: S, options?: EarsLoadOptions): S extends TextureSource ? void : Promise<void>; | ||
resetEars(): void; | ||
loadPanorama<S extends TextureSource | RemoteImage>(source: S): S extends TextureSource ? void : Promise<void>; | ||
@@ -98,0 +134,0 @@ loadBackground<S extends TextureSource | RemoteImage>(source: S, mapping?: Mapping): S extends TextureSource ? void : Promise<void>; |
@@ -1,2 +0,2 @@ | ||
import { inferModelType, isTextureSource, loadCapeToCanvas, loadImage, loadSkinToCanvas } from "skinview-utils"; | ||
import { inferModelType, isTextureSource, loadCapeToCanvas, loadEarsToCanvas, loadEarsToCanvasFromSkin, loadImage, loadSkinToCanvas } from "skinview-utils"; | ||
import { Color, PointLight, EquirectangularReflectionMapping, Group, NearestFilter, PerspectiveCamera, Scene, Texture, Vector2, WebGLRenderer, AmbientLight } from "three"; | ||
@@ -23,2 +23,6 @@ import { RootAnimation } from "./animation.js"; | ||
this.capeTexture.minFilter = NearestFilter; | ||
this.earsCanvas = document.createElement("canvas"); | ||
this.earsTexture = new Texture(this.earsCanvas); | ||
this.earsTexture.magFilter = NearestFilter; | ||
this.earsTexture.minFilter = NearestFilter; | ||
this.scene = new Scene(); | ||
@@ -35,3 +39,3 @@ this.camera = new PerspectiveCamera(); | ||
this.renderer.setPixelRatio(window.devicePixelRatio); | ||
this.playerObject = new PlayerObject(this.skinTexture, this.capeTexture); | ||
this.playerObject = new PlayerObject(this.skinTexture, this.capeTexture, this.earsTexture); | ||
this.playerObject.name = "player"; | ||
@@ -44,3 +48,6 @@ this.playerObject.skin.visible = false; | ||
if (options.skin !== undefined) { | ||
this.loadSkin(options.skin, options.model); | ||
this.loadSkin(options.skin, { | ||
model: options.model, | ||
ears: options.ears === "current-skin" | ||
}); | ||
} | ||
@@ -50,2 +57,7 @@ if (options.cape !== undefined) { | ||
} | ||
if (options.ears !== undefined && options.ears !== "current-skin") { | ||
this.loadEars(options.ears.source, { | ||
textureType: options.ears.textureType | ||
}); | ||
} | ||
if (options.width !== undefined) { | ||
@@ -88,3 +100,3 @@ this.width = options.width; | ||
} | ||
loadSkin(source, model = "auto-detect", options = {}) { | ||
loadSkin(source, options = {}) { | ||
if (source === null) { | ||
@@ -95,11 +107,22 @@ this.resetSkin(); | ||
loadSkinToCanvas(this.skinCanvas, source); | ||
const actualModel = model === "auto-detect" ? inferModelType(this.skinCanvas) : model; | ||
this.skinTexture.needsUpdate = true; | ||
this.playerObject.skin.modelType = actualModel; | ||
if (options.model === undefined || options.model === "auto-detect") { | ||
this.playerObject.skin.modelType = inferModelType(this.skinCanvas); | ||
} | ||
else { | ||
this.playerObject.skin.modelType = options.model; | ||
} | ||
if (options.makeVisible !== false) { | ||
this.playerObject.skin.visible = true; | ||
} | ||
if (options.ears === true || options.ears == "load-only") { | ||
loadEarsToCanvasFromSkin(this.earsCanvas, source); | ||
this.earsTexture.needsUpdate = true; | ||
if (options.ears === true) { | ||
this.playerObject.ears.visible = true; | ||
} | ||
} | ||
} | ||
else { | ||
return loadImage(source).then(image => this.loadSkin(image, model, options)); | ||
return loadImage(source).then(image => this.loadSkin(image, options)); | ||
} | ||
@@ -128,2 +151,25 @@ } | ||
} | ||
loadEars(source, options = {}) { | ||
if (source === null) { | ||
this.resetEars(); | ||
} | ||
else if (isTextureSource(source)) { | ||
if (options.textureType === "skin") { | ||
loadEarsToCanvasFromSkin(this.earsCanvas, source); | ||
} | ||
else { | ||
loadEarsToCanvas(this.earsCanvas, source); | ||
} | ||
this.earsTexture.needsUpdate = true; | ||
if (options.makeVisible !== false) { | ||
this.playerObject.ears.visible = true; | ||
} | ||
} | ||
else { | ||
return loadImage(source).then(image => this.loadEars(image, options)); | ||
} | ||
} | ||
resetEars() { | ||
this.playerObject.ears.visible = false; | ||
} | ||
loadPanorama(source) { | ||
@@ -130,0 +176,0 @@ return this.loadBackground(source, EquirectangularReflectionMapping); |
{ | ||
"name": "skinview3d", | ||
"version": "2.2.1", | ||
"version": "2.3.0-alpha.1", | ||
"description": "Three.js powered Minecraft skin viewer", | ||
@@ -42,3 +42,3 @@ "main": "libs/skinview3d.js", | ||
"@types/three": "^0.136.1", | ||
"skinview-utils": "^0.6.2", | ||
"skinview-utils": "^0.7.0", | ||
"three": "^0.136.0" | ||
@@ -45,0 +45,0 @@ }, |
@@ -15,2 +15,3 @@ skinview3d | ||
* Capes | ||
* Ears | ||
* Elytras | ||
@@ -108,3 +109,32 @@ * Slim Arms | ||
## Ears | ||
skinview3d supports two types of ear texture: | ||
* `standalone`: 14x7 image that contains the ear ([example](https://github.com/bs-community/skinview3d/blob/master/examples/img/ears.png)) | ||
* `skin`: Skin texture that contains the ear (e.g. [deadmau5's skin](https://minecraft.fandom.com/wiki/Easter_eggs#Deadmau5.27s_ears)) | ||
Usage: | ||
```js | ||
// You can specify ears in the constructor: | ||
new skinview3d.SkinViewer({ | ||
skin: "img/deadmau5.png", | ||
// Use ears drawn on the current skin (img/deadmau5.png) | ||
ears: "current-skin", | ||
// Or use ears from other textures | ||
ears: { | ||
textureType: "standalone", // "standalone" or "skin" | ||
source: "img/ears.png" | ||
} | ||
}); | ||
// Show ears when loading skins: | ||
skinViewer.loadSkin("img/deadmau5.png", { ears: true }); | ||
// Use ears from other textures: | ||
skinViewer.loadEars("img/ears.png", { textureType: "standalone" }); | ||
skinViewer.loadEars("img/deadmau5.png", { textureType: "skin" }); | ||
``` | ||
# Build | ||
`npm run build` |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
1391400
2794
139
1
+ Addedskinview-utils@0.7.1(transitive)
- Removed@types/offscreencanvas@2019.7.3(transitive)
- Removedskinview-utils@0.6.2(transitive)
Updatedskinview-utils@^0.7.0