paperlab 0.0.1 → 0.2.0

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.
package/dist/index.d.ts CHANGED
@@ -6,6 +6,14 @@ import { z } from 'zod';
6
6
  * The zod schema is the single source of truth: it validates the public API,
7
7
  * generates editor panels, defines the `.paper` preset format, and feeds the docs.
8
8
  * If a feature can't serialize into this schema, it waits.
9
+ *
10
+ * Every schema here exports BOTH of its types, and the difference is
11
+ * load-bearing. `z.infer` is the parsed config — every default filled in,
12
+ * every field present — and it is what the renderer reads. `z.input` is what
13
+ * a caller is allowed to write, where anything with a default is optional,
14
+ * and it is what every public prop must take. Handing a component the
15
+ * inferred type instead demands that the caller supply every field of every
16
+ * nested object, which turns the documented one-liner into a type error.
9
17
  */
10
18
  declare const sheetSchema: z.ZodObject<{
11
19
  /** World units. A letter sheet is ~1 × 1.4, a receipt ~1 × 2.6. */
@@ -13,7 +21,12 @@ declare const sheetSchema: z.ZodObject<{
13
21
  height: z.ZodDefault<z.ZodNumber>;
14
22
  /** Visual thickness in mm-ish units; drives edge/shadow treatment, not geometry (yet). */
15
23
  thickness: z.ZodDefault<z.ZodNumber>;
16
- /** 'auto' sizes the grid from the active deformers' needs. */
24
+ /**
25
+ * `'auto'` gives the LONG side 72 segments, whatever is on the sheet — a
26
+ * deformer's `minSegments` can only raise that floor, never lower it, so in
27
+ * practice a blank sheet is tessellated exactly as finely as a crumpled
28
+ * one. Set a number to take the decision yourself.
29
+ */
17
30
  segments: z.ZodDefault<z.ZodUnion<[z.ZodLiteral<"auto">, z.ZodNumber]>>;
18
31
  cornerRadius: z.ZodDefault<z.ZodNumber>;
19
32
  }, "strip", z.ZodTypeAny, {
@@ -1071,6 +1084,8 @@ declare const contentSchema: z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
1071
1084
  } | undefined;
1072
1085
  }>]>;
1073
1086
  type ContentConfig = z.infer<typeof contentSchema>;
1087
+ /** What a caller may WRITE — defaults still unfilled. This is the prop type. */
1088
+ type ContentConfigInput = z.input<typeof contentSchema>;
1074
1089
  declare const paperEdges: readonly ["top", "right", "bottom", "left"];
1075
1090
  /**
1076
1091
  * Fragment-side effects, composed in registration order into one shader
@@ -1080,6 +1095,8 @@ declare const paperEdges: readonly ["top", "right", "bottom", "left"];
1080
1095
  declare const surfaceSchema: z.ZodObject<{
1081
1096
  /** Paper fiber noise, 0..1. */
1082
1097
  grain: z.ZodOptional<z.ZodNumber>;
1098
+ /** Light passing through the sheet from behind, 0..1. Stock defaults apply. */
1099
+ translucency: z.ZodOptional<z.ZodNumber>;
1083
1100
  /** Torn-edge alpha with a lightened fiber band. */
1084
1101
  deckle: z.ZodOptional<z.ZodObject<{
1085
1102
  edges: z.ZodDefault<z.ZodArray<z.ZodEnum<["top", "right", "bottom", "left"]>, "many">>;
@@ -1099,13 +1116,13 @@ declare const surfaceSchema: z.ZodObject<{
1099
1116
  positions: z.ZodDefault<z.ZodArray<z.ZodNumber, "many">>;
1100
1117
  strength: z.ZodDefault<z.ZodNumber>;
1101
1118
  }, "strip", z.ZodTypeAny, {
1119
+ strength: number;
1102
1120
  angle: number;
1103
1121
  positions: number[];
1104
- strength: number;
1105
1122
  }, {
1123
+ strength?: number | undefined;
1106
1124
  angle?: number | undefined;
1107
1125
  positions?: number[] | undefined;
1108
- strength?: number | undefined;
1109
1126
  }>>;
1110
1127
  /** Yellowing + foxing spots, 0..1. */
1111
1128
  aging: z.ZodOptional<z.ZodNumber>;
@@ -1160,14 +1177,15 @@ declare const surfaceSchema: z.ZodObject<{
1160
1177
  }>>;
1161
1178
  }, "strip", z.ZodTypeAny, {
1162
1179
  grain?: number | undefined;
1180
+ translucency?: number | undefined;
1163
1181
  deckle?: {
1164
1182
  edges: ("left" | "right" | "top" | "bottom")[];
1165
1183
  roughness: number;
1166
1184
  } | undefined;
1167
1185
  creaseLines?: {
1186
+ strength: number;
1168
1187
  angle: number;
1169
1188
  positions: number[];
1170
- strength: number;
1171
1189
  } | undefined;
1172
1190
  aging?: number | undefined;
1173
1191
  showThrough?: number | undefined;
@@ -1184,14 +1202,15 @@ declare const surfaceSchema: z.ZodObject<{
1184
1202
  } | undefined;
1185
1203
  }, {
1186
1204
  grain?: number | undefined;
1205
+ translucency?: number | undefined;
1187
1206
  deckle?: {
1188
1207
  edges?: ("left" | "right" | "top" | "bottom")[] | undefined;
1189
1208
  roughness?: number | undefined;
1190
1209
  } | undefined;
1191
1210
  creaseLines?: {
1211
+ strength?: number | undefined;
1192
1212
  angle?: number | undefined;
1193
1213
  positions?: number[] | undefined;
1194
- strength?: number | undefined;
1195
1214
  } | undefined;
1196
1215
  aging?: number | undefined;
1197
1216
  showThrough?: number | undefined;
@@ -1208,6 +1227,7 @@ declare const surfaceSchema: z.ZodObject<{
1208
1227
  } | undefined;
1209
1228
  }>;
1210
1229
  type SurfaceConfig = z.infer<typeof surfaceSchema>;
1230
+ type SurfaceConfigInput = z.input<typeof surfaceSchema>;
1211
1231
  type PaperEdge = (typeof paperEdges)[number];
1212
1232
  declare const behaviorConfigSchema: z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
1213
1233
  progress: z.ZodDefault<z.ZodNumber>;
@@ -1356,8 +1376,28 @@ declare const behaviorConfigSchema: z.ZodDiscriminatedUnion<"type", [z.ZodObject
1356
1376
  tumble?: number | undefined;
1357
1377
  respawn?: boolean | undefined;
1358
1378
  range?: number | undefined;
1379
+ }>, z.ZodObject<{
1380
+ progress: z.ZodDefault<z.ZodNumber>;
1381
+ coarseness: z.ZodDefault<z.ZodNumber>;
1382
+ ball: z.ZodDefault<z.ZodNumber>;
1383
+ seed: z.ZodDefault<z.ZodNumber>;
1384
+ } & {
1385
+ type: z.ZodLiteral<"crumple">;
1386
+ }, "strip", z.ZodTypeAny, {
1387
+ type: "crumple";
1388
+ progress: number;
1389
+ coarseness: number;
1390
+ ball: number;
1391
+ seed: number;
1392
+ }, {
1393
+ type: "crumple";
1394
+ progress?: number | undefined;
1395
+ coarseness?: number | undefined;
1396
+ ball?: number | undefined;
1397
+ seed?: number | undefined;
1359
1398
  }>]>;
1360
1399
  type BehaviorConfig = z.infer<typeof behaviorConfigSchema>;
1400
+ type BehaviorConfigInput = z.input<typeof behaviorConfigSchema>;
1361
1401
  /** Advanced escape hatch: a raw deformer stack (editing one forks the behavior). */
1362
1402
  declare const deformerInstanceSchema: z.ZodObject<{
1363
1403
  type: z.ZodString;
@@ -1373,6 +1413,7 @@ declare const deformerInstanceSchema: z.ZodObject<{
1373
1413
  enabled?: boolean | undefined;
1374
1414
  }>;
1375
1415
  type DeformerInstanceConfig = z.infer<typeof deformerInstanceSchema>;
1416
+ type DeformerInstanceConfigInput = z.input<typeof deformerInstanceSchema>;
1376
1417
  /** Kept in sync with `idleNames` in physics/idle.ts (asserted by test). */
1377
1418
  declare const physicsNames: readonly ["none", "float", "tumble", "dangle", "taped", "breeze"];
1378
1419
  declare const clothConfigSchema: z.ZodObject<{
@@ -1432,16 +1473,18 @@ declare const physicsSchema: z.ZodUnion<[z.ZodEnum<["none", "float", "tumble", "
1432
1473
  floor?: number | undefined;
1433
1474
  }>]>;
1434
1475
  type PhysicsConfig = z.infer<typeof physicsSchema>;
1435
- declare const lightingNames: readonly ["studio", "window", "leaves", "goldenhour", "noir"];
1476
+ type PhysicsConfigInput = z.input<typeof physicsSchema>;
1477
+ declare const lightingNames: readonly ["studio", "window", "leaves", "goldenhour", "noir", "nave"];
1436
1478
  /** Scene-level presentation, serialized with the paper. */
1437
1479
  declare const sceneSchema: z.ZodObject<{
1438
- lighting: z.ZodDefault<z.ZodEnum<["studio", "window", "leaves", "goldenhour", "noir"]>>;
1480
+ lighting: z.ZodDefault<z.ZodEnum<["studio", "window", "leaves", "goldenhour", "noir", "nave"]>>;
1439
1481
  }, "strip", z.ZodTypeAny, {
1440
- lighting: "studio" | "window" | "leaves" | "goldenhour" | "noir";
1482
+ lighting: "studio" | "window" | "leaves" | "goldenhour" | "noir" | "nave";
1441
1483
  }, {
1442
- lighting?: "studio" | "window" | "leaves" | "goldenhour" | "noir" | undefined;
1484
+ lighting?: "studio" | "window" | "leaves" | "goldenhour" | "noir" | "nave" | undefined;
1443
1485
  }>;
1444
1486
  type SceneConfig = z.infer<typeof sceneSchema>;
1487
+ type SceneConfigInput = z.input<typeof sceneSchema>;
1445
1488
  type LightingName = (typeof lightingNames)[number];
1446
1489
  /**
1447
1490
  * A state is a set of parameter overrides on the base preset — never a
@@ -1595,7 +1638,12 @@ declare const paperConfigSchema: z.ZodEffects<z.ZodObject<{
1595
1638
  height: z.ZodDefault<z.ZodNumber>;
1596
1639
  /** Visual thickness in mm-ish units; drives edge/shadow treatment, not geometry (yet). */
1597
1640
  thickness: z.ZodDefault<z.ZodNumber>;
1598
- /** 'auto' sizes the grid from the active deformers' needs. */
1641
+ /**
1642
+ * `'auto'` gives the LONG side 72 segments, whatever is on the sheet — a
1643
+ * deformer's `minSegments` can only raise that floor, never lower it, so in
1644
+ * practice a blank sheet is tessellated exactly as finely as a crumpled
1645
+ * one. Set a number to take the decision yourself.
1646
+ */
1599
1647
  segments: z.ZodDefault<z.ZodUnion<[z.ZodLiteral<"auto">, z.ZodNumber]>>;
1600
1648
  cornerRadius: z.ZodDefault<z.ZodNumber>;
1601
1649
  }, "strip", z.ZodTypeAny, {
@@ -2494,6 +2542,25 @@ declare const paperConfigSchema: z.ZodEffects<z.ZodObject<{
2494
2542
  tumble?: number | undefined;
2495
2543
  respawn?: boolean | undefined;
2496
2544
  range?: number | undefined;
2545
+ }>, z.ZodObject<{
2546
+ progress: z.ZodDefault<z.ZodNumber>;
2547
+ coarseness: z.ZodDefault<z.ZodNumber>;
2548
+ ball: z.ZodDefault<z.ZodNumber>;
2549
+ seed: z.ZodDefault<z.ZodNumber>;
2550
+ } & {
2551
+ type: z.ZodLiteral<"crumple">;
2552
+ }, "strip", z.ZodTypeAny, {
2553
+ type: "crumple";
2554
+ progress: number;
2555
+ coarseness: number;
2556
+ ball: number;
2557
+ seed: number;
2558
+ }, {
2559
+ type: "crumple";
2560
+ progress?: number | undefined;
2561
+ coarseness?: number | undefined;
2562
+ ball?: number | undefined;
2563
+ seed?: number | undefined;
2497
2564
  }>]>>;
2498
2565
  deformers: z.ZodOptional<z.ZodArray<z.ZodObject<{
2499
2566
  type: z.ZodString;
@@ -2511,6 +2578,8 @@ declare const paperConfigSchema: z.ZodEffects<z.ZodObject<{
2511
2578
  surface: z.ZodDefault<z.ZodObject<{
2512
2579
  /** Paper fiber noise, 0..1. */
2513
2580
  grain: z.ZodOptional<z.ZodNumber>;
2581
+ /** Light passing through the sheet from behind, 0..1. Stock defaults apply. */
2582
+ translucency: z.ZodOptional<z.ZodNumber>;
2514
2583
  /** Torn-edge alpha with a lightened fiber band. */
2515
2584
  deckle: z.ZodOptional<z.ZodObject<{
2516
2585
  edges: z.ZodDefault<z.ZodArray<z.ZodEnum<["top", "right", "bottom", "left"]>, "many">>;
@@ -2530,13 +2599,13 @@ declare const paperConfigSchema: z.ZodEffects<z.ZodObject<{
2530
2599
  positions: z.ZodDefault<z.ZodArray<z.ZodNumber, "many">>;
2531
2600
  strength: z.ZodDefault<z.ZodNumber>;
2532
2601
  }, "strip", z.ZodTypeAny, {
2602
+ strength: number;
2533
2603
  angle: number;
2534
2604
  positions: number[];
2535
- strength: number;
2536
2605
  }, {
2606
+ strength?: number | undefined;
2537
2607
  angle?: number | undefined;
2538
2608
  positions?: number[] | undefined;
2539
- strength?: number | undefined;
2540
2609
  }>>;
2541
2610
  /** Yellowing + foxing spots, 0..1. */
2542
2611
  aging: z.ZodOptional<z.ZodNumber>;
@@ -2591,14 +2660,15 @@ declare const paperConfigSchema: z.ZodEffects<z.ZodObject<{
2591
2660
  }>>;
2592
2661
  }, "strip", z.ZodTypeAny, {
2593
2662
  grain?: number | undefined;
2663
+ translucency?: number | undefined;
2594
2664
  deckle?: {
2595
2665
  edges: ("left" | "right" | "top" | "bottom")[];
2596
2666
  roughness: number;
2597
2667
  } | undefined;
2598
2668
  creaseLines?: {
2669
+ strength: number;
2599
2670
  angle: number;
2600
2671
  positions: number[];
2601
- strength: number;
2602
2672
  } | undefined;
2603
2673
  aging?: number | undefined;
2604
2674
  showThrough?: number | undefined;
@@ -2615,14 +2685,15 @@ declare const paperConfigSchema: z.ZodEffects<z.ZodObject<{
2615
2685
  } | undefined;
2616
2686
  }, {
2617
2687
  grain?: number | undefined;
2688
+ translucency?: number | undefined;
2618
2689
  deckle?: {
2619
2690
  edges?: ("left" | "right" | "top" | "bottom")[] | undefined;
2620
2691
  roughness?: number | undefined;
2621
2692
  } | undefined;
2622
2693
  creaseLines?: {
2694
+ strength?: number | undefined;
2623
2695
  angle?: number | undefined;
2624
2696
  positions?: number[] | undefined;
2625
- strength?: number | undefined;
2626
2697
  } | undefined;
2627
2698
  aging?: number | undefined;
2628
2699
  showThrough?: number | undefined;
@@ -2670,11 +2741,11 @@ declare const paperConfigSchema: z.ZodEffects<z.ZodObject<{
2670
2741
  floor?: number | undefined;
2671
2742
  }>]>>;
2672
2743
  scene: z.ZodDefault<z.ZodObject<{
2673
- lighting: z.ZodDefault<z.ZodEnum<["studio", "window", "leaves", "goldenhour", "noir"]>>;
2744
+ lighting: z.ZodDefault<z.ZodEnum<["studio", "window", "leaves", "goldenhour", "noir", "nave"]>>;
2674
2745
  }, "strip", z.ZodTypeAny, {
2675
- lighting: "studio" | "window" | "leaves" | "goldenhour" | "noir";
2746
+ lighting: "studio" | "window" | "leaves" | "goldenhour" | "noir" | "nave";
2676
2747
  }, {
2677
- lighting?: "studio" | "window" | "leaves" | "goldenhour" | "noir" | undefined;
2748
+ lighting?: "studio" | "window" | "leaves" | "goldenhour" | "noir" | "nave" | undefined;
2678
2749
  }>>;
2679
2750
  onTwos: z.ZodDefault<z.ZodBoolean>;
2680
2751
  /** Interaction state machine — overrides-on-base diffs (spec M6 §1). */
@@ -2918,14 +2989,15 @@ declare const paperConfigSchema: z.ZodEffects<z.ZodObject<{
2918
2989
  };
2919
2990
  surface: {
2920
2991
  grain?: number | undefined;
2992
+ translucency?: number | undefined;
2921
2993
  deckle?: {
2922
2994
  edges: ("left" | "right" | "top" | "bottom")[];
2923
2995
  roughness: number;
2924
2996
  } | undefined;
2925
2997
  creaseLines?: {
2998
+ strength: number;
2926
2999
  angle: number;
2927
3000
  positions: number[];
2928
- strength: number;
2929
3001
  } | undefined;
2930
3002
  aging?: number | undefined;
2931
3003
  showThrough?: number | undefined;
@@ -2950,7 +3022,7 @@ declare const paperConfigSchema: z.ZodEffects<z.ZodObject<{
2950
3022
  floor: number;
2951
3023
  };
2952
3024
  scene: {
2953
- lighting: "studio" | "window" | "leaves" | "goldenhour" | "noir";
3025
+ lighting: "studio" | "window" | "leaves" | "goldenhour" | "noir" | "nave";
2954
3026
  };
2955
3027
  onTwos: boolean;
2956
3028
  states?: {
@@ -3011,6 +3083,12 @@ declare const paperConfigSchema: z.ZodEffects<z.ZodObject<{
3011
3083
  tumble: number;
3012
3084
  respawn: boolean;
3013
3085
  range: number;
3086
+ } | {
3087
+ type: "crumple";
3088
+ progress: number;
3089
+ coarseness: number;
3090
+ ball: number;
3091
+ seed: number;
3014
3092
  } | undefined;
3015
3093
  deformers?: {
3016
3094
  type: string;
@@ -3240,6 +3318,12 @@ declare const paperConfigSchema: z.ZodEffects<z.ZodObject<{
3240
3318
  tumble?: number | undefined;
3241
3319
  respawn?: boolean | undefined;
3242
3320
  range?: number | undefined;
3321
+ } | {
3322
+ type: "crumple";
3323
+ progress?: number | undefined;
3324
+ coarseness?: number | undefined;
3325
+ ball?: number | undefined;
3326
+ seed?: number | undefined;
3243
3327
  } | undefined;
3244
3328
  deformers?: {
3245
3329
  type: string;
@@ -3248,14 +3332,15 @@ declare const paperConfigSchema: z.ZodEffects<z.ZodObject<{
3248
3332
  }[] | undefined;
3249
3333
  surface?: {
3250
3334
  grain?: number | undefined;
3335
+ translucency?: number | undefined;
3251
3336
  deckle?: {
3252
3337
  edges?: ("left" | "right" | "top" | "bottom")[] | undefined;
3253
3338
  roughness?: number | undefined;
3254
3339
  } | undefined;
3255
3340
  creaseLines?: {
3341
+ strength?: number | undefined;
3256
3342
  angle?: number | undefined;
3257
3343
  positions?: number[] | undefined;
3258
- strength?: number | undefined;
3259
3344
  } | undefined;
3260
3345
  aging?: number | undefined;
3261
3346
  showThrough?: number | undefined;
@@ -3280,7 +3365,7 @@ declare const paperConfigSchema: z.ZodEffects<z.ZodObject<{
3280
3365
  floor?: number | undefined;
3281
3366
  } | undefined;
3282
3367
  scene?: {
3283
- lighting?: "studio" | "window" | "leaves" | "goldenhour" | "noir" | undefined;
3368
+ lighting?: "studio" | "window" | "leaves" | "goldenhour" | "noir" | "nave" | undefined;
3284
3369
  } | undefined;
3285
3370
  onTwos?: boolean | undefined;
3286
3371
  }>, {
@@ -3450,14 +3535,15 @@ declare const paperConfigSchema: z.ZodEffects<z.ZodObject<{
3450
3535
  };
3451
3536
  surface: {
3452
3537
  grain?: number | undefined;
3538
+ translucency?: number | undefined;
3453
3539
  deckle?: {
3454
3540
  edges: ("left" | "right" | "top" | "bottom")[];
3455
3541
  roughness: number;
3456
3542
  } | undefined;
3457
3543
  creaseLines?: {
3544
+ strength: number;
3458
3545
  angle: number;
3459
3546
  positions: number[];
3460
- strength: number;
3461
3547
  } | undefined;
3462
3548
  aging?: number | undefined;
3463
3549
  showThrough?: number | undefined;
@@ -3482,7 +3568,7 @@ declare const paperConfigSchema: z.ZodEffects<z.ZodObject<{
3482
3568
  floor: number;
3483
3569
  };
3484
3570
  scene: {
3485
- lighting: "studio" | "window" | "leaves" | "goldenhour" | "noir";
3571
+ lighting: "studio" | "window" | "leaves" | "goldenhour" | "noir" | "nave";
3486
3572
  };
3487
3573
  onTwos: boolean;
3488
3574
  states?: {
@@ -3543,6 +3629,12 @@ declare const paperConfigSchema: z.ZodEffects<z.ZodObject<{
3543
3629
  tumble: number;
3544
3630
  respawn: boolean;
3545
3631
  range: number;
3632
+ } | {
3633
+ type: "crumple";
3634
+ progress: number;
3635
+ coarseness: number;
3636
+ ball: number;
3637
+ seed: number;
3546
3638
  } | undefined;
3547
3639
  deformers?: {
3548
3640
  type: string;
@@ -3772,6 +3864,12 @@ declare const paperConfigSchema: z.ZodEffects<z.ZodObject<{
3772
3864
  tumble?: number | undefined;
3773
3865
  respawn?: boolean | undefined;
3774
3866
  range?: number | undefined;
3867
+ } | {
3868
+ type: "crumple";
3869
+ progress?: number | undefined;
3870
+ coarseness?: number | undefined;
3871
+ ball?: number | undefined;
3872
+ seed?: number | undefined;
3775
3873
  } | undefined;
3776
3874
  deformers?: {
3777
3875
  type: string;
@@ -3780,14 +3878,15 @@ declare const paperConfigSchema: z.ZodEffects<z.ZodObject<{
3780
3878
  }[] | undefined;
3781
3879
  surface?: {
3782
3880
  grain?: number | undefined;
3881
+ translucency?: number | undefined;
3783
3882
  deckle?: {
3784
3883
  edges?: ("left" | "right" | "top" | "bottom")[] | undefined;
3785
3884
  roughness?: number | undefined;
3786
3885
  } | undefined;
3787
3886
  creaseLines?: {
3887
+ strength?: number | undefined;
3788
3888
  angle?: number | undefined;
3789
3889
  positions?: number[] | undefined;
3790
- strength?: number | undefined;
3791
3890
  } | undefined;
3792
3891
  aging?: number | undefined;
3793
3892
  showThrough?: number | undefined;
@@ -3812,7 +3911,7 @@ declare const paperConfigSchema: z.ZodEffects<z.ZodObject<{
3812
3911
  floor?: number | undefined;
3813
3912
  } | undefined;
3814
3913
  scene?: {
3815
- lighting?: "studio" | "window" | "leaves" | "goldenhour" | "noir" | undefined;
3914
+ lighting?: "studio" | "window" | "leaves" | "goldenhour" | "noir" | "nave" | undefined;
3816
3915
  } | undefined;
3817
3916
  onTwos?: boolean | undefined;
3818
3917
  }>;
@@ -3941,10 +4040,20 @@ interface PaperMeshProps {
3941
4040
  preset?: string | PaperConfigInput;
3942
4041
  sheet?: Partial<SheetConfig>;
3943
4042
  stock?: StockName;
3944
- content?: ContentConfig;
3945
- behavior?: BehaviorConfig;
3946
- deformers?: DeformerInstanceConfig[];
3947
- physics?: PhysicsConfig | 'cloth';
4043
+ /**
4044
+ * These take the schema's INPUT types, not its parsed ones: writing
4045
+ * `content={{ type: 'text', text: 'hi' }}` has to compile, and with the
4046
+ * inferred type it does not — it demands every field of every nested
4047
+ * object. Every default stays a default.
4048
+ */
4049
+ content?: ContentConfigInput;
4050
+ behavior?: BehaviorConfigInput;
4051
+ deformers?: DeformerInstanceConfigInput[];
4052
+ /** Fragment-side effects: grain, aging, deckle, creases, perforation. */
4053
+ surface?: SurfaceConfigInput;
4054
+ /** Scene-level presentation that travels with the paper (lighting). */
4055
+ scene?: SceneConfigInput;
4056
+ physics?: PhysicsConfigInput | 'cloth';
3948
4057
  onTwos?: boolean;
3949
4058
  /** Show draggable behavior handles; cloth sheets become grabbable. */
3950
4059
  interactive?: boolean;
@@ -4093,6 +4202,18 @@ interface SheetDims {
4093
4202
  width: number;
4094
4203
  height: number;
4095
4204
  }
4205
+ /**
4206
+ * The options type of a registry entry whose concrete shape is unknowable at
4207
+ * the storage site. The registries are heterogeneous — every behavior,
4208
+ * deformer and layout declares its own options — and this is the only top type
4209
+ * that admits all of them. `unknown` collapses `keyof O & string` (a
4210
+ * behavior's `progressParam`) to `never`, and `Record<string, unknown>` is
4211
+ * rejected in both directions: an entry's own `stack`/`pose` demands its own
4212
+ * keys, and an interface-declared options type has no implicit index
4213
+ * signature. Narrowing this would close the registries to the community
4214
+ * extensions they exist for.
4215
+ */
4216
+ type AnyOptions = any;
4096
4217
  interface DeformerContext {
4097
4218
  /** Seconds since the paper mounted. */
4098
4219
  t: number;
@@ -4115,6 +4236,14 @@ interface Deformer<O = Record<string, unknown>> {
4115
4236
  glsl?: {
4116
4237
  chunk: string;
4117
4238
  uniforms(o: O): Record<string, unknown>;
4239
+ /**
4240
+ * The option whose uniform scales with a field instance's per-sheet
4241
+ * `bias` (0 = flat, 1 = exactly as configured), letting one instanced
4242
+ * draw call bend every sheet differently. Deformers whose strength has
4243
+ * no linear form omit this and ignore bias — `roll` is arc-length-exact,
4244
+ * so a "half roll" is a shorter roll, not a scaled one.
4245
+ */
4246
+ strength?: keyof O & string;
4118
4247
  };
4119
4248
  geometry?: {
4120
4249
  minSegments?: number;
@@ -4389,6 +4518,16 @@ interface LightingPreset {
4389
4518
  drift: number;
4390
4519
  angle: number;
4391
4520
  };
4521
+ /**
4522
+ * Distance haze. Depth in a deep space is staged almost entirely by fog —
4523
+ * it is what turns a row of banners into a receding colonnade instead of
4524
+ * a flat row of rectangles.
4525
+ */
4526
+ fog?: {
4527
+ color: string;
4528
+ near: number;
4529
+ far: number;
4530
+ };
4392
4531
  }
4393
4532
  declare const lightingPresets: Record<LightingName, LightingPreset>;
4394
4533
  declare function getLightingPreset(name: LightingName): LightingPreset;
@@ -4406,18 +4545,46 @@ interface PaperLightingProps {
4406
4545
  scale?: number;
4407
4546
  /** Override prefers-reduced-motion (freezes gobo drift). */
4408
4547
  reducedMotion?: boolean;
4548
+ /**
4549
+ * Shadow map resolution, overriding the preset's. 0 turns the shadow pass
4550
+ * off — it re-renders the scene's geometry, so on a weak machine it is
4551
+ * often the single most expensive thing in the frame.
4552
+ */
4553
+ shadowMapSize?: number;
4554
+ /** Draw the soft contact shadow. It is its own render pass. */
4555
+ contactShadow?: boolean;
4409
4556
  }
4410
4557
  /**
4411
4558
  * A scene's lighting rig from one serialized name: key light (spot with a
4412
4559
  * procedural gobo, or directional), ambient fill, tone-mapping exposure,
4413
4560
  * and the contact shadow. Swap presets to restyle the same paper.
4414
4561
  */
4415
- declare function PaperLighting({ preset, floor, scale, reducedMotion, }: PaperLightingProps): react.JSX.Element;
4562
+ declare function PaperLighting({ preset, floor, scale, reducedMotion, shadowMapSize, contactShadow, }: PaperLightingProps): react.JSX.Element;
4416
4563
 
4417
4564
  /** Community deformers register here; built-ins are pre-registered. */
4418
- declare function registerDeformer(deformer: Deformer<any>): void;
4419
- declare function getDeformer(id: string): Deformer<any>;
4565
+ declare function registerDeformer(deformer: Deformer<AnyOptions>): void;
4566
+ declare function getDeformer(id: string): Deformer<AnyOptions>;
4420
4567
  declare function listDeformers(): string[];
4568
+ /**
4569
+ * Resolve a raw `deformers` stack — the Advanced fork of a behavior — into
4570
+ * instances safe to render.
4571
+ *
4572
+ * The escape hatch used to pass its options straight through, so a preset
4573
+ * naming an option that doesn't exist (`frequency` where wave wants
4574
+ * `wavelength`) reached the GLSL builder as `undefined` and died there with
4575
+ * a message about `.length`, or reached the CPU path and quietly produced
4576
+ * NaN vertices. Parsing through each deformer's own schema turns that into
4577
+ * the validation error it always was, and fills in defaults for whatever a
4578
+ * hand-written preset left out.
4579
+ *
4580
+ * Disabled entries keep their slot: the GLSL uniform namespace is indexed by
4581
+ * position, so dropping one here would rename every uniform after it.
4582
+ */
4583
+ declare function resolveDeformerStack(raw: {
4584
+ type: string;
4585
+ options?: Record<string, unknown>;
4586
+ enabled?: boolean;
4587
+ }[]): DeformerInstance[];
4421
4588
 
4422
4589
  /**
4423
4590
  * Run an ordered deformer stack over a sheet geometry: each vertex starts
@@ -4478,6 +4645,11 @@ type BendOptions = z.infer<typeof bendOptionsSchema>;
4478
4645
  * Gentle global arc around a cylinder centered on the sheet — a standing
4479
4646
  * paper's lean. Arc-length preserving, like roll, but symmetric about the
4480
4647
  * center instead of one-sided.
4648
+ *
4649
+ * Written in its cancellation-free form throughout: `r(1 − cos θ)` is
4650
+ * `2r·sin²(θ/2)`, and the in-plane shift goes through `sinMinusX`. Same arc,
4651
+ * same numbers to sixteen places — it is only the float32 half that could
4652
+ * tell the difference, and that is exactly the half the parity gate checks.
4481
4653
  */
4482
4654
  declare const bend: Deformer<BendOptions>;
4483
4655
 
@@ -4540,6 +4712,112 @@ type WaveOptions = z.infer<typeof waveOptionsSchema>;
4540
4712
  */
4541
4713
  declare const wave: Deformer<WaveOptions>;
4542
4714
 
4715
+ declare const drapeOptionsSchema: z.ZodObject<{
4716
+ /** Fold depth at the free edge, world units. */
4717
+ amplitude: z.ZodDefault<z.ZodNumber>;
4718
+ /** How many folds run down the drop. */
4719
+ folds: z.ZodDefault<z.ZodNumber>;
4720
+ /**
4721
+ * How fast folds deepen away from the pinned edge. 1 is linear; higher
4722
+ * holds the top flat and gathers all the movement at the free end, which
4723
+ * is what a sheet hung from a rod actually does.
4724
+ */
4725
+ falloff: z.ZodDefault<z.ZodNumber>;
4726
+ /** How much a second, non-harmonic fold breaks the regularity. */
4727
+ irregular: z.ZodDefault<z.ZodNumber>;
4728
+ /** How much the sheet narrows as its folds deepen. */
4729
+ gather: z.ZodDefault<z.ZodNumber>;
4730
+ pinnedEdge: z.ZodDefault<z.ZodEnum<["top", "bottom"]>>;
4731
+ }, "strip", z.ZodTypeAny, {
4732
+ amplitude: number;
4733
+ pinnedEdge: "top" | "bottom";
4734
+ folds: number;
4735
+ falloff: number;
4736
+ irregular: number;
4737
+ gather: number;
4738
+ }, {
4739
+ amplitude?: number | undefined;
4740
+ pinnedEdge?: "top" | "bottom" | undefined;
4741
+ folds?: number | undefined;
4742
+ falloff?: number | undefined;
4743
+ irregular?: number | undefined;
4744
+ gather?: number | undefined;
4745
+ }>;
4746
+ type DrapeOptions = z.infer<typeof drapeOptionsSchema>;
4747
+ /**
4748
+ * Hung paper: vertical folds running the length of the drop, shallow at the
4749
+ * fixed edge and deepening toward the free one.
4750
+ *
4751
+ * `wave` can put ripples on a sheet, but a traveling sine is a flag, not a
4752
+ * curtain — it kinks the sheet ACROSS its drop and it is uniform end to end.
4753
+ * Cloth hung from an edge does the opposite: the folds run WITH the drop and
4754
+ * they grow as they get further from whatever is holding the sheet up. Two
4755
+ * details do most of the work:
4756
+ *
4757
+ * - the folds are not harmonic. A pure sine reads as corrugated metal, so a
4758
+ * second wave at an incommensurate frequency breaks the repeat.
4759
+ * - gathered paper is narrower than flat paper. Pulling the surface toward
4760
+ * its centerline in proportion to fold depth is what stops the drape from
4761
+ * looking like a texture painted on a rectangle.
4762
+ */
4763
+ declare const drape: Deformer<DrapeOptions>;
4764
+
4765
+ declare const crumpleOptionsSchema: z.ZodObject<{
4766
+ /** How crushed, 0..1. Peak-to-peak height, and it drives the pull too. */
4767
+ amount: z.ZodDefault<z.ZodNumber>;
4768
+ /** Facets per world unit. Higher is finer, and needs more segments to resolve. */
4769
+ scale: z.ZodDefault<z.ZodNumber>;
4770
+ /**
4771
+ * How much the sheet draws in on itself. Crumpled paper occupies a smaller
4772
+ * footprint than flat paper; without this it reads as an embossed sheet
4773
+ * rather than a crushed one.
4774
+ */
4775
+ pull: z.ZodDefault<z.ZodNumber>;
4776
+ /** A different crush of the same paper. */
4777
+ seed: z.ZodDefault<z.ZodNumber>;
4778
+ }, "strip", z.ZodTypeAny, {
4779
+ amount: number;
4780
+ seed: number;
4781
+ scale: number;
4782
+ pull: number;
4783
+ }, {
4784
+ amount?: number | undefined;
4785
+ seed?: number | undefined;
4786
+ scale?: number | undefined;
4787
+ pull?: number | undefined;
4788
+ }>;
4789
+ type CrumpleOptions = z.infer<typeof crumpleOptionsSchema>;
4790
+ /**
4791
+ * Paper that has been handled.
4792
+ *
4793
+ * Six deformers and not one of them crushed a sheet — `wave` and `fold` were
4794
+ * the nearest and neither reads as crumpled. This is the missing primitive.
4795
+ *
4796
+ * The field is a jittered grid of cells, each pushed up or down, with the
4797
+ * height going to zero exactly on the boundary between them: `F2 − F1`, the
4798
+ * gap between the two nearest cell points, signed per cell. That vanishes on
4799
+ * every boundary, so the sheet stays continuous, and its gradient flips
4800
+ * across one — which is a crease. The result is an irregular polygonal
4801
+ * network of facets alternating toward and away from you, which is what a
4802
+ * sheet crushed in a fist actually is.
4803
+ *
4804
+ * **The normals matter more than the displacement here**, and getting there
4805
+ * took three tries worth recording. Three summed triangle waves: periodic,
4806
+ * an egg-crate. Plain distance-to-nearest (`F1`): irregular but smooth cone
4807
+ * tips, so it read as hammered metal. Only creases with a sign change across
4808
+ * them shade like paper.
4809
+ *
4810
+ * Both normal paths agree with that: the hero path averages vertex normals
4811
+ * over a dense grid, the field path probes two tangents a hundredth of a
4812
+ * sheet apart. Both need facets several segments wide.
4813
+ *
4814
+ * Cost, measured rather than assumed: a field of these runs about 45% longer
4815
+ * per frame than the same field of an undeformed preset, and almost none of
4816
+ * that is geometry — `segments: 'auto'` already gives every sheet 72 a side.
4817
+ * It is the nine cell lookups per probe, three probes deep for the normal.
4818
+ */
4819
+ declare const crumple: Deformer<CrumpleOptions>;
4820
+
4543
4821
  /**
4544
4822
  * The shared fake-aerodynamics core (spec M6 §4): velocity-linked lift +
4545
4823
  * curated noise, per v0.2's "reads more real than a true sim" doctrine.
@@ -4584,7 +4862,7 @@ declare function flightPose(t: number, o: FlightParams, phase: number, pose: Aer
4584
4862
  declare function carryDrive(speed: number): number;
4585
4863
 
4586
4864
  /** A draggable 3D grab point; drags write back to behavior params. */
4587
- interface HandleSpec<O = any> {
4865
+ interface HandleSpec<O = AnyOptions> {
4588
4866
  id: string;
4589
4867
  /** UV-space (0..1) anchor of the grab point on the flat sheet. */
4590
4868
  anchor(o: O, sheet: SheetDims): [number, number];
@@ -4601,7 +4879,7 @@ interface HandleSpec<O = any> {
4601
4879
  * underneath is an Advanced disclosure. New behaviors are the community
4602
4880
  * on-ramp: ~50 lines over existing deformers.
4603
4881
  */
4604
- interface Behavior<O = any> {
4882
+ interface Behavior<O = AnyOptions> {
4605
4883
  id: string;
4606
4884
  label: string;
4607
4885
  defaults: O;
@@ -4626,8 +4904,8 @@ interface Behavior<O = any> {
4626
4904
  }
4627
4905
 
4628
4906
  /** Community behaviors register here; built-ins are pre-registered. */
4629
- declare function registerBehavior(behavior: Behavior<any>): void;
4630
- declare function getBehavior(id: string): Behavior<any>;
4907
+ declare function registerBehavior(behavior: Behavior<AnyOptions>): void;
4908
+ declare function getBehavior(id: string): Behavior<AnyOptions>;
4631
4909
  declare function listBehaviors(): string[];
4632
4910
 
4633
4911
  declare const peelOptionsSchema: z.ZodObject<{
@@ -4834,6 +5112,37 @@ type FlightOptions = z.infer<typeof flightOptionsSchema>;
4834
5112
  */
4835
5113
  declare const flight: Behavior<FlightOptions>;
4836
5114
 
5115
+ declare const crumpleBehaviorOptionsSchema: z.ZodObject<{
5116
+ /** 0 = flat sheet, 1 = crushed. */
5117
+ progress: z.ZodDefault<z.ZodNumber>;
5118
+ /** Few big facets at 0, many small ones at 1. */
5119
+ coarseness: z.ZodDefault<z.ZodNumber>;
5120
+ /** How far the sheet curls in on itself as it crushes. */
5121
+ ball: z.ZodDefault<z.ZodNumber>;
5122
+ /** A different crush of the same paper. */
5123
+ seed: z.ZodDefault<z.ZodNumber>;
5124
+ }, "strip", z.ZodTypeAny, {
5125
+ progress: number;
5126
+ coarseness: number;
5127
+ ball: number;
5128
+ seed: number;
5129
+ }, {
5130
+ progress?: number | undefined;
5131
+ coarseness?: number | undefined;
5132
+ ball?: number | undefined;
5133
+ seed?: number | undefined;
5134
+ }>;
5135
+ type CrumpleBehaviorOptions = z.infer<typeof crumpleBehaviorOptionsSchema>;
5136
+ /**
5137
+ * A sheet being screwed up in a fist.
5138
+ *
5139
+ * Two deformers, in this order for a reason: `crumple` reads the flat sheet
5140
+ * position to place its creases, so it has to run before anything that moves
5141
+ * the sheet around. Crush the paper, then curl the crushed paper — the other
5142
+ * way round would crease a curved sheet as if it were still flat.
5143
+ */
5144
+ declare const crumpleBehavior: Behavior<CrumpleBehaviorOptions>;
5145
+
4837
5146
  declare const idleNames: readonly ["float", "tumble", "dangle", "taped", "breeze"];
4838
5147
  type IdleName = (typeof idleNames)[number];
4839
5148
  interface IdlePose {
@@ -4897,18 +5206,34 @@ declare function buildFieldFragmentShader(): string;
4897
5206
  * three.js. `phase` is the motion driver's continuous offset in turns
4898
5207
  * (0..1 = one full cycle); cyclic layouts use it, static ones ignore it.
4899
5208
  * Community layouts are ~30 lines.
5209
+ *
5210
+ * Every built-in names a place paper actually sits — a fanned swatch deck, a
5211
+ * slipped stack, a heap on a desk — because arrangement alone is what makes a
5212
+ * field read as a photo carousel instead of as paper. The other half of that
5213
+ * is `bias`: paper in the world does not all bend alike.
4900
5214
  */
4901
5215
  interface PaperPose {
4902
5216
  position: [number, number, number];
4903
5217
  rotation: [number, number, number];
4904
5218
  scale: number;
5219
+ /**
5220
+ * How strongly this sheet takes the field's deformation: 1 = exactly as the
5221
+ * preset configures it, 0 = flat. Lets one instanced draw call curl the top
5222
+ * of a pile while the sheets pressed underneath stay flat. Omitted = 1.
5223
+ */
5224
+ bias?: number;
4905
5225
  }
4906
5226
  interface Layout<O = Record<string, unknown>> {
4907
5227
  id: string;
4908
5228
  label: string;
4909
5229
  defaults: O;
4910
5230
  optionsSchema: z.ZodType<O, z.ZodTypeDef, unknown>;
4911
- pose(i: number, n: number, o: O, phase: number): PaperPose;
5231
+ /**
5232
+ * `sheet` is the field's paper size. Layouts that arrange by CONTACT —
5233
+ * edges meeting, sheets resting on each other — cannot work without it,
5234
+ * and a layout that ignores it may simply omit the parameter.
5235
+ */
5236
+ pose(i: number, n: number, o: O, phase: number, sheet: SheetDims): PaperPose;
4912
5237
  }
4913
5238
  declare const ringSchema: z.ZodObject<{
4914
5239
  radius: z.ZodDefault<z.ZodNumber>;
@@ -4920,85 +5245,320 @@ declare const ringSchema: z.ZodObject<{
4920
5245
  radius?: number | undefined;
4921
5246
  tiltDeg?: number | undefined;
4922
5247
  }>;
5248
+ /** Prints pegged around a circle — the one carousel worth keeping. */
4923
5249
  declare const ring: Layout<z.infer<typeof ringSchema>>;
4924
- declare const deckSchema: z.ZodObject<{
4925
- spread: z.ZodDefault<z.ZodNumber>;
5250
+ declare const fanSchema: z.ZodObject<{
5251
+ /** Total angular sweep from the first sheet to the last, degrees. */
5252
+ sweep: z.ZodDefault<z.ZodNumber>;
5253
+ /** Where the shared pin sits, in half-sheet-heights below center. 1 = the bottom edge. */
5254
+ hinge: z.ZodDefault<z.ZodNumber>;
5255
+ /** Thickness step so the sheets stack in order instead of z-fighting. */
4926
5256
  lift: z.ZodDefault<z.ZodNumber>;
5257
+ /** How much flatter the middle of the fan sits than its outer sheets. */
5258
+ bow: z.ZodDefault<z.ZodNumber>;
4927
5259
  }, "strip", z.ZodTypeAny, {
4928
- spread: number;
5260
+ sweep: number;
5261
+ hinge: number;
4929
5262
  lift: number;
5263
+ bow: number;
4930
5264
  }, {
4931
- spread?: number | undefined;
5265
+ sweep?: number | undefined;
5266
+ hinge?: number | undefined;
4932
5267
  lift?: number | undefined;
5268
+ bow?: number | undefined;
4933
5269
  }>;
4934
- declare const deck: Layout<z.infer<typeof deckSchema>>;
4935
- declare const cascadeSchema: z.ZodObject<{
4936
- gap: z.ZodDefault<z.ZodNumber>;
4937
- drop: z.ZodDefault<z.ZodNumber>;
5270
+ /**
5271
+ * A Pantone deck, a paint-chip book, a hand of cards: every sheet pinned at
5272
+ * one shared point and swung open. The sheets nearest the outside of the
5273
+ * sweep carry the most curl, which is what sells the hinge as a hinge.
5274
+ */
5275
+ declare const fan: Layout<z.infer<typeof fanSchema>>;
5276
+ declare const spreadSchema: z.ZodObject<{
5277
+ /** How far each sheet slides past the one below it. */
5278
+ slip: z.ZodDefault<z.ZodNumber>;
5279
+ /** Direction of the slide, degrees. 0 slides right, 90 slides up. */
5280
+ angle: z.ZodDefault<z.ZodNumber>;
5281
+ lift: z.ZodDefault<z.ZodNumber>;
5282
+ /** How much more the sheets at the far end of the slide bow. */
5283
+ bow: z.ZodDefault<z.ZodNumber>;
5284
+ /** Nothing hand-slid is perfectly square — a touch of per-sheet rotation. */
5285
+ drift: z.ZodDefault<z.ZodNumber>;
4938
5286
  }, "strip", z.ZodTypeAny, {
4939
- gap: number;
4940
- drop: number;
5287
+ drift: number;
5288
+ angle: number;
5289
+ lift: number;
5290
+ bow: number;
5291
+ slip: number;
4941
5292
  }, {
4942
- gap?: number | undefined;
4943
- drop?: number | undefined;
5293
+ drift?: number | undefined;
5294
+ angle?: number | undefined;
5295
+ lift?: number | undefined;
5296
+ bow?: number | undefined;
5297
+ slip?: number | undefined;
4944
5298
  }>;
4945
- declare const cascade: Layout<z.infer<typeof cascadeSchema>>;
4946
- declare const helixSchema: z.ZodObject<{
4947
- radius: z.ZodDefault<z.ZodNumber>;
4948
- height: z.ZodDefault<z.ZodNumber>;
4949
- turns: z.ZodDefault<z.ZodNumber>;
5299
+ /**
5300
+ * A ream pushed sideways, or a deck dealt across a table: parallel sheets at
5301
+ * a constant offset, each one bowing a little more as it comes free of the
5302
+ * stack's weight.
5303
+ */
5304
+ declare const spread: Layout<z.infer<typeof spreadSchema>>;
5305
+ declare const pileSchema: z.ZodObject<{
5306
+ /** How far sheets wander from the center of the heap. */
5307
+ scatter: z.ZodDefault<z.ZodNumber>;
5308
+ /** Widest angle a sheet sits off square, degrees. */
5309
+ turn: z.ZodDefault<z.ZodNumber>;
5310
+ lift: z.ZodDefault<z.ZodNumber>;
5311
+ /** How flat the sheets underneath are pressed by the ones on top. */
5312
+ press: z.ZodDefault<z.ZodNumber>;
5313
+ seed: z.ZodDefault<z.ZodNumber>;
4950
5314
  }, "strip", z.ZodTypeAny, {
4951
- radius: number;
4952
- height: number;
4953
- turns: number;
5315
+ seed: number;
5316
+ lift: number;
5317
+ scatter: number;
5318
+ turn: number;
5319
+ press: number;
4954
5320
  }, {
4955
- radius?: number | undefined;
4956
- height?: number | undefined;
4957
- turns?: number | undefined;
5321
+ seed?: number | undefined;
5322
+ lift?: number | undefined;
5323
+ scatter?: number | undefined;
5324
+ turn?: number | undefined;
5325
+ press?: number | undefined;
4958
5326
  }>;
4959
- declare const helix: Layout<z.infer<typeof helixSchema>>;
5327
+ /**
5328
+ * The heap on a desk. The physical tell no parametric curve can fake: sheets
5329
+ * rest ON each other, so only the top of the pile keeps its curl and
5330
+ * everything below is pressed flat by the weight above it.
5331
+ */
5332
+ declare const pile: Layout<z.infer<typeof pileSchema>>;
4960
5333
  declare const wallSchema: z.ZodObject<{
4961
5334
  gapX: z.ZodDefault<z.ZodNumber>;
4962
5335
  gapY: z.ZodDefault<z.ZodNumber>;
4963
5336
  jitterAmt: z.ZodDefault<z.ZodNumber>;
5337
+ /** Spread of sag across the wall — no two pinned sheets hang alike. */
5338
+ sag: z.ZodDefault<z.ZodNumber>;
4964
5339
  }, "strip", z.ZodTypeAny, {
5340
+ sag: number;
4965
5341
  gapX: number;
4966
5342
  gapY: number;
4967
5343
  jitterAmt: number;
4968
5344
  }, {
5345
+ sag?: number | undefined;
4969
5346
  gapX?: number | undefined;
4970
5347
  gapY?: number | undefined;
4971
5348
  jitterAmt?: number | undefined;
4972
5349
  }>;
5350
+ /** A studio wall of pinned sheets: a grid, but nothing hangs quite square. */
4973
5351
  declare const wall: Layout<z.infer<typeof wallSchema>>;
4974
- declare const tunnelSchema: z.ZodObject<{
4975
- radius: z.ZodDefault<z.ZodNumber>;
4976
- spacing: z.ZodDefault<z.ZodNumber>;
4977
- }, "strip", z.ZodTypeAny, {
4978
- radius: number;
4979
- spacing: number;
4980
- }, {
4981
- radius?: number | undefined;
4982
- spacing?: number | undefined;
4983
- }>;
4984
- declare const tunnel: Layout<z.infer<typeof tunnelSchema>>;
4985
- declare const scatterSchema: z.ZodObject<{
5352
+ declare const spillSchema: z.ZodObject<{
4986
5353
  spreadX: z.ZodDefault<z.ZodNumber>;
4987
5354
  spreadY: z.ZodDefault<z.ZodNumber>;
4988
5355
  depth: z.ZodDefault<z.ZodNumber>;
5356
+ /** How far sheets pitch and roll out of the picture plane. */
5357
+ tumble: z.ZodDefault<z.ZodNumber>;
5358
+ /** Spread of bend across the sheets — a spill does not fold them alike. */
5359
+ vary: z.ZodDefault<z.ZodNumber>;
4989
5360
  seed: z.ZodDefault<z.ZodNumber>;
4990
5361
  }, "strip", z.ZodTypeAny, {
5362
+ tumble: number;
5363
+ seed: number;
4991
5364
  spreadX: number;
4992
5365
  spreadY: number;
4993
5366
  depth: number;
4994
- seed: number;
5367
+ vary: number;
4995
5368
  }, {
5369
+ tumble?: number | undefined;
5370
+ seed?: number | undefined;
4996
5371
  spreadX?: number | undefined;
4997
5372
  spreadY?: number | undefined;
4998
5373
  depth?: number | undefined;
5374
+ vary?: number | undefined;
5375
+ }>;
5376
+ /**
5377
+ * A dropped folder's worth of paper, mid-air — what a `pile` looks like the
5378
+ * moment before it settles. Loose in all three axes, and (the part that
5379
+ * separates it from confetti) every sheet caught at its own angle AND its
5380
+ * own amount of bend.
5381
+ */
5382
+ declare const spill: Layout<z.infer<typeof spillSchema>>;
5383
+ declare const sweepSchema: z.ZodObject<{
5384
+ columns: z.ZodDefault<z.ZodNumber>;
5385
+ /** Breathing room around each specimen. */
5386
+ gap: z.ZodDefault<z.ZodNumber>;
5387
+ /** Deformation at the first specimen and at the last. */
5388
+ from: z.ZodDefault<z.ZodNumber>;
5389
+ to: z.ZodDefault<z.ZodNumber>;
5390
+ }, "strip", z.ZodTypeAny, {
5391
+ columns: number;
5392
+ gap: number;
5393
+ from: number;
5394
+ to: number;
5395
+ }, {
5396
+ columns?: number | undefined;
5397
+ gap?: number | undefined;
5398
+ from?: number | undefined;
5399
+ to?: number | undefined;
5400
+ }>;
5401
+ /**
5402
+ * A specimen chart: the same sheet mounted in a grid, its deformation ramped
5403
+ * across the series so one image shows a curl at ten stages instead of one.
5404
+ * The layout the rest of this library exists to make possible — and the one
5405
+ * that documents every deformer for free.
5406
+ *
5407
+ * Only as legible as the preset it charts: a sheet with no behavior or
5408
+ * deformers has nothing for the ramp to scale, and every specimen comes out
5409
+ * identical.
5410
+ */
5411
+ declare const sweep: Layout<z.infer<typeof sweepSchema>>;
5412
+ declare const bookSchema: z.ZodObject<{
5413
+ /** How far the outermost page lifts off the block, degrees. */
5414
+ spread: z.ZodDefault<z.ZodNumber>;
5415
+ /** Fraction of the pages bound to the left. 0 = a one-sided sample book. */
5416
+ split: z.ZodDefault<z.ZodNumber>;
5417
+ /** Page thickness — the gap between pages of one block. */
5418
+ lift: z.ZodDefault<z.ZodNumber>;
5419
+ /** How much more a lifted page arcs than one lying flat in the block. */
5420
+ gutter: z.ZodDefault<z.ZodNumber>;
5421
+ }, "strip", z.ZodTypeAny, {
5422
+ split: number;
5423
+ gutter: number;
5424
+ lift: number;
5425
+ spread: number;
5426
+ }, {
5427
+ split?: number | undefined;
5428
+ gutter?: number | undefined;
5429
+ lift?: number | undefined;
5430
+ spread?: number | undefined;
5431
+ }>;
5432
+ /**
5433
+ * An open codex: pages hinged on a shared spine, each block splaying away
5434
+ * from the gutter. `split` slides it between the two bound forms paper takes
5435
+ * — 0.5 is a book lying open, 0 is a swatch deck or sample book bound down
5436
+ * one side. Pages lying flat in the block are pressed by the ones above;
5437
+ * only the lifted pages keep their arc.
5438
+ */
5439
+ declare const book: Layout<z.infer<typeof bookSchema>>;
5440
+ declare const accordionSchema: z.ZodObject<{
5441
+ /** How far each panel tilts off the strip's line, degrees. 0 = flat, 90 = shut. */
5442
+ angle: z.ZodDefault<z.ZodNumber>;
5443
+ /** A concertina holds its creases — how much bow the panels keep. */
5444
+ slack: z.ZodDefault<z.ZodNumber>;
5445
+ }, "strip", z.ZodTypeAny, {
5446
+ angle: number;
5447
+ slack: number;
5448
+ }, {
5449
+ angle?: number | undefined;
5450
+ slack?: number | undefined;
5451
+ }>;
5452
+ /**
5453
+ * A concertina: panels alternating about creases they genuinely share, so
5454
+ * the sheets read as ONE folded strip rather than as N separate papers —
5455
+ * the only layout here where that is true. Adjacent edges are solved to
5456
+ * meet, which is why it needs the sheet's real width.
5457
+ */
5458
+ declare const accordion: Layout<z.infer<typeof accordionSchema>>;
5459
+ declare const rackSchema: z.ZodObject<{
5460
+ /** Gap along the row, as a fraction of the paper's width. Under 1 they overlap. */
5461
+ spacing: z.ZodDefault<z.ZodNumber>;
5462
+ /** How far a sheet leans back off vertical, degrees. */
5463
+ lean: z.ZodDefault<z.ZodNumber>;
5464
+ /** How much that lean differs sheet to sheet — nothing propped is uniform. */
5465
+ vary: z.ZodDefault<z.ZodNumber>;
5466
+ /** Small rotations off square. */
5467
+ sway: z.ZodDefault<z.ZodNumber>;
5468
+ seed: z.ZodDefault<z.ZodNumber>;
5469
+ }, "strip", z.ZodTypeAny, {
5470
+ sway: number;
5471
+ seed: number;
5472
+ spacing: number;
5473
+ vary: number;
5474
+ lean: number;
5475
+ }, {
5476
+ sway?: number | undefined;
4999
5477
  seed?: number | undefined;
5478
+ spacing?: number | undefined;
5479
+ vary?: number | undefined;
5480
+ lean?: number | undefined;
5000
5481
  }>;
5001
- declare const scatter: Layout<z.infer<typeof scatterSchema>>;
5482
+ /**
5483
+ * Prints stood in a row and leaning back — against a wall, in a rack, propped
5484
+ * along a shelf. The one arrangement here that RESTS on a surface rather than
5485
+ * floating: every sheet pivots on the bottom edge it actually stands on, so
5486
+ * the row shares a floor. The further a sheet has leaned, the more it bows
5487
+ * under its own weight.
5488
+ *
5489
+ * (Stacking these front-to-back the way a letter tray really holds paper is
5490
+ * physically honest and visually useless — the front sheet hides the rest.
5491
+ * A row is the arrangement you can actually see.)
5492
+ */
5493
+ declare const rack: Layout<z.infer<typeof rackSchema>>;
5494
+ declare const colonnadeSchema: z.ZodObject<{
5495
+ /** The walk the colonnade is built along — see `stage/path`. */
5496
+ path: z.ZodDefault<z.ZodObject<{
5497
+ points: z.ZodDefault<z.ZodArray<z.ZodTuple<[z.ZodNumber, z.ZodNumber], null>, "many">>;
5498
+ closed: z.ZodDefault<z.ZodBoolean>;
5499
+ }, "strip", z.ZodTypeAny, {
5500
+ points: [number, number][];
5501
+ closed: boolean;
5502
+ }, {
5503
+ points?: [number, number][] | undefined;
5504
+ closed?: boolean | undefined;
5505
+ }>>;
5506
+ /** Half-width of the clear aisle: how far each banner stands off the walk line. */
5507
+ aisle: z.ZodDefault<z.ZodNumber>;
5508
+ /** How much that gap opens and closes along the walk. Nothing hung by hand is a corridor. */
5509
+ breathe: z.ZodDefault<z.ZodNumber>;
5510
+ /** Widest angle a banner turns off square to the aisle, degrees. */
5511
+ twist: z.ZodDefault<z.ZodNumber>;
5512
+ /** Fraction of the walk left clear at each end, so the figure has somewhere to enter from. */
5513
+ margin: z.ZodDefault<z.ZodNumber>;
5514
+ /** Spread of banner heights, 0..1. */
5515
+ rise: z.ZodDefault<z.ZodNumber>;
5516
+ /** How far the banners lift off the floor, as a fraction of their height. 0 = they pool on it. */
5517
+ hover: z.ZodDefault<z.ZodNumber>;
5518
+ /** Spread of deformation — no two lengths of hung paper drape alike. */
5519
+ drape: z.ZodDefault<z.ZodNumber>;
5520
+ seed: z.ZodDefault<z.ZodNumber>;
5521
+ }, "strip", z.ZodTypeAny, {
5522
+ path: {
5523
+ points: [number, number][];
5524
+ closed: boolean;
5525
+ };
5526
+ seed: number;
5527
+ hover: number;
5528
+ drape: number;
5529
+ margin: number;
5530
+ twist: number;
5531
+ aisle: number;
5532
+ breathe: number;
5533
+ rise: number;
5534
+ }, {
5535
+ path?: {
5536
+ points?: [number, number][] | undefined;
5537
+ closed?: boolean | undefined;
5538
+ } | undefined;
5539
+ seed?: number | undefined;
5540
+ hover?: number | undefined;
5541
+ drape?: number | undefined;
5542
+ margin?: number | undefined;
5543
+ twist?: number | undefined;
5544
+ aisle?: number | undefined;
5545
+ breathe?: number | undefined;
5546
+ rise?: number | undefined;
5547
+ }>;
5548
+ /**
5549
+ * A nave of hanging banners flanking a walk: paper as ARCHITECTURE rather
5550
+ * than as an object on a desk. The first layout here that arranges along a
5551
+ * path instead of around an origin, which is what lets a figure walk through
5552
+ * it — the aisle is guaranteed clear because the banners are placed off the
5553
+ * walk line, not merely near it.
5554
+ *
5555
+ * Banners alternate ranks (left, right, left…) and the two ranks are
5556
+ * staggered by a quarter step, so you pass them one at a time rather than
5557
+ * through a ladder of matched pairs. Each faces across the aisle: a banner
5558
+ * ahead of you presents its face, which is the whole reason to print
5559
+ * anything on it.
5560
+ */
5561
+ declare const colonnade: Layout<z.infer<typeof colonnadeSchema>>;
5002
5562
  /**
5003
5563
  * A block of stamps: flat rows × columns grid in register, floating a hair
5004
5564
  * above the (field-rendered) backing sheet. Standard layout contract — it
@@ -5006,10 +5566,479 @@ declare const scatter: Layout<z.infer<typeof scatterSchema>>;
5006
5566
  * by the field renderer, not by `pose`.
5007
5567
  */
5008
5568
  declare const sheet: Layout<SheetLayoutOptions>;
5009
- declare function registerLayout(layout: Layout<any>): void;
5010
- declare function getLayout(id: string): Layout<any>;
5569
+ declare function registerLayout(layout: Layout<AnyOptions>): void;
5570
+ declare function getLayout(id: string): Layout<AnyOptions>;
5011
5571
  declare function listLayouts(): string[];
5012
5572
 
5573
+ /**
5574
+ * Framing a field is arithmetic, not guesswork: layouts are pure `pose`
5575
+ * functions, so we can just ask one where all its sheets are and put the
5576
+ * camera where they all fit. Community layouts get framed for free.
5577
+ */
5578
+ interface FieldBounds {
5579
+ center: [number, number, number];
5580
+ /** Half-extents — the box reaches `center ± half`. */
5581
+ half: [number, number, number];
5582
+ }
5583
+ /**
5584
+ * The box `n` sheets occupy under a layout. Each sheet is treated as a ball
5585
+ * of its half-diagonal, which covers every rotation the pose can apply
5586
+ * without having to build the pose matrices.
5587
+ */
5588
+ declare function fieldBounds(layout: Layout<AnyOptions>, n: number, options: unknown, sheet: SheetDims): FieldBounds;
5589
+ /**
5590
+ * Where to put a perspective camera so every sheet a layout poses lands in
5591
+ * frame. Solved per sheet at its own depth rather than against the field's
5592
+ * bounding box: a `ring`'s widest sheets sit at mid-depth, and pretending
5593
+ * that width exists at the near face would shove the camera far enough back
5594
+ * to lose the gallery entirely.
5595
+ */
5596
+ declare function fitCamera(layout: Layout<AnyOptions>, n: number, options: unknown, sheet: SheetDims, fovDeg: number, aspect: number, margin?: number): {
5597
+ position: [number, number, number];
5598
+ target: [number, number, number];
5599
+ };
5600
+
5601
+ declare const stageSchema: z.ZodObject<{
5602
+ path: z.ZodDefault<z.ZodObject<{
5603
+ points: z.ZodDefault<z.ZodArray<z.ZodTuple<[z.ZodNumber, z.ZodNumber], null>, "many">>;
5604
+ closed: z.ZodDefault<z.ZodBoolean>;
5605
+ }, "strip", z.ZodTypeAny, {
5606
+ points: [number, number][];
5607
+ closed: boolean;
5608
+ }, {
5609
+ points?: [number, number][] | undefined;
5610
+ closed?: boolean | undefined;
5611
+ }>>;
5612
+ shot: z.ZodDefault<z.ZodObject<{
5613
+ shot: z.ZodDefault<z.ZodEnum<["follow", "lead", "low", "wide"]>>;
5614
+ distance: z.ZodDefault<z.ZodNumber>;
5615
+ height: z.ZodDefault<z.ZodNumber>;
5616
+ lookAhead: z.ZodDefault<z.ZodNumber>;
5617
+ offset: z.ZodDefault<z.ZodNumber>;
5618
+ }, "strip", z.ZodTypeAny, {
5619
+ height: number;
5620
+ offset: number;
5621
+ distance: number;
5622
+ shot: "follow" | "lead" | "low" | "wide";
5623
+ lookAhead: number;
5624
+ }, {
5625
+ height?: number | undefined;
5626
+ offset?: number | undefined;
5627
+ distance?: number | undefined;
5628
+ shot?: "follow" | "lead" | "low" | "wide" | undefined;
5629
+ lookAhead?: number | undefined;
5630
+ }>>;
5631
+ figure: z.ZodDefault<z.ZodObject<{
5632
+ height: z.ZodDefault<z.ZodNumber>;
5633
+ speed: z.ZodDefault<z.ZodNumber>;
5634
+ stride: z.ZodDefault<z.ZodNumber>;
5635
+ swing: z.ZodDefault<z.ZodNumber>;
5636
+ color: z.ZodDefault<z.ZodString>;
5637
+ }, "strip", z.ZodTypeAny, {
5638
+ height: number;
5639
+ speed: number;
5640
+ color: string;
5641
+ stride: number;
5642
+ swing: number;
5643
+ }, {
5644
+ height?: number | undefined;
5645
+ speed?: number | undefined;
5646
+ color?: string | undefined;
5647
+ stride?: number | undefined;
5648
+ swing?: number | undefined;
5649
+ }>>;
5650
+ /** Stage mode is built for `nave`; the others are all front-lit. */
5651
+ lighting: z.ZodDefault<z.ZodEnum<["studio", "window", "leaves", "goldenhour", "noir", "nave"]>>;
5652
+ showFigure: z.ZodDefault<z.ZodBoolean>;
5653
+ source: z.ZodDefault<z.ZodObject<{
5654
+ /** The bright void the walk resolves toward. Without it the vanishing point is a hole. */
5655
+ enabled: z.ZodDefault<z.ZodBoolean>;
5656
+ color: z.ZodDefault<z.ZodString>;
5657
+ /** How far past the end of the walk it stands, world units. */
5658
+ beyond: z.ZodDefault<z.ZodNumber>;
5659
+ /**
5660
+ * A cyclorama around the whole stage, graded from the source colour at the
5661
+ * horizon to near-dark overhead. The source plane only faces down the walk,
5662
+ * so without this every shot that isn't axial — `wide` especially — looks
5663
+ * out at a black void where the room should be.
5664
+ */
5665
+ surround: z.ZodDefault<z.ZodBoolean>;
5666
+ /** Colour overhead. The horizon takes the source's own colour. */
5667
+ zenith: z.ZodDefault<z.ZodString>;
5668
+ /** Size, as a multiple of the PAPER height — it only has to out-fill the frame. */
5669
+ spread: z.ZodDefault<z.ZodNumber>;
5670
+ }, "strip", z.ZodTypeAny, {
5671
+ color: string;
5672
+ enabled: boolean;
5673
+ spread: number;
5674
+ zenith: string;
5675
+ beyond: number;
5676
+ surround: boolean;
5677
+ }, {
5678
+ color?: string | undefined;
5679
+ enabled?: boolean | undefined;
5680
+ spread?: number | undefined;
5681
+ zenith?: string | undefined;
5682
+ beyond?: number | undefined;
5683
+ surround?: boolean | undefined;
5684
+ }>>;
5685
+ ground: z.ZodDefault<z.ZodObject<{
5686
+ /** The floor. Without something to catch the shadows there is no ground and no scale. */
5687
+ enabled: z.ZodDefault<z.ZodBoolean>;
5688
+ color: z.ZodDefault<z.ZodString>;
5689
+ }, "strip", z.ZodTypeAny, {
5690
+ color: string;
5691
+ enabled: boolean;
5692
+ }, {
5693
+ color?: string | undefined;
5694
+ enabled?: boolean | undefined;
5695
+ }>>;
5696
+ }, "strip", z.ZodTypeAny, {
5697
+ path: {
5698
+ points: [number, number][];
5699
+ closed: boolean;
5700
+ };
5701
+ lighting: "studio" | "window" | "leaves" | "goldenhour" | "noir" | "nave";
5702
+ figure: {
5703
+ height: number;
5704
+ speed: number;
5705
+ color: string;
5706
+ stride: number;
5707
+ swing: number;
5708
+ };
5709
+ source: {
5710
+ color: string;
5711
+ enabled: boolean;
5712
+ spread: number;
5713
+ zenith: string;
5714
+ beyond: number;
5715
+ surround: boolean;
5716
+ };
5717
+ shot: {
5718
+ height: number;
5719
+ offset: number;
5720
+ distance: number;
5721
+ shot: "follow" | "lead" | "low" | "wide";
5722
+ lookAhead: number;
5723
+ };
5724
+ showFigure: boolean;
5725
+ ground: {
5726
+ color: string;
5727
+ enabled: boolean;
5728
+ };
5729
+ }, {
5730
+ path?: {
5731
+ points?: [number, number][] | undefined;
5732
+ closed?: boolean | undefined;
5733
+ } | undefined;
5734
+ lighting?: "studio" | "window" | "leaves" | "goldenhour" | "noir" | "nave" | undefined;
5735
+ figure?: {
5736
+ height?: number | undefined;
5737
+ speed?: number | undefined;
5738
+ color?: string | undefined;
5739
+ stride?: number | undefined;
5740
+ swing?: number | undefined;
5741
+ } | undefined;
5742
+ source?: {
5743
+ color?: string | undefined;
5744
+ enabled?: boolean | undefined;
5745
+ spread?: number | undefined;
5746
+ zenith?: string | undefined;
5747
+ beyond?: number | undefined;
5748
+ surround?: boolean | undefined;
5749
+ } | undefined;
5750
+ shot?: {
5751
+ height?: number | undefined;
5752
+ offset?: number | undefined;
5753
+ distance?: number | undefined;
5754
+ shot?: "follow" | "lead" | "low" | "wide" | undefined;
5755
+ lookAhead?: number | undefined;
5756
+ } | undefined;
5757
+ showFigure?: boolean | undefined;
5758
+ ground?: {
5759
+ color?: string | undefined;
5760
+ enabled?: boolean | undefined;
5761
+ } | undefined;
5762
+ }>;
5763
+ type StageConfig = z.infer<typeof stageSchema>;
5764
+ type StageConfigInput = z.input<typeof stageSchema>;
5765
+
5766
+ /**
5767
+ * Render quality tiers.
5768
+ *
5769
+ * A stage is the heaviest thing this library draws — tens of thousands of
5770
+ * subdivided vertices, a shadow pass, a translucent fragment shader and a
5771
+ * full-screen backdrop — and it has to run on machines nobody developing it
5772
+ * owns. Quality is deliberately NOT part of `stageSchema`: it describes the
5773
+ * device, not the artwork, so it must never travel in a preset or a shared
5774
+ * link. Two people opening the same link should see the same scene at
5775
+ * whatever fidelity their hardware can hold.
5776
+ *
5777
+ * The four knobs, in the order they actually cost:
5778
+ *
5779
+ * - `segments` — subdivisions along a banner's long edge. Quadratic: every
5780
+ * sheet is a grid, so halving this quarters the vertex work.
5781
+ * - `shadowMapSize` — the shadow pass re-renders the scene's geometry. 0
5782
+ * turns shadows off, which on a weak machine is the difference between
5783
+ * moving and not.
5784
+ * - `dpr` — fragment cost scales with the square of it, and this scene is
5785
+ * fragment-heavy (translucency, fog, a full-screen backdrop).
5786
+ * - `surround` — one more full-screen draw; cheap, but free to drop.
5787
+ */
5788
+ declare const qualityNames: readonly ["auto", "low", "medium", "high"];
5789
+ type QualityName = (typeof qualityNames)[number];
5790
+ type QualityTier = Exclude<QualityName, 'auto'>;
5791
+
5792
+ interface PaperStageSceneProps {
5793
+ /** Walk, shot, figure, lighting — see `stageSchema`. */
5794
+ stage?: StageConfigInput;
5795
+ /** Any layout, but `colonnade` is the one built to arrange along a walk. */
5796
+ layout?: string;
5797
+ layoutOptions?: Record<string, unknown>;
5798
+ /** Per-banner slots, exactly as in field mode. */
5799
+ papers?: FieldPaperSlot[];
5800
+ images?: string[];
5801
+ /**
5802
+ * Words on the banners. A string is split across them a line at a time; an
5803
+ * array is used as given. This is the whole point of the mode — a space
5804
+ * built out of something the viewer wrote.
5805
+ */
5806
+ text?: string | string[];
5807
+ /** Shared preset behind every banner. */
5808
+ preset?: string | PaperConfigInput;
5809
+ /** How many banners, when none of `papers` / `images` / `text` says. */
5810
+ count?: number;
5811
+ /**
5812
+ * How far along the walk the figure is, 0..1. Bind it to scroll and the
5813
+ * page scrolls the walk. Omit and it walks on the clock at its own speed.
5814
+ */
5815
+ progress?: number;
5816
+ reducedMotion?: boolean;
5817
+ /**
5818
+ * How much the render is allowed to cost. `auto` (the default) starts in
5819
+ * the middle and adapts to whatever the machine turns out to manage — this
5820
+ * scene runs on hardware nobody developing it owns. Not part of the stage
5821
+ * config: quality describes the DEVICE, not the artwork, so it must never
5822
+ * travel in a preset or a shared link.
5823
+ */
5824
+ quality?: QualityName;
5825
+ /**
5826
+ * Fires when `auto` moves the tier. Useful for showing the viewer what
5827
+ * they are getting, and for measuring what real machines settle on.
5828
+ */
5829
+ onQualityChange?(tier: QualityTier): void;
5830
+ }
5831
+ interface PaperStageProps extends PaperStageSceneProps {
5832
+ children?: React.ReactNode;
5833
+ className?: string;
5834
+ style?: React.CSSProperties;
5835
+ }
5836
+ declare function PaperStageScene({ stage: stageInput, quality, onQualityChange, layout, layoutOptions, papers, images, text, preset, count, progress, reducedMotion, }: PaperStageSceneProps): react.JSX.Element;
5837
+ /** `<PaperStage />` owns its Canvas; `<PaperStageScene />` drops into an existing one. */
5838
+ declare function PaperStage({ children, className, style, ...sceneProps }: PaperStageProps): react.JSX.Element;
5839
+
5840
+ /**
5841
+ * Named stages. A mode with no presets asks its visitor to invent a space
5842
+ * out of eleven sliders before it will show them anything — and stage mode
5843
+ * takes about fifteen seconds to understand once you have seen one, which
5844
+ * means the presets ARE the explanation.
5845
+ *
5846
+ * Each names somewhere paper is actually hung at architectural scale, the
5847
+ * same rule the layouts follow.
5848
+ */
5849
+ interface StagePreset {
5850
+ id: string;
5851
+ label: string;
5852
+ /** One line, shown under the name. What you are about to look at. */
5853
+ description: string;
5854
+ stage: StageConfigInput;
5855
+ layout: string;
5856
+ layoutOptions?: Record<string, unknown>;
5857
+ /** The paper itself — banners differ per stage more than anything else. */
5858
+ paper?: PaperConfigInput;
5859
+ count: number;
5860
+ text?: string;
5861
+ }
5862
+ declare const stagePresets: Record<string, StagePreset>;
5863
+ declare function getStagePreset(id: string): StagePreset;
5864
+ declare function listStagePresets(): string[];
5865
+
5866
+ /**
5867
+ * The walk — a path across the ground plane that a figure follows and that
5868
+ * layouts arrange paper along. Pure 2D math (x, z on the floor, y is always
5869
+ * up), no three.js, so it tests in node and is cheap enough to call from
5870
+ * inside a layout's pure `pose`.
5871
+ *
5872
+ * Centripetal Catmull-Rom through the control points — it will not cusp or
5873
+ * overshoot when two points bunch together, which a uniform spline does —
5874
+ * resampled to a uniform arc-length polyline. That resampling is the point:
5875
+ * `pointAt(s)` advances at constant SPEED, so a figure stepping `s` forward
5876
+ * at a steady rate covers ground at a steady rate. A raw spline parameter
5877
+ * would have it sprint through the straights and crawl around the corners.
5878
+ */
5879
+ /** A point on the floor. */
5880
+ type Ground = [x: number, z: number];
5881
+ declare const walkPathSchema: z.ZodObject<{
5882
+ /**
5883
+ * Control points on the ground plane, [x, z]. The default walks away from
5884
+ * the camera down -Z — the shot every reference image is composed on.
5885
+ */
5886
+ points: z.ZodDefault<z.ZodArray<z.ZodTuple<[z.ZodNumber, z.ZodNumber], null>, "many">>;
5887
+ /** Join the last point back to the first: an endless walk, and the only form `phase` can slide. */
5888
+ closed: z.ZodDefault<z.ZodBoolean>;
5889
+ }, "strip", z.ZodTypeAny, {
5890
+ points: [number, number][];
5891
+ closed: boolean;
5892
+ }, {
5893
+ points?: [number, number][] | undefined;
5894
+ closed?: boolean | undefined;
5895
+ }>;
5896
+ type WalkPathOptions = z.infer<typeof walkPathSchema>;
5897
+ interface WalkPath {
5898
+ /** Total arc length in world units. */
5899
+ readonly length: number;
5900
+ readonly closed: boolean;
5901
+ /** `s` is normalized arc length: 0 = the start, 1 = the end. Closed paths wrap, open paths clamp. */
5902
+ pointAt(s: number): Ground;
5903
+ /** Unit forward direction at `s`. */
5904
+ tangentAt(s: number): Ground;
5905
+ /** Unit LEFT-hand normal at `s` — the side of the aisle a walker's left hand points to. */
5906
+ normalAt(s: number): Ground;
5907
+ }
5908
+ declare function createWalkPath(options: WalkPathOptions): WalkPath;
5909
+
5910
+ /**
5911
+ * Named walks. A path is a list of control points, which is the right thing
5912
+ * to serialize and the wrong thing to put in front of someone — nobody wants
5913
+ * to type coordinates to find out what a curved colonnade looks like. These
5914
+ * are the shapes worth starting from; every one resolves to ordinary points,
5915
+ * so editing on from here stays possible.
5916
+ */
5917
+ declare const walkNames: readonly ["straight", "bend", "ess", "ring", "spiral"];
5918
+ type WalkName = (typeof walkNames)[number];
5919
+ declare const walks: Record<WalkName, WalkPathOptions>;
5920
+ declare function getWalk(name: WalkName): WalkPathOptions;
5921
+
5922
+ /**
5923
+ * Where to put the camera on a walk.
5924
+ *
5925
+ * `fitCamera` in field/framing.ts solves a different problem — get every
5926
+ * sheet inside the frustum — and solving it here would produce the neutral
5927
+ * three-quarter product shot that stage mode exists to avoid. These are
5928
+ * SHOTS: a camera stationed relative to the walking figure, framing the
5929
+ * space rather than the objects, with the vanishing point doing the work.
5930
+ */
5931
+ declare const shotNames: readonly ["follow", "lead", "low", "wide"];
5932
+ type ShotName = (typeof shotNames)[number];
5933
+ declare const shotSchema: z.ZodObject<{
5934
+ shot: z.ZodDefault<z.ZodEnum<["follow", "lead", "low", "wide"]>>;
5935
+ /**
5936
+ * How far the camera stands off the figure ALONG the walk, world units.
5937
+ * `wide` reads it as how far back it stands; how far it steps aside is
5938
+ * derived from the paper, since that is what it has to clear.
5939
+ */
5940
+ distance: z.ZodDefault<z.ZodNumber>;
5941
+ /** Multiplier on the shot's natural camera height. 1 is as designed. */
5942
+ height: z.ZodDefault<z.ZodNumber>;
5943
+ /** How far up the walk the camera looks past the figure, world units. */
5944
+ lookAhead: z.ZodDefault<z.ZodNumber>;
5945
+ /** Sideways step off the walk line, world units. Positive is the walker's left. */
5946
+ offset: z.ZodDefault<z.ZodNumber>;
5947
+ }, "strip", z.ZodTypeAny, {
5948
+ height: number;
5949
+ offset: number;
5950
+ distance: number;
5951
+ shot: "follow" | "lead" | "low" | "wide";
5952
+ lookAhead: number;
5953
+ }, {
5954
+ height?: number | undefined;
5955
+ offset?: number | undefined;
5956
+ distance?: number | undefined;
5957
+ shot?: "follow" | "lead" | "low" | "wide" | undefined;
5958
+ lookAhead?: number | undefined;
5959
+ }>;
5960
+ type ShotOptions = z.infer<typeof shotSchema>;
5961
+ interface StageShot {
5962
+ position: [x: number, y: number, z: number];
5963
+ target: [x: number, y: number, z: number];
5964
+ }
5965
+ /**
5966
+ * What each shot is FOR. A stage has two subjects at very different scales —
5967
+ * a body about 1.75 units tall and paper five times that — and a camera that
5968
+ * only knows about the body frames the body, which is how a colonnade of
5969
+ * printed banners ends up showing its bottom third and the tops of some
5970
+ * letterforms. Camera height stays a body measurement (eye level is eye
5971
+ * level); where it AIMS is a blend, and the paper carries most of it.
5972
+ */
5973
+ interface StageScale {
5974
+ /** Standing height of the figure. */
5975
+ figure: number;
5976
+ /** Height of the tallest paper on the stage. */
5977
+ paper: number;
5978
+ }
5979
+
5980
+ /**
5981
+ * Stage-mode export. Same anatomy and version as the paper and field
5982
+ * exports, with one addition that matters more than the rest: the scroll
5983
+ * variant. `progress` is the whole interaction model of a stage, and a
5984
+ * scroll-driven hero is what most people opening this menu actually want —
5985
+ * so the export writes the pinning and the scroll math, which is the part
5986
+ * that is fiddly to get right and boring to write.
5987
+ */
5988
+ interface StageExportInput {
5989
+ stage: StageConfigInput;
5990
+ layout: string;
5991
+ layoutOptions?: Record<string, unknown>;
5992
+ /** The banner itself — dims, stock, drape. Omitted uses the built-in banner. */
5993
+ paper?: PaperConfigInput;
5994
+ /** The words the space is built from. Omitted renders blank banners. */
5995
+ text?: string;
5996
+ count?: number;
5997
+ /** Bind the walk to page scroll, pinned, rather than to the clock. */
5998
+ scroll?: boolean;
5999
+ /** Exported component name. */
6000
+ componentName?: string;
6001
+ }
6002
+ /** Which named walk these points are, if any — the export reads better for it. */
6003
+ declare function walkNameFor(path: StageConfig['path']): WalkName | undefined;
6004
+ /** The stage config with defaults removed — what actually needs writing down. */
6005
+ declare function diffStage(stage: StageConfigInput): Record<string, unknown>;
6006
+ /**
6007
+ * JSON.stringify, except an array of plain numbers stays on one line. A walk
6008
+ * is a list of coordinate pairs, and the default pretty-printer spreads each
6009
+ * `[6, 17]` over four lines — twenty lines of punctuation for one gentle
6010
+ * curve. Exported code is a product surface; it should read like something a
6011
+ * person wrote.
6012
+ */
6013
+ declare function stringifyStage(value: unknown, indent?: number): string;
6014
+ /** The one-line visual an agent verifies after `npm run dev`. */
6015
+ declare function describeStage(input: StageExportInput): string;
6016
+ /** Component source shared by the JSX snippet and the agent payload. */
6017
+ declare function buildStageComponentSource(input: StageExportInput): string;
6018
+ /** The self-contained stage integration brief — one paste into a coding agent. */
6019
+ declare function buildStageAgentPayload(input: StageExportInput): string;
6020
+
6021
+ /** How much of the incident key light a fully translucent sheet passes on. */
6022
+ declare const TRANSMISSION_GAIN = 0.5;
6023
+ interface TranslucencyValues {
6024
+ translucency: number;
6025
+ /** Unit world direction from the scene toward the key light. */
6026
+ direction: THREE.Vector3;
6027
+ color: THREE.Color;
6028
+ /** Light the room passes through the sheet from every direction at once. */
6029
+ ambient: number;
6030
+ }
6031
+ /**
6032
+ * Resolve the transmission uniforms from the paper and the scene's lighting
6033
+ * preset — the key light's own position and color, so translucency can never
6034
+ * disagree with the lamp casting the shadows.
6035
+ */
6036
+ declare function translucencyValues(translucency: number, lighting: LightingName): TranslucencyValues;
6037
+ /** Ready-to-bind uniform objects for a shader program. */
6038
+ declare function translucencyUniforms(translucency: number, lighting: LightingName): Record<string, {
6039
+ value: unknown;
6040
+ }>;
6041
+
5013
6042
  /**
5014
6043
  * A stock is a named bundle of material + geometry defaults — choosing paper
5015
6044
  * at a print shop. Individual controls always override; schema-wise these are
@@ -5023,6 +6052,12 @@ interface Stock {
5023
6052
  roughness: number;
5024
6053
  /** 0 = opaque. Vellum is translucent. */
5025
6054
  opacity: number;
6055
+ /**
6056
+ * How much light passes THROUGH the sheet when something is behind it,
6057
+ * 0..1. Distinct from `opacity`: newsprint is fully opaque to look at and
6058
+ * still glows on a lightbox. This is what makes a backlit banner read.
6059
+ */
6060
+ translucency: number;
5026
6061
  /** Ink multiply tint for content drawn on this stock (thermal prints grey-black). */
5027
6062
  inkColor: string;
5028
6063
  /** Thermal-printer banding intensity baked into the grain effect. */
@@ -5040,7 +6075,16 @@ interface Stock {
5040
6075
  declare const stocks: Record<StockName, Stock>;
5041
6076
  declare function getStock(name: StockName): Stock;
5042
6077
 
5043
- declare function atlasGrid(count: number): {
6078
+ /**
6079
+ * Grid shape for `count` tiles of a given aspect (height / width).
6080
+ *
6081
+ * Square tiles want a square grid, but a stage banner is 5.7 times taller
6082
+ * than it is wide, and packing those into a square GRID makes an atlas five
6083
+ * times taller than it is wide — which then has to be squashed to fit the
6084
+ * texture budget, and the content with it. Choosing cols/rows ≈ aspect keeps
6085
+ * the atlas itself roughly square whatever shape the paper is.
6086
+ */
6087
+ declare function atlasGrid(count: number, aspect?: number): {
5044
6088
  cols: number;
5045
6089
  rows: number;
5046
6090
  };
@@ -5147,7 +6191,9 @@ declare function composeSurface(surface: SurfaceConfig, stock: Stock, thickness:
5147
6191
  sheet?: {
5148
6192
  width: number;
5149
6193
  height: number;
5150
- }): ComposedSurface;
6194
+ },
6195
+ /** Whose key light transmission is measured against. */
6196
+ lighting?: LightingName): ComposedSurface;
5151
6197
 
5152
6198
  interface PaperMaterialProps {
5153
6199
  stock: Stock;
@@ -5161,6 +6207,8 @@ interface PaperMaterialProps {
5161
6207
  width: number;
5162
6208
  height: number;
5163
6209
  };
6210
+ /** Scene lighting — transmission is measured against its key light. */
6211
+ lighting?: LightingName;
5164
6212
  }
5165
6213
  /**
5166
6214
  * The paper's skin: MeshStandardMaterial (real lighting preserved) extended
@@ -5169,7 +6217,7 @@ interface PaperMaterialProps {
5169
6217
  * paper doesn't mirror its front through the sheet. Programs rebuild only
5170
6218
  * on structure change; value edits mutate uniforms in place.
5171
6219
  */
5172
- declare function PaperMaterial({ stock, texture, backTexture, surface, thickness, sheet, }: PaperMaterialProps): react.JSX.Element;
6220
+ declare function PaperMaterial({ stock, texture, backTexture, surface, thickness, sheet, lighting, }: PaperMaterialProps): react.JSX.Element;
5173
6221
 
5174
6222
  type ReceiptContent = Extract<ContentConfig, {
5175
6223
  type: 'receipt';
@@ -5355,4 +6403,4 @@ interface ModeContext {
5355
6403
  */
5356
6404
  declare function resolveMode(requested: PaperModeRequest, ctx: ModeContext): PaperMode;
5357
6405
 
5358
- export { AGENT_PAYLOAD_VERSION, type AeroPose, type BackContentConfig, type BackingDrawSpec, type Behavior, type BehaviorConfig, type BendOptions, type CarryOptions, type ClothConfig, type ClothParams, ClothSim, type ComposedDisplacement, type ComposedSurface, type ContentAtlas, type ContentConfig, type CoreStateName, type CurlOptions, type DampedValue, type Deformer, type DeformerContext, type DeformerInstance, type DeformerInstanceConfig, DropZone, type DropZoneConfig, type DropZoneProps, DropZoneRegistry, type FallOptions, type FieldA11yController, type FieldExportInput, type FieldExportPaper, type FieldExportZone, type FieldGroupData, type FieldPaperSlot, type FlightOptions, type FlightParams, type FlipOptions, type FlyOptions, type FoldOptions, type HandleSpec, type HangOptions, type IdleName, type IdlePreset, type KeyboardCarry, type KeyboardStepResult, type Layout, type LetterFoldOptions, type LightingName, type LightingPreset, ON_TWOS_FPS, PARITY_EPSILON, Paper, type PaperConfig, type PaperConfigInput, type PaperEdge, PaperFallback, PaperField, PaperFieldMesh, type PaperFieldMeshProps, type PaperFieldProps, type PaperHandle, PaperLighting, type PaperLightingProps, PaperMaterial, type PaperMaterialProps, PaperMesh, type PaperMeshProps, PaperMirror, type PaperMode, type PaperModeRequest, type PaperPose, type PaperProps, PaperStateMachine, type PaperStateMachineOptions, type PaperStates, type PaperStatesInput, type ParityCase, type ParityResult, type PeelOptions, type PhysicsConfig, type PinMode, type PlacedPaper, type ReceiptContent, type RollOptions, SHEET_LIFT, type SceneConfig, type SheetConfig, type SheetDims, type SheetLayoutOptions, type StateDef, type StateEvent, type StateName, type StateTransitionConfig, type Stock, type StockName, type SurfaceConfig, type SurfaceMaps, type UnrollOptions, type UsePaperStatesResult, type WaveOptions, applyDeformerStack, atlasGrid, backContentSchema, barcodeBars, behaviorConfigSchema, bend, bendOptionsSchema, buildAgentPayload, buildDisplacementGLSL, buildFieldAgentPayload, buildFieldComponentSource, buildFieldFragmentShader, buildFieldVertexShader, buildJsxSnippet, carry, carryDrive, carryOptionsSchema, cascade, clothConfigSchema, composeSurface, contentSchema, contentText, coreStateNames, cornerNames, createSheetGeometry, curl, curlOptionsSchema, dampTo, deck, deformerInstanceSchema, describeConfig, describeFieldConfig, diffConfig, diffFieldProps, displacePoint, distinctFieldPresets, drawBacking, fall, fallOptionsSchema, fieldKeyboardStep, flattenNumeric, flight, flightOptionsSchema, flightPose, flip, flipOptionsSchema, fly, flyOptionsSchema, fold, foldOptionsSchema, getBehavior, getDeformer, getIdlePreset, getLayout, getLightingPreset, getPreset, getStock, groupFieldPapers, gust, hang, hangOptionsSchema, helix, idleNames, idlePresets, isBuiltinPreset, letterFold, letterFoldOptionsSchema, lightenHex, lightingNames, lightingPresets, listBehaviors, listDeformers, listLayouts, listPresets, makeGoboTexture, mergeConfig, mergeWithDeletes, outwardCorner, paperConfigSchema, paperEdges, paperStatesSchema, parityCases, parsePreset, peel, peelOptionsSchema, physicsNames, physicsSchema, quantizeProgress, quantizeTime, receiptContentSchema, receiptTotals, recordStateOverride, registerBehavior, registerDeformer, registerLayout, registerPreset, resolveConfig, resolveFieldSlotConfig, resolveMode, resolveSegments, resolveStateConfig, ring, roll, rollOptionsSchema, runParityHarness, scatter, sceneSchema, serializePreset, sheet, sheetBackingSize, sheetLayoutSchema, sheetSchema, sheetSlotXY, silhouetteRects, stackMinSegments, stackUniformValues, stateDefSchema, stateEventTransitions, stateTransitionSchema, stockNames, stockSchema, stocks, stripStates, supportsWebGL, surfaceSchema, tornEdgesOnDetach, tunnel, uniquePresetName, unregisterPreset, unroll, unrollOptionsSchema, useContentAtlas, usePaperStates, usePrefersReducedMotion, wall, wave, waveOptionsSchema, withSheetCellFromPaper, zoneAccepts };
6406
+ export { AGENT_PAYLOAD_VERSION, type AeroPose, type BackContentConfig, type BackingDrawSpec, type Behavior, type BehaviorConfig, type BehaviorConfigInput, type BendOptions, type CarryOptions, type ClothConfig, type ClothParams, ClothSim, type ComposedDisplacement, type ComposedSurface, type ContentAtlas, type ContentConfig, type ContentConfigInput, type CoreStateName, type CrumpleBehaviorOptions, type CrumpleOptions, type CurlOptions, type DampedValue, type Deformer, type DeformerContext, type DeformerInstance, type DeformerInstanceConfig, type DeformerInstanceConfigInput, type DrapeOptions, DropZone, type DropZoneConfig, type DropZoneProps, DropZoneRegistry, type FallOptions, type FieldA11yController, type FieldBounds, type FieldExportInput, type FieldExportPaper, type FieldExportZone, type FieldGroupData, type FieldPaperSlot, type FlightOptions, type FlightParams, type FlipOptions, type FlyOptions, type FoldOptions, type Ground, type HandleSpec, type HangOptions, type IdleName, type IdlePreset, type KeyboardCarry, type KeyboardStepResult, type Layout, type LetterFoldOptions, type LightingName, type LightingPreset, ON_TWOS_FPS, PARITY_EPSILON, Paper, type PaperConfig, type PaperConfigInput, type PaperEdge, PaperFallback, PaperField, PaperFieldMesh, type PaperFieldMeshProps, type PaperFieldProps, type PaperHandle, PaperLighting, type PaperLightingProps, PaperMaterial, type PaperMaterialProps, PaperMesh, type PaperMeshProps, PaperMirror, type PaperMode, type PaperModeRequest, type PaperPose, type PaperProps, PaperStage, type PaperStageProps, PaperStageScene, type PaperStageSceneProps, PaperStateMachine, type PaperStateMachineOptions, type PaperStates, type PaperStatesInput, type ParityCase, type ParityResult, type PeelOptions, type PhysicsConfig, type PhysicsConfigInput, type PinMode, type PlacedPaper, type QualityName, type QualityTier, type ReceiptContent, type RollOptions, SHEET_LIFT, type SceneConfig, type SceneConfigInput, type SheetConfig, type SheetDims, type SheetLayoutOptions, type ShotName, type ShotOptions, type StageConfig, type StageConfigInput, type StageExportInput, type StagePreset, type StageScale, type StageShot, type StateDef, type StateEvent, type StateName, type StateTransitionConfig, type Stock, type StockName, type SurfaceConfig, type SurfaceConfigInput, type SurfaceMaps, TRANSMISSION_GAIN, type TranslucencyValues, type UnrollOptions, type UsePaperStatesResult, type WalkName, type WalkPath, type WalkPathOptions, type WaveOptions, accordion, applyDeformerStack, atlasGrid, backContentSchema, barcodeBars, behaviorConfigSchema, bend, bendOptionsSchema, book, buildAgentPayload, buildDisplacementGLSL, buildFieldAgentPayload, buildFieldComponentSource, buildFieldFragmentShader, buildFieldVertexShader, buildJsxSnippet, buildStageAgentPayload, buildStageComponentSource, carry, carryDrive, carryOptionsSchema, clothConfigSchema, colonnade, composeSurface, contentSchema, contentText, coreStateNames, cornerNames, createSheetGeometry, createWalkPath, crumple, crumpleBehavior, crumpleBehaviorOptionsSchema, crumpleOptionsSchema, curl, curlOptionsSchema, dampTo, deformerInstanceSchema, describeConfig, describeFieldConfig, describeStage, diffConfig, diffFieldProps, diffStage, displacePoint, distinctFieldPresets, drape, drapeOptionsSchema, drawBacking, fall, fallOptionsSchema, fan, fieldBounds, fieldKeyboardStep, fitCamera, flattenNumeric, flight, flightOptionsSchema, flightPose, flip, flipOptionsSchema, fly, flyOptionsSchema, fold, foldOptionsSchema, getBehavior, getDeformer, getIdlePreset, getLayout, getLightingPreset, getPreset, getStagePreset, getStock, getWalk, groupFieldPapers, gust, hang, hangOptionsSchema, idleNames, idlePresets, isBuiltinPreset, letterFold, letterFoldOptionsSchema, lightenHex, lightingNames, lightingPresets, listBehaviors, listDeformers, listLayouts, listPresets, listStagePresets, makeGoboTexture, mergeConfig, mergeWithDeletes, outwardCorner, paperConfigSchema, paperEdges, paperStatesSchema, parityCases, parsePreset, peel, peelOptionsSchema, physicsNames, physicsSchema, pile, qualityNames, quantizeProgress, quantizeTime, rack, receiptContentSchema, receiptTotals, recordStateOverride, registerBehavior, registerDeformer, registerLayout, registerPreset, resolveConfig, resolveDeformerStack, resolveFieldSlotConfig, resolveMode, resolveSegments, resolveStateConfig, ring, roll, rollOptionsSchema, runParityHarness, sceneSchema, serializePreset, sheet, sheetBackingSize, sheetLayoutSchema, sheetSchema, sheetSlotXY, shotNames, silhouetteRects, spill, spread, stackMinSegments, stackUniformValues, stagePresets, stageSchema, stateDefSchema, stateEventTransitions, stateTransitionSchema, stockNames, stockSchema, stocks, stringifyStage, stripStates, supportsWebGL, surfaceSchema, sweep, tornEdgesOnDetach, translucencyUniforms, translucencyValues, uniquePresetName, unregisterPreset, unroll, unrollOptionsSchema, useContentAtlas, usePaperStates, usePrefersReducedMotion, walkNameFor, walkNames, walks, wall, wave, waveOptionsSchema, withSheetCellFromPaper, zoneAccepts };