# Pop Networks

> MUST READ before building or editing POP networks, particle systems, GPU point/geometry work, glslPOP compute, or converting SOP chains to POPs in TouchDesigner 2025+.

- Skill: `dylanroscover/pop-networks` (Agent Skill)
- Install (CLI): `npx skillmds@latest add dylanroscover/pop-networks`
- Raw SKILL.md: https://api.skillmd.com/api/skills/dylanroscover/pop-networks/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: dylanroscover (https://skillmd.com/u/dylanroscover)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/dylanroscover/pop-networks

---

<!-- Generated by Embody/Envoy - Do not remove this comment - sha:1f0bd4b8bf261c96 -->

# POP Networks

Build GPU-resident point and geometry systems with TouchDesigner POPs. POPs are the 2025+ point-operator family: geometry attributes live on the GPU, many operations run in parallel, and the right chain can replace CPU-heavy SOP or particle workflows.

Use this skill with `/create-operator`, `/visual-aesthetics`, `performance.md`, `network-layout.md`, and `td-python.md`. POP correctness is not just a clean network: it is a rendered frame, readable layout, bounded performance, and no operator errors.

## POPs vs SOPs

Use POPs when the work is point-heavy, particle-heavy, or naturally parallel:

- Many points, particles, trails, instancing templates, or live geometry streams.
- GPU-side displacement, filtering, attributes, neighborhood queries, texture lookups, or simulation loops.
- Geometry that needs to stay GPU-resident for rendering, instancing, GLSL, or TOP/MAT interop.
- SOP chains whose main cost is moving or filtering lots of points every frame.

Keep SOPs when they are the honest tool:

- Booleans, UV unwrap, small static meshes, precise CPU geometry tools, or legacy SOP-only workflows.
- Tiny one-off static shapes where a SOP is clearer and has no measurable cost.
- Any workflow that needs a mature CPU operator with no POP equivalent.

Prefer POPs for dynamic scale, not as a religion. Start from the user's goal, expected point count, and render path, then choose the family that keeps the system understandable and fast.

## Core Vocabulary

Generators create points or geometry:

- `gridPOP`, `boxPOP`, `spherePOP`, `torusPOP`, `tubePOP`, `circlePOP`, `linePOP`, `rectanglePOP`.
- `randomPOP`, `sprinklePOP`, `pointgeneratorPOP`, `patternPOP`, `curvePOP`.
- `particlePOP` creates and manages built-in particles over time.
- `sourcePOP` is common in feedback-style particle systems.

Filters and topology ops reshape or route data:

- `transformPOP`, `mathPOP`, `mathmixPOP`, `mathcombinePOP`, `normalizePOP`, `limitPOP`, `rerangePOP`, `quantizePOP`, `trigPOP`.
- `noisePOP` for built-in noise displacement or attribute generation.
- `attributePOP`, `attributecombinePOP`, `attributeconvertPOP`, `normalPOP`.
- `mergePOP`, `switchPOP`, `selectPOP`, `deletePOP`, `groupPOP`, `sortPOP`, `copyPOP`, `blendPOP`, `nullPOP`.
- `primitivePOP`, `convertPOP`, `extrudePOP`, `subdividePOP`, `facetPOP`, `polygonizePOP`.

Spatial and simulation ops add interaction:

- `neighborPOP` adds `Nebr` and `NumNebrs` for GPU spatial-neighbor logic.
- `proximityPOP`, `rayPOP`, `fieldPOP`, `lookuptexturePOP`, `lookupchannelPOP`.
- `feedbackPOP` loops frame-to-frame. Input 0 is the reset geometry; loopback from the output is automatic.
- `cachePOP`, `cacheblendPOP`, `cacheselectPOP`, `trailPOP`, `linemetricsPOP`, `skinPOP`.
- Forces for particle workflows should start conservative: gravity around `0.1-0.2`, damping around `0.98`.

GLSL POPs are for work the built-ins cannot express cleanly:

- `glslPOP`: default custom compute operator for one attribute class, multi-pass support.
- `glsladvancedPOP`: use only when you need multi-class read/write, `I[]` index-buffer access, extra outputs, or custom output counts.
- `glslcopyPOP`: copy source geometry many times with custom per-copy transforms.
- `glslcreatePOP`, `glslselectPOP` for create/select patterns around GLSL outputs.

Converters bridge POPs to other families:

- Into POPs: `soptoPOP`, `choptoPOP`, `dattoPOP`, `toptoPOP`, file/Alembic/point-file POPs.
- Out of POPs: `poptoCHOP`, `poptoDAT`, `glslmultiTOP`, MAT attribute pages.
- `lookuptexturePOP` samples TOPs from POP attributes. Set lookup attrs deliberately.

## geometryCOMP Setup Ritual

For renderable POP geometry, build inside a `geometryCOMP`:

1. Create the `geometryCOMP`.
2. Delete the auto-created torus immediately.
3. Build the POP chain left-to-right and terminate in `null_out` or another role-named `nullPOP`.
4. Set display and render flags on the output `nullPOP`.
5. Add a material that can shade the points or geometry.
6. Reference the MAT on the `geometryCOMP` with a relative path such as `./pointsprite_particles`.
7. Render through a camera, light as needed, and a Render TOP.

Point rendering needs point primitives and a point-capable material:

- Points alone do not render. On generators, set Connectivity to create point primitives when you intend to render points.
- Use `pointspriteMAT` for particle sprites, or a MAT that can read point/vertex attributes for the intended render style.
- The POP render color attribute is `Color` as `float4`, not `Cd`. `Cd` is the SOP habit and will not do what you expect in POP render paths.
- `constantMAT` can render point and primitive `Color` when point color application is enabled.
- Filled POP surfaces may be invisible from one side under backface culling. If that is not desired, set the MAT cull face to neither.

## Attributes

Reserved/common attributes to recognize:

- `P` float3 position, `N` float3 normal, `T` float4 tangent, `Color` float4 RGBA, `Tex` float3 texture coordinate.
- `PointScale`, `LineWidth`, `Weight`.
- Particle attributes from `particlePOP`: `PartVel`, `PartId`, `PartAge`, `PartLifeSpan`, `PartDrag`, `PartMass`, `PartForce`.
- Neighbor attributes from `neighborPOP`: `Nebr`, `NumNebrs`.

Access components as `P.x`, `P.y`, `P.z`, `Color.r`, or with POP parameter component syntax such as `P(0)`. Use dot notation in GLSL for readability.

Custom attributes must exist before downstream code writes them. Use `attributePOP` upstream or the Create Attributes sequence on the GLSL POP itself. In sequence parameters, set the block count first, then set names and types such as `attr0name` and `attr0type`.

## Particle Lifecycle

For `particlePOP` and `feedbackPOP`, creation is not enough:

1. Pulse `initializepulse` to reset from the input geometry.
2. Pulse `startpulse` to begin playback.
3. Use `play` to pause or resume without resetting.
4. Reinitialize after changing attribute schema, birth/life/capacity, or any upstream reset geometry that changes the expected state.

Particle capacity is a hard cap:

- `pointgeneratorPOP.numpoints` is emission positions, not live particle count.
- `particlePOP.birthrate` is births per second.
- `particlePOP.life` is seconds each particle remains alive.
- `particlePOP.maxparticles` must be at least `birthrate x life`, or particles are culled before their intended lifespan.

Start with modest counts and ramp only after measuring. Never default to millions.

## GLSL POP Discipline

Use built-in POPs before custom GLSL when a short POP chain is clearer. `lookuptexturePOP -> mathmixPOP` is often better than a shader for texture lookup plus arithmetic.

For `glslPOP`:

- Write shader code in the auto-docked `<name>_compute` DAT. Do not point at an unrelated text DAT.
- Read compile details from the docked `<name>_info` DAT; the operator error may only say compile failed.
- List every written attribute in `outputattrs`.
- Create custom output attributes first with the `attr` sequence, for example `attr0name` and `attr0type`, or create them upstream with `attributePOP`.
- With default `outputaccess=writeonly`, attributes listed in `outputattrs` that the shader does not write may be zeroed. Use `readwrite` when the shader must read output buffers, such as reading other points during a simulation.
- Guard indexes: `if (idx >= uint(P.length())) return;`.
- `TDPerlinNoise()` is not available in compute shaders. Use built-in `noisePOP`, a sampler input, or custom compute-safe noise.
- Uniforms are auto-declared by TD. Do not redeclare them in the shader; a redeclared uniform can produce a "Redeclaration" compile error.
- Use `vec` uniform sequence entries for runtime values. `const` sequence entries recompile the shader when they change.

For `glslcopyPOP`:

- Input 0 is source geometry. Input 1 is template points when copy count should follow points.
- Write the point shader in the auto-docked `<name>_ptCompute` DAT. Separate text DATs can compile while `TDCopyIndex()` stays wrong.
- Delete unused `_vertCompute` and `_primCompute` docked DATs only if you are sure that build does not need them.
- Core functions include `TDCopyIndex()`, `TDTemplate_P()`, `TDTemplate_AttribName()`, `TDIn_P()`, `TDInputIndex()`, and `TDUpdatePointGroups()`.

For `glsladvancedPOP`:

- Use it only when `glslPOP` cannot express the output class, topology, index buffer, or output-count requirements.
- Allocate output buffers explicitly. Point outputs need custom max points > 0; primitive/vertex/index outputs need custom max triangles > 0.
- Custom attributes need both Create Attribs and the matching output attributes parameter (`ptoutputattrs`, `primoutputattrs`, or `vertoutputattrs`).
- In cache feedback patterns, use `cachePOP -> locked nullPOP` to break cook dependency loops. Refresh with the unlock-cook-lock sequence: `null.lock = False; null.cook(force=True); null.lock = True`. A `.tdxn` does not store that null's points (Embody's locked-content warning names it): after the COMP is rebuilt from its `.tdxn`, run the refresh again.

## Conversion and Extraction

Use conversions deliberately because GPU -> CPU readback can stall:

- `poptoCHOP` and `poptoDAT` download GPU data to CPU. Keep counts small or sample/debug only.
- `poptoCHOP` channel names use `attr_component`, for example `P_0`, `P_1`, `P_2`.
- `lookuptexturePOP` defaults can use world position components (`P(0)`, `P(1)`) rather than UVs. Set lookup index attrs to `Tex(0)` and `Tex(1)` when sampling by UV.
- pbrMAT and phongMAT read `Tex` as a vertex attribute, not a point attribute. Use `attributeconvertPOP` with point-to-vertex conversion for `Tex`; disable conflicting built-in vertex Tex on the source if needed.
- `normalPOP` should set tangents to `alwayscompute` when using pbrMAT, or PBR lighting can fail.

## Embody Workflow Gates

Performance is part of the build:

- Before any particle, feedback, GLSL, instancing, or large POP build, call `get_project_performance(include_hotspots=5)` and record the baseline required by `performance.md`.
- Re-check after each significant step, not only at the end.
- Watch GPU headroom, frame time, dropped frames, hotspot cook time, and memory. Stop on the `performance.md` thresholds.
- Start particle and instance counts modestly, then ramp with evidence. Do not default to millions.

Layout is part of the build:

- POP chains still follow the 200-unit grid and left-to-right signal flow.
- `glslPOP`, `glslcopyPOP`, and other GLSL operators dock compute/info DATs. Place every docked DAT with the docked-DAT formula from `network-layout.md`.
- `execute_python` creation drops POPs at `(0, 0)` unless you position them. A `LAYOUT WARNING` is a hard stop: query layout, move the ops, move docked DATs, and verify again.
- Every logical POP cluster gets an annotation enclosing its operators.

Naming is part of readability:

- Use `optype_name` for processing ops: `grid_points`, `noise_displace`, `glsl_sim`, `particle_emit`, `feedback_state`, `null_out`.
- Name DATs by role, not type. Keep generated docked DAT names unless the operator requires them.

Verification is visual and structural:

- A POP render chain is verified by rendering it. Capture the Render TOP output with `capture_top` and judge the frame using `/visual-aesthetics`.
- Let simulations settle before judging. Empty early frames can be lifecycle or demand issues, not final appearance.
- Verify animation over time with multiple captures when the POP chain is time-dependent.
- Run `get_op_errors` with `recurse=true` after creating or modifying the network. Fix errors and warnings before claiming the build works.

## Trap List

- `rectanglePOP` size parameters are `sizeu` and `sizev`, not `sizex` or `sizey`. Setting `sizex`/`sizey` silently does nothing. General rule: verify live parameters with `get_parameter` before trusting type-level help or component names.
- The default torus inside a new `geometryCOMP` will render if you leave it there. Delete it before building the POP chain -- this is the general geometryCOMP rule; see `/create-operator` -> "Geometry COMP: delete the default torus" for the render-flag detail.
- No display/render flags on the output `nullPOP` means the render is empty.
- Points without point primitives do not render.
- POP render color is `Color` (`float4`), not SOP-style `Cd`.
- `particlePOP` and `feedbackPOP` need `initializepulse -> startpulse -> play`. Reinitialize after attribute changes or schema changes.
- `maxparticles < birthrate x life` culls particles.
- Custom attributes must exist before GLSL writes them. Create them with the `attr` sequence (`attr0name`, `attr0type`) or upstream `attributePOP`.
- `glslPOP` writes to the docked compute DAT. Do not redeclare auto uniforms. Use `vec` for runtime values and avoid `const` for values that should animate without recompiling.
- `TDPerlinNoise()` is not available in POP compute shaders.
- `normalPOP` needs tangents set to `alwayscompute` for PBR lighting.
- pbrMAT reads vertex `Tex`, not point `Tex`; convert with `attributeconvertPOP`.
- `mathmixPOP` and `mathcombinePOP` sequences start empty. Set `numBlocks` before setting `comb0oper`, `vec0*`, or similar sequence parameters.
- `poptoCHOP` outputs channels like `P_0`, `P_1`, `P_2`, not `P.x`.
- `feedbackPOP` starts empty until initialized. Cache-feedback loops need the locked-null unlock-cook-lock refresh sequence.
- `copyPOP` multiplies source vertices by template count. For many copies, prefer GPU instancing or a simpler point-rendered approach.
- `poptoCHOP` and `poptoDAT` read back from GPU to CPU. Use them for debugging or bounded extraction, not large live particle fields.
- `lookuptexturePOP` defaults may sample by `P`, not `Tex`. Set lookup attrs explicitly.
- Filled primitives may disappear from one side because of MAT culling.

Adapted from Derivative's TDMCPSkills (td-pop-family), with permission. Verify build-specific behavior against docs.derivative.ca.

