From 7475f5ade202042b5bfbaadace4fd0e5ff84aaba Mon Sep 17 00:00:00 2001 From: Oscar Beaumont Date: Fri, 14 Mar 2025 19:16:58 +0800 Subject: [PATCH 1/4] Reenable Specta integration --- Cargo.lock | 22 +++++++++++++++++++++ Cargo.toml | 6 +++--- editor/Cargo.toml | 1 + editor/src/generate_ts_types.rs | 35 ++++++++------------------------- 4 files changed, 34 insertions(+), 30 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 830d8ac025..181c10d405 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2594,6 +2594,7 @@ dependencies = [ "serde", "serde_json", "specta", + "specta-typescript", "spin", "thiserror 2.0.12", "tokio", @@ -6250,6 +6251,27 @@ dependencies = [ "syn 2.0.99", ] +[[package]] +name = "specta-serde" +version = "0.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77216504061374659e7245eac53d30c7b3e5fe64b88da97c753e7184b0781e63" +dependencies = [ + "specta", + "thiserror 1.0.69", +] + +[[package]] +name = "specta-typescript" +version = "0.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3220a0c365e51e248ac98eab5a6a32f544ff6f961906f09d3ee10903a4f52b2d" +dependencies = [ + "specta", + "specta-serde", + "thiserror 1.0.69", +] + [[package]] name = "spin" version = "0.9.8" diff --git a/Cargo.toml b/Cargo.toml index 27b9876488..5939ecc4bf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -85,11 +85,11 @@ fern = { version = "0.7", features = ["colored"] } num_enum = "0.7" num-derive = "0.4" num-traits = { version = "0.2", default-features = false, features = ["i128"] } -specta = { version = "2.0.0-rc.22", features = [ - "glam", +specta = { version = "=2.0.0-rc.22", features = [ "derive", - # "typescript", + "glam", ] } +specta-typescript = { version = "=0.0.9" } syn = { version = "2.0", default-features = false, features = [ "full", "derive", diff --git a/editor/Cargo.toml b/editor/Cargo.toml index 64c5659ecd..40b19a521d 100644 --- a/editor/Cargo.toml +++ b/editor/Cargo.toml @@ -44,6 +44,7 @@ futures = { workspace = true } glam = { workspace = true, features = ["serde", "debug-glam-assert"] } derivative = { workspace = true } specta = { workspace = true } +specta-typescript = { workspace = true } image = { workspace = true, features = ["bmp", "png"] } dyn-any = { workspace = true } num_enum = { workspace = true } diff --git a/editor/src/generate_ts_types.rs b/editor/src/generate_ts_types.rs index 659b860f16..6904bc242f 100644 --- a/editor/src/generate_ts_types.rs +++ b/editor/src/generate_ts_types.rs @@ -1,34 +1,15 @@ /// Running this test will generate a `types.ts` file at the root of the repo, /// containing every type annotated with `specta::Type` -// #[cfg(all(test, feature = "specta-export"))] -#[ignore] + #[test] fn generate_ts_types() { - // TODO: Un-comment this out when we figure out how to reenable the "typescript` Specta feature flag - - // use crate::messages::prelude::FrontendMessage; - // use specta::ts::{export_named_datatype, BigIntExportBehavior, ExportConfig}; - // use specta::{NamedType, TypeMap}; - // use std::fs::File; - // use std::io::Write; - - // let config = ExportConfig::new().bigint(BigIntExportBehavior::Number); - - // let mut type_map = TypeMap::default(); - - // let datatype = FrontendMessage::definition_named_data_type(&mut type_map); - - // let mut export = String::new(); - - // export += &export_named_datatype(&config, &datatype, &type_map).unwrap(); - - // type_map - // .iter() - // .map(|(_, v)| v) - // .flat_map(|v| export_named_datatype(&config, v, &type_map)) - // .for_each(|e| export += &format!("\n\n{e}")); + use specta::TypeCollection; + use specta_typescript::{BigIntExportBehavior, Typescript}; - // let mut file = File::create("../types.ts").unwrap(); + use crate::messages::prelude::FrontendMessage; - // write!(file, "{export}").ok(); + Typescript::default() + .bigint(BigIntExportBehavior::Number) + .export_to("../frontend/src/bindings.ts", TypeCollection::default().register::()) + .unwrap(); } From bf4b9f23d9b97a6427a26a7df9f5ecf5c4100180 Mon Sep 17 00:00:00 2001 From: Oscar Beaumont Date: Fri, 14 Mar 2025 21:13:27 +0800 Subject: [PATCH 2/4] wasm idea --- Cargo.lock | 2 ++ frontend/bindings_from_node.ts | 2 ++ frontend/wasm/Cargo.toml | 2 ++ frontend/wasm/export.js | 7 +++++++ frontend/wasm/src/lib.rs | 12 ++++++++++++ pnpm-lock.yaml | 9 +++++++++ 6 files changed, 34 insertions(+) create mode 100644 frontend/bindings_from_node.ts create mode 100644 frontend/wasm/export.js create mode 100644 pnpm-lock.yaml diff --git a/Cargo.lock b/Cargo.lock index 181c10d405..82ba680a57 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2631,6 +2631,8 @@ dependencies = [ "ron", "serde", "serde-wasm-bindgen", + "specta", + "specta-typescript", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", diff --git a/frontend/bindings_from_node.ts b/frontend/bindings_from_node.ts new file mode 100644 index 0000000000..38db3fd5c8 --- /dev/null +++ b/frontend/bindings_from_node.ts @@ -0,0 +1,2 @@ +// This file has been generated by Specta. DO NOT EDIT. + diff --git a/frontend/wasm/Cargo.toml b/frontend/wasm/Cargo.toml index 5cd82877bc..a585d2a6ed 100644 --- a/frontend/wasm/Cargo.toml +++ b/frontend/wasm/Cargo.toml @@ -48,6 +48,8 @@ web-sys = { workspace = true, features = [ "HtmlCanvasElement", "IdleRequestOptions", ] } +specta = { workspace = true } +specta-typescript = { workspace = true } # Optional workspace dependencies ron = { workspace = true, optional = true } diff --git a/frontend/wasm/export.js b/frontend/wasm/export.js new file mode 100644 index 0000000000..f224593c66 --- /dev/null +++ b/frontend/wasm/export.js @@ -0,0 +1,7 @@ +import fs from "node:fs"; +import path from "node:path"; +import graphite, { get_specta_types } from "./pkg/graphite_wasm.js"; + +graphite(fs.readFileSync(path.join(import.meta.dirname, './pkg/graphite_wasm_bg.wasm'))).then(() => + fs.writeFileSync("bindings_from_node.ts", get_specta_types()) +); diff --git a/frontend/wasm/src/lib.rs b/frontend/wasm/src/lib.rs index 730fb4215c..c0d6230497 100644 --- a/frontend/wasm/src/lib.rs +++ b/frontend/wasm/src/lib.rs @@ -34,6 +34,18 @@ pub fn init_graphite() { log::set_max_level(log::LevelFilter::Debug); } +#[cfg(debug_assertions)] +#[wasm_bindgen] +pub fn get_specta_types() -> String { + use specta::TypeCollection; + use specta_typescript::{BigIntExportBehavior, Typescript}; + + Typescript::default() + .bigint(BigIntExportBehavior::Number) + .export(&TypeCollection::default()) // TODO: .register::() + .unwrap() // TODO: Error handling with Node script +} + /// When a panic occurs, notify the user and log the error to the JS console before the backend dies pub fn panic_hook(info: &panic::PanicHookInfo) { let info = info.to_string(); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000000..9b60ae1782 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,9 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: {} From 27756aa07da1b2b4e9984eb37fb2de0978e7de91 Mon Sep 17 00:00:00 2001 From: Oscar Beaumont Date: Fri, 14 Mar 2025 21:19:29 +0800 Subject: [PATCH 3/4] improve --- frontend/bindings_from_node.ts | 274 +++++++++++++++++++++++++++++++++ frontend/wasm/src/lib.rs | 6 +- 2 files changed, 277 insertions(+), 3 deletions(-) diff --git a/frontend/bindings_from_node.ts b/frontend/bindings_from_node.ts index 38db3fd5c8..09de261c3b 100644 --- a/frontend/bindings_from_node.ts +++ b/frontend/bindings_from_node.ts @@ -1,2 +1,276 @@ // This file has been generated by Specta. DO NOT EDIT. +export type ActionKeys = { Action: any } | { keys: LayoutKeysGroup } + +export type BoxSelection = { startX: number; startY: number; endX: number; endY: number } + +export type BreadcrumbTrailButtons = { labels: string[]; disabled: boolean; tooltip: string } + +export type CheckboxInput = { checked: boolean; disabled: boolean; icon: string; tooltip: string } + +/** + * Structure that represents a color. + * Internally alpha is stored as `f32` that ranges from `0.0` (transparent) to `1.0` (opaque). + * The other components (RGB) are stored as `f32` that range from `0.0` up to `f32::MAX`, + * the values encode the brightness of each channel proportional to the light intensity in cd/m² (nits) in HDR, and `0.0` (black) to `1.0` (white) in SDR color. + */ +export type Color = { red: number; green: number; blue: number; alpha: number } + +export type ColorInput = { value: FillChoice; disabled: boolean; allowNone: boolean; tooltip: string } + +export type ContextMenuData = { ToggleLayer: { nodeId: NodeId; currentlyIsNode: boolean } } | "CreateNode" + +export type ContextMenuInformation = { contextMenuCoordinates: [number, number]; contextMenuData: ContextMenuData } + +export type Curve = { manipulatorGroups: CurveManipulatorGroup[]; firstHandle: [number, number]; lastHandle: [number, number] } + +export type CurveInput = { value: Curve; disabled: boolean; tooltip: string } + +export type CurveManipulatorGroup = { anchor: [number, number]; handles: [([number, number]), ([number, number])] } + +/** + * The new value of the UI, sent as part of a diff. + * + * An update can represent a single widget or an entire SubLayout, or just a single layout group. + */ +export type DiffUpdate = { subLayout: LayoutGroup[] } | { layoutGroup: LayoutGroup } | { widget: WidgetHolder } + +export type DocumentId = number + +export type DropdownInput = { entries: MenuListEntry[][]; selectedIndex: number | null; drawIcon: boolean; interactive: boolean; disabled: boolean; tooltip: string } + +/** + * Describes the fill of a layer, but unlike [`Fill`], this doesn't store a [`Gradient`] directly but just its [`GradientStops`]. + * + * Can be None, a solid [Color], or a linear/radial [Gradient]. + * + * In the future we'll probably also add a pattern fill. + */ +export type FillChoice = "None" | { Solid: Color } | { Gradient: GradientStops } + +/** + * A font type (storing font family and font style and an optional preview URL) + */ +export type Font = { fontFamily: string; fontStyle: string } + +export type FontInput = { fontFamily: string; fontStyle: string; isStyle: boolean; disabled: boolean; tooltip: string } + +export type FrontendClickTargets = { nodeClickTargets: string[]; layerClickTargets: string[]; portClickTargets: string[]; iconClickTargets: string[]; allNodesBoundingBox: string; importExportsBoundingBox: string; modifyImportExport: string[] } + +export type FrontendDocumentDetails = { isAutoSaved: boolean; isSaved: boolean; name: string; id: DocumentId } + +export type FrontendGraphDataType = "General" | "Raster" | "VectorData" | "Number" | "Group" | "Artboard" + +export type FrontendGraphInput = { dataType: FrontendGraphDataType; name: string; resolvedType: string | null; validTypes: string[]; connectedTo: OutputConnector | null } + +export type FrontendGraphOutput = { dataType: FrontendGraphDataType; name: string; resolvedType: string | null; connectedTo: InputConnector[] } + +export type FrontendMessage = { DisplayDialog: { title: string; icon: string } } | "DisplayDialogDismiss" | { DisplayDialogPanic: { panicInfo: string } } | { DisplayEditableTextbox: { text: string; lineHeightRatio: number; fontSize: number; color: Color; url: string; transform: [number, number, number, number, number, number]; maxWidth: number | null; maxHeight: number | null } } | { DisplayEditableTextboxTransform: { transform: [number, number, number, number, number, number] } } | "DisplayRemoveEditableTextbox" | { SendUIMetadata: { inputTypeDescriptions: ([string, string])[]; nodeDescriptions: ([string, string])[]; nodeTypes: FrontendNodeType[] } } | { TriggerAboutGraphiteLocalizedCommitDate: { commitDate: string } } | "TriggerDelayedZoomCanvasToFitAll" | { TriggerDownloadImage: { svg: string; name: string; mime: string; size: [number, number] } } | { TriggerDownloadTextFile: { document: string; name: string } } | { TriggerFetchAndOpenDocument: { name: string; filename: string } } | { TriggerFontLoad: { font: Font } } | "TriggerImport" | { TriggerIndexedDbRemoveDocument: { documentId: DocumentId } } | { TriggerIndexedDbWriteDocument: { document: string; details: FrontendDocumentDetails } } | "TriggerLoadFirstAutoSaveDocument" | "TriggerLoadRestAutoSaveDocuments" | "TriggerLoadPreferences" | "TriggerOpenDocument" | "TriggerPaste" | { TriggerSavePreferences: { preferences: PreferencesMessageHandler } } | { TriggerSaveActiveDocument: { documentId: DocumentId } } | "TriggerTextCommit" | { TriggerTextCopy: { copyText: string } } | { TriggerUpgradeDocumentToVectorManipulationFormat: { documentId: DocumentId; documentName: string; documentIsAutoSaved: boolean; documentIsSaved: boolean; documentSerializedContent: string } } | { TriggerVisitLink: { url: string } } | { UpdateActiveDocument: { documentId: DocumentId } } | { UpdateImportsExports: { imports: ([FrontendGraphOutput, number, number])[]; exports: ([FrontendGraphInput, number, number])[]; addImport: [number, number] | null; addExport: [number, number] | null } } | { UpdateInSelectedNetwork: { inSelectedNetwork: boolean } } | { UpdateBox: { box: BoxSelection | null } } | { UpdateContextMenuInformation: { contextMenuInformation: ContextMenuInformation | null } } | { UpdateClickTargets: { clickTargets: FrontendClickTargets | null } } | { UpdateGraphViewOverlay: { open: boolean } } | { UpdateImportReorderIndex: { importIndex: number | null } } | { UpdateExportReorderIndex: { exportIndex: number | null } } | { UpdateLayerWidths: { layerWidths: Partial<{ [key in NodeId]: number }>; chainWidths: Partial<{ [key in NodeId]: number }>; hasLeftInputWire: Partial<{ [key in NodeId]: boolean }> } } | { UpdateDialogButtons: { layoutTarget: LayoutTarget; diff: WidgetDiff[] } } | { UpdateDialogColumn1: { layoutTarget: LayoutTarget; diff: WidgetDiff[] } } | { UpdateDialogColumn2: { layoutTarget: LayoutTarget; diff: WidgetDiff[] } } | { UpdateDocumentArtwork: { svg: string } } | { UpdateDocumentBarLayout: { layoutTarget: LayoutTarget; diff: WidgetDiff[] } } | { UpdateDocumentLayerDetails: { data: LayerPanelEntry } } | { UpdateDocumentLayerStructure: { dataBuffer: RawBuffer } } | { UpdateDocumentLayerStructureJs: { dataBuffer: JsRawBuffer } } | { UpdateDocumentModeLayout: { layoutTarget: LayoutTarget; diff: WidgetDiff[] } } | { UpdateDocumentRulers: { origin: [number, number]; spacing: number; interval: number; visible: boolean } } | { UpdateDocumentScrollbars: { position: [number, number]; size: [number, number]; multiplier: [number, number] } } | { UpdateEyedropperSamplingState: { mousePosition: [number, number] | null; primaryColor: string; secondaryColor: string; setColorChoice: string | null } } | { UpdateGraphFadeArtwork: { percentage: number } } | { UpdateInputHints: { hintData: HintData } } | { UpdateLayersPanelControlBarLayout: { layoutTarget: LayoutTarget; diff: WidgetDiff[] } } | { UpdateMenuBarLayout: { layoutTarget: LayoutTarget; layout: MenuBarEntry[] } } | { UpdateMouseCursor: { cursor: MouseCursorIcon } } | { UpdateNodeGraph: { nodes: FrontendNode[]; wires: FrontendNodeWire[]; wiresDirectNotGridAligned: boolean } } | { UpdateNodeGraphControlBarLayout: { layoutTarget: LayoutTarget; diff: WidgetDiff[] } } | { UpdateNodeGraphSelection: { selected: NodeId[] } } | { UpdateNodeGraphTransform: { transform: Transform } } | { UpdateNodeThumbnail: { id: NodeId; value: string } } | { UpdateOpenDocumentsList: { openDocuments: FrontendDocumentDetails[] } } | { UpdatePropertyPanelSectionsLayout: { layoutTarget: LayoutTarget; diff: WidgetDiff[] } } | { UpdateToolOptionsLayout: { layoutTarget: LayoutTarget; diff: WidgetDiff[] } } | { UpdateToolShelfLayout: { layoutTarget: LayoutTarget; diff: WidgetDiff[] } } | { UpdateWirePathInProgress: { wirePath: WirePath | null } } | { UpdateWorkingColorsLayout: { layoutTarget: LayoutTarget; diff: WidgetDiff[] } } + +export type FrontendNode = { id: NodeId; isLayer: boolean; canBeLayer: boolean; reference: string | null; displayName: string; primaryInput: FrontendGraphInput | null; exposedInputs: FrontendGraphInput[]; primaryOutput: FrontendGraphOutput | null; exposedOutputs: FrontendGraphOutput[]; position: [number, number]; visible: boolean; locked: boolean; previewed: boolean; errors: string | null; uiOnly: boolean } + +export type FrontendNodeType = { name: string; category: string } + +export type FrontendNodeWire = { wireStart: OutputConnector; wireEnd: InputConnector; dashed: boolean } + +/** + * A list of colors associated with positions (in the range 0 to 1) along a gradient. + */ +export type GradientStops = ([number, Color])[] + +export type GraphWireStyle = "Direct" | "GridAligned" + +export type HintData = HintGroup[] + +export type HintGroup = HintInfo[] + +export type HintInfo = { +/** + * A `KeysGroup` specifies all the keys pressed simultaneously to perform an action (like "Ctrl C" to copy). + * Usually at most one is given, but less commonly, multiple can be used to describe additional hotkeys not used simultaneously (like the four different arrow keys to nudge a layer). + */ +keyGroups: LayoutKeysGroup[]; +/** + * `None` means that the regular `key_groups` should be used for all platforms, `Some` is an override for a Mac-only input hint. + */ +keyGroupsMac: LayoutKeysGroup[] | null; +/** + * An optional `MouseMotion` that can indicate the mouse action, like which mouse button is used and whether a drag occurs. + * No such icon is shown if `None` is given, and it can be combined with `key_groups` if desired. + */ +mouse: MouseMotion | null; +/** + * The text describing what occurs with this input combination. + */ +label: string; +/** + * Draws a prepended "+" symbol which indicates that this is a refinement upon a previous hint in the group. + */ +plus: boolean; +/** + * Draws a prepended "/" symbol which indicates that this is an alternative to a previous hint in the group. + */ +slash: boolean } + +export type IconButton = { icon: string; hoverIcon: string | null; size: number; disabled: boolean; active: boolean; tooltip: string } + +export type IconLabel = { icon: string; disabled: boolean; tooltip: string } + +export type ImageButton = { image: string; width: string | null; height: string | null; tooltip: string } + +/** + * Represents an input connector with index based on the [`DocumentNode::inputs`] index, not the visible input index + */ +export type InputConnector = { node: { nodeId: NodeId; inputIndex: number } } | { export: number } + +/** + * This widget allows for the flexible use of the layout system. + * In a custom layout, one can define a widget that is just used to trigger code on the backend. + * This is used in MenuLayout to pipe the triggering of messages from the frontend to backend. + */ +export type InvisibleStandinInput = Record + +export type JsRawBuffer = number[] + +export type LayerPanelEntry = { id: NodeId; alias: string; tooltip: string; inSelectedNetwork: boolean; childrenAllowed: boolean; childrenPresent: boolean; expanded: boolean; depth: number; visible: boolean; parentsVisible: boolean; unlocked: boolean; parentsUnlocked: boolean; parentId: NodeId | null; selected: boolean; ancestorOfSelected: boolean; descendantOfSelected: boolean } + +export type LayoutGroup = { column: { columnWidgets: WidgetHolder[] } } | { row: { rowWidgets: WidgetHolder[] } } | { section: { name: string; visible: boolean; pinned: boolean; id: number; layout: LayoutGroup[] } } + +export type LayoutKey = { key: string; label: string } + +export type LayoutKeysGroup = LayoutKey[] + +export type LayoutTarget = +/** + * Contains the action buttons at the bottom of the dialog. Must be shown with the `FrontendMessage::DisplayDialog` message. + */ +"DialogButtons" | +/** + * Contains the contents of the dialog's primary column. Must be shown with the `FrontendMessage::DisplayDialog` message. + */ +"DialogColumn1" | +/** + * Contains the contents of the dialog's secondary column (often blank). Must be shown with the `FrontendMessage::DisplayDialog` message. + */ +"DialogColumn2" | +/** + * Contains the widgets located directly above the canvas to the right, for example the zoom in and out buttons. + */ +"DocumentBar" | +/** + * Contains the dropdown for design / select / guide mode found on the top left of the canvas. + */ +"DocumentMode" | +/** + * Options for opacity seen at the top of the Layers panel. + */ +"LayersPanelControlBar" | +/** + * The dropdown menu at the very top of the application: File, Edit, etc. + */ +"MenuBar" | +/** + * Bar at the top of the node graph containing the location and the "Preview" and "Hide" buttons. + */ +"NodeGraphControlBar" | +/** + * The body of the Properties panel containing many collapsable sections. + */ +"PropertiesSections" | +/** + * The bar directly above the canvas, left-aligned and to the right of the document mode dropdown. + */ +"ToolOptions" | +/** + * The vertical buttons for all of the tools on the left of the canvas. + */ +"ToolShelf" | +/** + * The color swatch for the working colors and a flip and reset button found at the bottom of the tool shelf. + */ +"WorkingColors" | "LayoutTargetLength" + +export type MenuBarEntry = { label: string; icon: string | null; shortcut: ActionKeys | null; action: WidgetHolder; children: MenuBarEntryChildren; disabled: boolean } + +export type MenuBarEntryChildren = MenuBarEntry[][] + +export type MenuListEntry = { value: string; label: string; icon: string; shortcut: string[]; shortcutRequiresLock: boolean; disabled: boolean; children: MenuListEntry[][] } + +export type MouseCursorIcon = "Default" | "None" | "ZoomIn" | "ZoomOut" | "Grabbing" | "Crosshair" | "Text" | "Move" | "NSResize" | "EWResize" | "NESWResize" | "NWSEResize" | "Rotate" + +export type MouseMotion = "None" | "Lmb" | "Rmb" | "Mmb" | "ScrollUp" | "ScrollDown" | "Drag" | "LmbDouble" | "LmbDrag" | "RmbDrag" | "RmbDouble" | "MmbDrag" + +export type NodeCatalog = { disabled: boolean } + +export type NodeId = number + +export type NumberInput = { label: string; tooltip: string; disabled: boolean; value: number | null; min: number | null; max: number | null; isInteger: boolean; displayDecimalPlaces: number; unit: string; unitIsHiddenWhenEditing: boolean; mode: NumberInputMode; incrementBehavior: NumberInputIncrementBehavior; step: number; rangeMin: number | null; rangeMax: number | null; minWidth: number } + +export type NumberInputIncrementBehavior = "Add" | "Multiply" | "Callback" + +export type NumberInputMode = "Increment" | "Range" + +/** + * Represents an output connector + */ +export type OutputConnector = { node: { nodeId: NodeId; outputIndex: number } } | { import: number } + +export type ParameterExposeButton = { exposed: boolean; dataType: FrontendGraphDataType; tooltip: string } + +export type PivotInput = { position: PivotPosition; disabled: boolean } + +export type PivotPosition = "None" | "TopLeft" | "TopCenter" | "TopRight" | "CenterLeft" | "Center" | "CenterRight" | "BottomLeft" | "BottomCenter" | "BottomRight" + +export type PopoverButton = { style: string | null; icon: string | null; disabled: boolean; tooltip: string; popoverLayout: LayoutGroup[]; popoverMinWidth: number | null } + +export type PreferencesMessageHandler = { imaginate_server_hostname: string; imaginate_refresh_frequency: number; selection_mode: SelectionMode; zoom_with_scroll: boolean; use_vello: boolean; vector_meshes: boolean; graph_wire_style: GraphWireStyle } + +export type RadioEntryData = { value: string; label: string; icon: string; tooltip: string } + +export type RadioInput = { entries: RadioEntryData[]; disabled: boolean; selectedIndex: number | null; minWidth: number } + +export type RawBuffer = number[] + +export type SelectionMode = "Touched" | "Enclosed" | "Directional" + +export type Separator = { direction: SeparatorDirection; type: SeparatorType } + +export type SeparatorDirection = "Horizontal" | "Vertical" + +export type SeparatorType = "Related" | "Unrelated" | "Section" + +export type TextAreaInput = { value: string; label: string | null; disabled: boolean; tooltip: string } + +export type TextButton = { label: string; icon: string | null; hoverIcon: string | null; flush: boolean; emphasized: boolean; minWidth: number; disabled: boolean; tooltip: string; menuListChildren: MenuListEntry[][] } + +export type TextInput = { value: string; label: string | null; disabled: boolean; tooltip: string; centered: boolean; minWidth: number } + +export type TextLabel = { disabled: boolean; bold: boolean; italic: boolean; centerAlign: boolean; tableAlign: boolean; multiline: boolean; minWidth: number; tooltip: string; value: string } + +export type Transform = { scale: number; x: number; y: number } + +export type Widget = { BreadcrumbTrailButtons: BreadcrumbTrailButtons } | { CheckboxInput: CheckboxInput } | { ColorInput: ColorInput } | { CurveInput: CurveInput } | { DropdownInput: DropdownInput } | { FontInput: FontInput } | { IconButton: IconButton } | { IconLabel: IconLabel } | { ImageButton: ImageButton } | { InvisibleStandinInput: InvisibleStandinInput } | { NodeCatalog: NodeCatalog } | { NumberInput: NumberInput } | { ParameterExposeButton: ParameterExposeButton } | { PivotInput: PivotInput } | { PopoverButton: PopoverButton } | { RadioInput: RadioInput } | { Separator: Separator } | { TextAreaInput: TextAreaInput } | { TextButton: TextButton } | { TextInput: TextInput } | { TextLabel: TextLabel } | { WorkingColorsInput: WorkingColorsInput } + +/** + * A single change to part of the UI, containing the location of the change and the new value. + */ +export type WidgetDiff = { +/** + * A path to the change + * e.g. [0, 1, 2] in the properties panel is the first section, second row and third widget. + * An empty path [] shows that the entire panel has changed and is sent when the UI is first created. + */ +widgetPath: number[]; +/** + * What the specified part of the UI has changed to. + */ +newValue: DiffUpdate } + +export type WidgetHolder = { widgetId: WidgetId; widget: Widget } + +export type WidgetId = number + +export type WirePath = { pathString: string; dataType: FrontendGraphDataType; thick: boolean; dashed: boolean } + +export type WorkingColorsInput = { primary: Color; secondary: Color } + diff --git a/frontend/wasm/src/lib.rs b/frontend/wasm/src/lib.rs index c0d6230497..bc7cfb98e6 100644 --- a/frontend/wasm/src/lib.rs +++ b/frontend/wasm/src/lib.rs @@ -36,14 +36,14 @@ pub fn init_graphite() { #[cfg(debug_assertions)] #[wasm_bindgen] -pub fn get_specta_types() -> String { +pub fn get_specta_types() -> Result { use specta::TypeCollection; use specta_typescript::{BigIntExportBehavior, Typescript}; Typescript::default() .bigint(BigIntExportBehavior::Number) - .export(&TypeCollection::default()) // TODO: .register::() - .unwrap() // TODO: Error handling with Node script + .export(&TypeCollection::default().register::()) + .map_err(|err| err.to_string()) } /// When a panic occurs, notify the user and log the error to the JS console before the backend dies From 54cbb5e66731ed2418c731832770d83bc6925f11 Mon Sep 17 00:00:00 2001 From: Oscar Beaumont Date: Sat, 3 May 2025 02:37:24 +0800 Subject: [PATCH 4/4] Delete pnpm-lock.yaml --- pnpm-lock.yaml | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 pnpm-lock.yaml diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml deleted file mode 100644 index 9b60ae1782..0000000000 --- a/pnpm-lock.yaml +++ /dev/null @@ -1,9 +0,0 @@ -lockfileVersion: '9.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -importers: - - .: {}