@brecht and I (@JacquesLucke) talked about this. We agreed to move forward with the following approach.
* A Curves object has an optional pointer to a sculp mesh object. The original mesh of that object is used as sculp, instead of the evaluated mesh.
* If a curves object references a base mesh, two additional attributes are added to the curves domain:
* `MLoopTri` index: Index of the triangle that the root hair point is attached to.
* Barycentric coordinates: Position within the referenced triangle.
* The exact naming convention for these attributes still has to be decided.
* Vectors in the `position` attribute are in the local space of the object (instead of some relative coordinates based on the sculp).
* Updating the sculp is an explicit operation. When the sculp object is edited, the hair stays at the same position.
* An operator can be used to replace a sculp object with a new one.
* A deform node in geometry nodes is used to deform the hair based on a deformation of the base mesh.
* It has these inputs:
* `Curves`: Undeformed hair curves.
* `Deformed Base Mesh`: The animated or simulated base mesh. The topology must match the topology of the sculp mesh.
* `Rest Position`: A vector field input that determines the original position of each vertex of the defomed base mesh. Usually, this just references a named attribute like `rest_position`/`original_position`. This attribute has to be set on the sculp.
* The output is just the deformed curves.