@niobrix/solidjs-skinview3d
Version:
A SolidJS wrapper for SkinView3D
209 lines (205 loc) • 6.37 kB
JSX
// src/SolidSkinView3D.tsx
import { SkinViewer, WalkingAnimation } from "skinview3d";
import { createEffect, createSignal, onCleanup, onMount } from "solid-js";
// src/SolidSkinView3D.module.css
var SolidSkinView3D_default = {};
// src/SolidSkinView3D.tsx
var SolidSkinView3D = (props) => {
const [viewer, setViewer] = createSignal(null);
const [isLoading, setIsLoading] = createSignal(true);
let canvasRef;
let animationId = null;
let animation = null;
onMount(() => {
if (!canvasRef)
return;
const skinViewerOptions = {
canvas: canvasRef,
alpha: true,
width: props.width || 300,
height: props.height || 400,
fov: props.fov || 70
};
if (props.background) {
skinViewerOptions.background = props.background;
}
const skinViewer = new SkinViewer(skinViewerOptions);
setViewer(skinViewer);
const orbitControls = skinViewer.controls;
orbitControls.enableRotate = true;
orbitControls.enableZoom = true;
orbitControls.enablePan = false;
if (props.zoom !== void 0) {
skinViewer.camera.position.z = props.zoom;
}
if (props.autoRotate) {
const rotateSpeed = props.rotateSpeed || 5e-3;
const animate = () => {
skinViewer.playerObject.rotation.y += rotateSpeed;
animationId = requestAnimationFrame(animate);
};
animate();
}
const handleSkinLoaded = () => {
setIsLoading(false);
if (props.onSkinLoaded) {
props.onSkinLoaded();
}
};
const handleSkinError = (error) => {
setIsLoading(false);
if (props.onSkinError) {
props.onSkinError(error);
}
};
if (props.skinUrl) {
setIsLoading(true);
const skinOptions = {};
if (typeof props.ears === "boolean") {
skinOptions.ears = props.ears;
} else if (props.ears) {
skinOptions.ears = false;
}
skinViewer.loadSkin(props.skinUrl, skinOptions).then(() => {
if (props.ears && typeof props.ears !== "boolean") {
skinViewer.loadEars(props.ears.source, { textureType: props.ears.textureType });
}
handleSkinLoaded();
}).catch(handleSkinError);
} else {
setIsLoading(false);
}
if (props.capeUrl) {
skinViewer.loadCape(props.capeUrl, {
backEquipment: props.backEquipment || "cape"
});
}
animation = new WalkingAnimation();
skinViewer.animation = animation;
if (props.onReady) {
props.onReady(skinViewer);
}
const handleResize = () => {
if (props.autoResize) {
const parent = canvasRef.parentElement;
if (parent) {
skinViewer.setSize(parent.clientWidth, parent.clientHeight);
}
}
};
if (props.autoResize) {
window.addEventListener("resize", handleResize);
handleResize();
}
onCleanup(() => {
if (props.autoResize) {
window.removeEventListener("resize", handleResize);
}
if (animationId !== null) {
cancelAnimationFrame(animationId);
}
if (viewer()) {
viewer()?.dispose();
}
});
});
createEffect(() => {
const currentViewer = viewer();
if (currentViewer && props.skinUrl) {
setIsLoading(true);
const skinOptions = {};
if (typeof props.ears === "boolean") {
skinOptions.ears = props.ears;
} else if (props.ears) {
skinOptions.ears = false;
}
currentViewer.loadSkin(props.skinUrl, skinOptions).then(() => {
if (props.ears && typeof props.ears !== "boolean") {
currentViewer.loadEars(props.ears.source, { textureType: props.ears.textureType });
}
setIsLoading(false);
if (props.onSkinLoaded) {
props.onSkinLoaded();
}
}).catch((error) => {
setIsLoading(false);
if (props.onSkinError) {
props.onSkinError(error);
}
});
}
});
createEffect(() => {
const currentViewer = viewer();
if (currentViewer && props.capeUrl !== void 0) {
if (props.capeUrl) {
currentViewer.loadCape(props.capeUrl, {
backEquipment: props.backEquipment || "cape"
});
} else {
currentViewer.loadCape(null);
}
}
});
createEffect(() => {
const currentViewer = viewer();
if (currentViewer && props.backEquipment && props.capeUrl) {
currentViewer.loadCape(props.capeUrl, {
backEquipment: props.backEquipment
});
}
});
createEffect(() => {
const currentViewer = viewer();
if (currentViewer && (props.width || props.height)) {
currentViewer.setSize(
props.width || currentViewer.width,
props.height || currentViewer.height
);
}
});
createEffect(() => {
const currentViewer = viewer();
if (currentViewer && props.background !== void 0) {
currentViewer.background = props.background;
}
});
createEffect(() => {
const currentViewer = viewer();
if (currentViewer && props.zoom !== void 0) {
currentViewer.camera.position.z = props.zoom;
}
});
createEffect(() => {
const currentViewer = viewer();
if (currentViewer && props.fov !== void 0) {
currentViewer.fov = props.fov;
}
});
createEffect(() => {
if (props.autoRotate) {
if (animationId === null && viewer()) {
const rotateSpeed = props.rotateSpeed || 5e-3;
const animate = () => {
const currentViewer = viewer();
if (currentViewer) {
currentViewer.playerObject.rotation.y += rotateSpeed;
}
animationId = requestAnimationFrame(animate);
};
animate();
}
} else if (animationId !== null) {
cancelAnimationFrame(animationId);
animationId = null;
}
});
return <div class={SolidSkinView3D_default.container}><div class={SolidSkinView3D_default.wrapper}><canvas ref={canvasRef} class={`${SolidSkinView3D_default.canvas} ${props.className || ""}`} />{props.showLoader !== false && isLoading() && <div class={SolidSkinView3D_default.loader}><div class={SolidSkinView3D_default.spinner} /></div>}</div></div>;
};
var SolidSkinView3D_default2 = SolidSkinView3D;
// src/index.tsx
var src_default = SolidSkinView3D_default2;
export {
SolidSkinView3D_default2 as SolidSkinView3D,
src_default as default
};