# \`PointInstancer\` Prototype Scope Best Practices

**URL:** <https://forum.aousd.org/t/pointinstancer-prototype-scope-best-practices/2662>\
**Category:** USD\
**Created:** [August 28, 2025, 8:02pm UTC](https://forum.aousd.org/t/pointinstancer-prototype-scope-best-practices/2662 "2025-08-28T20:02:11Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![nvmkuruc](https://avatars.discourse-cdn.com/v4/letter/n/76d3ee/32.png) [@nvmkuruc](https://forum.aousd.org/u/nvmkuruc)\
**Post date:** [August 28, 2025, 8:02pm UTC](https://forum.aousd.org/t/pointinstancer-prototype-scope-best-practices/2662/1 "2025-08-28T20:02:11Z")

</div>

Hello. We’re looking to align our best practices for `PointInstancer` and native instancing prototypes scopes.

With some feedback from ASWF’s assets working group, for native instancing, we aligned on `def` with ancestral `class`.

```auto
class "prototype_sources" {
    def Xform "source_1" { ... } 
    def Xform "source_2" { ... }
}

```

Our hope was that we could adopt something similar for `PointInstancers`.

```auto
def PointInstancer "instancer" {
    rel prototypes = [<Prototypes/source_1>, <Prototypes/source_2>]
    class "Prototypes" {
        def Xform "source_1" { ... }
        def Xform "source_2" { ... }
    }
}

```

The reasoning was two-fold:

- It seemed nice to provide the same guidance for point instancers and native instances.
- It might be hard to disambiguate between an intentional source scopes and dangling overs in a script looking to cleanup cruft.

We were a little surprised that `class` doesn’t work as the `Prototypes` scope specifier here while `over` does. It appears to be because of the traversal predicate ([OpenUSD/pxr/usdImaging/usdImaging/delegate.cpp at dev · PixarAnimationStudios/OpenUSD](https://github.com/PixarAnimationStudios/OpenUSD/blob/dev/pxr/usdImaging/usdImaging/delegate.cpp#L289)).

There’s no `HasConcreteDefiningSpecifier` only `HasDefiningSpecifier` which includes abstract (`class`) and concrete (`def`). The `IsAbstract` predicate is required to filter out these `class` specifiers, but it also filters out any prims with ancestral `class` specifiers.

Just like it’s useful to define a “concretely defining subgraph” of an `over`, it seems like it might be useful to be able to form a traversal predicate for a “concretely defining subgraph” of a `class`.

If there’s agreement that such a traversal predicate is useful, would it be worth expanding display predicate of prototypes to allow for “concretely defining subgraphs” of `class` in addition to `over`?

Thanks in advance for the consideration.

---

<div class="post-metadata">

**Author:** ![spiff](https://sea2.discourse-cdn.com/flex016/user_avatar/forum.aousd.org/spiff/32/22_2.png) [@spiff](https://forum.aousd.org/u/spiff)\
**Post date:** [September 19, 2025, 11:49pm UTC](https://forum.aousd.org/t/pointinstancer-prototype-scope-best-practices/2662/2 "2025-09-19T23:49:52Z")

</div>

> [@nvmkuruc](#):
>
> It might be hard to disambiguate between an intentional source scopes and dangling overs in a script looking to cleanup cruft.

A cleanup script should only be pruning overs that are inert (and therefore from the leaves up) so I’m not sure I see a real issue there, but…

The consistency with NI prototype organization is compelling. I’m not familiar with the specifics of the assets group recommendations, but just to put it out there, we think there’s value in reserving **global** classes for use with inherits and specializes, as it gives DCC’s a clue as to what their use is and how to present/organize them. But given that a) we’re unlikely to add a new specifier for this purpose, b) using `class` as a container has less friction than using `over` (because of authoring API’s that attempt to define all ancestors of a newly def’d prim), this seems worthwhile to me.

Are you interested in making a PR (it was, IIRC, an @asluk PR that introduced HasDefiningSpecifier for use with PI prototypes)?

---

<div class="post-metadata">

**Author:** ![nvmkuruc](https://avatars.discourse-cdn.com/v4/letter/n/76d3ee/32.png) [@nvmkuruc](https://forum.aousd.org/u/nvmkuruc)\
**Post date:** [September 22, 2025, 1:57pm UTC](https://forum.aousd.org/t/pointinstancer-prototype-scope-best-practices/2662/3 "2025-09-22T13:57:03Z")

</div>

Thanks Spiff for the thoughts. I think we’d be happy to contribute a PR.

Regarding the cleanup example, I think you could imagine different users might have different perspectives on what they might consider cruft. Consider the following spec tree authored on the root layer with `Asset_1` being originally introduced (concretely defined) on a sub layer

```auto
over "Asset_1"
{
   over "Geometry" (append apiSchemas = "MaterialBindingAPI")
   {
       rel material:binding = <../Materials/OverrideMaterial> (materialBindingStrength = "strongerThanDescendants")
   }
   over "Materials"
   {
       def Material "OverrideMaterial" (references = @material_library.usd@</metal>)
       {
       }
   }
}

```

It defines a new material and overrides the material binding on the geometry scope. Were `Asset_1` to be removed on the sublayer, you could imagine wanting a helper available to remove the entire `Asset_1` spec tree on the root layer, even though it contains a concretely defining specifier as a leaf.
