paperlab 0.3.1 → 0.5.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/README.md +16 -16
- package/dist/{chunk-XE4E43MD.js → chunk-6IADJZX5.js} +2424 -2242
- package/dist/chunk-6IADJZX5.js.map +1 -0
- package/dist/index.cjs +887 -843
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +450 -1934
- package/dist/index.d.ts +450 -1934
- package/dist/index.js +202 -429
- package/dist/index.js.map +1 -1
- package/dist/slots-CIo7FnlY.d.cts +13357 -0
- package/dist/slots-CIo7FnlY.d.ts +13357 -0
- package/dist/stage.cjs +2377 -2125
- package/dist/stage.cjs.map +1 -1
- package/dist/stage.d.cts +52 -204
- package/dist/stage.d.ts +52 -204
- package/dist/stage.js +29 -18
- package/dist/stage.js.map +1 -1
- package/package.json +2 -2
- package/dist/chunk-XE4E43MD.js.map +0 -1
- package/dist/slots-DUMR64HB.d.cts +0 -6661
- package/dist/slots-DUMR64HB.d.ts +0 -6661
package/dist/index.cjs
CHANGED
|
@@ -30,203 +30,85 @@ var __toCommonJS = (mod2) => __copyProps(__defProp({}, "__esModule", { value: tr
|
|
|
30
30
|
// src/index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
|
-
AGENT_PAYLOAD_VERSION: () => AGENT_PAYLOAD_VERSION,
|
|
34
33
|
AUTO_CEILING: () => AUTO_CEILING,
|
|
35
|
-
ClothSim: () => ClothSim,
|
|
36
34
|
DropZone: () => DropZone,
|
|
37
|
-
DropZoneRegistry: () => DropZoneRegistry,
|
|
38
35
|
FLAT_SEGMENTS: () => FLAT_SEGMENTS,
|
|
39
36
|
LightRig: () => LightRig,
|
|
40
|
-
ON_TWOS_FPS: () => ON_TWOS_FPS,
|
|
41
37
|
PARITY_EPSILON: () => PARITY_EPSILON,
|
|
42
38
|
Paper: () => Paper,
|
|
43
|
-
|
|
39
|
+
PaperBackdrop: () => PaperBackdrop,
|
|
44
40
|
PaperField: () => PaperField,
|
|
45
41
|
PaperFieldMesh: () => PaperFieldMesh,
|
|
46
42
|
PaperLighting: () => PaperLighting,
|
|
47
|
-
PaperMaterial: () => PaperMaterial,
|
|
48
43
|
PaperMesh: () => PaperMesh,
|
|
49
|
-
PaperMirror: () => PaperMirror,
|
|
50
|
-
PaperStateMachine: () => PaperStateMachine,
|
|
51
44
|
SAG_TOL: () => SAG_TOL,
|
|
52
|
-
|
|
53
|
-
TRANSMISSION_GAIN: () => TRANSMISSION_GAIN,
|
|
54
|
-
accordion: () => accordion,
|
|
55
|
-
applyDeformerStack: () => applyDeformerStack,
|
|
56
|
-
atlasGrid: () => atlasGrid,
|
|
57
|
-
backContentSchema: () => backContentSchema,
|
|
58
|
-
barcodeBars: () => barcodeBars,
|
|
45
|
+
backdropSchema: () => backdropSchema,
|
|
59
46
|
behaviorConfigSchema: () => behaviorConfigSchema,
|
|
60
|
-
bend: () => bend,
|
|
61
|
-
bendOptionsSchema: () => bendOptionsSchema,
|
|
62
|
-
book: () => book,
|
|
63
47
|
buildAgentPayload: () => buildAgentPayload,
|
|
64
|
-
buildDisplacementGLSL: () => buildDisplacementGLSL,
|
|
65
48
|
buildFieldAgentPayload: () => buildFieldAgentPayload,
|
|
66
49
|
buildFieldComponentSource: () => buildFieldComponentSource,
|
|
67
|
-
buildFieldFragmentShader: () => buildFieldFragmentShader,
|
|
68
|
-
buildFieldVertexShader: () => buildFieldVertexShader,
|
|
69
50
|
buildJsxSnippet: () => buildJsxSnippet,
|
|
70
|
-
cardContentSchema: () => cardContentSchema,
|
|
71
|
-
carry: () => carry,
|
|
72
|
-
carryDrive: () => carryDrive,
|
|
73
|
-
carryOptionsSchema: () => carryOptionsSchema,
|
|
74
51
|
clothConfigSchema: () => clothConfigSchema,
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
contentSchema: () => contentSchema,
|
|
78
|
-
contentText: () => contentText,
|
|
52
|
+
contentNames: () => contentNames,
|
|
53
|
+
contentSchemaFor: () => contentSchemaFor,
|
|
79
54
|
coreStateNames: () => coreStateNames,
|
|
80
|
-
cornerNames: () => cornerNames,
|
|
81
|
-
createSheetGeometry: () => createSheetGeometry,
|
|
82
|
-
crumple: () => crumple,
|
|
83
|
-
crumpleBehavior: () => crumpleBehavior,
|
|
84
|
-
crumpleBehaviorOptionsSchema: () => crumpleBehaviorOptionsSchema,
|
|
85
|
-
crumpleOptionsSchema: () => crumpleOptionsSchema,
|
|
86
|
-
curl: () => curl,
|
|
87
|
-
curlOptionsSchema: () => curlOptionsSchema,
|
|
88
|
-
dampTo: () => dampTo,
|
|
89
|
-
deformerInstanceSchema: () => deformerInstanceSchema,
|
|
90
55
|
describeConfig: () => describeConfig,
|
|
91
56
|
describeFieldConfig: () => describeFieldConfig,
|
|
92
57
|
diffConfig: () => diffConfig,
|
|
93
58
|
diffFieldProps: () => diffFieldProps,
|
|
94
|
-
displacePoint: () => displacePoint,
|
|
95
|
-
distinctFieldPresets: () => distinctFieldPresets,
|
|
96
|
-
drape: () => drape,
|
|
97
|
-
drapeOptionsSchema: () => drapeOptionsSchema,
|
|
98
|
-
drawBacking: () => drawBacking,
|
|
99
|
-
fall: () => fall,
|
|
100
|
-
fallOptionsSchema: () => fallOptionsSchema,
|
|
101
|
-
fan: () => fan,
|
|
102
|
-
fieldBounds: () => fieldBounds,
|
|
103
|
-
fieldKeyboardStep: () => fieldKeyboardStep,
|
|
104
|
-
filmNames: () => filmNames,
|
|
105
|
-
fitCamera: () => fitCamera,
|
|
106
|
-
flattenNumeric: () => flattenNumeric,
|
|
107
|
-
flight: () => flight,
|
|
108
|
-
flightOptionsSchema: () => flightOptionsSchema,
|
|
109
|
-
flightPose: () => flightPose,
|
|
110
|
-
flip: () => flip,
|
|
111
|
-
flipOptionsSchema: () => flipOptionsSchema,
|
|
112
|
-
fly: () => fly,
|
|
113
|
-
flyOptionsSchema: () => flyOptionsSchema,
|
|
114
|
-
fold: () => fold,
|
|
115
|
-
foldOptionsSchema: () => foldOptionsSchema,
|
|
116
59
|
getBehavior: () => getBehavior,
|
|
117
60
|
getDeformer: () => getDeformer,
|
|
118
|
-
getIdlePreset: () => getIdlePreset,
|
|
119
61
|
getLayout: () => getLayout,
|
|
120
|
-
getLightingPreset: () => getLightingPreset,
|
|
121
62
|
getPreset: () => getPreset,
|
|
122
63
|
getStock: () => getStock,
|
|
123
|
-
groupFieldPapers: () => groupFieldPapers,
|
|
124
|
-
gust: () => gust,
|
|
125
|
-
hang: () => hang,
|
|
126
|
-
hangOptionsSchema: () => hangOptionsSchema,
|
|
127
64
|
idleNames: () => idleNames,
|
|
128
|
-
idlePresets: () => idlePresets,
|
|
129
65
|
isBuiltinPreset: () => isBuiltinPreset,
|
|
130
|
-
letterFold: () => letterFold,
|
|
131
|
-
letterFoldOptionsSchema: () => letterFoldOptionsSchema,
|
|
132
66
|
lightAngles: () => lightAngles,
|
|
133
|
-
lightPosition: () => lightPosition,
|
|
134
67
|
lightSchema: () => lightSchema,
|
|
135
|
-
lightenHex: () => lightenHex,
|
|
136
68
|
lightingNames: () => lightingNames,
|
|
137
|
-
lightingPresets: () => lightingPresets,
|
|
138
69
|
listBehaviors: () => listBehaviors,
|
|
139
70
|
listDeformers: () => listDeformers,
|
|
140
71
|
listLayouts: () => listLayouts,
|
|
141
72
|
listPresets: () => listPresets,
|
|
142
|
-
makeGoboTexture: () => makeGoboTexture,
|
|
143
73
|
mergeConfig: () => mergeConfig,
|
|
144
74
|
mergeWithDeletes: () => mergeWithDeletes,
|
|
145
|
-
outwardCorner: () => outwardCorner,
|
|
146
75
|
paperConfigSchema: () => paperConfigSchema,
|
|
147
76
|
paperEdges: () => paperEdges,
|
|
148
77
|
paperStatesSchema: () => paperStatesSchema,
|
|
149
78
|
parityCases: () => parityCases,
|
|
150
79
|
parsePreset: () => parsePreset,
|
|
151
|
-
peel: () => peel,
|
|
152
|
-
peelOptionsSchema: () => peelOptionsSchema,
|
|
153
80
|
physicsNames: () => physicsNames,
|
|
154
|
-
physicsSchema: () => physicsSchema,
|
|
155
|
-
pile: () => pile,
|
|
156
|
-
quantizeProgress: () => quantizeProgress,
|
|
157
81
|
quantizeSegments: () => quantizeSegments,
|
|
158
|
-
quantizeTime: () => quantizeTime,
|
|
159
|
-
rack: () => rack,
|
|
160
|
-
receiptContentSchema: () => receiptContentSchema,
|
|
161
|
-
receiptTotals: () => receiptTotals,
|
|
162
82
|
recordStateOverride: () => recordStateOverride,
|
|
163
83
|
registerBehavior: () => registerBehavior,
|
|
164
84
|
registerDeformer: () => registerDeformer,
|
|
165
85
|
registerLayout: () => registerLayout,
|
|
166
86
|
registerPreset: () => registerPreset,
|
|
167
|
-
resolveConfig: () => resolveConfig,
|
|
168
|
-
resolveDeformerStack: () => resolveDeformerStack,
|
|
169
|
-
resolveFieldSlotConfig: () => resolveFieldSlotConfig,
|
|
170
87
|
resolveLighting: () => resolveLighting,
|
|
171
|
-
resolveMode: () => resolveMode,
|
|
172
|
-
resolveSegments: () => resolveSegments,
|
|
173
88
|
resolveStateConfig: () => resolveStateConfig,
|
|
174
|
-
ribbon: () => ribbon,
|
|
175
|
-
ribbonOptionsSchema: () => ribbonOptionsSchema,
|
|
176
|
-
ring: () => ring,
|
|
177
|
-
roll: () => roll,
|
|
178
|
-
rollOptionsSchema: () => rollOptionsSchema,
|
|
179
89
|
runParityHarness: () => runParityHarness,
|
|
180
90
|
sceneSchema: () => sceneSchema,
|
|
181
91
|
segmentsForArc: () => segmentsForArc,
|
|
182
92
|
segmentsForSine: () => segmentsForSine,
|
|
183
93
|
serializePreset: () => serializePreset,
|
|
184
|
-
settle: () => settle,
|
|
185
|
-
settleOptionsSchema: () => settleOptionsSchema,
|
|
186
|
-
sheet: () => sheet,
|
|
187
|
-
sheetBackingSize: () => sheetBackingSize,
|
|
188
94
|
sheetLayoutSchema: () => sheetLayoutSchema,
|
|
189
|
-
sheetSchema: () => sheetSchema,
|
|
190
|
-
sheetSlotXY: () => sheetSlotXY,
|
|
191
|
-
silhouetteRects: () => silhouetteRects,
|
|
192
95
|
spanAlong: () => spanAlong,
|
|
193
|
-
spill: () => spill,
|
|
194
|
-
spread: () => spread,
|
|
195
|
-
stackAutoSegments: () => stackAutoSegments,
|
|
196
|
-
stackMinSegments: () => stackMinSegments,
|
|
197
|
-
stackUniformValues: () => stackUniformValues,
|
|
198
96
|
stateDefSchema: () => stateDefSchema,
|
|
199
|
-
stateEventTransitions: () => stateEventTransitions,
|
|
200
|
-
stateTransitionSchema: () => stateTransitionSchema,
|
|
201
97
|
stockNames: () => stockNames,
|
|
202
|
-
stockSchema: () => stockSchema,
|
|
203
98
|
stocks: () => stocks,
|
|
204
|
-
stripStates: () => stripStates,
|
|
205
99
|
supportsWebGL: () => supportsWebGL,
|
|
206
|
-
surfaceSchema: () => surfaceSchema,
|
|
207
|
-
sweep: () => sweep,
|
|
208
|
-
tornEdgesOnDetach: () => tornEdgesOnDetach,
|
|
209
|
-
translucencyUniforms: () => translucencyUniforms,
|
|
210
|
-
translucencyValues: () => translucencyValues,
|
|
211
100
|
uniquePresetName: () => uniquePresetName,
|
|
212
101
|
unregisterPreset: () => unregisterPreset,
|
|
213
|
-
unroll: () => unroll,
|
|
214
|
-
unrollOptionsSchema: () => unrollOptionsSchema,
|
|
215
|
-
useContentAtlas: () => useContentAtlas,
|
|
216
102
|
usePaperStates: () => usePaperStates,
|
|
217
103
|
usePrefersReducedMotion: () => usePrefersReducedMotion,
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
waveOptionsSchema: () => waveOptionsSchema,
|
|
221
|
-
withSheetCellFromPaper: () => withSheetCellFromPaper,
|
|
222
|
-
wrapLines: () => wrapLines,
|
|
223
|
-
zoneAccepts: () => zoneAccepts
|
|
104
|
+
washSchema: () => washSchema,
|
|
105
|
+
wrapLines: () => wrapLines
|
|
224
106
|
});
|
|
225
107
|
module.exports = __toCommonJS(index_exports);
|
|
226
108
|
|
|
227
109
|
// src/Paper.tsx
|
|
228
|
-
var
|
|
229
|
-
var
|
|
110
|
+
var import_fiber4 = require("@react-three/fiber");
|
|
111
|
+
var import_react10 = require("react");
|
|
230
112
|
|
|
231
113
|
// src/PaperMesh.tsx
|
|
232
114
|
var THREE7 = __toESM(require("three"), 1);
|
|
@@ -1147,6 +1029,31 @@ var stockNames = [
|
|
|
1147
1029
|
"sticker"
|
|
1148
1030
|
];
|
|
1149
1031
|
var stockSchema = import_zod14.z.enum(stockNames);
|
|
1032
|
+
var washSchema = import_zod14.z.object({
|
|
1033
|
+
/** The first pigment. */
|
|
1034
|
+
color: import_zod14.z.string().default("#4a5b8c").describe("color"),
|
|
1035
|
+
/** The second. Blooms alternate, and overlaps multiply into a third. */
|
|
1036
|
+
secondary: import_zod14.z.string().default("#b06a6a").describe("color"),
|
|
1037
|
+
/** How many pools of colour. */
|
|
1038
|
+
blooms: import_zod14.z.number().int().min(1).max(24).default(7),
|
|
1039
|
+
/** How far a pool runs before it dries — its size against the sheet. */
|
|
1040
|
+
spread: import_zod14.z.number().min(0.1).max(1).default(0.7),
|
|
1041
|
+
/** Softness of the wet edge. 0 is a hard cut, 1 is a pool still moving. */
|
|
1042
|
+
bleed: import_zod14.z.number().min(0).max(1).default(0.5),
|
|
1043
|
+
/** How much pigment is in the water. */
|
|
1044
|
+
intensity: import_zod14.z.number().min(0).max(1).default(0.55),
|
|
1045
|
+
/**
|
|
1046
|
+
* Edge darkening — the ring of pigment left where a pool dried.
|
|
1047
|
+
*
|
|
1048
|
+
* The signature of the medium, and the one thing a plain gradient cannot
|
|
1049
|
+
* fake. Without it a wash reads as an airbrush.
|
|
1050
|
+
*/
|
|
1051
|
+
edge: import_zod14.z.number().min(0).max(1).default(0.6),
|
|
1052
|
+
/** Pigment settling into the tooth of the paper. */
|
|
1053
|
+
granulation: import_zod14.z.number().min(0).max(1).default(0.35),
|
|
1054
|
+
/** Fixed so a preset paints the same wash every time. */
|
|
1055
|
+
seed: import_zod14.z.number().int().min(0).max(99).default(0)
|
|
1056
|
+
});
|
|
1150
1057
|
var blankContentBase = import_zod14.z.object({
|
|
1151
1058
|
type: import_zod14.z.literal("blank")
|
|
1152
1059
|
});
|
|
@@ -1171,7 +1078,7 @@ var textContentBase = import_zod14.z.object({
|
|
|
1171
1078
|
/** px at texture resolution (long edge = 1024 logical px before DPR). */
|
|
1172
1079
|
size: import_zod14.z.number().min(8).max(256).default(44),
|
|
1173
1080
|
weight: import_zod14.z.number().min(100).max(900).default(400),
|
|
1174
|
-
color: import_zod14.z.string().default("#2b2620"),
|
|
1081
|
+
color: import_zod14.z.string().default("#2b2620").describe("color"),
|
|
1175
1082
|
align: import_zod14.z.enum(["left", "center", "right"]).default("left"),
|
|
1176
1083
|
/** Fraction of the short edge. */
|
|
1177
1084
|
padding: import_zod14.z.number().min(0).max(0.4).default(0.09),
|
|
@@ -1221,7 +1128,7 @@ var cardContentBase = import_zod14.z.object({
|
|
|
1221
1128
|
* was cropped rather than as a card that was set.
|
|
1222
1129
|
*/
|
|
1223
1130
|
size: import_zod14.z.number().min(8).max(256).default(58),
|
|
1224
|
-
color: import_zod14.z.string().default("#2b2620"),
|
|
1131
|
+
color: import_zod14.z.string().default("#2b2620").describe("color"),
|
|
1225
1132
|
align: import_zod14.z.enum(["left", "center"]).default("left"),
|
|
1226
1133
|
padding: import_zod14.z.number().min(0).max(0.4).default(0.1)
|
|
1227
1134
|
});
|
|
@@ -1240,14 +1147,15 @@ var receiptContentBase = import_zod14.z.object({
|
|
|
1240
1147
|
timestamp: import_zod14.z.string().optional(),
|
|
1241
1148
|
footer: import_zod14.z.string().default("KEEP FOR YOUR RECORDS")
|
|
1242
1149
|
});
|
|
1150
|
+
var withWash = { wash: washSchema.optional() };
|
|
1243
1151
|
var backContentSchema = import_zod14.z.discriminatedUnion("type", [
|
|
1244
|
-
blankContentBase,
|
|
1245
|
-
imageContentBase,
|
|
1246
|
-
textContentBase,
|
|
1247
|
-
cardContentBase,
|
|
1248
|
-
receiptContentBase
|
|
1152
|
+
blankContentBase.extend(withWash),
|
|
1153
|
+
imageContentBase.extend(withWash),
|
|
1154
|
+
textContentBase.extend(withWash),
|
|
1155
|
+
cardContentBase.extend(withWash),
|
|
1156
|
+
receiptContentBase.extend(withWash)
|
|
1249
1157
|
]);
|
|
1250
|
-
var withBack = { back: backContentSchema.optional() };
|
|
1158
|
+
var withBack = { back: backContentSchema.optional(), ...withWash };
|
|
1251
1159
|
var blankContentSchema = blankContentBase.extend(withBack);
|
|
1252
1160
|
var imageContentSchema = imageContentBase.extend(withBack);
|
|
1253
1161
|
var textContentSchema = textContentBase.extend(withBack);
|
|
@@ -1260,6 +1168,14 @@ var contentSchema = import_zod14.z.discriminatedUnion("type", [
|
|
|
1260
1168
|
cardContentSchema,
|
|
1261
1169
|
receiptContentSchema
|
|
1262
1170
|
]);
|
|
1171
|
+
var contentNames = contentSchema.options.map(
|
|
1172
|
+
(option) => option.shape.type.value
|
|
1173
|
+
);
|
|
1174
|
+
function contentSchemaFor(type) {
|
|
1175
|
+
const option = contentSchema.options.find((candidate) => candidate.shape.type.value === type);
|
|
1176
|
+
if (!option) throw new Error(`Unknown content type: ${type}`);
|
|
1177
|
+
return option;
|
|
1178
|
+
}
|
|
1263
1179
|
var paperEdges = ["top", "right", "bottom", "left"];
|
|
1264
1180
|
var surfaceSchema = import_zod14.z.object({
|
|
1265
1181
|
/** Paper fiber noise, 0..1. */
|
|
@@ -1347,8 +1263,70 @@ var lightingNames = [
|
|
|
1347
1263
|
"lightbox"
|
|
1348
1264
|
];
|
|
1349
1265
|
var filmNames = ["agx", "neutral", "filmic"];
|
|
1266
|
+
var lightSchema = import_zod14.z.object({
|
|
1267
|
+
/** Tone-mapping exposure — the stop the whole picture is printed at. */
|
|
1268
|
+
exposure: import_zod14.z.number().min(0.1).max(4).optional(),
|
|
1269
|
+
/**
|
|
1270
|
+
* The tone curve — the film, where `exposure` is the stop.
|
|
1271
|
+
*
|
|
1272
|
+
* `filmic` is ACES, which is what every preset used to be pinned to and is
|
|
1273
|
+
* kept so a scene tuned against it can say so. On near-white paper it is
|
|
1274
|
+
* the wrong film: it desaturates and drags bright neutrals toward
|
|
1275
|
+
* yellow-green, which is the sepia cast a lit sheet used to pick up.
|
|
1276
|
+
*/
|
|
1277
|
+
film: import_zod14.z.enum(filmNames).optional(),
|
|
1278
|
+
/** Key light strength. */
|
|
1279
|
+
key: import_zod14.z.number().min(0).max(12).optional(),
|
|
1280
|
+
/** Key light colour. */
|
|
1281
|
+
color: import_zod14.z.string().optional().describe("color"),
|
|
1282
|
+
/**
|
|
1283
|
+
* Where the key stands, degrees around the vertical. 0° is straight in
|
|
1284
|
+
* front of the paper (+Z, beside the camera), 90° is off to the right,
|
|
1285
|
+
* and ±180° is directly behind it — which is where `nave` puts it, and
|
|
1286
|
+
* why that preset is carried by light coming THROUGH the paper.
|
|
1287
|
+
*/
|
|
1288
|
+
direction: import_zod14.z.number().min(-180).max(180).optional(),
|
|
1289
|
+
/** How high the key stands, degrees above the horizon. */
|
|
1290
|
+
height: import_zod14.z.number().min(-30).max(89).optional(),
|
|
1291
|
+
/** Flat fill from every direction at once. Cheap, and it kills form — reach for `studio` first. */
|
|
1292
|
+
ambient: import_zod14.z.number().min(0).max(2).optional(),
|
|
1293
|
+
/** The room's own light: an environment map built from `sky`. Directional fill, and the only thing paper's sheen has to reflect. */
|
|
1294
|
+
studio: import_zod14.z.number().min(0).max(3).optional(),
|
|
1295
|
+
/** Distance haze, as a multiple of the preset's. 0 clears the air entirely; 2 halves the distance you can see. */
|
|
1296
|
+
haze: import_zod14.z.number().min(0).max(3).optional()
|
|
1297
|
+
});
|
|
1298
|
+
var backdropSchema = import_zod14.z.object({
|
|
1299
|
+
/** Behind everything, and behind the picture where it does not reach. */
|
|
1300
|
+
color: import_zod14.z.string().default("#171717").describe("color"),
|
|
1301
|
+
/** A URL, or an uploaded picture. Empty is the colour on its own. */
|
|
1302
|
+
image: import_zod14.z.string().default(""),
|
|
1303
|
+
fit: import_zod14.z.enum(["cover", "contain"]).default("cover"),
|
|
1304
|
+
/**
|
|
1305
|
+
* Toward the colour, so the paper stays the subject.
|
|
1306
|
+
*
|
|
1307
|
+
* A backdrop at full strength competes with the sheet in front of it —
|
|
1308
|
+
* which is what a real photographer solves by putting the background out
|
|
1309
|
+
* of the light, and what this solves by mixing it back toward the ground
|
|
1310
|
+
* it sits on.
|
|
1311
|
+
*/
|
|
1312
|
+
fade: import_zod14.z.number().min(0).max(1).default(0.25),
|
|
1313
|
+
/** Out of focus, for the same reason. */
|
|
1314
|
+
blur: import_zod14.z.number().min(0).max(1).default(0.2)
|
|
1315
|
+
});
|
|
1350
1316
|
var sceneSchema = import_zod14.z.object({
|
|
1351
|
-
lighting: import_zod14.z.enum(lightingNames).default("studio")
|
|
1317
|
+
lighting: import_zod14.z.enum(lightingNames).default("studio"),
|
|
1318
|
+
/** What is behind the sheet. Unset leaves the canvas alone. */
|
|
1319
|
+
backdrop: backdropSchema.optional(),
|
|
1320
|
+
/**
|
|
1321
|
+
* Overrides on the named preset — the same authorable half stage mode has
|
|
1322
|
+
* always had, and which a lone sheet had no way to reach.
|
|
1323
|
+
*
|
|
1324
|
+
* A preset was the starting point everywhere EXCEPT here: a stage could be
|
|
1325
|
+
* "nave, but the sun is lower", and a `<Paper>` could only be one of seven
|
|
1326
|
+
* rigs exactly as shipped. `<PaperLighting>` has taken these overrides all
|
|
1327
|
+
* along; nothing was passing them.
|
|
1328
|
+
*/
|
|
1329
|
+
light: lightSchema.default({})
|
|
1352
1330
|
});
|
|
1353
1331
|
var coreStateNames = ["rest", "hover", "pressed", "picked", "placed"];
|
|
1354
1332
|
var isStateName = (s) => coreStateNames.includes(s) || s.startsWith("custom:");
|
|
@@ -1481,11 +1459,11 @@ function computeSheetNormals(geometry) {
|
|
|
1481
1459
|
for (let i = 0, l = nrm.length; i < l; i += 3) {
|
|
1482
1460
|
const x = nrm[i];
|
|
1483
1461
|
const y = nrm[i + 1];
|
|
1484
|
-
const
|
|
1485
|
-
const len = Math.sqrt(x * x + y * y +
|
|
1462
|
+
const z25 = nrm[i + 2];
|
|
1463
|
+
const len = Math.sqrt(x * x + y * y + z25 * z25) || 1;
|
|
1486
1464
|
nrm[i] = x / len;
|
|
1487
1465
|
nrm[i + 1] = y / len;
|
|
1488
|
-
nrm[i + 2] =
|
|
1466
|
+
nrm[i + 2] = z25 / len;
|
|
1489
1467
|
}
|
|
1490
1468
|
normalAttr.needsUpdate = true;
|
|
1491
1469
|
}
|
|
@@ -1669,6 +1647,33 @@ var builtins = {
|
|
|
1669
1647
|
behavior: { type: "letter-fold", progress: 0.4, crease: 0.3 },
|
|
1670
1648
|
surface: { creaseLines: { angle: 0, positions: [1 / 3, 2 / 3], strength: 0.5 } }
|
|
1671
1649
|
},
|
|
1650
|
+
/**
|
|
1651
|
+
* The wash, shown rather than described.
|
|
1652
|
+
*
|
|
1653
|
+
* A `wash` is a field on every content type, which means it is reachable
|
|
1654
|
+
* from any preset and discoverable from none — a toggle three folders down
|
|
1655
|
+
* is not an argument for the feature. This is the argument: type set over
|
|
1656
|
+
* paint, on cotton, deckled, with the paper still showing through both.
|
|
1657
|
+
*/
|
|
1658
|
+
"washed-letter": {
|
|
1659
|
+
meta: { name: "Washed letter", tags: ["wash", "text"] },
|
|
1660
|
+
// Printer stock, not vellum: vellum is translucent and takes the room's
|
|
1661
|
+
// grey through the back of the sheet, which turns a wash the colour of
|
|
1662
|
+
// dishwater. Pigment needs something white behind it.
|
|
1663
|
+
sheet: { width: 1.05, height: 1.45 },
|
|
1664
|
+
stock: "printer",
|
|
1665
|
+
content: {
|
|
1666
|
+
type: "text",
|
|
1667
|
+
text: "Painted first,\nwritten after.",
|
|
1668
|
+
font: 'Georgia, "Times New Roman", serif',
|
|
1669
|
+
size: 52,
|
|
1670
|
+
valign: "center",
|
|
1671
|
+
align: "center",
|
|
1672
|
+
wash: { color: "#5b6f9a", secondary: "#c08a86", blooms: 6, spread: 0.85, intensity: 0.5, seed: 3 }
|
|
1673
|
+
},
|
|
1674
|
+
behavior: { type: "peel", progress: 0.12, corner: "bottom-right", radius: 0.3 },
|
|
1675
|
+
surface: { grain: 0.35, deckle: { edges: ["bottom", "right"], roughness: 0.45 } }
|
|
1676
|
+
},
|
|
1672
1677
|
"vintage-note": {
|
|
1673
1678
|
meta: { name: "Vintage note", tags: ["aging", "text"] },
|
|
1674
1679
|
sheet: { width: 1.1, height: 1.4 },
|
|
@@ -2109,6 +2114,109 @@ function paintCard(ctx, w, h, content, stock, dpr) {
|
|
|
2109
2114
|
}
|
|
2110
2115
|
}
|
|
2111
2116
|
|
|
2117
|
+
// src/content/wash.ts
|
|
2118
|
+
function mulberry32(seed) {
|
|
2119
|
+
let a = seed * 1831565813 + 2654435769;
|
|
2120
|
+
return () => {
|
|
2121
|
+
a |= 0;
|
|
2122
|
+
a = a + 1831565813 | 0;
|
|
2123
|
+
let t = Math.imul(a ^ a >>> 15, 1 | a);
|
|
2124
|
+
t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t;
|
|
2125
|
+
return ((t ^ t >>> 14) >>> 0) / 4294967296;
|
|
2126
|
+
};
|
|
2127
|
+
}
|
|
2128
|
+
function rgba(hex, alpha) {
|
|
2129
|
+
const m = /^#?([0-9a-f]{6})$/i.exec(hex.trim());
|
|
2130
|
+
const n = m ? Number.parseInt(m[1], 16) : 8421504;
|
|
2131
|
+
return `rgba(${n >> 16 & 255}, ${n >> 8 & 255}, ${n & 255}, ${Math.max(0, Math.min(1, alpha))})`;
|
|
2132
|
+
}
|
|
2133
|
+
function bloomShape(rng) {
|
|
2134
|
+
return {
|
|
2135
|
+
phase: [rng() * Math.PI * 2, rng() * Math.PI * 2, rng() * Math.PI * 2],
|
|
2136
|
+
amp: [0.18 + rng() * 0.1, 0.09 + rng() * 0.06, 0.05 + rng() * 0.04]
|
|
2137
|
+
};
|
|
2138
|
+
}
|
|
2139
|
+
function bloomPath(ctx, cx, cy, radius, shape, from = 0, to = 1) {
|
|
2140
|
+
const { phase, amp } = shape;
|
|
2141
|
+
const STEPS = Math.max(6, Math.round(72 * (to - from)));
|
|
2142
|
+
ctx.beginPath();
|
|
2143
|
+
for (let i = 0; i <= STEPS; i++) {
|
|
2144
|
+
const t = (from + (to - from) * i / STEPS) * Math.PI * 2;
|
|
2145
|
+
const wobble = amp[0] * Math.sin(2 * t + phase[0]) + amp[1] * Math.sin(3 * t + phase[1]) + amp[2] * Math.sin(5 * t + phase[2]);
|
|
2146
|
+
const r = radius * (1 + wobble);
|
|
2147
|
+
const x = cx + Math.cos(t) * r;
|
|
2148
|
+
const y = cy + Math.sin(t) * r;
|
|
2149
|
+
if (i === 0) ctx.moveTo(x, y);
|
|
2150
|
+
else ctx.lineTo(x, y);
|
|
2151
|
+
}
|
|
2152
|
+
if (from === 0 && to === 1) ctx.closePath();
|
|
2153
|
+
}
|
|
2154
|
+
function canBlur(ctx) {
|
|
2155
|
+
if (!("filter" in ctx)) return false;
|
|
2156
|
+
const before = ctx.filter;
|
|
2157
|
+
try {
|
|
2158
|
+
ctx.filter = "blur(2px)";
|
|
2159
|
+
const worked = ctx.filter !== "none" && ctx.filter !== before;
|
|
2160
|
+
ctx.filter = before;
|
|
2161
|
+
return worked;
|
|
2162
|
+
} catch {
|
|
2163
|
+
return false;
|
|
2164
|
+
}
|
|
2165
|
+
}
|
|
2166
|
+
function paintWash(ctx, w, h, wash) {
|
|
2167
|
+
const rng = mulberry32(wash.seed + 1);
|
|
2168
|
+
const short = Math.min(w, h);
|
|
2169
|
+
const blurs = canBlur(ctx);
|
|
2170
|
+
ctx.save();
|
|
2171
|
+
ctx.globalCompositeOperation = "multiply";
|
|
2172
|
+
for (let i = 0; i < wash.blooms; i++) {
|
|
2173
|
+
const pigment = i % 2 === 0 ? wash.color : wash.secondary;
|
|
2174
|
+
const cx = (rng() * 1.5 - 0.25) * w;
|
|
2175
|
+
const cy = (rng() * 1.5 - 0.25) * h;
|
|
2176
|
+
const radius = short * wash.spread * (0.28 + rng() * 0.34);
|
|
2177
|
+
const alpha = wash.intensity * (0.35 + rng() * 0.4);
|
|
2178
|
+
const shape = bloomShape(rng);
|
|
2179
|
+
ctx.save();
|
|
2180
|
+
if (blurs) ctx.filter = `blur(${(2 + wash.bleed * 26) * (0.6 + rng() * 0.8)}px)`;
|
|
2181
|
+
const gx = cx + (rng() - 0.5) * radius * 0.5;
|
|
2182
|
+
const gy = cy + (rng() - 0.5) * radius * 0.5;
|
|
2183
|
+
const grad = ctx.createRadialGradient(gx, gy, radius * 0.05, gx, gy, radius * 1.15);
|
|
2184
|
+
grad.addColorStop(0, rgba(pigment, alpha * 0.55));
|
|
2185
|
+
grad.addColorStop(0.62, rgba(pigment, alpha));
|
|
2186
|
+
grad.addColorStop(1, rgba(pigment, alpha * 0.75));
|
|
2187
|
+
ctx.fillStyle = grad;
|
|
2188
|
+
bloomPath(ctx, cx, cy, radius, shape);
|
|
2189
|
+
ctx.fill();
|
|
2190
|
+
if (wash.edge > 0) {
|
|
2191
|
+
if (blurs) ctx.filter = `blur(${(1.5 + wash.bleed * 9) * (0.6 + rng() * 0.6)}px)`;
|
|
2192
|
+
ctx.lineWidth = Math.max(1, radius * (0.03 + wash.edge * 0.05));
|
|
2193
|
+
const arcs = 5;
|
|
2194
|
+
const overlap = 0.4 / arcs;
|
|
2195
|
+
for (let a = 0; a < arcs; a++) {
|
|
2196
|
+
ctx.strokeStyle = rgba(pigment, alpha * wash.edge * (0.15 + rng() * 1.05));
|
|
2197
|
+
bloomPath(ctx, cx, cy, radius, shape, a / arcs, (a + 1) / arcs + overlap);
|
|
2198
|
+
ctx.stroke();
|
|
2199
|
+
}
|
|
2200
|
+
}
|
|
2201
|
+
ctx.restore();
|
|
2202
|
+
if (wash.granulation > 0) {
|
|
2203
|
+
ctx.save();
|
|
2204
|
+
bloomPath(ctx, cx, cy, radius, shape);
|
|
2205
|
+
ctx.clip();
|
|
2206
|
+
const grains = Math.round(wash.granulation * 900);
|
|
2207
|
+
ctx.fillStyle = rgba(pigment, wash.granulation * alpha * 0.5);
|
|
2208
|
+
for (let g = 0; g < grains; g++) {
|
|
2209
|
+
const a = rng() * Math.PI * 2;
|
|
2210
|
+
const d = Math.sqrt(rng()) * radius;
|
|
2211
|
+
const size = 1 + rng() * (short * 4e-3);
|
|
2212
|
+
ctx.fillRect(cx + Math.cos(a) * d, cy + Math.sin(a) * d, size, size);
|
|
2213
|
+
}
|
|
2214
|
+
ctx.restore();
|
|
2215
|
+
}
|
|
2216
|
+
}
|
|
2217
|
+
ctx.restore();
|
|
2218
|
+
}
|
|
2219
|
+
|
|
2112
2220
|
// src/content/texture.ts
|
|
2113
2221
|
var LONG_EDGE = 1024;
|
|
2114
2222
|
var DPR = 2;
|
|
@@ -2159,6 +2267,7 @@ function renderContentToCanvas(content, sheet2, stock, image) {
|
|
|
2159
2267
|
canvas.height = h;
|
|
2160
2268
|
const ctx = canvas.getContext("2d");
|
|
2161
2269
|
paintBackground(ctx, w, h, stock);
|
|
2270
|
+
if (content.wash) paintWash(ctx, w, h, content.wash);
|
|
2162
2271
|
if (content.type === "image" && image && content.src) paintImage(ctx, w, h, image, content.fit);
|
|
2163
2272
|
if (content.type === "text") paintText(ctx, w, h, content, stock);
|
|
2164
2273
|
if (content.type === "receipt") paintReceipt(ctx, w, h, content, stock);
|
|
@@ -3031,13 +3140,13 @@ var ClothSim = class {
|
|
|
3031
3140
|
this.stillFrames = 0;
|
|
3032
3141
|
}
|
|
3033
3142
|
/** Nearest particle to a local-space point — the grab interface. */
|
|
3034
|
-
grabNearest(x, y,
|
|
3143
|
+
grabNearest(x, y, z25) {
|
|
3035
3144
|
let best = -1;
|
|
3036
3145
|
let bestDist = Infinity;
|
|
3037
3146
|
for (let i = 0; i < this.count; i++) {
|
|
3038
3147
|
const dx = this.positions[i * 3] - x;
|
|
3039
3148
|
const dy = this.positions[i * 3 + 1] - y;
|
|
3040
|
-
const dz = this.positions[i * 3 + 2] -
|
|
3149
|
+
const dz = this.positions[i * 3 + 2] - z25;
|
|
3041
3150
|
const d = dx * dx + dy * dy + dz * dz;
|
|
3042
3151
|
if (d < bestDist) {
|
|
3043
3152
|
bestDist = d;
|
|
@@ -3048,15 +3157,15 @@ var ClothSim = class {
|
|
|
3048
3157
|
this.wake();
|
|
3049
3158
|
return best;
|
|
3050
3159
|
}
|
|
3051
|
-
moveGrab(x, y,
|
|
3160
|
+
moveGrab(x, y, z25) {
|
|
3052
3161
|
if (this.grabbedIndex < 0) return;
|
|
3053
3162
|
const i3 = this.grabbedIndex * 3;
|
|
3054
3163
|
this.positions[i3] = x;
|
|
3055
3164
|
this.positions[i3 + 1] = y;
|
|
3056
|
-
this.positions[i3 + 2] =
|
|
3165
|
+
this.positions[i3 + 2] = z25;
|
|
3057
3166
|
this.prev[i3] = x;
|
|
3058
3167
|
this.prev[i3 + 1] = y;
|
|
3059
|
-
this.prev[i3 + 2] =
|
|
3168
|
+
this.prev[i3 + 2] = z25;
|
|
3060
3169
|
this.wake();
|
|
3061
3170
|
}
|
|
3062
3171
|
release() {
|
|
@@ -3092,19 +3201,19 @@ var ClothSim = class {
|
|
|
3092
3201
|
}
|
|
3093
3202
|
const x = p[i3];
|
|
3094
3203
|
const y = p[i3 + 1];
|
|
3095
|
-
const
|
|
3204
|
+
const z25 = p[i3 + 2];
|
|
3096
3205
|
const gust2 = wind * (0.55 + 0.45 * Math.sin(this.time * 1.7 + x * 2.1 + y * 1.3)) * 0.9;
|
|
3097
3206
|
const ax = gust2 * 0.25;
|
|
3098
3207
|
const az = gust2;
|
|
3099
3208
|
const vx = (x - this.prev[i3]) * damping;
|
|
3100
3209
|
const vy = (y - this.prev[i3 + 1]) * damping;
|
|
3101
|
-
const vz = (
|
|
3210
|
+
const vz = (z25 - this.prev[i3 + 2]) * damping;
|
|
3102
3211
|
this.prev[i3] = x;
|
|
3103
3212
|
this.prev[i3 + 1] = y;
|
|
3104
|
-
this.prev[i3 + 2] =
|
|
3213
|
+
this.prev[i3 + 2] = z25;
|
|
3105
3214
|
p[i3] = x + vx + ax * dt2;
|
|
3106
3215
|
p[i3 + 1] = y + vy - gravity * 3.2 * dt2;
|
|
3107
|
-
p[i3 + 2] =
|
|
3216
|
+
p[i3 + 2] = z25 + vz + az * dt2;
|
|
3108
3217
|
maxTravel = Math.max(maxTravel, vx * vx + vy * vy + vz * vz);
|
|
3109
3218
|
}
|
|
3110
3219
|
for (let iter = 0; iter < SOLVER_ITERATIONS; iter++) {
|
|
@@ -3161,7 +3270,6 @@ var THREE5 = __toESM(require("three"), 1);
|
|
|
3161
3270
|
var THREE4 = __toESM(require("three"), 1);
|
|
3162
3271
|
|
|
3163
3272
|
// src/scene/lighting.ts
|
|
3164
|
-
var import_zod22 = require("zod");
|
|
3165
3273
|
var lightingPresets = {
|
|
3166
3274
|
studio: {
|
|
3167
3275
|
id: "studio",
|
|
@@ -3322,46 +3430,14 @@ var lightingPresets = {
|
|
|
3322
3430
|
function getLightingPreset(name) {
|
|
3323
3431
|
return lightingPresets[name];
|
|
3324
3432
|
}
|
|
3325
|
-
var lightSchema = import_zod22.z.object({
|
|
3326
|
-
/** Tone-mapping exposure — the stop the whole picture is printed at. */
|
|
3327
|
-
exposure: import_zod22.z.number().min(0.1).max(4).optional(),
|
|
3328
|
-
/**
|
|
3329
|
-
* The tone curve — the film, where `exposure` is the stop.
|
|
3330
|
-
*
|
|
3331
|
-
* `filmic` is ACES, which is what every preset used to be pinned to and is
|
|
3332
|
-
* kept so a scene tuned against it can say so. On near-white paper it is
|
|
3333
|
-
* the wrong film: it desaturates and drags bright neutrals toward
|
|
3334
|
-
* yellow-green, which is the sepia cast a lit sheet used to pick up.
|
|
3335
|
-
*/
|
|
3336
|
-
film: import_zod22.z.enum(filmNames).optional(),
|
|
3337
|
-
/** Key light strength. */
|
|
3338
|
-
key: import_zod22.z.number().min(0).max(12).optional(),
|
|
3339
|
-
/** Key light colour. */
|
|
3340
|
-
color: import_zod22.z.string().optional(),
|
|
3341
|
-
/**
|
|
3342
|
-
* Where the key stands, degrees around the vertical. 0° is straight in
|
|
3343
|
-
* front of the paper (+Z, beside the camera), 90° is off to the right,
|
|
3344
|
-
* and ±180° is directly behind it — which is where `nave` puts it, and
|
|
3345
|
-
* why that preset is carried by light coming THROUGH the paper.
|
|
3346
|
-
*/
|
|
3347
|
-
direction: import_zod22.z.number().min(-180).max(180).optional(),
|
|
3348
|
-
/** How high the key stands, degrees above the horizon. */
|
|
3349
|
-
height: import_zod22.z.number().min(-30).max(89).optional(),
|
|
3350
|
-
/** Flat fill from every direction at once. Cheap, and it kills form — reach for `studio` first. */
|
|
3351
|
-
ambient: import_zod22.z.number().min(0).max(2).optional(),
|
|
3352
|
-
/** The room's own light: an environment map built from `sky`. Directional fill, and the only thing paper's sheen has to reflect. */
|
|
3353
|
-
studio: import_zod22.z.number().min(0).max(3).optional(),
|
|
3354
|
-
/** Distance haze, as a multiple of the preset's. 0 clears the air entirely; 2 halves the distance you can see. */
|
|
3355
|
-
haze: import_zod22.z.number().min(0).max(3).optional()
|
|
3356
|
-
});
|
|
3357
3433
|
var DEG6 = 180 / Math.PI;
|
|
3358
3434
|
function lightAngles(position) {
|
|
3359
|
-
const [x, y,
|
|
3360
|
-
const distance = Math.hypot(x, y,
|
|
3435
|
+
const [x, y, z25] = position;
|
|
3436
|
+
const distance = Math.hypot(x, y, z25);
|
|
3361
3437
|
if (distance < 1e-9) return { azimuth: 0, elevation: 90, distance: 0 };
|
|
3362
|
-
const ground = Math.hypot(x,
|
|
3438
|
+
const ground = Math.hypot(x, z25);
|
|
3363
3439
|
return {
|
|
3364
|
-
azimuth: ground < 1e-9 ? 0 : Math.atan2(x,
|
|
3440
|
+
azimuth: ground < 1e-9 ? 0 : Math.atan2(x, z25) * DEG6,
|
|
3365
3441
|
elevation: Math.atan2(y, ground) * DEG6,
|
|
3366
3442
|
distance
|
|
3367
3443
|
};
|
|
@@ -3459,8 +3535,8 @@ vec3 plTransmission(vec3 inkFilter) {
|
|
|
3459
3535
|
);
|
|
3460
3536
|
function translucencyValues(translucency, lighting) {
|
|
3461
3537
|
const preset = typeof lighting === "string" ? getLightingPreset(lighting) : lighting;
|
|
3462
|
-
const [x, y,
|
|
3463
|
-
const direction = new THREE4.Vector3(x, y,
|
|
3538
|
+
const [x, y, z25] = preset.key.position;
|
|
3539
|
+
const direction = new THREE4.Vector3(x, y, z25);
|
|
3464
3540
|
if (direction.lengthSq() < 1e-12) direction.set(0, 1, 0);
|
|
3465
3541
|
direction.normalize();
|
|
3466
3542
|
const color = new THREE4.Color(preset.key.color).multiplyScalar(preset.key.intensity * TRANSMISSION_GAIN);
|
|
@@ -4622,6 +4698,7 @@ var PaperMesh = (0, import_react7.forwardRef)(function PaperMesh2(props, ref) {
|
|
|
4622
4698
|
props.interactive && !isCloth && behavior?.handles?.map((h, i) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
4623
4699
|
"mesh",
|
|
4624
4700
|
{
|
|
4701
|
+
userData: { paperlabChrome: true },
|
|
4625
4702
|
ref: (m) => {
|
|
4626
4703
|
handleRefs.current[i] = m;
|
|
4627
4704
|
},
|
|
@@ -4765,7 +4842,7 @@ var toneMappings = {
|
|
|
4765
4842
|
neutral: THREE9.NeutralToneMapping,
|
|
4766
4843
|
filmic: THREE9.ACESFilmicToneMapping
|
|
4767
4844
|
};
|
|
4768
|
-
function
|
|
4845
|
+
function mulberry322(seed) {
|
|
4769
4846
|
let a = seed;
|
|
4770
4847
|
return () => {
|
|
4771
4848
|
a |= 0;
|
|
@@ -4799,7 +4876,7 @@ function makeGoboTexture(kind) {
|
|
|
4799
4876
|
}
|
|
4800
4877
|
ctx.restore();
|
|
4801
4878
|
} else {
|
|
4802
|
-
const rand =
|
|
4879
|
+
const rand = mulberry322(7);
|
|
4803
4880
|
for (const [count, radius, alpha] of [
|
|
4804
4881
|
[26, 70, 0.75],
|
|
4805
4882
|
[40, 38, 0.6],
|
|
@@ -4947,17 +5024,85 @@ function PaperLighting({
|
|
|
4947
5024
|
] });
|
|
4948
5025
|
}
|
|
4949
5026
|
|
|
5027
|
+
// src/scene/backdrop.tsx
|
|
5028
|
+
var THREE10 = __toESM(require("three"), 1);
|
|
5029
|
+
var import_react9 = require("react");
|
|
5030
|
+
var import_fiber3 = require("@react-three/fiber");
|
|
5031
|
+
function PaperBackdrop({ backdrop }) {
|
|
5032
|
+
const scene = (0, import_fiber3.useThree)((s) => s.scene);
|
|
5033
|
+
const size = (0, import_fiber3.useThree)((s) => s.size);
|
|
5034
|
+
const [image, setImage] = (0, import_react9.useState)(null);
|
|
5035
|
+
const src = backdrop?.image ?? "";
|
|
5036
|
+
(0, import_react9.useEffect)(() => {
|
|
5037
|
+
if (!src) {
|
|
5038
|
+
setImage(null);
|
|
5039
|
+
return;
|
|
5040
|
+
}
|
|
5041
|
+
let live = true;
|
|
5042
|
+
const img = new Image();
|
|
5043
|
+
img.crossOrigin = "anonymous";
|
|
5044
|
+
img.onload = () => live && setImage(img);
|
|
5045
|
+
img.onerror = () => live && setImage(null);
|
|
5046
|
+
img.src = src;
|
|
5047
|
+
return () => {
|
|
5048
|
+
live = false;
|
|
5049
|
+
};
|
|
5050
|
+
}, [src]);
|
|
5051
|
+
const key = JSON.stringify({ backdrop: backdrop ?? null, w: size.width, h: size.height, loaded: !!image });
|
|
5052
|
+
(0, import_react9.useEffect)(() => {
|
|
5053
|
+
if (!backdrop) return;
|
|
5054
|
+
const previous = scene.background;
|
|
5055
|
+
const texture = paintBackdrop(backdrop, size.width, size.height, image);
|
|
5056
|
+
scene.background = texture;
|
|
5057
|
+
return () => {
|
|
5058
|
+
scene.background = previous;
|
|
5059
|
+
texture.dispose();
|
|
5060
|
+
};
|
|
5061
|
+
}, [key]);
|
|
5062
|
+
return null;
|
|
5063
|
+
}
|
|
5064
|
+
function paintBackdrop(backdrop, width, height, image) {
|
|
5065
|
+
const w = Math.max(2, Math.round(width / 2));
|
|
5066
|
+
const h = Math.max(2, Math.round(height / 2));
|
|
5067
|
+
const canvas = document.createElement("canvas");
|
|
5068
|
+
canvas.width = w;
|
|
5069
|
+
canvas.height = h;
|
|
5070
|
+
const ctx = canvas.getContext("2d");
|
|
5071
|
+
ctx.fillStyle = backdrop.color;
|
|
5072
|
+
ctx.fillRect(0, 0, w, h);
|
|
5073
|
+
if (image && image.width > 0 && image.height > 0) {
|
|
5074
|
+
const scale = backdrop.fit === "cover" ? Math.max(w / image.width, h / image.height) : Math.min(w / image.width, h / image.height);
|
|
5075
|
+
const dw = image.width * scale;
|
|
5076
|
+
const dh = image.height * scale;
|
|
5077
|
+
ctx.save();
|
|
5078
|
+
if (backdrop.blur > 0) ctx.filter = `blur(${backdrop.blur * Math.min(w, h) * 0.06}px)`;
|
|
5079
|
+
ctx.drawImage(image, (w - dw) / 2, (h - dh) / 2, dw, dh);
|
|
5080
|
+
ctx.restore();
|
|
5081
|
+
if (backdrop.fade > 0) {
|
|
5082
|
+
ctx.globalAlpha = backdrop.fade;
|
|
5083
|
+
ctx.fillStyle = backdrop.color;
|
|
5084
|
+
ctx.fillRect(0, 0, w, h);
|
|
5085
|
+
ctx.globalAlpha = 1;
|
|
5086
|
+
}
|
|
5087
|
+
}
|
|
5088
|
+
const texture = new THREE10.CanvasTexture(canvas);
|
|
5089
|
+
texture.colorSpace = THREE10.SRGBColorSpace;
|
|
5090
|
+
return texture;
|
|
5091
|
+
}
|
|
5092
|
+
|
|
4950
5093
|
// src/Paper.tsx
|
|
4951
5094
|
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
4952
|
-
var Paper = (0,
|
|
5095
|
+
var Paper = (0, import_react10.forwardRef)(function Paper2({ children, className, style, ...meshProps }, ref) {
|
|
4953
5096
|
const config = useResolvedConfig(meshProps);
|
|
4954
|
-
const webgl = (0,
|
|
5097
|
+
const webgl = (0, import_react10.useMemo)(() => typeof window === "undefined" ? true : supportsWebGL(), []);
|
|
4955
5098
|
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className, style: { width: "100%", height: "100%", ...style }, children: [
|
|
4956
|
-
webgl ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
5099
|
+
webgl ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_fiber4.Canvas, { shadows: true, camera: { position: [0, 0.35, 2.4], fov: 40 }, dpr: [1, 2], children: [
|
|
5100
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PaperBackdrop, { backdrop: config.scene.backdrop }),
|
|
4957
5101
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
4958
5102
|
PaperLighting,
|
|
4959
5103
|
{
|
|
4960
5104
|
preset: config.scene.lighting,
|
|
5105
|
+
light: config.scene.light,
|
|
4961
5106
|
floor: -1.05,
|
|
4962
5107
|
scale: 8,
|
|
4963
5108
|
reducedMotion: meshProps.reducedMotion
|
|
@@ -4971,14 +5116,14 @@ var Paper = (0, import_react9.forwardRef)(function Paper2({ children, className,
|
|
|
4971
5116
|
});
|
|
4972
5117
|
|
|
4973
5118
|
// src/PaperField.tsx
|
|
4974
|
-
var
|
|
5119
|
+
var THREE16 = __toESM(require("three"), 1);
|
|
4975
5120
|
var import_gsap5 = require("gsap");
|
|
4976
|
-
var
|
|
4977
|
-
var
|
|
5121
|
+
var import_fiber7 = require("@react-three/fiber");
|
|
5122
|
+
var import_react17 = require("react");
|
|
4978
5123
|
|
|
4979
5124
|
// src/field/dropZones.tsx
|
|
4980
|
-
var
|
|
4981
|
-
var
|
|
5125
|
+
var THREE11 = __toESM(require("three"), 1);
|
|
5126
|
+
var import_react11 = require("react");
|
|
4982
5127
|
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
4983
5128
|
var DropZoneRegistry = class {
|
|
4984
5129
|
zones = /* @__PURE__ */ new Map();
|
|
@@ -5017,7 +5162,7 @@ var DropZoneRegistry = class {
|
|
|
5017
5162
|
for (const fn of this.listeners) fn();
|
|
5018
5163
|
}
|
|
5019
5164
|
};
|
|
5020
|
-
var DropZoneContext = (0,
|
|
5165
|
+
var DropZoneContext = (0, import_react11.createContext)(null);
|
|
5021
5166
|
var globCache = /* @__PURE__ */ new Map();
|
|
5022
5167
|
var globRegExp = (glob) => {
|
|
5023
5168
|
let re = globCache.get(glob);
|
|
@@ -5033,13 +5178,13 @@ function zoneAccepts(zone, name) {
|
|
|
5033
5178
|
}
|
|
5034
5179
|
var zoneContains = (zone, x, y) => Math.abs(x - zone.bounds.position[0]) <= zone.bounds.size[0] / 2 && Math.abs(y - zone.bounds.position[1]) <= zone.bounds.size[1] / 2;
|
|
5035
5180
|
function DropZone(props) {
|
|
5036
|
-
const registry4 = (0,
|
|
5181
|
+
const registry4 = (0, import_react11.useContext)(DropZoneContext);
|
|
5037
5182
|
const { id, accept, bounds, highlight = "glow", onPlace } = props;
|
|
5038
|
-
const place = (0,
|
|
5039
|
-
(0,
|
|
5183
|
+
const place = (0, import_react11.useRef)(onPlace);
|
|
5184
|
+
(0, import_react11.useEffect)(() => {
|
|
5040
5185
|
place.current = onPlace;
|
|
5041
5186
|
}, [onPlace]);
|
|
5042
|
-
(0,
|
|
5187
|
+
(0, import_react11.useEffect)(() => {
|
|
5043
5188
|
if (!registry4) return;
|
|
5044
5189
|
return registry4.register({
|
|
5045
5190
|
id,
|
|
@@ -5053,17 +5198,17 @@ function DropZone(props) {
|
|
|
5053
5198
|
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(DropZoneVisual, { registry: registry4, config: { id, accept, bounds, highlight } });
|
|
5054
5199
|
}
|
|
5055
5200
|
function DropZoneVisual({ registry: registry4, config }) {
|
|
5056
|
-
(0,
|
|
5201
|
+
(0, import_react11.useSyncExternalStore)(registry4.subscribe, registry4.getVersion, registry4.getVersion);
|
|
5057
5202
|
const hovered = registry4.hovered === config.id;
|
|
5058
5203
|
const style = config.highlight ?? "glow";
|
|
5059
5204
|
const [w, h] = config.bounds.size;
|
|
5060
|
-
const edges = (0,
|
|
5061
|
-
const plane = new
|
|
5062
|
-
const geo = new
|
|
5205
|
+
const edges = (0, import_react11.useMemo)(() => {
|
|
5206
|
+
const plane = new THREE11.PlaneGeometry(w, h);
|
|
5207
|
+
const geo = new THREE11.EdgesGeometry(plane);
|
|
5063
5208
|
plane.dispose();
|
|
5064
5209
|
return geo;
|
|
5065
5210
|
}, [w, h]);
|
|
5066
|
-
(0,
|
|
5211
|
+
(0, import_react11.useEffect)(() => () => edges.dispose(), [edges]);
|
|
5067
5212
|
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("group", { position: config.bounds.position, children: [
|
|
5068
5213
|
style !== "outline" && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("mesh", { children: [
|
|
5069
5214
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("planeGeometry", { args: [w, h] }),
|
|
@@ -5082,18 +5227,18 @@ function DropZoneVisual({ registry: registry4, config }) {
|
|
|
5082
5227
|
}
|
|
5083
5228
|
|
|
5084
5229
|
// src/field/sheetGrid.ts
|
|
5085
|
-
var
|
|
5086
|
-
var sheetLayoutSchema =
|
|
5087
|
-
rows:
|
|
5088
|
-
columns:
|
|
5230
|
+
var import_zod22 = require("zod");
|
|
5231
|
+
var sheetLayoutSchema = import_zod22.z.object({
|
|
5232
|
+
rows: import_zod22.z.number().int().min(1).max(12).default(2),
|
|
5233
|
+
columns: import_zod22.z.number().int().min(1).max(12).default(5),
|
|
5089
5234
|
/** World-units gap between slots. Stamps are printed in register — no jitter. */
|
|
5090
|
-
gutter:
|
|
5235
|
+
gutter: import_zod22.z.number().min(0).max(1).default(0.08),
|
|
5091
5236
|
/** Slot footprint in world units (the paper preset should match). */
|
|
5092
|
-
cellWidth:
|
|
5093
|
-
cellHeight:
|
|
5237
|
+
cellWidth: import_zod22.z.number().min(0.1).max(4).default(0.72),
|
|
5238
|
+
cellHeight: import_zod22.z.number().min(0.1).max(4).default(0.86),
|
|
5094
5239
|
/** Render the shared backing sheet behind the grid. */
|
|
5095
|
-
backing:
|
|
5096
|
-
backingMargin:
|
|
5240
|
+
backing: import_zod22.z.boolean().default(true),
|
|
5241
|
+
backingMargin: import_zod22.z.number().min(0).max(1).default(0.12)
|
|
5097
5242
|
});
|
|
5098
5243
|
var SHEET_LIFT = 0.012;
|
|
5099
5244
|
function withSheetCellFromPaper(parsed, rawOptions, paperDims) {
|
|
@@ -5185,24 +5330,24 @@ function resolveFieldSlotConfig(slot, fallback, index, layoutId, layoutOptions)
|
|
|
5185
5330
|
}
|
|
5186
5331
|
|
|
5187
5332
|
// src/field/fieldGroup.tsx
|
|
5188
|
-
var
|
|
5333
|
+
var THREE13 = __toESM(require("three"), 1);
|
|
5189
5334
|
var import_gsap3 = require("gsap");
|
|
5190
|
-
var
|
|
5191
|
-
var
|
|
5335
|
+
var import_fiber5 = require("@react-three/fiber");
|
|
5336
|
+
var import_react13 = require("react");
|
|
5192
5337
|
var import_three_custom_shader_material2 = __toESM(require("three-custom-shader-material"), 1);
|
|
5193
5338
|
|
|
5194
5339
|
// src/content/atlas.ts
|
|
5195
|
-
var
|
|
5196
|
-
var
|
|
5340
|
+
var THREE12 = __toESM(require("three"), 1);
|
|
5341
|
+
var import_react12 = require("react");
|
|
5197
5342
|
var MAX_ATLAS = 4096;
|
|
5198
5343
|
function atlasGrid(count, aspect = 1) {
|
|
5199
5344
|
const cols = Math.max(1, Math.min(count, Math.ceil(Math.sqrt(count * Math.max(aspect, 0.01)))));
|
|
5200
5345
|
return { cols, rows: Math.max(1, Math.ceil(count / cols)) };
|
|
5201
5346
|
}
|
|
5202
5347
|
function useContentAtlas(contents, sheet2, stock) {
|
|
5203
|
-
const [atlas, setAtlas] = (0,
|
|
5348
|
+
const [atlas, setAtlas] = (0, import_react12.useState)(null);
|
|
5204
5349
|
const stableContents = useStable(contents);
|
|
5205
|
-
(0,
|
|
5350
|
+
(0, import_react12.useEffect)(() => {
|
|
5206
5351
|
let disposed = false;
|
|
5207
5352
|
const aspect = sheet2.height / sheet2.width;
|
|
5208
5353
|
const { cols, rows } = atlasGrid(contents.length, aspect);
|
|
@@ -5218,8 +5363,8 @@ function useContentAtlas(contents, sheet2, stock) {
|
|
|
5218
5363
|
const ctx = canvas.getContext("2d");
|
|
5219
5364
|
ctx.fillStyle = stock.color;
|
|
5220
5365
|
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
5221
|
-
const texture = new
|
|
5222
|
-
texture.colorSpace =
|
|
5366
|
+
const texture = new THREE12.CanvasTexture(canvas);
|
|
5367
|
+
texture.colorSpace = THREE12.SRGBColorSpace;
|
|
5223
5368
|
texture.anisotropy = 4;
|
|
5224
5369
|
setAtlas({ texture, cols, rows });
|
|
5225
5370
|
const drawTile = (index, tile) => {
|
|
@@ -5378,21 +5523,21 @@ function cap(s) {
|
|
|
5378
5523
|
}
|
|
5379
5524
|
|
|
5380
5525
|
// src/field/layouts/index.ts
|
|
5381
|
-
var
|
|
5526
|
+
var import_zod24 = require("zod");
|
|
5382
5527
|
|
|
5383
5528
|
// src/stage/path.ts
|
|
5384
|
-
var
|
|
5385
|
-
var walkPathSchema =
|
|
5529
|
+
var import_zod23 = require("zod");
|
|
5530
|
+
var walkPathSchema = import_zod23.z.object({
|
|
5386
5531
|
/**
|
|
5387
5532
|
* Control points on the ground plane, [x, z]. The default walks away from
|
|
5388
5533
|
* the camera down -Z — the shot every reference image is composed on.
|
|
5389
5534
|
*/
|
|
5390
|
-
points:
|
|
5535
|
+
points: import_zod23.z.array(import_zod23.z.tuple([import_zod23.z.number(), import_zod23.z.number()])).min(2).default([
|
|
5391
5536
|
[0, 9],
|
|
5392
5537
|
[0, -9]
|
|
5393
5538
|
]),
|
|
5394
5539
|
/** Join the last point back to the first: an endless walk, and the only form `phase` can slide. */
|
|
5395
|
-
closed:
|
|
5540
|
+
closed: import_zod23.z.boolean().default(false)
|
|
5396
5541
|
});
|
|
5397
5542
|
var SAMPLES_PER_SEGMENT = 24;
|
|
5398
5543
|
var EPSILON = 1e-6;
|
|
@@ -5518,9 +5663,9 @@ function jitter2(seed, i) {
|
|
|
5518
5663
|
function ramp(i, n) {
|
|
5519
5664
|
return n > 1 ? i / (n - 1) : 1;
|
|
5520
5665
|
}
|
|
5521
|
-
var ringSchema =
|
|
5522
|
-
radius:
|
|
5523
|
-
tiltDeg:
|
|
5666
|
+
var ringSchema = import_zod24.z.object({
|
|
5667
|
+
radius: import_zod24.z.number().min(0.5).max(12).default(2.6),
|
|
5668
|
+
tiltDeg: import_zod24.z.number().min(-45).max(45).default(8)
|
|
5524
5669
|
});
|
|
5525
5670
|
var ring = {
|
|
5526
5671
|
id: "ring",
|
|
@@ -5538,15 +5683,15 @@ var ring = {
|
|
|
5538
5683
|
};
|
|
5539
5684
|
}
|
|
5540
5685
|
};
|
|
5541
|
-
var fanSchema =
|
|
5686
|
+
var fanSchema = import_zod24.z.object({
|
|
5542
5687
|
/** Total angular sweep from the first sheet to the last, degrees. */
|
|
5543
|
-
sweep:
|
|
5688
|
+
sweep: import_zod24.z.number().min(0).max(180).default(72),
|
|
5544
5689
|
/** Where the shared pin sits, in half-sheet-heights below center. 1 = the bottom edge. */
|
|
5545
|
-
hinge:
|
|
5690
|
+
hinge: import_zod24.z.number().min(0).max(4).default(1.15),
|
|
5546
5691
|
/** Thickness step so the sheets stack in order instead of z-fighting. */
|
|
5547
|
-
lift:
|
|
5692
|
+
lift: import_zod24.z.number().min(2e-3).max(0.08).default(0.012),
|
|
5548
5693
|
/** How much flatter the middle of the fan sits than its outer sheets. */
|
|
5549
|
-
bow:
|
|
5694
|
+
bow: import_zod24.z.number().min(0).max(1).default(0.7)
|
|
5550
5695
|
});
|
|
5551
5696
|
var fan = {
|
|
5552
5697
|
id: "fan",
|
|
@@ -5566,16 +5711,16 @@ var fan = {
|
|
|
5566
5711
|
};
|
|
5567
5712
|
}
|
|
5568
5713
|
};
|
|
5569
|
-
var spreadSchema =
|
|
5714
|
+
var spreadSchema = import_zod24.z.object({
|
|
5570
5715
|
/** How far each sheet slides past the one below it. */
|
|
5571
|
-
slip:
|
|
5716
|
+
slip: import_zod24.z.number().min(0.02).max(2).default(0.3),
|
|
5572
5717
|
/** Direction of the slide, degrees. 0 slides right, 90 slides up. */
|
|
5573
|
-
angle:
|
|
5574
|
-
lift:
|
|
5718
|
+
angle: import_zod24.z.number().min(-180).max(180).default(28),
|
|
5719
|
+
lift: import_zod24.z.number().min(2e-3).max(0.08).default(0.012),
|
|
5575
5720
|
/** How much more the sheets at the far end of the slide bow. */
|
|
5576
|
-
bow:
|
|
5721
|
+
bow: import_zod24.z.number().min(0).max(1).default(0.6),
|
|
5577
5722
|
/** Nothing hand-slid is perfectly square — a touch of per-sheet rotation. */
|
|
5578
|
-
drift:
|
|
5723
|
+
drift: import_zod24.z.number().min(0).max(1).default(0.15)
|
|
5579
5724
|
});
|
|
5580
5725
|
var spread = {
|
|
5581
5726
|
id: "spread",
|
|
@@ -5593,15 +5738,15 @@ var spread = {
|
|
|
5593
5738
|
};
|
|
5594
5739
|
}
|
|
5595
5740
|
};
|
|
5596
|
-
var pileSchema =
|
|
5741
|
+
var pileSchema = import_zod24.z.object({
|
|
5597
5742
|
/** How far sheets wander from the center of the heap. */
|
|
5598
|
-
scatter:
|
|
5743
|
+
scatter: import_zod24.z.number().min(0).max(2).default(0.22),
|
|
5599
5744
|
/** Widest angle a sheet sits off square, degrees. */
|
|
5600
|
-
turn:
|
|
5601
|
-
lift:
|
|
5745
|
+
turn: import_zod24.z.number().min(0).max(180).default(24),
|
|
5746
|
+
lift: import_zod24.z.number().min(2e-3).max(0.08).default(0.011),
|
|
5602
5747
|
/** How flat the sheets underneath are pressed by the ones on top. */
|
|
5603
|
-
press:
|
|
5604
|
-
seed:
|
|
5748
|
+
press: import_zod24.z.number().min(0).max(1).default(0.85),
|
|
5749
|
+
seed: import_zod24.z.number().int().min(0).max(9999).default(3)
|
|
5605
5750
|
});
|
|
5606
5751
|
var pile = {
|
|
5607
5752
|
id: "pile",
|
|
@@ -5617,12 +5762,12 @@ var pile = {
|
|
|
5617
5762
|
};
|
|
5618
5763
|
}
|
|
5619
5764
|
};
|
|
5620
|
-
var wallSchema =
|
|
5621
|
-
gapX:
|
|
5622
|
-
gapY:
|
|
5623
|
-
jitterAmt:
|
|
5765
|
+
var wallSchema = import_zod24.z.object({
|
|
5766
|
+
gapX: import_zod24.z.number().min(0.05).max(1).default(0.22),
|
|
5767
|
+
gapY: import_zod24.z.number().min(0.05).max(1).default(0.3),
|
|
5768
|
+
jitterAmt: import_zod24.z.number().min(0).max(1).default(0.25),
|
|
5624
5769
|
/** Spread of sag across the wall — no two pinned sheets hang alike. */
|
|
5625
|
-
sag:
|
|
5770
|
+
sag: import_zod24.z.number().min(0).max(1).default(0.45)
|
|
5626
5771
|
});
|
|
5627
5772
|
var wall = {
|
|
5628
5773
|
id: "wall",
|
|
@@ -5648,15 +5793,15 @@ var wall = {
|
|
|
5648
5793
|
};
|
|
5649
5794
|
}
|
|
5650
5795
|
};
|
|
5651
|
-
var spillSchema =
|
|
5652
|
-
spreadX:
|
|
5653
|
-
spreadY:
|
|
5654
|
-
depth:
|
|
5796
|
+
var spillSchema = import_zod24.z.object({
|
|
5797
|
+
spreadX: import_zod24.z.number().min(0.5).max(8).default(2.4),
|
|
5798
|
+
spreadY: import_zod24.z.number().min(0.5).max(8).default(1.5),
|
|
5799
|
+
depth: import_zod24.z.number().min(0).max(6).default(1.6),
|
|
5655
5800
|
/** How far sheets pitch and roll out of the picture plane. */
|
|
5656
|
-
tumble:
|
|
5801
|
+
tumble: import_zod24.z.number().min(0).max(1).default(0.5),
|
|
5657
5802
|
/** Spread of bend across the sheets — a spill does not fold them alike. */
|
|
5658
|
-
vary:
|
|
5659
|
-
seed:
|
|
5803
|
+
vary: import_zod24.z.number().min(0).max(1).default(0.6),
|
|
5804
|
+
seed: import_zod24.z.number().int().min(0).max(9999).default(7)
|
|
5660
5805
|
});
|
|
5661
5806
|
var spill = {
|
|
5662
5807
|
id: "spill",
|
|
@@ -5681,13 +5826,13 @@ var spill = {
|
|
|
5681
5826
|
};
|
|
5682
5827
|
}
|
|
5683
5828
|
};
|
|
5684
|
-
var sweepSchema =
|
|
5685
|
-
columns:
|
|
5829
|
+
var sweepSchema = import_zod24.z.object({
|
|
5830
|
+
columns: import_zod24.z.number().int().min(1).max(24).default(5),
|
|
5686
5831
|
/** Breathing room around each specimen. */
|
|
5687
|
-
gap:
|
|
5832
|
+
gap: import_zod24.z.number().min(0).max(2).default(0.22),
|
|
5688
5833
|
/** Deformation at the first specimen and at the last. */
|
|
5689
|
-
from:
|
|
5690
|
-
to:
|
|
5834
|
+
from: import_zod24.z.number().min(0).max(1).default(0),
|
|
5835
|
+
to: import_zod24.z.number().min(0).max(1).default(1)
|
|
5691
5836
|
});
|
|
5692
5837
|
var sweep = {
|
|
5693
5838
|
id: "sweep",
|
|
@@ -5711,15 +5856,15 @@ var sweep = {
|
|
|
5711
5856
|
};
|
|
5712
5857
|
}
|
|
5713
5858
|
};
|
|
5714
|
-
var bookSchema =
|
|
5859
|
+
var bookSchema = import_zod24.z.object({
|
|
5715
5860
|
/** How far the outermost page lifts off the block, degrees. */
|
|
5716
|
-
spread:
|
|
5861
|
+
spread: import_zod24.z.number().min(0).max(150).default(55),
|
|
5717
5862
|
/** Fraction of the pages bound to the left. 0 = a one-sided sample book. */
|
|
5718
|
-
split:
|
|
5863
|
+
split: import_zod24.z.number().min(0).max(1).default(0.5),
|
|
5719
5864
|
/** Page thickness — the gap between pages of one block. */
|
|
5720
|
-
lift:
|
|
5865
|
+
lift: import_zod24.z.number().min(1e-3).max(0.05).default(8e-3),
|
|
5721
5866
|
/** How much more a lifted page arcs than one lying flat in the block. */
|
|
5722
|
-
gutter:
|
|
5867
|
+
gutter: import_zod24.z.number().min(0).max(1).default(0.6)
|
|
5723
5868
|
});
|
|
5724
5869
|
var book = {
|
|
5725
5870
|
id: "book",
|
|
@@ -5746,11 +5891,11 @@ var book = {
|
|
|
5746
5891
|
};
|
|
5747
5892
|
}
|
|
5748
5893
|
};
|
|
5749
|
-
var accordionSchema =
|
|
5894
|
+
var accordionSchema = import_zod24.z.object({
|
|
5750
5895
|
/** How far each panel tilts off the strip's line, degrees. 0 = flat, 90 = shut. */
|
|
5751
|
-
angle:
|
|
5896
|
+
angle: import_zod24.z.number().min(0).max(89).default(55),
|
|
5752
5897
|
/** A concertina holds its creases — how much bow the panels keep. */
|
|
5753
|
-
slack:
|
|
5898
|
+
slack: import_zod24.z.number().min(0).max(1).default(0.15)
|
|
5754
5899
|
});
|
|
5755
5900
|
var accordion = {
|
|
5756
5901
|
id: "accordion",
|
|
@@ -5769,16 +5914,16 @@ var accordion = {
|
|
|
5769
5914
|
};
|
|
5770
5915
|
}
|
|
5771
5916
|
};
|
|
5772
|
-
var rackSchema =
|
|
5917
|
+
var rackSchema = import_zod24.z.object({
|
|
5773
5918
|
/** Gap along the row, as a fraction of the paper's width. Under 1 they overlap. */
|
|
5774
|
-
spacing:
|
|
5919
|
+
spacing: import_zod24.z.number().min(0.05).max(2).default(0.82),
|
|
5775
5920
|
/** How far a sheet leans back off vertical, degrees. */
|
|
5776
|
-
lean:
|
|
5921
|
+
lean: import_zod24.z.number().min(0).max(70).default(16),
|
|
5777
5922
|
/** How much that lean differs sheet to sheet — nothing propped is uniform. */
|
|
5778
|
-
vary:
|
|
5923
|
+
vary: import_zod24.z.number().min(0).max(1).default(0.55),
|
|
5779
5924
|
/** Small rotations off square. */
|
|
5780
|
-
sway:
|
|
5781
|
-
seed:
|
|
5925
|
+
sway: import_zod24.z.number().min(0).max(1).default(0.35),
|
|
5926
|
+
seed: import_zod24.z.number().int().min(0).max(9999).default(5)
|
|
5782
5927
|
});
|
|
5783
5928
|
var rack = {
|
|
5784
5929
|
id: "rack",
|
|
@@ -5802,19 +5947,19 @@ var rack = {
|
|
|
5802
5947
|
};
|
|
5803
5948
|
}
|
|
5804
5949
|
};
|
|
5805
|
-
var colonnadeSchema =
|
|
5950
|
+
var colonnadeSchema = import_zod24.z.object({
|
|
5806
5951
|
/** The walk the colonnade is built along — see `stage/path`. */
|
|
5807
5952
|
path: walkPathSchema.default({}),
|
|
5808
5953
|
/** Half-width of the clear aisle: how far each banner stands off the walk line. */
|
|
5809
|
-
aisle:
|
|
5954
|
+
aisle: import_zod24.z.number().min(0.2).max(20).default(2.4),
|
|
5810
5955
|
/** How much that gap opens and closes along the walk. Nothing hung by hand is a corridor. */
|
|
5811
|
-
breathe:
|
|
5956
|
+
breathe: import_zod24.z.number().min(0).max(1).default(0.3),
|
|
5812
5957
|
/** Widest angle a banner turns off square to the aisle, degrees. */
|
|
5813
|
-
twist:
|
|
5958
|
+
twist: import_zod24.z.number().min(0).max(90).default(22),
|
|
5814
5959
|
/** Fraction of the walk left clear at each end, so the figure has somewhere to enter from. */
|
|
5815
|
-
margin:
|
|
5960
|
+
margin: import_zod24.z.number().min(0).max(0.45).default(0.05),
|
|
5816
5961
|
/** Spread of banner heights, 0..1. */
|
|
5817
|
-
rise:
|
|
5962
|
+
rise: import_zod24.z.number().min(0).max(1).default(0.28),
|
|
5818
5963
|
/**
|
|
5819
5964
|
* How far the banners lift off the floor, as a fraction of their height.
|
|
5820
5965
|
*
|
|
@@ -5828,10 +5973,10 @@ var colonnadeSchema = import_zod25.z.object({
|
|
|
5828
5973
|
* The bound used to be 0, so the one thing this option documented itself
|
|
5829
5974
|
* as doing was the one thing it could not do.
|
|
5830
5975
|
*/
|
|
5831
|
-
hover:
|
|
5976
|
+
hover: import_zod24.z.number().min(-0.5).max(1).default(0),
|
|
5832
5977
|
/** Spread of deformation — no two lengths of hung paper drape alike. */
|
|
5833
|
-
drape:
|
|
5834
|
-
seed:
|
|
5978
|
+
drape: import_zod24.z.number().min(0).max(1).default(0.5),
|
|
5979
|
+
seed: import_zod24.z.number().int().min(0).max(9999).default(2)
|
|
5835
5980
|
});
|
|
5836
5981
|
function colonnadeStop(i, n, margin) {
|
|
5837
5982
|
const side = i % 2 === 0 ? 1 : -1;
|
|
@@ -5916,7 +6061,7 @@ function fieldShapeStack(config, progress) {
|
|
|
5916
6061
|
|
|
5917
6062
|
// src/field/fieldGroup.tsx
|
|
5918
6063
|
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
5919
|
-
var scratchObj = new
|
|
6064
|
+
var scratchObj = new THREE13.Object3D();
|
|
5920
6065
|
var scratchAero = { position: [0, 0, 0], rotation: [0, 0, 0] };
|
|
5921
6066
|
var FIELD_SEGMENT_CAP = 48;
|
|
5922
6067
|
var FIELD_AUTO_CEILING = 128;
|
|
@@ -5935,11 +6080,11 @@ function FieldGroup({
|
|
|
5935
6080
|
const stock = getStock(config.stock);
|
|
5936
6081
|
const rig = useLightRig(config.scene.lighting);
|
|
5937
6082
|
const behavior = config.behavior && !config.deformers ? getBehavior(config.behavior.type) : null;
|
|
5938
|
-
const progressRef = (0,
|
|
6083
|
+
const progressRef = (0, import_react13.useRef)(
|
|
5939
6084
|
behavior ? config.behavior[behavior.progressParam] : 0
|
|
5940
6085
|
);
|
|
5941
6086
|
const buildStackAt = (progress) => fieldShapeStack(config, progress);
|
|
5942
|
-
const initialStack = (0,
|
|
6087
|
+
const initialStack = (0, import_react13.useMemo)(
|
|
5943
6088
|
() => buildStackAt(progressRef.current),
|
|
5944
6089
|
[
|
|
5945
6090
|
JSON.stringify(config.behavior ?? null),
|
|
@@ -5948,7 +6093,7 @@ function FieldGroup({
|
|
|
5948
6093
|
]
|
|
5949
6094
|
);
|
|
5950
6095
|
const structureKey = initialStack.map((i) => i.type).join("|");
|
|
5951
|
-
const geometry = (0,
|
|
6096
|
+
const geometry = (0, import_react13.useMemo)(() => {
|
|
5952
6097
|
const floor = stackMinSegments(initialStack, config.sheet);
|
|
5953
6098
|
const want = [0, 0];
|
|
5954
6099
|
for (const p of PROGRESS_SAMPLES2) {
|
|
@@ -5977,28 +6122,28 @@ function FieldGroup({
|
|
|
5977
6122
|
atlasIdx[i] = i;
|
|
5978
6123
|
phase[i] = indices[i] * 0.618034 % 1 * 4;
|
|
5979
6124
|
}
|
|
5980
|
-
geo.setAttribute("aAtlas", new
|
|
5981
|
-
geo.setAttribute("aPhase", new
|
|
5982
|
-
geo.setAttribute("aBias", new
|
|
6125
|
+
geo.setAttribute("aAtlas", new THREE13.InstancedBufferAttribute(atlasIdx, 1));
|
|
6126
|
+
geo.setAttribute("aPhase", new THREE13.InstancedBufferAttribute(phase, 1));
|
|
6127
|
+
geo.setAttribute("aBias", new THREE13.InstancedBufferAttribute(bias, 1));
|
|
5983
6128
|
return geo;
|
|
5984
6129
|
}, [JSON.stringify(config.sheet), structureKey, count, autoCeiling]);
|
|
5985
|
-
(0,
|
|
6130
|
+
(0, import_react13.useEffect)(() => () => geometry.dispose(), [geometry]);
|
|
5986
6131
|
const atlas = useContentAtlas(contents, config.sheet, stock);
|
|
5987
|
-
const shader = (0,
|
|
6132
|
+
const shader = (0, import_react13.useMemo)(() => {
|
|
5988
6133
|
const composed = buildDisplacementGLSL(initialStack, config.sheet);
|
|
5989
6134
|
const uniforms = {};
|
|
5990
6135
|
for (const [name, value] of Object.entries(composed.uniforms)) {
|
|
5991
6136
|
uniforms[name] = {
|
|
5992
|
-
value: Array.isArray(value) && value.length === 2 ? new
|
|
6137
|
+
value: Array.isArray(value) && value.length === 2 ? new THREE13.Vector2(...value) : value
|
|
5993
6138
|
};
|
|
5994
6139
|
}
|
|
5995
6140
|
uniforms.uPlTime = { value: 0 };
|
|
5996
6141
|
uniforms.uAtlas = { value: null };
|
|
5997
|
-
uniforms.uAtlasGrid = { value: new
|
|
6142
|
+
uniforms.uAtlasGrid = { value: new THREE13.Vector2(1, 1) };
|
|
5998
6143
|
uniforms.uBackDarken = {
|
|
5999
6144
|
value: 1 - Math.min(0.45, 0.12 + config.sheet.thickness * 0.9) * stock.opacity
|
|
6000
6145
|
};
|
|
6001
|
-
uniforms.uStockColor = { value: new
|
|
6146
|
+
uniforms.uStockColor = { value: new THREE13.Color(stock.color) };
|
|
6002
6147
|
uniforms.uShowThrough = { value: config.surface.showThrough ?? stock.showThrough };
|
|
6003
6148
|
Object.assign(uniforms, translucencyUniforms(config.surface.translucency ?? stock.translucency, rig));
|
|
6004
6149
|
return {
|
|
@@ -6013,19 +6158,19 @@ function FieldGroup({
|
|
|
6013
6158
|
config.surface.showThrough,
|
|
6014
6159
|
config.surface.translucency
|
|
6015
6160
|
]);
|
|
6016
|
-
(0,
|
|
6161
|
+
(0, import_react13.useEffect)(() => {
|
|
6017
6162
|
const values = translucencyValues(config.surface.translucency ?? stock.translucency, rig);
|
|
6018
6163
|
shader.uniforms.uTranslucency.value = values.translucency;
|
|
6019
6164
|
shader.uniforms.uBackLightDir.value.copy(values.direction);
|
|
6020
6165
|
shader.uniforms.uBackLightColor.value.copy(values.color);
|
|
6021
6166
|
shader.uniforms.uAmbientTransmission.value = values.ambient;
|
|
6022
6167
|
}, [shader, rig, config.surface.translucency, stock.translucency]);
|
|
6023
|
-
(0,
|
|
6168
|
+
(0, import_react13.useEffect)(() => {
|
|
6024
6169
|
if (!atlas) return;
|
|
6025
6170
|
shader.uniforms.uAtlas.value = atlas.texture;
|
|
6026
6171
|
shader.uniforms.uAtlasGrid.value.set(atlas.cols, atlas.rows);
|
|
6027
6172
|
}, [atlas, shader]);
|
|
6028
|
-
(0,
|
|
6173
|
+
(0, import_react13.useEffect)(() => {
|
|
6029
6174
|
if (!behavior || shared.reduced) return;
|
|
6030
6175
|
const state = { p: progressRef.current };
|
|
6031
6176
|
const tween = import_gsap3.gsap.to(state, {
|
|
@@ -6042,8 +6187,8 @@ function FieldGroup({
|
|
|
6042
6187
|
tween.kill();
|
|
6043
6188
|
};
|
|
6044
6189
|
}, [structureKey, shared.reduced]);
|
|
6045
|
-
const meshRef = (0,
|
|
6046
|
-
(0,
|
|
6190
|
+
const meshRef = (0, import_react13.useRef)(null);
|
|
6191
|
+
(0, import_fiber5.useFrame)(({ clock }) => {
|
|
6047
6192
|
const mesh = meshRef.current;
|
|
6048
6193
|
if (!mesh) return;
|
|
6049
6194
|
const elapsed = clock.elapsedTime - Math.max(shared.mountTimeRef.current, 0);
|
|
@@ -6053,7 +6198,7 @@ function FieldGroup({
|
|
|
6053
6198
|
for (const [name, value] of Object.entries(values)) {
|
|
6054
6199
|
const uniform = shader.uniforms[name];
|
|
6055
6200
|
if (!uniform) continue;
|
|
6056
|
-
if (uniform.value instanceof
|
|
6201
|
+
if (uniform.value instanceof THREE13.Vector2 && Array.isArray(value)) {
|
|
6057
6202
|
uniform.value.set(value[0], value[1]);
|
|
6058
6203
|
} else {
|
|
6059
6204
|
uniform.value = value;
|
|
@@ -6137,13 +6282,13 @@ function FieldGroup({
|
|
|
6137
6282
|
children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
6138
6283
|
import_three_custom_shader_material2.default,
|
|
6139
6284
|
{
|
|
6140
|
-
baseMaterial:
|
|
6285
|
+
baseMaterial: THREE13.MeshStandardMaterial,
|
|
6141
6286
|
vertexShader: shader.vertexShader,
|
|
6142
6287
|
fragmentShader: shader.fragmentShader,
|
|
6143
6288
|
uniforms: shader.uniforms,
|
|
6144
6289
|
roughness: stock.roughness,
|
|
6145
6290
|
metalness: 0,
|
|
6146
|
-
side:
|
|
6291
|
+
side: THREE13.DoubleSide
|
|
6147
6292
|
},
|
|
6148
6293
|
`${structureKey}:${count}`
|
|
6149
6294
|
)
|
|
@@ -6189,8 +6334,8 @@ var easeOut = (t) => 1 - (1 - t) ** 3;
|
|
|
6189
6334
|
var easeInOut = (t) => t < 0.5 ? 2 * t * t : 1 - (-2 * t + 2) ** 2 / 2;
|
|
6190
6335
|
|
|
6191
6336
|
// src/field/backingSheet.tsx
|
|
6192
|
-
var
|
|
6193
|
-
var
|
|
6337
|
+
var THREE14 = __toESM(require("three"), 1);
|
|
6338
|
+
var import_react14 = require("react");
|
|
6194
6339
|
|
|
6195
6340
|
// src/content/backing.ts
|
|
6196
6341
|
function silhouetteRects(o, count) {
|
|
@@ -6263,7 +6408,7 @@ function BackingSheet({
|
|
|
6263
6408
|
removed
|
|
6264
6409
|
}) {
|
|
6265
6410
|
const { width, height } = sheetBackingSize(options);
|
|
6266
|
-
const canvas = (0,
|
|
6411
|
+
const canvas = (0, import_react14.useMemo)(() => {
|
|
6267
6412
|
if (typeof document === "undefined") return null;
|
|
6268
6413
|
const c = document.createElement("canvas");
|
|
6269
6414
|
const scale = Math.min(1024, Math.round(360 * Math.max(width, height))) / Math.max(width, height);
|
|
@@ -6271,14 +6416,14 @@ function BackingSheet({
|
|
|
6271
6416
|
c.height = Math.max(2, Math.round(height * scale));
|
|
6272
6417
|
return c;
|
|
6273
6418
|
}, [width, height]);
|
|
6274
|
-
const texture = (0,
|
|
6419
|
+
const texture = (0, import_react14.useMemo)(() => canvas ? new THREE14.CanvasTexture(canvas) : null, [canvas]);
|
|
6275
6420
|
const removedKey = [...removed].sort((a, b) => a - b).join(",");
|
|
6276
|
-
(0,
|
|
6421
|
+
(0, import_react14.useEffect)(() => {
|
|
6277
6422
|
if (!canvas || !texture) return;
|
|
6278
6423
|
drawBacking(canvas, { options, count, tint: BACKING_TINT, removed });
|
|
6279
6424
|
texture.needsUpdate = true;
|
|
6280
6425
|
}, [canvas, texture, JSON.stringify(options), count, removedKey]);
|
|
6281
|
-
(0,
|
|
6426
|
+
(0, import_react14.useEffect)(() => () => texture?.dispose(), [texture]);
|
|
6282
6427
|
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("mesh", { receiveShadow: true, children: [
|
|
6283
6428
|
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("planeGeometry", { args: [width, height] }),
|
|
6284
6429
|
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("meshStandardMaterial", { map: texture, color: "#ffffff", roughness: 0.92, metalness: 0 })
|
|
@@ -6286,10 +6431,10 @@ function BackingSheet({
|
|
|
6286
6431
|
}
|
|
6287
6432
|
|
|
6288
6433
|
// src/field/interactiveField.tsx
|
|
6289
|
-
var
|
|
6434
|
+
var THREE15 = __toESM(require("three"), 1);
|
|
6290
6435
|
var import_gsap4 = require("gsap");
|
|
6291
|
-
var
|
|
6292
|
-
var
|
|
6436
|
+
var import_fiber6 = require("@react-three/fiber");
|
|
6437
|
+
var import_react15 = require("react");
|
|
6293
6438
|
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
6294
6439
|
var PICK_BEHAVIORS = /* @__PURE__ */ new Set(["peel", "carry"]);
|
|
6295
6440
|
function InteractiveField(props) {
|
|
@@ -6297,15 +6442,15 @@ function InteractiveField(props) {
|
|
|
6297
6442
|
const total = papers.length;
|
|
6298
6443
|
const layout = getLayout(layoutId);
|
|
6299
6444
|
const reduced = usePrefersReducedMotion(props.reducedMotion);
|
|
6300
|
-
const contextRegistry = (0,
|
|
6301
|
-
const registry4 = (0,
|
|
6302
|
-
const camera = (0,
|
|
6303
|
-
const gl = (0,
|
|
6304
|
-
const controls = (0,
|
|
6305
|
-
const [removed, setRemoved] = (0,
|
|
6306
|
-
const [slotPatches, setSlotPatches] = (0,
|
|
6307
|
-
const [slotStates, setSlotStates] = (0,
|
|
6308
|
-
const slotConfigs = (0,
|
|
6445
|
+
const contextRegistry = (0, import_react15.useContext)(DropZoneContext);
|
|
6446
|
+
const registry4 = (0, import_react15.useMemo)(() => contextRegistry ?? new DropZoneRegistry(), [contextRegistry]);
|
|
6447
|
+
const camera = (0, import_fiber6.useThree)((s) => s.camera);
|
|
6448
|
+
const gl = (0, import_fiber6.useThree)((s) => s.gl);
|
|
6449
|
+
const controls = (0, import_fiber6.useThree)((s) => s.controls);
|
|
6450
|
+
const [removed, setRemoved] = (0, import_react15.useState)(EMPTY_SET);
|
|
6451
|
+
const [slotPatches, setSlotPatches] = (0, import_react15.useState)({});
|
|
6452
|
+
const [slotStates, setSlotStates] = (0, import_react15.useState)({});
|
|
6453
|
+
const slotConfigs = (0, import_react15.useMemo)(
|
|
6309
6454
|
() => papers.map((slot, i) => {
|
|
6310
6455
|
const config = resolveFieldSlotConfig(slot, fallback, i, layoutId, layoutOptions);
|
|
6311
6456
|
const patch = slotPatches[i];
|
|
@@ -6319,14 +6464,14 @@ function InteractiveField(props) {
|
|
|
6319
6464
|
slotPatches
|
|
6320
6465
|
]
|
|
6321
6466
|
);
|
|
6322
|
-
const poses = (0,
|
|
6467
|
+
const poses = (0, import_react15.useMemo)(
|
|
6323
6468
|
() => slotConfigs.map((_, i) => layout.pose(i, total, layoutOptions, 0, props.sheet)),
|
|
6324
6469
|
[layoutId, JSON.stringify(layoutOptions), total, props.sheet.width, props.sheet.height]
|
|
6325
6470
|
);
|
|
6326
|
-
const groupRefs = (0,
|
|
6327
|
-
const handleRefs = (0,
|
|
6328
|
-
const pressRef = (0,
|
|
6329
|
-
const carriedRef = (0,
|
|
6471
|
+
const groupRefs = (0, import_react15.useRef)([]);
|
|
6472
|
+
const handleRefs = (0, import_react15.useRef)([]);
|
|
6473
|
+
const pressRef = (0, import_react15.useRef)(null);
|
|
6474
|
+
const carriedRef = (0, import_react15.useRef)(null);
|
|
6330
6475
|
const zonesLive = () => [...props.zones ?? [], ...registry4.list()];
|
|
6331
6476
|
const slotName = (i) => {
|
|
6332
6477
|
const preset = papers[i]?.preset ?? fallback;
|
|
@@ -6339,10 +6484,10 @@ function InteractiveField(props) {
|
|
|
6339
6484
|
}
|
|
6340
6485
|
props.onSlotStateChange?.(i, state);
|
|
6341
6486
|
};
|
|
6342
|
-
const raycaster = (0,
|
|
6343
|
-
const planeScratch = (0,
|
|
6344
|
-
const pointScratch = (0,
|
|
6345
|
-
const ndcScratch = (0,
|
|
6487
|
+
const raycaster = (0, import_react15.useMemo)(() => new THREE15.Raycaster(), []);
|
|
6488
|
+
const planeScratch = (0, import_react15.useMemo)(() => new THREE15.Plane(new THREE15.Vector3(0, 0, 1), 0), []);
|
|
6489
|
+
const pointScratch = (0, import_react15.useMemo)(() => new THREE15.Vector3(), []);
|
|
6490
|
+
const ndcScratch = (0, import_react15.useMemo)(() => new THREE15.Vector2(), []);
|
|
6346
6491
|
const planePoint = (clientX, clientY, planeZ) => {
|
|
6347
6492
|
const rect = gl.domElement.getBoundingClientRect();
|
|
6348
6493
|
ndcScratch.set(
|
|
@@ -6472,7 +6617,7 @@ function InteractiveField(props) {
|
|
|
6472
6617
|
import_gsap4.gsap.to(group.rotation, { x: home.rotation[0], y: home.rotation[1], z: home.rotation[2], duration });
|
|
6473
6618
|
import_gsap4.gsap.to(group.scale, { x: home.scale, y: home.scale, z: home.scale, duration: duration * 0.5 });
|
|
6474
6619
|
};
|
|
6475
|
-
const onPointerMoveRef = (0,
|
|
6620
|
+
const onPointerMoveRef = (0, import_react15.useRef)(() => {
|
|
6476
6621
|
});
|
|
6477
6622
|
onPointerMoveRef.current = (e) => {
|
|
6478
6623
|
const press = pressRef.current;
|
|
@@ -6496,7 +6641,7 @@ function InteractiveField(props) {
|
|
|
6496
6641
|
pick(slot, hit[0], hit[1], pointerId);
|
|
6497
6642
|
}
|
|
6498
6643
|
};
|
|
6499
|
-
const onPointerUpRef = (0,
|
|
6644
|
+
const onPointerUpRef = (0, import_react15.useRef)(() => {
|
|
6500
6645
|
});
|
|
6501
6646
|
onPointerUpRef.current = (e) => {
|
|
6502
6647
|
pressRef.current = null;
|
|
@@ -6505,12 +6650,12 @@ function InteractiveField(props) {
|
|
|
6505
6650
|
if (carried.pointerId !== null && e.pointerId !== carried.pointerId) return;
|
|
6506
6651
|
const name = slotName(carried.slot);
|
|
6507
6652
|
const zone = zonesLive().find(
|
|
6508
|
-
(
|
|
6653
|
+
(z25) => zoneContains(z25, carried.x.value, carried.y.value) && zoneAccepts(z25, name)
|
|
6509
6654
|
);
|
|
6510
6655
|
if (zone) settleInto(carried, zone);
|
|
6511
6656
|
else returnHome(carried);
|
|
6512
6657
|
};
|
|
6513
|
-
(0,
|
|
6658
|
+
(0, import_react15.useEffect)(() => {
|
|
6514
6659
|
const move = (e) => onPointerMoveRef.current(e);
|
|
6515
6660
|
const up = (e) => onPointerUpRef.current(e);
|
|
6516
6661
|
window.addEventListener("pointermove", move);
|
|
@@ -6520,7 +6665,7 @@ function InteractiveField(props) {
|
|
|
6520
6665
|
window.removeEventListener("pointerup", up);
|
|
6521
6666
|
};
|
|
6522
6667
|
}, []);
|
|
6523
|
-
(0,
|
|
6668
|
+
(0, import_fiber6.useFrame)((_, delta) => {
|
|
6524
6669
|
const carried = carriedRef.current;
|
|
6525
6670
|
if (!carried || carried.settling) return;
|
|
6526
6671
|
const group = groupRefs.current[carried.slot];
|
|
@@ -6546,19 +6691,19 @@ function InteractiveField(props) {
|
|
|
6546
6691
|
group.position.z = carried.homePose.position[2] + 0.15;
|
|
6547
6692
|
handle.set("drive", carryDrive(speed));
|
|
6548
6693
|
const lag = 0.25;
|
|
6549
|
-
group.rotation.y += (
|
|
6550
|
-
group.rotation.x += (
|
|
6694
|
+
group.rotation.y += (THREE15.MathUtils.clamp(-vx * lag, -0.6, 0.6) - group.rotation.y) * 0.12;
|
|
6695
|
+
group.rotation.x += (THREE15.MathUtils.clamp(vy * lag * 0.7, -0.5, 0.5) - group.rotation.x) * 0.12;
|
|
6551
6696
|
}
|
|
6552
6697
|
const name = slotName(carried.slot);
|
|
6553
6698
|
const zone = zonesLive().find(
|
|
6554
|
-
(
|
|
6699
|
+
(z25) => zoneContains(z25, group.position.x, group.position.y) && zoneAccepts(z25, name)
|
|
6555
6700
|
);
|
|
6556
6701
|
registry4.setHovered(zone?.id ?? null);
|
|
6557
6702
|
const targetScale = (zone ? 1.03 : 1) * carried.homePose.scale;
|
|
6558
6703
|
group.scale.x += (targetScale - group.scale.x) * 0.15;
|
|
6559
6704
|
group.scale.y = group.scale.z = group.scale.x;
|
|
6560
6705
|
});
|
|
6561
|
-
const a11yImplRef = (0,
|
|
6706
|
+
const a11yImplRef = (0, import_react15.useRef)(null);
|
|
6562
6707
|
a11yImplRef.current = {
|
|
6563
6708
|
pick: (slot) => {
|
|
6564
6709
|
const home = poses[slot];
|
|
@@ -6567,7 +6712,7 @@ function InteractiveField(props) {
|
|
|
6567
6712
|
},
|
|
6568
6713
|
placeAtZone: (slot, zoneId) => {
|
|
6569
6714
|
const carried = carriedRef.current;
|
|
6570
|
-
const zone = zonesLive().find((
|
|
6715
|
+
const zone = zonesLive().find((z25) => z25.id === zoneId);
|
|
6571
6716
|
const group = groupRefs.current[slot];
|
|
6572
6717
|
if (!carried || carried.slot !== slot || !zone || !group) return;
|
|
6573
6718
|
group.position.x = zone.bounds.position[0];
|
|
@@ -6580,10 +6725,10 @@ function InteractiveField(props) {
|
|
|
6580
6725
|
const carried = carriedRef.current;
|
|
6581
6726
|
if (carried && carried.slot === slot && !carried.settling) returnHome(carried);
|
|
6582
6727
|
},
|
|
6583
|
-
zoneIds: () => zonesLive().map((
|
|
6728
|
+
zoneIds: () => zonesLive().map((z25) => z25.id),
|
|
6584
6729
|
slotState: (slot) => slotStates[slot] ?? "rest"
|
|
6585
6730
|
};
|
|
6586
|
-
(0,
|
|
6731
|
+
(0, import_react15.useEffect)(() => {
|
|
6587
6732
|
const ref = props.a11yRef;
|
|
6588
6733
|
if (!ref) return;
|
|
6589
6734
|
ref.current = {
|
|
@@ -6636,7 +6781,7 @@ function InteractiveField(props) {
|
|
|
6636
6781
|
}
|
|
6637
6782
|
|
|
6638
6783
|
// src/field/keyboardMirror.tsx
|
|
6639
|
-
var
|
|
6784
|
+
var import_react16 = require("react");
|
|
6640
6785
|
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
6641
6786
|
function fieldKeyboardStep(carry2, slot, key, controller) {
|
|
6642
6787
|
if (!carry2) {
|
|
@@ -6682,7 +6827,7 @@ function FieldKeyboardMirror({
|
|
|
6682
6827
|
papers,
|
|
6683
6828
|
controller
|
|
6684
6829
|
}) {
|
|
6685
|
-
const [carrying, setCarrying] = (0,
|
|
6830
|
+
const [carrying, setCarrying] = (0, import_react16.useState)(null);
|
|
6686
6831
|
const paperLabel = (slot, i) => {
|
|
6687
6832
|
try {
|
|
6688
6833
|
const config = resolveConfig({ preset: slot.preset });
|
|
@@ -6785,16 +6930,16 @@ function fitCamera(layout, n, options, sheet2, fovDeg, aspect, margin = 1.06) {
|
|
|
6785
6930
|
|
|
6786
6931
|
// src/PaperField.tsx
|
|
6787
6932
|
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
6788
|
-
var PaperFieldMesh = (0,
|
|
6933
|
+
var PaperFieldMesh = (0, import_react17.forwardRef)(
|
|
6789
6934
|
function PaperFieldMesh2(props, ref) {
|
|
6790
6935
|
const reduced = usePrefersReducedMotion(props.reducedMotion);
|
|
6791
|
-
const papers = (0,
|
|
6936
|
+
const papers = (0, import_react17.useMemo)(
|
|
6792
6937
|
() => effectiveFieldPapers(props.papers, props.images),
|
|
6793
6938
|
[props.papers, props.images]
|
|
6794
6939
|
);
|
|
6795
6940
|
const stablePapers = useStable(papers);
|
|
6796
6941
|
const stablePreset = useStable(props.preset ?? null);
|
|
6797
|
-
const groups = (0,
|
|
6942
|
+
const groups = (0, import_react17.useMemo)(
|
|
6798
6943
|
() => groupFieldPapers(stablePapers, stablePreset ?? void 0),
|
|
6799
6944
|
[stablePapers, stablePreset]
|
|
6800
6945
|
);
|
|
@@ -6803,22 +6948,22 @@ var PaperFieldMesh = (0, import_react16.forwardRef)(
|
|
|
6803
6948
|
const layout = getLayout(layoutId);
|
|
6804
6949
|
const firstSheet = groups[0]?.config.sheet;
|
|
6805
6950
|
const stableLayoutOptions = useStable(props.layoutOptions ?? {});
|
|
6806
|
-
const layoutOptions = (0,
|
|
6951
|
+
const layoutOptions = (0, import_react17.useMemo)(
|
|
6807
6952
|
// Sheet grids size their cells from the papers themselves — gutter is
|
|
6808
6953
|
// then literally the spacing between stamps (explicit cell dims win).
|
|
6809
6954
|
() => resolveLayoutOptions(layoutId, layout, stableLayoutOptions, firstSheet),
|
|
6810
6955
|
[layoutId, stableLayoutOptions, firstSheet?.width, firstSheet?.height]
|
|
6811
6956
|
);
|
|
6812
|
-
const phaseRef = (0,
|
|
6813
|
-
const dragVelRef = (0,
|
|
6814
|
-
const mountTimeRef = (0,
|
|
6815
|
-
const morphRef = (0,
|
|
6816
|
-
const prevLayout = (0,
|
|
6817
|
-
const gl = (0,
|
|
6957
|
+
const phaseRef = (0, import_react17.useRef)(0);
|
|
6958
|
+
const dragVelRef = (0, import_react17.useRef)(0);
|
|
6959
|
+
const mountTimeRef = (0, import_react17.useRef)(-1);
|
|
6960
|
+
const morphRef = (0, import_react17.useRef)({ from: null, t: 1 });
|
|
6961
|
+
const prevLayout = (0, import_react17.useRef)({ id: layoutId, options: layoutOptions });
|
|
6962
|
+
const gl = (0, import_fiber7.useThree)((s) => s.gl);
|
|
6818
6963
|
const driver = reduced ? "none" : props.motion?.driver ?? "autoplay";
|
|
6819
6964
|
const speed = props.motion?.speed ?? 0.5;
|
|
6820
6965
|
const entranceType = reduced ? "none" : props.entrance?.type ?? "rise";
|
|
6821
|
-
(0,
|
|
6966
|
+
(0, import_react17.useEffect)(() => {
|
|
6822
6967
|
const prev = prevLayout.current;
|
|
6823
6968
|
if (prev.id !== layoutId || JSON.stringify(prev.options) !== JSON.stringify(layoutOptions)) {
|
|
6824
6969
|
morphRef.current = { from: prev, t: 0 };
|
|
@@ -6826,7 +6971,7 @@ var PaperFieldMesh = (0, import_react16.forwardRef)(
|
|
|
6826
6971
|
prevLayout.current = { id: layoutId, options: layoutOptions };
|
|
6827
6972
|
}
|
|
6828
6973
|
}, [layoutId, layoutOptions]);
|
|
6829
|
-
(0,
|
|
6974
|
+
(0, import_react17.useEffect)(() => {
|
|
6830
6975
|
if (driver !== "drag") return;
|
|
6831
6976
|
const el = gl.domElement;
|
|
6832
6977
|
let lastX = null;
|
|
@@ -6852,7 +6997,7 @@ var PaperFieldMesh = (0, import_react16.forwardRef)(
|
|
|
6852
6997
|
window.removeEventListener("pointerup", up);
|
|
6853
6998
|
};
|
|
6854
6999
|
}, [driver, gl]);
|
|
6855
|
-
(0,
|
|
7000
|
+
(0, import_fiber7.useFrame)(({ clock }, delta) => {
|
|
6856
7001
|
if (mountTimeRef.current < 0) mountTimeRef.current = clock.elapsedTime;
|
|
6857
7002
|
if (driver === "autoplay") phaseRef.current += delta * speed * 0.02;
|
|
6858
7003
|
if (driver === "drag") {
|
|
@@ -6910,14 +7055,14 @@ var PaperFieldMesh = (0, import_react16.forwardRef)(
|
|
|
6910
7055
|
}
|
|
6911
7056
|
);
|
|
6912
7057
|
function FitCamera(meshProps) {
|
|
6913
|
-
const camera = (0,
|
|
6914
|
-
const width = (0,
|
|
6915
|
-
const height = (0,
|
|
7058
|
+
const camera = (0, import_fiber7.useThree)((s) => s.camera);
|
|
7059
|
+
const width = (0, import_fiber7.useThree)((s) => s.size.width);
|
|
7060
|
+
const height = (0, import_fiber7.useThree)((s) => s.size.height);
|
|
6916
7061
|
const papersProp = useStable(meshProps.papers ?? null);
|
|
6917
7062
|
const imagesProp = useStable(meshProps.images ?? null);
|
|
6918
7063
|
const presetProp = useStable(meshProps.preset ?? null);
|
|
6919
7064
|
const optionsProp = useStable(meshProps.layoutOptions ?? {});
|
|
6920
|
-
const field = (0,
|
|
7065
|
+
const field = (0, import_react17.useMemo)(() => {
|
|
6921
7066
|
const papers = effectiveFieldPapers(papersProp ?? void 0, imagesProp ?? void 0);
|
|
6922
7067
|
const layoutId = meshProps.layout ?? "ring";
|
|
6923
7068
|
const layout = getLayout(layoutId);
|
|
@@ -6925,8 +7070,8 @@ function FitCamera(meshProps) {
|
|
|
6925
7070
|
const options = resolveLayoutOptions(layoutId, layout, optionsProp, sheet2);
|
|
6926
7071
|
return { layout, n: papers.length, options, sheet: sheet2 ?? DEFAULT_SHEET };
|
|
6927
7072
|
}, [papersProp, imagesProp, presetProp, meshProps.layout, optionsProp]);
|
|
6928
|
-
(0,
|
|
6929
|
-
if (!(camera instanceof
|
|
7073
|
+
(0, import_react17.useEffect)(() => {
|
|
7074
|
+
if (!(camera instanceof THREE16.PerspectiveCamera)) return;
|
|
6930
7075
|
const { position, target } = fitCamera(
|
|
6931
7076
|
field.layout,
|
|
6932
7077
|
field.n,
|
|
@@ -6941,33 +7086,25 @@ function FitCamera(meshProps) {
|
|
|
6941
7086
|
}, [camera, width, height, field]);
|
|
6942
7087
|
return null;
|
|
6943
7088
|
}
|
|
6944
|
-
var PaperField = (0,
|
|
6945
|
-
const
|
|
6946
|
-
const
|
|
6947
|
-
const
|
|
7089
|
+
var PaperField = (0, import_react17.forwardRef)(function PaperField2({ children, className, style, scene, ...meshProps }, ref) {
|
|
7090
|
+
const rig = sceneSchema.parse(scene ?? {});
|
|
7091
|
+
const registry4 = (0, import_react17.useMemo)(() => new DropZoneRegistry(), []);
|
|
7092
|
+
const a11yRef = (0, import_react17.useRef)(null);
|
|
7093
|
+
const papers = (0, import_react17.useMemo)(
|
|
6948
7094
|
() => effectiveFieldPapers(meshProps.papers, meshProps.images),
|
|
6949
7095
|
[meshProps.papers, meshProps.images]
|
|
6950
7096
|
);
|
|
6951
7097
|
const stablePapers = useStable(papers);
|
|
6952
7098
|
const stablePreset = useStable(meshProps.preset ?? null);
|
|
6953
|
-
const interactive = (0,
|
|
7099
|
+
const interactive = (0, import_react17.useMemo)(
|
|
6954
7100
|
() => fieldIsInteractive(stablePapers, stablePreset ?? void 0, meshProps.interactive),
|
|
6955
7101
|
[stablePapers, stablePreset, meshProps.interactive]
|
|
6956
7102
|
);
|
|
6957
7103
|
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className, style: { width: "100%", height: "100%", ...style }, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(DropZoneContext.Provider, { value: registry4, children: [
|
|
6958
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
7104
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_fiber7.Canvas, { shadows: true, camera: { position: [0, 0.6, 5.2], fov: 45 }, dpr: [1, 2], children: [
|
|
6959
7105
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(FitCamera, { ...meshProps }),
|
|
6960
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
6961
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
6962
|
-
"directionalLight",
|
|
6963
|
-
{
|
|
6964
|
-
position: [3, 5, 4],
|
|
6965
|
-
intensity: 1.4,
|
|
6966
|
-
castShadow: true,
|
|
6967
|
-
"shadow-mapSize": [1024, 1024],
|
|
6968
|
-
"shadow-normalBias": 0.05
|
|
6969
|
-
}
|
|
6970
|
-
),
|
|
7106
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(PaperBackdrop, { backdrop: rig.backdrop }),
|
|
7107
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(PaperLighting, { preset: rig.lighting, light: rig.light, floor: -2.4, scale: 14 }),
|
|
6971
7108
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(PaperFieldMesh, { ref, a11yControllerRef: a11yRef, ...meshProps }),
|
|
6972
7109
|
children
|
|
6973
7110
|
] }),
|
|
@@ -6975,307 +7112,6 @@ var PaperField = (0, import_react16.forwardRef)(function PaperField2({ children,
|
|
|
6975
7112
|
] }) });
|
|
6976
7113
|
});
|
|
6977
7114
|
|
|
6978
|
-
// src/field/parity.ts
|
|
6979
|
-
var THREE16 = __toESM(require("three"), 1);
|
|
6980
|
-
var GRID = 48;
|
|
6981
|
-
var PARITY_EPSILON = 5e-4;
|
|
6982
|
-
var parityCases = [
|
|
6983
|
-
{
|
|
6984
|
-
name: "roll: defaults",
|
|
6985
|
-
stack: [{ type: "roll", options: { angle: 90, boundary: 0, radius: 0.12, spiral: 0.015 } }],
|
|
6986
|
-
sheet: { width: 1, height: 1.4 },
|
|
6987
|
-
t: 0
|
|
6988
|
-
},
|
|
6989
|
-
{
|
|
6990
|
-
name: "roll: tight receipt roll, rolling down",
|
|
6991
|
-
stack: [{ type: "roll", options: { angle: 270, boundary: -0.4, radius: 0.07, spiral: 0.02 } }],
|
|
6992
|
-
sheet: { width: 1, height: 2.6 },
|
|
6993
|
-
t: 0
|
|
6994
|
-
},
|
|
6995
|
-
{
|
|
6996
|
-
name: "curl: bottom-right peel",
|
|
6997
|
-
stack: [{ type: "curl", options: { corner: "bottom-right", amount: 0.45, radius: 0.2, skew: 0 } }],
|
|
6998
|
-
sheet: { width: 1.5, height: 1 },
|
|
6999
|
-
t: 0
|
|
7000
|
-
},
|
|
7001
|
-
{
|
|
7002
|
-
name: "curl: skewed top-left",
|
|
7003
|
-
stack: [{ type: "curl", options: { corner: "top-left", amount: 0.7, radius: 0.3, skew: 15 } }],
|
|
7004
|
-
sheet: { width: 1, height: 1 },
|
|
7005
|
-
t: 0
|
|
7006
|
-
},
|
|
7007
|
-
{
|
|
7008
|
-
name: "bend: positive arc at an angle",
|
|
7009
|
-
stack: [{ type: "bend", options: { curvature: 1.2, angle: 33 } }],
|
|
7010
|
-
sheet: { width: 1, height: 1.4 },
|
|
7011
|
-
t: 0
|
|
7012
|
-
},
|
|
7013
|
-
{
|
|
7014
|
-
/**
|
|
7015
|
-
* The gentle end, which nothing used to cover: the gate only ever tried
|
|
7016
|
-
* |curvature| ≥ 0.6, and `photo-print` — the field starter preset — bends
|
|
7017
|
-
* at 0.35. That band is where the arc's float32 evaluation loses its
|
|
7018
|
-
* cancellation, and where the two paths were 6e-4 apart until `bend` was
|
|
7019
|
-
* rewritten in cancellation-free form. Keep a case down here.
|
|
7020
|
-
*/
|
|
7021
|
-
name: "bend: barely-there arc (the band photo-print lives in)",
|
|
7022
|
-
stack: [{ type: "bend", options: { curvature: 0.35, angle: 0 } }],
|
|
7023
|
-
sheet: { width: 1.2, height: 0.9 },
|
|
7024
|
-
t: 0
|
|
7025
|
-
},
|
|
7026
|
-
{
|
|
7027
|
-
name: "bend: the gentlest arc the schema allows",
|
|
7028
|
-
stack: [{ type: "bend", options: { curvature: 0.02, angle: 61 } }],
|
|
7029
|
-
sheet: { width: 2, height: 2.6 },
|
|
7030
|
-
t: 0
|
|
7031
|
-
},
|
|
7032
|
-
{
|
|
7033
|
-
name: "bend: negative arc",
|
|
7034
|
-
stack: [{ type: "bend", options: { curvature: -0.8, angle: 0 } }],
|
|
7035
|
-
sheet: { width: 1, height: 1.4 },
|
|
7036
|
-
t: 0
|
|
7037
|
-
},
|
|
7038
|
-
{
|
|
7039
|
-
name: "fold: 90\xB0 hinge",
|
|
7040
|
-
stack: [{ type: "fold", options: { angle: 90, offset: 0, foldAngle: 90, radius: 0.06 } }],
|
|
7041
|
-
sheet: { width: 1, height: 1.4 },
|
|
7042
|
-
t: 0
|
|
7043
|
-
},
|
|
7044
|
-
{
|
|
7045
|
-
name: "fold: deep fold, travelling down",
|
|
7046
|
-
stack: [{ type: "fold", options: { angle: 270, offset: 0.2, foldAngle: 165, radius: 0.04 } }],
|
|
7047
|
-
sheet: { width: 1, height: 1.4 },
|
|
7048
|
-
t: 0
|
|
7049
|
-
},
|
|
7050
|
-
{
|
|
7051
|
-
name: "wave: free ripple at t=1.234",
|
|
7052
|
-
stack: [
|
|
7053
|
-
{
|
|
7054
|
-
type: "wave",
|
|
7055
|
-
options: { amplitude: 0.05, wavelength: 0.5, speed: 1, angle: 20, pinnedEdge: "none" }
|
|
7056
|
-
}
|
|
7057
|
-
],
|
|
7058
|
-
sheet: { width: 1, height: 1 },
|
|
7059
|
-
t: 1.234
|
|
7060
|
-
},
|
|
7061
|
-
{
|
|
7062
|
-
name: "wave: pinned top at t=2.5",
|
|
7063
|
-
stack: [
|
|
7064
|
-
{
|
|
7065
|
-
type: "wave",
|
|
7066
|
-
options: { amplitude: 0.04, wavelength: 0.4, speed: 1.5, angle: 80, pinnedEdge: "top" }
|
|
7067
|
-
}
|
|
7068
|
-
],
|
|
7069
|
-
sheet: { width: 1.2, height: 1.5 },
|
|
7070
|
-
t: 2.5
|
|
7071
|
-
},
|
|
7072
|
-
{
|
|
7073
|
-
name: "drape: banner hung from the top",
|
|
7074
|
-
stack: [
|
|
7075
|
-
{
|
|
7076
|
-
type: "drape",
|
|
7077
|
-
options: { amplitude: 0.17, folds: 5, falloff: 1.6, irregular: 0.45, gather: 0.5, pinnedEdge: "top" }
|
|
7078
|
-
}
|
|
7079
|
-
],
|
|
7080
|
-
sheet: { width: 1.5, height: 8.5 },
|
|
7081
|
-
t: 0
|
|
7082
|
-
},
|
|
7083
|
-
{
|
|
7084
|
-
name: "drape: deep irregular folds pinned at the bottom",
|
|
7085
|
-
stack: [
|
|
7086
|
-
{
|
|
7087
|
-
type: "drape",
|
|
7088
|
-
options: { amplitude: 0.55, folds: 11, falloff: 0.4, irregular: 1, gather: 1, pinnedEdge: "bottom" }
|
|
7089
|
-
}
|
|
7090
|
-
],
|
|
7091
|
-
sheet: { width: 2.2, height: 3 },
|
|
7092
|
-
t: 0
|
|
7093
|
-
},
|
|
7094
|
-
{
|
|
7095
|
-
name: "crumple: defaults",
|
|
7096
|
-
stack: [{ type: "crumple", options: { amount: 0.35, scale: 3, pull: 0.4, seed: 0 } }],
|
|
7097
|
-
sheet: { width: 1, height: 1.4 },
|
|
7098
|
-
t: 0
|
|
7099
|
-
},
|
|
7100
|
-
{
|
|
7101
|
-
// The adversarial one. `fract` is a sawtooth, so the two halves disagree
|
|
7102
|
-
// hardest where a crease lands exactly on a sample — a fine scale and a
|
|
7103
|
-
// seed whose fold directions are near-axis puts the most creases in
|
|
7104
|
-
// reach of the grid.
|
|
7105
|
-
name: "crumple: fully crushed, fine creases, off-axis seed",
|
|
7106
|
-
stack: [{ type: "crumple", options: { amount: 1, scale: 7.5, pull: 1, seed: 5 } }],
|
|
7107
|
-
sheet: { width: 1.3, height: 0.9 },
|
|
7108
|
-
t: 0
|
|
7109
|
-
},
|
|
7110
|
-
{
|
|
7111
|
-
// Crush then curl, which is the order the crumple BEHAVIOR stacks them:
|
|
7112
|
-
// the creases have to be placed on the flat sheet, not on a bent one.
|
|
7113
|
-
name: "stacked: crumple \u2218 bend (the crumple behavior)",
|
|
7114
|
-
stack: [
|
|
7115
|
-
{ type: "crumple", options: { amount: 0.62, scale: 3.3, pull: 0.5, seed: 2 } },
|
|
7116
|
-
{ type: "bend", options: { curvature: 0.31, angle: 35 } }
|
|
7117
|
-
],
|
|
7118
|
-
sheet: { width: 1.1, height: 1.4 },
|
|
7119
|
-
t: 0
|
|
7120
|
-
},
|
|
7121
|
-
{
|
|
7122
|
-
name: "stacked: letter-fold pair (fold \u2218 fold)",
|
|
7123
|
-
stack: [
|
|
7124
|
-
{ type: "fold", options: { angle: 270, offset: 0.2333, foldAngle: 120, radius: 0.05 } },
|
|
7125
|
-
{ type: "fold", options: { angle: 90, offset: 0.2333, foldAngle: 100, radius: 0.08 } }
|
|
7126
|
-
],
|
|
7127
|
-
sheet: { width: 1, height: 1.4 },
|
|
7128
|
-
t: 0
|
|
7129
|
-
},
|
|
7130
|
-
{
|
|
7131
|
-
name: "stacked: bend \u2218 roll \u2218 wave",
|
|
7132
|
-
stack: [
|
|
7133
|
-
{ type: "bend", options: { curvature: 0.6, angle: 0 } },
|
|
7134
|
-
{ type: "roll", options: { angle: 90, boundary: 0.1, radius: 0.15, spiral: 0 } },
|
|
7135
|
-
{
|
|
7136
|
-
type: "wave",
|
|
7137
|
-
options: { amplitude: 0.02, wavelength: 0.6, speed: 0.7, angle: 45, pinnedEdge: "none" }
|
|
7138
|
-
}
|
|
7139
|
-
],
|
|
7140
|
-
sheet: { width: 1, height: 1.4 },
|
|
7141
|
-
t: 0.8
|
|
7142
|
-
}
|
|
7143
|
-
];
|
|
7144
|
-
function buildParityFragment(stack, sheet2) {
|
|
7145
|
-
const composed = buildDisplacementGLSL(stack, sheet2);
|
|
7146
|
-
return (
|
|
7147
|
-
/* glsl */
|
|
7148
|
-
`#version 300 es
|
|
7149
|
-
precision highp float;
|
|
7150
|
-
uniform float uPlTime;
|
|
7151
|
-
uniform float uPlBias;
|
|
7152
|
-
${composed.functionsSrc}
|
|
7153
|
-
${composed.displaceSrc}
|
|
7154
|
-
out vec4 outColor;
|
|
7155
|
-
void main() {
|
|
7156
|
-
vec2 uv = (gl_FragCoord.xy - 0.5) / float(${GRID - 1});
|
|
7157
|
-
vec3 p = vec3((uv - 0.5) * uSheet, 0.0);
|
|
7158
|
-
outColor = vec4(plDisplace(p, uv, uPlTime, uPlBias), 1.0);
|
|
7159
|
-
}
|
|
7160
|
-
`
|
|
7161
|
-
);
|
|
7162
|
-
}
|
|
7163
|
-
var VERT = `#version 300 es
|
|
7164
|
-
in vec2 aPos;
|
|
7165
|
-
void main() { gl_Position = vec4(aPos, 0.0, 1.0); }
|
|
7166
|
-
`;
|
|
7167
|
-
function compile(gl, type, src) {
|
|
7168
|
-
const shader = gl.createShader(type);
|
|
7169
|
-
gl.shaderSource(shader, src);
|
|
7170
|
-
gl.compileShader(shader);
|
|
7171
|
-
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
|
|
7172
|
-
throw new Error(`[paperlab parity] shader compile failed: ${gl.getShaderInfoLog(shader)}`);
|
|
7173
|
-
}
|
|
7174
|
-
return shader;
|
|
7175
|
-
}
|
|
7176
|
-
function runCaseOnGPU(gl, c, bias = 1) {
|
|
7177
|
-
const composed = buildDisplacementGLSL(c.stack, c.sheet);
|
|
7178
|
-
const program = gl.createProgram();
|
|
7179
|
-
gl.attachShader(program, compile(gl, gl.VERTEX_SHADER, VERT));
|
|
7180
|
-
gl.attachShader(program, compile(gl, gl.FRAGMENT_SHADER, buildParityFragment(c.stack, c.sheet)));
|
|
7181
|
-
gl.linkProgram(program);
|
|
7182
|
-
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
|
|
7183
|
-
throw new Error(`[paperlab parity] link failed: ${gl.getProgramInfoLog(program)}`);
|
|
7184
|
-
}
|
|
7185
|
-
gl.useProgram(program);
|
|
7186
|
-
for (const [name, value] of Object.entries(composed.uniforms)) {
|
|
7187
|
-
const loc = gl.getUniformLocation(program, name);
|
|
7188
|
-
if (!loc) continue;
|
|
7189
|
-
if (typeof value === "number") gl.uniform1f(loc, value);
|
|
7190
|
-
else if (value.length === 2) gl.uniform2f(loc, value[0], value[1]);
|
|
7191
|
-
else if (value.length === 3) gl.uniform3f(loc, value[0], value[1], value[2]);
|
|
7192
|
-
else gl.uniform4f(loc, value[0], value[1], value[2], value[3]);
|
|
7193
|
-
}
|
|
7194
|
-
const timeLoc = gl.getUniformLocation(program, "uPlTime");
|
|
7195
|
-
if (timeLoc) gl.uniform1f(timeLoc, c.t);
|
|
7196
|
-
const biasLoc = gl.getUniformLocation(program, "uPlBias");
|
|
7197
|
-
if (biasLoc) gl.uniform1f(biasLoc, bias);
|
|
7198
|
-
const quad = gl.createBuffer();
|
|
7199
|
-
gl.bindBuffer(gl.ARRAY_BUFFER, quad);
|
|
7200
|
-
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 3, -1, -1, 3]), gl.STATIC_DRAW);
|
|
7201
|
-
const posLoc = gl.getAttribLocation(program, "aPos");
|
|
7202
|
-
gl.enableVertexAttribArray(posLoc);
|
|
7203
|
-
gl.vertexAttribPointer(posLoc, 2, gl.FLOAT, false, 0, 0);
|
|
7204
|
-
const tex = gl.createTexture();
|
|
7205
|
-
gl.bindTexture(gl.TEXTURE_2D, tex);
|
|
7206
|
-
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA32F, GRID, GRID, 0, gl.RGBA, gl.FLOAT, null);
|
|
7207
|
-
const fbo = gl.createFramebuffer();
|
|
7208
|
-
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
|
|
7209
|
-
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);
|
|
7210
|
-
gl.viewport(0, 0, GRID, GRID);
|
|
7211
|
-
gl.drawArrays(gl.TRIANGLES, 0, 3);
|
|
7212
|
-
const out = new Float32Array(GRID * GRID * 4);
|
|
7213
|
-
gl.readPixels(0, 0, GRID, GRID, gl.RGBA, gl.FLOAT, out);
|
|
7214
|
-
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
7215
|
-
return out;
|
|
7216
|
-
}
|
|
7217
|
-
function runBiasCases(gl) {
|
|
7218
|
-
const results = [];
|
|
7219
|
-
for (const c of parityCases) {
|
|
7220
|
-
const strengths = c.stack.map((i) => getDeformer(i.type).glsl?.strength !== void 0);
|
|
7221
|
-
if (!strengths.every((h) => h === strengths[0])) continue;
|
|
7222
|
-
const scales = strengths[0];
|
|
7223
|
-
const at0 = runCaseOnGPU(gl, c, 0);
|
|
7224
|
-
const reference = scales ? null : runCaseOnGPU(gl, c, 1);
|
|
7225
|
-
let maxError = 0;
|
|
7226
|
-
for (let row = 0; row < GRID; row++) {
|
|
7227
|
-
for (let col = 0; col < GRID; col++) {
|
|
7228
|
-
const i4 = (row * GRID + col) * 4;
|
|
7229
|
-
const ex = reference ? reference[i4] : (col / (GRID - 1) - 0.5) * c.sheet.width;
|
|
7230
|
-
const ey = reference ? reference[i4 + 1] : (row / (GRID - 1) - 0.5) * c.sheet.height;
|
|
7231
|
-
const ez = reference ? reference[i4 + 2] : 0;
|
|
7232
|
-
maxError = Math.max(
|
|
7233
|
-
maxError,
|
|
7234
|
-
Math.abs(at0[i4] - ex),
|
|
7235
|
-
Math.abs(at0[i4 + 1] - ey),
|
|
7236
|
-
Math.abs(at0[i4 + 2] - ez)
|
|
7237
|
-
);
|
|
7238
|
-
}
|
|
7239
|
-
}
|
|
7240
|
-
results.push({
|
|
7241
|
-
name: `bias: ${c.name} \u2192 ${scales ? "flat at 0" : "ignores bias"}`,
|
|
7242
|
-
maxError,
|
|
7243
|
-
pass: maxError < PARITY_EPSILON
|
|
7244
|
-
});
|
|
7245
|
-
}
|
|
7246
|
-
return results;
|
|
7247
|
-
}
|
|
7248
|
-
function runParityHarness(canvas) {
|
|
7249
|
-
const cnv = canvas ?? document.createElement("canvas");
|
|
7250
|
-
const gl = cnv.getContext("webgl2");
|
|
7251
|
-
if (!gl) throw new Error("[paperlab parity] WebGL2 unavailable");
|
|
7252
|
-
if (!gl.getExtension("EXT_color_buffer_float")) {
|
|
7253
|
-
throw new Error("[paperlab parity] EXT_color_buffer_float unavailable");
|
|
7254
|
-
}
|
|
7255
|
-
const point = new THREE16.Vector3();
|
|
7256
|
-
const parity = parityCases.map((c) => {
|
|
7257
|
-
const gpu = runCaseOnGPU(gl, c);
|
|
7258
|
-
let maxError = 0;
|
|
7259
|
-
for (let row = 0; row < GRID; row++) {
|
|
7260
|
-
for (let col = 0; col < GRID; col++) {
|
|
7261
|
-
const u = col / (GRID - 1);
|
|
7262
|
-
const v = row / (GRID - 1);
|
|
7263
|
-
point.set((u - 0.5) * c.sheet.width, (v - 0.5) * c.sheet.height, 0);
|
|
7264
|
-
displacePoint(point, u, v, c.stack, { t: c.t, sheet: c.sheet });
|
|
7265
|
-
const i4 = (row * GRID + col) * 4;
|
|
7266
|
-
maxError = Math.max(
|
|
7267
|
-
maxError,
|
|
7268
|
-
Math.abs(gpu[i4] - point.x),
|
|
7269
|
-
Math.abs(gpu[i4 + 1] - point.y),
|
|
7270
|
-
Math.abs(gpu[i4 + 2] - point.z)
|
|
7271
|
-
);
|
|
7272
|
-
}
|
|
7273
|
-
}
|
|
7274
|
-
return { name: c.name, maxError, pass: maxError < PARITY_EPSILON };
|
|
7275
|
-
});
|
|
7276
|
-
return [...parity, ...runBiasCases(gl)];
|
|
7277
|
-
}
|
|
7278
|
-
|
|
7279
7115
|
// src/config/diff.ts
|
|
7280
7116
|
function isPlainObject(v) {
|
|
7281
7117
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
@@ -7320,7 +7156,8 @@ function diffConfig(config) {
|
|
|
7320
7156
|
} else if (config.physics !== "none") {
|
|
7321
7157
|
out.physics = config.physics;
|
|
7322
7158
|
}
|
|
7323
|
-
|
|
7159
|
+
const scene = diffAgainst(config.scene, sceneSchema.parse({}));
|
|
7160
|
+
if (Object.keys(scene).length > 0) out.scene = scene;
|
|
7324
7161
|
if (config.onTwos) out.onTwos = true;
|
|
7325
7162
|
if (config.states) out.states = config.states;
|
|
7326
7163
|
const meta = diffAgainst(config.meta, paperConfigSchema.parse({}).meta);
|
|
@@ -7331,14 +7168,35 @@ function jsxValue(value) {
|
|
|
7331
7168
|
if (typeof value === "string") return `"${value}"`;
|
|
7332
7169
|
return `{${JSON.stringify(value)}}`;
|
|
7333
7170
|
}
|
|
7171
|
+
function withoutUploads(value) {
|
|
7172
|
+
let replaced = 0;
|
|
7173
|
+
const walk = (node) => {
|
|
7174
|
+
if (typeof node === "string") {
|
|
7175
|
+
if (!node.startsWith("data:")) return node;
|
|
7176
|
+
replaced++;
|
|
7177
|
+
const extension = node.startsWith("data:image/png") ? "png" : "jpg";
|
|
7178
|
+
return `/paperlab-image-${replaced}.${extension}`;
|
|
7179
|
+
}
|
|
7180
|
+
if (Array.isArray(node)) return node.map(walk);
|
|
7181
|
+
if (node && typeof node === "object") {
|
|
7182
|
+
return Object.fromEntries(Object.entries(node).map(([k, v]) => [k, walk(v)]));
|
|
7183
|
+
}
|
|
7184
|
+
return node;
|
|
7185
|
+
};
|
|
7186
|
+
return { value: walk(value), replaced };
|
|
7187
|
+
}
|
|
7188
|
+
var UPLOAD_NOTE = "// Uploaded pictures cannot travel in a snippet \u2014 the paths below are\n// stand-ins, in order. Point them at your own files.";
|
|
7334
7189
|
function buildJsxSnippet(config) {
|
|
7335
|
-
const
|
|
7336
|
-
delete
|
|
7190
|
+
const diffed = diffConfig(config);
|
|
7191
|
+
delete diffed.meta;
|
|
7192
|
+
const { value: diff, replaced } = withoutUploads(diffed);
|
|
7337
7193
|
const props = Object.entries(diff).map(([key, value]) => ` ${key}=${jsxValue(value)}`);
|
|
7338
7194
|
if (props.length === 0) return "<Paper />";
|
|
7339
|
-
|
|
7195
|
+
const snippet = `<Paper
|
|
7340
7196
|
${props.join("\n")}
|
|
7341
7197
|
/>`;
|
|
7198
|
+
return replaced > 0 ? `${UPLOAD_NOTE}
|
|
7199
|
+
${snippet}` : snippet;
|
|
7342
7200
|
}
|
|
7343
7201
|
|
|
7344
7202
|
// src/config/agent-payload.ts
|
|
@@ -7388,7 +7246,10 @@ function componentName(config) {
|
|
|
7388
7246
|
}
|
|
7389
7247
|
function buildAgentPayload(config) {
|
|
7390
7248
|
const name = componentName(config);
|
|
7391
|
-
const
|
|
7249
|
+
const { value: stripped, replaced } = withoutUploads(diffConfig(config));
|
|
7250
|
+
const preset = JSON.stringify(stripped, null, 2);
|
|
7251
|
+
const uploadNote = replaced > 0 ? `${UPLOAD_NOTE}
|
|
7252
|
+
` : "";
|
|
7392
7253
|
return `Integrate a Paperlab paper component into this project. (paperlab agent-payload v${AGENT_PAYLOAD_VERSION})
|
|
7393
7254
|
|
|
7394
7255
|
1. Install the dependencies:
|
|
@@ -7401,7 +7262,7 @@ function buildAgentPayload(config) {
|
|
|
7401
7262
|
\`\`\`tsx
|
|
7402
7263
|
import { Paper, type PaperConfigInput } from 'paperlab'
|
|
7403
7264
|
|
|
7404
|
-
const preset = ${preset.replace(/\n/g, "\n")} satisfies PaperConfigInput
|
|
7265
|
+
${uploadNote}const preset = ${preset.replace(/\n/g, "\n")} satisfies PaperConfigInput
|
|
7405
7266
|
|
|
7406
7267
|
export function ${name}() {
|
|
7407
7268
|
return <Paper preset={preset} />
|
|
@@ -7444,7 +7305,9 @@ function distinctFieldPresets(input) {
|
|
|
7444
7305
|
function nonDefault(value, defaults) {
|
|
7445
7306
|
const out = {};
|
|
7446
7307
|
for (const [k, v] of Object.entries(value ?? {})) {
|
|
7447
|
-
if (v
|
|
7308
|
+
if (v === void 0) continue;
|
|
7309
|
+
const same = v === defaults[k] || JSON.stringify(v) === JSON.stringify(defaults[k]);
|
|
7310
|
+
if (!same) out[k] = v;
|
|
7448
7311
|
}
|
|
7449
7312
|
return out;
|
|
7450
7313
|
}
|
|
@@ -7457,6 +7320,11 @@ function diffFieldProps(input) {
|
|
|
7457
7320
|
if (Object.keys(motion).length > 0) out.motion = motion;
|
|
7458
7321
|
const entrance = nonDefault(input.entrance, ENTRANCE_DEFAULTS);
|
|
7459
7322
|
if (Object.keys(entrance).length > 0) out.entrance = entrance;
|
|
7323
|
+
const scene = nonDefault(
|
|
7324
|
+
sceneSchema.parse(input.scene ?? {}),
|
|
7325
|
+
sceneSchema.parse({})
|
|
7326
|
+
);
|
|
7327
|
+
if (Object.keys(scene).length > 0) out.scene = scene;
|
|
7460
7328
|
return out;
|
|
7461
7329
|
}
|
|
7462
7330
|
var LAYOUT_PHRASES = {
|
|
@@ -7490,7 +7358,7 @@ function describeFieldConfig(input) {
|
|
|
7490
7358
|
parts.push("hovering peels/reacts per paper (interaction states)");
|
|
7491
7359
|
if (zones.length > 0) {
|
|
7492
7360
|
parts.push(
|
|
7493
|
-
`dragging one past its tear threshold detaches it to carry to the ${zones.map((
|
|
7361
|
+
`dragging one past its tear threshold detaches it to carry to the ${zones.map((z25) => z25.id).join(" or ")} zone (release elsewhere flutters it back)`
|
|
7494
7362
|
);
|
|
7495
7363
|
}
|
|
7496
7364
|
} else {
|
|
@@ -7598,204 +7466,380 @@ Constraints: don't modify the preset values; three >= 0.160 and React 19 are
|
|
|
7598
7466
|
required; the component needs no props.`;
|
|
7599
7467
|
}
|
|
7600
7468
|
|
|
7601
|
-
// src/
|
|
7602
|
-
|
|
7603
|
-
|
|
7604
|
-
|
|
7605
|
-
|
|
7606
|
-
|
|
7607
|
-
|
|
7608
|
-
0
|
|
7609
|
-
|
|
7610
|
-
|
|
7611
|
-
|
|
7612
|
-
|
|
7613
|
-
|
|
7614
|
-
|
|
7615
|
-
|
|
7616
|
-
|
|
7617
|
-
|
|
7618
|
-
|
|
7619
|
-
|
|
7620
|
-
|
|
7621
|
-
|
|
7622
|
-
|
|
7623
|
-
|
|
7624
|
-
|
|
7625
|
-
|
|
7626
|
-
|
|
7627
|
-
|
|
7628
|
-
|
|
7629
|
-
|
|
7630
|
-
|
|
7631
|
-
|
|
7632
|
-
|
|
7633
|
-
|
|
7634
|
-
|
|
7635
|
-
|
|
7636
|
-
|
|
7637
|
-
|
|
7638
|
-
|
|
7639
|
-
|
|
7640
|
-
|
|
7641
|
-
|
|
7642
|
-
|
|
7643
|
-
|
|
7644
|
-
|
|
7645
|
-
|
|
7646
|
-
|
|
7647
|
-
|
|
7648
|
-
|
|
7649
|
-
|
|
7469
|
+
// src/field/parity.ts
|
|
7470
|
+
var THREE17 = __toESM(require("three"), 1);
|
|
7471
|
+
var GRID = 48;
|
|
7472
|
+
var PARITY_EPSILON = 5e-4;
|
|
7473
|
+
var parityCases = [
|
|
7474
|
+
{
|
|
7475
|
+
name: "roll: defaults",
|
|
7476
|
+
stack: [{ type: "roll", options: { angle: 90, boundary: 0, radius: 0.12, spiral: 0.015 } }],
|
|
7477
|
+
sheet: { width: 1, height: 1.4 },
|
|
7478
|
+
t: 0
|
|
7479
|
+
},
|
|
7480
|
+
{
|
|
7481
|
+
name: "roll: tight receipt roll, rolling down",
|
|
7482
|
+
stack: [{ type: "roll", options: { angle: 270, boundary: -0.4, radius: 0.07, spiral: 0.02 } }],
|
|
7483
|
+
sheet: { width: 1, height: 2.6 },
|
|
7484
|
+
t: 0
|
|
7485
|
+
},
|
|
7486
|
+
{
|
|
7487
|
+
name: "curl: bottom-right peel",
|
|
7488
|
+
stack: [{ type: "curl", options: { corner: "bottom-right", amount: 0.45, radius: 0.2, skew: 0 } }],
|
|
7489
|
+
sheet: { width: 1.5, height: 1 },
|
|
7490
|
+
t: 0
|
|
7491
|
+
},
|
|
7492
|
+
{
|
|
7493
|
+
name: "curl: skewed top-left",
|
|
7494
|
+
stack: [{ type: "curl", options: { corner: "top-left", amount: 0.7, radius: 0.3, skew: 15 } }],
|
|
7495
|
+
sheet: { width: 1, height: 1 },
|
|
7496
|
+
t: 0
|
|
7497
|
+
},
|
|
7498
|
+
{
|
|
7499
|
+
name: "bend: positive arc at an angle",
|
|
7500
|
+
stack: [{ type: "bend", options: { curvature: 1.2, angle: 33 } }],
|
|
7501
|
+
sheet: { width: 1, height: 1.4 },
|
|
7502
|
+
t: 0
|
|
7503
|
+
},
|
|
7504
|
+
{
|
|
7505
|
+
/**
|
|
7506
|
+
* The gentle end, which nothing used to cover: the gate only ever tried
|
|
7507
|
+
* |curvature| ≥ 0.6, and `photo-print` — the field starter preset — bends
|
|
7508
|
+
* at 0.35. That band is where the arc's float32 evaluation loses its
|
|
7509
|
+
* cancellation, and where the two paths were 6e-4 apart until `bend` was
|
|
7510
|
+
* rewritten in cancellation-free form. Keep a case down here.
|
|
7511
|
+
*/
|
|
7512
|
+
name: "bend: barely-there arc (the band photo-print lives in)",
|
|
7513
|
+
stack: [{ type: "bend", options: { curvature: 0.35, angle: 0 } }],
|
|
7514
|
+
sheet: { width: 1.2, height: 0.9 },
|
|
7515
|
+
t: 0
|
|
7516
|
+
},
|
|
7517
|
+
{
|
|
7518
|
+
name: "bend: the gentlest arc the schema allows",
|
|
7519
|
+
stack: [{ type: "bend", options: { curvature: 0.02, angle: 61 } }],
|
|
7520
|
+
sheet: { width: 2, height: 2.6 },
|
|
7521
|
+
t: 0
|
|
7522
|
+
},
|
|
7523
|
+
{
|
|
7524
|
+
name: "bend: negative arc",
|
|
7525
|
+
stack: [{ type: "bend", options: { curvature: -0.8, angle: 0 } }],
|
|
7526
|
+
sheet: { width: 1, height: 1.4 },
|
|
7527
|
+
t: 0
|
|
7528
|
+
},
|
|
7529
|
+
{
|
|
7530
|
+
name: "fold: 90\xB0 hinge",
|
|
7531
|
+
stack: [{ type: "fold", options: { angle: 90, offset: 0, foldAngle: 90, radius: 0.06 } }],
|
|
7532
|
+
sheet: { width: 1, height: 1.4 },
|
|
7533
|
+
t: 0
|
|
7534
|
+
},
|
|
7535
|
+
{
|
|
7536
|
+
name: "fold: deep fold, travelling down",
|
|
7537
|
+
stack: [{ type: "fold", options: { angle: 270, offset: 0.2, foldAngle: 165, radius: 0.04 } }],
|
|
7538
|
+
sheet: { width: 1, height: 1.4 },
|
|
7539
|
+
t: 0
|
|
7540
|
+
},
|
|
7541
|
+
{
|
|
7542
|
+
name: "wave: free ripple at t=1.234",
|
|
7543
|
+
stack: [
|
|
7544
|
+
{
|
|
7545
|
+
type: "wave",
|
|
7546
|
+
options: { amplitude: 0.05, wavelength: 0.5, speed: 1, angle: 20, pinnedEdge: "none" }
|
|
7547
|
+
}
|
|
7548
|
+
],
|
|
7549
|
+
sheet: { width: 1, height: 1 },
|
|
7550
|
+
t: 1.234
|
|
7551
|
+
},
|
|
7552
|
+
{
|
|
7553
|
+
name: "wave: pinned top at t=2.5",
|
|
7554
|
+
stack: [
|
|
7555
|
+
{
|
|
7556
|
+
type: "wave",
|
|
7557
|
+
options: { amplitude: 0.04, wavelength: 0.4, speed: 1.5, angle: 80, pinnedEdge: "top" }
|
|
7558
|
+
}
|
|
7559
|
+
],
|
|
7560
|
+
sheet: { width: 1.2, height: 1.5 },
|
|
7561
|
+
t: 2.5
|
|
7562
|
+
},
|
|
7563
|
+
{
|
|
7564
|
+
name: "drape: banner hung from the top",
|
|
7565
|
+
stack: [
|
|
7566
|
+
{
|
|
7567
|
+
type: "drape",
|
|
7568
|
+
options: { amplitude: 0.17, folds: 5, falloff: 1.6, irregular: 0.45, gather: 0.5, pinnedEdge: "top" }
|
|
7569
|
+
}
|
|
7570
|
+
],
|
|
7571
|
+
sheet: { width: 1.5, height: 8.5 },
|
|
7572
|
+
t: 0
|
|
7573
|
+
},
|
|
7574
|
+
{
|
|
7575
|
+
name: "drape: deep irregular folds pinned at the bottom",
|
|
7576
|
+
stack: [
|
|
7577
|
+
{
|
|
7578
|
+
type: "drape",
|
|
7579
|
+
options: { amplitude: 0.55, folds: 11, falloff: 0.4, irregular: 1, gather: 1, pinnedEdge: "bottom" }
|
|
7580
|
+
}
|
|
7581
|
+
],
|
|
7582
|
+
sheet: { width: 2.2, height: 3 },
|
|
7583
|
+
t: 0
|
|
7584
|
+
},
|
|
7585
|
+
{
|
|
7586
|
+
name: "crumple: defaults",
|
|
7587
|
+
stack: [{ type: "crumple", options: { amount: 0.35, scale: 3, pull: 0.4, seed: 0 } }],
|
|
7588
|
+
sheet: { width: 1, height: 1.4 },
|
|
7589
|
+
t: 0
|
|
7590
|
+
},
|
|
7591
|
+
{
|
|
7592
|
+
// The adversarial one. `fract` is a sawtooth, so the two halves disagree
|
|
7593
|
+
// hardest where a crease lands exactly on a sample — a fine scale and a
|
|
7594
|
+
// seed whose fold directions are near-axis puts the most creases in
|
|
7595
|
+
// reach of the grid.
|
|
7596
|
+
name: "crumple: fully crushed, fine creases, off-axis seed",
|
|
7597
|
+
stack: [{ type: "crumple", options: { amount: 1, scale: 7.5, pull: 1, seed: 5 } }],
|
|
7598
|
+
sheet: { width: 1.3, height: 0.9 },
|
|
7599
|
+
t: 0
|
|
7600
|
+
},
|
|
7601
|
+
{
|
|
7602
|
+
// Crush then curl, which is the order the crumple BEHAVIOR stacks them:
|
|
7603
|
+
// the creases have to be placed on the flat sheet, not on a bent one.
|
|
7604
|
+
name: "stacked: crumple \u2218 bend (the crumple behavior)",
|
|
7605
|
+
stack: [
|
|
7606
|
+
{ type: "crumple", options: { amount: 0.62, scale: 3.3, pull: 0.5, seed: 2 } },
|
|
7607
|
+
{ type: "bend", options: { curvature: 0.31, angle: 35 } }
|
|
7608
|
+
],
|
|
7609
|
+
sheet: { width: 1.1, height: 1.4 },
|
|
7610
|
+
t: 0
|
|
7611
|
+
},
|
|
7612
|
+
{
|
|
7613
|
+
name: "stacked: letter-fold pair (fold \u2218 fold)",
|
|
7614
|
+
stack: [
|
|
7615
|
+
{ type: "fold", options: { angle: 270, offset: 0.2333, foldAngle: 120, radius: 0.05 } },
|
|
7616
|
+
{ type: "fold", options: { angle: 90, offset: 0.2333, foldAngle: 100, radius: 0.08 } }
|
|
7617
|
+
],
|
|
7618
|
+
sheet: { width: 1, height: 1.4 },
|
|
7619
|
+
t: 0
|
|
7620
|
+
},
|
|
7621
|
+
{
|
|
7622
|
+
name: "stacked: bend \u2218 roll \u2218 wave",
|
|
7623
|
+
stack: [
|
|
7624
|
+
{ type: "bend", options: { curvature: 0.6, angle: 0 } },
|
|
7625
|
+
{ type: "roll", options: { angle: 90, boundary: 0.1, radius: 0.15, spiral: 0 } },
|
|
7626
|
+
{
|
|
7627
|
+
type: "wave",
|
|
7628
|
+
options: { amplitude: 0.02, wavelength: 0.6, speed: 0.7, angle: 45, pinnedEdge: "none" }
|
|
7629
|
+
}
|
|
7630
|
+
],
|
|
7631
|
+
sheet: { width: 1, height: 1.4 },
|
|
7632
|
+
t: 0.8
|
|
7633
|
+
}
|
|
7634
|
+
];
|
|
7635
|
+
function buildParityFragment(stack, sheet2) {
|
|
7636
|
+
const composed = buildDisplacementGLSL(stack, sheet2);
|
|
7637
|
+
return (
|
|
7638
|
+
/* glsl */
|
|
7639
|
+
`#version 300 es
|
|
7640
|
+
precision highp float;
|
|
7641
|
+
uniform float uPlTime;
|
|
7642
|
+
uniform float uPlBias;
|
|
7643
|
+
${composed.functionsSrc}
|
|
7644
|
+
${composed.displaceSrc}
|
|
7645
|
+
out vec4 outColor;
|
|
7646
|
+
void main() {
|
|
7647
|
+
vec2 uv = (gl_FragCoord.xy - 0.5) / float(${GRID - 1});
|
|
7648
|
+
vec3 p = vec3((uv - 0.5) * uSheet, 0.0);
|
|
7649
|
+
outColor = vec4(plDisplace(p, uv, uPlTime, uPlBias), 1.0);
|
|
7650
|
+
}
|
|
7651
|
+
`
|
|
7652
|
+
);
|
|
7653
|
+
}
|
|
7654
|
+
var VERT = `#version 300 es
|
|
7655
|
+
in vec2 aPos;
|
|
7656
|
+
void main() { gl_Position = vec4(aPos, 0.0, 1.0); }
|
|
7657
|
+
`;
|
|
7658
|
+
function compile(gl, type, src) {
|
|
7659
|
+
const shader = gl.createShader(type);
|
|
7660
|
+
gl.shaderSource(shader, src);
|
|
7661
|
+
gl.compileShader(shader);
|
|
7662
|
+
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
|
|
7663
|
+
throw new Error(`[paperlab parity] shader compile failed: ${gl.getShaderInfoLog(shader)}`);
|
|
7664
|
+
}
|
|
7665
|
+
return shader;
|
|
7666
|
+
}
|
|
7667
|
+
function runCaseOnGPU(gl, c, bias = 1) {
|
|
7668
|
+
const composed = buildDisplacementGLSL(c.stack, c.sheet);
|
|
7669
|
+
const program = gl.createProgram();
|
|
7670
|
+
gl.attachShader(program, compile(gl, gl.VERTEX_SHADER, VERT));
|
|
7671
|
+
gl.attachShader(program, compile(gl, gl.FRAGMENT_SHADER, buildParityFragment(c.stack, c.sheet)));
|
|
7672
|
+
gl.linkProgram(program);
|
|
7673
|
+
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
|
|
7674
|
+
throw new Error(`[paperlab parity] link failed: ${gl.getProgramInfoLog(program)}`);
|
|
7675
|
+
}
|
|
7676
|
+
gl.useProgram(program);
|
|
7677
|
+
for (const [name, value] of Object.entries(composed.uniforms)) {
|
|
7678
|
+
const loc = gl.getUniformLocation(program, name);
|
|
7679
|
+
if (!loc) continue;
|
|
7680
|
+
if (typeof value === "number") gl.uniform1f(loc, value);
|
|
7681
|
+
else if (value.length === 2) gl.uniform2f(loc, value[0], value[1]);
|
|
7682
|
+
else if (value.length === 3) gl.uniform3f(loc, value[0], value[1], value[2]);
|
|
7683
|
+
else gl.uniform4f(loc, value[0], value[1], value[2], value[3]);
|
|
7684
|
+
}
|
|
7685
|
+
const timeLoc = gl.getUniformLocation(program, "uPlTime");
|
|
7686
|
+
if (timeLoc) gl.uniform1f(timeLoc, c.t);
|
|
7687
|
+
const biasLoc = gl.getUniformLocation(program, "uPlBias");
|
|
7688
|
+
if (biasLoc) gl.uniform1f(biasLoc, bias);
|
|
7689
|
+
const quad = gl.createBuffer();
|
|
7690
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, quad);
|
|
7691
|
+
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 3, -1, -1, 3]), gl.STATIC_DRAW);
|
|
7692
|
+
const posLoc = gl.getAttribLocation(program, "aPos");
|
|
7693
|
+
gl.enableVertexAttribArray(posLoc);
|
|
7694
|
+
gl.vertexAttribPointer(posLoc, 2, gl.FLOAT, false, 0, 0);
|
|
7695
|
+
const tex = gl.createTexture();
|
|
7696
|
+
gl.bindTexture(gl.TEXTURE_2D, tex);
|
|
7697
|
+
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA32F, GRID, GRID, 0, gl.RGBA, gl.FLOAT, null);
|
|
7698
|
+
const fbo = gl.createFramebuffer();
|
|
7699
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
|
|
7700
|
+
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);
|
|
7701
|
+
gl.viewport(0, 0, GRID, GRID);
|
|
7702
|
+
gl.drawArrays(gl.TRIANGLES, 0, 3);
|
|
7703
|
+
const out = new Float32Array(GRID * GRID * 4);
|
|
7704
|
+
gl.readPixels(0, 0, GRID, GRID, gl.RGBA, gl.FLOAT, out);
|
|
7705
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
7706
|
+
return out;
|
|
7707
|
+
}
|
|
7708
|
+
function runBiasCases(gl) {
|
|
7709
|
+
const results = [];
|
|
7710
|
+
for (const c of parityCases) {
|
|
7711
|
+
const strengths = c.stack.map((i) => getDeformer(i.type).glsl?.strength !== void 0);
|
|
7712
|
+
if (!strengths.every((h) => h === strengths[0])) continue;
|
|
7713
|
+
const scales = strengths[0];
|
|
7714
|
+
const at0 = runCaseOnGPU(gl, c, 0);
|
|
7715
|
+
const reference = scales ? null : runCaseOnGPU(gl, c, 1);
|
|
7716
|
+
let maxError = 0;
|
|
7717
|
+
for (let row = 0; row < GRID; row++) {
|
|
7718
|
+
for (let col = 0; col < GRID; col++) {
|
|
7719
|
+
const i4 = (row * GRID + col) * 4;
|
|
7720
|
+
const ex = reference ? reference[i4] : (col / (GRID - 1) - 0.5) * c.sheet.width;
|
|
7721
|
+
const ey = reference ? reference[i4 + 1] : (row / (GRID - 1) - 0.5) * c.sheet.height;
|
|
7722
|
+
const ez = reference ? reference[i4 + 2] : 0;
|
|
7723
|
+
maxError = Math.max(
|
|
7724
|
+
maxError,
|
|
7725
|
+
Math.abs(at0[i4] - ex),
|
|
7726
|
+
Math.abs(at0[i4 + 1] - ey),
|
|
7727
|
+
Math.abs(at0[i4 + 2] - ez)
|
|
7728
|
+
);
|
|
7729
|
+
}
|
|
7730
|
+
}
|
|
7731
|
+
results.push({
|
|
7732
|
+
name: `bias: ${c.name} \u2192 ${scales ? "flat at 0" : "ignores bias"}`,
|
|
7733
|
+
maxError,
|
|
7734
|
+
pass: maxError < PARITY_EPSILON
|
|
7735
|
+
});
|
|
7736
|
+
}
|
|
7737
|
+
return results;
|
|
7738
|
+
}
|
|
7739
|
+
function runParityHarness(canvas) {
|
|
7740
|
+
const cnv = canvas ?? document.createElement("canvas");
|
|
7741
|
+
const gl = cnv.getContext("webgl2");
|
|
7742
|
+
if (!gl) throw new Error("[paperlab parity] WebGL2 unavailable");
|
|
7743
|
+
if (!gl.getExtension("EXT_color_buffer_float")) {
|
|
7744
|
+
throw new Error("[paperlab parity] EXT_color_buffer_float unavailable");
|
|
7745
|
+
}
|
|
7746
|
+
const point = new THREE17.Vector3();
|
|
7747
|
+
const parity = parityCases.map((c) => {
|
|
7748
|
+
const gpu = runCaseOnGPU(gl, c);
|
|
7749
|
+
let maxError = 0;
|
|
7750
|
+
for (let row = 0; row < GRID; row++) {
|
|
7751
|
+
for (let col = 0; col < GRID; col++) {
|
|
7752
|
+
const u = col / (GRID - 1);
|
|
7753
|
+
const v = row / (GRID - 1);
|
|
7754
|
+
point.set((u - 0.5) * c.sheet.width, (v - 0.5) * c.sheet.height, 0);
|
|
7755
|
+
displacePoint(point, u, v, c.stack, { t: c.t, sheet: c.sheet });
|
|
7756
|
+
const i4 = (row * GRID + col) * 4;
|
|
7757
|
+
maxError = Math.max(
|
|
7758
|
+
maxError,
|
|
7759
|
+
Math.abs(gpu[i4] - point.x),
|
|
7760
|
+
Math.abs(gpu[i4 + 1] - point.y),
|
|
7761
|
+
Math.abs(gpu[i4 + 2] - point.z)
|
|
7762
|
+
);
|
|
7763
|
+
}
|
|
7764
|
+
}
|
|
7765
|
+
return { name: c.name, maxError, pass: maxError < PARITY_EPSILON };
|
|
7766
|
+
});
|
|
7767
|
+
return [...parity, ...runBiasCases(gl)];
|
|
7768
|
+
}
|
|
7769
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
7770
|
+
0 && (module.exports = {
|
|
7771
|
+
AUTO_CEILING,
|
|
7772
|
+
DropZone,
|
|
7773
|
+
FLAT_SEGMENTS,
|
|
7774
|
+
LightRig,
|
|
7775
|
+
PARITY_EPSILON,
|
|
7776
|
+
Paper,
|
|
7777
|
+
PaperBackdrop,
|
|
7778
|
+
PaperField,
|
|
7779
|
+
PaperFieldMesh,
|
|
7780
|
+
PaperLighting,
|
|
7781
|
+
PaperMesh,
|
|
7782
|
+
SAG_TOL,
|
|
7783
|
+
backdropSchema,
|
|
7784
|
+
behaviorConfigSchema,
|
|
7785
|
+
buildAgentPayload,
|
|
7786
|
+
buildFieldAgentPayload,
|
|
7787
|
+
buildFieldComponentSource,
|
|
7788
|
+
buildJsxSnippet,
|
|
7650
7789
|
clothConfigSchema,
|
|
7651
|
-
|
|
7652
|
-
|
|
7653
|
-
contentSchema,
|
|
7654
|
-
contentText,
|
|
7790
|
+
contentNames,
|
|
7791
|
+
contentSchemaFor,
|
|
7655
7792
|
coreStateNames,
|
|
7656
|
-
cornerNames,
|
|
7657
|
-
createSheetGeometry,
|
|
7658
|
-
crumple,
|
|
7659
|
-
crumpleBehavior,
|
|
7660
|
-
crumpleBehaviorOptionsSchema,
|
|
7661
|
-
crumpleOptionsSchema,
|
|
7662
|
-
curl,
|
|
7663
|
-
curlOptionsSchema,
|
|
7664
|
-
dampTo,
|
|
7665
|
-
deformerInstanceSchema,
|
|
7666
7793
|
describeConfig,
|
|
7667
7794
|
describeFieldConfig,
|
|
7668
7795
|
diffConfig,
|
|
7669
7796
|
diffFieldProps,
|
|
7670
|
-
displacePoint,
|
|
7671
|
-
distinctFieldPresets,
|
|
7672
|
-
drape,
|
|
7673
|
-
drapeOptionsSchema,
|
|
7674
|
-
drawBacking,
|
|
7675
|
-
fall,
|
|
7676
|
-
fallOptionsSchema,
|
|
7677
|
-
fan,
|
|
7678
|
-
fieldBounds,
|
|
7679
|
-
fieldKeyboardStep,
|
|
7680
|
-
filmNames,
|
|
7681
|
-
fitCamera,
|
|
7682
|
-
flattenNumeric,
|
|
7683
|
-
flight,
|
|
7684
|
-
flightOptionsSchema,
|
|
7685
|
-
flightPose,
|
|
7686
|
-
flip,
|
|
7687
|
-
flipOptionsSchema,
|
|
7688
|
-
fly,
|
|
7689
|
-
flyOptionsSchema,
|
|
7690
|
-
fold,
|
|
7691
|
-
foldOptionsSchema,
|
|
7692
7797
|
getBehavior,
|
|
7693
7798
|
getDeformer,
|
|
7694
|
-
getIdlePreset,
|
|
7695
7799
|
getLayout,
|
|
7696
|
-
getLightingPreset,
|
|
7697
7800
|
getPreset,
|
|
7698
7801
|
getStock,
|
|
7699
|
-
groupFieldPapers,
|
|
7700
|
-
gust,
|
|
7701
|
-
hang,
|
|
7702
|
-
hangOptionsSchema,
|
|
7703
7802
|
idleNames,
|
|
7704
|
-
idlePresets,
|
|
7705
7803
|
isBuiltinPreset,
|
|
7706
|
-
letterFold,
|
|
7707
|
-
letterFoldOptionsSchema,
|
|
7708
7804
|
lightAngles,
|
|
7709
|
-
lightPosition,
|
|
7710
7805
|
lightSchema,
|
|
7711
|
-
lightenHex,
|
|
7712
7806
|
lightingNames,
|
|
7713
|
-
lightingPresets,
|
|
7714
7807
|
listBehaviors,
|
|
7715
7808
|
listDeformers,
|
|
7716
7809
|
listLayouts,
|
|
7717
7810
|
listPresets,
|
|
7718
|
-
makeGoboTexture,
|
|
7719
7811
|
mergeConfig,
|
|
7720
7812
|
mergeWithDeletes,
|
|
7721
|
-
outwardCorner,
|
|
7722
7813
|
paperConfigSchema,
|
|
7723
7814
|
paperEdges,
|
|
7724
7815
|
paperStatesSchema,
|
|
7725
7816
|
parityCases,
|
|
7726
7817
|
parsePreset,
|
|
7727
|
-
peel,
|
|
7728
|
-
peelOptionsSchema,
|
|
7729
7818
|
physicsNames,
|
|
7730
|
-
physicsSchema,
|
|
7731
|
-
pile,
|
|
7732
|
-
quantizeProgress,
|
|
7733
7819
|
quantizeSegments,
|
|
7734
|
-
quantizeTime,
|
|
7735
|
-
rack,
|
|
7736
|
-
receiptContentSchema,
|
|
7737
|
-
receiptTotals,
|
|
7738
7820
|
recordStateOverride,
|
|
7739
7821
|
registerBehavior,
|
|
7740
7822
|
registerDeformer,
|
|
7741
7823
|
registerLayout,
|
|
7742
7824
|
registerPreset,
|
|
7743
|
-
resolveConfig,
|
|
7744
|
-
resolveDeformerStack,
|
|
7745
|
-
resolveFieldSlotConfig,
|
|
7746
7825
|
resolveLighting,
|
|
7747
|
-
resolveMode,
|
|
7748
|
-
resolveSegments,
|
|
7749
7826
|
resolveStateConfig,
|
|
7750
|
-
ribbon,
|
|
7751
|
-
ribbonOptionsSchema,
|
|
7752
|
-
ring,
|
|
7753
|
-
roll,
|
|
7754
|
-
rollOptionsSchema,
|
|
7755
7827
|
runParityHarness,
|
|
7756
7828
|
sceneSchema,
|
|
7757
7829
|
segmentsForArc,
|
|
7758
7830
|
segmentsForSine,
|
|
7759
7831
|
serializePreset,
|
|
7760
|
-
settle,
|
|
7761
|
-
settleOptionsSchema,
|
|
7762
|
-
sheet,
|
|
7763
|
-
sheetBackingSize,
|
|
7764
7832
|
sheetLayoutSchema,
|
|
7765
|
-
sheetSchema,
|
|
7766
|
-
sheetSlotXY,
|
|
7767
|
-
silhouetteRects,
|
|
7768
7833
|
spanAlong,
|
|
7769
|
-
spill,
|
|
7770
|
-
spread,
|
|
7771
|
-
stackAutoSegments,
|
|
7772
|
-
stackMinSegments,
|
|
7773
|
-
stackUniformValues,
|
|
7774
7834
|
stateDefSchema,
|
|
7775
|
-
stateEventTransitions,
|
|
7776
|
-
stateTransitionSchema,
|
|
7777
7835
|
stockNames,
|
|
7778
|
-
stockSchema,
|
|
7779
7836
|
stocks,
|
|
7780
|
-
stripStates,
|
|
7781
7837
|
supportsWebGL,
|
|
7782
|
-
surfaceSchema,
|
|
7783
|
-
sweep,
|
|
7784
|
-
tornEdgesOnDetach,
|
|
7785
|
-
translucencyUniforms,
|
|
7786
|
-
translucencyValues,
|
|
7787
7838
|
uniquePresetName,
|
|
7788
7839
|
unregisterPreset,
|
|
7789
|
-
unroll,
|
|
7790
|
-
unrollOptionsSchema,
|
|
7791
|
-
useContentAtlas,
|
|
7792
7840
|
usePaperStates,
|
|
7793
7841
|
usePrefersReducedMotion,
|
|
7794
|
-
|
|
7795
|
-
|
|
7796
|
-
waveOptionsSchema,
|
|
7797
|
-
withSheetCellFromPaper,
|
|
7798
|
-
wrapLines,
|
|
7799
|
-
zoneAccepts
|
|
7842
|
+
washSchema,
|
|
7843
|
+
wrapLines
|
|
7800
7844
|
});
|
|
7801
7845
|
//# sourceMappingURL=index.cjs.map
|