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
5 changes: 5 additions & 0 deletions .github/workflows/website.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@ jobs:
cd website
npm run generate-editor-structure

- name: Generate node catalog documentation
run: |
cd tools/node-docs
cargo run

- name: 🌐 Build Graphite website with Zola
env:
MODE: prod
Expand Down
4 changes: 4 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@
// Configured in `.prettierrc`
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
// Website: don't format Zola/Tera-templated HTML on save
"[html]": {
"editor.formatOnSave": false
},
// Handlebars: don't save on format
// (`about.hbs` is used by Cargo About to encode license information)
"[handlebars]": {
Expand Down
19 changes: 17 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 10 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ members = [
"node-graph/node-macro",
"node-graph/preprocessor",
"proc-macros",
"tools/crate-hierarchy-viz"
"tools/crate-hierarchy-viz",
"tools/node-docs"
]
default-members = [
"editor",
Expand Down Expand Up @@ -137,6 +138,7 @@ log = "0.4"
bitflags = { version = "2.4", features = ["serde"] }
ctor = "0.2"
convert_case = "0.8"
indoc = "2.0.5"
derivative = "2.2"
thiserror = "2"
anyhow = "1.0"
Expand All @@ -151,7 +153,7 @@ wgpu = { version = "27.0", features = [
"spirv",
"strict_asserts",
] }
once_cell = "1.13" # Remove when `core::cell::LazyCell` (<https://doc.rust-lang.org/core/cell/struct.LazyCell.html>) is stabilized in Rust 1.80 and we bump our MSRV
once_cell = "1.13" # Remove and replace with `core::cell::LazyCell` (<https://doc.rust-lang.org/core/cell/struct.LazyCell.html>)
wasm-bindgen = "=0.2.100" # NOTICE: ensure this stays in sync with the `wasm-bindgen-cli` version in `website/content/volunteer/guide/project-setup/_index.md`. We pin this version because wasm-bindgen upgrades may break various things.
wasm-bindgen-futures = "0.4"
js-sys = "=0.3.77"
Expand All @@ -177,10 +179,16 @@ winit = { git = "https://github.com/rust-windowing/winit.git" }
keyboard-types = "0.8"
url = "2.5"
tokio = { version = "1.29", features = ["fs", "macros", "io-std", "rt"] }
# Linebender ecosystem (BEGIN)
kurbo = { version = "0.12", features = ["serde"] }
vello = { git = "https://github.com/linebender/vello" }
vello_encoding = { git = "https://github.com/linebender/vello" }
resvg = "0.45"
usvg = "0.45"
parley = "0.6"
skrifa = "0.36"
polycool = "0.4"
# Linebender ecosystem (END)
rand = { version = "0.9", default-features = false, features = ["std_rng"] }
rand_chacha = "0.9"
glam = { version = "0.29", default-features = false, features = [
Expand All @@ -194,8 +202,6 @@ image = { version = "0.25", default-features = false, features = [
"jpeg",
"bmp",
] }
parley = "0.6"
skrifa = "0.36"
pretty_assertions = "1.4"
fern = { version = "0.7", features = ["colored"] }
num_enum = { version = "0.7", default-features = false }
Expand All @@ -217,7 +223,6 @@ syn = { version = "2.0", default-features = false, features = [
"extra-traits",
"proc-macro",
] }
kurbo = { version = "0.12", features = ["serde"] }
lyon_geom = "1.0"
petgraph = { version = "0.7", default-features = false, features = ["graphmap"] }
half = { version = "2.4", default-features = false, features = ["bytemuck"] }
Expand All @@ -234,7 +239,6 @@ tracing-subscriber = { version = "0.3", features = ["env-filter"] }
tracing = "0.1"
rfd = "0.15"
open = "5.3"
polycool = "0.4"
spin = "0.10"
clap = "4.5"
spirv-std = { git = "https://github.com/Firestar99/rust-gpu-new", rev = "c12f216121820580731440ee79ebc7403d6ea04f", features = ["bytemuck"] }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ pub struct DocumentNodeDefinition {

// We use the once_cell to use the document node definitions throughout the editor without passing a reference
// TODO: If dynamic node library is required, use a Mutex as well
// TODO: Replace with `core::cell::LazyCell` (<https://doc.rust-lang.org/core/cell/struct.LazyCell.html>) or similar
static DOCUMENT_NODE_TYPES: once_cell::sync::Lazy<HashMap<DefinitionIdentifier, DocumentNodeDefinition>> = once_cell::sync::Lazy::new(document_node_definitions);

/// Defines the "signature" or "header file"-like metadata for the document nodes, but not the implementation (which is defined in the node registry).
Expand Down Expand Up @@ -1773,7 +1774,7 @@ fn document_node_definitions() -> HashMap<DefinitionIdentifier, DocumentNodeDefi
},
DocumentNodeDefinition {
identifier: "Boolean Operation",
category: "Vector",
category: "Vector: Modifier",
node_template: NodeTemplate {
document_node: DocumentNode {
implementation: DocumentNodeImplementation::Network(NodeNetwork {
Expand Down Expand Up @@ -2076,6 +2077,7 @@ fn document_node_definitions() -> HashMap<DefinitionIdentifier, DocumentNodeDefi

type NodeProperties = HashMap<String, Box<dyn Fn(NodeId, &mut NodePropertiesContext) -> Vec<LayoutGroup> + Send + Sync>>;

// TODO: Replace with `core::cell::LazyCell` (<https://doc.rust-lang.org/core/cell/struct.LazyCell.html>) or similar
pub static NODE_OVERRIDES: once_cell::sync::Lazy<NodeProperties> = once_cell::sync::Lazy::new(static_node_properties);

/// Defines the logic for inputs to display a custom properties panel widget.
Expand All @@ -2102,6 +2104,7 @@ fn static_node_properties() -> NodeProperties {

type InputProperties = HashMap<String, Box<dyn Fn(NodeId, usize, &mut NodePropertiesContext) -> Result<Vec<LayoutGroup>, String> + Send + Sync>>;

// TODO: Replace with `core::cell::LazyCell` (<https://doc.rust-lang.org/core/cell/struct.LazyCell.html>) or similar
static INPUT_OVERRIDES: once_cell::sync::Lazy<InputProperties> = once_cell::sync::Lazy::new(static_input_properties);

/// Defines the logic for inputs to display a custom properties panel widget.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ pub(super) fn post_process_nodes(custom: Vec<DocumentNodeDefinition>) -> HashMap
..Default::default()
},
},
category: category.unwrap_or("UNCATEGORIZED"),
category,
description: Cow::Borrowed(description),
properties: *properties,
},
Expand Down
4 changes: 2 additions & 2 deletions editor/src/node_graph_executor/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ use graphene_std::wasm_application_io::{RenderOutputType, WasmApplicationIo, Was
use graphene_std::{Artboard, Context, Graphic};
use interpreted_executor::dynamic_executor::{DynamicExecutor, IntrospectError, ResolvedDocumentNodeTypesDelta};
use interpreted_executor::util::wrap_network_in_scope;
use once_cell::sync::Lazy;
use spin::Mutex;
use std::sync::Arc;
use std::sync::mpsc::{Receiver, Sender};
Expand Down Expand Up @@ -108,7 +107,8 @@ impl NodeGraphUpdateSender for InternalNodeGraphUpdateSender {
}
}

pub static NODE_RUNTIME: Lazy<Mutex<Option<NodeRuntime>>> = Lazy::new(|| Mutex::new(None));
// TODO: Replace with `core::cell::LazyCell` (<https://doc.rust-lang.org/core/cell/struct.LazyCell.html>) or similar
pub static NODE_RUNTIME: once_cell::sync::Lazy<Mutex<Option<NodeRuntime>>> = once_cell::sync::Lazy::new(|| Mutex::new(None));

impl NodeRuntime {
pub fn new(receiver: Receiver<GraphRuntimeRequest>, sender: Sender<NodeGraphUpdate>) -> Self {
Expand Down
43 changes: 26 additions & 17 deletions node-graph/graph-craft/src/document/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,15 +116,15 @@ macro_rules! tagged_value {
_ => Err(format!("Cannot convert {:?} to TaggedValue",std::any::type_name_of_val(input))),
}
}
/// Returns a TaggedValue from the type, where that value is its type's `Default::default()`
pub fn from_type(input: &Type) -> Option<Self> {
match input {
Type::Generic(_) => None,
Type::Concrete(concrete_type) => {
let internal_id = concrete_type.id?;
use std::any::TypeId;
// TODO: Add default implementations for types such as TaggedValue::Subpaths, and use the defaults here and in document_node_types
// Tries using the default for the tagged value type. If it not implemented, then uses the default used in document_node_types. If it is not used there, then TaggedValue::None is returned.
Some(match internal_id {
Some(match concrete_type.id? {
x if x == TypeId::of::<()>() => TaggedValue::None,
$( x if x == TypeId::of::<$ty>() => TaggedValue::$identifier(Default::default()), )*
_ => return None,
Expand All @@ -139,6 +139,15 @@ macro_rules! tagged_value {
pub fn from_type_or_none(input: &Type) -> Self {
Self::from_type(input).unwrap_or(TaggedValue::None)
}
pub fn to_debug_string(&self) -> String {
match self {
Self::None => "()".to_string(),
$( Self::$identifier(x) => format!("{:?}", x), )*
Self::RenderOutput(_) => "RenderOutput".to_string(),
Self::SurfaceFrame(_) => "SurfaceFrame".to_string(),
Self::EditorApi(_) => "WasmEditorApi".to_string(),
}
}
}

$(
Expand Down Expand Up @@ -351,24 +360,24 @@ impl TaggedValue {
match ty {
Type::Generic(_) => None,
Type::Concrete(concrete_type) => {
let internal_id = concrete_type.id?;
let ty = concrete_type.id?;
use std::any::TypeId;
// TODO: Add default implementations for types such as TaggedValue::Subpaths, and use the defaults here and in document_node_types
// Tries using the default for the tagged value type. If it not implemented, then uses the default used in document_node_types. If it is not used there, then TaggedValue::None is returned.
let ty = match internal_id {
x if x == TypeId::of::<()>() => TaggedValue::None,
x if x == TypeId::of::<String>() => TaggedValue::String(string.into()),
x if x == TypeId::of::<f64>() => FromStr::from_str(string).map(TaggedValue::F64).ok()?,
x if x == TypeId::of::<f32>() => FromStr::from_str(string).map(TaggedValue::F32).ok()?,
x if x == TypeId::of::<u64>() => FromStr::from_str(string).map(TaggedValue::U64).ok()?,
x if x == TypeId::of::<u32>() => FromStr::from_str(string).map(TaggedValue::U32).ok()?,
x if x == TypeId::of::<DVec2>() => to_dvec2(string).map(TaggedValue::DVec2)?,
x if x == TypeId::of::<bool>() => FromStr::from_str(string).map(TaggedValue::Bool).ok()?,
x if x == TypeId::of::<Color>() => to_color(string).map(TaggedValue::ColorNotInTable)?,
x if x == TypeId::of::<Option<Color>>() => TaggedValue::ColorNotInTable(to_color(string)?),
x if x == TypeId::of::<Table<Color>>() => to_color(string).map(|color| TaggedValue::Color(Table::new_from_element(color)))?,
x if x == TypeId::of::<Fill>() => to_color(string).map(|color| TaggedValue::Fill(Fill::solid(color)))?,
x if x == TypeId::of::<ReferencePoint>() => to_reference_point(string).map(TaggedValue::ReferencePoint)?,
let ty = match () {
() if ty == TypeId::of::<()>() => TaggedValue::None,
() if ty == TypeId::of::<String>() => TaggedValue::String(string.into()),
() if ty == TypeId::of::<f64>() => FromStr::from_str(string).map(TaggedValue::F64).ok()?,
() if ty == TypeId::of::<f32>() => FromStr::from_str(string).map(TaggedValue::F32).ok()?,
() if ty == TypeId::of::<u64>() => FromStr::from_str(string).map(TaggedValue::U64).ok()?,
() if ty == TypeId::of::<u32>() => FromStr::from_str(string).map(TaggedValue::U32).ok()?,
() if ty == TypeId::of::<DVec2>() => to_dvec2(string).map(TaggedValue::DVec2)?,
() if ty == TypeId::of::<bool>() => FromStr::from_str(string).map(TaggedValue::Bool).ok()?,
() if ty == TypeId::of::<Color>() => to_color(string).map(TaggedValue::ColorNotInTable)?,
() if ty == TypeId::of::<Option<Color>>() => TaggedValue::ColorNotInTable(to_color(string)?),
() if ty == TypeId::of::<Table<Color>>() => to_color(string).map(|color| TaggedValue::Color(Table::new_from_element(color)))?,
() if ty == TypeId::of::<Fill>() => to_color(string).map(|color| TaggedValue::Fill(Fill::solid(color)))?,
() if ty == TypeId::of::<ReferencePoint>() => to_reference_point(string).map(TaggedValue::ReferencePoint)?,
_ => return None,
};
Some(ty)
Expand Down
15 changes: 8 additions & 7 deletions node-graph/graphene-cli/src/export.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ pub fn detect_file_type(path: &Path) -> Result<FileType, String> {
Some("svg") => Ok(FileType::Svg),
Some("png") => Ok(FileType::Png),
Some("jpg" | "jpeg") => Ok(FileType::Jpg),
_ => Err(format!("Unsupported file extension. Supported formats: .svg, .png, .jpg")),
_ => Err("Unsupported file extension. Supported formats: .svg, .png, .jpg".to_string()),
}
}

Expand All @@ -31,8 +31,7 @@ pub async fn export_document(
output_path: PathBuf,
file_type: FileType,
scale: f64,
width: Option<u32>,
height: Option<u32>,
(width, height): (Option<u32>, Option<u32>),
transparent: bool,
) -> Result<(), Box<dyn Error>> {
// Determine export format based on file type
Expand All @@ -42,10 +41,12 @@ pub async fn export_document(
};

// Create render config with export settings
let mut render_config = RenderConfig::default();
render_config.export_format = export_format;
render_config.for_export = true;
render_config.scale = scale;
let mut render_config = RenderConfig {
scale,
export_format,
for_export: true,
..Default::default()
};

// Set viewport dimensions if specified
if let (Some(w), Some(h)) = (width, height) {
Expand Down
10 changes: 5 additions & 5 deletions node-graph/graphene-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,9 @@ async fn main() -> Result<(), Box<dyn Error>> {
Command::Compile { ref document, .. } => document,
Command::Export { ref document, .. } => document,
Command::ListNodeIdentifiers => {
let mut ids: Vec<_> = graphene_std::registry::NODE_METADATA.lock().unwrap().keys().cloned().collect();
ids.sort_by_key(|x| x.as_str().to_string());
for id in ids {
let mut nodes: Vec<_> = graphene_std::registry::NODE_METADATA.lock().unwrap().keys().cloned().collect();
nodes.sort_by_key(|x| x.as_str().to_string());
for id in nodes {
println!("{}", id.as_str());
}
return Ok(());
Expand All @@ -108,7 +108,7 @@ async fn main() -> Result<(), Box<dyn Error>> {

let document_string = std::fs::read_to_string(document_path).expect("Failed to read document");

log::info!("creating gpu context",);
log::info!("Creating GPU context");
let mut application_io = block_on(WasmApplicationIo::new_offscreen());

if let Command::Export { image: Some(ref image_path), .. } = app.command {
Expand Down Expand Up @@ -164,7 +164,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
let executor = create_executor(proto_graph)?;

// Perform export
export::export_document(&executor, wgpu_executor_ref, output, file_type, scale, width, height, transparent).await?;
export::export_document(&executor, wgpu_executor_ref, output, file_type, scale, (width, height), transparent).await?;
}
_ => unreachable!("All other commands should be handled before this match statement is run"),
}
Expand Down
4 changes: 2 additions & 2 deletions node-graph/interpreted-executor/src/node_registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ use graphene_std::wasm_application_io::WasmEditorApi;
use graphene_std::wasm_application_io::WasmSurfaceHandle;
use graphene_std::{Artboard, Context, Graphic, NodeIO, NodeIOTypes, ProtoNodeIdentifier, concrete, fn_type_fut, future};
use node_registry_macros::{async_node, convert_node, into_node};
use once_cell::sync::Lazy;
use std::collections::HashMap;
#[cfg(feature = "gpu")]
use std::sync::Arc;
Expand Down Expand Up @@ -282,7 +281,8 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
map
}

pub static NODE_REGISTRY: Lazy<HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeConstructor>>> = Lazy::new(|| node_registry());
// TODO: Replace with `core::cell::LazyCell` (<https://doc.rust-lang.org/core/cell/struct.LazyCell.html>) or similar
pub static NODE_REGISTRY: once_cell::sync::Lazy<HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeConstructor>>> = once_cell::sync::Lazy::new(|| node_registry());

mod node_registry_macros {
macro_rules! async_node {
Expand Down
14 changes: 14 additions & 0 deletions node-graph/libraries/core-types/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,20 @@ bitflags! {
}
}

impl ContextFeatures {
pub fn name(&self) -> &'static str {
match *self {
ContextFeatures::FOOTPRINT => "Footprint",
ContextFeatures::REAL_TIME => "RealTime",
ContextFeatures::ANIMATION_TIME => "AnimationTime",
ContextFeatures::POINTER => "Pointer",
ContextFeatures::INDEX => "Index",
ContextFeatures::VARARGS => "VarArgs",
_ => "Multiple Features",
}
}
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, dyn_any::DynAny, serde::Serialize, serde::Deserialize, Default)]
pub struct ContextDependencies {
pub extract: ContextFeatures,
Expand Down
3 changes: 2 additions & 1 deletion node-graph/libraries/core-types/src/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use std::sync::{LazyLock, Mutex};
#[derive(Clone, Debug)]
pub struct NodeMetadata {
pub display_name: &'static str,
pub category: Option<&'static str>,
pub category: &'static str,
pub fields: Vec<FieldMetadata>,
pub description: &'static str,
pub properties: Option<&'static str>,
Expand All @@ -23,6 +23,7 @@ pub struct NodeMetadata {
pub struct FieldMetadata {
pub name: &'static str,
pub description: &'static str,
pub hidden: bool,
pub exposed: bool,
pub widget_override: RegistryWidgetOverride,
pub value_source: RegistryValueSource,
Expand Down
Loading
Loading