blockymodel-web 0.1.0

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.
Files changed (71) hide show
  1. package/LICENSE +21 -0
  2. package/dist/blockymodel-web.js +2717 -0
  3. package/dist/blockymodel-web.js.map +1 -0
  4. package/dist/blockymodel-web.umd.cjs +122 -0
  5. package/dist/blockymodel-web.umd.cjs.map +1 -0
  6. package/dist/editor/Editor.d.ts +94 -0
  7. package/dist/editor/Editor.d.ts.map +1 -0
  8. package/dist/editor/History.d.ts +52 -0
  9. package/dist/editor/History.d.ts.map +1 -0
  10. package/dist/editor/SelectionManager.d.ts +57 -0
  11. package/dist/editor/SelectionManager.d.ts.map +1 -0
  12. package/dist/editor/Serializer.d.ts +44 -0
  13. package/dist/editor/Serializer.d.ts.map +1 -0
  14. package/dist/editor/TransformManager.d.ts +73 -0
  15. package/dist/editor/TransformManager.d.ts.map +1 -0
  16. package/dist/editor/commands/AddNodeCommand.d.ts +24 -0
  17. package/dist/editor/commands/AddNodeCommand.d.ts.map +1 -0
  18. package/dist/editor/commands/Command.d.ts +50 -0
  19. package/dist/editor/commands/Command.d.ts.map +1 -0
  20. package/dist/editor/commands/RemoveNodeCommand.d.ts +28 -0
  21. package/dist/editor/commands/RemoveNodeCommand.d.ts.map +1 -0
  22. package/dist/editor/commands/SetPositionCommand.d.ts +24 -0
  23. package/dist/editor/commands/SetPositionCommand.d.ts.map +1 -0
  24. package/dist/editor/commands/SetPropertyCommand.d.ts +41 -0
  25. package/dist/editor/commands/SetPropertyCommand.d.ts.map +1 -0
  26. package/dist/editor/commands/SetRotationCommand.d.ts +24 -0
  27. package/dist/editor/commands/SetRotationCommand.d.ts.map +1 -0
  28. package/dist/editor/commands/SetScaleCommand.d.ts +24 -0
  29. package/dist/editor/commands/SetScaleCommand.d.ts.map +1 -0
  30. package/dist/editor/index.d.ts +15 -0
  31. package/dist/editor/index.d.ts.map +1 -0
  32. package/dist/index.d.ts +21 -0
  33. package/dist/index.d.ts.map +1 -0
  34. package/dist/loaders/BlockyModelLoader.d.ts +48 -0
  35. package/dist/loaders/BlockyModelLoader.d.ts.map +1 -0
  36. package/dist/types/blockymodel.d.ts +72 -0
  37. package/dist/types/blockymodel.d.ts.map +1 -0
  38. package/dist/ui/HierarchyPanel.d.ts +73 -0
  39. package/dist/ui/HierarchyPanel.d.ts.map +1 -0
  40. package/dist/ui/PropertyPanel.d.ts +59 -0
  41. package/dist/ui/PropertyPanel.d.ts.map +1 -0
  42. package/dist/ui/UVEditor.d.ts +56 -0
  43. package/dist/ui/UVEditor.d.ts.map +1 -0
  44. package/dist/ui/index.d.ts +4 -0
  45. package/dist/ui/index.d.ts.map +1 -0
  46. package/dist/viewer/ViewerController.d.ts +71 -0
  47. package/dist/viewer/ViewerController.d.ts.map +1 -0
  48. package/package.json +63 -0
  49. package/src/editor/Editor.ts +196 -0
  50. package/src/editor/History.ts +123 -0
  51. package/src/editor/SelectionManager.ts +183 -0
  52. package/src/editor/Serializer.ts +212 -0
  53. package/src/editor/TransformManager.ts +270 -0
  54. package/src/editor/commands/AddNodeCommand.ts +53 -0
  55. package/src/editor/commands/Command.ts +63 -0
  56. package/src/editor/commands/RemoveNodeCommand.ts +59 -0
  57. package/src/editor/commands/SetPositionCommand.ts +51 -0
  58. package/src/editor/commands/SetPropertyCommand.ts +100 -0
  59. package/src/editor/commands/SetRotationCommand.ts +51 -0
  60. package/src/editor/commands/SetScaleCommand.ts +51 -0
  61. package/src/editor/index.ts +19 -0
  62. package/src/index.ts +49 -0
  63. package/src/loaders/BlockyModelLoader.ts +281 -0
  64. package/src/main.ts +290 -0
  65. package/src/styles.css +597 -0
  66. package/src/types/blockymodel.ts +82 -0
  67. package/src/ui/HierarchyPanel.ts +343 -0
  68. package/src/ui/PropertyPanel.ts +434 -0
  69. package/src/ui/UVEditor.ts +336 -0
  70. package/src/ui/index.ts +4 -0
  71. package/src/viewer/ViewerController.ts +295 -0
@@ -0,0 +1,48 @@
1
+ import * as THREE from "three";
2
+ import type { BlockyModel } from "../types/blockymodel";
3
+ /**
4
+ * Loader for .blockymodel files
5
+ * Parses JSON and builds Three.js Object3D hierarchy
6
+ */
7
+ export declare class BlockyModelLoader extends THREE.Loader {
8
+ constructor(manager?: THREE.LoadingManager);
9
+ /**
10
+ * Load a .blockymodel file from URL
11
+ */
12
+ load(url: string): Promise<THREE.Group>;
13
+ /**
14
+ * Load from File object (for drag-drop / file input)
15
+ */
16
+ loadFromFile(file: File): Promise<THREE.Group>;
17
+ /**
18
+ * Parse BlockyModel JSON into Three.js scene graph
19
+ */
20
+ parse(json: BlockyModel): THREE.Group;
21
+ /**
22
+ * Recursively parse a BlockyNode into Three.js Object3D
23
+ */
24
+ private parseNode;
25
+ /**
26
+ * Create the appropriate Object3D based on shape type
27
+ */
28
+ private createNodeObject;
29
+ /**
30
+ * Create a box mesh from shape data
31
+ */
32
+ private createBox;
33
+ /**
34
+ * Create a quad (plane) mesh from shape data
35
+ */
36
+ private createQuad;
37
+ /**
38
+ * Create material based on shading mode
39
+ * Phase 1: Basic color material, texture mapping in Phase 2
40
+ */
41
+ private createMaterial;
42
+ }
43
+ /**
44
+ * Helper to apply a texture to all meshes in a loaded model
45
+ * Phase 1: Simple texture application without UV mapping
46
+ */
47
+ export declare function applyTextureToModel(model: THREE.Group, texture: THREE.Texture): void;
48
+ //# sourceMappingURL=BlockyModelLoader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BlockyModelLoader.d.ts","sourceRoot":"","sources":["../../src/loaders/BlockyModelLoader.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,EACV,WAAW,EAIZ,MAAM,sBAAsB,CAAC;AAO9B;;;GAGG;AACH,qBAAa,iBAAkB,SAAQ,KAAK,CAAC,MAAM;gBACrC,OAAO,CAAC,EAAE,KAAK,CAAC,cAAc;IAI1C;;OAEG;IACG,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC;IAS7C;;OAEG;IACG,YAAY,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC;IAMpD;;OAEG;IACH,KAAK,CAAC,IAAI,EAAE,WAAW,GAAG,KAAK,CAAC,KAAK;IAcrC;;OAEG;IACH,OAAO,CAAC,SAAS;IAyBjB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAsBxB;;OAEG;IACH,OAAO,CAAC,SAAS;IAkCjB;;OAEG;IACH,OAAO,CAAC,UAAU;IA6DlB;;;OAGG;IACH,OAAO,CAAC,cAAc;CAqCvB;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,KAAK,CAAC,KAAK,EAClB,OAAO,EAAE,KAAK,CAAC,OAAO,GACrB,IAAI,CAgBN"}
@@ -0,0 +1,72 @@
1
+ /**
2
+ * BlockyModel format type definitions
3
+ * Based on Hytale's native 3D model format
4
+ */
5
+ export interface Vec3 {
6
+ x: number;
7
+ y: number;
8
+ z: number;
9
+ }
10
+ export interface Vec2 {
11
+ x: number;
12
+ y: number;
13
+ }
14
+ export interface Quaternion {
15
+ w: number;
16
+ x: number;
17
+ y: number;
18
+ z: number;
19
+ }
20
+ export interface FaceUV {
21
+ offset: Vec2;
22
+ mirror: {
23
+ x: boolean;
24
+ y: boolean;
25
+ };
26
+ angle: 0 | 90 | 180 | 270;
27
+ }
28
+ export interface TextureLayout {
29
+ front?: FaceUV;
30
+ back?: FaceUV;
31
+ left?: FaceUV;
32
+ right?: FaceUV;
33
+ top?: FaceUV;
34
+ bottom?: FaceUV;
35
+ }
36
+ export type ShapeType = "box" | "quad" | "none";
37
+ export type ShadingMode = "standard" | "flat" | "fullbright" | "reflective";
38
+ export type NormalDirection = "+X" | "-X" | "+Y" | "-Y" | "+Z" | "-Z";
39
+ export interface ShapeSettings {
40
+ size?: Vec3;
41
+ normal?: NormalDirection;
42
+ isPiece?: boolean;
43
+ isStaticBox?: boolean;
44
+ }
45
+ export interface BlockyShape {
46
+ type: ShapeType;
47
+ offset: Vec3;
48
+ stretch: Vec3;
49
+ settings: ShapeSettings;
50
+ textureLayout: TextureLayout;
51
+ unwrapMode: "custom" | "auto";
52
+ visible: boolean;
53
+ doubleSided: boolean;
54
+ shadingMode: ShadingMode;
55
+ }
56
+ export interface BlockyNode {
57
+ id: string;
58
+ name: string;
59
+ position?: Vec3;
60
+ orientation?: Quaternion;
61
+ shape: BlockyShape;
62
+ children: BlockyNode[];
63
+ }
64
+ export interface BlockyModel {
65
+ lod?: "auto" | string;
66
+ format?: "character" | "prop";
67
+ nodes: BlockyNode[];
68
+ }
69
+ export declare const DEFAULT_POSITION: Vec3;
70
+ export declare const DEFAULT_ORIENTATION: Quaternion;
71
+ export declare const DEFAULT_STRETCH: Vec3;
72
+ //# sourceMappingURL=blockymodel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blockymodel.d.ts","sourceRoot":"","sources":["../../src/types/blockymodel.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,IAAI;IACnB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,MAAM,WAAW,IAAI;IACnB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,MAAM,WAAW,UAAU;IACzB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,MAAM,WAAW,MAAM;IACrB,MAAM,EAAE,IAAI,CAAC;IACb,MAAM,EAAE;QAAE,CAAC,EAAE,OAAO,CAAC;QAAC,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IACnC,KAAK,EAAE,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,GAAG,CAAC;CAC3B;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,SAAS,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,CAAC;AAEhD,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,MAAM,GAAG,YAAY,GAAG,YAAY,CAAC;AAE5E,MAAM,MAAM,eAAe,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAEtE,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,SAAS,CAAC;IAChB,MAAM,EAAE,IAAI,CAAC;IACb,OAAO,EAAE,IAAI,CAAC;IACd,QAAQ,EAAE,aAAa,CAAC;IACxB,aAAa,EAAE,aAAa,CAAC;IAC7B,UAAU,EAAE,QAAQ,GAAG,MAAM,CAAC;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,WAAW,CAAC;CAC1B;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,IAAI,CAAC;IAChB,WAAW,CAAC,EAAE,UAAU,CAAC;IACzB,KAAK,EAAE,WAAW,CAAC;IACnB,QAAQ,EAAE,UAAU,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,WAAW;IAC1B,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,WAAW,GAAG,MAAM,CAAC;IAC9B,KAAK,EAAE,UAAU,EAAE,CAAC;CACrB;AAGD,eAAO,MAAM,gBAAgB,EAAE,IAA2B,CAAC;AAC3D,eAAO,MAAM,mBAAmB,EAAE,UAAuC,CAAC;AAC1E,eAAO,MAAM,eAAe,EAAE,IAA2B,CAAC"}
@@ -0,0 +1,73 @@
1
+ import type { Editor } from "../editor/Editor";
2
+ /**
3
+ * Hierarchy panel showing the model tree structure
4
+ */
5
+ export declare class HierarchyPanel {
6
+ private editor;
7
+ private container;
8
+ private treeContainer;
9
+ private contextMenu;
10
+ private contextTarget;
11
+ constructor(editor: Editor, containerId: string);
12
+ /**
13
+ * Build the hierarchy panel UI
14
+ */
15
+ private buildUI;
16
+ /**
17
+ * Setup event listeners
18
+ */
19
+ private setupEventListeners;
20
+ /**
21
+ * Refresh the hierarchy tree
22
+ */
23
+ refresh(): void;
24
+ /**
25
+ * Build tree recursively
26
+ */
27
+ private buildTree;
28
+ /**
29
+ * Get icon for object type
30
+ */
31
+ private getIcon;
32
+ /**
33
+ * Toggle expand/collapse
34
+ */
35
+ private toggleExpand;
36
+ /**
37
+ * Update selection highlight
38
+ */
39
+ private updateSelection;
40
+ /**
41
+ * Show context menu
42
+ */
43
+ private showContextMenu;
44
+ /**
45
+ * Hide context menu
46
+ */
47
+ private hideContextMenu;
48
+ /**
49
+ * Handle context menu action
50
+ */
51
+ private handleContextAction;
52
+ /**
53
+ * Add a child box
54
+ */
55
+ private addChildBox;
56
+ /**
57
+ * Add a child group
58
+ */
59
+ private addChildGroup;
60
+ /**
61
+ * Duplicate a node
62
+ */
63
+ private duplicateNode;
64
+ /**
65
+ * Delete a node
66
+ */
67
+ private deleteNode;
68
+ /**
69
+ * Cleanup
70
+ */
71
+ dispose(): void;
72
+ }
73
+ //# sourceMappingURL=HierarchyPanel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HierarchyPanel.d.ts","sourceRoot":"","sources":["../../src/ui/HierarchyPanel.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAI/C;;GAEG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,SAAS,CAAc;IAC/B,OAAO,CAAC,aAAa,CAAe;IACpC,OAAO,CAAC,WAAW,CAA4B;IAC/C,OAAO,CAAC,aAAa,CAA+B;gBAExC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM;IAY/C;;OAEG;IACH,OAAO,CAAC,OAAO;IAsBf;;OAEG;IACH,OAAO,CAAC,mBAAmB;IA0C3B;;OAEG;IACH,OAAO,IAAI,IAAI;IAWf;;OAEG;IACH,OAAO,CAAC,SAAS;IA4DjB;;OAEG;IACH,OAAO,CAAC,OAAO;IAWf;;OAEG;IACH,OAAO,CAAC,YAAY;IAWpB;;OAEG;IACH,OAAO,CAAC,eAAe;IAkBvB;;OAEG;IACH,OAAO,CAAC,eAAe;IAkBvB;;OAEG;IACH,OAAO,CAAC,eAAe;IAOvB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAiB3B;;OAEG;IACH,OAAO,CAAC,WAAW;IAcnB;;OAEG;IACH,OAAO,CAAC,aAAa;IAUrB;;OAEG;IACH,OAAO,CAAC,aAAa;IAYrB;;OAEG;IACH,OAAO,CAAC,UAAU;IAWlB;;OAEG;IACH,OAAO,IAAI,IAAI;CAMhB"}
@@ -0,0 +1,59 @@
1
+ import * as THREE from "three";
2
+ import type { Editor } from "../editor/Editor";
3
+ /**
4
+ * Property panel for editing selected object properties
5
+ */
6
+ export declare class PropertyPanel {
7
+ private editor;
8
+ private container;
9
+ private currentObject;
10
+ private isUpdating;
11
+ private nameInput;
12
+ private posInputs;
13
+ private rotInputs;
14
+ private scaleInputs;
15
+ private sizeInputs;
16
+ private offsetInputs;
17
+ private visibleCheckbox;
18
+ private doubleSidedCheckbox;
19
+ private shadingModeSelect;
20
+ private shapeTypeSpan;
21
+ constructor(editor: Editor, containerId: string);
22
+ /**
23
+ * Build the property panel UI
24
+ */
25
+ private buildUI;
26
+ /**
27
+ * Setup event listeners
28
+ */
29
+ private setupEventListeners;
30
+ /**
31
+ * Setup Vec3 input handlers
32
+ */
33
+ private setupVec3Input;
34
+ /**
35
+ * Set the object to display properties for
36
+ */
37
+ setObject(object: THREE.Object3D | null): void;
38
+ /**
39
+ * Update UI from current object
40
+ */
41
+ private updateFromObject;
42
+ /**
43
+ * Rebuild geometry after size/offset changes
44
+ */
45
+ private rebuildGeometry;
46
+ /**
47
+ * Show property sections
48
+ */
49
+ private showProperties;
50
+ /**
51
+ * Show empty state
52
+ */
53
+ private showEmpty;
54
+ /**
55
+ * Cleanup
56
+ */
57
+ dispose(): void;
58
+ }
59
+ //# sourceMappingURL=PropertyPanel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PropertyPanel.d.ts","sourceRoot":"","sources":["../../src/ui/PropertyPanel.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAO/C;;GAEG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,SAAS,CAAc;IAC/B,OAAO,CAAC,aAAa,CAA+B;IACpD,OAAO,CAAC,UAAU,CAAkB;IAGpC,OAAO,CAAC,SAAS,CAAoB;IACrC,OAAO,CAAC,SAAS,CAAqE;IACtF,OAAO,CAAC,SAAS,CAAqE;IACtF,OAAO,CAAC,WAAW,CAAqE;IACxF,OAAO,CAAC,UAAU,CAAqE;IACvF,OAAO,CAAC,YAAY,CAAqE;IACzF,OAAO,CAAC,eAAe,CAAoB;IAC3C,OAAO,CAAC,mBAAmB,CAAoB;IAC/C,OAAO,CAAC,iBAAiB,CAAqB;IAC9C,OAAO,CAAC,aAAa,CAAe;gBAExB,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM;IAY/C;;OAEG;IACH,OAAO,CAAC,OAAO;IAoHf;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAmH3B;;OAEG;IACH,OAAO,CAAC,cAAc;IAkBtB;;OAEG;IACH,SAAS,CAAC,MAAM,EAAE,KAAK,CAAC,QAAQ,GAAG,IAAI,GAAG,IAAI;IAW9C;;OAEG;IACH,OAAO,CAAC,gBAAgB;IA0DxB;;OAEG;IACH,OAAO,CAAC,eAAe;IAwBvB;;OAEG;IACH,OAAO,CAAC,cAAc;IAUtB;;OAEG;IACH,OAAO,CAAC,SAAS;IAUjB;;OAEG;IACH,OAAO,IAAI,IAAI;CAGhB"}
@@ -0,0 +1,56 @@
1
+ import * as THREE from "three";
2
+ import type { Editor } from "../editor/Editor";
3
+ /**
4
+ * UV Editor panel for per-face texture UV editing
5
+ */
6
+ export declare class UVEditor {
7
+ private editor;
8
+ private container;
9
+ private currentObject;
10
+ private isUpdating;
11
+ private faceInputs;
12
+ constructor(editor: Editor, containerId: string);
13
+ /**
14
+ * Build the UV editor UI
15
+ */
16
+ private buildUI;
17
+ /**
18
+ * Setup event listeners
19
+ */
20
+ private setupEventListeners;
21
+ /**
22
+ * Handle face UV change
23
+ */
24
+ private handleFaceChange;
25
+ /**
26
+ * Get texture layout from current object
27
+ */
28
+ private getTextureLayout;
29
+ /**
30
+ * Set the object to edit UVs for
31
+ */
32
+ setObject(object: THREE.Object3D | null): void;
33
+ /**
34
+ * Update UI from current object
35
+ */
36
+ private updateFromObject;
37
+ /**
38
+ * Apply texture layout to geometry UVs
39
+ * Note: This is a simplified implementation - full UV mapping would require
40
+ * knowing the texture atlas dimensions
41
+ */
42
+ private applyTextureLayout;
43
+ /**
44
+ * Show content
45
+ */
46
+ private showContent;
47
+ /**
48
+ * Show empty state
49
+ */
50
+ private showEmpty;
51
+ /**
52
+ * Cleanup
53
+ */
54
+ dispose(): void;
55
+ }
56
+ //# sourceMappingURL=UVEditor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UVEditor.d.ts","sourceRoot":"","sources":["../../src/ui/UVEditor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAsB/C;;GAEG;AACH,qBAAa,QAAQ;IACnB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,SAAS,CAAc;IAC/B,OAAO,CAAC,aAAa,CAA+B;IACpD,OAAO,CAAC,UAAU,CAAkB;IACpC,OAAO,CAAC,UAAU,CAMH;gBAEH,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM;IAY/C;;OAEG;IACH,OAAO,CAAC,OAAO;IA0Df;;OAEG;IACH,OAAO,CAAC,mBAAmB;IA2C3B;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAkCxB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAIxB;;OAEG;IACH,SAAS,CAAC,MAAM,EAAE,KAAK,CAAC,QAAQ,GAAG,IAAI,GAAG,IAAI;IAY9C;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAqBxB;;;;OAIG;IACH,OAAO,CAAC,kBAAkB;IA4D1B;;OAEG;IACH,OAAO,CAAC,WAAW;IAQnB;;OAEG;IACH,OAAO,CAAC,SAAS;IAQjB;;OAEG;IACH,OAAO,IAAI,IAAI;CAIhB"}
@@ -0,0 +1,4 @@
1
+ export { PropertyPanel } from "./PropertyPanel";
2
+ export { HierarchyPanel } from "./HierarchyPanel";
3
+ export { UVEditor } from "./UVEditor";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ui/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,71 @@
1
+ import * as THREE from "three";
2
+ import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
3
+ export interface ViewerOptions {
4
+ container: HTMLElement;
5
+ backgroundColor?: number;
6
+ }
7
+ /**
8
+ * Main viewer controller
9
+ * Manages Three.js scene, camera, controls, and model loading
10
+ */
11
+ export declare class ViewerController {
12
+ readonly scene: THREE.Scene;
13
+ readonly camera: THREE.PerspectiveCamera;
14
+ readonly renderer: THREE.WebGLRenderer;
15
+ readonly controls: OrbitControls;
16
+ readonly domElement: HTMLElement;
17
+ private loader;
18
+ private textureLoader;
19
+ private currentModel;
20
+ private animationId;
21
+ constructor(options: ViewerOptions);
22
+ private setupLighting;
23
+ private setupHelpers;
24
+ private handleResize;
25
+ private animate;
26
+ /**
27
+ * Load a .blockymodel file
28
+ */
29
+ loadModel(file: File): Promise<THREE.Group>;
30
+ /**
31
+ * Get the currently loaded model
32
+ */
33
+ getModel(): THREE.Group | null;
34
+ /**
35
+ * Load a texture and apply to current model
36
+ */
37
+ loadTexture(file: File): Promise<void>;
38
+ /**
39
+ * Fit camera to view the entire model
40
+ */
41
+ fitCameraToModel(): void;
42
+ /**
43
+ * Reset camera to default position
44
+ */
45
+ resetCamera(): void;
46
+ /**
47
+ * Set background color
48
+ */
49
+ setBackgroundColor(color: number | string): void;
50
+ /**
51
+ * Toggle wireframe mode on all meshes
52
+ */
53
+ toggleWireframe(enabled: boolean): void;
54
+ /**
55
+ * Get model hierarchy for debugging
56
+ */
57
+ getModelHierarchy(): object | null;
58
+ /**
59
+ * Count meshes in model
60
+ */
61
+ private countMeshes;
62
+ /**
63
+ * Dispose of model resources
64
+ */
65
+ private disposeModel;
66
+ /**
67
+ * Clean up all resources
68
+ */
69
+ dispose(): void;
70
+ }
71
+ //# sourceMappingURL=ViewerController.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ViewerController.d.ts","sourceRoot":"","sources":["../../src/viewer/ViewerController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,aAAa,EAAE,MAAM,8CAA8C,CAAC;AAG7E,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,WAAW,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;GAGG;AACH,qBAAa,gBAAgB;IAC3B,SAAgB,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC;IACnC,SAAgB,MAAM,EAAE,KAAK,CAAC,iBAAiB,CAAC;IAChD,SAAgB,QAAQ,EAAE,KAAK,CAAC,aAAa,CAAC;IAC9C,SAAgB,QAAQ,EAAE,aAAa,CAAC;IACxC,SAAgB,UAAU,EAAE,WAAW,CAAC;IAExC,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,aAAa,CAAsB;IAC3C,OAAO,CAAC,YAAY,CAA4B;IAChD,OAAO,CAAC,WAAW,CAAuB;gBAE9B,OAAO,EAAE,aAAa;IAiDlC,OAAO,CAAC,aAAa;IAwBrB,OAAO,CAAC,YAAY;IAWpB,OAAO,CAAC,YAAY;IASpB,OAAO,CAAC,OAAO,CAIb;IAEF;;OAEG;IACG,SAAS,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC;IAuBjD;;OAEG;IACH,QAAQ,IAAI,KAAK,CAAC,KAAK,GAAG,IAAI;IAI9B;;OAEG;IACG,WAAW,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAoB5C;;OAEG;IACH,gBAAgB,IAAI,IAAI;IAqBxB;;OAEG;IACH,WAAW,IAAI,IAAI;IAUnB;;OAEG;IACH,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAIhD;;OAEG;IACH,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IASvC;;OAEG;IACH,iBAAiB,IAAI,MAAM,GAAG,IAAI;IAalC;;OAEG;IACH,OAAO,CAAC,WAAW;IAQnB;;OAEG;IACH,OAAO,CAAC,YAAY;IAapB;;OAEG;IACH,OAAO,IAAI,IAAI;CAYhB"}
package/package.json ADDED
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "blockymodel-web",
3
+ "version": "0.1.0",
4
+ "description": "Web-based 3D editor for BlockyModel format with transform gizmos, hierarchy panel, property editing, and undo/redo",
5
+ "type": "module",
6
+ "main": "./dist/blockymodel-web.umd.cjs",
7
+ "module": "./dist/blockymodel-web.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/blockymodel-web.js",
13
+ "require": "./dist/blockymodel-web.umd.cjs"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist",
18
+ "src"
19
+ ],
20
+ "scripts": {
21
+ "dev": "vite",
22
+ "build": "tsc && vite build",
23
+ "build:lib": "vite build --mode lib && tsc -p tsconfig.build.json",
24
+ "preview": "vite preview",
25
+ "typecheck": "tsc --noEmit",
26
+ "test": "vitest",
27
+ "test:run": "vitest run",
28
+ "test:coverage": "vitest run --coverage",
29
+ "prepublishOnly": "npm run build:lib"
30
+ },
31
+ "keywords": [
32
+ "blockymodel",
33
+ "hytale",
34
+ "3d-editor",
35
+ "threejs",
36
+ "voxel",
37
+ "model-editor",
38
+ "webgl"
39
+ ],
40
+ "author": "Zacx <zacxdev@gmail.com>",
41
+ "license": "MIT",
42
+ "repository": {
43
+ "type": "git",
44
+ "url": "git+https://github.com/ZacxDev/blockymodel-web.git"
45
+ },
46
+ "bugs": {
47
+ "url": "https://github.com/ZacxDev/blockymodel-web/issues"
48
+ },
49
+ "homepage": "https://github.com/ZacxDev/blockymodel-web#readme",
50
+ "peerDependencies": {
51
+ "three": ">=0.150.0"
52
+ },
53
+ "devDependencies": {
54
+ "@types/node": "^25.2.0",
55
+ "@types/three": "^0.170.0",
56
+ "@vitest/coverage-v8": "^4.0.18",
57
+ "jsdom": "^28.0.0",
58
+ "three": "^0.170.0",
59
+ "typescript": "^5.7.0",
60
+ "vite": "^6.0.0",
61
+ "vitest": "^4.0.18"
62
+ }
63
+ }
@@ -0,0 +1,196 @@
1
+ import * as THREE from "three";
2
+ import { SelectionManager } from "./SelectionManager";
3
+ import { TransformManager } from "./TransformManager";
4
+ import { History } from "./History";
5
+ import type { Command } from "./commands/Command";
6
+ import type { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
7
+
8
+ export type EditorEvent =
9
+ | "selectionChanged"
10
+ | "objectChanged"
11
+ | "historyChanged"
12
+ | "modeChanged"
13
+ | "modelLoaded";
14
+
15
+ export interface EditorOptions {
16
+ scene: THREE.Scene;
17
+ camera: THREE.Camera;
18
+ renderer: THREE.WebGLRenderer;
19
+ controls: OrbitControls;
20
+ domElement: HTMLElement;
21
+ }
22
+
23
+ type EventCallback = (...args: unknown[]) => void;
24
+
25
+ /**
26
+ * Central editor state manager
27
+ * Coordinates selection, transforms, history, and emits events for UI updates
28
+ */
29
+ export class Editor {
30
+ public readonly scene: THREE.Scene;
31
+ public readonly camera: THREE.Camera;
32
+ public readonly renderer: THREE.WebGLRenderer;
33
+ public readonly controls: OrbitControls;
34
+ public readonly domElement: HTMLElement;
35
+
36
+ public readonly selection: SelectionManager;
37
+ public readonly transform: TransformManager;
38
+ public readonly history: History;
39
+
40
+ private currentModel: THREE.Group | null = null;
41
+ private eventListeners: Map<EditorEvent, Set<EventCallback>> = new Map();
42
+
43
+ constructor(options: EditorOptions) {
44
+ this.scene = options.scene;
45
+ this.camera = options.camera;
46
+ this.renderer = options.renderer;
47
+ this.controls = options.controls;
48
+ this.domElement = options.domElement;
49
+
50
+ // Initialize subsystems
51
+ this.history = new History();
52
+ this.selection = new SelectionManager(this);
53
+ this.transform = new TransformManager(this);
54
+
55
+ // Forward selection events
56
+ this.selection.on("selectionChanged", (object: THREE.Object3D | null) => {
57
+ this.emit("selectionChanged", object);
58
+ this.transform.attach(object);
59
+ });
60
+
61
+ // Forward transform events
62
+ this.transform.on("objectChanged", (...args: unknown[]) => {
63
+ const object = args[0] as THREE.Object3D;
64
+ const command = args[1] as Command;
65
+ this.history.execute(command);
66
+ this.emit("objectChanged", object);
67
+ });
68
+
69
+ // Forward history events
70
+ this.history.on("historyChanged", () => {
71
+ this.emit("historyChanged");
72
+ });
73
+
74
+ // Listen for mode changes
75
+ this.transform.on("modeChanged", (...args: unknown[]) => {
76
+ const mode = args[0] as string;
77
+ this.emit("modeChanged", mode);
78
+ });
79
+ }
80
+
81
+ /**
82
+ * Set the current model being edited
83
+ */
84
+ setModel(model: THREE.Group | null): void {
85
+ this.currentModel = model;
86
+ this.selection.deselect();
87
+ this.history.clear();
88
+ this.emit("modelLoaded", model);
89
+ }
90
+
91
+ /**
92
+ * Get the current model
93
+ */
94
+ getModel(): THREE.Group | null {
95
+ return this.currentModel;
96
+ }
97
+
98
+ /**
99
+ * Get the currently selected object
100
+ */
101
+ getSelected(): THREE.Object3D | null {
102
+ return this.selection.getSelected();
103
+ }
104
+
105
+ /**
106
+ * Select an object
107
+ */
108
+ select(object: THREE.Object3D | null): void {
109
+ this.selection.select(object);
110
+ }
111
+
112
+ /**
113
+ * Execute a command (adds to history)
114
+ */
115
+ execute(command: Command): void {
116
+ this.history.execute(command);
117
+ this.emit("objectChanged", this.getSelected());
118
+ }
119
+
120
+ /**
121
+ * Undo the last command
122
+ */
123
+ undo(): void {
124
+ this.history.undo();
125
+ this.emit("objectChanged", this.getSelected());
126
+ }
127
+
128
+ /**
129
+ * Redo the last undone command
130
+ */
131
+ redo(): void {
132
+ this.history.redo();
133
+ this.emit("objectChanged", this.getSelected());
134
+ }
135
+
136
+ /**
137
+ * Check if undo is available
138
+ */
139
+ canUndo(): boolean {
140
+ return this.history.canUndo();
141
+ }
142
+
143
+ /**
144
+ * Check if redo is available
145
+ */
146
+ canRedo(): boolean {
147
+ return this.history.canRedo();
148
+ }
149
+
150
+ /**
151
+ * Set transform mode
152
+ */
153
+ setTransformMode(mode: "translate" | "rotate" | "scale"): void {
154
+ this.transform.setMode(mode);
155
+ }
156
+
157
+ /**
158
+ * Get current transform mode
159
+ */
160
+ getTransformMode(): "translate" | "rotate" | "scale" {
161
+ return this.transform.getMode();
162
+ }
163
+
164
+ /**
165
+ * Add event listener
166
+ */
167
+ on(event: EditorEvent, callback: EventCallback): void {
168
+ if (!this.eventListeners.has(event)) {
169
+ this.eventListeners.set(event, new Set());
170
+ }
171
+ this.eventListeners.get(event)!.add(callback);
172
+ }
173
+
174
+ /**
175
+ * Remove event listener
176
+ */
177
+ off(event: EditorEvent, callback: EventCallback): void {
178
+ this.eventListeners.get(event)?.delete(callback);
179
+ }
180
+
181
+ /**
182
+ * Emit an event
183
+ */
184
+ emit(event: EditorEvent, ...args: unknown[]): void {
185
+ this.eventListeners.get(event)?.forEach((callback) => callback(...args));
186
+ }
187
+
188
+ /**
189
+ * Clean up resources
190
+ */
191
+ dispose(): void {
192
+ this.selection.dispose();
193
+ this.transform.dispose();
194
+ this.eventListeners.clear();
195
+ }
196
+ }