Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .storybook/main.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { StorybookConfig } from "@storybook/react-vite";
const config: StorybookConfig = {
stories: ["../src/**/*.stories.@(js|jsx|ts|tsx)"],
addons: ["@storybook/addon-essentials", "@storybook/addon-controls"],
addons: ["@storybook/addon-docs"],

framework: {
name: "@storybook/react-vite",
Expand Down
4 changes: 2 additions & 2 deletions .storybook/preview.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Preview } from "@storybook/react";
import { themes } from "@storybook/theming";
import type { Preview } from "@storybook/react-vite";
import { themes } from "storybook/theming";

const preview: Preview = {
parameters: {
Expand Down
37 changes: 19 additions & 18 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,46 +1,47 @@
{
"name": "react-skinview3d",
"version": "6.0.0",
"version": "7.0.0",
"description": "A React component for skinview3d Minecraft viewer",
"author": "Hacksore",
"license": "MIT",
"repository": "Hacksore/react-skinview3d",
"type": "module",
"files": ["dist"],
"main": "./dist/index.cjs",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.es.js"
"import": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
},
"require": {
"types": "./dist/index.d.cts",
"default": "./dist/index.cjs"
}
}
},
"engines": {
"node": ">=22"
},
"scripts": {
"build": "rollup -c",
"start": "rollup -c -w",
"build": "tsdown",
"format": "biome format --write",
"lint": "biome lint",
"storybook": "storybook dev -p 6006",
"build-storybook": "storybook build"
},
"devDependencies": {
"@biomejs/biome": "^1.9.4",
"@rollup/plugin-commonjs": "^28.0.3",
"@rollup/plugin-node-resolve": "^16.0.1",
"@rollup/plugin-terser": "^0.4.1",
"@rollup/plugin-typescript": "^12.1.2",
"@storybook/addon-controls": "^8.6.12",
"@storybook/addon-essentials": "^8.6.12",
"@storybook/react": "^8.6.12",
"@storybook/react-vite": "^8.6.12",
"@storybook/theming": "^8.6.12",
"@storybook/react-vite": "^9.1.4",
"@types/react": "^19.1.2",
"@types/react-dom": "^19.1.3",
"rollup": "^4.40.1",
"storybook": "^8.6.12",
"typescript": "5.8.3"
"storybook": "^9.1.4",
"tsdown": "^0.14.2",
"typescript": "5.8.3",
"@storybook/addon-docs": "^9.1.4"
},
"files": ["dist"],
"peerDependencies": {
"react": ">=16.8.0",
"react-dom": ">=16.8.0"
Expand Down
1,918 changes: 933 additions & 985 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

33 changes: 0 additions & 33 deletions rollup.config.js

This file was deleted.

69 changes: 3 additions & 66 deletions src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,74 +1,13 @@
import { useEffect, useRef } from "react";
import { SkinViewer, type SkinViewerOptions } from "skinview3d";
import type { HTMLAttributes } from "react";

/**
* Interface describing the callback parameters when the skin viewer is ready
*/
export interface ViewerReadyCallbackOptions {
/**
* The instance of the skinview3d viewer that can be used to control the skin display
*/
viewer: SkinViewer;
/**
* The reference to the canvas element where the skin is rendered
*/
canvasRef: HTMLCanvasElement;
}

/**
* Props interface for the ReactSkinview3d component
*/
export interface ReactSkinview3dOptions {
/**
* CSS class names to apply to the canvas element
*/
className?: HTMLAttributes<HTMLCanvasElement>["className"];
/**
* The width of the canvas in pixels or as a CSS value
*/
width: number | string;
/**
* The height of the canvas in pixels or as a CSS value
*/
height: number | string;
/**
* URL of the Minecraft skin texture to display
*/
skinUrl: string;
/**
* Optional URL of the Minecraft cape texture to display
*/
capeUrl?: string;
/**
* A callback function that is called when the skin viewer is ready
* @param {ViewerReadyCallbackOptions} options - The options object containing the viewer instance and canvas reference
* @param {SkinViewer} options.viewer - The instance of the skinview3d viewer
* @param {HTMLCanvasElement} options.canvasRef - The reference to the canvas element
* @example
* ```tsx
* onReady={({ viewer, canvasRef }) => {
* // Access the viewer instance
* viewer.autoRotate = true;
* // Access the canvas element
* console.log(canvasRef);
* }}
* ```
*/
onReady?: ({ viewer, canvasRef }: ViewerReadyCallbackOptions) => void;
/**
* Additional configuration options passed directly to the skinview3d constructor
* @see [skinview3d documentation](https://bs-community.github.io/skinview3d/) for available options
*/
options?: SkinViewerOptions;
}
import { SkinViewer } from "skinview3d";
import type { ReactSkinview3dOptions } from "./types.js";

/**
* React component that renders a 3D Minecraft skin viewer
* @param {ReactSkinview3dOptions} props - The component props
* @returns {React.ReactElement} A canvas element with the 3D skin viewer
*/
const ReactSkinview3d = ({
export const ReactSkinview3d = ({
className,
width,
height,
Expand Down Expand Up @@ -126,5 +65,3 @@ const ReactSkinview3d = ({

return <canvas className={className} ref={canvasRef} />;
};

export default ReactSkinview3d;
99 changes: 84 additions & 15 deletions src/stories/skinview3d.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,66 @@
import React, { useRef, useState } from "react";
import type { Meta, StoryObj } from "@storybook/react";
import ReactSkinview3d from "..";
import type { Meta, StoryObj } from "@storybook/react-vite";
import { ReactSkinview3d } from "..";
import type { SkinViewer } from "skinview3d";
import { WalkingAnimation } from "skinview3d";

const meta: Meta<typeof ReactSkinview3d> = {
title: "Examples",
component: ReactSkinview3d,
tags: ["autodocs"],
argTypes: {
width: {
control: { type: "number" },
description: "Width of the canvas in pixels",
defaultValue: 150,
},
height: {
control: { type: "number" },
description: "Height of the canvas in pixels",
defaultValue: 300,
},
skinUrl: {
control: { type: "select" },
options: [
"textures/skin-legacyhat-default-no_hd.png",
"textures/skin-1.8-default-no_hd.png",
"textures/skin-1.8-slim-no_hd.png",
"textures/skin-old-default-no_hd.png",
],
description: "Select a skin texture to display",
},
capeUrl: {
control: { type: "text" },
description: "Optional URL of the Minecraft cape texture",
},
className: {
control: { type: "text" },
description: "CSS class names to apply to the canvas element",
},
onReady: {
control: false,
description: "Callback function when the skin viewer is ready",
},
options: {
control: false,
description: "Additional configuration options for skinview3d",
},
},
args: {
width: 150,
height: 300,
skinUrl: "textures/skin-legacyhat-default-no_hd.png",
},
} satisfies Meta<typeof ReactSkinview3d>;

export default meta;
type Story = StoryObj<typeof meta>;

export const Basic: Story = {
render: () => {
return (
<ReactSkinview3d
skinUrl="textures/skin-legacyhat-default-no_hd.png"
height={300}
width={150}
/>
);
args: {
skinUrl: "textures/skin-legacyhat-default-no_hd.png",
height: 300,
width: 150,
},
};

Expand Down Expand Up @@ -50,12 +89,15 @@ export const Multiple: Story = {
};

export const Animation: Story = {
render: () => (
args: {
className: "viewer",
skinUrl: "textures/skin-legacyhat-default-no_hd.png",
height: 300,
width: 150,
},
render: (args) => (
<ReactSkinview3d
className="viewer"
skinUrl="textures/skin-legacyhat-default-no_hd.png"
height={300}
width={150}
{...args}
onReady={({ viewer }) => {
// Add an animation
viewer.animation = new WalkingAnimation();
Expand All @@ -66,6 +108,33 @@ export const Animation: Story = {
),
};

export const Interactive: Story = {
args: {
skinUrl: "textures/skin-legacyhat-default-no_hd.png",
height: 300,
width: 150,
className: "viewer",
},
argTypes: {
...meta.argTypes,
skinUrl: {
control: { type: "select" },
options: [
"textures/skin-legacyhat-default-no_hd.png",
"textures/skin-1.8-default-no_hd.png",
"textures/skin-1.8-slim-no_hd.png",
"textures/skin-old-default-no_hd.png",
],
description: "Select a skin texture to display",
},
capeUrl: {
control: { type: "select" },
options: ["", "textures/mojang-classic-cape.png"],
description: "Select a cape texture to display",
},
},
};

export const Screenshot: Story = {
render: () => {
const [url, setUrl] = useState("");
Expand Down
64 changes: 64 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import type { SkinViewer } from "skinview3d";
import type { SkinViewerOptions } from "skinview3d";
import type { HTMLAttributes } from "react";

/**
* Interface describing the callback parameters when the skin viewer is ready
*/
export interface ViewerReadyCallbackOptions {
/**
* The instance of the skinview3d viewer that can be used to control the skin display
*/
viewer: SkinViewer;
/**
* The reference to the canvas element where the skin is rendered
*/
canvasRef: HTMLCanvasElement;
}

/**
* Props interface for the ReactSkinview3d component
*/
export interface ReactSkinview3dOptions {
/**
* CSS class names to apply to the canvas element
*/
className?: HTMLAttributes<HTMLCanvasElement>["className"];
/**
* The width of the canvas in pixels or as a CSS value
*/
width: number | string;
/**
* The height of the canvas in pixels or as a CSS value
*/
height: number | string;
/**
* URL of the Minecraft skin texture to display
*/
skinUrl: string;
/**
* Optional URL of the Minecraft cape texture to display
*/
capeUrl?: string;
/**
* A callback function that is called when the skin viewer is ready
* @param {ViewerReadyCallbackOptions} options - The options object containing the viewer instance and canvas reference
* @param {SkinViewer} options.viewer - The instance of the skinview3d viewer
* @param {HTMLCanvasElement} options.canvasRef - The reference to the canvas element
* @example
* ```tsx
* onReady={({ viewer, canvasRef }) => {
* // Access the viewer instance
* viewer.autoRotate = true;
* // Access the canvas element
* console.log(canvasRef);
* }}
* ```
*/
onReady?: ({ viewer, canvasRef }: ViewerReadyCallbackOptions) => void;
/**
* Additional configuration options passed directly to the skinview3d constructor
* @see [skinview3d documentation](https://bs-community.github.io/skinview3d/) for available options
*/
options?: SkinViewerOptions;
}
Loading