Skip to content

Add a family

  1. Define semantic input. Add program/<kind>.ts with strict Zod objects, unique identity checks, reference validation, and cycle checks where needed.
  2. Define the plugin. Add families/<kind>.ts using defineFamily().
  3. Normalize. Convert every node, relation, and group to GraphIR; never parse facts from display labels.
  4. Select placement. Return a configured shared strategy or a cohesive bespoke placer that still emits the common Placement shape.
  5. Define notation. Map every finite style key to shared caps, dashes, and a legend label.
  6. Register built-ins. Add the definition to BUILT_IN_FAMILIES, or use an isolated custom FamilyRegistry outside the built-in catalogue.
  7. Create fixtures. Hand-author realistic easy, medium, and hard programs.
  8. Verify visually. Run the family harness, inspect all PNGs, then run the complete gate.
export const exampleFamily = defineFamily({
kind: 'example',
schema: exampleProgramSchema,
orthogonalEdges: true,
normalize(program) {
return { title: program.title, nodes: [], relations: [], groups: [] };
},
placement() {
return { strategy: 'layered', config: { direction: 'RIGHT' } };
},
notation(styleKey) {
return NOTATION[styleKey];
},
});

If the definition needs to import routing, labels, icons, colours, or the harness, the responsibility is in the wrong layer.