How to have custom node appear in Shader Editor/Add/Texture menu?

The Blender API has methods for defining nodes, but unfortunately not a lot of documentation or examples. I’d like to create a simple node that would appear in the Shader Editor/Add/Texture menu capable of generating an image. At the moment though, not even the poll() method of my Node class is being called. How do I get my node to show up in this menu?

This is my best try to far. I’m getting an error saying

    raise KeyError("Node categories list '%s' already registered" % identifier)
KeyError: "Node categories list 'SHADER' already registered"
Error: Python script failed, check the message in the system console


import bpy
import nodeitems_utils 

class SortedNodeCategory(nodeitems_utils .NodeCategory):
    def __init__(self, identifier, name, description="", items=None):
        # for builtin nodes the convention is to sort by name
        if isinstance(items, list):
            items = sorted(items, key=lambda item: item.label.lower())

        super().__init__(identifier, name, description, items)

class ShaderNewNodeCategory(SortedNodeCategory):
    def poll(cls, context):
        return (context.space_data.tree_type == 'ShaderNodeTree' and

class ImageGenNode(bpy.types.Node):
    Tooltip: Generate a simple image
    bl_idname = "kitfox.image_gen_node"
    bl_label = "Image Gen"
    bl_icon = "SPEAKER"

    color_out : bpy.props.FloatVectorProperty(
        default = [.5, .5, .5, 1.0], size=4, subtype = "COLOR", soft_min = 0.0, soft_max = 1.0

    def init(self, context):
       "NodeSocketColor", "Color")
        print("ImageGenNode init()")

    def execute(self):
        print("ImageGenNode execute()")
        return {"color_out": self.color_out}

    def output(self):
        print("ImageGenNode output()")
        return self.execute()
    # Additional buttons displayed on the node.
    def draw_buttons(self, context, layout):
        print("ImageGenNode draw_buttons()")
        layout.prop(self, "color_out", text="walla")
    def poll(cls, ntree):
        print("ImageGenNode poll()")
        return True
# all categories in a list
shader_node_categories = [
    # identifier, label, items list
    ShaderNewNodeCategory('SH_NEW_TEXTURE', "Texture", items=[
        # our basic node

def register():
    nodeitems_utils.register_node_categories('SHADER', shader_node_categories)

    print("Registered ImageGenNode")

def unregister():

if __name__ == "__main__":