dylanroscover / 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+.
<!-- 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.particlePOPcreates and manages built-in particles over time.sourcePOPis common in feedback-style particle systems.
Filters and topology ops reshape or route data:
transformPOP,mathPOP,mathmixPOP,mathcombinePOP,normalizePOP,limitPOP,rerangePOP,quantizePOP,trigPOP.noisePOPfor 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:
neighborPOPaddsNebrandNumNebrsfor GPU spatial-neighbor logic.proximityPOP,rayPOP,fieldPOP,lookuptexturePOP,lookupchannelPOP.feedbackPOPloops 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 around0.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,glslselectPOPfor 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. lookuptexturePOPsamples TOPs from POP attributes. Set lookup attrs deliberately.
geometryCOMP Setup Ritual
For renderable POP geometry, build inside a geometryCOMP:
- Create the
geometryCOMP. - Delete the auto-created torus immediately.
- Build the POP chain left-to-right and terminate in
null_outor another role-namednullPOP. - Set display and render flags on the output
nullPOP. - Add a material that can shade the points or geometry.
- Reference the MAT on the
geometryCOMPwith a relative path such as./pointsprite_particles. - 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
pointspriteMATfor particle sprites, or a MAT that can read point/vertex attributes for the intended render style. - The POP render color attribute is
Colorasfloat4, notCd.Cdis the SOP habit and will not do what you expect in POP render paths. constantMATcan render point and primitiveColorwhen 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:
Pfloat3 position,Nfloat3 normal,Tfloat4 tangent,Colorfloat4 RGBA,Texfloat3 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:
- Pulse
initializepulseto reset from the input geometry. - Pulse
startpulseto begin playback. - Use
playto pause or resume without resetting. - 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.numpointsis emission positions, not live particle count.particlePOP.birthrateis births per second.particlePOP.lifeis seconds each particle remains alive.particlePOP.maxparticlesmust be at leastbirthrate 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>_computeDAT. Do not point at an unrelated text DAT. - Read compile details from the docked
<name>_infoDAT; the operator error may only say compile failed. - List every written attribute in
outputattrs. - Create custom output attributes first with the
attrsequence, for exampleattr0nameandattr0type, or create them upstream withattributePOP. - With default
outputaccess=writeonly, attributes listed inoutputattrsthat the shader does not write may be zeroed. Usereadwritewhen the shader must read output buffers, such as reading other points during a simulation. - Guard indexes:
if (idx >= uint(P.length())) return;. TDPerlinNoise()andTDSimplexNoise()compile in glslPOP compute shaders on 2025.33230 (verified 2026-09-25; older guidance said they did not). PrefernoisePOPwhen a built-in does the job.- Uniforms are auto-declared by TD. Do not redeclare them in the shader; a redeclared uniform can produce a "Redeclaration" compile error.
- Use
vecuniform sequence entries for runtime values.constsequence 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>_ptComputeDAT. Separate text DATs can compile whileTDCopyIndex()stays wrong. - Delete unused
_vertComputeand_primComputedocked DATs only if you are sure that build does not need them. - Core functions include
TDCopyIndex(),TDTemplate_P(),TDTemplate_AttribName(),TDIn_P(),TDInputIndex(), andTDUpdatePointGroups().
For glsladvancedPOP:
- Use it only when
glslPOPcannot 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, orvertoutputattrs). - In cache feedback patterns, use
cachePOP -> locked nullPOPto break cook dependency loops. Refresh with the unlock-cook-lock sequence:null.lock = False; null.cook(force=True); null.lock = True. A.tdxndoes 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:
poptoCHOPandpoptoDATdownload GPU data to CPU. Keep counts small or sample/debug only.poptoCHOPchannel names useattr_component, for exampleP_0,P_1,P_2.lookuptexturePOPdefaults can use world position components (P(0),P(1)) rather than UVs. Set lookup index attrs toTex(0)andTex(1)when sampling by UV.- pbrMAT and phongMAT read
Texas a vertex attribute, not a point attribute. UseattributeconvertPOPwith point-to-vertex conversion forTex; disable conflicting built-in vertex Tex on the source if needed. normalPOPshould set tangents toalwayscomputewhen 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 byperformance.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.mdthresholds. - 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 fromnetwork-layout.md.execute_pythoncreation drops POPs at(0, 0)unless you position them. ALAYOUT WARNINGis 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_namefor 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_topand 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_errorswithrecurse=trueafter creating or modifying the network. Fix errors and warnings before claiming the build works.
Trap List
rectanglePOPsize parameters aresizeuandsizev, notsizexorsizey. Settingsizex/sizeysilently does nothing. General rule: verify live parameters withget_parameterbefore trusting type-level help or component names.- The default torus inside a new
geometryCOMPwill 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
nullPOPmeans the render is empty. - Points without point primitives do not render.
- POP render color is
Color(float4), not SOP-styleCd. particlePOPandfeedbackPOPneedinitializepulse -> startpulse -> play. Reinitialize after attribute changes or schema changes.maxparticles < birthrate x lifeculls particles.- Custom attributes must exist before GLSL writes them. Create them with the
attrsequence (attr0name,attr0type) or upstreamattributePOP. glslPOPwrites to the docked compute DAT. Do not redeclare auto uniforms. Usevecfor runtime values and avoidconstfor values that should animate without recompiling.- Under the default
outputaccess=writeonlythe shader cannot READ an output buffer:P[idx] = P[idx] + ...fails with "can't read from writeonly object". Read the input point withTDIn_P(), or setoutputaccess=readwritewhen you must read other points' output. normalPOPneeds tangents set toalwayscomputefor PBR lighting.- pbrMAT reads vertex
Tex, not pointTex; convert withattributeconvertPOP. mathmixPOPandmathcombinePOPsequences start empty. SetnumBlocksbefore settingcomb0oper,vec0*, or similar sequence parameters.poptoCHOPoutputs channels likeP_0,P_1,P_2, notP.x.feedbackPOPstarts empty until initialized. Cache-feedback loops need the locked-null unlock-cook-lock refresh sequence.copyPOPmultiplies source vertices by template count. For many copies, prefer GPU instancing or a simpler point-rendered approach.poptoCHOPandpoptoDATread back from GPU to CPU. Use them for debugging or bounded extraction, not large live particle fields.lookuptexturePOPdefaults may sample byP, notTex. 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.