Skip to content

Commit d4b6ff8

Browse files
committed
chore: integrate with sb
1 parent 571ac66 commit d4b6ff8

File tree

8 files changed

+281
-3
lines changed

8 files changed

+281
-3
lines changed

.eslintrc.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
module.exports = {
22
parser: "@typescript-eslint/parser", // Eslint TypeScript Parser
3-
extends: ["prettier/@typescript-eslint", "plugin:prettier/recommended"],
3+
extends: [
4+
"prettier/@typescript-eslint",
5+
"plugin:prettier/recommended",
6+
"plugin:storybook/recommended"
7+
],
48
plugins: ["@typescript-eslint"],
59
parserOptions: {
610
ecmaVersion: 2019,

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,6 @@ stats.html
2525
tsconfig.tsbuildinfo
2626
oasis-npm
2727
api
28-
miniprogram.js
28+
miniprogram.js
29+
*storybook.log
30+
storybook-static
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { WebGLEngine, type WebGLEngineConfiguration } from "@galacean/engine";
2+
import { makeDecorator, useEffect } from 'storybook/preview-api';
3+
4+
export interface CanvasOptions {
5+
width?: number;
6+
height?: number;
7+
engineOptions?: Omit<WebGLEngineConfiguration, 'canvas'>
8+
}
9+
10+
export const withCanvas = makeDecorator({
11+
name: 'withCanvas',
12+
parameterName: 'canvas',
13+
wrapper: (storyFn, context, { parameters = {} }) => {
14+
const container = document.createElement('div');
15+
container.style.width = '100vw';
16+
container.style.height = '100vh';
17+
container.style.position = 'relative';
18+
container.style.overflow = 'hidden';
19+
20+
const canvas = document.createElement('canvas');
21+
canvas.id = 'canvas';
22+
canvas.style.width = '100%';
23+
canvas.style.height = '100%';
24+
container.appendChild(canvas);
25+
26+
const canvasOptions = context.parameters.canvas || {};
27+
28+
const enginePromise = WebGLEngine.create({
29+
canvas: canvas,
30+
graphicDeviceOptions: {
31+
32+
},
33+
...(canvasOptions.engineOptions || {})
34+
});
35+
36+
context.getEngine = () => {
37+
return enginePromise;
38+
};
39+
40+
useEffect(() => {
41+
return () => {
42+
enginePromise.then(engine => {
43+
engine.destroy();
44+
});
45+
};
46+
}, []);
47+
48+
const story = storyFn(context);
49+
if (typeof story === 'string') {
50+
const div = document.createElement('div');
51+
div.innerHTML = story;
52+
container.appendChild(div);
53+
} else if (story instanceof HTMLElement) {
54+
container.appendChild(story);
55+
}
56+
57+
return container;
58+
}
59+
});

.storybook/main.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
2+
3+
import { join, dirname } from "path";
4+
5+
function getAbsolutePath(value) {
6+
return dirname(require.resolve(join(value, 'package.json')))
7+
}
8+
9+
/** @type { import('@storybook/html-vite').StorybookConfig } */
10+
const config = {
11+
"stories": [
12+
"../stories/**/*.mdx",
13+
"../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)"
14+
],
15+
"addons": [
16+
getAbsolutePath("@storybook/addon-links"),
17+
getAbsolutePath("@storybook/addon-essentials")
18+
],
19+
"framework": {
20+
"name": getAbsolutePath('@storybook/html-vite'),
21+
"options": {}
22+
},
23+
"core": {
24+
"disableTelemetry": true
25+
}
26+
};
27+
28+
export default config;

.storybook/preview.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { withCanvas } from './decorators/withCanvas';
2+
3+
/** @type { import('@storybook/html-vite').Preview } */
4+
const preview = {
5+
parameters: {
6+
controls: {
7+
matchers: {
8+
color: /(background|color)$/i,
9+
date: /Date$/i,
10+
},
11+
},
12+
// Default canvas options
13+
canvas: {
14+
engineOptions: {
15+
// Default engine options here
16+
}
17+
},
18+
layout: 'fullscreen',
19+
},
20+
decorators: [withCanvas]
21+
};
22+
23+
export default preview;

package.json

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,21 @@
2121
"build": "rollup -c",
2222
"b:all": "pnpm run b:types && cross-env BUILD_TYPE=ALL rollup -c",
2323
"clean": "pnpm -r exec rm -rf dist && pnpm -r exec rm -rf types",
24-
"release": "bumpp -r"
24+
"release": "bumpp -r",
25+
"storybook": "storybook dev -p 6006",
26+
"build-storybook": "storybook build"
2527
},
2628
"devDependencies": {
2729
"@commitlint/cli": "^11.0.0",
2830
"@commitlint/config-conventional": "^11.0.0",
31+
"@galacean/engine": "^1.5.0",
2932
"@rollup/plugin-commonjs": "^25.0.0",
3033
"@rollup/plugin-inject": "^5.0.3",
3134
"@rollup/plugin-node-resolve": "^15.0.1",
3235
"@rollup/plugin-replace": "^5.0.2",
36+
"@storybook/addon-essentials": "9.0.0-alpha.12",
37+
"@storybook/addon-links": "^9.0.11",
38+
"@storybook/html-vite": "^9.0.11",
3339
"@swc/core": "^1.3.49",
3440
"@swc/helpers": "^0.5.0",
3541
"@types/chai": "^4.3.3",
@@ -46,6 +52,7 @@
4652
"eslint": "^7.32.0",
4753
"eslint-config-prettier": "^7.2.0",
4854
"eslint-plugin-prettier": "^3.4.1",
55+
"eslint-plugin-storybook": "^9.0.11",
4956
"floss": "^5.0.1",
5057
"husky": "^8.0.3",
5158
"lint-staged": "^10.5.4",
@@ -58,6 +65,7 @@
5865
"rollup-plugin-modify": "^3.0.0",
5966
"rollup-plugin-string": "^3.0.0",
6067
"rollup-plugin-swc3": "^0.8.0",
68+
"storybook": "^9.0.11",
6169
"ts-node": "^10",
6270
"typescript": "^4.8.3"
6371
},

stories/BasicScene.stories.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { Camera, Entity, MeshRenderer, PrimitiveMesh } from "@galacean/engine";
2+
3+
export default {
4+
title: 'Basic Scene',
5+
parameters: {
6+
canvas: {
7+
engineOptions: {
8+
// Custom engine options for this story
9+
}
10+
}
11+
}
12+
};
13+
14+
export const BasicCube = {
15+
render: async (args, context) => {
16+
// Get the engine using the convenient getEngine function
17+
const engine = await context.getEngine();
18+
19+
const scene = engine.sceneManager.activeScene;
20+
const rootEntity = scene.createRootEntity();
21+
22+
// Create camera
23+
const cameraEntity = rootEntity.createChild("camera");
24+
cameraEntity.transform.setPosition(0, 0, 5);
25+
const camera = cameraEntity.addComponent(Camera);
26+
camera.enableFrustumCulling = true;
27+
28+
// Create cube
29+
const cubeEntity = rootEntity.createChild("cube");
30+
const renderer = cubeEntity.addComponent(MeshRenderer);
31+
renderer.mesh = PrimitiveMesh.createCuboid(engine, 1, 1, 1);
32+
33+
// Auto-rotate cube
34+
engine.run();
35+
36+
// Return empty div as the canvas is already in the container
37+
return document.createElement('div');
38+
}
39+
};

stories/Gizmo.stories.ts

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
2+
import {
3+
Camera,
4+
MeshRenderer,
5+
PrimitiveMesh,
6+
Vector3,
7+
WebGLEngine,
8+
DirectLight,
9+
BlinnPhongMaterial,
10+
Color,
11+
Layer
12+
} from "@galacean/engine";
13+
import { Gizmo, Group, State } from "../packages/gizmo/src";
14+
15+
export default {
16+
title: 'Toolkit/Gizmo',
17+
parameters: {
18+
canvas: {
19+
engineOptions: {
20+
alpha: true,
21+
antialias: true
22+
}
23+
}
24+
},
25+
argTypes: {
26+
gizmoState: {
27+
control: { type: 'select' },
28+
options: ['translate', 'rotate', 'scale', 'all'],
29+
mapping: {
30+
'translate': State.translate,
31+
'rotate': State.rotate,
32+
'scale': State.scale,
33+
'all': State.all
34+
},
35+
defaultValue: 'translate'
36+
},
37+
gizmoSize: {
38+
control: { type: 'range', min: 0, max: 2, step: 0.1 },
39+
defaultValue: 0.8
40+
}
41+
}
42+
};
43+
44+
export const GizmoDemo = {
45+
args: {
46+
gizmoState: "translate",
47+
gizmoSize: 0.8
48+
},
49+
render:async (args, context) => {
50+
const engine: WebGLEngine = await context.getEngine();
51+
52+
engine.canvas.resizeByClientSize(window.devicePixelRatio)
53+
54+
const scene = engine.sceneManager.activeScene;
55+
const rootEntity = scene.createRootEntity("root");
56+
57+
const cameraEntity = rootEntity.createChild("camera");
58+
cameraEntity.transform.setPosition(0, 2, 5);
59+
cameraEntity.transform.lookAt(new Vector3(0, 0, 0));
60+
const camera = cameraEntity.addComponent(Camera);
61+
camera.enableFrustumCulling = true;
62+
63+
const lightEntity = rootEntity.createChild("light");
64+
lightEntity.transform.setPosition(1, 3, 2);
65+
lightEntity.transform.lookAt(new Vector3(0, 0, 0));
66+
const light = lightEntity.addComponent(DirectLight);
67+
light.color = new Color(1, 1, 1, 1).toLinear(new Color());
68+
69+
const cubeEntity = rootEntity.createChild("cube");
70+
const renderer = cubeEntity.addComponent(MeshRenderer);
71+
cubeEntity.layer = Layer.Layer22;
72+
renderer.mesh = PrimitiveMesh.createCuboid(engine, 1, 1, 1);
73+
74+
const material = new BlinnPhongMaterial(engine);
75+
material.baseColor = new Color(0.7, 0.3, 0.3, 1.0).toLinear(new Color());
76+
renderer.setMaterial(material);
77+
78+
const group = new Group();
79+
80+
81+
const gizmoEntity = rootEntity.createChild("editor-gizmo");
82+
gizmoEntity.layer = Layer.Layer31;
83+
84+
const gizmo = gizmoEntity.addComponent(Gizmo);
85+
86+
gizmo.init(camera, group);
87+
88+
group.addEntity(cubeEntity)
89+
gizmo.state = args.gizmoState;
90+
gizmo.size = args.gizmoSize;
91+
92+
engine.on("gizmo-move-start", (axis) => {
93+
console.log(`Gizmo move started on axis: ${axis}`);
94+
});
95+
96+
engine.on("gizmo-move-end", () => {
97+
console.log("Gizmo move ended");
98+
});
99+
100+
const updateGizmo = () => {
101+
gizmo.state = args.gizmoState;
102+
gizmo.size = args.gizmoSize;
103+
};
104+
105+
context.watch = (newArgs) => {
106+
args = newArgs;
107+
updateGizmo();
108+
};
109+
110+
engine.run();
111+
112+
return document.createElement('div');
113+
}
114+
};
115+

0 commit comments

Comments
 (0)