@field/cascade 0.4.0 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. package/AGENTS.md +18 -0
  2. package/ARCHITECTURE.md +53 -7
  3. package/CHANGELOG.md +68 -0
  4. package/CONTRIBUTING.md +33 -0
  5. package/DESIGN.md +9 -6
  6. package/README.md +80 -4
  7. package/dist/assets/{CodeEditor-BNOJIDzL.js → CodeEditor-BHej8kM9.js} +7 -7
  8. package/dist/assets/{CodePanel-2wp2G0Fj.js → CodePanel-CT3eirK8.js} +2 -2
  9. package/dist/assets/{CustomNodeDialog-DNqaVBqA.js → CustomNodeDialog-BG0m7_Rv.js} +1 -1
  10. package/dist/assets/{ProjectSettings-DcdYF2E1.js → ProjectSettings-BxoLWJG6.js} +2 -2
  11. package/dist/assets/{SettingsDialog-D2xVvyiR.js → SettingsDialog-r9PzZ22z.js} +1 -1
  12. package/dist/assets/{VersionHistoryDialog-DW288ykF.js → VersionHistoryDialog-B6zUV6Dy.js} +1 -1
  13. package/dist/assets/{core-B1y38i95.js → core-wwx5881P.js} +2 -2
  14. package/dist/assets/{cssMode-BLucnaln.js → cssMode-DY5T2Or0.js} +1 -1
  15. package/dist/assets/definitions-BgCvRHyR.js +1 -0
  16. package/dist/assets/{editor.api-B3Et3Pph.js → editor.api-mkORHEMm.js} +1 -1
  17. package/dist/assets/{freemarker2-DVlPoano.js → freemarker2-CIWlk0sw.js} +1 -1
  18. package/dist/assets/geo-CIxgs0oE.js +1 -0
  19. package/dist/assets/{handlebars-B5FZBAMR.js → handlebars-t4jbj3Br.js} +1 -1
  20. package/dist/assets/{html-FodD8KbR.js → html-Ctx7UOlY.js} +1 -1
  21. package/dist/assets/{htmlMode-CsG57VCD.js → htmlMode-BKNZxVw7.js} +1 -1
  22. package/dist/assets/{image-B3F-nq25.js → image-BCBFz0gD.js} +3 -3
  23. package/dist/assets/index-CeqTfMbr.js +212 -0
  24. package/dist/assets/{index-Y2ock1cw.css → index-ilgbOu6G.css} +1 -1
  25. package/dist/assets/{javascript-B3gonF_H.js → javascript-Da_TJBzH.js} +1 -1
  26. package/dist/assets/{jsonMode-Y3w1ahZg.js → jsonMode-Ftt5d1nV.js} +1 -1
  27. package/dist/assets/{liquid-CTpWXIYO.js → liquid-D5kWYG57.js} +1 -1
  28. package/dist/assets/{lspLanguageFeatures-CODBdKEZ.js → lspLanguageFeatures-B-93LC_L.js} +1 -1
  29. package/dist/assets/{mdx-CDAQJZIz.js → mdx-DGT3C_qs.js} +1 -1
  30. package/dist/assets/nodeTypeUtils-BDJsc2Ks.js +1 -0
  31. package/dist/assets/pop-BJGN5Ac4.js +1 -0
  32. package/dist/assets/{python-LOIlxJU-.js → python-Bz3Eew5S.js} +1 -1
  33. package/dist/assets/{razor-CllPQSHo.js → razor-CFDdKpKI.js} +1 -1
  34. package/dist/assets/{tsMode-CO28ut8t.js → tsMode-BaCINWBI.js} +1 -1
  35. package/dist/assets/{typescript-ruU9wKQ_.js → typescript-BoOWspVs.js} +1 -1
  36. package/dist/assets/{workers-Bc1Ywp4-.js → workers-dSWyDxsQ.js} +1 -1
  37. package/dist/assets/{xml-DoXP2Dh1.js → xml-eFi1_vYt.js} +1 -1
  38. package/dist/assets/{yaml-D9YPyGiJ.js → yaml-a7xrJHxm.js} +1 -1
  39. package/dist/cli/index.js +16266 -12653
  40. package/dist/cli/runtime/io.ts +31 -25
  41. package/dist/contracts/definition.d.ts +21 -2
  42. package/dist/contracts/index.d.ts +2 -0
  43. package/dist/contracts/index.js +2 -0
  44. package/dist/contracts/particles.d.ts +54 -0
  45. package/dist/contracts/particles.js +167 -0
  46. package/dist/contracts/scene.d.ts +129 -0
  47. package/dist/contracts/scene.js +73 -0
  48. package/dist/contracts/schema.js +1 -1
  49. package/dist/contracts/validate.js +4 -2
  50. package/dist/contracts/values.d.ts +3 -2
  51. package/dist/contracts/values.js +9 -0
  52. package/dist/index.html +3 -3
  53. package/dist/io.d.ts +4 -16
  54. package/dist/io.js +26 -8
  55. package/dist/player/app.js +810 -0
  56. package/dist/player/embed.d.ts +4 -0
  57. package/dist/player/embed.js +77 -0
  58. package/dist/player/types.d.ts +35 -0
  59. package/dist/runtime/builtins/core/index.d.ts +3 -2
  60. package/dist/runtime/builtins/core/index.js +6 -2
  61. package/dist/runtime/builtins/core/structural.d.ts +168 -0
  62. package/dist/runtime/builtins/core/structural.js +175 -0
  63. package/dist/runtime/builtins/core/time.d.ts +165 -0
  64. package/dist/runtime/builtins/core/time.js +110 -0
  65. package/dist/runtime/builtins/geo/definitions.d.ts +247 -0
  66. package/dist/runtime/builtins/geo/definitions.js +70 -0
  67. package/dist/runtime/builtins/geo/index.d.ts +2 -1
  68. package/dist/runtime/builtins/geo/index.js +3 -1
  69. package/dist/runtime/builtins/geo/render.d.ts +87 -0
  70. package/dist/runtime/builtins/geo/render.js +87 -0
  71. package/dist/runtime/builtins/geo/svgExport.d.ts +11 -0
  72. package/dist/runtime/builtins/geo/svgExport.js +10 -0
  73. package/dist/runtime/builtins/index.d.ts +5 -2
  74. package/dist/runtime/builtins/index.js +13 -3
  75. package/dist/runtime/builtins/pop/definitions.d.ts +2120 -0
  76. package/dist/runtime/builtins/pop/definitions.js +815 -0
  77. package/dist/runtime/builtins/pop/index.d.ts +2 -0
  78. package/dist/runtime/builtins/pop/index.js +2 -0
  79. package/dist/runtime/builtins/scene/definitions.d.ts +356 -0
  80. package/dist/runtime/builtins/scene/definitions.js +224 -0
  81. package/dist/runtime/builtins/scene/index.d.ts +2 -0
  82. package/dist/runtime/builtins/scene/index.js +2 -0
  83. package/dist/runtime/geometry/render.d.ts +109 -0
  84. package/dist/runtime/geometry/render.js +145 -0
  85. package/dist/runtime/geometry/svg.d.ts +29 -0
  86. package/dist/runtime/geometry/svg.js +11 -5
  87. package/dist/runtime/index.d.ts +1 -0
  88. package/dist/runtime/index.js +1 -0
  89. package/dist/runtime/pop/cache.d.ts +27 -0
  90. package/dist/runtime/pop/cache.js +123 -0
  91. package/dist/runtime/pop/forces.d.ts +202 -0
  92. package/dist/runtime/pop/forces.js +519 -0
  93. package/dist/runtime/pop/index.d.ts +5 -0
  94. package/dist/runtime/pop/index.js +5 -0
  95. package/dist/runtime/pop/state.d.ts +136 -0
  96. package/dist/runtime/pop/state.js +283 -0
  97. package/dist/runtime/pop/trail.d.ts +62 -0
  98. package/dist/runtime/pop/trail.js +142 -0
  99. package/dist/runtime/runtime.js +221 -3
  100. package/dist/runtime/scene/index.d.ts +50 -0
  101. package/dist/runtime/scene/index.js +94 -0
  102. package/dist/studio/panel.d.ts +68 -1
  103. package/doc/HEADLESS_GPU.md +4 -4
  104. package/doc/NODE_REFERENCE.md +372 -1
  105. package/doc/PROJECT_AUTHORING.md +16 -4
  106. package/doc/WEB_PLAYER.md +131 -0
  107. package/package.json +16 -2
  108. package/dist/assets/geo-DhyFdBXX.js +0 -1
  109. package/dist/assets/index-CC6YQw2n.js +0 -212
  110. package/dist/assets/nodeTypeUtils-BBA1JqHx.js +0 -1
@@ -53,6 +53,32 @@ Runs on `portable`.
53
53
  | --- | --- | --- | --- |
54
54
  | `camera` | `camera` | | |
55
55
 
56
+ ### `cascade.core.Feedback`
57
+
58
+ Feedback — Runs its contents once per step, carrying the previous result forward.
59
+
60
+ Runs on `portable`.
61
+
62
+ **Inputs**
63
+
64
+ | name | type | default | range |
65
+ | --- | --- | --- | --- |
66
+ | `initial` | `any` | `null` | |
67
+ | `steps` | `int` | `1` | |
68
+
69
+ **Props**
70
+
71
+ | name | type | default | range |
72
+ | --- | --- | --- | --- |
73
+ | `history` | `int` | `0` | 0…100000 |
74
+
75
+ **Outputs**
76
+
77
+ | name | type | default | range |
78
+ | --- | --- | --- | --- |
79
+ | `result` | `any` | | |
80
+ | `history` | `array` | | |
81
+
56
82
  ### `cascade.core.Input`
57
83
 
58
84
  Input — Defines a public graph or subnet input
@@ -147,6 +173,25 @@ Runs on `portable`.
147
173
  | --- | --- | --- | --- |
148
174
  | `output` | `any` | | |
149
175
 
176
+ ### `cascade.core.Previous`
177
+
178
+ Previous — The previous step's state, inside a Feedback container. The first step gets the container's initial value.
179
+
180
+ Runs on `portable`.
181
+
182
+ **Inputs**
183
+
184
+ | name | type | default | range |
185
+ | --- | --- | --- | --- |
186
+ | `initial` | `any` | `null` | |
187
+
188
+ **Outputs**
189
+
190
+ | name | type | default | range |
191
+ | --- | --- | --- | --- |
192
+ | `value` | `any` | | |
193
+ | `step` | `int` | | |
194
+
150
195
  ### `cascade.core.Random`
151
196
 
152
197
  Random — Generate a deterministic unit value from an explicit seed.
@@ -250,6 +295,28 @@ Runs on `portable`.
250
295
  | --- | --- | --- | --- |
251
296
  | `output` | `any` | | |
252
297
 
298
+ ### `cascade.core.Time`
299
+
300
+ Time — The current frame and time, as values the graph can read.
301
+
302
+ Runs on `portable`.
303
+
304
+ **Props**
305
+
306
+ | name | type | default | range |
307
+ | --- | --- | --- | --- |
308
+ | `frame` | `int` | `1` | |
309
+ | `fframe` | `float` | `1` | |
310
+ | `time` | `float` | `0` | |
311
+
312
+ **Outputs**
313
+
314
+ | name | type | default | range |
315
+ | --- | --- | --- | --- |
316
+ | `frame` | `int` | | |
317
+ | `fframe` | `float` | | |
318
+ | `time` | `float` | | |
319
+
253
320
  ### `cascade.geo.Circle`
254
321
 
255
322
  Circle — A closed circle, as one cubic Bezier chain or as a polygon of divisions segments.
@@ -339,6 +406,39 @@ Runs on `portable`.
339
406
  | --- | --- | --- | --- |
340
407
  | `geometry` | `geometry` | | |
341
408
 
409
+ ### `cascade.geo.Render`
410
+
411
+ Render — Draw a scene through a camera, as a raster.
412
+
413
+ Runs on `portable`.
414
+
415
+ **Inputs**
416
+
417
+ | name | type | default | range |
418
+ | --- | --- | --- | --- |
419
+ | `scene` | `scene` | | |
420
+ | `camera` | `camera` | | |
421
+
422
+ **Props**
423
+
424
+ | name | type | default | range |
425
+ | --- | --- | --- | --- |
426
+ | `size` | `vec2i` | `[1280,720]` | 16…8192 |
427
+ | `filename` | `string` | `"render.png"` | |
428
+ | `background` | `color` | `[0,0,0,0]` | |
429
+ | `stroke` | `color` | `[0,0,0,1]` | |
430
+ | `strokeWidth` | `float` | `1` | 0…200 |
431
+ | `opacity` | `float` | `1` | 0…1 |
432
+ | `drawPoints` | `bool` | `false` | |
433
+ | `pointRadius` | `float` | `1.5` | 0…50 |
434
+
435
+ **Outputs**
436
+
437
+ | name | type | default | range |
438
+ | --- | --- | --- | --- |
439
+ | `image` | `image` | | |
440
+ | `asset` | `asset` | | |
441
+
342
442
  ### `cascade.geo.SvgExport`
343
443
 
344
444
  SVG Export — Write geometry as an SVG document, one group element per group.
@@ -359,6 +459,8 @@ Runs on `portable`.
359
459
  | `width` | `float` | `0` | |
360
460
  | `height` | `float` | `0` | |
361
461
  | `margin` | `float` | `0` | |
462
+ | `bounds` | `vec4` | `[0,0,0,0]` | |
463
+ | `background` | `color` | `[0,0,0,0]` | |
362
464
  | `stroke` | `color` | `[0,0,0,1]` | |
363
465
  | `strokeWidth` | `float` | `1` | |
364
466
  | `opacity` | `float` | `1` | 0…1 |
@@ -396,6 +498,275 @@ Runs on `portable`.
396
498
  | --- | --- | --- | --- |
397
499
  | `geometry` | `geometry` | | |
398
500
 
501
+ ### `cascade.pop.FieldForce`
502
+
503
+ POP Field Force — Pull particles along a field's gradient and around its contours. The calligraphy force.
504
+
505
+ Runs on `portable`.
506
+
507
+ **Inputs**
508
+
509
+ | name | type | default | range |
510
+ | --- | --- | --- | --- |
511
+ | `particles` | `geometry` | | |
512
+ | `field` | `geometry` | | |
513
+
514
+ **Props**
515
+
516
+ | name | type | default | range |
517
+ | --- | --- | --- | --- |
518
+ | `normal` | `float` | `0` | -100000…100000 |
519
+ | `tangential` | `float` | `2600` | -100000…100000 |
520
+ | `radius` | `float` | `20` | 0…10000 |
521
+ | `level` | `float` | `0.28` | 0…1 |
522
+ | `hold` | `float` | `5200` | 0…100000 |
523
+
524
+ **Outputs**
525
+
526
+ | name | type | default | range |
527
+ | --- | --- | --- | --- |
528
+ | `geometry` | `geometry` | | |
529
+
530
+ ### `cascade.pop.NoiseForce`
531
+
532
+ POP Noise Force — Push particles along a heading read from a noise field.
533
+
534
+ Runs on `portable`.
535
+
536
+ **Inputs**
537
+
538
+ | name | type | default | range |
539
+ | --- | --- | --- | --- |
540
+ | `particles` | `geometry` | | |
541
+
542
+ **Props**
543
+
544
+ | name | type | default | range |
545
+ | --- | --- | --- | --- |
546
+ | `amplitude` | `float` | `6` | 0…500 |
547
+ | `frequency` | `float` | `0.3` | 0.001…10 |
548
+ | `evolve` | `float` | `0` | -1000…1000 |
549
+ | `timestep` | `float` | `0.041666666666666664` | 0.004166666666666667…1 |
550
+ | `seed` | `int` | `7` | 0…999999 |
551
+
552
+ **Outputs**
553
+
554
+ | name | type | default | range |
555
+ | --- | --- | --- | --- |
556
+ | `geometry` | `geometry` | | |
557
+
558
+ ### `cascade.pop.Separate`
559
+
560
+ POP Separate — Push neighbours apart within a radius.
561
+
562
+ Runs on `portable`.
563
+
564
+ **Inputs**
565
+
566
+ | name | type | default | range |
567
+ | --- | --- | --- | --- |
568
+ | `particles` | `geometry` | | |
569
+
570
+ **Props**
571
+
572
+ | name | type | default | range |
573
+ | --- | --- | --- | --- |
574
+ | `radius` | `float` | `0.5` | 0…100 |
575
+ | `strength` | `float` | `4` | 0…500 |
576
+ | `timestep` | `float` | `0.041666666666666664` | 0.004166666666666667…1 |
577
+
578
+ **Outputs**
579
+
580
+ | name | type | default | range |
581
+ | --- | --- | --- | --- |
582
+ | `geometry` | `geometry` | | |
583
+
584
+ ### `cascade.pop.Simulate`
585
+
586
+ POP Simulate — Re-simulate a particle system from frame zero to this frame.
587
+
588
+ Runs on `portable`.
589
+
590
+ **Inputs**
591
+
592
+ | name | type | default | range |
593
+ | --- | --- | --- | --- |
594
+ | `geometry` | `geometry` | | |
595
+ | `frame` | `float` | `1` | |
596
+ | `attract` | `geometry` | | |
597
+ | `field` | `geometry` | | |
598
+
599
+ **Props**
600
+
601
+ | name | type | default | range |
602
+ | --- | --- | --- | --- |
603
+ | `trail_length` | `int` | `14` | 1…500 |
604
+ | `trail_increment` | `int` | `1` | 1…32 |
605
+ | `substeps` | `int` | `1` | 1…32 |
606
+ | `timestep` | `float` | `0.041666666666666664` | 0.004166666666666667…1 |
607
+ | `impulse` | `int` | `6` | 0…100000 |
608
+ | `life` | `float` | `4` | 0…3600 |
609
+ | `lifevar` | `float` | `0.4` | 0…1 |
610
+ | `force` | `vec2` | `[0,0]` | |
611
+ | `airresist` | `float` | `0.4` | 0…20 |
612
+ | `noise_amplitude` | `float` | `14` | 0…500 |
613
+ | `noise_frequency` | `float` | `0.02` | 0.001…10 |
614
+ | `noise_evolve` | `float` | `0.08` | -10…10 |
615
+ | `field_normal` | `float` | `0` | -20000…20000 |
616
+ | `field_tangential` | `float` | `0` | -20000…20000 |
617
+ | `field_radius` | `float` | `24` | 0.5…2000 |
618
+ | `field_level` | `float` | `0.35` | 0…1 |
619
+ | `field_hold` | `float` | `0` | 0…40000 |
620
+ | `birth_area` | `vec4` | `[0,0,0,0]` | |
621
+ | `birth_hue` | `vec2` | `[0,0]` | 0…1 |
622
+ | `birth_saturation` | `float` | `0.6` | 0…1 |
623
+ | `birth_value` | `float` | `1` | 0…1 |
624
+ | `attract_amplitude` | `float` | `0` | 0…20000 |
625
+ | `attract_radius` | `float` | `60` | 0…5000 |
626
+ | `separate_radius` | `float` | `0` | 0…500 |
627
+ | `separate_strength` | `float` | `12` | 0…500 |
628
+ | `maxspeed` | `float` | `60` | 0…10000 |
629
+ | `wrap` | `vec4` | `[0,0,0,0]` | |
630
+ | `seed` | `int` | `7` | 0…999999 |
631
+
632
+ **Outputs**
633
+
634
+ | name | type | default | range |
635
+ | --- | --- | --- | --- |
636
+ | `geometry` | `geometry` | | |
637
+ | `trails` | `geometry` | | |
638
+
639
+ ### `cascade.pop.Solver`
640
+
641
+ POP Solver — Advance a particle system by one timestep.
642
+
643
+ Runs on `portable`.
644
+
645
+ **Inputs**
646
+
647
+ | name | type | default | range |
648
+ | --- | --- | --- | --- |
649
+ | `particles` | `geometry` | | |
650
+
651
+ **Props**
652
+
653
+ | name | type | default | range |
654
+ | --- | --- | --- | --- |
655
+ | `timestep_mode` | `string` | `"fixed"` | |
656
+ | `timestep` | `float` | `0.041666666666666664` | 0.004166666666666667…1 |
657
+ | `maxspeed` | `float` | `0` | 0…10000 |
658
+ | `force` | `vec2` | `[0,0]` | |
659
+ | `airresist` | `float` | `0` | 0…20 |
660
+
661
+ **Outputs**
662
+
663
+ | name | type | default | range |
664
+ | --- | --- | --- | --- |
665
+ | `geometry` | `geometry` | | |
666
+
667
+ ### `cascade.pop.Source`
668
+
669
+ POP Source — Birth particles from a geometry's points.
670
+
671
+ Runs on `portable`.
672
+
673
+ **Inputs**
674
+
675
+ | name | type | default | range |
676
+ | --- | --- | --- | --- |
677
+ | `geometry` | `geometry` | | |
678
+ | `particles` | `geometry` | | |
679
+
680
+ **Props**
681
+
682
+ | name | type | default | range |
683
+ | --- | --- | --- | --- |
684
+ | `impulse` | `int` | `8` | 0…100000 |
685
+ | `life` | `float` | `3` | 0…3600 |
686
+ | `lifevar` | `float` | `0.3` | 0…1 |
687
+ | `velocity` | `vec2` | `[0,0]` | |
688
+ | `seed` | `int` | `7` | 0…999999 |
689
+
690
+ **Outputs**
691
+
692
+ | name | type | default | range |
693
+ | --- | --- | --- | --- |
694
+ | `geometry` | `geometry` | | |
695
+
696
+ ### `cascade.pop.Trail`
697
+
698
+ POP Trail — Build trails from a Feedback container's history.
699
+
700
+ Runs on `portable`.
701
+
702
+ **Inputs**
703
+
704
+ | name | type | default | range |
705
+ | --- | --- | --- | --- |
706
+ | `history` | `array` | | |
707
+ | `particles` | `geometry` | | |
708
+
709
+ **Props**
710
+
711
+ | name | type | default | range |
712
+ | --- | --- | --- | --- |
713
+ | `result` | `string` | `"polylines"` | |
714
+ | `length` | `int` | `12` | 1…100000 |
715
+ | `increment` | `int` | `1` | 1…1000 |
716
+ | `velocityscale` | `float` | `1` | 0…100 |
717
+
718
+ **Outputs**
719
+
720
+ | name | type | default | range |
721
+ | --- | --- | --- | --- |
722
+ | `geometry` | `geometry` | | |
723
+
724
+ ### `cascade.scene.Light`
725
+
726
+ Light — A light, following Houdini's /obj/hlight. Nothing shades with lights yet — the viewport draws wireframe and points.
727
+
728
+ Runs on `portable`.
729
+
730
+ **Inputs**
731
+
732
+ | name | type | default | range |
733
+ | --- | --- | --- | --- |
734
+ | `translate` | `vec3` | `[0,0,5]` | |
735
+ | `direction` | `vec3` | `[0,0,-1]` | |
736
+ | `color` | `color` | `[1,1,1,1]` | |
737
+ | `intensity` | `float` | `1` | |
738
+
739
+ **Props**
740
+
741
+ | name | type | default | range |
742
+ | --- | --- | --- | --- |
743
+ | `type` | `string` | `"point"` | |
744
+ | `coneangle` | `float` | `45` | 0…180 |
745
+
746
+ **Outputs**
747
+
748
+ | name | type | default | range |
749
+ | --- | --- | --- | --- |
750
+ | `light` | `light` | | |
751
+
752
+ ### `cascade.scene.Scene`
753
+
754
+ Scene — Geometry, a camera and lights, assembled into a scene. Attach anything to the input.
755
+
756
+ Runs on `portable`.
757
+
758
+ **Inputs**
759
+
760
+ | name | type | default | range |
761
+ | --- | --- | --- | --- |
762
+ | `inputs` | `any` | | |
763
+
764
+ **Outputs**
765
+
766
+ | name | type | default | range |
767
+ | --- | --- | --- | --- |
768
+ | `scene` | `scene` | | |
769
+
399
770
  ## Studio node libraries
400
771
 
401
772
  Class-based nodes, available in Studio. Their parameters are declared in the
@@ -413,7 +784,7 @@ under `src/nodes/<library>/nodes/`.
413
784
 
414
785
  ### Geometry — `cascade.geo.*`
415
786
 
416
- **Geometry.** `cascade.geo.Rectangle` (A closed four-point polygon, counter-clockwise from bottom-left.), `cascade.geo.Circle` (A closed circle, as one cubic Bezier chain or as a polygon of divisions segments.), `cascade.geo.Transform` (Translate, rotate and scale geometry about a pivot.), `cascade.geo.Merge` (Concatenate geometries, taking the union of their attributes.), `cascade.geo.CopyToPoints` (Instance one geometry onto every point of another.), `cascade.geo.SvgExport` (Write geometry as an SVG document, one group element per group.)
787
+ **Geometry.** `cascade.geo.Rectangle` (A closed four-point polygon, counter-clockwise from bottom-left.), `cascade.geo.Circle` (A closed circle, as one cubic Bezier chain or as a polygon of divisions segments.), `cascade.geo.Transform` (Translate, rotate and scale geometry about a pivot.), `cascade.geo.Merge` (Concatenate geometries, taking the union of their attributes.), `cascade.geo.CopyToPoints` (Instance one geometry onto every point of another.), `cascade.geo.SvgExport` (Write geometry as an SVG document, one group element per group.), `cascade.geo.Render` (Draw a scene through a camera, as a raster.)
417
788
 
418
789
  ### Image — `cascade.image.*`
419
790
 
@@ -564,12 +564,24 @@ Applications can use `createRuntime()` from `cascade/runtime` directly. Register
564
564
 
565
565
  Server and browser hosts are deliberately explicit. A graph that uses Python or shell stages belongs on the server or behind an application-defined bridge; the runtime does not silently move computation between environments.
566
566
 
567
- The Studio single-HTML/folder exporter is not this embedding API. It currently
567
+ For a browser-only deployment, build a static player:
568
+
569
+ ```bash
570
+ cascade build index.cascade --out web-player --asset assets/source.svg
571
+ ```
572
+
573
+ The output directory must be new. Serve it over HTTP(S), open `index.html`, or
574
+ embed `player.html` in an iframe. `embed.js` supplies same-origin playback,
575
+ parameter and output controls. Only explicitly included files and literal typed
576
+ asset/image references are copied; server capabilities are rejected, not proxied.
577
+ See [Web player](WEB_PLAYER.md) for the full deployment and asset contract.
578
+
579
+ The Studio single-HTML/folder exporter is separate from this player. It currently
568
580
  serializes a compatibility graph into its own small browser runtime, so it does
569
581
  not preserve every node, capability, or runtime behavior. Use it only after
570
- testing the exported artifact for the particular graph. For a dependable
571
- custom experience today, embed `cascade/runtime` in an application and provide
572
- the graph's declared modules and capabilities explicitly.
582
+ testing the exported artifact for the particular graph. Prefer `cascade build`
583
+ for definition-v1 browser graphs, or embed `cascade/runtime` directly when an
584
+ application needs custom capabilities and presentation.
573
585
 
574
586
  ## Verify a project
575
587
 
@@ -0,0 +1,131 @@
1
+ # Browser player
2
+
3
+ The player runs a compatible graph in a browser without Studio or a Cascade
4
+ server. Available in Cascade 0.5+. Install `@field/cascade@latest`, or build the
5
+ checkout when developing Cascade itself.
6
+
7
+ ## Build and launch
8
+
9
+ From a project containing `index.cascade`:
10
+
11
+ ```sh
12
+ cascade build index.cascade --out web-player
13
+ ```
14
+
15
+ The output directory must not already exist. It contains `index.html`,
16
+ `player.html`, `app.js`, `embed.js`, and any included assets. Serve that directory
17
+ with an ordinary static HTTP server or hosting service, then open `index.html`.
18
+ Do not open it through `file://`: browser module and asset loading requires HTTP.
19
+ No application backend is required. WebGPU needs a supported browser/device and
20
+ a secure context such as HTTPS or localhost.
21
+
22
+ Graph definitions are inspected and compiled at build time, not executed.
23
+ The build rejects unsupported server capabilities, server transport imports,
24
+ Node dependencies and dynamic node modules. It does not publish or upload files.
25
+
26
+ ## Embed
27
+
28
+ For a simple embed, including across origins:
29
+
30
+ ```html
31
+ <iframe src="/artwork/player.html" title="Generative artwork"
32
+ style="width:100%;height:600px;border:0"></iframe>
33
+ ```
34
+
35
+ For programmatic controls on the **same origin**:
36
+
37
+ Give the host container an explicit height, for example
38
+ `<div id="artwork" style="height:600px"></div>`. The iframe fills that container.
39
+
40
+ ```js
41
+ import { mount } from './web-player/embed.js';
42
+
43
+ const player = await mount(document.querySelector('#artwork'), {
44
+ frame: 1,
45
+ fps: 30,
46
+ autoplay: false,
47
+ output: { nodeId: 'render', port: 'image' },
48
+ });
49
+
50
+ await player.setProp('render', 'strokeWidth', 2);
51
+ await player.seek(48);
52
+ player.play();
53
+ // Later, when the host view is removed:
54
+ await player.dispose();
55
+ ```
56
+
57
+ The generic `mountPlayer` export from `cascade/player` accepts the same options
58
+ plus `url`, pointing to a built `player.html`. Each mount creates an iframe, so
59
+ two sketches can use the same node IDs and cache filenames without sharing data.
60
+ Programmatic cross-origin control is not provided; use the iframe directly.
61
+
62
+ Mount resolves after the first successful cook and display. A failed startup
63
+ rejects and removes the failed embed. Playback starts paused unless requested;
64
+ runtime failures pause playback and expose their diagnostic. Frame work is
65
+ serialized and playback coalesces requests instead of building a catch-up queue.
66
+
67
+ ## Controls and output
68
+
69
+ `PlayerController` provides:
70
+
71
+ - `play()`, `pause()`, `seek(frame)`.
72
+ - `setInput(nodeId, name, value)` and `setProp(nodeId, name, value)`, which await
73
+ the resulting cook.
74
+ - `selectOutput(nodeId, port)` and `getOutput(nodeId, port)`.
75
+ - `downloadOutput()`, returning the selected output as a `Blob`.
76
+ - `resize(width, height)` for the display, without changing authored resolution.
77
+ - `subscribe(listener)` for `frame`, `playing` and `error` events; returns an
78
+ unsubscribe function.
79
+ - `dispose()`, which stops work and releases runtime, GPU, image and iframe resources.
80
+
81
+ Output selection defaults to the last renderable output in the run result;
82
+ select a node and port explicitly when a graph has several deliverables. Images/SVG and
83
+ geometry/scenes are displayable; scene rendering currently uses the shared CPU
84
+ wireframe/point renderer, not a shaded GPU renderer. Camera conventions match
85
+ Studio and offline rendering. For durable image retention, obtain a Blob:
86
+ image references returned by `getOutput` are current-frame references, not an
87
+ archive of every rendered frame.
88
+
89
+ ## Assets and resource limits
90
+
91
+ Literal typed image/asset references in graph inputs or props are included
92
+ automatically. Files whose paths are computed in node code must be listed:
93
+
94
+ ```sh
95
+ cascade build index.cascade --out web-player --asset assets/photo.png
96
+ ```
97
+
98
+ Repeat `--asset` for additional files. Only those files are copied, preserving
99
+ project-relative paths below the output's `assets/` directory. Directories,
100
+ hidden files, path traversal and symlinks escaping the project are rejected.
101
+ The builder never copies the entire project, credentials, Python environments
102
+ or cache directories. Review authored graph values and custom code before
103
+ publishing: project modules are trusted code, not a sandbox.
104
+
105
+ The player supplies one asset store for declared `assets` capabilities and
106
+ existing `cascade/io` imports. Reads resolve packaged files; writes stay in
107
+ memory and create immutable references. `mediaUrl` resolves through that store,
108
+ not Studio's `/api/media`. Server-only preview transformations are unsupported
109
+ and fail explicitly rather than returning different pixels silently.
110
+
111
+ Generated encoded assets are limited to 256 MiB and 4,096 entries per iframe.
112
+ After a cook, assets no longer reachable from graph outputs, authored/controller
113
+ values or active display leases are released. Feedback history keeps referenced
114
+ images alive. Exceeding the live budget fails with a diagnostic; live images
115
+ are not silently replaced or evicted. Disposal revokes all generated URLs.
116
+
117
+ ## Host limits
118
+
119
+ | Graph requirement | Static player |
120
+ | --- | --- |
121
+ | Definition-v1 CPU nodes, core/geometry/POP/scene built-ins | Supported |
122
+ | Canvas drawing and compatible `cascade/io` helpers | Supported |
123
+ | Declared `assets` | Packaged inputs and in-memory generated outputs |
124
+ | Declared `gpu` | Browser WebGPU, if available; no Dawn in the browser |
125
+ | Python, shell, filesystem, Studio/server transport | Rejected |
126
+ | Dynamic modules or mixed execution styles | Rejected |
127
+ | Project Studio panels | Not included |
128
+
129
+ Separate heavy preprocessing from the live graph when possible: export its
130
+ result as an explicit asset, then build the browser-compatible graph around
131
+ that input. The player does not emulate server operations or carry credentials.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@field/cascade",
3
- "version": "0.4.0",
3
+ "version": "0.5.2",
4
4
  "description": "Visual programming for generative art",
5
5
  "license": "MIT",
6
6
  "author": "FIELD.IO <marcus@field.io>",
@@ -8,7 +8,7 @@
8
8
  "type": "git",
9
9
  "url": "git+https://github.com/marcuswendt/cascade.git"
10
10
  },
11
- "homepage": "https://github.com/marcuswendt/cascade#readme",
11
+ "homepage": "https://cascade.field.io",
12
12
  "keywords": [
13
13
  "node-graph",
14
14
  "visual-programming",
@@ -34,6 +34,7 @@
34
34
  "doc/NODE_REFERENCE.md",
35
35
  "doc/PROJECT_AUTHORING.md",
36
36
  "doc/HEADLESS_GPU.md",
37
+ "doc/WEB_PLAYER.md",
37
38
  "README.md",
38
39
  "LICENSE"
39
40
  ],
@@ -77,6 +78,14 @@
77
78
  "types": "./dist/runtime/camera/index.d.ts",
78
79
  "default": "./dist/runtime/camera/index.js"
79
80
  },
81
+ "./runtime/render": {
82
+ "types": "./dist/runtime/geometry/render.d.ts",
83
+ "default": "./dist/runtime/geometry/render.js"
84
+ },
85
+ "./runtime/scene": {
86
+ "types": "./dist/runtime/scene/index.d.ts",
87
+ "default": "./dist/runtime/scene/index.js"
88
+ },
80
89
  "./runtime/definition/extract": {
81
90
  "types": "./dist/runtime/definition/extract.d.ts",
82
91
  "default": "./dist/runtime/definition/extract.js"
@@ -103,6 +112,10 @@
103
112
  },
104
113
  "./studio/panel": {
105
114
  "types": "./dist/studio/panel.d.ts"
115
+ },
116
+ "./player": {
117
+ "types": "./dist/player/embed.d.ts",
118
+ "default": "./dist/player/embed.js"
106
119
  }
107
120
  },
108
121
  "scripts": {
@@ -122,6 +135,7 @@
122
135
  "test:run": "vitest run",
123
136
  "test:coverage": "vitest run --coverage",
124
137
  "test:package": "node scripts/smoke-package.mjs",
138
+ "test:player": "node scripts/smoke-player.mjs",
125
139
  "build:node-reference": "tsx scripts/build-node-reference.mjs"
126
140
  },
127
141
  "dependencies": {
@@ -1 +0,0 @@
1
- import{b as e,f as t,s as n,x as r}from"./index-CC6YQw2n.js";r(n,{assets:e});export{t as geoLibrary};