paperlab 0.4.0 → 0.5.1
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 +20 -18
- package/dist/{chunk-4ZU5DZEF.js → chunk-HRXQTJFS.js} +526 -225
- package/dist/chunk-HRXQTJFS.js.map +1 -0
- package/dist/index.cjs +590 -274
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +36 -65
- package/dist/index.d.ts +36 -65
- package/dist/index.js +26 -3
- 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 +2448 -2159
- package/dist/stage.cjs.map +1 -1
- package/dist/stage.d.cts +52 -28
- package/dist/stage.d.ts +52 -28
- package/dist/stage.js +41 -15
- package/dist/stage.js.map +1 -1
- package/package.json +4 -4
- package/dist/chunk-4ZU5DZEF.js.map +0 -1
- package/dist/slots-BYoLxVZ4.d.cts +0 -6008
- package/dist/slots-BYoLxVZ4.d.ts +0 -6008
|
@@ -909,6 +909,31 @@ var stockNames = [
|
|
|
909
909
|
"sticker"
|
|
910
910
|
];
|
|
911
911
|
var stockSchema = z14.enum(stockNames);
|
|
912
|
+
var washSchema = z14.object({
|
|
913
|
+
/** The first pigment. */
|
|
914
|
+
color: z14.string().default("#4a5b8c").describe("color"),
|
|
915
|
+
/** The second. Blooms alternate, and overlaps multiply into a third. */
|
|
916
|
+
secondary: z14.string().default("#b06a6a").describe("color"),
|
|
917
|
+
/** How many pools of colour. */
|
|
918
|
+
blooms: z14.number().int().min(1).max(24).default(7),
|
|
919
|
+
/** How far a pool runs before it dries — its size against the sheet. */
|
|
920
|
+
spread: z14.number().min(0.1).max(1).default(0.7),
|
|
921
|
+
/** Softness of the wet edge. 0 is a hard cut, 1 is a pool still moving. */
|
|
922
|
+
bleed: z14.number().min(0).max(1).default(0.5),
|
|
923
|
+
/** How much pigment is in the water. */
|
|
924
|
+
intensity: z14.number().min(0).max(1).default(0.55),
|
|
925
|
+
/**
|
|
926
|
+
* Edge darkening — the ring of pigment left where a pool dried.
|
|
927
|
+
*
|
|
928
|
+
* The signature of the medium, and the one thing a plain gradient cannot
|
|
929
|
+
* fake. Without it a wash reads as an airbrush.
|
|
930
|
+
*/
|
|
931
|
+
edge: z14.number().min(0).max(1).default(0.6),
|
|
932
|
+
/** Pigment settling into the tooth of the paper. */
|
|
933
|
+
granulation: z14.number().min(0).max(1).default(0.35),
|
|
934
|
+
/** Fixed so a preset paints the same wash every time. */
|
|
935
|
+
seed: z14.number().int().min(0).max(99).default(0)
|
|
936
|
+
});
|
|
912
937
|
var blankContentBase = z14.object({
|
|
913
938
|
type: z14.literal("blank")
|
|
914
939
|
});
|
|
@@ -933,7 +958,7 @@ var textContentBase = z14.object({
|
|
|
933
958
|
/** px at texture resolution (long edge = 1024 logical px before DPR). */
|
|
934
959
|
size: z14.number().min(8).max(256).default(44),
|
|
935
960
|
weight: z14.number().min(100).max(900).default(400),
|
|
936
|
-
color: z14.string().default("#2b2620"),
|
|
961
|
+
color: z14.string().default("#2b2620").describe("color"),
|
|
937
962
|
align: z14.enum(["left", "center", "right"]).default("left"),
|
|
938
963
|
/** Fraction of the short edge. */
|
|
939
964
|
padding: z14.number().min(0).max(0.4).default(0.09),
|
|
@@ -983,7 +1008,7 @@ var cardContentBase = z14.object({
|
|
|
983
1008
|
* was cropped rather than as a card that was set.
|
|
984
1009
|
*/
|
|
985
1010
|
size: z14.number().min(8).max(256).default(58),
|
|
986
|
-
color: z14.string().default("#2b2620"),
|
|
1011
|
+
color: z14.string().default("#2b2620").describe("color"),
|
|
987
1012
|
align: z14.enum(["left", "center"]).default("left"),
|
|
988
1013
|
padding: z14.number().min(0).max(0.4).default(0.1)
|
|
989
1014
|
});
|
|
@@ -1002,14 +1027,15 @@ var receiptContentBase = z14.object({
|
|
|
1002
1027
|
timestamp: z14.string().optional(),
|
|
1003
1028
|
footer: z14.string().default("KEEP FOR YOUR RECORDS")
|
|
1004
1029
|
});
|
|
1030
|
+
var withWash = { wash: washSchema.optional() };
|
|
1005
1031
|
var backContentSchema = z14.discriminatedUnion("type", [
|
|
1006
|
-
blankContentBase,
|
|
1007
|
-
imageContentBase,
|
|
1008
|
-
textContentBase,
|
|
1009
|
-
cardContentBase,
|
|
1010
|
-
receiptContentBase
|
|
1032
|
+
blankContentBase.extend(withWash),
|
|
1033
|
+
imageContentBase.extend(withWash),
|
|
1034
|
+
textContentBase.extend(withWash),
|
|
1035
|
+
cardContentBase.extend(withWash),
|
|
1036
|
+
receiptContentBase.extend(withWash)
|
|
1011
1037
|
]);
|
|
1012
|
-
var withBack = { back: backContentSchema.optional() };
|
|
1038
|
+
var withBack = { back: backContentSchema.optional(), ...withWash };
|
|
1013
1039
|
var blankContentSchema = blankContentBase.extend(withBack);
|
|
1014
1040
|
var imageContentSchema = imageContentBase.extend(withBack);
|
|
1015
1041
|
var textContentSchema = textContentBase.extend(withBack);
|
|
@@ -1022,6 +1048,14 @@ var contentSchema = z14.discriminatedUnion("type", [
|
|
|
1022
1048
|
cardContentSchema,
|
|
1023
1049
|
receiptContentSchema
|
|
1024
1050
|
]);
|
|
1051
|
+
var contentNames = contentSchema.options.map(
|
|
1052
|
+
(option) => option.shape.type.value
|
|
1053
|
+
);
|
|
1054
|
+
function contentSchemaFor(type) {
|
|
1055
|
+
const option = contentSchema.options.find((candidate) => candidate.shape.type.value === type);
|
|
1056
|
+
if (!option) throw new Error(`Unknown content type: ${type}`);
|
|
1057
|
+
return option;
|
|
1058
|
+
}
|
|
1025
1059
|
var paperEdges = ["top", "right", "bottom", "left"];
|
|
1026
1060
|
var surfaceSchema = z14.object({
|
|
1027
1061
|
/** Paper fiber noise, 0..1. */
|
|
@@ -1109,8 +1143,70 @@ var lightingNames = [
|
|
|
1109
1143
|
"lightbox"
|
|
1110
1144
|
];
|
|
1111
1145
|
var filmNames = ["agx", "neutral", "filmic"];
|
|
1146
|
+
var lightSchema = z14.object({
|
|
1147
|
+
/** Tone-mapping exposure — the stop the whole picture is printed at. */
|
|
1148
|
+
exposure: z14.number().min(0.1).max(4).optional(),
|
|
1149
|
+
/**
|
|
1150
|
+
* The tone curve — the film, where `exposure` is the stop.
|
|
1151
|
+
*
|
|
1152
|
+
* `filmic` is ACES, which is what every preset used to be pinned to and is
|
|
1153
|
+
* kept so a scene tuned against it can say so. On near-white paper it is
|
|
1154
|
+
* the wrong film: it desaturates and drags bright neutrals toward
|
|
1155
|
+
* yellow-green, which is the sepia cast a lit sheet used to pick up.
|
|
1156
|
+
*/
|
|
1157
|
+
film: z14.enum(filmNames).optional(),
|
|
1158
|
+
/** Key light strength. */
|
|
1159
|
+
key: z14.number().min(0).max(12).optional(),
|
|
1160
|
+
/** Key light colour. */
|
|
1161
|
+
color: z14.string().optional().describe("color"),
|
|
1162
|
+
/**
|
|
1163
|
+
* Where the key stands, degrees around the vertical. 0° is straight in
|
|
1164
|
+
* front of the paper (+Z, beside the camera), 90° is off to the right,
|
|
1165
|
+
* and ±180° is directly behind it — which is where `nave` puts it, and
|
|
1166
|
+
* why that preset is carried by light coming THROUGH the paper.
|
|
1167
|
+
*/
|
|
1168
|
+
direction: z14.number().min(-180).max(180).optional(),
|
|
1169
|
+
/** How high the key stands, degrees above the horizon. */
|
|
1170
|
+
height: z14.number().min(-30).max(89).optional(),
|
|
1171
|
+
/** Flat fill from every direction at once. Cheap, and it kills form — reach for `studio` first. */
|
|
1172
|
+
ambient: z14.number().min(0).max(2).optional(),
|
|
1173
|
+
/** The room's own light: an environment map built from `sky`. Directional fill, and the only thing paper's sheen has to reflect. */
|
|
1174
|
+
studio: z14.number().min(0).max(3).optional(),
|
|
1175
|
+
/** Distance haze, as a multiple of the preset's. 0 clears the air entirely; 2 halves the distance you can see. */
|
|
1176
|
+
haze: z14.number().min(0).max(3).optional()
|
|
1177
|
+
});
|
|
1178
|
+
var backdropSchema = z14.object({
|
|
1179
|
+
/** Behind everything, and behind the picture where it does not reach. */
|
|
1180
|
+
color: z14.string().default("#171717").describe("color"),
|
|
1181
|
+
/** A URL, or an uploaded picture. Empty is the colour on its own. */
|
|
1182
|
+
image: z14.string().default(""),
|
|
1183
|
+
fit: z14.enum(["cover", "contain"]).default("cover"),
|
|
1184
|
+
/**
|
|
1185
|
+
* Toward the colour, so the paper stays the subject.
|
|
1186
|
+
*
|
|
1187
|
+
* A backdrop at full strength competes with the sheet in front of it —
|
|
1188
|
+
* which is what a real photographer solves by putting the background out
|
|
1189
|
+
* of the light, and what this solves by mixing it back toward the ground
|
|
1190
|
+
* it sits on.
|
|
1191
|
+
*/
|
|
1192
|
+
fade: z14.number().min(0).max(1).default(0.25),
|
|
1193
|
+
/** Out of focus, for the same reason. */
|
|
1194
|
+
blur: z14.number().min(0).max(1).default(0.2)
|
|
1195
|
+
});
|
|
1112
1196
|
var sceneSchema = z14.object({
|
|
1113
|
-
lighting: z14.enum(lightingNames).default("studio")
|
|
1197
|
+
lighting: z14.enum(lightingNames).default("studio"),
|
|
1198
|
+
/** What is behind the sheet. Unset leaves the canvas alone. */
|
|
1199
|
+
backdrop: backdropSchema.optional(),
|
|
1200
|
+
/**
|
|
1201
|
+
* Overrides on the named preset — the same authorable half stage mode has
|
|
1202
|
+
* always had, and which a lone sheet had no way to reach.
|
|
1203
|
+
*
|
|
1204
|
+
* A preset was the starting point everywhere EXCEPT here: a stage could be
|
|
1205
|
+
* "nave, but the sun is lower", and a `<Paper>` could only be one of seven
|
|
1206
|
+
* rigs exactly as shipped. `<PaperLighting>` has taken these overrides all
|
|
1207
|
+
* along; nothing was passing them.
|
|
1208
|
+
*/
|
|
1209
|
+
light: lightSchema.default({})
|
|
1114
1210
|
});
|
|
1115
1211
|
var coreStateNames = ["rest", "hover", "pressed", "picked", "placed"];
|
|
1116
1212
|
var isStateName = (s) => coreStateNames.includes(s) || s.startsWith("custom:");
|
|
@@ -1332,6 +1428,33 @@ var builtins = {
|
|
|
1332
1428
|
behavior: { type: "letter-fold", progress: 0.4, crease: 0.3 },
|
|
1333
1429
|
surface: { creaseLines: { angle: 0, positions: [1 / 3, 2 / 3], strength: 0.5 } }
|
|
1334
1430
|
},
|
|
1431
|
+
/**
|
|
1432
|
+
* The wash, shown rather than described.
|
|
1433
|
+
*
|
|
1434
|
+
* A `wash` is a field on every content type, which means it is reachable
|
|
1435
|
+
* from any preset and discoverable from none — a toggle three folders down
|
|
1436
|
+
* is not an argument for the feature. This is the argument: type set over
|
|
1437
|
+
* paint, on cotton, deckled, with the paper still showing through both.
|
|
1438
|
+
*/
|
|
1439
|
+
"washed-letter": {
|
|
1440
|
+
meta: { name: "Washed letter", tags: ["wash", "text"] },
|
|
1441
|
+
// Printer stock, not vellum: vellum is translucent and takes the room's
|
|
1442
|
+
// grey through the back of the sheet, which turns a wash the colour of
|
|
1443
|
+
// dishwater. Pigment needs something white behind it.
|
|
1444
|
+
sheet: { width: 1.05, height: 1.45 },
|
|
1445
|
+
stock: "printer",
|
|
1446
|
+
content: {
|
|
1447
|
+
type: "text",
|
|
1448
|
+
text: "Painted first,\nwritten after.",
|
|
1449
|
+
font: 'Georgia, "Times New Roman", serif',
|
|
1450
|
+
size: 52,
|
|
1451
|
+
valign: "center",
|
|
1452
|
+
align: "center",
|
|
1453
|
+
wash: { color: "#5b6f9a", secondary: "#c08a86", blooms: 6, spread: 0.85, intensity: 0.5, seed: 3 }
|
|
1454
|
+
},
|
|
1455
|
+
behavior: { type: "peel", progress: 0.12, corner: "bottom-right", radius: 0.3 },
|
|
1456
|
+
surface: { grain: 0.35, deckle: { edges: ["bottom", "right"], roughness: 0.45 } }
|
|
1457
|
+
},
|
|
1335
1458
|
"vintage-note": {
|
|
1336
1459
|
meta: { name: "Vintage note", tags: ["aging", "text"] },
|
|
1337
1460
|
sheet: { width: 1.1, height: 1.4 },
|
|
@@ -2266,7 +2389,6 @@ function getIdlePreset(name) {
|
|
|
2266
2389
|
}
|
|
2267
2390
|
|
|
2268
2391
|
// src/scene/lighting.ts
|
|
2269
|
-
import { z as z22 } from "zod";
|
|
2270
2392
|
var lightingPresets = {
|
|
2271
2393
|
studio: {
|
|
2272
2394
|
id: "studio",
|
|
@@ -2427,46 +2549,14 @@ var lightingPresets = {
|
|
|
2427
2549
|
function getLightingPreset(name) {
|
|
2428
2550
|
return lightingPresets[name];
|
|
2429
2551
|
}
|
|
2430
|
-
var lightSchema = z22.object({
|
|
2431
|
-
/** Tone-mapping exposure — the stop the whole picture is printed at. */
|
|
2432
|
-
exposure: z22.number().min(0.1).max(4).optional(),
|
|
2433
|
-
/**
|
|
2434
|
-
* The tone curve — the film, where `exposure` is the stop.
|
|
2435
|
-
*
|
|
2436
|
-
* `filmic` is ACES, which is what every preset used to be pinned to and is
|
|
2437
|
-
* kept so a scene tuned against it can say so. On near-white paper it is
|
|
2438
|
-
* the wrong film: it desaturates and drags bright neutrals toward
|
|
2439
|
-
* yellow-green, which is the sepia cast a lit sheet used to pick up.
|
|
2440
|
-
*/
|
|
2441
|
-
film: z22.enum(filmNames).optional(),
|
|
2442
|
-
/** Key light strength. */
|
|
2443
|
-
key: z22.number().min(0).max(12).optional(),
|
|
2444
|
-
/** Key light colour. */
|
|
2445
|
-
color: z22.string().optional(),
|
|
2446
|
-
/**
|
|
2447
|
-
* Where the key stands, degrees around the vertical. 0° is straight in
|
|
2448
|
-
* front of the paper (+Z, beside the camera), 90° is off to the right,
|
|
2449
|
-
* and ±180° is directly behind it — which is where `nave` puts it, and
|
|
2450
|
-
* why that preset is carried by light coming THROUGH the paper.
|
|
2451
|
-
*/
|
|
2452
|
-
direction: z22.number().min(-180).max(180).optional(),
|
|
2453
|
-
/** How high the key stands, degrees above the horizon. */
|
|
2454
|
-
height: z22.number().min(-30).max(89).optional(),
|
|
2455
|
-
/** Flat fill from every direction at once. Cheap, and it kills form — reach for `studio` first. */
|
|
2456
|
-
ambient: z22.number().min(0).max(2).optional(),
|
|
2457
|
-
/** The room's own light: an environment map built from `sky`. Directional fill, and the only thing paper's sheen has to reflect. */
|
|
2458
|
-
studio: z22.number().min(0).max(3).optional(),
|
|
2459
|
-
/** Distance haze, as a multiple of the preset's. 0 clears the air entirely; 2 halves the distance you can see. */
|
|
2460
|
-
haze: z22.number().min(0).max(3).optional()
|
|
2461
|
-
});
|
|
2462
2552
|
var DEG6 = 180 / Math.PI;
|
|
2463
2553
|
function lightAngles(position) {
|
|
2464
|
-
const [x, y,
|
|
2465
|
-
const distance = Math.hypot(x, y,
|
|
2554
|
+
const [x, y, z25] = position;
|
|
2555
|
+
const distance = Math.hypot(x, y, z25);
|
|
2466
2556
|
if (distance < 1e-9) return { azimuth: 0, elevation: 90, distance: 0 };
|
|
2467
|
-
const ground = Math.hypot(x,
|
|
2557
|
+
const ground = Math.hypot(x, z25);
|
|
2468
2558
|
return {
|
|
2469
|
-
azimuth: ground < 1e-9 ? 0 : Math.atan2(x,
|
|
2559
|
+
azimuth: ground < 1e-9 ? 0 : Math.atan2(x, z25) * DEG6,
|
|
2470
2560
|
elevation: Math.atan2(y, ground) * DEG6,
|
|
2471
2561
|
distance
|
|
2472
2562
|
};
|
|
@@ -3053,11 +3143,11 @@ function computeSheetNormals(geometry) {
|
|
|
3053
3143
|
for (let i = 0, l = nrm.length; i < l; i += 3) {
|
|
3054
3144
|
const x = nrm[i];
|
|
3055
3145
|
const y = nrm[i + 1];
|
|
3056
|
-
const
|
|
3057
|
-
const len = Math.sqrt(x * x + y * y +
|
|
3146
|
+
const z25 = nrm[i + 2];
|
|
3147
|
+
const len = Math.sqrt(x * x + y * y + z25 * z25) || 1;
|
|
3058
3148
|
nrm[i] = x / len;
|
|
3059
3149
|
nrm[i + 1] = y / len;
|
|
3060
|
-
nrm[i + 2] =
|
|
3150
|
+
nrm[i + 2] = z25 / len;
|
|
3061
3151
|
}
|
|
3062
3152
|
normalAttr.needsUpdate = true;
|
|
3063
3153
|
}
|
|
@@ -3190,6 +3280,109 @@ function paintCard(ctx, w, h, content, stock, dpr) {
|
|
|
3190
3280
|
}
|
|
3191
3281
|
}
|
|
3192
3282
|
|
|
3283
|
+
// src/content/wash.ts
|
|
3284
|
+
function mulberry32(seed) {
|
|
3285
|
+
let a = seed * 1831565813 + 2654435769;
|
|
3286
|
+
return () => {
|
|
3287
|
+
a |= 0;
|
|
3288
|
+
a = a + 1831565813 | 0;
|
|
3289
|
+
let t = Math.imul(a ^ a >>> 15, 1 | a);
|
|
3290
|
+
t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t;
|
|
3291
|
+
return ((t ^ t >>> 14) >>> 0) / 4294967296;
|
|
3292
|
+
};
|
|
3293
|
+
}
|
|
3294
|
+
function rgba(hex, alpha) {
|
|
3295
|
+
const m = /^#?([0-9a-f]{6})$/i.exec(hex.trim());
|
|
3296
|
+
const n = m ? Number.parseInt(m[1], 16) : 8421504;
|
|
3297
|
+
return `rgba(${n >> 16 & 255}, ${n >> 8 & 255}, ${n & 255}, ${Math.max(0, Math.min(1, alpha))})`;
|
|
3298
|
+
}
|
|
3299
|
+
function bloomShape(rng) {
|
|
3300
|
+
return {
|
|
3301
|
+
phase: [rng() * Math.PI * 2, rng() * Math.PI * 2, rng() * Math.PI * 2],
|
|
3302
|
+
amp: [0.18 + rng() * 0.1, 0.09 + rng() * 0.06, 0.05 + rng() * 0.04]
|
|
3303
|
+
};
|
|
3304
|
+
}
|
|
3305
|
+
function bloomPath(ctx, cx, cy, radius, shape, from = 0, to = 1) {
|
|
3306
|
+
const { phase, amp } = shape;
|
|
3307
|
+
const STEPS = Math.max(6, Math.round(72 * (to - from)));
|
|
3308
|
+
ctx.beginPath();
|
|
3309
|
+
for (let i = 0; i <= STEPS; i++) {
|
|
3310
|
+
const t = (from + (to - from) * i / STEPS) * Math.PI * 2;
|
|
3311
|
+
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]);
|
|
3312
|
+
const r = radius * (1 + wobble);
|
|
3313
|
+
const x = cx + Math.cos(t) * r;
|
|
3314
|
+
const y = cy + Math.sin(t) * r;
|
|
3315
|
+
if (i === 0) ctx.moveTo(x, y);
|
|
3316
|
+
else ctx.lineTo(x, y);
|
|
3317
|
+
}
|
|
3318
|
+
if (from === 0 && to === 1) ctx.closePath();
|
|
3319
|
+
}
|
|
3320
|
+
function canBlur(ctx) {
|
|
3321
|
+
if (!("filter" in ctx)) return false;
|
|
3322
|
+
const before = ctx.filter;
|
|
3323
|
+
try {
|
|
3324
|
+
ctx.filter = "blur(2px)";
|
|
3325
|
+
const worked = ctx.filter !== "none" && ctx.filter !== before;
|
|
3326
|
+
ctx.filter = before;
|
|
3327
|
+
return worked;
|
|
3328
|
+
} catch {
|
|
3329
|
+
return false;
|
|
3330
|
+
}
|
|
3331
|
+
}
|
|
3332
|
+
function paintWash(ctx, w, h, wash) {
|
|
3333
|
+
const rng = mulberry32(wash.seed + 1);
|
|
3334
|
+
const short = Math.min(w, h);
|
|
3335
|
+
const blurs = canBlur(ctx);
|
|
3336
|
+
ctx.save();
|
|
3337
|
+
ctx.globalCompositeOperation = "multiply";
|
|
3338
|
+
for (let i = 0; i < wash.blooms; i++) {
|
|
3339
|
+
const pigment = i % 2 === 0 ? wash.color : wash.secondary;
|
|
3340
|
+
const cx = (rng() * 1.5 - 0.25) * w;
|
|
3341
|
+
const cy = (rng() * 1.5 - 0.25) * h;
|
|
3342
|
+
const radius = short * wash.spread * (0.28 + rng() * 0.34);
|
|
3343
|
+
const alpha = wash.intensity * (0.35 + rng() * 0.4);
|
|
3344
|
+
const shape = bloomShape(rng);
|
|
3345
|
+
ctx.save();
|
|
3346
|
+
if (blurs) ctx.filter = `blur(${(2 + wash.bleed * 26) * (0.6 + rng() * 0.8)}px)`;
|
|
3347
|
+
const gx = cx + (rng() - 0.5) * radius * 0.5;
|
|
3348
|
+
const gy = cy + (rng() - 0.5) * radius * 0.5;
|
|
3349
|
+
const grad = ctx.createRadialGradient(gx, gy, radius * 0.05, gx, gy, radius * 1.15);
|
|
3350
|
+
grad.addColorStop(0, rgba(pigment, alpha * 0.55));
|
|
3351
|
+
grad.addColorStop(0.62, rgba(pigment, alpha));
|
|
3352
|
+
grad.addColorStop(1, rgba(pigment, alpha * 0.75));
|
|
3353
|
+
ctx.fillStyle = grad;
|
|
3354
|
+
bloomPath(ctx, cx, cy, radius, shape);
|
|
3355
|
+
ctx.fill();
|
|
3356
|
+
if (wash.edge > 0) {
|
|
3357
|
+
if (blurs) ctx.filter = `blur(${(1.5 + wash.bleed * 9) * (0.6 + rng() * 0.6)}px)`;
|
|
3358
|
+
ctx.lineWidth = Math.max(1, radius * (0.03 + wash.edge * 0.05));
|
|
3359
|
+
const arcs = 5;
|
|
3360
|
+
const overlap = 0.4 / arcs;
|
|
3361
|
+
for (let a = 0; a < arcs; a++) {
|
|
3362
|
+
ctx.strokeStyle = rgba(pigment, alpha * wash.edge * (0.15 + rng() * 1.05));
|
|
3363
|
+
bloomPath(ctx, cx, cy, radius, shape, a / arcs, (a + 1) / arcs + overlap);
|
|
3364
|
+
ctx.stroke();
|
|
3365
|
+
}
|
|
3366
|
+
}
|
|
3367
|
+
ctx.restore();
|
|
3368
|
+
if (wash.granulation > 0) {
|
|
3369
|
+
ctx.save();
|
|
3370
|
+
bloomPath(ctx, cx, cy, radius, shape);
|
|
3371
|
+
ctx.clip();
|
|
3372
|
+
const grains = Math.round(wash.granulation * 900);
|
|
3373
|
+
ctx.fillStyle = rgba(pigment, wash.granulation * alpha * 0.5);
|
|
3374
|
+
for (let g = 0; g < grains; g++) {
|
|
3375
|
+
const a = rng() * Math.PI * 2;
|
|
3376
|
+
const d = Math.sqrt(rng()) * radius;
|
|
3377
|
+
const size = 1 + rng() * (short * 4e-3);
|
|
3378
|
+
ctx.fillRect(cx + Math.cos(a) * d, cy + Math.sin(a) * d, size, size);
|
|
3379
|
+
}
|
|
3380
|
+
ctx.restore();
|
|
3381
|
+
}
|
|
3382
|
+
}
|
|
3383
|
+
ctx.restore();
|
|
3384
|
+
}
|
|
3385
|
+
|
|
3193
3386
|
// src/content/texture.ts
|
|
3194
3387
|
var LONG_EDGE = 1024;
|
|
3195
3388
|
var DPR = 2;
|
|
@@ -3240,6 +3433,7 @@ function renderContentToCanvas(content, sheet2, stock, image) {
|
|
|
3240
3433
|
canvas.height = h;
|
|
3241
3434
|
const ctx = canvas.getContext("2d");
|
|
3242
3435
|
paintBackground(ctx, w, h, stock);
|
|
3436
|
+
if (content.wash) paintWash(ctx, w, h, content.wash);
|
|
3243
3437
|
if (content.type === "image" && image && content.src) paintImage(ctx, w, h, image, content.fit);
|
|
3244
3438
|
if (content.type === "text") paintText(ctx, w, h, content, stock);
|
|
3245
3439
|
if (content.type === "receipt") paintReceipt(ctx, w, h, content, stock);
|
|
@@ -3451,13 +3645,13 @@ var ClothSim = class {
|
|
|
3451
3645
|
this.stillFrames = 0;
|
|
3452
3646
|
}
|
|
3453
3647
|
/** Nearest particle to a local-space point — the grab interface. */
|
|
3454
|
-
grabNearest(x, y,
|
|
3648
|
+
grabNearest(x, y, z25) {
|
|
3455
3649
|
let best = -1;
|
|
3456
3650
|
let bestDist = Infinity;
|
|
3457
3651
|
for (let i = 0; i < this.count; i++) {
|
|
3458
3652
|
const dx = this.positions[i * 3] - x;
|
|
3459
3653
|
const dy = this.positions[i * 3 + 1] - y;
|
|
3460
|
-
const dz = this.positions[i * 3 + 2] -
|
|
3654
|
+
const dz = this.positions[i * 3 + 2] - z25;
|
|
3461
3655
|
const d = dx * dx + dy * dy + dz * dz;
|
|
3462
3656
|
if (d < bestDist) {
|
|
3463
3657
|
bestDist = d;
|
|
@@ -3468,15 +3662,15 @@ var ClothSim = class {
|
|
|
3468
3662
|
this.wake();
|
|
3469
3663
|
return best;
|
|
3470
3664
|
}
|
|
3471
|
-
moveGrab(x, y,
|
|
3665
|
+
moveGrab(x, y, z25) {
|
|
3472
3666
|
if (this.grabbedIndex < 0) return;
|
|
3473
3667
|
const i3 = this.grabbedIndex * 3;
|
|
3474
3668
|
this.positions[i3] = x;
|
|
3475
3669
|
this.positions[i3 + 1] = y;
|
|
3476
|
-
this.positions[i3 + 2] =
|
|
3670
|
+
this.positions[i3 + 2] = z25;
|
|
3477
3671
|
this.prev[i3] = x;
|
|
3478
3672
|
this.prev[i3 + 1] = y;
|
|
3479
|
-
this.prev[i3 + 2] =
|
|
3673
|
+
this.prev[i3 + 2] = z25;
|
|
3480
3674
|
this.wake();
|
|
3481
3675
|
}
|
|
3482
3676
|
release() {
|
|
@@ -3512,19 +3706,19 @@ var ClothSim = class {
|
|
|
3512
3706
|
}
|
|
3513
3707
|
const x = p[i3];
|
|
3514
3708
|
const y = p[i3 + 1];
|
|
3515
|
-
const
|
|
3709
|
+
const z25 = p[i3 + 2];
|
|
3516
3710
|
const gust2 = wind * (0.55 + 0.45 * Math.sin(this.time * 1.7 + x * 2.1 + y * 1.3)) * 0.9;
|
|
3517
3711
|
const ax = gust2 * 0.25;
|
|
3518
3712
|
const az = gust2;
|
|
3519
3713
|
const vx = (x - this.prev[i3]) * damping;
|
|
3520
3714
|
const vy = (y - this.prev[i3 + 1]) * damping;
|
|
3521
|
-
const vz = (
|
|
3715
|
+
const vz = (z25 - this.prev[i3 + 2]) * damping;
|
|
3522
3716
|
this.prev[i3] = x;
|
|
3523
3717
|
this.prev[i3 + 1] = y;
|
|
3524
|
-
this.prev[i3 + 2] =
|
|
3718
|
+
this.prev[i3 + 2] = z25;
|
|
3525
3719
|
p[i3] = x + vx + ax * dt2;
|
|
3526
3720
|
p[i3 + 1] = y + vy - gravity * 3.2 * dt2;
|
|
3527
|
-
p[i3 + 2] =
|
|
3721
|
+
p[i3 + 2] = z25 + vz + az * dt2;
|
|
3528
3722
|
maxTravel = Math.max(maxTravel, vx * vx + vy * vy + vz * vz);
|
|
3529
3723
|
}
|
|
3530
3724
|
for (let iter = 0; iter < SOLVER_ITERATIONS; iter++) {
|
|
@@ -3632,8 +3826,8 @@ vec3 plTransmission(vec3 inkFilter) {
|
|
|
3632
3826
|
);
|
|
3633
3827
|
function translucencyValues(translucency, lighting) {
|
|
3634
3828
|
const preset = typeof lighting === "string" ? getLightingPreset(lighting) : lighting;
|
|
3635
|
-
const [x, y,
|
|
3636
|
-
const direction = new THREE4.Vector3(x, y,
|
|
3829
|
+
const [x, y, z25] = preset.key.position;
|
|
3830
|
+
const direction = new THREE4.Vector3(x, y, z25);
|
|
3637
3831
|
if (direction.lengthSq() < 1e-12) direction.set(0, 1, 0);
|
|
3638
3832
|
direction.normalize();
|
|
3639
3833
|
const color = new THREE4.Color(preset.key.color).multiplyScalar(preset.key.intensity * TRANSMISSION_GAIN);
|
|
@@ -4386,6 +4580,7 @@ var PaperMesh = forwardRef(function PaperMesh2(props, ref) {
|
|
|
4386
4580
|
props.interactive && !isCloth && behavior?.handles?.map((h, i) => /* @__PURE__ */ jsxs(
|
|
4387
4581
|
"mesh",
|
|
4388
4582
|
{
|
|
4583
|
+
userData: { paperlabChrome: true },
|
|
4389
4584
|
ref: (m) => {
|
|
4390
4585
|
handleRefs.current[i] = m;
|
|
4391
4586
|
},
|
|
@@ -4529,7 +4724,7 @@ var toneMappings = {
|
|
|
4529
4724
|
neutral: THREE9.NeutralToneMapping,
|
|
4530
4725
|
filmic: THREE9.ACESFilmicToneMapping
|
|
4531
4726
|
};
|
|
4532
|
-
function
|
|
4727
|
+
function mulberry322(seed) {
|
|
4533
4728
|
let a = seed;
|
|
4534
4729
|
return () => {
|
|
4535
4730
|
a |= 0;
|
|
@@ -4563,7 +4758,7 @@ function makeGoboTexture(kind) {
|
|
|
4563
4758
|
}
|
|
4564
4759
|
ctx.restore();
|
|
4565
4760
|
} else {
|
|
4566
|
-
const rand =
|
|
4761
|
+
const rand = mulberry322(7);
|
|
4567
4762
|
for (const [count, radius, alpha] of [
|
|
4568
4763
|
[26, 70, 0.75],
|
|
4569
4764
|
[40, 38, 0.6],
|
|
@@ -4711,9 +4906,75 @@ function PaperLighting({
|
|
|
4711
4906
|
] });
|
|
4712
4907
|
}
|
|
4713
4908
|
|
|
4714
|
-
// src/
|
|
4909
|
+
// src/scene/backdrop.tsx
|
|
4715
4910
|
import * as THREE10 from "three";
|
|
4716
|
-
import {
|
|
4911
|
+
import { useEffect as useEffect7, useState as useState4 } from "react";
|
|
4912
|
+
import { useThree as useThree3 } from "@react-three/fiber";
|
|
4913
|
+
function PaperBackdrop({ backdrop }) {
|
|
4914
|
+
const scene = useThree3((s) => s.scene);
|
|
4915
|
+
const size = useThree3((s) => s.size);
|
|
4916
|
+
const [image, setImage] = useState4(null);
|
|
4917
|
+
const src = backdrop?.image ?? "";
|
|
4918
|
+
useEffect7(() => {
|
|
4919
|
+
if (!src) {
|
|
4920
|
+
setImage(null);
|
|
4921
|
+
return;
|
|
4922
|
+
}
|
|
4923
|
+
let live = true;
|
|
4924
|
+
const img = new Image();
|
|
4925
|
+
img.crossOrigin = "anonymous";
|
|
4926
|
+
img.onload = () => live && setImage(img);
|
|
4927
|
+
img.onerror = () => live && setImage(null);
|
|
4928
|
+
img.src = src;
|
|
4929
|
+
return () => {
|
|
4930
|
+
live = false;
|
|
4931
|
+
};
|
|
4932
|
+
}, [src]);
|
|
4933
|
+
const key = JSON.stringify({ backdrop: backdrop ?? null, w: size.width, h: size.height, loaded: !!image });
|
|
4934
|
+
useEffect7(() => {
|
|
4935
|
+
if (!backdrop) return;
|
|
4936
|
+
const previous = scene.background;
|
|
4937
|
+
const texture = paintBackdrop(backdrop, size.width, size.height, image);
|
|
4938
|
+
scene.background = texture;
|
|
4939
|
+
return () => {
|
|
4940
|
+
scene.background = previous;
|
|
4941
|
+
texture.dispose();
|
|
4942
|
+
};
|
|
4943
|
+
}, [key]);
|
|
4944
|
+
return null;
|
|
4945
|
+
}
|
|
4946
|
+
function paintBackdrop(backdrop, width, height, image) {
|
|
4947
|
+
const w = Math.max(2, Math.round(width / 2));
|
|
4948
|
+
const h = Math.max(2, Math.round(height / 2));
|
|
4949
|
+
const canvas = document.createElement("canvas");
|
|
4950
|
+
canvas.width = w;
|
|
4951
|
+
canvas.height = h;
|
|
4952
|
+
const ctx = canvas.getContext("2d");
|
|
4953
|
+
ctx.fillStyle = backdrop.color;
|
|
4954
|
+
ctx.fillRect(0, 0, w, h);
|
|
4955
|
+
if (image && image.width > 0 && image.height > 0) {
|
|
4956
|
+
const scale = backdrop.fit === "cover" ? Math.max(w / image.width, h / image.height) : Math.min(w / image.width, h / image.height);
|
|
4957
|
+
const dw = image.width * scale;
|
|
4958
|
+
const dh = image.height * scale;
|
|
4959
|
+
ctx.save();
|
|
4960
|
+
if (backdrop.blur > 0) ctx.filter = `blur(${backdrop.blur * Math.min(w, h) * 0.06}px)`;
|
|
4961
|
+
ctx.drawImage(image, (w - dw) / 2, (h - dh) / 2, dw, dh);
|
|
4962
|
+
ctx.restore();
|
|
4963
|
+
if (backdrop.fade > 0) {
|
|
4964
|
+
ctx.globalAlpha = backdrop.fade;
|
|
4965
|
+
ctx.fillStyle = backdrop.color;
|
|
4966
|
+
ctx.fillRect(0, 0, w, h);
|
|
4967
|
+
ctx.globalAlpha = 1;
|
|
4968
|
+
}
|
|
4969
|
+
}
|
|
4970
|
+
const texture = new THREE10.CanvasTexture(canvas);
|
|
4971
|
+
texture.colorSpace = THREE10.SRGBColorSpace;
|
|
4972
|
+
return texture;
|
|
4973
|
+
}
|
|
4974
|
+
|
|
4975
|
+
// src/field/dropZones.tsx
|
|
4976
|
+
import * as THREE11 from "three";
|
|
4977
|
+
import { createContext as createContext2, useContext as useContext2, useEffect as useEffect8, useMemo as useMemo5, useRef as useRef5, useSyncExternalStore } from "react";
|
|
4717
4978
|
import { jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
4718
4979
|
var DropZoneRegistry = class {
|
|
4719
4980
|
zones = /* @__PURE__ */ new Map();
|
|
@@ -4771,10 +5032,10 @@ function DropZone(props) {
|
|
|
4771
5032
|
const registry4 = useContext2(DropZoneContext);
|
|
4772
5033
|
const { id, accept, bounds, highlight = "glow", onPlace } = props;
|
|
4773
5034
|
const place = useRef5(onPlace);
|
|
4774
|
-
|
|
5035
|
+
useEffect8(() => {
|
|
4775
5036
|
place.current = onPlace;
|
|
4776
5037
|
}, [onPlace]);
|
|
4777
|
-
|
|
5038
|
+
useEffect8(() => {
|
|
4778
5039
|
if (!registry4) return;
|
|
4779
5040
|
return registry4.register({
|
|
4780
5041
|
id,
|
|
@@ -4793,12 +5054,12 @@ function DropZoneVisual({ registry: registry4, config }) {
|
|
|
4793
5054
|
const style = config.highlight ?? "glow";
|
|
4794
5055
|
const [w, h] = config.bounds.size;
|
|
4795
5056
|
const edges = useMemo5(() => {
|
|
4796
|
-
const plane = new
|
|
4797
|
-
const geo = new
|
|
5057
|
+
const plane = new THREE11.PlaneGeometry(w, h);
|
|
5058
|
+
const geo = new THREE11.EdgesGeometry(plane);
|
|
4798
5059
|
plane.dispose();
|
|
4799
5060
|
return geo;
|
|
4800
5061
|
}, [w, h]);
|
|
4801
|
-
|
|
5062
|
+
useEffect8(() => () => edges.dispose(), [edges]);
|
|
4802
5063
|
return /* @__PURE__ */ jsxs3("group", { position: config.bounds.position, children: [
|
|
4803
5064
|
style !== "outline" && /* @__PURE__ */ jsxs3("mesh", { children: [
|
|
4804
5065
|
/* @__PURE__ */ jsx6("planeGeometry", { args: [w, h] }),
|
|
@@ -4817,18 +5078,18 @@ function DropZoneVisual({ registry: registry4, config }) {
|
|
|
4817
5078
|
}
|
|
4818
5079
|
|
|
4819
5080
|
// src/field/sheetGrid.ts
|
|
4820
|
-
import { z as
|
|
4821
|
-
var sheetLayoutSchema =
|
|
4822
|
-
rows:
|
|
4823
|
-
columns:
|
|
5081
|
+
import { z as z22 } from "zod";
|
|
5082
|
+
var sheetLayoutSchema = z22.object({
|
|
5083
|
+
rows: z22.number().int().min(1).max(12).default(2),
|
|
5084
|
+
columns: z22.number().int().min(1).max(12).default(5),
|
|
4824
5085
|
/** World-units gap between slots. Stamps are printed in register — no jitter. */
|
|
4825
|
-
gutter:
|
|
5086
|
+
gutter: z22.number().min(0).max(1).default(0.08),
|
|
4826
5087
|
/** Slot footprint in world units (the paper preset should match). */
|
|
4827
|
-
cellWidth:
|
|
4828
|
-
cellHeight:
|
|
5088
|
+
cellWidth: z22.number().min(0.1).max(4).default(0.72),
|
|
5089
|
+
cellHeight: z22.number().min(0.1).max(4).default(0.86),
|
|
4829
5090
|
/** Render the shared backing sheet behind the grid. */
|
|
4830
|
-
backing:
|
|
4831
|
-
backingMargin:
|
|
5091
|
+
backing: z22.boolean().default(true),
|
|
5092
|
+
backingMargin: z22.number().min(0).max(1).default(0.12)
|
|
4832
5093
|
});
|
|
4833
5094
|
var SHEET_LIFT = 0.012;
|
|
4834
5095
|
function withSheetCellFromPaper(parsed, rawOptions, paperDims) {
|
|
@@ -4875,18 +5136,18 @@ function tornEdgesOnDetach(i, o) {
|
|
|
4875
5136
|
}
|
|
4876
5137
|
|
|
4877
5138
|
// src/stage/path.ts
|
|
4878
|
-
import { z as
|
|
4879
|
-
var walkPathSchema =
|
|
5139
|
+
import { z as z23 } from "zod";
|
|
5140
|
+
var walkPathSchema = z23.object({
|
|
4880
5141
|
/**
|
|
4881
5142
|
* Control points on the ground plane, [x, z]. The default walks away from
|
|
4882
5143
|
* the camera down -Z — the shot every reference image is composed on.
|
|
4883
5144
|
*/
|
|
4884
|
-
points:
|
|
5145
|
+
points: z23.array(z23.tuple([z23.number(), z23.number()])).min(2).default([
|
|
4885
5146
|
[0, 9],
|
|
4886
5147
|
[0, -9]
|
|
4887
5148
|
]),
|
|
4888
5149
|
/** Join the last point back to the first: an endless walk, and the only form `phase` can slide. */
|
|
4889
|
-
closed:
|
|
5150
|
+
closed: z23.boolean().default(false)
|
|
4890
5151
|
});
|
|
4891
5152
|
var SAMPLES_PER_SEGMENT = 24;
|
|
4892
5153
|
var EPSILON = 1e-6;
|
|
@@ -5001,7 +5262,7 @@ function getWalkPath(options) {
|
|
|
5001
5262
|
}
|
|
5002
5263
|
|
|
5003
5264
|
// src/field/layouts/index.ts
|
|
5004
|
-
import { z as
|
|
5265
|
+
import { z as z24 } from "zod";
|
|
5005
5266
|
var DEFAULT_SHEET = { width: 1, height: 1.4 };
|
|
5006
5267
|
var TAU3 = Math.PI * 2;
|
|
5007
5268
|
var DEG7 = Math.PI / 180;
|
|
@@ -5013,9 +5274,9 @@ function jitter2(seed, i) {
|
|
|
5013
5274
|
function ramp(i, n) {
|
|
5014
5275
|
return n > 1 ? i / (n - 1) : 1;
|
|
5015
5276
|
}
|
|
5016
|
-
var ringSchema =
|
|
5017
|
-
radius:
|
|
5018
|
-
tiltDeg:
|
|
5277
|
+
var ringSchema = z24.object({
|
|
5278
|
+
radius: z24.number().min(0.5).max(12).default(2.6),
|
|
5279
|
+
tiltDeg: z24.number().min(-45).max(45).default(8)
|
|
5019
5280
|
});
|
|
5020
5281
|
var ring = {
|
|
5021
5282
|
id: "ring",
|
|
@@ -5033,15 +5294,15 @@ var ring = {
|
|
|
5033
5294
|
};
|
|
5034
5295
|
}
|
|
5035
5296
|
};
|
|
5036
|
-
var fanSchema =
|
|
5297
|
+
var fanSchema = z24.object({
|
|
5037
5298
|
/** Total angular sweep from the first sheet to the last, degrees. */
|
|
5038
|
-
sweep:
|
|
5299
|
+
sweep: z24.number().min(0).max(180).default(72),
|
|
5039
5300
|
/** Where the shared pin sits, in half-sheet-heights below center. 1 = the bottom edge. */
|
|
5040
|
-
hinge:
|
|
5301
|
+
hinge: z24.number().min(0).max(4).default(1.15),
|
|
5041
5302
|
/** Thickness step so the sheets stack in order instead of z-fighting. */
|
|
5042
|
-
lift:
|
|
5303
|
+
lift: z24.number().min(2e-3).max(0.08).default(0.012),
|
|
5043
5304
|
/** How much flatter the middle of the fan sits than its outer sheets. */
|
|
5044
|
-
bow:
|
|
5305
|
+
bow: z24.number().min(0).max(1).default(0.7)
|
|
5045
5306
|
});
|
|
5046
5307
|
var fan = {
|
|
5047
5308
|
id: "fan",
|
|
@@ -5061,16 +5322,16 @@ var fan = {
|
|
|
5061
5322
|
};
|
|
5062
5323
|
}
|
|
5063
5324
|
};
|
|
5064
|
-
var spreadSchema =
|
|
5325
|
+
var spreadSchema = z24.object({
|
|
5065
5326
|
/** How far each sheet slides past the one below it. */
|
|
5066
|
-
slip:
|
|
5327
|
+
slip: z24.number().min(0.02).max(2).default(0.3),
|
|
5067
5328
|
/** Direction of the slide, degrees. 0 slides right, 90 slides up. */
|
|
5068
|
-
angle:
|
|
5069
|
-
lift:
|
|
5329
|
+
angle: z24.number().min(-180).max(180).default(28),
|
|
5330
|
+
lift: z24.number().min(2e-3).max(0.08).default(0.012),
|
|
5070
5331
|
/** How much more the sheets at the far end of the slide bow. */
|
|
5071
|
-
bow:
|
|
5332
|
+
bow: z24.number().min(0).max(1).default(0.6),
|
|
5072
5333
|
/** Nothing hand-slid is perfectly square — a touch of per-sheet rotation. */
|
|
5073
|
-
drift:
|
|
5334
|
+
drift: z24.number().min(0).max(1).default(0.15)
|
|
5074
5335
|
});
|
|
5075
5336
|
var spread = {
|
|
5076
5337
|
id: "spread",
|
|
@@ -5088,15 +5349,15 @@ var spread = {
|
|
|
5088
5349
|
};
|
|
5089
5350
|
}
|
|
5090
5351
|
};
|
|
5091
|
-
var pileSchema =
|
|
5352
|
+
var pileSchema = z24.object({
|
|
5092
5353
|
/** How far sheets wander from the center of the heap. */
|
|
5093
|
-
scatter:
|
|
5354
|
+
scatter: z24.number().min(0).max(2).default(0.22),
|
|
5094
5355
|
/** Widest angle a sheet sits off square, degrees. */
|
|
5095
|
-
turn:
|
|
5096
|
-
lift:
|
|
5356
|
+
turn: z24.number().min(0).max(180).default(24),
|
|
5357
|
+
lift: z24.number().min(2e-3).max(0.08).default(0.011),
|
|
5097
5358
|
/** How flat the sheets underneath are pressed by the ones on top. */
|
|
5098
|
-
press:
|
|
5099
|
-
seed:
|
|
5359
|
+
press: z24.number().min(0).max(1).default(0.85),
|
|
5360
|
+
seed: z24.number().int().min(0).max(9999).default(3)
|
|
5100
5361
|
});
|
|
5101
5362
|
var pile = {
|
|
5102
5363
|
id: "pile",
|
|
@@ -5112,12 +5373,12 @@ var pile = {
|
|
|
5112
5373
|
};
|
|
5113
5374
|
}
|
|
5114
5375
|
};
|
|
5115
|
-
var wallSchema =
|
|
5116
|
-
gapX:
|
|
5117
|
-
gapY:
|
|
5118
|
-
jitterAmt:
|
|
5376
|
+
var wallSchema = z24.object({
|
|
5377
|
+
gapX: z24.number().min(0.05).max(1).default(0.22),
|
|
5378
|
+
gapY: z24.number().min(0.05).max(1).default(0.3),
|
|
5379
|
+
jitterAmt: z24.number().min(0).max(1).default(0.25),
|
|
5119
5380
|
/** Spread of sag across the wall — no two pinned sheets hang alike. */
|
|
5120
|
-
sag:
|
|
5381
|
+
sag: z24.number().min(0).max(1).default(0.45)
|
|
5121
5382
|
});
|
|
5122
5383
|
var wall = {
|
|
5123
5384
|
id: "wall",
|
|
@@ -5143,15 +5404,15 @@ var wall = {
|
|
|
5143
5404
|
};
|
|
5144
5405
|
}
|
|
5145
5406
|
};
|
|
5146
|
-
var spillSchema =
|
|
5147
|
-
spreadX:
|
|
5148
|
-
spreadY:
|
|
5149
|
-
depth:
|
|
5407
|
+
var spillSchema = z24.object({
|
|
5408
|
+
spreadX: z24.number().min(0.5).max(8).default(2.4),
|
|
5409
|
+
spreadY: z24.number().min(0.5).max(8).default(1.5),
|
|
5410
|
+
depth: z24.number().min(0).max(6).default(1.6),
|
|
5150
5411
|
/** How far sheets pitch and roll out of the picture plane. */
|
|
5151
|
-
tumble:
|
|
5412
|
+
tumble: z24.number().min(0).max(1).default(0.5),
|
|
5152
5413
|
/** Spread of bend across the sheets — a spill does not fold them alike. */
|
|
5153
|
-
vary:
|
|
5154
|
-
seed:
|
|
5414
|
+
vary: z24.number().min(0).max(1).default(0.6),
|
|
5415
|
+
seed: z24.number().int().min(0).max(9999).default(7)
|
|
5155
5416
|
});
|
|
5156
5417
|
var spill = {
|
|
5157
5418
|
id: "spill",
|
|
@@ -5176,13 +5437,13 @@ var spill = {
|
|
|
5176
5437
|
};
|
|
5177
5438
|
}
|
|
5178
5439
|
};
|
|
5179
|
-
var sweepSchema =
|
|
5180
|
-
columns:
|
|
5440
|
+
var sweepSchema = z24.object({
|
|
5441
|
+
columns: z24.number().int().min(1).max(24).default(5),
|
|
5181
5442
|
/** Breathing room around each specimen. */
|
|
5182
|
-
gap:
|
|
5443
|
+
gap: z24.number().min(0).max(2).default(0.22),
|
|
5183
5444
|
/** Deformation at the first specimen and at the last. */
|
|
5184
|
-
from:
|
|
5185
|
-
to:
|
|
5445
|
+
from: z24.number().min(0).max(1).default(0),
|
|
5446
|
+
to: z24.number().min(0).max(1).default(1)
|
|
5186
5447
|
});
|
|
5187
5448
|
var sweep = {
|
|
5188
5449
|
id: "sweep",
|
|
@@ -5206,15 +5467,15 @@ var sweep = {
|
|
|
5206
5467
|
};
|
|
5207
5468
|
}
|
|
5208
5469
|
};
|
|
5209
|
-
var bookSchema =
|
|
5470
|
+
var bookSchema = z24.object({
|
|
5210
5471
|
/** How far the outermost page lifts off the block, degrees. */
|
|
5211
|
-
spread:
|
|
5472
|
+
spread: z24.number().min(0).max(150).default(55),
|
|
5212
5473
|
/** Fraction of the pages bound to the left. 0 = a one-sided sample book. */
|
|
5213
|
-
split:
|
|
5474
|
+
split: z24.number().min(0).max(1).default(0.5),
|
|
5214
5475
|
/** Page thickness — the gap between pages of one block. */
|
|
5215
|
-
lift:
|
|
5476
|
+
lift: z24.number().min(1e-3).max(0.05).default(8e-3),
|
|
5216
5477
|
/** How much more a lifted page arcs than one lying flat in the block. */
|
|
5217
|
-
gutter:
|
|
5478
|
+
gutter: z24.number().min(0).max(1).default(0.6)
|
|
5218
5479
|
});
|
|
5219
5480
|
var book = {
|
|
5220
5481
|
id: "book",
|
|
@@ -5241,11 +5502,11 @@ var book = {
|
|
|
5241
5502
|
};
|
|
5242
5503
|
}
|
|
5243
5504
|
};
|
|
5244
|
-
var accordionSchema =
|
|
5505
|
+
var accordionSchema = z24.object({
|
|
5245
5506
|
/** How far each panel tilts off the strip's line, degrees. 0 = flat, 90 = shut. */
|
|
5246
|
-
angle:
|
|
5507
|
+
angle: z24.number().min(0).max(89).default(55),
|
|
5247
5508
|
/** A concertina holds its creases — how much bow the panels keep. */
|
|
5248
|
-
slack:
|
|
5509
|
+
slack: z24.number().min(0).max(1).default(0.15)
|
|
5249
5510
|
});
|
|
5250
5511
|
var accordion = {
|
|
5251
5512
|
id: "accordion",
|
|
@@ -5264,16 +5525,16 @@ var accordion = {
|
|
|
5264
5525
|
};
|
|
5265
5526
|
}
|
|
5266
5527
|
};
|
|
5267
|
-
var rackSchema =
|
|
5528
|
+
var rackSchema = z24.object({
|
|
5268
5529
|
/** Gap along the row, as a fraction of the paper's width. Under 1 they overlap. */
|
|
5269
|
-
spacing:
|
|
5530
|
+
spacing: z24.number().min(0.05).max(2).default(0.82),
|
|
5270
5531
|
/** How far a sheet leans back off vertical, degrees. */
|
|
5271
|
-
lean:
|
|
5532
|
+
lean: z24.number().min(0).max(70).default(16),
|
|
5272
5533
|
/** How much that lean differs sheet to sheet — nothing propped is uniform. */
|
|
5273
|
-
vary:
|
|
5534
|
+
vary: z24.number().min(0).max(1).default(0.55),
|
|
5274
5535
|
/** Small rotations off square. */
|
|
5275
|
-
sway:
|
|
5276
|
-
seed:
|
|
5536
|
+
sway: z24.number().min(0).max(1).default(0.35),
|
|
5537
|
+
seed: z24.number().int().min(0).max(9999).default(5)
|
|
5277
5538
|
});
|
|
5278
5539
|
var rack = {
|
|
5279
5540
|
id: "rack",
|
|
@@ -5297,19 +5558,19 @@ var rack = {
|
|
|
5297
5558
|
};
|
|
5298
5559
|
}
|
|
5299
5560
|
};
|
|
5300
|
-
var colonnadeSchema =
|
|
5561
|
+
var colonnadeSchema = z24.object({
|
|
5301
5562
|
/** The walk the colonnade is built along — see `stage/path`. */
|
|
5302
5563
|
path: walkPathSchema.default({}),
|
|
5303
5564
|
/** Half-width of the clear aisle: how far each banner stands off the walk line. */
|
|
5304
|
-
aisle:
|
|
5565
|
+
aisle: z24.number().min(0.2).max(20).default(2.4),
|
|
5305
5566
|
/** How much that gap opens and closes along the walk. Nothing hung by hand is a corridor. */
|
|
5306
|
-
breathe:
|
|
5567
|
+
breathe: z24.number().min(0).max(1).default(0.3),
|
|
5307
5568
|
/** Widest angle a banner turns off square to the aisle, degrees. */
|
|
5308
|
-
twist:
|
|
5569
|
+
twist: z24.number().min(0).max(90).default(22),
|
|
5309
5570
|
/** Fraction of the walk left clear at each end, so the figure has somewhere to enter from. */
|
|
5310
|
-
margin:
|
|
5571
|
+
margin: z24.number().min(0).max(0.45).default(0.05),
|
|
5311
5572
|
/** Spread of banner heights, 0..1. */
|
|
5312
|
-
rise:
|
|
5573
|
+
rise: z24.number().min(0).max(1).default(0.28),
|
|
5313
5574
|
/**
|
|
5314
5575
|
* How far the banners lift off the floor, as a fraction of their height.
|
|
5315
5576
|
*
|
|
@@ -5323,10 +5584,10 @@ var colonnadeSchema = z25.object({
|
|
|
5323
5584
|
* The bound used to be 0, so the one thing this option documented itself
|
|
5324
5585
|
* as doing was the one thing it could not do.
|
|
5325
5586
|
*/
|
|
5326
|
-
hover:
|
|
5587
|
+
hover: z24.number().min(-0.5).max(1).default(0),
|
|
5327
5588
|
/** Spread of deformation — no two lengths of hung paper drape alike. */
|
|
5328
|
-
drape:
|
|
5329
|
-
seed:
|
|
5589
|
+
drape: z24.number().min(0).max(1).default(0.5),
|
|
5590
|
+
seed: z24.number().int().min(0).max(9999).default(2)
|
|
5330
5591
|
});
|
|
5331
5592
|
function colonnadeStop(i, n, margin) {
|
|
5332
5593
|
const side = i % 2 === 0 ? 1 : -1;
|
|
@@ -5401,10 +5662,25 @@ registerLayout(colonnade);
|
|
|
5401
5662
|
registerLayout(sheet);
|
|
5402
5663
|
|
|
5403
5664
|
// src/PaperField.tsx
|
|
5404
|
-
import * as
|
|
5665
|
+
import * as THREE16 from "three";
|
|
5405
5666
|
import { gsap as gsap5 } from "gsap";
|
|
5406
|
-
import { Canvas, useFrame as useFrame5, useThree as
|
|
5407
|
-
import { forwardRef as forwardRef2, useEffect as
|
|
5667
|
+
import { Canvas, useFrame as useFrame5, useThree as useThree6 } from "@react-three/fiber";
|
|
5668
|
+
import { forwardRef as forwardRef2, useEffect as useEffect14, useMemo as useMemo9, useRef as useRef8 } from "react";
|
|
5669
|
+
|
|
5670
|
+
// src/scene/release.tsx
|
|
5671
|
+
import { useThree as useThree4 } from "@react-three/fiber";
|
|
5672
|
+
import { useEffect as useEffect9 } from "react";
|
|
5673
|
+
function ReleaseContextOnUnmount() {
|
|
5674
|
+
const gl = useThree4((s) => s.gl);
|
|
5675
|
+
useEffect9(
|
|
5676
|
+
() => () => {
|
|
5677
|
+
gl.forceContextLoss();
|
|
5678
|
+
gl.dispose();
|
|
5679
|
+
},
|
|
5680
|
+
[gl]
|
|
5681
|
+
);
|
|
5682
|
+
return null;
|
|
5683
|
+
}
|
|
5408
5684
|
|
|
5409
5685
|
// src/field/slots.ts
|
|
5410
5686
|
var EMPTY_SET = /* @__PURE__ */ new Set();
|
|
@@ -5452,24 +5728,24 @@ function resolveFieldSlotConfig(slot, fallback, index, layoutId, layoutOptions)
|
|
|
5452
5728
|
}
|
|
5453
5729
|
|
|
5454
5730
|
// src/field/fieldGroup.tsx
|
|
5455
|
-
import * as
|
|
5731
|
+
import * as THREE13 from "three";
|
|
5456
5732
|
import { gsap as gsap3 } from "gsap";
|
|
5457
5733
|
import { useFrame as useFrame3 } from "@react-three/fiber";
|
|
5458
|
-
import { useEffect as
|
|
5734
|
+
import { useEffect as useEffect11, useMemo as useMemo6, useRef as useRef6 } from "react";
|
|
5459
5735
|
import CustomShaderMaterial2 from "three-custom-shader-material";
|
|
5460
5736
|
|
|
5461
5737
|
// src/content/atlas.ts
|
|
5462
|
-
import * as
|
|
5463
|
-
import { useEffect as
|
|
5738
|
+
import * as THREE12 from "three";
|
|
5739
|
+
import { useEffect as useEffect10, useState as useState5 } from "react";
|
|
5464
5740
|
var MAX_ATLAS = 4096;
|
|
5465
5741
|
function atlasGrid(count, aspect = 1) {
|
|
5466
5742
|
const cols = Math.max(1, Math.min(count, Math.ceil(Math.sqrt(count * Math.max(aspect, 0.01)))));
|
|
5467
5743
|
return { cols, rows: Math.max(1, Math.ceil(count / cols)) };
|
|
5468
5744
|
}
|
|
5469
5745
|
function useContentAtlas(contents, sheet2, stock) {
|
|
5470
|
-
const [atlas, setAtlas] =
|
|
5746
|
+
const [atlas, setAtlas] = useState5(null);
|
|
5471
5747
|
const stableContents = useStable(contents);
|
|
5472
|
-
|
|
5748
|
+
useEffect10(() => {
|
|
5473
5749
|
let disposed = false;
|
|
5474
5750
|
const aspect = sheet2.height / sheet2.width;
|
|
5475
5751
|
const { cols, rows } = atlasGrid(contents.length, aspect);
|
|
@@ -5485,8 +5761,8 @@ function useContentAtlas(contents, sheet2, stock) {
|
|
|
5485
5761
|
const ctx = canvas.getContext("2d");
|
|
5486
5762
|
ctx.fillStyle = stock.color;
|
|
5487
5763
|
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
5488
|
-
const texture = new
|
|
5489
|
-
texture.colorSpace =
|
|
5764
|
+
const texture = new THREE12.CanvasTexture(canvas);
|
|
5765
|
+
texture.colorSpace = THREE12.SRGBColorSpace;
|
|
5490
5766
|
texture.anisotropy = 4;
|
|
5491
5767
|
setAtlas({ texture, cols, rows });
|
|
5492
5768
|
const drawTile = (index, tile) => {
|
|
@@ -5655,7 +5931,7 @@ function fieldShapeStack(config, progress) {
|
|
|
5655
5931
|
|
|
5656
5932
|
// src/field/fieldGroup.tsx
|
|
5657
5933
|
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
5658
|
-
var scratchObj = new
|
|
5934
|
+
var scratchObj = new THREE13.Object3D();
|
|
5659
5935
|
var scratchAero = { position: [0, 0, 0], rotation: [0, 0, 0] };
|
|
5660
5936
|
var FIELD_SEGMENT_CAP = 48;
|
|
5661
5937
|
var FIELD_AUTO_CEILING = 128;
|
|
@@ -5716,28 +5992,28 @@ function FieldGroup({
|
|
|
5716
5992
|
atlasIdx[i] = i;
|
|
5717
5993
|
phase[i] = indices[i] * 0.618034 % 1 * 4;
|
|
5718
5994
|
}
|
|
5719
|
-
geo.setAttribute("aAtlas", new
|
|
5720
|
-
geo.setAttribute("aPhase", new
|
|
5721
|
-
geo.setAttribute("aBias", new
|
|
5995
|
+
geo.setAttribute("aAtlas", new THREE13.InstancedBufferAttribute(atlasIdx, 1));
|
|
5996
|
+
geo.setAttribute("aPhase", new THREE13.InstancedBufferAttribute(phase, 1));
|
|
5997
|
+
geo.setAttribute("aBias", new THREE13.InstancedBufferAttribute(bias, 1));
|
|
5722
5998
|
return geo;
|
|
5723
5999
|
}, [JSON.stringify(config.sheet), structureKey, count, autoCeiling]);
|
|
5724
|
-
|
|
6000
|
+
useEffect11(() => () => geometry.dispose(), [geometry]);
|
|
5725
6001
|
const atlas = useContentAtlas(contents, config.sheet, stock);
|
|
5726
6002
|
const shader = useMemo6(() => {
|
|
5727
6003
|
const composed = buildDisplacementGLSL(initialStack, config.sheet);
|
|
5728
6004
|
const uniforms = {};
|
|
5729
6005
|
for (const [name, value] of Object.entries(composed.uniforms)) {
|
|
5730
6006
|
uniforms[name] = {
|
|
5731
|
-
value: Array.isArray(value) && value.length === 2 ? new
|
|
6007
|
+
value: Array.isArray(value) && value.length === 2 ? new THREE13.Vector2(...value) : value
|
|
5732
6008
|
};
|
|
5733
6009
|
}
|
|
5734
6010
|
uniforms.uPlTime = { value: 0 };
|
|
5735
6011
|
uniforms.uAtlas = { value: null };
|
|
5736
|
-
uniforms.uAtlasGrid = { value: new
|
|
6012
|
+
uniforms.uAtlasGrid = { value: new THREE13.Vector2(1, 1) };
|
|
5737
6013
|
uniforms.uBackDarken = {
|
|
5738
6014
|
value: 1 - Math.min(0.45, 0.12 + config.sheet.thickness * 0.9) * stock.opacity
|
|
5739
6015
|
};
|
|
5740
|
-
uniforms.uStockColor = { value: new
|
|
6016
|
+
uniforms.uStockColor = { value: new THREE13.Color(stock.color) };
|
|
5741
6017
|
uniforms.uShowThrough = { value: config.surface.showThrough ?? stock.showThrough };
|
|
5742
6018
|
Object.assign(uniforms, translucencyUniforms(config.surface.translucency ?? stock.translucency, rig));
|
|
5743
6019
|
return {
|
|
@@ -5752,19 +6028,19 @@ function FieldGroup({
|
|
|
5752
6028
|
config.surface.showThrough,
|
|
5753
6029
|
config.surface.translucency
|
|
5754
6030
|
]);
|
|
5755
|
-
|
|
6031
|
+
useEffect11(() => {
|
|
5756
6032
|
const values = translucencyValues(config.surface.translucency ?? stock.translucency, rig);
|
|
5757
6033
|
shader.uniforms.uTranslucency.value = values.translucency;
|
|
5758
6034
|
shader.uniforms.uBackLightDir.value.copy(values.direction);
|
|
5759
6035
|
shader.uniforms.uBackLightColor.value.copy(values.color);
|
|
5760
6036
|
shader.uniforms.uAmbientTransmission.value = values.ambient;
|
|
5761
6037
|
}, [shader, rig, config.surface.translucency, stock.translucency]);
|
|
5762
|
-
|
|
6038
|
+
useEffect11(() => {
|
|
5763
6039
|
if (!atlas) return;
|
|
5764
6040
|
shader.uniforms.uAtlas.value = atlas.texture;
|
|
5765
6041
|
shader.uniforms.uAtlasGrid.value.set(atlas.cols, atlas.rows);
|
|
5766
6042
|
}, [atlas, shader]);
|
|
5767
|
-
|
|
6043
|
+
useEffect11(() => {
|
|
5768
6044
|
if (!behavior || shared.reduced) return;
|
|
5769
6045
|
const state = { p: progressRef.current };
|
|
5770
6046
|
const tween = gsap3.to(state, {
|
|
@@ -5792,7 +6068,7 @@ function FieldGroup({
|
|
|
5792
6068
|
for (const [name, value] of Object.entries(values)) {
|
|
5793
6069
|
const uniform = shader.uniforms[name];
|
|
5794
6070
|
if (!uniform) continue;
|
|
5795
|
-
if (uniform.value instanceof
|
|
6071
|
+
if (uniform.value instanceof THREE13.Vector2 && Array.isArray(value)) {
|
|
5796
6072
|
uniform.value.set(value[0], value[1]);
|
|
5797
6073
|
} else {
|
|
5798
6074
|
uniform.value = value;
|
|
@@ -5876,13 +6152,13 @@ function FieldGroup({
|
|
|
5876
6152
|
children: /* @__PURE__ */ jsx7(
|
|
5877
6153
|
CustomShaderMaterial2,
|
|
5878
6154
|
{
|
|
5879
|
-
baseMaterial:
|
|
6155
|
+
baseMaterial: THREE13.MeshStandardMaterial,
|
|
5880
6156
|
vertexShader: shader.vertexShader,
|
|
5881
6157
|
fragmentShader: shader.fragmentShader,
|
|
5882
6158
|
uniforms: shader.uniforms,
|
|
5883
6159
|
roughness: stock.roughness,
|
|
5884
6160
|
metalness: 0,
|
|
5885
|
-
side:
|
|
6161
|
+
side: THREE13.DoubleSide
|
|
5886
6162
|
},
|
|
5887
6163
|
`${structureKey}:${count}`
|
|
5888
6164
|
)
|
|
@@ -5928,8 +6204,8 @@ var easeOut = (t) => 1 - (1 - t) ** 3;
|
|
|
5928
6204
|
var easeInOut = (t) => t < 0.5 ? 2 * t * t : 1 - (-2 * t + 2) ** 2 / 2;
|
|
5929
6205
|
|
|
5930
6206
|
// src/field/backingSheet.tsx
|
|
5931
|
-
import * as
|
|
5932
|
-
import { useEffect as
|
|
6207
|
+
import * as THREE14 from "three";
|
|
6208
|
+
import { useEffect as useEffect12, useMemo as useMemo7 } from "react";
|
|
5933
6209
|
|
|
5934
6210
|
// src/content/backing.ts
|
|
5935
6211
|
function silhouetteRects(o, count) {
|
|
@@ -6010,14 +6286,14 @@ function BackingSheet({
|
|
|
6010
6286
|
c.height = Math.max(2, Math.round(height * scale));
|
|
6011
6287
|
return c;
|
|
6012
6288
|
}, [width, height]);
|
|
6013
|
-
const texture = useMemo7(() => canvas ? new
|
|
6289
|
+
const texture = useMemo7(() => canvas ? new THREE14.CanvasTexture(canvas) : null, [canvas]);
|
|
6014
6290
|
const removedKey = [...removed].sort((a, b) => a - b).join(",");
|
|
6015
|
-
|
|
6291
|
+
useEffect12(() => {
|
|
6016
6292
|
if (!canvas || !texture) return;
|
|
6017
6293
|
drawBacking(canvas, { options, count, tint: BACKING_TINT, removed });
|
|
6018
6294
|
texture.needsUpdate = true;
|
|
6019
6295
|
}, [canvas, texture, JSON.stringify(options), count, removedKey]);
|
|
6020
|
-
|
|
6296
|
+
useEffect12(() => () => texture?.dispose(), [texture]);
|
|
6021
6297
|
return /* @__PURE__ */ jsxs4("mesh", { receiveShadow: true, children: [
|
|
6022
6298
|
/* @__PURE__ */ jsx8("planeGeometry", { args: [width, height] }),
|
|
6023
6299
|
/* @__PURE__ */ jsx8("meshStandardMaterial", { map: texture, color: "#ffffff", roughness: 0.92, metalness: 0 })
|
|
@@ -6025,10 +6301,10 @@ function BackingSheet({
|
|
|
6025
6301
|
}
|
|
6026
6302
|
|
|
6027
6303
|
// src/field/interactiveField.tsx
|
|
6028
|
-
import * as
|
|
6304
|
+
import * as THREE15 from "three";
|
|
6029
6305
|
import { gsap as gsap4 } from "gsap";
|
|
6030
|
-
import { useFrame as useFrame4, useThree as
|
|
6031
|
-
import { useContext as useContext3, useEffect as
|
|
6306
|
+
import { useFrame as useFrame4, useThree as useThree5 } from "@react-three/fiber";
|
|
6307
|
+
import { useContext as useContext3, useEffect as useEffect13, useMemo as useMemo8, useRef as useRef7, useState as useState6 } from "react";
|
|
6032
6308
|
import { jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
6033
6309
|
var PICK_BEHAVIORS = /* @__PURE__ */ new Set(["peel", "carry"]);
|
|
6034
6310
|
function InteractiveField(props) {
|
|
@@ -6038,12 +6314,12 @@ function InteractiveField(props) {
|
|
|
6038
6314
|
const reduced = usePrefersReducedMotion(props.reducedMotion);
|
|
6039
6315
|
const contextRegistry = useContext3(DropZoneContext);
|
|
6040
6316
|
const registry4 = useMemo8(() => contextRegistry ?? new DropZoneRegistry(), [contextRegistry]);
|
|
6041
|
-
const camera =
|
|
6042
|
-
const gl =
|
|
6043
|
-
const controls =
|
|
6044
|
-
const [removed, setRemoved] =
|
|
6045
|
-
const [slotPatches, setSlotPatches] =
|
|
6046
|
-
const [slotStates, setSlotStates] =
|
|
6317
|
+
const camera = useThree5((s) => s.camera);
|
|
6318
|
+
const gl = useThree5((s) => s.gl);
|
|
6319
|
+
const controls = useThree5((s) => s.controls);
|
|
6320
|
+
const [removed, setRemoved] = useState6(EMPTY_SET);
|
|
6321
|
+
const [slotPatches, setSlotPatches] = useState6({});
|
|
6322
|
+
const [slotStates, setSlotStates] = useState6({});
|
|
6047
6323
|
const slotConfigs = useMemo8(
|
|
6048
6324
|
() => papers.map((slot, i) => {
|
|
6049
6325
|
const config = resolveFieldSlotConfig(slot, fallback, i, layoutId, layoutOptions);
|
|
@@ -6078,10 +6354,10 @@ function InteractiveField(props) {
|
|
|
6078
6354
|
}
|
|
6079
6355
|
props.onSlotStateChange?.(i, state);
|
|
6080
6356
|
};
|
|
6081
|
-
const raycaster = useMemo8(() => new
|
|
6082
|
-
const planeScratch = useMemo8(() => new
|
|
6083
|
-
const pointScratch = useMemo8(() => new
|
|
6084
|
-
const ndcScratch = useMemo8(() => new
|
|
6357
|
+
const raycaster = useMemo8(() => new THREE15.Raycaster(), []);
|
|
6358
|
+
const planeScratch = useMemo8(() => new THREE15.Plane(new THREE15.Vector3(0, 0, 1), 0), []);
|
|
6359
|
+
const pointScratch = useMemo8(() => new THREE15.Vector3(), []);
|
|
6360
|
+
const ndcScratch = useMemo8(() => new THREE15.Vector2(), []);
|
|
6085
6361
|
const planePoint = (clientX, clientY, planeZ) => {
|
|
6086
6362
|
const rect = gl.domElement.getBoundingClientRect();
|
|
6087
6363
|
ndcScratch.set(
|
|
@@ -6244,12 +6520,12 @@ function InteractiveField(props) {
|
|
|
6244
6520
|
if (carried.pointerId !== null && e.pointerId !== carried.pointerId) return;
|
|
6245
6521
|
const name = slotName(carried.slot);
|
|
6246
6522
|
const zone = zonesLive().find(
|
|
6247
|
-
(
|
|
6523
|
+
(z25) => zoneContains(z25, carried.x.value, carried.y.value) && zoneAccepts(z25, name)
|
|
6248
6524
|
);
|
|
6249
6525
|
if (zone) settleInto(carried, zone);
|
|
6250
6526
|
else returnHome(carried);
|
|
6251
6527
|
};
|
|
6252
|
-
|
|
6528
|
+
useEffect13(() => {
|
|
6253
6529
|
const move = (e) => onPointerMoveRef.current(e);
|
|
6254
6530
|
const up = (e) => onPointerUpRef.current(e);
|
|
6255
6531
|
window.addEventListener("pointermove", move);
|
|
@@ -6285,12 +6561,12 @@ function InteractiveField(props) {
|
|
|
6285
6561
|
group.position.z = carried.homePose.position[2] + 0.15;
|
|
6286
6562
|
handle.set("drive", carryDrive(speed));
|
|
6287
6563
|
const lag = 0.25;
|
|
6288
|
-
group.rotation.y += (
|
|
6289
|
-
group.rotation.x += (
|
|
6564
|
+
group.rotation.y += (THREE15.MathUtils.clamp(-vx * lag, -0.6, 0.6) - group.rotation.y) * 0.12;
|
|
6565
|
+
group.rotation.x += (THREE15.MathUtils.clamp(vy * lag * 0.7, -0.5, 0.5) - group.rotation.x) * 0.12;
|
|
6290
6566
|
}
|
|
6291
6567
|
const name = slotName(carried.slot);
|
|
6292
6568
|
const zone = zonesLive().find(
|
|
6293
|
-
(
|
|
6569
|
+
(z25) => zoneContains(z25, group.position.x, group.position.y) && zoneAccepts(z25, name)
|
|
6294
6570
|
);
|
|
6295
6571
|
registry4.setHovered(zone?.id ?? null);
|
|
6296
6572
|
const targetScale = (zone ? 1.03 : 1) * carried.homePose.scale;
|
|
@@ -6306,7 +6582,7 @@ function InteractiveField(props) {
|
|
|
6306
6582
|
},
|
|
6307
6583
|
placeAtZone: (slot, zoneId) => {
|
|
6308
6584
|
const carried = carriedRef.current;
|
|
6309
|
-
const zone = zonesLive().find((
|
|
6585
|
+
const zone = zonesLive().find((z25) => z25.id === zoneId);
|
|
6310
6586
|
const group = groupRefs.current[slot];
|
|
6311
6587
|
if (!carried || carried.slot !== slot || !zone || !group) return;
|
|
6312
6588
|
group.position.x = zone.bounds.position[0];
|
|
@@ -6319,10 +6595,10 @@ function InteractiveField(props) {
|
|
|
6319
6595
|
const carried = carriedRef.current;
|
|
6320
6596
|
if (carried && carried.slot === slot && !carried.settling) returnHome(carried);
|
|
6321
6597
|
},
|
|
6322
|
-
zoneIds: () => zonesLive().map((
|
|
6598
|
+
zoneIds: () => zonesLive().map((z25) => z25.id),
|
|
6323
6599
|
slotState: (slot) => slotStates[slot] ?? "rest"
|
|
6324
6600
|
};
|
|
6325
|
-
|
|
6601
|
+
useEffect13(() => {
|
|
6326
6602
|
const ref = props.a11yRef;
|
|
6327
6603
|
if (!ref) return;
|
|
6328
6604
|
ref.current = {
|
|
@@ -6375,7 +6651,7 @@ function InteractiveField(props) {
|
|
|
6375
6651
|
}
|
|
6376
6652
|
|
|
6377
6653
|
// src/field/keyboardMirror.tsx
|
|
6378
|
-
import { useState as
|
|
6654
|
+
import { useState as useState7 } from "react";
|
|
6379
6655
|
import { jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
6380
6656
|
function fieldKeyboardStep(carry2, slot, key, controller) {
|
|
6381
6657
|
if (!carry2) {
|
|
@@ -6421,7 +6697,7 @@ function FieldKeyboardMirror({
|
|
|
6421
6697
|
papers,
|
|
6422
6698
|
controller
|
|
6423
6699
|
}) {
|
|
6424
|
-
const [carrying, setCarrying] =
|
|
6700
|
+
const [carrying, setCarrying] = useState7(null);
|
|
6425
6701
|
const paperLabel = (slot, i) => {
|
|
6426
6702
|
try {
|
|
6427
6703
|
const config = resolveConfig({ preset: slot.preset });
|
|
@@ -6553,11 +6829,11 @@ var PaperFieldMesh = forwardRef2(
|
|
|
6553
6829
|
const mountTimeRef = useRef8(-1);
|
|
6554
6830
|
const morphRef = useRef8({ from: null, t: 1 });
|
|
6555
6831
|
const prevLayout = useRef8({ id: layoutId, options: layoutOptions });
|
|
6556
|
-
const gl =
|
|
6832
|
+
const gl = useThree6((s) => s.gl);
|
|
6557
6833
|
const driver = reduced ? "none" : props.motion?.driver ?? "autoplay";
|
|
6558
6834
|
const speed = props.motion?.speed ?? 0.5;
|
|
6559
6835
|
const entranceType = reduced ? "none" : props.entrance?.type ?? "rise";
|
|
6560
|
-
|
|
6836
|
+
useEffect14(() => {
|
|
6561
6837
|
const prev = prevLayout.current;
|
|
6562
6838
|
if (prev.id !== layoutId || JSON.stringify(prev.options) !== JSON.stringify(layoutOptions)) {
|
|
6563
6839
|
morphRef.current = { from: prev, t: 0 };
|
|
@@ -6565,7 +6841,7 @@ var PaperFieldMesh = forwardRef2(
|
|
|
6565
6841
|
prevLayout.current = { id: layoutId, options: layoutOptions };
|
|
6566
6842
|
}
|
|
6567
6843
|
}, [layoutId, layoutOptions]);
|
|
6568
|
-
|
|
6844
|
+
useEffect14(() => {
|
|
6569
6845
|
if (driver !== "drag") return;
|
|
6570
6846
|
const el = gl.domElement;
|
|
6571
6847
|
let lastX = null;
|
|
@@ -6649,9 +6925,9 @@ var PaperFieldMesh = forwardRef2(
|
|
|
6649
6925
|
}
|
|
6650
6926
|
);
|
|
6651
6927
|
function FitCamera(meshProps) {
|
|
6652
|
-
const camera =
|
|
6653
|
-
const width =
|
|
6654
|
-
const height =
|
|
6928
|
+
const camera = useThree6((s) => s.camera);
|
|
6929
|
+
const width = useThree6((s) => s.size.width);
|
|
6930
|
+
const height = useThree6((s) => s.size.height);
|
|
6655
6931
|
const papersProp = useStable(meshProps.papers ?? null);
|
|
6656
6932
|
const imagesProp = useStable(meshProps.images ?? null);
|
|
6657
6933
|
const presetProp = useStable(meshProps.preset ?? null);
|
|
@@ -6664,8 +6940,8 @@ function FitCamera(meshProps) {
|
|
|
6664
6940
|
const options = resolveLayoutOptions(layoutId, layout, optionsProp, sheet2);
|
|
6665
6941
|
return { layout, n: papers.length, options, sheet: sheet2 ?? DEFAULT_SHEET };
|
|
6666
6942
|
}, [papersProp, imagesProp, presetProp, meshProps.layout, optionsProp]);
|
|
6667
|
-
|
|
6668
|
-
if (!(camera instanceof
|
|
6943
|
+
useEffect14(() => {
|
|
6944
|
+
if (!(camera instanceof THREE16.PerspectiveCamera)) return;
|
|
6669
6945
|
const { position, target } = fitCamera(
|
|
6670
6946
|
field.layout,
|
|
6671
6947
|
field.n,
|
|
@@ -6680,7 +6956,8 @@ function FitCamera(meshProps) {
|
|
|
6680
6956
|
}, [camera, width, height, field]);
|
|
6681
6957
|
return null;
|
|
6682
6958
|
}
|
|
6683
|
-
var PaperField = forwardRef2(function PaperField2({ children, className, style, ...meshProps }, ref) {
|
|
6959
|
+
var PaperField = forwardRef2(function PaperField2({ children, className, style, scene, ...meshProps }, ref) {
|
|
6960
|
+
const rig = sceneSchema.parse(scene ?? {});
|
|
6684
6961
|
const registry4 = useMemo9(() => new DropZoneRegistry(), []);
|
|
6685
6962
|
const a11yRef = useRef8(null);
|
|
6686
6963
|
const papers = useMemo9(
|
|
@@ -6696,19 +6973,11 @@ var PaperField = forwardRef2(function PaperField2({ children, className, style,
|
|
|
6696
6973
|
return /* @__PURE__ */ jsx11("div", { className, style: { width: "100%", height: "100%", ...style }, children: /* @__PURE__ */ jsxs7(DropZoneContext.Provider, { value: registry4, children: [
|
|
6697
6974
|
/* @__PURE__ */ jsxs7(Canvas, { shadows: true, camera: { position: [0, 0.6, 5.2], fov: 45 }, dpr: [1, 2], children: [
|
|
6698
6975
|
/* @__PURE__ */ jsx11(FitCamera, { ...meshProps }),
|
|
6699
|
-
/* @__PURE__ */ jsx11(
|
|
6700
|
-
/* @__PURE__ */ jsx11(
|
|
6701
|
-
"directionalLight",
|
|
6702
|
-
{
|
|
6703
|
-
position: [3, 5, 4],
|
|
6704
|
-
intensity: 1.4,
|
|
6705
|
-
castShadow: true,
|
|
6706
|
-
"shadow-mapSize": [1024, 1024],
|
|
6707
|
-
"shadow-normalBias": 0.05
|
|
6708
|
-
}
|
|
6709
|
-
),
|
|
6976
|
+
/* @__PURE__ */ jsx11(PaperBackdrop, { backdrop: rig.backdrop }),
|
|
6977
|
+
/* @__PURE__ */ jsx11(PaperLighting, { preset: rig.lighting, light: rig.light, floor: -2.4, scale: 14 }),
|
|
6710
6978
|
/* @__PURE__ */ jsx11(PaperFieldMesh, { ref, a11yControllerRef: a11yRef, ...meshProps }),
|
|
6711
|
-
children
|
|
6979
|
+
children,
|
|
6980
|
+
/* @__PURE__ */ jsx11(ReleaseContextOnUnmount, {})
|
|
6712
6981
|
] }),
|
|
6713
6982
|
interactive && /* @__PURE__ */ jsx11(FieldKeyboardMirror, { papers, controller: a11yRef })
|
|
6714
6983
|
] }) });
|
|
@@ -6758,7 +7027,8 @@ function diffConfig(config) {
|
|
|
6758
7027
|
} else if (config.physics !== "none") {
|
|
6759
7028
|
out.physics = config.physics;
|
|
6760
7029
|
}
|
|
6761
|
-
|
|
7030
|
+
const scene = diffAgainst(config.scene, sceneSchema.parse({}));
|
|
7031
|
+
if (Object.keys(scene).length > 0) out.scene = scene;
|
|
6762
7032
|
if (config.onTwos) out.onTwos = true;
|
|
6763
7033
|
if (config.states) out.states = config.states;
|
|
6764
7034
|
const meta = diffAgainst(config.meta, paperConfigSchema.parse({}).meta);
|
|
@@ -6769,14 +7039,35 @@ function jsxValue(value) {
|
|
|
6769
7039
|
if (typeof value === "string") return `"${value}"`;
|
|
6770
7040
|
return `{${JSON.stringify(value)}}`;
|
|
6771
7041
|
}
|
|
7042
|
+
function withoutUploads(value) {
|
|
7043
|
+
let replaced = 0;
|
|
7044
|
+
const walk = (node) => {
|
|
7045
|
+
if (typeof node === "string") {
|
|
7046
|
+
if (!node.startsWith("data:")) return node;
|
|
7047
|
+
replaced++;
|
|
7048
|
+
const extension = node.startsWith("data:image/png") ? "png" : "jpg";
|
|
7049
|
+
return `/paperlab-image-${replaced}.${extension}`;
|
|
7050
|
+
}
|
|
7051
|
+
if (Array.isArray(node)) return node.map(walk);
|
|
7052
|
+
if (node && typeof node === "object") {
|
|
7053
|
+
return Object.fromEntries(Object.entries(node).map(([k, v]) => [k, walk(v)]));
|
|
7054
|
+
}
|
|
7055
|
+
return node;
|
|
7056
|
+
};
|
|
7057
|
+
return { value: walk(value), replaced };
|
|
7058
|
+
}
|
|
7059
|
+
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.";
|
|
6772
7060
|
function buildJsxSnippet(config) {
|
|
6773
|
-
const
|
|
6774
|
-
delete
|
|
7061
|
+
const diffed = diffConfig(config);
|
|
7062
|
+
delete diffed.meta;
|
|
7063
|
+
const { value: diff, replaced } = withoutUploads(diffed);
|
|
6775
7064
|
const props = Object.entries(diff).map(([key, value]) => ` ${key}=${jsxValue(value)}`);
|
|
6776
7065
|
if (props.length === 0) return "<Paper />";
|
|
6777
|
-
|
|
7066
|
+
const snippet = `<Paper
|
|
6778
7067
|
${props.join("\n")}
|
|
6779
7068
|
/>`;
|
|
7069
|
+
return replaced > 0 ? `${UPLOAD_NOTE}
|
|
7070
|
+
${snippet}` : snippet;
|
|
6780
7071
|
}
|
|
6781
7072
|
|
|
6782
7073
|
// src/config/agent-payload.ts
|
|
@@ -6826,7 +7117,10 @@ function componentName(config) {
|
|
|
6826
7117
|
}
|
|
6827
7118
|
function buildAgentPayload(config) {
|
|
6828
7119
|
const name = componentName(config);
|
|
6829
|
-
const
|
|
7120
|
+
const { value: stripped, replaced } = withoutUploads(diffConfig(config));
|
|
7121
|
+
const preset = JSON.stringify(stripped, null, 2);
|
|
7122
|
+
const uploadNote = replaced > 0 ? `${UPLOAD_NOTE}
|
|
7123
|
+
` : "";
|
|
6830
7124
|
return `Integrate a Paperlab paper component into this project. (paperlab agent-payload v${AGENT_PAYLOAD_VERSION})
|
|
6831
7125
|
|
|
6832
7126
|
1. Install the dependencies:
|
|
@@ -6839,7 +7133,7 @@ function buildAgentPayload(config) {
|
|
|
6839
7133
|
\`\`\`tsx
|
|
6840
7134
|
import { Paper, type PaperConfigInput } from 'paperlab'
|
|
6841
7135
|
|
|
6842
|
-
const preset = ${preset.replace(/\n/g, "\n")} satisfies PaperConfigInput
|
|
7136
|
+
${uploadNote}const preset = ${preset.replace(/\n/g, "\n")} satisfies PaperConfigInput
|
|
6843
7137
|
|
|
6844
7138
|
export function ${name}() {
|
|
6845
7139
|
return <Paper preset={preset} />
|
|
@@ -6869,11 +7163,17 @@ export {
|
|
|
6869
7163
|
segmentsForArc,
|
|
6870
7164
|
segmentsForSine,
|
|
6871
7165
|
stockNames,
|
|
7166
|
+
washSchema,
|
|
7167
|
+
contentNames,
|
|
7168
|
+
contentSchemaFor,
|
|
6872
7169
|
paperEdges,
|
|
6873
7170
|
behaviorConfigSchema,
|
|
6874
7171
|
physicsNames,
|
|
6875
7172
|
clothConfigSchema,
|
|
6876
7173
|
lightingNames,
|
|
7174
|
+
lightSchema,
|
|
7175
|
+
backdropSchema,
|
|
7176
|
+
sceneSchema,
|
|
6877
7177
|
coreStateNames,
|
|
6878
7178
|
stateDefSchema,
|
|
6879
7179
|
paperStatesSchema,
|
|
@@ -6897,7 +7197,6 @@ export {
|
|
|
6897
7197
|
getBehavior,
|
|
6898
7198
|
listBehaviors,
|
|
6899
7199
|
idleNames,
|
|
6900
|
-
lightSchema,
|
|
6901
7200
|
lightAngles,
|
|
6902
7201
|
resolveLighting,
|
|
6903
7202
|
LightRig,
|
|
@@ -6913,6 +7212,8 @@ export {
|
|
|
6913
7212
|
PaperMesh,
|
|
6914
7213
|
cssColorOr,
|
|
6915
7214
|
PaperLighting,
|
|
7215
|
+
PaperBackdrop,
|
|
7216
|
+
ReleaseContextOnUnmount,
|
|
6916
7217
|
DropZone,
|
|
6917
7218
|
sheetLayoutSchema,
|
|
6918
7219
|
buildDisplacementGLSL,
|
|
@@ -6930,4 +7231,4 @@ export {
|
|
|
6930
7231
|
describeConfig,
|
|
6931
7232
|
buildAgentPayload
|
|
6932
7233
|
};
|
|
6933
|
-
//# sourceMappingURL=chunk-
|
|
7234
|
+
//# sourceMappingURL=chunk-HRXQTJFS.js.map
|