blockymodel-web 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,279 @@
1
+ # blockymodel-web
2
+
3
+ Web-based 3D editor for BlockyModel format (.blockymodel) built with [Three.js](https://threejs.org/).
4
+
5
+ ![License](https://img.shields.io/npm/l/blockymodel-web)
6
+ ![npm](https://img.shields.io/npm/v/blockymodel-web)
7
+
8
+ **[Live Demo](https://editor.hytalegarage.com)** - Try the editor in your browser
9
+
10
+ ## Features
11
+
12
+ - **3D Viewport** - Interactive scene with orbit controls
13
+ - **Selection** - Click to select objects with visual highlighting
14
+ - **Transform Gizmos** - Move, rotate, and scale with keyboard shortcuts (G/R/S)
15
+ - **Property Panel** - Edit position, rotation, scale, and shape properties
16
+ - **Hierarchy Panel** - Tree view with add/delete/duplicate via context menu
17
+ - **UV Editor** - Per-face texture offset, mirror, and rotation
18
+ - **Undo/Redo** - Full history with Ctrl+Z / Ctrl+Y
19
+ - **Save/Export** - Download as .blockymodel JSON
20
+
21
+ ## Installation
22
+
23
+ ```bash
24
+ npm install blockymodel-web three
25
+ ```
26
+
27
+ ## Quick Start
28
+
29
+ ### As a Library
30
+
31
+ ```typescript
32
+ import {
33
+ Editor,
34
+ ViewerController,
35
+ BlockyModelLoader,
36
+ PropertyPanel,
37
+ HierarchyPanel
38
+ } from 'blockymodel-web';
39
+
40
+ // Create container
41
+ const container = document.getElementById('viewport');
42
+
43
+ // Initialize viewer
44
+ const viewer = new ViewerController(container);
45
+
46
+ // Load a model
47
+ const loader = new BlockyModelLoader();
48
+ const model = await loader.loadAsync('/path/to/model.blockymodel');
49
+ viewer.scene.add(model);
50
+
51
+ // Enable editing
52
+ const editor = new Editor(
53
+ viewer.scene,
54
+ viewer.camera,
55
+ viewer.renderer,
56
+ viewer.controls
57
+ );
58
+
59
+ // Add UI panels
60
+ const hierarchy = new HierarchyPanel(
61
+ document.getElementById('hierarchy'),
62
+ editor
63
+ );
64
+
65
+ const properties = new PropertyPanel(
66
+ document.getElementById('properties'),
67
+ editor
68
+ );
69
+ ```
70
+
71
+ ### Standalone App
72
+
73
+ ```bash
74
+ git clone https://github.com/ZacxDev/blockymodel-web.git
75
+ cd blockymodel-web
76
+ npm install
77
+ npm run dev
78
+ ```
79
+
80
+ Open http://localhost:3000 and load a .blockymodel file.
81
+
82
+ ## Keyboard Shortcuts
83
+
84
+ | Key | Action |
85
+ |-----|--------|
86
+ | G | Translate mode |
87
+ | R | Rotate mode |
88
+ | S | Scale mode |
89
+ | Delete | Remove selected node |
90
+ | Ctrl+Z | Undo |
91
+ | Ctrl+Y | Redo |
92
+
93
+ ## API Reference
94
+
95
+ ### Editor
96
+
97
+ Central state manager that coordinates all editing components.
98
+
99
+ ```typescript
100
+ const editor = new Editor(scene, camera, renderer, orbitControls);
101
+
102
+ // Events
103
+ editor.on('selectionChanged', (object) => { });
104
+ editor.on('objectChanged', (object) => { });
105
+ editor.on('historyChanged', () => { });
106
+
107
+ // Methods
108
+ editor.select(object); // Select an object
109
+ editor.deselect(); // Clear selection
110
+ editor.getSelected(); // Get selected object
111
+ editor.execute(command); // Execute a command (adds to history)
112
+ editor.undo(); // Undo last command
113
+ editor.redo(); // Redo last undone command
114
+ ```
115
+
116
+ ### Commands
117
+
118
+ All state changes go through commands for undo/redo support.
119
+
120
+ ```typescript
121
+ import {
122
+ SetPositionCommand,
123
+ SetRotationCommand,
124
+ SetScaleCommand,
125
+ SetPropertyCommand,
126
+ AddNodeCommand,
127
+ RemoveNodeCommand
128
+ } from 'blockymodel-web';
129
+
130
+ // Move an object
131
+ editor.execute(new SetPositionCommand(
132
+ object,
133
+ new THREE.Vector3(10, 0, 0), // new position
134
+ object.position.clone() // old position
135
+ ));
136
+
137
+ // Change a property
138
+ editor.execute(new SetPropertyCommand(
139
+ object,
140
+ 'userData.customProp', // supports nested paths
141
+ 'newValue',
142
+ 'oldValue'
143
+ ));
144
+
145
+ // Add a child node
146
+ const child = new THREE.Mesh(geometry, material);
147
+ editor.execute(new AddNodeCommand(parent, child));
148
+ ```
149
+
150
+ ### Serializer
151
+
152
+ Export the scene back to BlockyModel format.
153
+
154
+ ```typescript
155
+ import { Serializer } from 'blockymodel-web';
156
+
157
+ const serializer = new Serializer();
158
+
159
+ // Get as object
160
+ const model = serializer.serialize(scene);
161
+
162
+ // Get as JSON string
163
+ const json = serializer.toJSON(scene);
164
+
165
+ // Download file
166
+ const blob = new Blob([json], { type: 'application/json' });
167
+ const url = URL.createObjectURL(blob);
168
+ const a = document.createElement('a');
169
+ a.href = url;
170
+ a.download = 'model.blockymodel';
171
+ a.click();
172
+ ```
173
+
174
+ ### BlockyModelLoader
175
+
176
+ Load .blockymodel files into Three.js.
177
+
178
+ ```typescript
179
+ import { BlockyModelLoader, applyTextureToModel } from 'blockymodel-web';
180
+
181
+ const loader = new BlockyModelLoader();
182
+
183
+ // Async/await
184
+ const model = await loader.loadAsync('/model.blockymodel');
185
+ scene.add(model);
186
+
187
+ // With texture
188
+ const texture = new THREE.TextureLoader().load('/texture.png');
189
+ applyTextureToModel(model, texture);
190
+ ```
191
+
192
+ ## BlockyModel Format
193
+
194
+ ```typescript
195
+ interface BlockyModel {
196
+ format?: "character" | "prop";
197
+ lod?: "auto" | string;
198
+ nodes: BlockyNode[];
199
+ }
200
+
201
+ interface BlockyNode {
202
+ id: string;
203
+ name: string;
204
+ position?: { x: number; y: number; z: number };
205
+ orientation?: { w: number; x: number; y: number; z: number };
206
+ shape: {
207
+ type: "box" | "quad" | "none";
208
+ offset: { x: number; y: number; z: number };
209
+ stretch: { x: number; y: number; z: number };
210
+ settings: {
211
+ size?: { x: number; y: number; z: number };
212
+ };
213
+ textureLayout: {
214
+ front?: FaceUV;
215
+ back?: FaceUV;
216
+ left?: FaceUV;
217
+ right?: FaceUV;
218
+ top?: FaceUV;
219
+ bottom?: FaceUV;
220
+ };
221
+ visible: boolean;
222
+ doubleSided: boolean;
223
+ shadingMode: "standard" | "flat" | "fullbright" | "reflective";
224
+ };
225
+ children: BlockyNode[];
226
+ }
227
+ ```
228
+
229
+ ## Development
230
+
231
+ ```bash
232
+ # Install dependencies
233
+ npm install
234
+
235
+ # Start dev server
236
+ npm run dev
237
+
238
+ # Run tests
239
+ npm run test:run
240
+
241
+ # Run tests with coverage
242
+ npm run test:coverage
243
+
244
+ # Type check
245
+ npm run typecheck
246
+
247
+ # Build for production
248
+ npm run build
249
+
250
+ # Build library for npm
251
+ npm run build:lib
252
+ ```
253
+
254
+ ## Project Structure
255
+
256
+ ```
257
+ src/
258
+ ├── editor/
259
+ │ ├── Editor.ts # Central state manager
260
+ │ ├── SelectionManager.ts # Raycasting + selection
261
+ │ ├── TransformManager.ts # Transform gizmos
262
+ │ ├── History.ts # Undo/redo stack
263
+ │ ├── Serializer.ts # Export to JSON
264
+ │ └── commands/ # Command pattern implementations
265
+ ├── ui/
266
+ │ ├── PropertyPanel.ts # Transform/shape editing
267
+ │ ├── HierarchyPanel.ts # Tree view + context menu
268
+ │ └── UVEditor.ts # Per-face UV controls
269
+ ├── loaders/
270
+ │ └── BlockyModelLoader.ts
271
+ ├── viewer/
272
+ │ └── ViewerController.ts
273
+ └── types/
274
+ └── blockymodel.ts # TypeScript interfaces
275
+ ```
276
+
277
+ ## License
278
+
279
+ MIT
@@ -0,0 +1,133 @@
1
+ {
2
+ "format": "prop",
3
+ "lod": "auto",
4
+ "nodes": [
5
+ {
6
+ "id": "root",
7
+ "name": "SampleModel",
8
+ "position": { "x": 0, "y": 0, "z": 0 },
9
+ "orientation": { "w": 1, "x": 0, "y": 0, "z": 0 },
10
+ "shape": {
11
+ "type": "none",
12
+ "offset": { "x": 0, "y": 0, "z": 0 },
13
+ "stretch": { "x": 1, "y": 1, "z": 1 },
14
+ "settings": {},
15
+ "textureLayout": {},
16
+ "unwrapMode": "auto",
17
+ "visible": true,
18
+ "doubleSided": false,
19
+ "shadingMode": "standard"
20
+ },
21
+ "children": [
22
+ {
23
+ "id": "body",
24
+ "name": "Body",
25
+ "position": { "x": 0, "y": 8, "z": 0 },
26
+ "orientation": { "w": 1, "x": 0, "y": 0, "z": 0 },
27
+ "shape": {
28
+ "type": "box",
29
+ "offset": { "x": 0, "y": 0, "z": 0 },
30
+ "stretch": { "x": 1, "y": 1, "z": 1 },
31
+ "settings": {
32
+ "size": { "x": 8, "y": 12, "z": 4 }
33
+ },
34
+ "textureLayout": {
35
+ "front": { "offset": { "x": 0, "y": 0 }, "mirror": { "x": false, "y": false }, "angle": 0 },
36
+ "back": { "offset": { "x": 0, "y": 0 }, "mirror": { "x": false, "y": false }, "angle": 0 },
37
+ "left": { "offset": { "x": 0, "y": 0 }, "mirror": { "x": false, "y": false }, "angle": 0 },
38
+ "right": { "offset": { "x": 0, "y": 0 }, "mirror": { "x": false, "y": false }, "angle": 0 },
39
+ "top": { "offset": { "x": 0, "y": 0 }, "mirror": { "x": false, "y": false }, "angle": 0 },
40
+ "bottom": { "offset": { "x": 0, "y": 0 }, "mirror": { "x": false, "y": false }, "angle": 0 }
41
+ },
42
+ "unwrapMode": "custom",
43
+ "visible": true,
44
+ "doubleSided": false,
45
+ "shadingMode": "standard"
46
+ },
47
+ "children": []
48
+ },
49
+ {
50
+ "id": "head",
51
+ "name": "Head",
52
+ "position": { "x": 0, "y": 18, "z": 0 },
53
+ "orientation": { "w": 1, "x": 0, "y": 0, "z": 0 },
54
+ "shape": {
55
+ "type": "box",
56
+ "offset": { "x": 0, "y": 0, "z": 0 },
57
+ "stretch": { "x": 1, "y": 1, "z": 1 },
58
+ "settings": {
59
+ "size": { "x": 8, "y": 8, "z": 8 }
60
+ },
61
+ "textureLayout": {
62
+ "front": { "offset": { "x": 0, "y": 0 }, "mirror": { "x": false, "y": false }, "angle": 0 },
63
+ "back": { "offset": { "x": 0, "y": 0 }, "mirror": { "x": false, "y": false }, "angle": 0 },
64
+ "left": { "offset": { "x": 0, "y": 0 }, "mirror": { "x": false, "y": false }, "angle": 0 },
65
+ "right": { "offset": { "x": 0, "y": 0 }, "mirror": { "x": false, "y": false }, "angle": 0 },
66
+ "top": { "offset": { "x": 0, "y": 0 }, "mirror": { "x": false, "y": false }, "angle": 0 },
67
+ "bottom": { "offset": { "x": 0, "y": 0 }, "mirror": { "x": false, "y": false }, "angle": 0 }
68
+ },
69
+ "unwrapMode": "custom",
70
+ "visible": true,
71
+ "doubleSided": false,
72
+ "shadingMode": "standard"
73
+ },
74
+ "children": []
75
+ },
76
+ {
77
+ "id": "left_arm",
78
+ "name": "LeftArm",
79
+ "position": { "x": -6, "y": 12, "z": 0 },
80
+ "orientation": { "w": 1, "x": 0, "y": 0, "z": 0 },
81
+ "shape": {
82
+ "type": "box",
83
+ "offset": { "x": 0, "y": 0, "z": 0 },
84
+ "stretch": { "x": 1, "y": 1, "z": 1 },
85
+ "settings": {
86
+ "size": { "x": 4, "y": 12, "z": 4 }
87
+ },
88
+ "textureLayout": {
89
+ "front": { "offset": { "x": 0, "y": 0 }, "mirror": { "x": false, "y": false }, "angle": 0 },
90
+ "back": { "offset": { "x": 0, "y": 0 }, "mirror": { "x": false, "y": false }, "angle": 0 },
91
+ "left": { "offset": { "x": 0, "y": 0 }, "mirror": { "x": false, "y": false }, "angle": 0 },
92
+ "right": { "offset": { "x": 0, "y": 0 }, "mirror": { "x": false, "y": false }, "angle": 0 },
93
+ "top": { "offset": { "x": 0, "y": 0 }, "mirror": { "x": false, "y": false }, "angle": 0 },
94
+ "bottom": { "offset": { "x": 0, "y": 0 }, "mirror": { "x": false, "y": false }, "angle": 0 }
95
+ },
96
+ "unwrapMode": "custom",
97
+ "visible": true,
98
+ "doubleSided": false,
99
+ "shadingMode": "standard"
100
+ },
101
+ "children": []
102
+ },
103
+ {
104
+ "id": "right_arm",
105
+ "name": "RightArm",
106
+ "position": { "x": 6, "y": 12, "z": 0 },
107
+ "orientation": { "w": 1, "x": 0, "y": 0, "z": 0 },
108
+ "shape": {
109
+ "type": "box",
110
+ "offset": { "x": 0, "y": 0, "z": 0 },
111
+ "stretch": { "x": 1, "y": 1, "z": 1 },
112
+ "settings": {
113
+ "size": { "x": 4, "y": 12, "z": 4 }
114
+ },
115
+ "textureLayout": {
116
+ "front": { "offset": { "x": 0, "y": 0 }, "mirror": { "x": false, "y": false }, "angle": 0 },
117
+ "back": { "offset": { "x": 0, "y": 0 }, "mirror": { "x": false, "y": false }, "angle": 0 },
118
+ "left": { "offset": { "x": 0, "y": 0 }, "mirror": { "x": false, "y": false }, "angle": 0 },
119
+ "right": { "offset": { "x": 0, "y": 0 }, "mirror": { "x": false, "y": false }, "angle": 0 },
120
+ "top": { "offset": { "x": 0, "y": 0 }, "mirror": { "x": false, "y": false }, "angle": 0 },
121
+ "bottom": { "offset": { "x": 0, "y": 0 }, "mirror": { "x": false, "y": false }, "angle": 0 }
122
+ },
123
+ "unwrapMode": "custom",
124
+ "visible": true,
125
+ "doubleSided": false,
126
+ "shadingMode": "standard"
127
+ },
128
+ "children": []
129
+ }
130
+ ]
131
+ }
132
+ ]
133
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blockymodel-web",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Web-based 3D editor for BlockyModel format with transform gizmos, hierarchy panel, property editing, and undo/redo",
5
5
  "type": "module",
6
6
  "main": "./dist/blockymodel-web.umd.cjs",