Skip to content

Fixes/23 - Node based automatic port Registration, Serialization, Publishing, Dynamic Ports, and Parameter exposing using PortRegistry - #55

Merged
vade merged 69 commits into
mainfrom
fixes/23
Oct 26, 2025
Merged

vade merged 69 commits into
mainfrom
fixes/23

Conversation

@vade

@vade vade commented Oct 21, 2025 •

Copy link
Copy Markdown
Member

This is a WIP implementation of a new infrastructure in Fabric to

  • make less broilerplate code to define a node and its port
  • removes manual serialization / deserialization
  • lets node handle an array of type erased AnyPorts
  • lets a author define nodes in one spot

Implementation

  • Each node gets a registry
  • Each node has a new entrypoint to register a port and its property name.

Subtleties

  • because of strict typing, access to port / port parameters requires proxying each port with a matching known type, this is lame, but i dont know if theres a better way?
  • All saved files are not compatible with this PR

Consequences

  • every single node needs to get re-written

Proposed WIP API

For example the pre-amble code to MeshNode now looks like:

public class MeshNode : BaseRenderableNode<Mesh>
{
    override public class var name:String { "Mesh" }
    override public class var nodeType:Node.NodeType { .Object(objectType: .Mesh) }

    // Register ports, in order of appearance
    override public class func registerPorts(context: Context) -> [(name: String, port: Port)] {
        [
            ("inputGeometry",  NodePort<Geometry>(name: "Geometry", kind: .Inlet)),
            ("inputMaterial",  NodePort<Material>(name: "Material", kind: .Inlet)),
            ("inputCastsShadow",  ParameterPort(parameter: BoolParameter("Enable Shadows", true, .button) ) ),
            ("inputDoubleSided",  ParameterPort(parameter: BoolParameter("Double Sided", false, .button) ) ),
            ("inputCullingMode",  ParameterPort(parameter: StringParameter("Culling Mode", "Back", ["Back", "Front", "None"], .dropdown) ) ),
        ]
    }
        
    // Ergonomic access (no storage assignment needed)
    public var inputGeometry: NodePort<Geometry>   { port(named: "inputGeometry") }
    public var inputMaterial: NodePort<Material>   { port(named: "inputMaterial") }
    public var inputCastsShadow: ParameterPort<Bool>   { port(named: "inputCastsShadow") }
    public var inputDoubleSided: ParameterPort<Bool>   { port(named: "inputDoubleSided") }
    public var inputCullingMode: NodePort<String>   { port(named: "inputCullingMode") }
  • Note there is no need to add new decode / encode entry points
  • Note the registration of nodes in registerPorts closure
  • Note the proxying of properties via calls like public var inputCullingMode: NodePort<String> { port(named: "inputCullingMode") } are required for type safe access, and its fragile / will break if not wired up correctly

Nice to have:

  • This might be able to be implemented as a Swift Macro which would provide the port proxy and handle the registration call in a more ergonomic manner?

@vade

vade commented Oct 21, 2025

Copy link
Copy Markdown
Member Author

@tobyspark im not quite there, but this sort of API gets us

  • removal of boilerplate codable implementations and errors for ports and params
  • dynamic ports (in theory need to validate its working)
  • publishing that supports serialization

Thoughts on the API above? This was WAY more work than anticipated so far (and more to go)

@vade

vade commented Oct 21, 2025

Copy link
Copy Markdown
Member Author

Note this API also provides the base ExecutionMode and TimeMode ideas from QC, allowing us to identify Consumer, Producer and Processor nodes, as well as TimeBase nodes which could have their patch time exposed as an input.

@tobyspark

Copy link
Copy Markdown
Member

Add PortType for metatype handling anyport encoding / decoding shit fucking christ.

...yikes. There will be beer. At some point. I promise.

@tobyspark

Copy link
Copy Markdown
Member

I will need to kick the tyres with a new-node-from-whole-cloth to be able to have any kind of meaningful thought. Wrapping a shader was a good start, but a) I haven’t touched Swift in a while and b) yeah, a book chapter is my personal kryptonite.

vade added 19 commits October 21, 2025 17:44
… is correct. Suspect we dont need the merging func in registry, but we can revisit once we try dynamic port bullshit.
…on, we need to add a subscription, and properly hydrate initial values post init / decoding
…n param updates - since we removed observation from Satin, we have to deal with the consequences of our decision lol
…adata requirements like time mode, execution mode, desc.
@vade

vade commented Oct 25, 2025

Copy link
Copy Markdown
Member Author

@tobyspark haha awesome. Im close to closing this out.

My overall take away is ergonomics are better (less code) for the port definitions but in some sense could be error prone due the fact that swift has no KVC support ootb - so i had to roll this annoying shim with exposing proxy ports

Good news is, when we move Fabric to swift package manager, we should be able to expose a custom macro class wrapper thingy which lets us define a set of ports if a more elegant manner, that doesnt require duplication of defines.

But that will be a second pass.

@vade

vade commented Oct 25, 2025

Copy link
Copy Markdown
Member Author

I've got 2 more nodes to port to the new registration, then i have to re-test everything to ensure i havent broken stuff, but in theory if it works, we should have the first stable-ish file format for the alpha run?

@vade

vade commented Oct 25, 2025

Copy link
Copy Markdown
Member Author

So in theory, this branch should be working, but the number of changes is uh not trivial. I did a quick pass and things seemed to mostly work?

Kick the tires if you can!

side effect is this also fixes missing serialization for some nodes, super shape and the PBR material nodes.

@vade
vade merged commit 9215110 into main Oct 26, 2025
@vade
vade deleted the fixes/23 branch October 26, 2025 18:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants