paperlab 0.7.0 → 0.7.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/dist/{chunk-MZCAN3AR.js → chunk-NTDVOOBA.js} +207 -12
- package/dist/chunk-NTDVOOBA.js.map +1 -0
- package/dist/index.cjs +206 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/dist/stage.cjs +206 -11
- package/dist/stage.cjs.map +1 -1
- package/dist/stage.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-MZCAN3AR.js.map +0 -1
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/Paper.tsx","../src/PaperMesh.tsx","../src/config/schema.ts","../src/config/merge.ts","../src/behaviors/peel.ts","../src/deformers/curl.ts","../src/core/tessellation.ts","../src/behaviors/unroll.ts","../src/deformers/roll.ts","../src/behaviors/flip.ts","../src/behaviors/letter-fold.ts","../src/behaviors/hang.ts","../src/behaviors/fly.ts","../src/behaviors/fall.ts","../src/behaviors/carry.ts","../src/behaviors/flight.ts","../src/physics/aero.ts","../src/behaviors/crumple.ts","../src/behaviors/settle.ts","../src/behaviors/ribbon.ts","../src/config/serialize.ts","../src/core/normals.ts","../src/core/stable.ts","../src/core/sheet.ts","../src/core/stock.ts","../src/config/presets/index.ts","../src/content/texture.ts","../src/content/receipt.ts","../src/content/type.ts","../src/content/card.ts","../src/content/wash.ts","../src/deformers/compose.ts","../src/deformers/registry.ts","../src/deformers/bend.ts","../src/deformers/fold.ts","../src/deformers/wave.ts","../src/deformers/drape.ts","../src/deformers/crumple.ts","../src/deformers/memory.ts","../src/surface/creases.ts","../src/behaviors/registry.ts","../src/physics/idle.ts","../src/physics/cloth.ts","../src/surface/damageContract.ts","../src/physics/damage.ts","../src/physics/strip.ts","../src/surface/PaperMaterial.tsx","../../../node_modules/.pnpm/three-custom-shader-material@6.4.0_@react-three+fiber@9.7.0_@types+react@19.2.18_react-_9d22c69745b4efc41799679dbea453f4/node_modules/src/defaults.ts","../../../node_modules/.pnpm/three-custom-shader-material@6.4.0_@react-three+fiber@9.7.0_@types+react@19.2.18_react-_9d22c69745b4efc41799679dbea453f4/node_modules/src/maps/keywordMap.ts","../../../node_modules/.pnpm/three-custom-shader-material@6.4.0_@react-three+fiber@9.7.0_@types+react@19.2.18_react-_9d22c69745b4efc41799679dbea453f4/node_modules/src/maps/availabilityMap.ts","../../../node_modules/.pnpm/three-custom-shader-material@6.4.0_@react-three+fiber@9.7.0_@types+react@19.2.18_react-_9d22c69745b4efc41799679dbea453f4/node_modules/src/maps/patchMap.ts","../../../node_modules/.pnpm/three-custom-shader-material@6.4.0_@react-three+fiber@9.7.0_@types+react@19.2.18_react-_9d22c69745b4efc41799679dbea453f4/node_modules/src/maps/requiredPropsMap.ts","../../../node_modules/.pnpm/three-custom-shader-material@6.4.0_@react-three+fiber@9.7.0_@types+react@19.2.18_react-_9d22c69745b4efc41799679dbea453f4/node_modules/src/sdbm.js","../../../node_modules/.pnpm/three-custom-shader-material@6.4.0_@react-three+fiber@9.7.0_@types+react@19.2.18_react-_9d22c69745b4efc41799679dbea453f4/node_modules/src/utils.ts","../../../node_modules/.pnpm/three-custom-shader-material@6.4.0_@react-three+fiber@9.7.0_@types+react@19.2.18_react-_9d22c69745b4efc41799679dbea453f4/node_modules/src/index.ts","../../../node_modules/.pnpm/three-custom-shader-material@6.4.0_@react-three+fiber@9.7.0_@types+react@19.2.18_react-_9d22c69745b4efc41799679dbea453f4/node_modules/src/React/index.tsx","../src/surface/compose.ts","../src/surface/translucency.ts","../src/scene/lighting.ts","../src/scene/rig.tsx","../src/surface/useDamageTexture.ts","../src/a11y/index.tsx","../src/motion/onTwos.ts","../src/states/usePaperStates.ts","../src/states/machine.ts","../src/scene/PaperLighting.tsx","../src/scene/environment.ts","../src/scene/color.ts","../src/scene/backdrop.tsx","../src/scene/release.tsx","../src/PaperField.tsx","../src/field/dropZones.tsx","../src/field/sheetGrid.ts","../src/field/slots.ts","../src/field/fieldGroup.tsx","../src/content/atlas.ts","../src/field/compose.ts","../src/field/layouts/index.ts","../src/stage/path.ts","../src/field/stack.ts","../src/field/backingSheet.tsx","../src/content/backing.ts","../src/field/interactiveField.tsx","../src/field/keyboardMirror.tsx","../src/field/framing.ts","../src/config/diff.ts","../src/config/agent-payload.ts","../src/config/field-export.ts","../src/field/parity.ts"],"sourcesContent":["/**\n * The public API.\n *\n * Everything named here is a promise: once it is on npm, taking it away costs\n * whoever imported it a migration. So the bar is not \"is this useful?\" but\n * \"would I support this for years?\" — and the answer for a shader builder, a\n * texture painter or a tessellation constant is no. Those are the inside of\n * the box, and the box is `<Paper>`, `<PaperField>`, `<PaperStage>` and the\n * data that describes them.\n *\n * Three things survive that bar despite looking internal, each for a reason\n * written where it is exported: the parity harness, the tessellation\n * arithmetic, and line breaking. Each is the answer to a question a caller\n * can genuinely ask and cannot otherwise answer.\n *\n * Adding a name here later is free. Removing one is not. When in doubt, leave\n * it out.\n */\n\n// ── The components ──────────────────────────────────────────────────────────\n\nexport { Paper, type PaperProps } from './Paper'\nexport { PaperMesh, type PaperMeshProps, type PaperHandle } from './PaperMesh'\nexport {\n PaperField,\n PaperFieldMesh,\n DropZone,\n type PaperFieldProps,\n type PaperFieldMeshProps,\n type FieldPaperSlot,\n type DropZoneConfig,\n type DropZoneProps,\n type PlacedPaper,\n} from './PaperField'\n\n// ── The schema. It is the spec: if it cannot serialize, it does not ship. ───\n\nexport {\n paperConfigSchema,\n sceneSchema,\n backdropSchema,\n behaviorConfigSchema,\n clothConfigSchema,\n stripConfigSchema,\n paperStatesSchema,\n stateDefSchema,\n physicsNames,\n lightingNames,\n stockNames,\n contentNames,\n contentSchemaFor,\n washSchema,\n creaseSchema,\n memorySchema,\n paperEdges,\n coreStateNames,\n type PaperConfig,\n type PaperConfigInput,\n type SheetConfig,\n type StockName,\n type ContentConfig,\n type ContentConfigInput,\n type WashConfig,\n type BackContentConfig,\n type BehaviorConfig,\n type BehaviorConfigInput,\n type DeformerInstanceConfig,\n type DeformerInstanceConfigInput,\n type SurfaceConfig,\n type SurfaceConfigInput,\n type CreaseConfig,\n type CreaseConfigInput,\n type MemoryConfig,\n type MemoryConfigInput,\n type PaperEdge,\n type PhysicsConfig,\n type PhysicsConfigInput,\n type ClothConfig,\n type StripConfig,\n type SceneConfig,\n type BackdropConfig,\n type SceneConfigInput,\n type LightingName,\n type FilmName,\n type CoreStateName,\n type StateName,\n type StateDef,\n type StateTransitionConfig,\n type PaperStates,\n type PaperStatesInput,\n} from './config/schema'\n\nexport { sheetLayoutSchema, type SheetLayoutOptions } from './field/sheetGrid'\n\n// ── Presets, and the file format ────────────────────────────────────────────\n\nexport {\n getPreset,\n listPresets,\n registerPreset,\n unregisterPreset,\n isBuiltinPreset,\n uniquePresetName,\n} from './config/presets'\nexport { parsePreset, serializePreset, mergeConfig, mergeWithDeletes } from './config/serialize'\nexport { diffConfig, buildJsxSnippet } from './config/diff'\n\n// ── Export: the brief an agent or a codebase receives ───────────────────────\n\nexport { buildAgentPayload, describeConfig } from './config/agent-payload'\nexport {\n buildFieldAgentPayload,\n buildFieldComponentSource,\n describeFieldConfig,\n diffFieldProps,\n type FieldExportInput,\n type FieldExportPaper,\n type FieldExportZone,\n} from './config/field-export'\n\n// ── The registries, and the three ways to extend them ───────────────────────\n\nexport type { Deformer, DeformerInstance, DeformerContext, SheetDims } from './deformers/types'\nexport { registerDeformer, getDeformer, listDeformers } from './deformers/registry'\nexport type { Behavior, HandleSpec } from './behaviors/types'\nexport { registerBehavior, getBehavior, listBehaviors } from './behaviors/registry'\nexport { getLayout, listLayouts, registerLayout, type Layout, type PaperPose } from './field/layouts'\nexport { stocks, getStock, type Stock } from './core/stock'\n// The seam between the sheet and whatever damages it. One interface and the\n// meaning of its four bytes — see `surface/damageContract.ts` for why this and\n// not a plugin API for the composer and the solver.\nexport {\n DAMAGE_CHANNELS,\n DAMAGE_LOOK_DEFAULTS,\n type DamageLook,\n type DamageSource,\n} from './surface/damageContract'\nexport { idleNames, type IdleName, type IdlePreset } from './physics/idle'\n/**\n * The longest strip the `strip` sim can still draw at a given perforation\n * spacing. Exported for authoring UI: past it the chain's node count is capped\n * and the roll comes apart, so a length control needs to know where to stop.\n */\nexport { maxStripLength } from './physics/strip'\n\n/**\n * Paper memory — creasing, and what a sheet keeps of a fold.\n *\n * `applyMemory` is exported because it is the one piece a host might need to\n * reproduce outside the frame loop: an exporter or a thumbnailer that builds\n * a stack by hand has to fold the creases in the same way, or a shared link\n * renders one shape in the editor and another in the picture of it.\n */\nexport { applyMemory, CreaseTracker, MAX_SET, MAX_CREASES } from './deformers/memory'\n\n// ── Lighting is data, not an enum ───────────────────────────────────────────\n\nexport {\n lightSchema,\n resolveLighting,\n lightAngles,\n type LightingPreset,\n type LightAngles,\n type LightOverrides,\n type LightOverridesInput,\n} from './scene/lighting'\nexport { PaperLighting, type PaperLightingProps } from './scene/PaperLighting'\n// Rendered by whoever owns the canvas — see the note on the component.\nexport { PaperBackdrop } from './scene/backdrop'\n// Publish a resolved rig to the paper under it, so a hand-lit scene's\n// transmission agrees with its lamps. `<PaperStage>` does this for you.\nexport { LightRig } from './scene/rig'\n\n// ── Interaction states ──────────────────────────────────────────────────────\n\nexport { resolveStateConfig, recordStateOverride, type StateEvent } from './states/machine'\nexport { usePaperStates, type UsePaperStatesResult } from './states/usePaperStates'\n\n// ── Accessibility ───────────────────────────────────────────────────────────\n\nexport { usePrefersReducedMotion, supportsWebGL } from './a11y'\n\n// ── The three that look internal and are not ────────────────────────────────\n\n/**\n * The GPU/CPU parity harness — public on purpose, and the reasoning is worth\n * writing down because it reads like test infrastructure that leaked.\n *\n * It is test infrastructure. It is also the only way to check the invariant\n * the contribution ladder is built on: a deformer ships a JS `displace` and a\n * GLSL chunk, and the two must agree. `CONTRIBUTING.md` asks a contributor to\n * add cases to `field/parity.ts` and run `pnpm test:parity`, which needs a\n * real WebGL context, which means a browser, which means it runs from an app\n * — and the apps consume this library **through its public API only**. So the\n * harness is either exported or that invariant has no gate.\n *\n * The narrow read is that this is a repo concern that a published consumer\n * will never call. The wider one is that someone writing a deformer in their\n * own project faces exactly the problem this solves, and has no other way to\n * solve it. Exported for the second reason; kept to five names for the first.\n */\nexport {\n runParityHarness,\n parityCases,\n PARITY_EPSILON,\n type ParityCase,\n type ParityResult,\n} from './field/parity'\n\n/**\n * The arithmetic behind `geometry.autoSegments`. Public because\n * `registerDeformer` is: a deformer someone else writes has to be able to\n * answer the same question the built-in seven answer, and the answer should\n * be the same formula rather than a guess at what the library does.\n */\nexport {\n AUTO_CEILING,\n FLAT_SEGMENTS,\n quantizeSegments,\n SAG_TOL,\n segmentsForArc,\n segmentsForSine,\n spanAlong,\n} from './core/tessellation'\n\n/**\n * Line breaking is exported because it is the answer to \"where does this\n * wrap\", and a caller measuring a block of type before laying a sheet out\n * has to get the same answer the painter will.\n */\nexport { wrapLines } from './content/type'\n","import { Canvas } from '@react-three/fiber'\nimport { forwardRef, useMemo } from 'react'\nimport { PaperMesh, useResolvedConfig, type PaperHandle, type PaperMeshProps } from './PaperMesh'\nimport { PaperFallback, PaperMirror, supportsWebGL } from './a11y'\nimport { PaperLighting } from './scene/PaperLighting'\nimport { PaperBackdrop } from './scene/backdrop'\nimport { ReleaseContextOnUnmount } from './scene/release'\n\nexport interface PaperProps extends PaperMeshProps {\n /** Extra children rendered inside the canvas (lights are provided). */\n children?: React.ReactNode\n className?: string\n style?: React.CSSProperties\n}\n\n/**\n * `<Paper />` owns its own `<Canvas>` and fills its parent container —\n * the parent must have a height. Use `<PaperMesh />` inside an existing\n * R3F scene instead.\n *\n * Ships with its accessibility layer: a hidden DOM mirror of the content,\n * `prefers-reduced-motion` support, and a flat DOM fallback when WebGL is\n * unavailable.\n */\nexport const Paper = forwardRef<PaperHandle, PaperProps>(function Paper(\n { children, className, style, ...meshProps },\n ref,\n) {\n // Keyed on every prop resolveConfig reads — a content/stock/behavior change\n // must refresh the fallback, mirror, and lighting, not just the mesh.\n const config = useResolvedConfig(meshProps)\n const webgl = useMemo(() => (typeof window === 'undefined' ? true : supportsWebGL()), [])\n\n return (\n <div className={className} style={{ width: '100%', height: '100%', ...style }}>\n {webgl ? (\n <Canvas shadows camera={{ position: [0, 0.35, 2.4], fov: 40 }} dpr={[1, 2]}>\n <PaperBackdrop backdrop={config.scene.backdrop} />\n <PaperLighting\n preset={config.scene.lighting}\n // The overrides, which this component was resolving without: a\n // preset whose scene said \"studio, but dimmer\" rendered as plain\n // studio here while the editor showed the dimmer one.\n light={config.scene.light}\n floor={-1.05}\n scale={8}\n reducedMotion={meshProps.reducedMotion}\n />\n <PaperMesh ref={ref} {...meshProps} />\n {children}\n <ReleaseContextOnUnmount />\n </Canvas>\n ) : (\n <PaperFallback config={config} />\n )}\n <PaperMirror config={config} />\n </div>\n )\n})\n","import * as THREE from 'three'\nimport { gsap } from 'gsap'\nimport { useFrame, useThree } from '@react-three/fiber'\nimport type { ThreeEvent } from '@react-three/fiber'\nimport { forwardRef, useEffect, useImperativeHandle, useMemo, useRef } from 'react'\nimport type {\n BehaviorConfigInput,\n ClothConfig,\n CreaseConfig,\n StripConfig,\n ContentConfigInput,\n DeformerInstanceConfigInput,\n MemoryConfigInput,\n PaperConfig,\n PaperConfigInput,\n PhysicsConfigInput,\n SceneConfigInput,\n SheetConfig,\n StockName,\n SurfaceConfigInput,\n} from './config/schema'\nimport { paperConfigSchema } from './config/schema'\nimport { mergeConfig, parsePreset, serializePreset } from './config/serialize'\nimport { computeSheetNormals } from './core/normals'\nimport { useStable } from './core/stable'\nimport { createSheetGeometry, resolveSegments, surfacePointAt } from './core/sheet'\nimport { FLAT_SEGMENTS, type SegmentPair } from './core/tessellation'\nimport { getStock } from './core/stock'\nimport { getPreset } from './config/presets'\nimport { useContentTexture } from './content/texture'\nimport { applyDeformerStack, displacePoint, stackAutoSegments, stackMinSegments } from './deformers/compose'\nimport { applyMemory, CreaseTracker } from './deformers/memory'\nimport { resolveCreases } from './surface/creases'\nimport { stackIsAnimated } from './deformers/registry'\nimport type { DeformerInstance } from './deformers/types'\nimport { getBehavior } from './behaviors/registry'\nimport { resolveDeformerStack } from './deformers/registry'\nimport type { Behavior } from './behaviors/types'\nimport { getIdlePreset, type IdleName, type IdlePose } from './physics/idle'\nimport { ClothSim } from './physics/cloth'\nimport { DamageCoupling } from './physics/damage'\nimport { StripSim, stripNodeCount } from './physics/strip'\nimport { PaperMaterial } from './surface/PaperMaterial'\nimport type { DamageSource } from './surface/damageContract'\nimport { usePrefersReducedMotion } from './a11y'\nimport { quantizeProgress, quantizeTime } from './motion/onTwos'\nimport { usePaperStates } from './states/usePaperStates'\nimport type { PaperStateMachine, StateEvent } from './states/machine'\n\nexport interface PaperMeshProps {\n /** Built-in preset name, or a (partial) preset object. Props below override it. */\n preset?: string | PaperConfigInput\n sheet?: Partial<SheetConfig>\n stock?: StockName\n /**\n * These take the schema's INPUT types, not its parsed ones: writing\n * `content={{ type: 'text', text: 'hi' }}` has to compile, and with the\n * inferred type it does not — it demands every field of every nested\n * object. Every default stays a default.\n */\n content?: ContentConfigInput\n behavior?: BehaviorConfigInput\n deformers?: DeformerInstanceConfigInput[]\n /** Fragment-side effects: grain, aging, deckle, creases, perforation. */\n surface?: SurfaceConfigInput\n /**\n * What the sheet remembers being folded — how much of a fold this paper\n * keeps, and the creases it already carries. A sheet can be handed its\n * creases (a letter that arrives having been folded once) as readily as it\n * can be folded into them.\n */\n memory?: MemoryConfigInput\n /** Scene-level presentation that travels with the paper (lighting). */\n scene?: SceneConfigInput\n physics?: PhysicsConfigInput | 'cloth'\n onTwos?: boolean\n /** Show draggable behavior handles; cloth sheets become grabbable. */\n interactive?: boolean\n /** Start the behavior's transport loop on mount. */\n autoplay?: boolean\n /** Override prefers-reduced-motion (default: follow the system setting). */\n reducedMotion?: boolean\n position?: [number, number, number]\n rotation?: [number, number, number]\n /** Fires every animation tick with the behavior's progress (0..1). */\n onProgress?(value: number): void\n /** Fires when a handle drag ends, with the params the drag changed. */\n onBehaviorChange?(patch: Record<string, unknown>): void\n /**\n * Fires when folding the paper leaves a crease it did not have.\n *\n * The sheet applies its own creases immediately — this is how they get\n * PERSISTED. Recording happens in the frame loop, where a fold's peak\n * actually is, and routing that through React sixty times a second would\n * cost more than the rest of the feature; so the mesh holds the live truth\n * and reports it, and the host writes it into config whenever it likes.\n * The same split `onBehaviorChange` uses for handle drags.\n */\n onCrease?(creases: CreaseConfig[]): void\n /**\n * Interaction states: when the config carries `states`, pointer triggers\n * are live by default. Set false to sculpt a stateful paper without the\n * machine firing (the editor's state-editing mode).\n */\n stateTriggers?: boolean\n /** Fires when the state machine changes state. */\n onStateChange?(state: string): void\n /** Fires for `onEnter` actions ('emit:<event>'). */\n onStateAction?(event: string, state: string): void\n /**\n * What has happened to this sheet — char, wet, heat and missing paper — as\n * a grid over its UV.\n *\n * The sheet draws whatever damage it is handed and does not know what\n * caused it, the same way it draws `content` without knowing who painted\n * it. `DamageField` from `paperlab/fx` is one source; a baked texture or a\n * recorded burn played back would be others. A prop and not config,\n * because it is live state that changes every frame and does not belong in\n * a preset or a share link. See `DamageSource`.\n */\n damage?: DamageSource | null\n}\n\nexport interface PaperHandle {\n play(): void\n pause(): void\n readonly playing: boolean\n /** Live-override a behavior param. 'progress' always maps to the behavior's progress param. */\n set(param: string, value: unknown): void\n getProgress(): number\n /** Current full state (including live overrides) as a preset. */\n snapshot(): PaperConfig\n toJSON(): string\n readonly mesh: THREE.Mesh | null\n /**\n * Where a behavior's grab point currently sits, in world space, or null\n * when the behavior has no handles (or `interactive` is off).\n *\n * The handle is not at the corner it names: it rides the deformed surface,\n * so its position is only known after the frame's deformer stack has run.\n * Anything that wants to point AT the handle — a coach-mark, a tooltip,\n * an arrow — has to ask the frame rather than compute a UV, which is why\n * reading it is a method here and not a prop the sheet could publish.\n *\n * Written into `target` when one is passed, so a per-frame reader does not\n * allocate a vector sixty times a second.\n */\n handlePoint(id?: string, target?: THREE.Vector3): THREE.Vector3 | null\n /**\n * Where a point of the sheet is right now, in world space: `(u, v)` over\n * the sheet, `v = 0` its bottom edge — the same UV the damage grid is laid\n * out on, so a cell of damage can be asked where it is. Null before the\n * sheet has mounted.\n *\n * On the DRAWN surface, after this frame's simulation and deformer stack,\n * which is the reason it is a method: an ember that leaves the burn front\n * has to leave from where the paper is, and a draped or crumpled sheet is\n * nowhere a UV alone could say. Interpolated across the triangle the GPU\n * draws, so the point is on the paper and not a hair behind it.\n *\n * Written into `target` when one is passed, like {@link handlePoint}.\n */\n surfacePoint(u: number, v: number, target?: THREE.Vector3): THREE.Vector3 | null\n /** Interaction-state machine access (null when the config has no states). */\n readonly state: string\n sendState(event: StateEvent): string | null\n /**\n * Drive to 'picked' through the legal chain (rest→hover→pressed→picked),\n * instantly, so every side effect fires — the keyboard/a11y entry point\n * where no pointer hover/press ever ran. Returns true if it landed.\n */\n pickProgrammatic(): boolean\n /** Instant, legal place (picked → placed) so onEnter/emit fires. */\n placeProgrammatic(): boolean\n /** Instant, legal return (picked → rest). */\n returnProgrammatic(): boolean\n}\n\n/**\n * Everything {@link resolveConfig} reads, as a plain tuple.\n *\n * Compared with {@link useStable} rather than serialized: a dependency array\n * is evaluated on EVERY render, and `content` can hold a whole bitmap as a\n * data URL, so a `JSON.stringify` here was megabytes of garbage per frame of\n * a slider drag. (There was a `resolveConfigKey` exporting the string form\n * for consumers to key their own caches on; it was never part of the package\n * entry, so no consumer could reach it, and nothing else uses it now.)\n */\nfunction configInputs(props: PaperMeshProps): unknown[] {\n return [\n props.preset ?? null,\n props.sheet ?? null,\n props.stock ?? null,\n props.content ?? null,\n props.behavior ?? null,\n props.deformers ?? null,\n props.surface ?? null,\n props.memory ?? null,\n props.scene ?? null,\n props.physics ?? null,\n props.onTwos ?? null,\n ]\n}\n\n/** Resolve once, and again only when the inputs actually differ. */\nexport function useResolvedConfig(props: PaperMeshProps): PaperConfig {\n const inputs = useStable(configInputs(props))\n // biome-ignore lint/correctness/useExhaustiveDependencies: `inputs` IS every prop resolveConfig reads; the props object itself is new each render.\n return useMemo(() => resolveConfig(props), [inputs])\n}\n\n/** Resolve preset + prop overrides into a validated config. */\nexport function resolveConfig(props: PaperMeshProps): PaperConfig {\n const base = props.preset\n ? typeof props.preset === 'string'\n ? getPreset(props.preset)\n : parsePreset(props.preset)\n : paperConfigSchema.parse({})\n const overrides: PaperConfigInput = {}\n if (props.sheet) overrides.sheet = { ...base.sheet, ...props.sheet }\n if (props.stock) overrides.stock = props.stock\n if (props.content) overrides.content = props.content\n if (props.behavior) overrides.behavior = props.behavior\n if (props.deformers) overrides.deformers = props.deformers\n // Surface merges over the stock's defaults rather than replacing them, so\n // `surface={{ grain: 0.6 }}` on thermal keeps thermal's banding.\n if (props.surface) overrides.surface = { ...base.surface, ...props.surface }\n // Merged like surface, and for the same reason: `memory={{ set: 0.2 }}` on a\n // preset that ships creased should turn the retention down, not flatten the\n // paper on its way past.\n if (props.memory) overrides.memory = { ...base.memory, ...props.memory }\n if (props.scene) overrides.scene = { ...base.scene, ...props.scene }\n if (props.physics) overrides.physics = props.physics\n if (props.onTwos !== undefined) overrides.onTwos = props.onTwos\n return paperConfigSchema.parse(mergeConfig(base as PaperConfigInput, overrides))\n}\n\n/** Cloth grids cap their resolution — 5k verlet particles is the budget ceiling. */\nconst CLOTH_MAX_SEGMENTS = 28\n\n/** Where `'auto'` probes a behavior's sweep. Endpoints matter most — a play\n * usually starts or ends at its tightest. */\nconst PROGRESS_SAMPLES = [0, 0.25, 0.5, 0.75, 1] as const\n\nconst dragPlane = new THREE.Plane()\nconst dragPoint = new THREE.Vector3()\nconst planeNormal = new THREE.Vector3()\nconst anchorScratch = new THREE.Vector3()\nconst worldScratch = new THREE.Vector3()\nconst quatScratch = new THREE.Quaternion()\n\n/**\n * The atom: one sheet of paper, hero-mode CPU path. The cloth sim solves the\n * particles and the deformer stack runs over them — both, not either; only a\n * strip owns its vertices outright. GSAP owns animated values; useFrame owns\n * geometry writes.\n */\nexport const PaperMesh = forwardRef<PaperHandle, PaperMeshProps>(function PaperMesh(props, ref) {\n // Each resolveConfig call is several zod parses (superRefine re-parses every\n // state override) — memoized so a render without config-prop changes is free.\n const resolved = useResolvedConfig(props)\n // Reduced motion: behaviors freeze at their resting pose, physics is off,\n // idle motion is off. The sheet still renders fully sculpted.\n const reduced = usePrefersReducedMotion(props.reducedMotion)\n // Interaction states: the machine animates a live config between state\n // overrides; `config` below is that animated view (the base when no states).\n // Reduced motion keeps the machine but makes transitions instant.\n const statesLive = Boolean(resolved.states) && props.stateTriggers !== false\n const {\n config,\n machine,\n state: machineState,\n } = usePaperStates(resolved, statesLive, reduced, props.onStateAction, props.onStateChange)\n const behavior: Behavior | null = config.behavior ? getBehavior(config.behavior.type) : null\n const machineRef = useRef<PaperStateMachine | null>(null)\n machineRef.current = machine\n // The animated `config` has `states` stripped — keep the resolved preset\n // around so snapshot()/toJSON() never lose the state machine.\n const resolvedRef = useRef(resolved)\n resolvedRef.current = resolved\n // Two object-shaped simulations now, so the kind is read off the tag rather\n // than off `typeof` — which was only ever \"cloth\" by having no rival.\n const simKind =\n !reduced && typeof config.physics === 'object' ? (config.physics.type as 'cloth' | 'strip') : null\n const isCloth = simKind === 'cloth'\n const isStrip = simKind === 'strip'\n const idle =\n !reduced && typeof config.physics === 'string' && config.physics !== 'none'\n ? getIdlePreset(config.physics as IdleName)\n : null\n\n const meshRef = useRef<THREE.Mesh>(null)\n const groupRef = useRef<THREE.Group>(null)\n const handleRefs = useRef<(THREE.Mesh | null)[]>([])\n\n const overridesRef = useRef<Record<string, unknown>>({})\n const dirtyRef = useRef(true)\n const playingRef = useRef(false)\n const tweenRef = useRef<gsap.core.Tween | null>(null)\n const draggingRef = useRef<string | null>(null)\n\n const configRef = useRef(config)\n configRef.current = config\n\n /**\n * The caller's rotation with the preset's `scene.turn` folded in.\n *\n * Additive, and about Y: `turn` is how the composition wants to be READ\n * (see `sceneSchema.turn`), while the prop is where the caller has decided\n * to put this paper. A preset does not get to overrule that, so it leans on\n * top of it.\n */\n const baseRotation = useMemo<[number, number, number]>(() => {\n const [rx, ry, rz] = props.rotation ?? [0, 0, 0]\n return [rx, ry + (config.scene.turn * Math.PI) / 180, rz]\n }, [props.rotation, config.scene.turn])\n\n const controls = useThree((s) => s.controls) as { enabled?: boolean } | null\n const camera = useThree((s) => s.camera)\n\n const behaviorKey = JSON.stringify(config.behavior ?? null)\n const deformersKey = JSON.stringify(config.deformers ?? null)\n const sheetKey = JSON.stringify(config.sheet)\n /**\n * What the SHAPE path needs to know about physics, and nothing more.\n *\n * Deliberately not `JSON.stringify(config.physics)`. A simulation's config\n * is live — `strip.scroll` is rewritten every single frame by the host —\n * and a key that moves every frame re-runs the segment probe, hands the\n * geometry memo fresh array identities, rebuilds the geometry, and through\n * it rebuilds the sim, which throws away everything the sim had integrated.\n * A scroll-driven roll pinned to its own starting tail forever, sixty times\n * a second.\n *\n * Nothing downstream of here reads a sim's VALUES: an object-shaped physics\n * means there is no deformer stack at all, so the only thing that can change\n * the shape path is whether a sim is present and which one.\n */\n const physicsKey = typeof config.physics === 'object' ? config.physics.type : config.physics\n\n /**\n * The crease LINES, without their depths.\n *\n * Depth is exactly the part that moves while you are folding, and the only\n * thing downstream of this key is the geometry probe — which does not care.\n * `fold`'s appetite for segments is set by its hinge radius and its\n * direction, never by how far it has closed, so a crease deepening from 2°\n * to 20° cannot change the answer. Keying on the depth too would rebuild\n * the geometry on every frame of every fold, and take the sim and the\n * base-position buffer down with it — the same trap `physicsKey` above\n * exists to avoid.\n */\n const memoryKey = config.memory.creases.map((c) => `${c.angle}:${c.offset}`).join('|')\n\n /**\n * The creases WITH their depths — what the sheet is actually carrying.\n *\n * The lines-only key above cannot serve here, and the difference is the\n * whole reason there are two. Dragging a crease deeper changes no line, so\n * a lines-only key never fires: the tracker would go on holding the array\n * it was handed when the crease was created, the shading would follow the\n * edit (it reads config) and the geometry would not, and the depth slider\n * would darken the mark without bending the paper.\n */\n const creaseKey = config.memory.creases.map((c) => `${c.angle}:${c.offset}:${c.depth}`).join('|')\n\n /**\n * The sheet's live memory. Seeded from config and updated in the frame\n * loop; `onCrease` is how it gets back to config.\n */\n const creasesRef = useRef<CreaseTracker | null>(null)\n creasesRef.current ??= new CreaseTracker(config.memory.creases)\n const creases = creasesRef.current\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: The keys are change triggers; the body only touches refs.\n useEffect(() => {\n if (!draggingRef.current && !playingRef.current) overridesRef.current = {}\n // The slots track folds in a stack that no longer exists. The creases they\n // left do not go with it — a sheet does not un-crease because you gave it\n // a new behavior — so they carry over as the sheet's authored set.\n creases.reset()\n dirtyRef.current = true\n }, [behaviorKey, deformersKey, sheetKey, physicsKey])\n\n // Config-side creases changing means something outside the frame loop has an\n // opinion: an edit, a shared link, or the host persisting what we just\n // recorded. `adopt` works out which — an edit resets the folds it was\n // watching, an echo of its own recording does not.\n // biome-ignore lint/correctness/useExhaustiveDependencies: Keyed on the creases themselves; the body reads them off config.\n useEffect(() => {\n creases.adopt(configRef.current.memory.creases)\n dirtyRef.current = true\n }, [creaseKey])\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: Keyed on the stack shape — the probe reads config off a ref.\n const { minSegments, autoSegments, animatedStack } = useMemo(() => {\n const cfg = configRef.current\n // Creases are in the probe because a crease with no live fold on its line\n // is a fold instance the grid has never been asked about — an authored\n // dog-ear on an otherwise flat sheet needs `fold`'s 48-segment floor as\n // much as a real fold does, and a flat sheet is tessellated 2×2.\n const probe = withMemory(buildStack(cfg, {}), cfg)\n if (!probe) {\n return {\n minSegments: [2, 2] as SegmentPair,\n autoSegments: [FLAT_SEGMENTS, FLAT_SEGMENTS] as SegmentPair,\n animatedStack: false,\n }\n }\n\n // The grid is built once; a behavior's stack is not the same shape all\n // the way through. An unroll is a tight roll at one end of its progress\n // and a flat sheet at the other, so sizing to the configured moment\n // would leave the sheet under-tessellated for the rest of the play.\n // Sample the sweep and keep the densest answer. Every behavior's\n // progressParam is a 0..1 number — pinned by behaviors.test.ts, because\n // this loop silently samples the wrong range if that ever stops holding.\n //\n // Whether the stack is TIME-DRIVEN is answered off the same sweep, and\n // for the same reason: it is a property of the stack's shape, not of the\n // moment it happens to be at, and the frame loop needs it before it has\n // built anything — see `useFrame` below.\n const want = stackAutoSegments(probe, cfg.sheet)\n let animated = stackIsAnimated(probe)\n if (cfg.behavior && !cfg.deformers) {\n const param = getBehavior(cfg.behavior.type).progressParam\n for (const p of PROGRESS_SAMPLES) {\n const at = withMemory(buildStack(cfg, { [param]: p }), cfg)\n if (!at) continue\n const [x, y] = stackAutoSegments(at, cfg.sheet)\n if (x > want[0]) want[0] = x\n if (y > want[1]) want[1] = y\n animated ||= stackIsAnimated(at)\n }\n }\n return {\n minSegments: stackMinSegments(probe, cfg.sheet),\n autoSegments: want,\n animatedStack: animated,\n }\n }, [behaviorKey, deformersKey, physicsKey, memoryKey])\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: Keyed on the sheet — rebuilding geometry on identity would orphan GPU buffers every render.\n const geometry = useMemo(() => {\n if (isStrip) {\n // A strip is a 2×N quad ribbon: one column each side, one row per chain\n // node. The row count has to agree with the sim exactly, so both derive\n // it from the same function.\n const strip = configRef.current.physics as StripConfig\n const nodes = stripNodeCount(config.sheet.height, strip.perforation)\n return new THREE.PlaneGeometry(config.sheet.width, config.sheet.height, 1, nodes - 1)\n }\n if (!isCloth) return createSheetGeometry(config.sheet, minSegments, autoSegments)\n // Cloth: explicit capped grid so sim particles == mesh vertices. Square,\n // because the sim's constraints are laid out on a square lattice.\n //\n // The stack's own floor is in the max now that cloth can host one: a fold\n // needs 48 segments to bend through rather than crease along, and a\n // crumple more, and a shape running over a simulation is no less entitled\n // to the grid it needs than one running over a flat sheet. Still capped —\n // every particle is a constraint solve five times a frame.\n const [sx, sy] = resolveSegments(config.sheet, minSegments)\n const capped = Math.min(Math.max(sx, sy), CLOTH_MAX_SEGMENTS)\n return new THREE.PlaneGeometry(config.sheet.width, config.sheet.height, capped, capped)\n }, [\n sheetKey,\n minSegments,\n autoSegments,\n isCloth,\n isStrip,\n isStrip ? (config.physics as StripConfig).perforation : 0,\n ])\n\n // Imperatively-created geometry is ours to free — R3F only auto-disposes\n // JSX-created objects, so a sheet change would otherwise orphan GPU buffers.\n useEffect(() => () => geometry.dispose(), [geometry])\n\n const basePositions = useMemo(\n () => Float32Array.from(geometry.attributes.position!.array as Float32Array),\n [geometry],\n )\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: Rebuild only on geometry or pin layout change — sliders update the sim in place.\n const stripSim = useMemo(() => {\n if (!isStrip) return null\n const strip = configRef.current.physics as StripConfig\n return new StripSim(config.sheet.height, config.sheet.width, {\n scroll: strip.scroll,\n tightness: strip.tightness,\n core: strip.core,\n tail: strip.tail,\n perforation: strip.perforation,\n crease: strip.crease,\n stiffness: strip.stiffness,\n drag: strip.drag,\n gravity: strip.gravity,\n floor: strip.floor,\n inertia: strip.inertia,\n })\n }, [geometry, isStrip])\n\n // The sim the last committed render was running, so a rebuild can carry its\n // drape over instead of starting flat. Written after commit, never during a\n // render, or a render React threw away would be the one adopted from.\n const lastSimRef = useRef<ClothSim | null>(null)\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: Rebuild only on geometry or pin layout change — sliders update the sim in place.\n const sim = useMemo(() => {\n if (!isCloth) return null\n const cloth = configRef.current.physics as ClothConfig\n const cols = (geometry.parameters as { widthSegments: number }).widthSegments + 1\n const rows = (geometry.parameters as { heightSegments: number }).heightSegments + 1\n const next = new ClothSim(cols, rows, config.sheet.width, config.sheet.height, cloth.pins, {\n stiffness: cloth.stiffness,\n gravity: cloth.gravity,\n wind: cloth.wind,\n floor: cloth.floor,\n })\n // A resize keeps the drape; a restructure does not. `adopt` decides which\n // this was — see the note on it.\n next.adopt(lastSimRef.current)\n return next\n }, [geometry, isCloth, isCloth ? (config.physics as ClothConfig).pins : ''])\n\n useEffect(() => {\n lastSimRef.current = sim\n }, [sim])\n\n // What the sim feels of `damage`. Per sim, so a rebuilt one reads it afresh.\n const coupling = useMemo(() => (sim ? new DamageCoupling(sim) : null), [sim])\n\n const stock = getStock(config.stock)\n const texture = useContentTexture(config.content, config.sheet, stock)\n const backTexture = useContentTexture(config.content.back, config.sheet, stock)\n\n // Per-frame config: when a state machine is live it OWNS the animated numeric\n // values (GSAP tweens them); we poll its mutable liveConfig each frame rather\n // than routing every tick through React. Falls back to the React config for\n // non-stateful papers.\n const liveConfig = (): PaperConfig => machineRef.current?.liveConfig ?? configRef.current\n\n const effectiveOptions = (t: number): Record<string, unknown> | null => {\n const cfg = liveConfig()\n if (!cfg.behavior || !behavior) return null\n const o = { ...cfg.behavior, ...overridesRef.current }\n return behavior.loop ? { ...o, ...behavior.loop(o, t) } : o\n }\n\n const play = () => {\n if (!behavior) return\n playingRef.current = true\n if (tweenRef.current) {\n tweenRef.current.play()\n return\n }\n const param = behavior.progressParam\n const start = (effectiveOptions(0)?.[param] as number) ?? 0\n const state = { p: start }\n tweenRef.current = gsap.to(state, {\n p: 1,\n duration: behavior.duration * (1 - start),\n ease: 'power2.inOut',\n yoyo: behavior.loopMode === 'yoyo',\n repeat: -1,\n onRepeat: () => {\n if (behavior.loopMode === 'restart') state.p = 0\n },\n onUpdate: () => {\n const p = configRef.current.onTwos ? quantizeProgress(state.p, behavior.duration) : state.p\n overridesRef.current[param] = p\n dirtyRef.current = true\n props.onProgress?.(p)\n },\n })\n }\n\n const pause = () => {\n playingRef.current = false\n tweenRef.current?.pause()\n }\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: Mount-only: autoplay starts once, and the cleanup kills the tween on unmount.\n useEffect(() => {\n if (props.autoplay && !reduced) play()\n return () => {\n tweenRef.current?.kill()\n tweenRef.current = null\n }\n }, [])\n\n const snapshot = (): PaperConfig => {\n // Re-attach `states`: the rendered config is the animated view with the\n // machine stripped, but a snapshot is a preset — states are part of it.\n const states = resolvedRef.current.states\n const cfg = states ? { ...configRef.current, states } : configRef.current\n if (!cfg.behavior) return states ? paperConfigSchema.parse(cfg) : cfg\n return paperConfigSchema.parse({\n ...cfg,\n behavior: { ...cfg.behavior, ...overridesRef.current },\n })\n }\n\n useImperativeHandle(ref, () => ({\n play,\n pause,\n get playing() {\n return playingRef.current\n },\n set(param: string, value: unknown) {\n const key = param === 'progress' && behavior ? behavior.progressParam : param\n overridesRef.current[key] = value\n dirtyRef.current = true\n if (behavior && key === behavior.progressParam) props.onProgress?.(value as number)\n },\n getProgress() {\n if (!behavior) return 0\n return (effectiveOptions(0)?.[behavior.progressParam] as number) ?? 0\n },\n snapshot,\n toJSON: () => serializePreset(snapshot()),\n get mesh() {\n return meshRef.current\n },\n handlePoint(id?: string, target?: THREE.Vector3) {\n const handles = behavior?.handles\n if (!handles?.length) return null\n const index = id ? handles.findIndex((h) => h.id === id) : 0\n const mesh = handleRefs.current[index]\n if (!mesh) return null\n return mesh.getWorldPosition(target ?? new THREE.Vector3())\n },\n surfacePoint(u: number, v: number, target?: THREE.Vector3) {\n const mesh = meshRef.current\n if (!mesh) return null\n // Every sheet is a PlaneGeometry — shape, cloth and strip alike — so its\n // grid is on the parameters, and the position attribute is whatever this\n // frame wrote there.\n const { widthSegments, heightSegments } = geometry.parameters\n const out = surfacePointAt(\n geometry.attributes.position!.array,\n widthSegments + 1,\n heightSegments + 1,\n u,\n v,\n target ?? new THREE.Vector3(),\n )\n mesh.updateWorldMatrix(true, false)\n return out.applyMatrix4(mesh.matrixWorld)\n },\n get state() {\n return machineState\n },\n sendState: (event: StateEvent) => machineRef.current?.send(event) ?? null,\n pickProgrammatic: () => machineRef.current?.pickProgrammatic() ?? false,\n placeProgrammatic: () => machineRef.current?.placeProgrammatic() ?? false,\n returnProgrammatic: () => machineRef.current?.returnProgrammatic() ?? false,\n }))\n\n /**\n * The crease lines the shader draws.\n *\n * Off CONFIG rather than off the tracker, and that is the honest trade. The\n * shading is a shader uniform behind a React memo, so it updates when the\n * host writes a recorded crease back — a frame or two after the geometry\n * has it. A crease that has just formed is a fold the sheet is still most\n * of the way inside; the mark landing as it opens rather than as it closes\n * is the order it happens in on real paper anyway.\n */\n const shadedCreases = useMemo(\n () => resolveCreases(config.surface, config.memory.creases, config.sheet),\n [config.surface, config.memory.creases, config.sheet],\n )\n\n const idlePose = useRef<IdlePose>({ position: [0, 0, 0], rotation: [0, 0, 0] })\n\n useFrame(({ clock }, delta) => {\n const cfg = liveConfig()\n // Reduced motion freezes time-driven deformers at their resting phase.\n const now = reduced ? 0 : cfg.onTwos ? quantizeTime(clock.elapsedTime) : clock.elapsedTime\n\n // Whole-sheet motion — idle presets and behavior transforms (flight's\n // travel across the scene) compose additively; vertices stay untouched.\n const hasBehaviorTransform = Boolean(behavior?.transform && cfg.behavior)\n if ((idle?.transform || hasBehaviorTransform) && groupRef.current) {\n const pose = idlePose.current\n pose.position[0] = pose.position[1] = pose.position[2] = 0\n pose.rotation[0] = pose.rotation[1] = pose.rotation[2] = 0\n idle?.transform?.(now, pose)\n if (hasBehaviorTransform) {\n const o = effectiveOptions(now)\n if (o) behavior!.transform!(o, now, pose, cfg.sheet)\n }\n const base = props.position ?? [0, 0, 0]\n const baseRot = baseRotation\n groupRef.current.position.set(\n base[0] + pose.position[0],\n base[1] + pose.position[1],\n base[2] + pose.position[2],\n )\n groupRef.current.rotation.set(\n baseRot[0] + pose.rotation[0],\n baseRot[1] + pose.rotation[1],\n baseRot[2] + pose.rotation[2],\n )\n }\n\n // Simulation path: the strip owns the vertices.\n if (isStrip && stripSim) {\n const strip = cfg.physics as StripConfig\n stripSim.setParams({\n scroll: strip.scroll,\n tightness: strip.tightness,\n core: strip.core,\n tail: strip.tail,\n crease: strip.crease,\n stiffness: strip.stiffness,\n drag: strip.drag,\n gravity: strip.gravity,\n floor: strip.floor,\n inertia: strip.inertia,\n })\n stripSim.step(delta)\n if (!stripSim.asleep) {\n const position = geometry.attributes.position as THREE.BufferAttribute\n stripSim.writeInto(position.array as Float32Array)\n position.needsUpdate = true\n // Per-segment normals are what make the folds read: the underside of\n // each turn faces away from the key and goes dark on its own.\n computeSheetNormals(geometry)\n geometry.computeBoundingSphere()\n }\n return\n }\n\n // Shape: the deformer stack, run over whatever it is given as a base.\n //\n // `base` is the flat rest pose for a sheet that is only a shape, and the\n // simulation's live particles for one that is both. That substitution is\n // the whole of the composition: a deformer is a pure map from a point to\n // a point, so folding a draped sheet is folding the points the drape put\n // there. `force` is the simulation saying its vertices moved even though\n // nothing about the stack did.\n //\n // Decide whether there is anything to do BEFORE building it. A resting\n // sheet — no loop, no time-driven deformer, no transition, nothing\n // dirtied — used to expand its whole stack every frame and throw it\n // away, which is a behavior's `stack()` call and its deformer objects\n // sixty times a second for a picture that does not move.\n const applyShape = (base: Float32Array, force: boolean): boolean => {\n const animated = !reduced && animatedStack\n const hasLoop = !reduced && Boolean(cfg.behavior && behavior?.loop)\n // A state transition tweens numeric leaves off the React path, so the\n // stack must re-apply every frame while the machine is transitioning.\n const machineAnimating = Boolean(machineRef.current?.transitioning)\n if (!force && !dirtyRef.current && !hasLoop && !animated && !machineAnimating) return false\n\n const raw = buildStack(cfg, overridesRef.current, behavior, now)\n\n // How much this paper keeps: its own override, else what the stock is\n // made of. The same shape as every other stock default in the library.\n const setAmount = cfg.memory.set ?? stock.takesSet\n\n // Read the folds BEFORE memory rewrites them. `applyMemory` raises a live\n // fold to its crease's depth, and a tracker watching that would be reading\n // its own output — the crease would hold the fold open, and the held-open\n // fold would keep the crease alive, with nothing in the loop that is\n // actually the paper being folded.\n if (raw && creases.observe(raw, setAmount)) props.onCrease?.(creases.creases)\n\n const stack = withMemory(raw, cfg, creases.creases)\n if (!stack) return false\n dirtyRef.current = false\n\n const ctx = { t: now, sheet: cfg.sheet }\n applyDeformerStack(geometry, base, stack, ctx)\n\n if (props.interactive && behavior?.handles) {\n const o = effectiveOptions(now)\n behavior.handles.forEach((h, i) => {\n const mesh = handleRefs.current[i]\n if (!mesh || !o) return\n const [u, v] = h.anchor(o, cfg.sheet)\n anchorScratch.set((u - 0.5) * cfg.sheet.width, (v - 0.5) * cfg.sheet.height, 0)\n displacePoint(anchorScratch, u, v, stack, ctx)\n mesh.position.copy(anchorScratch)\n })\n }\n return true\n }\n\n // Simulation path: cloth writes the vertices, and may hand them on.\n if (isCloth && sim) {\n const cloth = cfg.physics as ClothConfig\n sim.setParams({\n wind: cloth.wind,\n gravity: cloth.gravity,\n stiffness: cloth.stiffness,\n floor: cloth.floor,\n })\n // Damage first — char, heat, wet and missing paper are levers on the\n // solve, and a free read when the source has not moved.\n coupling?.update(props.damage)\n sim.step(delta)\n const moved = !sim.asleep\n if (moved) coupling?.follow()\n // The stack first refusal: if there is one, it owns the write, because\n // its base is the sim's own array and writing that array to the\n // geometry first would only be overwritten. If there is none, the sim's\n // positions ARE the vertices, exactly as before.\n if (!applyShape(sim.positions, moved) && moved) {\n const position = geometry.attributes.position as THREE.BufferAttribute\n ;(position.array as Float32Array).set(sim.positions)\n position.needsUpdate = true\n computeSheetNormals(geometry)\n }\n return\n }\n\n // Shape path: the deformer stack over the flat sheet.\n applyShape(basePositions, false)\n })\n\n const localDragPoint = (e: ThreeEvent<PointerEvent>): { x: number; y: number } | null => {\n const group = groupRef.current\n if (!group) return null\n planeNormal.set(0, 0, 1).applyQuaternion(group.getWorldQuaternion(quatScratch))\n dragPlane.setFromNormalAndCoplanarPoint(planeNormal, group.getWorldPosition(dragPoint))\n const hit = e.ray.intersectPlane(dragPlane, dragPoint)\n if (!hit) return null\n group.worldToLocal(hit)\n return { x: hit.x, y: hit.y }\n }\n\n const onHandleDrag = (e: ThreeEvent<PointerEvent>) => {\n if (!behavior?.handles || !draggingRef.current) return\n const handleSpec = behavior.handles.find((h) => h.id === draggingRef.current)\n const local = localDragPoint(e)\n const o = effectiveOptions(0)\n if (!handleSpec || !local || !o) return\n Object.assign(overridesRef.current, handleSpec.drag(local, o, configRef.current.sheet))\n dirtyRef.current = true\n const p = overridesRef.current[behavior.progressParam]\n if (typeof p === 'number') props.onProgress?.(p)\n }\n\n // Cloth grab: pick the particle under the pointer, then drag it on a\n // camera-facing plane through the grab point — full 3D pull, not just\n // in-plane.\n const grabAnchor = useRef(new THREE.Vector3())\n /**\n * Where the vertex you grabbed sits relative to the particle behind it.\n *\n * Zero unless a deformer is running over the simulation, and then it is\n * exactly the displacement that deformer applied at the moment of the grab.\n * The pointer speaks in RENDERED space and the sim only understands its own,\n * so the offset is what translates between them — carried as a constant\n * rather than inverted every frame, because a deformer is a map with no\n * inverse to ask for. Exact when the grab lands and honest as it drifts.\n */\n const grabOffset = useRef(new THREE.Vector3())\n const clothDown = (e: ThreeEvent<PointerEvent>) => {\n if (!isCloth || !sim || !props.interactive || !groupRef.current) return\n e.stopPropagation()\n if (controls) controls.enabled = false\n grabAnchor.current.copy(e.point) // world-space anchor for the drag plane\n const local = groupRef.current.worldToLocal(worldScratch.copy(e.point))\n // Nearest RENDERED vertex, not nearest particle: they are the same sheet\n // only when nothing is deforming it, and the pointer hit the rendered one.\n const drawn = geometry.attributes.position!.array as Float32Array\n const index = nearestVertex(drawn, sim.count, local.x, local.y, local.z)\n sim.grab(index)\n const i3 = index * 3\n grabOffset.current.set(\n drawn[i3]! - sim.positions[i3]!,\n drawn[i3 + 1]! - sim.positions[i3 + 1]!,\n drawn[i3 + 2]! - sim.positions[i3 + 2]!,\n )\n draggingRef.current = 'cloth'\n ;(e.target as Element).setPointerCapture(e.pointerId)\n }\n const clothMove = (e: ThreeEvent<PointerEvent>) => {\n if (draggingRef.current !== 'cloth' || !sim || !groupRef.current) return\n camera.getWorldDirection(planeNormal)\n dragPlane.setFromNormalAndCoplanarPoint(planeNormal, grabAnchor.current)\n const hit = e.ray.intersectPlane(dragPlane, dragPoint)\n if (!hit) return\n groupRef.current.worldToLocal(hit)\n const offset = grabOffset.current\n sim.moveGrab(hit.x - offset.x, hit.y - offset.y, hit.z - offset.z)\n }\n const clothUp = (e: ThreeEvent<PointerEvent>) => {\n if (draggingRef.current !== 'cloth' || !sim) return\n draggingRef.current = null\n if (controls) controls.enabled = true\n sim.release()\n ;(e.target as Element).releasePointerCapture(e.pointerId)\n }\n\n /**\n * Take hold of the paper and pull, and the roll turns.\n *\n * Same drag plane as cloth — camera-facing, through the point first\n * touched — which degrades the right way for a strip. Head-on, that plane\n * holds depth fixed and the gesture is purely up and down, which is the\n * pull the object is famous for; from three-quarters it opens up and the\n * paper can be drawn out toward the viewer as well.\n *\n * The sim reads only y and z: the strip carries its width along x and never\n * twists, so there is nothing for a sideways drag to mean.\n */\n const stripDown = (e: ThreeEvent<PointerEvent>) => {\n if (!isStrip || !stripSim || !props.interactive || !groupRef.current) return\n e.stopPropagation()\n const local = groupRef.current.worldToLocal(worldScratch.copy(e.point))\n // Nothing is committed until the grab lands. `grabNearest` returns -1 when\n // there is no free paper to catch — every node still wound on the roll\n // belongs to the spiral — and disabling the camera before finding that out\n // left the controls dead for good: the early return skips both the pointer\n // capture and `stripUp`, so nothing ever turned them back on.\n if (stripSim.grabNearest(local.y, local.z) < 0) return\n if (controls) controls.enabled = false\n grabAnchor.current.copy(e.point)\n draggingRef.current = 'strip'\n ;(e.target as Element).setPointerCapture(e.pointerId)\n }\n const stripMove = (e: ThreeEvent<PointerEvent>) => {\n if (draggingRef.current !== 'strip' || !stripSim || !groupRef.current) return\n camera.getWorldDirection(planeNormal)\n dragPlane.setFromNormalAndCoplanarPoint(planeNormal, grabAnchor.current)\n const hit = e.ray.intersectPlane(dragPlane, dragPoint)\n if (!hit) return\n groupRef.current.worldToLocal(hit)\n stripSim.moveGrab(hit.y, hit.z)\n }\n const stripUp = (e: ThreeEvent<PointerEvent>) => {\n if (draggingRef.current !== 'strip' || !stripSim) return\n draggingRef.current = null\n if (controls) controls.enabled = true\n stripSim.release()\n ;(e.target as Element).releasePointerCapture(e.pointerId)\n }\n\n // Interaction-state triggers (rest ↔ hover ↔ pressed); pick/place/return\n // are driven by the field's carry controller through `sendState`.\n const sendState = (event: StateEvent) => machineRef.current?.send(event)\n\n return (\n <group ref={groupRef} position={props.position} rotation={baseRotation}>\n <mesh\n ref={meshRef}\n geometry={geometry}\n castShadow\n receiveShadow\n frustumCulled={false}\n onPointerOver={statesLive ? () => sendState('enter') : undefined}\n onPointerOut={statesLive ? () => sendState('leave') : undefined}\n onPointerDown={\n isCloth || isStrip || statesLive\n ? (e) => {\n if (isCloth) clothDown(e)\n if (isStrip) stripDown(e)\n if (statesLive) sendState('down')\n }\n : undefined\n }\n onPointerMove={isCloth ? clothMove : isStrip ? stripMove : undefined}\n onPointerUp={\n isCloth || isStrip || statesLive\n ? (e) => {\n if (isCloth) clothUp(e)\n if (isStrip) stripUp(e)\n if (statesLive) sendState('up')\n }\n : undefined\n }\n >\n <PaperMaterial\n stock={stock}\n texture={texture}\n backTexture={backTexture}\n surface={config.surface}\n thickness={config.sheet.thickness}\n sheet={config.sheet}\n lighting={config.scene.lighting}\n creases={shadedCreases}\n damage={props.damage}\n />\n </mesh>\n {props.interactive &&\n // Any simulation, not cloth alone: a sim owns the vertices, so there\n // is no deformer stack for a handle to drive. Harmless as `!isCloth`\n // only because the schema makes a sim and a behavior exclusive — the\n // intent is what is written here.\n !simKind &&\n behavior?.handles?.map((h, i) => (\n <mesh\n key={h.id}\n // Marked as chrome so a renderer that is producing a PICTURE can\n // leave it out. The handle is an editing affordance, and it is\n // drawn with `depthTest: false` precisely so it sits on top of\n // the sheet — which makes it the most prominent thing in any\n // frame captured for export. The editor's capture rig reads this.\n userData={{ paperlabChrome: true }}\n ref={(m) => {\n handleRefs.current[i] = m\n }}\n onPointerDown={(e) => {\n e.stopPropagation()\n draggingRef.current = h.id\n pause()\n if (controls) controls.enabled = false\n ;(e.target as Element).setPointerCapture(e.pointerId)\n }}\n onPointerMove={onHandleDrag}\n onPointerUp={(e) => {\n if (!draggingRef.current) return\n draggingRef.current = null\n if (controls) controls.enabled = true\n ;(e.target as Element).releasePointerCapture(e.pointerId)\n props.onBehaviorChange?.({ ...overridesRef.current })\n }}\n >\n <sphereGeometry args={[0.035, 16, 16]} />\n <meshBasicMaterial color=\"#4f7cff\" depthTest={false} transparent opacity={0.9} />\n </mesh>\n ))}\n </group>\n )\n})\n\n/**\n * A stack with the sheet's CONFIGURED creases folded in — the probe's view of\n * memory.\n *\n * The frame loop does not use this: it has the tracker's live creases, which\n * are ahead of config by however long the host takes to persist them. Both\n * paths agree on the lines, which is the only thing the geometry probe reads.\n */\nfunction withMemory(\n stack: DeformerInstance[] | null,\n config: PaperConfig,\n creases: CreaseConfig[] = config.memory.creases,\n): DeformerInstance[] | null {\n // A strip owns its vertices outright; cloth hands them on to the stack.\n // Which means a crease on a CLOTH sheet is now a fold the geometry runs,\n // not just a mark the shader draws — the paper remembers a fold whether or\n // not it is being simulated.\n if (isStripConfig(config.physics)) return null\n const out = applyMemory(stack ?? [], creases)\n // Empty and null mean different things upstream — null is \"nothing deforms\n // this sheet\", which is the answer that gets it the flat-sheet grid.\n return out.length > 0 ? out : null\n}\n\n/**\n * The vertex nearest a local-space point, by index.\n *\n * Reads the array it is handed rather than the simulation, which is the point\n * of it: what a pointer touched is what is on screen.\n */\nfunction nearestVertex(array: Float32Array, count: number, x: number, y: number, z: number): number {\n let best = -1\n let bestDist = Infinity\n for (let i = 0; i < count; i++) {\n const i3 = i * 3\n const dx = array[i3]! - x\n const dy = array[i3 + 1]! - y\n const dz = array[i3 + 2]! - z\n const d = dx * dx + dy * dy + dz * dz\n if (d < bestDist) {\n bestDist = d\n best = i\n }\n }\n return best\n}\n\n/** The one simulation that will not share its vertices. See the schema. */\nfunction isStripConfig(physics: PaperConfig['physics']): boolean {\n return typeof physics === 'object' && physics.type === 'strip'\n}\n\n/** Expand the config into the deformer stack that should run this frame. */\nfunction buildStack(\n config: PaperConfig,\n overrides: Record<string, unknown>,\n behavior?: Behavior | null,\n t = 0,\n): DeformerInstance[] | null {\n // A strip owns the vertices outright — no deformer stack. Cloth does not:\n // it writes the vertices and the stack runs over what it wrote.\n if (isStripConfig(config.physics)) return null\n const idle =\n typeof config.physics === 'string' && config.physics !== 'none'\n ? getIdlePreset(config.physics as IdleName)\n : null\n const idleStack = idle?.stack?.() ?? []\n\n let shapeStack: DeformerInstance[] = []\n if (config.deformers) {\n // Raw deformer stack wins — it's the Advanced fork of a behavior.\n shapeStack = resolveDeformerStack(config.deformers)\n } else if (config.behavior) {\n const b = behavior ?? getBehavior(config.behavior.type)\n let options: Record<string, unknown> = { ...config.behavior, ...overrides }\n if (b.loop) options = { ...options, ...b.loop(options, t) }\n shapeStack = b.stack(options, config.sheet)\n }\n\n const combined = [...shapeStack, ...idleStack]\n return combined.length > 0 ? combined : null\n}\n","import { z } from 'zod'\nimport { mergeConfig } from './merge'\nimport { peelOptionsSchema } from '../behaviors/peel'\nimport { unrollOptionsSchema } from '../behaviors/unroll'\nimport { flipOptionsSchema } from '../behaviors/flip'\nimport { letterFoldOptionsSchema } from '../behaviors/letter-fold'\nimport { hangOptionsSchema } from '../behaviors/hang'\nimport { flyOptionsSchema } from '../behaviors/fly'\nimport { fallOptionsSchema } from '../behaviors/fall'\nimport { carryOptionsSchema } from '../behaviors/carry'\nimport { flightOptionsSchema } from '../behaviors/flight'\nimport { crumpleBehaviorOptionsSchema } from '../behaviors/crumple'\nimport { settleOptionsSchema } from '../behaviors/settle'\nimport { ribbonOptionsSchema } from '../behaviors/ribbon'\n\n/**\n * The zod schema is the single source of truth: it validates the public API,\n * generates editor panels, defines the `.paper` preset format, and feeds the docs.\n * If a feature can't serialize into this schema, it waits.\n *\n * Every schema here exports BOTH of its types, and the difference is\n * load-bearing. `z.infer` is the parsed config — every default filled in,\n * every field present — and it is what the renderer reads. `z.input` is what\n * a caller is allowed to write, where anything with a default is optional,\n * and it is what every public prop must take. Handing a component the\n * inferred type instead demands that the caller supply every field of every\n * nested object, which turns the documented one-liner into a type error.\n */\n\n// ── Sheet ────────────────────────────────────────────────────────────────────\n\nexport const sheetSchema = z.object({\n /** World units. A letter sheet is ~1 × 1.4, a receipt ~1 × 2.6. */\n width: z.number().positive().max(20).default(1),\n height: z.number().positive().max(20).default(1.4),\n /** Visual thickness in mm-ish units; drives edge/shadow treatment, not geometry (yet). */\n thickness: z.number().min(0).max(2).default(0.2),\n /**\n * `'auto'` sizes the grid from the active deformers' needs — genuinely, as\n * of 0.3.0. It asks each one what these options require (a gentle bend and\n * a tight roll are not the same request), takes the densest answer, and\n * snaps it to a ladder so dragging a slider does not rebuild the mesh.\n *\n * It is capped at 72, which is what it used to hand out flat regardless of\n * what was on the sheet, so `'auto'` can only ever subdivide LESS than it\n * did before — a blank sheet drops from 72 a side to 8, and stops being\n * tessellated as finely as a crumpled one.\n *\n * Set a number to take the decision yourself; a deformer's `minSegments`\n * still raises it, because that is a correctness floor rather than a\n * preference.\n */\n segments: z.union([z.literal('auto'), z.number().int().min(2).max(256)]).default('auto'),\n cornerRadius: z.number().min(0).max(0.5).default(0),\n})\n\nexport type SheetConfig = z.infer<typeof sheetSchema>\n\n// ── Stock ────────────────────────────────────────────────────────────────────\n\nexport const stockNames = [\n 'printer',\n 'thermal',\n 'kraft',\n 'newsprint',\n 'vellum',\n 'photo-gloss',\n 'sticker',\n] as const\nexport const stockSchema = z.enum(stockNames)\nexport type StockName = z.infer<typeof stockSchema>\n\n// ── Content ──────────────────────────────────────────────────────────────────\n\n/**\n * A watercolour wash, painted under whatever else the sheet carries.\n *\n * It is a FIELD on every content type rather than a content type of its own,\n * and that is the whole design. A wash is a ground, not a subject: the thing\n * people want is a letter written over one, a card laid on one, a poster with\n * one behind the type. Made a sixth member of the union it would have been\n * mutually exclusive with the text it exists to sit behind, and the only way\n * to get both would have been to bake the words into an uploaded picture —\n * which is exactly the trick this library exists to avoid.\n *\n * Painted rather than shipped as artwork, for the same reason `DEMO_CARDS`\n * are typeset rather than photographed. A bitmap is ~100KB that cannot cross\n * a share link, does not survive an export to someone else's codebase, and\n * does not know what stock it is lying on. A wash described in nine numbers\n * travels anywhere the config does, tints against the paper under it, and\n * curls with the mesh because it IS the texture.\n */\nexport const washSchema = z.object({\n /** The first pigment. */\n color: z.string().default('#4a5b8c').describe('color'),\n /** The second. Blooms alternate, and overlaps multiply into a third. */\n secondary: z.string().default('#b06a6a').describe('color'),\n /** How many pools of colour. */\n blooms: z.number().int().min(1).max(24).default(7),\n /** How far a pool runs before it dries — its size against the sheet. */\n spread: z.number().min(0.1).max(1).default(0.7),\n /** Softness of the wet edge. 0 is a hard cut, 1 is a pool still moving. */\n bleed: z.number().min(0).max(1).default(0.5),\n /** How much pigment is in the water. */\n intensity: z.number().min(0).max(1).default(0.55),\n /**\n * Edge darkening — the ring of pigment left where a pool dried.\n *\n * The signature of the medium, and the one thing a plain gradient cannot\n * fake. Without it a wash reads as an airbrush.\n */\n edge: z.number().min(0).max(1).default(0.6),\n /** Pigment settling into the tooth of the paper. */\n granulation: z.number().min(0).max(1).default(0.35),\n /** Fixed so a preset paints the same wash every time. */\n seed: z.number().int().min(0).max(99).default(0),\n})\n\nexport type WashConfig = z.infer<typeof washSchema>\n\nconst blankContentBase = z.object({\n type: z.literal('blank'),\n})\n\nconst imageContentBase = z.object({\n type: z.literal('image'),\n /**\n * Empty means \"no picture yet\", and renders as bare stock rather than as\n * a failure. That is what lets a built-in preset be an image preset\n * without shipping — or fetching — a photograph: `photo-print` and\n * `postage-stamp` are containers for the caller's own art, handed over via\n * `<PaperField images={...} />` or `content.src`.\n */\n src: z.string().default(''),\n fit: z.enum(['cover', 'contain']).default('cover'),\n /** Read by the hidden DOM mirror and the no-WebGL fallback. */\n alt: z.string().optional(),\n})\n\nconst textContentBase = z.object({\n type: z.literal('text'),\n text: z.string().default('Dear reader,'),\n font: z.string().default('Georgia, \"Times New Roman\", serif'),\n /** px at texture resolution (long edge = 1024 logical px before DPR). */\n size: z.number().min(8).max(256).default(44),\n weight: z.number().min(100).max(900).default(400),\n color: z.string().default('#2b2620').describe('color'),\n align: z.enum(['left', 'center', 'right']).default('left'),\n /** Fraction of the short edge. */\n padding: z.number().min(0).max(0.4).default(0.09),\n lineHeight: z.number().min(0.8).max(3).default(1.45),\n /**\n * Letter-spacing, in em. The one control display type cannot do without:\n * a line set large enough to be read across a room needs its tracking\n * pulled IN, and a small line of uppercase small-print needs it pushed\n * out, and neither is achievable by changing the size.\n */\n tracking: z.number().min(-0.1).max(0.6).default(0),\n /**\n * Where the block sits down the sheet.\n *\n * `top` is the old behaviour and stays the default, because a letter\n * starts at the top of the page. `center` is what a card, a label or a\n * poster wants — a block of type optically centred in the sheet rather\n * than hung from its top edge.\n */\n valign: z.enum(['top', 'center']).default('top'),\n})\n\n/**\n * A card: the small stiff printed thing paper is most often cut into.\n *\n * One type covers the index card, the library due-date card, the museum\n * wall label, the telegram slip and the gallery quote sheet, because they\n * are the same object — a tracked label, a rule, a body, and a line of small\n * print — differing only in which parts are present.\n *\n * It exists because `text` could not make any of them. `text` sets a block\n * of prose in one size and one weight; every artifact above is a\n * COMPOSITION, with a hierarchy and a rule in it, and composing one out of\n * plain text meant hand-placing newlines and hoping.\n */\nconst cardContentBase = z.object({\n type: z.literal('card'),\n /** Small, tracked, uppercase by convention — the label at the top. */\n title: z.string().default(''),\n /** The card's reason for existing. */\n body: z.string().default(''),\n /** Attribution, catalogue number, date — the line in small print at the foot. */\n note: z.string().default(''),\n /** A hairline under the title. What separates a label from a paragraph. */\n rule: z.boolean().default(true),\n /**\n * Ruled writing lines behind the body, as on an index card.\n *\n * Drawn UNDER the type and in the stock's own ink at low alpha, so they\n * read as printed on the card rather than as underlines on the words.\n */\n ruled: z.boolean().default(false),\n font: z.string().default('Georgia, \"Times New Roman\", serif'),\n /**\n * Body size, px at texture resolution. Title and note derive from it.\n *\n * Set larger than the `text` default on purpose. A card is a small object\n * read close up, so its type is LARGE relative to the sheet; at the text\n * block's 42 the composition floated in the middle of the card with a\n * third of the stock empty above and below it, which reads as a page that\n * was cropped rather than as a card that was set.\n */\n size: z.number().min(8).max(256).default(58),\n color: z.string().default('#2b2620').describe('color'),\n align: z.enum(['left', 'center']).default('left'),\n padding: z.number().min(0).max(0.4).default(0.1),\n})\n\nconst receiptContentBase = z.object({\n type: z.literal('receipt'),\n store: z.string().default('PAPERLAB'),\n address: z.string().default('124 PAPER ST'),\n items: z.array(z.object({ name: z.string(), price: z.number() })).default([\n { name: 'CURL, TRUE', price: 12 },\n { name: 'ROLL, TIGHT', price: 8.5 },\n { name: 'SHEET, ONE', price: 0.99 },\n ]),\n taxRate: z.number().min(0).max(1).default(0.08),\n barcode: z.boolean().default(true),\n /** Fixed so presets render deterministically; omit for \"now\". */\n timestamp: z.string().optional(),\n footer: z.string().default('KEEP FOR YOUR RECORDS'),\n})\n\n/** A ground under the subject, on either side of the sheet. */\nconst withWash = { wash: washSchema.optional() }\n\n/** What can print on the reverse side (letter front / blank back, printed front / kraft back). */\nexport const backContentSchema = z.discriminatedUnion('type', [\n blankContentBase.extend(withWash),\n imageContentBase.extend(withWash),\n textContentBase.extend(withWash),\n cardContentBase.extend(withWash),\n receiptContentBase.extend(withWash),\n])\n\nexport type BackContentConfig = z.infer<typeof backContentSchema>\n\n/**\n * What every content type carries besides its own subject: what prints on\n * the reverse, and what is washed on underneath.\n */\nconst withBack = { back: backContentSchema.optional(), ...withWash }\n\nexport const blankContentSchema = blankContentBase.extend(withBack)\nexport const imageContentSchema = imageContentBase.extend(withBack)\nexport const textContentSchema = textContentBase.extend(withBack)\nexport const cardContentSchema = cardContentBase.extend(withBack)\nexport const receiptContentSchema = receiptContentBase.extend(withBack)\n\nexport const contentSchema = z.discriminatedUnion('type', [\n blankContentSchema,\n imageContentSchema,\n textContentSchema,\n cardContentSchema,\n receiptContentSchema,\n])\n\nexport type ContentConfig = z.infer<typeof contentSchema>\n/** What a caller may WRITE — defaults still unfilled. This is the prop type. */\nexport type ContentConfigInput = z.input<typeof contentSchema>\n\n/**\n * Every kind of thing that can print on a sheet, in declaration order.\n *\n * Read off the union rather than written out beside it. The sibling name\n * lists here (`stockNames`, `physicsNames`) are the SOURCE their schema is\n * built from, so a hand-written array is the single source of truth; this\n * one is not — the union is — and a second copy would be free to drift the\n * day a sixth content type lands.\n */\nexport const contentNames = contentSchema.options.map(\n (option) => option.shape.type.value,\n) as readonly ContentConfig['type'][]\n\n/**\n * One variant's schema, by its `type`.\n *\n * Exists so that a caller GENERATING UI from the schema — the editor's\n * inspector already does this for behaviors, layouts and the stage — can\n * reach a content variant without reaching into the union's internals.\n * Which member carries which discriminator is the union's own fact to\n * state, not a walk's to rediscover.\n */\nexport function contentSchemaFor(type: ContentConfig['type']): (typeof contentSchema)['options'][number] {\n const option = contentSchema.options.find((candidate) => candidate.shape.type.value === type)\n if (!option) throw new Error(`Unknown content type: ${type}`)\n return option\n}\n\n// ── Surface ──────────────────────────────────────────────────────────────────\n\nexport const paperEdges = ['top', 'right', 'bottom', 'left'] as const\n\n/**\n * Fragment-side effects, composed in registration order into one shader\n * program. Stocks contribute defaults (thermal → banding + yellowing);\n * explicit surface config overrides per effect.\n */\nexport const surfaceSchema = z.object({\n /** Paper fiber noise, 0..1. */\n grain: z.number().min(0).max(1).optional(),\n /** Light passing through the sheet from behind, 0..1. Stock defaults apply. */\n translucency: z.number().min(0).max(1).optional(),\n /** Torn-edge alpha with a lightened fiber band. */\n deckle: z\n .object({\n edges: z.array(z.enum(paperEdges)).default(['bottom']),\n roughness: z.number().min(0).max(1).default(0.5),\n })\n .optional(),\n /** Visual AO/highlight companion to the fold deformer. */\n creaseLines: z\n .object({\n /** Crease line direction, degrees (0 = horizontal lines). */\n angle: z.number().min(-360).max(360).default(0),\n /** Positions across the sheet, 0..1 fractions. */\n positions: z.array(z.number().min(0).max(1)).default([1 / 3, 2 / 3]),\n strength: z.number().min(0).max(1).default(0.5),\n })\n .optional(),\n /** Yellowing + foxing spots, 0..1. */\n aging: z.number().min(0).max(1).optional(),\n /** Reversed front-content ghost on the backside, 0..1. Stock defaults apply. */\n showThrough: z.number().min(0).max(1).optional(),\n /**\n * Postage-stamp perforation: alpha-punched semicircular holes along chosen\n * edges. `state` flips an edge to a ripped-through profile (torn) — set\n * automatically when a paper detaches from a `sheet` field, manual wins.\n */\n perforation: z\n .object({\n edges: z.union([z.array(z.enum(paperEdges)), z.literal('all')]).default('all'),\n /** World units — default tuned to stamp scale. */\n holeRadius: z.number().min(0.002).max(0.1).default(0.016),\n spacing: z.number().min(0.01).max(0.5).default(0.055),\n state: z\n .object({\n top: z.enum(['intact', 'torn']).optional(),\n right: z.enum(['intact', 'torn']).optional(),\n bottom: z.enum(['intact', 'torn']).optional(),\n left: z.enum(['intact', 'torn']).optional(),\n })\n .default({}),\n })\n .optional(),\n})\n\nexport type SurfaceConfig = z.infer<typeof surfaceSchema>\nexport type SurfaceConfigInput = z.input<typeof surfaceSchema>\nexport type PaperEdge = (typeof paperEdges)[number]\n\n// ── Memory ───────────────────────────────────────────────────────────────────\n\n/**\n * A crease the paper carries: a line it has been folded along and did not\n * fully come back from.\n *\n * `angle` and `offset` name the line exactly as {@link foldOptionsSchema}\n * does — angle is the direction the fold TRAVELS and the crease line runs\n * perpendicular to it, offset is the signed distance of that line from the\n * sheet's centre along the travel direction. Naming the line in the fold\n * deformer's own terms is what lets a remembered crease and a live fold\n * recognise each other as the same crease rather than stack into two.\n */\nexport const creaseSchema = z.object({\n angle: z.number().min(-360).max(360).default(90),\n offset: z.number().min(-20).max(20).default(0),\n /**\n * The residual fold angle in degrees, signed — how far open the crease\n * still sits once nothing is holding the paper. This is the whole of what\n * a crease IS: geometry and shading both read it, and it is what makes the\n * field authorable by hand (a dog-ear is a crease with a big `depth` near\n * a corner) rather than only recordable.\n */\n depth: z.number().min(-180).max(180).default(12),\n})\n\nexport type CreaseConfig = z.infer<typeof creaseSchema>\nexport type CreaseConfigInput = z.input<typeof creaseSchema>\n\n/**\n * What the sheet remembers having been done to it.\n *\n * Paper is PLASTIC where cloth is elastic: fold it and it keeps the fold.\n * Every deformer in the library is a pure function of its options, so a\n * sheet folded to 180° and back to 0° comes out of the stack pristine —\n * which is right for cloth and wrong for the one material Paperlab models.\n * This is the layer that remembers, and it lives beside the stack rather\n * than inside it precisely so deformers stay pure.\n */\nexport const memorySchema = z.object({\n /**\n * How much of a fold this paper keeps, 0..1, over the stock's own\n * {@link Stock.takesSet}. Kraft holds a crease hard; vellum springs most\n * of the way back.\n */\n set: z.number().min(0).max(1).optional(),\n /**\n * The creases themselves. Recorded by folding the paper (see\n * `onCrease`), or written by hand — a preset can ship already creased.\n *\n * Capped at four because that is what the crease shader carries, and a\n * cap the schema states is better than one the renderer applies silently.\n */\n creases: z.array(creaseSchema).max(4).default([]),\n})\n\nexport type MemoryConfig = z.infer<typeof memorySchema>\nexport type MemoryConfigInput = z.input<typeof memorySchema>\n\n// ── Behavior & deformers ─────────────────────────────────────────────────────\n\nexport const behaviorConfigSchema = z.discriminatedUnion('type', [\n peelOptionsSchema.extend({ type: z.literal('peel') }),\n unrollOptionsSchema.extend({ type: z.literal('unroll') }),\n flipOptionsSchema.extend({ type: z.literal('flip') }),\n letterFoldOptionsSchema.extend({ type: z.literal('letter-fold') }),\n hangOptionsSchema.extend({ type: z.literal('hang') }),\n flyOptionsSchema.extend({ type: z.literal('fly') }),\n fallOptionsSchema.extend({ type: z.literal('fall') }),\n carryOptionsSchema.extend({ type: z.literal('carry') }),\n flightOptionsSchema.extend({ type: z.literal('flight') }),\n crumpleBehaviorOptionsSchema.extend({ type: z.literal('crumple') }),\n settleOptionsSchema.extend({ type: z.literal('settle') }),\n ribbonOptionsSchema.extend({ type: z.literal('ribbon') }),\n])\n\nexport type BehaviorConfig = z.infer<typeof behaviorConfigSchema>\nexport type BehaviorConfigInput = z.input<typeof behaviorConfigSchema>\n\n/** Advanced escape hatch: a raw deformer stack (editing one forks the behavior). */\nexport const deformerInstanceSchema = z.object({\n type: z.string(),\n options: z.record(z.string(), z.unknown()).default({}),\n enabled: z.boolean().default(true),\n})\n\nexport type DeformerInstanceConfig = z.infer<typeof deformerInstanceSchema>\nexport type DeformerInstanceConfigInput = z.input<typeof deformerInstanceSchema>\n\n// ── Physics ──────────────────────────────────────────────────────────────────\n\n/** Kept in sync with `idleNames` in physics/idle.ts (asserted by test). */\nexport const physicsNames = ['none', 'float', 'tumble', 'dangle', 'taped', 'breeze'] as const\n\nexport const clothConfigSchema = z.object({\n type: z.literal('cloth'),\n pins: z.enum(['top-edge', 'top-corners', 'corner', 'none']).default('top-edge'),\n wind: z.number().min(0).max(1).default(0.3),\n /** Bend stiffness: 1 = crisp paper, 0 = silk. */\n stiffness: z.number().min(0).max(1).default(0.8),\n gravity: z.number().min(0).max(2).default(1),\n /** Local-space ground plane the sheet settles onto. */\n floor: z.number().min(-5).max(0).default(-1.4),\n})\n\nexport type ClothConfig = z.infer<typeof clothConfigSchema>\n\n/**\n * A strip of paper paying off a roll, and the pile it makes when it lands.\n *\n * The one simulation with a driving body: `scroll` turns the roll, the roll\n * extrudes paper, and the paper is left to fall. Bind `scroll` to the page —\n * it is a MONOTONIC world-unit figure, not a 0..1 progress, because the sim\n * differentiates it and only ever reads the delta.\n */\nexport const stripConfigSchema = z.object({\n type: z.literal('strip'),\n /** How far the page has scrolled, in world units of paper asked for. */\n scroll: z.number().min(-1000).max(1000).default(0),\n /** Thin layers and many turns, or few and fat. */\n tightness: z.number().min(0).max(1).default(0.6),\n /** Radius of the cardboard tube — the roll never pays out past it. */\n core: z.number().min(0.01).max(0.5).default(0.09),\n /** Paper already hanging before the first scroll. A roll always has a leaf out. */\n tail: z.number().min(0).max(20).default(1.1),\n /** Spacing of the perforations: one sheet's worth of strip, in world units. */\n perforation: z.number().min(0.05).max(5).default(1),\n /**\n * How much a perforation remembers being folded. 0 = a fresh roll, 1 = one\n * that has been used.\n *\n * The default is high on purpose: below about 0.6 the landed paper flops\n * over in flat panels and spreads across the floor, and at 0.7 it holds its\n * folds and stacks into an accordion. The pile is the point.\n */\n crease: z.number().min(0).max(1).default(0.7),\n /** Bend stiffness between perforations. 1 = card, 0 = cloth. */\n stiffness: z.number().min(0).max(1).default(0.55),\n /** Broadside air drag — what makes paper float down rather than drop. */\n drag: z.number().min(0).max(1).default(0.55),\n gravity: z.number().min(0).max(2).default(1),\n /**\n * How far below the roll the paper lands. A DISTANCE below the roll's axis,\n * matching `unroll.floor`, not a signed y like `cloth.floor` — the roll\n * family measures drops, and the composition is centred on the origin so\n * an absolute y would not survive the offset anyway.\n */\n floor: z.number().min(0.1).max(30).default(1.2),\n /** How long the roll coasts after the scroll stops. */\n inertia: z.number().min(0).max(1).default(0.45),\n})\n\nexport type StripConfig = z.infer<typeof stripConfigSchema>\n\nexport const physicsSchema = z.union([\n z.enum(physicsNames),\n z.literal('cloth').transform(() => clothConfigSchema.parse({ type: 'cloth' })),\n z.literal('strip').transform(() => stripConfigSchema.parse({ type: 'strip' })),\n clothConfigSchema,\n stripConfigSchema,\n])\n\nexport type PhysicsConfig = z.infer<typeof physicsSchema>\nexport type PhysicsConfigInput = z.input<typeof physicsSchema>\n\n// ── Scene ────────────────────────────────────────────────────────────────────\n\nexport const lightingNames = [\n 'studio',\n 'window',\n 'leaves',\n 'goldenhour',\n 'noir',\n 'nave',\n 'raking',\n 'lightbox',\n] as const\n\n/**\n * The film the picture is printed on — the tone curve that maps unbounded\n * scene light onto a screen.\n *\n * This matters more here than in most 3D work because the subject is almost\n * white. A sheet of printer stock sits at `#fbfaf7`, and a lit one runs past\n * 1.0 constantly, so the whole image lives in the part of the curve where\n * tone mappers disagree most.\n *\n * - `neutral` — **the default.** Khronos PBR Neutral, built specifically to\n * preserve hue and saturation through the highlight roll-off. On a warm\n * backlit hall it is the only one of the three that keeps the light warm.\n * - `agx` — filmic, with a long, very graceful roll-off. It also desaturates\n * hard as it approaches white, which is a look; on a scene whose subject\n * IS warm light through paper it bleaches the thing you came for.\n * - `filmic` — ACES. High contrast, drifts bright neutrals toward\n * yellow-green, and washes out badly once a source is bright enough to\n * clip. This is what every preset was pinned to before.\n *\n * Measured on `nave` rather than argued: rendered through all three with the\n * source authored as a real HDR emitter, `neutral` holds the cream glow,\n * `agx` and `filmic` both bleach it to grey-white.\n */\nexport const filmNames = ['agx', 'neutral', 'filmic'] as const\n\n/** Scene-level presentation, serialized with the paper. */\n/**\n * Overrides on top of a named preset — the Blender-panel half of lighting.\n *\n * Every field is optional ON PURPOSE. An unset field means \"whatever the\n * preset says\", so a shared link carries the two sliders you actually moved\n * rather than a frozen copy of a rig you never touched, and re-basing onto\n * another preset keeps your intent instead of your numbers.\n */\nexport const lightSchema = z.object({\n /** Tone-mapping exposure — the stop the whole picture is printed at. */\n exposure: z.number().min(0.1).max(4).optional(),\n /**\n * The tone curve — the film, where `exposure` is the stop.\n *\n * `filmic` is ACES, which is what every preset used to be pinned to and is\n * kept so a scene tuned against it can say so. On near-white paper it is\n * the wrong film: it desaturates and drags bright neutrals toward\n * yellow-green, which is the sepia cast a lit sheet used to pick up.\n */\n film: z.enum(filmNames).optional(),\n /** Key light strength. */\n key: z.number().min(0).max(12).optional(),\n /** Key light colour. */\n color: z.string().optional().describe('color'),\n /**\n * Where the key stands, degrees around the vertical. 0° is straight in\n * front of the paper (+Z, beside the camera), 90° is off to the right,\n * and ±180° is directly behind it — which is where `nave` puts it, and\n * why that preset is carried by light coming THROUGH the paper.\n */\n direction: z.number().min(-180).max(180).optional(),\n /** How high the key stands, degrees above the horizon. */\n height: z.number().min(-30).max(89).optional(),\n /** Flat fill from every direction at once. Cheap, and it kills form — reach for `studio` first. */\n ambient: z.number().min(0).max(2).optional(),\n /** The room's own light: an environment map built from `sky`. Directional fill, and the only thing paper's sheen has to reflect. */\n studio: z.number().min(0).max(3).optional(),\n /** Distance haze, as a multiple of the preset's. 0 clears the air entirely; 2 halves the distance you can see. */\n haze: z.number().min(0).max(3).optional(),\n})\n\nexport type LightOverrides = z.infer<typeof lightSchema>\nexport type LightOverridesInput = z.input<typeof lightSchema>\n\n/**\n * What is behind the sheet.\n *\n * Optional, and that is deliberate: an unset backdrop means the canvas is\n * left exactly as it was found. `<Paper>` has always rendered onto whatever\n * is behind it, and a default that painted the frame would change the look\n * of every sheet already on a page.\n *\n * It is part of the CONFIG rather than a preview trick in the editor,\n * because the whole export story is that the code you copy makes the picture\n * you were looking at. A backdrop that existed only in the editor would make\n * the most-photographed part of a composition the one thing that does not\n * travel.\n */\nexport const backdropSchema = z.object({\n /** Behind everything, and behind the picture where it does not reach. */\n color: z.string().default('#171717').describe('color'),\n /** A URL, or an uploaded picture. Empty is the colour on its own. */\n image: z.string().default(''),\n fit: z.enum(['cover', 'contain']).default('cover'),\n /**\n * Toward the colour, so the paper stays the subject.\n *\n * A backdrop at full strength competes with the sheet in front of it —\n * which is what a real photographer solves by putting the background out\n * of the light, and what this solves by mixing it back toward the ground\n * it sits on.\n */\n fade: z.number().min(0).max(1).default(0.25),\n /** Out of focus, for the same reason. */\n blur: z.number().min(0).max(1).default(0.2),\n})\n\nexport type BackdropConfig = z.infer<typeof backdropSchema>\n\nexport const sceneSchema = z.object({\n lighting: z.enum(lightingNames).default('studio'),\n /** What is behind the sheet. Unset leaves the canvas alone. */\n backdrop: backdropSchema.optional(),\n /**\n * Degrees the whole composition is turned about its vertical axis, so a\n * preset can choose the angle it is READ from.\n *\n * Every camera in the library is fixed and head-on — `<Paper>` sits at\n * `(0, 0.35, 2.4)` looking down -Z, and neither it nor the editor fits a\n * camera to its content. That is the right default for a sheet, which is\n * flat and faces you. It is the wrong one for anything whose shape lives\n * in DEPTH: the `strip` sim folds in z by construction, so head-on its\n * roll and the whole accordion of its pile are edge-on and the preset\n * renders as a blank white column.\n *\n * A camera field would have been the other way to fix it, and is worse: it\n * is meaningless inside `<PaperField>` and `<PaperMesh>`, where the caller\n * owns the camera and there may be a dozen papers sharing it. Turning the\n * paper works everywhere, because it is a property of the paper.\n *\n * Additive with the `rotation` prop rather than overriding it — the prop\n * is the caller's, and a preset does not get to overrule it.\n */\n turn: z.number().min(-180).max(180).default(0),\n /**\n * Overrides on the named preset — the same authorable half stage mode has\n * always had, and which a lone sheet had no way to reach.\n *\n * A preset was the starting point everywhere EXCEPT here: a stage could be\n * \"nave, but the sun is lower\", and a `<Paper>` could only be one of seven\n * rigs exactly as shipped. `<PaperLighting>` has taken these overrides all\n * along; nothing was passing them.\n */\n light: lightSchema.default({}),\n})\n\nexport type SceneConfig = z.infer<typeof sceneSchema>\nexport type SceneConfigInput = z.input<typeof sceneSchema>\nexport type LightingName = (typeof lightingNames)[number]\nexport type FilmName = (typeof filmNames)[number]\n\n// ── Interaction states ───────────────────────────────────────────────────────\n\n/**\n * A state is a set of parameter overrides on the base preset — never a\n * separate preset. The base stays the single source of truth; states are\n * diffs. Triggers are fixed and built-in for v1 (pointer + pick/drop flow);\n * `custom:*` names are the escape hatch for editor v2.\n */\nexport const coreStateNames = ['rest', 'hover', 'pressed', 'picked', 'placed'] as const\nexport type CoreStateName = (typeof coreStateNames)[number]\nexport type StateName = CoreStateName | `custom:${string}`\n\nconst isStateName = (s: string): boolean =>\n (coreStateNames as readonly string[]).includes(s) || s.startsWith('custom:')\n\n// Typed as plain string (not the template-literal union) so PaperConfig stays\n// assignable to PaperConfigInput; the refine still enforces valid names.\nconst stateNameSchema = z.string().refine(isStateName, {\n message: `state names are ${coreStateNames.join(', ')} or \"custom:<name>\"`,\n})\n\nexport const stateTransitionSchema = z.object({\n duration: z.number().min(0).max(5).default(0.35),\n /** GSAP ease name. */\n ease: z.string().default('power2.out'),\n})\n\nexport const stateDefSchema = z.object({\n /** Deep-partial override of the paper schema (behavior params, surface, …). */\n overrides: z.record(z.string(), z.unknown()).default({}),\n /** Transition INTO this state. */\n transition: stateTransitionSchema.prefault({}),\n /** Chained actions after arriving. v1: 'emit:<event>' only. */\n onEnter: z.array(z.string().regex(/^emit:[\\w-]+$/, 'v1 actions are \"emit:<event>\"')).default([]),\n})\n\nexport const paperStatesSchema = z.object({\n initial: stateNameSchema.default('rest'),\n states: z\n .record(z.string(), stateDefSchema)\n .default({})\n .refine((rec) => Object.keys(rec).every(isStateName), {\n message: `state names are ${coreStateNames.join(', ')} or \"custom:<name>\"`,\n }),\n /** World-units drag distance that flips pressed → picked (pick-enabled behaviors only). */\n pickThreshold: z.number().min(0.005).max(1).default(0.1),\n})\n\nexport type StateTransitionConfig = z.infer<typeof stateTransitionSchema>\nexport type StateDef = z.infer<typeof stateDefSchema>\nexport type PaperStates = z.infer<typeof paperStatesSchema>\nexport type PaperStatesInput = z.input<typeof paperStatesSchema>\n\n// ── Paper config ─────────────────────────────────────────────────────────────\n\nexport const metaSchema = z.object({\n name: z.string().default('untitled'),\n author: z.string().optional(),\n version: z.string().default('0'),\n tags: z.array(z.string()).default([]),\n})\n\nexport const paperConfigSchema = z\n .object({\n meta: metaSchema.prefault({}),\n sheet: sheetSchema.prefault({}),\n stock: stockSchema.default('printer'),\n content: contentSchema.default({ type: 'blank' }),\n /** A behavior OR a raw deformer stack — if both are present, `deformers` wins (it's the fork). */\n behavior: behaviorConfigSchema.optional(),\n deformers: z.array(deformerInstanceSchema).optional(),\n surface: surfaceSchema.default({}),\n /**\n * What the sheet remembers being folded — creases outlive the fold.\n *\n * Present by default, and on: paper that forgets is the bug this exists\n * to fix, so remembering is not something a preset should have to ask\n * for. `memory: { set: 0 }` is the opt-out, and it is what every sheet in\n * the library did before this shipped.\n */\n memory: memorySchema.prefault({}),\n physics: physicsSchema.default('none'),\n scene: sceneSchema.prefault({}),\n onTwos: z.boolean().default(false),\n /** Interaction state machine — overrides-on-base diffs. */\n states: paperStatesSchema.optional(),\n })\n .superRefine((config, ctx) => {\n // Cloth HOSTS a shape: the sim writes the vertices, and the deformer\n // stack runs over what it wrote. A deformer is a pure map from a point to\n // a point, so it does not care whether the point it was handed came from\n // a flat rest pose or from a sheet that has spent a second falling — and\n // \"fold the paper you are holding\" is the whole reason to want it.\n //\n // A strip does not, and the difference is not squeamishness. Cloth\n // simulates the sheet's OWN grid, so a deformer's uv means on the sim\n // what it means everywhere else. A strip is a 2×N ribbon whose rows are\n // chain nodes: its uv runs along a length of paper that is partly wound\n // on a roll, and a fold placed by uv would land somewhere the sheet is\n // not.\n if (\n typeof config.physics === 'object' &&\n config.physics.type === 'strip' &&\n (config.behavior || config.deformers)\n ) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: ['physics'],\n message:\n \"the strip simulation and behavior/deformers are exclusive — the roll owns the vertices, and its rows are chain nodes rather than the sheet's own grid (pick Shape OR Strip)\",\n })\n }\n // State overrides must stay serializable schema paths: merging them over\n // the base must still parse. (`paperConfigSchema` is initialized by the\n // time any parse runs; the merged candidate carries no `states`, so this\n // cannot recurse.)\n if (config.states) {\n const { states: _states, ...baseSansStates } = config\n for (const [name, def] of Object.entries(config.states.states)) {\n if (!def) continue\n if ((def.overrides as Record<string, unknown>).states !== undefined) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: ['states', 'states', name, 'overrides'],\n message: 'state overrides cannot override `states` (no nested state machines)',\n })\n continue\n }\n const candidate = mergeConfig(baseSansStates as Record<string, unknown>, def.overrides)\n const result = paperConfigSchema.safeParse(candidate)\n if (!result.success) {\n const first = result.error.issues[0]\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: ['states', 'states', name, 'overrides'],\n message: `state \"${name}\" overrides don't validate against the paper schema: ${\n first ? `${first.path.join('.')} — ${first.message}` : 'invalid'\n }`,\n })\n }\n }\n }\n })\n\nexport type PaperConfig = z.infer<typeof paperConfigSchema>\nexport type PaperConfigInput = z.input<typeof paperConfigSchema>\n","/**\n * Deep-merge preset config with prop overrides (overrides win; arrays and\n * discriminated unions replace wholesale, plain objects merge).\n *\n * Lives in its own module (not serialize.ts) because the schema needs it to\n * validate state overrides — schema → serialize would be circular.\n */\nexport function mergeConfig<T>(base: T, override: unknown): T {\n if (override === undefined) return base\n if (\n base !== null &&\n override !== null &&\n typeof base === 'object' &&\n typeof override === 'object' &&\n !Array.isArray(base) &&\n !Array.isArray(override)\n ) {\n // A content/behavior union with a different `type` replaces wholesale —\n // merging { type: 'text' } over { type: 'image', src } would leak `src`.\n const b = base as Record<string, unknown>\n const o = override as Record<string, unknown>\n if ('type' in b && 'type' in o && b.type !== o.type) return override as T\n const out: Record<string, unknown> = { ...b }\n for (const key of Object.keys(o)) {\n out[key] = mergeConfig(b[key], o[key])\n }\n return out as T\n }\n return override as T\n}\n\n/**\n * Like {@link mergeConfig}, but an explicit `undefined` DELETES its key instead\n * of being ignored — the semantics a BASE-config write needs: structural\n * setters can clear `behavior`/`deformers` or toggle a surface effect off.\n * Discriminated unions (differing `type`) still replace wholesale.\n */\nexport function mergeWithDeletes<T>(base: T, patch: unknown): T {\n if (\n base !== null &&\n patch !== null &&\n typeof base === 'object' &&\n typeof patch === 'object' &&\n !Array.isArray(base) &&\n !Array.isArray(patch)\n ) {\n const b = base as Record<string, unknown>\n const p = patch as Record<string, unknown>\n if ('type' in b && 'type' in p && b.type !== p.type) return patch as T\n const out: Record<string, unknown> = { ...b }\n for (const [key, value] of Object.entries(p)) {\n if (value === undefined) delete out[key]\n else out[key] = mergeWithDeletes(b[key], value)\n }\n return out as T\n }\n return patch as T\n}\n","import { z } from 'zod'\nimport type { Behavior } from './types'\nimport { cornerNames } from '../deformers/curl'\n\nexport const peelOptionsSchema = z.object({\n progress: z.number().min(0).max(1).default(0.35),\n /** 'auto' resolves per slot in a `sheet` field (outward-facing corner); standalone it means bottom-right. */\n corner: z.enum([...cornerNames, 'auto']).default('bottom-right'),\n /** Curl sharpness — small is a tight dog-ear, large a soft lift. */\n radius: z.number().min(0.05).max(0.6).default(0.16),\n})\n\nexport type PeelOptions = z.infer<typeof peelOptionsSchema>\n\nconst CORNER_UV: Record<(typeof cornerNames)[number], [number, number]> = {\n 'top-left': [0, 1],\n 'top-right': [1, 1],\n 'bottom-left': [0, 0],\n 'bottom-right': [1, 0],\n}\n\n/** Fields resolve 'auto' per slot; anywhere else it falls back to the default corner. */\nconst concreteCorner = (c: PeelOptions['corner']) => (c === 'auto' ? 'bottom-right' : c)\n\n/** A corner lifts and curls back — the hero-image hover peel. */\nexport const peel: Behavior<PeelOptions> = {\n id: 'peel',\n label: 'Peel',\n defaults: peelOptionsSchema.parse({}),\n optionsSchema: peelOptionsSchema,\n signature: ['progress', 'corner'],\n progressParam: 'progress',\n duration: 2.2,\n loopMode: 'yoyo',\n stack(o) {\n // A deep peel lifts on a softer cylinder — a fixed tight radius would\n // wind the sheet into a dart. Growing the radius with progress keeps the\n // curl reading as a page lift at every depth.\n return [\n {\n type: 'curl',\n options: {\n corner: concreteCorner(o.corner),\n amount: o.progress,\n radius: o.radius + o.progress * 0.3,\n skew: 0,\n },\n },\n ]\n },\n handles: [\n {\n id: 'corner',\n anchor: (o) => CORNER_UV[concreteCorner(o.corner)],\n drag(local, o, sheet) {\n // Pull toward the sheet center = more peel: distance from the flat\n // corner along the inward diagonal, normalized to half the diagonal.\n const [ux, uy] = CORNER_UV[concreteCorner(o.corner)]\n const cx = (ux - 0.5) * sheet.width\n const cy = (uy - 0.5) * sheet.height\n const diag = Math.hypot(sheet.width, sheet.height)\n const inX = -cx / Math.hypot(cx, cy)\n const inY = -cy / Math.hypot(cx, cy)\n const dist = (local.x - cx) * inX + (local.y - cy) * inY\n return { progress: Math.min(1, Math.max(0, dist / (diag * 0.5))) }\n },\n },\n ],\n}\n","import { z } from 'zod'\nimport type { Deformer } from './types'\nimport { segmentsForArc } from '../core/tessellation'\n\nexport const cornerNames = ['top-left', 'top-right', 'bottom-left', 'bottom-right'] as const\n\nexport const curlOptionsSchema = z.object({\n corner: z.enum(cornerNames).default('bottom-right'),\n /** How far the curl has traveled from the corner, as a fraction of the diagonal. */\n amount: z.number().min(0).max(1).default(0.35),\n /** Cylinder radius — curl sharpness. */\n radius: z.number().min(0.02).max(1).default(0.16),\n /** Skew of the fold line away from the corner diagonal, degrees. */\n skew: z.number().min(-40).max(40).default(0),\n})\n\nexport type CurlOptions = z.infer<typeof curlOptionsSchema>\n\nconst DEG = Math.PI / 180\n\nconst CORNER_SIGNS: Record<(typeof cornerNames)[number], [number, number]> = {\n 'top-left': [-1, 1],\n 'top-right': [1, 1],\n 'bottom-left': [-1, -1],\n 'bottom-right': [1, -1],\n}\n\n/**\n * Corner-anchored cylinder wrap — the peel/dog-ear deformer, and the\n * crown-jewel realism case: the mesh genuinely wraps the cylinder so content\n * bends with perfect continuity and the backside becomes visible.\n *\n * The fold line runs perpendicular to the corner diagonal and travels inward\n * with `amount`; everything cornerward of it wraps around the cylinder.\n */\nexport const curl: Deformer<CurlOptions> = {\n id: 'curl',\n label: 'Curl',\n defaults: curlOptionsSchema.parse({}),\n optionsSchema: curlOptionsSchema,\n geometry: {\n minSegments: 48,\n // Curl rolls the corner region around `radius`, travelling inward along\n // the diagonal as `amount` rises. The diagonal is the span the arc can\n // reach across, and `radius` is its curvature throughout.\n autoSegments: (o, sheet) => segmentsForArc(Math.hypot(sheet.width, sheet.height), o.radius),\n // The corner diagonal, plus whatever `skew` turns it by — the same\n // direction `displace` builds below, and the one the wrap runs along.\n axis: (o, sheet) => {\n const [sx, sy] = CORNER_SIGNS[o.corner]\n return Math.atan2(sy * sheet.height, sx * sheet.width) / DEG + o.skew\n },\n },\n displace(out, _uv, o, ctx) {\n const [sx, sy] = CORNER_SIGNS[o.corner]\n const { width, height } = ctx.sheet\n const cx = (sx * width) / 2\n const cy = (sy * height) / 2\n\n // Outward direction: from sheet center toward the corner, plus skew.\n const diag = Math.hypot(width, height)\n const baseX = (sx * width) / diag\n const baseY = (sy * height) / diag\n const skew = o.skew * DEG\n const cosK = Math.cos(skew)\n const sinK = Math.sin(skew)\n const dirX = baseX * cosK - baseY * sinK\n const dirY = baseX * sinK + baseY * cosK\n\n // Signed distance past the fold line (fold travels inward with amount).\n const travel = o.amount * diag * 0.5\n const e = (out.x - cx) * dirX + (out.y - cy) * dirY\n const s = e + travel\n if (s <= 0) return\n\n const theta = s / o.radius\n const sin = Math.sin(theta)\n const cos = Math.cos(theta)\n const boundary = e - s // = -travel\n const newE = boundary + (o.radius - out.z) * sin\n const newZ = o.radius * (1 - cos) + out.z * cos\n\n out.x += dirX * (newE - e)\n out.y += dirY * (newE - e)\n out.z = newZ\n },\n glsl: {\n chunk: /* glsl */ `\nvoid FN(inout vec3 p, vec2 uv, float t) {\n vec2 c = U_cornerSign * uSheet * 0.5;\n float diag = length(uSheet);\n vec2 base = U_cornerSign * uSheet / diag;\n float cosK = cos(U_skew);\n float sinK = sin(U_skew);\n vec2 dir = vec2(base.x * cosK - base.y * sinK, base.x * sinK + base.y * cosK);\n float travel = U_amount * diag * 0.5;\n float e = dot(p.xy - c, dir);\n float s = e + travel;\n if (s <= 0.0) return;\n float theta = s / U_radius;\n float sn = sin(theta);\n float cs = cos(theta);\n float newE = (e - s) + (U_radius - p.z) * sn;\n float newZ = U_radius * (1.0 - cs) + p.z * cs;\n p.xy += dir * (newE - e);\n p.z = newZ;\n}\n`,\n strength: 'amount',\n uniforms: (o) => {\n const [sx, sy] = CORNER_SIGNS[o.corner]\n return {\n cornerSign: [sx, sy],\n amount: o.amount,\n radius: o.radius,\n skew: o.skew * DEG,\n }\n },\n },\n}\n","/**\n * How finely a sheet has to be subdivided for a deformer to look like the\n * surface it is approximating instead of like the polygons it is made of.\n *\n * A deformed mesh is a piecewise-linear stand-in for a curved surface, and the\n * error is the **sagitta**: the gap between a chord and the arc it cuts\n * across. For a chord of length `h` on a circle of radius `r` that gap is\n * `h²/8r` to well under a percent for any chord worth drawing. Invert it and\n * the whole question — \"how many segments does this need?\" — has a closed\n * form: pick the error you are willing to see, and the segment count falls\n * out of the radius.\n *\n * That is the difference between this and `minSegments`. `minSegments` is a\n * correctness FLOOR — the density below which a deformer stops working at\n * all. This is a QUALITY TARGET, and unlike a floor it has to depend on the\n * options: a bend at `curvature: 0.05` and a roll at `radius: 0.02` are not\n * remotely the same request, and one constant per deformer cannot answer for\n * both.\n */\n\nimport type { SheetDims } from '../deformers/types'\n\n/**\n * The error we are willing to see, in world units (a letter sheet is 1 × 1.4,\n * so 1 unit ≈ 216 mm and this is ≈ 0.09 mm).\n *\n * Calibrated, not picked: at `segments: 'auto'`'s old flat 72, the default\n * `roll` (radius 0.12 across a 1.4 span) already ran at a sagitta of 3.9e-4.\n * Setting the tolerance there means the tightest configuration in common use\n * keeps exactly the density it ships with today, and everything gentler —\n * which was paying for that same grid and getting fourteen times the\n * precision it needed — stops paying. The number is a statement about the\n * status quo, so changing it re-lights every preset in the library.\n */\nexport const SAG_TOL = 4e-4\n\n/**\n * Ceiling for `'auto'` in hero mode, and it is a CPU budget rather than a\n * round number.\n *\n * Hero mode re-deforms every vertex in JS on the main thread, every frame,\n * for any animated stack — and `wave` is animated, so a hanging poster pays\n * it forever rather than only while something plays. Measured, one sheet,\n * one re-deform (`drape + wave`, and `crumple` tracks it within 5%), before\n * and after the loop was rewritten around a single-function inner call site\n * and `computeSheetNormals`:\n *\n * | grid | verts | was | now |\n * | ----: | -----: | ---: | ---: |\n * | 72 | 3,796 | 0.74 | 0.27 |\n * | 128 | 11,868 | 2.30 | 0.84 |\n * | 192 | 26,634 | 5.01 | 1.89 |\n * | 256 | 47,288 | 8.74 | 3.38 |\n *\n * **192, raised from 128, and the price is why.** 128 was picked when it cost\n * 2.30 ms — the last step that still left room for a scene around it. 192 now\n * costs 1.89 ms, which is less than 128 ever did, so the old line was drawn\n * against a price that no longer exists.\n *\n * The reason it is nearly free in practice is the axis split: a demand lands\n * on the direction that bends and the other axis stays at `FLAT_SEGMENTS`. A\n * `drape` at its own defaults wants 154 across and two segments down, so the\n * raise costs it 0.02 ms rather than the 1.89 ms a square 192 grid implies.\n * The square case is reachable — a stack that bends both ways, `wave` over\n * `drape` — and it is opt-in through options rather than something a preset\n * hands anybody.\n *\n * What it buys, all of it previously capped: `drape` at its defaults (154),\n * `roll` and `fold` at `radius: 0.02` (175), `curl` at `radius: 0.02` (142).\n * No preset that ships reaches even 128 after the axis split, so this changes\n * nothing already in the library — it stops punishing people who ask for a\n * tighter crease than any preset uses.\n *\n * Still NOT high enough for everything the arithmetic asks: `wave` at\n * `amplitude: 0.3` wants 272 and a 16-fold `drape` at full depth wants 1377.\n * Those stay capped, and the gap is real rather than hidden. Set `segments`\n * to a number (up to the schema's 256) to go past it.\n *\n * A field is capped far lower and separately, because a field draws this\n * geometry N times — see `FIELD_AUTO_CEILING`.\n */\nexport const AUTO_CEILING = 192\n\n/**\n * What a sheet gets when nothing deforms it. A flat plane is exact at one\n * segment; this is the small margin that keeps anything interpolated across\n * the quad (lighting terms, translucency) from reading the corners only.\n */\nexport const FLAT_SEGMENTS = 8\n\n/**\n * What `'auto'` handed out flat, on every sheet, before it learned to adapt.\n *\n * Still load-bearing in two places: it is what `resolveSegments` assumes when\n * a caller has no deformer stack to ask (so the exported helper answers today\n * exactly what it answered before), and it is what a field is allowed to ask\n * for, since a field draws its buffer once per instance.\n */\nexport const LEGACY_FLAT_SEGMENTS = 72\n\n/**\n * Resolved counts are snapped to this ladder. Without it the grid would be a\n * continuous function of the options, so dragging a curvature slider would\n * rebuild the geometry — a new `PlaneGeometry`, a fresh base-position copy,\n * and a disposed buffer — on every tick. Snapped, a drag crosses a step\n * rarely and holds one buffer the rest of the time.\n */\nconst LADDER = [FLAT_SEGMENTS, 12, 16, 24, 32, 48, 64, LEGACY_FLAT_SEGMENTS, 96, 128, AUTO_CEILING] as const\n\n/** Smallest ladder step at or above `n`, clamped to the ceiling. */\nexport function quantizeSegments(n: number): number {\n for (const step of LADDER) if (n <= step) return step\n return AUTO_CEILING\n}\n\n/**\n * A resolved grid: segments along the sheet's own X and Y.\n *\n * Two numbers rather than one because a sheet is not subdivided by a single\n * density. A banner 1.5 wide and 8.5 tall, draped in folds that run across\n * its width, needs the folds resolved ACROSS and needs almost nothing down\n * the drop — and a single number, however it is distributed, answers one of\n * those questions by getting the other one wrong.\n */\nexport type SegmentPair = [x: number, y: number]\n\n/**\n * Split a deformer's segment demand onto the sheet's two axes.\n *\n * A deformer curves along ONE direction — `roll`, `bend`, `fold` and `wave`\n * all name it `angle`, `drape`'s folds run across the width, `curl` works\n * down a corner diagonal — and `segmentsForArc` answers in segments along\n * THAT direction. Turning that into a grid is a projection: the demand is\n * really a density (segments per world unit along the curve), and each axis\n * needs enough of it that a grid edge's component along the curve stays\n * inside the chord the sagitta bound allows.\n *\n * Hence `width·|cos θ|·density` and `height·|sin θ|·density`. A bend across\n * x asks everything of x and nothing of y, which is exactly right: the sheet\n * does not move along y, so subdividing it there buys a bigger buffer and an\n * identical picture.\n *\n * `null` is for a deformer with no single direction — `crumple`'s creases\n * run every way at once. That case keeps the old behaviour of spreading the\n * demand by aspect ratio, which is the honest answer when the demand really\n * is isotropic.\n */\nexport function axialSegments(sheet: SheetDims, angleDeg: number | null, n: number): SegmentPair {\n if (!(n > 0)) return [0, 0]\n if (angleDeg === null) {\n const long = Math.max(sheet.width, sheet.height)\n if (!(long > 0)) return [n, n]\n return [(sheet.width / long) * n, (sheet.height / long) * n]\n }\n const span = spanAlong(sheet, angleDeg)\n if (!(span > 0)) return [n, n]\n const rad = (angleDeg * Math.PI) / 180\n const density = n / span\n return [sheet.width * Math.abs(Math.cos(rad)) * density, sheet.height * Math.abs(Math.sin(rad)) * density]\n}\n\n/**\n * Extent of the sheet along a direction in its own plane, degrees. For a\n * rectangle centered on the origin this is exactly `|w·cos| + |h·sin|` — the\n * projection of both half-extents onto the axis, doubled.\n */\nexport function spanAlong(sheet: SheetDims, angleDeg: number): number {\n const rad = (angleDeg * Math.PI) / 180\n return Math.abs(sheet.width * Math.cos(rad)) + Math.abs(sheet.height * Math.sin(rad))\n}\n\n/**\n * Segments needed to hold a circular arc of radius `r` across `span` within\n * `tol`. Straight inversion of `sag = h²/8r`.\n *\n * A flat or near-flat arc (huge radius) needs nothing, hence the 0 — callers\n * take the max against the floor, so 0 means \"this deformer is not the reason\n * for any subdivision\", which is exactly true of a bend at curvature 0.\n */\nexport function segmentsForArc(span: number, radius: number, tol = SAG_TOL): number {\n if (!(span > 0) || !(radius > 0) || !Number.isFinite(radius)) return 0\n return span / Math.sqrt(8 * radius * tol)\n}\n\n/**\n * Same question for a sinusoid, which is the shape `wave` and `drape` both\n * make. Peak curvature of `A·sin(2πx/λ)` is `A(2π/λ)²` at the crest, so the\n * tightest radius on the curve is its reciprocal and the arc form takes over\n * from there.\n */\nexport function segmentsForSine(span: number, amplitude: number, wavelength: number, tol = SAG_TOL): number {\n if (!(amplitude > 0) || !(wavelength > 0)) return 0\n const k = (2 * Math.PI) / wavelength\n const peakCurvature = amplitude * k * k\n if (!(peakCurvature > 0)) return 0\n return segmentsForArc(span, 1 / peakCurvature, tol)\n}\n","import { z } from 'zod'\nimport type { Behavior } from './types'\nimport type { DeformerInstance, SheetDims } from '../deformers/types'\nimport { rollRadius } from '../deformers/roll'\n\nexport const unrollOptionsSchema = z.object({\n /** 0 = fully rolled cylinder, 1 = flat sheet. */\n progress: z.number().min(0).max(1).default(0.5),\n /** How tightly the paper is wound — thin layers and many turns, or few and fat. */\n tightness: z.number().min(0).max(1).default(0.5),\n /** Idle rocking of the rolled end. */\n sway: z.number().min(0).max(1).default(0.25),\n /** Which end of the sheet holds the roll. `top` hangs the paper below it. */\n from: z.enum(['bottom', 'top']).default('bottom'),\n /** Radius of the tube the paper is wound onto — the roll never shrinks past it. */\n core: z.number().min(0.005).max(0.5).default(0.03),\n /**\n * Paper already hanging at `progress` 0, in world units.\n *\n * A roll on a holder is never a bare cylinder: there is always a leaf out,\n * because that is what you take hold of. Starting from nothing showing\n * reads as a fresh roll still in its wrapper.\n */\n tail: z.number().min(0).max(20).default(0),\n /**\n * How far below the roll the paper lands, in world units. Omit and it\n * hangs forever.\n *\n * Paper that reaches the ground does not stop and does not carry on\n * through it: it creases and runs out flat. Everything past this distance\n * turns a right angle and lies down.\n */\n floor: z.number().min(0.1).max(50).optional(),\n /**\n * Hold the roll still in space and let the paper hang off it, instead of\n * letting the roll ride along with the shrinking wound region.\n */\n fixed: z.boolean().default(false),\n})\n\nexport type UnrollOptions = z.infer<typeof unrollOptionsSchema>\n\n/** Layer gap at `tightness` 0 and 1. Visible thickness, not a real receipt's 60µm. */\nconst LOOSE = 0.1\nconst TIGHT = 0.02\n\nfunction layerThickness(tightness: number): number {\n return LOOSE - tightness * (LOOSE - TIGHT)\n}\n\n/**\n * The span `progress` sweeps the roll boundary across: from the far edge\n * (everything wound) past the near edge (flat, plus slack so the last of the\n * paper fully relaxes).\n */\nfunction sweep(o: UnrollOptions, sheet: SheetDims): { start: number; end: number } {\n const maxRadius = rollRadius(sheet.height, o.core, layerThickness(o.tightness))\n // `tail` starts the boundary short of the far edge, so that much paper is\n // already flat at progress 0. Capped so it cannot start past the end.\n const tail = Math.min(o.tail, sheet.height)\n return { start: -sheet.height / 2 + tail, end: sheet.height / 2 + maxRadius * 2 }\n}\n\n/** Where the wound region begins, as a signed distance along the roll direction. */\nfunction rollBoundary(o: UnrollOptions, sheet: SheetDims): number {\n const { start, end } = sweep(o, sheet)\n return start + o.progress * (end - start)\n}\n\n/** Softness of the crease where the paper meets the ground, scaled to the sheet. */\nconst LANDING_RADIUS = 0.035\n\n/**\n * The crease where the drop meets the ground: a right-angle hinge at the\n * floor line, so the paper above stays vertical and everything below turns\n * over and runs out flat.\n *\n * `fold`, not a second `roll`, and not a steeper angle — both were tried in\n * `ribbon`, which lands a strip the same way, and the notes there are worth\n * reading before touching this. A roll wraps the landed length up and over\n * and ends in the air (a hook, not a pool); anything but exactly 90° either\n * drives the paper on through the floor or floats it back up.\n */\nfunction landing(\n o: UnrollOptions,\n sheet: SheetDims,\n boundary: number,\n rollRadiusNow: number,\n): DeformerInstance {\n const radius = Math.min(0.5, Math.max(0.02, sheet.height * LANDING_RADIUS))\n // The hinge wraps a small cylinder rather than turning on the spot, so the\n // flap leaves it lower than the crease line by exactly that much. Raise the\n // crease by it so the LANDED length sits on the floor, not under it.\n const hingeDrop = radius / (Math.PI / 2)\n\n // The floor in the sheet's own coordinates. The roll is pinned in space and\n // the paper travels past it, so a fixed floor is a MOVING line down here —\n // it sits `floor` below wherever the roll boundary currently is.\n //\n // Clamped clear of the roll itself: a floor closer than the roll's own\n // radius would put the bottom of the roll below the crease line, and the\n // hinge would fold the roll over instead of the paper hanging off it.\n const below = Math.max(o.floor!, rollRadiusNow + radius)\n const floorLine = o.from === 'top' ? boundary - below : -boundary + below\n\n return {\n type: 'fold',\n // Travel points from the roll toward the floor, so \"past the crease\"\n // means \"the length that has arrived\", not the drop above it.\n options:\n o.from === 'top'\n ? { angle: -90, offset: -floorLine - hingeDrop, foldAngle: 90, radius }\n : { angle: 90, offset: floorLine - hingeDrop, foldAngle: 90, radius },\n }\n}\n\n/**\n * Paper coming off a roll: the sheet hangs flat and whatever is left is wound\n * at one end. Content bends true around the roll.\n *\n * The roll SHRINKS as the paper comes off it, because its radius is derived\n * from how much paper is still wound rather than being a constant. That is\n * both the honest physics and the whole appeal of a long sheet: scroll it out\n * and the roll visibly runs down to its tube.\n */\nexport const unroll: Behavior<UnrollOptions> = {\n id: 'unroll',\n label: 'Unroll',\n defaults: unrollOptionsSchema.parse({}),\n optionsSchema: unrollOptionsSchema,\n signature: ['progress', 'tightness'],\n progressParam: 'progress',\n duration: 3,\n loopMode: 'yoyo',\n stack(o, sheet) {\n const thickness = layerThickness(o.tightness)\n const boundary = rollBoundary(o, sheet)\n // Paper still on the roll: the span from the boundary to the far edge.\n const wound = Math.max(0, sheet.height / 2 - boundary)\n const radius = rollRadius(wound, o.core, thickness)\n const stack: DeformerInstance[] = [\n {\n type: 'roll',\n options: {\n // Both directions sweep the same boundary; only which half of the\n // sheet counts as \"past\" it changes. 270 winds the bottom (a\n // receipt feeding downward), 90 winds the top (paper hanging below).\n angle: o.from === 'top' ? 90 : 270,\n boundary,\n radius,\n thickness,\n },\n },\n ]\n if (o.floor !== undefined) stack.push(landing(o, sheet, boundary, radius))\n return stack\n },\n loop(o, t) {\n if (o.sway === 0) return {}\n // The rolled tail rocks gently; transient — never persisted.\n const wobble = Math.sin(t * 1.5) * 0.01 * o.sway\n return { progress: Math.min(1, Math.max(0, o.progress + wobble)) }\n },\n transform(o, _t, pose, sheet) {\n if (!o.fixed) return\n // The wound region shrinks toward the far edge, carrying the roll with\n // it. A roll on a holder does not move — the paper does — so cancel that\n // travel and let the flat tail grow away instead, which is the thing you\n // actually watch.\n //\n // Anchored on the UNROLLED end, so a fully paid-out sheet sits exactly\n // where an undeformed one would and the roll hangs off the edge of that\n // box. Anchoring on the rolled end instead is the same motion, but it\n // parks the whole composition a sheet-length away from the origin, which\n // makes every preset using it need a bespoke camera.\n const travel = sweep(o, sheet).end - rollBoundary(o, sheet)\n pose.position[1] += o.from === 'top' ? travel : -travel\n },\n handles: [\n {\n id: 'roll-edge',\n // The grab point is the edge the paper leaves the roll on, so it tracks\n // the boundary — which runs top-to-bottom for a roll at the bottom and\n // bottom-to-top for one at the top.\n anchor: (o) => {\n const v = o.from === 'top' ? o.progress : 1 - o.progress\n return [0.5, Math.max(0.02, Math.min(0.98, v))]\n },\n drag(local, o, sheet) {\n // Dragging away from the roll unrolls the paper, whichever end it is on.\n const along = local.y / sheet.height\n const p = o.from === 'top' ? 0.5 + along : 0.5 - along\n return { progress: Math.min(1, Math.max(0, p)) }\n },\n },\n ],\n}\n","import { z } from 'zod'\nimport type { Deformer } from './types'\nimport { segmentsForArc, spanAlong } from '../core/tessellation'\n\nexport const rollOptionsSchema = z.object({\n /** Direction of rolling in the sheet plane, degrees. 0 = +x, 90 = +y. */\n angle: z.number().min(-360).max(360).default(90),\n /** Signed distance (along the roll direction, from sheet center) where the roll begins. */\n boundary: z.number().min(-20).max(20).default(0),\n /** Radius of the OUTERMOST wrap — the one the flat sheet leaves the roll on. */\n radius: z.number().min(0.01).max(2).default(0.12),\n /** Gap between consecutive wraps, in world units. 0 = a bare cylinder. */\n thickness: z.number().min(0).max(0.2).default(0.015),\n})\n\nexport type RollOptions = z.infer<typeof rollOptionsSchema>\n\nconst DEG = Math.PI / 180\nconst TAU = Math.PI * 2\n\n/**\n * How far in the spiral is allowed to wind, as a fraction of its outer\n * radius. Paper past that point keeps coiling at a constant radius instead.\n *\n * A spiral that runs all the way to zero collapses every remaining vertex\n * onto one point: degenerate triangles, no normals, an unlit hole in the\n * sheet. Sizing a roll with {@link rollRadius} never reaches here, but\n * `roll` is public and its options are independent numbers, so \"more paper\n * than fits\" has to land somewhere survivable rather than somewhere invalid.\n */\nconst MIN_RADIUS_FRACTION = 0.08\n\n/**\n * Angle swept after winding arc length `s` onto a spiral that starts at\n * radius `r0` and loses `k` of it per radian.\n *\n * Arc length along that spiral is `s = r0·θ − k·θ²/2`, so θ is the smaller\n * root of the quadratic. Written rationalized (`2s / (r0 + √disc)`) rather\n * than as `(r0 − √disc) / k`: the two are equal in exact arithmetic, but the\n * subtractive form cancels catastrophically as k → 0 — precisely the common\n * case, a plain cylinder — and divides by k on top of that.\n *\n * Past the point where the radius would fall below its floor, the spiral\n * continues as a circle at that radius, which keeps the map C¹ and the\n * geometry non-degenerate.\n */\nexport function windAngle(s: number, r0: number, k: number): number {\n if (k <= 0) return s / r0\n const rMin = r0 * MIN_RADIUS_FRACTION\n const thetaFloor = (r0 - rMin) / k\n const sFloor = r0 * thetaFloor - (k * thetaFloor * thetaFloor) / 2\n if (s >= sFloor) return thetaFloor + (s - sFloor) / rMin\n return (2 * s) / (r0 + Math.sqrt(r0 * r0 - 2 * k * s))\n}\n\n/** Radius reached after sweeping `theta`, floored so the coil never collapses. */\nexport function windRadius(theta: number, r0: number, k: number): number {\n return Math.max(r0 - k * theta, r0 * MIN_RADIUS_FRACTION)\n}\n\n/**\n * Outer radius of a roll holding `length` of paper wound onto a core of\n * radius `core` at the given layer `thickness`.\n *\n * The Archimedean identity `L = π(R² − core²) / thickness`, solved for R.\n * It is the exact inverse of what {@link roll} does, which is the property\n * that matters: size a roll with this and its innermost wrap lands precisely\n * on `core` — the paper runs out exactly when the spiral reaches the tube,\n * rather than overshooting into a negative radius or stopping short.\n */\nexport function rollRadius(length: number, core: number, thickness: number): number {\n return Math.sqrt(core * core + (Math.max(0, length) * thickness) / Math.PI)\n}\n\n/**\n * Wrap the sheet around a roll lying across the roll direction. Everything\n * past `boundary` winds; the wrap is C¹-continuous at the boundary and\n * preserves arc length (content never stretches).\n *\n * The paper winds INWARD — the far end of the sheet ends up at the core, and\n * the flat portion leaves from the outermost wrap. That is the only way round\n * that a real roll can be: paper is dispensed off the outside, so the end you\n * are holding must be the outermost layer.\n *\n * The circle's centre is FIXED at `radius` above the boundary and only the\n * radius varies, which is what makes the wraps concentric. Deriving the\n * centre from the current radius instead — the obvious way to write this, and\n * what this deformer did until the geometry was checked — pins every wrap\n * tangent to the plane at the same point, so the wraps form a rosette of\n * circles through one point rather than a spiral, and the sheet passes\n * through itself once per revolution. That bug is invisible at `thickness`\n * 0 (a true cylinder does return to its start) and exactly cancels at every\n * multiple of 2π, so it survived both the golden vectors and the GPU parity\n * gate: they agreed with each other, and both were wrong.\n *\n * Points arriving with z ≠ 0 (from earlier deformers in the stack) ride\n * along the rolled surface's inward normal, so stacks compose sanely.\n */\nexport const roll: Deformer<RollOptions> = {\n id: 'roll',\n label: 'Roll',\n defaults: rollOptionsSchema.parse({}),\n optionsSchema: rollOptionsSchema,\n geometry: {\n minSegments: 48,\n // The INNERMOST wrap is the tightest curvature on the sheet, so it sets\n // the density — the outer one used to, back when the spiral grew outward.\n // Floored at a fraction of the outer radius because segment count scales\n // as 1/√r: a roll wound to a hair's breadth would otherwise ask for a\n // grid nobody can afford, to resolve a few square millimetres at the core.\n autoSegments: (o, sheet) => {\n const span = spanAlong(sheet, o.angle)\n const wound = Math.max(0, span / 2 - o.boundary)\n const k = o.thickness / TAU\n return segmentsForArc(span, windRadius(windAngle(wound, o.radius, k), o.radius, k))\n },\n axis: (o) => o.angle,\n },\n displace(out, _uv, o) {\n const dirX = Math.cos(o.angle * DEG)\n const dirY = Math.sin(o.angle * DEG)\n const d = out.x * dirX + out.y * dirY\n const s = d - o.boundary\n if (s <= 0) return\n\n const k = o.thickness / TAU\n const theta = windAngle(s, o.radius, k)\n // Incoming z rides the inward normal, so it shortens the radius.\n const r = windRadius(theta, o.radius, k) - out.z\n const newD = o.boundary + r * Math.sin(theta)\n const newZ = o.radius - r * Math.cos(theta)\n\n out.x += dirX * (newD - d)\n out.y += dirY * (newD - d)\n out.z = newZ\n },\n glsl: {\n chunk: /* glsl */ `\nvoid FN(inout vec3 p, vec2 uv, float t) {\n vec2 dir = vec2(cos(U_angle), sin(U_angle));\n float d = dot(p.xy, dir);\n float s = d - U_boundary;\n if (s <= 0.0) return;\n float k = U_thickness / 6.2831853071795864;\n float rMin = U_radius * 0.08;\n float thetaFloor = (U_radius - rMin) / max(k, 1e-9);\n float sFloor = U_radius * thetaFloor - 0.5 * k * thetaFloor * thetaFloor;\n float theta = k <= 0.0\n ? s / U_radius\n : (s >= sFloor\n ? thetaFloor + (s - sFloor) / rMin\n : (2.0 * s) / (U_radius + sqrt(U_radius * U_radius - 2.0 * k * s)));\n float r = max(U_radius - k * theta, rMin) - p.z;\n float newD = U_boundary + r * sin(theta);\n float newZ = U_radius - r * cos(theta);\n p.xy += dir * (newD - d);\n p.z = newZ;\n}\n`,\n uniforms: (o) => ({\n angle: o.angle * DEG,\n boundary: o.boundary,\n radius: o.radius,\n thickness: o.thickness,\n }),\n },\n}\n","import { z } from 'zod'\nimport type { Behavior } from './types'\n\nexport const flipOptionsSchema = z.object({\n /** 0 = flat, 1 = page fully turned over the spine. */\n progress: z.number().min(0).max(1).default(0.3),\n /** Which edge is the spine. */\n spine: z.enum(['left', 'right']).default('left'),\n /** Softness of the turning curl. */\n radius: z.number().min(0.1).max(0.8).default(0.3),\n})\n\nexport type FlipOptions = z.infer<typeof flipOptionsSchema>\n\n/**\n * A page turn: the free edge curls up and rolls over toward the spine —\n * the roll deformer with its boundary swept across the page.\n */\nexport const flip: Behavior<FlipOptions> = {\n id: 'flip',\n label: 'Flip',\n defaults: flipOptionsSchema.parse({}),\n optionsSchema: flipOptionsSchema,\n signature: ['progress', 'spine'],\n progressParam: 'progress',\n duration: 1.8,\n loopMode: 'yoyo',\n stack(o, sheet) {\n // Rolling direction points at the free edge; the boundary starts past\n // the free edge (flat) and sweeps to the spine (fully turned).\n const angle = o.spine === 'left' ? 0 : 180\n const start = sheet.width / 2\n const end = -sheet.width / 2\n return [\n {\n type: 'roll',\n options: {\n angle,\n boundary: start + o.progress * (end - start),\n radius: o.radius,\n thickness: 0,\n },\n },\n ]\n },\n handles: [\n {\n id: 'free-edge',\n anchor: (o) => (o.spine === 'left' ? [0.98, 0.5] : [0.02, 0.5]),\n drag(local, o, sheet) {\n // Dragging the free edge toward the spine turns the page.\n const x = o.spine === 'left' ? local.x : -local.x\n return { progress: Math.min(1, Math.max(0, 0.5 - x / sheet.width)) }\n },\n },\n ],\n}\n","import { z } from 'zod'\nimport type { Behavior } from './types'\n\nexport const letterFoldOptionsSchema = z.object({\n /** 0 = flat letter, 1 = fully tri-folded. */\n progress: z.number().min(0).max(1).default(0.4),\n /** Softness of the two creases. */\n crease: z.number().min(0).max(1).default(0.3),\n})\n\nexport type LetterFoldOptions = z.infer<typeof letterFoldOptionsSchema>\n\n/**\n * The classic tri-fold: the bottom third folds up first, then the top third\n * folds down over it. Two fold deformers stacked — order is the physics.\n */\nexport const letterFold: Behavior<LetterFoldOptions> = {\n id: 'letter-fold',\n label: 'Letter fold',\n defaults: letterFoldOptionsSchema.parse({}),\n optionsSchema: letterFoldOptionsSchema,\n signature: ['progress', 'crease'],\n progressParam: 'progress',\n duration: 2.6,\n loopMode: 'yoyo',\n stack(o, sheet) {\n const radius = 0.02 + o.crease * 0.06\n // The bottom flap leads, the top flap follows slightly behind so the\n // motion reads as two deliberate folds, not one collapse.\n const bottom = Math.min(1, o.progress * 1.25)\n const top = Math.max(0, o.progress * 1.25 - 0.25)\n return [\n {\n // Bottom third folds up and over (fold travels downward from -h/6).\n type: 'fold',\n options: {\n angle: 270,\n offset: sheet.height / 6,\n foldAngle: bottom * 165,\n radius,\n },\n },\n {\n // Top third folds down across the (already folded) bottom flap.\n type: 'fold',\n options: {\n angle: 90,\n offset: sheet.height / 6,\n foldAngle: top * 150,\n radius: radius * 1.6,\n },\n },\n ]\n },\n handles: [\n {\n id: 'top-flap',\n anchor: () => [0.5, 1],\n drag(local, _o, sheet) {\n // Pulling the top edge down folds the letter.\n return { progress: Math.min(1, Math.max(0, (sheet.height / 2 - local.y) / sheet.height)) }\n },\n },\n ],\n}\n","import { z } from 'zod'\nimport type { Behavior } from './types'\n\nexport const hangOptionsSchema = z.object({\n /** Wind strength driving the ripple. */\n wind: z.number().min(0).max(1).default(0.4),\n /** Gravity bulge of the hanging sheet. */\n sag: z.number().min(0).max(1).default(0.3),\n})\n\nexport type HangOptions = z.infer<typeof hangOptionsSchema>\n\n/** A poster hanging from its top edge, rippling in wind. */\nexport const hang: Behavior<HangOptions> = {\n id: 'hang',\n label: 'Hang',\n defaults: hangOptionsSchema.parse({}),\n optionsSchema: hangOptionsSchema,\n signature: ['wind', 'sag'],\n progressParam: 'wind',\n duration: 4,\n loopMode: 'yoyo',\n stack(o) {\n return [\n { type: 'bend', options: { curvature: 0.15 + o.sag * 0.55, angle: 90 } },\n {\n type: 'wave',\n options: {\n amplitude: o.wind * 0.055,\n wavelength: 0.45,\n speed: 0.9 + o.wind * 0.8,\n angle: 75,\n pinnedEdge: 'top',\n },\n },\n ]\n },\n}\n","import { z } from 'zod'\nimport type { Behavior } from './types'\n\nexport const flyOptionsSchema = z.object({\n /** Ripple energy. */\n flutter: z.number().min(0).max(1).default(0.5),\n /** Aerodynamic arc of the sheet. */\n curve: z.number().min(0).max(1).default(0.4),\n})\n\nexport type FlyOptions = z.infer<typeof flyOptionsSchema>\n\n/** A note carried on air — arched and fluttering. Pair with the `tumble` idle. */\nexport const fly: Behavior<FlyOptions> = {\n id: 'fly',\n label: 'Fly',\n defaults: flyOptionsSchema.parse({}),\n optionsSchema: flyOptionsSchema,\n signature: ['flutter', 'curve'],\n progressParam: 'flutter',\n duration: 3.5,\n loopMode: 'yoyo',\n stack(o) {\n return [\n { type: 'bend', options: { curvature: 0.25 + o.curve, angle: 0 } },\n {\n type: 'wave',\n options: {\n amplitude: o.flutter * 0.07,\n wavelength: 0.7,\n speed: 1.6,\n angle: 30,\n pinnedEdge: 'none',\n },\n },\n ]\n },\n}\n","import { z } from 'zod'\nimport type { Behavior } from './types'\n\nexport const fallOptionsSchema = z.object({\n /** Air resistance ripple while falling. */\n flutter: z.number().min(0).max(1).default(0.6),\n /** A falling sheet always lifts a corner. */\n curl: z.number().min(0).max(1).default(0.3),\n})\n\nexport type FallOptions = z.infer<typeof fallOptionsSchema>\n\n/** A dropped sheet — corner lifted, rippling. Pair with the `tumble` idle for the descent. */\nexport const fall: Behavior<FallOptions> = {\n id: 'fall',\n label: 'Fall',\n defaults: fallOptionsSchema.parse({}),\n optionsSchema: fallOptionsSchema,\n signature: ['flutter', 'curl'],\n progressParam: 'flutter',\n duration: 3,\n loopMode: 'yoyo',\n stack(o) {\n return [\n {\n type: 'curl',\n options: { corner: 'top-right', amount: o.curl * 0.4, radius: 0.3, skew: 0 },\n },\n {\n type: 'wave',\n options: {\n amplitude: o.flutter * 0.055,\n wavelength: 0.85,\n speed: 1.3,\n angle: 60,\n pinnedEdge: 'none',\n },\n },\n ]\n },\n}\n","import { z } from 'zod'\nimport type { Behavior } from './types'\nimport { cornerNames } from '../deformers/curl'\n\nexport const carryOptionsSchema = z.object({\n /**\n * The grab point — where the pointer was on the paper at pick time.\n * 'auto' is resolved by the carry controller (usually the peeled corner:\n * continuity from peel → carry is the immersion moment).\n */\n grab: z.enum([...cornerNames, 'auto']).default('auto'),\n /** From stock feel: a stamp is stiff — it flutters, it doesn't flow. */\n stiffness: z.number().min(0).max(1).default(0.7),\n flutter: z.number().min(0).max(1).default(0.5),\n /** How far the paper's yaw trails the drag direction (runtime transform). */\n lag: z.number().min(0).max(1).default(0.35),\n /** Drag-speed drive (0..1). Written live by the carry controller. */\n drive: z.number().min(0).max(1).default(0.25),\n})\n\nexport type CarryOptions = z.infer<typeof carryOptionsSchema>\n\ntype Corner = (typeof cornerNames)[number]\n\nconst concreteGrab = (g: CarryOptions['grab']): Corner => (g === 'auto' ? 'top-left' : g)\n\n/** Bend-axis angle pointing from the grab corner toward the sheet center. */\nconst DROOP_ANGLE: Record<Corner, number> = {\n 'top-left': -45,\n 'top-right': -135,\n 'bottom-left': 45,\n 'bottom-right': 135,\n}\n\n/** The edge the grab corner hangs from — that edge doesn't flutter. */\nconst PIN_EDGE: Record<Corner, 'top' | 'bottom'> = {\n 'top-left': 'top',\n 'top-right': 'top',\n 'bottom-left': 'bottom',\n 'bottom-right': 'bottom',\n}\n\n/**\n * A held paper, alive from motion (the field/cheap path):\n * droop away from the grab point + drag-velocity flutter. The hero path —\n * cloth with a single pin following the cursor — is the existing\n * `physics: 'cloth'` grab; this behavior is what fields and exports run.\n */\nexport const carry: Behavior<CarryOptions> = {\n id: 'carry',\n label: 'Carry',\n defaults: carryOptionsSchema.parse({}),\n optionsSchema: carryOptionsSchema,\n signature: ['stiffness', 'flutter'],\n progressParam: 'drive',\n duration: 2.4,\n loopMode: 'yoyo',\n stack(o) {\n const grab = concreteGrab(o.grab)\n // Softer paper droops harder from the pinch; motion adds a touch more.\n const droop = (1 - o.stiffness) * 1.6 + o.drive * 0.35\n return [\n {\n type: 'bend',\n options: { curvature: -droop, angle: DROOP_ANGLE[grab] },\n },\n {\n type: 'wave',\n options: {\n amplitude: o.flutter * (0.012 + o.drive * 0.085),\n wavelength: 0.55,\n speed: 1.4 + o.drive * 1.8,\n angle: DROOP_ANGLE[grab],\n pinnedEdge: PIN_EDGE[grab],\n },\n },\n ]\n },\n}\n","import { z } from 'zod'\nimport type { Behavior } from './types'\nimport { flightPose } from '../physics/aero'\n\nexport const flightOptionsSchema = z.object({\n /** Directional wind vector — paper travels ACROSS the scene, not just down. */\n wind: z\n .tuple([z.number().min(-2).max(2), z.number().min(-2).max(2), z.number().min(-2).max(2)])\n .default([0.6, 0.08, 0]),\n gustiness: z.number().min(0).max(1).default(0.4),\n tumble: z.number().min(0).max(1).default(0.6),\n /** 'loop' is a seamless idle cycle; 'drift' travels along the wind. */\n path: z.enum(['drift', 'loop']).default('drift'),\n /** Drift only: exit the scene → re-enter the opposite side. */\n respawn: z.boolean().default(true),\n /** Half-extent of the travel before respawn wraps it. */\n range: z.number().min(0.5).max(12).default(3.5),\n})\n\nexport type FlightOptions = z.infer<typeof flightOptionsSchema>\n\n/**\n * Untethered paper carried across the scene on the wind —\n * the falling-leaf tumble core + directional travel + lift. Transform +\n * deformer based, so it's instancing-safe: a `scatter` layout + `flight`\n * idle = papers blowing through a hero section.\n */\nexport const flight: Behavior<FlightOptions> = {\n id: 'flight',\n label: 'Flight',\n defaults: flightOptionsSchema.parse({}),\n optionsSchema: flightOptionsSchema,\n signature: ['gustiness', 'tumble', 'path'],\n progressParam: 'tumble',\n duration: 6,\n loopMode: 'yoyo',\n stack(o) {\n // The sheet itself arcs and ripples; travel/tumble live in `transform`.\n return [\n { type: 'bend', options: { curvature: 0.35 + o.tumble * 0.4, angle: 20 } },\n {\n type: 'wave',\n options: {\n amplitude: 0.02 + o.gustiness * 0.03,\n wavelength: 0.8,\n speed: 1.1 + o.gustiness,\n angle: 35,\n pinnedEdge: 'none',\n },\n },\n ]\n },\n transform(o, t, pose) {\n flightPose(t, o, 0, pose)\n },\n}\n","/**\n * The shared fake-aerodynamics core: velocity-linked lift +\n * curated noise, per v0.2's \"reads more real than a true sim\" doctrine.\n * Pure math, no three.js, no allocation in the per-frame paths — `carry`\n * and `flight` both source their motion here.\n */\n\nexport interface AeroPose {\n position: [number, number, number]\n rotation: [number, number, number]\n}\n\n/**\n * Critically-damped spring toward a target — the carry pin's cursor\n * follow. Mutates `state` in place; returns nothing.\n */\nexport interface DampedValue {\n value: number\n velocity: number\n}\n\nexport function dampTo(state: DampedValue, target: number, smoothing: number, dt: number): void {\n // Critically damped: ω from smoothing (≈ time to close 90% of the gap).\n const omega = 2 / Math.max(smoothing, 1e-4)\n const x = omega * dt\n const exp = 1 / (1 + x + 0.48 * x * x + 0.235 * x * x * x)\n const change = state.value - target\n const temp = (state.velocity + omega * change) * dt\n state.velocity = (state.velocity - omega * temp) * exp\n state.value = target + (change + temp) * exp\n}\n\n/** Coherent gust factor in [1-g, 1+g] — curated, seeded, cheap. */\nexport function gust(t: number, seed: number, gustiness: number): number {\n const n =\n Math.sin(t * 1.7 + seed * 12.9898) * 0.6 +\n Math.sin(t * 0.53 + seed * 78.233) * 0.3 +\n Math.sin(t * 3.1 + seed * 3.7) * 0.1\n return 1 + n * gustiness\n}\n\nexport interface FlightParams {\n wind: [number, number, number]\n gustiness: number\n tumble: number\n path: 'drift' | 'loop'\n /** Exit the scene → re-enter the opposite side (drift only). */\n respawn: boolean\n /** Half-extent of the drift travel before respawn wraps it. */\n range: number\n}\n\n/**\n * Free paper on the wind: the falling-leaf tumble core + a directional wind\n * vector + lift, so paper travels ACROSS, not just down. A pure function of\n * time and phase — instancing-safe, deterministic, loopable.\n */\nexport function flightPose(t: number, o: FlightParams, phase: number, pose: AeroPose): void {\n const g = gust(t + phase * 7.3, phase, o.gustiness)\n const time = t + phase * 11.7\n\n if (o.path === 'loop') {\n // A seamless closed circuit: travel scaled by the wind vector.\n const s = Math.max(0.2, Math.hypot(o.wind[0], o.wind[1], o.wind[2]))\n const a = time * 0.35\n pose.position[0] = Math.sin(a) * o.range * 0.8 * Math.sign(o.wind[0] || 1)\n pose.position[1] = Math.sin(a * 2) * o.range * 0.18 * s\n pose.position[2] = Math.cos(a) * o.range * 0.35\n } else {\n // Drift: travel along the wind; respawn wraps the along-wind coordinate.\n const travel = time * 0.55 * g\n const wrap = (v: number, r: number) => (o.respawn ? ((((v + r) % (2 * r)) + 2 * r) % (2 * r)) - r : v)\n pose.position[0] = wrap(o.wind[0] * travel, o.range)\n pose.position[1] = wrap(o.wind[1] * travel, o.range * 0.6) + Math.sin(time * 1.3) * 0.08 * g\n pose.position[2] = wrap(o.wind[2] * travel, o.range)\n }\n\n // The falling-leaf tumble: see-saw pitch/roll with a lift bob, gust-scaled.\n pose.rotation[0] = Math.sin(time * 0.5 + 1) * 0.65 * o.tumble\n pose.rotation[1] = Math.sin(time * 0.23) * 0.4 * o.tumble\n pose.rotation[2] = Math.sin(time * 0.7) * 0.55 * o.tumble\n pose.position[1] += Math.sin(time * 1.4) * 0.06 * o.tumble * g\n}\n\n/**\n * Carry flutter drive: how much a held paper ripples for a given drag speed\n * (world units/s). Saturates — a violent drag doesn't tear the illusion.\n */\nexport function carryDrive(speed: number): number {\n return Math.min(1, speed * 0.55)\n}\n","import { z } from 'zod'\nimport type { Behavior } from './types'\n\nexport const crumpleBehaviorOptionsSchema = z.object({\n /** 0 = flat sheet, 1 = crushed. */\n progress: z.number().min(0).max(1).default(0.55),\n /** Few big facets at 0, many small ones at 1. */\n coarseness: z.number().min(0).max(1).default(0.35),\n /** How far the sheet curls in on itself as it crushes. */\n ball: z.number().min(0).max(1).default(0.5),\n /** A different crush of the same paper. */\n seed: z.number().int().min(0).max(7).default(0),\n})\n\nexport type CrumpleBehaviorOptions = z.infer<typeof crumpleBehaviorOptionsSchema>\n\n/**\n * A sheet being screwed up in a fist.\n *\n * Two deformers, in this order for a reason: `crumple` reads the flat sheet\n * position to place its creases, so it has to run before anything that moves\n * the sheet around. Crush the paper, then curl the crushed paper — the other\n * way round would crease a curved sheet as if it were still flat.\n */\nexport const crumpleBehavior: Behavior<CrumpleBehaviorOptions> = {\n id: 'crumple',\n label: 'Crumple',\n defaults: crumpleBehaviorOptionsSchema.parse({}),\n optionsSchema: crumpleBehaviorOptionsSchema,\n signature: ['progress', 'ball', 'coarseness'],\n progressParam: 'progress',\n duration: 2.6,\n loopMode: 'yoyo',\n stack(o) {\n return [\n {\n type: 'crumple',\n options: {\n amount: o.progress,\n scale: 1.5 + o.coarseness * 4.5,\n pull: 0.5,\n seed: o.seed,\n },\n },\n // The sheet closing in on itself. Paper does not crush flat, and\n // without this the result reads as texture rather than as a ball.\n {\n type: 'bend',\n options: { curvature: o.progress * o.ball * 0.9, angle: 35 },\n },\n ]\n },\n}\n","import { z } from 'zod'\nimport type { Behavior } from './types'\n\nexport const settleOptionsSchema = z.object({\n /**\n * How long ago it landed, 0..1.\n *\n * 0 is the instant of arrival — still carrying the shape it fell in. 1 is\n * a sheet that has been lying there, where its own weight has flattened\n * out everything except what its stiffness refuses to give up.\n */\n relax: z.number().min(0).max(1).default(0.45),\n /**\n * How hard the paper resists lying flat, 0..1.\n *\n * This is the stock, not the pose: tissue surrenders completely, card\n * never does. It is the whole reason a settled sheet reads as PAPER and\n * not as a decal — at 0 the mesh is a rectangle painted on the floor.\n */\n lift: z.number().min(0).max(1).default(0.45),\n /** Which corner stayed up. */\n corner: z.enum(['top-left', 'top-right', 'bottom-left', 'bottom-right']).default('top-right'),\n /**\n * Slack across the middle — the low, long undulation of a sheet that is\n * touching a floor in two places and bridging between them.\n */\n slack: z.number().min(0).max(1).default(0.4),\n})\n\nexport type SettleOptions = z.infer<typeof settleOptionsSchema>\n\n/**\n * A sheet that has landed and relaxed.\n *\n * The library could drop paper (`fall`), fly it (`fly`, `flight`), heap it\n * (`pile`) and catch it mid-air (`spill`) — and had no way at all to show a\n * sheet that has ARRIVED. Every reference installation worth copying has\n * paper on the floor: sheets settled on concrete after the fall, ribbons\n * pooling where they meet the ground. It is the most beautiful detail in the\n * set and it appears in it twice.\n *\n * The distinction from `fall` is not the shape, it is the CLOCK. `fall`\n * flutters — its wave carries `speed: 1.3`, and it is a sheet still arguing\n * with the air. This one is over. Everything here is static, and that is the\n * point: a settled sheet that ripples is a settled sheet nobody believes.\n *\n * Which is also why it composes rather than deforming: a landed sheet is a\n * gentle curl the stiffness held on to, plus a long slack undulation where\n * it bridges the floor. Both already exist, and a deformer that can be\n * spelled out of the ones we have does not earn a GLSL twin and a parity\n * case.\n */\nexport const settle: Behavior<SettleOptions> = {\n id: 'settle',\n label: 'Settle',\n defaults: settleOptionsSchema.parse({}),\n optionsSchema: settleOptionsSchema,\n signature: ['relax', 'lift'],\n progressParam: 'relax',\n duration: 2.4,\n loopMode: 'yoyo',\n stack(o) {\n // Relaxing flattens the sheet, so `relax` SUBTRACTS. Stiffness is the\n // floor under it: however long it lies there, `lift` is what it will\n // never give back.\n const held = o.lift * (1 - o.relax * 0.55)\n return [\n {\n type: 'curl',\n options: {\n corner: o.corner,\n // A settled corner turns up gently and over a long distance. A\n // tight curl reads as a sheet being rolled, which is a hand doing\n // something to it rather than gravity having finished with it.\n // Calibrated against `fall`, which lifts a corner by `curl * 0.4`\n // — a settled sheet should keep MORE than a falling one, not less,\n // because the corner it is holding up is the one thing gravity\n // could not take from it. The first pass at 0.32 with a 0.5 radius\n // rendered a flat rectangle, which is the one outcome this\n // behavior exists to avoid.\n amount: held * 0.75,\n radius: 0.2 + (1 - held) * 0.14,\n // Off the diagonal, because a corner that lifts along its exact\n // diagonal reads as folded rather than as fallen.\n skew: 11,\n },\n },\n {\n type: 'wave',\n options: {\n amplitude: o.slack * (1 - o.relax * 0.4) * 0.085,\n // Long: one slow rise across the sheet, not a ripple. A settled\n // sheet touches the floor in a couple of places and bridges\n // between them, and that bridge is a single arc.\n wavelength: 1.6,\n // Static. This is the whole behavior.\n speed: 0,\n angle: 22,\n pinnedEdge: 'none',\n },\n },\n ]\n },\n}\n","import { z } from 'zod'\nimport type { Behavior } from './types'\n\nexport const ribbonOptionsSchema = z.object({\n /**\n * How much of the drop is lying on the floor, as a fraction of the height.\n *\n * This is the whole image. A strip that stops dead at the ground reads as\n * a strip that was cut to fit; one that arrives with a length to spare and\n * turns over reads as paper meeting a floor, which is the thing the\n * reference installations are actually about.\n */\n pool: z.number().min(0).max(0.5).default(0.16),\n /** How tightly it turns where it lands. Low is a soft slump, high is a curl. */\n curl: z.number().min(0).max(1).default(0.45),\n /** Folds running down the length. A printed strip is never a flat plane. */\n drape: z.number().min(0).max(1).default(0.5),\n})\n\nexport type RibbonOptions = z.infer<typeof ribbonOptionsSchema>\n\n/**\n * A strip hung from the ceiling that reaches the floor and keeps going.\n *\n * The single most striking image in the reference set, and the reason it\n * took until now to build is that it needs three separate things that did\n * not exist a week ago: a room with a ceiling to hang from, hardware to hang\n * BY, and type that can be set down the length of a sheet without looking\n * like a caption. It is the payoff for all of them.\n *\n * The mathematics is not new, which is the point of the contribution ladder.\n * A ribbon is a `drape` down its length and a `fold` whose hinge sits at the\n * floor line rather than at the sheet's centre — `fold.offset` has always\n * been able to say \"crease here\", and nothing had ever asked it to.\n */\nexport const ribbon: Behavior<RibbonOptions> = {\n id: 'ribbon',\n label: 'Ribbon',\n defaults: ribbonOptionsSchema.parse({}),\n optionsSchema: ribbonOptionsSchema,\n /**\n * `curl`, not `pool` — and the reason is tessellation rather than taste.\n *\n * The grid is sized by sampling this parameter from 0 to 1, so it has to\n * BE a 0..1 parameter (a `pool` that stops at 0.5 would be sampled across\n * a range it rejects), and it should be the one that drives the geometry\n * hardest. `curl` opens the crease from a right angle to a fold back on\n * itself, and the sharpest turn is exactly the case that demands the most\n * segments across the hinge.\n */\n signature: ['pool', 'curl', 'drape'],\n progressParam: 'curl',\n duration: 3,\n loopMode: 'yoyo',\n stack(o, sheet) {\n // Where the floor is, in the sheet's own coordinates — a `pool` fraction\n // above the bottom edge, so the length below that line is what turns\n // over. This is why the behavior needs the sheet at all, where most take\n // only their options.\n //\n // The hinge travels DOWNWARD (-90°), and that is not cosmetic: it is\n // what makes \"past the crease\" mean \"below the floor line\" rather than\n // \"above it\". Pointed the other way, the fold would have turned the\n // whole drop from the ceiling down.\n const floorLine = -sheet.height / 2 + sheet.height * o.pool\n\n // How soft the crease is. `curl` drives this rather than the fold angle\n // — see the fold below for why.\n const radius = Math.min(0.5, Math.max(0.02, sheet.height * (0.035 - o.curl * 0.027)))\n\n /**\n * The hinge does not turn on the spot: it wraps a cylinder of radius\n * `radius / φ`, and the flap leaves that cylinder lower than the crease\n * line by exactly that much.\n *\n * Which means placing the crease AT the floor buries the pool under it.\n * That is what was happening — the pooled length came out about 9cm\n * below the ground on the ribbon stage's own numbers, so the one thing\n * the stage exists to show was inside the floor. The crease goes up by\n * the hinge's own radius so that the POOL lands on the line, which is\n * the thing that has to be true; where the crease sits is arithmetic.\n */\n const hingeDrop = radius / (Math.PI / 2)\n\n return [\n {\n // `drape` — the deformer named after the thing this is.\n //\n // It briefly used `wave` instead, to work around a report that\n // `drape` rendered an invisible sheet on the hero path. That report\n // was wrong: it rested on counting the colours in a screenshot, and\n // a near-flat strip filling the frame has about as many colours as\n // an empty one. `deformers/draws.test.ts` now asserts on geometry\n // what the screenshot was being asked to guess at.\n //\n // `wave` was never the same picture. A wave is a sine of fixed\n // amplitude end to end, so its folds ran just as deep at the clip as\n // at the floor; a hung strip is FLAT where it is held and gathers as\n // it falls, which is exactly `falloff`, and it narrows as it gathers,\n // which is `gather`. Neither has an equivalent in `wave`.\n type: 'drape',\n options: {\n // Depth at the free end. Larger than the wave's amplitude was,\n // because this one starts at nothing under the clip rather than\n // running at full depth the whole way down.\n amplitude: o.drape * 0.1,\n // Few and long. A printed strip carries two or three slow folds\n // down its drop; more than that is a curtain, not a ribbon.\n folds: 2.5,\n // Holds the top flat and gathers the movement toward the floor,\n // which is what a strip hung from a single clip does.\n falloff: 1.5,\n // Off a pure sine, so the folds do not read as corrugation.\n irregular: 0.5,\n // Gentle. The pooled length has to lie FLAT on the floor, and a\n // hard pinch would narrow it as it went.\n gather: 0.22,\n pinnedEdge: 'top',\n },\n },\n {\n // `fold`, not `roll` — and this is the second correction the render\n // forced. A roll wraps the pooled length around a cylinder, so it\n // curls up and over and ends in the air: a hook, not a pool. Paper\n // meeting a floor does not wrap, it CREASES and then lies down.\n //\n // A hinge at the floor line with a soft radius is exactly that: the\n // drop above stays vertical, and everything below turns through\n // roughly a right angle and runs out flat along the ground.\n type: 'fold',\n options: {\n // Travel measured down the drop, so the crease line sits across\n // the ribbon and the flap below it is what turns.\n angle: -90,\n offset: -floorLine - hingeDrop,\n // Exactly a right angle, at every setting, and this is the fix\n // for the thing the ribbon stage was actually failing at.\n //\n // A hinge is one angle: whatever it turns through, the pooled\n // length leaves the crease in a straight line and holds that\n // heading. Only 90° is the floor. It shipped as `62 + curl * 46`\n // (62°..108°), so below curl 0.61 the pool went on travelling\n // downward and vanished THROUGH the floor — which is why the one\n // stage built around this behavior rendered as flat strips\n // stopping at the ground — and above it the pool tilted back UP\n // and floated. Both halves of the range were wrong, in opposite\n // directions, and only the midpoint was ever right.\n //\n // Paper with more length than floor does not rise at a constant\n // angle; it buckles and lies in an S, which one hinge cannot\n // describe and should not pretend to.\n foldAngle: 90,\n // So `curl` drives the CREASE instead, which is what its own\n // description always claimed — \"how tightly it turns where it\n // lands. Low is a soft slump, high is a curl.\" A soft radius is a\n // sheet slumping over the join; a tight one is a sheet that has\n // been creased. It scales with the sheet, because a radius that\n // reads as a fold on a short strip reads as a knife-edge on a long\n // one.\n radius,\n },\n },\n ]\n },\n}\n","import { paperConfigSchema, type PaperConfig, type PaperConfigInput } from './schema'\n\nexport { mergeConfig, mergeWithDeletes } from './merge'\n\n/** Parse anything preset-shaped (object or JSON string) into a full, defaulted config. */\nexport function parsePreset(input: PaperConfigInput | string): PaperConfig {\n const raw = typeof input === 'string' ? JSON.parse(input) : input\n return paperConfigSchema.parse(raw)\n}\n\n/** Serialize a config to `.paper` JSON. */\nexport function serializePreset(config: PaperConfig): string {\n return JSON.stringify(config, null, 2)\n}\n","import type * as THREE from 'three'\n\n/**\n * Recompute vertex normals for a sheet, straight over the typed arrays.\n *\n * Identical arithmetic to `BufferGeometry.computeVertexNormals()` — same\n * `cross(C − B, A − B)` per face, same accumulate-then-normalize — and it\n * agrees with it bit for bit (`core/normals.test.ts` asserts exact equality,\n * not a tolerance). What it does not do is go through `Vector3` and the\n * `BufferAttribute` accessors, which is three's cost and not the maths'.\n *\n * Worth having its own file because of where it sits: this runs once per\n * animated sheet per frame in hero mode, over a grid that `segments: 'auto'`\n * is allowed to take to 128 (16.6k vertices, 32.8k faces). Measured on a\n * `drape + wave` sheet at that ceiling it is 1.37 ms through three and\n * 0.18 ms here — normals were three quarters of the cost of a `roll`'s\n * frame and are now a tenth of it.\n *\n * Falls back to three for anything that is not an indexed mesh carrying a\n * normal attribute, which is the only shape this fast path knows.\n */\nexport function computeSheetNormals(geometry: THREE.BufferGeometry): void {\n const index = geometry.index\n const normalAttr = geometry.attributes.normal as THREE.BufferAttribute | undefined\n const positionAttr = geometry.attributes.position as THREE.BufferAttribute | undefined\n if (!index || !normalAttr || !positionAttr) {\n geometry.computeVertexNormals()\n return\n }\n const pos = positionAttr.array as Float32Array\n const nrm = normalAttr.array as Float32Array\n const idx = index.array as Uint16Array | Uint32Array\n\n nrm.fill(0)\n for (let i = 0, l = idx.length; i < l; i += 3) {\n const a = idx[i]! * 3\n const b = idx[i + 1]! * 3\n const c = idx[i + 2]! * 3\n const bx = pos[b]!\n const by = pos[b + 1]!\n const bz = pos[b + 2]!\n const cbx = pos[c]! - bx\n const cby = pos[c + 1]! - by\n const cbz = pos[c + 2]! - bz\n const abx = pos[a]! - bx\n const aby = pos[a + 1]! - by\n const abz = pos[a + 2]! - bz\n // The face normal, unnormalized — its length is twice the triangle's\n // area, which is the area weighting three's version also relies on.\n const nx = cby * abz - cbz * aby\n const ny = cbz * abx - cbx * abz\n const nz = cbx * aby - cby * abx\n nrm[a] = nrm[a]! + nx\n nrm[a + 1] = nrm[a + 1]! + ny\n nrm[a + 2] = nrm[a + 2]! + nz\n nrm[b] = nrm[b]! + nx\n nrm[b + 1] = nrm[b + 1]! + ny\n nrm[b + 2] = nrm[b + 2]! + nz\n nrm[c] = nrm[c]! + nx\n nrm[c + 1] = nrm[c + 1]! + ny\n nrm[c + 2] = nrm[c + 2]! + nz\n }\n\n for (let i = 0, l = nrm.length; i < l; i += 3) {\n const x = nrm[i]!\n const y = nrm[i + 1]!\n const z = nrm[i + 2]!\n // Divide rather than multiply by a reciprocal: `Vector3.normalize()`\n // divides, and one rounding difference per component is the whole\n // distance between \"bit-identical to three\" and \"close enough\", which\n // is not a claim worth weakening to save two multiplies.\n //\n // A vertex whose faces cancelled out has no normal to give. three's\n // `normalize()` divides by `length() || 1` and leaves the zero; so does\n // this, rather than dividing by zero and poisoning the lighting.\n const len = Math.sqrt(x * x + y * y + z * z) || 1\n nrm[i] = x / len\n nrm[i + 1] = y / len\n nrm[i + 2] = z / len\n }\n normalAttr.needsUpdate = true\n}\n","import { useRef } from 'react'\n\n/**\n * Deep-equality memo deps, without serializing anything.\n *\n * Several hooks here need to recompute on the CONTENT of a prop rather than\n * on its identity, because the props in question — the paper slots, a\n * preset, a content list — are rebuilt as fresh objects on every render of\n * whatever is above. The library used to spell that as\n * `[JSON.stringify(papers)]`, which reads well and is a trap: a dependency\n * array is evaluated on **every render**, so the serialization is paid every\n * render whether or not anything changed, and it is paid in garbage rather\n * than in time.\n *\n * That is affordable for a layout's options and ruinous for a paper. An\n * image slot carries its bitmap inline as a data URL, so a field of fourteen\n * photographs serialized roughly seventeen megabytes per render — and the\n * controls that render the most are the continuous ones, which is why\n * dragging a speed slider was the way to take the tab out with an\n * out-of-memory crash.\n *\n * `useStable` compares instead of serializing. Nothing is allocated, and the\n * comparison short-circuits on `Object.is` at every level, so the common\n * case — a fresh wrapper around the same inner objects — costs a handful of\n * pointer checks no matter how large the data URL underneath is.\n */\nexport function useStable<T>(value: T): T {\n const held = useRef(value)\n if (!deepEqual(held.current, value)) held.current = value\n return held.current\n}\n\n/**\n * Structural equality over JSON-shaped data, matching what the\n * `JSON.stringify` comparison it replaces considered equal.\n *\n * That last part is the reason for the `undefined` handling below: stringify\n * drops a key whose value is `undefined`, so `{a: 1, b: undefined}` and\n * `{a: 1}` used to compare equal and must go on doing so — a config that\n * spells an absent option either way should not rebuild the field.\n */\nexport function deepEqual(a: unknown, b: unknown): boolean {\n if (Object.is(a, b)) return true\n if (typeof a !== 'object' || typeof b !== 'object' || a === null || b === null) return false\n\n if (Array.isArray(a) || Array.isArray(b)) {\n if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length) return false\n for (let i = 0; i < a.length; i++) if (!deepEqual(a[i], b[i])) return false\n return true\n }\n\n const left = a as Record<string, unknown>\n const right = b as Record<string, unknown>\n // Keys carrying `undefined` do not count, on either side — see above.\n const keys = new Set<string>()\n for (const key of Object.keys(left)) if (left[key] !== undefined) keys.add(key)\n for (const key of Object.keys(right)) if (right[key] !== undefined) keys.add(key)\n for (const key of keys) if (!deepEqual(left[key], right[key])) return false\n return true\n}\n","import * as THREE from 'three'\nimport type { SheetConfig } from '../config/schema'\nimport { FLAT_SEGMENTS, LEGACY_FLAT_SEGMENTS, quantizeSegments, type SegmentPair } from './tessellation'\n\n/**\n * Resolve the subdivision grid for a sheet.\n *\n * `minSegments` is the correctness floor the active deformers require, and it\n * applies however `segments` is set. `autoSegments` is what those deformers\n * WANT for the options they are carrying, and it is what `'auto'` resolves\n * to — see `stackAutoSegments` and `core/tessellation.ts`.\n *\n * Both are per axis, because a demand is a demand along a DIRECTION. A\n * banner draped in folds across its width needs those folds resolved across\n * and needs almost nothing down its drop; a single number spread by aspect\n * ratio gives the drop the density and the folds the leftovers, which is\n * both the expensive answer and the wrong-looking one. A bare number is\n * still accepted and still means \"this many, both ways\".\n *\n * `'auto'` used to hand the long side a flat 72 whatever was on the sheet, so\n * a blank page was tessellated exactly as finely as a crumpled one and every\n * `minSegments` in the library was dead weight — nothing could ever raise a\n * grid that already started at the highest value anyone asked for. It now\n * sizes to the work, quantized onto a ladder so that dragging a slider does\n * not rebuild the mesh.\n *\n * Omitting `autoSegments` keeps the old flat 72, which is what a caller with\n * no deformer stack in hand should get — this helper is exported, and its\n * answer to an unchanged call should not have changed.\n */\nexport function resolveSegments(\n sheet: SheetConfig,\n minSegments: number | SegmentPair = 2,\n autoSegments: number | SegmentPair = LEGACY_FLAT_SEGMENTS,\n): [number, number] {\n // A bare floor is a floor both ways — it says nothing about direction.\n const [minX, minY] = typeof minSegments === 'number' ? [minSegments, minSegments] : minSegments\n if (sheet.segments !== 'auto') {\n return [Math.max(sheet.segments, minX, 2), Math.max(sheet.segments, minY, 2)]\n }\n // A bare TARGET is the old contract: one density for the long edge, spread\n // over the short one by aspect, snapped to the ladder once. Callers with a\n // stack in hand pass a pair instead, and each axis is then snapped on its\n // own — which is the point of asking per axis at all.\n const [wantX, wantY] =\n typeof autoSegments === 'number'\n ? spreadByAspect(sheet, quantizeSegments(Math.max(autoSegments, FLAT_SEGMENTS)))\n : [\n quantizeSegments(Math.max(wantOrFlat(autoSegments[0]), FLAT_SEGMENTS)),\n quantizeSegments(Math.max(wantOrFlat(autoSegments[1]), FLAT_SEGMENTS)),\n ]\n return [Math.max(wantX, minX, 2), Math.max(wantY, minY, 2)]\n}\n\nconst wantOrFlat = (n: number) => (Number.isFinite(n) ? n : FLAT_SEGMENTS)\n\nfunction spreadByAspect(sheet: SheetConfig, target: number): [number, number] {\n const long = Math.max(sheet.width, sheet.height)\n if (!(long > 0)) return [target, target]\n return [Math.round((sheet.width / long) * target), Math.round((sheet.height / long) * target)]\n}\n\n/**\n * The point on a sheet's drawn surface at `(u, v)`, in the geometry's local\n * space, written into `out`.\n *\n * `positions` is a `PlaneGeometry`-ordered grid of `cols × rows` vertices —\n * the order every sheet in the library is built in, cloth particles and strip\n * nodes included. That order runs its rows TOP first, while `v` runs from the\n * BOTTOM: `v = 0` is the bottom edge, as it is in the mesh's own `uv`\n * attribute and in row 0 of a `DamageSource`. The flip is done here, once, so\n * that nothing reading damage at a UV and asking where that is has to know.\n *\n * Interpolated across the TRIANGLE three draws, not bilinearly across the\n * cell. On a flat grid the two agree; on a deformed one they do not, and the\n * triangle is what is on screen — an ember that leaves a point a millimetre\n * inside the paper is an ember that leaves from behind it.\n *\n * `u` and `v` are clamped to the sheet.\n */\nexport function surfacePointAt(\n positions: ArrayLike<number>,\n cols: number,\n rows: number,\n u: number,\n v: number,\n out: THREE.Vector3,\n): THREE.Vector3 {\n const fx = Math.min(1, Math.max(0, u)) * (cols - 1)\n const fy = (1 - Math.min(1, Math.max(0, v))) * (rows - 1)\n const ix = Math.min(Math.floor(fx), cols - 2)\n const iy = Math.min(Math.floor(fy), rows - 2)\n const tx = fx - ix\n const ty = fy - iy\n // PlaneGeometry's cell: a (ix, iy), b (ix, iy+1), c (ix+1, iy+1),\n // d (ix+1, iy), drawn as the triangles a-b-d and b-c-d — split along b-d.\n const a = (iy * cols + ix) * 3\n const b = a + cols * 3\n const c = b + 3\n const d = a + 3\n for (let axis = 0; axis < 3; axis++) {\n const pa = positions[a + axis]!\n const pb = positions[b + axis]!\n const pc = positions[c + axis]!\n const pd = positions[d + axis]!\n const value =\n tx + ty <= 1 ? pa + tx * (pd - pa) + ty * (pb - pa) : pc + (1 - tx) * (pb - pc) + (1 - ty) * (pd - pc)\n out.setComponent(axis, value)\n }\n return out\n}\n\n/**\n * Geometry factory. The sheet lives in its local XY plane, centered on the\n * origin, facing +Z. Deformers displace these vertices; the base (flat)\n * positions are kept by the caller for re-deformation each frame.\n */\nexport function createSheetGeometry(\n sheet: SheetConfig,\n minSegments: number | SegmentPair = 2,\n autoSegments: number | SegmentPair = LEGACY_FLAT_SEGMENTS,\n): THREE.PlaneGeometry {\n const [sx, sy] = resolveSegments(sheet, minSegments, autoSegments)\n return new THREE.PlaneGeometry(sheet.width, sheet.height, sx, sy)\n}\n","import type { StockName } from '../config/schema'\n\n/**\n * A stock is a named bundle of material + geometry defaults — choosing paper\n * at a print shop. Individual controls always override; schema-wise these are\n * just defaults.\n */\nexport interface Stock {\n id: StockName\n label: string\n /** Base tint, also used as the canvas background behind content. */\n color: string\n roughness: number\n /** 0 = opaque. Vellum is translucent. */\n opacity: number\n /**\n * How much light passes THROUGH the sheet when something is behind it,\n * 0..1. Distinct from `opacity`: newsprint is fully opaque to look at and\n * still glows on a lightbox. This is what makes a backlit banner read.\n */\n translucency: number\n /** Ink multiply tint for content drawn on this stock (thermal prints grey-black). */\n inkColor: string\n /** Thermal-printer banding intensity baked into the grain effect. */\n banding: number\n /** Surface effects this stock ships with; explicit surface config overrides per key. */\n defaultSurface: { grain?: number; aging?: number }\n /** Reversed front-content ghost on the backside (thin stocks let ink show). */\n showThrough: number\n /** Glossy near-white glue underside (stickers) — forces showThrough 0. */\n adhesive: boolean\n /**\n * How hard this paper holds a crease, 0..1 — the material half of\n * {@link MemoryConfig}. Fibrous, thick stocks take a set and keep it;\n * coated and translucent ones spring most of the way back.\n *\n * Not a fraction of anything on its own: `memory.ts` scales it by\n * `MAX_SET`, so 1 here means \"as much as paper ever remembers\", not \"stays\n * exactly as folded\".\n */\n takesSet: number\n}\n\nexport const stocks: Record<StockName, Stock> = {\n printer: {\n id: 'printer',\n label: 'Printer',\n color: '#fbfaf7',\n roughness: 0.88,\n opacity: 1,\n translucency: 0.2,\n inkColor: '#222222',\n banding: 0,\n defaultSurface: { grain: 0.12 },\n showThrough: 0,\n adhesive: false,\n // Office bond creases cleanly and holds it — the reference paper.\n takesSet: 0.6,\n },\n thermal: {\n id: 'thermal',\n label: 'Thermal',\n color: '#f6f3e9',\n roughness: 0.62,\n opacity: 1,\n translucency: 0.34,\n inkColor: '#3a3a3a',\n banding: 0.35,\n defaultSurface: { aging: 0.1 },\n showThrough: 0.06,\n adhesive: false,\n // Thin and already curled off a roll; a fold in it stays folded.\n takesSet: 0.65,\n },\n kraft: {\n id: 'kraft',\n label: 'Kraft',\n color: '#c9a06c',\n roughness: 0.96,\n opacity: 1,\n translucency: 0.08,\n inkColor: '#33261a',\n banding: 0,\n defaultSurface: { grain: 0.5 },\n showThrough: 0,\n adhesive: false,\n // Thick and fibrous. The crease is a break, and it never comes back.\n takesSet: 0.85,\n },\n newsprint: {\n id: 'newsprint',\n label: 'Newsprint',\n color: '#e9e4d6',\n roughness: 0.95,\n opacity: 1,\n translucency: 0.38,\n inkColor: '#3d3a34',\n banding: 0,\n defaultSurface: { grain: 0.7, aging: 0.15 },\n showThrough: 0.06,\n adhesive: false,\n // Soft, short-fibred, and barely sprung — it crumples rather than resists.\n takesSet: 0.8,\n },\n vellum: {\n id: 'vellum',\n label: 'Vellum',\n color: '#f4f2ec',\n roughness: 0.42,\n opacity: 0.62,\n translucency: 0.86,\n inkColor: '#4a453d',\n banding: 0,\n defaultSurface: {},\n showThrough: 0.55,\n adhesive: false,\n // Translucent and plasticky: it fights the fold and mostly wins.\n takesSet: 0.25,\n },\n 'photo-gloss': {\n id: 'photo-gloss',\n label: 'Photo gloss',\n color: '#ffffff',\n roughness: 0.22,\n opacity: 1,\n translucency: 0.03,\n inkColor: '#111111',\n banding: 0,\n defaultSurface: {},\n showThrough: 0,\n adhesive: false,\n // The coating resists, then cracks white — little angle kept, lots of mark.\n takesSet: 0.3,\n },\n // Photo-gloss-like face, glossy near-white glue underside. The default\n // carrier for perforated stamp sheets.\n sticker: {\n id: 'sticker',\n label: 'Sticker',\n color: '#ffffff',\n roughness: 0.3,\n opacity: 1,\n translucency: 0.06,\n inkColor: '#1a1a1a',\n banding: 0,\n defaultSurface: {},\n showThrough: 0,\n adhesive: true,\n // A face sheet on a release liner; the liner does most of the remembering.\n takesSet: 0.5,\n },\n}\n\nexport function getStock(name: StockName): Stock {\n return stocks[name]\n}\n","import { paperConfigSchema, type PaperConfig, type PaperConfigInput } from '../schema'\n\n/**\n * Built-in `.paper` presets. A preset is the serialized closure of one Paper —\n * the unit of saving, sharing, and code export. Stored as plain JSON-safe\n * objects, validated on access.\n */\nconst builtins: Record<string, PaperConfigInput> = {\n 'receipt-unroll': {\n meta: { name: 'Receipt unroll', tags: ['receipt', 'unroll', 'hero'] },\n sheet: { width: 1, height: 2.6 },\n stock: 'thermal',\n content: {\n type: 'receipt',\n store: 'nawwara.studio',\n address: '124 Paper St',\n items: [\n { name: 'Curl, true', price: 12 },\n { name: 'Roll, tight', price: 8.5 },\n { name: 'Sheet, one', price: 0.99 },\n ],\n timestamp: '11.07.2026 18:42',\n },\n behavior: { type: 'unroll', progress: 0.55, tightness: 0.55, sway: 0.3 },\n surface: { deckle: { edges: ['bottom'], roughness: 0.6 } },\n },\n /**\n * A roll on a holder with a leaf already out, meant to be driven by scroll:\n * bind `behavior.progress` to how far down the page you are and the paper\n * pays out while the roll runs down toward its tube.\n *\n * The three parts that make it read as a real roll rather than a curled\n * sheet: `fixed` keeps the roll on its holder and moves the paper instead,\n * `tail` means there is always a leaf to take hold of, and `floor` gives\n * the drop somewhere to land — paper that reaches the ground creases and\n * lies down rather than hanging into the void forever. A `core` a third of\n * the full radius is a real cardboard tube, so the roll still looks like a\n * roll after it has been used down.\n */\n 'paper-roll': {\n meta: { name: 'Paper roll', tags: ['roll', 'unroll', 'scroll', 'hero'] },\n sheet: { width: 1, height: 5 },\n stock: 'newsprint',\n content: { type: 'blank' },\n behavior: {\n type: 'unroll',\n progress: 0.25,\n tightness: 0.8,\n sway: 0.15,\n from: 'top',\n fixed: true,\n core: 0.12,\n tail: 0.5,\n floor: 2.4,\n },\n surface: { deckle: { edges: ['bottom'], roughness: 0.5 } },\n },\n /**\n * The one that is a SIMULATION rather than a shape.\n *\n * `paper-roll` above draws this same object with a deformer stack, and for\n * a roll paying out against a wall that is the cheaper and better answer.\n * This preset exists for the half that geometry cannot reach: what happens\n * once the paper hits the ground. A deformer can bend a sheet along a curve\n * you have already chosen; it cannot discover that a strip under\n * compression buckles at its weakest hinge, and it cannot let one fold land\n * on the one beneath it. Both of those are what a pile IS.\n *\n * Bind `physics.scroll` to the page and the roll turns:\n *\n * ```tsx\n * const [scroll, setScroll] = useState(0)\n * useEffect(() => {\n * const onScroll = () => setScroll(window.scrollY / 120)\n * window.addEventListener('scroll', onScroll, { passive: true })\n * return () => window.removeEventListener('scroll', onScroll)\n * }, [])\n * <Paper preset=\"toilet-roll\" physics={{ type: 'strip', scroll }} />\n * ```\n *\n * It is a MONOTONIC world-unit number, not a 0..1 progress — the sim\n * differentiates it, so scrolling back up rewinds the roll and drags the\n * pile taut before it lifts.\n *\n * The proportions are the real object's: a panel as wide as it is long, so\n * `perforation` equals the sheet width and the strip tears into squares.\n */\n 'toilet-roll': {\n meta: { name: 'Toilet roll', tags: ['roll', 'scroll', 'simulation', 'hero'] },\n // The proportions are a real roll's, at the scale the library is viewed\n // at: `<Paper>` and the editor both look at the origin through about two\n // world units and neither fits a camera to its content, so the whole\n // composition — roll, drop and pile — has to live inside that. A panel is\n // as wide as it is long and the roll is about a panel across, which is\n // what a toilet roll is.\n //\n // Twenty-three panels of paper. Not a real roll's several hundred, but\n // enough that a full page of scrolling does not empty it: one scroll unit\n // is about one unit of paper on a fresh roll, so this is a couple of\n // screens' worth before the tube shows.\n sheet: { width: 0.6, height: 14 },\n stock: 'printer',\n content: { type: 'blank' },\n physics: {\n type: 'strip',\n scroll: 0,\n // Wound tightly enough to hold this much paper at a believable size: the\n // outer radius lands at 0.61 of the panel width against a real roll's\n // 0.57, over about nine visible turns.\n //\n // `tightness` is doing double duty and the trade is worth knowing about.\n // A layer gap IS the paper's thickness, so it also sets how far apart\n // self-collision holds two folds — wind tighter for a neater roll and\n // the pile on the floor gets flatter, looser for a fatter pile and the\n // roll coarsens. This is the middle of that.\n //\n // It is ALSO the roll's rim, and that is the reason not to raise it on\n // looks alone. A layer gap is a real space between two wound turns, so\n // the roll's end face is concentric rings with nothing between them,\n // and off head-on you see between them — a fine sawtooth around the\n // rim that winding tighter genuinely reduces. It was tried. Tightening\n // to 0.78 also moves the roll's proportion to 0.553 of a panel width,\n // nearer a real roll's 0.57 than this is, so it looked like a free win\n // — and it throws the pile 1.33 units out in x against the 0.874 a\n // square parent can see, spreading 5.9 panel-widths. Framing beats the\n // rim. The sawtooth is what a roll wound from ONE zero-thickness\n // ribbon costs; it is not tuned away, and a caller who wants it gone\n // wants a thicker `stock` or fewer, fatter turns.\n tightness: 0.65,\n // A real cardboard tube, and a floor on how tight the spiral ever winds.\n // The innermost wrap is the coarsest thing in the roll — the same\n // arc-length step spans a bigger angle the smaller the radius — so the\n // core is what stops a nearly-empty roll turning back into a polygon.\n core: 0.12,\n // A panel and a half already hanging. A roll on a holder always has a\n // leaf out; starting from a bare cylinder reads as one still wrapped.\n tail: 0.9,\n perforation: 0.6,\n // The four numbers below were chosen TOGETHER, and by worst case rather\n // than by a good-looking run. A pile is chaotic: change `crease` by\n // 0.05 and one 14-second scroll can spread 2.0 panel-widths of floor or\n // 4.2, so a single trajectory is a sample and not a measurement. These\n // are scored over nine — three scroll depths crossed with three feed\n // rates — on how far the composition ever gets from the origin.\n //\n // What that fixed: the shipped set spread 2.9 panel-widths on average\n // and 4.0 at worst, and threw paper 1.60 units out in z. It ran off the\n // side of the frame and kept going. These hold 2.2 average, 2.8 worst,\n // and 1.09 out — while keeping the pile's height (about ten layers)\n // intact, which is the thing all of this exists to show.\n //\n // The most load-bearing of them. Below about 0.6 the landed paper flops\n // over in flat panels and runs away across the floor instead of folding\n // back; high is what makes the perforations hold and the pile\n // accordion. A used roll remembering its creases is the whole effect.\n crease: 0.9,\n // Low enough that a panel buckles rather than steering the pile: at 0.5\n // the sheet was stiff enough to push the folds already down along the\n // floor ahead of it, which is what \"spreads across four panels\" was.\n stiffness: 0.4,\n // High: paper is light and broad, and this is what separates it from a\n // rope hanging off a drum. It also damps the sideways travel that\n // carried the pile out of frame.\n drag: 0.85,\n gravity: 1,\n // The drop, measured from the roll's axis. Together with the roll's own\n // radius this IS the height of the composition, which is centred on the\n // origin — so keep their sum under about 1.7 or the roll and the pile\n // fall outside the ~1.75 units `<Paper>`'s fixed camera can see.\n //\n // Shortened from 1.2, and it is the single most effective number here:\n // a longer fall is more airtime for the strip to pick a direction and\n // glide, so it landed still travelling and slid. Worst-case spread goes\n // 4.2 panel-widths to 3.1 and the pile keeps its full depth. It buys\n // vertical room as well, which is what lets the roll sit further up.\n floor: 0.85,\n inertia: 0.5,\n },\n surface: { grain: 0.25 },\n // The preset is unreadable without this, and that is not a figure of\n // speech: the strip sim folds in DEPTH, and every camera in the library\n // is fixed and head-on, so `<Paper preset=\"toilet-roll\" />` framed the\n // roll end-on and the entire accordion edge-on and rendered a blank white\n // column. This is the three-quarter view the pile actually reads from —\n // enough to see along the folds and around the roll's rim, not so much\n // that the strip's face turns away.\n //\n // The ceiling is framing, not taste. Turning swaps the pile's DEPTH for\n // WIDTH, and depth is free — the camera has plenty — while width is not.\n // Measured over fifteen scroll trajectories the pile reaches 1.27 units\n // of depth at worst, and `halfWidth·cos θ + 1.27·sin θ` crosses the 0.874\n // half-view a square parent gets at 28°. Twenty-five leaves real margin\n // (0.809) and gives up almost nothing of the angle.\n //\n // Do not raise it without re-measuring that depth: the two numbers are\n // coupled, and the pile's depth is not stable under small changes to the\n // physics — see the note on `floor`.\n //\n // A parent narrower than square still crops the pile's far edge. That is\n // the honest limit of a fixed camera, and the caller's answer is their\n // own `rotation` prop, which this composes with rather than overrides.\n scene: { turn: 25 },\n },\n 'letter-fold': {\n meta: { name: 'Letter fold', tags: ['fold', 'text'] },\n sheet: { width: 1, height: 1.4 },\n stock: 'printer',\n content: {\n type: 'text',\n text: 'Dear you,\\n\\nSome things are worth folding carefully.\\n\\nYours,\\nN.',\n },\n behavior: { type: 'letter-fold', progress: 0.4, crease: 0.3 },\n // A letter that has been folded before. These were painted-on\n // `creaseLines` until the paper could carry real ones — two marks in the\n // shader at exactly the two places the tri-fold bends, which is a good\n // impression of a crease right up until you unfold the letter and it\n // comes back perfectly flat. As memory they bend the sheet as well as\n // marking it, and folding the letter deepens the creases it already has\n // rather than drawing a second pair on top of them.\n //\n // The lines are `letterFold`'s own: travel down and up, each a sixth of\n // the sheet from the middle. Shallower than a fold leaves (printer keeps\n // about 20°) because this letter has been folded once and put away, not\n // folded and reopened in front of you.\n memory: {\n creases: [\n { angle: 270, offset: 1.4 / 6, depth: 13 },\n { angle: 90, offset: 1.4 / 6, depth: 11 },\n ],\n },\n },\n /**\n * The wash, shown rather than described.\n *\n * A `wash` is a field on every content type, which means it is reachable\n * from any preset and discoverable from none — a toggle three folders down\n * is not an argument for the feature. This is the argument: type set over\n * paint, on cotton, deckled, with the paper still showing through both.\n */\n 'washed-letter': {\n meta: { name: 'Washed letter', tags: ['wash', 'text'] },\n // Printer stock, not vellum: vellum is translucent and takes the room's\n // grey through the back of the sheet, which turns a wash the colour of\n // dishwater. Pigment needs something white behind it.\n sheet: { width: 1.05, height: 1.45 },\n stock: 'printer',\n content: {\n type: 'text',\n text: 'Painted first,\\nwritten after.',\n font: 'Georgia, \"Times New Roman\", serif',\n size: 52,\n valign: 'center',\n align: 'center',\n wash: { color: '#5b6f9a', secondary: '#c08a86', blooms: 6, spread: 0.85, intensity: 0.5, seed: 3 },\n },\n behavior: { type: 'peel', progress: 0.12, corner: 'bottom-right', radius: 0.3 },\n surface: { grain: 0.35, deckle: { edges: ['bottom', 'right'], roughness: 0.45 } },\n },\n 'vintage-note': {\n meta: { name: 'Vintage note', tags: ['aging', 'text'] },\n sheet: { width: 1.1, height: 1.4 },\n stock: 'newsprint',\n content: {\n type: 'text',\n text: 'FOUND, ONE PAPER ENGINE.\\n\\nReward if returned to the web.',\n font: 'Georgia, serif',\n size: 40,\n },\n behavior: { type: 'peel', progress: 0.18, corner: 'top-right', radius: 0.22 },\n surface: { aging: 0.55, grain: 0.6, deckle: { edges: ['top', 'bottom'], roughness: 0.4 } },\n },\n 'hero-peel': {\n meta: { name: 'Hero peel', tags: ['peel', 'card', 'hero'] },\n sheet: { width: 1.5, height: 1 },\n stock: 'photo-gloss',\n // Was a live Unsplash URL — a third-party network fetch inside one of\n // the first things anybody renders, which fails offline, behind a proxy,\n // under a strict CSP, and on the day the URL changes. The demo here is\n // the PEEL; the photograph was incidental, and a typeset card is both\n // self-contained and more on-brand for a paper library.\n content: {\n type: 'card',\n title: 'Print no. 4',\n body: 'Lift the corner.',\n note: 'Gloss, 240gsm',\n align: 'center',\n },\n behavior: { type: 'peel', progress: 0.35, corner: 'bottom-right', radius: 0.16 },\n },\n 'page-flip': {\n meta: { name: 'Page flip', tags: ['flip', 'text'] },\n sheet: { width: 1, height: 1.4 },\n stock: 'printer',\n content: {\n type: 'text',\n text: 'Chapter One\\n\\nIt was a paper town, and everything in it folded.',\n },\n behavior: { type: 'flip', progress: 0.3, spine: 'left', radius: 0.3 },\n },\n 'hanging-poster': {\n meta: { name: 'Hanging poster', tags: ['hang', 'text', 'wind'] },\n sheet: { width: 1.1, height: 1.55 },\n stock: 'printer',\n // Also de-Unsplashed. A poster is a typographic object anyway — every\n // paper installation worth the name hangs WORDS — so this shows off the\n // tracking and the optical centring rather than someone else's photo.\n content: {\n type: 'text',\n text: 'THE\\nPAPER\\nSHOW',\n size: 96,\n align: 'center',\n valign: 'center',\n tracking: 0.08,\n lineHeight: 1.15,\n },\n behavior: { type: 'hang', wind: 0.45, sag: 0.3 },\n },\n 'pinned-sheet': {\n meta: { name: 'Pinned sheet', tags: ['cloth', 'wind', 'interactive'] },\n sheet: { width: 1.2, height: 1.5 },\n stock: 'printer',\n content: {\n type: 'text',\n text: 'Grab me.\\n\\n(cloth: pinned at the top edge,\\nwind from the left)',\n size: 40,\n },\n physics: { type: 'cloth', pins: 'top-edge', wind: 0.45, stiffness: 0.8, gravity: 1, floor: -1.4 },\n },\n 'flying-note': {\n meta: { name: 'Flying note', tags: ['fly', 'tumble', 'text'] },\n sheet: { width: 1, height: 0.7 },\n stock: 'printer',\n content: {\n type: 'text',\n text: 'meet me where\\nthe paper lands',\n size: 52,\n align: 'center',\n padding: 0.16,\n },\n behavior: { type: 'fly', flutter: 0.55, curve: 0.45 },\n physics: 'tumble',\n },\n 'blank-sheet': {\n meta: { name: 'Blank sheet', tags: ['starter'] },\n stock: 'printer',\n },\n // The driving use case: one stamp of the 2×5 block. Hover peels the\n // outward-facing corner ('auto' resolves per sheet slot), pressing deepens\n // the peel; the perforation tears when it detaches (field auto-wiring).\n 'postage-stamp': {\n meta: { name: 'Postage stamp', tags: ['sticker', 'stamp', 'states', 'sheet'] },\n sheet: { width: 0.64, height: 0.78, thickness: 0.08 },\n stock: 'sticker',\n // No `src`: a stamp's art is the caller's, and the library ships no\n // assets and fetches none. The perforation, the sticker stock and the\n // peel — which is what this preset is actually here to demonstrate —\n // all read perfectly well on bare stock.\n content: { type: 'image', fit: 'cover', alt: 'A postage stamp' },\n behavior: { type: 'peel', progress: 0, corner: 'auto', radius: 0.12 },\n surface: { perforation: { edges: 'all', holeRadius: 0.014, spacing: 0.05 } },\n states: {\n initial: 'rest',\n states: {\n hover: {\n overrides: { behavior: { progress: 0.22 } },\n transition: { duration: 0.25, ease: 'power2.out' },\n },\n pressed: {\n overrides: { behavior: { progress: 0.5 } },\n transition: { duration: 0.16, ease: 'power3.out' },\n },\n // Picked is auto-choreographed at pick time (carry hanging from the\n // peeled corner); placed announces itself for a host postmark overlay.\n placed: { overrides: {}, onEnter: ['emit:postmark'] },\n },\n pickThreshold: 0.08,\n },\n },\n 'photo-print': {\n meta: { name: 'Photo print', tags: ['image', 'starter'] },\n sheet: { width: 1.2, height: 0.9 },\n stock: 'photo-gloss',\n // Same: the field starter is a CONTAINER. Its whole documented use is\n // `<PaperField images={photos} preset=\"photo-print\" />`, where the\n // photographs are the caller's.\n content: { type: 'image', fit: 'cover', alt: 'A photographic print' },\n // No print lies perfectly flat. A shade of bow is the whole difference\n // between a sheet of paper and a rectangle — and since this is the field\n // starter, it is what a layout's per-sheet bias has to scale.\n deformers: [{ type: 'bend', options: { curvature: 0.35, angle: 0 } }],\n },\n 'crumpled-note': {\n meta: { name: 'Crumpled note', tags: ['crumple', 'text', 'handled'] },\n sheet: { width: 1.1, height: 1.4 },\n stock: 'printer',\n content: {\n type: 'text',\n text: 'I wrote it out three times\\nand threw all three away.',\n size: 42,\n },\n behavior: { type: 'crumple', progress: 0.62, coarseness: 0.4, ball: 0.55 },\n // Handled paper is dirty paper: the grain is what stops the facets\n // reading as folded plastic.\n surface: { grain: 0.5, aging: 0.18 },\n },\n /**\n * The second after the fall. `fall` is a sheet still arguing with the air;\n * this one has stopped — which is the half of the story the library could\n * not tell, and the half every paper installation is actually made of.\n */\n /**\n * A strip hung the full drop of a room. Tall and narrow on purpose: the\n * proportion IS the object, and a ribbon that is not much longer than it\n * is wide is a poster.\n */\n 'paper-ribbon': {\n meta: { name: 'Paper ribbon', tags: ['ribbon', 'hang', 'text'] },\n sheet: { width: 0.85, height: 6.4 },\n stock: 'printer',\n content: {\n type: 'text',\n // Short words, set small. The measure on a 0.85-wide strip is about\n // 220px at texture resolution, and anything larger breaks mid-word —\n // a ribbon reading \"an d th e pa pe r\" is a ribbon nobody can read.\n text: 'the paper\\nkept going\\nlong after\\nthe floor\\nran out',\n size: 34,\n align: 'center',\n valign: 'center',\n lineHeight: 1.5,\n tracking: 0.02,\n },\n behavior: { type: 'ribbon', pool: 0.17, curl: 0.42, drape: 0.55 },\n surface: { grain: 0.18 },\n },\n 'settled-sheet': {\n meta: { name: 'Settled sheet', tags: ['settle', 'floor', 'text'] },\n sheet: { width: 1.2, height: 0.9 },\n stock: 'printer',\n content: {\n type: 'card',\n title: 'Found',\n body: 'on the floor, face up,\\nwhere somebody dropped it.',\n note: 'no. 31',\n },\n behavior: { type: 'settle', relax: 0.6, lift: 0.5, slack: 0.45 },\n surface: { grain: 0.2 },\n },\n 'typed-note': {\n meta: { name: 'Typed note', tags: ['text', 'starter'] },\n sheet: { width: 1, height: 1.4 },\n stock: 'printer',\n content: {\n type: 'text',\n text: 'Dear reader,\\n\\nPaper is the product. Everything else hangs off the sheet.\\n\\n— Paperlab',\n },\n },\n}\n\n/** User presets registered at runtime (the editor persists these to localStorage). */\nconst userPresets = new Map<string, PaperConfigInput>()\n\nexport function getPreset(name: string): PaperConfig {\n const raw = builtins[name] ?? userPresets.get(name)\n if (!raw) {\n throw new Error(`[paperlab] Unknown preset \"${name}\". Registered: ${listPresets().join(', ')}`)\n }\n return paperConfigSchema.parse(raw)\n}\n\n/** Register a user preset (validated). Built-in names are reserved. */\nexport function registerPreset(name: string, input: PaperConfigInput): void {\n if (name in builtins) {\n throw new Error(`[paperlab] \"${name}\" is a built-in preset — pick another name.`)\n }\n paperConfigSchema.parse(input) // fail fast on invalid configs\n userPresets.set(name, input)\n}\n\nexport function unregisterPreset(name: string): void {\n userPresets.delete(name)\n}\n\nexport function isBuiltinPreset(name: string): boolean {\n return name in builtins\n}\n\nexport function listPresets(): string[] {\n return [...Object.keys(builtins), ...userPresets.keys()]\n}\n\n/**\n * A collision-free preset name built from `base`: `base`, else `base 2`,\n * `base 3`, … The disambiguating suffix always grows from the SAME base — a\n * name derived from a synthetic base (e.g. an untitled import → \"imported\")\n * must not fall back to the original when it collides. `taken` reports whether\n * a candidate is already used (built-in or user preset).\n */\nexport function uniquePresetName(base: string, taken: (name: string) => boolean): string {\n if (!taken(base)) return base\n let n = 2\n let name = `${base} ${n}`\n while (taken(name)) name = `${base} ${++n}`\n return name\n}\n","import * as THREE from 'three'\nimport { useEffect, useState } from 'react'\nimport type { BackContentConfig, ContentConfig, SheetConfig } from '../config/schema'\nimport type { Stock } from '../core/stock'\nimport { paintReceipt } from './receipt'\nimport { paintCard } from './card'\nimport { paintWash } from './wash'\nimport { ensureFont, wrapLines } from './type'\n\n/**\n * All content is composited onto a canvas and applied as a texture — content\n * deforms with the mesh because the mesh deforms, never a 2D trick.\n * Long edge = 1024 logical px × DPR 2 so text stays crisp when curled.\n */\nconst LONG_EDGE = 1024\nconst DPR = 2\n\nexport function contentCanvasSize(sheet: SheetConfig): [number, number] {\n const long = Math.max(sheet.width, sheet.height)\n const w = Math.round((sheet.width / long) * LONG_EDGE * DPR)\n const h = Math.round((sheet.height / long) * LONG_EDGE * DPR)\n return [w, h]\n}\n\nfunction paintBackground(ctx: CanvasRenderingContext2D, w: number, h: number, stock: Stock) {\n ctx.fillStyle = stock.color\n ctx.fillRect(0, 0, w, h)\n}\n\nfunction paintImage(\n ctx: CanvasRenderingContext2D,\n w: number,\n h: number,\n img: HTMLImageElement,\n fit: 'cover' | 'contain',\n) {\n const scale =\n fit === 'cover' ? Math.max(w / img.width, h / img.height) : Math.min(w / img.width, h / img.height)\n const dw = img.width * scale\n const dh = img.height * scale\n ctx.drawImage(img, (w - dw) / 2, (h - dh) / 2, dw, dh)\n}\n\nfunction paintText(\n ctx: CanvasRenderingContext2D,\n w: number,\n h: number,\n content: Extract<ContentConfig, { type: 'text' }>,\n stock: Stock,\n) {\n const size = content.size * DPR\n const pad = content.padding * Math.min(w, h)\n const font = `${content.weight} ${size}px ${content.font}`\n ctx.font = font\n ctx.fillStyle = content.color === '#2b2620' ? stock.inkColor : content.color\n ctx.textBaseline = 'top'\n ctx.textAlign = content.align\n // Tracking is set before measuring, not after: `measureText` honours\n // `letterSpacing`, so wrapping against the untracked width would break\n // lines to a measure the painted line does not have.\n ctx.letterSpacing = `${content.tracking}em`\n\n const maxWidth = w - pad * 2\n const x = content.align === 'left' ? pad : content.align === 'right' ? w - pad : w / 2\n const lineStep = size * content.lineHeight\n\n const lines = wrapLines(ctx, content.text, maxWidth, font)\n // Re-assert: wrapLines restores the font it was handed, which drops the\n // spacing the measure was taken with.\n ctx.font = font\n ctx.letterSpacing = `${content.tracking}em`\n\n // `center` optically centres the whole block rather than hanging it from\n // the top edge — what a label or a poster wants, where `top` is what a\n // letter wants because a letter starts at the top of the page.\n const block = lines.length * lineStep\n let y = content.valign === 'center' ? Math.max(pad, (h - block) / 2) : pad\n\n for (const line of lines) {\n if (y > h - pad) break\n ctx.fillText(line, x, y)\n y += lineStep\n }\n ctx.letterSpacing = '0em'\n}\n\n/**\n * Render content to a canvas. Synchronous — image content needs a decoded\n * HTMLImageElement passed in (the hook below handles loading).\n */\nexport function renderContentToCanvas(\n content: ContentConfig | BackContentConfig,\n sheet: SheetConfig,\n stock: Stock,\n image?: HTMLImageElement,\n): HTMLCanvasElement {\n const [w, h] = contentCanvasSize(sheet)\n const canvas = document.createElement('canvas')\n canvas.width = w\n canvas.height = h\n const ctx = canvas.getContext('2d')!\n paintBackground(ctx, w, h, stock)\n // Under everything the sheet carries, and over the stock. A wash is a\n // ground: the letter is written on it, not beside it.\n if (content.wash) paintWash(ctx, w, h, content.wash)\n if (content.type === 'image' && image && content.src) paintImage(ctx, w, h, image, content.fit)\n if (content.type === 'text') paintText(ctx, w, h, content, stock)\n if (content.type === 'receipt') paintReceipt(ctx, w, h, content, stock)\n if (content.type === 'card') paintCard(ctx, w, h, content, stock, DPR)\n return canvas\n}\n\nfunction makeTexture(canvas: HTMLCanvasElement): THREE.CanvasTexture {\n const tex = new THREE.CanvasTexture(canvas)\n tex.colorSpace = THREE.SRGBColorSpace\n tex.anisotropy = 8\n tex.generateMipmaps = true\n return tex\n}\n\n/**\n * React hook: content config → texture. Re-renders only on content change,\n * never per-frame. Waits for image decode / document.fonts.ready.\n */\nexport function useContentTexture(\n content: ContentConfig | BackContentConfig | undefined,\n sheet: SheetConfig,\n stock: Stock,\n): THREE.CanvasTexture | null {\n const [texture, setTexture] = useState<THREE.CanvasTexture | null>(null)\n const key = JSON.stringify({ content: content ?? null, w: sheet.width, h: sheet.height, stock: stock.id })\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: key serializes the content, sheet and stock the canvas draws from.\n useEffect(() => {\n let disposed = false\n let tex: THREE.CanvasTexture | null = null\n\n if (!content) {\n setTexture(null)\n return\n }\n\n const commit = (canvas: HTMLCanvasElement) => {\n if (disposed) return\n tex = makeTexture(canvas)\n setTexture(tex)\n }\n\n if (content.type === 'image' && content.src) {\n const img = new Image()\n img.crossOrigin = 'anonymous'\n img.onload = () => commit(renderContentToCanvas(content, sheet, stock, img))\n // A URL that never loads must not leave the sheet textureless — it\n // still has stock, and bare stock is the honest picture of \"no image\".\n img.onerror = () => commit(renderContentToCanvas(content, sheet, stock))\n img.src = content.src\n } else if (content.type === 'text' || content.type === 'card') {\n // Ask for the face BY NAME. `document.fonts.ready` alone only waits for\n // what the document already requested, and a family named inside a\n // canvas font string was never requested by anything — so on a page\n // with no DOM element using it, `ready` resolves at once and the sheet\n // paints in the fallback.\n void ensureFont(content.font, content.size * DPR).then(() =>\n commit(renderContentToCanvas(content, sheet, stock)),\n )\n } else if (content.type === 'receipt') {\n document.fonts.ready.then(() => commit(renderContentToCanvas(content, sheet, stock)))\n } else {\n commit(renderContentToCanvas(content, sheet, stock))\n }\n\n return () => {\n disposed = true\n tex?.dispose()\n }\n }, [key])\n\n return texture\n}\n","import type { ContentConfig } from '../config/schema'\nimport type { Stock } from '../core/stock'\n\nexport type ReceiptContent = Extract<ContentConfig, { type: 'receipt' }>\n\nexport interface ReceiptTotals {\n subtotal: number\n tax: number\n total: number\n}\n\nexport function receiptTotals(content: ReceiptContent): ReceiptTotals {\n const subtotal = content.items.reduce((sum, item) => sum + item.price, 0)\n const tax = subtotal * content.taxRate\n return { subtotal, tax, total: subtotal + tax }\n}\n\n/** Deterministic bar widths from a string — stylized Code-128 look. */\nexport function barcodeBars(seed: string): number[] {\n // Not a scannable Code 128 (real encoding tracked for later) — but the\n // start/stop guard structure and 1–4 module widths match the real thing.\n let h = 2166136261\n for (let i = 0; i < seed.length; i++) {\n h ^= seed.charCodeAt(i)\n h = Math.imul(h, 16777619)\n }\n const bars: number[] = [2, 1, 1, 4] // start guard\n for (let i = 0; i < 30; i++) {\n h = Math.imul(h ^ (h >>> 15), 2246822519)\n bars.push(1 + (Math.abs(h) % 4))\n }\n bars.push(2, 3, 3, 1, 1, 2) // stop guard\n return bars\n}\n\nconst money = (v: number) => v.toFixed(2)\n\n/**\n * The procedural receipt: store header, line items, totals, barcode,\n * timestamp, footer. Pairs with `deckle: { edges: ['bottom'] }` for the\n * jagged thermal tear. One-liner meme potential by design.\n */\nexport function paintReceipt(\n ctx: CanvasRenderingContext2D,\n w: number,\n h: number,\n content: ReceiptContent,\n stock: Stock,\n): void {\n const ink = stock.inkColor\n const pad = w * 0.09\n const colWidth = w - pad * 2\n const base = Math.round(w / 15) // font size scales with receipt width\n const mono = (size: number, weight = 400) => `${weight} ${size}px ui-monospace, Menlo, Consolas, monospace`\n\n let y = h * 0.045\n const line = (step = 1.6) => (y += base * step)\n\n const center = (text: string, size = base, weight = 400) => {\n ctx.font = mono(size, weight)\n ctx.textAlign = 'center'\n ctx.fillText(text, w / 2, y)\n }\n const row = (left: string, right: string, size = base) => {\n ctx.font = mono(size)\n ctx.textAlign = 'left'\n ctx.fillText(left, pad, y)\n ctx.textAlign = 'right'\n ctx.fillText(right, w - pad, y)\n }\n const divider = () => {\n ctx.font = mono(base)\n ctx.textAlign = 'center'\n ctx.fillText('- '.repeat(Math.floor(colWidth / (base * 1.1))).trim(), w / 2, y)\n }\n\n ctx.fillStyle = ink\n ctx.textBaseline = 'top'\n\n center(content.store.toUpperCase(), base * 1.5, 700)\n line(2.4)\n center(content.address.toUpperCase())\n line(1.8)\n divider()\n line(1.8)\n\n for (const item of content.items) {\n row(item.name.toUpperCase(), money(item.price))\n line()\n }\n line(0.4)\n divider()\n line(1.8)\n\n const totals = receiptTotals(content)\n row('SUBTOTAL', money(totals.subtotal))\n line()\n row(`TAX ${(content.taxRate * 100).toFixed(0)}%`, money(totals.tax))\n line()\n row('TOTAL', money(totals.total), base * 1.15)\n line(2)\n\n center(content.timestamp ?? new Date().toLocaleString('en-GB'), base * 0.9)\n line(2.2)\n\n if (content.barcode) {\n const bars = barcodeBars(content.store)\n const modules = bars.reduce((a, b) => a + b, 0)\n const module = (colWidth * 0.85) / modules\n const barH = base * 3.2\n let x = (w - modules * module) / 2\n bars.forEach((width, i) => {\n if (i % 2 === 0) ctx.fillRect(x, y, width * module, barH)\n x += width * module\n })\n y += barH\n line(1.8)\n }\n\n center(content.footer.toUpperCase(), base * 0.9)\n}\n","/**\n * Line breaking, shared by every content type that sets prose.\n *\n * It lives on its own because `paintText` and `paintCard` were about to\n * carry two copies of it, and two copies of a line-breaker is two answers to\n * \"where does this wrap\" — which on a sheet that CURLS is not a cosmetic\n * disagreement: the reader sees the break land on a fold.\n */\n\n/**\n * Wrap a paragraph to a measure, breaking a word that cannot fit on its own.\n *\n * The last clause is the part the old loop got wrong. It appended a word\n * whenever the line was empty, on the reasonable theory that one word always\n * fits — but a long URL or a compound on a narrow banner does not, and it\n * ran off the edge of the sheet with nothing to stop it. A sheet is a\n * physical object: type that leaves it has left it.\n */\nexport function wrapLines(\n ctx: CanvasRenderingContext2D,\n text: string,\n maxWidth: number,\n font: string,\n): string[] {\n const previous = ctx.font\n ctx.font = font\n const out: string[] = []\n\n for (const paragraph of text.split('\\n')) {\n if (paragraph.trim() === '') {\n // An empty line is a paragraph break, and it should survive as one.\n out.push('')\n continue\n }\n let line = ''\n for (const word of paragraph.split(/\\s+/).filter(Boolean)) {\n const attempt = line ? `${line} ${word}` : word\n if (line && ctx.measureText(attempt).width > maxWidth) {\n out.push(line)\n line = word\n } else {\n line = attempt\n }\n // The word itself is wider than the measure: break it rather than\n // let it hang off the sheet.\n while (ctx.measureText(line).width > maxWidth && line.length > 1) {\n let cut = line.length - 1\n while (cut > 1 && ctx.measureText(line.slice(0, cut)).width > maxWidth) cut--\n out.push(line.slice(0, cut))\n line = line.slice(cut)\n }\n }\n if (line) out.push(line)\n }\n\n ctx.font = previous\n return out\n}\n\n/**\n * Ask the browser to actually load the face before painting with it.\n *\n * `document.fonts.ready` — which this library already awaited — resolves\n * when the fonts the DOCUMENT has requested have settled. A face named only\n * inside a canvas `ctx.font` string was never requested by anything, so on a\n * page where no DOM element uses it `ready` resolves immediately and the\n * canvas paints in the fallback. The sheet then renders in Times while the\n * preset says Playfair, silently and only sometimes, which is the worst\n * shape a bug can have.\n *\n * `fonts.load()` is the request. Failures are swallowed on purpose: a font\n * that will not load is a fallback, not an exception, and a sheet that\n * refuses to render is worse than one set in the wrong face.\n */\nexport async function ensureFont(font: string, size: number): Promise<void> {\n if (typeof document === 'undefined' || !document.fonts) return\n try {\n await document.fonts.load(`${size}px ${font}`)\n } catch {\n // Unparseable family list, or a face the browser will not fetch.\n }\n try {\n await document.fonts.ready\n } catch {\n // Ignored for the same reason.\n }\n}\n","import type { ContentConfig } from '../config/schema'\nimport type { Stock } from '../core/stock'\nimport { wrapLines } from './type'\n\nexport type CardContent = Extract<ContentConfig, { type: 'card' }>\n\n/**\n * The card: a tracked label, a rule, a body, and a line of small print.\n *\n * Held to the receipt's standard rather than the text block's, which is the\n * whole reason it exists. The receipt is the only content type in this\n * library anybody art-directed — it knows what a dashed rule is, what a\n * barcode looks like, and that a total belongs at the bottom — and\n * everything else went through one `fillText` loop in the system serif.\n *\n * The proportions below are the composition, and they are ratios of the body\n * size rather than numbers, so a card scales as a card instead of as a\n * paragraph that grew.\n */\n\n/** Title sits well under the body: it is a label, not a heading. */\nconst TITLE_RATIO = 0.52\n/** Small print smaller still, and the two are deliberately different sizes. */\nconst NOTE_RATIO = 0.46\n/** Tracking for the title. Uppercase at small sizes closes up without it. */\nconst TITLE_TRACKING = 0.16\nconst NOTE_TRACKING = 0.06\n\nexport function paintCard(\n ctx: CanvasRenderingContext2D,\n w: number,\n h: number,\n content: CardContent,\n stock: Stock,\n dpr: number,\n): void {\n const ink = content.color === '#2b2620' ? stock.inkColor : content.color\n const size = content.size * dpr\n const pad = content.padding * Math.min(w, h)\n const maxWidth = w - pad * 2\n const x = content.align === 'center' ? w / 2 : pad\n ctx.textAlign = content.align === 'center' ? 'center' : 'left'\n ctx.textBaseline = 'alphabetic'\n\n const titleSize = size * TITLE_RATIO\n const noteSize = size * NOTE_RATIO\n const bodyStep = size * 1.35\n\n // Measure the whole composition before drawing any of it, so the block can\n // be centred in the card. A card whose type is hung from the top edge\n // reads as a page that got cut off rather than as a card.\n const bodyLines = content.body ? wrapLines(ctx, content.body, maxWidth, `${size}px ${content.font}`) : []\n const titleBlock = content.title ? titleSize * 1.9 : 0\n const ruleBlock = content.rule && content.title ? titleSize * 0.9 : 0\n const noteBlock = content.note ? noteSize * 2.4 : 0\n const bodyBlock = bodyLines.length * bodyStep\n const total = titleBlock + ruleBlock + bodyBlock + noteBlock\n\n let y = Math.max(pad, (h - total) / 2) + size * 0.9\n\n if (content.title) {\n ctx.font = `${titleSize}px ${content.font}`\n ctx.letterSpacing = `${TITLE_TRACKING}em`\n ctx.fillStyle = ink\n ctx.globalAlpha = 0.72\n ctx.fillText(content.title.toUpperCase(), x, y - size * 0.5)\n ctx.globalAlpha = 1\n ctx.letterSpacing = '0em'\n y += titleBlock - size * 0.5\n\n if (content.rule) {\n // A hairline, not a border: it separates, it does not enclose.\n ctx.save()\n ctx.strokeStyle = ink\n ctx.globalAlpha = 0.28\n ctx.lineWidth = Math.max(1, dpr * 0.75)\n ctx.beginPath()\n ctx.moveTo(content.align === 'center' ? w / 2 - maxWidth / 2 : pad, y - titleSize * 0.5)\n ctx.lineTo(content.align === 'center' ? w / 2 + maxWidth / 2 : pad + maxWidth, y - titleSize * 0.5)\n ctx.stroke()\n ctx.restore()\n y += ruleBlock\n }\n }\n\n if (content.ruled && bodyLines.length > 0) {\n // Writing lines, drawn UNDER the type and in the stock's own ink at low\n // alpha, so they read as printed on the card rather than as underlines\n // on the words.\n ctx.save()\n ctx.strokeStyle = ink\n ctx.globalAlpha = 0.14\n ctx.lineWidth = Math.max(1, dpr * 0.6)\n for (let i = 0; i < bodyLines.length; i++) {\n const lineY = y + i * bodyStep + size * 0.28\n ctx.beginPath()\n ctx.moveTo(pad, lineY)\n ctx.lineTo(pad + maxWidth, lineY)\n ctx.stroke()\n }\n ctx.restore()\n }\n\n ctx.font = `${size}px ${content.font}`\n ctx.fillStyle = ink\n for (const line of bodyLines) {\n if (y > h - pad) break\n ctx.fillText(line, x, y)\n y += bodyStep\n }\n\n if (content.note) {\n ctx.font = `${noteSize}px ${content.font}`\n ctx.letterSpacing = `${NOTE_TRACKING}em`\n ctx.globalAlpha = 0.6\n ctx.fillText(content.note, x, Math.min(y + noteSize * 1.4, h - pad))\n ctx.globalAlpha = 1\n ctx.letterSpacing = '0em'\n }\n}\n","import type { WashConfig } from '../config/schema'\n\n/**\n * Painting a watercolour wash.\n *\n * Five things separate watercolour from a soft gradient, and this paints\n * four of them deliberately. In the order they matter:\n *\n * 1. **Edge darkening.** Pigment migrates to the boundary of a pool as the\n * water retreats and dries there in a ring. It is the signature of the\n * medium — without it any amount of blur reads as an airbrush — and it is\n * the one effect a radial gradient cannot fake, because the ring follows\n * the pool's own irregular outline rather than a circle.\n * 2. **An irregular wet edge.** A pool is not a disc. Its outline is a few\n * low harmonics riding on a radius, which is what makes lobes rather than\n * the even scallops a single frequency gives.\n * 3. **Glazing.** Two washes over each other are darker than either, and a\n * different hue from both. `multiply` is not a stylistic choice here; it\n * is what transparent pigment over transparent pigment does.\n * 4. **Granulation.** Heavy pigment settles into the tooth of the paper and\n * leaves it speckled. Confined to where there IS pigment — speckling the\n * whole sheet would be a dirty scan, not a granulating wash.\n *\n * The fifth is the paper, and this file does not paint it: the wash goes on\n * over the stock's own colour, and the surface shader's grain and aging run\n * later over everything. That ordering is the point of washing UNDER the\n * content rather than compositing a picture on top of it.\n */\n\n/**\n * Deterministic PRNG, so a seed paints the same wash forever.\n *\n * A preset that repainted itself differently on every mount would be a\n * different artwork each time the component remounted, and no screenshot,\n * share link or export would agree with any other.\n */\nfunction mulberry32(seed: number): () => number {\n let a = seed * 0x6d2b79f5 + 0x9e3779b9\n return () => {\n a |= 0\n a = (a + 0x6d2b79f5) | 0\n let t = Math.imul(a ^ (a >>> 15), 1 | a)\n t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296\n }\n}\n\n/** `#rrggbb` → `rgba(r, g, b, alpha)`. Anything unparseable paints as grey. */\nfunction rgba(hex: string, alpha: number): string {\n const m = /^#?([0-9a-f]{6})$/i.exec(hex.trim())\n const n = m ? Number.parseInt(m[1]!, 16) : 0x808080\n return `rgba(${(n >> 16) & 255}, ${(n >> 8) & 255}, ${n & 255}, ${Math.max(0, Math.min(1, alpha))})`\n}\n\n/**\n * A pool's outline, as three harmonics on a radius.\n *\n * Two would read as an ellipse and one gives a flower; three is where it\n * stops looking generated.\n *\n * Drawn from a shape decided ONCE per pool rather than from the generator,\n * because the fill, the dried edge and the granulation clip are three passes\n * over the SAME pool. Re-rolling the outline for each of them was drawing a\n * rim that belonged to a different shape than the one it was supposed to be\n * the rim of — which is why the first version had thin wandering lines\n * across it that read as pen, not pigment.\n */\ninterface BloomShape {\n phase: [number, number, number]\n amp: [number, number, number]\n}\n\nfunction bloomShape(rng: () => number): BloomShape {\n return {\n phase: [rng() * Math.PI * 2, rng() * Math.PI * 2, rng() * Math.PI * 2],\n amp: [0.18 + rng() * 0.1, 0.09 + rng() * 0.06, 0.05 + rng() * 0.04],\n }\n}\n\n/**\n * The outline, or an arc of it.\n *\n * `from`/`to` are turns, 0..1. A whole pool is one closed path; its dried\n * edge is drawn as several arcs instead, because pigment does not dry evenly\n * all the way round — a pool that sat against a tilt leaves a heavy rim on\n * one side and almost none on the other, and a rim of uniform weight is the\n * tell that a wash was generated rather than painted.\n */\nfunction bloomPath(\n ctx: CanvasRenderingContext2D,\n cx: number,\n cy: number,\n radius: number,\n shape: BloomShape,\n from = 0,\n to = 1,\n): void {\n const { phase, amp } = shape\n const STEPS = Math.max(6, Math.round(72 * (to - from)))\n ctx.beginPath()\n for (let i = 0; i <= STEPS; i++) {\n const t = (from + ((to - from) * i) / STEPS) * Math.PI * 2\n const wobble =\n amp[0]! * Math.sin(2 * t + phase[0]!) +\n amp[1]! * Math.sin(3 * t + phase[1]!) +\n amp[2]! * Math.sin(5 * t + phase[2]!)\n const r = radius * (1 + wobble)\n const x = cx + Math.cos(t) * r\n const y = cy + Math.sin(t) * r\n if (i === 0) ctx.moveTo(x, y)\n else ctx.lineTo(x, y)\n }\n if (from === 0 && to === 1) ctx.closePath()\n}\n\n/**\n * Whether this canvas can blur.\n *\n * `ctx.filter` is how the wet edge is made, and where it is missing every\n * pool would come out cut with scissors. Detected rather than assumed\n * because the answer differs between a browser and a headless canvas, and a\n * wash is not worth throwing a render away over: without it the fill still\n * lands, just harder-edged.\n */\nfunction canBlur(ctx: CanvasRenderingContext2D): boolean {\n if (!('filter' in ctx)) return false\n const before = ctx.filter\n try {\n ctx.filter = 'blur(2px)'\n const worked = ctx.filter !== 'none' && ctx.filter !== before\n ctx.filter = before\n return worked\n } catch {\n return false\n }\n}\n\nexport function paintWash(ctx: CanvasRenderingContext2D, w: number, h: number, wash: WashConfig): void {\n const rng = mulberry32(wash.seed + 1)\n const short = Math.min(w, h)\n const blurs = canBlur(ctx)\n\n ctx.save()\n // Transparent pigment over transparent pigment. Two pools crossing are\n // darker than either and a third hue; on the stock alone a pool tints the\n // paper rather than covering it.\n ctx.globalCompositeOperation = 'multiply'\n\n for (let i = 0; i < wash.blooms; i++) {\n const pigment = i % 2 === 0 ? wash.color : wash.secondary\n // Pools are allowed off the edge. A wash that stops politely inside the\n // sheet reads as a printed shape; one that runs off it reads as paint.\n const cx = (rng() * 1.5 - 0.25) * w\n const cy = (rng() * 1.5 - 0.25) * h\n const radius = short * wash.spread * (0.28 + rng() * 0.34)\n const alpha = wash.intensity * (0.35 + rng() * 0.4)\n\n // Decided before any pass draws, so all three describe one pool.\n const shape = bloomShape(rng)\n\n ctx.save()\n if (blurs) ctx.filter = `blur(${(2 + wash.bleed * 26) * (0.6 + rng() * 0.8)}px)`\n\n // The body of the pool. The gradient's centre is offset from the shape's,\n // because water pools to one side as it dries rather than evenly.\n const gx = cx + (rng() - 0.5) * radius * 0.5\n const gy = cy + (rng() - 0.5) * radius * 0.5\n const grad = ctx.createRadialGradient(gx, gy, radius * 0.05, gx, gy, radius * 1.15)\n grad.addColorStop(0, rgba(pigment, alpha * 0.55))\n grad.addColorStop(0.62, rgba(pigment, alpha))\n grad.addColorStop(1, rgba(pigment, alpha * 0.75))\n ctx.fillStyle = grad\n bloomPath(ctx, cx, cy, radius, shape)\n ctx.fill()\n\n // The dried edge, following the pool's OWN outline rather than a circle,\n // and unevenly — heavy on one side, nearly absent on another.\n if (wash.edge > 0) {\n if (blurs) ctx.filter = `blur(${(1.5 + wash.bleed * 9) * (0.6 + rng() * 0.6)}px)`\n ctx.lineWidth = Math.max(1, radius * (0.03 + wash.edge * 0.05))\n const arcs = 5\n // Arcs overlap slightly so the seams between them do not read as gaps.\n const overlap = 0.4 / arcs\n for (let a = 0; a < arcs; a++) {\n ctx.strokeStyle = rgba(pigment, alpha * wash.edge * (0.15 + rng() * 1.05))\n bloomPath(ctx, cx, cy, radius, shape, a / arcs, (a + 1) / arcs + overlap)\n ctx.stroke()\n }\n }\n ctx.restore()\n\n // Pigment in the tooth of the paper, kept inside the pool it settled out\n // of. Speckling the whole sheet would be a dirty scan, not granulation.\n if (wash.granulation > 0) {\n ctx.save()\n bloomPath(ctx, cx, cy, radius, shape)\n ctx.clip()\n const grains = Math.round(wash.granulation * 900)\n ctx.fillStyle = rgba(pigment, wash.granulation * alpha * 0.5)\n for (let g = 0; g < grains; g++) {\n const a = rng() * Math.PI * 2\n // sqrt keeps the scatter even across the disc instead of crowding\n // the centre, which is where a uniform radius puts everything.\n const d = Math.sqrt(rng()) * radius\n const size = 1 + rng() * (short * 0.004)\n ctx.fillRect(cx + Math.cos(a) * d, cy + Math.sin(a) * d, size, size)\n }\n ctx.restore()\n }\n }\n\n ctx.restore()\n}\n","import * as THREE from 'three'\nimport { computeSheetNormals } from '../core/normals'\nimport { axialSegments, type SegmentPair } from '../core/tessellation'\nimport type { AnyOptions, Deformer, DeformerContext, DeformerInstance, SheetDims } from './types'\nimport { getDeformer } from './registry'\n\n// Preallocated scratch — deformer loops are allocation-free.\nconst scratchPos = new THREE.Vector3()\nconst scratchUv = new THREE.Vector2()\n\n/**\n * The resolved stack, reused across frames: two parallel arrays rather than a\n * list of objects, refilled in place. `applyDeformerStack` runs every frame\n * for any animated sheet, and a `filter()` plus a registry lookup per vertex\n * is a per-frame allocation and 16k map probes for an answer that only\n * changes when the stack does.\n */\nconst activeFns: ((out: THREE.Vector3, uv: THREE.Vector2, o: AnyOptions, ctx: DeformerContext) => void)[] = []\nconst activeOptions: AnyOptions[] = []\n\n/**\n * Run an ordered deformer stack over a sheet geometry: each vertex starts\n * from its flat base position and flows through every enabled deformer in\n * order. Writes positions in place and recomputes normals.\n */\nexport function applyDeformerStack(\n geometry: THREE.BufferGeometry,\n basePositions: Float32Array,\n stack: DeformerInstance[],\n ctx: DeformerContext,\n): void {\n const position = geometry.attributes.position as THREE.BufferAttribute\n const uv = geometry.attributes.uv as THREE.BufferAttribute\n const array = position.array as Float32Array\n const uvArray = uv.array as Float32Array\n const count = position.count\n\n activeFns.length = 0\n activeOptions.length = 0\n for (const instance of stack) {\n if (instance.enabled === false) continue\n activeFns.push(getDeformer(instance.type).displace)\n activeOptions.push(instance.options)\n }\n\n // One deformer over every vertex, then the next — rather than every\n // deformer over one vertex, then the next. A deformer only ever reads and\n // writes the vertex it was handed, so sweeping the sheet per deformer is\n // the same composition in a different order, and it puts ONE function\n // behind the inner call site instead of the whole stack. It also costs an\n // extra pass over the position array per deformer, which is sequential and\n // measures as nothing beside what the call site buys.\n array.set(basePositions)\n for (let k = 0; k < activeFns.length; k++) {\n const displace = activeFns[k]!\n const options = activeOptions[k]\n for (let v = 0; v < count; v++) {\n const i3 = v * 3\n const i2 = v * 2\n scratchPos.set(array[i3]!, array[i3 + 1]!, array[i3 + 2]!)\n scratchUv.set(uvArray[i2]!, uvArray[i2 + 1]!)\n displace(scratchPos, scratchUv, options, ctx)\n array[i3] = scratchPos.x\n array[i3 + 1] = scratchPos.y\n array[i3 + 2] = scratchPos.z\n }\n }\n\n position.needsUpdate = true\n computeSheetNormals(geometry)\n}\n\n/** A single point through the stack — used for handle anchors and tests. */\nexport function displacePoint(\n point: THREE.Vector3,\n uvX: number,\n uvY: number,\n stack: DeformerInstance[],\n ctx: DeformerContext,\n): THREE.Vector3 {\n scratchUv.set(uvX, uvY)\n for (const instance of stack) {\n if (instance.enabled === false) continue\n getDeformer(instance.type).displace(point, scratchUv, instance.options, ctx)\n }\n return point\n}\n\n/**\n * The densest grid any deformer in the stack REQUIRES to work at all, per\n * axis — the componentwise max of every entry's floor projected onto the\n * sheet's own X and Y by the direction that entry curves in.\n */\nexport function stackMinSegments(stack: DeformerInstance[], sheet: SheetDims): SegmentPair {\n const out: SegmentPair = [2, 2]\n for (const instance of stack) {\n const deformer = getDeformer(instance.type)\n const floor = deformer.geometry?.minSegments\n if (!floor) continue\n take(out, deformer, instance.options, sheet, floor)\n }\n return out\n}\n\n/**\n * The densest grid any deformer in the stack WANTS, given the options it is\n * actually carrying — what `segments: 'auto'` resolves to, per axis.\n *\n * Disabled instances are skipped, exactly as `applyDeformerStack` skips them:\n * a deformer that is not displacing anything has no opinion about the grid.\n * (`stackMinSegments` does not skip them, and that difference is deliberate —\n * a floor is about what the stack could do, a target about what it is doing.)\n *\n * A deformer with no `autoSegments` falls back to its floor, which is the\n * right answer for one whose cost does not move with its options.\n */\nexport function stackAutoSegments(stack: DeformerInstance[], sheet: SheetDims): SegmentPair {\n const out: SegmentPair = [0, 0]\n for (const instance of stack) {\n if (instance.enabled === false) continue\n const deformer = getDeformer(instance.type)\n const geometry = deformer.geometry\n if (!geometry) continue\n const want = geometry.autoSegments\n ? geometry.autoSegments(instance.options, sheet)\n : (geometry.minSegments ?? 0)\n take(out, deformer, instance.options, sheet, want)\n }\n return out\n}\n\n/** Project one demand onto the two axes and keep it if it raises either. */\nfunction take(\n out: SegmentPair,\n deformer: Deformer<AnyOptions>,\n options: AnyOptions,\n sheet: SheetDims,\n demand: number,\n): void {\n // A community deformer whose `axis` cannot answer for these options — or\n // one that has none — falls back to spreading the demand over both axes,\n // which is the conservative half of the choice: it over-subdivides rather\n // than under-subdividing something that is actually bending.\n const declared = deformer.geometry?.axis?.(options, sheet)\n const angle = typeof declared === 'number' && Number.isFinite(declared) ? declared : null\n const [x, y] = axialSegments(sheet, angle, demand)\n if (x > out[0]) out[0] = x\n if (y > out[1]) out[1] = y\n}\n","import { z } from 'zod'\nimport type { AnyOptions, Deformer, DeformerInstance } from './types'\nimport { roll } from './roll'\nimport { curl } from './curl'\nimport { bend } from './bend'\nimport { fold } from './fold'\nimport { wave } from './wave'\nimport { drape } from './drape'\nimport { crumple } from './crumple'\n\nconst registry = new Map<string, Deformer<AnyOptions>>()\n\n/** Community deformers register here; built-ins are pre-registered. */\nexport function registerDeformer(deformer: Deformer<AnyOptions>): void {\n registry.set(deformer.id, deformer)\n}\n\nexport function getDeformer(id: string): Deformer<AnyOptions> {\n const d = registry.get(id)\n if (!d) {\n throw new Error(`[paperlab] Unknown deformer \"${id}\". Registered: ${[...registry.keys()].join(', ')}`)\n }\n return d\n}\n\nexport function listDeformers(): string[] {\n return [...registry.keys()]\n}\n\nregisterDeformer(roll)\nregisterDeformer(curl)\nregisterDeformer(bend)\nregisterDeformer(fold)\nregisterDeformer(wave)\nregisterDeformer(drape)\nregisterDeformer(crumple)\n\n/**\n * Resolve a raw `deformers` stack — the Advanced fork of a behavior — into\n * instances safe to render.\n *\n * The escape hatch used to pass its options straight through, so a preset\n * naming an option that doesn't exist (`frequency` where wave wants\n * `wavelength`) reached the GLSL builder as `undefined` and died there with\n * a message about `.length`, or reached the CPU path and quietly produced\n * NaN vertices. Parsing through each deformer's own schema turns that into\n * the validation error it always was, and fills in defaults for whatever a\n * hand-written preset left out.\n *\n * Disabled entries keep their slot: the GLSL uniform namespace is indexed by\n * position, so dropping one here would rename every uniform after it.\n */\nexport function resolveDeformerStack(\n raw: { type: string; options?: Record<string, unknown>; enabled?: boolean }[],\n): DeformerInstance[] {\n return raw.map((instance, i) => {\n const deformer = getDeformer(instance.type)\n // Strict: an unknown key here is almost always a typo for a real option,\n // and silently dropping it means the preset renders wrong with no clue\n // why. Every built-in schema is a plain object; anything exotic a\n // community deformer brings is parsed as it comes.\n const schema =\n deformer.optionsSchema instanceof z.ZodObject ? deformer.optionsSchema.strict() : deformer.optionsSchema\n const parsed = schema.safeParse(instance.options ?? {})\n if (!parsed.success) {\n const issue = parsed.error.issues[0]\n throw new Error(\n `[paperlab] deformers[${i}] (\"${instance.type}\"): ${\n issue ? `${issue.path.join('.') || 'options'} — ${issue.message}` : 'invalid options'\n }`,\n )\n }\n return {\n type: instance.type,\n options: parsed.data as Record<string, unknown>,\n enabled: instance.enabled,\n }\n })\n}\n\n/** True if any enabled instance re-deforms every frame (wave etc.). */\nexport function stackIsAnimated(stack: { type: string; enabled?: boolean }[]): boolean {\n return stack.some((i) => i.enabled !== false && registry.get(i.type)?.animated)\n}\n","import { z } from 'zod'\nimport type { Deformer } from './types'\nimport { segmentsForArc, spanAlong } from '../core/tessellation'\n\nexport const bendOptionsSchema = z.object({\n /** 1/radius in world units; sign flips the arc direction. 0 = flat. */\n curvature: z.number().min(-4).max(4).default(0.6),\n /** Bend axis direction in the sheet plane, degrees. 0 bends across x. */\n angle: z.number().min(-360).max(360).default(0),\n})\n\nexport type BendOptions = z.infer<typeof bendOptionsSchema>\n\nconst DEG = Math.PI / 180\nconst EPS = 1e-5\n\n/**\n * `sin(x) − x`, without the cancellation that eats it for small x.\n *\n * The arc's in-plane shift is `r·sin θ − d`, and `d` IS `r·θ` — so for a\n * gentle bend it is a difference of two nearly-equal large numbers, and the\n * answer is the few bits that survive. JS computes that in float64 and gets\n * away with it; the GLSL twin computes it in float32 and does not, which put\n * the two paths 6e-4 apart at low curvature — past the parity gate's epsilon.\n * The series is exact to well under a float32 ulp below |x| = 1 and both\n * implementations take the same branch, so the two paths agree by\n * construction rather than by luck.\n */\nfunction sinMinusX(x: number): number {\n if (Math.abs(x) > 1) return Math.sin(x) - x\n const x2 = x * x\n return ((-x * x2) / 6) * (1 - (x2 / 20) * (1 - (x2 / 42) * (1 - x2 / 72)))\n}\n\n/**\n * Gentle global arc around a cylinder centered on the sheet — a standing\n * paper's lean. Arc-length preserving, like roll, but symmetric about the\n * center instead of one-sided.\n *\n * Written in its cancellation-free form throughout: `r(1 − cos θ)` is\n * `2r·sin²(θ/2)`, and the in-plane shift goes through `sinMinusX`. Same arc,\n * same numbers to sixteen places — it is only the float32 half that could\n * tell the difference, and that is exactly the half the parity gate checks.\n */\nexport const bend: Deformer<BendOptions> = {\n id: 'bend',\n label: 'Bend',\n defaults: bendOptionsSchema.parse({}),\n optionsSchema: bendOptionsSchema,\n geometry: {\n minSegments: 16,\n // A pure circular arc of radius 1/curvature, so the sagitta form answers\n // this exactly. This is the deformer the old flat 72 over-served most:\n // at the default 0.6 it wants 24, and the field starter preset is a bend.\n autoSegments: (o, sheet) => segmentsForArc(spanAlong(sheet, o.angle), 1 / Math.abs(o.curvature)),\n axis: (o) => o.angle,\n },\n displace(out, _uv, o) {\n if (Math.abs(o.curvature) < EPS) return\n const dirX = Math.cos(o.angle * DEG)\n const dirY = Math.sin(o.angle * DEG)\n const d = out.x * dirX + out.y * dirY\n\n const r = 1 / o.curvature\n const theta = d * o.curvature\n const sin = Math.sin(theta)\n const halfSin = Math.sin(theta * 0.5)\n const z0 = out.z\n\n // (r − z)·sin θ − d, with d = r·θ folded in so the big terms never meet.\n const shift = r * sinMinusX(theta) - z0 * sin\n out.x += dirX * shift\n out.y += dirY * shift\n out.z = 2 * r * halfSin * halfSin + z0 * Math.cos(theta)\n },\n glsl: {\n chunk: /* glsl */ `\nfloat FN_sinm(float x) {\n if (abs(x) > 1.0) return sin(x) - x;\n float x2 = x * x;\n return (-x * x2 / 6.0) * (1.0 - (x2 / 20.0) * (1.0 - (x2 / 42.0) * (1.0 - x2 / 72.0)));\n}\n\nvoid FN(inout vec3 p, vec2 uv, float t) {\n if (abs(U_curvature) < 1e-5) return;\n vec2 dir = vec2(cos(U_angle), sin(U_angle));\n float d = dot(p.xy, dir);\n float r = 1.0 / U_curvature;\n float theta = d * U_curvature;\n float sn = sin(theta);\n float hs = sin(theta * 0.5);\n float z0 = p.z;\n float shift = r * FN_sinm(theta) - z0 * sn;\n p.xy += dir * shift;\n p.z = 2.0 * r * hs * hs + z0 * cos(theta);\n}\n`,\n strength: 'curvature',\n uniforms: (o) => ({ curvature: o.curvature, angle: o.angle * DEG }),\n },\n}\n","import { z } from 'zod'\nimport type { Deformer } from './types'\nimport { segmentsForArc, spanAlong } from '../core/tessellation'\n\nexport const foldOptionsSchema = z.object({\n /** Direction of the fold travel in the sheet plane, degrees (the crease line runs perpendicular). */\n angle: z.number().min(-360).max(360).default(90),\n /** Signed distance of the crease line from the sheet center, along the travel direction. */\n offset: z.number().min(-20).max(20).default(0),\n /** How far the flap folds over, degrees. 180 = flat against the sheet. */\n foldAngle: z.number().min(-180).max(180).default(90),\n /** Width of the soft hinge — paper never creases to a mathematical edge. */\n radius: z.number().min(0.005).max(0.5).default(0.04),\n})\n\nexport type FoldOptions = z.infer<typeof foldOptionsSchema>\n\nconst DEG = Math.PI / 180\n\n/**\n * Angular crease across a line: within the hinge width the sheet wraps a\n * small cylinder (a roll), beyond it the flap continues rigid at the full\n * fold angle. n folds = n instances stacked (half-fold, letter-fold,\n * accordion). Arc-length preserving like every Paperlab deformer.\n */\nexport const fold: Deformer<FoldOptions> = {\n id: 'fold',\n label: 'Fold',\n defaults: foldOptionsSchema.parse({}),\n optionsSchema: foldOptionsSchema,\n geometry: {\n minSegments: 48,\n // The fillet is an arc of `radius`; everything either side of it is flat.\n // The crease is small, but the grid is uniform, so the density it needs\n // is the density the whole sheet gets.\n autoSegments: (o, sheet) => segmentsForArc(spanAlong(sheet, o.angle), o.radius),\n axis: (o) => o.angle,\n },\n displace(out, _uv, o) {\n const phi = o.foldAngle * DEG\n if (Math.abs(phi) < 1e-6) return\n const dirX = Math.cos(o.angle * DEG)\n const dirY = Math.sin(o.angle * DEG)\n const d = out.x * dirX + out.y * dirY\n const s = d - o.offset\n if (s <= 0) return\n\n // Signed hinge cylinder: radius R = radius/phi carries the fold\n // direction, so one code path serves folds up and down.\n const R = o.radius / phi\n let newD: number\n let newZ: number\n if (s <= o.radius) {\n // Inside the hinge: identical to a roll of signed radius R.\n const theta = (s / o.radius) * phi\n const sin = Math.sin(theta)\n const cos = Math.cos(theta)\n newD = o.offset + (R - out.z) * sin\n newZ = R * (1 - cos) + out.z * cos\n } else {\n // Past the hinge: rigid flap continuing from the arc's end along its\n // tangent; incoming z rides the rotated surface normal.\n const rest = s - o.radius\n const sin = Math.sin(phi)\n const cos = Math.cos(phi)\n newD = o.offset + R * sin + rest * cos - out.z * sin\n newZ = R * (1 - cos) + rest * sin + out.z * cos\n }\n\n out.x += dirX * (newD - d)\n out.y += dirY * (newD - d)\n out.z = newZ\n },\n glsl: {\n chunk: /* glsl */ `\nvoid FN(inout vec3 p, vec2 uv, float t) {\n if (abs(U_foldAngle) < 1e-6) return;\n vec2 dir = vec2(cos(U_angle), sin(U_angle));\n float d = dot(p.xy, dir);\n float s = d - U_offset;\n if (s <= 0.0) return;\n float R = U_radius / U_foldAngle;\n float newD;\n float newZ;\n if (s <= U_radius) {\n float theta = (s / U_radius) * U_foldAngle;\n float sn = sin(theta);\n float cs = cos(theta);\n newD = U_offset + (R - p.z) * sn;\n newZ = R * (1.0 - cs) + p.z * cs;\n } else {\n float rest = s - U_radius;\n float sn = sin(U_foldAngle);\n float cs = cos(U_foldAngle);\n newD = U_offset + R * sn + rest * cs - p.z * sn;\n newZ = R * (1.0 - cs) + rest * sn + p.z * cs;\n }\n p.xy += dir * (newD - d);\n p.z = newZ;\n}\n`,\n strength: 'foldAngle',\n uniforms: (o) => ({\n angle: o.angle * DEG,\n offset: o.offset,\n foldAngle: o.foldAngle * DEG,\n radius: o.radius,\n }),\n },\n}\n","import { z } from 'zod'\nimport type { Deformer } from './types'\nimport { segmentsForSine, spanAlong } from '../core/tessellation'\n\nexport const waveOptionsSchema = z.object({\n amplitude: z.number().min(0).max(0.3).default(0.04),\n wavelength: z.number().min(0.05).max(2).default(0.5),\n /** Travel speed; 0 freezes the ripple. */\n speed: z.number().min(0).max(3).default(0.8),\n /** Travel direction in the sheet plane, degrees. */\n angle: z.number().min(-360).max(360).default(90),\n /** Zero the displacement at one edge (a taped/pinned edge doesn't ripple). */\n pinnedEdge: z.enum(['none', 'top', 'bottom', 'left', 'right']).default('none'),\n})\n\nexport type WaveOptions = z.infer<typeof waveOptionsSchema>\n\nconst DEG = Math.PI / 180\nconst TAU = Math.PI * 2\n\n/**\n * Traveling sine displacement with a quieter second harmonic — idle flutter\n * and wind ripple. The only time-driven deformer so far: stacks containing\n * it re-deform every frame.\n */\nexport const wave: Deformer<WaveOptions> = {\n id: 'wave',\n label: 'Wave',\n defaults: waveOptionsSchema.parse({}),\n optionsSchema: waveOptionsSchema,\n geometry: {\n minSegments: 32,\n // `displace` is sin(phase) + 0.35·sin(2.7·phase). The harmonic is a\n // third the amplitude but curvature carries the SQUARE of the frequency,\n // so 0.35 × 2.7² ≈ 2.6 — the quiet term is the one that sets the grid,\n // by a factor of two and a half. Take whichever asks for more anyway.\n autoSegments: (o, sheet) => {\n const span = spanAlong(sheet, o.angle)\n return Math.max(\n segmentsForSine(span, o.amplitude, o.wavelength),\n segmentsForSine(span, o.amplitude * 0.35, o.wavelength / 2.7),\n )\n },\n axis: (o) => o.angle,\n },\n animated: true,\n displace(out, uv, o, ctx) {\n if (o.amplitude === 0) return\n const dirX = Math.cos(o.angle * DEG)\n const dirY = Math.sin(o.angle * DEG)\n const d = out.x * dirX + out.y * dirY\n const phase = (d / o.wavelength - o.speed * ctx.t) * TAU\n let env = 1\n if (o.pinnedEdge === 'top') env = 1 - uv.y\n else if (o.pinnedEdge === 'bottom') env = uv.y\n else if (o.pinnedEdge === 'left') env = uv.x\n else if (o.pinnedEdge === 'right') env = 1 - uv.x\n out.z += o.amplitude * env * (Math.sin(phase) + 0.35 * Math.sin(phase * 2.7 + 1.3))\n },\n glsl: {\n chunk: /* glsl */ `\nvoid FN(inout vec3 p, vec2 uv, float t) {\n if (U_amplitude == 0.0) return;\n vec2 dir = vec2(cos(U_angle), sin(U_angle));\n float d = dot(p.xy, dir);\n float phase = (d / U_wavelength - U_speed * t) * 6.283185307179586;\n float env = 1.0;\n if (U_pin == 1.0) env = 1.0 - uv.y;\n else if (U_pin == 2.0) env = uv.y;\n else if (U_pin == 3.0) env = uv.x;\n else if (U_pin == 4.0) env = 1.0 - uv.x;\n p.z += U_amplitude * env * (sin(phase) + 0.35 * sin(phase * 2.7 + 1.3));\n}\n`,\n strength: 'amplitude',\n uniforms: (o) => ({\n amplitude: o.amplitude,\n wavelength: o.wavelength,\n speed: o.speed,\n angle: o.angle * DEG,\n pin: { none: 0, top: 1, bottom: 2, left: 3, right: 4 }[o.pinnedEdge],\n }),\n },\n}\n","import { z } from 'zod'\nimport type { Deformer } from './types'\nimport { segmentsForSine } from '../core/tessellation'\n\nexport const drapeOptionsSchema = z.object({\n /** Fold depth at the free edge, world units. */\n amplitude: z.number().min(0).max(0.6).default(0.12),\n /** How many folds run down the drop. */\n folds: z.number().min(0.5).max(16).default(4),\n /**\n * How fast folds deepen away from the pinned edge. 1 is linear; higher\n * holds the top flat and gathers all the movement at the free end, which\n * is what a sheet hung from a rod actually does.\n */\n falloff: z.number().min(0.3).max(4).default(1.6),\n /** How much a second, non-harmonic fold breaks the regularity. */\n irregular: z.number().min(0).max(1).default(0.45),\n /** How much the sheet narrows as its folds deepen. */\n gather: z.number().min(0).max(1).default(0.5),\n pinnedEdge: z.enum(['top', 'bottom']).default('top'),\n})\n\nexport type DrapeOptions = z.infer<typeof drapeOptionsSchema>\n\nconst TAU = Math.PI * 2\n\n/**\n * Hung paper: vertical folds running the length of the drop, shallow at the\n * fixed edge and deepening toward the free one.\n *\n * `wave` can put ripples on a sheet, but a traveling sine is a flag, not a\n * curtain — it kinks the sheet ACROSS its drop and it is uniform end to end.\n * Cloth hung from an edge does the opposite: the folds run WITH the drop and\n * they grow as they get further from whatever is holding the sheet up. Two\n * details do most of the work:\n *\n * - the folds are not harmonic. A pure sine reads as corrugated metal, so a\n * second wave at an incommensurate frequency breaks the repeat.\n * - gathered paper is narrower than flat paper. Pulling the surface toward\n * its centerline in proportion to fold depth is what stops the drape from\n * looking like a texture painted on a rectangle.\n */\nexport const drape: Deformer<DrapeOptions> = {\n id: 'drape',\n label: 'Drape',\n defaults: drapeOptionsSchema.parse({}),\n optionsSchema: drapeOptionsSchema,\n geometry: {\n minSegments: 48,\n // `folds` fold across the width, so the wavelength is width/folds, and\n // the irregular term rides at 1.7x that frequency. Same reasoning as\n // wave: the faster term usually wins despite the smaller amplitude.\n autoSegments: (o, sheet) => {\n if (o.folds <= 0) return 0\n const lambda = sheet.width / o.folds\n return Math.max(\n segmentsForSine(sheet.width, o.amplitude, lambda),\n segmentsForSine(sheet.width, o.amplitude * 0.6 * o.irregular, lambda / 1.7),\n )\n },\n // Across the width, always. `pinnedEdge` picks which end of the DROP the\n // folds grow from; it never turns the folds themselves, which run with\n // the drop and therefore vary across `uv.x`.\n axis: () => 0,\n },\n displace(out, uv, o) {\n if (o.amplitude === 0) return\n // Distance from the pinned edge, 0 at the fixing and 1 at the free end.\n const drop = o.pinnedEdge === 'top' ? 1 - uv.y : uv.y\n const depth = drop ** o.falloff\n const u = uv.x * TAU * o.folds\n const fold = Math.sin(u) + o.irregular * 0.6 * Math.sin(u * 1.7 + 2.1)\n out.z += o.amplitude * depth * fold\n const pinch = o.gather * depth * Math.min(o.amplitude * o.folds * 0.8, 0.6)\n out.x *= 1 - pinch\n },\n glsl: {\n chunk: /* glsl */ `\nvoid FN(inout vec3 p, vec2 uv, float t) {\n if (U_amplitude == 0.0) return;\n float drop = U_pin == 1.0 ? 1.0 - uv.y : uv.y;\n float depth = pow(drop, U_falloff);\n float u = uv.x * 6.283185307179586 * U_folds;\n float fold = sin(u) + U_irregular * 0.6 * sin(u * 1.7 + 2.1);\n p.z += U_amplitude * depth * fold;\n float pinch = U_gather * depth * min(U_amplitude * U_folds * 0.8, 0.6);\n p.x *= 1.0 - pinch;\n}\n`,\n strength: 'amplitude',\n uniforms: (o) => ({\n amplitude: o.amplitude,\n folds: o.folds,\n falloff: o.falloff,\n irregular: o.irregular,\n gather: o.gather,\n pin: o.pinnedEdge === 'top' ? 1 : 2,\n }),\n },\n}\n","import { z } from 'zod'\nimport type { Deformer } from './types'\n\nexport const crumpleOptionsSchema = z.object({\n /** How crushed, 0..1. Peak-to-peak height, and it drives the pull too. */\n amount: z.number().min(0).max(1).default(0.35),\n /** Facets per world unit. Higher is finer, and needs more segments to resolve. */\n scale: z.number().min(0.5).max(8).default(3),\n /**\n * How much the sheet draws in on itself. Crumpled paper occupies a smaller\n * footprint than flat paper; without this it reads as an embossed sheet\n * rather than a crushed one.\n */\n pull: z.number().min(0).max(1).default(0.4),\n /** A different crush of the same paper. */\n seed: z.number().int().min(0).max(7).default(0),\n})\n\nexport type CrumpleOptions = z.infer<typeof crumpleOptionsSchema>\n\n/**\n * GLSL's `mod`, which is not JS's `%`.\n *\n * `%` keeps the sign of the dividend, so a cell at a negative coordinate\n * hashes to a different bucket on the two paths — and the sheet is centred on\n * the origin, so HALF of every sheet is at a negative coordinate. Mirroring\n * `x - y·floor(x/y)` is the whole reason the two halves agree.\n */\nfunction mod(x: number, y: number): number {\n return x - y * Math.floor(x / y)\n}\n\n/**\n * Where the feature point of a cell sits, 0..1 within it.\n *\n * Deliberately integer arithmetic on small numbers rather than the usual\n * `fract(sin(dot(…)) * 43758.5)` hash: that one takes the sine of a large\n * argument and multiplies the result by forty thousand, which turns a\n * last-bit difference between a CPU and a GPU into a completely different\n * number. Every product here stays under 2^13, which is exact in float32 and\n * in a double alike, so the two implementations land on the same point rather\n * than on nearby ones. The pattern repeats every 64 cells — far outside any\n * sheet you would put on screen.\n */\nfunction jitter(cx: number, cy: number, seed: number): [number, number] {\n const hx = mod(cx * 37 + cy * 17 + seed * 5, 64)\n const hy = mod(cx * 23 + cy * 41 + seed * 11, 64)\n return [0.2 + (0.6 * mod(hx * 13, 7)) / 6, 0.2 + (0.6 * mod(hy * 29, 11)) / 10]\n}\n\n/**\n * `F2 − F1` tops out at 0.9315 of a cell on this jitter (measured across\n * every seed and the whole `scale` range), so this brings the field back to\n * ±amount/2 — `amount` is then a peak-to-peak height you can reason about\n * rather than an arbitrary knob. `crumple.test.ts` holds the bound.\n */\nconst NORM = 0.5366\n\n/** Which way a cell's facet is pushed — half up, half down. */\nfunction cellSign(cx: number, cy: number, seed: number): number {\n return 1 - 2 * mod(cx * 11 + cy * 7 + seed * 3, 2)\n}\n\n/**\n * Paper that has been handled.\n *\n * Six deformers and not one of them crushed a sheet — `wave` and `fold` were\n * the nearest and neither reads as crumpled. This is the missing primitive.\n *\n * The field is a jittered grid of cells, each pushed up or down, with the\n * height going to zero exactly on the boundary between them: `F2 − F1`, the\n * gap between the two nearest cell points, signed per cell. That vanishes on\n * every boundary, so the sheet stays continuous, and its gradient flips\n * across one — which is a crease. The result is an irregular polygonal\n * network of facets alternating toward and away from you, which is what a\n * sheet crushed in a fist actually is.\n *\n * **The normals matter more than the displacement here**, and getting there\n * took three tries worth recording. Three summed triangle waves: periodic,\n * an egg-crate. Plain distance-to-nearest (`F1`): irregular but smooth cone\n * tips, so it read as hammered metal. Only creases with a sign change across\n * them shade like paper.\n *\n * Both normal paths agree with that: the hero path averages vertex normals\n * over a dense grid, the field path probes two tangents a hundredth of a\n * sheet apart. Both need facets several segments wide.\n *\n * Cost, measured rather than assumed (`pnpm perf:field --soft`): a field of\n * these runs about four times longer per frame at ×20, and six at ×60, than\n * the same field of an undeformed preset. That ratio used to read 45%, and it\n * grew without this deformer getting one instruction slower — `'auto'` now\n * sizes the grid to the work, so the undeformed sheet it is measured against\n * went from 72 segments a side to 8 and got very cheap, while crumple keeps\n * the density its creases need. Which makes the point sharper than before:\n * almost none of this cost is geometry. It is the nine cell lookups per\n * probe, three probes deep for the normal.\n */\nexport const crumple: Deformer<CrumpleOptions> = {\n id: 'crumple',\n label: 'Crumple',\n defaults: crumpleOptionsSchema.parse({}),\n optionsSchema: crumpleOptionsSchema,\n // A crease the grid cannot resolve is a smooth bump, and a sheet of smooth\n // bumps is not a crumple. Measured (`pnpm perf:field`), the real cost of\n // this deformer is not geometry at all: it is nine cell evaluations per\n // probe and three probes per vertex for the normal.\n //\n // No `autoSegments` here, and that is the honest answer rather than an\n // omission. Every other deformer approximates a smooth surface, so its\n // density falls out of a radius; a crumple's creases are where the gradient\n // is MEANT to break, so there is no sagitta to bound. What it wants is\n // segments per cell, and at the default `scale: 3` across a 1.4 span that\n // works out to the 72 this floor already asks for. So crumple is the one\n // deformer `'auto'` does not make cheaper — its floor was never the no-op\n // the others' were.\n geometry: { minSegments: 72 },\n displace(out, _uv, o) {\n if (o.amount === 0) return\n const qx = out.x * o.scale\n const qy = out.y * o.scale\n const gx = Math.floor(qx)\n const gy = Math.floor(qy)\n\n // Nearest and second-nearest cell point, and which cell won.\n let f1 = 1e9\n let f2 = 1e9\n let winX = gx\n let winY = gy\n for (let dy = -1; dy <= 1; dy++) {\n for (let dx = -1; dx <= 1; dx++) {\n const cx = gx + dx\n const cy = gy + dy\n const [jx, jy] = jitter(cx, cy, o.seed)\n const ex = cx + jx - qx\n const ey = cy + jy - qy\n const dist = Math.sqrt(ex * ex + ey * ey)\n if (dist < f1) {\n f2 = f1\n f1 = dist\n winX = cx\n winY = cy\n } else if (dist < f2) {\n f2 = dist\n }\n }\n }\n\n // Zero on every cell boundary, so the sheet never tears; the sign flips\n // as you cross one, which is what makes the boundary a crease.\n out.z += cellSign(winX, winY, o.seed) * (f2 - f1) * o.amount * NORM\n // Drawing in happens after the cell lookup reads the flat position, so\n // both implementations hash the same cell.\n const pull = 1 - o.amount * o.pull * 0.35\n out.x *= pull\n out.y *= pull\n },\n glsl: {\n chunk: /* glsl */ `\nvec2 FN_jitter(float cx, float cy, float seed) {\n float hx = mod(cx * 37.0 + cy * 17.0 + seed * 5.0, 64.0);\n float hy = mod(cx * 23.0 + cy * 41.0 + seed * 11.0, 64.0);\n return vec2(0.2 + 0.6 * mod(hx * 13.0, 7.0) / 6.0, 0.2 + 0.6 * mod(hy * 29.0, 11.0) / 10.0);\n}\n\nfloat FN_sign(float cx, float cy, float seed) {\n return 1.0 - 2.0 * mod(cx * 11.0 + cy * 7.0 + seed * 3.0, 2.0);\n}\n\nvoid FN(inout vec3 p, vec2 uv, float t) {\n if (U_amount == 0.0) return;\n vec2 flat2 = p.xy;\n vec2 q = flat2 * U_scale;\n vec2 g = floor(q);\n\n float f1 = 1e9;\n float f2 = 1e9;\n vec2 win = g;\n for (int dy = -1; dy <= 1; dy++) {\n for (int dx = -1; dx <= 1; dx++) {\n vec2 c = g + vec2(float(dx), float(dy));\n float dist = length(c + FN_jitter(c.x, c.y, U_seed) - q);\n if (dist < f1) { f2 = f1; f1 = dist; win = c; }\n else if (dist < f2) { f2 = dist; }\n }\n }\n\n p.z += FN_sign(win.x, win.y, U_seed) * (f2 - f1) * U_amount * ${NORM};\n float pull = 1.0 - U_amount * U_pull * 0.35;\n p.xy = flat2 * pull;\n}\n`,\n // `amount` drives both the height and the pull, so a field instance's\n // bias scales the whole crush rather than half of it.\n strength: 'amount',\n uniforms: (o) => ({ amount: o.amount, scale: o.scale, pull: o.pull, seed: o.seed }),\n },\n}\n","import type { CreaseConfig } from '../config/schema'\nimport type { FoldOptions } from './fold'\nimport type { DeformerInstance } from './types'\n\n/**\n * Paper memory: the sheet keeps what has been done to it.\n *\n * Every deformer is a pure function of its options — a sheet folded to 180°\n * and back to 0° flows through the stack and comes out pristine. That is\n * correct for cloth and wrong for paper, which is PLASTIC: the fibres break\n * along the fold and the crease outlives it.\n *\n * The fix lives here rather than inside the deformers, and deliberately.\n * Deformer purity is load-bearing — it is what gives the GLSL twins\n * something to be identical to, what lets the field scale one instance's\n * bend by a per-sheet bias, and what `test:parity` checks. So memory sits\n * ABOVE the stack: it watches the stack the behavior built, and it rewrites\n * that stack before it runs. Nothing below this file knows it exists.\n *\n * The whole layer is hero-path only. The field composes one GLSL program for\n * every sheet in an instanced draw call, and a crease is per-sheet state —\n * so a field of a hundred papers cannot carry a hundred crease sets without\n * per-instance attributes that don't exist yet. `applyMemory` is called from\n * `PaperMesh` and from nowhere in `field/`.\n */\n\n/**\n * What a paper at `takesSet: 1` keeps of a fold, as a fraction of the angle\n * it was folded to.\n *\n * Kraft folded flat (180°) comes to rest around 30° open, which is `180 ×\n * 0.85 × 0.2`. Keeping this multiplier here rather than folding it into the\n * stock values is what lets `memory.set` and `Stock.takesSet` both be honest\n * 0..1 knobs that use their whole range, instead of designer-facing sliders\n * that do everything interesting in their bottom fifth.\n */\nexport const MAX_SET = 0.2\n\n/**\n * Hinge width of a remembered crease, world units.\n *\n * Sharper than `fold`'s own 0.04 default, because a crease is not a fold: a\n * fold bends fibres that are pushing back, a crease is the line where they\n * already gave up. It is a constant rather than a schema field because it is\n * a property of broken paper and not a thing anyone tunes — `depth` is the\n * knob, and a second one here would only ever be set wrong.\n */\nexport const CREASE_RADIUS = 0.03\n\n/**\n * How far a fold has to CLOSE, from however open it last was and at a line\n * that stays put, before it leaves a crease. Degrees.\n *\n * This is the rule that separates the two things `fold` is used for, and it\n * has to, because they are the same deformer. A crease is made by the ACT of\n * folding: the angle closes while the line is held. `unroll`'s landing hinge\n * is a fold instance that sits at exactly 90° forever while its line travels\n * down the sheet (a fixed floor is a moving line in sheet coordinates) —\n * paper coming off a roll and turning at the floor is BENT, not creased, and\n * a trail of creases left behind it would be the obvious bug. Measuring the\n * closing rather than the angle gets both right, and gets them right without\n * asking a behavior to declare anything about its own folds.\n */\nexport const CREASE_MIN_GROWTH = 45\n\n/** How far a crease line may drift and still be the same crease. World units. */\nexport const CREASE_DRIFT = 0.02\n\n/** And in degrees, for the travel direction. */\nexport const CREASE_DRIFT_ANGLE = 2\n\n/** Below this the crease is neither visible nor worth a slot. Degrees. */\nexport const MIN_DEPTH = 1\n\n/** What the crease shader carries, and so what memory may record. */\nexport const MAX_CREASES = 4\n\n/**\n * A crease line in canonical form, for identity only.\n *\n * `(angle, offset)` and `(angle + 180, -offset)` name the same line through\n * the sheet — they differ in which half `fold` treats as the flap, not in\n * where the crease is. `letter-fold` uses exactly that pair (270 at +h/6 and\n * 90 at +h/6) and they are two DIFFERENT lines; folding both into a half-turn\n * range is what keeps them apart, and what stops a residual fold being\n * stacked on top of a live one that is already there.\n */\nfunction canonicalLine(angle: number, offset: number): [number, number] {\n let a = ((angle % 360) + 360) % 360\n let o = offset\n if (a >= 180) {\n a -= 180\n o = -o\n }\n return [a, o]\n}\n\n/** Whether two folds/creases describe the same physical line on the sheet. */\nexport function sameLine(\n a: { angle: number; offset: number },\n b: { angle: number; offset: number },\n): boolean {\n const [aa, ao] = canonicalLine(a.angle, a.offset)\n const [ba, bo] = canonicalLine(b.angle, b.offset)\n // Near 0/180 the canonical angle wraps, so compare the way an angle has to be.\n const d = Math.abs(aa - ba)\n const angleClose = Math.min(d, 180 - d) <= CREASE_DRIFT_ANGLE\n return angleClose && Math.abs(ao - bo) <= CREASE_DRIFT\n}\n\n/**\n * Fold a sheet's remembered creases into the stack that is about to run.\n *\n * A crease is a FLOOR on the fold at its line, never an addition. Where the\n * behavior is already folding that line further, the crease is invisible and\n * contributes nothing; as the behavior lets go, the fold angle falls to the\n * crease's depth and stops there. That is what makes the crease appear on\n * the way back out of a fold without anything having to detect the release —\n * and it is why the residual is written INTO the live instance rather than\n * added beside it. Two folds on one line would not be a deeper crease, they\n * would be two creases a hair apart, and `fold` does not commute.\n *\n * Creases with no live fold on their line are prepended: a sheet that is\n * already creased is creased BEFORE the behavior gets hold of it, so the\n * behavior bends a creased sheet rather than the crease bending a bent one.\n */\nexport function applyMemory(stack: DeformerInstance[], creases: CreaseConfig[]): DeformerInstance[] {\n if (creases.length === 0) return stack\n\n let out = stack\n const loose: CreaseConfig[] = []\n\n for (const crease of creases) {\n if (Math.abs(crease.depth) < MIN_DEPTH) continue\n const index = out.findIndex(\n (i) => i.type === 'fold' && i.enabled !== false && sameLine(i.options as FoldOptions, crease),\n )\n if (index === -1) {\n loose.push(crease)\n continue\n }\n const live = out[index]!\n const options = live.options as FoldOptions\n if (Math.abs(options.foldAngle) >= Math.abs(crease.depth)) continue\n // Copy on first write — the stack a behavior returns is not ours to edit,\n // and on a resting sheet it is the same array every frame.\n if (out === stack) out = [...stack]\n out[index] = { ...live, options: { ...options, foldAngle: crease.depth } }\n }\n\n if (loose.length === 0) return out\n return [...loose.map(toFold), ...out]\n}\n\n/** A remembered crease as the deformer that draws it. */\nfunction toFold(crease: CreaseConfig): DeformerInstance {\n return {\n type: 'fold',\n options: {\n angle: crease.angle,\n offset: crease.offset,\n foldAngle: crease.depth,\n radius: CREASE_RADIUS,\n } satisfies FoldOptions,\n }\n}\n\ninterface Slot {\n angle: number\n offset: number\n /** The most OPEN this line has been — every closing is measured from here. */\n trough: number\n /** The largest closing it has made from a trough. */\n bestGrowth: number\n /** How far shut it was at the top of that closing — the crease's own angle. */\n bestPeak: number\n /** Which way it was folded, so the crease opens back the way it came. */\n sign: number\n}\n\n/**\n * Watches a running deformer stack and records the creases it leaves.\n *\n * One per sheet, driven from the frame loop. It is deliberately not a\n * reducer over config: recording has to happen at frame rate to catch the\n * peak of a fold, and routing sixty writes a second through React would cost\n * more than the whole rest of the feature. Instead this holds the live truth\n * and says when it has changed, and the host persists that at its own pace —\n * the same split `onBehaviorChange` already uses for handle drags.\n *\n * Slots are keyed by POSITION in the stack, which is the only stable identity\n * a fold has: a behavior's stack is a pure function of its options, so\n * `stack[1]` is the same fold from frame to frame, while its angle and offset\n * are exactly the things that may legitimately move.\n */\nexport class CreaseTracker {\n private slots = new Map<number, Slot>()\n private recorded: CreaseConfig[] = []\n private authored: CreaseConfig[] = []\n /** What `observe` last handed out, so an echo can be told from an edit. */\n private lastReported: CreaseConfig[] = []\n\n constructor(authored: CreaseConfig[] = []) {\n this.authored = authored\n }\n\n /**\n * Forget how the paper got here without forgetting the creases.\n *\n * Called when the stack is replaced wholesale (a new behavior, a new\n * sheet): the slots describe folds that no longer exist, but a crease is a\n * property of the paper and survives being put down and picked up.\n */\n reset(authored: CreaseConfig[] = this.creases): void {\n this.slots.clear()\n this.recorded = []\n this.authored = authored\n }\n\n /**\n * Take on a crease set that came from outside, and work out which kind of\n * outside it was — because the two kinds want opposite things.\n *\n * It is USUALLY this tracker's own recording coming back, a frame or two\n * after `onCrease` handed it to the host. Then the slots must survive: the\n * fold that made the crease is very likely still closing, and resetting\n * its peak on the host's echo would stall the crease halfway into the\n * fold that was making it.\n *\n * But it can also be somebody EDITING the paper — a depth dragged down in\n * a panel, a shared link opened, a state's overrides settling. Then the\n * slots are the wrong story to keep. `merge` takes the deeper of two\n * creases on a line, so a recording of 20° would quietly outvote a human\n * asking for 5° and the slider would appear not to work; and it would go\n * on outvoting it, because the fold that recorded the 20 is still sitting\n * in a slot. An edit means the paper is what it is now, and the next\n * crease has to be earned by folding it again.\n *\n * The two are told apart by what we last reported. Anything else is an\n * edit, which is the safe way round: mistaking an echo for an edit costs\n * a crease that gets re-recorded on the next fold, while mistaking an edit\n * for an echo costs a control that does not work.\n */\n adopt(creases: CreaseConfig[]): void {\n if (!same(creases, this.lastReported)) this.slots.clear()\n this.authored = creases\n this.recorded = []\n }\n\n /** Everything the sheet currently carries, authored and recorded merged. */\n get creases(): CreaseConfig[] {\n return merge(this.authored, this.recorded)\n }\n\n /**\n * Take one frame's reading. Returns true when the crease set changed by\n * enough to be worth telling anyone about.\n */\n observe(stack: DeformerInstance[], set: number): boolean {\n if (set <= 0) return false\n\n for (let i = 0; i < stack.length; i++) {\n const instance = stack[i]!\n if (instance.type !== 'fold' || instance.enabled === false) continue\n const o = instance.options as FoldOptions\n const magnitude = Math.abs(o.foldAngle)\n const slot = this.slots.get(i)\n\n // A fold we have not seen, or one whose line has travelled out from\n // under itself. Either way the paper it is bending now is not the paper\n // it was bending, so counting starts again from where it is.\n //\n // The comparison is against where the line SETTLED, never against last\n // frame — absorbing drift a frame at a time would let a slowly\n // travelling hinge creep the length of the sheet without ever tripping\n // the tolerance it exists to trip.\n if (\n !slot ||\n Math.abs(slot.angle - o.angle) > CREASE_DRIFT_ANGLE ||\n Math.abs(slot.offset - o.offset) > CREASE_DRIFT\n ) {\n this.slots.set(i, {\n angle: o.angle,\n offset: o.offset,\n trough: magnitude,\n bestGrowth: 0,\n bestPeak: magnitude,\n sign: o.foldAngle < 0 ? -1 : 1,\n })\n continue\n }\n\n // The crease is the biggest CLOSING this line has made, measured from\n // however open it last was — not from wherever we happened to start\n // watching. A letter that arrives folded and is opened has closed\n // nothing, and creases nothing; open it and fold it again and the same\n // line has now made the whole travel, and creases. Both readings fall\n // out of a running minimum and nothing else.\n if (magnitude < slot.trough) slot.trough = magnitude\n const growth = magnitude - slot.trough\n if (growth > slot.bestGrowth) {\n slot.bestGrowth = growth\n slot.bestPeak = magnitude\n slot.sign = o.foldAngle < 0 ? -1 : 1\n }\n }\n\n const next: CreaseConfig[] = []\n for (const slot of this.slots.values()) {\n if (slot.bestGrowth < CREASE_MIN_GROWTH) continue\n const depth = slot.sign * slot.bestPeak * set * MAX_SET\n if (Math.abs(depth) < MIN_DEPTH) continue\n next.push({ angle: slot.angle, offset: slot.offset, depth })\n }\n\n if (same(next, this.recorded)) return false\n this.recorded = next\n this.lastReported = this.creases\n return true\n }\n}\n\n/**\n * Merge two crease sets, deepest wins per line, capped at what the shader\n * carries.\n *\n * Recorded creases meet authored ones on the same line whenever a preset\n * ships pre-creased and then gets folded along its own crease — and the\n * answer there is the deeper of the two, not their sum: folding a creased\n * sheet along its crease does not double the crease, it just re-makes it.\n */\nfunction merge(authored: CreaseConfig[], recorded: CreaseConfig[]): CreaseConfig[] {\n const out: CreaseConfig[] = []\n for (const crease of [...recorded, ...authored]) {\n const existing = out.find((c) => sameLine(c, crease))\n if (!existing) {\n // Copied, not shared. The deeper-wins line below WRITES to whatever is\n // in `out`, and pushing the argument by reference pointed that write\n // straight back into `this.recorded` — so reading the merged view\n // rewrote the depth that had just been recorded, the next frame saw a\n // change that was nothing but its own echo, and the tracker reported\n // one every frame for as long as an authored crease sat deeper than\n // the fold could make it.\n out.push({ ...crease })\n continue\n }\n if (Math.abs(crease.depth) > Math.abs(existing.depth)) existing.depth = crease.depth\n }\n // Over the cap, the deepest creases are the ones anyone would miss.\n if (out.length > MAX_CREASES) {\n out.sort((a, b) => Math.abs(b.depth) - Math.abs(a.depth))\n out.length = MAX_CREASES\n }\n return out\n}\n\n/** Whether two crease sets are the same to within a degree of depth. */\nfunction same(a: CreaseConfig[], b: CreaseConfig[]): boolean {\n if (a.length !== b.length) return false\n return a.every((crease, i) => {\n const other = b[i]!\n return sameLine(crease, other) && Math.abs(crease.depth - other.depth) < 0.5\n })\n}\n","import type { CreaseConfig, SurfaceConfig } from '../config/schema'\nimport { spanAlong } from '../core/tessellation'\nimport { MAX_SET } from '../deformers/memory'\n\n/** How many crease lines the shader carries. */\nconst MAX_SHADED = 4\n\n/**\n * One crease in the terms the crease shader wants — which are the terms\n * {@link CreaseConfig} and the `fold` deformer already use, and no longer a\n * translation of them.\n *\n * That is the whole point of this shape now. The shader used to be handed a\n * LINE direction and a 0..1 fraction across the sheet, so a remembered crease\n * had to be converted on the way in and the shader had to re-derive a\n * direction on the way out. Both conversions divided the sheet's own aspect\n * out, which is exact for a crease square to an edge and wrong for every\n * other one: a line scored at 45° across a 1.2 × 1.5 sheet came out at 51°.\n * Nobody noticed while creases only ever arrived from the built-in folds,\n * which are all axis-aligned. A fingertip scores them at any angle at all.\n *\n * So the shader now measures in the sheet's own local space, with the same\n * `dot(p.xy, dir) - offset` that `fold` displaces by, and the two cannot\n * disagree about where a line is because they are computing the same number.\n */\nexport interface CreaseShading {\n /** Direction the fold TRAVELS, degrees. The crease line runs across it. */\n angle: number\n /** Signed distance from the sheet's centre along `angle`, in world units. */\n offset: number\n /**\n * How hard it reads, −1..1, SIGNED: positive draws a ridge and negative a\n * groove.\n *\n * A fold toward the camera leaves paper that is concave from the front,\n * which is a valley — so a positive `depth` becomes a negative strength,\n * and the same crease seen from behind reads as the ridge it is. Unsigned\n * strength is why every crease used to render as the same grey smudge\n * whichever way the paper had been folded.\n */\n strength: number\n}\n\n/**\n * Everything that should draw as a crease line, from the two places creases\n * come from.\n *\n * `surface.creaseLines` is authored SHADING: a designer saying \"put fold\n * marks here\", with no geometry behind it. `memory.creases` is what the paper\n * has actually been folded along, and it bends the sheet as well as marking\n * it. They coexist because they answer different questions, and the authored\n * ones come first so that a hand-placed mark is never the one dropped at the\n * cap.\n *\n * The authored ones are the only ones converted, because they are the only\n * ones authored in a different language: `creaseLines` places lines as\n * fractions across the sheet, which is the right thing to type by hand and\n * the wrong thing to shade with.\n */\nexport function resolveCreases(\n surface: SurfaceConfig,\n creases: CreaseConfig[],\n sheet: { width: number; height: number },\n): CreaseShading[] {\n const out: CreaseShading[] = []\n\n const lines = surface.creaseLines\n if (lines) {\n // `creaseLines.angle` is the direction of the LINE; everything downstream\n // speaks in the direction the fold travels, which is across it.\n const angle = lines.angle + 90\n const span = spanAlong(sheet, angle)\n for (const position of lines.positions) {\n out.push({ angle, offset: (position - 0.5) * span, strength: lines.strength })\n }\n }\n\n for (const crease of creases) {\n out.push(creaseShading(crease))\n }\n\n if (out.length > MAX_SHADED) out.length = MAX_SHADED\n return out\n}\n\n/**\n * A remembered crease as the fragment shader draws it — which is now the same\n * crease, with only its depth reinterpreted.\n *\n * A crease reads hardest around a right angle and then saturates: a sheet\n * folded flat and reopened is not four times the mark of one folded to 45°,\n * it is a slightly harder version of the same line. The divisor is the depth\n * a 90° fold leaves in paper that remembers everything — read off\n * {@link MAX_SET} rather than written out, so retuning how much paper keeps\n * cannot leave the shading calibrated against the old answer.\n *\n * The sign survives: see {@link CreaseShading.strength}.\n */\nexport function creaseShading(crease: CreaseConfig): CreaseShading {\n return {\n angle: crease.angle,\n offset: crease.offset,\n strength: Math.max(-1, Math.min(1, -crease.depth / (90 * MAX_SET))),\n }\n}\n","import type { AnyOptions } from '../deformers/types'\nimport type { Behavior } from './types'\nimport { peel } from './peel'\nimport { unroll } from './unroll'\nimport { flip } from './flip'\nimport { letterFold } from './letter-fold'\nimport { hang } from './hang'\nimport { fly } from './fly'\nimport { fall } from './fall'\nimport { carry } from './carry'\nimport { flight } from './flight'\nimport { crumpleBehavior } from './crumple'\nimport { settle } from './settle'\nimport { ribbon } from './ribbon'\n\nconst registry = new Map<string, Behavior<AnyOptions>>()\n\n/** Community behaviors register here; built-ins are pre-registered. */\nexport function registerBehavior(behavior: Behavior<AnyOptions>): void {\n registry.set(behavior.id, behavior)\n}\n\nexport function getBehavior(id: string): Behavior<AnyOptions> {\n const b = registry.get(id)\n if (!b) {\n throw new Error(`[paperlab] Unknown behavior \"${id}\". Registered: ${[...registry.keys()].join(', ')}`)\n }\n return b\n}\n\nexport function listBehaviors(): string[] {\n return [...registry.keys()]\n}\n\nregisterBehavior(peel)\nregisterBehavior(unroll)\nregisterBehavior(flip)\nregisterBehavior(letterFold)\nregisterBehavior(hang)\nregisterBehavior(fly)\nregisterBehavior(fall)\nregisterBehavior(carry)\nregisterBehavior(flight)\nregisterBehavior(crumpleBehavior)\nregisterBehavior(settle)\nregisterBehavior(ribbon)\n","import type { DeformerInstance } from '../deformers/types'\n\nexport const idleNames = ['float', 'tumble', 'dangle', 'taped', 'breeze'] as const\nexport type IdleName = (typeof idleNames)[number]\n\nexport interface IdlePose {\n /** Offsets added to the paper's base transform each frame. */\n position: [number, number, number]\n rotation: [number, number, number]\n}\n\n/**\n * Curated fake physics: hand-tuned motion presets, no simulation. Cheap\n * enough for both hero and field modes, and — for things like the\n * falling-leaf tumble — they read *more* real than a true sim.\n */\nexport interface IdlePreset {\n id: IdleName\n label: string\n /** Whole-sheet motion, written into `pose` (allocation-free). */\n transform?(t: number, pose: IdlePose): void\n /** Extra deformers appended after the behavior's stack. */\n stack?(): DeformerInstance[]\n}\n\nexport const idlePresets: Record<IdleName, IdlePreset> = {\n float: {\n id: 'float',\n label: 'Float',\n transform(t, pose) {\n pose.position[1] = Math.sin(t * 0.9) * 0.05\n pose.rotation[1] = Math.sin(t * 0.31) * 0.16\n pose.rotation[2] = Math.sin(t * 0.23 + 1.2) * 0.05\n },\n },\n tumble: {\n id: 'tumble',\n label: 'Tumble',\n transform(t, pose) {\n // Falling-leaf: velocity-linked lift bob + curated wobble.\n pose.rotation[0] = Math.sin(t * 0.5 + 1) * 0.6\n pose.rotation[2] = Math.sin(t * 0.7) * 0.5\n pose.position[1] = Math.sin(t * 1.4) * 0.07\n pose.position[0] = Math.sin(t * 0.35) * 0.14\n },\n stack: () => [\n {\n type: 'wave',\n options: { amplitude: 0.02, wavelength: 0.9, speed: 0.9, angle: 25, pinnedEdge: 'none' },\n },\n ],\n },\n dangle: {\n id: 'dangle',\n label: 'Dangle',\n transform(t, pose) {\n // A hung tail's pendulum sway.\n pose.rotation[2] = Math.sin(t * 1.5) * 0.06\n pose.rotation[0] = Math.sin(t * 1.1 + 0.7) * 0.03\n },\n },\n taped: {\n id: 'taped',\n label: 'Taped',\n // Taped at the top of a wall: the free bottom edge breathes.\n stack: () => [\n {\n type: 'wave',\n options: { amplitude: 0.025, wavelength: 1.2, speed: 0.45, angle: 90, pinnedEdge: 'top' },\n },\n ],\n },\n breeze: {\n id: 'breeze',\n label: 'Breeze',\n stack: () => [\n {\n type: 'wave',\n options: { amplitude: 0.035, wavelength: 0.5, speed: 1.0, angle: 20, pinnedEdge: 'none' },\n },\n ],\n },\n}\n\nexport function getIdlePreset(name: IdleName): IdlePreset {\n return idlePresets[name]\n}\n","export type PinMode = 'top-edge' | 'top-corners' | 'corner' | 'none'\n\nexport interface ClothParams {\n /** Bend-spring strength: 1 = crisp paper, 0 = silk. Fabric mode falls out for free. */\n stiffness: number\n gravity: number\n wind: number\n /** Local-space y of the ground plane; particles settle onto it. */\n floor: number\n}\n\nconst FIXED_DT = 1 / 120\nconst SOLVER_ITERATIONS = 5\n\n/**\n * How much of the wind reaches a sheet turned edge-on to it.\n *\n * Zero would be the textbook answer and the wrong one: a sheet hanging exactly\n * along the wind would then hang perfectly still forever, because the one\n * thing that could break the symmetry is the wind it is not feeling. Real air\n * is turbulent and finds it. Small enough that a sheet still visibly turns its\n * face to the wind, large enough that it never stalls.\n */\nconst AERO_TURBULENCE = 0.15\n\n/**\n * How much of the sheet a hand takes hold of, in world units.\n *\n * A grab used to move exactly ONE particle, which is a pin and not a pinch:\n * the sheet came to a point under the cursor and the rest of it hung off that\n * singularity, which is the look every cheap cloth demo has. Fingers hold a\n * patch about a centimetre across, and against a sheet whose width is one\n * world unit — call it A4 — that is about 0.05.\n *\n * Clamped at both ends where it is used. Below a cell and a half it collapses\n * back to the single particle it is replacing however fine the grid is; above\n * a fifth of the sheet a hand would be holding most of a small one.\n */\nconst GRAB_RADIUS = 0.05\n\nconst SLEEP_EPSILON = 1e-6\nconst SLEEP_FRAMES = 45\n\n/**\n * How the hold falls off across that patch: 1 at the centre, 0 at the rim.\n *\n * Not a hard patch. Pinning a disc of particles rigidly is as wrong as pinning\n * one, in the other direction — the sheet gets a stiff coin in the middle of\n * it that gravity cannot bend. A falloff means the centre is held, the rim is\n * free, and everything between is partly both, which is what the pad of a\n * finger actually does to paper.\n *\n * Smoothstep rather than linear so the weight arrives at the rim with zero\n * slope; a kink in the weight is a visible crease in the drape.\n */\nfunction grabFalloff(distance: number, radius: number): number {\n const t = Math.min(1, Math.max(0, distance / radius))\n const s = 1 - t\n return s * s * (3 - 2 * s)\n}\n\n/**\n * Verlet mass-spring grid on the sheet's own vertices — structural + shear +\n * bend springs, pins as the interface, wind as a force field, fixed timestep\n * with substeps, sleep when kinetic energy is negligible.\n *\n * Cloth solves the particles and hands them on: `PaperMesh` runs the deformer\n * stack over `positions`, so a behavior composes with the sim rather than\n * replacing it (pinned by `cloth-hosts-a-shape.test.ts`). Only the STRIP owns\n * its vertices outright — its rows are chain nodes, not the sheet's grid.\n * Pure JS, no three dependency.\n */\nexport class ClothSim {\n readonly cols: number\n readonly rows: number\n readonly count: number\n /** The sheet this grid was laid out on. Read by {@link adopt}. */\n readonly width: number\n readonly height: number\n readonly positions: Float32Array\n private readonly prev: Float32Array\n private readonly pinned: Uint8Array\n private readonly pinTargets: Float32Array\n /**\n * The constraints, one typed array per field rather than one object each.\n *\n * Because the effects layer has to vary them across the sheet, and an\n * object with a fixed `rest` cannot be varied cheaply. Paper that chars\n * SHRINKS — that is what curls it toward the flame, not softening — which\n * is a shorter rest length on exactly the constraints the heat reached.\n * Burnt-through paper has to stop pulling on what is left, which is a\n * broken flag. A wet corner is floppier than the dry sheet above it, which\n * is a per-constraint stiffness. None of that is in this file; this file\n * only makes it possible, and at the defaults below the solve is\n * bit-identical to the object version it replaces.\n */\n readonly constraintCount: number\n readonly constraintA: Uint32Array\n readonly constraintB: Uint32Array\n /** 0 = structural, 1 = shear, 2 = bend (scaled by `stiffness` at solve time). */\n readonly constraintKind: Uint8Array\n /**\n * The length each constraint is laid out at. Never changes; the reference\n * to shrink from.\n *\n * Float64, not Float32, and that is measured rather than cautious: with\n * single-precision rest lengths every one of them rounded, and the first\n * typed-array version of this solve disagreed with the object version it\n * replaced in 476–711 of 714 coordinates after five seconds. The object\n * version held a JS number, which is a double.\n */\n readonly naturalLength: Float64Array\n /** The length it pulls toward now. `naturalLength` until something shrinks or stretches it. */\n readonly restLength: Float64Array\n /** A multiplier on the constraint's own strength. 1 is the paper as built. */\n readonly constraintStiffness: Float64Array\n /** Non-zero where the paper between two particles is gone. Skipped by the solve. */\n readonly broken: Uint8Array\n /**\n * How easily each particle is moved, 0..1: one over its mass, relative to\n * dry paper.\n *\n * Mass matters in exactly two places here, and both are wired, because a\n * \"heavier\" that touched neither would be another knob that does nothing.\n * Gravity is an acceleration, so weight alone does not make wet paper fall\n * differently. What does: the air pushes a heavy particle less (the aero\n * term is divided by mass), and the constraint solve moves a heavy particle\n * less than a light one it is tied to. Zero is infinite mass: static, moved by nothing — not the air, not the solve, and not gravity either.\n */\n readonly invMass: Float32Array\n /**\n * How far the middle of each BEND spring sits off the line between its ends\n * when relaxed, along the sheet's normal — a signed rest curvature, as a\n * sagitta in world units. Ignored on every other kind of constraint.\n *\n * Positive curls the paper toward its FRONT, the face a flat sheet turns to\n * +z — which puts the middle of each span that far BEHIND its ends. Paper\n * curling toward you is hollow on the side you see; the first cut of this\n * had the middle in front, which is a dome, and a dome's rim goes the other\n * way.\n *\n * The only lever here with a sign, and the sign is why it exists. A bend\n * spring is a distance, and a distance cannot tell paper curled toward you\n * from paper curled away: shorten it and the sheet buckles, but which way\n * is a coin toss, and gravity can flip it through later. Measured on the\n * first version, which pushed hot paper toward the front along its normal\n * and left the char to hold it — the curl held while the heat did and\n * snapped through to the BACK the moment the front had passed. Charred\n * paper stays curled toward the side that burnt because that side shrank\n * more: a curvature built into the material, which is what this is.\n *\n * Solved as a couple — the middle moves one way, the two ends half as far\n * the other — so it bends the sheet and never pushes it anywhere. A push\n * cannot do this job: it moves paper, and a uniformly curled sheet in still\n * air has no business going anywhere.\n */\n readonly restBend: Float64Array\n /** For each bend spring, the particle between its ends; -1 for every other kind. */\n readonly constraintMiddle: Int32Array\n private params: ClothParams\n private time = 0\n private accumulator = 0\n private stillFrames = 0\n private grabbedIndex = -1\n /**\n * A normal per particle, refreshed once a frame.\n *\n * The sim needs these for one thing only — how much wind each part of the\n * sheet is actually catching — and it needs its OWN rather than the mesh's,\n * because the mesh's are computed after the fact by the adapter and a\n * deformer may be running over the top of them by then. Once a frame rather\n * than once a substep: paper does not turn far in eight milliseconds, and\n * this is the only part of the step that is not a constraint solve.\n */\n private readonly normals: Float32Array\n /**\n * How hard each particle is held, 0..1. Zero for all but the handful under\n * a hand, so it doubles as the inverse mass the constraint solver wants:\n * a particle is as immovable as it is held.\n */\n private readonly grabWeights: Float32Array\n /** Just the held ones, so nothing iterates the whole sheet to find six. */\n private grabbed: number[] = []\n /** Each held particle's offset from the one under the cursor, at grab time. */\n private grabOffsets: Float32Array = new Float32Array(0)\n /** Where the hand was at the start of the last step, and how fast it moved. */\n private readonly grabAt = new Float32Array(3)\n private readonly grabWas = new Float32Array(3)\n private readonly grabVelocity = new Float32Array(3)\n /** True when the sim has settled and steps are skipped. */\n asleep = false\n\n constructor(cols: number, rows: number, width: number, height: number, pins: PinMode, params: ClothParams) {\n this.cols = cols\n this.rows = rows\n this.count = cols * rows\n this.width = width\n this.height = height\n this.params = { ...params }\n this.positions = new Float32Array(this.count * 3)\n this.prev = new Float32Array(this.count * 3)\n this.pinned = new Uint8Array(this.count)\n this.pinTargets = new Float32Array(this.count * 3)\n this.grabWeights = new Float32Array(this.count)\n this.normals = new Float32Array(this.count * 3)\n // Flat, facing the camera, until the first step measures otherwise.\n for (let i = 0; i < this.count; i++) this.normals[i * 3 + 2] = 1\n\n // Grid matches PlaneGeometry vertex order: row-major, top row first,\n // x left→right, y top→bottom (from +h/2 down).\n for (let r = 0; r < rows; r++) {\n for (let c = 0; c < cols; c++) {\n const i3 = (r * cols + c) * 3\n this.positions[i3] = (c / (cols - 1) - 0.5) * width\n this.positions[i3 + 1] = (0.5 - r / (rows - 1)) * height\n this.positions[i3 + 2] = 0\n }\n }\n this.prev.set(this.positions)\n\n const idx = (r: number, c: number) => r * cols + c\n const links: number[] = []\n const link = (a: number, b: number, kind: 0 | 1 | 2) => {\n links.push(a, b, kind)\n }\n for (let r = 0; r < rows; r++) {\n for (let c = 0; c < cols; c++) {\n if (c + 1 < cols) link(idx(r, c), idx(r, c + 1), 0)\n if (r + 1 < rows) link(idx(r, c), idx(r + 1, c), 0)\n if (c + 1 < cols && r + 1 < rows) {\n link(idx(r, c), idx(r + 1, c + 1), 1)\n link(idx(r, c + 1), idx(r + 1, c), 1)\n }\n if (c + 2 < cols) link(idx(r, c), idx(r, c + 2), 2)\n if (r + 2 < rows) link(idx(r, c), idx(r + 2, c), 2)\n }\n }\n\n const m = links.length / 3\n this.constraintCount = m\n this.constraintA = new Uint32Array(m)\n this.constraintB = new Uint32Array(m)\n this.constraintKind = new Uint8Array(m)\n this.naturalLength = new Float64Array(m)\n this.restLength = new Float64Array(m)\n this.constraintStiffness = new Float64Array(m).fill(1)\n this.broken = new Uint8Array(m)\n this.restBend = new Float64Array(m)\n this.constraintMiddle = new Int32Array(m).fill(-1)\n for (let k = 0; k < m; k++) {\n const a = links[k * 3]!\n const b = links[k * 3 + 1]!\n this.constraintA[k] = a\n this.constraintB[k] = b\n this.constraintKind[k] = links[k * 3 + 2]!\n // A bend spring runs two cells straight along a row or a column, so the\n // particle it bends around is the one halfway between, by index too.\n if (this.constraintKind[k] === 2) this.constraintMiddle[k] = (a + b) / 2\n const dx = this.positions[a * 3]! - this.positions[b * 3]!\n const dy = this.positions[a * 3 + 1]! - this.positions[b * 3 + 1]!\n const rest = Math.hypot(dx, dy)\n this.naturalLength[k] = rest\n this.restLength[k] = rest\n }\n this.invMass = new Float32Array(this.count).fill(1)\n\n // Pins hold their rest-pose position.\n const pin = (r: number, c: number) => {\n const i = idx(r, c)\n this.pinned[i] = 1\n this.pinTargets.set(this.positions.subarray(i * 3, i * 3 + 3), i * 3)\n }\n if (pins === 'top-edge') for (let c = 0; c < cols; c++) pin(0, c)\n if (pins === 'top-corners') {\n pin(0, 0)\n pin(0, cols - 1)\n }\n if (pins === 'corner') pin(0, 0)\n }\n\n /**\n * Carry a previous sim's drape across a rebuild.\n *\n * Sheet dimensions are a GEOMETRY dependency, so changing them builds a new\n * mesh and a new sim, and a new sim starts flat — which means a draped sheet\n * snaps rigid the instant it is resized. Nothing about the physics requires\n * that; it is only that nobody had carried the state over.\n *\n * What carries is the FREE particles, scaled by how much the sheet grew:\n * the constraints' rest lengths are laid out afresh at the new size, so\n * scaling the drape by the same ratio leaves every constraint exactly as\n * violated as it was and the sim simply continues. Pinned particles keep\n * the new layout's own rest positions instead — a pin holds a CORNER, and\n * the corner is where the resized sheet says it is.\n *\n * Refused in one case only: a different grid, because there is no\n * correspondence between the two sets of particles and the nearest thing to\n * one would be a guess. Everything else carries — a resize, a change of\n * pins, a deformer appearing on top. The sheet's state belongs to the sheet,\n * and none of those is a reason to have never fallen.\n *\n * That matters most for the one that is not a resize at all: a shape\n * arriving over a simulation rebuilds the mesh (the stack has its own\n * opinion about tessellation) without touching a single thing the physics\n * knows about. Resetting there would mean the sheet snapped flat the instant\n * you tried to fold the sheet you were holding, which is the whole point of\n * being able to.\n *\n * Returns whether it took.\n */\n adopt(previous: ClothSim | null | undefined): boolean {\n if (!previous || previous.cols !== this.cols || previous.rows !== this.rows) return false\n const sx = previous.width > 0 ? this.width / previous.width : 1\n const sy = previous.height > 0 ? this.height / previous.height : 1\n // Depth has no dimension of its own to scale by. The mean keeps a\n // uniform resize uniform, which is the case worth getting exactly right.\n const sz = (sx + sy) / 2\n for (let i = 0; i < this.count; i++) {\n if (this.pinned[i]) continue\n const i3 = i * 3\n this.positions[i3] = previous.positions[i3]! * sx\n this.positions[i3 + 1] = previous.positions[i3 + 1]! * sy\n this.positions[i3 + 2] = previous.positions[i3 + 2]! * sz\n // Velocity is the gap between the two, and verlet keeps it there. Carry\n // it too, or the sheet arrives at its new size perfectly still.\n this.prev[i3] = previous.prev[i3]! * sx\n this.prev[i3 + 1] = previous.prev[i3 + 1]! * sy\n this.prev[i3 + 2] = previous.prev[i3 + 2]! * sz\n }\n this.wake()\n return true\n }\n\n setParams(params: Partial<ClothParams>): void {\n // Called every frame while cloth renders — plain numeric compare, no JSON.\n let changed = false\n for (const key of ['stiffness', 'gravity', 'wind', 'floor'] as const) {\n const value = params[key]\n if (value !== undefined && value !== this.params[key]) {\n this.params[key] = value\n changed = true\n }\n }\n if (changed) this.wake()\n }\n\n wake(): void {\n this.asleep = false\n this.stillFrames = 0\n }\n\n /**\n * Take hold of the sheet at one particle.\n *\n * Separate from {@link grabNearest} because the particle a hand grabbed is\n * not always the particle nearest the point it touched: with a deformer\n * running over the simulation, what the pointer hit was a RENDERED vertex,\n * and the vertex it hit is the particle of the same index — the stack maps\n * a point to a point and never reorders them.\n *\n * What is taken hold of is a PATCH around that particle, not the particle\n * alone — see {@link GRAB_RADIUS}. The patch is measured across the GRID\n * rather than through space, because a hand holds a piece of the sheet and\n * keeps holding the same piece: measured through space, a fold that brought\n * a far corner near the fingers would silently add it to the grip.\n */\n grab(index: number): number {\n this.grabbedIndex = index >= 0 && index < this.count ? index : -1\n this.grabWeights.fill(0)\n this.grabbed = []\n if (this.grabbedIndex < 0) {\n this.grabOffsets = new Float32Array(0)\n this.wake()\n return -1\n }\n\n // Cell size on each axis, so the patch is round in the sheet's material\n // and not in its index space — the grid is only square when the sheet is.\n const cellX = this.cols > 1 ? this.width / (this.cols - 1) : this.width\n const cellY = this.rows > 1 ? this.height / (this.rows - 1) : this.height\n const cell = Math.max(cellX, cellY, 1e-6)\n const radius = Math.min(\n Math.max(GRAB_RADIUS, cell * 1.5),\n Math.max(cell, Math.min(this.width, this.height) * 0.2),\n )\n\n const centreRow = Math.floor(this.grabbedIndex / this.cols)\n const centreCol = this.grabbedIndex % this.cols\n const spanRows = Math.ceil(radius / cellY)\n const spanCols = Math.ceil(radius / cellX)\n const offsets: number[] = []\n const anchor = this.grabbedIndex * 3\n for (let r = centreRow - spanRows; r <= centreRow + spanRows; r++) {\n if (r < 0 || r >= this.rows) continue\n for (let c = centreCol - spanCols; c <= centreCol + spanCols; c++) {\n if (c < 0 || c >= this.cols) continue\n const i = r * this.cols + c\n // A pin is already held, and a particle with no mass to move is paper\n // that is not there — a pinch on a burnt-through hole closes on air.\n if (this.pinned[i] || this.invMass[i]! <= 0) continue\n const distance = Math.hypot((c - centreCol) * cellX, (r - centreRow) * cellY)\n const weight = i === this.grabbedIndex ? 1 : grabFalloff(distance, radius)\n if (weight <= 0) continue\n this.grabWeights[i] = weight\n this.grabbed.push(i)\n // Where this one sits relative to the fingers RIGHT NOW. The patch\n // travels rigidly: a pinch drags the paper, it does not iron it.\n const i3 = i * 3\n offsets.push(\n this.positions[i3]! - this.positions[anchor]!,\n this.positions[i3 + 1]! - this.positions[anchor + 1]!,\n this.positions[i3 + 2]! - this.positions[anchor + 2]!,\n )\n }\n }\n // A pinch that closed on nothing is not a grab, and must not report\n // itself as one: a hole wider than the patch, or a patch entirely pinned,\n // leaves no particle to hold. `grabNearest`'s callers read the return to\n // decide whether anything was caught (see `StripSim`'s, and the comment\n // on it), so saying yes here would be a grab that moves nothing and never\n // lets go.\n if (this.grabbed.length === 0) {\n this.grabbedIndex = -1\n this.grabOffsets = new Float32Array(0)\n this.wake()\n return -1\n }\n this.grabOffsets = Float32Array.from(offsets)\n this.grabAt.set(this.positions.subarray(anchor, anchor + 3))\n this.grabWas.set(this.grabAt)\n this.grabVelocity.fill(0)\n this.wake()\n return this.grabbedIndex\n }\n\n /** Nearest particle to a local-space point — the grab interface. */\n grabNearest(x: number, y: number, z: number): number {\n let best = -1\n let bestDist = Infinity\n for (let i = 0; i < this.count; i++) {\n const dx = this.positions[i * 3]! - x\n const dy = this.positions[i * 3 + 1]! - y\n const dz = this.positions[i * 3 + 2]! - z\n const d = dx * dx + dy * dy + dz * dz\n if (d < bestDist) {\n bestDist = d\n best = i\n }\n }\n return this.grab(best)\n }\n\n /** How hard one particle is being held, 0..1 — for tests and for the adapter. */\n grabWeightAt(index: number): number {\n return this.grabWeights[index] ?? 0\n }\n\n /** Where the fingers are now. The patch follows, each particle by its weight. */\n moveGrab(x: number, y: number, z: number): void {\n if (this.grabbedIndex < 0) return\n this.grabAt[0] = x\n this.grabAt[1] = y\n this.grabAt[2] = z\n this.wake()\n }\n\n /**\n * Let go — and let go at SPEED.\n *\n * This used to drop the paper dead. Every held particle had its previous\n * position overwritten with its current one on the way past, and in a verlet\n * integrator the gap between those two IS the velocity, so a sheet whipped\n * across the frame and released came to a perfect standstill and then fell\n * straight down. Whatever you did with your hand, the paper had never heard\n * of it.\n *\n * The hand's velocity is measured per second (see {@link step}) and spent\n * here, converted into the one-substep gap the integrator reads it back out\n * of. Measured per second rather than per frame because a frame is not a\n * fixed length and a substep is: throwing the same sheet at the same speed\n * must not depend on what the frame rate happened to be.\n */\n release(): void {\n for (const i of this.grabbed) {\n const i3 = i * 3\n const held = this.grabWeights[i]!\n this.prev[i3] = this.positions[i3]! - this.grabVelocity[0]! * FIXED_DT * held\n this.prev[i3 + 1] = this.positions[i3 + 1]! - this.grabVelocity[1]! * FIXED_DT * held\n this.prev[i3 + 2] = this.positions[i3 + 2]! - this.grabVelocity[2]! * FIXED_DT * held\n }\n this.grabbedIndex = -1\n this.grabbed = []\n this.grabWeights.fill(0)\n this.grabVelocity.fill(0)\n this.wake()\n }\n\n step(delta: number): void {\n if (this.asleep) return\n // How fast the hand is travelling, in world units a second. Measured here\n // and not in `moveGrab`, which has no clock and is called once per frame\n // at whatever rate the frames happen to arrive; `release` spends it.\n if (this.grabbedIndex >= 0 && delta > 0) {\n for (let axis = 0; axis < 3; axis++) {\n this.grabVelocity[axis] = (this.grabAt[axis]! - this.grabWas[axis]!) / delta\n }\n this.grabWas.set(this.grabAt)\n }\n this.updateNormals()\n this.accumulator = Math.min(this.accumulator + delta, FIXED_DT * 4)\n while (this.accumulator >= FIXED_DT) {\n this.substep(FIXED_DT)\n this.accumulator -= FIXED_DT\n }\n }\n\n /**\n * Which way each part of the sheet is facing, by central difference across\n * the grid.\n *\n * Clamped at the edges rather than wrapped or skipped: an edge particle\n * takes the one-sided difference, which is the same normal its neighbour\n * has, and an edge with no normal is an edge the wind cannot push.\n *\n * Which SIDE the normal points at is deliberately not worried about. The\n * force below is `n (n·v)`, a quadratic form, and that is unchanged by\n * flipping n — which is exactly right for paper, a surface with no front as\n * far as the air is concerned.\n */\n private updateNormals(): void {\n const p = this.positions\n const n = this.normals\n for (let r = 0; r < this.rows; r++) {\n for (let c = 0; c < this.cols; c++) {\n const left = (r * this.cols + (c > 0 ? c - 1 : c)) * 3\n const right = (r * this.cols + (c < this.cols - 1 ? c + 1 : c)) * 3\n const up = ((r > 0 ? r - 1 : r) * this.cols + c) * 3\n const down = ((r < this.rows - 1 ? r + 1 : r) * this.cols + c) * 3\n const ux = p[right]! - p[left]!\n const uy = p[right + 1]! - p[left + 1]!\n const uz = p[right + 2]! - p[left + 2]!\n // Row 0 is the top of the sheet, so this one runs down it.\n const vx = p[down]! - p[up]!\n const vy = p[down + 1]! - p[up + 1]!\n const vz = p[down + 2]! - p[up + 2]!\n const nx = vy * uz - vz * uy\n const ny = vz * ux - vx * uz\n const nz = vx * uy - vy * ux\n const length = Math.sqrt(nx * nx + ny * ny + nz * nz)\n const i3 = (r * this.cols + c) * 3\n if (length > 1e-12) {\n n[i3] = nx / length\n n[i3 + 1] = ny / length\n n[i3 + 2] = nz / length\n } else {\n // Degenerate: a pinched or fully collapsed patch. Leave the last\n // honest answer rather than inventing one.\n n[i3] = 0\n n[i3 + 1] = 0\n n[i3 + 2] = 0\n }\n }\n }\n }\n\n private substep(dt: number): void {\n const { gravity, wind, stiffness, floor } = this.params\n const p = this.positions\n const damping = 0.985\n const dt2 = dt * dt\n this.time += dt\n\n let maxTravel = 0\n for (let i = 0; i < this.count; i++) {\n const i3 = i * 3\n if (this.pinned[i]) {\n p[i3] = this.pinTargets[i3]!\n p[i3 + 1] = this.pinTargets[i3 + 1]!\n p[i3 + 2] = this.pinTargets[i3 + 2]!\n this.prev[i3] = p[i3]!\n this.prev[i3 + 1] = p[i3 + 1]!\n this.prev[i3 + 2] = p[i3 + 2]!\n continue\n }\n const x = p[i3]!\n const y = p[i3 + 1]!\n const z = p[i3 + 2]!\n const vx = (x - this.prev[i3]!) * damping\n const vy = (y - this.prev[i3 + 1]!) * damping\n const vz = (z - this.prev[i3 + 2]!) * damping\n\n // Gusty wind: coherent noise over time and position, blowing along +z\n // with a sideways component.\n const gust = wind * (0.55 + 0.45 * Math.sin(this.time * 1.7 + x * 2.1 + y * 1.3)) * 0.9\n // What the sheet CATCHES, which is not the same as what is blowing.\n //\n // The wind used to be a uniform shove along +z: every particle got the\n // same push whichever way its patch of paper happened to be facing. So a\n // sheet edge-on to the wind bellied out exactly as hard as one square to\n // it, a folded flap was pushed the same way as the face it was folded\n // behind, and nothing ever turned to the wind — which is the single most\n // recognisable thing paper does in air.\n //\n // The force on a thin surface is the air it intercepts, and that is the\n // component of the RELATIVE wind along the surface normal, pushed back\n // out along that normal: `n (n · (w − v))`.\n //\n // Relative is what earns the term its keep twice over. A sheet already\n // travelling with the wind stops being pushed by it, so a blown sheet\n // settles at a speed instead of accelerating away. And with no wind at\n // all the same expression is air RESISTANCE — which is why it is not\n // behind a test for whether it is windy. Paper's whole character in air\n // is that it does not fall like a stone, and it only does not because a\n // sheet falling face-down catches the air it is falling through while\n // one falling edge-down knifes past it. That fell out of this for free\n // and used to be missing entirely.\n //\n // Velocities here are per substep; the wind is per second, so the\n // particle's has to be converted before the two can be subtracted.\n const relX = gust * 0.25 - vx / dt\n const relY = -vy / dt\n const relZ = gust - vz / dt\n const nx = this.normals[i3]!\n const ny = this.normals[i3 + 1]!\n const nz = this.normals[i3 + 2]!\n const facing = nx * relX + ny * relY + nz * relZ\n // The turbulent residue keeps a sheet lying along the wind from stalling\n // in it forever; a still room has no turbulence to add.\n const ax = nx * facing * (1 - AERO_TURBULENCE) + gust * 0.25 * AERO_TURBULENCE\n const ay = ny * facing * (1 - AERO_TURBULENCE)\n const az = nz * facing * (1 - AERO_TURBULENCE) + gust * AERO_TURBULENCE\n // The air's push is a force, so it moves a heavy particle less. Gravity\n // is an acceleration and does not care — see `invMass`.\n const im = this.invMass[i]!\n // Zero inverse mass is infinite mass, and nothing moves it — gravity\n // included. The convention every solver shares, and the one a caller\n // reaching for \"hold this particle still\" will assume. `prev` is synced\n // so it leaves the moment it was frozen carrying no velocity.\n if (im <= 0) {\n this.prev[i3] = x\n this.prev[i3 + 1] = y\n this.prev[i3 + 2] = z\n continue\n }\n this.prev[i3] = x\n this.prev[i3 + 1] = y\n this.prev[i3 + 2] = z\n p[i3] = x + vx + ax * im * dt2\n p[i3 + 1] = y + vy + (ay * im - gravity * 3.2) * dt2\n p[i3 + 2] = z + vz + az * im * dt2\n maxTravel = Math.max(maxTravel, vx * vx + vy * vy + vz * vz)\n }\n\n // The hand. Held particles are integrated like any other and THEN drawn\n // toward where the fingers put them, by however hard each one is held —\n // so the centre of the pinch arrives exactly and the rim of it only\n // leans that way, still falling under gravity while it does.\n //\n // Their `prev` is deliberately left alone. It is the only record of how\n // fast the hand is moving them, and overwriting it is what used to make\n // a thrown sheet leave at a standstill; see `release`.\n for (let k = 0; k < this.grabbed.length; k++) {\n const i = this.grabbed[k]!\n const i3 = i * 3\n const k3 = k * 3\n const held = this.grabWeights[i]!\n for (let axis = 0; axis < 3; axis++) {\n const target = this.grabAt[axis]! + this.grabOffsets[k3 + axis]!\n p[i3 + axis] = p[i3 + axis]! + (target - p[i3 + axis]!) * held\n }\n }\n\n const {\n constraintA,\n constraintB,\n constraintKind,\n restLength,\n constraintStiffness,\n broken,\n invMass,\n restBend,\n constraintMiddle,\n normals,\n } = this\n const bend = 0.25 + stiffness * 0.7\n for (let iter = 0; iter < SOLVER_ITERATIONS; iter++) {\n for (let c = 0; c < this.constraintCount; c++) {\n // Paper that is not there any more does not hold anything up.\n if (broken[c]) continue\n const kind = constraintKind[c]!\n const k = (kind === 2 ? bend : kind === 1 ? 0.85 : 1) * constraintStiffness[c]!\n const ia = constraintA[c]!\n const ib = constraintB[c]!\n const a3 = ia * 3\n const b3 = ib * 3\n const dx = p[b3]! - p[a3]!\n const dy = p[b3 + 1]! - p[a3 + 1]!\n const dz = p[b3 + 2]! - p[a3 + 2]!\n const dist = Math.sqrt(dx * dx + dy * dy + dz * dz)\n if (dist === 0) continue\n // Inverse mass: 0 is immovable, 1 is free, and a particle under the\n // soft edge of a grab is honestly somewhere between. The old 0/1/2\n // weights were this same split for the two cases it could express;\n // the ratio reproduces them exactly and covers the rest.\n const ma = this.pinned[ia] ? 0 : invMass[ia]! * (1 - this.grabWeights[ia]!)\n const mb = this.pinned[ib] ? 0 : invMass[ib]! * (1 - this.grabWeights[ib]!)\n const total = ma + mb\n if (total <= 0) continue\n const diff = ((dist - restLength[c]!) / dist / total) * k\n const aw = ma\n const bw = mb\n p[a3] = p[a3]! + dx * diff * aw\n p[a3 + 1] = p[a3 + 1]! + dy * diff * aw\n p[a3 + 2] = p[a3 + 2]! + dz * diff * aw\n p[b3] = p[b3]! - dx * diff * bw\n p[b3 + 1] = p[b3 + 1]! - dy * diff * bw\n p[b3 + 2] = p[b3 + 2]! - dz * diff * bw\n\n // The signed half of a bend — see `restBend`. After the distance, so\n // the spring's length decides how far the paper bends and this only\n // which way. Behind a test, so an uncurled sheet runs exactly the\n // arithmetic it always has.\n const sag = restBend[c]!\n if (sag !== 0) {\n const im = constraintMiddle[c]!\n const m3 = im * 3\n const nx = normals[m3]!\n const ny = normals[m3 + 1]!\n const nz = normals[m3 + 2]!\n const offset =\n (p[m3]! - (p[a3]! + p[b3]!) / 2) * nx +\n (p[m3 + 1]! - (p[a3 + 1]! + p[b3 + 1]!) / 2) * ny +\n (p[m3 + 2]! - (p[a3 + 2]! + p[b3 + 2]!) / 2) * nz\n const mm = this.pinned[im] ? 0 : invMass[im]! * (1 - this.grabWeights[im]!)\n const weight = mm + (ma + mb) / 4\n if (weight > 0) {\n // The middle belongs `sag` BEHIND its ends — see `restBend`.\n const lambda = ((-sag - offset) / weight) * k\n const along = lambda * mm\n const back = lambda / 2\n p[m3] = p[m3]! + nx * along\n p[m3 + 1] = p[m3 + 1]! + ny * along\n p[m3 + 2] = p[m3 + 2]! + nz * along\n p[a3] = p[a3]! - nx * back * ma\n p[a3 + 1] = p[a3 + 1]! - ny * back * ma\n p[a3 + 2] = p[a3 + 2]! - nz * back * ma\n p[b3] = p[b3]! - nx * back * mb\n p[b3 + 1] = p[b3 + 1]! - ny * back * mb\n p[b3 + 2] = p[b3 + 2]! - nz * back * mb\n }\n }\n }\n }\n\n // Ground plane with friction.\n for (let i = 0; i < this.count; i++) {\n const i3 = i * 3\n if (p[i3 + 1]! < floor) {\n p[i3 + 1] = floor\n this.prev[i3] = this.prev[i3]! + (p[i3]! - this.prev[i3]!) * 0.5\n this.prev[i3 + 2] = this.prev[i3 + 2]! + (p[i3 + 2]! - this.prev[i3 + 2]!) * 0.5\n }\n }\n\n // Sleep bookkeeping: wind keeps the sheet awake by design.\n if (wind === 0 && this.grabbedIndex < 0) {\n if (maxTravel < SLEEP_EPSILON) {\n if (++this.stillFrames > SLEEP_FRAMES) this.asleep = true\n } else {\n this.stillFrames = 0\n }\n }\n }\n}\n","/**\n * What damage IS, as far as a sheet is concerned. The whole seam.\n *\n * The split is by responsibility. What has happened to the paper belongs to\n * the sheet — it is shading, alpha and eventually stiffness, and only the\n * sheet can draw or simulate those. What CAUSES it belongs to `paperlab/fx`:\n * a flame, a cup of water, a pair of scissors. The main entry draws whatever\n * damage it is handed and has no idea where it came from, which is exactly\n * how `content` already works — `<Paper>` renders a texture without knowing\n * who painted it.\n *\n * The alternative was a public plugin API for the surface composer and the\n * cloth solver, so that fx could reach in. More flexible, and it would have\n * had to be supported for years before a single effect existed to justify its\n * shape. This is one interface and four constants.\n *\n * **This file imports nothing, on purpose.** `paperlab/fx` depends on it —\n * the field is a `DamageSource` and its channel offsets are these — and the\n * boundary test allows fx to reach this one file and nothing else in the\n * library. The moment it imports three, React or the config schema, fx starts\n * dragging the library in behind it.\n */\n\n/**\n * A grid of damage over the sheet's UV, as the sheet reads it.\n *\n * Satisfied structurally by `DamageField` in `paperlab/fx`, and by anything\n * else that can produce four bytes per texel — a baked texture, a recorded\n * burn played back, a test fixture.\n */\nexport interface DamageSource {\n /** Texels along each edge. The grid is square and covers the whole sheet. */\n readonly size: number\n /**\n * RGBA per texel, 0..255, row-major from v = 0 — the channels are\n * {@link DAMAGE_CHANNELS}. Read in place, never copied: the source mutates\n * it and bumps `version`.\n *\n * Eight bits, deliberately. The simulation behind it can run in float; what\n * reaches the GPU is 16 KB per changed frame at 64², against 256 KB for a\n * 128² float texture, and it does not depend on float-texture filtering,\n * which not every phone GPU guarantees.\n */\n readonly pixels: Uint8Array\n /** Bumped whenever `pixels` changes. The sheet uploads on a change and never otherwise. */\n readonly version: number\n /**\n * How ragged a burnt or cut edge is DRAWN, 0..1; omitted means 1.\n *\n * Presentation only: per-fragment noise that moves the edge within the\n * grid's soft band, finer than the grid itself can carry. The physics reads\n * the grid and never this. It is the one part of drawing damage that costs\n * per pixel, which is why it is a number a source can turn down — `paperlab/fx`\n * sets it from its quality tier.\n */\n readonly detail?: number\n /**\n * The burn's own clock, in seconds; omitted means the frame clock.\n *\n * Presentation only. The ember line on a burning edge is beaded and alive —\n * its beads flicker and crawl — and a source that can be replayed wants\n * that motion to replay too: the same moment of the same burn should draw\n * the same beads, which the frame clock cannot promise. `DamageField`\n * hands over its simulated time.\n */\n readonly time?: number\n /**\n * How a burn is DRAWN — widths, intensities and shapes the sheet's damage\n * shading reads each frame. Presentation only; the physics never sees it.\n * Anything left out takes {@link DAMAGE_LOOK_DEFAULTS}.\n */\n readonly look?: DamageLook\n}\n\n/**\n * The knobs on what a burn looks like, in the units a person tunes by —\n * millimetres of A4 and plain multipliers. Every one is optional.\n */\nexport interface DamageLook {\n /** The ember line's widest bead, mm. */\n emberWidth?: number\n /** How bright the beads burn, × the default. */\n emberIntensity?: number\n /** How much of the edge is lit at once, 0..1. */\n emberCoverage?: number\n /** How fast the beads flicker and crawl, × the default. */\n emberFlicker?: number\n /** The dim crimson glow beside the beads, reaching into the char, 0..2. */\n emberGlow?: number\n /** Specks of glowing fibre along the edge, 0..2. */\n sparkle?: number\n /** The pale ash lip's widest point, mm. */\n lipWidth?: number\n /** How pale the ash lip is, × the sampled grey. */\n lipBrightness?: number\n /** 0 is grey char, 1 is dark orange to deep brown. */\n charWarmth?: number\n /** How visible the crack network in the char is, 0..1. */\n charCracks?: number\n /** How far the scorch reaches UP past the burn, mm. */\n scorchReach?: number\n /** How dark the scorch browns go, × the sampled ramp. */\n scorchDarkness?: number\n /** How strongly the scorch front breaks into fingers, × the default. */\n fingers?: number\n /** The burnt edge's long waves, ±mm. */\n edgeWave?: number\n /** The burnt edge's small bites in and out, ±mm. */\n edgeBite?: number\n}\n\n/**\n * What every burn is drawn with unless told otherwise — the combination Noor\n * tuned in the lab's sidebar on 2026-09-12, which is the look this ships.\n */\nexport const DAMAGE_LOOK_DEFAULTS: Required<DamageLook> = {\n // §5 asks for 0.3–1 mm. 1.8 was outside it, and outside the slider's range\n // it was tuned in — a control at its limit is a report that something\n // underneath is wrong, which in this case was a fire nothing could see.\n emberWidth: 0.9,\n emberIntensity: 1.45,\n emberCoverage: 0.6,\n emberFlicker: 1.65,\n emberGlow: 1.25,\n sparkle: 0.5,\n lipWidth: 1.2,\n // Was 1.5, its slider's ceiling, which made the ash lip brighter than the\n // paper it sits on. Ash is pale GREY; the reference's lip is dimmer than\n // the sheet, not a highlight drawn on it.\n lipBrightness: 0.85,\n // Was 1, also a ceiling. At full warmth the char is milk chocolate —\n // closer to cardboard than to charcoal (§5). Burnt paper keeps a little\n // warmth in the plates and reads near black in a frame with a fire in it.\n charWarmth: 0.3,\n // Was 1, also a ceiling. The cracks are drawn as thin polygon outlines, so\n // at full strength the char reads as a mosaic rather than as broken plates.\n charCracks: 0.55,\n scorchReach: 30,\n scorchDarkness: 1.17,\n fingers: 1.25,\n edgeWave: 8.5,\n edgeBite: 3.6,\n}\n\n/**\n * Which byte of a texel means what.\n *\n * char — scorch colour, the brown halo; on cloth, shrinkage and a curl toward the front.\n * saturation — wet darkening and smoothing; on cloth, added mass.\n * heat — how hot the paper is. Drawn only where it burns: the ember line, not the sheet.\n * presence — how much paper is there at all; below half, none is drawn.\n */\nexport const DAMAGE_CHANNELS = { char: 0, saturation: 1, heat: 2, presence: 3 } as const\n","import { DAMAGE_CHANNELS, type DamageSource } from '../surface/damageContract'\nimport type { ClothSim } from './cloth'\n\n/**\n * Damage, as the cloth feels it.\n *\n * The shading layer already draws a burn; this is what makes the paper under\n * it behave like burnt paper instead of a picture of it — the four-layer\n * rule's physics row. It lives in the main entry beside the sim, not in\n * `paperlab/fx`, for the same reason the shading does: `ClothSim` is not\n * exported, and what damage DOES to a sheet belongs to the sheet. fx decides\n * what causes it.\n *\n * Read from the 8-bit `pixels`, the same bytes the GPU draws, so the physics\n * and the picture cannot disagree about where the paper is. 1/255 is finer\n * than any of these levers can be seen to move.\n *\n * Cheap at rest: nothing is read unless the source's `version` moved.\n */\n\nconst { char: CHAR, saturation: SATURATION, presence: PRESENCE } = DAMAGE_CHANNELS\n\n/**\n * Presence below this, as a byte, is paper the sheet does not draw.\n *\n * The shader cuts at `step(0.5, presence)`: drawn from 127.5/255 up, so from\n * 128. The physics uses the same line, because a particle that is drawn but\n * has left the solve hangs in the air, and one that is gone but still in it\n * pulls on paper that can see it isn't there.\n */\nconst GONE_BELOW = 128\n\n/**\n * How far fully-charred paper shrinks in its own plane.\n *\n * Char shrinks — it does not soften, which would only make the sheet droop.\n * Every kind of spring alike: the shrinking is of the paper, and the curl is\n * {@link CHAR_CURL}'s job, not a difference in how far the springs shrink.\n */\nconst CHAR_SHRINK = 0.12\n\n/**\n * The curvature fully-charred paper relaxes into, toward the sheet's front,\n * in one over world units: 6 is a curl of radius a sixth of a sheet — about\n * three and a half centimetres on A4, which is what a burnt edge rolls to.\n *\n * Char and not heat, because a burnt edge STAYS curled. The first version\n * drove the curl from heat and it held only while the heat did; see\n * `ClothSim.restBend`. Toward the front because that is the side a flame is\n * held on, and the side that chars first shrinks most.\n */\nconst CHAR_CURL = 6\n\n/**\n * How steep the char has to be across a spring — as the squared byte\n * difference over four texels — before it counts as a burn front passing.\n * 16 over four texels is four bytes a texel; a real front is ten times that,\n * and the residue a cooling field leaves behind is well under it.\n */\nconst FRONT_GRADIENT = 16 * 16\n\n/**\n * How much heavier soaked paper is: at full saturation, `1 + WET_MASS` times\n * dry. Paper holds a few times its own weight in water; three is where a\n * soaked sheet stops being carried by the air and starts to hang.\n */\nconst WET_MASS = 2\n\n/**\n * Reads a `DamageSource` into one sheet's `ClothSim`: char into rest length\n * and rest curvature, saturation into mass, and missing paper out of the\n * solve altogether.\n *\n * Paper that is gone leaves the solve in two ways at once. Every constraint\n * touching it breaks, so it neither holds up nor pulls on what is left — a\n * sheet whose bottom half burnt away stops swinging from the weight of\n * nothing. And it loses its mass, so gravity and the air leave it alone too.\n *\n * What it does NOT do is fall. A gone particle is still a vertex, and the\n * triangles between it and the paper beside it are still drawn wherever the\n * paper is: let it drop and the burnt edge is dragged down after it in\n * streaks. So the ones next to live paper are carried along with it\n * ({@link follow}), and the ones in the middle of a hole stay where they\n * were, where nothing can see them.\n *\n * The limit, stated once: a sheet cannot come apart along a cut narrower than\n * a cloth cell. A constraint breaks only where a PARTICLE is gone, never\n * because the paper between two live ones is — breaking there would split\n * the sheet across a row of triangles that a fixed-topology mesh can only\n * draw stretched. A cut that thin separates the picture and not the paper;\n * really splitting a sheet takes a second mesh (see the fx plan).\n */\nexport class DamageCoupling {\n private readonly sim: ClothSim\n private source: DamageSource | null = null\n private version = -1\n private size = 0\n /** Each particle's texel, laid out for `size`. */\n private particleTexel = new Int32Array(0)\n /** Gone, per particle, as of the last read. */\n private readonly gone: Uint8Array\n /** The gone particles with live paper beside them. See {@link follow}. */\n private followers: number[] = []\n /**\n * Per bend spring, how squarely it lies ACROSS the burn front, 0..1 — and\n * remembered once it has been.\n *\n * A burnt edge rolls about an axis along the front, like a scroll; it does\n * not dish into a bowl. Measured with the curl in every bend spring alike: a\n * burnt band settled into a saddle, its corners forward and its middle BACK\n * (+0.07, −0.06), because a surface cannot curve two ways at once without\n * stretching and paper does not stretch. Curled across the front only, the\n * same band rolled toward the viewer along its whole edge (+0.13).\n *\n * \"Across the front\" is the direction the char is changing fastest in, at\n * the moment the front passes. It has to be remembered: once the front has\n * gone by, the char behind it is uniform and says nothing about direction,\n * but the paper stays rolled the way it rolled.\n */\n private readonly curlWeight: Float32Array\n\n constructor(sim: ClothSim) {\n this.sim = sim\n this.gone = new Uint8Array(sim.count)\n this.curlWeight = new Float32Array(sim.constraintCount)\n }\n\n /**\n * Bring the sim's levers up to date with `source`. Call before stepping.\n *\n * Returns whether anything was read. Free when the source has not changed,\n * and a null source hands every lever back at its default.\n */\n update(source: DamageSource | null | undefined): boolean {\n const next = source ?? null\n if (next === this.source && (next === null || next.version === this.version)) return false\n // A different source is a different sheet's history — a fresh sheet has\n // not rolled any way yet.\n if (next !== this.source) this.curlWeight.fill(0)\n this.source = next\n if (!next) {\n this.reset()\n return true\n }\n if (next.size !== this.size) this.layout(next.size)\n this.version = next.version\n this.read(next.pixels)\n this.sim.wake()\n return true\n }\n\n /**\n * Carry the gone particles at the edge of a hole along with the paper beside\n * them. Call after stepping.\n *\n * Each one goes where its live neighbours say it would be if the grid were\n * laid out flat around them — their positions plus its rest offset from\n * each, averaged. The triangles that straddle the burnt edge then keep\n * roughly their shape instead of stretching back to wherever the particle\n * was when it burnt. Only a band of a single particle's width, with live\n * paper pulling it both ways, is left averaging between them.\n */\n follow(): void {\n if (this.followers.length === 0) return\n const { gone, sim } = this\n const p = sim.positions\n const { cols, rows } = sim\n const cellX = cols > 1 ? sim.width / (cols - 1) : 0\n const cellY = rows > 1 ? sim.height / (rows - 1) : 0\n for (const g of this.followers) {\n const r = (g / cols) | 0\n const c = g % cols\n let sx = 0\n let sy = 0\n let sz = 0\n let n = 0\n for (let dr = -1; dr <= 1; dr++) {\n const nr = r + dr\n if (nr < 0 || nr >= rows) continue\n for (let dc = -1; dc <= 1; dc++) {\n const nc = c + dc\n if ((dr === 0 && dc === 0) || nc < 0 || nc >= cols) continue\n const j = nr * cols + nc\n if (gone[j]) continue\n const j3 = j * 3\n // Rows run down the sheet, so a neighbour a row BELOW sits lower,\n // and this particle a cell above it.\n sx += p[j3]! - dc * cellX\n sy += p[j3 + 1]! + dr * cellY\n sz += p[j3 + 2]!\n n++\n }\n }\n if (n === 0) continue\n const g3 = g * 3\n p[g3] = sx / n\n p[g3 + 1] = sy / n\n p[g3 + 2] = sz / n\n }\n }\n\n /** Map each particle to its texel. The damage grid's row 0 is v = 0, the sheet's BOTTOM. */\n private layout(size: number): void {\n const { cols, rows, count } = this.sim\n const last = size - 1\n this.size = size\n this.particleTexel = new Int32Array(count)\n for (let r = 0; r < rows; r++) {\n for (let c = 0; c < cols; c++) {\n const u = cols > 1 ? c / (cols - 1) : 0.5\n // The cloth's row 0 is the TOP.\n const v = rows > 1 ? 1 - r / (rows - 1) : 0.5\n this.particleTexel[r * cols + c] = Math.round(v * last) * size + Math.round(u * last)\n }\n }\n }\n\n private read(pixels: Uint8Array): void {\n const { sim, gone, particleTexel, curlWeight, size } = this\n const {\n invMass,\n restLength,\n naturalLength,\n restBend,\n broken,\n constraintA,\n constraintB,\n constraintKind,\n constraintMiddle,\n } = sim\n\n for (let i = 0; i < sim.count; i++) {\n const t = particleTexel[i]! * 4\n const isGone = pixels[t + PRESENCE]! < GONE_BELOW\n gone[i] = isGone ? 1 : 0\n // Exactly 1 at a dry texel — an undamaged sheet must stay bit-identical\n // to one with no source at all.\n invMass[i] = isGone ? 0 : 1 / (1 + (WET_MASS * pixels[t + SATURATION]!) / 255)\n }\n\n for (let k = 0; k < sim.constraintCount; k++) {\n const a = constraintA[k]!\n const b = constraintB[k]!\n // A bend spring over a gone particle would bridge the hole, holding the\n // two sides together through paper that is not there.\n const m = constraintMiddle[k]!\n if (gone[a] || gone[b] || (m >= 0 && gone[m])) {\n broken[k] = 1\n continue\n }\n broken[k] = 0\n let charSum = pixels[particleTexel[a]! * 4 + CHAR]! + pixels[particleTexel[b]! * 4 + CHAR]!\n let samples = 2\n if (m >= 0) {\n charSum += pixels[particleTexel[m]! * 4 + CHAR]!\n samples = 3\n }\n const char = charSum / (samples * 255)\n // Exactly the natural length, and exactly no bend, at char 0.\n restLength[k] = naturalLength[k]! * (1 - CHAR_SHRINK * char)\n if (constraintKind[k] === 2) {\n // Is a front passing here, and does this spring run across it? The\n // char gradient at the spring's middle, by central difference.\n const t = particleTexel[m]!\n const x = t % size\n const y = (t / size) | 0\n const gx =\n pixels[(y * size + Math.min(size - 1, x + 2)) * 4 + CHAR]! -\n pixels[(y * size + Math.max(0, x - 2)) * 4 + CHAR]!\n const gy =\n pixels[(Math.min(size - 1, y + 2) * size + x) * 4 + CHAR]! -\n pixels[(Math.max(0, y - 2) * size + x) * 4 + CHAR]!\n const steep = gx * gx + gy * gy\n if (steep > FRONT_GRADIENT) {\n // A spring along a row spans two columns; one down a column, two rows.\n const across = (b - a === 2 ? gx * gx : gy * gy) / steep\n if (across > curlWeight[k]!) curlWeight[k] = across\n }\n // A curvature as the sagitta of this spring's span: κL²/8.\n const span = naturalLength[k]!\n restBend[k] = (CHAR_CURL * char * curlWeight[k]! * span * span) / 8\n }\n }\n\n const followers: number[] = []\n const { cols, rows } = sim\n for (let i = 0; i < sim.count; i++) {\n if (!gone[i]) continue\n const r = (i / cols) | 0\n const c = i % cols\n let beside = false\n for (let dr = -1; dr <= 1 && !beside; dr++) {\n const nr = r + dr\n if (nr < 0 || nr >= rows) continue\n for (let dc = -1; dc <= 1; dc++) {\n const nc = c + dc\n if (nc < 0 || nc >= cols) continue\n if (!gone[nr * cols + nc]) {\n beside = true\n break\n }\n }\n }\n if (beside) followers.push(i)\n }\n this.followers = followers\n }\n\n private reset(): void {\n const { sim } = this\n sim.invMass.fill(1)\n sim.restBend.fill(0)\n sim.broken.fill(0)\n sim.restLength.set(sim.naturalLength)\n this.gone.fill(0)\n this.curlWeight.fill(0)\n this.followers = []\n this.version = -1\n sim.wake()\n }\n}\n","import { rollRadius, windAngle } from '../deformers/roll'\n\n/**\n * A strip of paper paying off a roll, and the pile it makes when it lands.\n *\n * The one simulation in the library with a DRIVING BODY. Cloth is a passive\n * grid that gravity and wind act on; this is a kinematic roll that the host\n * turns, extruding paper into a chain that is then left to fall. Scroll the\n * page, the roll spins, paper pays out, and it buckles into an accordion on\n * the floor. The pile is the point — everything else here exists to make it\n * possible.\n */\nexport interface StripParams {\n /**\n * The host's scroll position, in world units of paper it would like to see.\n * MONOTONIC and unbounded — bind it to `scrollY * k`, not to a 0..1\n * progress. The sim differentiates it, so only the delta between frames is\n * read and the absolute value never matters.\n */\n scroll: number\n /** How tightly the paper is wound: thin layers and many turns, or few and fat. */\n tightness: number\n /** Radius of the cardboard tube. The roll never pays out past it. */\n core: number\n /** Paper already hanging before the first scroll — a roll always has a leaf out. */\n tail: number\n /** Spacing of the perforations, in world units. One sheet's worth of strip. */\n perforation: number\n /** How much a perforation remembers being folded. 0 = a fresh roll, 1 = a used one. */\n crease: number\n /** Bend stiffness of the paper between perforations. 1 = card, 0 = cloth. */\n stiffness: number\n /** Broadside air drag. Paper is light and wide; this is what makes it float down. */\n drag: number\n gravity: number\n /** How far below the roll the paper lands. A distance, not a signed y. */\n floor: number\n /** How long the roll coasts after the scroll stops. 0 = stops dead, 1 = free-spinning. */\n inertia: number\n}\n\nconst FIXED_DT = 1 / 120\n/** Paper is inextensible; it takes more iterations than cloth to hold that. */\nconst SOLVER_ITERATIONS = 8\nconst SLEEP_EPSILON = 1e-7\nconst SLEEP_FRAMES = 45\n\n/** Layer gap at `tightness` 0 and 1 — visible thickness, not a real 60µm ply. */\nconst LOOSE = 0.055\nconst TIGHT = 0.012\n\n/**\n * Chain nodes per perforated panel.\n *\n * The floor is about four — below that a panel is a straight line and cannot\n * buckle. The number is far above that floor because the ROLL, not the pile,\n * sets the requirement: the same nodes that fold on the floor are the ones\n * drawing the spiral, and a wound turn is only as round as the nodes spanning\n * it. At five to a panel a full roll is a visible sixteen-sided polygon and\n * the innermost turn is drawn with FOUR nodes at 85° a step, which is coarse\n * enough that the chords cut clean through the neighbouring wrap and the\n * spiral comes apart into a sawtooth. See {@link safeSpiralRadius}.\n *\n * Affordable: the preset's chain is 198 nodes and costs 0.13 ms a frame,\n * under a hundredth of a 60fps budget. The chain is one-dimensional, so\n * resolution here is cheap in a way a cloth grid's never is.\n */\nconst NODES_PER_PANEL = 16\n/** Verlet nodes are two vertices each; this is the geometry budget, not the physics one. */\nconst MAX_NODES = 440\nconst MIN_NODES = 8\n\n/**\n * The bend constraint's constants were tuned at this spacing. Panels are\n * jointed every `segment`, so a finer chain has proportionally more joints\n * bending the same panel — without scaling by this, raising the resolution\n * for the roll's sake would quietly turn every panel to cloth.\n */\nconst REFERENCE_SEGMENT = 0.0375\n\n/**\n * Arc span the broadside/along-length split is measured over, in world units.\n *\n * Deliberately a DISTANCE rather than \"the two neighbouring nodes\". The split\n * decides how much of a node's motion the air resists, so a tangent estimated\n * from whatever happens to be adjacent makes drag a function of the node\n * count: a coarse chain reads a bend as travel along its own length and\n * barely damps it, a fine one reads the same bend as broadside and damps it\n * hard. Measured over a fixed span the answer is the same at any resolution,\n * which is what lets the roll's tessellation be raised without re-tuning\n * every drag constant beneath it.\n */\nconst TANGENT_SPAN = 0.09\n\n/** Share of a pull's unmet reach the roll gives up per substep. */\nconst PULL_STIFFNESS = 0.35\n\n/**\n * Solver iterations that also push overlapping folds apart.\n *\n * Self-collision used to run once, after the constraint loop had finished,\n * which is too late to matter in a pile: separating two folds moves them off\n * their rest lengths, and with no iterations left to restore those the next\n * substep pulled them straight back through each other. Interleaving the last\n * few passes lets length and separation settle together, which is the only\n * way a heap holds its own height.\n */\nconst COLLIDING_ITERATIONS = 4\n\n/** How much of a segment overlap is resolved per collision pass. */\nconst COLLISION_RELAXATION = 0.35\n\n/**\n * Tightest radius this chain can wind to without the spiral cutting through\n * itself.\n *\n * A wrap is drawn as a polygon of `segment`-long chords, and a chord of\n * length `s` on a circle of radius `r` dips `s²/8r` inside it. Once that dip\n * exceeds half the gap between wraps, the chord crosses into the wrap\n * beneath — so `s²/8r < t/2`, and the spiral must stop at `s²/4t`.\n *\n * Sizing a roll with {@link rollRadius} lands the innermost wrap exactly on\n * the core, so a well-proportioned roll never reaches this. It is here\n * because `core`, `tightness` and the sheet's length are independent numbers\n * a caller may set to anything, and \"wound tighter than it can be drawn\" has\n * to degrade to a smooth tight coil rather than to a starburst.\n */\nfunction safeSpiralRadius(segment: number, thickness: number): number {\n return thickness > 0 ? (segment * segment) / (4 * thickness) : 0\n}\n\nexport function layerThickness(tightness: number): number {\n return LOOSE - Math.min(1, Math.max(0, tightness)) * (LOOSE - TIGHT)\n}\n\n/**\n * How many nodes a strip of this length wants. Exported because the MESH has\n * to be built before the sim is — the geometry is a 2×N quad strip and its\n * row count has to agree with the chain exactly.\n */\nexport function stripNodeCount(length: number, perforation: number): number {\n const seg = Math.max(perforation, 1e-3) / NODES_PER_PANEL\n return Math.min(MAX_NODES, Math.max(MIN_NODES, Math.round(length / seg) + 1))\n}\n\n/**\n * The longest strip this chain can still draw properly, for a given\n * perforation spacing.\n *\n * {@link stripNodeCount} is CAPPED, and the cap does not fail loudly: past it\n * the node count stops growing, so `segment` (which is `length / (count - 1)`)\n * grows instead, and every constant that was tuned per node quietly changes\n * meaning. The first thing to break is the roll — a longer chord on the same\n * radius dips further inside the wrap beneath it, so the spiral heads for the\n * {@link safeSpiralRadius} threshold and comes apart into a starburst.\n *\n * Exported because it is a UI limit as much as a physics one: a length slider\n * that runs past this hands the user a roll that visibly falls apart, and the\n * editor has no other way to know where the ceiling is. The constants that set\n * it live here, so the derivation does too.\n */\nexport function maxStripLength(perforation: number): number {\n const seg = Math.max(perforation, 1e-3) / NODES_PER_PANEL\n // count = round(L/seg) + 1 must stay <= MAX_NODES, and `round` gives half a\n // step of slack before the cap actually binds.\n return (MAX_NODES - 1 - 0.5) * seg\n}\n\n/**\n * Verlet chain in the y–z plane, extruded from a kinematic roll.\n *\n * **The chain does not grow.** Nodes are never spawned or destroyed; they are\n * RECLASSIFIED. Every node exists from the first frame, and the ones that\n * have not been paid out yet are placed analytically on the roll's spiral\n * each substep while the rest run free. The boundary between the two walks\n * along the chain as paper feeds.\n *\n * That is worth the paragraph because the obvious implementation — spawn a\n * particle at the anchor as `L` grows — needs a resizing vertex buffer, has\n * to invent a velocity for each new particle, and pops visibly at the seam.\n * Here the buffer is fixed, rewind is the same code path run backwards, and\n * the tangential velocity the spec asks new paper to inherit falls out for\n * free: a node released from the spiral was already being moved along it, so\n * its Verlet velocity is the roll's surface velocity on the frame it lets go.\n *\n * **It simulates two dimensions, not three.** The strip hangs in y, folds in\n * z, and keeps its full width in x with no twist. Toilet paper piles in the\n * plane it unrolls in, so the third axis buys almost nothing visually and\n * costs the thing that actually matters — self-collision stays a 2D query,\n * which is what lets the folds stack instead of passing through each other.\n */\nexport class StripSim {\n /** Chain length. Node 0 is the deepest wrap; node `count-1` is the free tip. */\n readonly count: number\n /** Rest spacing between neighbours, in world units. */\n readonly segment: number\n /** Node centreline, y/z interleaved. x is implicit: the strip never twists. */\n private readonly pos: Float64Array\n private readonly prev: Float64Array\n /** Arc distance from the tip, per node. */\n private readonly arc: Float64Array\n /** 1 where a perforation hinges, and the sign of the crease it remembers. */\n private readonly perforated: Int8Array\n\n /** Bend gain correction for this chain's node spacing. See {@link REFERENCE_SEGMENT}. */\n private readonly bendScale: number\n /** Half-width, in nodes, of the window the drag tangent is measured over. */\n private readonly tangentNodes: number\n private readonly halfWidth: number\n private readonly totalLength: number\n /**\n * Paper that can never be paid out, because its inner end is glued to the\n * tube — which is true of every roll you have ever used.\n *\n * Without it the roll pays out to nothing, `firstFreeIndex` reaches 0, and\n * every node the roll was made of becomes free paper and falls: the whole\n * roll drops off its holder and lands flat on the pile. One wrap held back\n * leaves a cylinder at the core radius on the holder, which is what an\n * empty roll looks like and the closest this library can get to drawing a\n * cardboard tube out of the one sheet it has.\n */\n private tubeStub: number\n private params: StripParams\n\n /** Paid-out length: how much paper is off the roll. */\n private paid: number\n /** Angular velocity of the roll, rad/s. The thing that coasts. */\n private omega = 0\n /**\n * Whether anything has turned the roll yet — a scroll delta or a hand.\n *\n * `tail` is the opening pose, and editing it should re-pose the roll; but\n * once the host has scrolled, `paid` is the simulation's own state and\n * re-posing would yank the paper back out of the pile.\n */\n private driven = false\n private lastScroll: number\n private primed = false\n\n /** Node held by the pointer, or -1. Kinematic while held, like a wound node. */\n private grabbed = -1\n private grabY = 0\n private grabZ = 0\n\n private stillFrames = 0\n private accumulator = 0\n private time = 0\n asleep = false\n\n // Spatial hash for self-collision. Sized once, refilled in place — the\n // per-substep collision pass allocates nothing.\n private readonly cellOf: Int32Array\n private readonly bucketStart: Int32Array\n private readonly bucketItems: Int32Array\n private readonly bucketFill: Int32Array\n private readonly tableSize: number\n\n constructor(length: number, width: number, params: StripParams) {\n this.params = { ...params }\n this.totalLength = length\n this.halfWidth = width / 2\n this.count = stripNodeCount(length, params.perforation)\n this.segment = length / (this.count - 1)\n this.bendScale = Math.min(1, this.segment / REFERENCE_SEGMENT)\n this.tangentNodes = Math.max(1, Math.round(TANGENT_SPAN / this.segment))\n\n this.pos = new Float64Array(this.count * 2)\n this.prev = new Float64Array(this.count * 2)\n this.arc = new Float64Array(this.count)\n this.perforated = new Int8Array(this.count)\n\n for (let i = 0; i < this.count; i++) {\n this.arc[i] = (this.count - 1 - i) * this.segment\n }\n // A perforation sits wherever the arc distance from the tip crosses a\n // multiple of the spacing. The sign alternates so the pile accordions\n // instead of curling one way forever.\n const spacing = Math.max(params.perforation, this.segment * 2)\n for (let i = 0; i < this.count - 1; i++) {\n const here = Math.floor(this.arc[i]! / spacing)\n const next = Math.floor(this.arc[i + 1]! / spacing)\n if (here !== next) this.perforated[i] = here % 2 === 0 ? 1 : -1\n }\n\n this.tableSize = 1 << Math.ceil(Math.log2(Math.max(16, this.count * 2)))\n this.cellOf = new Int32Array(this.count)\n this.bucketStart = new Int32Array(this.tableSize + 1)\n this.bucketItems = new Int32Array(this.count)\n this.bucketFill = new Int32Array(this.tableSize)\n\n this.tubeStub = this.stubFor(params.core)\n this.paid = Math.min(params.tail, this.usableLength)\n this.lastScroll = params.scroll\n this.layOut()\n }\n\n /**\n * Local-space y the pile builds on, after centring. A host placing a\n * shadow catcher or a contact shadow needs this; it cannot derive it,\n * because the composition is offset to sit on the origin.\n */\n get floorY(): number {\n return -this.params.floor + this.centreOffset\n }\n\n /**\n * How far the whole composition is lifted so that it straddles the origin.\n *\n * The roll's axis is the sim's origin, which would park a long drop\n * entirely below the frame — `<Paper>` and the editor both look at the\n * origin through about two world units, and neither fits a camera to the\n * content. `unroll` learned the same lesson and left a note about it: a\n * composition anchored anywhere but the origin needs a bespoke camera at\n * every call site.\n *\n * Measured against the FULL radius rather than the current one, so it is a\n * constant for a given config. Deriving it from the live radius would drift\n * the entire pile upward as the roll ran down.\n */\n private get centreOffset(): number {\n return (this.params.floor - this.outerRadius) / 2\n }\n\n /**\n * The same centring, along the axis the pile actually grows in.\n *\n * Everything here is built around the DROP LINE — the z the paper leaves\n * the roll at — and that line is not the origin and does not stay put. It\n * starts at 0 on a full roll and travels back to `core - outerRadius` as\n * the roll runs down (see {@link tangentZ}), because the spiral's centre is\n * fixed and the tangent point walks in toward it. The pile builds around\n * wherever the line has been, so a composition that ignores this is offset\n * by half that travel before a single fold has landed, and z is DEPTH —\n * the axis a fixed head-on camera has the least room in.\n *\n * A constant for a given config, for the reason {@link centreOffset} is:\n * derived from the live radius it would slide the whole composition\n * backwards as the roll emptied, which reads far worse than sitting still\n * slightly off centre. Centring the line's travel splits the difference\n * between a full roll and an empty one.\n */\n private get centreShift(): number {\n return (this.outerRadius - this.params.core) / 2\n }\n\n /** Outer radius of what is still wound. Shrinks to `core` as the roll empties. */\n get radius(): number {\n return rollRadius(this.totalLength - this.paid, this.params.core, layerThickness(this.params.tightness))\n }\n\n /** Radius of the full roll. Fixes the spiral's centre, which must not move. */\n private get outerRadius(): number {\n return rollRadius(this.totalLength, this.params.core, layerThickness(this.params.tightness))\n }\n\n /**\n * The wrap that never leaves: one full turn around the core, but never so\n * much of a short sheet that there is nothing left to unroll.\n *\n * A method rather than a constant because `core` is a live control. It was\n * a constructor-time `readonly`, which meant dragging `core` moved the\n * radius the spiral is drawn at while `usableLength` and the end stop kept\n * answering for the old tube — the roll would run past its own floor, or\n * stop short of it, depending on which way the slider went.\n */\n private stubFor(core: number): number {\n return Math.min(Math.PI * 2 * core, this.totalLength * 0.3)\n }\n\n /** Paper that can actually leave the roll — everything but the glued stub. */\n private get usableLength(): number {\n return this.totalLength - this.tubeStub\n }\n\n /** How much paper is left to give. `0` is down to the tube, `1` is untouched. */\n get remaining(): number {\n return 1 - this.paid / this.usableLength\n }\n\n /**\n * Where the paper leaves the roll: the frontmost point of the current\n * outer wrap. The spiral's CENTRE is fixed (a lesson the `roll` deformer\n * paid for — see its notes), so as the roll runs down the tangent point\n * travels back toward the holder and the strip hangs closer to it. That\n * drift is real and worth keeping.\n */\n private get tangentZ(): number {\n return this.radius - this.outerRadius\n }\n\n /** Place every node: the wound ones on the spiral, the free ones straight down. */\n private layOut(): void {\n const firstFree = this.firstFreeIndex()\n for (let i = 0; i < this.count; i++) {\n const p = i * 2\n if (i < firstFree) {\n this.spiralPoint(this.arc[i]! - this.paid, p, this.pos)\n } else {\n this.pos[p] = -(this.paid - this.arc[i]!)\n this.pos[p + 1] = this.tangentZ\n }\n }\n this.prev.set(this.pos)\n }\n\n /** First node that has come off the roll. Everything below it is kinematic. */\n private firstFreeIndex(): number {\n // arc[i] <= paid means node i has been paid out. arc decreases with i.\n const free = Math.ceil(this.count - 1 - this.paid / this.segment)\n return Math.min(this.count - 1, Math.max(0, free))\n }\n\n /**\n * Position of a point `wound` along the spiral from the tangent point,\n * written into `out` at offset `o`.\n *\n * Angle 0 is the tangent point at the front of the roll; winding runs up\n * over the top, which is the \"over\" hang. The radius falls by one layer\n * per turn, so the wraps are concentric and exactly a thickness apart.\n */\n private spiralPoint(wound: number, o: number, out: Float64Array): void {\n const r0 = this.radius\n const thickness = layerThickness(this.params.tightness)\n const k = thickness / (Math.PI * 2)\n const phi = windAngle(Math.max(0, wound), r0, k)\n const floor = Math.max(this.params.core, safeSpiralRadius(this.segment, thickness))\n const r = Math.max(floor, r0 - k * phi)\n out[o] = r * Math.sin(phi)\n out[o + 1] = -this.outerRadius + r * Math.cos(phi)\n }\n\n setParams(params: Partial<StripParams>): void {\n let changed = false\n const tailBefore = this.params.tail\n for (const key of [\n 'scroll',\n 'tightness',\n 'core',\n 'tail',\n 'crease',\n 'stiffness',\n 'drag',\n 'gravity',\n 'floor',\n 'inertia',\n ] as const) {\n const value = params[key]\n if (value !== undefined && value !== this.params[key]) {\n this.params[key] = value\n changed = true\n }\n }\n // `perforation` is structural — it sets the node count and the hinge map,\n // so it cannot be patched in place. PaperMesh rebuilds the sim on it.\n\n // Two params own derived state, and both are live sliders in the editor.\n // Patching `this.params` alone left that state answering for the old\n // value: `core` sizes the glued stub, and `tail` IS the paid-out length\n // on a roll nobody has scrolled yet, so without this a tail drag did\n // nothing at all and a core drag desynced the end stop from the spiral.\n if (params.core !== undefined) {\n this.tubeStub = this.stubFor(params.core)\n // A bigger stub can leave less usable paper than is already out.\n this.paid = Math.min(this.paid, this.usableLength)\n }\n if (params.tail !== undefined && tailBefore !== this.params.tail) {\n // Only while the roll is still sitting at its opening pose. Once the\n // host has scrolled, `paid` is the simulation's own state and a tail\n // edit must not yank the paper back.\n if (!this.driven) {\n this.paid = Math.min(this.params.tail, this.usableLength)\n this.layOut()\n }\n }\n if (changed) this.wake()\n }\n\n wake(): void {\n this.asleep = false\n this.stillFrames = 0\n }\n\n /**\n * Take hold of the paper at a point, in the same y–z the vertex buffer is\n * written in — mesh-local coordinates, the lift already applied. Returns the\n * node caught, or -1 when there is no free paper to catch.\n *\n * Speaking the buffer's coordinates rather than the solver's is the whole\n * contract here: a caller has a raycast hit on the mesh and nothing else,\n * and the centring lift is an internal detail it has no way to know.\n *\n * Only paper that has left the roll can be caught — a wound node belongs to\n * the spiral, and pinning one would be pinning the roll itself.\n */\n grabNearest(y: number, z: number): number {\n const firstFree = this.firstFreeIndex()\n const localY = y - this.centreOffset\n const localZ = z - this.centreShift\n let best = -1\n let bestDist = Infinity\n for (let i = firstFree; i < this.count; i++) {\n const dy = this.pos[i * 2]! - localY\n const dz = this.pos[i * 2 + 1]! - localZ\n const d = dy * dy + dz * dz\n if (d < bestDist) {\n bestDist = d\n best = i\n }\n }\n this.grabbed = best\n this.grabY = localY\n this.grabZ = localZ\n this.wake()\n return best\n }\n\n moveGrab(y: number, z: number): void {\n if (this.grabbed < 0) return\n this.grabY = y - this.centreOffset\n this.grabZ = z - this.centreShift\n this.wake()\n }\n\n release(): void {\n this.grabbed = -1\n }\n\n /** Whether a pointer currently holds the paper. */\n get held(): boolean {\n return this.grabbed >= 0\n }\n\n step(delta: number): void {\n // A scroll delta must never be dropped just because the sim had gone to\n // sleep — the whole input path is \"the number changed\".\n if (this.params.scroll !== this.lastScroll) this.wake()\n if (this.asleep) return\n this.accumulator = Math.min(this.accumulator + delta, FIXED_DT * 4)\n while (this.accumulator >= FIXED_DT) {\n this.substep(FIXED_DT)\n this.accumulator -= FIXED_DT\n }\n }\n\n private substep(dt: number): void {\n this.time += dt\n this.driveRoll(dt)\n this.pullFeed(dt)\n this.integrate(dt)\n const firstFree = this.firstFreeIndex()\n this.pinWound(firstFree)\n for (let iter = 0; iter < SOLVER_ITERATIONS; iter++) {\n this.solveDistance(firstFree)\n this.solveBend(firstFree)\n if (iter >= SOLVER_ITERATIONS - COLLIDING_ITERATIONS) {\n this.solveSelfCollision(firstFree)\n this.solveFloor(firstFree)\n }\n this.pinWound(firstFree)\n }\n this.solveFloor(firstFree)\n }\n\n /**\n * Turn the roll. Scroll enters as an angle the roll OWES, which a leaky\n * integrator spends into angular velocity — so a steady scroll gives a\n * steady spin and a flick spikes and coasts down.\n *\n * `ΔL = R·Δθ` with the CURRENT radius, which is why the radius has to be\n * read inside the loop: a nearly-empty roll spins fast and gives up very\n * little paper for the same scroll, and that is the whole tell that a roll\n * is running out.\n */\n private driveRoll(dt: number): void {\n const scroll = this.params.scroll\n if (!this.primed) {\n // First frame: adopt the host's scroll origin rather than reading it as\n // one enormous delta and firing the whole roll off at once.\n this.lastScroll = scroll\n this.primed = true\n }\n // The host asks in world units of paper; the roll answers in radians. The\n // conversion is against the FULL radius, which is a constant — so one\n // scroll unit is about one unit of paper on a fresh roll, and less and\n // less as it empties.\n //\n // Dividing by the CURRENT radius instead is the obvious way to write this\n // and is wrong twice over: `ΔL = R·Δθ` multiplies the same radius straight\n // back, so it cancels and the roll pays out the same paper however full it\n // is — the exact tell this sim exists to show — and because the divisor\n // shrinks as the roll empties, the last of the paper leaves in a runaway\n // that slams into the end stop.\n const impulse = (scroll - this.lastScroll) / this.outerRadius\n this.lastScroll = scroll\n\n // The roll is a flywheel and a scroll delta is an ANGULAR IMPULSE on it,\n // not an angle the roll owes. A damped flywheel given impulse `J` turns\n // `J·tau` in total, so scaling the impulse by `1/tau` makes the paper a\n // given scroll pays out independent of how long the roll coasts —\n // `inertia` then buys the coast and nothing else, which is the only way\n // it is usable as a knob.\n //\n // Adding the impulse to a persistent `omega` WITHOUT that scaling is the\n // trap: the decay tail spends every increment ~tau/dt times over, so the\n // roll empties in a quarter-second whatever it is asked for.\n const tau = 0.012 + this.params.inertia * 0.55\n this.omega = this.omega * Math.exp(-dt / tau) + impulse / tau\n if (Math.abs(this.omega) < 1e-6) this.omega = 0\n\n // ΔL = R·Δθ at the CURRENT radius: a nearly-empty roll spins fast and\n // gives up very little paper, which is how a roll reads as running out.\n const next = this.paid + this.radius * this.omega * dt\n if (next !== this.paid) this.driven = true\n this.paid = Math.min(this.usableLength, Math.max(0, next))\n // Down to the tube (or fully rewound): the roll cannot keep turning.\n if (this.paid === 0 || this.paid === this.usableLength) this.omega = 0\n }\n\n /**\n * Take hold of the paper and pull, and the roll turns — the interaction the\n * real object is famous for.\n *\n * It is driven by TENSION rather than by mapping hand travel to an angle.\n * Paper does not stretch, so if the hand is further from the roll than there\n * is paper to reach it, the only way the constraint can be satisfied is for\n * the roll to give up more. That one rule gets the whole behaviour for free:\n * a slow pull feeds smoothly, a fast yank spins the roll and it carries on\n * after release, and pushing the paper back toward the roll does nothing at\n * all — which is exactly right, because slack does not rewind a roll. Only\n * scrolling up does.\n */\n private pullFeed(dt: number): void {\n if (this.grabbed < 0 || this.grabbed < this.firstFreeIndex()) return\n // How far the hand is from where the paper leaves the roll, against how\n // much paper there is between those two points.\n const reach = Math.hypot(this.grabY, this.grabZ - this.tangentZ)\n const available = this.paid - this.arc[this.grabbed]!\n const over = reach - available\n if (over <= 1e-6) return\n\n const feed = Math.min(over * PULL_STIFFNESS, this.usableLength - this.paid)\n if (feed <= 0) return\n this.paid += feed\n // Keep the flywheel in step with the hand, so letting go mid-pull leaves\n // the roll spinning at the speed it was actually being pulled at.\n this.omega = feed / (this.radius * dt)\n }\n\n /**\n * Verlet with ANISOTROPIC drag. A strip of paper barely notices the air\n * when it moves along its own length and is stopped almost dead when it\n * moves broadside, which is the difference between paper that floats down\n * and a rope that drops. Damping the velocity uniformly — the obvious\n * thing, and what cloth does — gets neither.\n */\n private integrate(dt: number): void {\n const { gravity, drag } = this.params\n const p = this.pos\n const dt2 = dt * dt\n const firstFree = this.firstFreeIndex()\n // Broadside drag is strong; along-length drag is nearly nothing.\n const across = Math.exp(-(0.6 + drag * 11) * dt)\n const along = Math.exp(-(0.4 + drag * 0.8) * dt)\n\n let travel = 0\n for (let i = firstFree; i < this.count; i++) {\n const o = i * 2\n if (i === this.grabbed) {\n // The hand owns this node. Its previous position is left alone, so\n // the chain feels the hand's velocity rather than a teleport.\n p[o] = this.grabY\n p[o + 1] = this.grabZ\n continue\n }\n const y = p[o]!\n const z = p[o + 1]!\n let vy = y - this.prev[o]!\n let vz = z - this.prev[o + 1]!\n\n // Segment tangent over a fixed arc span, clamped to what exists.\n const a = Math.max(firstFree, i - this.tangentNodes) * 2\n const b = Math.min(this.count - 1, i + this.tangentNodes) * 2\n let ty = p[b]! - p[a]!\n let tz = p[b + 1]! - p[a + 1]!\n const len = Math.hypot(ty, tz)\n if (len > 1e-9) {\n ty /= len\n tz /= len\n const vt = vy * ty + vz * tz\n // Normal component is whatever is left once the tangent one is out.\n const ny = vy - vt * ty\n const nz = vz - vt * tz\n vy = vt * ty * along + ny * across\n vz = vt * tz * along + nz * across\n }\n\n this.prev[o] = y\n this.prev[o + 1] = z\n // A vertical strip is in unstable equilibrium and will never pick a\n // side to fall toward. This is the nudge that lets it choose.\n const noise = Math.sin(this.time * 2.3 + i * 1.7) * 6e-5\n p[o] = y + vy - gravity * 3.2 * dt2\n p[o + 1] = z + vz + noise\n travel = Math.max(travel, vy * vy + vz * vz)\n }\n\n if (this.omega === 0 && this.grabbed < 0) {\n if (travel < SLEEP_EPSILON) {\n if (++this.stillFrames > SLEEP_FRAMES) this.asleep = true\n } else this.stillFrames = 0\n } else this.stillFrames = 0\n }\n\n /** Wound nodes are the roll's, not the solver's: rewrite them every pass. */\n private pinWound(firstFree: number): void {\n for (let i = 0; i < firstFree; i++) {\n this.spiralPoint(this.arc[i]! - this.paid, i * 2, this.pos)\n }\n // The first two free nodes leave along the tangent, so the strip comes\n // off the roll straight instead of kinking at the anchor.\n const tz = this.tangentZ\n for (let i = firstFree; i < Math.min(this.count, firstFree + 2); i++) {\n if (i === this.grabbed) continue\n const o = i * 2\n this.pos[o + 1] = this.pos[o + 1]! + (tz - this.pos[o + 1]!) * 0.5\n }\n if (this.grabbed >= firstFree) {\n this.pos[this.grabbed * 2] = this.grabY\n this.pos[this.grabbed * 2 + 1] = this.grabZ\n }\n }\n\n /** Paper does not stretch. Distance constraints run at full strength. */\n private solveDistance(firstFree: number): void {\n const p = this.pos\n const rest = this.segment\n for (let i = Math.max(0, firstFree - 1); i < this.count - 1; i++) {\n const a = i * 2\n const b = (i + 1) * 2\n const dy = p[b]! - p[a]!\n const dz = p[b + 1]! - p[a + 1]!\n const dist = Math.hypot(dy, dz)\n if (dist < 1e-9) continue\n const diff = ((dist - rest) / dist) * 0.5\n // A wound node is the roll's and a held one is the hand's; neither\n // moves, so its partner takes the whole correction.\n const aFixed = i < firstFree || i === this.grabbed\n const bFixed = i + 1 === this.grabbed\n if (aFixed && bFixed) continue\n const aw = aFixed ? 0 : bFixed ? 2 : 1\n const bw = bFixed ? 0 : aFixed ? 2 : 1\n p[a] = p[a]! + dy * diff * aw\n p[a + 1] = p[a + 1]! + dz * diff * aw\n p[b] = p[b]! - dy * diff * bw\n p[b + 1] = p[b + 1]! - dz * diff * bw\n }\n }\n\n /**\n * The bend constraint, and the reason this is not a rope preset.\n *\n * Every joint wants to be straight. A joint AT A PERFORATION wants it far\n * less, and may want a slight fold instead — those are the hinges the pile\n * folds at, and the alternating sign is what turns a heap into an\n * accordion. Uniform stiffness gives a coil; no stiffness gives a rope.\n */\n private solveBend(firstFree: number): void {\n const p = this.pos\n const { stiffness, crease } = this.params\n const start = Math.max(firstFree + 1, 1)\n for (let i = start; i < this.count - 1; i++) {\n const hinge = this.perforated[i]!\n // A perforation keeps a small fraction of the sheet's own stiffness.\n // Scaled by the node spacing so a panel bends the same however finely\n // the chain is cut: more joints over the same panel each do less.\n const k = (hinge !== 0 ? stiffness * 0.06 : stiffness) * 0.45 * this.bendScale\n if (k <= 0) continue\n const a = (i - 1) * 2\n const m = i * 2\n const b = (i + 1) * 2\n\n let ty = (p[a]! + p[b]!) * 0.5\n let tz = (p[a + 1]! + p[b + 1]!) * 0.5\n if (hinge !== 0 && crease > 0) {\n // A used roll remembers its creases: offset the rest position off the\n // chord, on the side this perforation folded to last time.\n let cy = p[b]! - p[a]!\n let cz = p[b + 1]! - p[a + 1]!\n const len = Math.hypot(cy, cz)\n if (len > 1e-9) {\n cy /= len\n cz /= len\n const bow = crease * this.segment * 0.35 * hinge\n ty += -cz * bow\n tz += cy * bow\n }\n }\n\n const dy = (ty - p[m]!) * k\n const dz = (tz - p[m + 1]!) * k\n if (i !== this.grabbed) {\n p[m] = p[m]! + dy\n p[m + 1] = p[m + 1]! + dz\n }\n // Push the neighbours the other way so bending cannot drag the chain.\n if (i - 1 >= firstFree && i - 1 !== this.grabbed) {\n p[a] = p[a]! - dy * 0.5\n p[a + 1] = p[a + 1]! - dz * 0.5\n }\n if (i + 1 !== this.grabbed) {\n p[b] = p[b]! - dy * 0.5\n p[b + 1] = p[b + 1]! - dz * 0.5\n }\n }\n }\n\n /**\n * Folds stack on each other instead of passing through. Without this the\n * pile collapses into a single flat line on the floor and there is nothing\n * to look at, which is the entire reason the preset exists.\n *\n * **Segment against segment, not node against node.** The obvious version\n * puts a sphere on every node and pushes overlapping pairs apart, and it\n * leaks: paper is thinner than the chain is finely cut — the layer gap here\n * is 0.027 against a node spacing of 0.037 — so those spheres do not touch\n * each other, and the chain is a string of beads with gaps between them\n * rather than a continuous tube. Another fold threads straight through a\n * gap, and once it is through, the point test pushes it out the far side\n * instead of back. It shows up exactly as a sheet edge buried in a surface.\n *\n * Testing the SEGMENTS closes the gaps, because a segment is the whole\n * length of paper between two nodes and not just its ends. The cost is a\n * closest-approach solve per candidate pair instead of a subtraction, which\n * is why the hash cell is sized to `segment + d`: a pair that can possibly\n * touch has its midpoints inside that, so a 3×3 neighbourhood is a complete\n * search rather than a hopeful one.\n *\n * Spatial hash over preallocated arrays, refilled by counting sort — no\n * allocation, and it does not degrade when the whole strip lands in one\n * cell, which is exactly what a pile IS.\n */\n private solveSelfCollision(firstFree: number): void {\n this.freeFrom = firstFree\n const p = this.pos\n const d = Math.max(layerThickness(this.params.tightness), 1e-4)\n const n = this.count\n const last = n - 2 // index of the final segment (i, i+1)\n if (last < firstFree + 2) return\n const cell = this.segment + d\n const inv = 1 / cell\n const table = this.tableSize\n const mask = table - 1\n\n const starts = this.bucketStart\n const items = this.bucketItems\n const placed = this.bucketFill\n starts.fill(0)\n placed.fill(0)\n\n // Hash each segment by its midpoint.\n for (let i = firstFree; i <= last; i++) {\n const my = (p[i * 2]! + p[(i + 1) * 2]!) * 0.5\n const mz = (p[i * 2 + 1]! + p[(i + 1) * 2 + 1]!) * 0.5\n const h = (((Math.floor(my * inv) * 92837111) ^ (Math.floor(mz * inv) * 689287499)) >>> 0) & mask\n this.cellOf[i] = h\n starts[h + 1]!++\n }\n for (let c = 0; c < table; c++) starts[c + 1]! += starts[c]!\n for (let i = firstFree; i <= last; i++) {\n const h = this.cellOf[i]!\n items[starts[h]! + placed[h]!++] = i\n }\n\n for (let i = firstFree; i <= last; i++) {\n const my = (p[i * 2]! + p[(i + 1) * 2]!) * 0.5\n const mz = (p[i * 2 + 1]! + p[(i + 1) * 2 + 1]!) * 0.5\n const cy = Math.floor(my * inv)\n const cz = Math.floor(mz * inv)\n for (let oy = -1; oy <= 1; oy++) {\n for (let oz = -1; oz <= 1; oz++) {\n const h = ((((cy + oy) * 92837111) ^ ((cz + oz) * 689287499)) >>> 0) & mask\n const end = starts[h + 1]!\n for (let e = starts[h]!; e < end; e++) {\n const j = items[e]!\n // Each pair once, and never segments that share a node or sit next\n // to one — those are held by the distance and bend constraints,\n // and separating them would only fight those.\n if (j >= i + 2) this.separate(i, j, d)\n }\n }\n }\n }\n }\n\n /**\n * Push segments `(i, i+1)` and `(j, j+1)` apart to `d`, if they are closer.\n *\n * Closest approach between two 2D segments, then the correction shared over\n * the four endpoints by how near each is to the touching point — so a fold\n * caught at its middle moves bodily, and one grazed at its tip barely\n * pivots. Wound and held nodes are the roll's and the hand's, so they take\n * none of it and their partner takes the lot.\n */\n private separate(i: number, j: number, d: number): void {\n const p = this.pos\n const a = i * 2\n const b = (i + 1) * 2\n const c = j * 2\n const e = (j + 1) * 2\n\n const uy = p[b]! - p[a]!\n const uz = p[b + 1]! - p[a + 1]!\n const vy = p[e]! - p[c]!\n const vz = p[e + 1]! - p[c + 1]!\n const wy = p[a]! - p[c]!\n const wz = p[a + 1]! - p[c + 1]!\n\n const uu = uy * uy + uz * uz\n const vv = vy * vy + vz * vz\n if (uu < 1e-12 || vv < 1e-12) return\n const uv = uy * vy + uz * vz\n const uw = uy * wy + uz * wz\n const vw = vy * wy + vz * wz\n\n const denom = uu * vv - uv * uv\n let s = denom > 1e-12 ? (uv * vw - vv * uw) / denom : 0\n s = s < 0 ? 0 : s > 1 ? 1 : s\n let t = (uv * s + vw) / vv\n if (t < 0) {\n t = 0\n s = -uw / uu\n } else if (t > 1) {\n t = 1\n s = (uv - uw) / uu\n }\n s = s < 0 ? 0 : s > 1 ? 1 : s\n\n let ny = p[c]! + vy * t - (p[a]! + uy * s)\n let nz = p[c + 1]! + vz * t - (p[a + 1]! + uz * s)\n let dist = Math.hypot(ny, nz)\n if (dist >= d) return\n if (dist < 1e-9) {\n // Exactly through each other: separate along this segment's own normal,\n // which is the only direction left that means anything.\n ny = -uz\n nz = uy\n dist = Math.hypot(ny, nz)\n if (dist < 1e-12) return\n ny = -ny\n nz = -nz\n }\n\n const push = ((d - dist) / dist) * COLLISION_RELAXATION\n const gy = ny * push\n const gz = nz * push\n // Normalized so the touching point itself moves the full correction.\n const ki = 0.5 / ((1 - s) * (1 - s) + s * s)\n const kj = 0.5 / ((1 - t) * (1 - t) + t * t)\n this.nudge(i, -gy * (1 - s) * ki, -gz * (1 - s) * ki)\n this.nudge(i + 1, -gy * s * ki, -gz * s * ki)\n this.nudge(j, gy * (1 - t) * kj, gz * (1 - t) * kj)\n this.nudge(j + 1, gy * t * kj, gz * t * kj)\n }\n\n /** First free node for the substep in flight — `nudge` runs in the innermost\n * collision loop and must not recompute it per call. */\n private freeFrom = 0\n\n /** Move a node, unless the roll or the hand owns it. */\n private nudge(i: number, dy: number, dz: number): void {\n if (i === this.grabbed || i < this.freeFrom) return\n this.pos[i * 2] = this.pos[i * 2]! + dy\n this.pos[i * 2 + 1] = this.pos[i * 2 + 1]! + dz\n }\n\n /** Restitution 0, friction high. Paper lands and stays; it does not slide. */\n private solveFloor(firstFree: number): void {\n const p = this.pos\n // Sim-space: the floor is `floor` below the roll's axis. The centring\n // offset is applied on the way OUT, in writeInto, so the solver never has\n // to carry it.\n const floor = -this.params.floor\n for (let i = firstFree; i < this.count; i++) {\n const o = i * 2\n // A hand may hold paper anywhere, including below the ground line.\n if (i === this.grabbed || p[o]! >= floor) continue\n p[o] = floor\n // Kill the bounce outright, and almost all of the slide with it.\n this.prev[o] = floor\n this.prev[o + 1] = this.prev[o + 1]! + (p[o + 1]! - this.prev[o + 1]!) * 0.92\n }\n }\n\n /**\n * Write the chain into a 2×N quad strip, in PlaneGeometry vertex order:\n * row-major, top row first, x left→right. Row `i` is node `i`, so the\n * content texture runs down the strip and folds with it.\n */\n writeInto(out: Float32Array): void {\n const lift = this.centreOffset\n const shift = this.centreShift\n for (let i = 0; i < this.count; i++) {\n const o = i * 2\n const y = this.pos[o]! + lift\n const z = this.pos[o + 1]! + shift\n const v = i * 6\n out[v] = -this.halfWidth\n out[v + 1] = y\n out[v + 2] = z\n out[v + 3] = this.halfWidth\n out[v + 4] = y\n out[v + 5] = z\n }\n }\n}\n","import * as THREE from 'three'\nimport { useEffect, useMemo } from 'react'\nimport { useFrame } from '@react-three/fiber'\nimport CustomShaderMaterial from 'three-custom-shader-material'\nimport type { LightingName, SurfaceConfig } from '../config/schema'\nimport type { Stock } from '../core/stock'\nimport { composeSurface } from './compose'\nimport { resolveCreases, type CreaseShading } from './creases'\nimport { useLightRig } from '../scene/rig'\nimport { DAMAGE_LOOK_DEFAULTS, type DamageSource } from './damageContract'\nimport { useDamageTexture } from './useDamageTexture'\n\nexport interface PaperMaterialProps {\n stock: Stock\n texture: THREE.Texture | null\n /** content.back rendered on the reverse side (stock color otherwise). */\n backTexture?: THREE.Texture | null\n surface: SurfaceConfig\n thickness: number\n /** World dims — perforation holes are sized in world units. */\n sheet?: { width: number; height: number }\n /**\n * Scene lighting — transmission is measured against its key light. A\n * `<LightRig>` above this material wins over it: in a stage the paper is\n * lit by the hall, not by the preset it was authored with.\n */\n lighting?: LightingName\n /**\n * Crease lines to draw, resolved from `surface.creaseLines` plus whatever\n * the sheet remembers being folded along. Left off, only the authored ones\n * render — which is what a material with no memory behind it should do.\n */\n creases?: CreaseShading[]\n /** Char, wet, heat and missing paper over the sheet's UV. See `DamageSource`. */\n damage?: DamageSource | null\n}\n\n/**\n * The paper's skin: MeshStandardMaterial (real lighting preserved) extended\n * with the composed surface-effect chunks. Content textures are sampled by\n * OUR fragment (not material.map) so front and back faces can differ — real\n * paper doesn't mirror its front through the sheet. Programs rebuild only\n * on structure change; value edits mutate uniforms in place.\n */\nexport function PaperMaterial({\n stock,\n texture,\n backTexture,\n surface,\n thickness,\n sheet,\n lighting = 'studio',\n creases,\n damage,\n}: PaperMaterialProps) {\n const rig = useLightRig(lighting)\n const damageTexture = useDamageTexture(damage)\n const composed = composeSurface(\n surface,\n stock,\n thickness,\n {\n hasFrontMap: Boolean(texture),\n hasBackMap: Boolean(backTexture),\n hasDamage: Boolean(damageTexture),\n },\n sheet,\n rig,\n creases ?? resolveCreases(surface, [], sheet ?? { width: 1, height: 1.4 }),\n )\n\n // Uniform objects bound to the current program; stable per structure.\n // biome-ignore lint/correctness/useExhaustiveDependencies: Uniform objects are bound per shader program — rebinding on value change would drop the binding every frame.\n const bound = useMemo(() => composed.uniforms, [composed.structureKey])\n useEffect(() => {\n for (const [key, uniform] of Object.entries(composed.uniforms)) {\n if (\n !bound[key] ||\n key === 'uFrontMap' ||\n key === 'uBackMap' ||\n key === 'uDamage' ||\n key === 'uDamageDetail' ||\n key === 'uDamageTime' ||\n key.startsWith('uLook')\n ) {\n continue\n }\n if (bound[key].value instanceof THREE.Color && uniform.value instanceof THREE.Color) {\n ;(bound[key].value as THREE.Color).copy(uniform.value)\n } else {\n bound[key].value = uniform.value\n }\n }\n })\n useEffect(() => {\n if (bound.uFrontMap) bound.uFrontMap.value = texture\n if (bound.uBackMap) bound.uBackMap.value = backTexture ?? null\n if (bound.uDamage) bound.uDamage.value = damageTexture\n }, [bound, texture, backTexture, damageTexture])\n // The fray follows the quality tier, which can change at any moment, so it\n // is read off the source each frame rather than baked into the program.\n useFrame((state) => {\n if (!bound.uDamageDetail) return\n // The burn's clock when it has one, so a replayed burn's ember line\n // flickers the same way twice; the frame clock otherwise. Clamped for the\n // same reason `detail` is.\n if (bound.uDamageTime) {\n const time = damage?.time ?? state.clock.elapsedTime\n bound.uDamageTime.value = Number.isFinite(time) ? time : 0\n }\n // How the burn is drawn, from the source's look over the defaults. Read\n // each frame like `detail`, so a slider in a lab moves it live.\n if (bound.uLook0) {\n const look = { ...DAMAGE_LOOK_DEFAULTS, ...damage?.look }\n const v = (x: number, d: number) => (Number.isFinite(x) ? x : d)\n const d = DAMAGE_LOOK_DEFAULTS\n ;(bound.uLook0.value as THREE.Vector4).set(\n v(look.emberWidth, d.emberWidth),\n v(look.emberIntensity, d.emberIntensity),\n v(look.emberCoverage, d.emberCoverage),\n v(look.emberFlicker, d.emberFlicker),\n )\n ;(bound.uLook1!.value as THREE.Vector4).set(\n v(look.emberGlow, d.emberGlow),\n v(look.lipWidth, d.lipWidth),\n v(look.lipBrightness, d.lipBrightness),\n v(look.charWarmth, d.charWarmth),\n )\n ;(bound.uLook2!.value as THREE.Vector4).set(\n v(look.charCracks, d.charCracks),\n v(look.scorchReach, d.scorchReach),\n v(look.scorchDarkness, d.scorchDarkness),\n v(look.fingers, d.fingers),\n )\n ;(bound.uLook3!.value as THREE.Vector4).set(\n v(look.edgeWave, d.edgeWave),\n v(look.edgeBite, d.edgeBite),\n v(look.sparkle, d.sparkle),\n 0,\n )\n }\n // Clamped rather than trusted: `detail` is a number on a public\n // interface, and an infinite one reaching the shader is multiplied by a\n // zero somewhere in the fray and paints NaN across the whole sheet.\n const detail = damage?.detail ?? 1\n bound.uDamageDetail.value = Number.isFinite(detail) ? Math.min(1, Math.max(0, detail)) : 1\n })\n\n return (\n <>\n <CustomShaderMaterial\n key={composed.structureKey}\n baseMaterial={THREE.MeshStandardMaterial}\n vertexShader={composed.vertexShader}\n fragmentShader={composed.fragmentShader}\n uniforms={bound}\n color=\"#ffffff\"\n roughness={stock.roughness}\n metalness={0}\n transparent={stock.opacity < 1}\n opacity={stock.opacity}\n alphaTest={composed.alphaTest}\n side={THREE.DoubleSide}\n />\n {/*\n What the shadow pass draws, when this sheet removes paper — see\n `ComposedSurface.depth`. Same uniforms object as the colour program,\n so the damage texture, the deckle and the perforation state are the\n ones the viewer sees. RGBA packing, which is what three's shadow maps\n read; three copies `side` and `alphaTest` over from the colour\n material itself.\n */}\n {composed.depth ? (\n <CustomShaderMaterial\n key={`${composed.structureKey}:depth`}\n attach=\"customDepthMaterial\"\n baseMaterial={THREE.MeshDepthMaterial}\n vertexShader={composed.depth.vertexShader}\n fragmentShader={composed.depth.fragmentShader}\n uniforms={bound}\n depthPacking={THREE.RGBADepthPacking}\n />\n ) : null}\n </>\n )\n}\n","export const defaultCsmDefinitions = /* glsl */ `\r\n \r\n#ifdef IS_VERTEX\r\n vec3 csm_Position;\r\n vec4 csm_PositionRaw;\r\n vec3 csm_Normal;\r\n\r\n // csm_PointSize\r\n #ifdef IS_POINTSMATERIAL\r\n float csm_PointSize;\r\n #endif\r\n#else\r\n vec4 csm_DiffuseColor;\r\n vec4 csm_FragColor;\r\n float csm_UnlitFac;\r\n\r\n // csm_Emissive, csm_Roughness, csm_Metalness\r\n #if defined IS_MESHSTANDARDMATERIAL || defined IS_MESHPHYSICALMATERIAL\r\n vec3 csm_Emissive;\r\n float csm_Roughness;\r\n float csm_Metalness;\r\n float csm_Iridescence;\r\n \r\n #if defined IS_MESHPHYSICALMATERIAL\r\n float csm_Clearcoat;\r\n float csm_ClearcoatRoughness;\r\n vec3 csm_ClearcoatNormal;\r\n float csm_Transmission;\r\n float csm_Thickness;\r\n #endif\r\n #endif\r\n\r\n // csm_AO\r\n #if defined IS_MESHSTANDARDMATERIAL || defined IS_MESHPHYSICALMATERIAL || defined IS_MESHBASICMATERIAL || defined IS_MESHLAMBERTMATERIAL || defined IS_MESHPHONGMATERIAL || defined IS_MESHTOONMATERIAL\r\n float csm_AO;\r\n #endif\r\n\r\n // csm_FragNormal\r\n #if defined IS_MESHLAMBERTMATERIAL || defined IS_MESHMATCAPMATERIAL || defined IS_MESHNORMALMATERIAL || defined IS_MESHPHONGMATERIAL || defined IS_MESHPHYSICALMATERIAL || defined IS_MESHSTANDARDMATERIAL || defined IS_MESHTOONMATERIAL || defined IS_SHADOWMATERIAL \r\n vec3 csm_FragNormal;\r\n #endif\r\n\r\n float csm_DepthAlpha;\r\n#endif\r\n`;\r\n\r\nexport const defaultCsmMainDefinitions = /* glsl */ `\r\n\r\n#ifdef IS_VERTEX\r\n // csm_Position & csm_PositionRaw\r\n #ifdef IS_UNKNOWN\r\n csm_Position = vec3(0.0);\r\n csm_PositionRaw = vec4(0.0);\r\n csm_Normal = vec3(0.0);\r\n #else\r\n csm_Position = position;\r\n csm_PositionRaw = projectionMatrix * modelViewMatrix * vec4(position, 1.);\r\n csm_Normal = normal;\r\n #endif\r\n\r\n // csm_PointSize\r\n #ifdef IS_POINTSMATERIAL\r\n csm_PointSize = size;\r\n #endif\r\n#else\r\n csm_UnlitFac = 0.0;\r\n\r\n // csm_DiffuseColor & csm_FragColor\r\n #if defined IS_UNKNOWN || defined IS_SHADERMATERIAL || defined IS_MESHDEPTHMATERIAL || defined IS_MESHDISTANCEMATERIAL || defined IS_MESHNORMALMATERIAL || defined IS_SHADOWMATERIAL\r\n csm_DiffuseColor = vec4(1.0, 0.0, 1.0, 1.0);\r\n csm_FragColor = vec4(1.0, 0.0, 1.0, 1.0);\r\n #else\r\n #ifdef USE_MAP\r\n vec4 _csm_sampledDiffuseColor = texture2D(map, vMapUv);\r\n\r\n #ifdef DECODE_VIDEO_TEXTURE\r\n // inline sRGB decode (TODO: Remove this code when https://crbug.com/1256340 is solved)\r\n _csm_sampledDiffuseColor = vec4(mix(pow(_csm_sampledDiffuseColor.rgb * 0.9478672986 + vec3(0.0521327014), vec3(2.4)), _csm_sampledDiffuseColor.rgb * 0.0773993808, vec3(lessThanEqual(_csm_sampledDiffuseColor.rgb, vec3(0.04045)))), _csm_sampledDiffuseColor.w);\r\n #endif\r\n\r\n csm_DiffuseColor = vec4(diffuse, opacity) * _csm_sampledDiffuseColor;\r\n csm_FragColor = vec4(diffuse, opacity) * _csm_sampledDiffuseColor;\r\n #else\r\n csm_DiffuseColor = vec4(diffuse, opacity);\r\n csm_FragColor = vec4(diffuse, opacity);\r\n #endif\r\n #endif\r\n\r\n // csm_Emissive, csm_Roughness, csm_Metalness\r\n #if defined IS_MESHSTANDARDMATERIAL || defined IS_MESHPHYSICALMATERIAL\r\n csm_Emissive = emissive;\r\n csm_Roughness = roughness;\r\n csm_Metalness = metalness;\r\n\r\n #ifdef USE_IRIDESCENCE\r\n csm_Iridescence = iridescence;\r\n #else\r\n csm_Iridescence = 0.0;\r\n #endif\r\n\r\n #if defined IS_MESHPHYSICALMATERIAL\r\n #ifdef USE_CLEARCOAT\r\n csm_Clearcoat = clearcoat;\r\n csm_ClearcoatRoughness = clearcoatRoughness;\r\n #else\r\n csm_Clearcoat = 0.0;\r\n csm_ClearcoatRoughness = 0.0;\r\n #endif\r\n\r\n #ifdef USE_TRANSMISSION\r\n csm_Transmission = transmission;\r\n csm_Thickness = thickness;\r\n #else\r\n csm_Transmission = 0.0;\r\n csm_Thickness = 0.0;\r\n #endif\r\n #endif\r\n #endif\r\n\r\n // csm_AO\r\n #if defined IS_MESHSTANDARDMATERIAL || defined IS_MESHPHYSICALMATERIAL || defined IS_MESHBASICMATERIAL || defined IS_MESHLAMBERTMATERIAL || defined IS_MESHPHONGMATERIAL || defined IS_MESHTOONMATERIAL\r\n csm_AO = 0.0;\r\n #endif\r\n\r\n #if defined IS_MESHLAMBERTMATERIAL || defined IS_MESHMATCAPMATERIAL || defined IS_MESHNORMALMATERIAL || defined IS_MESHPHONGMATERIAL || defined IS_MESHPHYSICALMATERIAL || defined IS_MESHSTANDARDMATERIAL || defined IS_MESHTOONMATERIAL || defined IS_SHADOWMATERIAL \r\n #ifdef FLAT_SHADED\r\n vec3 fdx = dFdx( vViewPosition );\r\n vec3 fdy = dFdy( vViewPosition );\r\n csm_FragNormal = normalize( cross( fdx, fdy ) );\r\n #else\r\n csm_FragNormal = normalize(vNormal);\r\n #ifdef DOUBLE_SIDED\r\n csm_FragNormal *= gl_FrontFacing ? 1.0 : - 1.0;\r\n #endif\r\n #endif\r\n #endif\r\n\r\n csm_DepthAlpha = 1.0;\r\n#endif\r\n`;\r\n\r\nexport const defaultVertDefinitions = /* glsl */ `\r\n varying mat4 csm_internal_vModelViewMatrix;\r\n`;\r\n\r\nexport const defaultVertMain = /* glsl */ `\r\n csm_internal_vModelViewMatrix = modelViewMatrix;\r\n`;\r\n\r\nexport const defaultFragDefinitions = /* glsl */ `\r\n varying mat4 csm_internal_vModelViewMatrix;\r\n`;\r\n\r\nexport const defaultFragMain = /* glsl */ `\r\n \r\n`;\r\n","export const keywordMap = {\r\n // PBR (frag)\r\n diffuse: \"csm_DiffuseColor\", // Color + alpha\r\n roughness: \"csm_Roughness\", // Roughness\r\n metalness: \"csm_Metalness\", // Metalness\r\n emissive: \"csm_Emissive\", // Emissive\r\n ao: \"csm_AO\", // AO\r\n fragNormal: \"csm_FragNormal\", // Fragment Normal\r\n clearcoat: \"csm_Clearcoat\", // Clearcoat factor\r\n clearcoatRoughness: \"csm_ClearcoatRoughness\", // Clearcoat roughness\r\n clearcoatNormal: \"csm_ClearcoatNormal\", // Clearcoat normals\r\n transmission: \"csm_Transmission\", // Transmission\r\n thickness: \"csm_Thickness\", // Thickness\r\n iridescence: \"csm_Iridescence\", // Iridescence\r\n\r\n // Extras\r\n pointSize: \"csm_PointSize\", // gl_PointSize (Frag)\r\n fragColor: \"csm_FragColor\", // gl_FragColor (Frag)\r\n depthAlpha: \"csm_DepthAlpha\", // Depth (MeshDepthMaterial)\r\n unlitFac: \"csm_UnlitFac\", // Unlit factor (mix between csm_FragColor and csm_DiffuseColor)\r\n\r\n // Vert\r\n position: \"csm_Position\", // gl_Position\r\n positionRaw: \"csm_PositionRaw\", // gl_Position (without projection)\r\n normal: \"csm_Normal\", // Vertex Normal\r\n};\r\n","import { keywordMap } from \"./keywordMap\";\r\n\r\n// Map of CSM keywords to the materials they are available in\r\n// Some keywords are only available in certain materials\r\nexport const availabilityMap = {\r\n [`${keywordMap.position}`]: \"*\",\r\n [`${keywordMap.positionRaw}`]: \"*\",\r\n [`${keywordMap.normal}`]: \"*\",\r\n [`${keywordMap.depthAlpha}`]: \"*\",\r\n [`${keywordMap.pointSize}`]: [\"PointsMaterial\"],\r\n\r\n [`${keywordMap.diffuse}`]: \"*\",\r\n [`${keywordMap.fragColor}`]: \"*\",\r\n [`${keywordMap.fragNormal}`]: \"*\",\r\n [`${keywordMap.unlitFac}`]: \"*\",\r\n [`${keywordMap.emissive}`]: [\"MeshStandardMaterial\", \"MeshPhysicalMaterial\"],\r\n [`${keywordMap.roughness}`]: [\"MeshStandardMaterial\", \"MeshPhysicalMaterial\"],\r\n [`${keywordMap.metalness}`]: [\"MeshStandardMaterial\", \"MeshPhysicalMaterial\"],\r\n [`${keywordMap.iridescence}`]: [\r\n \"MeshStandardMaterial\",\r\n \"MeshPhysicalMaterial\",\r\n ],\r\n [`${keywordMap.ao}`]: [\r\n \"MeshStandardMaterial\",\r\n \"MeshPhysicalMaterial\",\r\n \"MeshBasicMaterial\",\r\n \"MeshLambertMaterial\",\r\n \"MeshPhongMaterial\",\r\n \"MeshToonMaterial\",\r\n ],\r\n [`${keywordMap.clearcoat}`]: [\"MeshPhysicalMaterial\"],\r\n [`${keywordMap.clearcoatRoughness}`]: [\"MeshPhysicalMaterial\"],\r\n [`${keywordMap.clearcoatNormal}`]: [\"MeshPhysicalMaterial\"],\r\n [`${keywordMap.transmission}`]: [\"MeshPhysicalMaterial\"],\r\n [`${keywordMap.thickness}`]: [\"MeshPhysicalMaterial\"],\r\n};\r\n","import * as THREE from \"three\";\r\nimport { CSMPatchMap } from \"../types\";\r\nimport { keywordMap } from \"./keywordMap\";\r\n\r\n// Map of CSM keywords to their substitutions\r\nexport const defaultPatchMap: CSMPatchMap = {\r\n // VERT\r\n \"*\": {\r\n \"#include <lights_physical_fragment>\":\r\n THREE.ShaderChunk.lights_physical_fragment,\r\n \"#include <transmission_fragment>\": THREE.ShaderChunk.transmission_fragment,\r\n },\r\n [`${keywordMap.normal}`]: {\r\n \"#include <beginnormal_vertex>\": `\r\n vec3 objectNormal = ${keywordMap.normal};\r\n #ifdef USE_TANGENT\r\n\t vec3 objectTangent = vec3( tangent.xyz );\r\n #endif\r\n `,\r\n },\r\n [`${keywordMap.position}`]: {\r\n \"#include <begin_vertex>\": `\r\n vec3 transformed = ${keywordMap.position};\r\n `,\r\n },\r\n [`${keywordMap.positionRaw}`]: {\r\n \"#include <project_vertex>\": `\r\n #include <project_vertex>\r\n gl_Position = ${keywordMap.positionRaw};\r\n `,\r\n },\r\n [`${keywordMap.pointSize}`]: {\r\n \"gl_PointSize = size;\": `\r\n gl_PointSize = ${keywordMap.pointSize};\r\n `,\r\n },\r\n\r\n // FRAG\r\n\r\n [`${keywordMap.diffuse}`]: {\r\n \"#include <color_fragment>\": `\r\n #include <color_fragment>\r\n diffuseColor = ${keywordMap.diffuse};\r\n `,\r\n },\r\n [`${keywordMap.fragColor}`]: {\r\n \"#include <opaque_fragment>\": `\r\n #include <opaque_fragment>\r\n gl_FragColor = mix(gl_FragColor, ${keywordMap.fragColor}, ${keywordMap.unlitFac});\r\n `,\r\n },\r\n [`${keywordMap.emissive}`]: {\r\n \"vec3 totalEmissiveRadiance = emissive;\": `\r\n vec3 totalEmissiveRadiance = ${keywordMap.emissive};\r\n `,\r\n },\r\n [`${keywordMap.roughness}`]: {\r\n \"#include <roughnessmap_fragment>\": `\r\n #include <roughnessmap_fragment>\r\n roughnessFactor = ${keywordMap.roughness};\r\n `,\r\n },\r\n [`${keywordMap.metalness}`]: {\r\n \"#include <metalnessmap_fragment>\": `\r\n #include <metalnessmap_fragment>\r\n metalnessFactor = ${keywordMap.metalness};\r\n `,\r\n },\r\n [`${keywordMap.ao}`]: {\r\n \"#include <aomap_fragment>\": `\r\n #include <aomap_fragment>\r\n reflectedLight.indirectDiffuse *= 1. - ${keywordMap.ao};\r\n `,\r\n },\r\n [`${keywordMap.fragNormal}`]: {\r\n \"#include <normal_fragment_maps>\": `\r\n #include <normal_fragment_maps>\r\n normal = ${keywordMap.fragNormal};\r\n `,\r\n },\r\n [`${keywordMap.depthAlpha}`]: {\r\n \"gl_FragColor = vec4( vec3( 1.0 - fragCoordZ ), opacity );\": `\r\n gl_FragColor = vec4( vec3( 1.0 - fragCoordZ ), opacity * 1.0 - ${keywordMap.depthAlpha} );\r\n `,\r\n \"gl_FragColor = packDepthToRGBA( fragCoordZ );\": `\r\n if(${keywordMap.depthAlpha} < 1.0) discard;\r\n gl_FragColor = packDepthToRGBA( dist );\r\n `,\r\n \"gl_FragColor = packDepthToRGBA( dist );\": `\r\n if(${keywordMap.depthAlpha} < 1.0) discard;\r\n gl_FragColor = packDepthToRGBA( dist );\r\n `,\r\n },\r\n [`${keywordMap.clearcoat}`]: {\r\n \"material.clearcoat = clearcoat;\": `material.clearcoat = ${keywordMap.clearcoat};`,\r\n },\r\n [`${keywordMap.clearcoatRoughness}`]: {\r\n \"material.clearcoatRoughness = clearcoatRoughness;\": `material.clearcoatRoughness = ${keywordMap.clearcoatRoughness};`,\r\n },\r\n [`${keywordMap.clearcoatNormal}`]: {\r\n \"#include <clearcoat_normal_fragment_begin>\": `\r\n vec3 csm_coat_internal_orthogonal = csm_ClearcoatNormal - (dot(csm_ClearcoatNormal, nonPerturbedNormal) * nonPerturbedNormal);\r\n vec3 csm_coat_internal_projectedbump = mat3(csm_internal_vModelViewMatrix) * csm_coat_internal_orthogonal;\r\n vec3 clearcoatNormal = normalize(nonPerturbedNormal - csm_coat_internal_projectedbump);\r\n `,\r\n },\r\n [`${keywordMap.transmission}`]: {\r\n \"material.transmission = transmission;\": `\r\n material.transmission = ${keywordMap.transmission};\r\n `,\r\n },\r\n [`${keywordMap.thickness}`]: {\r\n \"material.thickness = thickness;\": `\r\n material.thickness = ${keywordMap.thickness};\r\n `,\r\n },\r\n [`${keywordMap.iridescence}`]: {\r\n \"material.iridescence = iridescence;\": `\r\n material.iridescence = ${keywordMap.iridescence};\r\n `,\r\n },\r\n};\r\n","import { keywordMap } from \"./keywordMap\";\r\n\r\n/**\r\n * Map of props to their keywords\r\n * this is because Three only injects some defines if certain properties are set in the material options.\r\n *\r\n * For example, \"clearcoat\" must be set for 3js to include the #USE_CLEARCOAT define in the shader.\r\n * and thus for our custom clearcoar variant to work\r\n */\r\nexport const requiredPropsMap = {\r\n clearcoat: [\r\n keywordMap.clearcoat,\r\n keywordMap.clearcoatNormal,\r\n keywordMap.clearcoatRoughness,\r\n ],\r\n transmission: [keywordMap.transmission],\r\n iridescence: [keywordMap.iridescence],\r\n};\r\n","//https://github.com/sindresorhus/sdbm\r\n\r\nexport default function sdbm(string) {\r\n let hash = 0;\r\n\r\n for (let i = 0; i < string.length; i++) {\r\n hash = string.charCodeAt(i) + (hash << 6) + (hash << 16) - hash;\r\n }\r\n\r\n // Convert it to an unsigned 32-bit integer.\r\n const h = hash >>> 0;\r\n const str = String(h);\r\n return str;\r\n}\r\n","import { MaterialConstructor } from \"./types\";\r\n\r\n// Hacky, yikes!\r\nexport function isConstructor<T extends MaterialConstructor>(\r\n f: T | InstanceType<T>\r\n): f is T {\r\n try {\r\n // @ts-ignore\r\n new f();\r\n } catch (err) {\r\n if ((err as any).message.indexOf(\"is not a constructor\") >= 0) {\r\n return false;\r\n }\r\n }\r\n return true;\r\n}\r\n\r\n// Remove all comments in a string\r\n// both block and inline comments\r\nexport function stripComments(str: string) {\r\n return str.replace(/\\/\\*[\\s\\S]*?\\*\\/|\\/\\/.*/g, \"\");\r\n}\r\n","import * as THREE from \"three\";\r\nimport {\r\n defaultCsmDefinitions,\r\n defaultCsmMainDefinitions,\r\n defaultFragDefinitions,\r\n defaultFragMain,\r\n defaultVertDefinitions,\r\n defaultVertMain,\r\n} from \"./defaults\";\r\nimport { availabilityMap, defaultPatchMap, keywordMap } from \"./maps\";\r\nimport { requiredPropsMap } from \"./maps/requiredPropsMap\";\r\nimport hash from \"./sdbm\";\r\nimport * as TYPES from \"./types\";\r\nimport { isConstructor, stripComments } from \"./utils\";\r\n\r\nexport default class CustomShaderMaterial<\r\n T extends TYPES.MaterialConstructor = typeof THREE.Material\r\n> extends THREE.Material {\r\n uniforms: TYPES.Uniform = {};\r\n vertexShader: string = \"\";\r\n fragmentShader: string = \"\";\r\n\r\n constructor({\r\n baseMaterial,\r\n vertexShader,\r\n fragmentShader,\r\n uniforms,\r\n patchMap,\r\n cacheKey,\r\n ...opts\r\n }: TYPES.CustomShaderMaterialParameters<T>) {\r\n if (!baseMaterial) {\r\n throw new Error(\"CustomShaderMaterial: baseMaterial is required.\");\r\n }\r\n\r\n let base: THREE.Material;\r\n if (isConstructor(baseMaterial)) {\r\n // If base material is a constructor, instantiate it\r\n // if opts is empty, replace it with undefined\r\n const isEmptyOpts = Object.keys(opts).length === 0;\r\n base = new baseMaterial(isEmptyOpts ? undefined : opts);\r\n } else {\r\n // Else, use the already created instance as the base material\r\n // and copy options onto it\r\n base = baseMaterial;\r\n Object.assign(base, opts);\r\n }\r\n\r\n // Blacklist some materials that are not supported\r\n const blackList = [\"ShaderMaterial\", \"RawShaderMaterial\"];\r\n if (blackList.includes(base.type)) {\r\n throw new Error(\r\n `CustomShaderMaterial does not support ${base.type} as a base material.`\r\n );\r\n }\r\n\r\n super();\r\n\r\n // Return a proxy to the base material with CSM types and methods\r\n const extendedBase = base as typeof base & TYPES.CSMProxy<T>;\r\n extendedBase.name = `CustomShaderMaterial<${base.name || base.type}>`;\r\n extendedBase.update = this.update;\r\n extendedBase.__csm = {\r\n prevOnBeforeCompile: base.onBeforeCompile,\r\n baseMaterial: base,\r\n vertexShader,\r\n fragmentShader,\r\n uniforms,\r\n patchMap,\r\n cacheKey,\r\n };\r\n\r\n const prevUniforms = extendedBase.uniforms || {};\r\n const newUniforms = uniforms || {};\r\n const mergedUniforms = { ...prevUniforms, ...newUniforms };\r\n\r\n extendedBase.uniforms = this.uniforms = mergedUniforms;\r\n extendedBase.vertexShader = this.vertexShader = vertexShader || \"\";\r\n extendedBase.fragmentShader = this.fragmentShader = fragmentShader || \"\";\r\n\r\n // Initialize custom shaders\r\n extendedBase.update({\r\n fragmentShader: extendedBase.fragmentShader,\r\n vertexShader: extendedBase.vertexShader,\r\n uniforms: extendedBase.uniforms,\r\n patchMap,\r\n cacheKey,\r\n });\r\n\r\n // Merge \"this\" with the extended base\r\n Object.assign(this, extendedBase);\r\n\r\n // Copy getters and setters from the base material\r\n const gettersAndSetters = Object.getOwnPropertyDescriptors(\r\n Object.getPrototypeOf(extendedBase)\r\n );\r\n\r\n for (const key in gettersAndSetters) {\r\n const descriptor = gettersAndSetters[key];\r\n if (descriptor.get || descriptor.set) {\r\n Object.defineProperty(this, key, descriptor);\r\n }\r\n }\r\n\r\n // Override type setter because of this BS: https://github.com/mrdoob/three.js/blob/841ca14e89f3ec925e071a321958e49a883343c0/src/materials/Material.js#L22\r\n Object.defineProperty(this, \"type\", {\r\n get() {\r\n return base.type;\r\n },\r\n set(value) {\r\n base.type = value;\r\n },\r\n });\r\n\r\n return this;\r\n }\r\n\r\n update({\r\n fragmentShader: _fs,\r\n vertexShader: _vs,\r\n uniforms,\r\n cacheKey,\r\n patchMap,\r\n }: Omit<TYPES.CustomShaderMaterialBaseParameters<T>, \"baseMaterial\">) {\r\n // Strip comments from shaders, makes it so that commented keywords are not detected\r\n const vertexShader = stripComments(_vs || \"\");\r\n const fragmentShader = stripComments(_fs || \"\");\r\n\r\n // Get typed `this` for the proxy\r\n const self = this as typeof this & TYPES.CSMProxy<T>;\r\n\r\n // Replace the shaders if they are provided\r\n if (uniforms) self.uniforms = uniforms;\r\n if (_vs) self.vertexShader = _vs;\r\n if (_fs) self.fragmentShader = _fs;\r\n\r\n // Some keywords require certain properties to be set for their chunks to be included via #ifdef\r\n // so we must check if the shaders contain these keywords and set the properties accordingly\r\n Object.entries(requiredPropsMap).forEach(([prop, matchKeywords]) => {\r\n for (const keyword in matchKeywords) {\r\n const matchKeyword = matchKeywords[keyword];\r\n if (\r\n (fragmentShader && fragmentShader.includes(matchKeyword)) ||\r\n (vertexShader && vertexShader.includes(matchKeyword))\r\n ) {\r\n // @ts-ignore\r\n if (!self[prop]) {\r\n // @ts-ignore\r\n self[prop] = 1;\r\n }\r\n }\r\n }\r\n });\r\n\r\n // Check it the previous onBeforeCompile exists\r\n const prevOnBeforeCompile = self.__csm.prevOnBeforeCompile;\r\n\r\n // Helper function to extend the shader\r\n const extendShader = (\r\n prevShader: string,\r\n newShader?: string,\r\n isFrag?: boolean\r\n ) => {\r\n let mainBody: string | undefined;\r\n let beforeMain: string = \"\";\r\n\r\n // Prepare the main body and beforeMain\r\n if (newShader) {\r\n // Simpler approach to extract main function body\r\n const mainStartIndex = newShader.search(/void\\s+main\\s*\\(\\s*\\)\\s*{/);\r\n if (mainStartIndex !== -1) {\r\n // Get everything before main function\r\n beforeMain = newShader.slice(0, mainStartIndex);\r\n\r\n // Find the matching closing brace using brace counting\r\n let braceCount = 0;\r\n let mainEndIndex = -1;\r\n\r\n for (let i = mainStartIndex; i < newShader.length; i++) {\r\n if (newShader[i] === \"{\") braceCount++;\r\n if (newShader[i] === \"}\") {\r\n braceCount--;\r\n if (braceCount === 0) {\r\n mainEndIndex = i;\r\n break;\r\n }\r\n }\r\n }\r\n\r\n if (mainEndIndex !== -1) {\r\n // Extract main body without the outer braces\r\n const fullMain = newShader.slice(mainStartIndex, mainEndIndex + 1);\r\n mainBody = fullMain.slice(fullMain.indexOf(\"{\") + 1, -1);\r\n }\r\n } else {\r\n beforeMain = newShader;\r\n }\r\n }\r\n\r\n // Set csm_UnlitFac if csm_FragColor is used to preserve\r\n // legacy behavior.\r\n if (isFrag) {\r\n const hasFragColor = newShader\r\n ? newShader.includes(keywordMap.fragColor)\r\n : false;\r\n if (hasFragColor && mainBody) {\r\n mainBody = \"csm_UnlitFac = 1.0;\\n\" + mainBody;\r\n }\r\n }\r\n\r\n const defaultsAlreadyIncluded = prevShader.includes(\"//~CSM_DEFAULTS\");\r\n\r\n // Inject\r\n if (defaultsAlreadyIncluded) {\r\n prevShader = prevShader.replace(\r\n \"void main() {\",\r\n `\r\n // THREE-CustomShaderMaterial by Faraz Shaikh: https://github.com/FarazzShaikh/THREE-CustomShaderMaterial\r\n \r\n ${beforeMain}\r\n \r\n void main() {\r\n `\r\n );\r\n\r\n const lastMainEndIndex = prevShader.lastIndexOf(\"//~CSM_MAIN_END\");\r\n\r\n if (lastMainEndIndex !== -1) {\r\n const toAppend = `\r\n ${mainBody ? `${mainBody}` : \"\"}\r\n //~CSM_MAIN_END\r\n `;\r\n prevShader =\r\n prevShader.slice(0, lastMainEndIndex) +\r\n toAppend +\r\n prevShader.slice(lastMainEndIndex);\r\n }\r\n } else {\r\n const regex = /void\\s*main\\s*\\(\\s*\\)\\s*{/gm;\r\n\r\n prevShader = prevShader.replace(\r\n regex,\r\n `\r\n // THREE-CustomShaderMaterial by Faraz Shaikh: https://github.com/FarazzShaikh/THREE-CustomShaderMaterial\r\n \r\n //~CSM_DEFAULTS\r\n ${isFrag ? defaultFragDefinitions : defaultVertDefinitions}\r\n ${defaultCsmDefinitions}\r\n \r\n ${beforeMain}\r\n \r\n void main() {\r\n {\r\n ${defaultCsmMainDefinitions}\r\n }\r\n ${isFrag ? defaultFragMain : defaultVertMain}\r\n\r\n ${mainBody ? `${mainBody}` : \"\"}\r\n //~CSM_MAIN_END\r\n `\r\n );\r\n }\r\n\r\n return prevShader;\r\n };\r\n\r\n // Override onBeforeCompile\r\n self.onBeforeCompile = (\r\n shader: THREE.WebGLProgramParametersWithUniforms,\r\n renderer: THREE.WebGLRenderer\r\n ) => {\r\n // Apply previous onBeforeCompile\r\n prevOnBeforeCompile?.(shader, renderer);\r\n\r\n const userPatchMap = patchMap || {};\r\n // const mergedPatchMap = { ...defaultPatchMap, ...userPatchMap };\r\n\r\n // Append some defines\r\n const type = self.type;\r\n const typeDefine = type\r\n ? `#define IS_${type.toUpperCase()};\\n`\r\n : `#define IS_UNKNOWN;\\n`;\r\n shader.vertexShader =\r\n typeDefine + \"#define IS_VERTEX\\n\" + shader.vertexShader;\r\n shader.fragmentShader =\r\n typeDefine + \"#define IS_FRAGMENT\\n\" + shader.fragmentShader;\r\n\r\n // Check if the keyword is available in the current material type\r\n const runPatchMap = (_patchMap: TYPES.CSMPatchMap) => {\r\n for (const keyword in _patchMap) {\r\n const doesIncludeInVert =\r\n keyword === \"*\" || (vertexShader && vertexShader.includes(keyword));\r\n const doesIncludeInFrag =\r\n keyword === \"*\" ||\r\n (fragmentShader && fragmentShader.includes(keyword));\r\n\r\n if (doesIncludeInFrag || doesIncludeInVert) {\r\n const availableIn = availabilityMap[keyword];\r\n\r\n if (\r\n availableIn &&\r\n availableIn !== \"*\" &&\r\n (Array.isArray(availableIn)\r\n ? !availableIn.includes(type)\r\n : availableIn !== type)\r\n ) {\r\n console.error(\r\n `CustomShaderMaterial: ${keyword} is not available in ${type}. Shader cannot compile.`\r\n );\r\n return;\r\n }\r\n\r\n const patchMap = _patchMap[keyword];\r\n\r\n for (const toReplace in patchMap) {\r\n const replaceWith = patchMap[toReplace];\r\n\r\n if (typeof replaceWith === \"object\") {\r\n const type = replaceWith.type;\r\n const value = replaceWith.value;\r\n\r\n if (type === \"fs\") {\r\n shader.fragmentShader = shader.fragmentShader.replace(\r\n toReplace,\r\n value\r\n );\r\n } else if (type === \"vs\") {\r\n shader.vertexShader = shader.vertexShader.replace(\r\n toReplace,\r\n value\r\n );\r\n }\r\n } else if (replaceWith) {\r\n shader.vertexShader = shader.vertexShader.replace(\r\n toReplace,\r\n replaceWith\r\n );\r\n shader.fragmentShader = shader.fragmentShader.replace(\r\n toReplace,\r\n replaceWith\r\n );\r\n }\r\n }\r\n }\r\n }\r\n };\r\n\r\n runPatchMap(defaultPatchMap);\r\n runPatchMap(userPatchMap);\r\n\r\n // Extend the shaders\r\n shader.vertexShader = extendShader(\r\n shader.vertexShader,\r\n vertexShader,\r\n false\r\n );\r\n\r\n shader.fragmentShader = extendShader(\r\n shader.fragmentShader,\r\n fragmentShader,\r\n true\r\n );\r\n\r\n if (uniforms) {\r\n shader.uniforms = { ...shader.uniforms, ...self.uniforms };\r\n }\r\n\r\n self.uniforms = shader.uniforms;\r\n };\r\n\r\n const prevCacheKey = self.customProgramCacheKey;\r\n\r\n self.customProgramCacheKey = () => {\r\n return (\r\n (cacheKey?.() || hash((vertexShader || \"\") + (fragmentShader || \"\"))) +\r\n prevCacheKey?.call(self)\r\n );\r\n };\r\n\r\n self.needsUpdate = true;\r\n }\r\n\r\n clone() {\r\n // Get typed `this` for the proxy\r\n const self = this as typeof this & TYPES.CSMProxy<T>;\r\n\r\n // @ts-ignore\r\n const newObj = new self.constructor({\r\n baseMaterial: self.__csm.baseMaterial.clone(),\r\n vertexShader: self.__csm.vertexShader,\r\n fragmentShader: self.__csm.fragmentShader,\r\n uniforms: self.__csm.uniforms,\r\n patchMap: self.__csm.patchMap,\r\n cacheKey: self.__csm.cacheKey,\r\n });\r\n\r\n return newObj;\r\n }\r\n}\r\n\r\nexport {\r\n type CSMPatchMap,\r\n type CSMProxy,\r\n type CustomShaderMaterialParameters,\r\n type MaterialConstructor,\r\n} from \"./types\";\r\n","import { AttachType } from \"@react-three/fiber/dist/declarations/src/core/renderer\";\r\nimport * as React from \"react\";\r\nimport { Material } from \"three\";\r\nimport CustomShaderMaterialImpl, { MaterialConstructor } from \"../index\";\r\nimport { CustomShaderMaterialProps } from \"./types\";\r\n\r\nfunction useDidUpdateEffect(\r\n fn: (...opts: any[]) => any,\r\n inputs: React.DependencyList\r\n) {\r\n const didMountRef = React.useRef(false);\r\n\r\n React.useEffect(() => {\r\n if (didMountRef.current) {\r\n return fn();\r\n }\r\n didMountRef.current = true;\r\n }, inputs);\r\n}\r\n\r\nfunction CustomShaderMaterial<T extends MaterialConstructor>(\r\n {\r\n baseMaterial,\r\n vertexShader,\r\n fragmentShader,\r\n uniforms,\r\n cacheKey,\r\n patchMap,\r\n attach,\r\n ...opts\r\n }: CustomShaderMaterialProps<T>,\r\n ref: React.Ref<InstanceType<T>>\r\n) {\r\n const material = React.useMemo(() => {\r\n return new CustomShaderMaterialImpl({\r\n baseMaterial,\r\n vertexShader,\r\n fragmentShader,\r\n uniforms,\r\n cacheKey,\r\n patchMap,\r\n ...opts,\r\n });\r\n }, [baseMaterial]);\r\n\r\n useDidUpdateEffect(() => {\r\n material.dispose();\r\n material.update({\r\n vertexShader,\r\n fragmentShader,\r\n uniforms,\r\n patchMap,\r\n cacheKey,\r\n });\r\n }, [vertexShader, fragmentShader, uniforms, patchMap, cacheKey]);\r\n\r\n React.useEffect(() => () => material.dispose(), [material]);\r\n\r\n return (\r\n <primitive\r\n ref={ref}\r\n attach={attach ?? \"material\"}\r\n object={material}\r\n {...opts}\r\n />\r\n );\r\n}\r\n\r\n// export default React.forwardRef(CustomShaderMaterial) as <\r\n// T extends MaterialConstructor\r\n// >(\r\n// props: CustomShaderMaterialProps<T> & { ref?: React.Ref<InstanceType<T>> }\r\n// ) => React.ReactElement;\r\n\r\nexport default React.forwardRef(CustomShaderMaterial) as <\r\n T extends MaterialConstructor = typeof Material\r\n>(\r\n props: CustomShaderMaterialProps<T> & {\r\n ref?: React.Ref<CustomShaderMaterialImpl<T>>;\r\n attach?: AttachType;\r\n }\r\n) => React.ReactElement;\r\n\r\nexport { type CustomShaderMaterialProps } from \"./types\";\r\n","import { DAMAGE_LOOK_DEFAULTS } from './damageContract'\nimport * as THREE from 'three'\nimport {\n paperEdges as paperEdgesOrder,\n type LightingName,\n type PaperEdge,\n type SurfaceConfig,\n} from '../config/schema'\nimport type { Stock } from '../core/stock'\nimport { CREASE_RADIUS } from '../deformers/memory'\nimport { resolveCreases, type CreaseShading } from './creases'\nimport type { LightingPreset } from '../scene/lighting'\nimport {\n TRANSLUCENCY_FRAGMENT,\n TRANSLUCENCY_VARYINGS,\n translucencyUniforms,\n translucencyVertexChunk,\n} from './translucency'\n\n/**\n * Surface effects are fragment-side chunks composed into ONE shader program\n * per effect set (grain + deckle + aging = one program). Uniforms are\n * namespaced per effect; shared helpers (noise) are included once.\n */\n\n/**\n * The shaded crease's width, as a fraction of the hinge the geometry bends\n * over.\n *\n * These are two halves of one crease and they are not the same width. The\n * fold deformer rounds a remembered crease over CREASE_RADIUS of\n * world, which is as sharp as a uniform grid can be asked to be; a real crease\n * is a burnished line an order of magnitude finer than that, and the only\n * place it can live is in the normal. So the shading draws the fine line\n * INSIDE the geometric hinge and the two add up.\n *\n * Derived from the deformer's own constant rather than typed out, because the\n * failure it prevents is silent: the shader used to carry its own widths in UV\n * fractions, which agreed with the geometry at exactly one sheet size and\n * drifted apart at every other — and drifted further every time two hands\n * resized the sheet.\n */\nconst SHADED_CREASE = 0.35\n\nexport interface ComposedSurface {\n /** Distinguishes shader *structures* — same key ⇒ same program, only uniforms change. */\n structureKey: string\n vertexShader: string\n fragmentShader: string\n uniforms: Record<string, { value: unknown }>\n /**\n * Anything that removes paper discards via alphaTest rather than blending.\n * That keeps the depth buffer right for the colour pass; it never made the\n * SHADOW right on its own — three's shadow material ignores alpha computed\n * in shader code. `depth`, below, is what does.\n */\n alphaTest: number\n /**\n * A depth-only program for the SHADOW MAP, or null when nothing on this\n * sheet removes paper and three's own depth material is already right.\n *\n * Shadow maps only. drei's `ContactShadows` renders the whole scene through\n * one override material and never reads a mesh's `customDepthMaterial`, so\n * the soft contact shadow under a `<Paper>` still ignores holes — that is a\n * separate pass and a separate fix.\n */\n depth: { vertexShader: string; fragmentShader: string } | null\n}\n\n/** Which content textures exist — part of the shader structure. */\nexport interface SurfaceMaps {\n hasFrontMap: boolean\n hasBackMap: boolean\n /**\n * A damage texture is attached — see `DamageSource`. Optional and false by\n * default, so a sheet nothing has damaged compiles exactly the program it\n * always did: same chunks, same structure key, same alpha test.\n */\n hasDamage?: boolean\n}\n\nconst VERTEX = /* glsl */ `\nvarying vec2 vPaperUv;\n${TRANSLUCENCY_VARYINGS}\nvoid main() {\n vPaperUv = uv;\n${translucencyVertexChunk({ model: 'modelMatrix', position: 'position', normal: 'normal' })}\n}\n`\n\nconst HELPERS = /* glsl */ `\nvarying vec2 vPaperUv;\nuniform float uBackDarken;\nuniform vec2 uSheetSize;\n\n/**\n * Where this fragment is on the sheet, in the sheet's OWN local space —\n * the same coordinates the deformers displace, centred on the sheet.\n *\n * Every effect below measures in these rather than in UV, and the difference\n * is not cosmetic. UV divides the sheet's aspect out, so a 1.2 x 1.5 sheet is\n * a unit square as far as the shader is concerned: fibre drawn round comes out\n * stretched, a tear bites deeper into the short edge than the long one, and a\n * crease line scored at 45 degrees renders at 51. Worse, all three change when\n * the sheet is RESIZED, which makes the paper's own material a function of how\n * big the piece is. Grain is a property of the stock and a crease is a broken\n * fibre; neither knows how large a sheet it was cut from.\n */\nvec2 plLocal() {\n return (vPaperUv - 0.5) * uSheetSize;\n}\n\n/**\n * The paper's relief, in world units above the sheet the mesh describes.\n *\n * Accumulated by whichever effects have a shape as well as a colour, and\n * spent once at the end of main by {@link plPerturb}. One shared field rather\n * than a perturbation per effect, because two effects that both tilt the\n * surface tilt it TOGETHER — a crease across a grained sheet is one surface,\n * not a crease lit on top of a grain lit on top of the paper.\n */\nfloat plHeight;\n\n/**\n * The relief, turned into the normal the lighting actually runs on.\n *\n * This is the change that makes the surface effects respond to light at all.\n * They used to be painted: a crease multiplied a grey band into the albedo\n * and added a fixed white sheen beside it, so the mark looked identical from\n * every angle and under every rig, and turning the sheet under the key light\n * did nothing to it. Real creased paper is two facets meeting at a line —\n * swing it and the crease flips from a dark line to a bright one. Only a\n * normal can do that, so now the effects describe a HEIGHT and the standard\n * material lights it.\n *\n * The maths is Mikkelsen's surface-gradient bump, which is what three's own\n * perturbNormalArb implements, with one deliberate difference: three\n * normalises the screen-space position derivatives, which makes a bump map\n * look the same at any scale and is the right call for a texture. Ours is a\n * real depth in world units — a crease is as deep as it is however close you\n * stand — so the raw derivatives stay, and the ratio between them and the\n * height's is a true surface slope.\n *\n * Analytic height plus screen derivatives also anti-aliases itself for free:\n * as a crease shrinks below a pixel the derivative flattens and the mark\n * fades, rather than crawling.\n */\nvec3 plPerturb(vec3 n, float height) {\n vec2 dH = vec2(dFdx(height), dFdy(height));\n if (dH.x == 0.0 && dH.y == 0.0) return n;\n // View-space position: the varying is its negation, by three's convention.\n vec3 sigmaX = dFdx(-vViewPosition);\n vec3 sigmaY = dFdy(-vViewPosition);\n vec3 r1 = cross(sigmaY, n);\n vec3 r2 = cross(n, sigmaX);\n float det = dot(sigmaX, r1) * (gl_FrontFacing ? 1.0 : -1.0);\n if (abs(det) < 1e-12) return n;\n vec3 grad = sign(det) * (dH.x * r1 + dH.y * r2);\n return normalize(abs(det) * n - grad);\n}\n\n/**\n * A gaussian bell of unit width, pre-filtered against this fragment's own\n * footprint.\n *\n * Convolving a gaussian with the pixel broadens it and flattens it by the\n * same factor, which conserves the integral: a crease seen from across the\n * room dims instead of breaking into a dotted line. s is the distance\n * across the feature in units of its own width, so a caller only ever has to\n * decide how wide the thing is.\n */\nfloat plBell(float s) {\n float px = fwidth(s);\n float widen = sqrt(1.0 + px * px);\n return exp(-(s * s) / (widen * widen)) / widen;\n}\n\nfloat plHash(vec2 p) {\n return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);\n}\n\nfloat plNoise(vec2 p) {\n vec2 i = floor(p);\n vec2 f = fract(p);\n vec2 u = f * f * (3.0 - 2.0 * f);\n return mix(\n mix(plHash(i), plHash(i + vec2(1.0, 0.0)), u.x),\n mix(plHash(i + vec2(0.0, 1.0)), plHash(i + vec2(1.0, 1.0)), u.x),\n u.y\n );\n}\n\nfloat plFbm(vec2 p) {\n float v = 0.0;\n float a = 0.5;\n for (int i = 0; i < 4; i++) {\n v += a * plNoise(p);\n p *= 2.03;\n a *= 0.5;\n }\n return v;\n}\n`\n\nconst edgeFlags = (edges: PaperEdge[]): THREE.Vector4 =>\n new THREE.Vector4(\n edges.includes('top') ? 1 : 0,\n edges.includes('right') ? 1 : 0,\n edges.includes('bottom') ? 1 : 0,\n edges.includes('left') ? 1 : 0,\n )\n\nconst GRAIN_CHUNK = /* glsl */ `\nuniform float uGrainAmount;\nuniform float uGrainBanding;\n\n/**\n * Fibre density, per world unit.\n *\n * Per WORLD UNIT and not per UV, which is the whole fix: the fibre in a sheet\n * is the stock's, and it does not get coarser because someone cut a bigger\n * piece or stretch oval because the piece is taller than it is wide.\n *\n * The number is carried over from when it was a UV frequency, so a sheet one\n * world unit wide is unchanged across its width. Its height is not, and that\n * is the point: a 1.4-tall sheet used to fit the same 240 cycles into a\n * longer span and its fibre ran visibly coarser the other way.\n */\nconst float PL_FIBRE = 240.0;\n\n/**\n * The coarser structure underneath it — paper's tooth, the part that has a\n * SHAPE and not just a colour.\n *\n * Separate from the fibre, and much lower, for a reason worth writing down:\n * the relief is differentiated in screen space, and a field at the fibre's own\n * frequency is a few pixels per cycle at any sane viewing distance, so its\n * derivative is noise and the sheet would sparkle. The tooth is safely above\n * the sampling rate, and it is the scale at which paper actually catches a\n * raking light anyway.\n */\nconst float PL_TOOTH = 70.0;\n\n/**\n * How far the tooth stands proud, in world units, at full grain.\n *\n * Real paper's surface relief is tens of microns. Against a sheet whose width\n * is one world unit — call it A4 — 0.00035 is about 70 microns, and at the\n * tooth's wavelength that is a surface tilting by four degrees or so. Enough\n * to break a specular highlight into paper, not enough to look pebbled.\n */\nconst float PL_TOOTH_RELIEF = 0.00035;\n\nvoid plGrain(inout vec4 color, inout float rough) {\n vec2 local = plLocal();\n float fiber = plFbm(local * PL_FIBRE);\n float fleck = plNoise(local * (PL_FIBRE * 3.75));\n float g = mix(0.5, fiber * 0.75 + fleck * 0.25, uGrainAmount);\n color.rgb *= 0.92 + g * 0.16;\n rough = clamp(rough + (g - 0.5) * uGrainAmount * 0.35, 0.0, 1.0);\n // The tooth, handed to the lighting rather than drawn. A single octave: the\n // relief only needs the scale the eye reads as texture, and the fbm above\n // is already carrying everything finer as colour.\n plHeight += (plNoise(local * PL_TOOTH) - 0.5) * PL_TOOTH_RELIEF * uGrainAmount;\n // Thermal-printer banding: faint horizontal density stripes.\n if (uGrainBanding > 0.0) {\n float band = sin(vPaperUv.y * 700.0) * 0.5 + 0.5;\n color.rgb *= 1.0 - uGrainBanding * 0.05 * band;\n }\n}\n`\n\nconst DECKLE_CHUNK = /* glsl */ `\nuniform vec4 uDeckleEdges; // top, right, bottom, left\nuniform float uDeckleRoughness;\n\n/** Gnaw frequency along a torn edge, per world unit — see {@link plLocal}. */\nconst float PL_DECKLE_GNAW = 26.0;\n\nvoid plDeckle(inout vec4 color) {\n // Distance to each selected edge, gnawed by low-frequency noise.\n //\n // The depth is in world units, taken against the sheet's mean dimension.\n // Against the MEAN rather than each edge's own span, which is what UV\n // amounted to: one roughness used to bite a third deeper into the short\n // edges of a 1 x 1.4 sheet than the long ones, for no reason anybody chose.\n //\n // Still proportional to the sheet rather than absolute, which is a decision\n // and not an oversight. A real deckle is a fibre length and would be the\n // same depth on any size of sheet; roughness is a 0..1 knob someone types,\n // and an absolute one would vanish on a poster and swallow a stamp.\n float depth = (0.012 + uDeckleRoughness * 0.05) * (uSheetSize.x + uSheetSize.y) * 0.5;\n float tear = 1.0;\n float fiberBand = 0.0;\n vec4 dists = vec4(1.0 - vPaperUv.y, 1.0 - vPaperUv.x, vPaperUv.y, vPaperUv.x);\n vec4 alongs = vec4(vPaperUv.x, vPaperUv.y, vPaperUv.x, vPaperUv.y);\n vec4 distScale = vec4(uSheetSize.y, uSheetSize.x, uSheetSize.y, uSheetSize.x);\n vec4 alongScale = vec4(uSheetSize.x, uSheetSize.y, uSheetSize.x, uSheetSize.y);\n for (int e = 0; e < 4; e++) {\n if (uDeckleEdges[e] < 0.5) continue;\n float n = plFbm(vec2(alongs[e] * alongScale[e] * PL_DECKLE_GNAW, float(e) * 7.31)) - 0.5;\n float boundary = depth * (0.55 + n * 1.6);\n float d = dists[e] * distScale[e] - boundary;\n tear = min(tear, step(0.0, d));\n // Lightened fiber band just inside the tear.\n fiberBand = max(fiberBand, smoothstep(depth * 1.4, 0.0, d) * step(0.0, d));\n }\n color.a *= tear;\n color.rgb = mix(color.rgb, vec3(1.0), fiberBand * 0.35);\n}\n`\n\nconst CREASE_CHUNK = /* glsl */ `\nuniform float uCreaseAngles[4];\nuniform float uCreaseStrengths[4];\nuniform float uCreaseOffsets[4];\nuniform float uCreaseWidth;\nuniform int uCreaseCount;\n\n/**\n * Peak tilt of a crease's own facets, as a slope.\n *\n * A gaussian groove of amplitude A and width w reaches a maximum slope of\n * about 0.86 A/w, so an amplitude of 0.55 w peaks near 25 degrees — steep\n * enough that turning the sheet visibly flips the line from dark to bright,\n * shallow enough that it never reads as a fold in its own right. Held as a\n * SLOPE rather than a depth because that is the quantity the lighting\n * responds to, and the only one that stays honest when the width changes.\n */\nconst float PL_CREASE_TILT = 0.55;\n\n/** How much grime a crease traps, at full strength. */\nconst float PL_CREASE_SOIL = 0.1;\n\nvoid plCrease(inout vec4 color, inout float rough) {\n vec2 p = plLocal();\n for (int i = 0; i < 4; i++) {\n if (i >= uCreaseCount) break;\n vec2 dir = vec2(cos(uCreaseAngles[i]), sin(uCreaseAngles[i]));\n // The identical measurement the fold deformer displaces by: signed\n // distance across the line, in the sheet's own space. Shading and\n // geometry cannot place a crease differently when the number they place\n // it by is the same number.\n float s = (dot(p, dir) - uCreaseOffsets[i]) / uCreaseWidth;\n float strength = uCreaseStrengths[i];\n float bell = plBell(s);\n\n // The relief. This is the fine burnished line where the fibres broke, and\n // it is deliberately narrower than the hinge the fold deformer bends\n // over: the mesh carries the wide bend, the shader carries the crease\n // inside it, and the two add up instead of competing. Signed, so a\n // mountain stands proud and a valley cuts in — the same crease read from\n // the other side of the sheet is the other one.\n plHeight += strength * uCreaseWidth * PL_CREASE_TILT * bell;\n\n // What is left for the albedo once the lighting is doing the work: a\n // crease collects dirt and its broken fibres scatter wider. The grey band\n // and the painted-on sheen that used to live here were standing in for a\n // normal, and there is one now.\n float mark = bell * abs(strength);\n color.rgb *= 1.0 - mark * PL_CREASE_SOIL;\n rough = clamp(rough + mark * 0.3, 0.0, 1.0);\n }\n}\n`\n\nconst PERFORATION_CHUNK = /* glsl */ `\nuniform vec4 uPerfEdges; // top, right, bottom, left enabled\nuniform vec4 uPerfTorn; // 1 = ripped-through profile, 0 = clean punches\nuniform float uPerfRadius; // world units\nuniform float uPerfSpacing;\n\nvoid plPerforation(inout vec4 color) {\n // Per-edge distance/along coordinates, converted from UV to world units so\n // hole size is stable across sheet dimensions.\n vec4 dists = vec4(1.0 - vPaperUv.y, 1.0 - vPaperUv.x, vPaperUv.y, vPaperUv.x);\n vec4 alongs = vec4(vPaperUv.x, vPaperUv.y, vPaperUv.x, vPaperUv.y);\n vec4 distScale = vec4(uSheetSize.y, uSheetSize.x, uSheetSize.y, uSheetSize.x);\n vec4 alongScale = vec4(uSheetSize.x, uSheetSize.y, uSheetSize.x, uSheetSize.y);\n float fiber = 0.0;\n for (int e = 0; e < 4; e++) {\n if (uPerfEdges[e] < 0.5) continue;\n float d = dists[e] * distScale[e];\n float a = alongs[e] * alongScale[e];\n // Signed distance along the edge to the nearest hole center.\n float cell = mod(a + uPerfSpacing * 0.5, uPerfSpacing) - uPerfSpacing * 0.5;\n if (uPerfTorn[e] < 0.5) {\n // Intact: clean semicircular punches on the edge line (alphaTest, not\n // blending — shadow correctness).\n if (length(vec2(cell, d)) < uPerfRadius) color.a = 0.0;\n } else {\n // Torn: ripped profile following the hole rhythm — alternating tabs and\n // notches, gnawed by noise, with a lightened fiber band along the tear.\n float rhythm = abs(sin(a / uPerfSpacing * 3.14159265));\n float n = plNoise(vec2(a * 40.0, float(e) * 7.31)) - 0.5;\n float cut = uPerfRadius * (0.35 + rhythm * 1.35 + n * 0.9);\n if (d < cut) color.a = 0.0;\n fiber = max(fiber, smoothstep(uPerfRadius * 2.4, 0.0, d - cut) * step(cut, d));\n }\n }\n color.rgb = mix(color.rgb, vec3(1.0), fiber * 0.4);\n}\n`\n\n/**\n * What happened to the paper, read from the damage texture — the part both\n * programs need: the fray and the cut.\n *\n * Written so that an untouched field is an exact identity — char 0, wet 0,\n * presence 1 multiplies by one and mixes by zero — because attaching a field\n * to a sheet before anything has burnt it must not change a single pixel.\n *\n * Presence is cut with `step`, not multiplied into alpha. Multiplying would\n * put the edge of a hole wherever `opacity × presence` crosses the alpha test,\n * which is presence 0.5 on an opaque stock and 0.81 on the 0.62-opacity one:\n * the same burn would eat further into some papers than others.\n *\n * Shared with the shadow pass, which is why it holds only what CUTS: the\n * depth program has no view position and no lighting, and a function in here\n * that reached for either would stop it compiling. What a burn looks like is\n * `DAMAGE_SHADE_CHUNK`, colour program only.\n */\nconst DAMAGE_CHUNK = /* glsl */ `\nuniform sampler2D uDamage;\nuniform float uDamageDetail;\n// (edgeWave mm, edgeBite mm, sparkle, –) — see DamageLook.\nuniform vec4 uLook3;\n\n// The damage grid's texels sit ON the sheet — texel x at u = x / (N - 1), its\n// corners on the sheet's corners, which is how the field paints and how the\n// physics reads it. A texture puts texel x at (x + 0.5) / N. Sampled straight,\n// the picture of a burn sat up to half a texel off the burn the paper feels.\nvec2 plDamageUv(vec2 uv) {\n vec2 n = vec2(textureSize(uDamage, 0));\n // Texel space, on the field's convention: texel x at u = x / (N - 1).\n vec2 t = uv * (n - 1.0) + 0.5;\n // Quintic-smoothed texel coordinates.\n //\n // Bilinear filtering is continuous but its DERIVATIVE is not: the blend\n // weight is a straight line inside each texel and turns a corner at every\n // boundary. Magnify a 64 grid to fill a macro crop — one cell is 4.9 mm of\n // A4, about 58 px there — and those corners fall on a 58 px lattice, so\n // every ramp drawn from this field can crease along it.\n //\n // Also tried against the contour rings, and also not their cause (that was\n // the scorch fingers). Kept because it costs nothing and the crease is\n // real:\n // Bending the fractional part through a quintic (6t^5 - 15t^4 + 10t^3,\n // whose first and second derivatives vanish at both ends) makes the\n // interpolation C2 without a single extra tap: the hardware still does one\n // bilinear fetch, it is just asked for a smoothed position. The sample at a\n // texel's centre is unchanged, so the half-texel alignment this function\n // exists for still holds — and a field nothing has happened to reads 1\n // everywhere whatever the position, so the untouched-sheet identity is\n // untouched too.\n vec2 i = floor(t - 0.5) + 0.5;\n vec2 f = t - i;\n f = f * f * f * (f * (f * 6.0 - 15.0) + 10.0);\n return (i + f) / n;\n}\n\n/**\n * The four channels here, frayed finer than the grid.\n *\n * One cell of the field is ~3.3 mm of A4, and a burnt edge is jagged at the\n * scale of a fibre (0.3–2 mm) — so the grid decides roughly WHERE and this\n * decides exactly where. Stretched along the fibre (the field's default grain\n * runs along u), so a tear follows the grain. Scaled by what is already\n * there, so pristine paper (char 0, presence 1) is untouched to the bit, and\n * skipped outright at detail 0: the zones still draw on every tier, only\n * without the finest octaves.\n */\n/**\n * Where on the grid this fragment reads its damage — warped.\n *\n * A burnt hole is never a circle: paper burns unevenly, and its edge wobbles\n * in long waves with small bites in and out. The field is too coarse to hold\n * that, so the READ is displaced instead: two octaves of noise in the sheet's\n * own space, a long wave of up to ±6 mm and short bites of ±2 mm. Every zone —\n * the cut, the lip, the ember line, the char, the scorch — reads through the\n * same warp, so they all follow one uneven edge. Warping a field nothing has\n * happened to reads the same untouched value everywhere, so the identity\n * holds.\n */\nvec2 plDamageWarpAt(vec2 paperUv) {\n vec2 p = (paperUv - 0.5) * uSheetSize;\n const float mm = 1.0 / 210.0;\n vec2 wave = vec2(plFbm(p * 26.0 + 3.1), plFbm(p * 26.0 + 17.7)) - 0.5;\n vec2 bite = vec2(plNoise(p * 95.0 + 5.3), plNoise(p * 95.0 + 41.9)) - 0.5;\n vec2 shift = (wave * 2.0 * uLook3.x + bite * 2.0 * uLook3.y) * mm;\n return plDamageUv(paperUv + shift / uSheetSize);\n}\n\nvec2 plDamageWarp() {\n return plDamageWarpAt(vPaperUv);\n}\n\n/** Presence softened over five taps — see \\`plDamageRead\\`. */\nfloat plSoftPresence(vec2 uv) {\n vec2 texel = 0.75 / vec2(textureSize(uDamage, 0));\n return (2.0 * texture2D(uDamage, uv).a\n + texture2D(uDamage, uv + vec2(texel.x, 0.0)).a + texture2D(uDamage, uv - vec2(texel.x, 0.0)).a\n + texture2D(uDamage, uv + vec2(0.0, texel.y)).a + texture2D(uDamage, uv - vec2(0.0, texel.y)).a) / 6.0;\n}\n\n/** The fray and the fibre at a point of the sheet (local units), scaled by detail. */\nvec2 plFray(vec2 p) {\n return vec2(\n (plFbm(vec2(p.x * 22.0, p.y * 48.0)) - 0.47) * uDamageDetail,\n (plNoise(vec2(p.x * 140.0, p.y * 420.0)) - 0.5) * uDamageDetail\n );\n}\n\n/**\n * The presence the cut is drawn from, at any point of the paper: warped,\n * softened and frayed exactly as \\`plDamageRead\\` does it for this fragment.\n */\nfloat plDrawnPresenceAt(vec2 paperUv) {\n float a = plSoftPresence(plDamageWarpAt(paperUv));\n if (uDamageDetail > 0.0) {\n vec2 ff = plFray((paperUv - 0.5) * uSheetSize);\n a = clamp(a + (ff.x * 0.36 + ff.y * 0.05) * (1.0 - smoothstep(0.9, 1.0, a)), 0.0, 1.0);\n }\n return a;\n}\n\n// The softened presence before the fray, from the last \\`plDamageRead\\`: what\n// the distance to the cut takes its slope from (see \\`plDamage\\`).\nfloat plDamageSmooth;\n\nvec4 plDamageRead() {\n vec2 uv = plDamageWarp();\n vec4 d = texture2D(uDamage, uv);\n // The cut runs on a SOFTENED presence. Paper burns through within a single\n // texel now, so the raw field is hard-edged and its half-presence contour\n // is the grid's own staircase — the fray below can only move a line within\n // the band it is given, and a one-texel band is not enough to hide a grid.\n // Five taps round the contour; an untouched field is 1 everywhere and\n // stays exactly 1.\n d.a = plSoftPresence(uv);\n plDamageSmooth = d.a;\n if (uDamageDetail > 0.0) {\n vec2 ff = plFray(plLocal());\n float fray = ff.x;\n float fibre = ff.y;\n float edge = 1.0 - smoothstep(0.9, 1.0, d.a);\n d.r = clamp(d.r + fray * 0.3 * smoothstep(0.0, 0.15, d.r), 0.0, 1.0);\n d.a = clamp(d.a + (fray * 0.36 + fibre * 0.05) * edge, 0.0, 1.0);\n }\n return d;\n}\n\nvoid plDamageCut(inout vec4 color, vec4 d) {\n // Missing paper: gone at half presence, on every stock alike.\n color.a *= step(0.5, d.a);\n}\n`\n\n/**\n * What a burn LOOKS like: the zones of `paperlab-fx-fire-spec.md` §5, drawn\n * per fragment from a grid that is coarser than every one of them.\n *\n * From the hole outward: void · ash lip · ember line · char · scorch · paper.\n * The field says roughly where each is — presence is where the paper ends,\n * char is how far burning has got — and this measures the rest in\n * MILLIMETRES from the cut, off the presence gradient, so a 1 mm ember line\n * is 1 mm at any zoom and on any size of sheet. A4 is one world unit across,\n * which is what `PL_MM` is.\n *\n * - **Scorch** is albedo only, multiplied in so the ink under it darkens with\n * it, and PERMANENT: it reads char, which never recedes. A long slow ramp\n * through the sampled browns, then a steep jump to clean paper in its last\n * stretch — an even blur is half of what made the first version read as a\n * gradient. It reaches further ABOVE the burn than below, because hot gas\n * rises and cooks the paper over it (§4.5): world up is worked out here, in\n * the sheet's own UV, from the surface's screen derivatives.\n * - **Char** is not black: near-black in a crack network of 1–4 mm cells, a\n * dark grey body, a brown undertone toward the scorch, and plates tilted so\n * a grazing light catches them. The ink under it is gone.\n * - **The ash lip** is pale, matte, lifted toward the viewer — it is what\n * makes a hole read as a hole on a black stage, by catching light.\n * - **The ember line** is the only thing on the sheet that emits. It sits\n * between the ash lip and the char, 0.3–1 mm wide, held crisp in screen\n * space, broken into beads that flicker and crawl on the burn's own clock\n * and cool down the blackbody ramp as the heat under them goes. Written to\n * `plDamageLight` in HDR — past paper white, for `FxPost` to bloom — and\n * added after transmission, which owns `csm_Emissive`.\n *\n * Heat paints nothing anywhere else. The wide glow this chunk once drew over\n * unburnt paper was the spec's first complaint: red added to white is pink.\n */\nconst DAMAGE_SHADE_CHUNK = /* glsl */ `\nuniform float uDamageTime;\n// The look, packed — see DamageLook for what each number means.\nuniform vec4 uLook0; // emberWidth mm, emberIntensity, emberCoverage, emberFlicker\nuniform vec4 uLook1; // emberGlow, lipWidth mm, lipBrightness, charWarmth\nuniform vec4 uLook2; // charCracks, scorchReach mm, scorchDarkness, fingers\n/** The light the burn gives off from the sheet itself: the ember line, and nothing else. */\nvec3 plDamageLight;\n\n// World units per millimetre: a default sheet is one unit across, and A4 is 210 mm.\nconst float PL_MM = 1.0 / 210.0;\n\nvec3 plLinear(vec3 srgb) {\n return pow(srgb, vec3(2.2));\n}\n\n/**\n * World up, as a direction in the sheet's UV, from how this fragment's UV and\n * view position change across the screen. Must be called in uniform control\n * flow — it is all derivatives.\n */\nvec2 plUpUv() {\n vec3 dpx = dFdx(-vViewPosition);\n vec3 dpy = dFdy(-vViewPosition);\n vec2 dux = dFdx(vPaperUv);\n vec2 duy = dFdy(vPaperUv);\n float det = dux.x * duy.y - dux.y * duy.x;\n if (abs(det) < 1e-14) return vec2(0.0, 1.0);\n vec3 dPdu = (dpx * duy.y - dpy * dux.y) / det;\n vec3 dPdv = (dpy * dux.x - dpx * duy.x) / det;\n vec3 up = (viewMatrix * vec4(0.0, 1.0, 0.0, 0.0)).xyz;\n vec2 g = vec2(dot(up, dPdu) / max(dot(dPdu, dPdu), 1e-12), dot(up, dPdv) / max(dot(dPdv, dPdv), 1e-12));\n float l = length(g);\n return l > 1e-6 ? g / l : vec2(0.0, 1.0);\n}\n\n/** F1 and F2 of a cell noise — the crack network in char. */\nvec2 plVoronoi(vec2 p) {\n vec2 i = floor(p);\n vec2 f = fract(p);\n float f1 = 8.0;\n float f2 = 8.0;\n for (int y = -1; y <= 1; y++) {\n for (int x = -1; x <= 1; x++) {\n vec2 o = vec2(float(x), float(y));\n vec2 r = o + vec2(plHash(i + o), plHash(i + o + 17.31)) - f;\n float dd = dot(r, r);\n if (dd < f1) {\n f2 = f1;\n f1 = dd;\n } else if (dd < f2) {\n f2 = dd;\n }\n }\n }\n return sqrt(vec2(f1, f2));\n}\n\n/** The scorch ramp, sampled off Scorch.png and Hero.png, as a tint over paper. 0 is the leading edge. */\nvec3 plScorchTint(float t) {\n vec3 paper = plLinear(vec3(0.90, 0.885, 0.855));\n vec3 c0 = plLinear(vec3(0.843, 0.741, 0.569)); // #D7BD91\n vec3 c1 = plLinear(vec3(0.745, 0.514, 0.263)); // #BE8343\n vec3 c2 = plLinear(vec3(0.631, 0.384, 0.180)); // #A1622E\n vec3 c3 = plLinear(vec3(0.541, 0.310, 0.141)); // #8A4F24\n vec3 c4 = plLinear(vec3(0.471, 0.275, 0.149)); // #784626\n vec3 c5 = plLinear(vec3(0.380, 0.216, 0.133)); // #613722\n vec3 c6 = plLinear(vec3(0.310, 0.200, 0.137)); // #4F3323\n float s = clamp(t, 0.0, 1.0) * 6.0;\n // Each stop is blended with a SMOOTH step, not a linear one.\n //\n // Seven colours joined by six straight segments is a ramp with a corner at\n // every joint: the colour is continuous there but its rate of change is\n // not, and the eye reads a discontinuous gradient as a faint line (Mach\n // banding). smoothstep's derivative is zero at both ends of a segment, so\n // consecutive segments meet with matching slope and there is no corner.\n //\n // Cheap insurance, not a bug fix — this was tried first against the macro\n // crops' contour rings and did NOT remove them; the cause turned out to be\n // the scorch fingers below, sampled in a frame that follows the contours.\n float k = smoothstep(0.0, 1.0, clamp(s, 0.0, 1.0));\n vec3 c = mix(c0, c1, k);\n c = mix(c, c2, smoothstep(0.0, 1.0, clamp(s - 1.0, 0.0, 1.0)));\n c = mix(c, c3, smoothstep(0.0, 1.0, clamp(s - 2.0, 0.0, 1.0)));\n c = mix(c, c4, smoothstep(0.0, 1.0, clamp(s - 3.0, 0.0, 1.0)));\n c = mix(c, c5, smoothstep(0.0, 1.0, clamp(s - 4.0, 0.0, 1.0)));\n c = mix(c, c6, smoothstep(0.0, 1.0, clamp(s - 5.0, 0.0, 1.0)));\n return min(c / paper, vec3(1.0));\n}\n\n/** The ember ramp (§5 zone 3): off → #870E03 → #A12108 → #F77E14 → #FEFBE0, hottest last. */\nvec3 plEmberRamp(float t) {\n vec3 c0 = plLinear(vec3(0.529, 0.055, 0.012));\n vec3 c1 = plLinear(vec3(0.631, 0.129, 0.031));\n vec3 c2 = plLinear(vec3(0.969, 0.494, 0.078));\n vec3 c3 = plLinear(vec3(0.996, 0.984, 0.878));\n vec3 c = mix(c0, c1, smoothstep(0.0, 0.3, t));\n c = mix(c, c2, smoothstep(0.3, 0.7, t));\n return mix(c, c3, smoothstep(0.75, 1.0, t));\n}\n\nvoid plDamage(inout vec4 color, inout float roughness) {\n plDamageLight = vec3(0.0);\n vec4 d = plDamageRead();\n vec2 uv = plDamageWarp();\n vec2 texel = 1.0 / vec2(textureSize(uDamage, 0));\n\n // Everything measured off screen derivatives, up front: derivatives are\n // undefined past a branch that only some fragments of a quad take.\n vec2 upUv = plUpUv();\n vec4 e = texture2D(uDamage, uv + vec2(texel.x, 0.0));\n vec4 w = texture2D(uDamage, uv - vec2(texel.x, 0.0));\n vec4 n = texture2D(uDamage, uv + vec2(0.0, texel.y));\n vec4 s = texture2D(uDamage, uv - vec2(0.0, texel.y));\n // Per world unit: one texel step is 1 / (N - 1) of the sheet.\n vec2 perWorld = (vec2(textureSize(uDamage, 0)) - 1.0) / uSheetSize;\n vec2 gradP = vec2(e.a - w.a, n.a - s.a) * 0.5 * perWorld;\n vec2 gradC = vec2(e.r - w.r, n.r - s.r) * 0.5 * perWorld;\n // Millimetres from the cut, on the paper side — measured against the field\n // the cut is DRAWN from (softened, frayed, warped), through its own screen\n // derivatives. It used to divide by the slope of the raw texels, and since\n // paper burns through within a texel that slope is a cliff while the drawn\n // edge is spread over millimetres: a point well into the char computed as a\n // hair from the cut, and the ember line drew there — found by the gate.\n // The slope, though, is the SMOOTH presence's. The fray's fibre noise\n // changes pixel to pixel, and its slope is a cliff everywhere it touches:\n // divided by that, a point deep in the char came out a hair from the cut\n // and the ember glow drew there — the gate's stray pixels. The fray still\n // moves where the edge is; it just cannot fake how steep it is.\n float smoothA = plDamageSmooth;\n vec2 cutSlope = vec2(dFdx(smoothA), dFdy(smoothA));\n float pxFromCut = (d.a - 0.5) / max(length(cutSlope), 1e-4);\n // Millimetres per pixel ALONG the way to the cut, not across the screen's\n // x: a sheet leaning away is foreshortened vertically, so above and below a\n // hole a pixel covers more paper than beside it, and a scale taken from x\n // alone drew the ember zone too many pixels deep on the top and bottom rims.\n vec2 toCutPx = cutSlope / max(length(cutSlope), 1e-6);\n float mmPerPx = length(dFdx(-vViewPosition) * toCutPx.x + dFdy(-vViewPosition) * toCutPx.y) / PL_MM;\n float mm = pxFromCut * mmPerPx;\n // About a pixel of antialiasing, never more: where the warp makes the\n // estimate jump between neighbours, fwidth(mm) is millimetres wide, and the\n // ember's soft tail — faint, but multiplied by its light — drew stray glow\n // well out into the char.\n float aa = min(fwidth(mm), 1.5 * mmPerPx);\n // Scorch reaches ahead of the char, and further UP than anywhere else:\n // the char a centimetre below this point, and the char a few millimetres\n // around it, each lent to the scorch at a discount (§4.2, §4.5).\n vec2 mmUv = vec2(PL_MM) / uSheetSize;\n float charBelow = max(texture2D(uDamage, uv - upUv * uLook2.y * mmUv).r, texture2D(uDamage, uv - upUv * 0.5 * uLook2.y * mmUv).r);\n // A ring of eight, averaged: four diagonal maxima drew the grid back in as\n // squares wherever the scorch was magnified.\n float charWide = 0.0;\n for (int k = 0; k < 8; k++) {\n float a = float(k) * 0.7853982;\n charWide += texture2D(uDamage, uv + vec2(cos(a), sin(a)) * 7.0 * mmUv).r;\n }\n charWide /= 8.0;\n // Only paper that has a CUT beside it has an edge: a half-eaten cell out\n // in the middle of the sheet reads as \"half a presence\" too, and without\n // this the ember line and the ash lip drew on it — islands of glow on\n // paper, the painted glow by another route.\n // Eased in, not switched: a hard threshold on the neighbouring texels drew\n // the grid back into the ember glow as small squares.\n float cutNear = 1.0 - smoothstep(0.3, 0.62, min(min(e.a, w.a), min(n.a, s.a)));\n // And the cut has to really be there. \\`mm\\` extrapolates this pixel's\n // slope to half presence, and the uneven edge's warp bends the field inside\n // those few millimetres — measured: with the warp off the stray ember light\n // the gate finds all but vanishes. So step across the PAPER toward where the\n // cut should be, half a millimetre past it but never beyond the ember\n // zone's own outer edge (the lip and the widest bead — 2.5 mm at the\n // spec's numbers, §5) plus that half, and read what the cut is drawn from.\n // Still paper: this is not an edge, however close the slope said it was.\n vec2 toCutPaper = -(dFdx(vPaperUv) * toCutPx.x + dFdy(vPaperUv) * toCutPx.y);\n float reachPx = min(max(mm, 0.0) + 0.5, uLook1.y + uLook0.x + 0.5) / max(mmPerPx, 1e-6);\n float pastA = plDrawnPresenceAt(vPaperUv + toCutPaper * reachPx);\n // And a hole, not a pinhole: the fray opens specks of void finer than a\n // pixel in part-burnt paper, which the check above would take for the\n // edge. The void has to go on for another half millimetre.\n float beyondA = plDrawnPresenceAt(vPaperUv + toCutPaper * (reachPx + 0.5 / max(mmPerPx, 1e-6)));\n cutNear *= (1.0 - smoothstep(0.42, 0.55, pastA)) * (1.0 - smoothstep(0.42, 0.55, beyondA));\n\n // An untouched texel is left exactly as it was — the identity the whole\n // seam is built on. Nothing here has happened to this paper.\n if (d.r <= 0.0 && d.g <= 0.0 && d.a >= 1.0 && charBelow <= 0.0 && charWide <= 0.0 && e.a >= 1.0 && w.a >= 1.0 && n.a >= 1.0 && s.a >= 1.0) {\n return;\n }\n\n vec2 p = plLocal();\n\n // Wet paper is darker and smoother: water fills the gaps between fibres\n // that scatter light, which is both effects from one cause.\n color.rgb *= 1.0 - 0.38 * d.g;\n roughness *= 1.0 - 0.45 * d.g;\n\n // ── Scorch ──────────────────────────────────────────────────────────────\n // Fingers: irregular teeth ALONG the scorch front, plus the grain's own\n // streaks. Measured along the front's tangent so they point outward.\n vec2 tangentC = length(gradC) > 1e-4 ? normalize(vec2(-gradC.y, gradC.x)) : vec2(1.0, 0.0);\n float along = dot(p, tangentC) / (4.0 * PL_MM);\n // Only where there really IS a front.\n //\n // This noise is sampled in a frame built from the char gradient, so that\n // its teeth run across the front wherever the front happens to point. That\n // works at the front and is meaningless behind it: a few millimetres into\n // the char the gradient is almost flat, its direction is whatever the\n // eight-bit field rounded to, and the frame turns with position — which\n // makes the noise a function OF THE CONTOURS rather than of the sheet. It\n // drew closed loops following the edge, nested a cell apart: the\n // \"concentric contour lines, like a topographic map or tree rings\" the\n // review found at macro range and left unexplained. Turning this one term\n // off removes them completely and changes nothing else.\n //\n // Measured on the scripted burn's peak: the gradient runs to about 19 at\n // the front and under 1 a few millimetres behind it.\n float frontness = smoothstep(1.0, 6.0, length(gradC));\n float fingers = (plFbm(vec2(along, dot(p, vec2(tangentC.y, -tangentC.x)) / (12.0 * PL_MM))) - 0.5) * 0.28 * frontness\n + (plFbm(vec2(p.x * 9.0, p.y * 30.0)) - 0.5) * 0.08;\n fingers *= uLook2.w;\n // Fingers on the borrowed scorch too, so the outer edge is irregular\n // teeth rather than a smooth offset of the char.\n float reach = 0.75 + fingers * 4.0;\n // The scorch reads a softened char — its own texel and the four around it\n // — so a bilinear 64² field magnified shows no contours or corners. The\n // char zone keeps the sharp one: its edge is meant to be crisp.\n float soft = (2.0 * d.r + e.r + w.r + n.r + s.r) / 6.0;\n float self_ = clamp(mix(d.r, soft, 0.65) + fingers * smoothstep(0.0, 0.08, d.r), 0.0, 1.0);\n float c = 1.0 - (1.0 - self_) * (1.0 - clamp(0.62 * charBelow * reach, 0.0, 1.0)) * (1.0 - clamp(0.4 * charWide * reach, 0.0, 1.0));\n // Fibre-scale grain in the scorch, so a smooth field magnified never shows\n // its contours — real scorch is fibrous (Scorch.png), not banded.\n c = clamp(c + ((plNoise(p * 300.0) - 0.5) * 0.07 + (plNoise(p * 90.0) - 0.5) * 0.06) * smoothstep(0.0, 0.1, c), 0.0, 1.0);\n // A dither of about one and a half of the damage texture's own levels.\n //\n // The field arrives as eight bits a channel, so char comes in steps of\n // 1/255 — and the leading edge below spans 0.03 of it, which is seven and a\n // half steps. The fibre grain above would have hidden them, but it is\n // multiplied by smoothstep(0, 0.1, c), which is approximately zero exactly\n // where the leading edge lives. This is not: it applies everywhere, and\n // being finer than a level it can only ever move a value into the\n // neighbouring one.\n c = clamp(c + (plNoise(p * 900.0) - 0.5) * (1.5 / 255.0), 0.0, 1.0);\n // A steep leading edge — paper to straw in a sliver — then the long ramp.\n float lead = smoothstep(0.02, 0.05, c);\n float ramp = smoothstep(0.05, 0.7, c);\n color.rgb *= mix(vec3(1.0), pow(plScorchTint(ramp), vec3(uLook2.z)), lead);\n\n // ── Char ────────────────────────────────────────────────────────────────\n // A wide, smooth hand-over from scorch to char — the gradient is the point.\n float charZone = smoothstep(0.5, 0.9, c);\n vec2 cells = plVoronoi(p / (3.6 * PL_MM));\n // Sparse: a real crack network is broken, not a tiled floor — most cell\n // borders never split.\n float crack = (1.0 - smoothstep(0.008, 0.03, cells.y - cells.x)) * smoothstep(0.45, 0.65, plNoise(p / (7.0 * PL_MM)));\n float plate = plHash(floor(p / (3.6 * PL_MM)) + 3.7);\n // Dark orange where the char meets the scorch, deep brown toward the cut —\n // warm all the way, and fading smoothly into the scorch's lighter browns\n // rather than stopping at a grey band.\n // Warm (dark orange → deep brown) or, turned down, the sampled greys.\n vec3 body = mix(plLinear(vec3(0.255, 0.239, 0.227)), plLinear(vec3(0.165, 0.086, 0.043)), uLook1.w);\n vec3 under = mix(plLinear(vec3(0.275, 0.169, 0.090)), plLinear(vec3(0.42, 0.18, 0.06)), uLook1.w);\n vec3 cracks = plLinear(vec3(0.039, 0.024, 0.016)); // #0A0604\n vec3 charColor = mix(under, body, smoothstep(0.66, 1.0, c));\n // Mottled at the plate scale and finer, and darker than the sampled body\n // under a bright key — the reference's char reads near black in the frame.\n charColor *= (0.75 + 0.35 * plate) * (0.8 + 0.4 * plNoise(p * 260.0));\n charColor = mix(charColor, cracks, crack * uLook2.x);\n color.rgb = mix(color.rgb, charColor, charZone);\n roughness = mix(roughness, 0.6, charZone);\n // Blistered, and each plate tilted its own way, so a raking light breaks\n // the char into plates rather than lighting it as one sheet of black.\n plHeight += charZone * ((plNoise(p * 380.0) - 0.5) * 0.00008 + (plate - 0.5) * 0.00018 - crack * 0.00016);\n\n // ── Ash lip ─────────────────────────────────────────────────────────────\n // Inside the spec's zones (§5): the lip 0.5–1.5 mm, then the ember line\n // 0.3–1 mm — 2.5 mm from the cut at most, which the gate holds it to.\n // Along the rim. Both the lip and the ember line below are laid out on this,\n // and unlike the scorch fingers above it is safe to sample noise in: it is\n // used ONLY within a couple of millimetres of the cut, where the presence\n // gradient is the actual edge and points somewhere real. The fingers'\n // mistake was carrying the same idea out into flat char, where the gradient\n // is rounding error and a noise sampled in its frame draws the contours.\n vec2 tangentP = length(gradP) > 1e-4 ? normalize(vec2(-gradP.y, gradP.x)) : vec2(1.0, 0.0);\n\n float lipWidth = mix(0.4, max(uLook1.y, 0.41), plFbm(p / (2.5 * PL_MM)));\n // Broken, not a hem. Ash flakes off a cooling edge in pieces, so the lip\n // comes and goes along the rim and wanders in width where it is there. It\n // used to be a continuous band of even width with a highlight down the\n // middle of it, which read as a neon tube round the hole — the single most\n // synthetic thing at wide view.\n float lipAlong = dot(p, tangentP) / (3.2 * PL_MM);\n float lipBreak = smoothstep(0.34, 0.56, plFbm(vec2(lipAlong, 0.9)));\n float lip = (1.0 - smoothstep(lipWidth - aa, lipWidth + aa, mm)) * step(d.a, 0.999) * cutNear * lipBreak;\n vec3 ash = plLinear(mix(vec3(0.525, 0.498, 0.490), vec3(0.741, 0.725, 0.725), plNoise(p * 520.0) * 0.6 + plNoise(p * 90.0) * 0.4)) * uLook1.z;\n color.rgb = mix(color.rgb, ash, lip);\n roughness = mix(roughness, 0.99, lip);\n // Barely raised. THIS is where the highlight came from: a 0.7 mm ridge\n // running round the hole is a cylinder, and a cylinder under a key light\n // has a specular line down it however rough the surface is. Ash is a\n // fragile crust a fraction of a millimetre proud of the paper, not a bead\n // of solder — and the shape of it belongs to the broken edge above, not to\n // a smooth ramp.\n plHeight += lip * (1.0 - mm / max(lipWidth, 0.1)) * 0.00018;\n\n // ── The ember line ──────────────────────────────────────────────────────\n // Beads along the cut: position along the edge, crawling on the burn's\n // clock, with a flicker of their own. Only where it is hot — and as the\n // heat goes the threshold rises, so the line breaks into fewer, dimmer\n // beads and they go out one by one.\n float s1 = dot(p, tangentP) / (2.4 * PL_MM) - uDamageTime * 0.55 * uLook0.w;\n float bead = plNoise(vec2(s1, 0.37)) * 0.7 + plNoise(vec2(s1 * 2.3, 5.1)) * 0.3;\n float flicker = 0.62 + 0.38 * plNoise(vec2(floor(s1) * 7.13, uDamageTime * 9.0 * uLook0.w));\n // Down to a smoulder's last flicker: a spent edge keeps a little heat in\n // the texture (\\`Afterglow\\`), and a bead should glow dim red on it rather\n // than vanish while the edge still has something to give.\n // Heat softened like the cut (its texel and the four around it), so the\n // beads and the crimson glow follow the burn rather than the grid's cells.\n float heatSoft = (2.0 * d.b + e.b + w.b + n.b + s.b) / 6.0;\n float hot = smoothstep(0.012, 0.55, heatSoft);\n // Coverage slides the threshold: more of the edge lit, or less.\n float shift = (uLook0.z - 0.5) * 0.5;\n float lit = smoothstep(mix(0.82, 0.45, hot) - shift, mix(0.9, 0.58, hot) - shift, bead);\n // Each bead tapers at its ends — a bead, not a dash cut from a strip.\n float width = max(mix(0.4, max(uLook0.x, 0.41), plNoise(vec2(s1 * 0.7, 9.0))) * (0.35 + 0.65 * lit), 1.4 * aa);\n float band = smoothstep(lipWidth - aa, lipWidth + aa, mm) * (1.0 - smoothstep(lipWidth + width - aa, lipWidth + width + aa, mm)) * cutNear;\n // Mostly orange: a bead is red at its ends and yellow-white only at its\n // hottest core, which is what Ember_line.png shows. Mapped low and pushed\n // high by a power, so white is the exception rather than the line.\n // Orange through, yellow-white at the hottest cores. Dim red alone reads\n // salmon once the curve desaturates it, so the ramp starts at orange and\n // only the cooling (low heat) falls back into red.\n float t = hot * flicker * (0.45 + 0.55 * lit);\n color.rgb = mix(color.rgb, plLinear(vec3(0.12, 0.04, 0.02)), band * lit);\n // Saturated orange at orange brightness; only the hottest cores are pushed\n // high enough for the curve to roll them to white.\n plDamageLight = plEmberRamp(t) * mix(0.8, 6.0, t * t * t * t) * band * lit * hot * uLook0.y;\n\n // The rest of a real burning edge (Ember_line.png): a dim crimson glow in\n // the char beside the beads — patches of it, drifting — and specks of\n // glowing fibre that come and go. Both stay under the bloom threshold, so\n // they read as heat in the char rather than as light; both only where the\n // edge is hot, and inside the zone the beads are held to — the lip plus\n // the widest bead, measured from the cut — so the glow never reaches out\n // over paper the gate says heat must not light.\n float zoneEnd = uLook1.y + uLook0.x;\n float seam = smoothstep(lipWidth - aa, lipWidth + aa, mm) * (1.0 - smoothstep(zoneEnd - 0.6, zoneEnd, mm)) * cutNear;\n float patch_ = smoothstep(0.35, 0.72, plFbm(p / (4.0 * PL_MM) + vec2(uDamageTime * 0.15 * uLook0.w, 0.0)));\n plDamageLight += vec3(0.55, 0.06, 0.01) * seam * patch_ * hot * uLook1.x;\n float speck = step(0.985, plHash(floor(p / (0.35 * PL_MM)) + floor(uDamageTime * 8.0 * uLook0.w)));\n plDamageLight += plEmberRamp(0.9) * 1.6 * speck * seam * hot * uLook3.z;\n\n plDamageCut(color, d);\n}\n`\n\n/**\n * The sheet-space half of `HELPERS`, for the shadow pass.\n *\n * `HELPERS` is written for the colour program, and part of it cannot compile\n * anywhere else: `plPerturb` reads `vViewPosition`, which a depth material\n * does not have — and GLSL compiles a function whether or not anything calls\n * it. So the depth program gets everything the CUTTING chunks need (the UV\n * varying, the sheet size, `plLocal`, the noise) and none of the lighting.\n *\n * Carved out of the one string at load time rather than written twice, so the\n * two can never drift, and so the colour program stays byte-for-byte what it\n * was. If an anchor below ever moves, this throws on import rather than\n * compiling a shadow program that silently differs.\n */\nfunction carveDepthHelpers(helpers: string): string {\n const darken = 'uniform float uBackDarken;\\n'\n const relief = helpers.indexOf(\"/**\\n * The paper's relief\")\n const bell = helpers.lastIndexOf('/**', helpers.indexOf('float plBell('))\n if (!helpers.includes(darken) || relief < 0 || bell <= relief) {\n throw new Error('compose: HELPERS changed shape — update carveDepthHelpers')\n }\n return (helpers.slice(0, relief) + helpers.slice(bell)).replace(darken, '')\n}\n\n/** Exported for its test, which pins what the shadow pass can and cannot see. */\nexport const DEPTH_HELPERS = carveDepthHelpers(HELPERS)\n\nconst DEPTH_VERTEX = /* glsl */ `\nvarying vec2 vPaperUv;\nvoid main() {\n vPaperUv = uv;\n}\n`\n\nconst AGING_CHUNK = /* glsl */ `\nuniform float uAgingAmount;\n\nvoid plAging(inout vec4 color) {\n // Yellowing deepens toward the edges, like light exposure.\n float edge = max(abs(vPaperUv.x - 0.5), abs(vPaperUv.y - 0.5)) * 2.0;\n vec3 yellowed = color.rgb * vec3(1.0, 0.94, 0.78);\n color.rgb = mix(color.rgb, yellowed, uAgingAmount * (0.45 + edge * 0.55));\n // Foxing: sparse rusty blotches.\n float fox = plFbm(vPaperUv * 14.0 + 3.7);\n float spots = smoothstep(0.62, 0.78, fox) * uAgingAmount;\n color.rgb = mix(color.rgb, vec3(0.62, 0.45, 0.26), spots * 0.5);\n}\n`\n\n/**\n * Compose the enabled effects into one program. The shader owns the base\n * color entirely: the FRONT face samples the content texture, the BACK face\n * renders the stock (or content.back) with an optional reversed show-through\n * ghost — a single DoubleSide map would mirror the front content onto the\n * back, which real paper doesn't do.\n */\nexport function composeSurface(\n surface: SurfaceConfig,\n stock: Stock,\n thickness: number,\n maps: SurfaceMaps = { hasFrontMap: false, hasBackMap: false },\n /** World dims — perforation holes are sized in world units. */\n sheet: { width: number; height: number } = { width: 1, height: 1.4 },\n /** Whose key light transmission is measured against — a preset name or the scene's resolved rig. */\n lighting: LightingName | LightingPreset = 'studio',\n /**\n * The crease lines to draw, already resolved. Authored `surface.creaseLines`\n * and the sheet's remembered creases both arrive here as the same thing —\n * see `resolveCreases`, which is the only place that knows they came from\n * two different questions.\n */\n creases: CreaseShading[] = resolveCreases(surface, [], sheet),\n): ComposedSurface {\n const grain = surface.grain ?? stock.defaultSurface.grain\n const aging = surface.aging ?? stock.defaultSurface.aging\n const deckle = surface.deckle\n const perforation = surface.perforation\n const banding = stock.banding\n // Adhesive undersides are opaque backing-paper white — nothing shows through.\n const showThrough = stock.adhesive ? 0 : (surface.showThrough ?? stock.showThrough)\n\n const chunks: string[] = []\n const calls: string[] = []\n const uniforms: Record<string, { value: unknown }> = {\n // Backside darkening: thicker/opaque stock lets less light through.\n // Adhesive backs skip it — the glue layer is its own bright surface.\n uBackDarken: {\n value: stock.adhesive ? 1 : 1 - Math.min(0.45, 0.12 + thickness * 0.9) * stock.opacity,\n },\n uStockColor: { value: new THREE.Color(stock.color) },\n // Always present, not just when something asks for it: every effect that\n // measures anything measures in the sheet's own space now — see plLocal.\n uSheetSize: { value: new THREE.Vector2(sheet.width, sheet.height) },\n uOpacity: { value: stock.opacity },\n uShowThrough: { value: showThrough },\n // Always compiled in: the shader early-outs at zero translucency, which\n // is cheaper than carrying a second program structure for it.\n ...translucencyUniforms(surface.translucency ?? stock.translucency, lighting),\n }\n if (maps.hasFrontMap) uniforms.uFrontMap = { value: null }\n if (maps.hasBackMap) uniforms.uBackMap = { value: null }\n\n if (grain !== undefined || banding > 0) {\n chunks.push(GRAIN_CHUNK)\n calls.push('plGrain(csm_DiffuseColor, csm_Roughness);')\n uniforms.uGrainAmount = { value: grain ?? 0 }\n uniforms.uGrainBanding = { value: banding }\n }\n if (deckle) {\n chunks.push(DECKLE_CHUNK)\n calls.push('plDeckle(csm_DiffuseColor);')\n uniforms.uDeckleEdges = { value: edgeFlags(deckle.edges) }\n uniforms.uDeckleRoughness = { value: deckle.roughness }\n }\n if (perforation) {\n const edges = perforation.edges === 'all' ? [...paperEdgesOrder] : perforation.edges\n chunks.push(PERFORATION_CHUNK)\n calls.push('plPerforation(csm_DiffuseColor);')\n uniforms.uPerfEdges = { value: edgeFlags(edges) }\n uniforms.uPerfTorn = {\n value: new THREE.Vector4(\n ...paperEdgesOrder.map((e) => (edges.includes(e) && perforation.state[e] === 'torn' ? 1 : 0)),\n ),\n }\n uniforms.uPerfRadius = { value: perforation.holeRadius }\n uniforms.uPerfSpacing = { value: perforation.spacing }\n }\n if (creases.length > 0) {\n chunks.push(CREASE_CHUNK)\n calls.push('plCrease(csm_DiffuseColor, csm_Roughness);')\n uniforms.uCreaseAngles = { value: pad(creases.map((c) => (c.angle * Math.PI) / 180)) }\n uniforms.uCreaseStrengths = { value: pad(creases.map((c) => c.strength)) }\n uniforms.uCreaseOffsets = { value: pad(creases.map((c) => c.offset)) }\n uniforms.uCreaseWidth = { value: CREASE_RADIUS * SHADED_CREASE }\n uniforms.uCreaseCount = { value: Math.min(creases.length, 4) }\n }\n if (aging !== undefined) {\n chunks.push(AGING_CHUNK)\n calls.push('plAging(csm_DiffuseColor);')\n uniforms.uAgingAmount = { value: aging }\n }\n // Last, so a burn chars over the yellowing and the ink alike.\n if (maps.hasDamage) {\n chunks.push(DAMAGE_CHUNK, DAMAGE_SHADE_CHUNK)\n calls.push('plDamage(csm_DiffuseColor, csm_Roughness);')\n // Bound by `PaperMaterial` to the uploaded texture; null only until then.\n uniforms.uDamage = { value: null }\n // Set by `PaperMaterial` from the source's `detail` every frame.\n uniforms.uDamageDetail = { value: 1 }\n // The burn's clock, which the ember line's beads move on — see `DamageSource.time`.\n uniforms.uDamageTime = { value: 0 }\n // How the burn is drawn — set from `DamageSource.look` every frame.\n const look = DAMAGE_LOOK_DEFAULTS\n uniforms.uLook0 = {\n value: new THREE.Vector4(look.emberWidth, look.emberIntensity, look.emberCoverage, look.emberFlicker),\n }\n uniforms.uLook1 = {\n value: new THREE.Vector4(look.emberGlow, look.lipWidth, look.lipBrightness, look.charWarmth),\n }\n uniforms.uLook2 = {\n value: new THREE.Vector4(look.charCracks, look.scorchReach, look.scorchDarkness, look.fingers),\n }\n uniforms.uLook3 = { value: new THREE.Vector4(look.edgeWave, look.edgeBite, look.sparkle, 0) }\n }\n\n /**\n * The shadow pass, for any sheet that removes paper.\n *\n * Holes cut in the colour program by alpha are invisible to the shadow\n * map: three renders shadows with its own depth material, which alpha-tests\n * a `map` if there is one and knows nothing of alpha computed in shader\n * code. So a torn edge, a perforation and a burnt-through hole all cast a\n * solid shadow — the most obvious fake a burn can have, and one the\n * deckle and perforation had been shipping since before this seam.\n *\n * The fix is the same chunks, run again in a depth program that DISCARDS\n * wherever the colour program would have cut. Only what cuts: grain,\n * creases and ageing change colour and not coverage, and a depth program\n * pays per fragment for everything in it.\n */\n const cutting: string[] = []\n const cuts: string[] = []\n if (deckle) {\n cutting.push(DECKLE_CHUNK)\n cuts.push('plDeckle(color);')\n }\n if (perforation) {\n cutting.push(PERFORATION_CHUNK)\n cuts.push('plPerforation(color);')\n }\n if (maps.hasDamage) {\n cutting.push(DAMAGE_CHUNK)\n cuts.push('plDamageCut(color, plDamageRead());')\n }\n const depth =\n cutting.length > 0\n ? {\n vertexShader: DEPTH_VERTEX,\n fragmentShader: /* glsl */ `\n${DEPTH_HELPERS}\n${cutting.join('\\n')}\nvoid main() {\n vec4 color = vec4(1.0);\n float roughness = 1.0;\n ${cuts.join('\\n ')}\n if (color.a < 0.5) discard;\n}\n`,\n }\n : null\n\n // Whether anything above described a SHAPE and not just a colour. The\n // perturbation is one pair of screen derivatives, which is cheap but not\n // free, and a plain sheet has nothing for it to do.\n // A burn has a shape too — blistered char, a lifted ash lip — and on an\n // untouched field its height is exactly zero, which `plPerturb` returns\n // unchanged, so attaching a field still costs a sheet no pixel.\n const relief = grain !== undefined || creases.length > 0 || Boolean(maps.hasDamage)\n\n const frontExpr = maps.hasFrontMap ? 'texture2D(uFrontMap, vPaperUv).rgb' : 'uStockColor'\n // The back reads correctly when the sheet is flipped → mirror x. Adhesive\n // undersides (sticker stock) are glossy near-white regardless of the front.\n const backBaseExpr = stock.adhesive\n ? 'vec3(0.965, 0.96, 0.945)'\n : maps.hasBackMap\n ? 'texture2D(uBackMap, vec2(1.0 - vPaperUv.x, vPaperUv.y)).rgb'\n : 'uStockColor'\n\n const fragmentShader = /* glsl */ `\n${HELPERS}\nuniform vec3 uStockColor;\nuniform float uOpacity;\nuniform float uShowThrough;\n${maps.hasFrontMap ? 'uniform sampler2D uFrontMap;' : ''}\n${maps.hasBackMap && !stock.adhesive ? 'uniform sampler2D uBackMap;' : ''}\n${TRANSLUCENCY_FRAGMENT}\n${chunks.join('\\n')}\nvoid main() {\n plHeight = 0.0;\n vec3 front = ${frontExpr};\n if (gl_FrontFacing) {\n csm_DiffuseColor = vec4(front, uOpacity);\n } else {\n vec3 backBase = ${backBaseExpr};\n csm_DiffuseColor = vec4(backBase * mix(vec3(1.0), front, uShowThrough), uOpacity);\n }\n ${calls.join('\\n ')}\n${relief ? ' // The relief every effect above described, spent once — see plPerturb.\\n csm_FragNormal = plPerturb(csm_FragNormal, plHeight);' : ''}\n if (!gl_FrontFacing) csm_DiffuseColor.rgb *= uBackDarken;\n ${stock.adhesive ? '// Adhesive underside: higher specular than the printed face.\\n if (!gl_FrontFacing) csm_Roughness = 0.18;' : ''}\n // What the key light pushes through the sheet, filtered by the ink on it.\n csm_Emissive = plTransmission(front);\n${maps.hasDamage ? ' // The ember line — the only light a burn gives off from the sheet itself.\\n csm_Emissive += plDamageLight;' : ''}\n}\n`\n\n return {\n structureKey: `${[\n grain !== undefined || banding > 0 ? 'g' : '',\n deckle ? 'd' : '',\n creases.length > 0 ? 'c' : '',\n aging !== undefined ? 'a' : '',\n perforation ? 'p' : '',\n stock.adhesive ? 'A' : '',\n ].join('')}:${maps.hasFrontMap ? 'F' : ''}${maps.hasBackMap ? 'B' : ''}${maps.hasDamage ? 'D' : ''}`,\n vertexShader: VERTEX,\n fragmentShader,\n uniforms,\n // Anything that removes paper needs fragments discarded rather than\n // blended — a hole has to cut the depth buffer and the shadow too.\n alphaTest: deckle || perforation || maps.hasDamage ? 0.5 : 0,\n depth,\n }\n}\n\nfunction pad(values: number[], fill = 0): number[] {\n const out = values.slice(0, 4)\n while (out.length < 4) out.push(fill)\n return out\n}\n","import * as THREE from 'three'\nimport type { LightingName } from '../config/schema'\nimport { getLightingPreset, type LightingPreset } from '../scene/lighting'\n\n/**\n * Light passing THROUGH the paper.\n *\n * Every reference image for stage mode is lit from behind: the paper is a\n * filter, not a surface catching a key light. That single change is what\n * separates \"a render of some paper\" from the look — and it is cheap,\n * because paper is thin and diffuse. No refraction, no transmission pass,\n * no `MeshPhysicalMaterial` (which does not instance): one dot product and\n * an additive emissive term, so it works identically in the instanced field\n * path and the hero path.\n *\n * The detail that sells it is the ink filter. What comes through a backlit\n * sheet is the lamp MINUS whatever is printed on it, which is why the\n * calligraphy on a lit banner reads dark against a glowing field instead of\n * blowing out with everything else.\n */\n\n/** Declared by both stages of both pipelines. */\nexport const TRANSLUCENCY_VARYINGS = /* glsl */ `\nvarying vec3 vPlWorldNormal;\nvarying vec3 vPlViewDir;\n`\n\nexport interface TranslucencyVertexSlots {\n /** Object → world matrix expression. Instanced meshes must fold in `instanceMatrix`. */\n model: string\n /** Final object-space position expression. */\n position: string\n /** Final object-space normal expression. */\n normal: string\n}\n\n/**\n * Vertex side: publish the world-space normal and view vector. Doing this in\n * the vertex shader (rather than reconstructing from `vNormal`) keeps the\n * chunk independent of where in three's fragment pipeline it gets injected.\n */\nexport function translucencyVertexChunk(slots: TranslucencyVertexSlots): string {\n return /* glsl */ `\n {\n mat4 plModel = ${slots.model};\n vec4 plWorld = plModel * vec4(${slots.position}, 1.0);\n // Uniform scale only — layouts scale sheets evenly, so the plain 3×3 is\n // the correct normal matrix here and skips an inverse-transpose.\n vPlWorldNormal = normalize(mat3(plModel) * ${slots.normal});\n vPlViewDir = cameraPosition - plWorld.xyz;\n }\n`\n}\n\n/** How much of the incident key light a fully translucent sheet passes on. */\nexport const TRANSMISSION_GAIN = 0.5\n\n/** Fragment side: uniforms plus `plTransmission(inkFilter)`. */\nexport const TRANSLUCENCY_FRAGMENT = /* glsl */ `\nuniform float uTranslucency;\nuniform vec3 uBackLightDir;\nuniform vec3 uBackLightColor;\nuniform float uAmbientTransmission;\n${TRANSLUCENCY_VARYINGS}\n\nvec3 plTransmission(vec3 inkFilter) {\n if (uTranslucency <= 0.0) return vec3(0.0);\n vec3 n = normalize(vPlWorldNormal);\n // Sheets render double-sided; the back face needs the normal it actually shows.\n if (!gl_FrontFacing) n = -n;\n // The lamp is BEHIND this sheet when the face we are looking at points away\n // from it — that is the whole test.\n float behind = clamp(-dot(n, uBackLightDir), 0.0, 1.0);\n // A grazing view looks through more paper, and more paper passes less light.\n float thickness = abs(dot(n, normalize(vPlViewDir)));\n // Paper in a lit room glows whatever way it is turned — a sheet standing\n // edge-on to the only lamp is not black. Without this floor, a banner\n // whose face runs parallel to the key light gets neither diffuse nor\n // transmission and drops out of the picture entirely.\n vec3 arriving = uBackLightColor * behind + uAmbientTransmission;\n return arriving * uTranslucency * mix(0.25, 1.0, thickness) * inkFilter;\n}\n`\n\nexport interface TranslucencyValues {\n translucency: number\n /** Unit world direction from the scene toward the key light. */\n direction: THREE.Vector3\n color: THREE.Color\n /** Light the room passes through the sheet from every direction at once. */\n ambient: number\n}\n\n/**\n * Resolve the transmission uniforms from the paper and the scene's lighting\n * — the key light's own position and color, so translucency can never\n * disagree with the lamp casting the shadows.\n *\n * It takes a resolved rig as well as a name because a rig is no longer\n * always a preset: once the light can be moved, the lamp this sheet is\n * backlit by is the one the SCENE ended up with, not the one the paper was\n * authored against.\n */\nexport function translucencyValues(\n translucency: number,\n lighting: LightingName | LightingPreset,\n): TranslucencyValues {\n const preset = typeof lighting === 'string' ? getLightingPreset(lighting) : lighting\n const [x, y, z] = preset.key.position\n const direction = new THREE.Vector3(x, y, z)\n // A key light at the origin has no direction to give; treat it as overhead.\n if (direction.lengthSq() < 1e-12) direction.set(0, 1, 0)\n direction.normalize()\n const color = new THREE.Color(preset.key.color).multiplyScalar(preset.key.intensity * TRANSMISSION_GAIN)\n return { translucency, direction, color, ambient: preset.ambient * TRANSMISSION_GAIN }\n}\n\n/** Ready-to-bind uniform objects for a shader program. */\nexport function translucencyUniforms(\n translucency: number,\n lighting: LightingName | LightingPreset,\n): Record<string, { value: unknown }> {\n const values = translucencyValues(translucency, lighting)\n return {\n uTranslucency: { value: values.translucency },\n uBackLightDir: { value: values.direction },\n uBackLightColor: { value: values.color },\n uAmbientTransmission: { value: values.ambient },\n }\n}\n","import type { FilmName, LightOverrides, LightingName } from '../config/schema'\n\n/**\n * Lighting presets: each is a key light + ambient level + contact shadow +\n * optional gobo (a texture the key light projects — window blinds, foliage).\n * Pure data here (testable in node); textures and R3F live in\n * PaperLighting.tsx. Serialized into presets as `scene.lighting`.\n *\n * A preset is the *starting point*, not the ceiling. `lightSchema` below is\n * the art-directable half: a handful of overrides that ride on top of a\n * named preset, so \"nave, but the sun is lower and the room is dimmer\" is a\n * thing you can say — and serialize — instead of a preset you have to fork.\n */\n\nexport interface LightingPreset {\n id: LightingName\n label: string\n ambient: number\n key: { color: string; intensity: number; position: [number, number, number] }\n contactShadowOpacity: number\n /** Contact shadow blur — hard for noir, long and soft for golden hour. */\n contactShadowBlur: number\n /** Renderer tone-mapping exposure while active. */\n exposure: number\n /**\n * The tone curve the picture is printed through.\n *\n * `exposure` picks the stop; this picks the FILM, and on a subject that is\n * almost white the film is the louder of the two. Every preset ships\n * `neutral` — Khronos PBR Neutral — because it is the only one of the\n * three that keeps a clipping sheet BOTH bright and the colour it actually\n * is. See the note on `filmNames` for what the other two do to warm light.\n */\n film: FilmName\n shadow: { mapSize: number; radius: number }\n gobo?: { kind: 'blinds' | 'leaves'; drift: number; angle: number }\n /**\n * Distance haze. Depth in a deep space is staged almost entirely by fog —\n * it is what turns a row of banners into a receding colonnade instead of\n * a flat row of rectangles.\n */\n fog?: { color: string; near: number; far: number }\n /**\n * The studio light: how strongly the room itself lights the paper.\n *\n * `<ambientLight>` adds brightness with no direction at all, which is the\n * single biggest reason a surface reads flat. This is the same brightness\n * with a SHAPE — an environment built from the sky below, so a sheet\n * turned toward the bright side of the room gets more light than one\n * turned away, and paper's sheen finally has something to reflect.\n */\n studio: number\n /**\n * The room, as three colours. It grades zenith → horizon → floor, carries\n * a soft disc of the key's own colour where the key stands, and becomes\n * both the environment map and (in stage mode) the cyclorama, so the\n * light and the space it is in cannot disagree.\n */\n sky: { zenith: string; horizon: string; ground: string }\n}\n\nexport const lightingPresets: Record<LightingName, LightingPreset> = {\n studio: {\n id: 'studio',\n label: 'Studio',\n ambient: 0.28,\n key: { color: '#ffffff', intensity: 1.6, position: [2.5, 4, 3] },\n contactShadowOpacity: 0.3,\n contactShadowBlur: 2.4,\n exposure: 1,\n film: 'neutral',\n shadow: { mapSize: 1024, radius: 4 },\n studio: 0.9,\n sky: { zenith: '#f6f7f9', horizon: '#e2e2e4', ground: '#b4b1ad' },\n },\n window: {\n id: 'window',\n label: 'Window',\n ambient: 0.22,\n key: { color: '#ffe3c0', intensity: 1.9, position: [3, 2.6, 2.6] },\n contactShadowOpacity: 0.35,\n contactShadowBlur: 2.6,\n exposure: 1,\n film: 'neutral',\n shadow: { mapSize: 1024, radius: 5 },\n gobo: { kind: 'blinds', drift: 0.004, angle: 0.62 },\n studio: 0.8,\n sky: { zenith: '#cfd8e6', horizon: '#f4e6d2', ground: '#8e8478' },\n },\n leaves: {\n id: 'leaves',\n label: 'Leaves',\n ambient: 0.2,\n key: { color: '#fff2d8', intensity: 2.0, position: [2.2, 3.6, 2.4] },\n contactShadowOpacity: 0.4,\n contactShadowBlur: 2.8,\n exposure: 1,\n film: 'neutral',\n shadow: { mapSize: 1024, radius: 6 },\n gobo: { kind: 'leaves', drift: 0.012, angle: 0.7 },\n studio: 0.85,\n sky: { zenith: '#bcd3c4', horizon: '#eae2c6', ground: '#6f7a5e' },\n },\n goldenhour: {\n id: 'goldenhour',\n label: 'Golden hour',\n ambient: 0.14,\n key: { color: '#ffb066', intensity: 2.4, position: [4, 0.9, 2.2] },\n contactShadowOpacity: 0.45,\n contactShadowBlur: 3.2,\n exposure: 1.15,\n film: 'neutral',\n shadow: { mapSize: 1024, radius: 7 },\n studio: 0.7,\n sky: { zenith: '#5d6f96', horizon: '#ffbe86', ground: '#4a3a2e' },\n },\n noir: {\n id: 'noir',\n label: 'Noir',\n ambient: 0.04,\n key: { color: '#ffffff', intensity: 2.6, position: [2, 3, 1.6] },\n contactShadowOpacity: 0.7,\n contactShadowBlur: 1.1,\n exposure: 1.05,\n film: 'neutral',\n shadow: { mapSize: 2048, radius: 1 },\n studio: 0.16,\n sky: { zenith: '#0d0d10', horizon: '#26262c', ground: '#050506' },\n },\n /**\n * A hard key at a grazing angle — the light paper is photographed under.\n *\n * This is the only preset in the set whose subject is the SURFACE rather\n * than the sheet. At eight degrees above the horizon the key skims across\n * the stock instead of landing on it, so every fibre, deckle tooth and\n * crease casts a shadow the length of itself and reads as RELIEF. It is\n * how a paper merchant shoots a swatch book, and it is the only way the\n * surface effects this library ships — grain, deckle, creaseLines, aging —\n * are visible as texture rather than as tint.\n *\n * Ambient and studio are both held down on purpose. Raking light works by\n * the shadows it casts, and fill is exactly the thing that fills those in;\n * turning `studio` up here does not brighten the picture so much as erase\n * the subject.\n */\n raking: {\n id: 'raking',\n label: 'Raking',\n // Lifted from 0.06/0.25 after looking at it: at the floor the shadow\n // side of a crumple went to near-black and the relief stopped reading as\n // relief and started reading as holes. This is the least fill that still\n // leaves a facet turned away from the key legible.\n ambient: 0.09,\n key: { color: '#fff6ea', intensity: 3.2, position: [5.81, 0.84, 1.24] },\n contactShadowOpacity: 0.6,\n contactShadowBlur: 1.6,\n exposure: 1,\n film: 'neutral',\n shadow: { mapSize: 2048, radius: 2 },\n studio: 0.32,\n sky: { zenith: '#2a2a2e', horizon: '#4a4844', ground: '#141314' },\n },\n /**\n * The sheet on a lightbox: the lamp is behind the paper and level with it.\n *\n * Every other front-lit preset shows you ink ON paper. This one shows you\n * light THROUGH it — which is the most beautiful thing paper does, and\n * which the library has been able to render since `translucency` became a\n * per-stock number without a single preset ever making it the subject.\n * Vellum glows, newsprint turns to a grey lantern with its fibres showing,\n * and a printed sheet reads backwards through itself.\n *\n * Printed a stop under for the same reason `nave` is: a backlit sheet\n * carries the lamp's whole intensity as transmission, so at 1.0 the paper\n * clips to flat white and takes its own texture with it.\n */\n lightbox: {\n id: 'lightbox',\n label: 'Lightbox',\n ambient: 0.05,\n key: { color: '#fdfdff', intensity: 4.5, position: [0, 0.7, -7.97] },\n // A sheet standing on a lit panel has almost nothing to cast onto.\n contactShadowOpacity: 0.15,\n contactShadowBlur: 4,\n exposure: 0.85,\n film: 'neutral',\n shadow: { mapSize: 1024, radius: 4 },\n studio: 0.35,\n sky: { zenith: '#dfe4ec', horizon: '#f6f8fc', ground: '#b9bec8' },\n },\n nave: {\n id: 'nave',\n label: 'Nave',\n // Dim, and the key sits BEHIND the walk rather than beside it: this mode\n // is carried by light coming through the paper, not off it. Ambient is\n // nearly nothing so the only bright thing in frame is the source itself —\n // what fills the shadow side is the room, which has a direction.\n ambient: 0.03,\n key: { color: '#fff1dc', intensity: 2.8, position: [0, 7, -16] },\n contactShadowOpacity: 0.55,\n contactShadowBlur: 3.6,\n // Printed a stop under. A backlit sheet carries its lamp's whole\n // intensity as transmission, so at 1.0 every banner in the hall clipped\n // to flat white and the folds — the entire reason the paper is draped —\n // vanished into the highlight.\n exposure: 0.8,\n film: 'neutral',\n shadow: { mapSize: 2048, radius: 6 },\n // Warm and light, not black: distance in a backlit hall washes TOWARD\n // the source, which is what separates haze from murk. It has to reach\n // past the end of the walk: at `far: 38` the back half of a 36-unit\n // colonnade was uniform fog colour, so the depth cue flattened exactly\n // where depth was the picture.\n fog: { color: '#a08d72', near: 9, far: 70 },\n studio: 0.55,\n sky: { zenith: '#241c17', horizon: '#fff4e2', ground: '#0e0b09' },\n },\n}\n\nexport function getLightingPreset(name: LightingName): LightingPreset {\n return lightingPresets[name]\n}\n\n// ── The authorable half ─────────────────────────────────────────────────────\n\n// `lightSchema` and its types live in `config/schema.ts` — they are part of\n// the serialized config, and `sceneSchema` needs them, which a schema that\n// imports FROM here cannot have. Re-exported because this is where the rig\n// they describe is resolved, and a caller reaching for the overrides looks\n// for them beside `resolveLighting`.\nexport { lightSchema, type LightOverrides, type LightOverridesInput } from '../config/schema'\n\n/** Where a light stands, in the terms a person would say it in. */\nexport interface LightAngles {\n /** Degrees around the vertical: 0 = in front (+Z), 90 = right (+X), ±180 = behind. */\n azimuth: number\n /** Degrees above the horizon. */\n elevation: number\n /** Distance from the origin. Only the direction matters to a directional light; this keeps round-trips exact. */\n distance: number\n}\n\nconst DEG = 180 / Math.PI\n\n/**\n * Decompose a key light's position into the two angles the panel edits.\n *\n * A light at the origin has no direction to give, so it is reported as\n * straight overhead — the same fallback the transmission model makes, and\n * they have to agree.\n */\nexport function lightAngles(position: readonly [number, number, number]): LightAngles {\n const [x, y, z] = position\n const distance = Math.hypot(x, y, z)\n if (distance < 1e-9) return { azimuth: 0, elevation: 90, distance: 0 }\n const ground = Math.hypot(x, z)\n return {\n azimuth: ground < 1e-9 ? 0 : Math.atan2(x, z) * DEG,\n elevation: Math.atan2(y, ground) * DEG,\n distance,\n }\n}\n\n/** The inverse: put a light back where those angles say it stands. */\nexport function lightPosition(angles: LightAngles): [number, number, number] {\n const azimuth = angles.azimuth / DEG\n const elevation = angles.elevation / DEG\n const ground = Math.cos(elevation) * angles.distance\n return [Math.sin(azimuth) * ground, Math.sin(elevation) * angles.distance, Math.cos(azimuth) * ground]\n}\n\n/**\n * A preset with the overrides applied — the rig everything else reads.\n *\n * This is deliberately the ONLY way a light gets resolved. The transmission\n * uniforms, the shadow-casting lamp, the environment and the exposure all\n * come out of one object, because the bug this replaces was exactly that\n * disagreement: the banners computed their backlit glow from `studio` while\n * the hall was lit by `nave`, and a sheet lit from behind by a lamp that is\n * actually in front of it is not a subtle error.\n */\nexport function resolveLighting(\n base: LightingName | LightingPreset,\n overrides?: LightOverrides,\n): LightingPreset {\n const preset = typeof base === 'string' ? getLightingPreset(base) : base\n if (!overrides) return preset\n\n const { exposure, film, key, color, direction, height, ambient, studio, haze } = overrides\n const moved = direction !== undefined || height !== undefined\n const angles = moved ? lightAngles(preset.key.position) : null\n\n return {\n ...preset,\n ambient: ambient ?? preset.ambient,\n studio: studio ?? preset.studio,\n exposure: exposure ?? preset.exposure,\n film: film ?? preset.film,\n key: {\n color: color ?? preset.key.color,\n intensity: key ?? preset.key.intensity,\n position: angles\n ? lightPosition({\n azimuth: direction ?? angles.azimuth,\n elevation: height ?? angles.elevation,\n // A key that has been dragged onto the horizon still has to stand\n // somewhere, so a light collapsed to the origin gets a real\n // distance rather than staying at zero and losing its direction.\n distance: angles.distance || 10,\n })\n : preset.key.position,\n },\n fog: resolveFog(preset.fog, haze),\n }\n}\n\n/**\n * Haze as a multiplier on the preset's own depth cue, so one slider reads\n * \"thicker air\" rather than asking for two distances in world units. It\n * pulls both ends in together: at 2× you see half as far, and the wash\n * starts half as far out, which is what actual haze does.\n */\nfunction resolveFog(fog: LightingPreset['fog'], haze: number | undefined): LightingPreset['fog'] {\n if (!fog || haze === undefined || haze === 1) return fog\n if (haze <= 0) return undefined\n return { color: fog.color, near: fog.near / haze, far: fog.far / haze }\n}\n","import { createContext, useContext, type ReactNode } from 'react'\nimport type { LightingName } from '../config/schema'\nimport { getLightingPreset, type LightingPreset } from './lighting'\n\n/**\n * The rig in force, for anything that has to agree with the lamps.\n *\n * Transmission is the reason this exists. `translucencyValues()` reads the\n * key light's own position and colour so a sheet's backlit glow can never\n * disagree with the lamp casting its shadow — but it read it from the\n * paper's OWN `scene.lighting`, and in stage mode the banners never carried\n * one. Every banner in every stage computed its glow from `studio`, a lamp\n * up and to the right, while the hall was lit by `nave` from behind. The\n * coupling was correct and the wire was missing.\n *\n * So the scene publishes the rig it is actually using, and the paper reads\n * that in preference to its own name. Outside a stage there is no provider,\n * nothing changes, and a paper lights itself as it always did.\n */\nconst LightRigContext = createContext<LightingPreset | null>(null)\n\nexport function LightRig({ rig, children }: { rig: LightingPreset; children: ReactNode }) {\n return <LightRigContext.Provider value={rig}>{children}</LightRigContext.Provider>\n}\n\n/** The scene's rig if one is published, otherwise the paper's own preset. */\nexport function useLightRig(own: LightingName): LightingPreset {\n return useContext(LightRigContext) ?? getLightingPreset(own)\n}\n","import * as THREE from 'three'\nimport { useFrame } from '@react-three/fiber'\nimport { useEffect, useMemo } from 'react'\nimport type { DamageSource } from './damageContract'\n\n/**\n * A `DamageSource` as a texture the surface shader can sample.\n *\n * The texture wraps the source's own `pixels` array — no copy — and is\n * re-uploaded only on a frame where `version` has moved. A burning sheet\n * uploads 16 KB a frame at 64²; a sheet whose damage has stopped changing\n * uploads nothing, which is the same \"costs nothing at rest\" rule the field\n * itself follows.\n *\n * Linear filtering is what keeps a 64² grid from cutting holes as a staircase:\n * the shader cuts at presence one half, and bilinear interpolation turns that\n * into straight segments between texels. A hard-edged field still shows them\n * as facets; a graded one, which a real burn is, shows far fewer. No\n * mipmaps — the sheet is never far enough away for a 64² grid to alias.\n */\nexport function useDamageTexture(source: DamageSource | null | undefined): THREE.DataTexture | null {\n const texture = useMemo(() => {\n if (!source) return null\n const t = new THREE.DataTexture(\n source.pixels,\n source.size,\n source.size,\n THREE.RGBAFormat,\n THREE.UnsignedByteType,\n )\n t.magFilter = THREE.LinearFilter\n t.minFilter = THREE.LinearFilter\n t.wrapS = THREE.ClampToEdgeWrapping\n t.wrapT = THREE.ClampToEdgeWrapping\n t.generateMipmaps = false\n // Data, not colour. A colour-managed texture would be decoded as sRGB and\n // move every channel's midpoint — presence one half would stop being the\n // edge of the hole.\n t.colorSpace = THREE.NoColorSpace\n // Row 0 is v = 0, which is how the source writes it.\n t.flipY = false\n t.userData.version = source.version\n t.needsUpdate = true\n return t\n }, [source])\n\n // Imperatively-created, so ours to free — R3F disposes only what JSX made.\n useEffect(() => () => texture?.dispose(), [texture])\n\n useFrame(() => {\n if (!source || !texture) return\n if (texture.userData.version === source.version) return\n texture.userData.version = source.version\n texture.needsUpdate = true\n })\n\n return texture\n}\n","import { useEffect, useState } from 'react'\nimport type { PaperConfig } from '../config/schema'\nimport { getStock } from '../core/stock'\nimport { receiptTotals, type ReceiptContent } from '../content/receipt'\n\n/**\n * Accessibility layer: reduced-motion handling, a hidden DOM mirror so the\n * paper's content exists for screen readers and find-in-page, and a no-WebGL\n * DOM fallback.\n */\n\nexport function usePrefersReducedMotion(override?: boolean): boolean {\n const [system, setSystem] = useState(\n () => typeof window !== 'undefined' && window.matchMedia?.('(prefers-reduced-motion: reduce)').matches,\n )\n useEffect(() => {\n const query = window.matchMedia?.('(prefers-reduced-motion: reduce)')\n if (!query) return\n const onChange = () => setSystem(query.matches)\n query.addEventListener('change', onChange)\n return () => query.removeEventListener('change', onChange)\n }, [])\n return override ?? system\n}\n\nlet webglSupport: boolean | null = null\n\nexport function supportsWebGL(): boolean {\n if (webglSupport !== null) return webglSupport\n try {\n const canvas = document.createElement('canvas')\n webglSupport = Boolean(canvas.getContext('webgl2') ?? canvas.getContext('webgl'))\n } catch {\n webglSupport = false\n }\n return webglSupport\n}\n\n/** Human-readable text equivalent of a paper's content. */\nexport function contentText(config: PaperConfig): string {\n const content = config.content\n if (content.type === 'text') return content.text\n if (content.type === 'image') return content.alt ?? 'An image printed on paper.'\n if (content.type === 'receipt') {\n const totals = receiptTotals(content as ReceiptContent)\n const items = content.items.map((i) => `${i.name} ${i.price.toFixed(2)}`).join(', ')\n return `Receipt from ${content.store}: ${items}. Total ${totals.total.toFixed(2)}. ${content.footer}`\n }\n return 'A blank sheet of paper.'\n}\n\nconst visuallyHidden: React.CSSProperties = {\n position: 'absolute',\n width: 1,\n height: 1,\n padding: 0,\n margin: -1,\n overflow: 'hidden',\n clip: 'rect(0 0 0 0)',\n whiteSpace: 'nowrap',\n border: 0,\n}\n\n/** Hidden DOM twin of the 3D paper — screen readers read it, ctrl-F finds it. */\nexport function PaperMirror({ config }: { config: PaperConfig }) {\n return (\n <div style={visuallyHidden} aria-hidden={false}>\n {contentText(config)}\n </div>\n )\n}\n\n/** No WebGL: the paper renders flat — content on a stock-tinted card. */\nexport function PaperFallback({ config }: { config: PaperConfig }) {\n const stock = getStock(config.stock)\n const isImage = config.content.type === 'image'\n return (\n <div\n role=\"img\"\n aria-label={contentText(config)}\n style={{\n width: '100%',\n height: '100%',\n display: 'grid',\n placeItems: 'center',\n background: 'transparent',\n }}\n >\n <div\n style={{\n aspectRatio: `${config.sheet.width} / ${config.sheet.height}`,\n maxWidth: '80%',\n maxHeight: '90%',\n background: stock.color,\n color: stock.inkColor,\n boxShadow: '0 6px 24px rgba(0,0,0,0.25)',\n padding: '8%',\n overflow: 'hidden',\n fontFamily: config.content.type === 'receipt' ? 'ui-monospace, monospace' : 'Georgia, serif',\n whiteSpace: 'pre-wrap',\n fontSize: 14,\n }}\n >\n {isImage && config.content.type === 'image' ? (\n <img\n src={config.content.src}\n alt={config.content.alt ?? ''}\n style={{ width: '100%', height: '100%', objectFit: 'cover', margin: '-8%' }}\n />\n ) : (\n contentText(config)\n )}\n </div>\n </div>\n )\n}\n","/**\n * Stop-motion feel: quantize continuous time to animation \"twos\"\n * (12 steps per second, like shooting on twos at 24fps). Applies to\n * deformer time, idle motion, and behavior progress; the camera is\n * excluded by default — quantized cameras read as jank, not craft.\n */\nexport const ON_TWOS_FPS = 12\n\nexport function quantizeTime(t: number, fps: number = ON_TWOS_FPS): number {\n return Math.floor(t * fps) / fps\n}\n\n/** Snap a 0..1 progress that plays over `duration` seconds to whole frames. */\nexport function quantizeProgress(p: number, duration: number, fps: number = ON_TWOS_FPS): number {\n const steps = Math.max(1, Math.round(duration * fps))\n return Math.round(p * steps) / steps\n}\n","import { useEffect, useMemo, useRef, useState } from 'react'\nimport type { PaperConfig } from '../config/schema'\nimport { PaperStateMachine, stripStates } from './machine'\n\nexport interface UsePaperStatesResult {\n /** The config to render this frame — animated when a machine is live. */\n config: PaperConfig\n /** Current state name ('rest' when no machine). */\n state: string\n /** Send triggers through this; null when states are absent or disabled. */\n machine: PaperStateMachine | null\n}\n\n/**\n * Bind a state machine to a config with `states`. The machine survives\n * config edits via `rebase` (current state and live values are kept —\n * flipping perforation to torn mid-pick must not snap the stamp to rest);\n * it is only rebuilt when states are toggled on/off.\n *\n * `animated` holds an IMMUTABLE structural snapshot for the React tree; it\n * updates only on structural boundaries (transition start/settle, state swap,\n * rebase), not per frame. Per-tick numeric values are read straight off\n * `machine.liveConfig` by the caller's frame loop — GSAP owns values, useFrame\n * owns uploads. `machine` is returned so the caller can poll it.\n */\nexport function usePaperStates(\n config: PaperConfig,\n enabled: boolean,\n instant: boolean,\n onAction?: (event: string, state: string) => void,\n onStateChange?: (state: string) => void,\n): UsePaperStatesResult {\n const live = enabled && Boolean(config.states)\n const key = useMemo(() => JSON.stringify(config), [config])\n\n // Callbacks live in refs so machine identity doesn't churn on new closures.\n const onActionRef = useRef(onAction)\n onActionRef.current = onAction\n const onStateChangeRef = useRef(onStateChange)\n onStateChangeRef.current = onStateChange\n\n const machineRef = useRef<PaperStateMachine | null>(null)\n const lastStateRef = useRef<string>('rest')\n const [animated, setAnimated] = useState<{ config: PaperConfig; state: string } | null>(null)\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: key serializes the config — the machine rebases onto a new config instead of being rebuilt.\n useEffect(() => {\n if (!live) {\n machineRef.current?.dispose()\n machineRef.current = null\n setAnimated(null)\n return\n }\n if (machineRef.current) {\n machineRef.current.rebase(config)\n return\n }\n const machine = new PaperStateMachine(config, {\n instant,\n // Structural boundaries only (not per tick) — safe to route to React.\n onChange: (c, state) => {\n if (state !== lastStateRef.current) {\n lastStateRef.current = state\n onStateChangeRef.current?.(state)\n }\n setAnimated({ config: c, state })\n },\n onAction: (event, state) => onActionRef.current?.(event, state),\n })\n machineRef.current = machine\n lastStateRef.current = machine.state\n setAnimated({ config: machine.structuralConfig(), state: machine.state })\n }, [key, live, instant])\n\n useEffect(\n () => () => {\n machineRef.current?.dispose()\n machineRef.current = null\n },\n [],\n )\n\n return {\n config: live && animated ? animated.config : stripStates(config),\n state: live && animated ? animated.state : 'rest',\n machine: live ? machineRef.current : null,\n }\n}\n","import { gsap } from 'gsap'\nimport { mergeConfig } from '../config/merge'\nimport {\n paperConfigSchema,\n paperStatesSchema,\n stateDefSchema,\n type PaperConfig,\n type StateName,\n} from '../config/schema'\n\n/**\n * The interaction-state engine. A state is a set of parameter overrides on\n * the base preset — never a separate preset. The machine\n * resolves each state to a full config (base + overrides), keeps ONE live\n * tween target of flattened numeric leaves, and always tweens FROM CURRENT\n * VALUES: a pointer that enters/leaves rapidly retargets the same tween\n * values instead of stacking or snapping.\n *\n * Delivery split (GSAP owns values, useFrame owns uploads):\n * GSAP animates the STABLE `flat` object in place; per-tick values are polled\n * off `liveConfig` by the consumer's frame loop, never pushed through React.\n * `onChange` fires only on STRUCTURAL boundaries (a transition's start and\n * settle, a state swap, a rebase) so the React tree re-renders a handful of\n * times per interaction instead of once per frame.\n */\n\n/** Built-in trigger events (v1 — user-defined wiring is parked for editor v2). */\nexport type StateEvent = 'enter' | 'leave' | 'down' | 'up' | 'pick' | 'place' | 'return'\n\n/** The fixed v1 transition table: pointer flow + pick/drop flow. */\nexport const stateEventTransitions: Record<string, Partial<Record<StateEvent, StateName>>> = {\n rest: { enter: 'hover' },\n hover: { leave: 'rest', down: 'pressed' },\n pressed: { up: 'hover', pick: 'picked' },\n picked: { place: 'placed', return: 'rest' },\n placed: {},\n}\n\nconst DEFAULT_TRANSITION = { duration: 0.35, ease: 'power2.out' }\n\n/** The base config with `states` stripped — what a state resolves against. */\nexport function stripStates(config: PaperConfig): PaperConfig {\n if (!config.states) return config\n const { states: _states, ...rest } = config\n return rest as PaperConfig\n}\n\n/**\n * Resolve a state name to its full config: base + that state's overrides.\n * States without a recorded def (e.g. an untouched 'rest') are the base.\n * The merge re-parses so a structural override (a behavior swapped to\n * `{ type: 'carry' }`) comes back with every default filled.\n */\nexport function resolveStateConfig(base: PaperConfig, state: string): PaperConfig {\n const def = base.states?.states[state]\n const flat = stripStates(base)\n if (!def || Object.keys(def.overrides).length === 0) return flat\n return paperConfigSchema.parse(mergeConfig(flat as Record<string, unknown>, def.overrides))\n}\n\n/** Drop `undefined` leaves at every depth, and any object left empty by that. */\nfunction pruneUndefined(value: unknown): unknown {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) return value\n const out: Record<string, unknown> = {}\n for (const [key, v] of Object.entries(value as Record<string, unknown>)) {\n if (v === undefined) continue\n const pruned = pruneUndefined(v)\n const isEmptyObject =\n pruned !== null &&\n typeof pruned === 'object' &&\n !Array.isArray(pruned) &&\n Object.keys(pruned).length === 0\n if (!isEmptyObject) out[key] = pruned\n }\n return out\n}\n\n/**\n * Record a patch into ONE state's override diff (Figma's overridden\n * affordance), returning a new base config with that state updated — the base\n * params and every other state stay untouched. This is how an authoring tool\n * writes while a state chip is active. `undefined` values are dropped at every\n * depth: an override can only SET a base param, never remove one. Re-parsing\n * runs the schema's per-state validation, so an override that wouldn't merge\n * cleanly throws here.\n */\nexport function recordStateOverride(\n config: PaperConfig,\n stateName: string,\n patch: Record<string, unknown>,\n): PaperConfig {\n const cleaned = pruneUndefined(patch) as Record<string, unknown>\n const states = config.states ?? paperStatesSchema.parse({})\n const def = states.states[stateName] ?? stateDefSchema.parse({})\n const overrides = mergeConfig(def.overrides, cleaned) as Record<string, unknown>\n return paperConfigSchema.parse({\n ...config,\n states: {\n ...states,\n states: { ...states.states, [stateName]: { ...def, overrides } },\n },\n })\n}\n\n// ── Numeric flattening (dot paths, array indices included) ──────────────────\n\nexport function flattenNumeric(\n value: unknown,\n prefix = '',\n out: Record<string, number> = {},\n): Record<string, number> {\n if (typeof value === 'number') {\n if (prefix) out[prefix] = value\n return out\n }\n if (value !== null && typeof value === 'object') {\n const entries = Array.isArray(value)\n ? value.map((v, i) => [String(i), v] as const)\n : Object.entries(value)\n for (const [key, v] of entries) {\n flattenNumeric(v, prefix ? `${prefix}.${key}` : key, out)\n }\n }\n return out\n}\n\nfunction setPath(target: Record<string, unknown>, path: string, value: number): void {\n const keys = path.split('.')\n let node: Record<string, unknown> = target\n for (let i = 0; i < keys.length - 1; i++) {\n const next = node[keys[i]!]\n if (next === null || typeof next !== 'object') return // structure changed under us\n node = next as Record<string, unknown>\n }\n node[keys[keys.length - 1]!] = value\n}\n\n/** Apply the flat numeric leaves onto a config object in place (no allocation). */\nfunction applyFlat(target: Record<string, unknown>, flat: Record<string, number>): void {\n for (const path in flat) setPath(target, path, flat[path]!)\n}\n\nconst clone = <T>(v: T): T => JSON.parse(JSON.stringify(v)) as T\n\n// ── The machine ──────────────────────────────────────────────────────────────\n\nexport interface PaperStateMachineOptions {\n /** Reduced motion: every transition applies instantly (duration 0). */\n instant?: boolean\n /**\n * Fires on STRUCTURAL boundaries only — a transition's start and settle, a\n * state swap, a rebase — with an immutable config snapshot. NOT per tick;\n * per-frame numeric values are polled off `liveConfig`.\n */\n onChange?: (config: PaperConfig, state: string) => void\n /** `onEnter` actions — v1 is 'emit:<event>' only; fires after arrival. */\n onAction?: (event: string, state: string) => void\n}\n\nexport class PaperStateMachine {\n state: string\n private base: PaperConfig\n private readonly opts: PaperStateMachineOptions\n /** Structural target of the current state; numeric leaves live in `flat`. */\n private structure: PaperConfig\n /**\n * The single live tween target — flattened numeric leaves of the config.\n * STABLE IDENTITY for the machine's lifetime: `goto`/`rebase` mutate it in\n * place (add/remove/keep keys) and never reassign, so an in-flight GSAP\n * tween keeps animating the same object across a rebase instead of freezing.\n */\n private readonly flat: Record<string, number> = {}\n /** Mutable working config, polled by the consumer's frame loop via `liveConfig`. */\n private live: PaperConfig\n private tween: gsap.core.Tween | null = null\n private resolved = new Map<string, PaperConfig>()\n\n constructor(base: PaperConfig, opts: PaperStateMachineOptions = {}) {\n this.base = base\n this.opts = opts\n this.state = base.states?.initial ?? 'rest'\n const target = this.resolve(this.state)\n this.structure = clone(target)\n this.live = clone(target)\n Object.assign(this.flat, flattenNumeric(target))\n }\n\n /** World-units drag distance that flips pressed → picked. */\n get pickThreshold(): number {\n return this.base.states?.pickThreshold ?? 0.1\n }\n\n /**\n * The live config — the mutable working object with the current tween values\n * applied in place. Cheap (no allocation); meant to be polled every frame.\n * Never hand this to React; use `structuralConfig()` for an immutable snapshot.\n */\n get liveConfig(): PaperConfig {\n applyFlat(this.live as unknown as Record<string, unknown>, this.flat)\n return this.live\n }\n\n /** Back-compat alias for `liveConfig` (tests, imperative reads). */\n get config(): PaperConfig {\n return this.liveConfig\n }\n\n /** True while a transition tween is in flight — consumers gate frame work on it. */\n get transitioning(): boolean {\n return this.tween !== null\n }\n\n /** Exposed for tests: the in-flight transition tween, if any. */\n get activeTween(): gsap.core.Tween | null {\n return this.tween\n }\n\n /** An immutable structural snapshot for React consumers (never the live object). */\n structuralConfig(): PaperConfig {\n const out = clone(this.structure) as unknown as Record<string, unknown>\n applyFlat(out, this.flat)\n return out as unknown as PaperConfig\n }\n\n /** Fire a built-in trigger; returns the new state or null if it doesn't apply. */\n send(event: StateEvent): string | null {\n const next = stateEventTransitions[this.state]?.[event]\n if (!next || next === this.state) return null\n this.goto(next)\n return next\n }\n\n /**\n * Drive to 'picked' through the legal chain (rest→hover→pressed→picked),\n * each hop instant so EVERY side effect fires (behavior override, backing\n * silhouette, onChange state reports, placed onEnter chain). This is the\n * keyboard/a11y entry point — it never produced pointer hover/press events,\n * so raw `send('pick')` from 'rest' was a no-op. Returns true if it landed.\n */\n pickProgrammatic(): boolean {\n for (const event of ['enter', 'down', 'pick'] as StateEvent[]) {\n const next = stateEventTransitions[this.state]?.[event]\n if (next && next !== this.state) this.goto(next, { instant: true })\n }\n return this.state === 'picked'\n }\n\n /** Instant, legal place (picked → placed) so onEnter/emit fires. */\n placeProgrammatic(): boolean {\n return this.driveInstant('place')\n }\n\n /** Instant, legal return (picked → rest). */\n returnProgrammatic(): boolean {\n return this.driveInstant('return')\n }\n\n private driveInstant(event: StateEvent): boolean {\n const next = stateEventTransitions[this.state]?.[event]\n if (!next || next === this.state) return false\n this.goto(next, { instant: true })\n return true\n }\n\n /** Transition to a state (escape hatch for custom states; `send` for triggers). */\n goto(state: string, opts?: { instant?: boolean }): void {\n const def = this.base.states?.states[state]\n const target = this.resolve(state)\n this.state = state\n\n const targetFlat = flattenNumeric(target)\n // Structure swaps immediately (content/stock changes don't interpolate);\n // numeric leaves keep their CURRENT values and tween to the target.\n this.structure = clone(target)\n this.live = clone(target)\n const changed: Record<string, number> = {}\n // Mutate `flat` in place (stable identity): drop stale keys, keep live\n // values for shared paths, seed new paths at their target.\n for (const path in this.flat) {\n if (!(path in targetFlat)) delete this.flat[path]\n }\n for (const [path, value] of Object.entries(targetFlat)) {\n const current = this.flat[path]\n // Paths new to this structure appear at their target value — there is\n // no current value to tween from.\n if (current === undefined) this.flat[path] = value\n else if (current !== value) changed[path] = value\n }\n\n const duration =\n this.opts.instant || opts?.instant ? 0 : (def?.transition.duration ?? DEFAULT_TRANSITION.duration)\n const ease = def?.transition.ease ?? DEFAULT_TRANSITION.ease\n\n // One tween, ever — kill the previous instead of stacking. Values pick up\n // exactly where the killed tween left them (this.flat is the target).\n this.tween?.kill()\n this.tween = null\n\n const arrive = () => {\n for (const [path, value] of Object.entries(changed)) this.flat[path] = value\n this.emitStructure()\n for (const action of def?.onEnter ?? []) {\n if (action.startsWith('emit:')) this.opts.onAction?.(action.slice(5), state)\n }\n }\n\n if (duration === 0 || Object.keys(changed).length === 0) {\n arrive()\n return\n }\n // Structural boundary #1: the start of the transition (React sees the new\n // state and structure). Ticks below never emit — GSAP mutates `flat`, the\n // consumer polls `liveConfig`; #2 is the settle in `arrive`.\n this.emitStructure()\n this.tween = gsap.to(this.flat, {\n ...changed,\n duration,\n ease,\n onComplete: () => {\n this.tween = null\n arrive()\n },\n })\n }\n\n /**\n * Swap the base config without resetting the machine — parameter edits and\n * runtime patches (torn perforation on detach) keep the current state and\n * live values instead of snapping back to `initial`. An in-flight tween is\n * left running on the SAME `flat` object, so the transition continues\n * smoothly to its target across the rebase (no freeze, no snap).\n */\n rebase(base: PaperConfig): void {\n this.base = base\n this.resolved.clear()\n const target = this.resolve(this.state)\n this.structure = clone(target)\n this.live = clone(target)\n const targetFlat = flattenNumeric(target)\n // In-place, identity-preserving: drop stale keys, seed genuinely new paths\n // at target, keep every existing (possibly mid-tween) value untouched.\n for (const path in this.flat) {\n if (!(path in targetFlat)) delete this.flat[path]\n }\n for (const [path, value] of Object.entries(targetFlat)) {\n if (!(path in this.flat)) this.flat[path] = value\n }\n // Structural change (e.g. perforation flipped to torn) → re-render the\n // structure; the tween keeps animating `flat`, so values never snap.\n this.emitStructure()\n }\n\n dispose(): void {\n this.tween?.kill()\n this.tween = null\n }\n\n private resolve(state: string): PaperConfig {\n let config = this.resolved.get(state)\n if (!config) {\n config = resolveStateConfig(this.base, state)\n this.resolved.set(state, config)\n }\n return config\n }\n\n private emitStructure(): void {\n this.opts.onChange?.(this.structuralConfig(), this.state)\n }\n}\n","import * as THREE from 'three'\nimport { useEffect, useMemo, useRef } from 'react'\nimport { useFrame, useThree } from '@react-three/fiber'\nimport { ContactShadows } from '@react-three/drei'\nimport type { FilmName, LightingName } from '../config/schema'\nimport { buildEnvironment } from './environment'\nimport { resolveLighting, type LightingPreset, type LightOverrides } from './lighting'\nimport { usePrefersReducedMotion } from '../a11y'\n\n/**\n * The rig's film name, as a three constant.\n *\n * The mapping lives here rather than beside the presets because\n * `lighting.ts` is deliberately pure — it is the half that runs in node\n * under vitest, and importing three into it to name three integers would\n * trade that for nothing.\n */\nconst toneMappings: Record<FilmName, THREE.ToneMapping> = {\n agx: THREE.AgXToneMapping,\n neutral: THREE.NeutralToneMapping,\n filmic: THREE.ACESFilmicToneMapping,\n}\n\n/** Deterministic PRNG so gobos render identically everywhere. */\nfunction mulberry32(seed: number) {\n let a = seed\n return () => {\n a |= 0\n a = (a + 0x6d2b79f5) | 0\n let t = Math.imul(a ^ (a >>> 15), 1 | a)\n t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296\n }\n}\n\n/**\n * Procedural gobo textures — no binary assets in the repo. White passes\n * light, dark blocks it (SpotLight.map multiplies the beam).\n */\nexport function makeGoboTexture(kind: 'blinds' | 'leaves'): THREE.CanvasTexture {\n const size = 512\n const canvas = document.createElement('canvas')\n canvas.width = canvas.height = size\n const ctx = canvas.getContext('2d')!\n ctx.fillStyle = '#ffffff'\n ctx.fillRect(0, 0, size, size)\n\n if (kind === 'blinds') {\n // Venetian slats: soft-edged dark bars, slightly rotated.\n ctx.save()\n ctx.translate(size / 2, size / 2)\n ctx.rotate(-0.06)\n const slat = 34\n const gap = 30\n for (let y = -size; y < size; y += slat + gap) {\n const grad = ctx.createLinearGradient(0, y, 0, y + slat)\n grad.addColorStop(0, 'rgba(20,20,20,0)')\n grad.addColorStop(0.25, 'rgba(20,20,20,0.92)')\n grad.addColorStop(0.75, 'rgba(20,20,20,0.92)')\n grad.addColorStop(1, 'rgba(20,20,20,0)')\n ctx.fillStyle = grad\n ctx.fillRect(-size, y, size * 2, slat)\n }\n ctx.restore()\n } else {\n // Dappled foliage: three scales of soft dark blobs.\n const rand = mulberry32(7)\n for (const [count, radius, alpha] of [\n [26, 70, 0.75],\n [40, 38, 0.6],\n [70, 16, 0.5],\n ] as const) {\n for (let i = 0; i < count; i++) {\n const x = rand() * size\n const y = rand() * size\n const r = radius * (0.6 + rand() * 0.8)\n const grad = ctx.createRadialGradient(x, y, 0, x, y, r)\n grad.addColorStop(0, `rgba(15,20,12,${alpha})`)\n grad.addColorStop(0.7, `rgba(15,20,12,${alpha * 0.55})`)\n grad.addColorStop(1, 'rgba(15,20,12,0)')\n ctx.fillStyle = grad\n ctx.beginPath()\n ctx.ellipse(x, y, r, r * (0.6 + rand() * 0.5), rand() * Math.PI, 0, Math.PI * 2)\n ctx.fill()\n }\n }\n }\n\n const texture = new THREE.CanvasTexture(canvas)\n texture.wrapS = texture.wrapT = THREE.RepeatWrapping\n return texture\n}\n\n/**\n * The studio light: the room, prefiltered, hung on the scene.\n *\n * Mounted as its own component so the PMREM pass runs when the RIG changes\n * and not when anything else in the lighting rerenders — it is a render\n * target and a chain of blur passes, which is cheap once and silly sixty\n * times a second.\n */\nfunction StudioLight({ rig }: { rig: LightingPreset }) {\n const gl = useThree((s) => s.gl)\n const scene = useThree((s) => s.scene)\n\n // Only the colours and the key's placement change the image; intensity is\n // applied by the scene, so dragging that slider must not rebuild anything.\n const sky = `${rig.sky.zenith}|${rig.sky.horizon}|${rig.sky.ground}|${rig.key.color}|${rig.key.intensity}|${rig.key.position.join()}`\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: `sky` is the digest of everything the image is built from.\n useEffect(() => {\n const environment = buildEnvironment(gl, rig)\n const previous = scene.environment\n scene.environment = environment.texture\n return () => {\n scene.environment = previous\n environment.dispose()\n }\n }, [gl, scene, sky])\n\n useEffect(() => {\n const previous = scene.environmentIntensity\n scene.environmentIntensity = rig.studio\n return () => {\n scene.environmentIntensity = previous\n }\n }, [scene, rig.studio])\n\n return null\n}\n\n/**\n * How bright the hemisphere stand-in runs against the environment it\n * replaces. Prefiltered irradiance integrates the whole sky, and a\n * hemisphere light is one cosine term, so matching them by eye means\n * pushing the cheap one up.\n */\nconst HEMISPHERE_STAND_IN = 1.6\n\nexport interface PaperLightingProps {\n preset?: LightingName\n /**\n * Overrides on the preset — exposure, key, direction, height, ambient,\n * studio, haze. See `lightSchema`.\n */\n light?: LightOverrides\n /**\n * An already-resolved rig, which wins over `preset`/`light`. Stage mode\n * resolves once and hands the same object to the lamps and to the paper,\n * so the two cannot be resolved differently.\n */\n rig?: LightingPreset\n /** Local y of the ground the contact shadow sits on. */\n floor?: number\n /** Contact shadow footprint. */\n scale?: number\n /** Override prefers-reduced-motion (freezes gobo drift). */\n reducedMotion?: boolean\n /**\n * Shadow map resolution, overriding the preset's. 0 turns the shadow pass\n * off — it re-renders the scene's geometry, so on a weak machine it is\n * often the single most expensive thing in the frame.\n */\n shadowMapSize?: number\n /** Draw the soft contact shadow. It is its own render pass. */\n contactShadow?: boolean\n /**\n * Light the scene with the room as well as with the lamp. Off is one\n * fewer texture read per fragment and a flatter picture; it is a quality\n * knob, not an art-direction one — turn the studio light DOWN with\n * `light.studio` if you want less of it.\n */\n environment?: boolean\n}\n\n/**\n * A scene's lighting rig from one serialized name plus whatever the author\n * overrode: key light (spot with a procedural gobo, or directional), the\n * room as an environment map, ambient fill, tone-mapping exposure, distance\n * haze, and the contact shadow. Swap presets to restyle the same paper;\n * move the sliders to light it yourself.\n */\nexport function PaperLighting({\n preset = 'studio',\n light,\n rig,\n floor = -1.2,\n scale = 10,\n reducedMotion,\n shadowMapSize,\n contactShadow = true,\n environment = true,\n}: PaperLightingProps) {\n const p = useMemo(() => rig ?? resolveLighting(preset, light), [rig, preset, light])\n const mapSize = shadowMapSize ?? p.shadow.mapSize\n const castShadow = mapSize > 0\n const reduced = usePrefersReducedMotion(reducedMotion)\n const gl = useThree((s) => s.gl)\n const scene = useThree((s) => s.scene)\n\n useEffect(() => {\n const previousExposure = gl.toneMappingExposure\n const previousFilm = gl.toneMapping\n gl.toneMappingExposure = p.exposure\n gl.toneMapping = toneMappings[p.film]\n return () => {\n gl.toneMappingExposure = previousExposure\n gl.toneMapping = previousFilm\n }\n }, [gl, p.exposure, p.film])\n\n // Set imperatively rather than via <fog attach=\"fog\" />, which would bind\n // to whatever group this rig happens to be mounted under instead of the scene.\n useEffect(() => {\n if (!p.fog) return\n const previous = scene.fog\n scene.fog = new THREE.Fog(p.fog.color, p.fog.near, p.fog.far)\n return () => {\n scene.fog = previous\n }\n }, [scene, p.fog])\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: Only the gobo kind rebuilds the texture — drift and intensity animate in place.\n const goboMap = useMemo(() => (p.gobo ? makeGoboTexture(p.gobo.kind) : null), [p.gobo?.kind])\n useEffect(() => () => goboMap?.dispose(), [goboMap])\n\n const driftRef = useRef(0)\n useFrame((_, delta) => {\n if (!goboMap || !p.gobo || reduced) return\n driftRef.current += delta * p.gobo.drift\n goboMap.offset.set(driftRef.current, driftRef.current * 0.6)\n })\n\n return (\n <>\n {p.studio > 0 &&\n (environment ? (\n <StudioLight rig={p} />\n ) : (\n // The studio light degrades rather than disappearing. A hemisphere\n // is the cheap half of what the room does — light from above, a\n // different colour from below — so a machine that cannot pay for\n // the environment still gets a lit figure with a top and a bottom\n // instead of a flat cut-out.\n <hemisphereLight\n color={p.sky.horizon}\n groundColor={p.sky.ground}\n intensity={p.studio * HEMISPHERE_STAND_IN}\n />\n ))}\n <ambientLight intensity={p.ambient} />\n {p.gobo && goboMap ? (\n <spotLight\n position={p.key.position}\n color={p.key.color}\n // decay 0 keeps intensity art-directable rather than distance-driven.\n intensity={p.key.intensity * 3.2}\n angle={p.gobo.angle}\n penumbra={0.5}\n decay={0}\n castShadow={castShadow}\n map={goboMap}\n shadow-mapSize={[mapSize || 1, mapSize || 1]}\n shadow-radius={p.shadow.radius}\n shadow-normalBias={0.05}\n />\n ) : (\n <directionalLight\n position={p.key.position}\n color={p.key.color}\n intensity={p.key.intensity}\n castShadow={castShadow}\n shadow-mapSize={[mapSize || 1, mapSize || 1]}\n shadow-radius={p.shadow.radius}\n shadow-normalBias={0.05}\n />\n )}\n {contactShadow && (\n <ContactShadows\n position={[0, floor, 0]}\n opacity={p.contactShadowOpacity}\n scale={scale}\n blur={p.contactShadowBlur}\n far={3}\n />\n )}\n </>\n )\n}\n","import * as THREE from 'three'\nimport type { LightingPreset } from './lighting'\nimport { lightAngles } from './lighting'\nimport { cssColorOr } from './color'\n\n/**\n * The room, drawn as an equirectangular image so it can light things.\n *\n * Stage mode already builds a graded sky around the whole space and it lit\n * nothing — it was a gradient mesh the camera looked at. This is the same\n * three colours plus a soft disc where the key stands, turned into an\n * environment map, so the hall is lit BY the room the viewer can see. That\n * is what puts direction into the fill: a banner turned toward the source\n * picks up the source, one turned away picks up the dark end of the room,\n * and paper's sheen finally has something to reflect.\n *\n * Procedural on purpose — the repo carries no HDRI, nothing is fetched, and\n * the grade stays editable from the same numbers the lights read.\n */\n\n/** Small is fine: PMREM blurs it into mip levels anyway, and roughness eats the detail. */\nconst WIDTH = 256\nconst HEIGHT = 128\n\n/**\n * Where a direction lands in an equirectangular image, matching three's own\n * `equirectUv`: `u = atan2(z, x) / 2π + 0.5`. Our azimuth is measured from\n * +Z instead (0° in front, 90° right), which works out to `u = 0.75 − az/360`.\n * Getting this right is what puts the bright patch of sky on the same side\n * of the room as the lamp casting the shadows.\n */\nexport function skyU(azimuthDeg: number): number {\n const u = 0.75 - azimuthDeg / 360\n return ((u % 1) + 1) % 1\n}\n\n/** Elevation to image row. Row 0 is the zenith — v is flipped by the texture. */\nexport function skyV(elevationDeg: number): number {\n return 0.5 - elevationDeg / 180\n}\n\n/**\n * Paint the room. The gradient runs zenith → horizon → ground with the\n * horizon held as a band rather than a hairline, because a room's brightest\n * region is the wall, not a mathematical line through it.\n */\nexport function drawSky(ctx: CanvasRenderingContext2D, preset: LightingPreset): void {\n // Guarded: a stage's sky colours are editable text, and `addColorStop`\n // throws on anything it cannot parse. See `cssColorOr`.\n const zenith = cssColorOr(preset.sky.zenith, '#241c17')\n const horizon = cssColorOr(preset.sky.horizon, '#fff4e2')\n const ground = cssColorOr(preset.sky.ground, '#141210')\n const grade = ctx.createLinearGradient(0, 0, 0, HEIGHT)\n grade.addColorStop(0, zenith)\n grade.addColorStop(0.32, zenith)\n grade.addColorStop(0.5, horizon)\n grade.addColorStop(0.58, horizon)\n grade.addColorStop(1, ground)\n ctx.fillStyle = grade\n ctx.fillRect(0, 0, WIDTH, HEIGHT)\n\n // The key's own patch of sky. Bright, wide and soft: this is a window or a\n // softbox, not a sun, and a hard disc would make the reflections read as\n // a lamp somebody left in shot.\n const angles = lightAngles(preset.key.position)\n const x = skyU(angles.azimuth) * WIDTH\n const y = skyV(angles.elevation) * HEIGHT\n const radius = WIDTH * 0.3\n const color = new THREE.Color(preset.key.color)\n // The disc carries the key's intensity, so turning the lamp up brightens\n // the room it is standing in rather than only the shadows it casts.\n const strength = Math.min(1, preset.key.intensity / 3)\n\n // Drawn three times across the seam so a key behind the paper — where the\n // wrap falls — is not sliced in half by the edge of the image.\n for (const offset of [-WIDTH, 0, WIDTH]) {\n const glow = ctx.createRadialGradient(x + offset, y, 0, x + offset, y, radius)\n glow.addColorStop(\n 0,\n `rgba(${(color.r * 255) | 0}, ${(color.g * 255) | 0}, ${(color.b * 255) | 0}, ${strength})`,\n )\n glow.addColorStop(1, `rgba(${(color.r * 255) | 0}, ${(color.g * 255) | 0}, ${(color.b * 255) | 0}, 0)`)\n ctx.fillStyle = glow\n ctx.fillRect(x + offset - radius, y - radius, radius * 2, radius * 2)\n }\n}\n\n/** The room as a texture. Caller owns disposal. */\nexport function makeSkyEquirect(preset: LightingPreset): THREE.CanvasTexture {\n const canvas = document.createElement('canvas')\n canvas.width = WIDTH\n canvas.height = HEIGHT\n const ctx = canvas.getContext('2d')!\n drawSky(ctx, preset)\n const texture = new THREE.CanvasTexture(canvas)\n texture.mapping = THREE.EquirectangularReflectionMapping\n texture.colorSpace = THREE.SRGBColorSpace\n return texture\n}\n\n/**\n * The room, prefiltered into the mip chain a rough surface needs.\n *\n * PMREM is the expensive part and it runs ONCE per rig — a render target and\n * a handful of blur passes — after which sampling it costs a texture read.\n * Both the target and the source canvas are the caller's to dispose.\n */\nexport function buildEnvironment(\n renderer: THREE.WebGLRenderer,\n preset: LightingPreset,\n): { texture: THREE.Texture; dispose(): void } {\n const equirect = makeSkyEquirect(preset)\n const pmrem = new THREE.PMREMGenerator(renderer)\n const target = pmrem.fromEquirectangular(equirect)\n pmrem.dispose()\n equirect.dispose()\n return {\n texture: target.texture,\n dispose: () => target.dispose(),\n }\n}\n","/**\n * Colour strings that came from a person, made safe to hand to a canvas.\n *\n * Every colour in a stage — zenith, horizon, ground, the source, the room —\n * is an editable text field, and a text field emits on every keystroke. So\n * the library is handed `#f`, and `#ff`, and `not-a-colour`, in the normal\n * course of somebody typing `#ffaa22`. That is expected input, not a bug in\n * the caller.\n *\n * It matters because `addColorStop` is one of the few canvas calls that\n * **throws** rather than ignoring what it cannot parse:\n *\n * ```\n * Failed to execute 'addColorStop' on 'CanvasGradient':\n * The value provided ('not-a-colour') could not be parsed as a color.\n * ```\n *\n * and the sky is built during render, so that throw reached React as an\n * uncaught error and took the whole editor down. Three.js is the forgiving\n * one here — `new THREE.Color('nonsense')` warns and carries on — which is\n * why only the gradient path ever broke.\n *\n * Validation is the canvas's own opinion rather than a regex, because the\n * set of things CSS calls a colour is large (`rebeccapurple`, `hsl(...)`,\n * `color-mix(...)`, whatever ships next) and a regex would reject valid\n * input the gradient would have accepted.\n */\n\n/** A 1×1 scratch context, made once, used only to ask \"is this a colour?\". */\nlet probe: CanvasRenderingContext2D | null | undefined\n\nfunction probeContext(): CanvasRenderingContext2D | null {\n if (probe !== undefined) return probe\n probe = typeof document === 'undefined' ? null : document.createElement('canvas').getContext('2d')\n return probe\n}\n\n/**\n * `value` if a canvas can parse it as a colour, else `fallback`.\n *\n * The test is two assignments from two different starting colours. An\n * invalid value leaves `fillStyle` untouched, so it still reads back as\n * whichever prior it started from and the two readings disagree; a valid one\n * normalizes to the same string both times. One assignment would not do —\n * the answer would depend on what the context happened to hold.\n */\nexport function cssColorOr(value: string, fallback: string): string {\n const ctx = probeContext()\n // No DOM (SSR, tests): pass the value through rather than invent a colour.\n // Nothing is being painted, so nothing can throw.\n if (!ctx) return value\n const previous = ctx.fillStyle\n ctx.fillStyle = '#000000'\n ctx.fillStyle = value\n const fromBlack = ctx.fillStyle\n ctx.fillStyle = '#ffffff'\n ctx.fillStyle = value\n const fromWhite = ctx.fillStyle\n ctx.fillStyle = previous\n return fromBlack === fromWhite ? value : fallback\n}\n","import * as THREE from 'three'\nimport { useEffect, useState } from 'react'\nimport { useThree } from '@react-three/fiber'\nimport type { BackdropConfig } from '../config/schema'\n\n/**\n * What is behind the sheet.\n *\n * Painted onto a canvas at the viewport's own size and handed to\n * `scene.background`, rather than assigned as a texture directly. Three\n * stretches a background texture to the frame whatever shape it is, so a\n * landscape photograph behind a 9:16 export would come out squashed — and\n * the export sizes are exactly where a backdrop matters most. Painting it\n * means `cover` is really cover, and `fade` and `blur` come along for free\n * in the same pass.\n *\n * It sets the SCENE's background, so it belongs to whoever owns the canvas.\n * `<Paper>` and `<PaperField>` render it; `<PaperMesh>` deliberately does\n * not — it drops into someone else's scene, and a sheet that repainted the\n * background of the app it was embedded in would be a component doing\n * something nobody asked it to.\n */\nexport function PaperBackdrop({ backdrop }: { backdrop?: BackdropConfig }) {\n const scene = useThree((s) => s.scene)\n const size = useThree((s) => s.size)\n const [image, setImage] = useState<HTMLImageElement | null>(null)\n\n const src = backdrop?.image ?? ''\n\n useEffect(() => {\n if (!src) {\n setImage(null)\n return\n }\n let live = true\n const img = new Image()\n img.crossOrigin = 'anonymous'\n // A picture that will not load leaves the colour, which is the honest\n // rendering of \"no backdrop image\" — not a black frame and not a throw.\n img.onload = () => live && setImage(img)\n img.onerror = () => live && setImage(null)\n img.src = src\n return () => {\n live = false\n }\n }, [src])\n\n const key = JSON.stringify({ backdrop: backdrop ?? null, w: size.width, h: size.height, loaded: !!image })\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: key serializes everything the paint reads.\n useEffect(() => {\n if (!backdrop) return\n const previous = scene.background\n const texture = paintBackdrop(backdrop, size.width, size.height, image)\n scene.background = texture\n return () => {\n scene.background = previous\n texture.dispose()\n }\n }, [key])\n\n return null\n}\n\n/** Exported for the test — the painting is the part that can be wrong. */\nexport function paintBackdrop(\n backdrop: BackdropConfig,\n width: number,\n height: number,\n image: HTMLImageElement | null,\n): THREE.CanvasTexture {\n // Half resolution. It is out of focus behind the subject and it is drawn\n // once per resize, so the pixels buy nothing and the memory is real.\n const w = Math.max(2, Math.round(width / 2))\n const h = Math.max(2, Math.round(height / 2))\n const canvas = document.createElement('canvas')\n canvas.width = w\n canvas.height = h\n const ctx = canvas.getContext('2d')!\n\n ctx.fillStyle = backdrop.color\n ctx.fillRect(0, 0, w, h)\n\n if (image && image.width > 0 && image.height > 0) {\n const scale =\n backdrop.fit === 'cover'\n ? Math.max(w / image.width, h / image.height)\n : Math.min(w / image.width, h / image.height)\n const dw = image.width * scale\n const dh = image.height * scale\n ctx.save()\n // Scaled by the SHORT edge: a blur measured in pixels is a different\n // amount of blur on a phone frame than on a hero, and the backdrop\n // should sit the same distance behind the paper in both.\n if (backdrop.blur > 0) ctx.filter = `blur(${backdrop.blur * Math.min(w, h) * 0.06}px)`\n ctx.drawImage(image, (w - dw) / 2, (h - dh) / 2, dw, dh)\n ctx.restore()\n if (backdrop.fade > 0) {\n ctx.globalAlpha = backdrop.fade\n ctx.fillStyle = backdrop.color\n ctx.fillRect(0, 0, w, h)\n ctx.globalAlpha = 1\n }\n }\n\n const texture = new THREE.CanvasTexture(canvas)\n texture.colorSpace = THREE.SRGBColorSpace\n return texture\n}\n","import { useThree } from '@react-three/fiber'\nimport { useEffect } from 'react'\n\n/**\n * Hands the WebGL context back when the canvas unmounts.\n *\n * A browser gives a page about sixteen live WebGL contexts and then starts\n * killing the oldest to make room. Anything that mounts and unmounts paper as\n * it scrolls — the reference page is forty-odd cards doing exactly that — goes\n * over that ceiling not because too many sheets are on screen at once, but\n * because the ones that left never gave their context back.\n *\n * React Three Fiber disposes the renderer's own resources on unmount, and that\n * is not the same thing: the drawing context itself survives until the garbage\n * collector gets to the canvas, which is whenever it likes. `forceContextLoss`\n * is three.js's way of saying *now*, and it is the documented one.\n *\n * Measured on the reference page before this existed: one scroll to the bottom\n * produced 101 \"Too many active WebGL contexts\" warnings at a peak of thirteen\n * simultaneous canvases — comfortably under the cap, and still exhausting it.\n * Nothing was visibly blank, because a card that scrolls back into view\n * remounts and builds a fresh context; the cost was paid in that churn.\n *\n * Rendered inside a `<Canvas>`, where `useThree` can reach the renderer.\n */\nexport function ReleaseContextOnUnmount() {\n const gl = useThree((s) => s.gl)\n useEffect(\n () => () => {\n // Both, in this order. `forceContextLoss` releases the context and\n // `dispose` releases what the renderer still holds against it; calling\n // dispose alone is what leaves the context standing.\n gl.forceContextLoss()\n gl.dispose()\n },\n [gl],\n )\n return null\n}\n","import * as THREE from 'three'\nimport { gsap } from 'gsap'\nimport { Canvas, useFrame, useThree } from '@react-three/fiber'\nimport { forwardRef, useEffect, useMemo, useRef } from 'react'\nimport { sceneSchema, type PaperConfigInput, type SceneConfigInput } from './config/schema'\nimport { PaperLighting } from './scene/PaperLighting'\nimport { PaperBackdrop } from './scene/backdrop'\nimport { ReleaseContextOnUnmount } from './scene/release'\nimport { usePrefersReducedMotion } from './a11y'\nimport { DropZoneContext, DropZoneRegistry, type DropZoneConfig, type PlacedPaper } from './field/dropZones'\nimport {\n EMPTY_SET,\n effectiveFieldPapers,\n fieldIsInteractive,\n groupFieldPapers,\n type FieldPaperSlot,\n} from './field/slots'\nimport { FieldGroup, type SharedMotion } from './field/fieldGroup'\nimport { BackingSheet } from './field/backingSheet'\nimport { InteractiveField, type FieldA11yController } from './field/interactiveField'\nimport { FieldKeyboardMirror } from './field/keyboardMirror'\nimport { DEFAULT_SHEET, getLayout } from './field/layouts'\nimport { useStable } from './core/stable'\nimport type { SheetLayoutOptions } from './field/sheetGrid'\nimport { fitCamera, resolveLayoutOptions } from './field/framing'\n\n// The field system lives in field/*; this module is the public composition,\n// so it forwards only what the public API names. The rest of field/* is\n// reachable from its own module for tests and for the internals — it is not\n// re-exported here, because a re-export is how something becomes public by\n// accident.\nexport {\n DropZone,\n type DropZoneConfig,\n type DropZoneProps,\n type PlacedPaper,\n} from './field/dropZones'\nexport type { FieldPaperSlot } from './field/slots'\n\nexport interface PaperFieldMeshProps {\n /** Per-paper slots; length sets the instance count. Slot presets override the shared one. */\n papers?: FieldPaperSlot[]\n /** Sugar: image URLs → papers with image content. */\n images?: string[]\n /** Shared preset for slots that don't name their own. */\n preset?: string | PaperConfigInput\n layout?: string\n layoutOptions?: Record<string, unknown>\n motion?: { driver?: 'autoplay' | 'drag' | 'none'; speed?: number }\n entrance?: { type?: 'rise' | 'scatter' | 'none'; stagger?: number; duration?: number }\n /** Override prefers-reduced-motion (default: follow the system setting). */\n reducedMotion?: boolean\n /**\n * Per-paper interaction (hero CPU path per slot instead of one instanced\n * draw call). Defaults to true when any slot's preset carries `states` —\n * a stateful field is interactive by nature.\n */\n interactive?: boolean\n /** Fires when any slot's state machine changes state. */\n onSlotStateChange?(slot: number, state: string): void\n /**\n * Fires with a paper's index when it is clicked. Supplying it is what makes\n * the papers pickable — without a handler nothing raycasts, which matters\n * because hit-testing an instanced mesh is per-instance work on a pointer\n * move and a field is the mode with hundreds of instances in it.\n */\n onSelect?(paper: number): void\n /** Serialized drop zones (the editor's path); `<DropZone>` children also work. */\n zones?: DropZoneConfig[]\n /** Fires when a picked paper settles into any zone. */\n onPlace?(paper: PlacedPaper, zone: string): void\n /** Imperative controls for the hidden keyboard flow (wired by PaperField). */\n a11yControllerRef?: React.MutableRefObject<FieldA11yController | null>\n /**\n * Lowers what `segments: 'auto'` may ask for, per sheet. A DEVICE knob, in\n * the same sense `<PaperStage>`'s `quality` is one: it describes what the\n * machine can draw, never what the artwork is, so it does not serialize\n * into a preset or a share link. It can only ever lower the field's own\n * ceiling; nothing here can subdivide a sheet further than the library\n * would on its own.\n */\n segmentCeiling?: number\n}\n\nexport interface PaperFieldProps extends PaperFieldMeshProps {\n /**\n * Lighting — the same `{ lighting, light }` a single sheet carries.\n *\n * This component used to light itself with a bare ambient and a bare\n * directional, while the editor previewed field mode through\n * `<PaperLighting>` like everything else. So the gallery you composed and\n * the gallery the exported code produced were lit by two different rigs,\n * and the export was the one nobody had looked at.\n */\n scene?: SceneConfigInput\n children?: React.ReactNode\n className?: string\n style?: React.CSSProperties\n}\n\n/**\n * Field mode: sheets render as one instanced draw call PER DISTINCT PRESET\n * (usually one). Deformer stacks run as composed GLSL vertex chunks\n * (parity-tested against the CPU path); content lives in per-group atlases;\n * motion state (driver phase, entrance clock, layout morph) is shared so\n * mixed-preset fields move as one field.\n */\nexport const PaperFieldMesh = forwardRef<THREE.Group, PaperFieldMeshProps>(\n function PaperFieldMesh(props, ref) {\n const reduced = usePrefersReducedMotion(props.reducedMotion)\n\n const papers = useMemo<FieldPaperSlot[]>(\n () => effectiveFieldPapers(props.papers, props.images),\n [props.papers, props.images],\n )\n // Content-compared, not serialized: papers and preset are fresh objects\n // every render, and a paper can carry a whole bitmap inline. See\n // `useStable` for why stringifying these was the expensive half.\n const stablePapers = useStable(papers)\n const stablePreset = useStable(props.preset ?? null)\n const groups = useMemo(\n () => groupFieldPapers(stablePapers, stablePreset ?? undefined),\n [stablePapers, stablePreset],\n )\n const total = papers.length\n\n const layoutId = props.layout ?? 'ring'\n const layout = getLayout(layoutId)\n const firstSheet = groups[0]?.config.sheet\n const stableLayoutOptions = useStable(props.layoutOptions ?? {})\n // biome-ignore lint/correctness/useExhaustiveDependencies: `layout` is derived from layoutId, and the sheet enters by its two dimensions.\n const layoutOptions = useMemo(\n // Sheet grids size their cells from the papers themselves — gutter is\n // then literally the spacing between stamps (explicit cell dims win).\n () => resolveLayoutOptions(layoutId, layout, stableLayoutOptions, firstSheet),\n [layoutId, stableLayoutOptions, firstSheet?.width, firstSheet?.height],\n )\n\n // ── Shared motion state: one driver phase / entrance clock / morph for\n // every group, so a mixed-preset field moves as one field. ──\n const phaseRef = useRef(0)\n const dragVelRef = useRef(0)\n const mountTimeRef = useRef(-1)\n const morphRef = useRef<SharedMotion['morphRef']['current']>({ from: null, t: 1 })\n const prevLayout = useRef({ id: layoutId, options: layoutOptions })\n const gl = useThree((s) => s.gl)\n\n const driver = reduced ? 'none' : (props.motion?.driver ?? 'autoplay')\n const speed = props.motion?.speed ?? 0.5\n const entranceType = reduced ? 'none' : (props.entrance?.type ?? 'rise')\n\n useEffect(() => {\n const prev = prevLayout.current\n if (prev.id !== layoutId || JSON.stringify(prev.options) !== JSON.stringify(layoutOptions)) {\n morphRef.current = { from: prev, t: 0 }\n gsap.to(morphRef.current, { t: 1, duration: 0.9, ease: 'power2.inOut' })\n prevLayout.current = { id: layoutId, options: layoutOptions }\n }\n }, [layoutId, layoutOptions])\n\n useEffect(() => {\n if (driver !== 'drag') return\n const el = gl.domElement\n let lastX: number | null = null\n const down = (e: PointerEvent) => {\n lastX = e.clientX\n }\n const move = (e: PointerEvent) => {\n if (lastX === null) return\n const dx = e.clientX - lastX\n lastX = e.clientX\n phaseRef.current += dx * 0.0012\n dragVelRef.current = dx * 0.0012\n }\n const up = () => {\n lastX = null\n }\n el.addEventListener('pointerdown', down)\n window.addEventListener('pointermove', move)\n window.addEventListener('pointerup', up)\n return () => {\n el.removeEventListener('pointerdown', down)\n window.removeEventListener('pointermove', move)\n window.removeEventListener('pointerup', up)\n }\n }, [driver, gl])\n\n useFrame(({ clock }, delta) => {\n if (mountTimeRef.current < 0) mountTimeRef.current = clock.elapsedTime\n if (driver === 'autoplay') phaseRef.current += delta * speed * 0.02\n if (driver === 'drag') {\n phaseRef.current += dragVelRef.current * 0.5\n dragVelRef.current *= 0.94\n }\n })\n\n const shared: SharedMotion = {\n phaseRef,\n mountTimeRef,\n morphRef,\n layoutId,\n layoutOptions,\n sheet: firstSheet ?? DEFAULT_SHEET,\n entranceType,\n stagger: props.entrance?.stagger ?? 0.06,\n entranceDuration: props.entrance?.duration ?? 0.9,\n total,\n reduced,\n }\n\n // A stateful field is interactive by nature: per-paper hero path (CPU,\n // raycastable, per-slot state machines) instead of one instanced call.\n // (`groups` already resolved every preset, so reuse them for the check.)\n const interactive =\n props.interactive ?? (papers.some((s) => s.states) || groups.some((g) => Boolean(g.config.states)))\n\n const isSheet = layoutId === 'sheet'\n const sheetOptions = isSheet ? (layoutOptions as SheetLayoutOptions) : null\n\n if (interactive) {\n return (\n <group ref={ref}>\n <InteractiveField\n papers={papers}\n fallback={props.preset}\n layoutId={layoutId}\n layoutOptions={layoutOptions}\n sheetOptions={sheetOptions}\n sheet={firstSheet ?? DEFAULT_SHEET}\n reducedMotion={props.reducedMotion}\n zones={props.zones}\n onSlotStateChange={props.onSlotStateChange}\n onPlace={props.onPlace}\n a11yRef={props.a11yControllerRef}\n />\n </group>\n )\n }\n\n return (\n <group ref={ref}>\n {sheetOptions?.backing && <BackingSheet options={sheetOptions} count={total} removed={EMPTY_SET} />}\n {groups.map((group, gi) => (\n <FieldGroup\n // biome-ignore lint/suspicious/noArrayIndexKey: groups are derived from the slot list in order, so position is their only identity.\n key={`${gi}:${group.indices.length}`}\n group={group}\n shared={shared}\n onSelect={props.onSelect}\n segmentCeiling={props.segmentCeiling}\n />\n ))}\n </group>\n )\n },\n)\n\n/**\n * Frames whatever the layout actually lays out. A fixed camera can only suit\n * one layout — a `wall` of 12 runs past the top of a frame that a `pile`\n * leaves nearly empty — and layouts are pure, so the right distance is just\n * arithmetic over their poses.\n */\nfunction FitCamera(meshProps: PaperFieldMeshProps) {\n const camera = useThree((s) => s.camera)\n const width = useThree((s) => s.size.width)\n const height = useThree((s) => s.size.height)\n\n // The camera refits on prop CONTENT, not on identity — compared rather\n // than serialized, because this runs on every render of the field.\n const papersProp = useStable(meshProps.papers ?? null)\n const imagesProp = useStable(meshProps.images ?? null)\n const presetProp = useStable(meshProps.preset ?? null)\n const optionsProp = useStable(meshProps.layoutOptions ?? {})\n const field = useMemo(() => {\n const papers = effectiveFieldPapers(papersProp ?? undefined, imagesProp ?? undefined)\n const layoutId = meshProps.layout ?? 'ring'\n const layout = getLayout(layoutId)\n const sheet = groupFieldPapers(papers, presetProp ?? undefined)[0]?.config.sheet\n const options = resolveLayoutOptions(layoutId, layout, optionsProp, sheet)\n return { layout, n: papers.length, options, sheet: sheet ?? DEFAULT_SHEET }\n }, [papersProp, imagesProp, presetProp, meshProps.layout, optionsProp])\n\n useEffect(() => {\n if (!(camera instanceof THREE.PerspectiveCamera)) return\n const { position, target } = fitCamera(\n field.layout,\n field.n,\n field.options,\n field.sheet,\n camera.fov,\n width / Math.max(height, 1),\n )\n camera.position.set(...position)\n camera.lookAt(...target)\n camera.updateProjectionMatrix()\n }, [camera, width, height, field])\n\n return null\n}\n\n/** `<PaperField />` owns its own Canvas; PaperFieldMesh drops into existing scenes. */\nexport const PaperField = forwardRef<THREE.Group, PaperFieldProps>(function PaperField(\n { children, className, style, scene, ...meshProps },\n ref,\n) {\n const rig = sceneSchema.parse(scene ?? {})\n const registry = useMemo(() => new DropZoneRegistry(), [])\n const a11yRef = useRef<FieldA11yController | null>(null)\n\n // The SAME derivations PaperFieldMesh uses — a slot naming a stateful\n // preset by string, or an images-driven field, must get the keyboard\n // mirror exactly when the mesh goes interactive.\n const papers = useMemo(\n () => effectiveFieldPapers(meshProps.papers, meshProps.images),\n [meshProps.papers, meshProps.images],\n )\n const stablePapers = useStable(papers)\n const stablePreset = useStable(meshProps.preset ?? null)\n const interactive = useMemo(\n () => fieldIsInteractive(stablePapers, stablePreset ?? undefined, meshProps.interactive),\n [stablePapers, stablePreset, meshProps.interactive],\n )\n\n return (\n <div className={className} style={{ width: '100%', height: '100%', ...style }}>\n <DropZoneContext.Provider value={registry}>\n <Canvas shadows camera={{ position: [0, 0.6, 5.2], fov: 45 }} dpr={[1, 2]}>\n <FitCamera {...meshProps} />\n <PaperBackdrop backdrop={rig.backdrop} />\n {/* The floor and footprint a gallery of sheets needs — a lone sheet\n sits closer to the camera and on a tighter shadow. */}\n <PaperLighting preset={rig.lighting} light={rig.light} floor={-2.4} scale={14} />\n <PaperFieldMesh ref={ref} a11yControllerRef={a11yRef} {...meshProps} />\n {children}\n <ReleaseContextOnUnmount />\n </Canvas>\n {interactive && <FieldKeyboardMirror papers={papers} controller={a11yRef} />}\n </DropZoneContext.Provider>\n </div>\n )\n})\n","import * as THREE from 'three'\nimport { createContext, useContext, useEffect, useMemo, useRef, useSyncExternalStore } from 'react'\nimport type { PaperConfig } from '../config/schema'\n\n// ── Drop zones ─────────────────────────────────────────────────────────────\n\nexport interface DropZoneConfig {\n id: string\n /** Preset-name globs ('stamp-*'); omitted = accept all. */\n accept?: string[]\n /** World-space rect on the field plane. */\n bounds: { position: [number, number, number]; size: [number, number] }\n highlight?: 'none' | 'glow' | 'outline'\n}\n\nexport interface PlacedPaper {\n slot: number\n presetName: string\n config: PaperConfig\n}\n\nexport interface DropZoneProps extends DropZoneConfig {\n onPlace?(paper: PlacedPaper, zone: string): void\n}\n\nexport interface ZoneEntry extends DropZoneConfig {\n onPlace?: DropZoneProps['onPlace']\n}\n\n/** Shared zone state: `<DropZone>` children register; the carry loop hit-tests. */\nexport class DropZoneRegistry {\n private zones = new Map<string, ZoneEntry>()\n private hoveredId: string | null = null\n private listeners = new Set<() => void>()\n private version = 0\n\n register(zone: ZoneEntry): () => void {\n this.zones.set(zone.id, zone)\n this.notify()\n return () => {\n this.zones.delete(zone.id)\n this.notify()\n }\n }\n\n list(): ZoneEntry[] {\n return [...this.zones.values()]\n }\n\n get(id: string): ZoneEntry | undefined {\n return this.zones.get(id)\n }\n\n get hovered(): string | null {\n return this.hoveredId\n }\n\n setHovered(id: string | null): void {\n if (this.hoveredId === id) return\n this.hoveredId = id\n this.notify()\n }\n\n subscribe = (fn: () => void): (() => void) => {\n this.listeners.add(fn)\n return () => this.listeners.delete(fn)\n }\n\n getVersion = (): number => this.version\n\n private notify(): void {\n this.version++\n for (const fn of this.listeners) fn()\n }\n}\n\nexport const DropZoneContext = createContext<DropZoneRegistry | null>(null)\n\n// Compiled accept-globs, cached — zoneAccepts runs every frame in the carry\n// loop, and a fresh RegExp per glob per frame is pure GC churn.\nconst globCache = new Map<string, RegExp>()\nconst globRegExp = (glob: string): RegExp => {\n let re = globCache.get(glob)\n if (!re) {\n re = new RegExp(`^${glob.replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&').replace(/\\*/g, '.*')}$`, 'i')\n globCache.set(glob, re)\n }\n return re\n}\n\n/** True when `name` matches the zone's accept globs (all zones accept by default). */\nexport function zoneAccepts(zone: Pick<DropZoneConfig, 'accept'>, name: string): boolean {\n if (!zone.accept || zone.accept.length === 0) return true\n return zone.accept.some((glob) => globRegExp(glob).test(name))\n}\n\nexport const zoneContains = (zone: ZoneEntry, x: number, y: number): boolean =>\n Math.abs(x - zone.bounds.position[0]) <= zone.bounds.size[0] / 2 &&\n Math.abs(y - zone.bounds.position[1]) <= zone.bounds.size[1] / 2\n\n/**\n * A drop target inside a `<PaperField>`. While a paper is picked, its center\n * is tested against the bounds each frame; hovering applies the highlight\n * and release inside fires `placed` + `onPlace`.\n */\nexport function DropZone(props: DropZoneProps) {\n const registry = useContext(DropZoneContext)\n const { id, accept, bounds, highlight = 'glow', onPlace } = props\n\n // `onPlace` is a notification, not a dependency. The natural way to pass\n // one is an inline arrow, which is a new function on every render of the\n // page above — naming it here re-registered the zone on every one of those\n // renders, bumping the registry version and re-rendering every\n // `DropZoneVisual` in the field. Held in a ref, the registration depends on\n // what the zone IS, and the callback is read at the moment it fires.\n const place = useRef(onPlace)\n useEffect(() => {\n place.current = onPlace\n }, [onPlace])\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: Serialized deps — re-registering on object identity would thrash the registry.\n useEffect(() => {\n if (!registry) return\n return registry.register({\n id,\n accept,\n bounds,\n highlight,\n onPlace: (paper, zone) => place.current?.(paper, zone),\n })\n }, [registry, id, JSON.stringify(accept ?? null), JSON.stringify(bounds), highlight])\n if (!registry) return null\n return <DropZoneVisual registry={registry} config={{ id, accept, bounds, highlight }} />\n}\n\n/** The translucent target — brightens when the carried paper is over it. */\nexport function DropZoneVisual({ registry, config }: { registry: DropZoneRegistry; config: DropZoneConfig }) {\n useSyncExternalStore(registry.subscribe, registry.getVersion, registry.getVersion)\n const hovered = registry.hovered === config.id\n const style = config.highlight ?? 'glow'\n const [w, h] = config.bounds.size\n // Memoized: an inline `new THREE.PlaneGeometry` in args would rebuild (and\n // leak) the edges every render — and this re-renders on every hover change.\n const edges = useMemo(() => {\n const plane = new THREE.PlaneGeometry(w, h)\n const geo = new THREE.EdgesGeometry(plane)\n plane.dispose()\n return geo\n }, [w, h])\n useEffect(() => () => edges.dispose(), [edges])\n return (\n <group position={config.bounds.position}>\n {style !== 'outline' && (\n <mesh>\n <planeGeometry args={[w, h]} />\n <meshBasicMaterial\n color={hovered && style === 'glow' ? '#8ea8ff' : '#5c6f9e'}\n transparent\n opacity={hovered && style === 'glow' ? 0.32 : 0.14}\n depthWrite={false}\n />\n </mesh>\n )}\n <lineSegments geometry={edges}>\n <lineBasicMaterial color={hovered ? '#aebfff' : '#6b7da8'} />\n </lineSegments>\n </group>\n )\n}\n","import { z } from 'zod'\nimport type { PaperEdge } from '../config/schema'\nimport type { CurlOptions } from '../deformers/curl'\n\n/**\n * Pure grid math for the `sheet` layout — a block of stamps on a shared\n * backing. Shared by the layout's pose function, the backing silhouette\n * renderer, the outward-corner smart default, and the torn-perforation\n * auto-wiring, so they can never disagree about where a slot sits.\n */\n\nexport const sheetLayoutSchema = z.object({\n rows: z.number().int().min(1).max(12).default(2),\n columns: z.number().int().min(1).max(12).default(5),\n /** World-units gap between slots. Stamps are printed in register — no jitter. */\n gutter: z.number().min(0).max(1).default(0.08),\n /** Slot footprint in world units (the paper preset should match). */\n cellWidth: z.number().min(0.1).max(4).default(0.72),\n cellHeight: z.number().min(0.1).max(4).default(0.86),\n /** Render the shared backing sheet behind the grid. */\n backing: z.boolean().default(true),\n backingMargin: z.number().min(0).max(1).default(0.12),\n})\n\nexport type SheetLayoutOptions = z.infer<typeof sheetLayoutSchema>\n\n/** Backing thickness + ε — papers float just above the backing sheet. */\nexport const SHEET_LIFT = 0.012\n\n/**\n * Cell footprint = the paper's own sheet dims unless the user set an\n * explicit cellWidth/cellHeight — so `gutter` is literally the spacing\n * between stamps, whatever preset populates the grid.\n */\nexport function withSheetCellFromPaper(\n parsed: SheetLayoutOptions,\n rawOptions: Record<string, unknown> | undefined,\n paperDims: { width: number; height: number } | undefined,\n): SheetLayoutOptions {\n if (!paperDims) return parsed\n const hasW = rawOptions !== undefined && rawOptions.cellWidth !== undefined\n const hasH = rawOptions !== undefined && rawOptions.cellHeight !== undefined\n if (hasW && hasH) return parsed\n return {\n ...parsed,\n cellWidth: hasW ? parsed.cellWidth : paperDims.width,\n cellHeight: hasH ? parsed.cellHeight : paperDims.height,\n }\n}\n\nexport function sheetSlotXY(i: number, o: SheetLayoutOptions): { x: number; y: number } {\n const col = i % o.columns\n const row = Math.floor(i / o.columns)\n return {\n x: (col - (o.columns - 1) / 2) * (o.cellWidth + o.gutter),\n y: ((o.rows - 1) / 2 - row) * (o.cellHeight + o.gutter),\n }\n}\n\n/** Grid bounds + margin — the backing sheet's size. */\nexport function sheetBackingSize(o: SheetLayoutOptions): { width: number; height: number } {\n return {\n width: o.columns * o.cellWidth + (o.columns - 1) * o.gutter + o.backingMargin * 2,\n height: o.rows * o.cellHeight + (o.rows - 1) * o.gutter + o.backingMargin * 2,\n }\n}\n\ntype Corner = CurlOptions['corner']\n\n/**\n * The corner facing away from the sheet's center — what a thumb would find.\n * A tie (an odd grid's exact-center row/column, where the\n * cell straddles the midline) breaks outward-and-down: strict `<` on both\n * axes sends the center right and down, so a dead-center cell peels\n * bottom-right — the standalone peel default.\n */\nexport function outwardCorner(i: number, o: Pick<SheetLayoutOptions, 'rows' | 'columns'>): Corner {\n const col = i % o.columns\n const row = Math.floor(i / o.columns)\n // Row 0 renders at the top of the grid.\n const horizontal = col + 0.5 < o.columns / 2 ? 'left' : 'right'\n const vertical = row + 0.5 < o.rows / 2 ? 'top' : 'bottom'\n return `${vertical}-${horizontal}` as Corner\n}\n\n/**\n * Perforation auto-wiring on detach: edges that faced a neighboring slot tear\n * through; edges on the sheet's outer boundary keep their clean punches.\n */\nexport function tornEdgesOnDetach(\n i: number,\n o: Pick<SheetLayoutOptions, 'rows' | 'columns'>,\n): Partial<Record<PaperEdge, 'torn' | 'intact'>> {\n const col = i % o.columns\n const row = Math.floor(i / o.columns)\n return {\n top: row > 0 ? 'torn' : 'intact',\n bottom: row < o.rows - 1 ? 'torn' : 'intact',\n left: col > 0 ? 'torn' : 'intact',\n right: col < o.columns - 1 ? 'torn' : 'intact',\n }\n}\n","import {\n contentSchema,\n paperConfigSchema,\n type ContentConfig,\n type ContentConfigInput,\n type PaperConfig,\n type PaperConfigInput,\n type PaperStatesInput,\n} from '../config/schema'\nimport { mergeConfig } from '../config/merge'\nimport { resolveConfig } from '../PaperMesh'\nimport { outwardCorner, sheetLayoutSchema } from './sheetGrid'\n\n/** A field slot references a preset — the spec's component/instance model. */\nexport interface FieldPaperSlot {\n preset?: string | PaperConfigInput\n /**\n * INPUT type, not the parsed one. A slot's content is written by a caller,\n * and the parsed type demands every default be supplied — which turned a\n * two-line content literal into a type error and is exactly the failure\n * `config/props.test.ts` was added to catch on the props. Parsed here\n * (`contentSchema.parse`) so consumers downstream still get a full config.\n */\n content?: ContentConfigInput\n /** Per-instance state overrides, merged over the preset's states. */\n states?: PaperStatesInput\n}\n\nexport interface FieldGroupData {\n config: PaperConfig\n /** Global slot indices this group renders (layout poses use global i / total n). */\n indices: number[]\n contents: ContentConfig[]\n}\n\nexport const EMPTY_SET: ReadonlySet<number> = new Set()\n\n/**\n * The effective slot list: explicit `papers`, the `images` sugar, or the\n * twelve-blank default. ONE derivation shared by PaperFieldMesh and the\n * PaperField wrapper, so the mesh and the keyboard mirror always agree on\n * which papers exist.\n */\nexport function effectiveFieldPapers(papers?: FieldPaperSlot[], images?: string[]): FieldPaperSlot[] {\n if (papers) return papers\n if (images) {\n return images.map((src) => ({\n content: { type: 'image', src, fit: 'cover' } as ContentConfig,\n }))\n }\n return Array.from({ length: 12 }, () => ({}))\n}\n\n/** Group slots by resolved preset — one instanced draw call per distinct preset. */\nexport function groupFieldPapers(\n papers: FieldPaperSlot[],\n fallback?: string | PaperConfigInput,\n): FieldGroupData[] {\n const groups = new Map<string, FieldGroupData>()\n papers.forEach((slot, i) => {\n const config = resolveConfig({ preset: slot.preset ?? fallback })\n const key = JSON.stringify(config)\n let group = groups.get(key)\n if (!group) {\n group = { config, indices: [], contents: [] }\n groups.set(key, group)\n }\n group.indices.push(i)\n group.contents.push(slot.content ? contentSchema.parse(slot.content) : config.content)\n })\n return [...groups.values()]\n}\n\n/**\n * Whether a field runs the per-paper interactive path. A stateful field is\n * interactive by nature — and \"stateful\" must RESOLVE presets: a slot naming\n * a stateful preset by string counts exactly like an inline `states` object.\n * The single decision shared by PaperFieldMesh (render path) and PaperField\n * (keyboard mirror), so pointer interaction and keyboard access never diverge.\n */\nexport function fieldIsInteractive(\n papers: FieldPaperSlot[],\n fallback?: string | PaperConfigInput,\n explicit?: boolean,\n): boolean {\n if (explicit !== undefined) return explicit\n return (\n papers.some((s) => s.states) || groupFieldPapers(papers, fallback).some((g) => Boolean(g.config.states))\n )\n}\n\n/**\n * Resolve one slot to its final render config: preset (or fallback) + slot\n * content + slot-level state overrides merged over the preset's states + the\n * `sheet` smart default (an 'auto' peel corner resolves to the corner facing\n * away from the sheet's center — what a thumb would find).\n */\nexport function resolveFieldSlotConfig(\n slot: FieldPaperSlot,\n fallback: string | PaperConfigInput | undefined,\n index: number,\n layoutId: string,\n layoutOptions: Record<string, unknown>,\n): PaperConfig {\n let config = resolveConfig({ preset: slot.preset ?? fallback })\n const patch: Record<string, unknown> = {}\n if (slot.content) patch.content = slot.content\n if (slot.states) patch.states = slot.states\n if (layoutId === 'sheet' && config.behavior?.type === 'peel' && config.behavior.corner === 'auto') {\n const o = sheetLayoutSchema.parse(layoutOptions)\n patch.behavior = { corner: outwardCorner(index, o) }\n }\n if (Object.keys(patch).length > 0) {\n config = paperConfigSchema.parse(mergeConfig(config as Record<string, unknown>, patch))\n }\n return config\n}\n","import * as THREE from 'three'\nimport { gsap } from 'gsap'\nimport { useFrame } from '@react-three/fiber'\nimport { useEffect, useMemo, useRef } from 'react'\nimport CustomShaderMaterial from 'three-custom-shader-material'\nimport { getStock } from '../core/stock'\nimport { createSheetGeometry } from '../core/sheet'\nimport { getBehavior } from '../behaviors/registry'\nimport { stackAutoSegments, stackMinSegments } from '../deformers/compose'\nimport type { SegmentPair } from '../core/tessellation'\nimport type { DeformerInstance, SheetDims } from '../deformers/types'\nimport type { AeroPose } from '../physics/aero'\nimport { useContentAtlas } from '../content/atlas'\nimport {\n buildDisplacementGLSL,\n buildFieldFragmentShader,\n buildFieldVertexShader,\n stackUniformValues,\n} from './compose'\nimport { getLayout, type PaperPose } from './layouts'\nimport { translucencyUniforms, translucencyValues } from '../surface/translucency'\nimport { useLightRig } from '../scene/rig'\nimport { fieldShapeStack } from './stack'\nimport type { FieldGroupData } from './slots'\n\nconst scratchObj = new THREE.Object3D()\nconst scratchAero: AeroPose = { position: [0, 0, 0], rotation: [0, 0, 0] }\n/**\n * Caps the FLOOR a deformer stack can demand of a field instance. Field mode\n * trades a deformer's stated minimum for instance count, which hero mode\n * never does.\n */\nexport const FIELD_SEGMENT_CAP = 48\n\n/**\n * Caps what `'auto'` may ASK for in a field, as distinct from the floor above.\n *\n * It used to sit at the old flat 72 on the grounds that a field draws this\n * buffer once per instance — a real argument, made when nothing else could\n * hold the count down. Two things changed. The demand now lands on the axis\n * that bends rather than being spread over both, so a banner asking 128\n * across asks 8 down and the buffer grows on one side only. And\n * `segmentCeiling` gives the caller a working lever, which is what the\n * quality tiers now use: `low` and `medium` cap themselves well below this\n * line, so raising it only raises what a machine that measured fast enough\n * is allowed to ask for.\n *\n * 128, matching what a hero sheet was allowed before the hero ceiling moved\n * to 192. A field still asks for less than one sheet does, which is the\n * asymmetry worth keeping.\n */\nexport const FIELD_AUTO_CEILING = 128\n\n/** Mirrors the hero path's sweep sampling — see PaperMesh. */\nconst PROGRESS_SAMPLES = [0, 0.25, 0.5, 0.75, 1] as const\n\n/** Motion state shared across groups so a mixed-preset field moves as one field. */\nexport interface SharedMotion {\n phaseRef: React.MutableRefObject<number>\n mountTimeRef: React.MutableRefObject<number>\n morphRef: React.MutableRefObject<{ from: { id: string; options: unknown } | null; t: number }>\n layoutId: string\n layoutOptions: Record<string, unknown>\n /** The field's paper size — one sheet for every group, so layouts agree. */\n sheet: SheetDims\n entranceType: 'rise' | 'scatter' | 'none'\n stagger: number\n entranceDuration: number\n total: number\n reduced: boolean\n}\n\n/** Opting a mesh out of raycasting entirely — cheaper than testing and discarding. */\nconst NO_RAYCAST = () => {}\n\n/** One instanced mesh: one preset's sheet/stock/behavior across its slots. */\nexport function FieldGroup({\n group,\n shared,\n onSelect,\n segmentCeiling,\n}: {\n group: FieldGroupData\n shared: SharedMotion\n /** Called with the paper's GLOBAL index — a group only holds the slots that share its preset. */\n onSelect?: (paper: number) => void\n /** Lowers what `'auto'` may ask for on this group's sheet. Never raises it. */\n segmentCeiling?: number\n}) {\n const autoCeiling = Math.min(segmentCeiling ?? FIELD_AUTO_CEILING, FIELD_AUTO_CEILING)\n const { config, indices, contents } = group\n const count = indices.length\n const stock = getStock(config.stock)\n // The scene's rig if it publishes one — in a stage the banners are lit by\n // the hall, not by the preset each one happens to carry.\n const rig = useLightRig(config.scene.lighting)\n // A raw deformer stack is the Advanced fork of a behavior and wins over one\n // — the same precedence the hero path's buildStack applies. Field mode used\n // to read `behavior` only, so a preset shaped by `deformers` rendered flat.\n const behavior = config.behavior && !config.deformers ? getBehavior(config.behavior.type) : null\n\n const progressRef = useRef(\n behavior ? ((config.behavior as Record<string, unknown>)[behavior.progressParam] as number) : 0,\n )\n const buildStackAt = (progress: number): DeformerInstance[] => fieldShapeStack(config, progress)\n // biome-ignore lint/correctness/useExhaustiveDependencies: Serialized deps — the stack rebuilds on shape, not on identity.\n const initialStack = useMemo(\n () => buildStackAt(progressRef.current),\n [\n JSON.stringify(config.behavior ?? null),\n JSON.stringify(config.deformers ?? null),\n JSON.stringify(config.sheet),\n ],\n )\n const structureKey = initialStack.map((i) => i.type).join('|')\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: Keyed on sheet, stack structure, count and the ceiling — the only things that change the buffer.\n const geometry = useMemo(() => {\n const floor = stackMinSegments(initialStack, config.sheet)\n // Same sweep-sampling as the hero path: one buffer serves every instance\n // for the whole play, so it has to hold the densest moment of it, not the\n // current one.\n const want: SegmentPair = [0, 0]\n for (const p of PROGRESS_SAMPLES) {\n const [x, y] = stackAutoSegments(buildStackAt(p), config.sheet)\n if (x > want[0]) want[0] = x\n if (y > want[1]) want[1] = y\n }\n const geo = createSheetGeometry(\n {\n ...config.sheet,\n segments:\n config.sheet.segments === 'auto' ? 'auto' : Math.min(config.sheet.segments, FIELD_SEGMENT_CAP),\n },\n [Math.min(floor[0], FIELD_SEGMENT_CAP), Math.min(floor[1], FIELD_SEGMENT_CAP)],\n // Bounded by the auto ceiling and NOT by FIELD_SEGMENT_CAP, which is a\n // floor cap and stays one. Capping the target as well looked tidy and\n // was a visual regression: it is the only thing that could have held\n // `crumple` — whose creases have no target, only a floor of 72 — down\n // to 48 in a field, which is coarser than the deformer says it needs to\n // look like a crumple at all.\n [Math.min(want[0], autoCeiling), Math.min(want[1], autoCeiling)],\n )\n const atlasIdx = new Float32Array(count)\n const phase = new Float32Array(count)\n const bias = new Float32Array(count).fill(1)\n for (let i = 0; i < count; i++) {\n atlasIdx[i] = i\n phase[i] = ((indices[i]! * 0.618034) % 1) * 4 // golden-ratio spread by global slot\n }\n geo.setAttribute('aAtlas', new THREE.InstancedBufferAttribute(atlasIdx, 1))\n geo.setAttribute('aPhase', new THREE.InstancedBufferAttribute(phase, 1))\n // Per-sheet deformation strength, written from the layout's pose each\n // frame — how a single instanced draw call bends every sheet differently.\n geo.setAttribute('aBias', new THREE.InstancedBufferAttribute(bias, 1))\n return geo\n }, [JSON.stringify(config.sheet), structureKey, count, autoCeiling])\n\n // Imperatively created — R3F won't auto-dispose a geometry passed via args.\n useEffect(() => () => geometry.dispose(), [geometry])\n\n const atlas = useContentAtlas(contents, config.sheet, stock)\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: Keyed on the stack structure — uniforms update in place, the program does not.\n const shader = useMemo(() => {\n const composed = buildDisplacementGLSL(initialStack, config.sheet)\n const uniforms: Record<string, { value: unknown }> = {}\n for (const [name, value] of Object.entries(composed.uniforms)) {\n uniforms[name] = {\n value: Array.isArray(value) && value.length === 2 ? new THREE.Vector2(...value) : value,\n }\n }\n uniforms.uPlTime = { value: 0 }\n uniforms.uAtlas = { value: null }\n uniforms.uAtlasGrid = { value: new THREE.Vector2(1, 1) }\n uniforms.uBackDarken = {\n value: 1 - Math.min(0.45, 0.12 + config.sheet.thickness * 0.9) * stock.opacity,\n }\n uniforms.uStockColor = { value: new THREE.Color(stock.color) }\n uniforms.uShowThrough = { value: config.surface.showThrough ?? stock.showThrough }\n // Transmission reads the scene's own key light, so a backlit sheet can\n // never disagree with the lamp casting its shadow.\n Object.assign(uniforms, translucencyUniforms(config.surface.translucency ?? stock.translucency, rig))\n return {\n vertexShader: buildFieldVertexShader(composed),\n fragmentShader: buildFieldFragmentShader(),\n uniforms,\n }\n }, [\n structureKey,\n JSON.stringify(config.sheet),\n stock.id,\n config.surface.showThrough,\n config.surface.translucency,\n ])\n\n // Moving a light writes four uniforms; it must never recompile a program,\n // which is what putting the rig in the memo above would have done on every\n // frame of a slider drag.\n useEffect(() => {\n const values = translucencyValues(config.surface.translucency ?? stock.translucency, rig)\n shader.uniforms.uTranslucency!.value = values.translucency\n ;(shader.uniforms.uBackLightDir!.value as THREE.Vector3).copy(values.direction)\n ;(shader.uniforms.uBackLightColor!.value as THREE.Color).copy(values.color)\n shader.uniforms.uAmbientTransmission!.value = values.ambient\n }, [shader, rig, config.surface.translucency, stock.translucency])\n\n useEffect(() => {\n if (!atlas) return\n shader.uniforms.uAtlas!.value = atlas.texture\n ;(shader.uniforms.uAtlasGrid!.value as THREE.Vector2).set(atlas.cols, atlas.rows)\n }, [atlas, shader])\n\n // Behavior progress loops on GSAP — the field is always alive.\n // biome-ignore lint/correctness/useExhaustiveDependencies: Keyed on the behavior itself; progress lives on a ref so the tween is not restarted each render.\n useEffect(() => {\n if (!behavior || shared.reduced) return\n const state = { p: progressRef.current }\n const tween = gsap.to(state, {\n p: 1,\n duration: behavior.duration * Math.max(0.05, 1 - state.p),\n ease: 'power2.inOut',\n yoyo: behavior.loopMode === 'yoyo',\n repeat: -1,\n onUpdate: () => {\n progressRef.current = state.p\n },\n })\n return () => {\n tween.kill()\n }\n }, [structureKey, shared.reduced])\n\n const meshRef = useRef<THREE.InstancedMesh>(null)\n\n useFrame(({ clock }) => {\n const mesh = meshRef.current\n if (!mesh) return\n const elapsed = clock.elapsedTime - Math.max(shared.mountTimeRef.current, 0)\n\n shader.uniforms.uPlTime!.value = shared.reduced ? 0 : clock.elapsedTime\n if (behavior) {\n const values = stackUniformValues(buildStackAt(progressRef.current), config.sheet)\n for (const [name, value] of Object.entries(values)) {\n const uniform = shader.uniforms[name]\n if (!uniform) continue\n if (uniform.value instanceof THREE.Vector2 && Array.isArray(value)) {\n uniform.value.set(value[0]!, value[1]!)\n } else {\n uniform.value = value\n }\n }\n }\n\n const layout = getLayout(shared.layoutId)\n const morph = shared.morphRef.current\n const behaviorTransform = behavior?.transform && config.behavior ? behavior : null\n const biasAttr = geometry.getAttribute('aBias') as THREE.InstancedBufferAttribute\n const biases = biasAttr.array as Float32Array\n let biasChanged = false\n for (let j = 0; j < count; j++) {\n const i = indices[j]!\n let pose = layout.pose(i, shared.total, shared.layoutOptions, shared.phaseRef.current, shared.sheet)\n if (morph.from && morph.t < 1) {\n const prev = getLayout(morph.from.id).pose(\n i,\n shared.total,\n morph.from.options,\n shared.phaseRef.current,\n shared.sheet,\n )\n pose = lerpPose(prev, pose, easeInOut(morph.t))\n }\n if (shared.entranceType !== 'none') {\n const tIn = Math.min(1, Math.max(0, (elapsed - i * shared.stagger) / shared.entranceDuration))\n if (tIn < 1) {\n pose = lerpPose(entrancePose(shared.entranceType, i, pose), pose, easeOut(tIn))\n }\n }\n const bias = Math.min(1, Math.max(0, pose.bias ?? 1))\n if (biases[j] !== bias) {\n biases[j] = bias\n biasChanged = true\n }\n scratchObj.position.set(...pose.position)\n scratchObj.rotation.set(...pose.rotation)\n scratchObj.scale.setScalar(pose.scale)\n // Behavior whole-sheet transforms (flight) run per instance, offset in\n // time by the same golden-ratio phase the shader flutter uses — pure\n // functions of t, so instancing stays exact.\n if (behaviorTransform) {\n const pose2 = scratchAero\n pose2.position[0] = pose2.position[1] = pose2.position[2] = 0\n pose2.rotation[0] = pose2.rotation[1] = pose2.rotation[2] = 0\n const t = shared.reduced ? 0 : clock.elapsedTime + ((i * 0.618034) % 1) * 4\n behaviorTransform.transform!(\n { ...config.behavior, [behaviorTransform.progressParam]: progressRef.current },\n t,\n pose2,\n shared.sheet,\n )\n scratchObj.position.x += pose2.position[0]\n scratchObj.position.y += pose2.position[1]\n scratchObj.position.z += pose2.position[2]\n scratchObj.rotation.x += pose2.rotation[0]\n scratchObj.rotation.y += pose2.rotation[1]\n scratchObj.rotation.z += pose2.rotation[2]\n }\n scratchObj.updateMatrix()\n mesh.setMatrixAt(j, scratchObj.matrix)\n }\n mesh.instanceMatrix.needsUpdate = true\n if (biasChanged) biasAttr.needsUpdate = true\n })\n\n return (\n // biome-ignore lint/a11y/noStaticElementInteractions: An R3F <instancedMesh> is a three.js object, not a DOM node — it has no role to give and no keyboard to receive. The keyboard route into the same action is on the canvas, which `useWalk` makes focusable and drives with the arrow keys.\n <instancedMesh\n ref={meshRef}\n args={[geometry, undefined, count]}\n frustumCulled={false}\n castShadow\n receiveShadow\n // Only raycastable when somebody is listening: hit-testing an instanced\n // mesh is per-instance work on every pointer move, and this is the mode\n // that puts hundreds of instances on screen at once. Spread rather than\n // `raycast={undefined}`, which does not mean \"leave the default\" — it\n // assigns undefined over the method three is about to call.\n {...(onSelect ? {} : { raycast: NO_RAYCAST })}\n onClick={\n onSelect &&\n ((event) => {\n if (event.instanceId === undefined) return\n // `instanceId` counts within THIS group; the layout — and anything\n // that wants to know which paper was clicked — counts across all of\n // them, so the group's own index list is the translation.\n const paper = indices[event.instanceId]\n if (paper === undefined) return\n event.stopPropagation()\n onSelect(paper)\n })\n }\n >\n <CustomShaderMaterial\n key={`${structureKey}:${count}`}\n baseMaterial={THREE.MeshStandardMaterial}\n vertexShader={shader.vertexShader}\n fragmentShader={shader.fragmentShader}\n uniforms={shader.uniforms}\n roughness={stock.roughness}\n metalness={0}\n side={THREE.DoubleSide}\n />\n </instancedMesh>\n )\n}\n\nfunction entrancePose(type: 'rise' | 'scatter', i: number, target: PaperPose): PaperPose {\n if (type === 'rise') {\n return {\n position: [target.position[0], target.position[1] - 3.2, target.position[2] - 0.5],\n rotation: [target.rotation[0] - 0.7, target.rotation[1], target.rotation[2] + 0.25],\n scale: target.scale * 0.85,\n bias: target.bias,\n }\n }\n const a = i * 2.399\n return {\n position: [Math.cos(a) * 7, Math.sin(a * 1.3) * 4, Math.sin(a) * 6],\n rotation: [Math.sin(a) * 2, a, Math.cos(a) * 2],\n scale: target.scale * 0.6,\n bias: target.bias,\n }\n}\n\nfunction lerpPose(a: PaperPose, b: PaperPose, t: number): PaperPose {\n const lerp = (x: number, y: number) => x + (y - x) * t\n return {\n position: [\n lerp(a.position[0], b.position[0]),\n lerp(a.position[1], b.position[1]),\n lerp(a.position[2], b.position[2]),\n ],\n rotation: [\n lerp(a.rotation[0], b.rotation[0]),\n lerp(a.rotation[1], b.rotation[1]),\n lerp(a.rotation[2], b.rotation[2]),\n ],\n scale: lerp(a.scale, b.scale),\n bias: lerp(a.bias ?? 1, b.bias ?? 1),\n }\n}\n\nconst easeOut = (t: number) => 1 - (1 - t) ** 3\nconst easeInOut = (t: number) => (t < 0.5 ? 2 * t * t : 1 - (-2 * t + 2) ** 2 / 2)\n","import * as THREE from 'three'\nimport { useEffect, useState } from 'react'\nimport type { ContentConfig, SheetConfig } from '../config/schema'\nimport type { Stock } from '../core/stock'\nimport { useStable } from '../core/stable'\nimport { renderContentToCanvas } from './texture'\n\n/**\n * Field mode packs every paper's content into one grid atlas — one texture,\n * one draw call. Tiles keep the sheet's aspect; images redraw their tile as\n * they decode (LQIP-ish: stock tint first, pixels when ready).\n */\n\nconst MAX_ATLAS = 4096\n\n/**\n * Grid shape for `count` tiles of a given aspect (height / width).\n *\n * Square tiles want a square grid, but a stage banner is 5.7 times taller\n * than it is wide, and packing those into a square GRID makes an atlas five\n * times taller than it is wide — which then has to be squashed to fit the\n * texture budget, and the content with it. Choosing cols/rows ≈ aspect keeps\n * the atlas itself roughly square whatever shape the paper is.\n */\nexport function atlasGrid(count: number, aspect = 1): { cols: number; rows: number } {\n const cols = Math.max(1, Math.min(count, Math.ceil(Math.sqrt(count * Math.max(aspect, 0.01)))))\n return { cols, rows: Math.max(1, Math.ceil(count / cols)) }\n}\n\nexport interface ContentAtlas {\n texture: THREE.CanvasTexture\n cols: number\n rows: number\n}\n\nexport function useContentAtlas(\n contents: ContentConfig[],\n sheet: SheetConfig,\n stock: Stock,\n): ContentAtlas | null {\n const [atlas, setAtlas] = useState<ContentAtlas | null>(null)\n // Compared rather than serialized. An image tile carries its bitmap inline\n // as a data URL, and this runs on every render of the field — building a\n // cache key out of the very thing that makes the cache worth having was\n // costing more per render than the atlas it was protecting.\n const stableContents = useStable(contents)\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: the atlas is drawn from the contents, sheet and stock named below.\n useEffect(() => {\n let disposed = false\n const aspect = sheet.height / sheet.width\n const { cols, rows } = atlasGrid(contents.length, aspect)\n // Fit the tile to the budget WITHOUT breaking its aspect: a tile squashed\n // to fit renders its content squashed too. Resolution is the thing that\n // gives, never shape.\n let tileW = Math.min(1024, Math.floor(MAX_ATLAS / cols))\n let tileH = Math.round(tileW * aspect)\n if (tileH * rows > MAX_ATLAS) {\n tileH = Math.floor(MAX_ATLAS / rows)\n tileW = Math.max(1, Math.round(tileH / aspect))\n }\n\n const canvas = document.createElement('canvas')\n canvas.width = tileW * cols\n canvas.height = tileH * rows\n const ctx = canvas.getContext('2d')!\n ctx.fillStyle = stock.color\n ctx.fillRect(0, 0, canvas.width, canvas.height)\n\n const texture = new THREE.CanvasTexture(canvas)\n texture.colorSpace = THREE.SRGBColorSpace\n texture.anisotropy = 4\n setAtlas({ texture, cols, rows })\n\n const drawTile = (index: number, tile: HTMLCanvasElement) => {\n if (disposed) return\n const x = (index % cols) * tileW\n const y = Math.floor(index / cols) * tileH\n ctx.drawImage(tile, x, y, tileW, tileH)\n texture.needsUpdate = true\n }\n\n contents.forEach((content, index) => {\n if (content.type === 'image') {\n const img = new Image()\n img.crossOrigin = 'anonymous'\n img.onload = () => drawTile(index, renderContentToCanvas(content, sheet, stock, img))\n img.src = content.src\n } else if (content.type === 'text' || content.type === 'receipt') {\n document.fonts.ready.then(() => drawTile(index, renderContentToCanvas(content, sheet, stock)))\n } else {\n drawTile(index, renderContentToCanvas(content, sheet, stock))\n }\n })\n\n return () => {\n disposed = true\n texture.dispose()\n }\n }, [stableContents, sheet.width, sheet.height, stock.id])\n\n return atlas\n}\n","import type { DeformerInstance, SheetDims } from '../deformers/types'\nimport { getDeformer } from '../deformers/registry'\nimport {\n TRANSLUCENCY_FRAGMENT,\n TRANSLUCENCY_VARYINGS,\n translucencyVertexChunk,\n} from '../surface/translucency'\n\n/**\n * Compose a deformer stack into GLSL — the GPU twin of deformers/compose.ts.\n * Each stack entry gets its own uniform namespace (`uRoll0_angle`,\n * `uFold1_offset`, …) so the same deformer type can appear twice\n * (letter-fold is two folds). Golden-vector parity with the JS path is\n * enforced by the GPU harness test.\n */\n\nexport interface ComposedDisplacement {\n /** Uniform declarations + displacement functions. */\n functionsSrc: string\n /** `vec3 plDisplace(vec3 p, vec2 uv, float t)` applying the whole stack. */\n displaceSrc: string\n /** Initial uniform values, keyed by their namespaced GLSL names (uSheet included). */\n uniforms: Record<string, number | number[]>\n}\n\nfunction glslType(value: number | number[]): string {\n if (typeof value === 'number') return 'float'\n return ['float', 'vec2', 'vec3', 'vec4'][value.length - 1]!\n}\n\n/**\n * Just the uniform VALUES for a stack (same namespaced keys as\n * buildDisplacementGLSL) — cheap enough to call every frame while a behavior\n * animates. Structure (names) is stable as long as the stack's type order is.\n */\nexport function stackUniformValues(\n stack: DeformerInstance[],\n sheet: SheetDims,\n): Record<string, number | number[]> {\n const uniforms: Record<string, number | number[]> = { uSheet: [sheet.width, sheet.height] }\n stack.forEach((instance, i) => {\n if (instance.enabled === false) return\n const deformer = getDeformer(instance.type)\n if (!deformer.glsl) return\n const ns = `u${cap(instance.type)}${i}_`\n const values = deformer.glsl.uniforms(instance.options) as Record<string, number | number[]>\n for (const [key, value] of Object.entries(values)) uniforms[ns + key] = value\n })\n return uniforms\n}\n\nexport function buildDisplacementGLSL(stack: DeformerInstance[], sheet: SheetDims): ComposedDisplacement {\n const decls: string[] = ['uniform vec2 uSheet;', 'float plBias = 1.0;']\n const functions: string[] = []\n const calls: string[] = []\n const uniforms: Record<string, number | number[]> = { uSheet: [sheet.width, sheet.height] }\n\n stack.forEach((instance, i) => {\n if (instance.enabled === false) return\n const deformer = getDeformer(instance.type)\n if (!deformer.glsl) {\n throw new Error(\n `[paperlab] Deformer \"${instance.type}\" has no GLSL implementation — it can't run in field mode.`,\n )\n }\n const ns = `u${cap(instance.type)}${i}_`\n const fn = `pl_${instance.type}${i}`\n const values = deformer.glsl.uniforms(instance.options) as Record<string, number | number[]>\n for (const [key, value] of Object.entries(values)) {\n decls.push(`uniform ${glslType(value)} ${ns}${key};`)\n uniforms[ns + key] = value\n }\n const strength = deformer.glsl.strength\n functions.push(\n deformer.glsl.chunk.replaceAll('FN', fn).replace(/U_(\\w+)/g, (_, name: string) =>\n // The strength uniform reads through the per-instance bias, so one\n // instanced draw call can bend every sheet by a different amount.\n name === strength ? `(${ns}${name} * plBias)` : ns + name,\n ),\n )\n calls.push(`${fn}(q, uv, t);`)\n })\n\n const displaceSrc = /* glsl */ `\nvec3 plDisplace(vec3 p, vec2 uv, float t, float bias) {\n plBias = bias;\n vec3 q = p;\n ${calls.join('\\n ')}\n return q;\n}\n`\n\n return { functionsSrc: `${decls.join('\\n')}\\n${functions.join('\\n')}`, displaceSrc, uniforms }\n}\n\n/**\n * The field-mode CSM vertex shader: displaced position + numerically\n * recomputed normal (two tangent probes — exact normals of an arbitrary\n * stack have no closed form).\n */\nexport function buildFieldVertexShader(composed: ComposedDisplacement): string {\n return /* glsl */ `\nuniform float uPlTime;\nattribute float aPhase;\nattribute float aAtlas;\nattribute float aBias;\nvarying vec2 vPaperUv;\nvarying float vAtlas;\n${TRANSLUCENCY_VARYINGS}\n${composed.functionsSrc}\n${composed.displaceSrc}\nvoid main() {\n float t = uPlTime + aPhase;\n vec3 p = plDisplace(position, uv, t, aBias);\n vec2 step = uSheet * 0.01;\n vec3 px = plDisplace(position + vec3(step.x, 0.0, 0.0), uv + vec2(0.01, 0.0), t, aBias);\n vec3 py = plDisplace(position + vec3(0.0, step.y, 0.0), uv + vec2(0.0, 0.01), t, aBias);\n vec3 n = cross(px - p, py - p);\n csm_Normal = length(n) > 1e-12 ? normalize(n) : vec3(0.0, 0.0, 1.0);\n csm_Position = p;\n${translucencyVertexChunk({ model: 'modelMatrix * instanceMatrix', position: 'p', normal: 'csm_Normal' })}\n vPaperUv = uv;\n vAtlas = aAtlas;\n}\n`\n}\n\n/**\n * Field fragment shader: per-instance tile from the shared content atlas on\n * the FRONT face; the BACK face renders the stock with an optional reversed\n * show-through ghost (per-paper back textures are a hero-mode feature).\n */\nexport function buildFieldFragmentShader(): string {\n return /* glsl */ `\nuniform sampler2D uAtlas;\nuniform vec2 uAtlasGrid;\nuniform float uBackDarken;\nuniform vec3 uStockColor;\nuniform float uShowThrough;\nvarying vec2 vPaperUv;\nvarying float vAtlas;\n${TRANSLUCENCY_FRAGMENT}\nvoid main() {\n float col = mod(vAtlas, uAtlasGrid.x);\n float row = floor(vAtlas / uAtlasGrid.x);\n vec2 tiled = (vPaperUv + vec2(col, uAtlasGrid.y - 1.0 - row)) / uAtlasGrid;\n vec4 front = texture2D(uAtlas, tiled);\n if (gl_FrontFacing) {\n csm_DiffuseColor = front;\n } else {\n csm_DiffuseColor = vec4(uStockColor * mix(vec3(1.0), front.rgb, uShowThrough), 1.0);\n csm_DiffuseColor.rgb *= uBackDarken;\n }\n // Light coming through the sheet, filtered by what is printed on it. Same\n // ink either side — the light passes through the same fibres regardless of\n // which face happens to be turned toward the camera.\n csm_Emissive = plTransmission(front.rgb);\n}\n`\n}\n\nfunction cap(s: string): string {\n return s.charAt(0).toUpperCase() + s.slice(1).replace(/-(\\w)/g, (_, c: string) => c.toUpperCase())\n}\n","import { z } from 'zod'\nimport type { AnyOptions, SheetDims } from '../../deformers/types'\nimport { SHEET_LIFT, sheetLayoutSchema, sheetSlotXY, type SheetLayoutOptions } from '../sheetGrid'\nimport { getWalkPath, walkPathSchema } from '../../stage/path'\n\n/**\n * A layout is a pure `pose(i, n, options, phase)` function — no state, no\n * three.js. `phase` is the motion driver's continuous offset in turns\n * (0..1 = one full cycle); cyclic layouts use it, static ones ignore it.\n * Community layouts are ~30 lines.\n *\n * Every built-in names a place paper actually sits — a fanned swatch deck, a\n * slipped stack, a heap on a desk — because arrangement alone is what makes a\n * field read as a photo carousel instead of as paper. The other half of that\n * is `bias`: paper in the world does not all bend alike.\n */\n\nexport interface PaperPose {\n position: [number, number, number]\n rotation: [number, number, number]\n scale: number\n /**\n * How strongly this sheet takes the field's deformation: 1 = exactly as the\n * preset configures it, 0 = flat. Lets one instanced draw call curl the top\n * of a pile while the sheets pressed underneath stay flat. Omitted = 1.\n */\n bias?: number\n}\n\nexport interface Layout<O = Record<string, unknown>> {\n id: string\n label: string\n defaults: O\n optionsSchema: z.ZodType<O, unknown>\n /**\n * `sheet` is the field's paper size. Layouts that arrange by CONTACT —\n * edges meeting, sheets resting on each other — cannot work without it,\n * and a layout that ignores it may simply omit the parameter.\n */\n pose(i: number, n: number, o: O, phase: number, sheet: SheetDims): PaperPose\n /**\n * Where along a walk this layout put each paper, as normalized arc length,\n * in the layout's own index order.\n *\n * Only layouts that arrange along a PATH can answer, which is why it is\n * optional. Stage mode uses it to let a viewer step from one paper to the\n * next: the stops have to be where the paper actually is, and the only\n * thing that knows that is the function that placed it.\n */\n walkStops?(n: number, o: O): number[]\n}\n\n/** For the odd caller that has no papers yet to measure. */\nexport const DEFAULT_SHEET: SheetDims = { width: 1, height: 1.4 }\n\nconst TAU = Math.PI * 2\nconst DEG = Math.PI / 180\n\n/** Deterministic per-index jitter — layouts must be pure. */\nfunction jitter(seed: number, i: number): number {\n let h = Math.imul((seed * 1000 + i + 1) ^ 0x9e3779b9, 2654435761)\n h = Math.imul(h ^ (h >>> 13), 3266489917)\n return (((h ^ (h >>> 16)) >>> 0) / 4294967295) * 2 - 1\n}\n\n/** 0 at the first sheet, 1 at the last — the spine of most layouts. */\nfunction ramp(i: number, n: number): number {\n return n > 1 ? i / (n - 1) : 1\n}\n\nconst ringSchema = z.object({\n radius: z.number().min(0.5).max(12).default(2.6),\n tiltDeg: z.number().min(-45).max(45).default(8),\n})\n/** Prints pegged around a circle — the one carousel worth keeping. */\nexport const ring: Layout<z.infer<typeof ringSchema>> = {\n id: 'ring',\n label: 'Ring',\n defaults: ringSchema.parse({}),\n optionsSchema: ringSchema,\n pose(i, n, o, phase) {\n const theta = (i / n + phase) * TAU\n return {\n position: [Math.sin(theta) * o.radius, 0, Math.cos(theta) * o.radius],\n // Face radially OUTWARD so the papers nearest the camera show their\n // front (content) side — you stand outside the ring, not inside it.\n rotation: [(o.tiltDeg * Math.PI) / 180, theta, 0],\n scale: 1,\n }\n },\n}\n\nconst fanSchema = z.object({\n /** Total angular sweep from the first sheet to the last, degrees. */\n sweep: z.number().min(0).max(180).default(72),\n /** Where the shared pin sits, in half-sheet-heights below center. 1 = the bottom edge. */\n hinge: z.number().min(0).max(4).default(1.15),\n /** Thickness step so the sheets stack in order instead of z-fighting. */\n lift: z.number().min(0.002).max(0.08).default(0.012),\n /** How much flatter the middle of the fan sits than its outer sheets. */\n bow: z.number().min(0).max(1).default(0.7),\n})\n/**\n * A Pantone deck, a paint-chip book, a hand of cards: every sheet pinned at\n * one shared point and swung open. The sheets nearest the outside of the\n * sweep carry the most curl, which is what sells the hinge as a hinge.\n */\nexport const fan: Layout<z.infer<typeof fanSchema>> = {\n id: 'fan',\n label: 'Fan',\n defaults: fanSchema.parse({}),\n optionsSchema: fanSchema,\n pose(i, n, o, _phase, sheet) {\n const f = n > 1 ? i / (n - 1) : 0.5\n const theta = (f - 0.5) * o.sweep * DEG\n const hinge = (o.hinge * sheet.height) / 2\n // Swing the sheet about the shared pivot, then shift so the middle sheet\n // sits at the origin — the fan stays centered as `sweep` opens and closes.\n const open = Math.abs(f - 0.5) * 2\n return {\n position: [-Math.sin(theta) * hinge, Math.cos(theta) * hinge - hinge, i * o.lift],\n rotation: [0, 0, theta],\n scale: 1,\n bias: 1 - (1 - open) * o.bow,\n }\n },\n}\n\nconst spreadSchema = z.object({\n /** How far each sheet slides past the one below it. */\n slip: z.number().min(0.02).max(2).default(0.3),\n /** Direction of the slide, degrees. 0 slides right, 90 slides up. */\n angle: z.number().min(-180).max(180).default(28),\n lift: z.number().min(0.002).max(0.08).default(0.012),\n /** How much more the sheets at the far end of the slide bow. */\n bow: z.number().min(0).max(1).default(0.6),\n /** Nothing hand-slid is perfectly square — a touch of per-sheet rotation. */\n drift: z.number().min(0).max(1).default(0.15),\n})\n/**\n * A ream pushed sideways, or a deck dealt across a table: parallel sheets at\n * a constant offset, each one bowing a little more as it comes free of the\n * stack's weight.\n */\nexport const spread: Layout<z.infer<typeof spreadSchema>> = {\n id: 'spread',\n label: 'Spread',\n defaults: spreadSchema.parse({}),\n optionsSchema: spreadSchema,\n pose(i, n, o) {\n const centered = i - (n - 1) / 2\n const a = o.angle * DEG\n return {\n position: [Math.cos(a) * o.slip * centered, Math.sin(a) * o.slip * centered, i * o.lift],\n rotation: [0, 0, jitter(11, i) * 0.2 * o.drift],\n scale: 1,\n bias: 1 - (1 - ramp(i, n)) * o.bow,\n }\n },\n}\n\nconst pileSchema = z.object({\n /** How far sheets wander from the center of the heap. */\n scatter: z.number().min(0).max(2).default(0.22),\n /** Widest angle a sheet sits off square, degrees. */\n turn: z.number().min(0).max(180).default(24),\n lift: z.number().min(0.002).max(0.08).default(0.011),\n /** How flat the sheets underneath are pressed by the ones on top. */\n press: z.number().min(0).max(1).default(0.85),\n seed: z.number().int().min(0).max(9999).default(3),\n})\n/**\n * The heap on a desk. The physical tell no parametric curve can fake: sheets\n * rest ON each other, so only the top of the pile keeps its curl and\n * everything below is pressed flat by the weight above it.\n */\nexport const pile: Layout<z.infer<typeof pileSchema>> = {\n id: 'pile',\n label: 'Pile',\n defaults: pileSchema.parse({}),\n optionsSchema: pileSchema,\n pose(i, n, o) {\n return {\n position: [jitter(o.seed, i) * o.scatter, jitter(o.seed + 1, i) * o.scatter * 0.8, i * o.lift],\n rotation: [0, 0, jitter(o.seed + 2, i) * o.turn * DEG],\n scale: 1,\n bias: 1 - (1 - ramp(i, n)) * o.press,\n }\n },\n}\n\nconst wallSchema = z.object({\n gapX: z.number().min(0.05).max(1).default(0.22),\n gapY: z.number().min(0.05).max(1).default(0.3),\n jitterAmt: z.number().min(0).max(1).default(0.25),\n /** Spread of sag across the wall — no two pinned sheets hang alike. */\n sag: z.number().min(0).max(1).default(0.45),\n})\n/** A studio wall of pinned sheets: a grid, but nothing hangs quite square. */\nexport const wall: Layout<z.infer<typeof wallSchema>> = {\n id: 'wall',\n label: 'Wall',\n defaults: wallSchema.parse({}),\n optionsSchema: wallSchema,\n pose(i, n, o, _phase, sheet) {\n const cols = Math.ceil(Math.sqrt((n * sheet.height) / sheet.width))\n const rows = Math.ceil(n / cols)\n const col = i % cols\n const row = Math.floor(i / cols)\n // Gaps are breathing room around the real paper — a wall of 1.2×0.9\n // prints and a wall of 1×1.4 letters both want even gutters.\n const cellW = sheet.width + o.gapX\n const cellH = sheet.height + o.gapY\n return {\n position: [\n (col - (cols - 1) / 2) * cellW,\n ((rows - 1) / 2 - row) * cellH,\n jitter(5, i) * 0.04 * o.jitterAmt * 4,\n ],\n rotation: [0, 0, jitter(6, i) * 0.05 * o.jitterAmt * 4],\n scale: 1,\n bias: 1 - Math.abs(jitter(7, i)) * o.sag,\n }\n },\n}\n\nconst spillSchema = z.object({\n spreadX: z.number().min(0.5).max(8).default(2.4),\n spreadY: z.number().min(0.5).max(8).default(1.5),\n depth: z.number().min(0).max(6).default(1.6),\n /** How far sheets pitch and roll out of the picture plane. */\n tumble: z.number().min(0).max(1).default(0.5),\n /** Spread of bend across the sheets — a spill does not fold them alike. */\n vary: z.number().min(0).max(1).default(0.6),\n seed: z.number().int().min(0).max(9999).default(7),\n})\n/**\n * A dropped folder's worth of paper, mid-air — what a `pile` looks like the\n * moment before it settles. Loose in all three axes, and (the part that\n * separates it from confetti) every sheet caught at its own angle AND its\n * own amount of bend.\n */\nexport const spill: Layout<z.infer<typeof spillSchema>> = {\n id: 'spill',\n label: 'Spill',\n defaults: spillSchema.parse({}),\n optionsSchema: spillSchema,\n pose(i, _n, o) {\n const tumble = o.tumble * 2\n return {\n position: [\n jitter(o.seed, i) * o.spreadX,\n jitter(o.seed + 1, i) * o.spreadY,\n jitter(o.seed + 2, i) * o.depth,\n ],\n rotation: [\n jitter(o.seed + 3, i) * 0.4 * tumble,\n jitter(o.seed + 4, i) * 0.5 * tumble,\n jitter(o.seed + 5, i) * 0.4 * tumble,\n ],\n scale: 0.85 + Math.abs(jitter(o.seed + 6, i)) * 0.3,\n bias: 1 - Math.abs(jitter(o.seed + 7, i)) * o.vary,\n }\n },\n}\n\nconst sweepSchema = z.object({\n columns: z.number().int().min(1).max(24).default(5),\n /** Breathing room around each specimen. */\n gap: z.number().min(0).max(2).default(0.22),\n /** Deformation at the first specimen and at the last. */\n from: z.number().min(0).max(1).default(0),\n to: z.number().min(0).max(1).default(1),\n})\n/**\n * A specimen chart: the same sheet mounted in a grid, its deformation ramped\n * across the series so one image shows a curl at ten stages instead of one.\n * The layout the rest of this library exists to make possible — and the one\n * that documents every deformer for free.\n *\n * Only as legible as the preset it charts: a sheet with no behavior or\n * deformers has nothing for the ramp to scale, and every specimen comes out\n * identical.\n */\nexport const sweep: Layout<z.infer<typeof sweepSchema>> = {\n id: 'sweep',\n label: 'Sweep',\n defaults: sweepSchema.parse({}),\n optionsSchema: sweepSchema,\n pose(i, n, o, _phase, sheet) {\n const cols = Math.min(o.columns, Math.max(n, 1))\n const rows = Math.ceil(n / cols)\n const col = i % cols\n const row = Math.floor(i / cols)\n return {\n position: [\n (col - (cols - 1) / 2) * (sheet.width + o.gap),\n ((rows - 1) / 2 - row) * (sheet.height + o.gap),\n 0,\n ],\n rotation: [0, 0, 0],\n scale: 1,\n bias: o.from + (o.to - o.from) * ramp(i, n),\n }\n },\n}\n\nconst bookSchema = z.object({\n /** How far the outermost page lifts off the block, degrees. */\n spread: z.number().min(0).max(150).default(55),\n /** Fraction of the pages bound to the left. 0 = a one-sided sample book. */\n split: z.number().min(0).max(1).default(0.5),\n /** Page thickness — the gap between pages of one block. */\n lift: z.number().min(0.001).max(0.05).default(0.008),\n /** How much more a lifted page arcs than one lying flat in the block. */\n gutter: z.number().min(0).max(1).default(0.6),\n})\n/**\n * An open codex: pages hinged on a shared spine, each block splaying away\n * from the gutter. `split` slides it between the two bound forms paper takes\n * — 0.5 is a book lying open, 0 is a swatch deck or sample book bound down\n * one side. Pages lying flat in the block are pressed by the ones above;\n * only the lifted pages keep their arc.\n */\nexport const book: Layout<z.infer<typeof bookSchema>> = {\n id: 'book',\n label: 'Book',\n defaults: bookSchema.parse({}),\n optionsSchema: bookSchema,\n pose(i, n, o, _phase, sheet) {\n const half = sheet.width / 2\n const left = Math.round(n * o.split)\n const onLeft = i < left\n const count = onLeft ? left : n - left\n const k = onLeft ? i : i - left\n const f = count > 1 ? k / (count - 1) : 1\n const theta = f * o.spread * DEG\n // Swing the page about the spine at x = 0; `side` mirrors the left block.\n const side = onLeft ? -1 : 1\n const cos = Math.cos(theta)\n const sin = Math.sin(theta)\n // Stack along the page's own normal so pages standing near-vertical\n // separate sideways rather than sinking into each other.\n const offset = k * o.lift\n return {\n position: [side * (half * cos - offset * sin), 0, half * sin + offset * cos],\n rotation: [0, -side * theta, 0],\n scale: 1,\n bias: 1 - (1 - f) * o.gutter,\n }\n },\n}\n\nconst accordionSchema = z.object({\n /** How far each panel tilts off the strip's line, degrees. 0 = flat, 90 = shut. */\n angle: z.number().min(0).max(89).default(55),\n /** A concertina holds its creases — how much bow the panels keep. */\n slack: z.number().min(0).max(1).default(0.15),\n})\n/**\n * A concertina: panels alternating about creases they genuinely share, so\n * the sheets read as ONE folded strip rather than as N separate papers —\n * the only layout here where that is true. Adjacent edges are solved to\n * meet, which is why it needs the sheet's real width.\n */\nexport const accordion: Layout<z.infer<typeof accordionSchema>> = {\n id: 'accordion',\n label: 'Accordion',\n defaults: accordionSchema.parse({}),\n optionsSchema: accordionSchema,\n pose(i, n, o, _phase, sheet) {\n const theta = o.angle * DEG\n const side = i % 2 === 0 ? 1 : -1\n // Solving edge-meets-edge for alternating ±angle puts every panel center\n // on one line, spaced by the panel's foreshortened width.\n const step = sheet.width * Math.cos(theta)\n return {\n position: [(i - (n - 1) / 2) * step, 0, 0],\n rotation: [0, side * theta, 0],\n scale: 1,\n bias: o.slack,\n }\n },\n}\n\nconst rackSchema = z.object({\n /** Gap along the row, as a fraction of the paper's width. Under 1 they overlap. */\n spacing: z.number().min(0.05).max(2).default(0.82),\n /** How far a sheet leans back off vertical, degrees. */\n lean: z.number().min(0).max(70).default(16),\n /** How much that lean differs sheet to sheet — nothing propped is uniform. */\n vary: z.number().min(0).max(1).default(0.55),\n /** Small rotations off square. */\n sway: z.number().min(0).max(1).default(0.35),\n seed: z.number().int().min(0).max(9999).default(5),\n})\n/**\n * Prints stood in a row and leaning back — against a wall, in a rack, propped\n * along a shelf. The one arrangement here that RESTS on a surface rather than\n * floating: every sheet pivots on the bottom edge it actually stands on, so\n * the row shares a floor. The further a sheet has leaned, the more it bows\n * under its own weight.\n *\n * (Stacking these front-to-back the way a letter tray really holds paper is\n * physically honest and visually useless — the front sheet hides the rest.\n * A row is the arrangement you can actually see.)\n */\nexport const rack: Layout<z.infer<typeof rackSchema>> = {\n id: 'rack',\n label: 'Rack',\n defaults: rackSchema.parse({}),\n optionsSchema: rackSchema,\n pose(i, n, o, _phase, sheet) {\n const lean = o.lean * DEG * (1 + jitter(o.seed, i) * o.vary)\n const half = sheet.height / 2\n return {\n position: [\n (i - (n - 1) / 2) * sheet.width * o.spacing,\n // Standing on the floor: the bottom edge stays at y = 0 as it leans.\n half * Math.cos(lean),\n -half * Math.sin(lean) + i * 0.004,\n ],\n rotation: [-lean, jitter(o.seed + 1, i) * 0.12 * o.sway, jitter(o.seed + 2, i) * 0.06 * o.sway],\n scale: 1,\n // A sheet leaning further has more of its own weight to carry.\n bias: o.lean === 0 ? 0 : Math.min(1, lean / (o.lean * DEG * (1 + o.vary))),\n }\n },\n}\n\nconst colonnadeSchema = z.object({\n /** The walk the colonnade is built along — see `stage/path`. */\n path: walkPathSchema.prefault({}),\n /** Half-width of the clear aisle: how far each banner stands off the walk line. */\n aisle: z.number().min(0.2).max(20).default(2.4),\n /** How much that gap opens and closes along the walk. Nothing hung by hand is a corridor. */\n breathe: z.number().min(0).max(1).default(0.3),\n /** Widest angle a banner turns off square to the aisle, degrees. */\n twist: z.number().min(0).max(90).default(22),\n /** Fraction of the walk left clear at each end, so the figure has somewhere to enter from. */\n margin: z.number().min(0).max(0.45).default(0.05),\n /** Spread of banner heights, 0..1. */\n rise: z.number().min(0).max(1).default(0.28),\n /**\n * How far the banners lift off the floor, as a fraction of their height.\n *\n * NEGATIVE is allowed, and it is what pooling actually requires. At 0 a\n * banner's bottom EDGE sits on the floor — which is not the same as paper\n * pooling on it, however much the old comment here claimed otherwise. A\n * ribbon creases a pool-length above its bottom edge, so it has to hang\n * that much lower for the crease to land on the ground and the slack to\n * lie ON it rather than in mid-air parallel to it.\n *\n * The bound used to be 0, so the one thing this option documented itself\n * as doing was the one thing it could not do.\n */\n hover: z.number().min(-0.5).max(1).default(0),\n /** Spread of deformation — no two lengths of hung paper drape alike. */\n drape: z.number().min(0).max(1).default(0.5),\n seed: z.number().int().min(0).max(9999).default(2),\n})\n/**\n * A nave of hanging banners flanking a walk: paper as ARCHITECTURE rather\n * than as an object on a desk. The first layout here that arranges along a\n * path instead of around an origin, which is what lets a figure walk through\n * it — the aisle is guaranteed clear because the banners are placed off the\n * walk line, not merely near it.\n *\n * Banners alternate ranks (left, right, left…) and the two ranks are\n * staggered by a quarter step, so you pass them one at a time rather than\n * through a ladder of matched pairs. Each faces across the aisle: a banner\n * ahead of you presents its face, which is the whole reason to print\n * anything on it.\n */\n/**\n * How far along the walk banner `i` stands, before any phase offset.\n *\n * Pulled out of `pose` because two things now need it and they must not\n * disagree: the banner is PLACED here, and stage mode STOPS here when the\n * viewer steps from one paper to the next. A stop that is not where the\n * paper is would be a navigation that misses everything it aims at.\n */\nexport function colonnadeStop(i: number, n: number, margin: number): number {\n const side = i % 2 === 0 ? 1 : -1\n const pairs = Math.max(Math.ceil(n / 2), 1)\n const k = Math.floor(i / 2)\n const span = 1 - margin * 2\n const step = pairs > 1 ? span / (pairs - 1) : 0\n return margin + (pairs > 1 ? k * step : span / 2) + side * step * 0.25\n}\n\nexport const colonnade: Layout<z.infer<typeof colonnadeSchema>> = {\n id: 'colonnade',\n label: 'Colonnade',\n defaults: colonnadeSchema.parse({}),\n optionsSchema: colonnadeSchema,\n walkStops(n, o) {\n return Array.from({ length: n }, (_, i) => colonnadeStop(i, n, o.margin))\n },\n pose(i, n, o, phase, sheet) {\n const path = getWalkPath(o.path)\n const side = i % 2 === 0 ? 1 : -1\n const base = colonnadeStop(i, n, o.margin)\n // Only a closed walk can slide: on an open one, offsetting by phase would\n // teleport the far banner back to the near end mid-shot.\n const s = path.closed ? base + phase : base\n const [px, pz] = path.pointAt(s)\n const [nx, nz] = path.normalAt(s)\n const scale = 1 + jitter(o.seed, i) * o.rise * 0.5\n const offset = o.aisle * (1 + jitter(o.seed + 1, i) * o.breathe)\n const height = sheet.height * scale\n // Face the centerline: the inward direction is the aisle normal, negated\n // on whichever rank this banner stands in.\n const yaw = Math.atan2(-side * nx, -side * nz) + jitter(o.seed + 2, i) * o.twist * DEG\n return {\n position: [px + nx * side * offset, height / 2 + height * o.hover, pz + nz * side * offset],\n rotation: [0, yaw, 0],\n scale,\n bias: 1 - Math.abs(jitter(o.seed + 3, i)) * o.drape,\n }\n },\n}\n\n/**\n * A block of stamps: flat rows × columns grid in register, floating a hair\n * above the (field-rendered) backing sheet. Standard layout contract — it\n * also works standalone as a plain grid; `backing`/`backingMargin` are read\n * by the field renderer, not by `pose`.\n */\nexport const sheet: Layout<SheetLayoutOptions> = {\n id: 'sheet',\n label: 'Sheet',\n defaults: sheetLayoutSchema.parse({}),\n optionsSchema: sheetLayoutSchema,\n pose(i, _n, o) {\n const { x, y } = sheetSlotXY(i, o)\n return { position: [x, y, SHEET_LIFT], rotation: [0, 0, 0], scale: 1 }\n },\n}\n\nconst registry = new Map<string, Layout<AnyOptions>>()\n\nexport function registerLayout(layout: Layout<AnyOptions>): void {\n registry.set(layout.id, layout)\n}\n\nexport function getLayout(id: string): Layout<AnyOptions> {\n const layout = registry.get(id)\n if (!layout) {\n throw new Error(`[paperlab] Unknown layout \"${id}\". Registered: ${[...registry.keys()].join(', ')}`)\n }\n return layout\n}\n\nexport function listLayouts(): string[] {\n return [...registry.keys()]\n}\n\nregisterLayout(ring)\nregisterLayout(fan)\nregisterLayout(spread)\nregisterLayout(pile)\nregisterLayout(wall)\nregisterLayout(spill)\nregisterLayout(sweep)\nregisterLayout(book)\nregisterLayout(accordion)\nregisterLayout(rack)\nregisterLayout(colonnade)\nregisterLayout(sheet)\n","import { z } from 'zod'\n\n/**\n * The walk — a path across the ground plane that a figure follows and that\n * layouts arrange paper along. Pure 2D math (x, z on the floor, y is always\n * up), no three.js, so it tests in node and is cheap enough to call from\n * inside a layout's pure `pose`.\n *\n * Centripetal Catmull-Rom through the control points — it will not cusp or\n * overshoot when two points bunch together, which a uniform spline does —\n * resampled to a uniform arc-length polyline. That resampling is the point:\n * `pointAt(s)` advances at constant SPEED, so a figure stepping `s` forward\n * at a steady rate covers ground at a steady rate. A raw spline parameter\n * would have it sprint through the straights and crawl around the corners.\n */\n\n/** A point on the floor. */\nexport type Ground = [x: number, z: number]\n\nexport const walkPathSchema = z.object({\n /**\n * Control points on the ground plane, [x, z]. The default walks away from\n * the camera down -Z — the shot every reference image is composed on.\n */\n points: z\n .array(z.tuple([z.number(), z.number()]))\n .min(2)\n .default([\n [0, 9],\n [0, -9],\n ]),\n /** Join the last point back to the first: an endless walk, and the only form `phase` can slide. */\n closed: z.boolean().default(false),\n})\n\nexport type WalkPathOptions = z.infer<typeof walkPathSchema>\n\nexport interface WalkPath {\n /** Total arc length in world units. */\n readonly length: number\n readonly closed: boolean\n /** `s` is normalized arc length: 0 = the start, 1 = the end. Closed paths wrap, open paths clamp. */\n pointAt(s: number): Ground\n /** Unit forward direction at `s`. */\n tangentAt(s: number): Ground\n /** Unit LEFT-hand normal at `s` — the side of the aisle a walker's left hand points to. */\n normalAt(s: number): Ground\n}\n\n/** Polyline resolution. 24 per segment holds a tight curve to well under a millimetre of chord error. */\nconst SAMPLES_PER_SEGMENT = 24\n\n/** Coincident control points would collapse the knot spacing and divide by zero. */\nconst EPSILON = 1e-6\n\n/** Centripetal: alpha = 0.5. (0 would be uniform, 1 chordal.) */\nconst ALPHA = 0.5\n\nfunction knot(a: Ground, b: Ground, t: number): number {\n return t + Math.max(Math.hypot(b[0] - a[0], b[1] - a[1]), EPSILON) ** ALPHA\n}\n\n/** Linear interpolation in knot space — the Barry-Goldman building block. */\nfunction lerpKnot(a: Ground, b: Ground, ta: number, tb: number, t: number): Ground {\n const span = tb - ta\n const k = span === 0 ? 0 : (t - ta) / span\n return [a[0] + (b[0] - a[0]) * k, a[1] + (b[1] - a[1]) * k]\n}\n\n/** One centripetal Catmull-Rom segment p1→p2, `u` in 0..1. */\nfunction segmentPoint(p0: Ground, p1: Ground, p2: Ground, p3: Ground, u: number): Ground {\n const t0 = 0\n const t1 = knot(p0, p1, t0)\n const t2 = knot(p1, p2, t1)\n const t3 = knot(p2, p3, t2)\n const t = t1 + (t2 - t1) * u\n const a1 = lerpKnot(p0, p1, t0, t1, t)\n const a2 = lerpKnot(p1, p2, t1, t2, t)\n const a3 = lerpKnot(p2, p3, t2, t3, t)\n const b1 = lerpKnot(a1, a2, t0, t2, t)\n const b2 = lerpKnot(a2, a3, t1, t3, t)\n return lerpKnot(b1, b2, t1, t2, t)\n}\n\n/** The phantom control point beyond an open path's end: reflect the interior neighbor. */\nfunction reflect(end: Ground, inner: Ground): Ground {\n return [2 * end[0] - inner[0], 2 * end[1] - inner[1]]\n}\n\nexport function createWalkPath(options: WalkPathOptions): WalkPath {\n const pts = options.points as Ground[]\n const n = pts.length\n const closed = options.closed && n > 2\n const segments = closed ? n : n - 1\n\n // Resample the spline into a uniformly-indexed polyline, carrying the\n // cumulative arc length so `s` can be inverted by search.\n const samples: Ground[] = []\n const cumulative: number[] = []\n let total = 0\n for (let seg = 0; seg < segments; seg++) {\n const p1 = pts[seg]!\n const p2 = pts[(seg + 1) % n]!\n const p0 = closed ? pts[(seg - 1 + n) % n]! : seg > 0 ? pts[seg - 1]! : reflect(pts[0]!, pts[1]!)\n const p3 = closed ? pts[(seg + 2) % n]! : seg + 2 < n ? pts[seg + 2]! : reflect(pts[n - 1]!, pts[n - 2]!)\n // The last sample of a segment is the first of the next — emit it only\n // at the very end of an open path, where nothing follows to repeat it.\n const last = seg === segments - 1 && !closed ? SAMPLES_PER_SEGMENT : SAMPLES_PER_SEGMENT - 1\n for (let k = 0; k <= last; k++) {\n const point = segmentPoint(p0, p1, p2, p3, k / SAMPLES_PER_SEGMENT)\n const previous = samples[samples.length - 1]\n if (previous) total += Math.hypot(point[0] - previous[0], point[1] - previous[1])\n samples.push(point)\n cumulative.push(total)\n }\n }\n if (closed) {\n // Close the ring: the start point repeats as the final sample so a\n // search near s = 1 has a segment to land in.\n const first = samples[0]!\n const previous = samples[samples.length - 1]!\n total += Math.hypot(first[0] - previous[0], first[1] - previous[1])\n samples.push([first[0], first[1]])\n cumulative.push(total)\n }\n\n const length = total\n\n function normalize(s: number): number {\n if (!Number.isFinite(s)) return 0\n if (!closed) return Math.min(Math.max(s, 0), 1)\n const wrapped = s - Math.floor(s)\n return wrapped\n }\n\n function pointAt(s: number): Ground {\n const target = normalize(s) * length\n if (length === 0) return [samples[0]![0], samples[0]![1]]\n // Binary search for the first sample at or past the target distance.\n let low = 0\n let high = cumulative.length - 1\n while (low < high) {\n const mid = (low + high) >> 1\n if (cumulative[mid]! < target) low = mid + 1\n else high = mid\n }\n const i = Math.max(low, 1)\n const before = cumulative[i - 1]!\n const span = cumulative[i]! - before\n const k = span <= 0 ? 0 : (target - before) / span\n const a = samples[i - 1]!\n const b = samples[i]!\n return [a[0] + (b[0] - a[0]) * k, a[1] + (b[1] - a[1]) * k]\n }\n\n /** Central difference over a fixed world-space step — stable at any path length. */\n function tangentAt(s: number): Ground {\n const ds = length > 0 ? Math.min(0.01, 0.5 / length) : 0.01\n const here = normalize(s)\n const a = pointAt(closed ? here - ds : Math.max(here - ds, 0))\n const b = pointAt(closed ? here + ds : Math.min(here + ds, 1))\n const dx = b[0] - a[0]\n const dz = b[1] - a[1]\n const len = Math.hypot(dx, dz)\n // A degenerate path has no direction to report; -Z is the house forward.\n return len < EPSILON ? [0, -1] : [dx / len, dz / len]\n }\n\n function normalAt(s: number): Ground {\n const [tx, tz] = tangentAt(s)\n // Left of forward, with +Y up: right = forward × up, so left is its negation.\n return [tz, -tx]\n }\n\n return { length, closed, pointAt, tangentAt, normalAt }\n}\n\n/**\n * Building the arc-length table costs a few hundred flops, and `pose` runs\n * per sheet per frame — so paths are memoized by value. Same options in,\n * same object out, which keeps layouts pure from the outside.\n */\nconst cache = new Map<string, WalkPath>()\nconst CACHE_LIMIT = 32\n\nexport function getWalkPath(options: WalkPathOptions): WalkPath {\n const key = `${options.closed ? 'c' : 'o'}|${options.points.map((p) => `${p[0]},${p[1]}`).join(';')}`\n const hit = cache.get(key)\n if (hit) return hit\n const path = createWalkPath(options)\n if (cache.size >= CACHE_LIMIT) {\n const oldest = cache.keys().next().value\n if (oldest !== undefined) cache.delete(oldest)\n }\n cache.set(key, path)\n return path\n}\n","import { getBehavior } from '../behaviors/registry'\nimport { resolveDeformerStack } from '../deformers/registry'\nimport type { PaperConfig } from '../config/schema'\nimport type { DeformerInstance } from '../deformers/types'\n\n/**\n * The deformer stack one field group renders, at a given behavior progress.\n *\n * A raw `deformers` array is the Advanced fork of a behavior and wins over\n * one — the same precedence the hero path's `buildStack` applies. Field mode\n * once read `behavior` only, so a preset shaped by `deformers` (the way to\n * say \"this print has a permanent bow\") silently rendered flat.\n */\nexport function fieldShapeStack(config: PaperConfig, progress: number): DeformerInstance[] {\n if (config.deformers) return resolveDeformerStack(config.deformers)\n if (!config.behavior) return []\n const behavior = getBehavior(config.behavior.type)\n const options = { ...config.behavior, [behavior.progressParam]: progress }\n return behavior.stack(options, config.sheet)\n}\n","import * as THREE from 'three'\nimport { useEffect, useMemo } from 'react'\nimport { drawBacking } from '../content/backing'\nimport { sheetBackingSize, type SheetLayoutOptions } from './sheetGrid'\n\n/** Warmer than printer stock — the classic gummed backing paper. */\nconst BACKING_TINT = '#f3ecdd'\n\n/**\n * The shared sheet behind a stamp grid: one extra paper sized to the grid\n * bounds + margin, non-interactive, excluded from `papers` indices. Its\n * content is a generated canvas of ghost silhouettes, redrawn on state\n * change (never per-frame).\n */\nexport function BackingSheet({\n options,\n count,\n removed,\n}: {\n options: SheetLayoutOptions\n count: number\n removed: ReadonlySet<number>\n}) {\n const { width, height } = sheetBackingSize(options)\n const canvas = useMemo(() => {\n if (typeof document === 'undefined') return null\n const c = document.createElement('canvas')\n const scale = Math.min(1024, Math.round(360 * Math.max(width, height))) / Math.max(width, height)\n c.width = Math.max(2, Math.round(width * scale))\n c.height = Math.max(2, Math.round(height * scale))\n return c\n }, [width, height])\n const texture = useMemo(() => (canvas ? new THREE.CanvasTexture(canvas) : null), [canvas])\n\n const removedKey = [...removed].sort((a, b) => a - b).join(',')\n // biome-ignore lint/correctness/useExhaustiveDependencies: Serialized deps — options and the removed set are fresh objects every render.\n useEffect(() => {\n if (!canvas || !texture) return\n drawBacking(canvas, { options, count, tint: BACKING_TINT, removed })\n texture.needsUpdate = true\n }, [canvas, texture, JSON.stringify(options), count, removedKey])\n useEffect(() => () => texture?.dispose(), [texture])\n\n return (\n <mesh receiveShadow>\n <planeGeometry args={[width, height]} />\n <meshStandardMaterial map={texture} color=\"#ffffff\" roughness={0.92} metalness={0} />\n </mesh>\n )\n}\n","import { sheetBackingSize, sheetSlotXY, type SheetLayoutOptions } from '../field/sheetGrid'\n\n/**\n * The backing sheet's generated content: per-slot ghost silhouettes a few\n * percent lighter than the backing tint. When a slot's paper detaches\n * (picked/placed), its silhouette lightens further and gains a faint\n * adhesive-sheen gradient — the visual proof of removal. Redrawn on state\n * change, never per-frame.\n */\n\nexport interface SilhouetteRect {\n /** Canvas-UV rect (0..1, y down) of slot i on the backing sheet. */\n x: number\n y: number\n w: number\n h: number\n}\n\n/** Pure: where each slot's silhouette sits on the backing, in canvas UV. */\nexport function silhouetteRects(o: SheetLayoutOptions, count: number): SilhouetteRect[] {\n const { width, height } = sheetBackingSize(o)\n const rects: SilhouetteRect[] = []\n for (let i = 0; i < count; i++) {\n const { x, y } = sheetSlotXY(i, o)\n rects.push({\n x: (x - o.cellWidth / 2 + width / 2) / width,\n // World y up → canvas y down.\n y: (height / 2 - y - o.cellHeight / 2) / height,\n w: o.cellWidth / width,\n h: o.cellHeight / height,\n })\n }\n return rects\n}\n\n/** Lighten a hex tint toward white by `amount` (0..1). */\nexport function lightenHex(hex: string, amount: number): string {\n const n = parseInt(hex.replace('#', ''), 16)\n const ch = (shift: number) => {\n const c = (n >> shift) & 0xff\n return Math.min(255, Math.round(c + (255 - c) * amount))\n }\n return `#${((ch(16) << 16) | (ch(8) << 8) | ch(0)).toString(16).padStart(6, '0')}`\n}\n\nexport interface BackingDrawSpec {\n options: SheetLayoutOptions\n count: number\n tint: string\n /** Slot indices whose paper has been picked/placed away. */\n removed: ReadonlySet<number>\n}\n\n/** Draw the backing content onto a canvas (called on state change only). */\nexport function drawBacking(canvas: HTMLCanvasElement, spec: BackingDrawSpec): void {\n const ctx = canvas.getContext('2d')\n if (!ctx) return\n const { width: cw, height: chh } = canvas\n ctx.fillStyle = spec.tint\n ctx.fillRect(0, 0, cw, chh)\n\n const rects = silhouetteRects(spec.options, spec.count)\n rects.forEach((r, i) => {\n const removed = spec.removed.has(i)\n const x = r.x * cw\n const y = r.y * chh\n const w = r.w * cw\n const h = r.h * chh\n const radius = Math.min(w, h) * 0.06\n\n ctx.fillStyle = lightenHex(spec.tint, removed ? 0.5 : 0.07)\n roundedRect(ctx, x, y, w, h, radius)\n ctx.fill()\n\n if (removed) {\n // Faint adhesive sheen: a diagonal highlight across the bare silhouette.\n const sheen = ctx.createLinearGradient(x, y, x + w, y + h)\n sheen.addColorStop(0, 'rgba(255,255,255,0)')\n sheen.addColorStop(0.5, 'rgba(255,255,255,0.35)')\n sheen.addColorStop(1, 'rgba(255,255,255,0)')\n ctx.fillStyle = sheen\n roundedRect(ctx, x, y, w, h, radius)\n ctx.fill()\n }\n })\n}\n\nfunction roundedRect(\n ctx: CanvasRenderingContext2D,\n x: number,\n y: number,\n w: number,\n h: number,\n r: number,\n): void {\n ctx.beginPath()\n ctx.moveTo(x + r, y)\n ctx.arcTo(x + w, y, x + w, y + h, r)\n ctx.arcTo(x + w, y + h, x, y + h, r)\n ctx.arcTo(x, y + h, x, y, r)\n ctx.arcTo(x, y, x + w, y, r)\n ctx.closePath()\n}\n","import * as THREE from 'three'\nimport { gsap } from 'gsap'\nimport { useFrame, useThree, type ThreeEvent } from '@react-three/fiber'\nimport { useContext, useEffect, useMemo, useRef, useState } from 'react'\nimport { paperConfigSchema, type PaperConfigInput } from '../config/schema'\nimport { mergeConfig } from '../config/merge'\nimport { PaperMesh, type PaperHandle } from '../PaperMesh'\nimport { carryDrive, dampTo, type DampedValue } from '../physics/aero'\nimport { usePrefersReducedMotion } from '../a11y'\nimport type { SheetDims } from '../deformers/types'\nimport { getLayout, type PaperPose } from './layouts'\nimport { tornEdgesOnDetach, type SheetLayoutOptions } from './sheetGrid'\nimport {\n DropZoneContext,\n DropZoneRegistry,\n DropZoneVisual,\n zoneAccepts,\n zoneContains,\n type DropZoneConfig,\n type PlacedPaper,\n type ZoneEntry,\n} from './dropZones'\nimport { BackingSheet } from './backingSheet'\nimport { EMPTY_SET, resolveFieldSlotConfig, type FieldPaperSlot } from './slots'\n\n/** Imperative field controls for the hidden a11y keyboard flow. */\nexport interface FieldA11yController {\n pick(slot: number): boolean\n placeAtZone(slot: number, zoneId: string): void\n cancel(slot: number): void\n zoneIds(): string[]\n slotState(slot: number): string\n}\n\nexport interface InteractiveFieldProps {\n papers: FieldPaperSlot[]\n fallback?: string | PaperConfigInput\n layoutId: string\n layoutOptions: Record<string, unknown>\n sheetOptions: SheetLayoutOptions | null\n /** The field's paper size, for layouts that arrange by contact. */\n sheet: SheetDims\n reducedMotion?: boolean\n /** Serialized zones (the editor's) — merged with `<DropZone>` children. */\n zones?: DropZoneConfig[]\n onSlotStateChange?(slot: number, state: string): void\n onPlace?(paper: PlacedPaper, zone: string): void\n a11yRef?: React.MutableRefObject<FieldA11yController | null>\n}\n\n/** Behaviors with a grab point — the only ones a drag can pick. */\nconst PICK_BEHAVIORS = new Set(['peel', 'carry'])\n\ninterface CarriedPaper {\n slot: number\n pointerId: number | null\n x: DampedValue\n y: DampedValue\n targetX: number\n targetY: number\n lastX: number\n lastY: number\n homePose: PaperPose\n settling: boolean\n}\n\ninterface PressState {\n slot: number\n pointerId: number\n startX: number\n startY: number\n}\n\n/**\n * The interactive field: one hero-path PaperMesh per slot posed by the\n * layout, plus the carry controller — press past `pickThreshold` tears the\n * paper off (perforation auto-wires torn), it flies with the cursor\n * fluttering from drag velocity, zones test its center each frame, release\n * settles (snap → press → flatten) or flutters back to its slot.\n */\nexport function InteractiveField(props: InteractiveFieldProps) {\n const { papers, fallback, layoutId, layoutOptions, sheetOptions } = props\n const total = papers.length\n const layout = getLayout(layoutId)\n const reduced = usePrefersReducedMotion(props.reducedMotion)\n const contextRegistry = useContext(DropZoneContext)\n // Editor-serialized zones need hover state even without a provider.\n const registry = useMemo(() => contextRegistry ?? new DropZoneRegistry(), [contextRegistry])\n const camera = useThree((s) => s.camera)\n const gl = useThree((s) => s.gl)\n const controls = useThree((s) => s.controls) as { enabled?: boolean } | null\n\n // Once a stamp leaves its slot the silhouette stays bare — paper has\n // memory: a returned stamp sits ON its silhouette, detached.\n const [removed, setRemoved] = useState<ReadonlySet<number>>(EMPTY_SET)\n // Runtime config patches (torn perforation, carry override) — merged over\n // the slot config; the machine `rebase`s instead of resetting.\n const [slotPatches, setSlotPatches] = useState<Record<number, Record<string, unknown>>>({})\n const [slotStates, setSlotStates] = useState<Record<number, string>>({})\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: Serialized deps — slots and layout options are fresh objects every render.\n const slotConfigs = useMemo(\n () =>\n papers.map((slot, i) => {\n const config = resolveFieldSlotConfig(slot, fallback, i, layoutId, layoutOptions)\n const patch = slotPatches[i]\n return patch ? paperConfigSchema.parse(mergeConfig(config as Record<string, unknown>, patch)) : config\n }),\n [\n JSON.stringify(papers),\n JSON.stringify(fallback ?? null),\n layoutId,\n JSON.stringify(layoutOptions),\n slotPatches,\n ],\n )\n // biome-ignore lint/correctness/useExhaustiveDependencies: Serialized deps — poses depend on the layout, not on config identity.\n const poses = useMemo(\n () => slotConfigs.map((_, i) => layout.pose(i, total, layoutOptions, 0, props.sheet)),\n [layoutId, JSON.stringify(layoutOptions), total, props.sheet.width, props.sheet.height],\n )\n\n const groupRefs = useRef<(THREE.Group | null)[]>([])\n const handleRefs = useRef<(PaperHandle | null)[]>([])\n const pressRef = useRef<PressState | null>(null)\n const carriedRef = useRef<CarriedPaper | null>(null)\n\n // Registry zones can register after mount; read live in the frame loop.\n const zonesLive = (): ZoneEntry[] => [...(props.zones ?? []), ...registry.list()]\n\n const slotName = (i: number): string => {\n const preset = papers[i]?.preset ?? fallback\n return typeof preset === 'string' ? preset : (slotConfigs[i]?.meta.name ?? 'paper')\n }\n\n const onSlotState = (i: number, state: string) => {\n setSlotStates((prev) => ({ ...prev, [i]: state }))\n if (state === 'picked' || state === 'placed') {\n setRemoved((prev) => (prev.has(i) ? prev : new Set(prev).add(i)))\n }\n props.onSlotStateChange?.(i, state)\n }\n\n // ── Pointer → field-plane projection ──\n const raycaster = useMemo(() => new THREE.Raycaster(), [])\n const planeScratch = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 0, 1), 0), [])\n const pointScratch = useMemo(() => new THREE.Vector3(), [])\n const ndcScratch = useMemo(() => new THREE.Vector2(), [])\n const planePoint = (clientX: number, clientY: number, planeZ: number): [number, number] | null => {\n const rect = gl.domElement.getBoundingClientRect()\n ndcScratch.set(\n ((clientX - rect.left) / rect.width) * 2 - 1,\n -((clientY - rect.top) / rect.height) * 2 + 1,\n )\n raycaster.setFromCamera(ndcScratch, camera)\n planeScratch.constant = -planeZ\n const hit = raycaster.ray.intersectPlane(planeScratch, pointScratch)\n return hit ? [hit.x, hit.y] : null\n }\n\n // ── Pick: the tear ──\n const pick = (slot: number, atX: number, atY: number, pointerId: number | null = null): boolean => {\n const config = slotConfigs[slot]\n const handle = handleRefs.current[slot]\n const home = poses[slot]\n if (!config?.states || !handle || !home) return false\n if (!config.behavior || !PICK_BEHAVIORS.has(config.behavior.type)) return false\n if (slotStates[slot] === 'placed' || carriedRef.current) return false\n\n // Auto-wire the sticker model: perforation edges that faced neighbors\n // tear through (manual state wins), and `picked` defaults to a carry\n // hanging from the peeled corner unless the preset choreographs its own.\n const patch: Record<string, unknown> = {}\n if (sheetOptions && config.surface.perforation) {\n const auto = tornEdgesOnDetach(slot, sheetOptions)\n patch.surface = {\n perforation: { state: { ...auto, ...config.surface.perforation.state } },\n }\n }\n const pickedOverrides = config.states.states.picked?.overrides as { behavior?: unknown } | undefined\n if (!pickedOverrides?.behavior) {\n const grab =\n config.behavior.type === 'peel' && config.behavior.corner !== 'auto'\n ? config.behavior.corner\n : 'top-left'\n patch.states = {\n states: {\n picked: { overrides: { behavior: { type: 'carry', grab, drive: 0.3 } } },\n },\n }\n }\n if (Object.keys(patch).length > 0) {\n setSlotPatches((prev) => ({ ...prev, [slot]: mergeConfig(prev[slot] ?? {}, patch) }))\n }\n\n // Drive the machine through rest→hover→pressed→picked so every side effect\n // fires for BOTH pointer (already at 'pressed') and keyboard (still at\n // 'rest') entry — raw send('pick') from 'rest' was a silent no-op.\n handle.pickProgrammatic()\n carriedRef.current = {\n slot,\n pointerId,\n x: { value: atX, velocity: 0 },\n y: { value: atY, velocity: 0 },\n targetX: atX,\n targetY: atY,\n lastX: atX,\n lastY: atY,\n homePose: home,\n settling: false,\n }\n if (controls) controls.enabled = false\n return true\n }\n\n // ── The settle: the 400ms that sells everything ──\n const settleInto = (carried: CarriedPaper, zone: ZoneEntry) => {\n const group = groupRefs.current[carried.slot]\n const handle = handleRefs.current[carried.slot]\n if (!group || !handle) return\n carried.settling = true\n handle.placeProgrammatic()\n handle.set('drive', 0)\n registry.setHovered(null)\n\n const paper: PlacedPaper = {\n slot: carried.slot,\n presetName: slotName(carried.slot),\n config: slotConfigs[carried.slot]!,\n }\n const zoneZ = zone.bounds.position[2]\n const done = () => {\n carriedRef.current = null\n if (controls) controls.enabled = true\n zone.onPlace?.(paper, zone.id)\n props.onPlace?.(paper, zone.id)\n }\n if (reduced) {\n group.position.set(group.position.x, group.position.y, zoneZ + 0.005)\n group.rotation.set(0, 0, 0)\n group.scale.setScalar(1)\n done()\n return\n }\n const tl = gsap.timeline({ onComplete: done })\n // 1 · Snap — position tweens to the drop point on the zone plane.\n tl.to(group.position, { z: zoneZ + 0.005, duration: 0.12, ease: 'power3.out' }, 0)\n tl.to(group.rotation, { x: 0, y: 0, z: 0, duration: 0.12, ease: 'power3.out' }, 0)\n // 2 · Press — the paper bows into the surface, shadow tightening.\n tl.to(group.scale, { x: 1.02, y: 1.02, z: 1, duration: 0.09, ease: 'power2.in' }, 0.12)\n tl.to(group.position, { z: zoneZ + 0.001, duration: 0.18, ease: 'power2.out' }, 0.12)\n // 3 · Flatten — tiny overshoot on scale (1.0 → 0.985 → 1.0).\n tl.to(group.scale, { x: 0.985, y: 0.985, duration: 0.06, ease: 'power1.inOut' }, 0.3)\n tl.to(group.scale, { x: 1, y: 1, duration: 0.06, ease: 'power1.out' }, 0.36)\n }\n\n // ── The return: flutter back to the slot on a slight arc ──\n const returnHome = (carried: CarriedPaper) => {\n const group = groupRefs.current[carried.slot]\n const handle = handleRefs.current[carried.slot]\n if (!group || !handle) return\n carried.settling = true\n registry.setHovered(null)\n\n const home = carried.homePose\n const done = () => {\n handle.returnProgrammatic()\n carriedRef.current = null\n if (controls) controls.enabled = true\n }\n if (reduced) {\n group.position.set(...home.position)\n group.rotation.set(...home.rotation)\n group.scale.setScalar(home.scale)\n done()\n return\n }\n const from = { x: group.position.x, y: group.position.y, z: group.position.z }\n const dist = Math.hypot(from.x - home.position[0], from.y - home.position[1])\n const duration = Math.min(0.8, Math.max(0.25, dist * 0.55))\n // Curved path: a slight arc perpendicular to the travel, not linear.\n const arc = Math.min(0.35, dist * 0.25)\n const proxy = { t: 0 }\n gsap.to(proxy, {\n t: 1,\n duration,\n ease: 'power2.inOut',\n onUpdate: () => {\n const t = proxy.t\n const lift = Math.sin(t * Math.PI) * arc\n group.position.x = from.x + (home.position[0] - from.x) * t\n group.position.y = from.y + (home.position[1] - from.y) * t + lift\n group.position.z = from.z + (home.position[2] - from.z) * t\n // Flutter decays as it approaches.\n handle.set('drive', (1 - t) * 0.5)\n },\n onComplete: done,\n })\n gsap.to(group.rotation, { x: home.rotation[0], y: home.rotation[1], z: home.rotation[2], duration })\n gsap.to(group.scale, { x: home.scale, y: home.scale, z: home.scale, duration: duration * 0.5 })\n }\n\n // ── Press / drag / release wiring ──\n // Handlers close over the current render's state, so the fresh closures live\n // in refs and the window listeners attach ONCE — re-subscribing per render\n // (worst: per slot-state change mid-drag) is listener churn for nothing.\n const onPointerMoveRef = useRef<(e: PointerEvent) => void>(() => {})\n onPointerMoveRef.current = (e: PointerEvent) => {\n const press = pressRef.current\n const carried = carriedRef.current\n if (carried && !carried.settling && (carried.pointerId === null || e.pointerId === carried.pointerId)) {\n const hit = planePoint(e.clientX, e.clientY, carried.homePose.position[2] + 0.15)\n if (hit) {\n carried.targetX = hit[0]\n carried.targetY = hit[1]\n }\n return\n }\n if (!press) return\n const hit = planePoint(e.clientX, e.clientY, poses[press.slot]?.position[2] ?? 0)\n if (!hit) return\n const dist = Math.hypot(hit[0] - press.startX, hit[1] - press.startY)\n const threshold = slotConfigs[press.slot]?.states?.pickThreshold ?? 0.1\n if (dist > threshold) {\n const { slot, pointerId } = press\n pressRef.current = null\n pick(slot, hit[0], hit[1], pointerId)\n }\n }\n const onPointerUpRef = useRef<(e: PointerEvent) => void>(() => {})\n onPointerUpRef.current = (e: PointerEvent) => {\n pressRef.current = null\n const carried = carriedRef.current\n if (!carried || carried.settling) return\n if (carried.pointerId !== null && e.pointerId !== carried.pointerId) return\n const name = slotName(carried.slot)\n const zone = zonesLive().find(\n (z) => zoneContains(z, carried.x.value, carried.y.value) && zoneAccepts(z, name),\n )\n if (zone) settleInto(carried, zone)\n else returnHome(carried)\n }\n useEffect(() => {\n const move = (e: PointerEvent) => onPointerMoveRef.current(e)\n const up = (e: PointerEvent) => onPointerUpRef.current(e)\n window.addEventListener('pointermove', move)\n window.addEventListener('pointerup', up)\n return () => {\n window.removeEventListener('pointermove', move)\n window.removeEventListener('pointerup', up)\n }\n }, [])\n\n // ── The carry loop: damped follow, velocity flutter, zone hover ──\n useFrame((_, delta) => {\n const carried = carriedRef.current\n if (!carried || carried.settling) return\n const group = groupRefs.current[carried.slot]\n const handle = handleRefs.current[carried.slot]\n if (!group || !handle) return\n const dt = Math.min(delta, 1 / 30)\n\n if (reduced) {\n // Reduced motion: direct cursor-following, no flutter, no lag.\n carried.x.value = carried.lastX = carried.targetX\n carried.y.value = carried.lastY = carried.targetY\n group.position.x = carried.targetX\n group.position.y = carried.targetY\n group.position.z = carried.homePose.position[2] + 0.15\n } else {\n dampTo(carried.x, carried.targetX, 0.09, dt)\n dampTo(carried.y, carried.targetY, 0.09, dt)\n const vx = (carried.x.value - carried.lastX) / dt\n const vy = (carried.y.value - carried.lastY) / dt\n carried.lastX = carried.x.value\n carried.lastY = carried.y.value\n const speed = Math.hypot(vx, vy)\n group.position.x = carried.x.value\n group.position.y = carried.y.value\n group.position.z = carried.homePose.position[2] + 0.15\n // Drag velocity becomes flutter + rotational lag: yaw trails the drag.\n handle.set('drive', carryDrive(speed))\n const lag = 0.25\n group.rotation.y += (THREE.MathUtils.clamp(-vx * lag, -0.6, 0.6) - group.rotation.y) * 0.12\n group.rotation.x += (THREE.MathUtils.clamp(vy * lag * 0.7, -0.5, 0.5) - group.rotation.x) * 0.12\n }\n\n // Zone hover: center test each frame; scale-up is the \"this will stick\" cue.\n const name = slotName(carried.slot)\n const zone = zonesLive().find(\n (z) => zoneContains(z, group.position.x, group.position.y) && zoneAccepts(z, name),\n )\n registry.setHovered(zone?.id ?? null)\n const targetScale = (zone ? 1.03 : 1) * carried.homePose.scale\n group.scale.x += (targetScale - group.scale.x) * 0.15\n group.scale.y = group.scale.z = group.scale.x\n })\n\n // ── a11y controller: keyboard pick → move between zones → place/escape ──\n // Same ref-delegation as the pointer listeners: the real implementation is\n // rebuilt per render (fresh closures), the published object is stable.\n const a11yImplRef = useRef<FieldA11yController | null>(null)\n a11yImplRef.current = {\n pick: (slot) => {\n const home = poses[slot]\n if (!home) return false\n // pick() drives the machine (rest→…→picked) itself — no raw events.\n return pick(slot, home.position[0], home.position[1])\n },\n placeAtZone: (slot, zoneId) => {\n const carried = carriedRef.current\n const zone = zonesLive().find((z) => z.id === zoneId)\n const group = groupRefs.current[slot]\n if (!carried || carried.slot !== slot || !zone || !group) return\n group.position.x = zone.bounds.position[0]\n group.position.y = zone.bounds.position[1]\n carried.x.value = group.position.x\n carried.y.value = group.position.y\n settleInto(carried, zone)\n },\n cancel: (slot) => {\n const carried = carriedRef.current\n if (carried && carried.slot === slot && !carried.settling) returnHome(carried)\n },\n zoneIds: () => zonesLive().map((z) => z.id),\n slotState: (slot) => slotStates[slot] ?? 'rest',\n }\n useEffect(() => {\n const ref = props.a11yRef\n if (!ref) return\n ref.current = {\n pick: (slot) => a11yImplRef.current?.pick(slot) ?? false,\n placeAtZone: (slot, zoneId) => a11yImplRef.current?.placeAtZone(slot, zoneId),\n cancel: (slot) => a11yImplRef.current?.cancel(slot),\n zoneIds: () => a11yImplRef.current?.zoneIds() ?? [],\n slotState: (slot) => a11yImplRef.current?.slotState(slot) ?? 'rest',\n }\n return () => {\n ref.current = null\n }\n }, [props.a11yRef])\n\n return (\n <group>\n {sheetOptions?.backing && <BackingSheet options={sheetOptions} count={total} removed={removed} />}\n {(props.zones ?? []).map((zone) => (\n <DropZoneVisual key={zone.id} registry={registry} config={zone} />\n ))}\n {slotConfigs.map((config, i) => {\n const pose = poses[i]!\n return (\n <group\n // biome-ignore lint/suspicious/noArrayIndexKey: a slot IS its index — refs, poses, drags and drops all address a paper by slot number.\n key={i}\n ref={(g) => {\n groupRefs.current[i] = g\n }}\n position={pose.position}\n rotation={pose.rotation}\n scale={pose.scale}\n onPointerDown={(e: ThreeEvent<PointerEvent>) => {\n if (carriedRef.current) return\n const hit = planePoint(e.clientX, e.clientY, pose.position[2])\n if (!hit) return\n pressRef.current = { slot: i, pointerId: e.pointerId, startX: hit[0], startY: hit[1] }\n }}\n >\n <PaperMesh\n ref={(h) => {\n handleRefs.current[i] = h\n }}\n preset={config}\n reducedMotion={props.reducedMotion}\n onStateChange={(state) => onSlotState(i, state)}\n />\n </group>\n )\n })}\n </group>\n )\n}\n","import { useState } from 'react'\nimport { contentText } from '../a11y'\nimport { contentSchema } from '../config/schema'\nimport { resolveConfig } from '../PaperMesh'\nimport type { FieldA11yController } from './interactiveField'\nimport type { FieldPaperSlot } from './slots'\n\n/** Carry state of the hidden keyboard mirror: which paper is aloft, which zone is focused. */\nexport interface KeyboardCarry {\n slot: number\n zoneIndex: number\n}\n\n/** A keyboard step's decision: the next carry state and whether it consumed the key. */\nexport interface KeyboardStepResult {\n carry: KeyboardCarry | null\n handled: boolean\n}\n\n/**\n * The keyboard flow as a pure step (so it's testable without a DOM):\n * given the current carry state, the focused paper `slot`, and the pressed\n * `key`, it drives the field `controller` (pick → move between zones → place /\n * cancel) and returns the next carry state. All side effects go through\n * `controller`; the caller applies `carry` to its state and calls\n * `preventDefault()` when `handled` is true.\n */\nexport function fieldKeyboardStep(\n carry: KeyboardCarry | null,\n slot: number,\n key: string,\n controller: FieldA11yController,\n): KeyboardStepResult {\n if (!carry) {\n // Not carrying: Enter/Space on a focused paper picks it up.\n if (key === 'Enter' || key === ' ') {\n return { carry: controller.pick(slot) ? { slot, zoneIndex: 0 } : null, handled: true }\n }\n return { carry, handled: false }\n }\n // Carrying: only the paper actually aloft responds.\n if (carry.slot !== slot) return { carry, handled: false }\n const zoneCount = Math.max(controller.zoneIds().length, 1)\n if (key === 'ArrowRight' || key === 'ArrowDown') {\n return { carry: { ...carry, zoneIndex: (carry.zoneIndex + 1) % zoneCount }, handled: true }\n }\n if (key === 'ArrowLeft' || key === 'ArrowUp') {\n return {\n carry: { ...carry, zoneIndex: (carry.zoneIndex - 1 + zoneCount) % zoneCount },\n handled: true,\n }\n }\n if (key === 'Enter' || key === ' ') {\n const zone = controller.zoneIds()[carry.zoneIndex]\n if (zone) controller.placeAtZone(slot, zone)\n return { carry: null, handled: true }\n }\n if (key === 'Escape') {\n controller.cancel(slot)\n return { carry: null, handled: true }\n }\n return { carry, handled: false }\n}\n\nconst mirrorHidden: React.CSSProperties = {\n position: 'absolute',\n width: 1,\n height: 1,\n padding: 0,\n margin: -1,\n overflow: 'hidden',\n clip: 'rect(0 0 0 0)',\n whiteSpace: 'nowrap',\n border: 0,\n}\n\n/**\n * The hidden DOM mirror of an interactive field: each paper is a button.\n * Keyboard flow — focus a paper, Enter picks it, arrow keys move between\n * zones, Enter places, Escape returns it to its slot. The key\n * handling lives in the pure {@link fieldKeyboardStep} so it can be tested.\n */\nexport function FieldKeyboardMirror({\n papers,\n controller,\n}: {\n papers: FieldPaperSlot[]\n controller: React.MutableRefObject<FieldA11yController | null>\n}) {\n const [carrying, setCarrying] = useState<{ slot: number; zoneIndex: number } | null>(null)\n\n const paperLabel = (slot: FieldPaperSlot, i: number): string => {\n try {\n const config = resolveConfig({ preset: slot.preset })\n const content = slot.content ? contentSchema.parse(slot.content) : config.content\n return `Paper ${i + 1}: ${contentText({ ...config, content })}`\n } catch {\n return `Paper ${i + 1}`\n }\n }\n\n const onKeyDown = (i: number) => (e: React.KeyboardEvent) => {\n const ctl = controller.current\n if (!ctl) return\n const { carry, handled } = fieldKeyboardStep(carrying, i, e.key, ctl)\n if (handled) e.preventDefault()\n if (carry !== carrying) setCarrying(carry)\n }\n\n return (\n <fieldset style={mirrorHidden}>\n <legend>Interactive papers</legend>\n {papers.map((slot, i) => (\n <button\n // biome-ignore lint/suspicious/noArrayIndexKey: a slot IS its index — the carry state and every keyboard step address a paper by slot number.\n key={i}\n type=\"button\"\n onKeyDown={onKeyDown(i)}\n aria-label={paperLabel(slot, i)}\n aria-pressed={carrying?.slot === i}\n >\n {paperLabel(slot, i)}\n {carrying?.slot === i && (\n <span aria-live=\"polite\">\n {' '}\n — carrying; zone {controller.current?.zoneIds()[carrying.zoneIndex] ?? 'none'}; Enter places,\n Escape returns\n </span>\n )}\n </button>\n ))}\n </fieldset>\n )\n}\n","import type { AnyOptions, SheetDims } from '../deformers/types'\nimport type { Layout } from './layouts'\nimport { withSheetCellFromPaper, type SheetLayoutOptions } from './sheetGrid'\n\n/**\n * Framing a field is arithmetic, not guesswork: layouts are pure `pose`\n * functions, so we can just ask one where all its sheets are and put the\n * camera where they all fit. Community layouts get framed for free.\n */\n\nexport interface FieldBounds {\n center: [number, number, number]\n /** Half-extents — the box reaches `center ± half`. */\n half: [number, number, number]\n}\n\n/** Cyclic layouts sweep as `phase` advances; frame the whole cycle, not one instant. */\nconst PHASE_SAMPLES = 8\n\n/**\n * Resolve a layout's options the one way both the renderer and the camera\n * must agree on — sheet grids size their cells from the papers themselves.\n */\nexport function resolveLayoutOptions(\n layoutId: string,\n layout: Layout<AnyOptions>,\n propOptions: Record<string, unknown> | undefined,\n firstSheet: SheetDims | undefined,\n): Record<string, unknown> {\n const parsed = layout.optionsSchema.parse({\n ...layout.defaults,\n ...propOptions,\n }) as Record<string, unknown>\n if (layoutId !== 'sheet') return parsed\n return withSheetCellFromPaper(\n parsed as unknown as SheetLayoutOptions,\n propOptions,\n firstSheet,\n ) as unknown as Record<string, unknown>\n}\n\n/**\n * The box `n` sheets occupy under a layout. Each sheet is treated as a ball\n * of its half-diagonal, which covers every rotation the pose can apply\n * without having to build the pose matrices.\n */\nexport function fieldBounds(\n layout: Layout<AnyOptions>,\n n: number,\n options: unknown,\n sheet: SheetDims,\n): FieldBounds {\n const reach = Math.hypot(sheet.width, sheet.height) / 2\n if (n <= 0) return { center: [0, 0, 0], half: [reach, reach, 0] }\n\n const min = [Infinity, Infinity, Infinity]\n const max = [-Infinity, -Infinity, -Infinity]\n for (let s = 0; s < PHASE_SAMPLES; s++) {\n for (let i = 0; i < n; i++) {\n const pose = layout.pose(i, n, options, s / PHASE_SAMPLES, sheet)\n const r = reach * Math.max(pose.scale, 0)\n for (let axis = 0; axis < 3; axis++) {\n min[axis] = Math.min(min[axis]!, pose.position[axis]! - r)\n max[axis] = Math.max(max[axis]!, pose.position[axis]! + r)\n }\n }\n }\n return {\n center: [(min[0]! + max[0]!) / 2, (min[1]! + max[1]!) / 2, (min[2]! + max[2]!) / 2],\n half: [(max[0]! - min[0]!) / 2, (max[1]! - min[1]!) / 2, (max[2]! - min[2]!) / 2],\n }\n}\n\n/** The field has always been viewed from a shade above eye level — keep that. */\nconst LIFT = 0.11\nconst DEG = Math.PI / 180\n\n/**\n * Where to put a perspective camera so every sheet a layout poses lands in\n * frame. Solved per sheet at its own depth rather than against the field's\n * bounding box: a `ring`'s widest sheets sit at mid-depth, and pretending\n * that width exists at the near face would shove the camera far enough back\n * to lose the gallery entirely.\n */\nexport function fitCamera(\n layout: Layout<AnyOptions>,\n n: number,\n options: unknown,\n sheet: SheetDims,\n fovDeg: number,\n aspect: number,\n margin = 1.06,\n): { position: [number, number, number]; target: [number, number, number] } {\n const { center } = fieldBounds(layout, n, options, sheet)\n const reach = (Math.hypot(sheet.width, sheet.height) / 2) * margin\n const vTan = Math.tan((fovDeg * DEG) / 2)\n const hTan = vTan * Math.max(aspect, 0.01)\n\n let distance = 0.1\n for (let s = 0; s < PHASE_SAMPLES; s++) {\n for (let i = 0; i < Math.max(n, 0); i++) {\n const pose = layout.pose(i, n, options, s / PHASE_SAMPLES, sheet)\n const r = reach * Math.max(pose.scale, 0)\n // Depth of this sheet in front of the field's center — a sheet further\n // back needs correspondingly less distance to fit.\n const depth = pose.position[2]! - center[2]!\n distance = Math.max(\n distance,\n (Math.abs(pose.position[0]! - center[0]!) + r) / hTan + depth,\n (Math.abs(pose.position[1]! - center[1]!) + r) / vTan + depth,\n )\n }\n }\n return {\n position: [center[0], center[1] + distance * LIFT, center[2] + distance],\n target: center,\n }\n}\n","import {\n behaviorConfigSchema,\n clothConfigSchema,\n contentSchema,\n memorySchema,\n paperConfigSchema,\n sceneSchema,\n sheetSchema,\n type PaperConfig,\n type PaperConfigInput,\n} from './schema'\n\n/**\n * Presets are diffable: exports emit only non-default values, so a shared\n * `.paper` file or JSX snippet reads like intent, not like a database dump.\n */\n\nfunction isPlainObject(v: unknown): v is Record<string, unknown> {\n return typeof v === 'object' && v !== null && !Array.isArray(v)\n}\n\n/** Keys of `value` that differ from `defaults` (deep compare, shallow recurse). */\nfunction diffAgainst(\n value: Record<string, unknown>,\n defaults: Record<string, unknown>,\n keep: string[] = [],\n): Record<string, unknown> {\n const out: Record<string, unknown> = {}\n for (const [key, v] of Object.entries(value)) {\n if (keep.includes(key)) {\n out[key] = v\n continue\n }\n if (JSON.stringify(v) !== JSON.stringify(defaults[key])) {\n out[key] =\n isPlainObject(v) && isPlainObject(defaults[key])\n ? diffAgainst(v, defaults[key] as Record<string, unknown>)\n : v\n }\n }\n return out\n}\n\n/** The minimal PaperConfigInput that parses back to `config`. */\nexport function diffConfig(config: PaperConfig): PaperConfigInput {\n const base = paperConfigSchema.parse({})\n const out: Record<string, unknown> = {}\n\n const sheet = diffAgainst(config.sheet as never, sheetSchema.parse({}) as never)\n if (Object.keys(sheet).length > 0) out.sheet = sheet\n\n if (config.stock !== base.stock) out.stock = config.stock\n\n if (config.content.type !== 'blank') {\n // Defaults for this content type; required fields (image src) always kept.\n const defaults = contentSchema.parse(\n config.content.type === 'image'\n ? { type: 'image', src: config.content.src }\n : { type: config.content.type },\n ) as Record<string, unknown>\n out.content = {\n type: config.content.type,\n ...diffAgainst(config.content as never, defaults, config.content.type === 'image' ? ['src'] : []),\n }\n }\n\n if (config.behavior) {\n const defaults = behaviorConfigSchema.parse({ type: config.behavior.type }) as Record<string, unknown>\n out.behavior = { type: config.behavior.type, ...diffAgainst(config.behavior as never, defaults) }\n }\n if (config.deformers) out.deformers = config.deformers\n\n if (Object.keys(config.surface).length > 0) out.surface = config.surface\n\n // Diffed like the scene below, and for the same reason it is: `memory` is\n // going to grow fields, and a diff that names the ones it knows about\n // silently drops the next one. Without this a creased sheet exported to a\n // `.paper` file, a share link or a snippet came back flat — the editor\n // showed the creases and nothing that left the editor carried them.\n const memory = diffAgainst(config.memory as never, memorySchema.parse({}) as never)\n if (Object.keys(memory).length > 0) out.memory = memory\n\n if (typeof config.physics === 'object') {\n const defaults = clothConfigSchema.parse({ type: 'cloth' }) as Record<string, unknown>\n out.physics = { type: 'cloth', ...diffAgainst(config.physics as never, defaults) }\n } else if (config.physics !== 'none') {\n out.physics = config.physics\n }\n\n // The WHOLE scene, diffed like everything else. This used to read\n // `if (lighting !== 'studio') out.scene = { lighting }` — which was true\n // while `lighting` was the only thing in a scene, and quietly threw away\n // every field added beside it. A hand-tuned light rig and a backdrop both\n // vanished on the way into a `.paper` file, a share link and a snippet:\n // the editor showed them and nothing that left the editor carried them.\n const scene = diffAgainst(config.scene as never, sceneSchema.parse({}) as never)\n if (Object.keys(scene).length > 0) out.scene = scene\n if (config.onTwos) out.onTwos = true\n // States are already diffs on the base — emit them whole.\n if (config.states) out.states = config.states\n const meta = diffAgainst(config.meta as never, paperConfigSchema.parse({}).meta as never)\n if (Object.keys(meta).length > 0) out.meta = meta\n\n return out as PaperConfigInput\n}\n\n/** Render a value as compact JSX-attribute source. */\nfunction jsxValue(value: unknown): string {\n if (typeof value === 'string') return `\"${value}\"`\n return `{${JSON.stringify(value)}}`\n}\n\n/**\n * The same config with uploaded pictures swapped for paths.\n *\n * An uploaded image lives in a config as a data URL — a hundred kilobytes\n * and up of base64 — and there are now two places one can be: the sheet's\n * own content, and the backdrop behind it. Pasting that into somebody's\n * source file is not an export, and the reader cannot edit it, diff it, or\n * even scroll past it.\n *\n * So a code export gets a path in the same position instead, and says that\n * is what it did. A referenced URL is already something the receiver can\n * fetch and travels untouched. Emitting nothing was the other option and it\n * is worse: a sheet that silently loses its picture looks like a bug in the\n * library rather than a limit of the clipboard.\n *\n * The `.paper` file and the share link are deliberately NOT run through\n * this — a file has room for the bytes, and losing them there would lose\n * the artwork rather than reformat it.\n */\nexport function withoutUploads<T>(value: T): { value: T; replaced: number } {\n let replaced = 0\n const walk = (node: unknown): unknown => {\n if (typeof node === 'string') {\n if (!node.startsWith('data:')) return node\n replaced++\n const extension = node.startsWith('data:image/png') ? 'png' : 'jpg'\n return `/paperlab-image-${replaced}.${extension}`\n }\n if (Array.isArray(node)) return node.map(walk)\n if (node && typeof node === 'object') {\n return Object.fromEntries(Object.entries(node).map(([k, v]) => [k, walk(v)]))\n }\n return node\n }\n return { value: walk(value) as T, replaced }\n}\n\n/** The one-line warning a code export carries when it had to substitute. */\nexport const UPLOAD_NOTE =\n '// Uploaded pictures cannot travel in a snippet — the paths below are\\n// stand-ins, in order. Point them at your own files.'\n\n/**\n * A plain `<Paper />` snippet with only the non-default props — the\n * secondary export for people who read code.\n */\nexport function buildJsxSnippet(config: PaperConfig): string {\n const diffed = diffConfig(config) as Record<string, unknown>\n delete diffed.meta\n const { value: diff, replaced } = withoutUploads(diffed)\n const props = Object.entries(diff).map(([key, value]) => ` ${key}=${jsxValue(value)}`)\n if (props.length === 0) return '<Paper />'\n const snippet = `<Paper\\n${props.join('\\n')}\\n/>`\n return replaced > 0 ? `${UPLOAD_NOTE}\\n${snippet}` : snippet\n}\n","import type { PaperConfig } from './schema'\nimport { getStock } from '../core/stock'\nimport { UPLOAD_NOTE, diffConfig, withoutUploads } from './diff'\n\n/**\n * The primary export consumer is a coding agent; the human is the courier.\n * This template IS product surface: versioned, snapshot-tested, regenerated\n * from the config. Anatomy is fixed — install → inlined code → placement\n * contract → a verification step the agent can self-check → pre-empted\n * failure modes.\n */\n/**\n * v2: field exports (multi-preset galleries with inlined preset consts).\n * v3: interaction states, sheet/backing fields, drop zones, carry/flight.\n */\nexport const AGENT_PAYLOAD_VERSION = 3\n\nconst BEHAVIOR_PHRASES: Record<string, (o: Record<string, unknown>) => string> = {\n peel: (o) => `its ${String(o.corner ?? 'bottom-right').replace('-', ' ')} corner peeling up`,\n unroll: (o) =>\n (o.progress as number) < 0.35\n ? 'mostly wound into a roll at the bottom'\n : 'unrolling from a paper roll at the bottom',\n flip: () => 'mid page-turn',\n 'letter-fold': () => 'tri-folding like a letter',\n hang: () => 'hanging from its top edge, rippling',\n fly: () => 'arched and fluttering like it is airborne',\n fall: () => 'rippling with one corner lifted, like a dropped sheet',\n ribbon: (o) =>\n `hanging the full drop of the room and pooling on the floor, about ${Math.round((o as { pool: number }).pool * 100)}% of its length lying over`,\n settle: (o) =>\n (o as { relax: number }).relax > 0.7\n ? 'lying where it landed, flat but for one corner the stiffness kept'\n : 'just come to rest, still holding a little of the shape it fell in',\n carry: () => 'drooping from a pinched corner, fluttering as if being carried',\n flight: (o) =>\n o.path === 'loop' ? 'tumbling through a seamless airborne loop' : 'tumbling across the scene on the wind',\n crumple: (o) =>\n (o.progress as number) < 0.3\n ? 'lightly handled — a few soft creases across it'\n : (o.progress as number) < 0.7\n ? 'crushed into irregular creased facets, as if screwed up and flattened out again'\n : 'balled up in a fist',\n}\n\n/** One line an agent can verify against what it sees after `npm run dev`. */\nexport function describeConfig(config: PaperConfig): string {\n const stock = getStock(config.stock)\n const size = `${config.sheet.width}×${config.sheet.height}`\n\n let contentPhrase = 'a blank sheet'\n if (config.content.type === 'image') contentPhrase = 'a sheet printed with an image'\n if (config.content.type === 'text') contentPhrase = 'a sheet with typeset text'\n if (config.content.type === 'receipt') contentPhrase = `a store receipt for \"${config.content.store}\"`\n\n const parts = [`${contentPhrase} on ${stock.label.toLowerCase()} paper stock (${size})`]\n\n if (typeof config.physics === 'object') {\n const sim = config.physics\n parts.push(\n sim.type === 'strip'\n ? 'paying off a roll as the page scrolls, folding at its perforations into a pile on the floor'\n : sim.pins === 'none'\n ? 'falling and settling as cloth'\n : `pinned (${sim.pins}) and moving like cloth in wind`,\n )\n } else if (config.behavior) {\n const phrase = BEHAVIOR_PHRASES[config.behavior.type]\n if (phrase) parts.push(phrase(config.behavior as Record<string, unknown>))\n }\n\n if (config.surface.deckle) {\n parts.push(\n `torn (deckled) ${config.surface.deckle.edges.join(' and ')} edge${config.surface.deckle.edges.length > 1 ? 's' : ''}`,\n )\n }\n if ((config.surface.aging ?? 0) > 0.3) parts.push('visibly aged and yellowed')\n\n return parts.join(', ')\n}\n\nfunction componentName(config: PaperConfig): string {\n const raw = config.meta.name === 'untitled' ? 'PaperlabPaper' : config.meta.name\n const pascal = raw\n .replace(/[^a-zA-Z0-9]+(.)/g, (_, c: string) => c.toUpperCase())\n .replace(/^./, (c) => c.toUpperCase())\n .replace(/[^a-zA-Z0-9]/g, '')\n return /^[A-Za-z]/.test(pascal) ? pascal : `Paper${pascal}`\n}\n\n/** The self-contained integration brief — one paste into a coding agent. */\nexport function buildAgentPayload(config: PaperConfig): string {\n const name = componentName(config)\n // Uploaded pictures become paths: this payload is pasted into a coding\n // agent's context window, and a hundred kilobytes of base64 in there is\n // both useless and expensive.\n const { value: stripped, replaced } = withoutUploads(diffConfig(config))\n const preset = JSON.stringify(stripped, null, 2)\n const uploadNote = replaced > 0 ? `${UPLOAD_NOTE}\\n` : ''\n\n return `Integrate a Paperlab paper component into this project. (paperlab agent-payload v${AGENT_PAYLOAD_VERSION})\n\n1. Install the dependencies:\n\n npm i paperlab three @react-three/fiber gsap\n\n2. Create the component below as \\`components/${name}.tsx\\` (or the project's\n component convention). It is self-contained and owns its own <Canvas>:\n\n\\`\\`\\`tsx\nimport { Paper, type PaperConfigInput } from 'paperlab'\n\n${uploadNote}const preset = ${preset.replace(/\\n/g, '\\n')} satisfies PaperConfigInput\n\nexport function ${name}() {\n return <Paper preset={preset} />\n}\n\\`\\`\\`\n\n3. Sizing: the component fills its parent container. Place it where I ask;\n give the parent an explicit height.\n\n4. Verify: run the dev server. You should see ${describeConfig(config)}.\n If the canvas is blank, the parent container almost certainly has no height —\n give it one (this is the classic React Three Fiber integration bug, not a\n paperlab bug).\n\nConstraints: don't modify the preset values; three >= 0.160 and React 19 are\nrequired; the component needs no props.`\n}\n","import {\n sceneSchema,\n type ContentConfig,\n type PaperConfig,\n type PaperStatesInput,\n type SceneConfigInput,\n} from './schema'\nimport { diffConfig } from './diff'\nimport { AGENT_PAYLOAD_VERSION } from './agent-payload'\nimport { getLayout } from '../field/layouts'\n\n/**\n * Field-mode export. Every preset a field references is INLINED as a const —\n * receivers don't have the sender's local preset library. Same fixed payload\n * anatomy as the single-paper export, same version.\n */\n\nexport interface FieldExportPaper {\n /** Display name of the preset this slot uses (const naming + description). */\n presetName: string\n /** The RESOLVED preset config (user presets included — nothing to fetch). */\n preset: PaperConfig\n content?: ContentConfig\n /** Per-slot state overrides (slot 3's hover deeper than slot 4's). */\n states?: PaperStatesInput\n}\n\nexport interface FieldExportZone {\n id: string\n accept?: string[]\n bounds: { position: [number, number, number]; size: [number, number] }\n highlight?: 'none' | 'glow' | 'outline'\n}\n\nexport interface FieldExportInput {\n layout: string\n layoutOptions?: Record<string, unknown>\n motion?: { driver?: 'autoplay' | 'drag' | 'none'; speed?: number }\n entrance?: { type?: 'rise' | 'scatter' | 'none'; stagger?: number; duration?: number }\n papers: FieldExportPaper[]\n /** How the gallery is lit. Omitted means the schema's own default rig. */\n scene?: SceneConfigInput\n /** Drop zones — exported as `<DropZone>` children with an onPlace stub. */\n zones?: FieldExportZone[]\n}\n\nconst MOTION_DEFAULTS = { driver: 'autoplay', speed: 0.5 }\nconst ENTRANCE_DEFAULTS = { type: 'rise', stagger: 0.06, duration: 0.9 }\n\nfunction camel(name: string): string {\n const id = name.replace(/[^a-zA-Z0-9]+(.)/g, (_, c: string) => c.toUpperCase()).replace(/[^a-zA-Z0-9]/g, '')\n const safe = /^[A-Za-z]/.test(id) ? id : `preset${id}`\n return safe.charAt(0).toLowerCase() + safe.slice(1)\n}\n\ninterface DistinctPreset {\n varName: string\n presetName: string\n preset: PaperConfig\n}\n\n/** Distinct presets in slot order, with collision-safe const names. */\nexport function distinctFieldPresets(input: FieldExportInput): DistinctPreset[] {\n const byKey = new Map<string, DistinctPreset>()\n const usedNames = new Set<string>()\n for (const paper of input.papers) {\n const key = JSON.stringify(paper.preset)\n if (byKey.has(key)) continue\n let varName = camel(paper.presetName)\n while (usedNames.has(varName)) varName += '2'\n usedNames.add(varName)\n byKey.set(key, { varName, presetName: paper.presetName, preset: paper.preset })\n }\n return [...byKey.values()]\n}\n\n/**\n * The entries that differ from the defaults.\n *\n * Compared STRUCTURALLY rather than by reference. Most of what passes\n * through here is numbers and strings, where the two agree — but a layout\n * option holding an array, or a scene holding a nested rig, is never\n * reference-equal to the default it was copied from, so those exported a\n * prop that said exactly what the default already said.\n */\nfunction nonDefault<T extends Record<string, unknown>>(\n value: T | undefined,\n defaults: Record<string, unknown>,\n): Record<string, unknown> {\n const out: Record<string, unknown> = {}\n for (const [k, v] of Object.entries(value ?? {})) {\n if (v === undefined) continue\n const same = v === defaults[k] || JSON.stringify(v) === JSON.stringify(defaults[k])\n if (!same) out[k] = v\n }\n return out\n}\n\n/** The layout/motion/entrance props of the export, defaults stripped. */\nexport function diffFieldProps(input: FieldExportInput): Record<string, unknown> {\n const out: Record<string, unknown> = { layout: input.layout }\n const layout = getLayout(input.layout)\n const layoutOptions = nonDefault(input.layoutOptions ?? {}, layout.defaults as Record<string, unknown>)\n if (Object.keys(layoutOptions).length > 0) out.layoutOptions = layoutOptions\n const motion = nonDefault(input.motion, MOTION_DEFAULTS)\n if (Object.keys(motion).length > 0) out.motion = motion\n const entrance = nonDefault(input.entrance, ENTRANCE_DEFAULTS)\n if (Object.keys(entrance).length > 0) out.entrance = entrance\n // Resolved through the schema before comparing, so an input naming only\n // `lighting` is judged against a whole default rig rather than a\n // half-filled one.\n const scene = nonDefault(\n sceneSchema.parse(input.scene ?? {}) as unknown as Record<string, unknown>,\n sceneSchema.parse({}) as unknown as Record<string, unknown>,\n )\n if (Object.keys(scene).length > 0) out.scene = scene\n return out\n}\n\nconst LAYOUT_PHRASES: Record<string, string> = {\n ring: 'a ring you can see around',\n fan: 'a fanned swatch deck hinged at one corner',\n spread: 'a stack slid sideways, each sheet bowing further than the last',\n pile: 'a heap on a desk, the sheets underneath pressed flat',\n wall: 'a pinned studio wall of sheets, none hanging quite square',\n spill: 'a dropped stack caught mid-air, each sheet bent its own way',\n sweep: 'a specimen chart of one sheet at every stage of its deformation',\n book: 'an open book, its pages splayed from a shared spine',\n accordion: 'one continuous strip folded into a concertina',\n rack: 'prints stood in a row and leaning back against a wall',\n sheet: 'a stamp-block grid on a shared backing sheet',\n}\n\n/** The one-line visual an agent verifies after `npm run dev`. */\nexport function describeFieldConfig(input: FieldExportInput): string {\n const n = input.papers.length\n const stateful = input.papers.some((p) => p.preset.states || p.states)\n const zones = input.zones ?? []\n const parts: string[] = []\n\n if (input.layout === 'sheet') {\n const rows = Number(input.layoutOptions?.rows ?? 2)\n const columns = Number(input.layoutOptions?.columns ?? 5)\n parts.push(`a ${rows}×${columns} sheet of papers on a shared backing`)\n } else {\n const layoutPhrase = LAYOUT_PHRASES[input.layout] ?? `a ${input.layout} layout`\n parts.push(`${n} papers arranged in ${layoutPhrase}`)\n }\n\n const driver = input.motion?.driver ?? 'autoplay'\n if (stateful) {\n // Stateful fields render static and interactive — the motion driver is moot.\n parts.push('hovering peels/reacts per paper (interaction states)')\n if (zones.length > 0) {\n parts.push(\n `dragging one past its tear threshold detaches it to carry to the ${zones\n .map((z) => z.id)\n .join(' or ')} zone (release elsewhere flutters it back)`,\n )\n }\n } else {\n if (driver === 'autoplay') parts.push('slowly orbiting on their own')\n if (driver === 'drag') parts.push('draggable sideways with the pointer')\n if (zones.length > 0) parts.push(`${zones.length} drop zone${zones.length > 1 ? 's' : ''}`)\n }\n\n const distinct = distinctFieldPresets(input)\n if (distinct.length > 1) {\n parts.push(`mixing ${distinct.length} paper presets (${distinct.map((d) => d.presetName).join(', ')})`)\n }\n return parts.join(', ')\n}\n\n/** Component source shared by the JSX snippet and the agent payload. */\nexport function buildFieldComponentSource(input: FieldExportInput): string {\n const distinct = distinctFieldPresets(input)\n const varByKey = new Map(distinct.map((d) => [JSON.stringify(d.preset), d.varName]))\n\n // `satisfies` (not `as const`) — const-asserted arrays turn readonly and\n // stop matching the library's input types.\n const consts = distinct\n .map(\n (d) =>\n `const ${d.varName} = ${JSON.stringify(diffConfig(d.preset), null, 2)} satisfies PaperConfigInput`,\n )\n .join('\\n\\n')\n\n const slots = input.papers\n .map((paper) => {\n const varName = varByKey.get(JSON.stringify(paper.preset))!\n const content = paper.content ? `, content: ${JSON.stringify(paper.content)}` : ''\n const states = paper.states ? `, states: ${JSON.stringify(paper.states)}` : ''\n return ` { preset: ${varName}${content}${states} },`\n })\n .join('\\n')\n\n const props = Object.entries(diffFieldProps(input))\n .map(([key, value]) =>\n typeof value === 'string' ? ` ${key}=\"${value}\"` : ` ${key}={${JSON.stringify(value)}}`,\n )\n .join('\\n')\n\n const zones = input.zones ?? []\n const zoneImport = zones.length > 0 ? ', DropZone' : ''\n const zoneChildren = zones\n .map((zone) => {\n const accept = zone.accept ? ` accept={${JSON.stringify(zone.accept)}}` : ''\n const highlight = zone.highlight && zone.highlight !== 'glow' ? ` highlight=\"${zone.highlight}\"` : ''\n return ` <DropZone\n id=\"${zone.id}\"${accept}\n bounds={${JSON.stringify(zone.bounds)}}${highlight}\n onPlace={(paper, zone) => {\n // First-run smoke test — you should see this in the console on drop:\n console.log(paper.presetName, '→', zone.id)\n // Then replace it: stamp a postmark, advance the flow, persist the placement, …\n }}\n />`\n })\n .join('\\n')\n\n if (zones.length === 0) {\n return `import { PaperField, type FieldPaperSlot, type PaperConfigInput${zoneImport} } from 'paperlab'\n\n${consts}\n\nconst papers: FieldPaperSlot[] = [\n${slots}\n]\n\nexport function PaperGallery() {\n return (\n <PaperField\n papers={papers}\n${props}\n />\n )\n}`\n }\n\n return `import { PaperField, type FieldPaperSlot, type PaperConfigInput${zoneImport} } from 'paperlab'\n\n${consts}\n\nconst papers: FieldPaperSlot[] = [\n${slots}\n]\n\nexport function PaperGallery() {\n return (\n <PaperField\n papers={papers}\n${props}\n >\n${zoneChildren}\n </PaperField>\n )\n}`\n}\n\n/** The self-contained field integration brief — one paste into a coding agent. */\nexport function buildFieldAgentPayload(input: FieldExportInput): string {\n return `Integrate a Paperlab paper gallery into this project. (paperlab agent-payload v${AGENT_PAYLOAD_VERSION})\n\n1. Install the dependencies:\n\n npm i paperlab three @react-three/fiber gsap\n\n2. Create the component below as \\`components/PaperGallery.tsx\\` (or the\n project's component convention). It is self-contained — every preset it\n uses is inlined, and it owns its own <Canvas>:\n\n\\`\\`\\`tsx\n${buildFieldComponentSource(input)}\n\\`\\`\\`\n\n3. Sizing: the component fills its parent container. Place it where I ask;\n give the parent an explicit height.\n\n4. Verify: run the dev server. You should see ${describeFieldConfig(input)}.\n If the canvas is blank, the parent container almost certainly has no height —\n give it one (this is the classic React Three Fiber integration bug, not a\n paperlab bug).\n\nConstraints: don't modify the preset values; three >= 0.160 and React 19 are\nrequired; the component needs no props.`\n}\n","import * as THREE from 'three'\nimport type { DeformerInstance, SheetDims } from '../deformers/types'\nimport { displacePoint } from '../deformers/compose'\nimport { getDeformer } from '../deformers/registry'\nimport { buildDisplacementGLSL } from './compose'\n\n/**\n * Golden-vector parity: the JS (hero) and GLSL (field) implementations of a\n * deformer must produce identical displacements. This harness evaluates the\n * GLSL path on the real GPU — the stack's displacement functions run in a\n * fragment shader over an N×N grid, rendered to a float target and read\n * back — then epsilon-compares against the JS path. Browser-only (WebGL2);\n * driven by tools/parity.mjs in CI.\n */\n\nconst GRID = 48\n/** highp float + sin/cos implementation differences across GPUs. */\nexport const PARITY_EPSILON = 5e-4\n\nexport interface ParityCase {\n name: string\n stack: DeformerInstance[]\n sheet: SheetDims\n t: number\n}\n\nexport interface ParityResult {\n name: string\n maxError: number\n pass: boolean\n}\n\n/** One case per deformer feature worth guarding, both easy and adversarial. */\nexport const parityCases: ParityCase[] = [\n {\n name: 'roll: defaults',\n stack: [{ type: 'roll', options: { angle: 90, boundary: 0, radius: 0.12, thickness: 0.04 } }],\n sheet: { width: 1, height: 1.4 },\n t: 0,\n },\n {\n name: 'roll: tight receipt roll, rolling down',\n stack: [{ type: 'roll', options: { angle: 270, boundary: -0.4, radius: 0.07, thickness: 0.006 } }],\n sheet: { width: 1, height: 2.6 },\n t: 0,\n },\n {\n name: 'curl: bottom-right peel',\n stack: [{ type: 'curl', options: { corner: 'bottom-right', amount: 0.45, radius: 0.2, skew: 0 } }],\n sheet: { width: 1.5, height: 1 },\n t: 0,\n },\n {\n name: 'curl: skewed top-left',\n stack: [{ type: 'curl', options: { corner: 'top-left', amount: 0.7, radius: 0.3, skew: 15 } }],\n sheet: { width: 1, height: 1 },\n t: 0,\n },\n {\n name: 'bend: positive arc at an angle',\n stack: [{ type: 'bend', options: { curvature: 1.2, angle: 33 } }],\n sheet: { width: 1, height: 1.4 },\n t: 0,\n },\n {\n /**\n * The gentle end, which nothing used to cover: the gate only ever tried\n * |curvature| ≥ 0.6, and `photo-print` — the field starter preset — bends\n * at 0.35. That band is where the arc's float32 evaluation loses its\n * cancellation, and where the two paths were 6e-4 apart until `bend` was\n * rewritten in cancellation-free form. Keep a case down here.\n */\n name: 'bend: barely-there arc (the band photo-print lives in)',\n stack: [{ type: 'bend', options: { curvature: 0.35, angle: 0 } }],\n sheet: { width: 1.2, height: 0.9 },\n t: 0,\n },\n {\n name: 'bend: the gentlest arc the schema allows',\n stack: [{ type: 'bend', options: { curvature: 0.02, angle: 61 } }],\n sheet: { width: 2, height: 2.6 },\n t: 0,\n },\n {\n name: 'bend: negative arc',\n stack: [{ type: 'bend', options: { curvature: -0.8, angle: 0 } }],\n sheet: { width: 1, height: 1.4 },\n t: 0,\n },\n {\n name: 'fold: 90° hinge',\n stack: [{ type: 'fold', options: { angle: 90, offset: 0, foldAngle: 90, radius: 0.06 } }],\n sheet: { width: 1, height: 1.4 },\n t: 0,\n },\n {\n name: 'fold: deep fold, travelling down',\n stack: [{ type: 'fold', options: { angle: 270, offset: 0.2, foldAngle: 165, radius: 0.04 } }],\n sheet: { width: 1, height: 1.4 },\n t: 0,\n },\n {\n name: 'wave: free ripple at t=1.234',\n stack: [\n {\n type: 'wave',\n options: { amplitude: 0.05, wavelength: 0.5, speed: 1, angle: 20, pinnedEdge: 'none' },\n },\n ],\n sheet: { width: 1, height: 1 },\n t: 1.234,\n },\n {\n name: 'wave: pinned top at t=2.5',\n stack: [\n {\n type: 'wave',\n options: { amplitude: 0.04, wavelength: 0.4, speed: 1.5, angle: 80, pinnedEdge: 'top' },\n },\n ],\n sheet: { width: 1.2, height: 1.5 },\n t: 2.5,\n },\n {\n name: 'drape: banner hung from the top',\n stack: [\n {\n type: 'drape',\n options: { amplitude: 0.17, folds: 5, falloff: 1.6, irregular: 0.45, gather: 0.5, pinnedEdge: 'top' },\n },\n ],\n sheet: { width: 1.5, height: 8.5 },\n t: 0,\n },\n {\n name: 'drape: deep irregular folds pinned at the bottom',\n stack: [\n {\n type: 'drape',\n options: { amplitude: 0.55, folds: 11, falloff: 0.4, irregular: 1, gather: 1, pinnedEdge: 'bottom' },\n },\n ],\n sheet: { width: 2.2, height: 3 },\n t: 0,\n },\n {\n name: 'crumple: defaults',\n stack: [{ type: 'crumple', options: { amount: 0.35, scale: 3, pull: 0.4, seed: 0 } }],\n sheet: { width: 1, height: 1.4 },\n t: 0,\n },\n {\n // The adversarial one. `fract` is a sawtooth, so the two halves disagree\n // hardest where a crease lands exactly on a sample — a fine scale and a\n // seed whose fold directions are near-axis puts the most creases in\n // reach of the grid.\n name: 'crumple: fully crushed, fine creases, off-axis seed',\n stack: [{ type: 'crumple', options: { amount: 1, scale: 7.5, pull: 1, seed: 5 } }],\n sheet: { width: 1.3, height: 0.9 },\n t: 0,\n },\n {\n // Crush then curl, which is the order the crumple BEHAVIOR stacks them:\n // the creases have to be placed on the flat sheet, not on a bent one.\n name: 'stacked: crumple ∘ bend (the crumple behavior)',\n stack: [\n { type: 'crumple', options: { amount: 0.62, scale: 3.3, pull: 0.5, seed: 2 } },\n { type: 'bend', options: { curvature: 0.31, angle: 35 } },\n ],\n sheet: { width: 1.1, height: 1.4 },\n t: 0,\n },\n {\n name: 'stacked: letter-fold pair (fold ∘ fold)',\n stack: [\n { type: 'fold', options: { angle: 270, offset: 0.2333, foldAngle: 120, radius: 0.05 } },\n { type: 'fold', options: { angle: 90, offset: 0.2333, foldAngle: 100, radius: 0.08 } },\n ],\n sheet: { width: 1, height: 1.4 },\n t: 0,\n },\n {\n name: 'stacked: bend ∘ roll ∘ wave',\n stack: [\n { type: 'bend', options: { curvature: 0.6, angle: 0 } },\n { type: 'roll', options: { angle: 90, boundary: 0.1, radius: 0.15, thickness: 0 } },\n {\n type: 'wave',\n options: { amplitude: 0.02, wavelength: 0.6, speed: 0.7, angle: 45, pinnedEdge: 'none' },\n },\n ],\n sheet: { width: 1, height: 1.4 },\n t: 0.8,\n },\n]\n\nfunction buildParityFragment(stack: DeformerInstance[], sheet: SheetDims): string {\n const composed = buildDisplacementGLSL(stack, sheet)\n return /* glsl */ `#version 300 es\nprecision highp float;\nuniform float uPlTime;\nuniform float uPlBias;\n${composed.functionsSrc}\n${composed.displaceSrc}\nout vec4 outColor;\nvoid main() {\n vec2 uv = (gl_FragCoord.xy - 0.5) / float(${GRID - 1});\n vec3 p = vec3((uv - 0.5) * uSheet, 0.0);\n outColor = vec4(plDisplace(p, uv, uPlTime, uPlBias), 1.0);\n}\n`\n}\n\nconst VERT = `#version 300 es\nin vec2 aPos;\nvoid main() { gl_Position = vec4(aPos, 0.0, 1.0); }\n`\n\nfunction compile(gl: WebGL2RenderingContext, type: number, src: string): WebGLShader {\n const shader = gl.createShader(type)!\n gl.shaderSource(shader, src)\n gl.compileShader(shader)\n if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {\n throw new Error(`[paperlab parity] shader compile failed: ${gl.getShaderInfoLog(shader)}`)\n }\n return shader\n}\n\nfunction runCaseOnGPU(gl: WebGL2RenderingContext, c: ParityCase, bias = 1): Float32Array {\n const composed = buildDisplacementGLSL(c.stack, c.sheet)\n const program = gl.createProgram()!\n gl.attachShader(program, compile(gl, gl.VERTEX_SHADER, VERT))\n gl.attachShader(program, compile(gl, gl.FRAGMENT_SHADER, buildParityFragment(c.stack, c.sheet)))\n gl.linkProgram(program)\n if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {\n throw new Error(`[paperlab parity] link failed: ${gl.getProgramInfoLog(program)}`)\n }\n // biome-ignore lint/correctness/useHookAtTopLevel: WebGL's gl.useProgram, not a React hook\n gl.useProgram(program)\n\n for (const [name, value] of Object.entries(composed.uniforms)) {\n const loc = gl.getUniformLocation(program, name)\n if (!loc) continue\n if (typeof value === 'number') gl.uniform1f(loc, value)\n else if (value.length === 2) gl.uniform2f(loc, value[0]!, value[1]!)\n else if (value.length === 3) gl.uniform3f(loc, value[0]!, value[1]!, value[2]!)\n else gl.uniform4f(loc, value[0]!, value[1]!, value[2]!, value[3]!)\n }\n const timeLoc = gl.getUniformLocation(program, 'uPlTime')\n if (timeLoc) gl.uniform1f(timeLoc, c.t)\n const biasLoc = gl.getUniformLocation(program, 'uPlBias')\n if (biasLoc) gl.uniform1f(biasLoc, bias)\n\n const quad = gl.createBuffer()!\n gl.bindBuffer(gl.ARRAY_BUFFER, quad)\n gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 3, -1, -1, 3]), gl.STATIC_DRAW)\n const posLoc = gl.getAttribLocation(program, 'aPos')\n gl.enableVertexAttribArray(posLoc)\n gl.vertexAttribPointer(posLoc, 2, gl.FLOAT, false, 0, 0)\n\n const tex = gl.createTexture()!\n gl.bindTexture(gl.TEXTURE_2D, tex)\n gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA32F, GRID, GRID, 0, gl.RGBA, gl.FLOAT, null)\n const fbo = gl.createFramebuffer()!\n gl.bindFramebuffer(gl.FRAMEBUFFER, fbo)\n gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0)\n gl.viewport(0, 0, GRID, GRID)\n gl.drawArrays(gl.TRIANGLES, 0, 3)\n\n const out = new Float32Array(GRID * GRID * 4)\n gl.readPixels(0, 0, GRID, GRID, gl.RGBA, gl.FLOAT, out)\n gl.bindFramebuffer(gl.FRAMEBUFFER, null)\n return out\n}\n\n/**\n * The bias contract, checked on the GPU: a stack of strength-bearing\n * deformers must go completely flat at bias 0, and a stack of deformers that\n * opt out (roll) must ignore bias entirely. Parity alone can't catch this —\n * it only ever evaluates bias 1.\n */\nfunction runBiasCases(gl: WebGL2RenderingContext): ParityResult[] {\n const results: ParityResult[] = []\n for (const c of parityCases) {\n const strengths = c.stack.map((i) => getDeformer(i.type).glsl?.strength !== undefined)\n // Mixed stacks flatten only partway — nothing crisp to assert.\n if (!strengths.every((h) => h === strengths[0])) continue\n const scales = strengths[0]\n\n const at0 = runCaseOnGPU(gl, c, 0)\n const reference = scales ? null : runCaseOnGPU(gl, c, 1)\n let maxError = 0\n for (let row = 0; row < GRID; row++) {\n for (let col = 0; col < GRID; col++) {\n const i4 = (row * GRID + col) * 4\n // At bias 0 a scaling stack collapses onto the flat sheet; an opted-out\n // stack must land exactly where bias 1 put it.\n const ex = reference ? reference[i4]! : (col / (GRID - 1) - 0.5) * c.sheet.width\n const ey = reference ? reference[i4 + 1]! : (row / (GRID - 1) - 0.5) * c.sheet.height\n const ez = reference ? reference[i4 + 2]! : 0\n maxError = Math.max(\n maxError,\n Math.abs(at0[i4]! - ex),\n Math.abs(at0[i4 + 1]! - ey),\n Math.abs(at0[i4 + 2]! - ez),\n )\n }\n }\n results.push({\n name: `bias: ${c.name} → ${scales ? 'flat at 0' : 'ignores bias'}`,\n maxError,\n pass: maxError < PARITY_EPSILON,\n })\n }\n return results\n}\n\n/** Run every parity case. Requires a WebGL2 context with float render targets. */\nexport function runParityHarness(canvas?: HTMLCanvasElement): ParityResult[] {\n const cnv = canvas ?? document.createElement('canvas')\n const gl = cnv.getContext('webgl2')\n if (!gl) throw new Error('[paperlab parity] WebGL2 unavailable')\n if (!gl.getExtension('EXT_color_buffer_float')) {\n throw new Error('[paperlab parity] EXT_color_buffer_float unavailable')\n }\n\n const point = new THREE.Vector3()\n const parity = parityCases.map((c) => {\n const gpu = runCaseOnGPU(gl, c)\n let maxError = 0\n for (let row = 0; row < GRID; row++) {\n for (let col = 0; col < GRID; col++) {\n const u = col / (GRID - 1)\n const v = row / (GRID - 1)\n point.set((u - 0.5) * c.sheet.width, (v - 0.5) * c.sheet.height, 0)\n displacePoint(point, u, v, c.stack, { t: c.t, sheet: c.sheet })\n const i4 = (row * GRID + col) * 4\n maxError = Math.max(\n maxError,\n Math.abs(gpu[i4]! - point.x),\n Math.abs(gpu[i4 + 1]! - point.y),\n Math.abs(gpu[i4 + 2]! - point.z),\n )\n }\n }\n return { name: c.name, maxError, pass: maxError < PARITY_EPSILON }\n })\n return [...parity, ...runBiasCases(gl)]\n}\n"],"mappings":"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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA4D/B,IAAM;AAAA;AAAA,EAA0B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAwChC,IAAM;AAAA;AAAA,EAA0B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsDhC,IAAM;AAAA;AAAA,EAA+B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAwDrC,IAAM;AAAA;AAAA,EAA0B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAyKhC,IAAM;AAAA;AAAA,EAAgC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA+WtC,SAAS,kBAAkB,SAAyB;AAClD,QAAM,SAAS;AACf,QAAM,SAAS,QAAQ,QAAQ,4BAA4B;AAC3D,QAAM,OAAO,QAAQ,YAAY,OAAO,QAAQ,QAAQ,eAAe,CAAC;AACxE,MAAI,CAAC,QAAQ,SAAS,MAAM,KAAK,SAAS,KAAK,QAAQ,QAAQ;AAC7D,UAAM,IAAI,MAAM,gEAA2D;AAAA,EAC7E;AACA,UAAQ,QAAQ,MAAM,GAAG,MAAM,IAAI,QAAQ,MAAM,IAAI,GAAG,QAAQ,QAAQ,EAAE;AAC5E;AAGO,IAAM,gBAAgB,kBAAkB,OAAO;AAEtD,IAAM;AAAA;AAAA,EAA0B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOhC,IAAM;AAAA;AAAA,EAAyB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsBxB,SAAS,eACd,SACA,OACA,WACA,OAAoB,EAAE,aAAa,OAAO,YAAY,MAAM,GAE5DC,SAA2C,EAAE,OAAO,GAAG,QAAQ,IAAI,GAEnE,WAA0C,UAO1C,UAA2B,eAAe,SAAS,CAAC,GAAGA,MAAK,GAC3C;AACjB,QAAM,QAAQ,QAAQ,SAAS,MAAM,eAAe;AACpD,QAAM,QAAQ,QAAQ,SAAS,MAAM,eAAe;AACpD,QAAM,SAAS,QAAQ;AACvB,QAAM,cAAc,QAAQ;AAC5B,QAAM,UAAU,MAAM;AAEtB,QAAM,cAAc,MAAM,WAAW,IAAK,QAAQ,eAAe,MAAM;AAEvE,QAAM,SAAmB,CAAC;AAC1B,QAAM,QAAkB,CAAC;AACzB,QAAM,WAA+C;AAAA;AAAA;AAAA,IAGnD,aAAa;AAAA,MACX,OAAO,MAAM,WAAW,IAAI,IAAI,KAAK,IAAI,MAAM,OAAO,YAAY,GAAG,IAAI,MAAM;AAAA,IACjF;AAAA,IACA,aAAa,EAAE,OAAO,IAAU,aAAM,MAAM,KAAK,EAAE;AAAA;AAAA;AAAA,IAGnD,YAAY,EAAE,OAAO,IAAU,eAAQA,OAAM,OAAOA,OAAM,MAAM,EAAE;AAAA,IAClE,UAAU,EAAE,OAAO,MAAM,QAAQ;AAAA,IACjC,cAAc,EAAE,OAAO,YAAY;AAAA;AAAA;AAAA,IAGnC,GAAG,qBAAqB,QAAQ,gBAAgB,MAAM,cAAc,QAAQ;AAAA,EAC9E;AACA,MAAI,KAAK,YAAa,UAAS,YAAY,EAAE,OAAO,KAAK;AACzD,MAAI,KAAK,WAAY,UAAS,WAAW,EAAE,OAAO,KAAK;AAEvD,MAAI,UAAU,UAAa,UAAU,GAAG;AACtC,WAAO,KAAK,WAAW;AACvB,UAAM,KAAK,2CAA2C;AACtD,aAAS,eAAe,EAAE,OAAO,SAAS,EAAE;AAC5C,aAAS,gBAAgB,EAAE,OAAO,QAAQ;AAAA,EAC5C;AACA,MAAI,QAAQ;AACV,WAAO,KAAK,YAAY;AACxB,UAAM,KAAK,6BAA6B;AACxC,aAAS,eAAe,EAAE,OAAO,UAAU,OAAO,KAAK,EAAE;AACzD,aAAS,mBAAmB,EAAE,OAAO,OAAO,UAAU;AAAA,EACxD;AACA,MAAI,aAAa;AACf,UAAM,QAAQ,YAAY,UAAU,QAAQ,CAAC,GAAG,UAAe,IAAI,YAAY;AAC/E,WAAO,KAAK,iBAAiB;AAC7B,UAAM,KAAK,kCAAkC;AAC7C,aAAS,aAAa,EAAE,OAAO,UAAU,KAAK,EAAE;AAChD,aAAS,YAAY;AAAA,MACnB,OAAO,IAAU;AAAA,QACf,GAAG,WAAgB,IAAI,CAACC,OAAO,MAAM,SAASA,EAAC,KAAK,YAAY,MAAMA,EAAC,MAAM,SAAS,IAAI,CAAE;AAAA,MAC9F;AAAA,IACF;AACA,aAAS,cAAc,EAAE,OAAO,YAAY,WAAW;AACvD,aAAS,eAAe,EAAE,OAAO,YAAY,QAAQ;AAAA,EACvD;AACA,MAAI,QAAQ,SAAS,GAAG;AACtB,WAAO,KAAK,YAAY;AACxB,UAAM,KAAK,4CAA4C;AACvD,aAAS,gBAAgB,EAAE,OAAO,IAAI,QAAQ,IAAI,CAACC,OAAOA,GAAE,QAAQ,KAAK,KAAM,GAAG,CAAC,EAAE;AACrF,aAAS,mBAAmB,EAAE,OAAO,IAAI,QAAQ,IAAI,CAACA,OAAMA,GAAE,QAAQ,CAAC,EAAE;AACzE,aAAS,iBAAiB,EAAE,OAAO,IAAI,QAAQ,IAAI,CAACA,OAAMA,GAAE,MAAM,CAAC,EAAE;AACrE,aAAS,eAAe,EAAE,OAAO,gBAAgB,cAAc;AAC/D,aAAS,eAAe,EAAE,OAAO,KAAK,IAAI,QAAQ,QAAQ,CAAC,EAAE;AAAA,EAC/D;AACA,MAAI,UAAU,QAAW;AACvB,WAAO,KAAK,WAAW;AACvB,UAAM,KAAK,4BAA4B;AACvC,aAAS,eAAe,EAAE,OAAO,MAAM;AAAA,EACzC;AAEA,MAAI,KAAK,WAAW;AAClB,WAAO,KAAK,cAAc,kBAAkB;AAC5C,UAAM,KAAK,4CAA4C;AAEvD,aAAS,UAAU,EAAE,OAAO,KAAK;AAEjC,aAAS,gBAAgB,EAAE,OAAO,EAAE;AAEpC,aAAS,cAAc,EAAE,OAAO,EAAE;AAElC,UAAM,OAAO;AACb,aAAS,SAAS;AAAA,MAChB,OAAO,IAAU,eAAQ,KAAK,YAAY,KAAK,gBAAgB,KAAK,eAAe,KAAK,YAAY;AAAA,IACtG;AACA,aAAS,SAAS;AAAA,MAChB,OAAO,IAAU,eAAQ,KAAK,WAAW,KAAK,UAAU,KAAK,eAAe,KAAK,UAAU;AAAA,IAC7F;AACA,aAAS,SAAS;AAAA,MAChB,OAAO,IAAU,eAAQ,KAAK,YAAY,KAAK,aAAa,KAAK,gBAAgB,KAAK,OAAO;AAAA,IAC/F;AACA,aAAS,SAAS,EAAE,OAAO,IAAU,eAAQ,KAAK,UAAU,KAAK,UAAU,KAAK,SAAS,CAAC,EAAE;AAAA,EAC9F;AAiBA,QAAM,UAAoB,CAAC;AAC3B,QAAM,OAAiB,CAAC;AACxB,MAAI,QAAQ;AACV,YAAQ,KAAK,YAAY;AACzB,SAAK,KAAK,kBAAkB;AAAA,EAC9B;AACA,MAAI,aAAa;AACf,YAAQ,KAAK,iBAAiB;AAC9B,SAAK,KAAK,uBAAuB;AAAA,EACnC;AACA,MAAI,KAAK,WAAW;AAClB,YAAQ,KAAK,YAAY;AACzB,SAAK,KAAK,qCAAqC;AAAA,EACjD;AACA,QAAM,QACJ,QAAQ,SAAS,IACb;AAAA,IACE,cAAc;AAAA,IACd;AAAA;AAAA,MAA2B;AAAA,EACnC,aAAa;AAAA,EACb,QAAQ,KAAK,IAAI,CAAC;AAAA;AAAA;AAAA;AAAA,IAIhB,KAAK,KAAK,MAAM,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,EAIb,IACA;AAQN,QAAM,SAAS,UAAU,UAAa,QAAQ,SAAS,KAAK,QAAQ,KAAK,SAAS;AAElF,QAAM,YAAY,KAAK,cAAc,uCAAuC;AAG5E,QAAM,eAAe,MAAM,WACvB,6BACA,KAAK,aACH,gEACA;AAEN,QAAM;AAAA;AAAA,IAA4B;AAAA,EAClC,OAAO;AAAA;AAAA;AAAA;AAAA,EAIP,KAAK,cAAc,iCAAiC,EAAE;AAAA,EACtD,KAAK,cAAc,CAAC,MAAM,WAAW,gCAAgC,EAAE;AAAA,EACvE,qBAAqB;AAAA,EACrB,OAAO,KAAK,IAAI,CAAC;AAAA;AAAA;AAAA,iBAGF,SAAS;AAAA;AAAA;AAAA;AAAA,sBAIJ,YAAY;AAAA;AAAA;AAAA,IAG9B,MAAM,KAAK,MAAM,CAAC;AAAA,EACpB,SAAS,4IAAuI,EAAE;AAAA;AAAA,IAEhJ,MAAM,WAAW,gHAAgH,EAAE;AAAA;AAAA;AAAA,EAGrI,KAAK,YAAY,wHAAmH,EAAE;AAAA;AAAA;AAAA;AAItI,SAAO;AAAA,IACL,cAAc,GAAG;AAAA,MACf,UAAU,UAAa,UAAU,IAAI,MAAM;AAAA,MAC3C,SAAS,MAAM;AAAA,MACf,QAAQ,SAAS,IAAI,MAAM;AAAA,MAC3B,UAAU,SAAY,MAAM;AAAA,MAC5B,cAAc,MAAM;AAAA,MACpB,MAAM,WAAW,MAAM;AAAA,IACzB,EAAE,KAAK,EAAE,CAAC,IAAI,KAAK,cAAc,MAAM,EAAE,GAAG,KAAK,aAAa,MAAM,EAAE,GAAG,KAAK,YAAY,MAAM,EAAE;AAAA,IAClG,cAAc;AAAA,IACd;AAAA,IACA;AAAA;AAAA;AAAA,IAGA,WAAW,UAAU,eAAe,KAAK,YAAY,MAAM;AAAA,IAC3D;AAAA,EACF;AACF;AAEA,SAAS,IAAI,QAAkB,OAAO,GAAa;AACjD,QAAM,MAAM,OAAO,MAAM,GAAG,CAAC;AAC7B,SAAO,IAAI,SAAS,EAAG,KAAI,KAAK,IAAI;AACpC,SAAO;AACT;;;AGvsCA,IAAAC,gBAA0D;AAsBjD,IAAAC,sBAAA;AAHT,IAAM,sBAAkB,6BAAqC,IAAI;AAE1D,SAAS,SAAS,EAAE,KAAK,SAAS,GAAiD;AACxF,SAAO,6CAAC,gBAAgB,UAAhB,EAAyB,OAAO,KAAM,UAAS;AACzD;AAGO,SAAS,YAAY,KAAmC;AAC7D,aAAO,0BAAW,eAAe,KAAK,kBAAkB,GAAG;AAC7D;;;AC5BA,IAAAC,SAAuB;AACvB,mBAAyB;AACzB,IAAAC,gBAAmC;AAkB5B,SAAS,iBAAiB,QAAmE;AAClG,QAAM,cAAU,uBAAQ,MAAM;AAC5B,QAAI,CAAC,OAAQ,QAAO;AACpB,UAAM,IAAI,IAAU;AAAA,MAClB,OAAO;AAAA,MACP,OAAO;AAAA,MACP,OAAO;AAAA,MACD;AAAA,MACA;AAAA,IACR;AACA,MAAE,YAAkB;AACpB,MAAE,YAAkB;AACpB,MAAE,QAAc;AAChB,MAAE,QAAc;AAChB,MAAE,kBAAkB;AAIpB,MAAE,aAAmB;AAErB,MAAE,QAAQ;AACV,MAAE,SAAS,UAAU,OAAO;AAC5B,MAAE,cAAc;AAChB,WAAO;AAAA,EACT,GAAG,CAAC,MAAM,CAAC;AAGX,+BAAU,MAAM,MAAM,SAAS,QAAQ,GAAG,CAAC,OAAO,CAAC;AAEnD,6BAAS,MAAM;AACb,QAAI,CAAC,UAAU,CAAC,QAAS;AACzB,QAAI,QAAQ,SAAS,YAAY,OAAO,QAAS;AACjD,YAAQ,SAAS,UAAU,OAAO;AAClC,YAAQ,cAAc;AAAA,EACxB,CAAC;AAED,SAAO;AACT;;;Ad4FI,IAAAC,sBAAA;AAzGG,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,OAAAC;AAAA,EACA,WAAW;AAAA,EACX;AAAA,EACA;AACF,GAAuB;AACrB,QAAM,MAAM,YAAY,QAAQ;AAChC,QAAM,gBAAgB,iBAAiB,MAAM;AAC7C,QAAM,WAAW;AAAA,IACf;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,MACE,aAAa,QAAQ,OAAO;AAAA,MAC5B,YAAY,QAAQ,WAAW;AAAA,MAC/B,WAAW,QAAQ,aAAa;AAAA,IAClC;AAAA,IACAA;AAAA,IACA;AAAA,IACA,WAAW,eAAe,SAAS,CAAC,GAAGA,UAAS,EAAE,OAAO,GAAG,QAAQ,IAAI,CAAC;AAAA,EAC3E;AAIA,QAAM,YAAQ,uBAAQ,MAAM,SAAS,UAAU,CAAC,SAAS,YAAY,CAAC;AACtE,+BAAU,MAAM;AACd,eAAW,CAAC,KAAK,OAAO,KAAK,OAAO,QAAQ,SAAS,QAAQ,GAAG;AAC9D,UACE,CAAC,MAAM,GAAG,KACV,QAAQ,eACR,QAAQ,cACR,QAAQ,aACR,QAAQ,mBACR,QAAQ,iBACR,IAAI,WAAW,OAAO,GACtB;AACA;AAAA,MACF;AACA,UAAI,MAAM,GAAG,EAAE,iBAAuB,gBAAS,QAAQ,iBAAuB,cAAO;AACnF;AAAC,QAAC,MAAM,GAAG,EAAE,MAAsB,KAAK,QAAQ,KAAK;AAAA,MACvD,OAAO;AACL,cAAM,GAAG,EAAE,QAAQ,QAAQ;AAAA,MAC7B;AAAA,IACF;AAAA,EACF,CAAC;AACD,+BAAU,MAAM;AACd,QAAI,MAAM,UAAW,OAAM,UAAU,QAAQ;AAC7C,QAAI,MAAM,SAAU,OAAM,SAAS,QAAQ,eAAe;AAC1D,QAAI,MAAM,QAAS,OAAM,QAAQ,QAAQ;AAAA,EAC3C,GAAG,CAAC,OAAO,SAAS,aAAa,aAAa,CAAC;AAG/C,8BAAS,CAAC,UAAU;AAClB,QAAI,CAAC,MAAM,cAAe;AAI1B,QAAI,MAAM,aAAa;AACrB,YAAM,OAAO,QAAQ,QAAQ,MAAM,MAAM;AACzC,YAAM,YAAY,QAAQ,OAAO,SAAS,IAAI,IAAI,OAAO;AAAA,IAC3D;AAGA,QAAI,MAAM,QAAQ;AAChB,YAAM,OAAO,EAAE,GAAG,sBAAsB,GAAG,QAAQ,KAAK;AACxD,YAAMC,KAAI,CAACC,IAAWC,OAAe,OAAO,SAASD,EAAC,IAAIA,KAAIC;AAC9D,YAAM,IAAI;AACT,MAAC,MAAM,OAAO,MAAwB;AAAA,QACrCF,GAAE,KAAK,YAAY,EAAE,UAAU;AAAA,QAC/BA,GAAE,KAAK,gBAAgB,EAAE,cAAc;AAAA,QACvCA,GAAE,KAAK,eAAe,EAAE,aAAa;AAAA,QACrCA,GAAE,KAAK,cAAc,EAAE,YAAY;AAAA,MACrC;AACC,MAAC,MAAM,OAAQ,MAAwB;AAAA,QACtCA,GAAE,KAAK,WAAW,EAAE,SAAS;AAAA,QAC7BA,GAAE,KAAK,UAAU,EAAE,QAAQ;AAAA,QAC3BA,GAAE,KAAK,eAAe,EAAE,aAAa;AAAA,QACrCA,GAAE,KAAK,YAAY,EAAE,UAAU;AAAA,MACjC;AACC,MAAC,MAAM,OAAQ,MAAwB;AAAA,QACtCA,GAAE,KAAK,YAAY,EAAE,UAAU;AAAA,QAC/BA,GAAE,KAAK,aAAa,EAAE,WAAW;AAAA,QACjCA,GAAE,KAAK,gBAAgB,EAAE,cAAc;AAAA,QACvCA,GAAE,KAAK,SAAS,EAAE,OAAO;AAAA,MAC3B;AACC,MAAC,MAAM,OAAQ,MAAwB;AAAA,QACtCA,GAAE,KAAK,UAAU,EAAE,QAAQ;AAAA,QAC3BA,GAAE,KAAK,UAAU,EAAE,QAAQ;AAAA,QAC3BA,GAAE,KAAK,SAAS,EAAE,OAAO;AAAA,QACzB;AAAA,MACF;AAAA,IACF;AAIA,UAAM,SAAS,QAAQ,UAAU;AACjC,UAAM,cAAc,QAAQ,OAAO,SAAS,MAAM,IAAI,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,MAAM,CAAC,IAAI;AAAA,EAC3F,CAAC;AAED,SACE,8EACE;AAAA;AAAA,MAACG;AAAA,MAAA;AAAA,QAEC,cAAoB;AAAA,QACpB,cAAc,SAAS;AAAA,QACvB,gBAAgB,SAAS;AAAA,QACzB,UAAU;AAAA,QACV,OAAM;AAAA,QACN,WAAW,MAAM;AAAA,QACjB,WAAW;AAAA,QACX,aAAa,MAAM,UAAU;AAAA,QAC7B,SAAS,MAAM;AAAA,QACf,WAAW,SAAS;AAAA,QACpB,MAAY;AAAA;AAAA,MAXP,SAAS;AAAA,IAYhB;AAAA,IASC,SAAS,QACR;AAAA,MAACA;AAAA,MAAA;AAAA,QAEC,QAAO;AAAA,QACP,cAAoB;AAAA,QACpB,cAAc,SAAS,MAAM;AAAA,QAC7B,gBAAgB,SAAS,MAAM;AAAA,QAC/B,UAAU;AAAA,QACV,cAAoB;AAAA;AAAA,MANf,GAAG,SAAS,YAAY;AAAA,IAO/B,IACE;AAAA,KACN;AAEJ;;;AezLA,IAAAC,gBAAoC;AAkEhC,IAAAC,sBAAA;AAvDG,SAAS,wBAAwB,UAA6B;AACnE,QAAM,CAAC,QAAQ,SAAS,QAAI;AAAA,IAC1B,MAAM,OAAO,WAAW,eAAe,OAAO,aAAa,kCAAkC,EAAE;AAAA,EACjG;AACA,+BAAU,MAAM;AACd,UAAM,QAAQ,OAAO,aAAa,kCAAkC;AACpE,QAAI,CAAC,MAAO;AACZ,UAAM,WAAW,MAAM,UAAU,MAAM,OAAO;AAC9C,UAAM,iBAAiB,UAAU,QAAQ;AACzC,WAAO,MAAM,MAAM,oBAAoB,UAAU,QAAQ;AAAA,EAC3D,GAAG,CAAC,CAAC;AACL,SAAO,YAAY;AACrB;AAEA,IAAI,eAA+B;AAE5B,SAAS,gBAAyB;AACvC,MAAI,iBAAiB,KAAM,QAAO;AAClC,MAAI;AACF,UAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,mBAAe,QAAQ,OAAO,WAAW,QAAQ,KAAK,OAAO,WAAW,OAAO,CAAC;AAAA,EAClF,QAAQ;AACN,mBAAe;AAAA,EACjB;AACA,SAAO;AACT;AAGO,SAAS,YAAY,QAA6B;AACvD,QAAM,UAAU,OAAO;AACvB,MAAI,QAAQ,SAAS,OAAQ,QAAO,QAAQ;AAC5C,MAAI,QAAQ,SAAS,QAAS,QAAO,QAAQ,OAAO;AACpD,MAAI,QAAQ,SAAS,WAAW;AAC9B,UAAM,SAAS,cAAc,OAAyB;AACtD,UAAM,QAAQ,QAAQ,MAAM,IAAI,CAAC,MAAM,GAAG,EAAE,IAAI,IAAI,EAAE,MAAM,QAAQ,CAAC,CAAC,EAAE,EAAE,KAAK,IAAI;AACnF,WAAO,gBAAgB,QAAQ,KAAK,KAAK,KAAK,WAAW,OAAO,MAAM,QAAQ,CAAC,CAAC,KAAK,QAAQ,MAAM;AAAA,EACrG;AACA,SAAO;AACT;AAEA,IAAM,iBAAsC;AAAA,EAC1C,UAAU;AAAA,EACV,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,MAAM;AAAA,EACN,YAAY;AAAA,EACZ,QAAQ;AACV;AAGO,SAAS,YAAY,EAAE,OAAO,GAA4B;AAC/D,SACE,6CAAC,SAAI,OAAO,gBAAgB,eAAa,OACtC,sBAAY,MAAM,GACrB;AAEJ;AAGO,SAAS,cAAc,EAAE,OAAO,GAA4B;AACjE,QAAM,QAAQ,SAAS,OAAO,KAAK;AACnC,QAAM,UAAU,OAAO,QAAQ,SAAS;AACxC,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,cAAY,YAAY,MAAM;AAAA,MAC9B,OAAO;AAAA,QACL,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,YAAY;AAAA,QACZ,YAAY;AAAA,MACd;AAAA,MAEA;AAAA,QAAC;AAAA;AAAA,UACC,OAAO;AAAA,YACL,aAAa,GAAG,OAAO,MAAM,KAAK,MAAM,OAAO,MAAM,MAAM;AAAA,YAC3D,UAAU;AAAA,YACV,WAAW;AAAA,YACX,YAAY,MAAM;AAAA,YAClB,OAAO,MAAM;AAAA,YACb,WAAW;AAAA,YACX,SAAS;AAAA,YACT,UAAU;AAAA,YACV,YAAY,OAAO,QAAQ,SAAS,YAAY,4BAA4B;AAAA,YAC5E,YAAY;AAAA,YACZ,UAAU;AAAA,UACZ;AAAA,UAEC,qBAAW,OAAO,QAAQ,SAAS,UAClC;AAAA,YAAC;AAAA;AAAA,cACC,KAAK,OAAO,QAAQ;AAAA,cACpB,KAAK,OAAO,QAAQ,OAAO;AAAA,cAC3B,OAAO,EAAE,OAAO,QAAQ,QAAQ,QAAQ,WAAW,SAAS,QAAQ,MAAM;AAAA;AAAA,UAC5E,IAEA,YAAY,MAAM;AAAA;AAAA,MAEtB;AAAA;AAAA,EACF;AAEJ;;;AC7GO,IAAM,cAAc;AAEpB,SAAS,aAAa,GAAW,MAAc,aAAqB;AACzE,SAAO,KAAK,MAAM,IAAI,GAAG,IAAI;AAC/B;AAGO,SAAS,iBAAiBC,IAAW,UAAkB,MAAc,aAAqB;AAC/F,QAAM,QAAQ,KAAK,IAAI,GAAG,KAAK,MAAM,WAAW,GAAG,CAAC;AACpD,SAAO,KAAK,MAAMA,KAAI,KAAK,IAAI;AACjC;;;AChBA,IAAAC,gBAAqD;;;ACArD,kBAAqB;AA8Bd,IAAM,wBAAgF;AAAA,EAC3F,MAAM,EAAE,OAAO,QAAQ;AAAA,EACvB,OAAO,EAAE,OAAO,QAAQ,MAAM,UAAU;AAAA,EACxC,SAAS,EAAE,IAAI,SAAS,MAAM,SAAS;AAAA,EACvC,QAAQ,EAAE,OAAO,UAAU,QAAQ,OAAO;AAAA,EAC1C,QAAQ,CAAC;AACX;AAEA,IAAM,qBAAqB,EAAE,UAAU,MAAM,MAAM,aAAa;AAGzD,SAAS,YAAY,QAAkC;AAC5D,MAAI,CAAC,OAAO,OAAQ,QAAO;AAC3B,QAAM,EAAE,QAAQ,SAAS,GAAG,KAAK,IAAI;AACrC,SAAO;AACT;AAQO,SAAS,mBAAmB,MAAmB,OAA4B;AAChF,QAAM,MAAM,KAAK,QAAQ,OAAO,KAAK;AACrC,QAAM,OAAO,YAAY,IAAI;AAC7B,MAAI,CAAC,OAAO,OAAO,KAAK,IAAI,SAAS,EAAE,WAAW,EAAG,QAAO;AAC5D,SAAO,kBAAkB,MAAM,YAAY,MAAiC,IAAI,SAAS,CAAC;AAC5F;AAGA,SAAS,eAAe,OAAyB;AAC/C,MAAI,UAAU,QAAQ,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,EAAG,QAAO;AAChF,QAAM,MAA+B,CAAC;AACtC,aAAW,CAAC,KAAKC,EAAC,KAAK,OAAO,QAAQ,KAAgC,GAAG;AACvE,QAAIA,OAAM,OAAW;AACrB,UAAM,SAAS,eAAeA,EAAC;AAC/B,UAAM,gBACJ,WAAW,QACX,OAAO,WAAW,YAClB,CAAC,MAAM,QAAQ,MAAM,KACrB,OAAO,KAAK,MAAM,EAAE,WAAW;AACjC,QAAI,CAAC,cAAe,KAAI,GAAG,IAAI;AAAA,EACjC;AACA,SAAO;AACT;AAWO,SAAS,oBACd,QACA,WACA,OACa;AACb,QAAM,UAAU,eAAe,KAAK;AACpC,QAAM,SAAS,OAAO,UAAU,kBAAkB,MAAM,CAAC,CAAC;AAC1D,QAAM,MAAM,OAAO,OAAO,SAAS,KAAK,eAAe,MAAM,CAAC,CAAC;AAC/D,QAAM,YAAY,YAAY,IAAI,WAAW,OAAO;AACpD,SAAO,kBAAkB,MAAM;AAAA,IAC7B,GAAG;AAAA,IACH,QAAQ;AAAA,MACN,GAAG;AAAA,MACH,QAAQ,EAAE,GAAG,OAAO,QAAQ,CAAC,SAAS,GAAG,EAAE,GAAG,KAAK,UAAU,EAAE;AAAA,IACjE;AAAA,EACF,CAAC;AACH;AAIO,SAAS,eACd,OACA,SAAS,IACT,MAA8B,CAAC,GACP;AACxB,MAAI,OAAO,UAAU,UAAU;AAC7B,QAAI,OAAQ,KAAI,MAAM,IAAI;AAC1B,WAAO;AAAA,EACT;AACA,MAAI,UAAU,QAAQ,OAAO,UAAU,UAAU;AAC/C,UAAM,UAAU,MAAM,QAAQ,KAAK,IAC/B,MAAM,IAAI,CAACA,IAAG,MAAM,CAAC,OAAO,CAAC,GAAGA,EAAC,CAAU,IAC3C,OAAO,QAAQ,KAAK;AACxB,eAAW,CAAC,KAAKA,EAAC,KAAK,SAAS;AAC9B,qBAAeA,IAAG,SAAS,GAAG,MAAM,IAAI,GAAG,KAAK,KAAK,GAAG;AAAA,IAC1D;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,QAAQ,QAAiC,MAAc,OAAqB;AACnF,QAAM,OAAO,KAAK,MAAM,GAAG;AAC3B,MAAI,OAAgC;AACpC,WAAS,IAAI,GAAG,IAAI,KAAK,SAAS,GAAG,KAAK;AACxC,UAAM,OAAO,KAAK,KAAK,CAAC,CAAE;AAC1B,QAAI,SAAS,QAAQ,OAAO,SAAS,SAAU;AAC/C,WAAO;AAAA,EACT;AACA,OAAK,KAAK,KAAK,SAAS,CAAC,CAAE,IAAI;AACjC;AAGA,SAAS,UAAU,QAAiC,MAAoC;AACtF,aAAW,QAAQ,KAAM,SAAQ,QAAQ,MAAM,KAAK,IAAI,CAAE;AAC5D;AAEA,IAAM,QAAQ,CAAIA,OAAY,KAAK,MAAM,KAAK,UAAUA,EAAC,CAAC;AAiBnD,IAAM,oBAAN,MAAwB;AAAA,EAC7B;AAAA,EACQ;AAAA,EACS;AAAA;AAAA,EAET;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOS,OAA+B,CAAC;AAAA;AAAA,EAEzC;AAAA,EACA,QAAgC;AAAA,EAChC,WAAW,oBAAI,IAAyB;AAAA,EAEhD,YAAY,MAAmB,OAAiC,CAAC,GAAG;AAClE,SAAK,OAAO;AACZ,SAAK,OAAO;AACZ,SAAK,QAAQ,KAAK,QAAQ,WAAW;AACrC,UAAM,SAAS,KAAK,QAAQ,KAAK,KAAK;AACtC,SAAK,YAAY,MAAM,MAAM;AAC7B,SAAK,OAAO,MAAM,MAAM;AACxB,WAAO,OAAO,KAAK,MAAM,eAAe,MAAM,CAAC;AAAA,EACjD;AAAA;AAAA,EAGA,IAAI,gBAAwB;AAC1B,WAAO,KAAK,KAAK,QAAQ,iBAAiB;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,IAAI,aAA0B;AAC5B,cAAU,KAAK,MAA4C,KAAK,IAAI;AACpE,WAAO,KAAK;AAAA,EACd;AAAA;AAAA,EAGA,IAAI,SAAsB;AACxB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA,EAGA,IAAI,gBAAyB;AAC3B,WAAO,KAAK,UAAU;AAAA,EACxB;AAAA;AAAA,EAGA,IAAI,cAAsC;AACxC,WAAO,KAAK;AAAA,EACd;AAAA;AAAA,EAGA,mBAAgC;AAC9B,UAAM,MAAM,MAAM,KAAK,SAAS;AAChC,cAAU,KAAK,KAAK,IAAI;AACxB,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,KAAK,OAAkC;AACrC,UAAM,OAAO,sBAAsB,KAAK,KAAK,IAAI,KAAK;AACtD,QAAI,CAAC,QAAQ,SAAS,KAAK,MAAO,QAAO;AACzC,SAAK,KAAK,IAAI;AACd,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,mBAA4B;AAC1B,eAAW,SAAS,CAAC,SAAS,QAAQ,MAAM,GAAmB;AAC7D,YAAM,OAAO,sBAAsB,KAAK,KAAK,IAAI,KAAK;AACtD,UAAI,QAAQ,SAAS,KAAK,MAAO,MAAK,KAAK,MAAM,EAAE,SAAS,KAAK,CAAC;AAAA,IACpE;AACA,WAAO,KAAK,UAAU;AAAA,EACxB;AAAA;AAAA,EAGA,oBAA6B;AAC3B,WAAO,KAAK,aAAa,OAAO;AAAA,EAClC;AAAA;AAAA,EAGA,qBAA8B;AAC5B,WAAO,KAAK,aAAa,QAAQ;AAAA,EACnC;AAAA,EAEQ,aAAa,OAA4B;AAC/C,UAAM,OAAO,sBAAsB,KAAK,KAAK,IAAI,KAAK;AACtD,QAAI,CAAC,QAAQ,SAAS,KAAK,MAAO,QAAO;AACzC,SAAK,KAAK,MAAM,EAAE,SAAS,KAAK,CAAC;AACjC,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,KAAK,OAAe,MAAoC;AACtD,UAAM,MAAM,KAAK,KAAK,QAAQ,OAAO,KAAK;AAC1C,UAAM,SAAS,KAAK,QAAQ,KAAK;AACjC,SAAK,QAAQ;AAEb,UAAM,aAAa,eAAe,MAAM;AAGxC,SAAK,YAAY,MAAM,MAAM;AAC7B,SAAK,OAAO,MAAM,MAAM;AACxB,UAAM,UAAkC,CAAC;AAGzC,eAAW,QAAQ,KAAK,MAAM;AAC5B,UAAI,EAAE,QAAQ,YAAa,QAAO,KAAK,KAAK,IAAI;AAAA,IAClD;AACA,eAAW,CAAC,MAAM,KAAK,KAAK,OAAO,QAAQ,UAAU,GAAG;AACtD,YAAM,UAAU,KAAK,KAAK,IAAI;AAG9B,UAAI,YAAY,OAAW,MAAK,KAAK,IAAI,IAAI;AAAA,eACpC,YAAY,MAAO,SAAQ,IAAI,IAAI;AAAA,IAC9C;AAEA,UAAM,WACJ,KAAK,KAAK,WAAW,MAAM,UAAU,IAAK,KAAK,WAAW,YAAY,mBAAmB;AAC3F,UAAM,OAAO,KAAK,WAAW,QAAQ,mBAAmB;AAIxD,SAAK,OAAO,KAAK;AACjB,SAAK,QAAQ;AAEb,UAAM,SAAS,MAAM;AACnB,iBAAW,CAAC,MAAM,KAAK,KAAK,OAAO,QAAQ,OAAO,EAAG,MAAK,KAAK,IAAI,IAAI;AACvE,WAAK,cAAc;AACnB,iBAAW,UAAU,KAAK,WAAW,CAAC,GAAG;AACvC,YAAI,OAAO,WAAW,OAAO,EAAG,MAAK,KAAK,WAAW,OAAO,MAAM,CAAC,GAAG,KAAK;AAAA,MAC7E;AAAA,IACF;AAEA,QAAI,aAAa,KAAK,OAAO,KAAK,OAAO,EAAE,WAAW,GAAG;AACvD,aAAO;AACP;AAAA,IACF;AAIA,SAAK,cAAc;AACnB,SAAK,QAAQ,iBAAK,GAAG,KAAK,MAAM;AAAA,MAC9B,GAAG;AAAA,MACH;AAAA,MACA;AAAA,MACA,YAAY,MAAM;AAChB,aAAK,QAAQ;AACb,eAAO;AAAA,MACT;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,OAAO,MAAyB;AAC9B,SAAK,OAAO;AACZ,SAAK,SAAS,MAAM;AACpB,UAAM,SAAS,KAAK,QAAQ,KAAK,KAAK;AACtC,SAAK,YAAY,MAAM,MAAM;AAC7B,SAAK,OAAO,MAAM,MAAM;AACxB,UAAM,aAAa,eAAe,MAAM;AAGxC,eAAW,QAAQ,KAAK,MAAM;AAC5B,UAAI,EAAE,QAAQ,YAAa,QAAO,KAAK,KAAK,IAAI;AAAA,IAClD;AACA,eAAW,CAAC,MAAM,KAAK,KAAK,OAAO,QAAQ,UAAU,GAAG;AACtD,UAAI,EAAE,QAAQ,KAAK,MAAO,MAAK,KAAK,IAAI,IAAI;AAAA,IAC9C;AAGA,SAAK,cAAc;AAAA,EACrB;AAAA,EAEA,UAAgB;AACd,SAAK,OAAO,KAAK;AACjB,SAAK,QAAQ;AAAA,EACf;AAAA,EAEQ,QAAQ,OAA4B;AAC1C,QAAI,SAAS,KAAK,SAAS,IAAI,KAAK;AACpC,QAAI,CAAC,QAAQ;AACX,eAAS,mBAAmB,KAAK,MAAM,KAAK;AAC5C,WAAK,SAAS,IAAI,OAAO,MAAM;AAAA,IACjC;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,gBAAsB;AAC5B,SAAK,KAAK,WAAW,KAAK,iBAAiB,GAAG,KAAK,KAAK;AAAA,EAC1D;AACF;;;ADxVO,SAAS,eACd,QACA,SACA,SACA,UACA,eACsB;AACtB,QAAM,OAAO,WAAW,QAAQ,OAAO,MAAM;AAC7C,QAAM,UAAM,uBAAQ,MAAM,KAAK,UAAU,MAAM,GAAG,CAAC,MAAM,CAAC;AAG1D,QAAM,kBAAc,sBAAO,QAAQ;AACnC,cAAY,UAAU;AACtB,QAAM,uBAAmB,sBAAO,aAAa;AAC7C,mBAAiB,UAAU;AAE3B,QAAM,iBAAa,sBAAiC,IAAI;AACxD,QAAM,mBAAe,sBAAe,MAAM;AAC1C,QAAM,CAAC,UAAU,WAAW,QAAI,wBAAwD,IAAI;AAG5F,+BAAU,MAAM;AACd,QAAI,CAAC,MAAM;AACT,iBAAW,SAAS,QAAQ;AAC5B,iBAAW,UAAU;AACrB,kBAAY,IAAI;AAChB;AAAA,IACF;AACA,QAAI,WAAW,SAAS;AACtB,iBAAW,QAAQ,OAAO,MAAM;AAChC;AAAA,IACF;AACA,UAAM,UAAU,IAAI,kBAAkB,QAAQ;AAAA,MAC5C;AAAA;AAAA,MAEA,UAAU,CAACC,IAAG,UAAU;AACtB,YAAI,UAAU,aAAa,SAAS;AAClC,uBAAa,UAAU;AACvB,2BAAiB,UAAU,KAAK;AAAA,QAClC;AACA,oBAAY,EAAE,QAAQA,IAAG,MAAM,CAAC;AAAA,MAClC;AAAA,MACA,UAAU,CAAC,OAAO,UAAU,YAAY,UAAU,OAAO,KAAK;AAAA,IAChE,CAAC;AACD,eAAW,UAAU;AACrB,iBAAa,UAAU,QAAQ;AAC/B,gBAAY,EAAE,QAAQ,QAAQ,iBAAiB,GAAG,OAAO,QAAQ,MAAM,CAAC;AAAA,EAC1E,GAAG,CAAC,KAAK,MAAM,OAAO,CAAC;AAEvB;AAAA,IACE,MAAM,MAAM;AACV,iBAAW,SAAS,QAAQ;AAC5B,iBAAW,UAAU;AAAA,IACvB;AAAA,IACA,CAAC;AAAA,EACH;AAEA,SAAO;AAAA,IACL,QAAQ,QAAQ,WAAW,SAAS,SAAS,YAAY,MAAM;AAAA,IAC/D,OAAO,QAAQ,WAAW,SAAS,QAAQ;AAAA,IAC3C,SAAS,OAAO,WAAW,UAAU;AAAA,EACvC;AACF;;;A9Dy3BQ,IAAAC,sBAAA;AApxBR,SAAS,aAAa,OAAkC;AACtD,SAAO;AAAA,IACL,MAAM,UAAU;AAAA,IAChB,MAAM,SAAS;AAAA,IACf,MAAM,SAAS;AAAA,IACf,MAAM,WAAW;AAAA,IACjB,MAAM,YAAY;AAAA,IAClB,MAAM,aAAa;AAAA,IACnB,MAAM,WAAW;AAAA,IACjB,MAAM,UAAU;AAAA,IAChB,MAAM,SAAS;AAAA,IACf,MAAM,WAAW;AAAA,IACjB,MAAM,UAAU;AAAA,EAClB;AACF;AAGO,SAAS,kBAAkB,OAAoC;AACpE,QAAM,SAAS,UAAU,aAAa,KAAK,CAAC;AAE5C,aAAO,uBAAQ,MAAM,cAAc,KAAK,GAAG,CAAC,MAAM,CAAC;AACrD;AAGO,SAAS,cAAc,OAAoC;AAChE,QAAM,OAAO,MAAM,SACf,OAAO,MAAM,WAAW,WACtB,UAAU,MAAM,MAAM,IACtB,YAAY,MAAM,MAAM,IAC1B,kBAAkB,MAAM,CAAC,CAAC;AAC9B,QAAM,YAA8B,CAAC;AACrC,MAAI,MAAM,MAAO,WAAU,QAAQ,EAAE,GAAG,KAAK,OAAO,GAAG,MAAM,MAAM;AACnE,MAAI,MAAM,MAAO,WAAU,QAAQ,MAAM;AACzC,MAAI,MAAM,QAAS,WAAU,UAAU,MAAM;AAC7C,MAAI,MAAM,SAAU,WAAU,WAAW,MAAM;AAC/C,MAAI,MAAM,UAAW,WAAU,YAAY,MAAM;AAGjD,MAAI,MAAM,QAAS,WAAU,UAAU,EAAE,GAAG,KAAK,SAAS,GAAG,MAAM,QAAQ;AAI3E,MAAI,MAAM,OAAQ,WAAU,SAAS,EAAE,GAAG,KAAK,QAAQ,GAAG,MAAM,OAAO;AACvE,MAAI,MAAM,MAAO,WAAU,QAAQ,EAAE,GAAG,KAAK,OAAO,GAAG,MAAM,MAAM;AACnE,MAAI,MAAM,QAAS,WAAU,UAAU,MAAM;AAC7C,MAAI,MAAM,WAAW,OAAW,WAAU,SAAS,MAAM;AACzD,SAAO,kBAAkB,MAAM,YAAY,MAA0B,SAAS,CAAC;AACjF;AAGA,IAAM,qBAAqB;AAI3B,IAAM,mBAAmB,CAAC,GAAG,MAAM,KAAK,MAAM,CAAC;AAE/C,IAAM,YAAY,IAAU,aAAM;AAClC,IAAM,YAAY,IAAU,eAAQ;AACpC,IAAM,cAAc,IAAU,eAAQ;AACtC,IAAM,gBAAgB,IAAU,eAAQ;AACxC,IAAM,eAAe,IAAU,eAAQ;AACvC,IAAM,cAAc,IAAU,kBAAW;AAQlC,IAAM,gBAAY,0BAAwC,SAASC,WAAU,OAAO,KAAK;AAG9F,QAAM,WAAW,kBAAkB,KAAK;AAGxC,QAAM,UAAU,wBAAwB,MAAM,aAAa;AAI3D,QAAM,aAAa,QAAQ,SAAS,MAAM,KAAK,MAAM,kBAAkB;AACvE,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA,OAAO;AAAA,EACT,IAAI,eAAe,UAAU,YAAY,SAAS,MAAM,eAAe,MAAM,aAAa;AAC1F,QAAM,WAA4B,OAAO,WAAW,YAAY,OAAO,SAAS,IAAI,IAAI;AACxF,QAAM,iBAAa,sBAAiC,IAAI;AACxD,aAAW,UAAU;AAGrB,QAAM,kBAAc,sBAAO,QAAQ;AACnC,cAAY,UAAU;AAGtB,QAAM,UACJ,CAAC,WAAW,OAAO,OAAO,YAAY,WAAY,OAAO,QAAQ,OAA6B;AAChG,QAAM,UAAU,YAAY;AAC5B,QAAM,UAAU,YAAY;AAC5B,QAAM,OACJ,CAAC,WAAW,OAAO,OAAO,YAAY,YAAY,OAAO,YAAY,SACjE,cAAc,OAAO,OAAmB,IACxC;AAEN,QAAM,cAAU,sBAAmB,IAAI;AACvC,QAAM,eAAW,sBAAoB,IAAI;AACzC,QAAM,iBAAa,sBAA8B,CAAC,CAAC;AAEnD,QAAM,mBAAe,sBAAgC,CAAC,CAAC;AACvD,QAAM,eAAW,sBAAO,IAAI;AAC5B,QAAM,iBAAa,sBAAO,KAAK;AAC/B,QAAM,eAAW,sBAA+B,IAAI;AACpD,QAAM,kBAAc,sBAAsB,IAAI;AAE9C,QAAM,gBAAY,sBAAO,MAAM;AAC/B,YAAU,UAAU;AAUpB,QAAM,mBAAe,uBAAkC,MAAM;AAC3D,UAAM,CAAC,IAAI,IAAI,EAAE,IAAI,MAAM,YAAY,CAAC,GAAG,GAAG,CAAC;AAC/C,WAAO,CAAC,IAAI,KAAM,OAAO,MAAM,OAAO,KAAK,KAAM,KAAK,EAAE;AAAA,EAC1D,GAAG,CAAC,MAAM,UAAU,OAAO,MAAM,IAAI,CAAC;AAEtC,QAAM,eAAW,wBAAS,CAAC,MAAM,EAAE,QAAQ;AAC3C,QAAM,aAAS,wBAAS,CAAC,MAAM,EAAE,MAAM;AAEvC,QAAM,cAAc,KAAK,UAAU,OAAO,YAAY,IAAI;AAC1D,QAAM,eAAe,KAAK,UAAU,OAAO,aAAa,IAAI;AAC5D,QAAM,WAAW,KAAK,UAAU,OAAO,KAAK;AAgB5C,QAAM,aAAa,OAAO,OAAO,YAAY,WAAW,OAAO,QAAQ,OAAO,OAAO;AAcrF,QAAM,YAAY,OAAO,OAAO,QAAQ,IAAI,CAACC,OAAM,GAAGA,GAAE,KAAK,IAAIA,GAAE,MAAM,EAAE,EAAE,KAAK,GAAG;AAYrF,QAAM,YAAY,OAAO,OAAO,QAAQ,IAAI,CAACA,OAAM,GAAGA,GAAE,KAAK,IAAIA,GAAE,MAAM,IAAIA,GAAE,KAAK,EAAE,EAAE,KAAK,GAAG;AAMhG,QAAM,iBAAa,sBAA6B,IAAI;AACpD,aAAW,YAAY,IAAI,cAAc,OAAO,OAAO,OAAO;AAC9D,QAAM,UAAU,WAAW;AAG3B,+BAAU,MAAM;AACd,QAAI,CAAC,YAAY,WAAW,CAAC,WAAW,QAAS,cAAa,UAAU,CAAC;AAIzE,YAAQ,MAAM;AACd,aAAS,UAAU;AAAA,EACrB,GAAG,CAAC,aAAa,cAAc,UAAU,UAAU,CAAC;AAOpD,+BAAU,MAAM;AACd,YAAQ,MAAM,UAAU,QAAQ,OAAO,OAAO;AAC9C,aAAS,UAAU;AAAA,EACrB,GAAG,CAAC,SAAS,CAAC;AAGd,QAAM,EAAE,aAAa,cAAc,cAAc,QAAI,uBAAQ,MAAM;AACjE,UAAM,MAAM,UAAU;AAKtB,UAAMC,SAAQ,WAAW,WAAW,KAAK,CAAC,CAAC,GAAG,GAAG;AACjD,QAAI,CAACA,QAAO;AACV,aAAO;AAAA,QACL,aAAa,CAAC,GAAG,CAAC;AAAA,QAClB,cAAc,CAAC,eAAe,aAAa;AAAA,QAC3C,eAAe;AAAA,MACjB;AAAA,IACF;AAcA,UAAM,OAAO,kBAAkBA,QAAO,IAAI,KAAK;AAC/C,QAAI,WAAW,gBAAgBA,MAAK;AACpC,QAAI,IAAI,YAAY,CAAC,IAAI,WAAW;AAClC,YAAM,QAAQ,YAAY,IAAI,SAAS,IAAI,EAAE;AAC7C,iBAAWC,MAAK,kBAAkB;AAChC,cAAM,KAAK,WAAW,WAAW,KAAK,EAAE,CAAC,KAAK,GAAGA,GAAE,CAAC,GAAG,GAAG;AAC1D,YAAI,CAAC,GAAI;AACT,cAAM,CAACC,IAAGC,EAAC,IAAI,kBAAkB,IAAI,IAAI,KAAK;AAC9C,YAAID,KAAI,KAAK,CAAC,EAAG,MAAK,CAAC,IAAIA;AAC3B,YAAIC,KAAI,KAAK,CAAC,EAAG,MAAK,CAAC,IAAIA;AAC3B,qBAAa,gBAAgB,EAAE;AAAA,MACjC;AAAA,IACF;AACA,WAAO;AAAA,MACL,aAAa,iBAAiBH,QAAO,IAAI,KAAK;AAAA,MAC9C,cAAc;AAAA,MACd,eAAe;AAAA,IACjB;AAAA,EACF,GAAG,CAAC,aAAa,cAAc,YAAY,SAAS,CAAC;AAGrD,QAAM,eAAW,uBAAQ,MAAM;AAC7B,QAAI,SAAS;AAIX,YAAM,QAAQ,UAAU,QAAQ;AAChC,YAAM,QAAQ,eAAe,OAAO,MAAM,QAAQ,MAAM,WAAW;AACnE,aAAO,IAAU,qBAAc,OAAO,MAAM,OAAO,OAAO,MAAM,QAAQ,GAAG,QAAQ,CAAC;AAAA,IACtF;AACA,QAAI,CAAC,QAAS,QAAO,oBAAoB,OAAO,OAAO,aAAa,YAAY;AAShF,UAAM,CAAC,IAAI,EAAE,IAAI,gBAAgB,OAAO,OAAO,WAAW;AAC1D,UAAM,SAAS,KAAK,IAAI,KAAK,IAAI,IAAI,EAAE,GAAG,kBAAkB;AAC5D,WAAO,IAAU,qBAAc,OAAO,MAAM,OAAO,OAAO,MAAM,QAAQ,QAAQ,MAAM;AAAA,EACxF,GAAG;AAAA,IACD;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,UAAW,OAAO,QAAwB,cAAc;AAAA,EAC1D,CAAC;AAID,+BAAU,MAAM,MAAM,SAAS,QAAQ,GAAG,CAAC,QAAQ,CAAC;AAEpD,QAAM,oBAAgB;AAAA,IACpB,MAAM,aAAa,KAAK,SAAS,WAAW,SAAU,KAAqB;AAAA,IAC3E,CAAC,QAAQ;AAAA,EACX;AAGA,QAAM,eAAW,uBAAQ,MAAM;AAC7B,QAAI,CAAC,QAAS,QAAO;AACrB,UAAM,QAAQ,UAAU,QAAQ;AAChC,WAAO,IAAI,SAAS,OAAO,MAAM,QAAQ,OAAO,MAAM,OAAO;AAAA,MAC3D,QAAQ,MAAM;AAAA,MACd,WAAW,MAAM;AAAA,MACjB,MAAM,MAAM;AAAA,MACZ,MAAM,MAAM;AAAA,MACZ,aAAa,MAAM;AAAA,MACnB,QAAQ,MAAM;AAAA,MACd,WAAW,MAAM;AAAA,MACjB,MAAM,MAAM;AAAA,MACZ,SAAS,MAAM;AAAA,MACf,OAAO,MAAM;AAAA,MACb,SAAS,MAAM;AAAA,IACjB,CAAC;AAAA,EACH,GAAG,CAAC,UAAU,OAAO,CAAC;AAKtB,QAAM,iBAAa,sBAAwB,IAAI;AAG/C,QAAM,UAAM,uBAAQ,MAAM;AACxB,QAAI,CAAC,QAAS,QAAO;AACrB,UAAM,QAAQ,UAAU,QAAQ;AAChC,UAAM,OAAQ,SAAS,WAAyC,gBAAgB;AAChF,UAAM,OAAQ,SAAS,WAA0C,iBAAiB;AAClF,UAAM,OAAO,IAAI,SAAS,MAAM,MAAM,OAAO,MAAM,OAAO,OAAO,MAAM,QAAQ,MAAM,MAAM;AAAA,MACzF,WAAW,MAAM;AAAA,MACjB,SAAS,MAAM;AAAA,MACf,MAAM,MAAM;AAAA,MACZ,OAAO,MAAM;AAAA,IACf,CAAC;AAGD,SAAK,MAAM,WAAW,OAAO;AAC7B,WAAO;AAAA,EACT,GAAG,CAAC,UAAU,SAAS,UAAW,OAAO,QAAwB,OAAO,EAAE,CAAC;AAE3E,+BAAU,MAAM;AACd,eAAW,UAAU;AAAA,EACvB,GAAG,CAAC,GAAG,CAAC;AAGR,QAAM,eAAW,uBAAQ,MAAO,MAAM,IAAI,eAAe,GAAG,IAAI,MAAO,CAAC,GAAG,CAAC;AAE5E,QAAM,QAAQ,SAAS,OAAO,KAAK;AACnC,QAAM,UAAU,kBAAkB,OAAO,SAAS,OAAO,OAAO,KAAK;AACrE,QAAM,cAAc,kBAAkB,OAAO,QAAQ,MAAM,OAAO,OAAO,KAAK;AAM9E,QAAM,aAAa,MAAmB,WAAW,SAAS,cAAc,UAAU;AAElF,QAAM,mBAAmB,CAAC,MAA8C;AACtE,UAAM,MAAM,WAAW;AACvB,QAAI,CAAC,IAAI,YAAY,CAAC,SAAU,QAAO;AACvC,UAAM,IAAI,EAAE,GAAG,IAAI,UAAU,GAAG,aAAa,QAAQ;AACrD,WAAO,SAAS,OAAO,EAAE,GAAG,GAAG,GAAG,SAAS,KAAK,GAAG,CAAC,EAAE,IAAI;AAAA,EAC5D;AAEA,QAAM,OAAO,MAAM;AACjB,QAAI,CAAC,SAAU;AACf,eAAW,UAAU;AACrB,QAAI,SAAS,SAAS;AACpB,eAAS,QAAQ,KAAK;AACtB;AAAA,IACF;AACA,UAAM,QAAQ,SAAS;AACvB,UAAM,QAAS,iBAAiB,CAAC,IAAI,KAAK,KAAgB;AAC1D,UAAM,QAAQ,EAAE,GAAG,MAAM;AACzB,aAAS,UAAU,kBAAK,GAAG,OAAO;AAAA,MAChC,GAAG;AAAA,MACH,UAAU,SAAS,YAAY,IAAI;AAAA,MACnC,MAAM;AAAA,MACN,MAAM,SAAS,aAAa;AAAA,MAC5B,QAAQ;AAAA,MACR,UAAU,MAAM;AACd,YAAI,SAAS,aAAa,UAAW,OAAM,IAAI;AAAA,MACjD;AAAA,MACA,UAAU,MAAM;AACd,cAAMC,KAAI,UAAU,QAAQ,SAAS,iBAAiB,MAAM,GAAG,SAAS,QAAQ,IAAI,MAAM;AAC1F,qBAAa,QAAQ,KAAK,IAAIA;AAC9B,iBAAS,UAAU;AACnB,cAAM,aAAaA,EAAC;AAAA,MACtB;AAAA,IACF,CAAC;AAAA,EACH;AAEA,QAAM,QAAQ,MAAM;AAClB,eAAW,UAAU;AACrB,aAAS,SAAS,MAAM;AAAA,EAC1B;AAGA,+BAAU,MAAM;AACd,QAAI,MAAM,YAAY,CAAC,QAAS,MAAK;AACrC,WAAO,MAAM;AACX,eAAS,SAAS,KAAK;AACvB,eAAS,UAAU;AAAA,IACrB;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,WAAW,MAAmB;AAGlC,UAAM,SAAS,YAAY,QAAQ;AACnC,UAAM,MAAM,SAAS,EAAE,GAAG,UAAU,SAAS,OAAO,IAAI,UAAU;AAClE,QAAI,CAAC,IAAI,SAAU,QAAO,SAAS,kBAAkB,MAAM,GAAG,IAAI;AAClE,WAAO,kBAAkB,MAAM;AAAA,MAC7B,GAAG;AAAA,MACH,UAAU,EAAE,GAAG,IAAI,UAAU,GAAG,aAAa,QAAQ;AAAA,IACvD,CAAC;AAAA,EACH;AAEA,yCAAoB,KAAK,OAAO;AAAA,IAC9B;AAAA,IACA;AAAA,IACA,IAAI,UAAU;AACZ,aAAO,WAAW;AAAA,IACpB;AAAA,IACA,IAAI,OAAe,OAAgB;AACjC,YAAM,MAAM,UAAU,cAAc,WAAW,SAAS,gBAAgB;AACxE,mBAAa,QAAQ,GAAG,IAAI;AAC5B,eAAS,UAAU;AACnB,UAAI,YAAY,QAAQ,SAAS,cAAe,OAAM,aAAa,KAAe;AAAA,IACpF;AAAA,IACA,cAAc;AACZ,UAAI,CAAC,SAAU,QAAO;AACtB,aAAQ,iBAAiB,CAAC,IAAI,SAAS,aAAa,KAAgB;AAAA,IACtE;AAAA,IACA;AAAA,IACA,QAAQ,MAAM,gBAAgB,SAAS,CAAC;AAAA,IACxC,IAAI,OAAO;AACT,aAAO,QAAQ;AAAA,IACjB;AAAA,IACA,YAAY,IAAa,QAAwB;AAC/C,YAAM,UAAU,UAAU;AAC1B,UAAI,CAAC,SAAS,OAAQ,QAAO;AAC7B,YAAM,QAAQ,KAAK,QAAQ,UAAU,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI;AAC3D,YAAM,OAAO,WAAW,QAAQ,KAAK;AACrC,UAAI,CAAC,KAAM,QAAO;AAClB,aAAO,KAAK,iBAAiB,UAAU,IAAU,eAAQ,CAAC;AAAA,IAC5D;AAAA,IACA,aAAa,GAAWG,IAAW,QAAwB;AACzD,YAAM,OAAO,QAAQ;AACrB,UAAI,CAAC,KAAM,QAAO;AAIlB,YAAM,EAAE,eAAe,eAAe,IAAI,SAAS;AACnD,YAAM,MAAM;AAAA,QACV,SAAS,WAAW,SAAU;AAAA,QAC9B,gBAAgB;AAAA,QAChB,iBAAiB;AAAA,QACjB;AAAA,QACAA;AAAA,QACA,UAAU,IAAU,eAAQ;AAAA,MAC9B;AACA,WAAK,kBAAkB,MAAM,KAAK;AAClC,aAAO,IAAI,aAAa,KAAK,WAAW;AAAA,IAC1C;AAAA,IACA,IAAI,QAAQ;AACV,aAAO;AAAA,IACT;AAAA,IACA,WAAW,CAAC,UAAsB,WAAW,SAAS,KAAK,KAAK,KAAK;AAAA,IACrE,kBAAkB,MAAM,WAAW,SAAS,iBAAiB,KAAK;AAAA,IAClE,mBAAmB,MAAM,WAAW,SAAS,kBAAkB,KAAK;AAAA,IACpE,oBAAoB,MAAM,WAAW,SAAS,mBAAmB,KAAK;AAAA,EACxE,EAAE;AAYF,QAAM,oBAAgB;AAAA,IACpB,MAAM,eAAe,OAAO,SAAS,OAAO,OAAO,SAAS,OAAO,KAAK;AAAA,IACxE,CAAC,OAAO,SAAS,OAAO,OAAO,SAAS,OAAO,KAAK;AAAA,EACtD;AAEA,QAAM,eAAW,sBAAiB,EAAE,UAAU,CAAC,GAAG,GAAG,CAAC,GAAG,UAAU,CAAC,GAAG,GAAG,CAAC,EAAE,CAAC;AAE9E,8BAAS,CAAC,EAAE,MAAM,GAAG,UAAU;AAC7B,UAAM,MAAM,WAAW;AAEvB,UAAM,MAAM,UAAU,IAAI,IAAI,SAAS,aAAa,MAAM,WAAW,IAAI,MAAM;AAI/E,UAAM,uBAAuB,QAAQ,UAAU,aAAa,IAAI,QAAQ;AACxE,SAAK,MAAM,aAAa,yBAAyB,SAAS,SAAS;AACjE,YAAM,OAAO,SAAS;AACtB,WAAK,SAAS,CAAC,IAAI,KAAK,SAAS,CAAC,IAAI,KAAK,SAAS,CAAC,IAAI;AACzD,WAAK,SAAS,CAAC,IAAI,KAAK,SAAS,CAAC,IAAI,KAAK,SAAS,CAAC,IAAI;AACzD,YAAM,YAAY,KAAK,IAAI;AAC3B,UAAI,sBAAsB;AACxB,cAAM,IAAI,iBAAiB,GAAG;AAC9B,YAAI,EAAG,UAAU,UAAW,GAAG,KAAK,MAAM,IAAI,KAAK;AAAA,MACrD;AACA,YAAM,OAAO,MAAM,YAAY,CAAC,GAAG,GAAG,CAAC;AACvC,YAAM,UAAU;AAChB,eAAS,QAAQ,SAAS;AAAA,QACxB,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC;AAAA,QACzB,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC;AAAA,QACzB,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC;AAAA,MAC3B;AACA,eAAS,QAAQ,SAAS;AAAA,QACxB,QAAQ,CAAC,IAAI,KAAK,SAAS,CAAC;AAAA,QAC5B,QAAQ,CAAC,IAAI,KAAK,SAAS,CAAC;AAAA,QAC5B,QAAQ,CAAC,IAAI,KAAK,SAAS,CAAC;AAAA,MAC9B;AAAA,IACF;AAGA,QAAI,WAAW,UAAU;AACvB,YAAM,QAAQ,IAAI;AAClB,eAAS,UAAU;AAAA,QACjB,QAAQ,MAAM;AAAA,QACd,WAAW,MAAM;AAAA,QACjB,MAAM,MAAM;AAAA,QACZ,MAAM,MAAM;AAAA,QACZ,QAAQ,MAAM;AAAA,QACd,WAAW,MAAM;AAAA,QACjB,MAAM,MAAM;AAAA,QACZ,SAAS,MAAM;AAAA,QACf,OAAO,MAAM;AAAA,QACb,SAAS,MAAM;AAAA,MACjB,CAAC;AACD,eAAS,KAAK,KAAK;AACnB,UAAI,CAAC,SAAS,QAAQ;AACpB,cAAM,WAAW,SAAS,WAAW;AACrC,iBAAS,UAAU,SAAS,KAAqB;AACjD,iBAAS,cAAc;AAGvB,4BAAoB,QAAQ;AAC5B,iBAAS,sBAAsB;AAAA,MACjC;AACA;AAAA,IACF;AAgBA,UAAM,aAAa,CAAC,MAAoB,UAA4B;AAClE,YAAM,WAAW,CAAC,WAAW;AAC7B,YAAM,UAAU,CAAC,WAAW,QAAQ,IAAI,YAAY,UAAU,IAAI;AAGlE,YAAM,mBAAmB,QAAQ,WAAW,SAAS,aAAa;AAClE,UAAI,CAAC,SAAS,CAAC,SAAS,WAAW,CAAC,WAAW,CAAC,YAAY,CAAC,iBAAkB,QAAO;AAEtF,YAAM,MAAM,WAAW,KAAK,aAAa,SAAS,UAAU,GAAG;AAI/D,YAAM,YAAY,IAAI,OAAO,OAAO,MAAM;AAO1C,UAAI,OAAO,QAAQ,QAAQ,KAAK,SAAS,EAAG,OAAM,WAAW,QAAQ,OAAO;AAE5E,YAAM,QAAQ,WAAW,KAAK,KAAK,QAAQ,OAAO;AAClD,UAAI,CAAC,MAAO,QAAO;AACnB,eAAS,UAAU;AAEnB,YAAM,MAAM,EAAE,GAAG,KAAK,OAAO,IAAI,MAAM;AACvC,yBAAmB,UAAU,MAAM,OAAO,GAAG;AAE7C,UAAI,MAAM,eAAe,UAAU,SAAS;AAC1C,cAAM,IAAI,iBAAiB,GAAG;AAC9B,iBAAS,QAAQ,QAAQ,CAAC,GAAG,MAAM;AACjC,gBAAM,OAAO,WAAW,QAAQ,CAAC;AACjC,cAAI,CAAC,QAAQ,CAAC,EAAG;AACjB,gBAAM,CAAC,GAAGA,EAAC,IAAI,EAAE,OAAO,GAAG,IAAI,KAAK;AACpC,wBAAc,KAAK,IAAI,OAAO,IAAI,MAAM,QAAQA,KAAI,OAAO,IAAI,MAAM,QAAQ,CAAC;AAC9E,wBAAc,eAAe,GAAGA,IAAG,OAAO,GAAG;AAC7C,eAAK,SAAS,KAAK,aAAa;AAAA,QAClC,CAAC;AAAA,MACH;AACA,aAAO;AAAA,IACT;AAGA,QAAI,WAAW,KAAK;AAClB,YAAM,QAAQ,IAAI;AAClB,UAAI,UAAU;AAAA,QACZ,MAAM,MAAM;AAAA,QACZ,SAAS,MAAM;AAAA,QACf,WAAW,MAAM;AAAA,QACjB,OAAO,MAAM;AAAA,MACf,CAAC;AAGD,gBAAU,OAAO,MAAM,MAAM;AAC7B,UAAI,KAAK,KAAK;AACd,YAAM,QAAQ,CAAC,IAAI;AACnB,UAAI,MAAO,WAAU,OAAO;AAK5B,UAAI,CAAC,WAAW,IAAI,WAAW,KAAK,KAAK,OAAO;AAC9C,cAAM,WAAW,SAAS,WAAW;AACpC,QAAC,SAAS,MAAuB,IAAI,IAAI,SAAS;AACnD,iBAAS,cAAc;AACvB,4BAAoB,QAAQ;AAAA,MAC9B;AACA;AAAA,IACF;AAGA,eAAW,eAAe,KAAK;AAAA,EACjC,CAAC;AAED,QAAM,iBAAiB,CAACC,OAAiE;AACvF,UAAM,QAAQ,SAAS;AACvB,QAAI,CAAC,MAAO,QAAO;AACnB,gBAAY,IAAI,GAAG,GAAG,CAAC,EAAE,gBAAgB,MAAM,mBAAmB,WAAW,CAAC;AAC9E,cAAU,8BAA8B,aAAa,MAAM,iBAAiB,SAAS,CAAC;AACtF,UAAM,MAAMA,GAAE,IAAI,eAAe,WAAW,SAAS;AACrD,QAAI,CAAC,IAAK,QAAO;AACjB,UAAM,aAAa,GAAG;AACtB,WAAO,EAAE,GAAG,IAAI,GAAG,GAAG,IAAI,EAAE;AAAA,EAC9B;AAEA,QAAM,eAAe,CAACA,OAAgC;AACpD,QAAI,CAAC,UAAU,WAAW,CAAC,YAAY,QAAS;AAChD,UAAM,aAAa,SAAS,QAAQ,KAAK,CAAC,MAAM,EAAE,OAAO,YAAY,OAAO;AAC5E,UAAM,QAAQ,eAAeA,EAAC;AAC9B,UAAM,IAAI,iBAAiB,CAAC;AAC5B,QAAI,CAAC,cAAc,CAAC,SAAS,CAAC,EAAG;AACjC,WAAO,OAAO,aAAa,SAAS,WAAW,KAAK,OAAO,GAAG,UAAU,QAAQ,KAAK,CAAC;AACtF,aAAS,UAAU;AACnB,UAAMJ,KAAI,aAAa,QAAQ,SAAS,aAAa;AACrD,QAAI,OAAOA,OAAM,SAAU,OAAM,aAAaA,EAAC;AAAA,EACjD;AAKA,QAAM,iBAAa,sBAAO,IAAU,eAAQ,CAAC;AAW7C,QAAM,iBAAa,sBAAO,IAAU,eAAQ,CAAC;AAC7C,QAAM,YAAY,CAACI,OAAgC;AACjD,QAAI,CAAC,WAAW,CAAC,OAAO,CAAC,MAAM,eAAe,CAAC,SAAS,QAAS;AACjE,IAAAA,GAAE,gBAAgB;AAClB,QAAI,SAAU,UAAS,UAAU;AACjC,eAAW,QAAQ,KAAKA,GAAE,KAAK;AAC/B,UAAM,QAAQ,SAAS,QAAQ,aAAa,aAAa,KAAKA,GAAE,KAAK,CAAC;AAGtE,UAAM,QAAQ,SAAS,WAAW,SAAU;AAC5C,UAAM,QAAQ,cAAc,OAAO,IAAI,OAAO,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AACvE,QAAI,KAAK,KAAK;AACd,UAAM,KAAK,QAAQ;AACnB,eAAW,QAAQ;AAAA,MACjB,MAAM,EAAE,IAAK,IAAI,UAAU,EAAE;AAAA,MAC7B,MAAM,KAAK,CAAC,IAAK,IAAI,UAAU,KAAK,CAAC;AAAA,MACrC,MAAM,KAAK,CAAC,IAAK,IAAI,UAAU,KAAK,CAAC;AAAA,IACvC;AACA,gBAAY,UAAU;AACrB,IAACA,GAAE,OAAmB,kBAAkBA,GAAE,SAAS;AAAA,EACtD;AACA,QAAM,YAAY,CAACA,OAAgC;AACjD,QAAI,YAAY,YAAY,WAAW,CAAC,OAAO,CAAC,SAAS,QAAS;AAClE,WAAO,kBAAkB,WAAW;AACpC,cAAU,8BAA8B,aAAa,WAAW,OAAO;AACvE,UAAM,MAAMA,GAAE,IAAI,eAAe,WAAW,SAAS;AACrD,QAAI,CAAC,IAAK;AACV,aAAS,QAAQ,aAAa,GAAG;AACjC,UAAM,SAAS,WAAW;AAC1B,QAAI,SAAS,IAAI,IAAI,OAAO,GAAG,IAAI,IAAI,OAAO,GAAG,IAAI,IAAI,OAAO,CAAC;AAAA,EACnE;AACA,QAAM,UAAU,CAACA,OAAgC;AAC/C,QAAI,YAAY,YAAY,WAAW,CAAC,IAAK;AAC7C,gBAAY,UAAU;AACtB,QAAI,SAAU,UAAS,UAAU;AACjC,QAAI,QAAQ;AACX,IAACA,GAAE,OAAmB,sBAAsBA,GAAE,SAAS;AAAA,EAC1D;AAcA,QAAM,YAAY,CAACA,OAAgC;AACjD,QAAI,CAAC,WAAW,CAAC,YAAY,CAAC,MAAM,eAAe,CAAC,SAAS,QAAS;AACtE,IAAAA,GAAE,gBAAgB;AAClB,UAAM,QAAQ,SAAS,QAAQ,aAAa,aAAa,KAAKA,GAAE,KAAK,CAAC;AAMtE,QAAI,SAAS,YAAY,MAAM,GAAG,MAAM,CAAC,IAAI,EAAG;AAChD,QAAI,SAAU,UAAS,UAAU;AACjC,eAAW,QAAQ,KAAKA,GAAE,KAAK;AAC/B,gBAAY,UAAU;AACrB,IAACA,GAAE,OAAmB,kBAAkBA,GAAE,SAAS;AAAA,EACtD;AACA,QAAM,YAAY,CAACA,OAAgC;AACjD,QAAI,YAAY,YAAY,WAAW,CAAC,YAAY,CAAC,SAAS,QAAS;AACvE,WAAO,kBAAkB,WAAW;AACpC,cAAU,8BAA8B,aAAa,WAAW,OAAO;AACvE,UAAM,MAAMA,GAAE,IAAI,eAAe,WAAW,SAAS;AACrD,QAAI,CAAC,IAAK;AACV,aAAS,QAAQ,aAAa,GAAG;AACjC,aAAS,SAAS,IAAI,GAAG,IAAI,CAAC;AAAA,EAChC;AACA,QAAM,UAAU,CAACA,OAAgC;AAC/C,QAAI,YAAY,YAAY,WAAW,CAAC,SAAU;AAClD,gBAAY,UAAU;AACtB,QAAI,SAAU,UAAS,UAAU;AACjC,aAAS,QAAQ;AAChB,IAACA,GAAE,OAAmB,sBAAsBA,GAAE,SAAS;AAAA,EAC1D;AAIA,QAAM,YAAY,CAAC,UAAsB,WAAW,SAAS,KAAK,KAAK;AAEvE,SACE,8CAAC,WAAM,KAAK,UAAU,UAAU,MAAM,UAAU,UAAU,cACxD;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,KAAK;AAAA,QACL;AAAA,QACA,YAAU;AAAA,QACV,eAAa;AAAA,QACb,eAAe;AAAA,QACf,eAAe,aAAa,MAAM,UAAU,OAAO,IAAI;AAAA,QACvD,cAAc,aAAa,MAAM,UAAU,OAAO,IAAI;AAAA,QACtD,eACE,WAAW,WAAW,aAClB,CAACA,OAAM;AACL,cAAI,QAAS,WAAUA,EAAC;AACxB,cAAI,QAAS,WAAUA,EAAC;AACxB,cAAI,WAAY,WAAU,MAAM;AAAA,QAClC,IACA;AAAA,QAEN,eAAe,UAAU,YAAY,UAAU,YAAY;AAAA,QAC3D,aACE,WAAW,WAAW,aAClB,CAACA,OAAM;AACL,cAAI,QAAS,SAAQA,EAAC;AACtB,cAAI,QAAS,SAAQA,EAAC;AACtB,cAAI,WAAY,WAAU,IAAI;AAAA,QAChC,IACA;AAAA,QAGN;AAAA,UAAC;AAAA;AAAA,YACC;AAAA,YACA;AAAA,YACA;AAAA,YACA,SAAS,OAAO;AAAA,YAChB,WAAW,OAAO,MAAM;AAAA,YACxB,OAAO,OAAO;AAAA,YACd,UAAU,OAAO,MAAM;AAAA,YACvB,SAAS;AAAA,YACT,QAAQ,MAAM;AAAA;AAAA,QAChB;AAAA;AAAA,IACF;AAAA,IACC,MAAM;AAAA;AAAA;AAAA;AAAA,IAKL,CAAC,WACD,UAAU,SAAS,IAAI,CAAC,GAAG,MACzB;AAAA,MAAC;AAAA;AAAA,QAOC,UAAU,EAAE,gBAAgB,KAAK;AAAA,QACjC,KAAK,CAAC,MAAM;AACV,qBAAW,QAAQ,CAAC,IAAI;AAAA,QAC1B;AAAA,QACA,eAAe,CAACA,OAAM;AACpB,UAAAA,GAAE,gBAAgB;AAClB,sBAAY,UAAU,EAAE;AACxB,gBAAM;AACN,cAAI,SAAU,UAAS,UAAU;AAChC,UAACA,GAAE,OAAmB,kBAAkBA,GAAE,SAAS;AAAA,QACtD;AAAA,QACA,eAAe;AAAA,QACf,aAAa,CAACA,OAAM;AAClB,cAAI,CAAC,YAAY,QAAS;AAC1B,sBAAY,UAAU;AACtB,cAAI,SAAU,UAAS,UAAU;AAChC,UAACA,GAAE,OAAmB,sBAAsBA,GAAE,SAAS;AACxD,gBAAM,mBAAmB,EAAE,GAAG,aAAa,QAAQ,CAAC;AAAA,QACtD;AAAA,QAEA;AAAA,uDAAC,oBAAe,MAAM,CAAC,OAAO,IAAI,EAAE,GAAG;AAAA,UACvC,6CAAC,uBAAkB,OAAM,WAAU,WAAW,OAAO,aAAW,MAAC,SAAS,KAAK;AAAA;AAAA;AAAA,MA3B1E,EAAE;AAAA,IA4BT,CACD;AAAA,KACL;AAEJ,CAAC;AAUD,SAAS,WACP,OACA,QACA,UAA0B,OAAO,OAAO,SACb;AAK3B,MAAI,cAAc,OAAO,OAAO,EAAG,QAAO;AAC1C,QAAM,MAAM,YAAY,SAAS,CAAC,GAAG,OAAO;AAG5C,SAAO,IAAI,SAAS,IAAI,MAAM;AAChC;AAQA,SAAS,cAAc,OAAqB,OAAeH,IAAWC,IAAWG,KAAmB;AAClG,MAAI,OAAO;AACX,MAAI,WAAW;AACf,WAAS,IAAI,GAAG,IAAI,OAAO,KAAK;AAC9B,UAAM,KAAK,IAAI;AACf,UAAM,KAAK,MAAM,EAAE,IAAKJ;AACxB,UAAM,KAAK,MAAM,KAAK,CAAC,IAAKC;AAC5B,UAAM,KAAK,MAAM,KAAK,CAAC,IAAKG;AAC5B,UAAM,IAAI,KAAK,KAAK,KAAK,KAAK,KAAK;AACnC,QAAI,IAAI,UAAU;AAChB,iBAAW;AACX,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAGA,SAAS,cAAc,SAA0C;AAC/D,SAAO,OAAO,YAAY,YAAY,QAAQ,SAAS;AACzD;AAGA,SAAS,WACP,QACA,WACA,UACA,IAAI,GACuB;AAG3B,MAAI,cAAc,OAAO,OAAO,EAAG,QAAO;AAC1C,QAAM,OACJ,OAAO,OAAO,YAAY,YAAY,OAAO,YAAY,SACrD,cAAc,OAAO,OAAmB,IACxC;AACN,QAAM,YAAY,MAAM,QAAQ,KAAK,CAAC;AAEtC,MAAI,aAAiC,CAAC;AACtC,MAAI,OAAO,WAAW;AAEpB,iBAAa,qBAAqB,OAAO,SAAS;AAAA,EACpD,WAAW,OAAO,UAAU;AAC1B,UAAMC,KAAI,YAAY,YAAY,OAAO,SAAS,IAAI;AACtD,QAAI,UAAmC,EAAE,GAAG,OAAO,UAAU,GAAG,UAAU;AAC1E,QAAIA,GAAE,KAAM,WAAU,EAAE,GAAG,SAAS,GAAGA,GAAE,KAAK,SAAS,CAAC,EAAE;AAC1D,iBAAaA,GAAE,MAAM,SAAS,OAAO,KAAK;AAAA,EAC5C;AAEA,QAAM,WAAW,CAAC,GAAG,YAAY,GAAG,SAAS;AAC7C,SAAO,SAAS,SAAS,IAAI,WAAW;AAC1C;;;AgEvlCA,IAAAC,UAAuB;AACvB,IAAAC,gBAA2C;AAC3C,IAAAC,gBAAmC;AACnC,kBAA+B;;;ACH/B,IAAAC,SAAuB;;;AC6BvB,IAAI;AAEJ,SAAS,eAAgD;AACvD,MAAI,UAAU,OAAW,QAAO;AAChC,UAAQ,OAAO,aAAa,cAAc,OAAO,SAAS,cAAc,QAAQ,EAAE,WAAW,IAAI;AACjG,SAAO;AACT;AAWO,SAAS,WAAW,OAAe,UAA0B;AAClE,QAAM,MAAM,aAAa;AAGzB,MAAI,CAAC,IAAK,QAAO;AACjB,QAAM,WAAW,IAAI;AACrB,MAAI,YAAY;AAChB,MAAI,YAAY;AAChB,QAAM,YAAY,IAAI;AACtB,MAAI,YAAY;AAChB,MAAI,YAAY;AAChB,QAAM,YAAY,IAAI;AACtB,MAAI,YAAY;AAChB,SAAO,cAAc,YAAY,QAAQ;AAC3C;;;ADvCA,IAAM,QAAQ;AACd,IAAM,SAAS;AASR,SAAS,KAAK,YAA4B;AAC/C,QAAM,IAAI,OAAO,aAAa;AAC9B,UAAS,IAAI,IAAK,KAAK;AACzB;AAGO,SAAS,KAAK,cAA8B;AACjD,SAAO,MAAM,eAAe;AAC9B;AAOO,SAAS,QAAQ,KAA+B,QAA8B;AAGnF,QAAM,SAAS,WAAW,OAAO,IAAI,QAAQ,SAAS;AACtD,QAAM,UAAU,WAAW,OAAO,IAAI,SAAS,SAAS;AACxD,QAAM,SAAS,WAAW,OAAO,IAAI,QAAQ,SAAS;AACtD,QAAM,QAAQ,IAAI,qBAAqB,GAAG,GAAG,GAAG,MAAM;AACtD,QAAM,aAAa,GAAG,MAAM;AAC5B,QAAM,aAAa,MAAM,MAAM;AAC/B,QAAM,aAAa,KAAK,OAAO;AAC/B,QAAM,aAAa,MAAM,OAAO;AAChC,QAAM,aAAa,GAAG,MAAM;AAC5B,MAAI,YAAY;AAChB,MAAI,SAAS,GAAG,GAAG,OAAO,MAAM;AAKhC,QAAM,SAAS,YAAY,OAAO,IAAI,QAAQ;AAC9C,QAAMC,KAAI,KAAK,OAAO,OAAO,IAAI;AACjC,QAAMC,KAAI,KAAK,OAAO,SAAS,IAAI;AACnC,QAAM,SAAS,QAAQ;AACvB,QAAM,QAAQ,IAAU,aAAM,OAAO,IAAI,KAAK;AAG9C,QAAM,WAAW,KAAK,IAAI,GAAG,OAAO,IAAI,YAAY,CAAC;AAIrD,aAAW,UAAU,CAAC,CAAC,OAAO,GAAG,KAAK,GAAG;AACvC,UAAM,OAAO,IAAI,qBAAqBD,KAAI,QAAQC,IAAG,GAAGD,KAAI,QAAQC,IAAG,MAAM;AAC7E,SAAK;AAAA,MACH;AAAA,MACA,QAAS,MAAM,IAAI,MAAO,CAAC,KAAM,MAAM,IAAI,MAAO,CAAC,KAAM,MAAM,IAAI,MAAO,CAAC,KAAK,QAAQ;AAAA,IAC1F;AACA,SAAK,aAAa,GAAG,QAAS,MAAM,IAAI,MAAO,CAAC,KAAM,MAAM,IAAI,MAAO,CAAC,KAAM,MAAM,IAAI,MAAO,CAAC,MAAM;AACtG,QAAI,YAAY;AAChB,QAAI,SAASD,KAAI,SAAS,QAAQC,KAAI,QAAQ,SAAS,GAAG,SAAS,CAAC;AAAA,EACtE;AACF;AAGO,SAAS,gBAAgB,QAA6C;AAC3E,QAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,SAAO,QAAQ;AACf,SAAO,SAAS;AAChB,QAAM,MAAM,OAAO,WAAW,IAAI;AAClC,UAAQ,KAAK,MAAM;AACnB,QAAM,UAAU,IAAU,qBAAc,MAAM;AAC9C,UAAQ,UAAgB;AACxB,UAAQ,aAAmB;AAC3B,SAAO;AACT;AASO,SAAS,iBACd,UACA,QAC6C;AAC7C,QAAM,WAAW,gBAAgB,MAAM;AACvC,QAAM,QAAQ,IAAU,sBAAe,QAAQ;AAC/C,QAAM,SAAS,MAAM,oBAAoB,QAAQ;AACjD,QAAM,QAAQ;AACd,WAAS,QAAQ;AACjB,SAAO;AAAA,IACL,SAAS,OAAO;AAAA,IAChB,SAAS,MAAM,OAAO,QAAQ;AAAA,EAChC;AACF;;;ADkHI,IAAAC,sBAAA;AAzNJ,IAAM,eAAoD;AAAA,EACxD,KAAW;AAAA,EACX,SAAe;AAAA,EACf,QAAc;AAChB;AAGA,SAASC,YAAW,MAAc;AAChC,MAAI,IAAI;AACR,SAAO,MAAM;AACX,SAAK;AACL,QAAK,IAAI,aAAc;AACvB,QAAI,IAAI,KAAK,KAAK,IAAK,MAAM,IAAK,IAAI,CAAC;AACvC,QAAK,IAAI,KAAK,KAAK,IAAK,MAAM,GAAI,KAAK,CAAC,IAAK;AAC7C,aAAS,IAAK,MAAM,QAAS,KAAK;AAAA,EACpC;AACF;AAMO,SAAS,gBAAgB,MAAgD;AAC9E,QAAM,OAAO;AACb,QAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,SAAO,QAAQ,OAAO,SAAS;AAC/B,QAAM,MAAM,OAAO,WAAW,IAAI;AAClC,MAAI,YAAY;AAChB,MAAI,SAAS,GAAG,GAAG,MAAM,IAAI;AAE7B,MAAI,SAAS,UAAU;AAErB,QAAI,KAAK;AACT,QAAI,UAAU,OAAO,GAAG,OAAO,CAAC;AAChC,QAAI,OAAO,KAAK;AAChB,UAAM,OAAO;AACb,UAAM,MAAM;AACZ,aAASC,KAAI,CAAC,MAAMA,KAAI,MAAMA,MAAK,OAAO,KAAK;AAC7C,YAAM,OAAO,IAAI,qBAAqB,GAAGA,IAAG,GAAGA,KAAI,IAAI;AACvD,WAAK,aAAa,GAAG,kBAAkB;AACvC,WAAK,aAAa,MAAM,qBAAqB;AAC7C,WAAK,aAAa,MAAM,qBAAqB;AAC7C,WAAK,aAAa,GAAG,kBAAkB;AACvC,UAAI,YAAY;AAChB,UAAI,SAAS,CAAC,MAAMA,IAAG,OAAO,GAAG,IAAI;AAAA,IACvC;AACA,QAAI,QAAQ;AAAA,EACd,OAAO;AAEL,UAAM,OAAOD,YAAW,CAAC;AACzB,eAAW,CAAC,OAAO,QAAQ,KAAK,KAAK;AAAA,MACnC,CAAC,IAAI,IAAI,IAAI;AAAA,MACb,CAAC,IAAI,IAAI,GAAG;AAAA,MACZ,CAAC,IAAI,IAAI,GAAG;AAAA,IACd,GAAY;AACV,eAAS,IAAI,GAAG,IAAI,OAAO,KAAK;AAC9B,cAAME,KAAI,KAAK,IAAI;AACnB,cAAMD,KAAI,KAAK,IAAI;AACnB,cAAME,KAAI,UAAU,MAAM,KAAK,IAAI;AACnC,cAAM,OAAO,IAAI,qBAAqBD,IAAGD,IAAG,GAAGC,IAAGD,IAAGE,EAAC;AACtD,aAAK,aAAa,GAAG,iBAAiB,KAAK,GAAG;AAC9C,aAAK,aAAa,KAAK,iBAAiB,QAAQ,IAAI,GAAG;AACvD,aAAK,aAAa,GAAG,kBAAkB;AACvC,YAAI,YAAY;AAChB,YAAI,UAAU;AACd,YAAI,QAAQD,IAAGD,IAAGE,IAAGA,MAAK,MAAM,KAAK,IAAI,MAAM,KAAK,IAAI,KAAK,IAAI,GAAG,KAAK,KAAK,CAAC;AAC/E,YAAI,KAAK;AAAA,MACX;AAAA,IACF;AAAA,EACF;AAEA,QAAM,UAAU,IAAU,sBAAc,MAAM;AAC9C,UAAQ,QAAQ,QAAQ,QAAc;AACtC,SAAO;AACT;AAUA,SAAS,YAAY,EAAE,IAAI,GAA4B;AACrD,QAAM,SAAK,wBAAS,CAAC,MAAM,EAAE,EAAE;AAC/B,QAAM,YAAQ,wBAAS,CAAC,MAAM,EAAE,KAAK;AAIrC,QAAM,MAAM,GAAG,IAAI,IAAI,MAAM,IAAI,IAAI,IAAI,OAAO,IAAI,IAAI,IAAI,MAAM,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,SAAS,IAAI,IAAI,IAAI,SAAS,KAAK,CAAC;AAGnI,+BAAU,MAAM;AACd,UAAM,cAAc,iBAAiB,IAAI,GAAG;AAC5C,UAAM,WAAW,MAAM;AACvB,UAAM,cAAc,YAAY;AAChC,WAAO,MAAM;AACX,YAAM,cAAc;AACpB,kBAAY,QAAQ;AAAA,IACtB;AAAA,EACF,GAAG,CAAC,IAAI,OAAO,GAAG,CAAC;AAEnB,+BAAU,MAAM;AACd,UAAM,WAAW,MAAM;AACvB,UAAM,uBAAuB,IAAI;AACjC,WAAO,MAAM;AACX,YAAM,uBAAuB;AAAA,IAC/B;AAAA,EACF,GAAG,CAAC,OAAO,IAAI,MAAM,CAAC;AAEtB,SAAO;AACT;AAQA,IAAM,sBAAsB;AA6CrB,SAAS,cAAc;AAAA,EAC5B,SAAS;AAAA,EACT;AAAA,EACA;AAAA,EACA,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR;AAAA,EACA;AAAA,EACA,gBAAgB;AAAA,EAChB,cAAc;AAChB,GAAuB;AACrB,QAAMC,SAAI,uBAAQ,MAAM,OAAO,gBAAgB,QAAQ,KAAK,GAAG,CAAC,KAAK,QAAQ,KAAK,CAAC;AACnF,QAAM,UAAU,iBAAiBA,GAAE,OAAO;AAC1C,QAAM,aAAa,UAAU;AAC7B,QAAM,UAAU,wBAAwB,aAAa;AACrD,QAAM,SAAK,wBAAS,CAAC,MAAM,EAAE,EAAE;AAC/B,QAAM,YAAQ,wBAAS,CAAC,MAAM,EAAE,KAAK;AAErC,+BAAU,MAAM;AACd,UAAM,mBAAmB,GAAG;AAC5B,UAAM,eAAe,GAAG;AACxB,OAAG,sBAAsBA,GAAE;AAC3B,OAAG,cAAc,aAAaA,GAAE,IAAI;AACpC,WAAO,MAAM;AACX,SAAG,sBAAsB;AACzB,SAAG,cAAc;AAAA,IACnB;AAAA,EACF,GAAG,CAAC,IAAIA,GAAE,UAAUA,GAAE,IAAI,CAAC;AAI3B,+BAAU,MAAM;AACd,QAAI,CAACA,GAAE,IAAK;AACZ,UAAM,WAAW,MAAM;AACvB,UAAM,MAAM,IAAU,YAAIA,GAAE,IAAI,OAAOA,GAAE,IAAI,MAAMA,GAAE,IAAI,GAAG;AAC5D,WAAO,MAAM;AACX,YAAM,MAAM;AAAA,IACd;AAAA,EACF,GAAG,CAAC,OAAOA,GAAE,GAAG,CAAC;AAGjB,QAAM,cAAU,uBAAQ,MAAOA,GAAE,OAAO,gBAAgBA,GAAE,KAAK,IAAI,IAAI,MAAO,CAACA,GAAE,MAAM,IAAI,CAAC;AAC5F,+BAAU,MAAM,MAAM,SAAS,QAAQ,GAAG,CAAC,OAAO,CAAC;AAEnD,QAAM,eAAW,sBAAO,CAAC;AACzB,8BAAS,CAAC,GAAG,UAAU;AACrB,QAAI,CAAC,WAAW,CAACA,GAAE,QAAQ,QAAS;AACpC,aAAS,WAAW,QAAQA,GAAE,KAAK;AACnC,YAAQ,OAAO,IAAI,SAAS,SAAS,SAAS,UAAU,GAAG;AAAA,EAC7D,CAAC;AAED,SACE,8EACG;AAAA,IAAAA,GAAE,SAAS,MACT,cACC,6CAAC,eAAY,KAAKA,IAAG;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAOrB;AAAA,QAAC;AAAA;AAAA,UACC,OAAOA,GAAE,IAAI;AAAA,UACb,aAAaA,GAAE,IAAI;AAAA,UACnB,WAAWA,GAAE,SAAS;AAAA;AAAA,MACxB;AAAA;AAAA,IAEJ,6CAAC,kBAAa,WAAWA,GAAE,SAAS;AAAA,IACnCA,GAAE,QAAQ,UACT;AAAA,MAAC;AAAA;AAAA,QACC,UAAUA,GAAE,IAAI;AAAA,QAChB,OAAOA,GAAE,IAAI;AAAA,QAEb,WAAWA,GAAE,IAAI,YAAY;AAAA,QAC7B,OAAOA,GAAE,KAAK;AAAA,QACd,UAAU;AAAA,QACV,OAAO;AAAA,QACP;AAAA,QACA,KAAK;AAAA,QACL,kBAAgB,CAAC,WAAW,GAAG,WAAW,CAAC;AAAA,QAC3C,iBAAeA,GAAE,OAAO;AAAA,QACxB,qBAAmB;AAAA;AAAA,IACrB,IAEA;AAAA,MAAC;AAAA;AAAA,QACC,UAAUA,GAAE,IAAI;AAAA,QAChB,OAAOA,GAAE,IAAI;AAAA,QACb,WAAWA,GAAE,IAAI;AAAA,QACjB;AAAA,QACA,kBAAgB,CAAC,WAAW,GAAG,WAAW,CAAC;AAAA,QAC3C,iBAAeA,GAAE,OAAO;AAAA,QACxB,qBAAmB;AAAA;AAAA,IACrB;AAAA,IAED,iBACC;AAAA,MAAC;AAAA;AAAA,QACC,UAAU,CAAC,GAAG,OAAO,CAAC;AAAA,QACtB,SAASA,GAAE;AAAA,QACX;AAAA,QACA,MAAMA,GAAE;AAAA,QACR,KAAK;AAAA;AAAA,IACP;AAAA,KAEJ;AAEJ;;;AGhSA,IAAAC,UAAuB;AACvB,IAAAC,iBAAoC;AACpC,IAAAC,gBAAyB;AAoBlB,SAAS,cAAc,EAAE,SAAS,GAAkC;AACzE,QAAM,YAAQ,wBAAS,CAAC,MAAM,EAAE,KAAK;AACrC,QAAM,WAAO,wBAAS,CAAC,MAAM,EAAE,IAAI;AACnC,QAAM,CAAC,OAAO,QAAQ,QAAI,yBAAkC,IAAI;AAEhE,QAAM,MAAM,UAAU,SAAS;AAE/B,gCAAU,MAAM;AACd,QAAI,CAAC,KAAK;AACR,eAAS,IAAI;AACb;AAAA,IACF;AACA,QAAI,OAAO;AACX,UAAM,MAAM,IAAI,MAAM;AACtB,QAAI,cAAc;AAGlB,QAAI,SAAS,MAAM,QAAQ,SAAS,GAAG;AACvC,QAAI,UAAU,MAAM,QAAQ,SAAS,IAAI;AACzC,QAAI,MAAM;AACV,WAAO,MAAM;AACX,aAAO;AAAA,IACT;AAAA,EACF,GAAG,CAAC,GAAG,CAAC;AAER,QAAM,MAAM,KAAK,UAAU,EAAE,UAAU,YAAY,MAAM,GAAG,KAAK,OAAO,GAAG,KAAK,QAAQ,QAAQ,CAAC,CAAC,MAAM,CAAC;AAGzG,gCAAU,MAAM;AACd,QAAI,CAAC,SAAU;AACf,UAAM,WAAW,MAAM;AACvB,UAAM,UAAU,cAAc,UAAU,KAAK,OAAO,KAAK,QAAQ,KAAK;AACtE,UAAM,aAAa;AACnB,WAAO,MAAM;AACX,YAAM,aAAa;AACnB,cAAQ,QAAQ;AAAA,IAClB;AAAA,EACF,GAAG,CAAC,GAAG,CAAC;AAER,SAAO;AACT;AAGO,SAAS,cACd,UACA,OACA,QACA,OACqB;AAGrB,QAAMC,KAAI,KAAK,IAAI,GAAG,KAAK,MAAM,QAAQ,CAAC,CAAC;AAC3C,QAAM,IAAI,KAAK,IAAI,GAAG,KAAK,MAAM,SAAS,CAAC,CAAC;AAC5C,QAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,SAAO,QAAQA;AACf,SAAO,SAAS;AAChB,QAAM,MAAM,OAAO,WAAW,IAAI;AAElC,MAAI,YAAY,SAAS;AACzB,MAAI,SAAS,GAAG,GAAGA,IAAG,CAAC;AAEvB,MAAI,SAAS,MAAM,QAAQ,KAAK,MAAM,SAAS,GAAG;AAChD,UAAM,QACJ,SAAS,QAAQ,UACb,KAAK,IAAIA,KAAI,MAAM,OAAO,IAAI,MAAM,MAAM,IAC1C,KAAK,IAAIA,KAAI,MAAM,OAAO,IAAI,MAAM,MAAM;AAChD,UAAM,KAAK,MAAM,QAAQ;AACzB,UAAM,KAAK,MAAM,SAAS;AAC1B,QAAI,KAAK;AAIT,QAAI,SAAS,OAAO,EAAG,KAAI,SAAS,QAAQ,SAAS,OAAO,KAAK,IAAIA,IAAG,CAAC,IAAI,IAAI;AACjF,QAAI,UAAU,QAAQA,KAAI,MAAM,IAAI,IAAI,MAAM,GAAG,IAAI,EAAE;AACvD,QAAI,QAAQ;AACZ,QAAI,SAAS,OAAO,GAAG;AACrB,UAAI,cAAc,SAAS;AAC3B,UAAI,YAAY,SAAS;AACzB,UAAI,SAAS,GAAG,GAAGA,IAAG,CAAC;AACvB,UAAI,cAAc;AAAA,IACpB;AAAA,EACF;AAEA,QAAM,UAAU,IAAU,sBAAc,MAAM;AAC9C,UAAQ,aAAmB;AAC3B,SAAO;AACT;;;AC5GA,IAAAC,gBAAyB;AACzB,IAAAC,iBAA0B;AAwBnB,SAAS,0BAA0B;AACxC,QAAM,SAAK,wBAAS,CAAC,MAAM,EAAE,EAAE;AAC/B;AAAA,IACE,MAAM,MAAM;AAIV,SAAG,iBAAiB;AACpB,SAAG,QAAQ;AAAA,IACb;AAAA,IACA,CAAC,EAAE;AAAA,EACL;AACA,SAAO;AACT;;;ArEFQ,IAAAC,sBAAA;AAZD,IAAM,YAAQ,2BAAoC,SAASC,OAChE,EAAE,UAAU,WAAW,OAAO,GAAG,UAAU,GAC3C,KACA;AAGA,QAAM,SAAS,kBAAkB,SAAS;AAC1C,QAAM,YAAQ,wBAAQ,MAAO,OAAO,WAAW,cAAc,OAAO,cAAc,GAAI,CAAC,CAAC;AAExF,SACE,8CAAC,SAAI,WAAsB,OAAO,EAAE,OAAO,QAAQ,QAAQ,QAAQ,GAAG,MAAM,GACzE;AAAA,YACC,8CAAC,wBAAO,SAAO,MAAC,QAAQ,EAAE,UAAU,CAAC,GAAG,MAAM,GAAG,GAAG,KAAK,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,GACvE;AAAA,mDAAC,iBAAc,UAAU,OAAO,MAAM,UAAU;AAAA,MAChD;AAAA,QAAC;AAAA;AAAA,UACC,QAAQ,OAAO,MAAM;AAAA,UAIrB,OAAO,OAAO,MAAM;AAAA,UACpB,OAAO;AAAA,UACP,OAAO;AAAA,UACP,eAAe,UAAU;AAAA;AAAA,MAC3B;AAAA,MACA,6CAAC,aAAU,KAAW,GAAG,WAAW;AAAA,MACnC;AAAA,MACD,6CAAC,2BAAwB;AAAA,OAC3B,IAEA,6CAAC,iBAAc,QAAgB;AAAA,IAEjC,6CAAC,eAAY,QAAgB;AAAA,KAC/B;AAEJ,CAAC;;;AsE1DD,IAAAC,UAAuB;AACvB,IAAAC,eAAqB;AACrB,IAAAC,iBAA2C;AAC3C,IAAAC,iBAAuD;;;ACHvD,IAAAC,UAAuB;AACvB,IAAAC,iBAA4F;AAmInF,IAAAC,sBAAA;AAtGF,IAAM,mBAAN,MAAuB;AAAA,EACpB,QAAQ,oBAAI,IAAuB;AAAA,EACnC,YAA2B;AAAA,EAC3B,YAAY,oBAAI,IAAgB;AAAA,EAChC,UAAU;AAAA,EAElB,SAAS,MAA6B;AACpC,SAAK,MAAM,IAAI,KAAK,IAAI,IAAI;AAC5B,SAAK,OAAO;AACZ,WAAO,MAAM;AACX,WAAK,MAAM,OAAO,KAAK,EAAE;AACzB,WAAK,OAAO;AAAA,IACd;AAAA,EACF;AAAA,EAEA,OAAoB;AAClB,WAAO,CAAC,GAAG,KAAK,MAAM,OAAO,CAAC;AAAA,EAChC;AAAA,EAEA,IAAI,IAAmC;AACrC,WAAO,KAAK,MAAM,IAAI,EAAE;AAAA,EAC1B;AAAA,EAEA,IAAI,UAAyB;AAC3B,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,WAAW,IAAyB;AAClC,QAAI,KAAK,cAAc,GAAI;AAC3B,SAAK,YAAY;AACjB,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,YAAY,CAAC,OAAiC;AAC5C,SAAK,UAAU,IAAI,EAAE;AACrB,WAAO,MAAM,KAAK,UAAU,OAAO,EAAE;AAAA,EACvC;AAAA,EAEA,aAAa,MAAc,KAAK;AAAA,EAExB,SAAe;AACrB,SAAK;AACL,eAAW,MAAM,KAAK,UAAW,IAAG;AAAA,EACtC;AACF;AAEO,IAAM,sBAAkB,8BAAuC,IAAI;AAI1E,IAAM,YAAY,oBAAI,IAAoB;AAC1C,IAAM,aAAa,CAAC,SAAyB;AAC3C,MAAI,KAAK,UAAU,IAAI,IAAI;AAC3B,MAAI,CAAC,IAAI;AACP,SAAK,IAAI,OAAO,IAAI,KAAK,QAAQ,qBAAqB,MAAM,EAAE,QAAQ,OAAO,IAAI,CAAC,KAAK,GAAG;AAC1F,cAAU,IAAI,MAAM,EAAE;AAAA,EACxB;AACA,SAAO;AACT;AAGO,SAAS,YAAY,MAAsC,MAAuB;AACvF,MAAI,CAAC,KAAK,UAAU,KAAK,OAAO,WAAW,EAAG,QAAO;AACrD,SAAO,KAAK,OAAO,KAAK,CAAC,SAAS,WAAW,IAAI,EAAE,KAAK,IAAI,CAAC;AAC/D;AAEO,IAAM,eAAe,CAAC,MAAiBC,IAAWC,OACvD,KAAK,IAAID,KAAI,KAAK,OAAO,SAAS,CAAC,CAAC,KAAK,KAAK,OAAO,KAAK,CAAC,IAAI,KAC/D,KAAK,IAAIC,KAAI,KAAK,OAAO,SAAS,CAAC,CAAC,KAAK,KAAK,OAAO,KAAK,CAAC,IAAI;AAO1D,SAAS,SAAS,OAAsB;AAC7C,QAAMC,gBAAW,2BAAW,eAAe;AAC3C,QAAM,EAAE,IAAI,QAAQ,QAAQ,YAAY,QAAQ,QAAQ,IAAI;AAQ5D,QAAM,YAAQ,uBAAO,OAAO;AAC5B,gCAAU,MAAM;AACd,UAAM,UAAU;AAAA,EAClB,GAAG,CAAC,OAAO,CAAC;AAGZ,gCAAU,MAAM;AACd,QAAI,CAACA,UAAU;AACf,WAAOA,UAAS,SAAS;AAAA,MACvB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,SAAS,CAAC,OAAO,SAAS,MAAM,UAAU,OAAO,IAAI;AAAA,IACvD,CAAC;AAAA,EACH,GAAG,CAACA,WAAU,IAAI,KAAK,UAAU,UAAU,IAAI,GAAG,KAAK,UAAU,MAAM,GAAG,SAAS,CAAC;AACpF,MAAI,CAACA,UAAU,QAAO;AACtB,SAAO,6CAAC,kBAAe,UAAUA,WAAU,QAAQ,EAAE,IAAI,QAAQ,QAAQ,UAAU,GAAG;AACxF;AAGO,SAAS,eAAe,EAAE,UAAAA,WAAU,OAAO,GAA2D;AAC3G,2CAAqBA,UAAS,WAAWA,UAAS,YAAYA,UAAS,UAAU;AACjF,QAAM,UAAUA,UAAS,YAAY,OAAO;AAC5C,QAAM,QAAQ,OAAO,aAAa;AAClC,QAAM,CAACC,IAAG,CAAC,IAAI,OAAO,OAAO;AAG7B,QAAM,YAAQ,wBAAQ,MAAM;AAC1B,UAAM,QAAQ,IAAU,sBAAcA,IAAG,CAAC;AAC1C,UAAM,MAAM,IAAU,sBAAc,KAAK;AACzC,UAAM,QAAQ;AACd,WAAO;AAAA,EACT,GAAG,CAACA,IAAG,CAAC,CAAC;AACT,gCAAU,MAAM,MAAM,MAAM,QAAQ,GAAG,CAAC,KAAK,CAAC;AAC9C,SACE,8CAAC,WAAM,UAAU,OAAO,OAAO,UAC5B;AAAA,cAAU,aACT,8CAAC,UACC;AAAA,mDAAC,mBAAc,MAAM,CAACA,IAAG,CAAC,GAAG;AAAA,MAC7B;AAAA,QAAC;AAAA;AAAA,UACC,OAAO,WAAW,UAAU,SAAS,YAAY;AAAA,UACjD,aAAW;AAAA,UACX,SAAS,WAAW,UAAU,SAAS,OAAO;AAAA,UAC9C,YAAY;AAAA;AAAA,MACd;AAAA,OACF;AAAA,IAEF,6CAAC,kBAAa,UAAU,OACtB,uDAAC,uBAAkB,OAAO,UAAU,YAAY,WAAW,GAC7D;AAAA,KACF;AAEJ;;;ACxKA,IAAAC,eAAkB;AAWX,IAAM,oBAAoB,eAAE,OAAO;AAAA,EACxC,MAAM,eAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,QAAQ,CAAC;AAAA,EAC/C,SAAS,eAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,QAAQ,CAAC;AAAA;AAAA,EAElD,QAAQ,eAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,QAAQ,IAAI;AAAA;AAAA,EAE7C,WAAW,eAAE,OAAO,EAAE,IAAI,GAAG,EAAE,IAAI,CAAC,EAAE,QAAQ,IAAI;AAAA,EAClD,YAAY,eAAE,OAAO,EAAE,IAAI,GAAG,EAAE,IAAI,CAAC,EAAE,QAAQ,IAAI;AAAA;AAAA,EAEnD,SAAS,eAAE,QAAQ,EAAE,QAAQ,IAAI;AAAA,EACjC,eAAe,eAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,QAAQ,IAAI;AACtD,CAAC;AAKM,IAAM,aAAa;AAOnB,SAAS,uBACd,QACA,YACA,WACoB;AACpB,MAAI,CAAC,UAAW,QAAO;AACvB,QAAM,OAAO,eAAe,UAAa,WAAW,cAAc;AAClE,QAAM,OAAO,eAAe,UAAa,WAAW,eAAe;AACnE,MAAI,QAAQ,KAAM,QAAO;AACzB,SAAO;AAAA,IACL,GAAG;AAAA,IACH,WAAW,OAAO,OAAO,YAAY,UAAU;AAAA,IAC/C,YAAY,OAAO,OAAO,aAAa,UAAU;AAAA,EACnD;AACF;AAEO,SAAS,YAAY,GAAW,GAAiD;AACtF,QAAM,MAAM,IAAI,EAAE;AAClB,QAAM,MAAM,KAAK,MAAM,IAAI,EAAE,OAAO;AACpC,SAAO;AAAA,IACL,IAAI,OAAO,EAAE,UAAU,KAAK,MAAM,EAAE,YAAY,EAAE;AAAA,IAClD,KAAK,EAAE,OAAO,KAAK,IAAI,QAAQ,EAAE,aAAa,EAAE;AAAA,EAClD;AACF;AAGO,SAAS,iBAAiB,GAA0D;AACzF,SAAO;AAAA,IACL,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,UAAU,KAAK,EAAE,SAAS,EAAE,gBAAgB;AAAA,IAChF,QAAQ,EAAE,OAAO,EAAE,cAAc,EAAE,OAAO,KAAK,EAAE,SAAS,EAAE,gBAAgB;AAAA,EAC9E;AACF;AAWO,SAAS,cAAc,GAAW,GAAyD;AAChG,QAAM,MAAM,IAAI,EAAE;AAClB,QAAM,MAAM,KAAK,MAAM,IAAI,EAAE,OAAO;AAEpC,QAAM,aAAa,MAAM,MAAM,EAAE,UAAU,IAAI,SAAS;AACxD,QAAM,WAAW,MAAM,MAAM,EAAE,OAAO,IAAI,QAAQ;AAClD,SAAO,GAAG,QAAQ,IAAI,UAAU;AAClC;AAMO,SAAS,kBACd,GACA,GAC+C;AAC/C,QAAM,MAAM,IAAI,EAAE;AAClB,QAAM,MAAM,KAAK,MAAM,IAAI,EAAE,OAAO;AACpC,SAAO;AAAA,IACL,KAAK,MAAM,IAAI,SAAS;AAAA,IACxB,QAAQ,MAAM,EAAE,OAAO,IAAI,SAAS;AAAA,IACpC,MAAM,MAAM,IAAI,SAAS;AAAA,IACzB,OAAO,MAAM,EAAE,UAAU,IAAI,SAAS;AAAA,EACxC;AACF;;;AClEO,IAAM,YAAiC,oBAAI,IAAI;AAQ/C,SAAS,qBAAqB,QAA2B,QAAqC;AACnG,MAAI,OAAQ,QAAO;AACnB,MAAI,QAAQ;AACV,WAAO,OAAO,IAAI,CAAC,SAAS;AAAA,MAC1B,SAAS,EAAE,MAAM,SAAS,KAAK,KAAK,QAAQ;AAAA,IAC9C,EAAE;AAAA,EACJ;AACA,SAAO,MAAM,KAAK,EAAE,QAAQ,GAAG,GAAG,OAAO,CAAC,EAAE;AAC9C;AAGO,SAAS,iBACd,QACA,UACkB;AAClB,QAAM,SAAS,oBAAI,IAA4B;AAC/C,SAAO,QAAQ,CAAC,MAAM,MAAM;AAC1B,UAAM,SAAS,cAAc,EAAE,QAAQ,KAAK,UAAU,SAAS,CAAC;AAChE,UAAM,MAAM,KAAK,UAAU,MAAM;AACjC,QAAI,QAAQ,OAAO,IAAI,GAAG;AAC1B,QAAI,CAAC,OAAO;AACV,cAAQ,EAAE,QAAQ,SAAS,CAAC,GAAG,UAAU,CAAC,EAAE;AAC5C,aAAO,IAAI,KAAK,KAAK;AAAA,IACvB;AACA,UAAM,QAAQ,KAAK,CAAC;AACpB,UAAM,SAAS,KAAK,KAAK,UAAU,cAAc,MAAM,KAAK,OAAO,IAAI,OAAO,OAAO;AAAA,EACvF,CAAC;AACD,SAAO,CAAC,GAAG,OAAO,OAAO,CAAC;AAC5B;AASO,SAAS,mBACd,QACA,UACA,UACS;AACT,MAAI,aAAa,OAAW,QAAO;AACnC,SACE,OAAO,KAAK,CAAC,MAAM,EAAE,MAAM,KAAK,iBAAiB,QAAQ,QAAQ,EAAE,KAAK,CAAC,MAAM,QAAQ,EAAE,OAAO,MAAM,CAAC;AAE3G;AAQO,SAAS,uBACd,MACA,UACA,OACA,UACA,eACa;AACb,MAAI,SAAS,cAAc,EAAE,QAAQ,KAAK,UAAU,SAAS,CAAC;AAC9D,QAAM,QAAiC,CAAC;AACxC,MAAI,KAAK,QAAS,OAAM,UAAU,KAAK;AACvC,MAAI,KAAK,OAAQ,OAAM,SAAS,KAAK;AACrC,MAAI,aAAa,WAAW,OAAO,UAAU,SAAS,UAAU,OAAO,SAAS,WAAW,QAAQ;AACjG,UAAM,IAAI,kBAAkB,MAAM,aAAa;AAC/C,UAAM,WAAW,EAAE,QAAQ,cAAc,OAAO,CAAC,EAAE;AAAA,EACrD;AACA,MAAI,OAAO,KAAK,KAAK,EAAE,SAAS,GAAG;AACjC,aAAS,kBAAkB,MAAM,YAAY,QAAmC,KAAK,CAAC;AAAA,EACxF;AACA,SAAO;AACT;;;ACpHA,IAAAC,UAAuB;AACvB,IAAAC,eAAqB;AACrB,IAAAC,gBAAyB;AACzB,IAAAC,iBAA2C;;;ACH3C,IAAAC,UAAuB;AACvB,IAAAC,iBAAoC;AAYpC,IAAM,YAAY;AAWX,SAAS,UAAU,OAAe,SAAS,GAAmC;AACnF,QAAM,OAAO,KAAK,IAAI,GAAG,KAAK,IAAI,OAAO,KAAK,KAAK,KAAK,KAAK,QAAQ,KAAK,IAAI,QAAQ,IAAI,CAAC,CAAC,CAAC,CAAC;AAC9F,SAAO,EAAE,MAAM,MAAM,KAAK,IAAI,GAAG,KAAK,KAAK,QAAQ,IAAI,CAAC,EAAE;AAC5D;AAQO,SAAS,gBACd,UACAC,QACA,OACqB;AACrB,QAAM,CAAC,OAAO,QAAQ,QAAI,yBAA8B,IAAI;AAK5D,QAAM,iBAAiB,UAAU,QAAQ;AAGzC,gCAAU,MAAM;AACd,QAAI,WAAW;AACf,UAAM,SAASA,OAAM,SAASA,OAAM;AACpC,UAAM,EAAE,MAAM,KAAK,IAAI,UAAU,SAAS,QAAQ,MAAM;AAIxD,QAAI,QAAQ,KAAK,IAAI,MAAM,KAAK,MAAM,YAAY,IAAI,CAAC;AACvD,QAAI,QAAQ,KAAK,MAAM,QAAQ,MAAM;AACrC,QAAI,QAAQ,OAAO,WAAW;AAC5B,cAAQ,KAAK,MAAM,YAAY,IAAI;AACnC,cAAQ,KAAK,IAAI,GAAG,KAAK,MAAM,QAAQ,MAAM,CAAC;AAAA,IAChD;AAEA,UAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,WAAO,QAAQ,QAAQ;AACvB,WAAO,SAAS,QAAQ;AACxB,UAAM,MAAM,OAAO,WAAW,IAAI;AAClC,QAAI,YAAY,MAAM;AACtB,QAAI,SAAS,GAAG,GAAG,OAAO,OAAO,OAAO,MAAM;AAE9C,UAAM,UAAU,IAAU,sBAAc,MAAM;AAC9C,YAAQ,aAAmB;AAC3B,YAAQ,aAAa;AACrB,aAAS,EAAE,SAAS,MAAM,KAAK,CAAC;AAEhC,UAAM,WAAW,CAAC,OAAe,SAA4B;AAC3D,UAAI,SAAU;AACd,YAAMC,KAAK,QAAQ,OAAQ;AAC3B,YAAMC,KAAI,KAAK,MAAM,QAAQ,IAAI,IAAI;AACrC,UAAI,UAAU,MAAMD,IAAGC,IAAG,OAAO,KAAK;AACtC,cAAQ,cAAc;AAAA,IACxB;AAEA,aAAS,QAAQ,CAAC,SAAS,UAAU;AACnC,UAAI,QAAQ,SAAS,SAAS;AAC5B,cAAM,MAAM,IAAI,MAAM;AACtB,YAAI,cAAc;AAClB,YAAI,SAAS,MAAM,SAAS,OAAO,sBAAsB,SAASF,QAAO,OAAO,GAAG,CAAC;AACpF,YAAI,MAAM,QAAQ;AAAA,MACpB,WAAW,QAAQ,SAAS,UAAU,QAAQ,SAAS,WAAW;AAChE,iBAAS,MAAM,MAAM,KAAK,MAAM,SAAS,OAAO,sBAAsB,SAASA,QAAO,KAAK,CAAC,CAAC;AAAA,MAC/F,OAAO;AACL,iBAAS,OAAO,sBAAsB,SAASA,QAAO,KAAK,CAAC;AAAA,MAC9D;AAAA,IACF,CAAC;AAED,WAAO,MAAM;AACX,iBAAW;AACX,cAAQ,QAAQ;AAAA,IAClB;AAAA,EACF,GAAG,CAAC,gBAAgBA,OAAM,OAAOA,OAAM,QAAQ,MAAM,EAAE,CAAC;AAExD,SAAO;AACT;;;AC7EA,SAAS,SAAS,OAAkC;AAClD,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,SAAO,CAAC,SAAS,QAAQ,QAAQ,MAAM,EAAE,MAAM,SAAS,CAAC;AAC3D;AAOO,SAAS,mBACd,OACAG,QACmC;AACnC,QAAM,WAA8C,EAAE,QAAQ,CAACA,OAAM,OAAOA,OAAM,MAAM,EAAE;AAC1F,QAAM,QAAQ,CAAC,UAAU,MAAM;AAC7B,QAAI,SAAS,YAAY,MAAO;AAChC,UAAM,WAAW,YAAY,SAAS,IAAI;AAC1C,QAAI,CAAC,SAAS,KAAM;AACpB,UAAM,KAAK,IAAI,IAAI,SAAS,IAAI,CAAC,GAAG,CAAC;AACrC,UAAM,SAAS,SAAS,KAAK,SAAS,SAAS,OAAO;AACtD,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,MAAM,EAAG,UAAS,KAAK,GAAG,IAAI;AAAA,EAC1E,CAAC;AACD,SAAO;AACT;AAEO,SAAS,sBAAsB,OAA2BA,QAAwC;AACvG,QAAM,QAAkB,CAAC,wBAAwB,qBAAqB;AACtE,QAAM,YAAsB,CAAC;AAC7B,QAAM,QAAkB,CAAC;AACzB,QAAM,WAA8C,EAAE,QAAQ,CAACA,OAAM,OAAOA,OAAM,MAAM,EAAE;AAE1F,QAAM,QAAQ,CAAC,UAAU,MAAM;AAC7B,QAAI,SAAS,YAAY,MAAO;AAChC,UAAM,WAAW,YAAY,SAAS,IAAI;AAC1C,QAAI,CAAC,SAAS,MAAM;AAClB,YAAM,IAAI;AAAA,QACR,wBAAwB,SAAS,IAAI;AAAA,MACvC;AAAA,IACF;AACA,UAAM,KAAK,IAAI,IAAI,SAAS,IAAI,CAAC,GAAG,CAAC;AACrC,UAAM,KAAK,MAAM,SAAS,IAAI,GAAG,CAAC;AAClC,UAAM,SAAS,SAAS,KAAK,SAAS,SAAS,OAAO;AACtD,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,MAAM,GAAG;AACjD,YAAM,KAAK,WAAW,SAAS,KAAK,CAAC,IAAI,EAAE,GAAG,GAAG,GAAG;AACpD,eAAS,KAAK,GAAG,IAAI;AAAA,IACvB;AACA,UAAM,WAAW,SAAS,KAAK;AAC/B,cAAU;AAAA,MACR,SAAS,KAAK,MAAM,WAAW,MAAM,EAAE,EAAE;AAAA,QAAQ;AAAA,QAAY,CAAC,GAAG;AAAA;AAAA;AAAA,UAG/D,SAAS,WAAW,IAAI,EAAE,GAAG,IAAI,eAAe,KAAK;AAAA;AAAA,MACvD;AAAA,IACF;AACA,UAAM,KAAK,GAAG,EAAE,aAAa;AAAA,EAC/B,CAAC;AAED,QAAM;AAAA;AAAA,IAAyB;AAAA;AAAA;AAAA;AAAA,IAI7B,MAAM,KAAK,MAAM,CAAC;AAAA;AAAA;AAAA;AAAA;AAKpB,SAAO,EAAE,cAAc,GAAG,MAAM,KAAK,IAAI,CAAC;AAAA,EAAK,UAAU,KAAK,IAAI,CAAC,IAAI,aAAa,SAAS;AAC/F;AAOO,SAAS,uBAAuB,UAAwC;AAC7E;AAAA;AAAA,IAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOlB,qBAAqB;AAAA,EACrB,SAAS,YAAY;AAAA,EACrB,SAAS,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUpB,wBAAwB,EAAE,OAAO,gCAAgC,UAAU,KAAK,QAAQ,aAAa,CAAC,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAKzG;AAOO,SAAS,2BAAmC;AACjD;AAAA;AAAA,IAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQlB,qBAAqB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAkBvB;AAEA,SAAS,IAAI,GAAmB;AAC9B,SAAO,EAAE,OAAO,CAAC,EAAE,YAAY,IAAI,EAAE,MAAM,CAAC,EAAE,QAAQ,UAAU,CAAC,GAAGC,OAAcA,GAAE,YAAY,CAAC;AACnG;;;ACnKA,IAAAC,eAAkB;;;ACAlB,IAAAC,eAAkB;AAmBX,IAAM,iBAAiB,eAAE,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA,EAKrC,QAAQ,eACL,MAAM,eAAE,MAAM,CAAC,eAAE,OAAO,GAAG,eAAE,OAAO,CAAC,CAAC,CAAC,EACvC,IAAI,CAAC,EACL,QAAQ;AAAA,IACP,CAAC,GAAG,CAAC;AAAA,IACL,CAAC,GAAG,EAAE;AAAA,EACR,CAAC;AAAA;AAAA,EAEH,QAAQ,eAAE,QAAQ,EAAE,QAAQ,KAAK;AACnC,CAAC;AAiBD,IAAM,sBAAsB;AAG5B,IAAM,UAAU;AAGhB,IAAM,QAAQ;AAEd,SAAS,KAAK,GAAWC,IAAW,GAAmB;AACrD,SAAO,IAAI,KAAK,IAAI,KAAK,MAAMA,GAAE,CAAC,IAAI,EAAE,CAAC,GAAGA,GAAE,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,OAAO,KAAK;AACxE;AAGA,SAAS,SAAS,GAAWA,IAAW,IAAY,IAAY,GAAmB;AACjF,QAAM,OAAO,KAAK;AAClB,QAAMC,KAAI,SAAS,IAAI,KAAK,IAAI,MAAM;AACtC,SAAO,CAAC,EAAE,CAAC,KAAKD,GAAE,CAAC,IAAI,EAAE,CAAC,KAAKC,IAAG,EAAE,CAAC,KAAKD,GAAE,CAAC,IAAI,EAAE,CAAC,KAAKC,EAAC;AAC5D;AAGA,SAAS,aAAa,IAAY,IAAY,IAAY,IAAY,GAAmB;AACvF,QAAM,KAAK;AACX,QAAM,KAAK,KAAK,IAAI,IAAI,EAAE;AAC1B,QAAM,KAAK,KAAK,IAAI,IAAI,EAAE;AAC1B,QAAM,KAAK,KAAK,IAAI,IAAI,EAAE;AAC1B,QAAM,IAAI,MAAM,KAAK,MAAM;AAC3B,QAAM,KAAK,SAAS,IAAI,IAAI,IAAI,IAAI,CAAC;AACrC,QAAM,KAAK,SAAS,IAAI,IAAI,IAAI,IAAI,CAAC;AACrC,QAAM,KAAK,SAAS,IAAI,IAAI,IAAI,IAAI,CAAC;AACrC,QAAM,KAAK,SAAS,IAAI,IAAI,IAAI,IAAI,CAAC;AACrC,QAAM,KAAK,SAAS,IAAI,IAAI,IAAI,IAAI,CAAC;AACrC,SAAO,SAAS,IAAI,IAAI,IAAI,IAAI,CAAC;AACnC;AAGA,SAAS,QAAQ,KAAa,OAAuB;AACnD,SAAO,CAAC,IAAI,IAAI,CAAC,IAAI,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,IAAI,MAAM,CAAC,CAAC;AACtD;AAEO,SAAS,eAAe,SAAoC;AACjE,QAAM,MAAM,QAAQ;AACpB,QAAM,IAAI,IAAI;AACd,QAAM,SAAS,QAAQ,UAAU,IAAI;AACrC,QAAM,WAAW,SAAS,IAAI,IAAI;AAIlC,QAAM,UAAoB,CAAC;AAC3B,QAAM,aAAuB,CAAC;AAC9B,MAAI,QAAQ;AACZ,WAAS,MAAM,GAAG,MAAM,UAAU,OAAO;AACvC,UAAM,KAAK,IAAI,GAAG;AAClB,UAAM,KAAK,KAAK,MAAM,KAAK,CAAC;AAC5B,UAAM,KAAK,SAAS,KAAK,MAAM,IAAI,KAAK,CAAC,IAAK,MAAM,IAAI,IAAI,MAAM,CAAC,IAAK,QAAQ,IAAI,CAAC,GAAI,IAAI,CAAC,CAAE;AAChG,UAAM,KAAK,SAAS,KAAK,MAAM,KAAK,CAAC,IAAK,MAAM,IAAI,IAAI,IAAI,MAAM,CAAC,IAAK,QAAQ,IAAI,IAAI,CAAC,GAAI,IAAI,IAAI,CAAC,CAAE;AAGxG,UAAM,OAAO,QAAQ,WAAW,KAAK,CAAC,SAAS,sBAAsB,sBAAsB;AAC3F,aAASA,KAAI,GAAGA,MAAK,MAAMA,MAAK;AAC9B,YAAM,QAAQ,aAAa,IAAI,IAAI,IAAI,IAAIA,KAAI,mBAAmB;AAClE,YAAM,WAAW,QAAQ,QAAQ,SAAS,CAAC;AAC3C,UAAI,SAAU,UAAS,KAAK,MAAM,MAAM,CAAC,IAAI,SAAS,CAAC,GAAG,MAAM,CAAC,IAAI,SAAS,CAAC,CAAC;AAChF,cAAQ,KAAK,KAAK;AAClB,iBAAW,KAAK,KAAK;AAAA,IACvB;AAAA,EACF;AACA,MAAI,QAAQ;AAGV,UAAM,QAAQ,QAAQ,CAAC;AACvB,UAAM,WAAW,QAAQ,QAAQ,SAAS,CAAC;AAC3C,aAAS,KAAK,MAAM,MAAM,CAAC,IAAI,SAAS,CAAC,GAAG,MAAM,CAAC,IAAI,SAAS,CAAC,CAAC;AAClE,YAAQ,KAAK,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC;AACjC,eAAW,KAAK,KAAK;AAAA,EACvB;AAEA,QAAM,SAAS;AAEf,WAAS,UAAU,GAAmB;AACpC,QAAI,CAAC,OAAO,SAAS,CAAC,EAAG,QAAO;AAChC,QAAI,CAAC,OAAQ,QAAO,KAAK,IAAI,KAAK,IAAI,GAAG,CAAC,GAAG,CAAC;AAC9C,UAAM,UAAU,IAAI,KAAK,MAAM,CAAC;AAChC,WAAO;AAAA,EACT;AAEA,WAAS,QAAQ,GAAmB;AAClC,UAAM,SAAS,UAAU,CAAC,IAAI;AAC9B,QAAI,WAAW,EAAG,QAAO,CAAC,QAAQ,CAAC,EAAG,CAAC,GAAG,QAAQ,CAAC,EAAG,CAAC,CAAC;AAExD,QAAI,MAAM;AACV,QAAI,OAAO,WAAW,SAAS;AAC/B,WAAO,MAAM,MAAM;AACjB,YAAM,MAAO,MAAM,QAAS;AAC5B,UAAI,WAAW,GAAG,IAAK,OAAQ,OAAM,MAAM;AAAA,UACtC,QAAO;AAAA,IACd;AACA,UAAM,IAAI,KAAK,IAAI,KAAK,CAAC;AACzB,UAAM,SAAS,WAAW,IAAI,CAAC;AAC/B,UAAM,OAAO,WAAW,CAAC,IAAK;AAC9B,UAAMA,KAAI,QAAQ,IAAI,KAAK,SAAS,UAAU;AAC9C,UAAM,IAAI,QAAQ,IAAI,CAAC;AACvB,UAAMD,KAAI,QAAQ,CAAC;AACnB,WAAO,CAAC,EAAE,CAAC,KAAKA,GAAE,CAAC,IAAI,EAAE,CAAC,KAAKC,IAAG,EAAE,CAAC,KAAKD,GAAE,CAAC,IAAI,EAAE,CAAC,KAAKC,EAAC;AAAA,EAC5D;AAGA,WAAS,UAAU,GAAmB;AACpC,UAAM,KAAK,SAAS,IAAI,KAAK,IAAI,MAAM,MAAM,MAAM,IAAI;AACvD,UAAM,OAAO,UAAU,CAAC;AACxB,UAAM,IAAI,QAAQ,SAAS,OAAO,KAAK,KAAK,IAAI,OAAO,IAAI,CAAC,CAAC;AAC7D,UAAMD,KAAI,QAAQ,SAAS,OAAO,KAAK,KAAK,IAAI,OAAO,IAAI,CAAC,CAAC;AAC7D,UAAM,KAAKA,GAAE,CAAC,IAAI,EAAE,CAAC;AACrB,UAAM,KAAKA,GAAE,CAAC,IAAI,EAAE,CAAC;AACrB,UAAM,MAAM,KAAK,MAAM,IAAI,EAAE;AAE7B,WAAO,MAAM,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,KAAK,KAAK,GAAG;AAAA,EACtD;AAEA,WAAS,SAAS,GAAmB;AACnC,UAAM,CAAC,IAAI,EAAE,IAAI,UAAU,CAAC;AAE5B,WAAO,CAAC,IAAI,CAAC,EAAE;AAAA,EACjB;AAEA,SAAO,EAAE,QAAQ,QAAQ,SAAS,WAAW,SAAS;AACxD;AAOA,IAAM,QAAQ,oBAAI,IAAsB;AACxC,IAAM,cAAc;AAEb,SAAS,YAAY,SAAoC;AAC9D,QAAM,MAAM,GAAG,QAAQ,SAAS,MAAM,GAAG,IAAI,QAAQ,OAAO,IAAI,CAACE,OAAM,GAAGA,GAAE,CAAC,CAAC,IAAIA,GAAE,CAAC,CAAC,EAAE,EAAE,KAAK,GAAG,CAAC;AACnG,QAAM,MAAM,MAAM,IAAI,GAAG;AACzB,MAAI,IAAK,QAAO;AAChB,QAAM,OAAO,eAAe,OAAO;AACnC,MAAI,MAAM,QAAQ,aAAa;AAC7B,UAAM,SAAS,MAAM,KAAK,EAAE,KAAK,EAAE;AACnC,QAAI,WAAW,OAAW,OAAM,OAAO,MAAM;AAAA,EAC/C;AACA,QAAM,IAAI,KAAK,IAAI;AACnB,SAAO;AACT;;;AD/IO,IAAM,gBAA2B,EAAE,OAAO,GAAG,QAAQ,IAAI;AAEhE,IAAMC,OAAM,KAAK,KAAK;AACtB,IAAMC,OAAM,KAAK,KAAK;AAGtB,SAASC,QAAO,MAAc,GAAmB;AAC/C,MAAI,IAAI,KAAK,KAAM,OAAO,MAAO,IAAI,IAAK,YAAY,UAAU;AAChE,MAAI,KAAK,KAAK,IAAK,MAAM,IAAK,UAAU;AACxC,WAAU,IAAK,MAAM,QAAS,KAAK,aAAc,IAAI;AACvD;AAGA,SAAS,KAAK,GAAW,GAAmB;AAC1C,SAAO,IAAI,IAAI,KAAK,IAAI,KAAK;AAC/B;AAEA,IAAM,aAAa,eAAE,OAAO;AAAA,EAC1B,QAAQ,eAAE,OAAO,EAAE,IAAI,GAAG,EAAE,IAAI,EAAE,EAAE,QAAQ,GAAG;AAAA,EAC/C,SAAS,eAAE,OAAO,EAAE,IAAI,GAAG,EAAE,IAAI,EAAE,EAAE,QAAQ,CAAC;AAChD,CAAC;AAEM,IAAM,OAA2C;AAAA,EACtD,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU,WAAW,MAAM,CAAC,CAAC;AAAA,EAC7B,eAAe;AAAA,EACf,KAAK,GAAG,GAAG,GAAG,OAAO;AACnB,UAAM,SAAS,IAAI,IAAI,SAASF;AAChC,WAAO;AAAA,MACL,UAAU,CAAC,KAAK,IAAI,KAAK,IAAI,EAAE,QAAQ,GAAG,KAAK,IAAI,KAAK,IAAI,EAAE,MAAM;AAAA;AAAA;AAAA,MAGpE,UAAU,CAAE,EAAE,UAAU,KAAK,KAAM,KAAK,OAAO,CAAC;AAAA,MAChD,OAAO;AAAA,IACT;AAAA,EACF;AACF;AAEA,IAAM,YAAY,eAAE,OAAO;AAAA;AAAA,EAEzB,OAAO,eAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE,QAAQ,EAAE;AAAA;AAAA,EAE5C,OAAO,eAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,QAAQ,IAAI;AAAA;AAAA,EAE5C,MAAM,eAAE,OAAO,EAAE,IAAI,IAAK,EAAE,IAAI,IAAI,EAAE,QAAQ,KAAK;AAAA;AAAA,EAEnD,KAAK,eAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,QAAQ,GAAG;AAC3C,CAAC;AAMM,IAAM,MAAyC;AAAA,EACpD,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU,UAAU,MAAM,CAAC,CAAC;AAAA,EAC5B,eAAe;AAAA,EACf,KAAK,GAAG,GAAG,GAAG,QAAQG,QAAO;AAC3B,UAAM,IAAI,IAAI,IAAI,KAAK,IAAI,KAAK;AAChC,UAAM,SAAS,IAAI,OAAO,EAAE,QAAQF;AACpC,UAAM,QAAS,EAAE,QAAQE,OAAM,SAAU;AAGzC,UAAM,OAAO,KAAK,IAAI,IAAI,GAAG,IAAI;AACjC,WAAO;AAAA,MACL,UAAU,CAAC,CAAC,KAAK,IAAI,KAAK,IAAI,OAAO,KAAK,IAAI,KAAK,IAAI,QAAQ,OAAO,IAAI,EAAE,IAAI;AAAA,MAChF,UAAU,CAAC,GAAG,GAAG,KAAK;AAAA,MACtB,OAAO;AAAA,MACP,MAAM,KAAK,IAAI,QAAQ,EAAE;AAAA,IAC3B;AAAA,EACF;AACF;AAEA,IAAM,eAAe,eAAE,OAAO;AAAA;AAAA,EAE5B,MAAM,eAAE,OAAO,EAAE,IAAI,IAAI,EAAE,IAAI,CAAC,EAAE,QAAQ,GAAG;AAAA;AAAA,EAE7C,OAAO,eAAE,OAAO,EAAE,IAAI,IAAI,EAAE,IAAI,GAAG,EAAE,QAAQ,EAAE;AAAA,EAC/C,MAAM,eAAE,OAAO,EAAE,IAAI,IAAK,EAAE,IAAI,IAAI,EAAE,QAAQ,KAAK;AAAA;AAAA,EAEnD,KAAK,eAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,QAAQ,GAAG;AAAA;AAAA,EAEzC,OAAO,eAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,QAAQ,IAAI;AAC9C,CAAC;AAMM,IAAM,SAA+C;AAAA,EAC1D,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU,aAAa,MAAM,CAAC,CAAC;AAAA,EAC/B,eAAe;AAAA,EACf,KAAK,GAAG,GAAG,GAAG;AACZ,UAAM,WAAW,KAAK,IAAI,KAAK;AAC/B,UAAM,IAAI,EAAE,QAAQF;AACpB,WAAO;AAAA,MACL,UAAU,CAAC,KAAK,IAAI,CAAC,IAAI,EAAE,OAAO,UAAU,KAAK,IAAI,CAAC,IAAI,EAAE,OAAO,UAAU,IAAI,EAAE,IAAI;AAAA,MACvF,UAAU,CAAC,GAAG,GAAGC,QAAO,IAAI,CAAC,IAAI,MAAM,EAAE,KAAK;AAAA,MAC9C,OAAO;AAAA,MACP,MAAM,KAAK,IAAI,KAAK,GAAG,CAAC,KAAK,EAAE;AAAA,IACjC;AAAA,EACF;AACF;AAEA,IAAM,aAAa,eAAE,OAAO;AAAA;AAAA,EAE1B,SAAS,eAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,QAAQ,IAAI;AAAA;AAAA,EAE9C,MAAM,eAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE,QAAQ,EAAE;AAAA,EAC3C,MAAM,eAAE,OAAO,EAAE,IAAI,IAAK,EAAE,IAAI,IAAI,EAAE,QAAQ,KAAK;AAAA;AAAA,EAEnD,OAAO,eAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,QAAQ,IAAI;AAAA,EAC5C,MAAM,eAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,IAAI,EAAE,QAAQ,CAAC;AACnD,CAAC;AAMM,IAAM,OAA2C;AAAA,EACtD,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU,WAAW,MAAM,CAAC,CAAC;AAAA,EAC7B,eAAe;AAAA,EACf,KAAK,GAAG,GAAG,GAAG;AACZ,WAAO;AAAA,MACL,UAAU,CAACA,QAAO,EAAE,MAAM,CAAC,IAAI,EAAE,SAASA,QAAO,EAAE,OAAO,GAAG,CAAC,IAAI,EAAE,UAAU,KAAK,IAAI,EAAE,IAAI;AAAA,MAC7F,UAAU,CAAC,GAAG,GAAGA,QAAO,EAAE,OAAO,GAAG,CAAC,IAAI,EAAE,OAAOD,IAAG;AAAA,MACrD,OAAO;AAAA,MACP,MAAM,KAAK,IAAI,KAAK,GAAG,CAAC,KAAK,EAAE;AAAA,IACjC;AAAA,EACF;AACF;AAEA,IAAM,aAAa,eAAE,OAAO;AAAA,EAC1B,MAAM,eAAE,OAAO,EAAE,IAAI,IAAI,EAAE,IAAI,CAAC,EAAE,QAAQ,IAAI;AAAA,EAC9C,MAAM,eAAE,OAAO,EAAE,IAAI,IAAI,EAAE,IAAI,CAAC,EAAE,QAAQ,GAAG;AAAA,EAC7C,WAAW,eAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,QAAQ,IAAI;AAAA;AAAA,EAEhD,KAAK,eAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,QAAQ,IAAI;AAC5C,CAAC;AAEM,IAAM,OAA2C;AAAA,EACtD,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU,WAAW,MAAM,CAAC,CAAC;AAAA,EAC7B,eAAe;AAAA,EACf,KAAK,GAAG,GAAG,GAAG,QAAQE,QAAO;AAC3B,UAAM,OAAO,KAAK,KAAK,KAAK,KAAM,IAAIA,OAAM,SAAUA,OAAM,KAAK,CAAC;AAClE,UAAM,OAAO,KAAK,KAAK,IAAI,IAAI;AAC/B,UAAM,MAAM,IAAI;AAChB,UAAM,MAAM,KAAK,MAAM,IAAI,IAAI;AAG/B,UAAM,QAAQA,OAAM,QAAQ,EAAE;AAC9B,UAAM,QAAQA,OAAM,SAAS,EAAE;AAC/B,WAAO;AAAA,MACL,UAAU;AAAA,SACP,OAAO,OAAO,KAAK,KAAK;AAAA,UACvB,OAAO,KAAK,IAAI,OAAO;AAAA,QACzBD,QAAO,GAAG,CAAC,IAAI,OAAO,EAAE,YAAY;AAAA,MACtC;AAAA,MACA,UAAU,CAAC,GAAG,GAAGA,QAAO,GAAG,CAAC,IAAI,OAAO,EAAE,YAAY,CAAC;AAAA,MACtD,OAAO;AAAA,MACP,MAAM,IAAI,KAAK,IAAIA,QAAO,GAAG,CAAC,CAAC,IAAI,EAAE;AAAA,IACvC;AAAA,EACF;AACF;AAEA,IAAM,cAAc,eAAE,OAAO;AAAA,EAC3B,SAAS,eAAE,OAAO,EAAE,IAAI,GAAG,EAAE,IAAI,CAAC,EAAE,QAAQ,GAAG;AAAA,EAC/C,SAAS,eAAE,OAAO,EAAE,IAAI,GAAG,EAAE,IAAI,CAAC,EAAE,QAAQ,GAAG;AAAA,EAC/C,OAAO,eAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,QAAQ,GAAG;AAAA;AAAA,EAE3C,QAAQ,eAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,QAAQ,GAAG;AAAA;AAAA,EAE5C,MAAM,eAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,QAAQ,GAAG;AAAA,EAC1C,MAAM,eAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,IAAI,EAAE,QAAQ,CAAC;AACnD,CAAC;AAOM,IAAM,QAA6C;AAAA,EACxD,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU,YAAY,MAAM,CAAC,CAAC;AAAA,EAC9B,eAAe;AAAA,EACf,KAAK,GAAG,IAAI,GAAG;AACb,UAAM,SAAS,EAAE,SAAS;AAC1B,WAAO;AAAA,MACL,UAAU;AAAA,QACRA,QAAO,EAAE,MAAM,CAAC,IAAI,EAAE;AAAA,QACtBA,QAAO,EAAE,OAAO,GAAG,CAAC,IAAI,EAAE;AAAA,QAC1BA,QAAO,EAAE,OAAO,GAAG,CAAC,IAAI,EAAE;AAAA,MAC5B;AAAA,MACA,UAAU;AAAA,QACRA,QAAO,EAAE,OAAO,GAAG,CAAC,IAAI,MAAM;AAAA,QAC9BA,QAAO,EAAE,OAAO,GAAG,CAAC,IAAI,MAAM;AAAA,QAC9BA,QAAO,EAAE,OAAO,GAAG,CAAC,IAAI,MAAM;AAAA,MAChC;AAAA,MACA,OAAO,OAAO,KAAK,IAAIA,QAAO,EAAE,OAAO,GAAG,CAAC,CAAC,IAAI;AAAA,MAChD,MAAM,IAAI,KAAK,IAAIA,QAAO,EAAE,OAAO,GAAG,CAAC,CAAC,IAAI,EAAE;AAAA,IAChD;AAAA,EACF;AACF;AAEA,IAAM,cAAc,eAAE,OAAO;AAAA,EAC3B,SAAS,eAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,QAAQ,CAAC;AAAA;AAAA,EAElD,KAAK,eAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,QAAQ,IAAI;AAAA;AAAA,EAE1C,MAAM,eAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,QAAQ,CAAC;AAAA,EACxC,IAAI,eAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,QAAQ,CAAC;AACxC,CAAC;AAWM,IAAME,SAA6C;AAAA,EACxD,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU,YAAY,MAAM,CAAC,CAAC;AAAA,EAC9B,eAAe;AAAA,EACf,KAAK,GAAG,GAAG,GAAG,QAAQD,QAAO;AAC3B,UAAM,OAAO,KAAK,IAAI,EAAE,SAAS,KAAK,IAAI,GAAG,CAAC,CAAC;AAC/C,UAAM,OAAO,KAAK,KAAK,IAAI,IAAI;AAC/B,UAAM,MAAM,IAAI;AAChB,UAAM,MAAM,KAAK,MAAM,IAAI,IAAI;AAC/B,WAAO;AAAA,MACL,UAAU;AAAA,SACP,OAAO,OAAO,KAAK,MAAMA,OAAM,QAAQ,EAAE;AAAA,UACxC,OAAO,KAAK,IAAI,QAAQA,OAAM,SAAS,EAAE;AAAA,QAC3C;AAAA,MACF;AAAA,MACA,UAAU,CAAC,GAAG,GAAG,CAAC;AAAA,MAClB,OAAO;AAAA,MACP,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,KAAK,GAAG,CAAC;AAAA,IAC5C;AAAA,EACF;AACF;AAEA,IAAM,aAAa,eAAE,OAAO;AAAA;AAAA,EAE1B,QAAQ,eAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE,QAAQ,EAAE;AAAA;AAAA,EAE7C,OAAO,eAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,QAAQ,GAAG;AAAA;AAAA,EAE3C,MAAM,eAAE,OAAO,EAAE,IAAI,IAAK,EAAE,IAAI,IAAI,EAAE,QAAQ,IAAK;AAAA;AAAA,EAEnD,QAAQ,eAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,QAAQ,GAAG;AAC9C,CAAC;AAQM,IAAM,OAA2C;AAAA,EACtD,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU,WAAW,MAAM,CAAC,CAAC;AAAA,EAC7B,eAAe;AAAA,EACf,KAAK,GAAG,GAAG,GAAG,QAAQA,QAAO;AAC3B,UAAM,OAAOA,OAAM,QAAQ;AAC3B,UAAM,OAAO,KAAK,MAAM,IAAI,EAAE,KAAK;AACnC,UAAM,SAAS,IAAI;AACnB,UAAM,QAAQ,SAAS,OAAO,IAAI;AAClC,UAAME,KAAI,SAAS,IAAI,IAAI;AAC3B,UAAM,IAAI,QAAQ,IAAIA,MAAK,QAAQ,KAAK;AACxC,UAAM,QAAQ,IAAI,EAAE,SAASJ;AAE7B,UAAM,OAAO,SAAS,KAAK;AAC3B,UAAM,MAAM,KAAK,IAAI,KAAK;AAC1B,UAAM,MAAM,KAAK,IAAI,KAAK;AAG1B,UAAM,SAASI,KAAI,EAAE;AACrB,WAAO;AAAA,MACL,UAAU,CAAC,QAAQ,OAAO,MAAM,SAAS,MAAM,GAAG,OAAO,MAAM,SAAS,GAAG;AAAA,MAC3E,UAAU,CAAC,GAAG,CAAC,OAAO,OAAO,CAAC;AAAA,MAC9B,OAAO;AAAA,MACP,MAAM,KAAK,IAAI,KAAK,EAAE;AAAA,IACxB;AAAA,EACF;AACF;AAEA,IAAM,kBAAkB,eAAE,OAAO;AAAA;AAAA,EAE/B,OAAO,eAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE;AAAA;AAAA,EAE3C,OAAO,eAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,QAAQ,IAAI;AAC9C,CAAC;AAOM,IAAM,YAAqD;AAAA,EAChE,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU,gBAAgB,MAAM,CAAC,CAAC;AAAA,EAClC,eAAe;AAAA,EACf,KAAK,GAAG,GAAG,GAAG,QAAQF,QAAO;AAC3B,UAAM,QAAQ,EAAE,QAAQF;AACxB,UAAM,OAAO,IAAI,MAAM,IAAI,IAAI;AAG/B,UAAM,OAAOE,OAAM,QAAQ,KAAK,IAAI,KAAK;AACzC,WAAO;AAAA,MACL,UAAU,EAAE,KAAK,IAAI,KAAK,KAAK,MAAM,GAAG,CAAC;AAAA,MACzC,UAAU,CAAC,GAAG,OAAO,OAAO,CAAC;AAAA,MAC7B,OAAO;AAAA,MACP,MAAM,EAAE;AAAA,IACV;AAAA,EACF;AACF;AAEA,IAAM,aAAa,eAAE,OAAO;AAAA;AAAA,EAE1B,SAAS,eAAE,OAAO,EAAE,IAAI,IAAI,EAAE,IAAI,CAAC,EAAE,QAAQ,IAAI;AAAA;AAAA,EAEjD,MAAM,eAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE;AAAA;AAAA,EAE1C,MAAM,eAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,QAAQ,IAAI;AAAA;AAAA,EAE3C,MAAM,eAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,QAAQ,IAAI;AAAA,EAC3C,MAAM,eAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,IAAI,EAAE,QAAQ,CAAC;AACnD,CAAC;AAYM,IAAM,OAA2C;AAAA,EACtD,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU,WAAW,MAAM,CAAC,CAAC;AAAA,EAC7B,eAAe;AAAA,EACf,KAAK,GAAG,GAAG,GAAG,QAAQA,QAAO;AAC3B,UAAM,OAAO,EAAE,OAAOF,QAAO,IAAIC,QAAO,EAAE,MAAM,CAAC,IAAI,EAAE;AACvD,UAAM,OAAOC,OAAM,SAAS;AAC5B,WAAO;AAAA,MACL,UAAU;AAAA,SACP,KAAK,IAAI,KAAK,KAAKA,OAAM,QAAQ,EAAE;AAAA;AAAA,QAEpC,OAAO,KAAK,IAAI,IAAI;AAAA,QACpB,CAAC,OAAO,KAAK,IAAI,IAAI,IAAI,IAAI;AAAA,MAC/B;AAAA,MACA,UAAU,CAAC,CAAC,MAAMD,QAAO,EAAE,OAAO,GAAG,CAAC,IAAI,OAAO,EAAE,MAAMA,QAAO,EAAE,OAAO,GAAG,CAAC,IAAI,OAAO,EAAE,IAAI;AAAA,MAC9F,OAAO;AAAA;AAAA,MAEP,MAAM,EAAE,SAAS,IAAI,IAAI,KAAK,IAAI,GAAG,QAAQ,EAAE,OAAOD,QAAO,IAAI,EAAE,MAAM;AAAA,IAC3E;AAAA,EACF;AACF;AAEA,IAAM,kBAAkB,eAAE,OAAO;AAAA;AAAA,EAE/B,MAAM,eAAe,SAAS,CAAC,CAAC;AAAA;AAAA,EAEhC,OAAO,eAAE,OAAO,EAAE,IAAI,GAAG,EAAE,IAAI,EAAE,EAAE,QAAQ,GAAG;AAAA;AAAA,EAE9C,SAAS,eAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,QAAQ,GAAG;AAAA;AAAA,EAE7C,OAAO,eAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE;AAAA;AAAA,EAE3C,QAAQ,eAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,IAAI,EAAE,QAAQ,IAAI;AAAA;AAAA,EAEhD,MAAM,eAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,QAAQ,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAc3C,OAAO,eAAE,OAAO,EAAE,IAAI,IAAI,EAAE,IAAI,CAAC,EAAE,QAAQ,CAAC;AAAA;AAAA,EAE5C,OAAO,eAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,QAAQ,GAAG;AAAA,EAC3C,MAAM,eAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,IAAI,EAAE,QAAQ,CAAC;AACnD,CAAC;AAsBM,SAAS,cAAc,GAAW,GAAW,QAAwB;AAC1E,QAAM,OAAO,IAAI,MAAM,IAAI,IAAI;AAC/B,QAAM,QAAQ,KAAK,IAAI,KAAK,KAAK,IAAI,CAAC,GAAG,CAAC;AAC1C,QAAMI,KAAI,KAAK,MAAM,IAAI,CAAC;AAC1B,QAAM,OAAO,IAAI,SAAS;AAC1B,QAAM,OAAO,QAAQ,IAAI,QAAQ,QAAQ,KAAK;AAC9C,SAAO,UAAU,QAAQ,IAAIA,KAAI,OAAO,OAAO,KAAK,OAAO,OAAO;AACpE;AAEO,IAAM,YAAqD;AAAA,EAChE,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU,gBAAgB,MAAM,CAAC,CAAC;AAAA,EAClC,eAAe;AAAA,EACf,UAAU,GAAG,GAAG;AACd,WAAO,MAAM,KAAK,EAAE,QAAQ,EAAE,GAAG,CAAC,GAAG,MAAM,cAAc,GAAG,GAAG,EAAE,MAAM,CAAC;AAAA,EAC1E;AAAA,EACA,KAAK,GAAG,GAAG,GAAG,OAAOF,QAAO;AAC1B,UAAM,OAAO,YAAY,EAAE,IAAI;AAC/B,UAAM,OAAO,IAAI,MAAM,IAAI,IAAI;AAC/B,UAAM,OAAO,cAAc,GAAG,GAAG,EAAE,MAAM;AAGzC,UAAM,IAAI,KAAK,SAAS,OAAO,QAAQ;AACvC,UAAM,CAAC,IAAI,EAAE,IAAI,KAAK,QAAQ,CAAC;AAC/B,UAAM,CAAC,IAAI,EAAE,IAAI,KAAK,SAAS,CAAC;AAChC,UAAM,QAAQ,IAAID,QAAO,EAAE,MAAM,CAAC,IAAI,EAAE,OAAO;AAC/C,UAAM,SAAS,EAAE,SAAS,IAAIA,QAAO,EAAE,OAAO,GAAG,CAAC,IAAI,EAAE;AACxD,UAAM,SAASC,OAAM,SAAS;AAG9B,UAAM,MAAM,KAAK,MAAM,CAAC,OAAO,IAAI,CAAC,OAAO,EAAE,IAAID,QAAO,EAAE,OAAO,GAAG,CAAC,IAAI,EAAE,QAAQD;AACnF,WAAO;AAAA,MACL,UAAU,CAAC,KAAK,KAAK,OAAO,QAAQ,SAAS,IAAI,SAAS,EAAE,OAAO,KAAK,KAAK,OAAO,MAAM;AAAA,MAC1F,UAAU,CAAC,GAAG,KAAK,CAAC;AAAA,MACpB;AAAA,MACA,MAAM,IAAI,KAAK,IAAIC,QAAO,EAAE,OAAO,GAAG,CAAC,CAAC,IAAI,EAAE;AAAA,IAChD;AAAA,EACF;AACF;AAQO,IAAM,QAAoC;AAAA,EAC/C,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU,kBAAkB,MAAM,CAAC,CAAC;AAAA,EACpC,eAAe;AAAA,EACf,KAAK,GAAG,IAAI,GAAG;AACb,UAAM,EAAE,GAAAI,IAAG,GAAAC,GAAE,IAAI,YAAY,GAAG,CAAC;AACjC,WAAO,EAAE,UAAU,CAACD,IAAGC,IAAG,UAAU,GAAG,UAAU,CAAC,GAAG,GAAG,CAAC,GAAG,OAAO,EAAE;AAAA,EACvE;AACF;AAEA,IAAMC,YAAW,oBAAI,IAAgC;AAE9C,SAAS,eAAe,QAAkC;AAC/D,EAAAA,UAAS,IAAI,OAAO,IAAI,MAAM;AAChC;AAEO,SAAS,UAAU,IAAgC;AACxD,QAAM,SAASA,UAAS,IAAI,EAAE;AAC9B,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI,MAAM,8BAA8B,EAAE,kBAAkB,CAAC,GAAGA,UAAS,KAAK,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE;AAAA,EACrG;AACA,SAAO;AACT;AAEO,SAAS,cAAwB;AACtC,SAAO,CAAC,GAAGA,UAAS,KAAK,CAAC;AAC5B;AAEA,eAAe,IAAI;AACnB,eAAe,GAAG;AAClB,eAAe,MAAM;AACrB,eAAe,IAAI;AACnB,eAAe,IAAI;AACnB,eAAe,KAAK;AACpB,eAAeJ,MAAK;AACpB,eAAe,IAAI;AACnB,eAAe,SAAS;AACxB,eAAe,IAAI;AACnB,eAAe,SAAS;AACxB,eAAe,KAAK;;;AE5iBb,SAAS,gBAAgB,QAAqB,UAAsC;AACzF,MAAI,OAAO,UAAW,QAAO,qBAAqB,OAAO,SAAS;AAClE,MAAI,CAAC,OAAO,SAAU,QAAO,CAAC;AAC9B,QAAM,WAAW,YAAY,OAAO,SAAS,IAAI;AACjD,QAAM,UAAU,EAAE,GAAG,OAAO,UAAU,CAAC,SAAS,aAAa,GAAG,SAAS;AACzE,SAAO,SAAS,MAAM,SAAS,OAAO,KAAK;AAC7C;;;ALoUM,IAAAK,sBAAA;AA9TN,IAAM,aAAa,IAAU,iBAAS;AACtC,IAAM,cAAwB,EAAE,UAAU,CAAC,GAAG,GAAG,CAAC,GAAG,UAAU,CAAC,GAAG,GAAG,CAAC,EAAE;AAMlE,IAAM,oBAAoB;AAmB1B,IAAM,qBAAqB;AAGlC,IAAMC,oBAAmB,CAAC,GAAG,MAAM,KAAK,MAAM,CAAC;AAmB/C,IAAM,aAAa,MAAM;AAAC;AAGnB,SAAS,WAAW;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAOG;AACD,QAAM,cAAc,KAAK,IAAI,kBAAkB,oBAAoB,kBAAkB;AACrF,QAAM,EAAE,QAAQ,SAAS,SAAS,IAAI;AACtC,QAAM,QAAQ,QAAQ;AACtB,QAAM,QAAQ,SAAS,OAAO,KAAK;AAGnC,QAAM,MAAM,YAAY,OAAO,MAAM,QAAQ;AAI7C,QAAM,WAAW,OAAO,YAAY,CAAC,OAAO,YAAY,YAAY,OAAO,SAAS,IAAI,IAAI;AAE5F,QAAM,kBAAc;AAAA,IAClB,WAAa,OAAO,SAAqC,SAAS,aAAa,IAAe;AAAA,EAChG;AACA,QAAM,eAAe,CAAC,aAAyC,gBAAgB,QAAQ,QAAQ;AAE/F,QAAM,mBAAe;AAAA,IACnB,MAAM,aAAa,YAAY,OAAO;AAAA,IACtC;AAAA,MACE,KAAK,UAAU,OAAO,YAAY,IAAI;AAAA,MACtC,KAAK,UAAU,OAAO,aAAa,IAAI;AAAA,MACvC,KAAK,UAAU,OAAO,KAAK;AAAA,IAC7B;AAAA,EACF;AACA,QAAM,eAAe,aAAa,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,GAAG;AAG7D,QAAM,eAAW,wBAAQ,MAAM;AAC7B,UAAM,QAAQ,iBAAiB,cAAc,OAAO,KAAK;AAIzD,UAAM,OAAoB,CAAC,GAAG,CAAC;AAC/B,eAAWC,MAAKD,mBAAkB;AAChC,YAAM,CAACE,IAAGC,EAAC,IAAI,kBAAkB,aAAaF,EAAC,GAAG,OAAO,KAAK;AAC9D,UAAIC,KAAI,KAAK,CAAC,EAAG,MAAK,CAAC,IAAIA;AAC3B,UAAIC,KAAI,KAAK,CAAC,EAAG,MAAK,CAAC,IAAIA;AAAA,IAC7B;AACA,UAAM,MAAM;AAAA,MACV;AAAA,QACE,GAAG,OAAO;AAAA,QACV,UACE,OAAO,MAAM,aAAa,SAAS,SAAS,KAAK,IAAI,OAAO,MAAM,UAAU,iBAAiB;AAAA,MACjG;AAAA,MACA,CAAC,KAAK,IAAI,MAAM,CAAC,GAAG,iBAAiB,GAAG,KAAK,IAAI,MAAM,CAAC,GAAG,iBAAiB,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAO7E,CAAC,KAAK,IAAI,KAAK,CAAC,GAAG,WAAW,GAAG,KAAK,IAAI,KAAK,CAAC,GAAG,WAAW,CAAC;AAAA,IACjE;AACA,UAAM,WAAW,IAAI,aAAa,KAAK;AACvC,UAAM,QAAQ,IAAI,aAAa,KAAK;AACpC,UAAM,OAAO,IAAI,aAAa,KAAK,EAAE,KAAK,CAAC;AAC3C,aAAS,IAAI,GAAG,IAAI,OAAO,KAAK;AAC9B,eAAS,CAAC,IAAI;AACd,YAAM,CAAC,IAAM,QAAQ,CAAC,IAAK,WAAY,IAAK;AAAA,IAC9C;AACA,QAAI,aAAa,UAAU,IAAU,iCAAyB,UAAU,CAAC,CAAC;AAC1E,QAAI,aAAa,UAAU,IAAU,iCAAyB,OAAO,CAAC,CAAC;AAGvE,QAAI,aAAa,SAAS,IAAU,iCAAyB,MAAM,CAAC,CAAC;AACrE,WAAO;AAAA,EACT,GAAG,CAAC,KAAK,UAAU,OAAO,KAAK,GAAG,cAAc,OAAO,WAAW,CAAC;AAGnE,gCAAU,MAAM,MAAM,SAAS,QAAQ,GAAG,CAAC,QAAQ,CAAC;AAEpD,QAAM,QAAQ,gBAAgB,UAAU,OAAO,OAAO,KAAK;AAG3D,QAAM,aAAS,wBAAQ,MAAM;AAC3B,UAAM,WAAW,sBAAsB,cAAc,OAAO,KAAK;AACjE,UAAM,WAA+C,CAAC;AACtD,eAAW,CAAC,MAAM,KAAK,KAAK,OAAO,QAAQ,SAAS,QAAQ,GAAG;AAC7D,eAAS,IAAI,IAAI;AAAA,QACf,OAAO,MAAM,QAAQ,KAAK,KAAK,MAAM,WAAW,IAAI,IAAU,gBAAQ,GAAG,KAAK,IAAI;AAAA,MACpF;AAAA,IACF;AACA,aAAS,UAAU,EAAE,OAAO,EAAE;AAC9B,aAAS,SAAS,EAAE,OAAO,KAAK;AAChC,aAAS,aAAa,EAAE,OAAO,IAAU,gBAAQ,GAAG,CAAC,EAAE;AACvD,aAAS,cAAc;AAAA,MACrB,OAAO,IAAI,KAAK,IAAI,MAAM,OAAO,OAAO,MAAM,YAAY,GAAG,IAAI,MAAM;AAAA,IACzE;AACA,aAAS,cAAc,EAAE,OAAO,IAAU,cAAM,MAAM,KAAK,EAAE;AAC7D,aAAS,eAAe,EAAE,OAAO,OAAO,QAAQ,eAAe,MAAM,YAAY;AAGjF,WAAO,OAAO,UAAU,qBAAqB,OAAO,QAAQ,gBAAgB,MAAM,cAAc,GAAG,CAAC;AACpG,WAAO;AAAA,MACL,cAAc,uBAAuB,QAAQ;AAAA,MAC7C,gBAAgB,yBAAyB;AAAA,MACzC;AAAA,IACF;AAAA,EACF,GAAG;AAAA,IACD;AAAA,IACA,KAAK,UAAU,OAAO,KAAK;AAAA,IAC3B,MAAM;AAAA,IACN,OAAO,QAAQ;AAAA,IACf,OAAO,QAAQ;AAAA,EACjB,CAAC;AAKD,gCAAU,MAAM;AACd,UAAM,SAAS,mBAAmB,OAAO,QAAQ,gBAAgB,MAAM,cAAc,GAAG;AACxF,WAAO,SAAS,cAAe,QAAQ,OAAO;AAC7C,IAAC,OAAO,SAAS,cAAe,MAAwB,KAAK,OAAO,SAAS;AAC7E,IAAC,OAAO,SAAS,gBAAiB,MAAsB,KAAK,OAAO,KAAK;AAC1E,WAAO,SAAS,qBAAsB,QAAQ,OAAO;AAAA,EACvD,GAAG,CAAC,QAAQ,KAAK,OAAO,QAAQ,cAAc,MAAM,YAAY,CAAC;AAEjE,gCAAU,MAAM;AACd,QAAI,CAAC,MAAO;AACZ,WAAO,SAAS,OAAQ,QAAQ,MAAM;AACrC,IAAC,OAAO,SAAS,WAAY,MAAwB,IAAI,MAAM,MAAM,MAAM,IAAI;AAAA,EAClF,GAAG,CAAC,OAAO,MAAM,CAAC;AAIlB,gCAAU,MAAM;AACd,QAAI,CAAC,YAAY,OAAO,QAAS;AACjC,UAAM,QAAQ,EAAE,GAAG,YAAY,QAAQ;AACvC,UAAM,QAAQ,kBAAK,GAAG,OAAO;AAAA,MAC3B,GAAG;AAAA,MACH,UAAU,SAAS,WAAW,KAAK,IAAI,MAAM,IAAI,MAAM,CAAC;AAAA,MACxD,MAAM;AAAA,MACN,MAAM,SAAS,aAAa;AAAA,MAC5B,QAAQ;AAAA,MACR,UAAU,MAAM;AACd,oBAAY,UAAU,MAAM;AAAA,MAC9B;AAAA,IACF,CAAC;AACD,WAAO,MAAM;AACX,YAAM,KAAK;AAAA,IACb;AAAA,EACF,GAAG,CAAC,cAAc,OAAO,OAAO,CAAC;AAEjC,QAAM,cAAU,uBAA4B,IAAI;AAEhD,8BAAS,CAAC,EAAE,MAAM,MAAM;AACtB,UAAM,OAAO,QAAQ;AACrB,QAAI,CAAC,KAAM;AACX,UAAM,UAAU,MAAM,cAAc,KAAK,IAAI,OAAO,aAAa,SAAS,CAAC;AAE3E,WAAO,SAAS,QAAS,QAAQ,OAAO,UAAU,IAAI,MAAM;AAC5D,QAAI,UAAU;AACZ,YAAM,SAAS,mBAAmB,aAAa,YAAY,OAAO,GAAG,OAAO,KAAK;AACjF,iBAAW,CAAC,MAAM,KAAK,KAAK,OAAO,QAAQ,MAAM,GAAG;AAClD,cAAM,UAAU,OAAO,SAAS,IAAI;AACpC,YAAI,CAAC,QAAS;AACd,YAAI,QAAQ,iBAAuB,mBAAW,MAAM,QAAQ,KAAK,GAAG;AAClE,kBAAQ,MAAM,IAAI,MAAM,CAAC,GAAI,MAAM,CAAC,CAAE;AAAA,QACxC,OAAO;AACL,kBAAQ,QAAQ;AAAA,QAClB;AAAA,MACF;AAAA,IACF;AAEA,UAAM,SAAS,UAAU,OAAO,QAAQ;AACxC,UAAM,QAAQ,OAAO,SAAS;AAC9B,UAAM,oBAAoB,UAAU,aAAa,OAAO,WAAW,WAAW;AAC9E,UAAM,WAAW,SAAS,aAAa,OAAO;AAC9C,UAAM,SAAS,SAAS;AACxB,QAAI,cAAc;AAClB,aAASC,KAAI,GAAGA,KAAI,OAAOA,MAAK;AAC9B,YAAM,IAAI,QAAQA,EAAC;AACnB,UAAI,OAAO,OAAO,KAAK,GAAG,OAAO,OAAO,OAAO,eAAe,OAAO,SAAS,SAAS,OAAO,KAAK;AACnG,UAAI,MAAM,QAAQ,MAAM,IAAI,GAAG;AAC7B,cAAM,OAAO,UAAU,MAAM,KAAK,EAAE,EAAE;AAAA,UACpC;AAAA,UACA,OAAO;AAAA,UACP,MAAM,KAAK;AAAA,UACX,OAAO,SAAS;AAAA,UAChB,OAAO;AAAA,QACT;AACA,eAAO,SAAS,MAAM,MAAM,UAAU,MAAM,CAAC,CAAC;AAAA,MAChD;AACA,UAAI,OAAO,iBAAiB,QAAQ;AAClC,cAAM,MAAM,KAAK,IAAI,GAAG,KAAK,IAAI,IAAI,UAAU,IAAI,OAAO,WAAW,OAAO,gBAAgB,CAAC;AAC7F,YAAI,MAAM,GAAG;AACX,iBAAO,SAAS,aAAa,OAAO,cAAc,GAAG,IAAI,GAAG,MAAM,QAAQ,GAAG,CAAC;AAAA,QAChF;AAAA,MACF;AACA,YAAM,OAAO,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,KAAK,QAAQ,CAAC,CAAC;AACpD,UAAI,OAAOA,EAAC,MAAM,MAAM;AACtB,eAAOA,EAAC,IAAI;AACZ,sBAAc;AAAA,MAChB;AACA,iBAAW,SAAS,IAAI,GAAG,KAAK,QAAQ;AACxC,iBAAW,SAAS,IAAI,GAAG,KAAK,QAAQ;AACxC,iBAAW,MAAM,UAAU,KAAK,KAAK;AAIrC,UAAI,mBAAmB;AACrB,cAAM,QAAQ;AACd,cAAM,SAAS,CAAC,IAAI,MAAM,SAAS,CAAC,IAAI,MAAM,SAAS,CAAC,IAAI;AAC5D,cAAM,SAAS,CAAC,IAAI,MAAM,SAAS,CAAC,IAAI,MAAM,SAAS,CAAC,IAAI;AAC5D,cAAM,IAAI,OAAO,UAAU,IAAI,MAAM,cAAgB,IAAI,WAAY,IAAK;AAC1E,0BAAkB;AAAA,UAChB,EAAE,GAAG,OAAO,UAAU,CAAC,kBAAkB,aAAa,GAAG,YAAY,QAAQ;AAAA,UAC7E;AAAA,UACA;AAAA,UACA,OAAO;AAAA,QACT;AACA,mBAAW,SAAS,KAAK,MAAM,SAAS,CAAC;AACzC,mBAAW,SAAS,KAAK,MAAM,SAAS,CAAC;AACzC,mBAAW,SAAS,KAAK,MAAM,SAAS,CAAC;AACzC,mBAAW,SAAS,KAAK,MAAM,SAAS,CAAC;AACzC,mBAAW,SAAS,KAAK,MAAM,SAAS,CAAC;AACzC,mBAAW,SAAS,KAAK,MAAM,SAAS,CAAC;AAAA,MAC3C;AACA,iBAAW,aAAa;AACxB,WAAK,YAAYA,IAAG,WAAW,MAAM;AAAA,IACvC;AACA,SAAK,eAAe,cAAc;AAClC,QAAI,YAAa,UAAS,cAAc;AAAA,EAC1C,CAAC;AAED;AAAA;AAAA,IAEE;AAAA,MAAC;AAAA;AAAA,QACC,KAAK;AAAA,QACL,MAAM,CAAC,UAAU,QAAW,KAAK;AAAA,QACjC,eAAe;AAAA,QACf,YAAU;AAAA,QACV,eAAa;AAAA,QAMZ,GAAI,WAAW,CAAC,IAAI,EAAE,SAAS,WAAW;AAAA,QAC3C,SACE,aACC,CAAC,UAAU;AACV,cAAI,MAAM,eAAe,OAAW;AAIpC,gBAAM,QAAQ,QAAQ,MAAM,UAAU;AACtC,cAAI,UAAU,OAAW;AACzB,gBAAM,gBAAgB;AACtB,mBAAS,KAAK;AAAA,QAChB;AAAA,QAGF;AAAA,UAACA;AAAA,UAAA;AAAA,YAEC,cAAoB;AAAA,YACpB,cAAc,OAAO;AAAA,YACrB,gBAAgB,OAAO;AAAA,YACvB,UAAU,OAAO;AAAA,YACjB,WAAW,MAAM;AAAA,YACjB,WAAW;AAAA,YACX,MAAY;AAAA;AAAA,UAPP,GAAG,YAAY,IAAI,KAAK;AAAA,QAQ/B;AAAA;AAAA,IACF;AAAA;AAEJ;AAEA,SAAS,aAAa,MAA0B,GAAW,QAA8B;AACvF,MAAI,SAAS,QAAQ;AACnB,WAAO;AAAA,MACL,UAAU,CAAC,OAAO,SAAS,CAAC,GAAG,OAAO,SAAS,CAAC,IAAI,KAAK,OAAO,SAAS,CAAC,IAAI,GAAG;AAAA,MACjF,UAAU,CAAC,OAAO,SAAS,CAAC,IAAI,KAAK,OAAO,SAAS,CAAC,GAAG,OAAO,SAAS,CAAC,IAAI,IAAI;AAAA,MAClF,OAAO,OAAO,QAAQ;AAAA,MACtB,MAAM,OAAO;AAAA,IACf;AAAA,EACF;AACA,QAAM,IAAI,IAAI;AACd,SAAO;AAAA,IACL,UAAU,CAAC,KAAK,IAAI,CAAC,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,IAAI,GAAG,KAAK,IAAI,CAAC,IAAI,CAAC;AAAA,IAClE,UAAU,CAAC,KAAK,IAAI,CAAC,IAAI,GAAG,GAAG,KAAK,IAAI,CAAC,IAAI,CAAC;AAAA,IAC9C,OAAO,OAAO,QAAQ;AAAA,IACtB,MAAM,OAAO;AAAA,EACf;AACF;AAEA,SAAS,SAAS,GAAcC,IAAc,GAAsB;AAClE,QAAM,OAAO,CAACH,IAAWC,OAAcD,MAAKC,KAAID,MAAK;AACrD,SAAO;AAAA,IACL,UAAU;AAAA,MACR,KAAK,EAAE,SAAS,CAAC,GAAGG,GAAE,SAAS,CAAC,CAAC;AAAA,MACjC,KAAK,EAAE,SAAS,CAAC,GAAGA,GAAE,SAAS,CAAC,CAAC;AAAA,MACjC,KAAK,EAAE,SAAS,CAAC,GAAGA,GAAE,SAAS,CAAC,CAAC;AAAA,IACnC;AAAA,IACA,UAAU;AAAA,MACR,KAAK,EAAE,SAAS,CAAC,GAAGA,GAAE,SAAS,CAAC,CAAC;AAAA,MACjC,KAAK,EAAE,SAAS,CAAC,GAAGA,GAAE,SAAS,CAAC,CAAC;AAAA,MACjC,KAAK,EAAE,SAAS,CAAC,GAAGA,GAAE,SAAS,CAAC,CAAC;AAAA,IACnC;AAAA,IACA,OAAO,KAAK,EAAE,OAAOA,GAAE,KAAK;AAAA,IAC5B,MAAM,KAAK,EAAE,QAAQ,GAAGA,GAAE,QAAQ,CAAC;AAAA,EACrC;AACF;AAEA,IAAM,UAAU,CAAC,MAAc,KAAK,IAAI,MAAM;AAC9C,IAAM,YAAY,CAAC,MAAe,IAAI,MAAM,IAAI,IAAI,IAAI,KAAK,KAAK,IAAI,MAAM,IAAI;;;AM1YhF,IAAAC,UAAuB;AACvB,IAAAC,iBAAmC;;;ACkB5B,SAAS,gBAAgB,GAAuB,OAAiC;AACtF,QAAM,EAAE,OAAO,OAAO,IAAI,iBAAiB,CAAC;AAC5C,QAAM,QAA0B,CAAC;AACjC,WAAS,IAAI,GAAG,IAAI,OAAO,KAAK;AAC9B,UAAM,EAAE,GAAAC,IAAG,GAAAC,GAAE,IAAI,YAAY,GAAG,CAAC;AACjC,UAAM,KAAK;AAAA,MACT,IAAID,KAAI,EAAE,YAAY,IAAI,QAAQ,KAAK;AAAA;AAAA,MAEvC,IAAI,SAAS,IAAIC,KAAI,EAAE,aAAa,KAAK;AAAA,MACzC,GAAG,EAAE,YAAY;AAAA,MACjB,GAAG,EAAE,aAAa;AAAA,IACpB,CAAC;AAAA,EACH;AACA,SAAO;AACT;AAGO,SAAS,WAAW,KAAa,QAAwB;AAC9D,QAAM,IAAI,SAAS,IAAI,QAAQ,KAAK,EAAE,GAAG,EAAE;AAC3C,QAAM,KAAK,CAAC,UAAkB;AAC5B,UAAMC,KAAK,KAAK,QAAS;AACzB,WAAO,KAAK,IAAI,KAAK,KAAK,MAAMA,MAAK,MAAMA,MAAK,MAAM,CAAC;AAAA,EACzD;AACA,SAAO,KAAM,GAAG,EAAE,KAAK,KAAO,GAAG,CAAC,KAAK,IAAK,GAAG,CAAC,GAAG,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC;AAClF;AAWO,SAAS,YAAY,QAA2B,MAA6B;AAClF,QAAM,MAAM,OAAO,WAAW,IAAI;AAClC,MAAI,CAAC,IAAK;AACV,QAAM,EAAE,OAAO,IAAI,QAAQ,IAAI,IAAI;AACnC,MAAI,YAAY,KAAK;AACrB,MAAI,SAAS,GAAG,GAAG,IAAI,GAAG;AAE1B,QAAM,QAAQ,gBAAgB,KAAK,SAAS,KAAK,KAAK;AACtD,QAAM,QAAQ,CAACC,IAAG,MAAM;AACtB,UAAM,UAAU,KAAK,QAAQ,IAAI,CAAC;AAClC,UAAMH,KAAIG,GAAE,IAAI;AAChB,UAAMF,KAAIE,GAAE,IAAI;AAChB,UAAMC,KAAID,GAAE,IAAI;AAChB,UAAM,IAAIA,GAAE,IAAI;AAChB,UAAM,SAAS,KAAK,IAAIC,IAAG,CAAC,IAAI;AAEhC,QAAI,YAAY,WAAW,KAAK,MAAM,UAAU,MAAM,IAAI;AAC1D,gBAAY,KAAKJ,IAAGC,IAAGG,IAAG,GAAG,MAAM;AACnC,QAAI,KAAK;AAET,QAAI,SAAS;AAEX,YAAM,QAAQ,IAAI,qBAAqBJ,IAAGC,IAAGD,KAAII,IAAGH,KAAI,CAAC;AACzD,YAAM,aAAa,GAAG,qBAAqB;AAC3C,YAAM,aAAa,KAAK,wBAAwB;AAChD,YAAM,aAAa,GAAG,qBAAqB;AAC3C,UAAI,YAAY;AAChB,kBAAY,KAAKD,IAAGC,IAAGG,IAAG,GAAG,MAAM;AACnC,UAAI,KAAK;AAAA,IACX;AAAA,EACF,CAAC;AACH;AAEA,SAAS,YACP,KACAJ,IACAC,IACAG,IACA,GACAD,IACM;AACN,MAAI,UAAU;AACd,MAAI,OAAOH,KAAIG,IAAGF,EAAC;AACnB,MAAI,MAAMD,KAAII,IAAGH,IAAGD,KAAII,IAAGH,KAAI,GAAGE,EAAC;AACnC,MAAI,MAAMH,KAAII,IAAGH,KAAI,GAAGD,IAAGC,KAAI,GAAGE,EAAC;AACnC,MAAI,MAAMH,IAAGC,KAAI,GAAGD,IAAGC,IAAGE,EAAC;AAC3B,MAAI,MAAMH,IAAGC,IAAGD,KAAII,IAAGH,IAAGE,EAAC;AAC3B,MAAI,UAAU;AAChB;;;AD1DI,IAAAE,uBAAA;AAtCJ,IAAM,eAAe;AAQd,SAAS,aAAa;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,QAAM,EAAE,OAAO,OAAO,IAAI,iBAAiB,OAAO;AAClD,QAAM,aAAS,wBAAQ,MAAM;AAC3B,QAAI,OAAO,aAAa,YAAa,QAAO;AAC5C,UAAMC,KAAI,SAAS,cAAc,QAAQ;AACzC,UAAM,QAAQ,KAAK,IAAI,MAAM,KAAK,MAAM,MAAM,KAAK,IAAI,OAAO,MAAM,CAAC,CAAC,IAAI,KAAK,IAAI,OAAO,MAAM;AAChG,IAAAA,GAAE,QAAQ,KAAK,IAAI,GAAG,KAAK,MAAM,QAAQ,KAAK,CAAC;AAC/C,IAAAA,GAAE,SAAS,KAAK,IAAI,GAAG,KAAK,MAAM,SAAS,KAAK,CAAC;AACjD,WAAOA;AAAA,EACT,GAAG,CAAC,OAAO,MAAM,CAAC;AAClB,QAAM,cAAU,wBAAQ,MAAO,SAAS,IAAU,sBAAc,MAAM,IAAI,MAAO,CAAC,MAAM,CAAC;AAEzF,QAAM,aAAa,CAAC,GAAG,OAAO,EAAE,KAAK,CAAC,GAAGC,OAAM,IAAIA,EAAC,EAAE,KAAK,GAAG;AAE9D,gCAAU,MAAM;AACd,QAAI,CAAC,UAAU,CAAC,QAAS;AACzB,gBAAY,QAAQ,EAAE,SAAS,OAAO,MAAM,cAAc,QAAQ,CAAC;AACnE,YAAQ,cAAc;AAAA,EACxB,GAAG,CAAC,QAAQ,SAAS,KAAK,UAAU,OAAO,GAAG,OAAO,UAAU,CAAC;AAChE,gCAAU,MAAM,MAAM,SAAS,QAAQ,GAAG,CAAC,OAAO,CAAC;AAEnD,SACE,+CAAC,UAAK,eAAa,MACjB;AAAA,kDAAC,mBAAc,MAAM,CAAC,OAAO,MAAM,GAAG;AAAA,IACtC,8CAAC,0BAAqB,KAAK,SAAS,OAAM,WAAU,WAAW,MAAM,WAAW,GAAG;AAAA,KACrF;AAEJ;;;AEjDA,IAAAC,UAAuB;AACvB,IAAAC,eAAqB;AACrB,IAAAC,gBAAoD;AACpD,IAAAC,iBAAiE;AAwb7D,IAAAC,uBAAA;AAxYJ,IAAM,iBAAiB,oBAAI,IAAI,CAAC,QAAQ,OAAO,CAAC;AA6BzC,SAAS,iBAAiB,OAA8B;AAC7D,QAAM,EAAE,QAAQ,UAAU,UAAU,eAAe,aAAa,IAAI;AACpE,QAAM,QAAQ,OAAO;AACrB,QAAM,SAAS,UAAU,QAAQ;AACjC,QAAM,UAAU,wBAAwB,MAAM,aAAa;AAC3D,QAAM,sBAAkB,2BAAW,eAAe;AAElD,QAAMC,gBAAW,wBAAQ,MAAM,mBAAmB,IAAI,iBAAiB,GAAG,CAAC,eAAe,CAAC;AAC3F,QAAM,aAAS,wBAAS,CAAC,MAAM,EAAE,MAAM;AACvC,QAAM,SAAK,wBAAS,CAAC,MAAM,EAAE,EAAE;AAC/B,QAAM,eAAW,wBAAS,CAAC,MAAM,EAAE,QAAQ;AAI3C,QAAM,CAAC,SAAS,UAAU,QAAI,yBAA8B,SAAS;AAGrE,QAAM,CAAC,aAAa,cAAc,QAAI,yBAAkD,CAAC,CAAC;AAC1F,QAAM,CAAC,YAAY,aAAa,QAAI,yBAAiC,CAAC,CAAC;AAGvE,QAAM,kBAAc;AAAA,IAClB,MACE,OAAO,IAAI,CAAC,MAAM,MAAM;AACtB,YAAM,SAAS,uBAAuB,MAAM,UAAU,GAAG,UAAU,aAAa;AAChF,YAAM,QAAQ,YAAY,CAAC;AAC3B,aAAO,QAAQ,kBAAkB,MAAM,YAAY,QAAmC,KAAK,CAAC,IAAI;AAAA,IAClG,CAAC;AAAA,IACH;AAAA,MACE,KAAK,UAAU,MAAM;AAAA,MACrB,KAAK,UAAU,YAAY,IAAI;AAAA,MAC/B;AAAA,MACA,KAAK,UAAU,aAAa;AAAA,MAC5B;AAAA,IACF;AAAA,EACF;AAEA,QAAM,YAAQ;AAAA,IACZ,MAAM,YAAY,IAAI,CAAC,GAAG,MAAM,OAAO,KAAK,GAAG,OAAO,eAAe,GAAG,MAAM,KAAK,CAAC;AAAA,IACpF,CAAC,UAAU,KAAK,UAAU,aAAa,GAAG,OAAO,MAAM,MAAM,OAAO,MAAM,MAAM,MAAM;AAAA,EACxF;AAEA,QAAM,gBAAY,uBAA+B,CAAC,CAAC;AACnD,QAAM,iBAAa,uBAA+B,CAAC,CAAC;AACpD,QAAM,eAAW,uBAA0B,IAAI;AAC/C,QAAM,iBAAa,uBAA4B,IAAI;AAGnD,QAAM,YAAY,MAAmB,CAAC,GAAI,MAAM,SAAS,CAAC,GAAI,GAAGA,UAAS,KAAK,CAAC;AAEhF,QAAM,WAAW,CAAC,MAAsB;AACtC,UAAM,SAAS,OAAO,CAAC,GAAG,UAAU;AACpC,WAAO,OAAO,WAAW,WAAW,SAAU,YAAY,CAAC,GAAG,KAAK,QAAQ;AAAA,EAC7E;AAEA,QAAM,cAAc,CAAC,GAAW,UAAkB;AAChD,kBAAc,CAAC,UAAU,EAAE,GAAG,MAAM,CAAC,CAAC,GAAG,MAAM,EAAE;AACjD,QAAI,UAAU,YAAY,UAAU,UAAU;AAC5C,iBAAW,CAAC,SAAU,KAAK,IAAI,CAAC,IAAI,OAAO,IAAI,IAAI,IAAI,EAAE,IAAI,CAAC,CAAE;AAAA,IAClE;AACA,UAAM,oBAAoB,GAAG,KAAK;AAAA,EACpC;AAGA,QAAM,gBAAY,wBAAQ,MAAM,IAAU,kBAAU,GAAG,CAAC,CAAC;AACzD,QAAM,mBAAe,wBAAQ,MAAM,IAAU,cAAM,IAAU,gBAAQ,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AACrF,QAAM,mBAAe,wBAAQ,MAAM,IAAU,gBAAQ,GAAG,CAAC,CAAC;AAC1D,QAAM,iBAAa,wBAAQ,MAAM,IAAU,gBAAQ,GAAG,CAAC,CAAC;AACxD,QAAM,aAAa,CAAC,SAAiB,SAAiB,WAA4C;AAChG,UAAM,OAAO,GAAG,WAAW,sBAAsB;AACjD,eAAW;AAAA,OACP,UAAU,KAAK,QAAQ,KAAK,QAAS,IAAI;AAAA,MAC3C,GAAG,UAAU,KAAK,OAAO,KAAK,UAAU,IAAI;AAAA,IAC9C;AACA,cAAU,cAAc,YAAY,MAAM;AAC1C,iBAAa,WAAW,CAAC;AACzB,UAAM,MAAM,UAAU,IAAI,eAAe,cAAc,YAAY;AACnE,WAAO,MAAM,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI;AAAA,EAChC;AAGA,QAAM,OAAO,CAAC,MAAc,KAAa,KAAa,YAA2B,SAAkB;AACjG,UAAM,SAAS,YAAY,IAAI;AAC/B,UAAM,SAAS,WAAW,QAAQ,IAAI;AACtC,UAAM,OAAO,MAAM,IAAI;AACvB,QAAI,CAAC,QAAQ,UAAU,CAAC,UAAU,CAAC,KAAM,QAAO;AAChD,QAAI,CAAC,OAAO,YAAY,CAAC,eAAe,IAAI,OAAO,SAAS,IAAI,EAAG,QAAO;AAC1E,QAAI,WAAW,IAAI,MAAM,YAAY,WAAW,QAAS,QAAO;AAKhE,UAAM,QAAiC,CAAC;AACxC,QAAI,gBAAgB,OAAO,QAAQ,aAAa;AAC9C,YAAM,OAAO,kBAAkB,MAAM,YAAY;AACjD,YAAM,UAAU;AAAA,QACd,aAAa,EAAE,OAAO,EAAE,GAAG,MAAM,GAAG,OAAO,QAAQ,YAAY,MAAM,EAAE;AAAA,MACzE;AAAA,IACF;AACA,UAAM,kBAAkB,OAAO,OAAO,OAAO,QAAQ;AACrD,QAAI,CAAC,iBAAiB,UAAU;AAC9B,YAAM,OACJ,OAAO,SAAS,SAAS,UAAU,OAAO,SAAS,WAAW,SAC1D,OAAO,SAAS,SAChB;AACN,YAAM,SAAS;AAAA,QACb,QAAQ;AAAA,UACN,QAAQ,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,SAAS,MAAM,OAAO,IAAI,EAAE,EAAE;AAAA,QACzE;AAAA,MACF;AAAA,IACF;AACA,QAAI,OAAO,KAAK,KAAK,EAAE,SAAS,GAAG;AACjC,qBAAe,CAAC,UAAU,EAAE,GAAG,MAAM,CAAC,IAAI,GAAG,YAAY,KAAK,IAAI,KAAK,CAAC,GAAG,KAAK,EAAE,EAAE;AAAA,IACtF;AAKA,WAAO,iBAAiB;AACxB,eAAW,UAAU;AAAA,MACnB;AAAA,MACA;AAAA,MACA,GAAG,EAAE,OAAO,KAAK,UAAU,EAAE;AAAA,MAC7B,GAAG,EAAE,OAAO,KAAK,UAAU,EAAE;AAAA,MAC7B,SAAS;AAAA,MACT,SAAS;AAAA,MACT,OAAO;AAAA,MACP,OAAO;AAAA,MACP,UAAU;AAAA,MACV,UAAU;AAAA,IACZ;AACA,QAAI,SAAU,UAAS,UAAU;AACjC,WAAO;AAAA,EACT;AAGA,QAAM,aAAa,CAAC,SAAuB,SAAoB;AAC7D,UAAM,QAAQ,UAAU,QAAQ,QAAQ,IAAI;AAC5C,UAAM,SAAS,WAAW,QAAQ,QAAQ,IAAI;AAC9C,QAAI,CAAC,SAAS,CAAC,OAAQ;AACvB,YAAQ,WAAW;AACnB,WAAO,kBAAkB;AACzB,WAAO,IAAI,SAAS,CAAC;AACrB,IAAAA,UAAS,WAAW,IAAI;AAExB,UAAM,QAAqB;AAAA,MACzB,MAAM,QAAQ;AAAA,MACd,YAAY,SAAS,QAAQ,IAAI;AAAA,MACjC,QAAQ,YAAY,QAAQ,IAAI;AAAA,IAClC;AACA,UAAM,QAAQ,KAAK,OAAO,SAAS,CAAC;AACpC,UAAM,OAAO,MAAM;AACjB,iBAAW,UAAU;AACrB,UAAI,SAAU,UAAS,UAAU;AACjC,WAAK,UAAU,OAAO,KAAK,EAAE;AAC7B,YAAM,UAAU,OAAO,KAAK,EAAE;AAAA,IAChC;AACA,QAAI,SAAS;AACX,YAAM,SAAS,IAAI,MAAM,SAAS,GAAG,MAAM,SAAS,GAAG,QAAQ,IAAK;AACpE,YAAM,SAAS,IAAI,GAAG,GAAG,CAAC;AAC1B,YAAM,MAAM,UAAU,CAAC;AACvB,WAAK;AACL;AAAA,IACF;AACA,UAAM,KAAK,kBAAK,SAAS,EAAE,YAAY,KAAK,CAAC;AAE7C,OAAG,GAAG,MAAM,UAAU,EAAE,GAAG,QAAQ,MAAO,UAAU,MAAM,MAAM,aAAa,GAAG,CAAC;AACjF,OAAG,GAAG,MAAM,UAAU,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,UAAU,MAAM,MAAM,aAAa,GAAG,CAAC;AAEjF,OAAG,GAAG,MAAM,OAAO,EAAE,GAAG,MAAM,GAAG,MAAM,GAAG,GAAG,UAAU,MAAM,MAAM,YAAY,GAAG,IAAI;AACtF,OAAG,GAAG,MAAM,UAAU,EAAE,GAAG,QAAQ,MAAO,UAAU,MAAM,MAAM,aAAa,GAAG,IAAI;AAEpF,OAAG,GAAG,MAAM,OAAO,EAAE,GAAG,OAAO,GAAG,OAAO,UAAU,MAAM,MAAM,eAAe,GAAG,GAAG;AACpF,OAAG,GAAG,MAAM,OAAO,EAAE,GAAG,GAAG,GAAG,GAAG,UAAU,MAAM,MAAM,aAAa,GAAG,IAAI;AAAA,EAC7E;AAGA,QAAM,aAAa,CAAC,YAA0B;AAC5C,UAAM,QAAQ,UAAU,QAAQ,QAAQ,IAAI;AAC5C,UAAM,SAAS,WAAW,QAAQ,QAAQ,IAAI;AAC9C,QAAI,CAAC,SAAS,CAAC,OAAQ;AACvB,YAAQ,WAAW;AACnB,IAAAA,UAAS,WAAW,IAAI;AAExB,UAAM,OAAO,QAAQ;AACrB,UAAM,OAAO,MAAM;AACjB,aAAO,mBAAmB;AAC1B,iBAAW,UAAU;AACrB,UAAI,SAAU,UAAS,UAAU;AAAA,IACnC;AACA,QAAI,SAAS;AACX,YAAM,SAAS,IAAI,GAAG,KAAK,QAAQ;AACnC,YAAM,SAAS,IAAI,GAAG,KAAK,QAAQ;AACnC,YAAM,MAAM,UAAU,KAAK,KAAK;AAChC,WAAK;AACL;AAAA,IACF;AACA,UAAM,OAAO,EAAE,GAAG,MAAM,SAAS,GAAG,GAAG,MAAM,SAAS,GAAG,GAAG,MAAM,SAAS,EAAE;AAC7E,UAAM,OAAO,KAAK,MAAM,KAAK,IAAI,KAAK,SAAS,CAAC,GAAG,KAAK,IAAI,KAAK,SAAS,CAAC,CAAC;AAC5E,UAAM,WAAW,KAAK,IAAI,KAAK,KAAK,IAAI,MAAM,OAAO,IAAI,CAAC;AAE1D,UAAM,MAAM,KAAK,IAAI,MAAM,OAAO,IAAI;AACtC,UAAM,QAAQ,EAAE,GAAG,EAAE;AACrB,sBAAK,GAAG,OAAO;AAAA,MACb,GAAG;AAAA,MACH;AAAA,MACA,MAAM;AAAA,MACN,UAAU,MAAM;AACd,cAAM,IAAI,MAAM;AAChB,cAAM,OAAO,KAAK,IAAI,IAAI,KAAK,EAAE,IAAI;AACrC,cAAM,SAAS,IAAI,KAAK,KAAK,KAAK,SAAS,CAAC,IAAI,KAAK,KAAK;AAC1D,cAAM,SAAS,IAAI,KAAK,KAAK,KAAK,SAAS,CAAC,IAAI,KAAK,KAAK,IAAI;AAC9D,cAAM,SAAS,IAAI,KAAK,KAAK,KAAK,SAAS,CAAC,IAAI,KAAK,KAAK;AAE1D,eAAO,IAAI,UAAU,IAAI,KAAK,GAAG;AAAA,MACnC;AAAA,MACA,YAAY;AAAA,IACd,CAAC;AACD,sBAAK,GAAG,MAAM,UAAU,EAAE,GAAG,KAAK,SAAS,CAAC,GAAG,GAAG,KAAK,SAAS,CAAC,GAAG,GAAG,KAAK,SAAS,CAAC,GAAG,SAAS,CAAC;AACnG,sBAAK,GAAG,MAAM,OAAO,EAAE,GAAG,KAAK,OAAO,GAAG,KAAK,OAAO,GAAG,KAAK,OAAO,UAAU,WAAW,IAAI,CAAC;AAAA,EAChG;AAMA,QAAM,uBAAmB,uBAAkC,MAAM;AAAA,EAAC,CAAC;AACnE,mBAAiB,UAAU,CAACC,OAAoB;AAC9C,UAAM,QAAQ,SAAS;AACvB,UAAM,UAAU,WAAW;AAC3B,QAAI,WAAW,CAAC,QAAQ,aAAa,QAAQ,cAAc,QAAQA,GAAE,cAAc,QAAQ,YAAY;AACrG,YAAMC,OAAM,WAAWD,GAAE,SAASA,GAAE,SAAS,QAAQ,SAAS,SAAS,CAAC,IAAI,IAAI;AAChF,UAAIC,MAAK;AACP,gBAAQ,UAAUA,KAAI,CAAC;AACvB,gBAAQ,UAAUA,KAAI,CAAC;AAAA,MACzB;AACA;AAAA,IACF;AACA,QAAI,CAAC,MAAO;AACZ,UAAM,MAAM,WAAWD,GAAE,SAASA,GAAE,SAAS,MAAM,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC;AAChF,QAAI,CAAC,IAAK;AACV,UAAM,OAAO,KAAK,MAAM,IAAI,CAAC,IAAI,MAAM,QAAQ,IAAI,CAAC,IAAI,MAAM,MAAM;AACpE,UAAM,YAAY,YAAY,MAAM,IAAI,GAAG,QAAQ,iBAAiB;AACpE,QAAI,OAAO,WAAW;AACpB,YAAM,EAAE,MAAM,UAAU,IAAI;AAC5B,eAAS,UAAU;AACnB,WAAK,MAAM,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,SAAS;AAAA,IACtC;AAAA,EACF;AACA,QAAM,qBAAiB,uBAAkC,MAAM;AAAA,EAAC,CAAC;AACjE,iBAAe,UAAU,CAACA,OAAoB;AAC5C,aAAS,UAAU;AACnB,UAAM,UAAU,WAAW;AAC3B,QAAI,CAAC,WAAW,QAAQ,SAAU;AAClC,QAAI,QAAQ,cAAc,QAAQA,GAAE,cAAc,QAAQ,UAAW;AACrE,UAAM,OAAO,SAAS,QAAQ,IAAI;AAClC,UAAM,OAAO,UAAU,EAAE;AAAA,MACvB,CAACE,QAAM,aAAaA,KAAG,QAAQ,EAAE,OAAO,QAAQ,EAAE,KAAK,KAAK,YAAYA,KAAG,IAAI;AAAA,IACjF;AACA,QAAI,KAAM,YAAW,SAAS,IAAI;AAAA,QAC7B,YAAW,OAAO;AAAA,EACzB;AACA,gCAAU,MAAM;AACd,UAAM,OAAO,CAACF,OAAoB,iBAAiB,QAAQA,EAAC;AAC5D,UAAM,KAAK,CAACA,OAAoB,eAAe,QAAQA,EAAC;AACxD,WAAO,iBAAiB,eAAe,IAAI;AAC3C,WAAO,iBAAiB,aAAa,EAAE;AACvC,WAAO,MAAM;AACX,aAAO,oBAAoB,eAAe,IAAI;AAC9C,aAAO,oBAAoB,aAAa,EAAE;AAAA,IAC5C;AAAA,EACF,GAAG,CAAC,CAAC;AAGL,8BAAS,CAAC,GAAG,UAAU;AACrB,UAAM,UAAU,WAAW;AAC3B,QAAI,CAAC,WAAW,QAAQ,SAAU;AAClC,UAAM,QAAQ,UAAU,QAAQ,QAAQ,IAAI;AAC5C,UAAM,SAAS,WAAW,QAAQ,QAAQ,IAAI;AAC9C,QAAI,CAAC,SAAS,CAAC,OAAQ;AACvB,UAAM,KAAK,KAAK,IAAI,OAAO,IAAI,EAAE;AAEjC,QAAI,SAAS;AAEX,cAAQ,EAAE,QAAQ,QAAQ,QAAQ,QAAQ;AAC1C,cAAQ,EAAE,QAAQ,QAAQ,QAAQ,QAAQ;AAC1C,YAAM,SAAS,IAAI,QAAQ;AAC3B,YAAM,SAAS,IAAI,QAAQ;AAC3B,YAAM,SAAS,IAAI,QAAQ,SAAS,SAAS,CAAC,IAAI;AAAA,IACpD,OAAO;AACL,aAAO,QAAQ,GAAG,QAAQ,SAAS,MAAM,EAAE;AAC3C,aAAO,QAAQ,GAAG,QAAQ,SAAS,MAAM,EAAE;AAC3C,YAAM,MAAM,QAAQ,EAAE,QAAQ,QAAQ,SAAS;AAC/C,YAAM,MAAM,QAAQ,EAAE,QAAQ,QAAQ,SAAS;AAC/C,cAAQ,QAAQ,QAAQ,EAAE;AAC1B,cAAQ,QAAQ,QAAQ,EAAE;AAC1B,YAAM,QAAQ,KAAK,MAAM,IAAI,EAAE;AAC/B,YAAM,SAAS,IAAI,QAAQ,EAAE;AAC7B,YAAM,SAAS,IAAI,QAAQ,EAAE;AAC7B,YAAM,SAAS,IAAI,QAAQ,SAAS,SAAS,CAAC,IAAI;AAElD,aAAO,IAAI,SAAS,WAAW,KAAK,CAAC;AACrC,YAAM,MAAM;AACZ,YAAM,SAAS,MAAY,kBAAU,MAAM,CAAC,KAAK,KAAK,MAAM,GAAG,IAAI,MAAM,SAAS,KAAK;AACvF,YAAM,SAAS,MAAY,kBAAU,MAAM,KAAK,MAAM,KAAK,MAAM,GAAG,IAAI,MAAM,SAAS,KAAK;AAAA,IAC9F;AAGA,UAAM,OAAO,SAAS,QAAQ,IAAI;AAClC,UAAM,OAAO,UAAU,EAAE;AAAA,MACvB,CAACE,QAAM,aAAaA,KAAG,MAAM,SAAS,GAAG,MAAM,SAAS,CAAC,KAAK,YAAYA,KAAG,IAAI;AAAA,IACnF;AACA,IAAAH,UAAS,WAAW,MAAM,MAAM,IAAI;AACpC,UAAM,eAAe,OAAO,OAAO,KAAK,QAAQ,SAAS;AACzD,UAAM,MAAM,MAAM,cAAc,MAAM,MAAM,KAAK;AACjD,UAAM,MAAM,IAAI,MAAM,MAAM,IAAI,MAAM,MAAM;AAAA,EAC9C,CAAC;AAKD,QAAM,kBAAc,uBAAmC,IAAI;AAC3D,cAAY,UAAU;AAAA,IACpB,MAAM,CAAC,SAAS;AACd,YAAM,OAAO,MAAM,IAAI;AACvB,UAAI,CAAC,KAAM,QAAO;AAElB,aAAO,KAAK,MAAM,KAAK,SAAS,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC;AAAA,IACtD;AAAA,IACA,aAAa,CAAC,MAAM,WAAW;AAC7B,YAAM,UAAU,WAAW;AAC3B,YAAM,OAAO,UAAU,EAAE,KAAK,CAACG,QAAMA,IAAE,OAAO,MAAM;AACpD,YAAM,QAAQ,UAAU,QAAQ,IAAI;AACpC,UAAI,CAAC,WAAW,QAAQ,SAAS,QAAQ,CAAC,QAAQ,CAAC,MAAO;AAC1D,YAAM,SAAS,IAAI,KAAK,OAAO,SAAS,CAAC;AACzC,YAAM,SAAS,IAAI,KAAK,OAAO,SAAS,CAAC;AACzC,cAAQ,EAAE,QAAQ,MAAM,SAAS;AACjC,cAAQ,EAAE,QAAQ,MAAM,SAAS;AACjC,iBAAW,SAAS,IAAI;AAAA,IAC1B;AAAA,IACA,QAAQ,CAAC,SAAS;AAChB,YAAM,UAAU,WAAW;AAC3B,UAAI,WAAW,QAAQ,SAAS,QAAQ,CAAC,QAAQ,SAAU,YAAW,OAAO;AAAA,IAC/E;AAAA,IACA,SAAS,MAAM,UAAU,EAAE,IAAI,CAACA,QAAMA,IAAE,EAAE;AAAA,IAC1C,WAAW,CAAC,SAAS,WAAW,IAAI,KAAK;AAAA,EAC3C;AACA,gCAAU,MAAM;AACd,UAAM,MAAM,MAAM;AAClB,QAAI,CAAC,IAAK;AACV,QAAI,UAAU;AAAA,MACZ,MAAM,CAAC,SAAS,YAAY,SAAS,KAAK,IAAI,KAAK;AAAA,MACnD,aAAa,CAAC,MAAM,WAAW,YAAY,SAAS,YAAY,MAAM,MAAM;AAAA,MAC5E,QAAQ,CAAC,SAAS,YAAY,SAAS,OAAO,IAAI;AAAA,MAClD,SAAS,MAAM,YAAY,SAAS,QAAQ,KAAK,CAAC;AAAA,MAClD,WAAW,CAAC,SAAS,YAAY,SAAS,UAAU,IAAI,KAAK;AAAA,IAC/D;AACA,WAAO,MAAM;AACX,UAAI,UAAU;AAAA,IAChB;AAAA,EACF,GAAG,CAAC,MAAM,OAAO,CAAC;AAElB,SACE,+CAAC,WACE;AAAA,kBAAc,WAAW,8CAAC,gBAAa,SAAS,cAAc,OAAO,OAAO,SAAkB;AAAA,KAC7F,MAAM,SAAS,CAAC,GAAG,IAAI,CAAC,SACxB,8CAAC,kBAA6B,UAAUH,WAAU,QAAQ,QAArC,KAAK,EAAsC,CACjE;AAAA,IACA,YAAY,IAAI,CAAC,QAAQ,MAAM;AAC9B,YAAM,OAAO,MAAM,CAAC;AACpB,aACE;AAAA,QAAC;AAAA;AAAA,UAGC,KAAK,CAAC,MAAM;AACV,sBAAU,QAAQ,CAAC,IAAI;AAAA,UACzB;AAAA,UACA,UAAU,KAAK;AAAA,UACf,UAAU,KAAK;AAAA,UACf,OAAO,KAAK;AAAA,UACZ,eAAe,CAACC,OAAgC;AAC9C,gBAAI,WAAW,QAAS;AACxB,kBAAM,MAAM,WAAWA,GAAE,SAASA,GAAE,SAAS,KAAK,SAAS,CAAC,CAAC;AAC7D,gBAAI,CAAC,IAAK;AACV,qBAAS,UAAU,EAAE,MAAM,GAAG,WAAWA,GAAE,WAAW,QAAQ,IAAI,CAAC,GAAG,QAAQ,IAAI,CAAC,EAAE;AAAA,UACvF;AAAA,UAEA;AAAA,YAAC;AAAA;AAAA,cACC,KAAK,CAAC,MAAM;AACV,2BAAW,QAAQ,CAAC,IAAI;AAAA,cAC1B;AAAA,cACA,QAAQ;AAAA,cACR,eAAe,MAAM;AAAA,cACrB,eAAe,CAAC,UAAU,YAAY,GAAG,KAAK;AAAA;AAAA,UAChD;AAAA;AAAA,QArBK;AAAA,MAsBP;AAAA,IAEJ,CAAC;AAAA,KACH;AAEJ;;;ACheA,IAAAG,iBAAyB;AA+GnB,IAAAC,uBAAA;AApFC,SAAS,kBACdC,QACA,MACA,KACA,YACoB;AACpB,MAAI,CAACA,QAAO;AAEV,QAAI,QAAQ,WAAW,QAAQ,KAAK;AAClC,aAAO,EAAE,OAAO,WAAW,KAAK,IAAI,IAAI,EAAE,MAAM,WAAW,EAAE,IAAI,MAAM,SAAS,KAAK;AAAA,IACvF;AACA,WAAO,EAAE,OAAAA,QAAO,SAAS,MAAM;AAAA,EACjC;AAEA,MAAIA,OAAM,SAAS,KAAM,QAAO,EAAE,OAAAA,QAAO,SAAS,MAAM;AACxD,QAAM,YAAY,KAAK,IAAI,WAAW,QAAQ,EAAE,QAAQ,CAAC;AACzD,MAAI,QAAQ,gBAAgB,QAAQ,aAAa;AAC/C,WAAO,EAAE,OAAO,EAAE,GAAGA,QAAO,YAAYA,OAAM,YAAY,KAAK,UAAU,GAAG,SAAS,KAAK;AAAA,EAC5F;AACA,MAAI,QAAQ,eAAe,QAAQ,WAAW;AAC5C,WAAO;AAAA,MACL,OAAO,EAAE,GAAGA,QAAO,YAAYA,OAAM,YAAY,IAAI,aAAa,UAAU;AAAA,MAC5E,SAAS;AAAA,IACX;AAAA,EACF;AACA,MAAI,QAAQ,WAAW,QAAQ,KAAK;AAClC,UAAM,OAAO,WAAW,QAAQ,EAAEA,OAAM,SAAS;AACjD,QAAI,KAAM,YAAW,YAAY,MAAM,IAAI;AAC3C,WAAO,EAAE,OAAO,MAAM,SAAS,KAAK;AAAA,EACtC;AACA,MAAI,QAAQ,UAAU;AACpB,eAAW,OAAO,IAAI;AACtB,WAAO,EAAE,OAAO,MAAM,SAAS,KAAK;AAAA,EACtC;AACA,SAAO,EAAE,OAAAA,QAAO,SAAS,MAAM;AACjC;AAEA,IAAM,eAAoC;AAAA,EACxC,UAAU;AAAA,EACV,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,MAAM;AAAA,EACN,YAAY;AAAA,EACZ,QAAQ;AACV;AAQO,SAAS,oBAAoB;AAAA,EAClC;AAAA,EACA;AACF,GAGG;AACD,QAAM,CAAC,UAAU,WAAW,QAAI,yBAAqD,IAAI;AAEzF,QAAM,aAAa,CAAC,MAAsB,MAAsB;AAC9D,QAAI;AACF,YAAM,SAAS,cAAc,EAAE,QAAQ,KAAK,OAAO,CAAC;AACpD,YAAM,UAAU,KAAK,UAAU,cAAc,MAAM,KAAK,OAAO,IAAI,OAAO;AAC1E,aAAO,SAAS,IAAI,CAAC,KAAK,YAAY,EAAE,GAAG,QAAQ,QAAQ,CAAC,CAAC;AAAA,IAC/D,QAAQ;AACN,aAAO,SAAS,IAAI,CAAC;AAAA,IACvB;AAAA,EACF;AAEA,QAAM,YAAY,CAAC,MAAc,CAACC,OAA2B;AAC3D,UAAM,MAAM,WAAW;AACvB,QAAI,CAAC,IAAK;AACV,UAAM,EAAE,OAAAD,QAAO,QAAQ,IAAI,kBAAkB,UAAU,GAAGC,GAAE,KAAK,GAAG;AACpE,QAAI,QAAS,CAAAA,GAAE,eAAe;AAC9B,QAAID,WAAU,SAAU,aAAYA,MAAK;AAAA,EAC3C;AAEA,SACE,+CAAC,cAAS,OAAO,cACf;AAAA,kDAAC,YAAO,gCAAkB;AAAA,IACzB,OAAO,IAAI,CAAC,MAAM,MACjB;AAAA,MAAC;AAAA;AAAA,QAGC,MAAK;AAAA,QACL,WAAW,UAAU,CAAC;AAAA,QACtB,cAAY,WAAW,MAAM,CAAC;AAAA,QAC9B,gBAAc,UAAU,SAAS;AAAA,QAEhC;AAAA,qBAAW,MAAM,CAAC;AAAA,UAClB,UAAU,SAAS,KAClB,+CAAC,UAAK,aAAU,UACb;AAAA;AAAA,YAAI;AAAA,YACa,WAAW,SAAS,QAAQ,EAAE,SAAS,SAAS,KAAK;AAAA,YAAO;AAAA,aAEhF;AAAA;AAAA;AAAA,MAZG;AAAA,IAcP,CACD;AAAA,KACH;AAEJ;;;ACpHA,IAAM,gBAAgB;AAMf,SAAS,qBACd,UACA,QACA,aACA,YACyB;AACzB,QAAM,SAAS,OAAO,cAAc,MAAM;AAAA,IACxC,GAAG,OAAO;AAAA,IACV,GAAG;AAAA,EACL,CAAC;AACD,MAAI,aAAa,QAAS,QAAO;AACjC,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAOO,SAAS,YACd,QACA,GACA,SACAE,QACa;AACb,QAAM,QAAQ,KAAK,MAAMA,OAAM,OAAOA,OAAM,MAAM,IAAI;AACtD,MAAI,KAAK,EAAG,QAAO,EAAE,QAAQ,CAAC,GAAG,GAAG,CAAC,GAAG,MAAM,CAAC,OAAO,OAAO,CAAC,EAAE;AAEhE,QAAM,MAAM,CAAC,UAAU,UAAU,QAAQ;AACzC,QAAM,MAAM,CAAC,WAAW,WAAW,SAAS;AAC5C,WAAS,IAAI,GAAG,IAAI,eAAe,KAAK;AACtC,aAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,YAAM,OAAO,OAAO,KAAK,GAAG,GAAG,SAAS,IAAI,eAAeA,MAAK;AAChE,YAAMC,KAAI,QAAQ,KAAK,IAAI,KAAK,OAAO,CAAC;AACxC,eAAS,OAAO,GAAG,OAAO,GAAG,QAAQ;AACnC,YAAI,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,GAAI,KAAK,SAAS,IAAI,IAAKA,EAAC;AACzD,YAAI,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,GAAI,KAAK,SAAS,IAAI,IAAKA,EAAC;AAAA,MAC3D;AAAA,IACF;AAAA,EACF;AACA,SAAO;AAAA,IACL,QAAQ,EAAE,IAAI,CAAC,IAAK,IAAI,CAAC,KAAM,IAAI,IAAI,CAAC,IAAK,IAAI,CAAC,KAAM,IAAI,IAAI,CAAC,IAAK,IAAI,CAAC,KAAM,CAAC;AAAA,IAClF,MAAM,EAAE,IAAI,CAAC,IAAK,IAAI,CAAC,KAAM,IAAI,IAAI,CAAC,IAAK,IAAI,CAAC,KAAM,IAAI,IAAI,CAAC,IAAK,IAAI,CAAC,KAAM,CAAC;AAAA,EAClF;AACF;AAGA,IAAM,OAAO;AACb,IAAMC,OAAM,KAAK,KAAK;AASf,SAAS,UACd,QACA,GACA,SACAF,QACA,QACA,QACA,SAAS,MACiE;AAC1E,QAAM,EAAE,OAAO,IAAI,YAAY,QAAQ,GAAG,SAASA,MAAK;AACxD,QAAM,QAAS,KAAK,MAAMA,OAAM,OAAOA,OAAM,MAAM,IAAI,IAAK;AAC5D,QAAM,OAAO,KAAK,IAAK,SAASE,OAAO,CAAC;AACxC,QAAM,OAAO,OAAO,KAAK,IAAI,QAAQ,IAAI;AAEzC,MAAI,WAAW;AACf,WAAS,IAAI,GAAG,IAAI,eAAe,KAAK;AACtC,aAAS,IAAI,GAAG,IAAI,KAAK,IAAI,GAAG,CAAC,GAAG,KAAK;AACvC,YAAM,OAAO,OAAO,KAAK,GAAG,GAAG,SAAS,IAAI,eAAeF,MAAK;AAChE,YAAMC,KAAI,QAAQ,KAAK,IAAI,KAAK,OAAO,CAAC;AAGxC,YAAM,QAAQ,KAAK,SAAS,CAAC,IAAK,OAAO,CAAC;AAC1C,iBAAW,KAAK;AAAA,QACd;AAAA,SACC,KAAK,IAAI,KAAK,SAAS,CAAC,IAAK,OAAO,CAAC,CAAE,IAAIA,MAAK,OAAO;AAAA,SACvD,KAAK,IAAI,KAAK,SAAS,CAAC,IAAK,OAAO,CAAC,CAAE,IAAIA,MAAK,OAAO;AAAA,MAC1D;AAAA,IACF;AAAA,EACF;AACA,SAAO;AAAA,IACL,UAAU,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,WAAW,MAAM,OAAO,CAAC,IAAI,QAAQ;AAAA,IACvE,QAAQ;AAAA,EACV;AACF;;;AdyGU,IAAAE,uBAAA;AAnHH,IAAM,qBAAiB;AAAA,EAC5B,SAASC,gBAAe,OAAO,KAAK;AAClC,UAAM,UAAU,wBAAwB,MAAM,aAAa;AAE3D,UAAM,aAAS;AAAA,MACb,MAAM,qBAAqB,MAAM,QAAQ,MAAM,MAAM;AAAA,MACrD,CAAC,MAAM,QAAQ,MAAM,MAAM;AAAA,IAC7B;AAIA,UAAM,eAAe,UAAU,MAAM;AACrC,UAAM,eAAe,UAAU,MAAM,UAAU,IAAI;AACnD,UAAM,aAAS;AAAA,MACb,MAAM,iBAAiB,cAAc,gBAAgB,MAAS;AAAA,MAC9D,CAAC,cAAc,YAAY;AAAA,IAC7B;AACA,UAAM,QAAQ,OAAO;AAErB,UAAM,WAAW,MAAM,UAAU;AACjC,UAAM,SAAS,UAAU,QAAQ;AACjC,UAAM,aAAa,OAAO,CAAC,GAAG,OAAO;AACrC,UAAM,sBAAsB,UAAU,MAAM,iBAAiB,CAAC,CAAC;AAE/D,UAAM,oBAAgB;AAAA;AAAA;AAAA,MAGpB,MAAM,qBAAqB,UAAU,QAAQ,qBAAqB,UAAU;AAAA,MAC5E,CAAC,UAAU,qBAAqB,YAAY,OAAO,YAAY,MAAM;AAAA,IACvE;AAIA,UAAM,eAAW,uBAAO,CAAC;AACzB,UAAM,iBAAa,uBAAO,CAAC;AAC3B,UAAM,mBAAe,uBAAO,EAAE;AAC9B,UAAM,eAAW,uBAA4C,EAAE,MAAM,MAAM,GAAG,EAAE,CAAC;AACjF,UAAM,iBAAa,uBAAO,EAAE,IAAI,UAAU,SAAS,cAAc,CAAC;AAClE,UAAM,SAAK,yBAAS,CAAC,MAAM,EAAE,EAAE;AAE/B,UAAM,SAAS,UAAU,SAAU,MAAM,QAAQ,UAAU;AAC3D,UAAM,QAAQ,MAAM,QAAQ,SAAS;AACrC,UAAM,eAAe,UAAU,SAAU,MAAM,UAAU,QAAQ;AAEjE,kCAAU,MAAM;AACd,YAAM,OAAO,WAAW;AACxB,UAAI,KAAK,OAAO,YAAY,KAAK,UAAU,KAAK,OAAO,MAAM,KAAK,UAAU,aAAa,GAAG;AAC1F,iBAAS,UAAU,EAAE,MAAM,MAAM,GAAG,EAAE;AACtC,0BAAK,GAAG,SAAS,SAAS,EAAE,GAAG,GAAG,UAAU,KAAK,MAAM,eAAe,CAAC;AACvE,mBAAW,UAAU,EAAE,IAAI,UAAU,SAAS,cAAc;AAAA,MAC9D;AAAA,IACF,GAAG,CAAC,UAAU,aAAa,CAAC;AAE5B,kCAAU,MAAM;AACd,UAAI,WAAW,OAAQ;AACvB,YAAM,KAAK,GAAG;AACd,UAAI,QAAuB;AAC3B,YAAM,OAAO,CAACC,OAAoB;AAChC,gBAAQA,GAAE;AAAA,MACZ;AACA,YAAM,OAAO,CAACA,OAAoB;AAChC,YAAI,UAAU,KAAM;AACpB,cAAM,KAAKA,GAAE,UAAU;AACvB,gBAAQA,GAAE;AACV,iBAAS,WAAW,KAAK;AACzB,mBAAW,UAAU,KAAK;AAAA,MAC5B;AACA,YAAM,KAAK,MAAM;AACf,gBAAQ;AAAA,MACV;AACA,SAAG,iBAAiB,eAAe,IAAI;AACvC,aAAO,iBAAiB,eAAe,IAAI;AAC3C,aAAO,iBAAiB,aAAa,EAAE;AACvC,aAAO,MAAM;AACX,WAAG,oBAAoB,eAAe,IAAI;AAC1C,eAAO,oBAAoB,eAAe,IAAI;AAC9C,eAAO,oBAAoB,aAAa,EAAE;AAAA,MAC5C;AAAA,IACF,GAAG,CAAC,QAAQ,EAAE,CAAC;AAEf,iCAAS,CAAC,EAAE,MAAM,GAAG,UAAU;AAC7B,UAAI,aAAa,UAAU,EAAG,cAAa,UAAU,MAAM;AAC3D,UAAI,WAAW,WAAY,UAAS,WAAW,QAAQ,QAAQ;AAC/D,UAAI,WAAW,QAAQ;AACrB,iBAAS,WAAW,WAAW,UAAU;AACzC,mBAAW,WAAW;AAAA,MACxB;AAAA,IACF,CAAC;AAED,UAAM,SAAuB;AAAA,MAC3B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,OAAO,cAAc;AAAA,MACrB;AAAA,MACA,SAAS,MAAM,UAAU,WAAW;AAAA,MACpC,kBAAkB,MAAM,UAAU,YAAY;AAAA,MAC9C;AAAA,MACA;AAAA,IACF;AAKA,UAAM,cACJ,MAAM,gBAAgB,OAAO,KAAK,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,KAAK,CAAC,MAAM,QAAQ,EAAE,OAAO,MAAM,CAAC;AAEnG,UAAM,UAAU,aAAa;AAC7B,UAAM,eAAe,UAAW,gBAAuC;AAEvE,QAAI,aAAa;AACf,aACE,8CAAC,WAAM,KACL;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA,UAAU,MAAM;AAAA,UAChB;AAAA,UACA;AAAA,UACA;AAAA,UACA,OAAO,cAAc;AAAA,UACrB,eAAe,MAAM;AAAA,UACrB,OAAO,MAAM;AAAA,UACb,mBAAmB,MAAM;AAAA,UACzB,SAAS,MAAM;AAAA,UACf,SAAS,MAAM;AAAA;AAAA,MACjB,GACF;AAAA,IAEJ;AAEA,WACE,+CAAC,WAAM,KACJ;AAAA,oBAAc,WAAW,8CAAC,gBAAa,SAAS,cAAc,OAAO,OAAO,SAAS,WAAW;AAAA,MAChG,OAAO,IAAI,CAAC,OAAO,OAClB;AAAA,QAAC;AAAA;AAAA,UAGC;AAAA,UACA;AAAA,UACA,UAAU,MAAM;AAAA,UAChB,gBAAgB,MAAM;AAAA;AAAA,QAJjB,GAAG,EAAE,IAAI,MAAM,QAAQ,MAAM;AAAA,MAKpC,CACD;AAAA,OACH;AAAA,EAEJ;AACF;AAQA,SAAS,UAAU,WAAgC;AACjD,QAAM,aAAS,yBAAS,CAAC,MAAM,EAAE,MAAM;AACvC,QAAM,YAAQ,yBAAS,CAAC,MAAM,EAAE,KAAK,KAAK;AAC1C,QAAM,aAAS,yBAAS,CAAC,MAAM,EAAE,KAAK,MAAM;AAI5C,QAAM,aAAa,UAAU,UAAU,UAAU,IAAI;AACrD,QAAM,aAAa,UAAU,UAAU,UAAU,IAAI;AACrD,QAAM,aAAa,UAAU,UAAU,UAAU,IAAI;AACrD,QAAM,cAAc,UAAU,UAAU,iBAAiB,CAAC,CAAC;AAC3D,QAAM,YAAQ,wBAAQ,MAAM;AAC1B,UAAM,SAAS,qBAAqB,cAAc,QAAW,cAAc,MAAS;AACpF,UAAM,WAAW,UAAU,UAAU;AACrC,UAAM,SAAS,UAAU,QAAQ;AACjC,UAAMC,SAAQ,iBAAiB,QAAQ,cAAc,MAAS,EAAE,CAAC,GAAG,OAAO;AAC3E,UAAM,UAAU,qBAAqB,UAAU,QAAQ,aAAaA,MAAK;AACzE,WAAO,EAAE,QAAQ,GAAG,OAAO,QAAQ,SAAS,OAAOA,UAAS,cAAc;AAAA,EAC5E,GAAG,CAAC,YAAY,YAAY,YAAY,UAAU,QAAQ,WAAW,CAAC;AAEtE,gCAAU,MAAM;AACd,QAAI,EAAE,kBAAwB,2BAAoB;AAClD,UAAM,EAAE,UAAU,OAAO,IAAI;AAAA,MAC3B,MAAM;AAAA,MACN,MAAM;AAAA,MACN,MAAM;AAAA,MACN,MAAM;AAAA,MACN,OAAO;AAAA,MACP,QAAQ,KAAK,IAAI,QAAQ,CAAC;AAAA,IAC5B;AACA,WAAO,SAAS,IAAI,GAAG,QAAQ;AAC/B,WAAO,OAAO,GAAG,MAAM;AACvB,WAAO,uBAAuB;AAAA,EAChC,GAAG,CAAC,QAAQ,OAAO,QAAQ,KAAK,CAAC;AAEjC,SAAO;AACT;AAGO,IAAM,iBAAa,2BAAyC,SAASC,YAC1E,EAAE,UAAU,WAAW,OAAO,OAAO,GAAG,UAAU,GAClD,KACA;AACA,QAAM,MAAM,YAAY,MAAM,SAAS,CAAC,CAAC;AACzC,QAAMC,gBAAW,wBAAQ,MAAM,IAAI,iBAAiB,GAAG,CAAC,CAAC;AACzD,QAAM,cAAU,uBAAmC,IAAI;AAKvD,QAAM,aAAS;AAAA,IACb,MAAM,qBAAqB,UAAU,QAAQ,UAAU,MAAM;AAAA,IAC7D,CAAC,UAAU,QAAQ,UAAU,MAAM;AAAA,EACrC;AACA,QAAM,eAAe,UAAU,MAAM;AACrC,QAAM,eAAe,UAAU,UAAU,UAAU,IAAI;AACvD,QAAM,kBAAc;AAAA,IAClB,MAAM,mBAAmB,cAAc,gBAAgB,QAAW,UAAU,WAAW;AAAA,IACvF,CAAC,cAAc,cAAc,UAAU,WAAW;AAAA,EACpD;AAEA,SACE,8CAAC,SAAI,WAAsB,OAAO,EAAE,OAAO,QAAQ,QAAQ,QAAQ,GAAG,MAAM,GAC1E,yDAAC,gBAAgB,UAAhB,EAAyB,OAAOA,WAC/B;AAAA,mDAAC,yBAAO,SAAO,MAAC,QAAQ,EAAE,UAAU,CAAC,GAAG,KAAK,GAAG,GAAG,KAAK,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,GACtE;AAAA,oDAAC,aAAW,GAAG,WAAW;AAAA,MAC1B,8CAAC,iBAAc,UAAU,IAAI,UAAU;AAAA,MAGvC,8CAAC,iBAAc,QAAQ,IAAI,UAAU,OAAO,IAAI,OAAO,OAAO,MAAM,OAAO,IAAI;AAAA,MAC/E,8CAAC,kBAAe,KAAU,mBAAmB,SAAU,GAAG,WAAW;AAAA,MACpE;AAAA,MACD,8CAAC,2BAAwB;AAAA,OAC3B;AAAA,IACC,eAAe,8CAAC,uBAAoB,QAAgB,YAAY,SAAS;AAAA,KAC5E,GACF;AAEJ,CAAC;;;AepUD,SAAS,cAAcC,IAA0C;AAC/D,SAAO,OAAOA,OAAM,YAAYA,OAAM,QAAQ,CAAC,MAAM,QAAQA,EAAC;AAChE;AAGA,SAAS,YACP,OACA,UACA,OAAiB,CAAC,GACO;AACzB,QAAM,MAA+B,CAAC;AACtC,aAAW,CAAC,KAAKA,EAAC,KAAK,OAAO,QAAQ,KAAK,GAAG;AAC5C,QAAI,KAAK,SAAS,GAAG,GAAG;AACtB,UAAI,GAAG,IAAIA;AACX;AAAA,IACF;AACA,QAAI,KAAK,UAAUA,EAAC,MAAM,KAAK,UAAU,SAAS,GAAG,CAAC,GAAG;AACvD,UAAI,GAAG,IACL,cAAcA,EAAC,KAAK,cAAc,SAAS,GAAG,CAAC,IAC3C,YAAYA,IAAG,SAAS,GAAG,CAA4B,IACvDA;AAAA,IACR;AAAA,EACF;AACA,SAAO;AACT;AAGO,SAAS,WAAW,QAAuC;AAChE,QAAM,OAAO,kBAAkB,MAAM,CAAC,CAAC;AACvC,QAAM,MAA+B,CAAC;AAEtC,QAAMC,SAAQ,YAAY,OAAO,OAAgB,YAAY,MAAM,CAAC,CAAC,CAAU;AAC/E,MAAI,OAAO,KAAKA,MAAK,EAAE,SAAS,EAAG,KAAI,QAAQA;AAE/C,MAAI,OAAO,UAAU,KAAK,MAAO,KAAI,QAAQ,OAAO;AAEpD,MAAI,OAAO,QAAQ,SAAS,SAAS;AAEnC,UAAM,WAAW,cAAc;AAAA,MAC7B,OAAO,QAAQ,SAAS,UACpB,EAAE,MAAM,SAAS,KAAK,OAAO,QAAQ,IAAI,IACzC,EAAE,MAAM,OAAO,QAAQ,KAAK;AAAA,IAClC;AACA,QAAI,UAAU;AAAA,MACZ,MAAM,OAAO,QAAQ;AAAA,MACrB,GAAG,YAAY,OAAO,SAAkB,UAAU,OAAO,QAAQ,SAAS,UAAU,CAAC,KAAK,IAAI,CAAC,CAAC;AAAA,IAClG;AAAA,EACF;AAEA,MAAI,OAAO,UAAU;AACnB,UAAM,WAAW,qBAAqB,MAAM,EAAE,MAAM,OAAO,SAAS,KAAK,CAAC;AAC1E,QAAI,WAAW,EAAE,MAAM,OAAO,SAAS,MAAM,GAAG,YAAY,OAAO,UAAmB,QAAQ,EAAE;AAAA,EAClG;AACA,MAAI,OAAO,UAAW,KAAI,YAAY,OAAO;AAE7C,MAAI,OAAO,KAAK,OAAO,OAAO,EAAE,SAAS,EAAG,KAAI,UAAU,OAAO;AAOjE,QAAM,SAAS,YAAY,OAAO,QAAiB,aAAa,MAAM,CAAC,CAAC,CAAU;AAClF,MAAI,OAAO,KAAK,MAAM,EAAE,SAAS,EAAG,KAAI,SAAS;AAEjD,MAAI,OAAO,OAAO,YAAY,UAAU;AACtC,UAAM,WAAW,kBAAkB,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC1D,QAAI,UAAU,EAAE,MAAM,SAAS,GAAG,YAAY,OAAO,SAAkB,QAAQ,EAAE;AAAA,EACnF,WAAW,OAAO,YAAY,QAAQ;AACpC,QAAI,UAAU,OAAO;AAAA,EACvB;AAQA,QAAM,QAAQ,YAAY,OAAO,OAAgB,YAAY,MAAM,CAAC,CAAC,CAAU;AAC/E,MAAI,OAAO,KAAK,KAAK,EAAE,SAAS,EAAG,KAAI,QAAQ;AAC/C,MAAI,OAAO,OAAQ,KAAI,SAAS;AAEhC,MAAI,OAAO,OAAQ,KAAI,SAAS,OAAO;AACvC,QAAM,OAAO,YAAY,OAAO,MAAe,kBAAkB,MAAM,CAAC,CAAC,EAAE,IAAa;AACxF,MAAI,OAAO,KAAK,IAAI,EAAE,SAAS,EAAG,KAAI,OAAO;AAE7C,SAAO;AACT;AAGA,SAAS,SAAS,OAAwB;AACxC,MAAI,OAAO,UAAU,SAAU,QAAO,IAAI,KAAK;AAC/C,SAAO,IAAI,KAAK,UAAU,KAAK,CAAC;AAClC;AAqBO,SAAS,eAAkB,OAA0C;AAC1E,MAAI,WAAW;AACf,QAAM,OAAO,CAAC,SAA2B;AACvC,QAAI,OAAO,SAAS,UAAU;AAC5B,UAAI,CAAC,KAAK,WAAW,OAAO,EAAG,QAAO;AACtC;AACA,YAAM,YAAY,KAAK,WAAW,gBAAgB,IAAI,QAAQ;AAC9D,aAAO,mBAAmB,QAAQ,IAAI,SAAS;AAAA,IACjD;AACA,QAAI,MAAM,QAAQ,IAAI,EAAG,QAAO,KAAK,IAAI,IAAI;AAC7C,QAAI,QAAQ,OAAO,SAAS,UAAU;AACpC,aAAO,OAAO,YAAY,OAAO,QAAQ,IAAI,EAAE,IAAI,CAAC,CAACC,IAAGF,EAAC,MAAM,CAACE,IAAG,KAAKF,EAAC,CAAC,CAAC,CAAC;AAAA,IAC9E;AACA,WAAO;AAAA,EACT;AACA,SAAO,EAAE,OAAO,KAAK,KAAK,GAAQ,SAAS;AAC7C;AAGO,IAAM,cACX;AAMK,SAAS,gBAAgB,QAA6B;AAC3D,QAAM,SAAS,WAAW,MAAM;AAChC,SAAO,OAAO;AACd,QAAM,EAAE,OAAO,MAAM,SAAS,IAAI,eAAe,MAAM;AACvD,QAAM,QAAQ,OAAO,QAAQ,IAAI,EAAE,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM,KAAK,GAAG,IAAI,SAAS,KAAK,CAAC,EAAE;AACtF,MAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,QAAM,UAAU;AAAA,EAAW,MAAM,KAAK,IAAI,CAAC;AAAA;AAC3C,SAAO,WAAW,IAAI,GAAG,WAAW;AAAA,EAAK,OAAO,KAAK;AACvD;;;ACtJO,IAAM,wBAAwB;AAErC,IAAM,mBAA2E;AAAA,EAC/E,MAAM,CAAC,MAAM,OAAO,OAAO,EAAE,UAAU,cAAc,EAAE,QAAQ,KAAK,GAAG,CAAC;AAAA,EACxE,QAAQ,CAAC,MACN,EAAE,WAAsB,OACrB,2CACA;AAAA,EACN,MAAM,MAAM;AAAA,EACZ,eAAe,MAAM;AAAA,EACrB,MAAM,MAAM;AAAA,EACZ,KAAK,MAAM;AAAA,EACX,MAAM,MAAM;AAAA,EACZ,QAAQ,CAAC,MACP,qEAAqE,KAAK,MAAO,EAAuB,OAAO,GAAG,CAAC;AAAA,EACrH,QAAQ,CAAC,MACN,EAAwB,QAAQ,MAC7B,sEACA;AAAA,EACN,OAAO,MAAM;AAAA,EACb,QAAQ,CAAC,MACP,EAAE,SAAS,SAAS,8CAA8C;AAAA,EACpE,SAAS,CAAC,MACP,EAAE,WAAsB,MACrB,wDACC,EAAE,WAAsB,MACvB,oFACA;AACV;AAGO,SAAS,eAAe,QAA6B;AAC1D,QAAM,QAAQ,SAAS,OAAO,KAAK;AACnC,QAAM,OAAO,GAAG,OAAO,MAAM,KAAK,OAAI,OAAO,MAAM,MAAM;AAEzD,MAAI,gBAAgB;AACpB,MAAI,OAAO,QAAQ,SAAS,QAAS,iBAAgB;AACrD,MAAI,OAAO,QAAQ,SAAS,OAAQ,iBAAgB;AACpD,MAAI,OAAO,QAAQ,SAAS,UAAW,iBAAgB,wBAAwB,OAAO,QAAQ,KAAK;AAEnG,QAAM,QAAQ,CAAC,GAAG,aAAa,OAAO,MAAM,MAAM,YAAY,CAAC,iBAAiB,IAAI,GAAG;AAEvF,MAAI,OAAO,OAAO,YAAY,UAAU;AACtC,UAAM,MAAM,OAAO;AACnB,UAAM;AAAA,MACJ,IAAI,SAAS,UACT,gGACA,IAAI,SAAS,SACX,kCACA,WAAW,IAAI,IAAI;AAAA,IAC3B;AAAA,EACF,WAAW,OAAO,UAAU;AAC1B,UAAM,SAAS,iBAAiB,OAAO,SAAS,IAAI;AACpD,QAAI,OAAQ,OAAM,KAAK,OAAO,OAAO,QAAmC,CAAC;AAAA,EAC3E;AAEA,MAAI,OAAO,QAAQ,QAAQ;AACzB,UAAM;AAAA,MACJ,kBAAkB,OAAO,QAAQ,OAAO,MAAM,KAAK,OAAO,CAAC,QAAQ,OAAO,QAAQ,OAAO,MAAM,SAAS,IAAI,MAAM,EAAE;AAAA,IACtH;AAAA,EACF;AACA,OAAK,OAAO,QAAQ,SAAS,KAAK,IAAK,OAAM,KAAK,2BAA2B;AAE7E,SAAO,MAAM,KAAK,IAAI;AACxB;AAEA,SAAS,cAAc,QAA6B;AAClD,QAAM,MAAM,OAAO,KAAK,SAAS,aAAa,kBAAkB,OAAO,KAAK;AAC5E,QAAM,SAAS,IACZ,QAAQ,qBAAqB,CAAC,GAAGG,OAAcA,GAAE,YAAY,CAAC,EAC9D,QAAQ,MAAM,CAACA,OAAMA,GAAE,YAAY,CAAC,EACpC,QAAQ,iBAAiB,EAAE;AAC9B,SAAO,YAAY,KAAK,MAAM,IAAI,SAAS,QAAQ,MAAM;AAC3D;AAGO,SAAS,kBAAkB,QAA6B;AAC7D,QAAM,OAAO,cAAc,MAAM;AAIjC,QAAM,EAAE,OAAO,UAAU,SAAS,IAAI,eAAe,WAAW,MAAM,CAAC;AACvE,QAAM,SAAS,KAAK,UAAU,UAAU,MAAM,CAAC;AAC/C,QAAM,aAAa,WAAW,IAAI,GAAG,WAAW;AAAA,IAAO;AAEvD,SAAO,oFAAoF,qBAAqB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gDAMlE,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMlD,UAAU,kBAAkB,OAAO,QAAQ,OAAO,IAAI,CAAC;AAAA;AAAA,kBAEvC,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gDAQ0B,eAAe,MAAM,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOtE;;;ACnFA,IAAM,kBAAkB,EAAE,QAAQ,YAAY,OAAO,IAAI;AACzD,IAAM,oBAAoB,EAAE,MAAM,QAAQ,SAAS,MAAM,UAAU,IAAI;AAEvE,SAAS,MAAM,MAAsB;AACnC,QAAM,KAAK,KAAK,QAAQ,qBAAqB,CAAC,GAAGC,OAAcA,GAAE,YAAY,CAAC,EAAE,QAAQ,iBAAiB,EAAE;AAC3G,QAAM,OAAO,YAAY,KAAK,EAAE,IAAI,KAAK,SAAS,EAAE;AACpD,SAAO,KAAK,OAAO,CAAC,EAAE,YAAY,IAAI,KAAK,MAAM,CAAC;AACpD;AASO,SAAS,qBAAqB,OAA2C;AAC9E,QAAM,QAAQ,oBAAI,IAA4B;AAC9C,QAAM,YAAY,oBAAI,IAAY;AAClC,aAAW,SAAS,MAAM,QAAQ;AAChC,UAAM,MAAM,KAAK,UAAU,MAAM,MAAM;AACvC,QAAI,MAAM,IAAI,GAAG,EAAG;AACpB,QAAI,UAAU,MAAM,MAAM,UAAU;AACpC,WAAO,UAAU,IAAI,OAAO,EAAG,YAAW;AAC1C,cAAU,IAAI,OAAO;AACrB,UAAM,IAAI,KAAK,EAAE,SAAS,YAAY,MAAM,YAAY,QAAQ,MAAM,OAAO,CAAC;AAAA,EAChF;AACA,SAAO,CAAC,GAAG,MAAM,OAAO,CAAC;AAC3B;AAWA,SAAS,WACP,OACA,UACyB;AACzB,QAAM,MAA+B,CAAC;AACtC,aAAW,CAACC,IAAGC,EAAC,KAAK,OAAO,QAAQ,SAAS,CAAC,CAAC,GAAG;AAChD,QAAIA,OAAM,OAAW;AACrB,UAAMC,QAAOD,OAAM,SAASD,EAAC,KAAK,KAAK,UAAUC,EAAC,MAAM,KAAK,UAAU,SAASD,EAAC,CAAC;AAClF,QAAI,CAACE,MAAM,KAAIF,EAAC,IAAIC;AAAA,EACtB;AACA,SAAO;AACT;AAGO,SAAS,eAAe,OAAkD;AAC/E,QAAM,MAA+B,EAAE,QAAQ,MAAM,OAAO;AAC5D,QAAM,SAAS,UAAU,MAAM,MAAM;AACrC,QAAM,gBAAgB,WAAW,MAAM,iBAAiB,CAAC,GAAG,OAAO,QAAmC;AACtG,MAAI,OAAO,KAAK,aAAa,EAAE,SAAS,EAAG,KAAI,gBAAgB;AAC/D,QAAM,SAAS,WAAW,MAAM,QAAQ,eAAe;AACvD,MAAI,OAAO,KAAK,MAAM,EAAE,SAAS,EAAG,KAAI,SAAS;AACjD,QAAM,WAAW,WAAW,MAAM,UAAU,iBAAiB;AAC7D,MAAI,OAAO,KAAK,QAAQ,EAAE,SAAS,EAAG,KAAI,WAAW;AAIrD,QAAM,QAAQ;AAAA,IACZ,YAAY,MAAM,MAAM,SAAS,CAAC,CAAC;AAAA,IACnC,YAAY,MAAM,CAAC,CAAC;AAAA,EACtB;AACA,MAAI,OAAO,KAAK,KAAK,EAAE,SAAS,EAAG,KAAI,QAAQ;AAC/C,SAAO;AACT;AAEA,IAAM,iBAAyC;AAAA,EAC7C,MAAM;AAAA,EACN,KAAK;AAAA,EACL,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,MAAM;AAAA,EACN,OAAO;AAAA,EACP,OAAO;AAAA,EACP,MAAM;AAAA,EACN,WAAW;AAAA,EACX,MAAM;AAAA,EACN,OAAO;AACT;AAGO,SAAS,oBAAoB,OAAiC;AACnE,QAAM,IAAI,MAAM,OAAO;AACvB,QAAM,WAAW,MAAM,OAAO,KAAK,CAACE,OAAMA,GAAE,OAAO,UAAUA,GAAE,MAAM;AACrE,QAAM,QAAQ,MAAM,SAAS,CAAC;AAC9B,QAAM,QAAkB,CAAC;AAEzB,MAAI,MAAM,WAAW,SAAS;AAC5B,UAAM,OAAO,OAAO,MAAM,eAAe,QAAQ,CAAC;AAClD,UAAM,UAAU,OAAO,MAAM,eAAe,WAAW,CAAC;AACxD,UAAM,KAAK,KAAK,IAAI,OAAI,OAAO,sCAAsC;AAAA,EACvE,OAAO;AACL,UAAM,eAAe,eAAe,MAAM,MAAM,KAAK,KAAK,MAAM,MAAM;AACtE,UAAM,KAAK,GAAG,CAAC,uBAAuB,YAAY,EAAE;AAAA,EACtD;AAEA,QAAM,SAAS,MAAM,QAAQ,UAAU;AACvC,MAAI,UAAU;AAEZ,UAAM,KAAK,sDAAsD;AACjE,QAAI,MAAM,SAAS,GAAG;AACpB,YAAM;AAAA,QACJ,oEAAoE,MACjE,IAAI,CAACC,QAAMA,IAAE,EAAE,EACf,KAAK,MAAM,CAAC;AAAA,MACjB;AAAA,IACF;AAAA,EACF,OAAO;AACL,QAAI,WAAW,WAAY,OAAM,KAAK,8BAA8B;AACpE,QAAI,WAAW,OAAQ,OAAM,KAAK,qCAAqC;AACvE,QAAI,MAAM,SAAS,EAAG,OAAM,KAAK,GAAG,MAAM,MAAM,aAAa,MAAM,SAAS,IAAI,MAAM,EAAE,EAAE;AAAA,EAC5F;AAEA,QAAM,WAAW,qBAAqB,KAAK;AAC3C,MAAI,SAAS,SAAS,GAAG;AACvB,UAAM,KAAK,UAAU,SAAS,MAAM,mBAAmB,SAAS,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,IAAI,CAAC,GAAG;AAAA,EACxG;AACA,SAAO,MAAM,KAAK,IAAI;AACxB;AAGO,SAAS,0BAA0B,OAAiC;AACzE,QAAM,WAAW,qBAAqB,KAAK;AAC3C,QAAM,WAAW,IAAI,IAAI,SAAS,IAAI,CAAC,MAAM,CAAC,KAAK,UAAU,EAAE,MAAM,GAAG,EAAE,OAAO,CAAC,CAAC;AAInF,QAAM,SAAS,SACZ;AAAA,IACC,CAAC,MACC,SAAS,EAAE,OAAO,MAAM,KAAK,UAAU,WAAW,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC;AAAA,EACzE,EACC,KAAK,MAAM;AAEd,QAAM,QAAQ,MAAM,OACjB,IAAI,CAAC,UAAU;AACd,UAAM,UAAU,SAAS,IAAI,KAAK,UAAU,MAAM,MAAM,CAAC;AACzD,UAAM,UAAU,MAAM,UAAU,cAAc,KAAK,UAAU,MAAM,OAAO,CAAC,KAAK;AAChF,UAAM,SAAS,MAAM,SAAS,aAAa,KAAK,UAAU,MAAM,MAAM,CAAC,KAAK;AAC5E,WAAO,eAAe,OAAO,GAAG,OAAO,GAAG,MAAM;AAAA,EAClD,CAAC,EACA,KAAK,IAAI;AAEZ,QAAM,QAAQ,OAAO,QAAQ,eAAe,KAAK,CAAC,EAC/C;AAAA,IAAI,CAAC,CAAC,KAAK,KAAK,MACf,OAAO,UAAU,WAAW,SAAS,GAAG,KAAK,KAAK,MAAM,SAAS,GAAG,KAAK,KAAK,UAAU,KAAK,CAAC;AAAA,EAChG,EACC,KAAK,IAAI;AAEZ,QAAM,QAAQ,MAAM,SAAS,CAAC;AAC9B,QAAM,aAAa,MAAM,SAAS,IAAI,eAAe;AACrD,QAAM,eAAe,MAClB,IAAI,CAAC,SAAS;AACb,UAAM,SAAS,KAAK,SAAS,YAAY,KAAK,UAAU,KAAK,MAAM,CAAC,MAAM;AAC1E,UAAM,YAAY,KAAK,aAAa,KAAK,cAAc,SAAS,eAAe,KAAK,SAAS,MAAM;AACnG,WAAO;AAAA,cACC,KAAK,EAAE,IAAI,MAAM;AAAA,kBACb,KAAK,UAAU,KAAK,MAAM,CAAC,IAAI,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOtD,CAAC,EACA,KAAK,IAAI;AAEZ,MAAI,MAAM,WAAW,GAAG;AACtB,WAAO,kEAAkE,UAAU;AAAA;AAAA,EAErF,MAAM;AAAA;AAAA;AAAA,EAGN,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOL,KAAK;AAAA;AAAA;AAAA;AAAA,EAIL;AAEA,SAAO,kEAAkE,UAAU;AAAA;AAAA,EAEnF,MAAM;AAAA;AAAA;AAAA,EAGN,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOL,KAAK;AAAA;AAAA,EAEL,YAAY;AAAA;AAAA;AAAA;AAId;AAGO,SAAS,uBAAuB,OAAiC;AACtE,SAAO,kFAAkF,qBAAqB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAW9G,0BAA0B,KAAK,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gDAMc,oBAAoB,KAAK,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAO1E;;;AC7RA,IAAAC,UAAuB;AAevB,IAAM,OAAO;AAEN,IAAM,iBAAiB;AAgBvB,IAAM,cAA4B;AAAA,EACvC;AAAA,IACE,MAAM;AAAA,IACN,OAAO,CAAC,EAAE,MAAM,QAAQ,SAAS,EAAE,OAAO,IAAI,UAAU,GAAG,QAAQ,MAAM,WAAW,KAAK,EAAE,CAAC;AAAA,IAC5F,OAAO,EAAE,OAAO,GAAG,QAAQ,IAAI;AAAA,IAC/B,GAAG;AAAA,EACL;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,OAAO,CAAC,EAAE,MAAM,QAAQ,SAAS,EAAE,OAAO,KAAK,UAAU,MAAM,QAAQ,MAAM,WAAW,KAAM,EAAE,CAAC;AAAA,IACjG,OAAO,EAAE,OAAO,GAAG,QAAQ,IAAI;AAAA,IAC/B,GAAG;AAAA,EACL;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,OAAO,CAAC,EAAE,MAAM,QAAQ,SAAS,EAAE,QAAQ,gBAAgB,QAAQ,MAAM,QAAQ,KAAK,MAAM,EAAE,EAAE,CAAC;AAAA,IACjG,OAAO,EAAE,OAAO,KAAK,QAAQ,EAAE;AAAA,IAC/B,GAAG;AAAA,EACL;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,OAAO,CAAC,EAAE,MAAM,QAAQ,SAAS,EAAE,QAAQ,YAAY,QAAQ,KAAK,QAAQ,KAAK,MAAM,GAAG,EAAE,CAAC;AAAA,IAC7F,OAAO,EAAE,OAAO,GAAG,QAAQ,EAAE;AAAA,IAC7B,GAAG;AAAA,EACL;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,OAAO,CAAC,EAAE,MAAM,QAAQ,SAAS,EAAE,WAAW,KAAK,OAAO,GAAG,EAAE,CAAC;AAAA,IAChE,OAAO,EAAE,OAAO,GAAG,QAAQ,IAAI;AAAA,IAC/B,GAAG;AAAA,EACL;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAQE,MAAM;AAAA,IACN,OAAO,CAAC,EAAE,MAAM,QAAQ,SAAS,EAAE,WAAW,MAAM,OAAO,EAAE,EAAE,CAAC;AAAA,IAChE,OAAO,EAAE,OAAO,KAAK,QAAQ,IAAI;AAAA,IACjC,GAAG;AAAA,EACL;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,OAAO,CAAC,EAAE,MAAM,QAAQ,SAAS,EAAE,WAAW,MAAM,OAAO,GAAG,EAAE,CAAC;AAAA,IACjE,OAAO,EAAE,OAAO,GAAG,QAAQ,IAAI;AAAA,IAC/B,GAAG;AAAA,EACL;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,OAAO,CAAC,EAAE,MAAM,QAAQ,SAAS,EAAE,WAAW,MAAM,OAAO,EAAE,EAAE,CAAC;AAAA,IAChE,OAAO,EAAE,OAAO,GAAG,QAAQ,IAAI;AAAA,IAC/B,GAAG;AAAA,EACL;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,OAAO,CAAC,EAAE,MAAM,QAAQ,SAAS,EAAE,OAAO,IAAI,QAAQ,GAAG,WAAW,IAAI,QAAQ,KAAK,EAAE,CAAC;AAAA,IACxF,OAAO,EAAE,OAAO,GAAG,QAAQ,IAAI;AAAA,IAC/B,GAAG;AAAA,EACL;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,OAAO,CAAC,EAAE,MAAM,QAAQ,SAAS,EAAE,OAAO,KAAK,QAAQ,KAAK,WAAW,KAAK,QAAQ,KAAK,EAAE,CAAC;AAAA,IAC5F,OAAO,EAAE,OAAO,GAAG,QAAQ,IAAI;AAAA,IAC/B,GAAG;AAAA,EACL;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,OAAO;AAAA,MACL;AAAA,QACE,MAAM;AAAA,QACN,SAAS,EAAE,WAAW,MAAM,YAAY,KAAK,OAAO,GAAG,OAAO,IAAI,YAAY,OAAO;AAAA,MACvF;AAAA,IACF;AAAA,IACA,OAAO,EAAE,OAAO,GAAG,QAAQ,EAAE;AAAA,IAC7B,GAAG;AAAA,EACL;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,OAAO;AAAA,MACL;AAAA,QACE,MAAM;AAAA,QACN,SAAS,EAAE,WAAW,MAAM,YAAY,KAAK,OAAO,KAAK,OAAO,IAAI,YAAY,MAAM;AAAA,MACxF;AAAA,IACF;AAAA,IACA,OAAO,EAAE,OAAO,KAAK,QAAQ,IAAI;AAAA,IACjC,GAAG;AAAA,EACL;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,OAAO;AAAA,MACL;AAAA,QACE,MAAM;AAAA,QACN,SAAS,EAAE,WAAW,MAAM,OAAO,GAAG,SAAS,KAAK,WAAW,MAAM,QAAQ,KAAK,YAAY,MAAM;AAAA,MACtG;AAAA,IACF;AAAA,IACA,OAAO,EAAE,OAAO,KAAK,QAAQ,IAAI;AAAA,IACjC,GAAG;AAAA,EACL;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,OAAO;AAAA,MACL;AAAA,QACE,MAAM;AAAA,QACN,SAAS,EAAE,WAAW,MAAM,OAAO,IAAI,SAAS,KAAK,WAAW,GAAG,QAAQ,GAAG,YAAY,SAAS;AAAA,MACrG;AAAA,IACF;AAAA,IACA,OAAO,EAAE,OAAO,KAAK,QAAQ,EAAE;AAAA,IAC/B,GAAG;AAAA,EACL;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,OAAO,CAAC,EAAE,MAAM,WAAW,SAAS,EAAE,QAAQ,MAAM,OAAO,GAAG,MAAM,KAAK,MAAM,EAAE,EAAE,CAAC;AAAA,IACpF,OAAO,EAAE,OAAO,GAAG,QAAQ,IAAI;AAAA,IAC/B,GAAG;AAAA,EACL;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAAA,IAKE,MAAM;AAAA,IACN,OAAO,CAAC,EAAE,MAAM,WAAW,SAAS,EAAE,QAAQ,GAAG,OAAO,KAAK,MAAM,GAAG,MAAM,EAAE,EAAE,CAAC;AAAA,IACjF,OAAO,EAAE,OAAO,KAAK,QAAQ,IAAI;AAAA,IACjC,GAAG;AAAA,EACL;AAAA,EACA;AAAA;AAAA;AAAA,IAGE,MAAM;AAAA,IACN,OAAO;AAAA,MACL,EAAE,MAAM,WAAW,SAAS,EAAE,QAAQ,MAAM,OAAO,KAAK,MAAM,KAAK,MAAM,EAAE,EAAE;AAAA,MAC7E,EAAE,MAAM,QAAQ,SAAS,EAAE,WAAW,MAAM,OAAO,GAAG,EAAE;AAAA,IAC1D;AAAA,IACA,OAAO,EAAE,OAAO,KAAK,QAAQ,IAAI;AAAA,IACjC,GAAG;AAAA,EACL;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,OAAO;AAAA,MACL,EAAE,MAAM,QAAQ,SAAS,EAAE,OAAO,KAAK,QAAQ,QAAQ,WAAW,KAAK,QAAQ,KAAK,EAAE;AAAA,MACtF,EAAE,MAAM,QAAQ,SAAS,EAAE,OAAO,IAAI,QAAQ,QAAQ,WAAW,KAAK,QAAQ,KAAK,EAAE;AAAA,IACvF;AAAA,IACA,OAAO,EAAE,OAAO,GAAG,QAAQ,IAAI;AAAA,IAC/B,GAAG;AAAA,EACL;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,OAAO;AAAA,MACL,EAAE,MAAM,QAAQ,SAAS,EAAE,WAAW,KAAK,OAAO,EAAE,EAAE;AAAA,MACtD,EAAE,MAAM,QAAQ,SAAS,EAAE,OAAO,IAAI,UAAU,KAAK,QAAQ,MAAM,WAAW,EAAE,EAAE;AAAA,MAClF;AAAA,QACE,MAAM;AAAA,QACN,SAAS,EAAE,WAAW,MAAM,YAAY,KAAK,OAAO,KAAK,OAAO,IAAI,YAAY,OAAO;AAAA,MACzF;AAAA,IACF;AAAA,IACA,OAAO,EAAE,OAAO,GAAG,QAAQ,IAAI;AAAA,IAC/B,GAAG;AAAA,EACL;AACF;AAEA,SAAS,oBAAoB,OAA2BC,QAA0B;AAChF,QAAM,WAAW,sBAAsB,OAAOA,MAAK;AACnD;AAAA;AAAA,IAAkB;AAAA;AAAA;AAAA;AAAA,EAIlB,SAAS,YAAY;AAAA,EACrB,SAAS,WAAW;AAAA;AAAA;AAAA,8CAGwB,OAAO,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAKtD;AAEA,IAAM,OAAO;AAAA;AAAA;AAAA;AAKb,SAAS,QAAQ,IAA4B,MAAc,KAA0B;AACnF,QAAM,SAAS,GAAG,aAAa,IAAI;AACnC,KAAG,aAAa,QAAQ,GAAG;AAC3B,KAAG,cAAc,MAAM;AACvB,MAAI,CAAC,GAAG,mBAAmB,QAAQ,GAAG,cAAc,GAAG;AACrD,UAAM,IAAI,MAAM,4CAA4C,GAAG,iBAAiB,MAAM,CAAC,EAAE;AAAA,EAC3F;AACA,SAAO;AACT;AAEA,SAAS,aAAa,IAA4BC,IAAe,OAAO,GAAiB;AACvF,QAAM,WAAW,sBAAsBA,GAAE,OAAOA,GAAE,KAAK;AACvD,QAAM,UAAU,GAAG,cAAc;AACjC,KAAG,aAAa,SAAS,QAAQ,IAAI,GAAG,eAAe,IAAI,CAAC;AAC5D,KAAG,aAAa,SAAS,QAAQ,IAAI,GAAG,iBAAiB,oBAAoBA,GAAE,OAAOA,GAAE,KAAK,CAAC,CAAC;AAC/F,KAAG,YAAY,OAAO;AACtB,MAAI,CAAC,GAAG,oBAAoB,SAAS,GAAG,WAAW,GAAG;AACpD,UAAM,IAAI,MAAM,kCAAkC,GAAG,kBAAkB,OAAO,CAAC,EAAE;AAAA,EACnF;AAEA,KAAG,WAAW,OAAO;AAErB,aAAW,CAAC,MAAM,KAAK,KAAK,OAAO,QAAQ,SAAS,QAAQ,GAAG;AAC7D,UAAM,MAAM,GAAG,mBAAmB,SAAS,IAAI;AAC/C,QAAI,CAAC,IAAK;AACV,QAAI,OAAO,UAAU,SAAU,IAAG,UAAU,KAAK,KAAK;AAAA,aAC7C,MAAM,WAAW,EAAG,IAAG,UAAU,KAAK,MAAM,CAAC,GAAI,MAAM,CAAC,CAAE;AAAA,aAC1D,MAAM,WAAW,EAAG,IAAG,UAAU,KAAK,MAAM,CAAC,GAAI,MAAM,CAAC,GAAI,MAAM,CAAC,CAAE;AAAA,QACzE,IAAG,UAAU,KAAK,MAAM,CAAC,GAAI,MAAM,CAAC,GAAI,MAAM,CAAC,GAAI,MAAM,CAAC,CAAE;AAAA,EACnE;AACA,QAAM,UAAU,GAAG,mBAAmB,SAAS,SAAS;AACxD,MAAI,QAAS,IAAG,UAAU,SAASA,GAAE,CAAC;AACtC,QAAM,UAAU,GAAG,mBAAmB,SAAS,SAAS;AACxD,MAAI,QAAS,IAAG,UAAU,SAAS,IAAI;AAEvC,QAAM,OAAO,GAAG,aAAa;AAC7B,KAAG,WAAW,GAAG,cAAc,IAAI;AACnC,KAAG,WAAW,GAAG,cAAc,IAAI,aAAa,CAAC,IAAI,IAAI,GAAG,IAAI,IAAI,CAAC,CAAC,GAAG,GAAG,WAAW;AACvF,QAAM,SAAS,GAAG,kBAAkB,SAAS,MAAM;AACnD,KAAG,wBAAwB,MAAM;AACjC,KAAG,oBAAoB,QAAQ,GAAG,GAAG,OAAO,OAAO,GAAG,CAAC;AAEvD,QAAM,MAAM,GAAG,cAAc;AAC7B,KAAG,YAAY,GAAG,YAAY,GAAG;AACjC,KAAG,WAAW,GAAG,YAAY,GAAG,GAAG,SAAS,MAAM,MAAM,GAAG,GAAG,MAAM,GAAG,OAAO,IAAI;AAClF,QAAM,MAAM,GAAG,kBAAkB;AACjC,KAAG,gBAAgB,GAAG,aAAa,GAAG;AACtC,KAAG,qBAAqB,GAAG,aAAa,GAAG,mBAAmB,GAAG,YAAY,KAAK,CAAC;AACnF,KAAG,SAAS,GAAG,GAAG,MAAM,IAAI;AAC5B,KAAG,WAAW,GAAG,WAAW,GAAG,CAAC;AAEhC,QAAM,MAAM,IAAI,aAAa,OAAO,OAAO,CAAC;AAC5C,KAAG,WAAW,GAAG,GAAG,MAAM,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG;AACtD,KAAG,gBAAgB,GAAG,aAAa,IAAI;AACvC,SAAO;AACT;AAQA,SAAS,aAAa,IAA4C;AAChE,QAAM,UAA0B,CAAC;AACjC,aAAWA,MAAK,aAAa;AAC3B,UAAM,YAAYA,GAAE,MAAM,IAAI,CAAC,MAAM,YAAY,EAAE,IAAI,EAAE,MAAM,aAAa,MAAS;AAErF,QAAI,CAAC,UAAU,MAAM,CAAC,MAAM,MAAM,UAAU,CAAC,CAAC,EAAG;AACjD,UAAM,SAAS,UAAU,CAAC;AAE1B,UAAM,MAAM,aAAa,IAAIA,IAAG,CAAC;AACjC,UAAM,YAAY,SAAS,OAAO,aAAa,IAAIA,IAAG,CAAC;AACvD,QAAI,WAAW;AACf,aAAS,MAAM,GAAG,MAAM,MAAM,OAAO;AACnC,eAAS,MAAM,GAAG,MAAM,MAAM,OAAO;AACnC,cAAM,MAAM,MAAM,OAAO,OAAO;AAGhC,cAAM,KAAK,YAAY,UAAU,EAAE,KAAM,OAAO,OAAO,KAAK,OAAOA,GAAE,MAAM;AAC3E,cAAM,KAAK,YAAY,UAAU,KAAK,CAAC,KAAM,OAAO,OAAO,KAAK,OAAOA,GAAE,MAAM;AAC/E,cAAM,KAAK,YAAY,UAAU,KAAK,CAAC,IAAK;AAC5C,mBAAW,KAAK;AAAA,UACd;AAAA,UACA,KAAK,IAAI,IAAI,EAAE,IAAK,EAAE;AAAA,UACtB,KAAK,IAAI,IAAI,KAAK,CAAC,IAAK,EAAE;AAAA,UAC1B,KAAK,IAAI,IAAI,KAAK,CAAC,IAAK,EAAE;AAAA,QAC5B;AAAA,MACF;AAAA,IACF;AACA,YAAQ,KAAK;AAAA,MACX,MAAM,SAASA,GAAE,IAAI,WAAM,SAAS,cAAc,cAAc;AAAA,MAChE;AAAA,MACA,MAAM,WAAW;AAAA,IACnB,CAAC;AAAA,EACH;AACA,SAAO;AACT;AAGO,SAAS,iBAAiB,QAA4C;AAC3E,QAAM,MAAM,UAAU,SAAS,cAAc,QAAQ;AACrD,QAAM,KAAK,IAAI,WAAW,QAAQ;AAClC,MAAI,CAAC,GAAI,OAAM,IAAI,MAAM,sCAAsC;AAC/D,MAAI,CAAC,GAAG,aAAa,wBAAwB,GAAG;AAC9C,UAAM,IAAI,MAAM,sDAAsD;AAAA,EACxE;AAEA,QAAM,QAAQ,IAAU,gBAAQ;AAChC,QAAM,SAAS,YAAY,IAAI,CAACA,OAAM;AACpC,UAAM,MAAM,aAAa,IAAIA,EAAC;AAC9B,QAAI,WAAW;AACf,aAAS,MAAM,GAAG,MAAM,MAAM,OAAO;AACnC,eAAS,MAAM,GAAG,MAAM,MAAM,OAAO;AACnC,cAAM,IAAI,OAAO,OAAO;AACxB,cAAMC,KAAI,OAAO,OAAO;AACxB,cAAM,KAAK,IAAI,OAAOD,GAAE,MAAM,QAAQC,KAAI,OAAOD,GAAE,MAAM,QAAQ,CAAC;AAClE,sBAAc,OAAO,GAAGC,IAAGD,GAAE,OAAO,EAAE,GAAGA,GAAE,GAAG,OAAOA,GAAE,MAAM,CAAC;AAC9D,cAAM,MAAM,MAAM,OAAO,OAAO;AAChC,mBAAW,KAAK;AAAA,UACd;AAAA,UACA,KAAK,IAAI,IAAI,EAAE,IAAK,MAAM,CAAC;AAAA,UAC3B,KAAK,IAAI,IAAI,KAAK,CAAC,IAAK,MAAM,CAAC;AAAA,UAC/B,KAAK,IAAI,IAAI,KAAK,CAAC,IAAK,MAAM,CAAC;AAAA,QACjC;AAAA,MACF;AAAA,IACF;AACA,WAAO,EAAE,MAAMA,GAAE,MAAM,UAAU,MAAM,WAAW,eAAe;AAAA,EACnE,CAAC;AACD,SAAO,CAAC,GAAG,QAAQ,GAAG,aAAa,EAAE,CAAC;AACxC;","names":["import_fiber","import_react","THREE","import_gsap","import_fiber","import_react","import_zod","b","p","import_zod","sheet","k","sheet","e","c","sheet","import_zod","import_zod","DEG","k","sheet","r","sheet","v","p","import_zod","sheet","x","import_zod","sheet","import_zod","import_zod","import_zod","import_zod","import_zod","x","v","r","import_zod","import_zod","import_zod","sheet","l","b","c","x","y","z","b","sheet","v","b","c","THREE","import_react","v","w","pad","y","b","module","x","w","pad","x","y","r","x","y","w","sheet","w","pad","x","y","THREE","import_zod","import_zod","DEG","x","x2","sheet","r","import_zod","DEG","sheet","import_zod","DEG","TAU","sheet","import_zod","TAU","sheet","fold","import_zod","x","y","k","v","sheet","x","y","b","c","sheet","registry","b","r","c","b","k","x","y","z","p","gust","bend","p","r","c","j","j3","v","k","b","x","y","FIXED_DT","SOLVER_ITERATIONS","SLEEP_EPSILON","SLEEP_FRAMES","LOOSE","TIGHT","layerThickness","p","k","r","y","z","b","c","e","j","v","THREE","import_react","import_fiber","defaultCsmDefinitions","defaultCsmMainDefinitions","defaultVertDefinitions","defaultVertMain","defaultFragDefinitions","defaultFragMain","keywordMap","availabilityMap","defaultPatchMap","requiredPropsMap","sdbm","string","hash","i","h","isConstructor","f","err","stripComments","str","CustomShaderMaterial","baseMaterial","vertexShader","fragmentShader","uniforms","patchMap","cacheKey","opts","base","isEmptyOpts","extendedBase","mergedUniforms","gettersAndSetters","key","descriptor","value","_fs","_vs","self","prop","matchKeywords","keyword","matchKeyword","prevOnBeforeCompile","extendShader","prevShader","newShader","isFrag","mainBody","beforeMain","mainStartIndex","braceCount","mainEndIndex","fullMain","lastMainEndIndex","toAppend","regex","shader","renderer","userPatchMap","type","typeDefine","runPatchMap","_patchMap","doesIncludeInVert","availableIn","toReplace","replaceWith","prevCacheKey","useDidUpdateEffect","fn","inputs","didMountRef","React","CustomShaderMaterial","baseMaterial","vertexShader","fragmentShader","uniforms","cacheKey","patchMap","attach","opts","ref","material","CustomShaderMaterialImpl","jsx","index","THREE","THREE","DEG","x","y","z","x","y","z","sheet","e","c","import_react","import_jsx_runtime","THREE","import_react","import_jsx_runtime","sheet","v","x","d","j","import_react","import_jsx_runtime","p","import_react","v","c","import_jsx_runtime","PaperMesh","c","probe","p","x","y","v","e","z","b","THREE","import_react","import_fiber","THREE","x","y","import_jsx_runtime","mulberry32","y","x","r","p","THREE","import_react","import_fiber","w","import_fiber","import_react","import_jsx_runtime","Paper","THREE","import_gsap","import_fiber","import_react","THREE","import_react","import_jsx_runtime","x","y","registry","w","import_zod","THREE","import_gsap","import_fiber","import_react","THREE","import_react","sheet","x","y","sheet","c","import_zod","import_zod","b","k","p","TAU","DEG","jitter","sheet","sweep","k","x","y","registry","import_jsx_runtime","PROGRESS_SAMPLES","p","x","y","j","b","THREE","import_react","x","y","c","r","w","import_jsx_runtime","c","b","THREE","import_gsap","import_fiber","import_react","import_jsx_runtime","registry","e","hit","z","import_react","import_jsx_runtime","carry","e","sheet","r","DEG","import_jsx_runtime","PaperFieldMesh","e","sheet","PaperField","registry","v","sheet","k","c","c","k","v","same","p","z","THREE","sheet","c","v"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/Paper.tsx","../src/PaperMesh.tsx","../src/config/schema.ts","../src/config/merge.ts","../src/behaviors/peel.ts","../src/deformers/curl.ts","../src/core/tessellation.ts","../src/behaviors/unroll.ts","../src/deformers/roll.ts","../src/behaviors/flip.ts","../src/behaviors/letter-fold.ts","../src/behaviors/hang.ts","../src/behaviors/fly.ts","../src/behaviors/fall.ts","../src/behaviors/carry.ts","../src/behaviors/flight.ts","../src/physics/aero.ts","../src/behaviors/crumple.ts","../src/behaviors/settle.ts","../src/behaviors/ribbon.ts","../src/config/serialize.ts","../src/core/normals.ts","../src/core/stable.ts","../src/core/sheet.ts","../src/core/stock.ts","../src/config/presets/index.ts","../src/content/texture.ts","../src/content/receipt.ts","../src/content/type.ts","../src/content/card.ts","../src/content/wash.ts","../src/deformers/compose.ts","../src/deformers/registry.ts","../src/deformers/bend.ts","../src/deformers/fold.ts","../src/deformers/wave.ts","../src/deformers/drape.ts","../src/deformers/crumple.ts","../src/deformers/memory.ts","../src/surface/creases.ts","../src/behaviors/registry.ts","../src/physics/idle.ts","../src/physics/cloth.ts","../src/surface/damageContract.ts","../src/physics/damage.ts","../src/physics/strip.ts","../src/surface/PaperMaterial.tsx","../../../node_modules/.pnpm/three-custom-shader-material@6.4.0_@react-three+fiber@9.7.0_@types+react@19.2.18_react-_9d22c69745b4efc41799679dbea453f4/node_modules/src/defaults.ts","../../../node_modules/.pnpm/three-custom-shader-material@6.4.0_@react-three+fiber@9.7.0_@types+react@19.2.18_react-_9d22c69745b4efc41799679dbea453f4/node_modules/src/maps/keywordMap.ts","../../../node_modules/.pnpm/three-custom-shader-material@6.4.0_@react-three+fiber@9.7.0_@types+react@19.2.18_react-_9d22c69745b4efc41799679dbea453f4/node_modules/src/maps/availabilityMap.ts","../../../node_modules/.pnpm/three-custom-shader-material@6.4.0_@react-three+fiber@9.7.0_@types+react@19.2.18_react-_9d22c69745b4efc41799679dbea453f4/node_modules/src/maps/patchMap.ts","../../../node_modules/.pnpm/three-custom-shader-material@6.4.0_@react-three+fiber@9.7.0_@types+react@19.2.18_react-_9d22c69745b4efc41799679dbea453f4/node_modules/src/maps/requiredPropsMap.ts","../../../node_modules/.pnpm/three-custom-shader-material@6.4.0_@react-three+fiber@9.7.0_@types+react@19.2.18_react-_9d22c69745b4efc41799679dbea453f4/node_modules/src/sdbm.js","../../../node_modules/.pnpm/three-custom-shader-material@6.4.0_@react-three+fiber@9.7.0_@types+react@19.2.18_react-_9d22c69745b4efc41799679dbea453f4/node_modules/src/utils.ts","../../../node_modules/.pnpm/three-custom-shader-material@6.4.0_@react-three+fiber@9.7.0_@types+react@19.2.18_react-_9d22c69745b4efc41799679dbea453f4/node_modules/src/index.ts","../../../node_modules/.pnpm/three-custom-shader-material@6.4.0_@react-three+fiber@9.7.0_@types+react@19.2.18_react-_9d22c69745b4efc41799679dbea453f4/node_modules/src/React/index.tsx","../src/surface/compose.ts","../src/surface/translucency.ts","../src/scene/lighting.ts","../src/scene/rig.tsx","../src/surface/useDamageTexture.ts","../src/a11y/index.tsx","../src/motion/onTwos.ts","../src/states/usePaperStates.ts","../src/states/machine.ts","../src/scene/PaperLighting.tsx","../src/scene/environment.ts","../src/scene/color.ts","../src/scene/backdrop.tsx","../src/scene/release.tsx","../src/PaperField.tsx","../src/field/dropZones.tsx","../src/field/sheetGrid.ts","../src/field/slots.ts","../src/field/fieldGroup.tsx","../src/content/atlas.ts","../src/field/compose.ts","../src/field/layouts/index.ts","../src/stage/path.ts","../src/field/stack.ts","../src/field/backingSheet.tsx","../src/content/backing.ts","../src/field/interactiveField.tsx","../src/field/keyboardMirror.tsx","../src/field/framing.ts","../src/config/diff.ts","../src/config/agent-payload.ts","../src/config/field-export.ts","../src/field/parity.ts"],"sourcesContent":["/**\n * The public API.\n *\n * Everything named here is a promise: once it is on npm, taking it away costs\n * whoever imported it a migration. So the bar is not \"is this useful?\" but\n * \"would I support this for years?\" — and the answer for a shader builder, a\n * texture painter or a tessellation constant is no. Those are the inside of\n * the box, and the box is `<Paper>`, `<PaperField>`, `<PaperStage>` and the\n * data that describes them.\n *\n * Three things survive that bar despite looking internal, each for a reason\n * written where it is exported: the parity harness, the tessellation\n * arithmetic, and line breaking. Each is the answer to a question a caller\n * can genuinely ask and cannot otherwise answer.\n *\n * Adding a name here later is free. Removing one is not. When in doubt, leave\n * it out.\n */\n\n// ── The components ──────────────────────────────────────────────────────────\n\nexport { Paper, type PaperProps } from './Paper'\nexport { PaperMesh, type PaperMeshProps, type PaperHandle } from './PaperMesh'\nexport {\n PaperField,\n PaperFieldMesh,\n DropZone,\n type PaperFieldProps,\n type PaperFieldMeshProps,\n type FieldPaperSlot,\n type DropZoneConfig,\n type DropZoneProps,\n type PlacedPaper,\n} from './PaperField'\n\n// ── The schema. It is the spec: if it cannot serialize, it does not ship. ───\n\nexport {\n paperConfigSchema,\n sceneSchema,\n backdropSchema,\n behaviorConfigSchema,\n clothConfigSchema,\n stripConfigSchema,\n paperStatesSchema,\n stateDefSchema,\n physicsNames,\n lightingNames,\n stockNames,\n contentNames,\n contentSchemaFor,\n washSchema,\n creaseSchema,\n memorySchema,\n paperEdges,\n coreStateNames,\n type PaperConfig,\n type PaperConfigInput,\n type SheetConfig,\n type StockName,\n type ContentConfig,\n type ContentConfigInput,\n type WashConfig,\n type BackContentConfig,\n type BehaviorConfig,\n type BehaviorConfigInput,\n type DeformerInstanceConfig,\n type DeformerInstanceConfigInput,\n type SurfaceConfig,\n type SurfaceConfigInput,\n type CreaseConfig,\n type CreaseConfigInput,\n type MemoryConfig,\n type MemoryConfigInput,\n type PaperEdge,\n type PhysicsConfig,\n type PhysicsConfigInput,\n type ClothConfig,\n type StripConfig,\n type SceneConfig,\n type BackdropConfig,\n type SceneConfigInput,\n type LightingName,\n type FilmName,\n type CoreStateName,\n type StateName,\n type StateDef,\n type StateTransitionConfig,\n type PaperStates,\n type PaperStatesInput,\n} from './config/schema'\n\nexport { sheetLayoutSchema, type SheetLayoutOptions } from './field/sheetGrid'\n\n// ── Presets, and the file format ────────────────────────────────────────────\n\nexport {\n getPreset,\n listPresets,\n registerPreset,\n unregisterPreset,\n isBuiltinPreset,\n uniquePresetName,\n} from './config/presets'\nexport { parsePreset, serializePreset, mergeConfig, mergeWithDeletes } from './config/serialize'\nexport { diffConfig, buildJsxSnippet } from './config/diff'\n\n// ── Export: the brief an agent or a codebase receives ───────────────────────\n\nexport { buildAgentPayload, describeConfig } from './config/agent-payload'\nexport {\n buildFieldAgentPayload,\n buildFieldComponentSource,\n describeFieldConfig,\n diffFieldProps,\n type FieldExportInput,\n type FieldExportPaper,\n type FieldExportZone,\n} from './config/field-export'\n\n// ── The registries, and the three ways to extend them ───────────────────────\n\nexport type { Deformer, DeformerInstance, DeformerContext, SheetDims } from './deformers/types'\nexport { registerDeformer, getDeformer, listDeformers } from './deformers/registry'\nexport type { Behavior, HandleSpec } from './behaviors/types'\nexport { registerBehavior, getBehavior, listBehaviors } from './behaviors/registry'\nexport { getLayout, listLayouts, registerLayout, type Layout, type PaperPose } from './field/layouts'\nexport { stocks, getStock, type Stock } from './core/stock'\n// The seam between the sheet and whatever damages it. One interface and the\n// meaning of its four bytes — see `surface/damageContract.ts` for why this and\n// not a plugin API for the composer and the solver.\nexport {\n DAMAGE_CHANNELS,\n DAMAGE_LOOK_DEFAULTS,\n type DamageLook,\n type DamageSource,\n} from './surface/damageContract'\nexport { idleNames, type IdleName, type IdlePreset } from './physics/idle'\n/**\n * The longest strip the `strip` sim can still draw at a given perforation\n * spacing. Exported for authoring UI: past it the chain's node count is capped\n * and the roll comes apart, so a length control needs to know where to stop.\n */\nexport { maxStripLength } from './physics/strip'\n\n/**\n * Paper memory — creasing, and what a sheet keeps of a fold.\n *\n * `applyMemory` is exported because it is the one piece a host might need to\n * reproduce outside the frame loop: an exporter or a thumbnailer that builds\n * a stack by hand has to fold the creases in the same way, or a shared link\n * renders one shape in the editor and another in the picture of it.\n */\nexport { applyMemory, CreaseTracker, MAX_SET, MAX_CREASES } from './deformers/memory'\n\n// ── Lighting is data, not an enum ───────────────────────────────────────────\n\nexport {\n lightSchema,\n resolveLighting,\n lightAngles,\n type LightingPreset,\n type LightAngles,\n type LightOverrides,\n type LightOverridesInput,\n} from './scene/lighting'\nexport { PaperLighting, type PaperLightingProps } from './scene/PaperLighting'\n// Rendered by whoever owns the canvas — see the note on the component.\nexport { PaperBackdrop } from './scene/backdrop'\n// Publish a resolved rig to the paper under it, so a hand-lit scene's\n// transmission agrees with its lamps. `<PaperStage>` does this for you.\nexport { LightRig } from './scene/rig'\n\n// ── Interaction states ──────────────────────────────────────────────────────\n\nexport { resolveStateConfig, recordStateOverride, type StateEvent } from './states/machine'\nexport { usePaperStates, type UsePaperStatesResult } from './states/usePaperStates'\n\n// ── Accessibility ───────────────────────────────────────────────────────────\n\nexport { usePrefersReducedMotion, supportsWebGL } from './a11y'\n\n// ── The three that look internal and are not ────────────────────────────────\n\n/**\n * The GPU/CPU parity harness — public on purpose, and the reasoning is worth\n * writing down because it reads like test infrastructure that leaked.\n *\n * It is test infrastructure. It is also the only way to check the invariant\n * the contribution ladder is built on: a deformer ships a JS `displace` and a\n * GLSL chunk, and the two must agree. `CONTRIBUTING.md` asks a contributor to\n * add cases to `field/parity.ts` and run `pnpm test:parity`, which needs a\n * real WebGL context, which means a browser, which means it runs from an app\n * — and the apps consume this library **through its public API only**. So the\n * harness is either exported or that invariant has no gate.\n *\n * The narrow read is that this is a repo concern that a published consumer\n * will never call. The wider one is that someone writing a deformer in their\n * own project faces exactly the problem this solves, and has no other way to\n * solve it. Exported for the second reason; kept to five names for the first.\n */\nexport {\n runParityHarness,\n parityCases,\n PARITY_EPSILON,\n type ParityCase,\n type ParityResult,\n} from './field/parity'\n\n/**\n * The arithmetic behind `geometry.autoSegments`. Public because\n * `registerDeformer` is: a deformer someone else writes has to be able to\n * answer the same question the built-in seven answer, and the answer should\n * be the same formula rather than a guess at what the library does.\n */\nexport {\n AUTO_CEILING,\n FLAT_SEGMENTS,\n quantizeSegments,\n SAG_TOL,\n segmentsForArc,\n segmentsForSine,\n spanAlong,\n} from './core/tessellation'\n\n/**\n * Line breaking is exported because it is the answer to \"where does this\n * wrap\", and a caller measuring a block of type before laying a sheet out\n * has to get the same answer the painter will.\n */\nexport { wrapLines } from './content/type'\n","import { Canvas } from '@react-three/fiber'\nimport { forwardRef, useMemo } from 'react'\nimport { PaperMesh, useResolvedConfig, type PaperHandle, type PaperMeshProps } from './PaperMesh'\nimport { PaperFallback, PaperMirror, supportsWebGL } from './a11y'\nimport { PaperLighting } from './scene/PaperLighting'\nimport { PaperBackdrop } from './scene/backdrop'\nimport { ReleaseContextOnUnmount } from './scene/release'\n\nexport interface PaperProps extends PaperMeshProps {\n /** Extra children rendered inside the canvas (lights are provided). */\n children?: React.ReactNode\n className?: string\n style?: React.CSSProperties\n}\n\n/**\n * `<Paper />` owns its own `<Canvas>` and fills its parent container —\n * the parent must have a height. Use `<PaperMesh />` inside an existing\n * R3F scene instead.\n *\n * Ships with its accessibility layer: a hidden DOM mirror of the content,\n * `prefers-reduced-motion` support, and a flat DOM fallback when WebGL is\n * unavailable.\n */\nexport const Paper = forwardRef<PaperHandle, PaperProps>(function Paper(\n { children, className, style, ...meshProps },\n ref,\n) {\n // Keyed on every prop resolveConfig reads — a content/stock/behavior change\n // must refresh the fallback, mirror, and lighting, not just the mesh.\n const config = useResolvedConfig(meshProps)\n const webgl = useMemo(() => (typeof window === 'undefined' ? true : supportsWebGL()), [])\n\n return (\n <div className={className} style={{ width: '100%', height: '100%', ...style }}>\n {webgl ? (\n <Canvas shadows camera={{ position: [0, 0.35, 2.4], fov: 40 }} dpr={[1, 2]}>\n <PaperBackdrop backdrop={config.scene.backdrop} />\n <PaperLighting\n preset={config.scene.lighting}\n // The overrides, which this component was resolving without: a\n // preset whose scene said \"studio, but dimmer\" rendered as plain\n // studio here while the editor showed the dimmer one.\n light={config.scene.light}\n floor={-1.05}\n scale={8}\n reducedMotion={meshProps.reducedMotion}\n />\n <PaperMesh ref={ref} {...meshProps} />\n {children}\n <ReleaseContextOnUnmount />\n </Canvas>\n ) : (\n <PaperFallback config={config} />\n )}\n <PaperMirror config={config} />\n </div>\n )\n})\n","import * as THREE from 'three'\nimport { gsap } from 'gsap'\nimport { useFrame, useThree } from '@react-three/fiber'\nimport type { ThreeEvent } from '@react-three/fiber'\nimport { forwardRef, useEffect, useImperativeHandle, useMemo, useRef } from 'react'\nimport type {\n BehaviorConfigInput,\n ClothConfig,\n CreaseConfig,\n StripConfig,\n ContentConfigInput,\n DeformerInstanceConfigInput,\n MemoryConfigInput,\n PaperConfig,\n PaperConfigInput,\n PhysicsConfigInput,\n SceneConfigInput,\n SheetConfig,\n StockName,\n SurfaceConfigInput,\n} from './config/schema'\nimport { paperConfigSchema } from './config/schema'\nimport { mergeConfig, parsePreset, serializePreset } from './config/serialize'\nimport { computeSheetNormals } from './core/normals'\nimport { useStable } from './core/stable'\nimport { createSheetGeometry, resolveSegments, surfacePointAt } from './core/sheet'\nimport { FLAT_SEGMENTS, type SegmentPair } from './core/tessellation'\nimport { getStock } from './core/stock'\nimport { getPreset } from './config/presets'\nimport { useContentTexture } from './content/texture'\nimport { applyDeformerStack, displacePoint, stackAutoSegments, stackMinSegments } from './deformers/compose'\nimport { applyMemory, CreaseTracker } from './deformers/memory'\nimport { resolveCreases } from './surface/creases'\nimport { stackIsAnimated } from './deformers/registry'\nimport type { DeformerInstance } from './deformers/types'\nimport { getBehavior } from './behaviors/registry'\nimport { resolveDeformerStack } from './deformers/registry'\nimport type { Behavior } from './behaviors/types'\nimport { getIdlePreset, type IdleName, type IdlePose } from './physics/idle'\nimport { ClothSim } from './physics/cloth'\nimport { DamageCoupling } from './physics/damage'\nimport { StripSim, stripNodeCount } from './physics/strip'\nimport { PaperMaterial } from './surface/PaperMaterial'\nimport type { DamageSource } from './surface/damageContract'\nimport { usePrefersReducedMotion } from './a11y'\nimport { quantizeProgress, quantizeTime } from './motion/onTwos'\nimport { usePaperStates } from './states/usePaperStates'\nimport type { PaperStateMachine, StateEvent } from './states/machine'\n\nexport interface PaperMeshProps {\n /** Built-in preset name, or a (partial) preset object. Props below override it. */\n preset?: string | PaperConfigInput\n sheet?: Partial<SheetConfig>\n stock?: StockName\n /**\n * These take the schema's INPUT types, not its parsed ones: writing\n * `content={{ type: 'text', text: 'hi' }}` has to compile, and with the\n * inferred type it does not — it demands every field of every nested\n * object. Every default stays a default.\n */\n content?: ContentConfigInput\n behavior?: BehaviorConfigInput\n deformers?: DeformerInstanceConfigInput[]\n /** Fragment-side effects: grain, aging, deckle, creases, perforation. */\n surface?: SurfaceConfigInput\n /**\n * What the sheet remembers being folded — how much of a fold this paper\n * keeps, and the creases it already carries. A sheet can be handed its\n * creases (a letter that arrives having been folded once) as readily as it\n * can be folded into them.\n */\n memory?: MemoryConfigInput\n /** Scene-level presentation that travels with the paper (lighting). */\n scene?: SceneConfigInput\n physics?: PhysicsConfigInput | 'cloth'\n onTwos?: boolean\n /** Show draggable behavior handles; cloth sheets become grabbable. */\n interactive?: boolean\n /** Start the behavior's transport loop on mount. */\n autoplay?: boolean\n /** Override prefers-reduced-motion (default: follow the system setting). */\n reducedMotion?: boolean\n position?: [number, number, number]\n rotation?: [number, number, number]\n /** Fires every animation tick with the behavior's progress (0..1). */\n onProgress?(value: number): void\n /** Fires when a handle drag ends, with the params the drag changed. */\n onBehaviorChange?(patch: Record<string, unknown>): void\n /**\n * Fires when folding the paper leaves a crease it did not have.\n *\n * The sheet applies its own creases immediately — this is how they get\n * PERSISTED. Recording happens in the frame loop, where a fold's peak\n * actually is, and routing that through React sixty times a second would\n * cost more than the rest of the feature; so the mesh holds the live truth\n * and reports it, and the host writes it into config whenever it likes.\n * The same split `onBehaviorChange` uses for handle drags.\n */\n onCrease?(creases: CreaseConfig[]): void\n /**\n * Interaction states: when the config carries `states`, pointer triggers\n * are live by default. Set false to sculpt a stateful paper without the\n * machine firing (the editor's state-editing mode).\n */\n stateTriggers?: boolean\n /** Fires when the state machine changes state. */\n onStateChange?(state: string): void\n /** Fires for `onEnter` actions ('emit:<event>'). */\n onStateAction?(event: string, state: string): void\n /**\n * What has happened to this sheet — char, wet, heat and missing paper — as\n * a grid over its UV.\n *\n * The sheet draws whatever damage it is handed and does not know what\n * caused it, the same way it draws `content` without knowing who painted\n * it. `DamageField` from `paperlab/fx` is one source; a baked texture or a\n * recorded burn played back would be others. A prop and not config,\n * because it is live state that changes every frame and does not belong in\n * a preset or a share link. See `DamageSource`.\n */\n damage?: DamageSource | null\n}\n\nexport interface PaperHandle {\n play(): void\n pause(): void\n readonly playing: boolean\n /** Live-override a behavior param. 'progress' always maps to the behavior's progress param. */\n set(param: string, value: unknown): void\n getProgress(): number\n /** Current full state (including live overrides) as a preset. */\n snapshot(): PaperConfig\n toJSON(): string\n readonly mesh: THREE.Mesh | null\n /**\n * Where a behavior's grab point currently sits, in world space, or null\n * when the behavior has no handles (or `interactive` is off).\n *\n * The handle is not at the corner it names: it rides the deformed surface,\n * so its position is only known after the frame's deformer stack has run.\n * Anything that wants to point AT the handle — a coach-mark, a tooltip,\n * an arrow — has to ask the frame rather than compute a UV, which is why\n * reading it is a method here and not a prop the sheet could publish.\n *\n * Written into `target` when one is passed, so a per-frame reader does not\n * allocate a vector sixty times a second.\n */\n handlePoint(id?: string, target?: THREE.Vector3): THREE.Vector3 | null\n /**\n * Where a point of the sheet is right now, in world space: `(u, v)` over\n * the sheet, `v = 0` its bottom edge — the same UV the damage grid is laid\n * out on, so a cell of damage can be asked where it is. Null before the\n * sheet has mounted.\n *\n * On the DRAWN surface, after this frame's simulation and deformer stack,\n * which is the reason it is a method: an ember that leaves the burn front\n * has to leave from where the paper is, and a draped or crumpled sheet is\n * nowhere a UV alone could say. Interpolated across the triangle the GPU\n * draws, so the point is on the paper and not a hair behind it.\n *\n * Written into `target` when one is passed, like {@link handlePoint}.\n */\n surfacePoint(u: number, v: number, target?: THREE.Vector3): THREE.Vector3 | null\n /** Interaction-state machine access (null when the config has no states). */\n readonly state: string\n sendState(event: StateEvent): string | null\n /**\n * Drive to 'picked' through the legal chain (rest→hover→pressed→picked),\n * instantly, so every side effect fires — the keyboard/a11y entry point\n * where no pointer hover/press ever ran. Returns true if it landed.\n */\n pickProgrammatic(): boolean\n /** Instant, legal place (picked → placed) so onEnter/emit fires. */\n placeProgrammatic(): boolean\n /** Instant, legal return (picked → rest). */\n returnProgrammatic(): boolean\n}\n\n/**\n * Everything {@link resolveConfig} reads, as a plain tuple.\n *\n * Compared with {@link useStable} rather than serialized: a dependency array\n * is evaluated on EVERY render, and `content` can hold a whole bitmap as a\n * data URL, so a `JSON.stringify` here was megabytes of garbage per frame of\n * a slider drag. (There was a `resolveConfigKey` exporting the string form\n * for consumers to key their own caches on; it was never part of the package\n * entry, so no consumer could reach it, and nothing else uses it now.)\n */\nfunction configInputs(props: PaperMeshProps): unknown[] {\n return [\n props.preset ?? null,\n props.sheet ?? null,\n props.stock ?? null,\n props.content ?? null,\n props.behavior ?? null,\n props.deformers ?? null,\n props.surface ?? null,\n props.memory ?? null,\n props.scene ?? null,\n props.physics ?? null,\n props.onTwos ?? null,\n ]\n}\n\n/** Resolve once, and again only when the inputs actually differ. */\nexport function useResolvedConfig(props: PaperMeshProps): PaperConfig {\n const inputs = useStable(configInputs(props))\n // biome-ignore lint/correctness/useExhaustiveDependencies: `inputs` IS every prop resolveConfig reads; the props object itself is new each render.\n return useMemo(() => resolveConfig(props), [inputs])\n}\n\n/** Resolve preset + prop overrides into a validated config. */\nexport function resolveConfig(props: PaperMeshProps): PaperConfig {\n const base = props.preset\n ? typeof props.preset === 'string'\n ? getPreset(props.preset)\n : parsePreset(props.preset)\n : paperConfigSchema.parse({})\n const overrides: PaperConfigInput = {}\n if (props.sheet) overrides.sheet = { ...base.sheet, ...props.sheet }\n if (props.stock) overrides.stock = props.stock\n if (props.content) overrides.content = props.content\n if (props.behavior) overrides.behavior = props.behavior\n if (props.deformers) overrides.deformers = props.deformers\n // Surface merges over the stock's defaults rather than replacing them, so\n // `surface={{ grain: 0.6 }}` on thermal keeps thermal's banding.\n if (props.surface) overrides.surface = { ...base.surface, ...props.surface }\n // Merged like surface, and for the same reason: `memory={{ set: 0.2 }}` on a\n // preset that ships creased should turn the retention down, not flatten the\n // paper on its way past.\n if (props.memory) overrides.memory = { ...base.memory, ...props.memory }\n if (props.scene) overrides.scene = { ...base.scene, ...props.scene }\n if (props.physics) overrides.physics = props.physics\n if (props.onTwos !== undefined) overrides.onTwos = props.onTwos\n return paperConfigSchema.parse(mergeConfig(base as PaperConfigInput, overrides))\n}\n\n/** Cloth grids cap their resolution — 5k verlet particles is the budget ceiling. */\nconst CLOTH_MAX_SEGMENTS = 28\n\n/** Where `'auto'` probes a behavior's sweep. Endpoints matter most — a play\n * usually starts or ends at its tightest. */\nconst PROGRESS_SAMPLES = [0, 0.25, 0.5, 0.75, 1] as const\n\nconst dragPlane = new THREE.Plane()\nconst dragPoint = new THREE.Vector3()\nconst planeNormal = new THREE.Vector3()\nconst anchorScratch = new THREE.Vector3()\nconst worldScratch = new THREE.Vector3()\nconst quatScratch = new THREE.Quaternion()\n\n/**\n * The atom: one sheet of paper, hero-mode CPU path. The cloth sim solves the\n * particles and the deformer stack runs over them — both, not either; only a\n * strip owns its vertices outright. GSAP owns animated values; useFrame owns\n * geometry writes.\n */\nexport const PaperMesh = forwardRef<PaperHandle, PaperMeshProps>(function PaperMesh(props, ref) {\n // Each resolveConfig call is several zod parses (superRefine re-parses every\n // state override) — memoized so a render without config-prop changes is free.\n const resolved = useResolvedConfig(props)\n // Reduced motion: behaviors freeze at their resting pose, physics is off,\n // idle motion is off. The sheet still renders fully sculpted.\n const reduced = usePrefersReducedMotion(props.reducedMotion)\n // Interaction states: the machine animates a live config between state\n // overrides; `config` below is that animated view (the base when no states).\n // Reduced motion keeps the machine but makes transitions instant.\n const statesLive = Boolean(resolved.states) && props.stateTriggers !== false\n const {\n config,\n machine,\n state: machineState,\n } = usePaperStates(resolved, statesLive, reduced, props.onStateAction, props.onStateChange)\n const behavior: Behavior | null = config.behavior ? getBehavior(config.behavior.type) : null\n const machineRef = useRef<PaperStateMachine | null>(null)\n machineRef.current = machine\n // The animated `config` has `states` stripped — keep the resolved preset\n // around so snapshot()/toJSON() never lose the state machine.\n const resolvedRef = useRef(resolved)\n resolvedRef.current = resolved\n // Two object-shaped simulations now, so the kind is read off the tag rather\n // than off `typeof` — which was only ever \"cloth\" by having no rival.\n const simKind =\n !reduced && typeof config.physics === 'object' ? (config.physics.type as 'cloth' | 'strip') : null\n const isCloth = simKind === 'cloth'\n const isStrip = simKind === 'strip'\n const idle =\n !reduced && typeof config.physics === 'string' && config.physics !== 'none'\n ? getIdlePreset(config.physics as IdleName)\n : null\n\n const meshRef = useRef<THREE.Mesh>(null)\n const groupRef = useRef<THREE.Group>(null)\n const handleRefs = useRef<(THREE.Mesh | null)[]>([])\n\n const overridesRef = useRef<Record<string, unknown>>({})\n const dirtyRef = useRef(true)\n const playingRef = useRef(false)\n const tweenRef = useRef<gsap.core.Tween | null>(null)\n const draggingRef = useRef<string | null>(null)\n\n const configRef = useRef(config)\n configRef.current = config\n\n /**\n * The caller's rotation with the preset's `scene.turn` folded in.\n *\n * Additive, and about Y: `turn` is how the composition wants to be READ\n * (see `sceneSchema.turn`), while the prop is where the caller has decided\n * to put this paper. A preset does not get to overrule that, so it leans on\n * top of it.\n */\n const baseRotation = useMemo<[number, number, number]>(() => {\n const [rx, ry, rz] = props.rotation ?? [0, 0, 0]\n return [rx, ry + (config.scene.turn * Math.PI) / 180, rz]\n }, [props.rotation, config.scene.turn])\n\n const controls = useThree((s) => s.controls) as { enabled?: boolean } | null\n const camera = useThree((s) => s.camera)\n\n const behaviorKey = JSON.stringify(config.behavior ?? null)\n const deformersKey = JSON.stringify(config.deformers ?? null)\n const sheetKey = JSON.stringify(config.sheet)\n /**\n * What the SHAPE path needs to know about physics, and nothing more.\n *\n * Deliberately not `JSON.stringify(config.physics)`. A simulation's config\n * is live — `strip.scroll` is rewritten every single frame by the host —\n * and a key that moves every frame re-runs the segment probe, hands the\n * geometry memo fresh array identities, rebuilds the geometry, and through\n * it rebuilds the sim, which throws away everything the sim had integrated.\n * A scroll-driven roll pinned to its own starting tail forever, sixty times\n * a second.\n *\n * Nothing downstream of here reads a sim's VALUES: an object-shaped physics\n * means there is no deformer stack at all, so the only thing that can change\n * the shape path is whether a sim is present and which one.\n */\n const physicsKey = typeof config.physics === 'object' ? config.physics.type : config.physics\n\n /**\n * The crease LINES, without their depths.\n *\n * Depth is exactly the part that moves while you are folding, and the only\n * thing downstream of this key is the geometry probe — which does not care.\n * `fold`'s appetite for segments is set by its hinge radius and its\n * direction, never by how far it has closed, so a crease deepening from 2°\n * to 20° cannot change the answer. Keying on the depth too would rebuild\n * the geometry on every frame of every fold, and take the sim and the\n * base-position buffer down with it — the same trap `physicsKey` above\n * exists to avoid.\n */\n const memoryKey = config.memory.creases.map((c) => `${c.angle}:${c.offset}`).join('|')\n\n /**\n * The creases WITH their depths — what the sheet is actually carrying.\n *\n * The lines-only key above cannot serve here, and the difference is the\n * whole reason there are two. Dragging a crease deeper changes no line, so\n * a lines-only key never fires: the tracker would go on holding the array\n * it was handed when the crease was created, the shading would follow the\n * edit (it reads config) and the geometry would not, and the depth slider\n * would darken the mark without bending the paper.\n */\n const creaseKey = config.memory.creases.map((c) => `${c.angle}:${c.offset}:${c.depth}`).join('|')\n\n /**\n * The sheet's live memory. Seeded from config and updated in the frame\n * loop; `onCrease` is how it gets back to config.\n */\n const creasesRef = useRef<CreaseTracker | null>(null)\n creasesRef.current ??= new CreaseTracker(config.memory.creases)\n const creases = creasesRef.current\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: The keys are change triggers; the body only touches refs.\n useEffect(() => {\n if (!draggingRef.current && !playingRef.current) overridesRef.current = {}\n // The slots track folds in a stack that no longer exists. The creases they\n // left do not go with it — a sheet does not un-crease because you gave it\n // a new behavior — so they carry over as the sheet's authored set.\n creases.reset()\n dirtyRef.current = true\n }, [behaviorKey, deformersKey, sheetKey, physicsKey])\n\n // Config-side creases changing means something outside the frame loop has an\n // opinion: an edit, a shared link, or the host persisting what we just\n // recorded. `adopt` works out which — an edit resets the folds it was\n // watching, an echo of its own recording does not.\n // biome-ignore lint/correctness/useExhaustiveDependencies: Keyed on the creases themselves; the body reads them off config.\n useEffect(() => {\n creases.adopt(configRef.current.memory.creases)\n dirtyRef.current = true\n }, [creaseKey])\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: Keyed on the stack shape — the probe reads config off a ref.\n const { minSegments, autoSegments, animatedStack } = useMemo(() => {\n const cfg = configRef.current\n // Creases are in the probe because a crease with no live fold on its line\n // is a fold instance the grid has never been asked about — an authored\n // dog-ear on an otherwise flat sheet needs `fold`'s 48-segment floor as\n // much as a real fold does, and a flat sheet is tessellated 2×2.\n const probe = withMemory(buildStack(cfg, {}), cfg)\n if (!probe) {\n return {\n minSegments: [2, 2] as SegmentPair,\n autoSegments: [FLAT_SEGMENTS, FLAT_SEGMENTS] as SegmentPair,\n animatedStack: false,\n }\n }\n\n // The grid is built once; a behavior's stack is not the same shape all\n // the way through. An unroll is a tight roll at one end of its progress\n // and a flat sheet at the other, so sizing to the configured moment\n // would leave the sheet under-tessellated for the rest of the play.\n // Sample the sweep and keep the densest answer. Every behavior's\n // progressParam is a 0..1 number — pinned by behaviors.test.ts, because\n // this loop silently samples the wrong range if that ever stops holding.\n //\n // Whether the stack is TIME-DRIVEN is answered off the same sweep, and\n // for the same reason: it is a property of the stack's shape, not of the\n // moment it happens to be at, and the frame loop needs it before it has\n // built anything — see `useFrame` below.\n const want = stackAutoSegments(probe, cfg.sheet)\n let animated = stackIsAnimated(probe)\n if (cfg.behavior && !cfg.deformers) {\n const param = getBehavior(cfg.behavior.type).progressParam\n for (const p of PROGRESS_SAMPLES) {\n const at = withMemory(buildStack(cfg, { [param]: p }), cfg)\n if (!at) continue\n const [x, y] = stackAutoSegments(at, cfg.sheet)\n if (x > want[0]) want[0] = x\n if (y > want[1]) want[1] = y\n animated ||= stackIsAnimated(at)\n }\n }\n return {\n minSegments: stackMinSegments(probe, cfg.sheet),\n autoSegments: want,\n animatedStack: animated,\n }\n }, [behaviorKey, deformersKey, physicsKey, memoryKey])\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: Keyed on the sheet — rebuilding geometry on identity would orphan GPU buffers every render.\n const geometry = useMemo(() => {\n if (isStrip) {\n // A strip is a 2×N quad ribbon: one column each side, one row per chain\n // node. The row count has to agree with the sim exactly, so both derive\n // it from the same function.\n const strip = configRef.current.physics as StripConfig\n const nodes = stripNodeCount(config.sheet.height, strip.perforation)\n return new THREE.PlaneGeometry(config.sheet.width, config.sheet.height, 1, nodes - 1)\n }\n if (!isCloth) return createSheetGeometry(config.sheet, minSegments, autoSegments)\n // Cloth: explicit capped grid so sim particles == mesh vertices. Square,\n // because the sim's constraints are laid out on a square lattice.\n //\n // The stack's own floor is in the max now that cloth can host one: a fold\n // needs 48 segments to bend through rather than crease along, and a\n // crumple more, and a shape running over a simulation is no less entitled\n // to the grid it needs than one running over a flat sheet. Still capped —\n // every particle is a constraint solve five times a frame.\n const [sx, sy] = resolveSegments(config.sheet, minSegments)\n const capped = Math.min(Math.max(sx, sy), CLOTH_MAX_SEGMENTS)\n return new THREE.PlaneGeometry(config.sheet.width, config.sheet.height, capped, capped)\n }, [\n sheetKey,\n minSegments,\n autoSegments,\n isCloth,\n isStrip,\n isStrip ? (config.physics as StripConfig).perforation : 0,\n ])\n\n // Imperatively-created geometry is ours to free — R3F only auto-disposes\n // JSX-created objects, so a sheet change would otherwise orphan GPU buffers.\n useEffect(() => () => geometry.dispose(), [geometry])\n\n const basePositions = useMemo(\n () => Float32Array.from(geometry.attributes.position!.array as Float32Array),\n [geometry],\n )\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: Rebuild only on geometry or pin layout change — sliders update the sim in place.\n const stripSim = useMemo(() => {\n if (!isStrip) return null\n const strip = configRef.current.physics as StripConfig\n return new StripSim(config.sheet.height, config.sheet.width, {\n scroll: strip.scroll,\n tightness: strip.tightness,\n core: strip.core,\n tail: strip.tail,\n perforation: strip.perforation,\n crease: strip.crease,\n stiffness: strip.stiffness,\n drag: strip.drag,\n gravity: strip.gravity,\n floor: strip.floor,\n inertia: strip.inertia,\n })\n }, [geometry, isStrip])\n\n // The sim the last committed render was running, so a rebuild can carry its\n // drape over instead of starting flat. Written after commit, never during a\n // render, or a render React threw away would be the one adopted from.\n const lastSimRef = useRef<ClothSim | null>(null)\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: Rebuild only on geometry or pin layout change — sliders update the sim in place.\n const sim = useMemo(() => {\n if (!isCloth) return null\n const cloth = configRef.current.physics as ClothConfig\n const cols = (geometry.parameters as { widthSegments: number }).widthSegments + 1\n const rows = (geometry.parameters as { heightSegments: number }).heightSegments + 1\n const next = new ClothSim(cols, rows, config.sheet.width, config.sheet.height, cloth.pins, {\n stiffness: cloth.stiffness,\n gravity: cloth.gravity,\n wind: cloth.wind,\n floor: cloth.floor,\n })\n // A resize keeps the drape; a restructure does not. `adopt` decides which\n // this was — see the note on it.\n next.adopt(lastSimRef.current)\n return next\n }, [geometry, isCloth, isCloth ? (config.physics as ClothConfig).pins : ''])\n\n useEffect(() => {\n lastSimRef.current = sim\n }, [sim])\n\n // What the sim feels of `damage`. Per sim, so a rebuilt one reads it afresh.\n const coupling = useMemo(() => (sim ? new DamageCoupling(sim) : null), [sim])\n\n const stock = getStock(config.stock)\n const texture = useContentTexture(config.content, config.sheet, stock)\n const backTexture = useContentTexture(config.content.back, config.sheet, stock)\n\n // Per-frame config: when a state machine is live it OWNS the animated numeric\n // values (GSAP tweens them); we poll its mutable liveConfig each frame rather\n // than routing every tick through React. Falls back to the React config for\n // non-stateful papers.\n const liveConfig = (): PaperConfig => machineRef.current?.liveConfig ?? configRef.current\n\n const effectiveOptions = (t: number): Record<string, unknown> | null => {\n const cfg = liveConfig()\n if (!cfg.behavior || !behavior) return null\n const o = { ...cfg.behavior, ...overridesRef.current }\n return behavior.loop ? { ...o, ...behavior.loop(o, t) } : o\n }\n\n const play = () => {\n if (!behavior) return\n playingRef.current = true\n if (tweenRef.current) {\n tweenRef.current.play()\n return\n }\n const param = behavior.progressParam\n const start = (effectiveOptions(0)?.[param] as number) ?? 0\n const state = { p: start }\n tweenRef.current = gsap.to(state, {\n p: 1,\n duration: behavior.duration * (1 - start),\n ease: 'power2.inOut',\n yoyo: behavior.loopMode === 'yoyo',\n repeat: -1,\n onRepeat: () => {\n if (behavior.loopMode === 'restart') state.p = 0\n },\n onUpdate: () => {\n const p = configRef.current.onTwos ? quantizeProgress(state.p, behavior.duration) : state.p\n overridesRef.current[param] = p\n dirtyRef.current = true\n props.onProgress?.(p)\n },\n })\n }\n\n const pause = () => {\n playingRef.current = false\n tweenRef.current?.pause()\n }\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: Mount-only: autoplay starts once, and the cleanup kills the tween on unmount.\n useEffect(() => {\n if (props.autoplay && !reduced) play()\n return () => {\n tweenRef.current?.kill()\n tweenRef.current = null\n }\n }, [])\n\n const snapshot = (): PaperConfig => {\n // Re-attach `states`: the rendered config is the animated view with the\n // machine stripped, but a snapshot is a preset — states are part of it.\n const states = resolvedRef.current.states\n const cfg = states ? { ...configRef.current, states } : configRef.current\n if (!cfg.behavior) return states ? paperConfigSchema.parse(cfg) : cfg\n return paperConfigSchema.parse({\n ...cfg,\n behavior: { ...cfg.behavior, ...overridesRef.current },\n })\n }\n\n useImperativeHandle(ref, () => ({\n play,\n pause,\n get playing() {\n return playingRef.current\n },\n set(param: string, value: unknown) {\n const key = param === 'progress' && behavior ? behavior.progressParam : param\n overridesRef.current[key] = value\n dirtyRef.current = true\n if (behavior && key === behavior.progressParam) props.onProgress?.(value as number)\n },\n getProgress() {\n if (!behavior) return 0\n return (effectiveOptions(0)?.[behavior.progressParam] as number) ?? 0\n },\n snapshot,\n toJSON: () => serializePreset(snapshot()),\n get mesh() {\n return meshRef.current\n },\n handlePoint(id?: string, target?: THREE.Vector3) {\n const handles = behavior?.handles\n if (!handles?.length) return null\n const index = id ? handles.findIndex((h) => h.id === id) : 0\n const mesh = handleRefs.current[index]\n if (!mesh) return null\n return mesh.getWorldPosition(target ?? new THREE.Vector3())\n },\n surfacePoint(u: number, v: number, target?: THREE.Vector3) {\n const mesh = meshRef.current\n if (!mesh) return null\n // Every sheet is a PlaneGeometry — shape, cloth and strip alike — so its\n // grid is on the parameters, and the position attribute is whatever this\n // frame wrote there.\n const { widthSegments, heightSegments } = geometry.parameters\n const out = surfacePointAt(\n geometry.attributes.position!.array,\n widthSegments + 1,\n heightSegments + 1,\n u,\n v,\n target ?? new THREE.Vector3(),\n )\n mesh.updateWorldMatrix(true, false)\n return out.applyMatrix4(mesh.matrixWorld)\n },\n get state() {\n return machineState\n },\n sendState: (event: StateEvent) => machineRef.current?.send(event) ?? null,\n pickProgrammatic: () => machineRef.current?.pickProgrammatic() ?? false,\n placeProgrammatic: () => machineRef.current?.placeProgrammatic() ?? false,\n returnProgrammatic: () => machineRef.current?.returnProgrammatic() ?? false,\n }))\n\n /**\n * The crease lines the shader draws.\n *\n * Off CONFIG rather than off the tracker, and that is the honest trade. The\n * shading is a shader uniform behind a React memo, so it updates when the\n * host writes a recorded crease back — a frame or two after the geometry\n * has it. A crease that has just formed is a fold the sheet is still most\n * of the way inside; the mark landing as it opens rather than as it closes\n * is the order it happens in on real paper anyway.\n */\n const shadedCreases = useMemo(\n () => resolveCreases(config.surface, config.memory.creases, config.sheet),\n [config.surface, config.memory.creases, config.sheet],\n )\n\n const idlePose = useRef<IdlePose>({ position: [0, 0, 0], rotation: [0, 0, 0] })\n\n useFrame(({ clock }, delta) => {\n const cfg = liveConfig()\n // Reduced motion freezes time-driven deformers at their resting phase.\n const now = reduced ? 0 : cfg.onTwos ? quantizeTime(clock.elapsedTime) : clock.elapsedTime\n\n // Whole-sheet motion — idle presets and behavior transforms (flight's\n // travel across the scene) compose additively; vertices stay untouched.\n const hasBehaviorTransform = Boolean(behavior?.transform && cfg.behavior)\n if ((idle?.transform || hasBehaviorTransform) && groupRef.current) {\n const pose = idlePose.current\n pose.position[0] = pose.position[1] = pose.position[2] = 0\n pose.rotation[0] = pose.rotation[1] = pose.rotation[2] = 0\n idle?.transform?.(now, pose)\n if (hasBehaviorTransform) {\n const o = effectiveOptions(now)\n if (o) behavior!.transform!(o, now, pose, cfg.sheet)\n }\n const base = props.position ?? [0, 0, 0]\n const baseRot = baseRotation\n groupRef.current.position.set(\n base[0] + pose.position[0],\n base[1] + pose.position[1],\n base[2] + pose.position[2],\n )\n groupRef.current.rotation.set(\n baseRot[0] + pose.rotation[0],\n baseRot[1] + pose.rotation[1],\n baseRot[2] + pose.rotation[2],\n )\n }\n\n // Simulation path: the strip owns the vertices.\n if (isStrip && stripSim) {\n const strip = cfg.physics as StripConfig\n stripSim.setParams({\n scroll: strip.scroll,\n tightness: strip.tightness,\n core: strip.core,\n tail: strip.tail,\n crease: strip.crease,\n stiffness: strip.stiffness,\n drag: strip.drag,\n gravity: strip.gravity,\n floor: strip.floor,\n inertia: strip.inertia,\n })\n stripSim.step(delta)\n if (!stripSim.asleep) {\n const position = geometry.attributes.position as THREE.BufferAttribute\n stripSim.writeInto(position.array as Float32Array)\n position.needsUpdate = true\n // Per-segment normals are what make the folds read: the underside of\n // each turn faces away from the key and goes dark on its own.\n computeSheetNormals(geometry)\n geometry.computeBoundingSphere()\n }\n return\n }\n\n // Shape: the deformer stack, run over whatever it is given as a base.\n //\n // `base` is the flat rest pose for a sheet that is only a shape, and the\n // simulation's live particles for one that is both. That substitution is\n // the whole of the composition: a deformer is a pure map from a point to\n // a point, so folding a draped sheet is folding the points the drape put\n // there. `force` is the simulation saying its vertices moved even though\n // nothing about the stack did.\n //\n // Decide whether there is anything to do BEFORE building it. A resting\n // sheet — no loop, no time-driven deformer, no transition, nothing\n // dirtied — used to expand its whole stack every frame and throw it\n // away, which is a behavior's `stack()` call and its deformer objects\n // sixty times a second for a picture that does not move.\n const applyShape = (base: Float32Array, force: boolean): boolean => {\n const animated = !reduced && animatedStack\n const hasLoop = !reduced && Boolean(cfg.behavior && behavior?.loop)\n // A state transition tweens numeric leaves off the React path, so the\n // stack must re-apply every frame while the machine is transitioning.\n const machineAnimating = Boolean(machineRef.current?.transitioning)\n if (!force && !dirtyRef.current && !hasLoop && !animated && !machineAnimating) return false\n\n const raw = buildStack(cfg, overridesRef.current, behavior, now)\n\n // How much this paper keeps: its own override, else what the stock is\n // made of. The same shape as every other stock default in the library.\n const setAmount = cfg.memory.set ?? stock.takesSet\n\n // Read the folds BEFORE memory rewrites them. `applyMemory` raises a live\n // fold to its crease's depth, and a tracker watching that would be reading\n // its own output — the crease would hold the fold open, and the held-open\n // fold would keep the crease alive, with nothing in the loop that is\n // actually the paper being folded.\n if (raw && creases.observe(raw, setAmount)) props.onCrease?.(creases.creases)\n\n const stack = withMemory(raw, cfg, creases.creases)\n if (!stack) return false\n dirtyRef.current = false\n\n const ctx = { t: now, sheet: cfg.sheet }\n applyDeformerStack(geometry, base, stack, ctx)\n\n if (props.interactive && behavior?.handles) {\n const o = effectiveOptions(now)\n behavior.handles.forEach((h, i) => {\n const mesh = handleRefs.current[i]\n if (!mesh || !o) return\n const [u, v] = h.anchor(o, cfg.sheet)\n anchorScratch.set((u - 0.5) * cfg.sheet.width, (v - 0.5) * cfg.sheet.height, 0)\n displacePoint(anchorScratch, u, v, stack, ctx)\n mesh.position.copy(anchorScratch)\n })\n }\n return true\n }\n\n // Simulation path: cloth writes the vertices, and may hand them on.\n if (isCloth && sim) {\n const cloth = cfg.physics as ClothConfig\n sim.setParams({\n wind: cloth.wind,\n gravity: cloth.gravity,\n stiffness: cloth.stiffness,\n floor: cloth.floor,\n })\n // Damage first — char, heat, wet and missing paper are levers on the\n // solve, and a free read when the source has not moved.\n coupling?.update(props.damage)\n sim.step(delta)\n const moved = !sim.asleep\n if (moved && coupling) {\n coupling.follow()\n // A piece a burn cut loose leaves with its own edge: the triangles\n // left spanning the gap are hidden once it opens — see `tear`.\n const index = geometry.index\n if (index && coupling.tear(index.array as Uint16Array | Uint32Array)) index.needsUpdate = true\n }\n // The stack first refusal: if there is one, it owns the write, because\n // its base is the sim's own array and writing that array to the\n // geometry first would only be overwritten. If there is none, the sim's\n // positions ARE the vertices, exactly as before.\n if (!applyShape(sim.positions, moved) && moved) {\n const position = geometry.attributes.position as THREE.BufferAttribute\n ;(position.array as Float32Array).set(sim.positions)\n position.needsUpdate = true\n computeSheetNormals(geometry)\n }\n return\n }\n\n // Shape path: the deformer stack over the flat sheet.\n applyShape(basePositions, false)\n })\n\n const localDragPoint = (e: ThreeEvent<PointerEvent>): { x: number; y: number } | null => {\n const group = groupRef.current\n if (!group) return null\n planeNormal.set(0, 0, 1).applyQuaternion(group.getWorldQuaternion(quatScratch))\n dragPlane.setFromNormalAndCoplanarPoint(planeNormal, group.getWorldPosition(dragPoint))\n const hit = e.ray.intersectPlane(dragPlane, dragPoint)\n if (!hit) return null\n group.worldToLocal(hit)\n return { x: hit.x, y: hit.y }\n }\n\n const onHandleDrag = (e: ThreeEvent<PointerEvent>) => {\n if (!behavior?.handles || !draggingRef.current) return\n const handleSpec = behavior.handles.find((h) => h.id === draggingRef.current)\n const local = localDragPoint(e)\n const o = effectiveOptions(0)\n if (!handleSpec || !local || !o) return\n Object.assign(overridesRef.current, handleSpec.drag(local, o, configRef.current.sheet))\n dirtyRef.current = true\n const p = overridesRef.current[behavior.progressParam]\n if (typeof p === 'number') props.onProgress?.(p)\n }\n\n // Cloth grab: pick the particle under the pointer, then drag it on a\n // camera-facing plane through the grab point — full 3D pull, not just\n // in-plane.\n const grabAnchor = useRef(new THREE.Vector3())\n /**\n * Where the vertex you grabbed sits relative to the particle behind it.\n *\n * Zero unless a deformer is running over the simulation, and then it is\n * exactly the displacement that deformer applied at the moment of the grab.\n * The pointer speaks in RENDERED space and the sim only understands its own,\n * so the offset is what translates between them — carried as a constant\n * rather than inverted every frame, because a deformer is a map with no\n * inverse to ask for. Exact when the grab lands and honest as it drifts.\n */\n const grabOffset = useRef(new THREE.Vector3())\n const clothDown = (e: ThreeEvent<PointerEvent>) => {\n if (!isCloth || !sim || !props.interactive || !groupRef.current) return\n e.stopPropagation()\n if (controls) controls.enabled = false\n grabAnchor.current.copy(e.point) // world-space anchor for the drag plane\n const local = groupRef.current.worldToLocal(worldScratch.copy(e.point))\n // Nearest RENDERED vertex, not nearest particle: they are the same sheet\n // only when nothing is deforming it, and the pointer hit the rendered one.\n const drawn = geometry.attributes.position!.array as Float32Array\n const index = nearestVertex(drawn, sim.count, local.x, local.y, local.z)\n sim.grab(index)\n const i3 = index * 3\n grabOffset.current.set(\n drawn[i3]! - sim.positions[i3]!,\n drawn[i3 + 1]! - sim.positions[i3 + 1]!,\n drawn[i3 + 2]! - sim.positions[i3 + 2]!,\n )\n draggingRef.current = 'cloth'\n ;(e.target as Element).setPointerCapture(e.pointerId)\n }\n const clothMove = (e: ThreeEvent<PointerEvent>) => {\n if (draggingRef.current !== 'cloth' || !sim || !groupRef.current) return\n camera.getWorldDirection(planeNormal)\n dragPlane.setFromNormalAndCoplanarPoint(planeNormal, grabAnchor.current)\n const hit = e.ray.intersectPlane(dragPlane, dragPoint)\n if (!hit) return\n groupRef.current.worldToLocal(hit)\n const offset = grabOffset.current\n sim.moveGrab(hit.x - offset.x, hit.y - offset.y, hit.z - offset.z)\n }\n const clothUp = (e: ThreeEvent<PointerEvent>) => {\n if (draggingRef.current !== 'cloth' || !sim) return\n draggingRef.current = null\n if (controls) controls.enabled = true\n sim.release()\n ;(e.target as Element).releasePointerCapture(e.pointerId)\n }\n\n /**\n * Take hold of the paper and pull, and the roll turns.\n *\n * Same drag plane as cloth — camera-facing, through the point first\n * touched — which degrades the right way for a strip. Head-on, that plane\n * holds depth fixed and the gesture is purely up and down, which is the\n * pull the object is famous for; from three-quarters it opens up and the\n * paper can be drawn out toward the viewer as well.\n *\n * The sim reads only y and z: the strip carries its width along x and never\n * twists, so there is nothing for a sideways drag to mean.\n */\n const stripDown = (e: ThreeEvent<PointerEvent>) => {\n if (!isStrip || !stripSim || !props.interactive || !groupRef.current) return\n e.stopPropagation()\n const local = groupRef.current.worldToLocal(worldScratch.copy(e.point))\n // Nothing is committed until the grab lands. `grabNearest` returns -1 when\n // there is no free paper to catch — every node still wound on the roll\n // belongs to the spiral — and disabling the camera before finding that out\n // left the controls dead for good: the early return skips both the pointer\n // capture and `stripUp`, so nothing ever turned them back on.\n if (stripSim.grabNearest(local.y, local.z) < 0) return\n if (controls) controls.enabled = false\n grabAnchor.current.copy(e.point)\n draggingRef.current = 'strip'\n ;(e.target as Element).setPointerCapture(e.pointerId)\n }\n const stripMove = (e: ThreeEvent<PointerEvent>) => {\n if (draggingRef.current !== 'strip' || !stripSim || !groupRef.current) return\n camera.getWorldDirection(planeNormal)\n dragPlane.setFromNormalAndCoplanarPoint(planeNormal, grabAnchor.current)\n const hit = e.ray.intersectPlane(dragPlane, dragPoint)\n if (!hit) return\n groupRef.current.worldToLocal(hit)\n stripSim.moveGrab(hit.y, hit.z)\n }\n const stripUp = (e: ThreeEvent<PointerEvent>) => {\n if (draggingRef.current !== 'strip' || !stripSim) return\n draggingRef.current = null\n if (controls) controls.enabled = true\n stripSim.release()\n ;(e.target as Element).releasePointerCapture(e.pointerId)\n }\n\n // Interaction-state triggers (rest ↔ hover ↔ pressed); pick/place/return\n // are driven by the field's carry controller through `sendState`.\n const sendState = (event: StateEvent) => machineRef.current?.send(event)\n\n return (\n <group ref={groupRef} position={props.position} rotation={baseRotation}>\n <mesh\n ref={meshRef}\n geometry={geometry}\n castShadow\n receiveShadow\n frustumCulled={false}\n onPointerOver={statesLive ? () => sendState('enter') : undefined}\n onPointerOut={statesLive ? () => sendState('leave') : undefined}\n onPointerDown={\n isCloth || isStrip || statesLive\n ? (e) => {\n if (isCloth) clothDown(e)\n if (isStrip) stripDown(e)\n if (statesLive) sendState('down')\n }\n : undefined\n }\n onPointerMove={isCloth ? clothMove : isStrip ? stripMove : undefined}\n onPointerUp={\n isCloth || isStrip || statesLive\n ? (e) => {\n if (isCloth) clothUp(e)\n if (isStrip) stripUp(e)\n if (statesLive) sendState('up')\n }\n : undefined\n }\n >\n <PaperMaterial\n stock={stock}\n texture={texture}\n backTexture={backTexture}\n surface={config.surface}\n thickness={config.sheet.thickness}\n sheet={config.sheet}\n lighting={config.scene.lighting}\n creases={shadedCreases}\n damage={props.damage}\n />\n </mesh>\n {props.interactive &&\n // Any simulation, not cloth alone: a sim owns the vertices, so there\n // is no deformer stack for a handle to drive. Harmless as `!isCloth`\n // only because the schema makes a sim and a behavior exclusive — the\n // intent is what is written here.\n !simKind &&\n behavior?.handles?.map((h, i) => (\n <mesh\n key={h.id}\n // Marked as chrome so a renderer that is producing a PICTURE can\n // leave it out. The handle is an editing affordance, and it is\n // drawn with `depthTest: false` precisely so it sits on top of\n // the sheet — which makes it the most prominent thing in any\n // frame captured for export. The editor's capture rig reads this.\n userData={{ paperlabChrome: true }}\n ref={(m) => {\n handleRefs.current[i] = m\n }}\n onPointerDown={(e) => {\n e.stopPropagation()\n draggingRef.current = h.id\n pause()\n if (controls) controls.enabled = false\n ;(e.target as Element).setPointerCapture(e.pointerId)\n }}\n onPointerMove={onHandleDrag}\n onPointerUp={(e) => {\n if (!draggingRef.current) return\n draggingRef.current = null\n if (controls) controls.enabled = true\n ;(e.target as Element).releasePointerCapture(e.pointerId)\n props.onBehaviorChange?.({ ...overridesRef.current })\n }}\n >\n <sphereGeometry args={[0.035, 16, 16]} />\n <meshBasicMaterial color=\"#4f7cff\" depthTest={false} transparent opacity={0.9} />\n </mesh>\n ))}\n </group>\n )\n})\n\n/**\n * A stack with the sheet's CONFIGURED creases folded in — the probe's view of\n * memory.\n *\n * The frame loop does not use this: it has the tracker's live creases, which\n * are ahead of config by however long the host takes to persist them. Both\n * paths agree on the lines, which is the only thing the geometry probe reads.\n */\nfunction withMemory(\n stack: DeformerInstance[] | null,\n config: PaperConfig,\n creases: CreaseConfig[] = config.memory.creases,\n): DeformerInstance[] | null {\n // A strip owns its vertices outright; cloth hands them on to the stack.\n // Which means a crease on a CLOTH sheet is now a fold the geometry runs,\n // not just a mark the shader draws — the paper remembers a fold whether or\n // not it is being simulated.\n if (isStripConfig(config.physics)) return null\n const out = applyMemory(stack ?? [], creases)\n // Empty and null mean different things upstream — null is \"nothing deforms\n // this sheet\", which is the answer that gets it the flat-sheet grid.\n return out.length > 0 ? out : null\n}\n\n/**\n * The vertex nearest a local-space point, by index.\n *\n * Reads the array it is handed rather than the simulation, which is the point\n * of it: what a pointer touched is what is on screen.\n */\nfunction nearestVertex(array: Float32Array, count: number, x: number, y: number, z: number): number {\n let best = -1\n let bestDist = Infinity\n for (let i = 0; i < count; i++) {\n const i3 = i * 3\n const dx = array[i3]! - x\n const dy = array[i3 + 1]! - y\n const dz = array[i3 + 2]! - z\n const d = dx * dx + dy * dy + dz * dz\n if (d < bestDist) {\n bestDist = d\n best = i\n }\n }\n return best\n}\n\n/** The one simulation that will not share its vertices. See the schema. */\nfunction isStripConfig(physics: PaperConfig['physics']): boolean {\n return typeof physics === 'object' && physics.type === 'strip'\n}\n\n/** Expand the config into the deformer stack that should run this frame. */\nfunction buildStack(\n config: PaperConfig,\n overrides: Record<string, unknown>,\n behavior?: Behavior | null,\n t = 0,\n): DeformerInstance[] | null {\n // A strip owns the vertices outright — no deformer stack. Cloth does not:\n // it writes the vertices and the stack runs over what it wrote.\n if (isStripConfig(config.physics)) return null\n const idle =\n typeof config.physics === 'string' && config.physics !== 'none'\n ? getIdlePreset(config.physics as IdleName)\n : null\n const idleStack = idle?.stack?.() ?? []\n\n let shapeStack: DeformerInstance[] = []\n if (config.deformers) {\n // Raw deformer stack wins — it's the Advanced fork of a behavior.\n shapeStack = resolveDeformerStack(config.deformers)\n } else if (config.behavior) {\n const b = behavior ?? getBehavior(config.behavior.type)\n let options: Record<string, unknown> = { ...config.behavior, ...overrides }\n if (b.loop) options = { ...options, ...b.loop(options, t) }\n shapeStack = b.stack(options, config.sheet)\n }\n\n const combined = [...shapeStack, ...idleStack]\n return combined.length > 0 ? combined : null\n}\n","import { z } from 'zod'\nimport { mergeConfig } from './merge'\nimport { peelOptionsSchema } from '../behaviors/peel'\nimport { unrollOptionsSchema } from '../behaviors/unroll'\nimport { flipOptionsSchema } from '../behaviors/flip'\nimport { letterFoldOptionsSchema } from '../behaviors/letter-fold'\nimport { hangOptionsSchema } from '../behaviors/hang'\nimport { flyOptionsSchema } from '../behaviors/fly'\nimport { fallOptionsSchema } from '../behaviors/fall'\nimport { carryOptionsSchema } from '../behaviors/carry'\nimport { flightOptionsSchema } from '../behaviors/flight'\nimport { crumpleBehaviorOptionsSchema } from '../behaviors/crumple'\nimport { settleOptionsSchema } from '../behaviors/settle'\nimport { ribbonOptionsSchema } from '../behaviors/ribbon'\n\n/**\n * The zod schema is the single source of truth: it validates the public API,\n * generates editor panels, defines the `.paper` preset format, and feeds the docs.\n * If a feature can't serialize into this schema, it waits.\n *\n * Every schema here exports BOTH of its types, and the difference is\n * load-bearing. `z.infer` is the parsed config — every default filled in,\n * every field present — and it is what the renderer reads. `z.input` is what\n * a caller is allowed to write, where anything with a default is optional,\n * and it is what every public prop must take. Handing a component the\n * inferred type instead demands that the caller supply every field of every\n * nested object, which turns the documented one-liner into a type error.\n */\n\n// ── Sheet ────────────────────────────────────────────────────────────────────\n\nexport const sheetSchema = z.object({\n /** World units. A letter sheet is ~1 × 1.4, a receipt ~1 × 2.6. */\n width: z.number().positive().max(20).default(1),\n height: z.number().positive().max(20).default(1.4),\n /** Visual thickness in mm-ish units; drives edge/shadow treatment, not geometry (yet). */\n thickness: z.number().min(0).max(2).default(0.2),\n /**\n * `'auto'` sizes the grid from the active deformers' needs — genuinely, as\n * of 0.3.0. It asks each one what these options require (a gentle bend and\n * a tight roll are not the same request), takes the densest answer, and\n * snaps it to a ladder so dragging a slider does not rebuild the mesh.\n *\n * It is capped at 72, which is what it used to hand out flat regardless of\n * what was on the sheet, so `'auto'` can only ever subdivide LESS than it\n * did before — a blank sheet drops from 72 a side to 8, and stops being\n * tessellated as finely as a crumpled one.\n *\n * Set a number to take the decision yourself; a deformer's `minSegments`\n * still raises it, because that is a correctness floor rather than a\n * preference.\n */\n segments: z.union([z.literal('auto'), z.number().int().min(2).max(256)]).default('auto'),\n cornerRadius: z.number().min(0).max(0.5).default(0),\n})\n\nexport type SheetConfig = z.infer<typeof sheetSchema>\n\n// ── Stock ────────────────────────────────────────────────────────────────────\n\nexport const stockNames = [\n 'printer',\n 'thermal',\n 'kraft',\n 'newsprint',\n 'vellum',\n 'photo-gloss',\n 'sticker',\n] as const\nexport const stockSchema = z.enum(stockNames)\nexport type StockName = z.infer<typeof stockSchema>\n\n// ── Content ──────────────────────────────────────────────────────────────────\n\n/**\n * A watercolour wash, painted under whatever else the sheet carries.\n *\n * It is a FIELD on every content type rather than a content type of its own,\n * and that is the whole design. A wash is a ground, not a subject: the thing\n * people want is a letter written over one, a card laid on one, a poster with\n * one behind the type. Made a sixth member of the union it would have been\n * mutually exclusive with the text it exists to sit behind, and the only way\n * to get both would have been to bake the words into an uploaded picture —\n * which is exactly the trick this library exists to avoid.\n *\n * Painted rather than shipped as artwork, for the same reason `DEMO_CARDS`\n * are typeset rather than photographed. A bitmap is ~100KB that cannot cross\n * a share link, does not survive an export to someone else's codebase, and\n * does not know what stock it is lying on. A wash described in nine numbers\n * travels anywhere the config does, tints against the paper under it, and\n * curls with the mesh because it IS the texture.\n */\nexport const washSchema = z.object({\n /** The first pigment. */\n color: z.string().default('#4a5b8c').describe('color'),\n /** The second. Blooms alternate, and overlaps multiply into a third. */\n secondary: z.string().default('#b06a6a').describe('color'),\n /** How many pools of colour. */\n blooms: z.number().int().min(1).max(24).default(7),\n /** How far a pool runs before it dries — its size against the sheet. */\n spread: z.number().min(0.1).max(1).default(0.7),\n /** Softness of the wet edge. 0 is a hard cut, 1 is a pool still moving. */\n bleed: z.number().min(0).max(1).default(0.5),\n /** How much pigment is in the water. */\n intensity: z.number().min(0).max(1).default(0.55),\n /**\n * Edge darkening — the ring of pigment left where a pool dried.\n *\n * The signature of the medium, and the one thing a plain gradient cannot\n * fake. Without it a wash reads as an airbrush.\n */\n edge: z.number().min(0).max(1).default(0.6),\n /** Pigment settling into the tooth of the paper. */\n granulation: z.number().min(0).max(1).default(0.35),\n /** Fixed so a preset paints the same wash every time. */\n seed: z.number().int().min(0).max(99).default(0),\n})\n\nexport type WashConfig = z.infer<typeof washSchema>\n\nconst blankContentBase = z.object({\n type: z.literal('blank'),\n})\n\nconst imageContentBase = z.object({\n type: z.literal('image'),\n /**\n * Empty means \"no picture yet\", and renders as bare stock rather than as\n * a failure. That is what lets a built-in preset be an image preset\n * without shipping — or fetching — a photograph: `photo-print` and\n * `postage-stamp` are containers for the caller's own art, handed over via\n * `<PaperField images={...} />` or `content.src`.\n */\n src: z.string().default(''),\n fit: z.enum(['cover', 'contain']).default('cover'),\n /** Read by the hidden DOM mirror and the no-WebGL fallback. */\n alt: z.string().optional(),\n})\n\nconst textContentBase = z.object({\n type: z.literal('text'),\n text: z.string().default('Dear reader,'),\n font: z.string().default('Georgia, \"Times New Roman\", serif'),\n /** px at texture resolution (long edge = 1024 logical px before DPR). */\n size: z.number().min(8).max(256).default(44),\n weight: z.number().min(100).max(900).default(400),\n color: z.string().default('#2b2620').describe('color'),\n align: z.enum(['left', 'center', 'right']).default('left'),\n /** Fraction of the short edge. */\n padding: z.number().min(0).max(0.4).default(0.09),\n lineHeight: z.number().min(0.8).max(3).default(1.45),\n /**\n * Letter-spacing, in em. The one control display type cannot do without:\n * a line set large enough to be read across a room needs its tracking\n * pulled IN, and a small line of uppercase small-print needs it pushed\n * out, and neither is achievable by changing the size.\n */\n tracking: z.number().min(-0.1).max(0.6).default(0),\n /**\n * Where the block sits down the sheet.\n *\n * `top` is the old behaviour and stays the default, because a letter\n * starts at the top of the page. `center` is what a card, a label or a\n * poster wants — a block of type optically centred in the sheet rather\n * than hung from its top edge.\n */\n valign: z.enum(['top', 'center']).default('top'),\n})\n\n/**\n * A card: the small stiff printed thing paper is most often cut into.\n *\n * One type covers the index card, the library due-date card, the museum\n * wall label, the telegram slip and the gallery quote sheet, because they\n * are the same object — a tracked label, a rule, a body, and a line of small\n * print — differing only in which parts are present.\n *\n * It exists because `text` could not make any of them. `text` sets a block\n * of prose in one size and one weight; every artifact above is a\n * COMPOSITION, with a hierarchy and a rule in it, and composing one out of\n * plain text meant hand-placing newlines and hoping.\n */\nconst cardContentBase = z.object({\n type: z.literal('card'),\n /** Small, tracked, uppercase by convention — the label at the top. */\n title: z.string().default(''),\n /** The card's reason for existing. */\n body: z.string().default(''),\n /** Attribution, catalogue number, date — the line in small print at the foot. */\n note: z.string().default(''),\n /** A hairline under the title. What separates a label from a paragraph. */\n rule: z.boolean().default(true),\n /**\n * Ruled writing lines behind the body, as on an index card.\n *\n * Drawn UNDER the type and in the stock's own ink at low alpha, so they\n * read as printed on the card rather than as underlines on the words.\n */\n ruled: z.boolean().default(false),\n font: z.string().default('Georgia, \"Times New Roman\", serif'),\n /**\n * Body size, px at texture resolution. Title and note derive from it.\n *\n * Set larger than the `text` default on purpose. A card is a small object\n * read close up, so its type is LARGE relative to the sheet; at the text\n * block's 42 the composition floated in the middle of the card with a\n * third of the stock empty above and below it, which reads as a page that\n * was cropped rather than as a card that was set.\n */\n size: z.number().min(8).max(256).default(58),\n color: z.string().default('#2b2620').describe('color'),\n align: z.enum(['left', 'center']).default('left'),\n padding: z.number().min(0).max(0.4).default(0.1),\n})\n\nconst receiptContentBase = z.object({\n type: z.literal('receipt'),\n store: z.string().default('PAPERLAB'),\n address: z.string().default('124 PAPER ST'),\n items: z.array(z.object({ name: z.string(), price: z.number() })).default([\n { name: 'CURL, TRUE', price: 12 },\n { name: 'ROLL, TIGHT', price: 8.5 },\n { name: 'SHEET, ONE', price: 0.99 },\n ]),\n taxRate: z.number().min(0).max(1).default(0.08),\n barcode: z.boolean().default(true),\n /** Fixed so presets render deterministically; omit for \"now\". */\n timestamp: z.string().optional(),\n footer: z.string().default('KEEP FOR YOUR RECORDS'),\n})\n\n/** A ground under the subject, on either side of the sheet. */\nconst withWash = { wash: washSchema.optional() }\n\n/** What can print on the reverse side (letter front / blank back, printed front / kraft back). */\nexport const backContentSchema = z.discriminatedUnion('type', [\n blankContentBase.extend(withWash),\n imageContentBase.extend(withWash),\n textContentBase.extend(withWash),\n cardContentBase.extend(withWash),\n receiptContentBase.extend(withWash),\n])\n\nexport type BackContentConfig = z.infer<typeof backContentSchema>\n\n/**\n * What every content type carries besides its own subject: what prints on\n * the reverse, and what is washed on underneath.\n */\nconst withBack = { back: backContentSchema.optional(), ...withWash }\n\nexport const blankContentSchema = blankContentBase.extend(withBack)\nexport const imageContentSchema = imageContentBase.extend(withBack)\nexport const textContentSchema = textContentBase.extend(withBack)\nexport const cardContentSchema = cardContentBase.extend(withBack)\nexport const receiptContentSchema = receiptContentBase.extend(withBack)\n\nexport const contentSchema = z.discriminatedUnion('type', [\n blankContentSchema,\n imageContentSchema,\n textContentSchema,\n cardContentSchema,\n receiptContentSchema,\n])\n\nexport type ContentConfig = z.infer<typeof contentSchema>\n/** What a caller may WRITE — defaults still unfilled. This is the prop type. */\nexport type ContentConfigInput = z.input<typeof contentSchema>\n\n/**\n * Every kind of thing that can print on a sheet, in declaration order.\n *\n * Read off the union rather than written out beside it. The sibling name\n * lists here (`stockNames`, `physicsNames`) are the SOURCE their schema is\n * built from, so a hand-written array is the single source of truth; this\n * one is not — the union is — and a second copy would be free to drift the\n * day a sixth content type lands.\n */\nexport const contentNames = contentSchema.options.map(\n (option) => option.shape.type.value,\n) as readonly ContentConfig['type'][]\n\n/**\n * One variant's schema, by its `type`.\n *\n * Exists so that a caller GENERATING UI from the schema — the editor's\n * inspector already does this for behaviors, layouts and the stage — can\n * reach a content variant without reaching into the union's internals.\n * Which member carries which discriminator is the union's own fact to\n * state, not a walk's to rediscover.\n */\nexport function contentSchemaFor(type: ContentConfig['type']): (typeof contentSchema)['options'][number] {\n const option = contentSchema.options.find((candidate) => candidate.shape.type.value === type)\n if (!option) throw new Error(`Unknown content type: ${type}`)\n return option\n}\n\n// ── Surface ──────────────────────────────────────────────────────────────────\n\nexport const paperEdges = ['top', 'right', 'bottom', 'left'] as const\n\n/**\n * Fragment-side effects, composed in registration order into one shader\n * program. Stocks contribute defaults (thermal → banding + yellowing);\n * explicit surface config overrides per effect.\n */\nexport const surfaceSchema = z.object({\n /** Paper fiber noise, 0..1. */\n grain: z.number().min(0).max(1).optional(),\n /** Light passing through the sheet from behind, 0..1. Stock defaults apply. */\n translucency: z.number().min(0).max(1).optional(),\n /** Torn-edge alpha with a lightened fiber band. */\n deckle: z\n .object({\n edges: z.array(z.enum(paperEdges)).default(['bottom']),\n roughness: z.number().min(0).max(1).default(0.5),\n })\n .optional(),\n /** Visual AO/highlight companion to the fold deformer. */\n creaseLines: z\n .object({\n /** Crease line direction, degrees (0 = horizontal lines). */\n angle: z.number().min(-360).max(360).default(0),\n /** Positions across the sheet, 0..1 fractions. */\n positions: z.array(z.number().min(0).max(1)).default([1 / 3, 2 / 3]),\n strength: z.number().min(0).max(1).default(0.5),\n })\n .optional(),\n /** Yellowing + foxing spots, 0..1. */\n aging: z.number().min(0).max(1).optional(),\n /** Reversed front-content ghost on the backside, 0..1. Stock defaults apply. */\n showThrough: z.number().min(0).max(1).optional(),\n /**\n * Postage-stamp perforation: alpha-punched semicircular holes along chosen\n * edges. `state` flips an edge to a ripped-through profile (torn) — set\n * automatically when a paper detaches from a `sheet` field, manual wins.\n */\n perforation: z\n .object({\n edges: z.union([z.array(z.enum(paperEdges)), z.literal('all')]).default('all'),\n /** World units — default tuned to stamp scale. */\n holeRadius: z.number().min(0.002).max(0.1).default(0.016),\n spacing: z.number().min(0.01).max(0.5).default(0.055),\n state: z\n .object({\n top: z.enum(['intact', 'torn']).optional(),\n right: z.enum(['intact', 'torn']).optional(),\n bottom: z.enum(['intact', 'torn']).optional(),\n left: z.enum(['intact', 'torn']).optional(),\n })\n .default({}),\n })\n .optional(),\n})\n\nexport type SurfaceConfig = z.infer<typeof surfaceSchema>\nexport type SurfaceConfigInput = z.input<typeof surfaceSchema>\nexport type PaperEdge = (typeof paperEdges)[number]\n\n// ── Memory ───────────────────────────────────────────────────────────────────\n\n/**\n * A crease the paper carries: a line it has been folded along and did not\n * fully come back from.\n *\n * `angle` and `offset` name the line exactly as {@link foldOptionsSchema}\n * does — angle is the direction the fold TRAVELS and the crease line runs\n * perpendicular to it, offset is the signed distance of that line from the\n * sheet's centre along the travel direction. Naming the line in the fold\n * deformer's own terms is what lets a remembered crease and a live fold\n * recognise each other as the same crease rather than stack into two.\n */\nexport const creaseSchema = z.object({\n angle: z.number().min(-360).max(360).default(90),\n offset: z.number().min(-20).max(20).default(0),\n /**\n * The residual fold angle in degrees, signed — how far open the crease\n * still sits once nothing is holding the paper. This is the whole of what\n * a crease IS: geometry and shading both read it, and it is what makes the\n * field authorable by hand (a dog-ear is a crease with a big `depth` near\n * a corner) rather than only recordable.\n */\n depth: z.number().min(-180).max(180).default(12),\n})\n\nexport type CreaseConfig = z.infer<typeof creaseSchema>\nexport type CreaseConfigInput = z.input<typeof creaseSchema>\n\n/**\n * What the sheet remembers having been done to it.\n *\n * Paper is PLASTIC where cloth is elastic: fold it and it keeps the fold.\n * Every deformer in the library is a pure function of its options, so a\n * sheet folded to 180° and back to 0° comes out of the stack pristine —\n * which is right for cloth and wrong for the one material Paperlab models.\n * This is the layer that remembers, and it lives beside the stack rather\n * than inside it precisely so deformers stay pure.\n */\nexport const memorySchema = z.object({\n /**\n * How much of a fold this paper keeps, 0..1, over the stock's own\n * {@link Stock.takesSet}. Kraft holds a crease hard; vellum springs most\n * of the way back.\n */\n set: z.number().min(0).max(1).optional(),\n /**\n * The creases themselves. Recorded by folding the paper (see\n * `onCrease`), or written by hand — a preset can ship already creased.\n *\n * Capped at four because that is what the crease shader carries, and a\n * cap the schema states is better than one the renderer applies silently.\n */\n creases: z.array(creaseSchema).max(4).default([]),\n})\n\nexport type MemoryConfig = z.infer<typeof memorySchema>\nexport type MemoryConfigInput = z.input<typeof memorySchema>\n\n// ── Behavior & deformers ─────────────────────────────────────────────────────\n\nexport const behaviorConfigSchema = z.discriminatedUnion('type', [\n peelOptionsSchema.extend({ type: z.literal('peel') }),\n unrollOptionsSchema.extend({ type: z.literal('unroll') }),\n flipOptionsSchema.extend({ type: z.literal('flip') }),\n letterFoldOptionsSchema.extend({ type: z.literal('letter-fold') }),\n hangOptionsSchema.extend({ type: z.literal('hang') }),\n flyOptionsSchema.extend({ type: z.literal('fly') }),\n fallOptionsSchema.extend({ type: z.literal('fall') }),\n carryOptionsSchema.extend({ type: z.literal('carry') }),\n flightOptionsSchema.extend({ type: z.literal('flight') }),\n crumpleBehaviorOptionsSchema.extend({ type: z.literal('crumple') }),\n settleOptionsSchema.extend({ type: z.literal('settle') }),\n ribbonOptionsSchema.extend({ type: z.literal('ribbon') }),\n])\n\nexport type BehaviorConfig = z.infer<typeof behaviorConfigSchema>\nexport type BehaviorConfigInput = z.input<typeof behaviorConfigSchema>\n\n/** Advanced escape hatch: a raw deformer stack (editing one forks the behavior). */\nexport const deformerInstanceSchema = z.object({\n type: z.string(),\n options: z.record(z.string(), z.unknown()).default({}),\n enabled: z.boolean().default(true),\n})\n\nexport type DeformerInstanceConfig = z.infer<typeof deformerInstanceSchema>\nexport type DeformerInstanceConfigInput = z.input<typeof deformerInstanceSchema>\n\n// ── Physics ──────────────────────────────────────────────────────────────────\n\n/** Kept in sync with `idleNames` in physics/idle.ts (asserted by test). */\nexport const physicsNames = ['none', 'float', 'tumble', 'dangle', 'taped', 'breeze'] as const\n\nexport const clothConfigSchema = z.object({\n type: z.literal('cloth'),\n pins: z.enum(['top-edge', 'top-corners', 'corner', 'none']).default('top-edge'),\n wind: z.number().min(0).max(1).default(0.3),\n /** Bend stiffness: 1 = crisp paper, 0 = silk. */\n stiffness: z.number().min(0).max(1).default(0.8),\n gravity: z.number().min(0).max(2).default(1),\n /** Local-space ground plane the sheet settles onto. */\n floor: z.number().min(-5).max(0).default(-1.4),\n})\n\nexport type ClothConfig = z.infer<typeof clothConfigSchema>\n\n/**\n * A strip of paper paying off a roll, and the pile it makes when it lands.\n *\n * The one simulation with a driving body: `scroll` turns the roll, the roll\n * extrudes paper, and the paper is left to fall. Bind `scroll` to the page —\n * it is a MONOTONIC world-unit figure, not a 0..1 progress, because the sim\n * differentiates it and only ever reads the delta.\n */\nexport const stripConfigSchema = z.object({\n type: z.literal('strip'),\n /** How far the page has scrolled, in world units of paper asked for. */\n scroll: z.number().min(-1000).max(1000).default(0),\n /** Thin layers and many turns, or few and fat. */\n tightness: z.number().min(0).max(1).default(0.6),\n /** Radius of the cardboard tube — the roll never pays out past it. */\n core: z.number().min(0.01).max(0.5).default(0.09),\n /** Paper already hanging before the first scroll. A roll always has a leaf out. */\n tail: z.number().min(0).max(20).default(1.1),\n /** Spacing of the perforations: one sheet's worth of strip, in world units. */\n perforation: z.number().min(0.05).max(5).default(1),\n /**\n * How much a perforation remembers being folded. 0 = a fresh roll, 1 = one\n * that has been used.\n *\n * The default is high on purpose: below about 0.6 the landed paper flops\n * over in flat panels and spreads across the floor, and at 0.7 it holds its\n * folds and stacks into an accordion. The pile is the point.\n */\n crease: z.number().min(0).max(1).default(0.7),\n /** Bend stiffness between perforations. 1 = card, 0 = cloth. */\n stiffness: z.number().min(0).max(1).default(0.55),\n /** Broadside air drag — what makes paper float down rather than drop. */\n drag: z.number().min(0).max(1).default(0.55),\n gravity: z.number().min(0).max(2).default(1),\n /**\n * How far below the roll the paper lands. A DISTANCE below the roll's axis,\n * matching `unroll.floor`, not a signed y like `cloth.floor` — the roll\n * family measures drops, and the composition is centred on the origin so\n * an absolute y would not survive the offset anyway.\n */\n floor: z.number().min(0.1).max(30).default(1.2),\n /** How long the roll coasts after the scroll stops. */\n inertia: z.number().min(0).max(1).default(0.45),\n})\n\nexport type StripConfig = z.infer<typeof stripConfigSchema>\n\nexport const physicsSchema = z.union([\n z.enum(physicsNames),\n z.literal('cloth').transform(() => clothConfigSchema.parse({ type: 'cloth' })),\n z.literal('strip').transform(() => stripConfigSchema.parse({ type: 'strip' })),\n clothConfigSchema,\n stripConfigSchema,\n])\n\nexport type PhysicsConfig = z.infer<typeof physicsSchema>\nexport type PhysicsConfigInput = z.input<typeof physicsSchema>\n\n// ── Scene ────────────────────────────────────────────────────────────────────\n\nexport const lightingNames = [\n 'studio',\n 'window',\n 'leaves',\n 'goldenhour',\n 'noir',\n 'nave',\n 'raking',\n 'lightbox',\n] as const\n\n/**\n * The film the picture is printed on — the tone curve that maps unbounded\n * scene light onto a screen.\n *\n * This matters more here than in most 3D work because the subject is almost\n * white. A sheet of printer stock sits at `#fbfaf7`, and a lit one runs past\n * 1.0 constantly, so the whole image lives in the part of the curve where\n * tone mappers disagree most.\n *\n * - `neutral` — **the default.** Khronos PBR Neutral, built specifically to\n * preserve hue and saturation through the highlight roll-off. On a warm\n * backlit hall it is the only one of the three that keeps the light warm.\n * - `agx` — filmic, with a long, very graceful roll-off. It also desaturates\n * hard as it approaches white, which is a look; on a scene whose subject\n * IS warm light through paper it bleaches the thing you came for.\n * - `filmic` — ACES. High contrast, drifts bright neutrals toward\n * yellow-green, and washes out badly once a source is bright enough to\n * clip. This is what every preset was pinned to before.\n *\n * Measured on `nave` rather than argued: rendered through all three with the\n * source authored as a real HDR emitter, `neutral` holds the cream glow,\n * `agx` and `filmic` both bleach it to grey-white.\n */\nexport const filmNames = ['agx', 'neutral', 'filmic'] as const\n\n/** Scene-level presentation, serialized with the paper. */\n/**\n * Overrides on top of a named preset — the Blender-panel half of lighting.\n *\n * Every field is optional ON PURPOSE. An unset field means \"whatever the\n * preset says\", so a shared link carries the two sliders you actually moved\n * rather than a frozen copy of a rig you never touched, and re-basing onto\n * another preset keeps your intent instead of your numbers.\n */\nexport const lightSchema = z.object({\n /** Tone-mapping exposure — the stop the whole picture is printed at. */\n exposure: z.number().min(0.1).max(4).optional(),\n /**\n * The tone curve — the film, where `exposure` is the stop.\n *\n * `filmic` is ACES, which is what every preset used to be pinned to and is\n * kept so a scene tuned against it can say so. On near-white paper it is\n * the wrong film: it desaturates and drags bright neutrals toward\n * yellow-green, which is the sepia cast a lit sheet used to pick up.\n */\n film: z.enum(filmNames).optional(),\n /** Key light strength. */\n key: z.number().min(0).max(12).optional(),\n /** Key light colour. */\n color: z.string().optional().describe('color'),\n /**\n * Where the key stands, degrees around the vertical. 0° is straight in\n * front of the paper (+Z, beside the camera), 90° is off to the right,\n * and ±180° is directly behind it — which is where `nave` puts it, and\n * why that preset is carried by light coming THROUGH the paper.\n */\n direction: z.number().min(-180).max(180).optional(),\n /** How high the key stands, degrees above the horizon. */\n height: z.number().min(-30).max(89).optional(),\n /** Flat fill from every direction at once. Cheap, and it kills form — reach for `studio` first. */\n ambient: z.number().min(0).max(2).optional(),\n /** The room's own light: an environment map built from `sky`. Directional fill, and the only thing paper's sheen has to reflect. */\n studio: z.number().min(0).max(3).optional(),\n /** Distance haze, as a multiple of the preset's. 0 clears the air entirely; 2 halves the distance you can see. */\n haze: z.number().min(0).max(3).optional(),\n})\n\nexport type LightOverrides = z.infer<typeof lightSchema>\nexport type LightOverridesInput = z.input<typeof lightSchema>\n\n/**\n * What is behind the sheet.\n *\n * Optional, and that is deliberate: an unset backdrop means the canvas is\n * left exactly as it was found. `<Paper>` has always rendered onto whatever\n * is behind it, and a default that painted the frame would change the look\n * of every sheet already on a page.\n *\n * It is part of the CONFIG rather than a preview trick in the editor,\n * because the whole export story is that the code you copy makes the picture\n * you were looking at. A backdrop that existed only in the editor would make\n * the most-photographed part of a composition the one thing that does not\n * travel.\n */\nexport const backdropSchema = z.object({\n /** Behind everything, and behind the picture where it does not reach. */\n color: z.string().default('#171717').describe('color'),\n /** A URL, or an uploaded picture. Empty is the colour on its own. */\n image: z.string().default(''),\n fit: z.enum(['cover', 'contain']).default('cover'),\n /**\n * Toward the colour, so the paper stays the subject.\n *\n * A backdrop at full strength competes with the sheet in front of it —\n * which is what a real photographer solves by putting the background out\n * of the light, and what this solves by mixing it back toward the ground\n * it sits on.\n */\n fade: z.number().min(0).max(1).default(0.25),\n /** Out of focus, for the same reason. */\n blur: z.number().min(0).max(1).default(0.2),\n})\n\nexport type BackdropConfig = z.infer<typeof backdropSchema>\n\nexport const sceneSchema = z.object({\n lighting: z.enum(lightingNames).default('studio'),\n /** What is behind the sheet. Unset leaves the canvas alone. */\n backdrop: backdropSchema.optional(),\n /**\n * Degrees the whole composition is turned about its vertical axis, so a\n * preset can choose the angle it is READ from.\n *\n * Every camera in the library is fixed and head-on — `<Paper>` sits at\n * `(0, 0.35, 2.4)` looking down -Z, and neither it nor the editor fits a\n * camera to its content. That is the right default for a sheet, which is\n * flat and faces you. It is the wrong one for anything whose shape lives\n * in DEPTH: the `strip` sim folds in z by construction, so head-on its\n * roll and the whole accordion of its pile are edge-on and the preset\n * renders as a blank white column.\n *\n * A camera field would have been the other way to fix it, and is worse: it\n * is meaningless inside `<PaperField>` and `<PaperMesh>`, where the caller\n * owns the camera and there may be a dozen papers sharing it. Turning the\n * paper works everywhere, because it is a property of the paper.\n *\n * Additive with the `rotation` prop rather than overriding it — the prop\n * is the caller's, and a preset does not get to overrule it.\n */\n turn: z.number().min(-180).max(180).default(0),\n /**\n * Overrides on the named preset — the same authorable half stage mode has\n * always had, and which a lone sheet had no way to reach.\n *\n * A preset was the starting point everywhere EXCEPT here: a stage could be\n * \"nave, but the sun is lower\", and a `<Paper>` could only be one of seven\n * rigs exactly as shipped. `<PaperLighting>` has taken these overrides all\n * along; nothing was passing them.\n */\n light: lightSchema.default({}),\n})\n\nexport type SceneConfig = z.infer<typeof sceneSchema>\nexport type SceneConfigInput = z.input<typeof sceneSchema>\nexport type LightingName = (typeof lightingNames)[number]\nexport type FilmName = (typeof filmNames)[number]\n\n// ── Interaction states ───────────────────────────────────────────────────────\n\n/**\n * A state is a set of parameter overrides on the base preset — never a\n * separate preset. The base stays the single source of truth; states are\n * diffs. Triggers are fixed and built-in for v1 (pointer + pick/drop flow);\n * `custom:*` names are the escape hatch for editor v2.\n */\nexport const coreStateNames = ['rest', 'hover', 'pressed', 'picked', 'placed'] as const\nexport type CoreStateName = (typeof coreStateNames)[number]\nexport type StateName = CoreStateName | `custom:${string}`\n\nconst isStateName = (s: string): boolean =>\n (coreStateNames as readonly string[]).includes(s) || s.startsWith('custom:')\n\n// Typed as plain string (not the template-literal union) so PaperConfig stays\n// assignable to PaperConfigInput; the refine still enforces valid names.\nconst stateNameSchema = z.string().refine(isStateName, {\n message: `state names are ${coreStateNames.join(', ')} or \"custom:<name>\"`,\n})\n\nexport const stateTransitionSchema = z.object({\n duration: z.number().min(0).max(5).default(0.35),\n /** GSAP ease name. */\n ease: z.string().default('power2.out'),\n})\n\nexport const stateDefSchema = z.object({\n /** Deep-partial override of the paper schema (behavior params, surface, …). */\n overrides: z.record(z.string(), z.unknown()).default({}),\n /** Transition INTO this state. */\n transition: stateTransitionSchema.prefault({}),\n /** Chained actions after arriving. v1: 'emit:<event>' only. */\n onEnter: z.array(z.string().regex(/^emit:[\\w-]+$/, 'v1 actions are \"emit:<event>\"')).default([]),\n})\n\nexport const paperStatesSchema = z.object({\n initial: stateNameSchema.default('rest'),\n states: z\n .record(z.string(), stateDefSchema)\n .default({})\n .refine((rec) => Object.keys(rec).every(isStateName), {\n message: `state names are ${coreStateNames.join(', ')} or \"custom:<name>\"`,\n }),\n /** World-units drag distance that flips pressed → picked (pick-enabled behaviors only). */\n pickThreshold: z.number().min(0.005).max(1).default(0.1),\n})\n\nexport type StateTransitionConfig = z.infer<typeof stateTransitionSchema>\nexport type StateDef = z.infer<typeof stateDefSchema>\nexport type PaperStates = z.infer<typeof paperStatesSchema>\nexport type PaperStatesInput = z.input<typeof paperStatesSchema>\n\n// ── Paper config ─────────────────────────────────────────────────────────────\n\nexport const metaSchema = z.object({\n name: z.string().default('untitled'),\n author: z.string().optional(),\n version: z.string().default('0'),\n tags: z.array(z.string()).default([]),\n})\n\nexport const paperConfigSchema = z\n .object({\n meta: metaSchema.prefault({}),\n sheet: sheetSchema.prefault({}),\n stock: stockSchema.default('printer'),\n content: contentSchema.default({ type: 'blank' }),\n /** A behavior OR a raw deformer stack — if both are present, `deformers` wins (it's the fork). */\n behavior: behaviorConfigSchema.optional(),\n deformers: z.array(deformerInstanceSchema).optional(),\n surface: surfaceSchema.default({}),\n /**\n * What the sheet remembers being folded — creases outlive the fold.\n *\n * Present by default, and on: paper that forgets is the bug this exists\n * to fix, so remembering is not something a preset should have to ask\n * for. `memory: { set: 0 }` is the opt-out, and it is what every sheet in\n * the library did before this shipped.\n */\n memory: memorySchema.prefault({}),\n physics: physicsSchema.default('none'),\n scene: sceneSchema.prefault({}),\n onTwos: z.boolean().default(false),\n /** Interaction state machine — overrides-on-base diffs. */\n states: paperStatesSchema.optional(),\n })\n .superRefine((config, ctx) => {\n // Cloth HOSTS a shape: the sim writes the vertices, and the deformer\n // stack runs over what it wrote. A deformer is a pure map from a point to\n // a point, so it does not care whether the point it was handed came from\n // a flat rest pose or from a sheet that has spent a second falling — and\n // \"fold the paper you are holding\" is the whole reason to want it.\n //\n // A strip does not, and the difference is not squeamishness. Cloth\n // simulates the sheet's OWN grid, so a deformer's uv means on the sim\n // what it means everywhere else. A strip is a 2×N ribbon whose rows are\n // chain nodes: its uv runs along a length of paper that is partly wound\n // on a roll, and a fold placed by uv would land somewhere the sheet is\n // not.\n if (\n typeof config.physics === 'object' &&\n config.physics.type === 'strip' &&\n (config.behavior || config.deformers)\n ) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: ['physics'],\n message:\n \"the strip simulation and behavior/deformers are exclusive — the roll owns the vertices, and its rows are chain nodes rather than the sheet's own grid (pick Shape OR Strip)\",\n })\n }\n // State overrides must stay serializable schema paths: merging them over\n // the base must still parse. (`paperConfigSchema` is initialized by the\n // time any parse runs; the merged candidate carries no `states`, so this\n // cannot recurse.)\n if (config.states) {\n const { states: _states, ...baseSansStates } = config\n for (const [name, def] of Object.entries(config.states.states)) {\n if (!def) continue\n if ((def.overrides as Record<string, unknown>).states !== undefined) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: ['states', 'states', name, 'overrides'],\n message: 'state overrides cannot override `states` (no nested state machines)',\n })\n continue\n }\n const candidate = mergeConfig(baseSansStates as Record<string, unknown>, def.overrides)\n const result = paperConfigSchema.safeParse(candidate)\n if (!result.success) {\n const first = result.error.issues[0]\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: ['states', 'states', name, 'overrides'],\n message: `state \"${name}\" overrides don't validate against the paper schema: ${\n first ? `${first.path.join('.')} — ${first.message}` : 'invalid'\n }`,\n })\n }\n }\n }\n })\n\nexport type PaperConfig = z.infer<typeof paperConfigSchema>\nexport type PaperConfigInput = z.input<typeof paperConfigSchema>\n","/**\n * Deep-merge preset config with prop overrides (overrides win; arrays and\n * discriminated unions replace wholesale, plain objects merge).\n *\n * Lives in its own module (not serialize.ts) because the schema needs it to\n * validate state overrides — schema → serialize would be circular.\n */\nexport function mergeConfig<T>(base: T, override: unknown): T {\n if (override === undefined) return base\n if (\n base !== null &&\n override !== null &&\n typeof base === 'object' &&\n typeof override === 'object' &&\n !Array.isArray(base) &&\n !Array.isArray(override)\n ) {\n // A content/behavior union with a different `type` replaces wholesale —\n // merging { type: 'text' } over { type: 'image', src } would leak `src`.\n const b = base as Record<string, unknown>\n const o = override as Record<string, unknown>\n if ('type' in b && 'type' in o && b.type !== o.type) return override as T\n const out: Record<string, unknown> = { ...b }\n for (const key of Object.keys(o)) {\n out[key] = mergeConfig(b[key], o[key])\n }\n return out as T\n }\n return override as T\n}\n\n/**\n * Like {@link mergeConfig}, but an explicit `undefined` DELETES its key instead\n * of being ignored — the semantics a BASE-config write needs: structural\n * setters can clear `behavior`/`deformers` or toggle a surface effect off.\n * Discriminated unions (differing `type`) still replace wholesale.\n */\nexport function mergeWithDeletes<T>(base: T, patch: unknown): T {\n if (\n base !== null &&\n patch !== null &&\n typeof base === 'object' &&\n typeof patch === 'object' &&\n !Array.isArray(base) &&\n !Array.isArray(patch)\n ) {\n const b = base as Record<string, unknown>\n const p = patch as Record<string, unknown>\n if ('type' in b && 'type' in p && b.type !== p.type) return patch as T\n const out: Record<string, unknown> = { ...b }\n for (const [key, value] of Object.entries(p)) {\n if (value === undefined) delete out[key]\n else out[key] = mergeWithDeletes(b[key], value)\n }\n return out as T\n }\n return patch as T\n}\n","import { z } from 'zod'\nimport type { Behavior } from './types'\nimport { cornerNames } from '../deformers/curl'\n\nexport const peelOptionsSchema = z.object({\n progress: z.number().min(0).max(1).default(0.35),\n /** 'auto' resolves per slot in a `sheet` field (outward-facing corner); standalone it means bottom-right. */\n corner: z.enum([...cornerNames, 'auto']).default('bottom-right'),\n /** Curl sharpness — small is a tight dog-ear, large a soft lift. */\n radius: z.number().min(0.05).max(0.6).default(0.16),\n})\n\nexport type PeelOptions = z.infer<typeof peelOptionsSchema>\n\nconst CORNER_UV: Record<(typeof cornerNames)[number], [number, number]> = {\n 'top-left': [0, 1],\n 'top-right': [1, 1],\n 'bottom-left': [0, 0],\n 'bottom-right': [1, 0],\n}\n\n/** Fields resolve 'auto' per slot; anywhere else it falls back to the default corner. */\nconst concreteCorner = (c: PeelOptions['corner']) => (c === 'auto' ? 'bottom-right' : c)\n\n/** A corner lifts and curls back — the hero-image hover peel. */\nexport const peel: Behavior<PeelOptions> = {\n id: 'peel',\n label: 'Peel',\n defaults: peelOptionsSchema.parse({}),\n optionsSchema: peelOptionsSchema,\n signature: ['progress', 'corner'],\n progressParam: 'progress',\n duration: 2.2,\n loopMode: 'yoyo',\n stack(o) {\n // A deep peel lifts on a softer cylinder — a fixed tight radius would\n // wind the sheet into a dart. Growing the radius with progress keeps the\n // curl reading as a page lift at every depth.\n return [\n {\n type: 'curl',\n options: {\n corner: concreteCorner(o.corner),\n amount: o.progress,\n radius: o.radius + o.progress * 0.3,\n skew: 0,\n },\n },\n ]\n },\n handles: [\n {\n id: 'corner',\n anchor: (o) => CORNER_UV[concreteCorner(o.corner)],\n drag(local, o, sheet) {\n // Pull toward the sheet center = more peel: distance from the flat\n // corner along the inward diagonal, normalized to half the diagonal.\n const [ux, uy] = CORNER_UV[concreteCorner(o.corner)]\n const cx = (ux - 0.5) * sheet.width\n const cy = (uy - 0.5) * sheet.height\n const diag = Math.hypot(sheet.width, sheet.height)\n const inX = -cx / Math.hypot(cx, cy)\n const inY = -cy / Math.hypot(cx, cy)\n const dist = (local.x - cx) * inX + (local.y - cy) * inY\n return { progress: Math.min(1, Math.max(0, dist / (diag * 0.5))) }\n },\n },\n ],\n}\n","import { z } from 'zod'\nimport type { Deformer } from './types'\nimport { segmentsForArc } from '../core/tessellation'\n\nexport const cornerNames = ['top-left', 'top-right', 'bottom-left', 'bottom-right'] as const\n\nexport const curlOptionsSchema = z.object({\n corner: z.enum(cornerNames).default('bottom-right'),\n /** How far the curl has traveled from the corner, as a fraction of the diagonal. */\n amount: z.number().min(0).max(1).default(0.35),\n /** Cylinder radius — curl sharpness. */\n radius: z.number().min(0.02).max(1).default(0.16),\n /** Skew of the fold line away from the corner diagonal, degrees. */\n skew: z.number().min(-40).max(40).default(0),\n})\n\nexport type CurlOptions = z.infer<typeof curlOptionsSchema>\n\nconst DEG = Math.PI / 180\n\nconst CORNER_SIGNS: Record<(typeof cornerNames)[number], [number, number]> = {\n 'top-left': [-1, 1],\n 'top-right': [1, 1],\n 'bottom-left': [-1, -1],\n 'bottom-right': [1, -1],\n}\n\n/**\n * Corner-anchored cylinder wrap — the peel/dog-ear deformer, and the\n * crown-jewel realism case: the mesh genuinely wraps the cylinder so content\n * bends with perfect continuity and the backside becomes visible.\n *\n * The fold line runs perpendicular to the corner diagonal and travels inward\n * with `amount`; everything cornerward of it wraps around the cylinder.\n */\nexport const curl: Deformer<CurlOptions> = {\n id: 'curl',\n label: 'Curl',\n defaults: curlOptionsSchema.parse({}),\n optionsSchema: curlOptionsSchema,\n geometry: {\n minSegments: 48,\n // Curl rolls the corner region around `radius`, travelling inward along\n // the diagonal as `amount` rises. The diagonal is the span the arc can\n // reach across, and `radius` is its curvature throughout.\n autoSegments: (o, sheet) => segmentsForArc(Math.hypot(sheet.width, sheet.height), o.radius),\n // The corner diagonal, plus whatever `skew` turns it by — the same\n // direction `displace` builds below, and the one the wrap runs along.\n axis: (o, sheet) => {\n const [sx, sy] = CORNER_SIGNS[o.corner]\n return Math.atan2(sy * sheet.height, sx * sheet.width) / DEG + o.skew\n },\n },\n displace(out, _uv, o, ctx) {\n const [sx, sy] = CORNER_SIGNS[o.corner]\n const { width, height } = ctx.sheet\n const cx = (sx * width) / 2\n const cy = (sy * height) / 2\n\n // Outward direction: from sheet center toward the corner, plus skew.\n const diag = Math.hypot(width, height)\n const baseX = (sx * width) / diag\n const baseY = (sy * height) / diag\n const skew = o.skew * DEG\n const cosK = Math.cos(skew)\n const sinK = Math.sin(skew)\n const dirX = baseX * cosK - baseY * sinK\n const dirY = baseX * sinK + baseY * cosK\n\n // Signed distance past the fold line (fold travels inward with amount).\n const travel = o.amount * diag * 0.5\n const e = (out.x - cx) * dirX + (out.y - cy) * dirY\n const s = e + travel\n if (s <= 0) return\n\n const theta = s / o.radius\n const sin = Math.sin(theta)\n const cos = Math.cos(theta)\n const boundary = e - s // = -travel\n const newE = boundary + (o.radius - out.z) * sin\n const newZ = o.radius * (1 - cos) + out.z * cos\n\n out.x += dirX * (newE - e)\n out.y += dirY * (newE - e)\n out.z = newZ\n },\n glsl: {\n chunk: /* glsl */ `\nvoid FN(inout vec3 p, vec2 uv, float t) {\n vec2 c = U_cornerSign * uSheet * 0.5;\n float diag = length(uSheet);\n vec2 base = U_cornerSign * uSheet / diag;\n float cosK = cos(U_skew);\n float sinK = sin(U_skew);\n vec2 dir = vec2(base.x * cosK - base.y * sinK, base.x * sinK + base.y * cosK);\n float travel = U_amount * diag * 0.5;\n float e = dot(p.xy - c, dir);\n float s = e + travel;\n if (s <= 0.0) return;\n float theta = s / U_radius;\n float sn = sin(theta);\n float cs = cos(theta);\n float newE = (e - s) + (U_radius - p.z) * sn;\n float newZ = U_radius * (1.0 - cs) + p.z * cs;\n p.xy += dir * (newE - e);\n p.z = newZ;\n}\n`,\n strength: 'amount',\n uniforms: (o) => {\n const [sx, sy] = CORNER_SIGNS[o.corner]\n return {\n cornerSign: [sx, sy],\n amount: o.amount,\n radius: o.radius,\n skew: o.skew * DEG,\n }\n },\n },\n}\n","/**\n * How finely a sheet has to be subdivided for a deformer to look like the\n * surface it is approximating instead of like the polygons it is made of.\n *\n * A deformed mesh is a piecewise-linear stand-in for a curved surface, and the\n * error is the **sagitta**: the gap between a chord and the arc it cuts\n * across. For a chord of length `h` on a circle of radius `r` that gap is\n * `h²/8r` to well under a percent for any chord worth drawing. Invert it and\n * the whole question — \"how many segments does this need?\" — has a closed\n * form: pick the error you are willing to see, and the segment count falls\n * out of the radius.\n *\n * That is the difference between this and `minSegments`. `minSegments` is a\n * correctness FLOOR — the density below which a deformer stops working at\n * all. This is a QUALITY TARGET, and unlike a floor it has to depend on the\n * options: a bend at `curvature: 0.05` and a roll at `radius: 0.02` are not\n * remotely the same request, and one constant per deformer cannot answer for\n * both.\n */\n\nimport type { SheetDims } from '../deformers/types'\n\n/**\n * The error we are willing to see, in world units (a letter sheet is 1 × 1.4,\n * so 1 unit ≈ 216 mm and this is ≈ 0.09 mm).\n *\n * Calibrated, not picked: at `segments: 'auto'`'s old flat 72, the default\n * `roll` (radius 0.12 across a 1.4 span) already ran at a sagitta of 3.9e-4.\n * Setting the tolerance there means the tightest configuration in common use\n * keeps exactly the density it ships with today, and everything gentler —\n * which was paying for that same grid and getting fourteen times the\n * precision it needed — stops paying. The number is a statement about the\n * status quo, so changing it re-lights every preset in the library.\n */\nexport const SAG_TOL = 4e-4\n\n/**\n * Ceiling for `'auto'` in hero mode, and it is a CPU budget rather than a\n * round number.\n *\n * Hero mode re-deforms every vertex in JS on the main thread, every frame,\n * for any animated stack — and `wave` is animated, so a hanging poster pays\n * it forever rather than only while something plays. Measured, one sheet,\n * one re-deform (`drape + wave`, and `crumple` tracks it within 5%), before\n * and after the loop was rewritten around a single-function inner call site\n * and `computeSheetNormals`:\n *\n * | grid | verts | was | now |\n * | ----: | -----: | ---: | ---: |\n * | 72 | 3,796 | 0.74 | 0.27 |\n * | 128 | 11,868 | 2.30 | 0.84 |\n * | 192 | 26,634 | 5.01 | 1.89 |\n * | 256 | 47,288 | 8.74 | 3.38 |\n *\n * **192, raised from 128, and the price is why.** 128 was picked when it cost\n * 2.30 ms — the last step that still left room for a scene around it. 192 now\n * costs 1.89 ms, which is less than 128 ever did, so the old line was drawn\n * against a price that no longer exists.\n *\n * The reason it is nearly free in practice is the axis split: a demand lands\n * on the direction that bends and the other axis stays at `FLAT_SEGMENTS`. A\n * `drape` at its own defaults wants 154 across and two segments down, so the\n * raise costs it 0.02 ms rather than the 1.89 ms a square 192 grid implies.\n * The square case is reachable — a stack that bends both ways, `wave` over\n * `drape` — and it is opt-in through options rather than something a preset\n * hands anybody.\n *\n * What it buys, all of it previously capped: `drape` at its defaults (154),\n * `roll` and `fold` at `radius: 0.02` (175), `curl` at `radius: 0.02` (142).\n * No preset that ships reaches even 128 after the axis split, so this changes\n * nothing already in the library — it stops punishing people who ask for a\n * tighter crease than any preset uses.\n *\n * Still NOT high enough for everything the arithmetic asks: `wave` at\n * `amplitude: 0.3` wants 272 and a 16-fold `drape` at full depth wants 1377.\n * Those stay capped, and the gap is real rather than hidden. Set `segments`\n * to a number (up to the schema's 256) to go past it.\n *\n * A field is capped far lower and separately, because a field draws this\n * geometry N times — see `FIELD_AUTO_CEILING`.\n */\nexport const AUTO_CEILING = 192\n\n/**\n * What a sheet gets when nothing deforms it. A flat plane is exact at one\n * segment; this is the small margin that keeps anything interpolated across\n * the quad (lighting terms, translucency) from reading the corners only.\n */\nexport const FLAT_SEGMENTS = 8\n\n/**\n * What `'auto'` handed out flat, on every sheet, before it learned to adapt.\n *\n * Still load-bearing in two places: it is what `resolveSegments` assumes when\n * a caller has no deformer stack to ask (so the exported helper answers today\n * exactly what it answered before), and it is what a field is allowed to ask\n * for, since a field draws its buffer once per instance.\n */\nexport const LEGACY_FLAT_SEGMENTS = 72\n\n/**\n * Resolved counts are snapped to this ladder. Without it the grid would be a\n * continuous function of the options, so dragging a curvature slider would\n * rebuild the geometry — a new `PlaneGeometry`, a fresh base-position copy,\n * and a disposed buffer — on every tick. Snapped, a drag crosses a step\n * rarely and holds one buffer the rest of the time.\n */\nconst LADDER = [FLAT_SEGMENTS, 12, 16, 24, 32, 48, 64, LEGACY_FLAT_SEGMENTS, 96, 128, AUTO_CEILING] as const\n\n/** Smallest ladder step at or above `n`, clamped to the ceiling. */\nexport function quantizeSegments(n: number): number {\n for (const step of LADDER) if (n <= step) return step\n return AUTO_CEILING\n}\n\n/**\n * A resolved grid: segments along the sheet's own X and Y.\n *\n * Two numbers rather than one because a sheet is not subdivided by a single\n * density. A banner 1.5 wide and 8.5 tall, draped in folds that run across\n * its width, needs the folds resolved ACROSS and needs almost nothing down\n * the drop — and a single number, however it is distributed, answers one of\n * those questions by getting the other one wrong.\n */\nexport type SegmentPair = [x: number, y: number]\n\n/**\n * Split a deformer's segment demand onto the sheet's two axes.\n *\n * A deformer curves along ONE direction — `roll`, `bend`, `fold` and `wave`\n * all name it `angle`, `drape`'s folds run across the width, `curl` works\n * down a corner diagonal — and `segmentsForArc` answers in segments along\n * THAT direction. Turning that into a grid is a projection: the demand is\n * really a density (segments per world unit along the curve), and each axis\n * needs enough of it that a grid edge's component along the curve stays\n * inside the chord the sagitta bound allows.\n *\n * Hence `width·|cos θ|·density` and `height·|sin θ|·density`. A bend across\n * x asks everything of x and nothing of y, which is exactly right: the sheet\n * does not move along y, so subdividing it there buys a bigger buffer and an\n * identical picture.\n *\n * `null` is for a deformer with no single direction — `crumple`'s creases\n * run every way at once. That case keeps the old behaviour of spreading the\n * demand by aspect ratio, which is the honest answer when the demand really\n * is isotropic.\n */\nexport function axialSegments(sheet: SheetDims, angleDeg: number | null, n: number): SegmentPair {\n if (!(n > 0)) return [0, 0]\n if (angleDeg === null) {\n const long = Math.max(sheet.width, sheet.height)\n if (!(long > 0)) return [n, n]\n return [(sheet.width / long) * n, (sheet.height / long) * n]\n }\n const span = spanAlong(sheet, angleDeg)\n if (!(span > 0)) return [n, n]\n const rad = (angleDeg * Math.PI) / 180\n const density = n / span\n return [sheet.width * Math.abs(Math.cos(rad)) * density, sheet.height * Math.abs(Math.sin(rad)) * density]\n}\n\n/**\n * Extent of the sheet along a direction in its own plane, degrees. For a\n * rectangle centered on the origin this is exactly `|w·cos| + |h·sin|` — the\n * projection of both half-extents onto the axis, doubled.\n */\nexport function spanAlong(sheet: SheetDims, angleDeg: number): number {\n const rad = (angleDeg * Math.PI) / 180\n return Math.abs(sheet.width * Math.cos(rad)) + Math.abs(sheet.height * Math.sin(rad))\n}\n\n/**\n * Segments needed to hold a circular arc of radius `r` across `span` within\n * `tol`. Straight inversion of `sag = h²/8r`.\n *\n * A flat or near-flat arc (huge radius) needs nothing, hence the 0 — callers\n * take the max against the floor, so 0 means \"this deformer is not the reason\n * for any subdivision\", which is exactly true of a bend at curvature 0.\n */\nexport function segmentsForArc(span: number, radius: number, tol = SAG_TOL): number {\n if (!(span > 0) || !(radius > 0) || !Number.isFinite(radius)) return 0\n return span / Math.sqrt(8 * radius * tol)\n}\n\n/**\n * Same question for a sinusoid, which is the shape `wave` and `drape` both\n * make. Peak curvature of `A·sin(2πx/λ)` is `A(2π/λ)²` at the crest, so the\n * tightest radius on the curve is its reciprocal and the arc form takes over\n * from there.\n */\nexport function segmentsForSine(span: number, amplitude: number, wavelength: number, tol = SAG_TOL): number {\n if (!(amplitude > 0) || !(wavelength > 0)) return 0\n const k = (2 * Math.PI) / wavelength\n const peakCurvature = amplitude * k * k\n if (!(peakCurvature > 0)) return 0\n return segmentsForArc(span, 1 / peakCurvature, tol)\n}\n","import { z } from 'zod'\nimport type { Behavior } from './types'\nimport type { DeformerInstance, SheetDims } from '../deformers/types'\nimport { rollRadius } from '../deformers/roll'\n\nexport const unrollOptionsSchema = z.object({\n /** 0 = fully rolled cylinder, 1 = flat sheet. */\n progress: z.number().min(0).max(1).default(0.5),\n /** How tightly the paper is wound — thin layers and many turns, or few and fat. */\n tightness: z.number().min(0).max(1).default(0.5),\n /** Idle rocking of the rolled end. */\n sway: z.number().min(0).max(1).default(0.25),\n /** Which end of the sheet holds the roll. `top` hangs the paper below it. */\n from: z.enum(['bottom', 'top']).default('bottom'),\n /** Radius of the tube the paper is wound onto — the roll never shrinks past it. */\n core: z.number().min(0.005).max(0.5).default(0.03),\n /**\n * Paper already hanging at `progress` 0, in world units.\n *\n * A roll on a holder is never a bare cylinder: there is always a leaf out,\n * because that is what you take hold of. Starting from nothing showing\n * reads as a fresh roll still in its wrapper.\n */\n tail: z.number().min(0).max(20).default(0),\n /**\n * How far below the roll the paper lands, in world units. Omit and it\n * hangs forever.\n *\n * Paper that reaches the ground does not stop and does not carry on\n * through it: it creases and runs out flat. Everything past this distance\n * turns a right angle and lies down.\n */\n floor: z.number().min(0.1).max(50).optional(),\n /**\n * Hold the roll still in space and let the paper hang off it, instead of\n * letting the roll ride along with the shrinking wound region.\n */\n fixed: z.boolean().default(false),\n})\n\nexport type UnrollOptions = z.infer<typeof unrollOptionsSchema>\n\n/** Layer gap at `tightness` 0 and 1. Visible thickness, not a real receipt's 60µm. */\nconst LOOSE = 0.1\nconst TIGHT = 0.02\n\nfunction layerThickness(tightness: number): number {\n return LOOSE - tightness * (LOOSE - TIGHT)\n}\n\n/**\n * The span `progress` sweeps the roll boundary across: from the far edge\n * (everything wound) past the near edge (flat, plus slack so the last of the\n * paper fully relaxes).\n */\nfunction sweep(o: UnrollOptions, sheet: SheetDims): { start: number; end: number } {\n const maxRadius = rollRadius(sheet.height, o.core, layerThickness(o.tightness))\n // `tail` starts the boundary short of the far edge, so that much paper is\n // already flat at progress 0. Capped so it cannot start past the end.\n const tail = Math.min(o.tail, sheet.height)\n return { start: -sheet.height / 2 + tail, end: sheet.height / 2 + maxRadius * 2 }\n}\n\n/** Where the wound region begins, as a signed distance along the roll direction. */\nfunction rollBoundary(o: UnrollOptions, sheet: SheetDims): number {\n const { start, end } = sweep(o, sheet)\n return start + o.progress * (end - start)\n}\n\n/** Softness of the crease where the paper meets the ground, scaled to the sheet. */\nconst LANDING_RADIUS = 0.035\n\n/**\n * The crease where the drop meets the ground: a right-angle hinge at the\n * floor line, so the paper above stays vertical and everything below turns\n * over and runs out flat.\n *\n * `fold`, not a second `roll`, and not a steeper angle — both were tried in\n * `ribbon`, which lands a strip the same way, and the notes there are worth\n * reading before touching this. A roll wraps the landed length up and over\n * and ends in the air (a hook, not a pool); anything but exactly 90° either\n * drives the paper on through the floor or floats it back up.\n */\nfunction landing(\n o: UnrollOptions,\n sheet: SheetDims,\n boundary: number,\n rollRadiusNow: number,\n): DeformerInstance {\n const radius = Math.min(0.5, Math.max(0.02, sheet.height * LANDING_RADIUS))\n // The hinge wraps a small cylinder rather than turning on the spot, so the\n // flap leaves it lower than the crease line by exactly that much. Raise the\n // crease by it so the LANDED length sits on the floor, not under it.\n const hingeDrop = radius / (Math.PI / 2)\n\n // The floor in the sheet's own coordinates. The roll is pinned in space and\n // the paper travels past it, so a fixed floor is a MOVING line down here —\n // it sits `floor` below wherever the roll boundary currently is.\n //\n // Clamped clear of the roll itself: a floor closer than the roll's own\n // radius would put the bottom of the roll below the crease line, and the\n // hinge would fold the roll over instead of the paper hanging off it.\n const below = Math.max(o.floor!, rollRadiusNow + radius)\n const floorLine = o.from === 'top' ? boundary - below : -boundary + below\n\n return {\n type: 'fold',\n // Travel points from the roll toward the floor, so \"past the crease\"\n // means \"the length that has arrived\", not the drop above it.\n options:\n o.from === 'top'\n ? { angle: -90, offset: -floorLine - hingeDrop, foldAngle: 90, radius }\n : { angle: 90, offset: floorLine - hingeDrop, foldAngle: 90, radius },\n }\n}\n\n/**\n * Paper coming off a roll: the sheet hangs flat and whatever is left is wound\n * at one end. Content bends true around the roll.\n *\n * The roll SHRINKS as the paper comes off it, because its radius is derived\n * from how much paper is still wound rather than being a constant. That is\n * both the honest physics and the whole appeal of a long sheet: scroll it out\n * and the roll visibly runs down to its tube.\n */\nexport const unroll: Behavior<UnrollOptions> = {\n id: 'unroll',\n label: 'Unroll',\n defaults: unrollOptionsSchema.parse({}),\n optionsSchema: unrollOptionsSchema,\n signature: ['progress', 'tightness'],\n progressParam: 'progress',\n duration: 3,\n loopMode: 'yoyo',\n stack(o, sheet) {\n const thickness = layerThickness(o.tightness)\n const boundary = rollBoundary(o, sheet)\n // Paper still on the roll: the span from the boundary to the far edge.\n const wound = Math.max(0, sheet.height / 2 - boundary)\n const radius = rollRadius(wound, o.core, thickness)\n const stack: DeformerInstance[] = [\n {\n type: 'roll',\n options: {\n // Both directions sweep the same boundary; only which half of the\n // sheet counts as \"past\" it changes. 270 winds the bottom (a\n // receipt feeding downward), 90 winds the top (paper hanging below).\n angle: o.from === 'top' ? 90 : 270,\n boundary,\n radius,\n thickness,\n },\n },\n ]\n if (o.floor !== undefined) stack.push(landing(o, sheet, boundary, radius))\n return stack\n },\n loop(o, t) {\n if (o.sway === 0) return {}\n // The rolled tail rocks gently; transient — never persisted.\n const wobble = Math.sin(t * 1.5) * 0.01 * o.sway\n return { progress: Math.min(1, Math.max(0, o.progress + wobble)) }\n },\n transform(o, _t, pose, sheet) {\n if (!o.fixed) return\n // The wound region shrinks toward the far edge, carrying the roll with\n // it. A roll on a holder does not move — the paper does — so cancel that\n // travel and let the flat tail grow away instead, which is the thing you\n // actually watch.\n //\n // Anchored on the UNROLLED end, so a fully paid-out sheet sits exactly\n // where an undeformed one would and the roll hangs off the edge of that\n // box. Anchoring on the rolled end instead is the same motion, but it\n // parks the whole composition a sheet-length away from the origin, which\n // makes every preset using it need a bespoke camera.\n const travel = sweep(o, sheet).end - rollBoundary(o, sheet)\n pose.position[1] += o.from === 'top' ? travel : -travel\n },\n handles: [\n {\n id: 'roll-edge',\n // The grab point is the edge the paper leaves the roll on, so it tracks\n // the boundary — which runs top-to-bottom for a roll at the bottom and\n // bottom-to-top for one at the top.\n anchor: (o) => {\n const v = o.from === 'top' ? o.progress : 1 - o.progress\n return [0.5, Math.max(0.02, Math.min(0.98, v))]\n },\n drag(local, o, sheet) {\n // Dragging away from the roll unrolls the paper, whichever end it is on.\n const along = local.y / sheet.height\n const p = o.from === 'top' ? 0.5 + along : 0.5 - along\n return { progress: Math.min(1, Math.max(0, p)) }\n },\n },\n ],\n}\n","import { z } from 'zod'\nimport type { Deformer } from './types'\nimport { segmentsForArc, spanAlong } from '../core/tessellation'\n\nexport const rollOptionsSchema = z.object({\n /** Direction of rolling in the sheet plane, degrees. 0 = +x, 90 = +y. */\n angle: z.number().min(-360).max(360).default(90),\n /** Signed distance (along the roll direction, from sheet center) where the roll begins. */\n boundary: z.number().min(-20).max(20).default(0),\n /** Radius of the OUTERMOST wrap — the one the flat sheet leaves the roll on. */\n radius: z.number().min(0.01).max(2).default(0.12),\n /** Gap between consecutive wraps, in world units. 0 = a bare cylinder. */\n thickness: z.number().min(0).max(0.2).default(0.015),\n})\n\nexport type RollOptions = z.infer<typeof rollOptionsSchema>\n\nconst DEG = Math.PI / 180\nconst TAU = Math.PI * 2\n\n/**\n * How far in the spiral is allowed to wind, as a fraction of its outer\n * radius. Paper past that point keeps coiling at a constant radius instead.\n *\n * A spiral that runs all the way to zero collapses every remaining vertex\n * onto one point: degenerate triangles, no normals, an unlit hole in the\n * sheet. Sizing a roll with {@link rollRadius} never reaches here, but\n * `roll` is public and its options are independent numbers, so \"more paper\n * than fits\" has to land somewhere survivable rather than somewhere invalid.\n */\nconst MIN_RADIUS_FRACTION = 0.08\n\n/**\n * Angle swept after winding arc length `s` onto a spiral that starts at\n * radius `r0` and loses `k` of it per radian.\n *\n * Arc length along that spiral is `s = r0·θ − k·θ²/2`, so θ is the smaller\n * root of the quadratic. Written rationalized (`2s / (r0 + √disc)`) rather\n * than as `(r0 − √disc) / k`: the two are equal in exact arithmetic, but the\n * subtractive form cancels catastrophically as k → 0 — precisely the common\n * case, a plain cylinder — and divides by k on top of that.\n *\n * Past the point where the radius would fall below its floor, the spiral\n * continues as a circle at that radius, which keeps the map C¹ and the\n * geometry non-degenerate.\n */\nexport function windAngle(s: number, r0: number, k: number): number {\n if (k <= 0) return s / r0\n const rMin = r0 * MIN_RADIUS_FRACTION\n const thetaFloor = (r0 - rMin) / k\n const sFloor = r0 * thetaFloor - (k * thetaFloor * thetaFloor) / 2\n if (s >= sFloor) return thetaFloor + (s - sFloor) / rMin\n return (2 * s) / (r0 + Math.sqrt(r0 * r0 - 2 * k * s))\n}\n\n/** Radius reached after sweeping `theta`, floored so the coil never collapses. */\nexport function windRadius(theta: number, r0: number, k: number): number {\n return Math.max(r0 - k * theta, r0 * MIN_RADIUS_FRACTION)\n}\n\n/**\n * Outer radius of a roll holding `length` of paper wound onto a core of\n * radius `core` at the given layer `thickness`.\n *\n * The Archimedean identity `L = π(R² − core²) / thickness`, solved for R.\n * It is the exact inverse of what {@link roll} does, which is the property\n * that matters: size a roll with this and its innermost wrap lands precisely\n * on `core` — the paper runs out exactly when the spiral reaches the tube,\n * rather than overshooting into a negative radius or stopping short.\n */\nexport function rollRadius(length: number, core: number, thickness: number): number {\n return Math.sqrt(core * core + (Math.max(0, length) * thickness) / Math.PI)\n}\n\n/**\n * Wrap the sheet around a roll lying across the roll direction. Everything\n * past `boundary` winds; the wrap is C¹-continuous at the boundary and\n * preserves arc length (content never stretches).\n *\n * The paper winds INWARD — the far end of the sheet ends up at the core, and\n * the flat portion leaves from the outermost wrap. That is the only way round\n * that a real roll can be: paper is dispensed off the outside, so the end you\n * are holding must be the outermost layer.\n *\n * The circle's centre is FIXED at `radius` above the boundary and only the\n * radius varies, which is what makes the wraps concentric. Deriving the\n * centre from the current radius instead — the obvious way to write this, and\n * what this deformer did until the geometry was checked — pins every wrap\n * tangent to the plane at the same point, so the wraps form a rosette of\n * circles through one point rather than a spiral, and the sheet passes\n * through itself once per revolution. That bug is invisible at `thickness`\n * 0 (a true cylinder does return to its start) and exactly cancels at every\n * multiple of 2π, so it survived both the golden vectors and the GPU parity\n * gate: they agreed with each other, and both were wrong.\n *\n * Points arriving with z ≠ 0 (from earlier deformers in the stack) ride\n * along the rolled surface's inward normal, so stacks compose sanely.\n */\nexport const roll: Deformer<RollOptions> = {\n id: 'roll',\n label: 'Roll',\n defaults: rollOptionsSchema.parse({}),\n optionsSchema: rollOptionsSchema,\n geometry: {\n minSegments: 48,\n // The INNERMOST wrap is the tightest curvature on the sheet, so it sets\n // the density — the outer one used to, back when the spiral grew outward.\n // Floored at a fraction of the outer radius because segment count scales\n // as 1/√r: a roll wound to a hair's breadth would otherwise ask for a\n // grid nobody can afford, to resolve a few square millimetres at the core.\n autoSegments: (o, sheet) => {\n const span = spanAlong(sheet, o.angle)\n const wound = Math.max(0, span / 2 - o.boundary)\n const k = o.thickness / TAU\n return segmentsForArc(span, windRadius(windAngle(wound, o.radius, k), o.radius, k))\n },\n axis: (o) => o.angle,\n },\n displace(out, _uv, o) {\n const dirX = Math.cos(o.angle * DEG)\n const dirY = Math.sin(o.angle * DEG)\n const d = out.x * dirX + out.y * dirY\n const s = d - o.boundary\n if (s <= 0) return\n\n const k = o.thickness / TAU\n const theta = windAngle(s, o.radius, k)\n // Incoming z rides the inward normal, so it shortens the radius.\n const r = windRadius(theta, o.radius, k) - out.z\n const newD = o.boundary + r * Math.sin(theta)\n const newZ = o.radius - r * Math.cos(theta)\n\n out.x += dirX * (newD - d)\n out.y += dirY * (newD - d)\n out.z = newZ\n },\n glsl: {\n chunk: /* glsl */ `\nvoid FN(inout vec3 p, vec2 uv, float t) {\n vec2 dir = vec2(cos(U_angle), sin(U_angle));\n float d = dot(p.xy, dir);\n float s = d - U_boundary;\n if (s <= 0.0) return;\n float k = U_thickness / 6.2831853071795864;\n float rMin = U_radius * 0.08;\n float thetaFloor = (U_radius - rMin) / max(k, 1e-9);\n float sFloor = U_radius * thetaFloor - 0.5 * k * thetaFloor * thetaFloor;\n float theta = k <= 0.0\n ? s / U_radius\n : (s >= sFloor\n ? thetaFloor + (s - sFloor) / rMin\n : (2.0 * s) / (U_radius + sqrt(U_radius * U_radius - 2.0 * k * s)));\n float r = max(U_radius - k * theta, rMin) - p.z;\n float newD = U_boundary + r * sin(theta);\n float newZ = U_radius - r * cos(theta);\n p.xy += dir * (newD - d);\n p.z = newZ;\n}\n`,\n uniforms: (o) => ({\n angle: o.angle * DEG,\n boundary: o.boundary,\n radius: o.radius,\n thickness: o.thickness,\n }),\n },\n}\n","import { z } from 'zod'\nimport type { Behavior } from './types'\n\nexport const flipOptionsSchema = z.object({\n /** 0 = flat, 1 = page fully turned over the spine. */\n progress: z.number().min(0).max(1).default(0.3),\n /** Which edge is the spine. */\n spine: z.enum(['left', 'right']).default('left'),\n /** Softness of the turning curl. */\n radius: z.number().min(0.1).max(0.8).default(0.3),\n})\n\nexport type FlipOptions = z.infer<typeof flipOptionsSchema>\n\n/**\n * A page turn: the free edge curls up and rolls over toward the spine —\n * the roll deformer with its boundary swept across the page.\n */\nexport const flip: Behavior<FlipOptions> = {\n id: 'flip',\n label: 'Flip',\n defaults: flipOptionsSchema.parse({}),\n optionsSchema: flipOptionsSchema,\n signature: ['progress', 'spine'],\n progressParam: 'progress',\n duration: 1.8,\n loopMode: 'yoyo',\n stack(o, sheet) {\n // Rolling direction points at the free edge; the boundary starts past\n // the free edge (flat) and sweeps to the spine (fully turned).\n const angle = o.spine === 'left' ? 0 : 180\n const start = sheet.width / 2\n const end = -sheet.width / 2\n return [\n {\n type: 'roll',\n options: {\n angle,\n boundary: start + o.progress * (end - start),\n radius: o.radius,\n thickness: 0,\n },\n },\n ]\n },\n handles: [\n {\n id: 'free-edge',\n anchor: (o) => (o.spine === 'left' ? [0.98, 0.5] : [0.02, 0.5]),\n drag(local, o, sheet) {\n // Dragging the free edge toward the spine turns the page.\n const x = o.spine === 'left' ? local.x : -local.x\n return { progress: Math.min(1, Math.max(0, 0.5 - x / sheet.width)) }\n },\n },\n ],\n}\n","import { z } from 'zod'\nimport type { Behavior } from './types'\n\nexport const letterFoldOptionsSchema = z.object({\n /** 0 = flat letter, 1 = fully tri-folded. */\n progress: z.number().min(0).max(1).default(0.4),\n /** Softness of the two creases. */\n crease: z.number().min(0).max(1).default(0.3),\n})\n\nexport type LetterFoldOptions = z.infer<typeof letterFoldOptionsSchema>\n\n/**\n * The classic tri-fold: the bottom third folds up first, then the top third\n * folds down over it. Two fold deformers stacked — order is the physics.\n */\nexport const letterFold: Behavior<LetterFoldOptions> = {\n id: 'letter-fold',\n label: 'Letter fold',\n defaults: letterFoldOptionsSchema.parse({}),\n optionsSchema: letterFoldOptionsSchema,\n signature: ['progress', 'crease'],\n progressParam: 'progress',\n duration: 2.6,\n loopMode: 'yoyo',\n stack(o, sheet) {\n const radius = 0.02 + o.crease * 0.06\n // The bottom flap leads, the top flap follows slightly behind so the\n // motion reads as two deliberate folds, not one collapse.\n const bottom = Math.min(1, o.progress * 1.25)\n const top = Math.max(0, o.progress * 1.25 - 0.25)\n return [\n {\n // Bottom third folds up and over (fold travels downward from -h/6).\n type: 'fold',\n options: {\n angle: 270,\n offset: sheet.height / 6,\n foldAngle: bottom * 165,\n radius,\n },\n },\n {\n // Top third folds down across the (already folded) bottom flap.\n type: 'fold',\n options: {\n angle: 90,\n offset: sheet.height / 6,\n foldAngle: top * 150,\n radius: radius * 1.6,\n },\n },\n ]\n },\n handles: [\n {\n id: 'top-flap',\n anchor: () => [0.5, 1],\n drag(local, _o, sheet) {\n // Pulling the top edge down folds the letter.\n return { progress: Math.min(1, Math.max(0, (sheet.height / 2 - local.y) / sheet.height)) }\n },\n },\n ],\n}\n","import { z } from 'zod'\nimport type { Behavior } from './types'\n\nexport const hangOptionsSchema = z.object({\n /** Wind strength driving the ripple. */\n wind: z.number().min(0).max(1).default(0.4),\n /** Gravity bulge of the hanging sheet. */\n sag: z.number().min(0).max(1).default(0.3),\n})\n\nexport type HangOptions = z.infer<typeof hangOptionsSchema>\n\n/** A poster hanging from its top edge, rippling in wind. */\nexport const hang: Behavior<HangOptions> = {\n id: 'hang',\n label: 'Hang',\n defaults: hangOptionsSchema.parse({}),\n optionsSchema: hangOptionsSchema,\n signature: ['wind', 'sag'],\n progressParam: 'wind',\n duration: 4,\n loopMode: 'yoyo',\n stack(o) {\n return [\n { type: 'bend', options: { curvature: 0.15 + o.sag * 0.55, angle: 90 } },\n {\n type: 'wave',\n options: {\n amplitude: o.wind * 0.055,\n wavelength: 0.45,\n speed: 0.9 + o.wind * 0.8,\n angle: 75,\n pinnedEdge: 'top',\n },\n },\n ]\n },\n}\n","import { z } from 'zod'\nimport type { Behavior } from './types'\n\nexport const flyOptionsSchema = z.object({\n /** Ripple energy. */\n flutter: z.number().min(0).max(1).default(0.5),\n /** Aerodynamic arc of the sheet. */\n curve: z.number().min(0).max(1).default(0.4),\n})\n\nexport type FlyOptions = z.infer<typeof flyOptionsSchema>\n\n/** A note carried on air — arched and fluttering. Pair with the `tumble` idle. */\nexport const fly: Behavior<FlyOptions> = {\n id: 'fly',\n label: 'Fly',\n defaults: flyOptionsSchema.parse({}),\n optionsSchema: flyOptionsSchema,\n signature: ['flutter', 'curve'],\n progressParam: 'flutter',\n duration: 3.5,\n loopMode: 'yoyo',\n stack(o) {\n return [\n { type: 'bend', options: { curvature: 0.25 + o.curve, angle: 0 } },\n {\n type: 'wave',\n options: {\n amplitude: o.flutter * 0.07,\n wavelength: 0.7,\n speed: 1.6,\n angle: 30,\n pinnedEdge: 'none',\n },\n },\n ]\n },\n}\n","import { z } from 'zod'\nimport type { Behavior } from './types'\n\nexport const fallOptionsSchema = z.object({\n /** Air resistance ripple while falling. */\n flutter: z.number().min(0).max(1).default(0.6),\n /** A falling sheet always lifts a corner. */\n curl: z.number().min(0).max(1).default(0.3),\n})\n\nexport type FallOptions = z.infer<typeof fallOptionsSchema>\n\n/** A dropped sheet — corner lifted, rippling. Pair with the `tumble` idle for the descent. */\nexport const fall: Behavior<FallOptions> = {\n id: 'fall',\n label: 'Fall',\n defaults: fallOptionsSchema.parse({}),\n optionsSchema: fallOptionsSchema,\n signature: ['flutter', 'curl'],\n progressParam: 'flutter',\n duration: 3,\n loopMode: 'yoyo',\n stack(o) {\n return [\n {\n type: 'curl',\n options: { corner: 'top-right', amount: o.curl * 0.4, radius: 0.3, skew: 0 },\n },\n {\n type: 'wave',\n options: {\n amplitude: o.flutter * 0.055,\n wavelength: 0.85,\n speed: 1.3,\n angle: 60,\n pinnedEdge: 'none',\n },\n },\n ]\n },\n}\n","import { z } from 'zod'\nimport type { Behavior } from './types'\nimport { cornerNames } from '../deformers/curl'\n\nexport const carryOptionsSchema = z.object({\n /**\n * The grab point — where the pointer was on the paper at pick time.\n * 'auto' is resolved by the carry controller (usually the peeled corner:\n * continuity from peel → carry is the immersion moment).\n */\n grab: z.enum([...cornerNames, 'auto']).default('auto'),\n /** From stock feel: a stamp is stiff — it flutters, it doesn't flow. */\n stiffness: z.number().min(0).max(1).default(0.7),\n flutter: z.number().min(0).max(1).default(0.5),\n /** How far the paper's yaw trails the drag direction (runtime transform). */\n lag: z.number().min(0).max(1).default(0.35),\n /** Drag-speed drive (0..1). Written live by the carry controller. */\n drive: z.number().min(0).max(1).default(0.25),\n})\n\nexport type CarryOptions = z.infer<typeof carryOptionsSchema>\n\ntype Corner = (typeof cornerNames)[number]\n\nconst concreteGrab = (g: CarryOptions['grab']): Corner => (g === 'auto' ? 'top-left' : g)\n\n/** Bend-axis angle pointing from the grab corner toward the sheet center. */\nconst DROOP_ANGLE: Record<Corner, number> = {\n 'top-left': -45,\n 'top-right': -135,\n 'bottom-left': 45,\n 'bottom-right': 135,\n}\n\n/** The edge the grab corner hangs from — that edge doesn't flutter. */\nconst PIN_EDGE: Record<Corner, 'top' | 'bottom'> = {\n 'top-left': 'top',\n 'top-right': 'top',\n 'bottom-left': 'bottom',\n 'bottom-right': 'bottom',\n}\n\n/**\n * A held paper, alive from motion (the field/cheap path):\n * droop away from the grab point + drag-velocity flutter. The hero path —\n * cloth with a single pin following the cursor — is the existing\n * `physics: 'cloth'` grab; this behavior is what fields and exports run.\n */\nexport const carry: Behavior<CarryOptions> = {\n id: 'carry',\n label: 'Carry',\n defaults: carryOptionsSchema.parse({}),\n optionsSchema: carryOptionsSchema,\n signature: ['stiffness', 'flutter'],\n progressParam: 'drive',\n duration: 2.4,\n loopMode: 'yoyo',\n stack(o) {\n const grab = concreteGrab(o.grab)\n // Softer paper droops harder from the pinch; motion adds a touch more.\n const droop = (1 - o.stiffness) * 1.6 + o.drive * 0.35\n return [\n {\n type: 'bend',\n options: { curvature: -droop, angle: DROOP_ANGLE[grab] },\n },\n {\n type: 'wave',\n options: {\n amplitude: o.flutter * (0.012 + o.drive * 0.085),\n wavelength: 0.55,\n speed: 1.4 + o.drive * 1.8,\n angle: DROOP_ANGLE[grab],\n pinnedEdge: PIN_EDGE[grab],\n },\n },\n ]\n },\n}\n","import { z } from 'zod'\nimport type { Behavior } from './types'\nimport { flightPose } from '../physics/aero'\n\nexport const flightOptionsSchema = z.object({\n /** Directional wind vector — paper travels ACROSS the scene, not just down. */\n wind: z\n .tuple([z.number().min(-2).max(2), z.number().min(-2).max(2), z.number().min(-2).max(2)])\n .default([0.6, 0.08, 0]),\n gustiness: z.number().min(0).max(1).default(0.4),\n tumble: z.number().min(0).max(1).default(0.6),\n /** 'loop' is a seamless idle cycle; 'drift' travels along the wind. */\n path: z.enum(['drift', 'loop']).default('drift'),\n /** Drift only: exit the scene → re-enter the opposite side. */\n respawn: z.boolean().default(true),\n /** Half-extent of the travel before respawn wraps it. */\n range: z.number().min(0.5).max(12).default(3.5),\n})\n\nexport type FlightOptions = z.infer<typeof flightOptionsSchema>\n\n/**\n * Untethered paper carried across the scene on the wind —\n * the falling-leaf tumble core + directional travel + lift. Transform +\n * deformer based, so it's instancing-safe: a `scatter` layout + `flight`\n * idle = papers blowing through a hero section.\n */\nexport const flight: Behavior<FlightOptions> = {\n id: 'flight',\n label: 'Flight',\n defaults: flightOptionsSchema.parse({}),\n optionsSchema: flightOptionsSchema,\n signature: ['gustiness', 'tumble', 'path'],\n progressParam: 'tumble',\n duration: 6,\n loopMode: 'yoyo',\n stack(o) {\n // The sheet itself arcs and ripples; travel/tumble live in `transform`.\n return [\n { type: 'bend', options: { curvature: 0.35 + o.tumble * 0.4, angle: 20 } },\n {\n type: 'wave',\n options: {\n amplitude: 0.02 + o.gustiness * 0.03,\n wavelength: 0.8,\n speed: 1.1 + o.gustiness,\n angle: 35,\n pinnedEdge: 'none',\n },\n },\n ]\n },\n transform(o, t, pose) {\n flightPose(t, o, 0, pose)\n },\n}\n","/**\n * The shared fake-aerodynamics core: velocity-linked lift +\n * curated noise, per v0.2's \"reads more real than a true sim\" doctrine.\n * Pure math, no three.js, no allocation in the per-frame paths — `carry`\n * and `flight` both source their motion here.\n */\n\nexport interface AeroPose {\n position: [number, number, number]\n rotation: [number, number, number]\n}\n\n/**\n * Critically-damped spring toward a target — the carry pin's cursor\n * follow. Mutates `state` in place; returns nothing.\n */\nexport interface DampedValue {\n value: number\n velocity: number\n}\n\nexport function dampTo(state: DampedValue, target: number, smoothing: number, dt: number): void {\n // Critically damped: ω from smoothing (≈ time to close 90% of the gap).\n const omega = 2 / Math.max(smoothing, 1e-4)\n const x = omega * dt\n const exp = 1 / (1 + x + 0.48 * x * x + 0.235 * x * x * x)\n const change = state.value - target\n const temp = (state.velocity + omega * change) * dt\n state.velocity = (state.velocity - omega * temp) * exp\n state.value = target + (change + temp) * exp\n}\n\n/** Coherent gust factor in [1-g, 1+g] — curated, seeded, cheap. */\nexport function gust(t: number, seed: number, gustiness: number): number {\n const n =\n Math.sin(t * 1.7 + seed * 12.9898) * 0.6 +\n Math.sin(t * 0.53 + seed * 78.233) * 0.3 +\n Math.sin(t * 3.1 + seed * 3.7) * 0.1\n return 1 + n * gustiness\n}\n\nexport interface FlightParams {\n wind: [number, number, number]\n gustiness: number\n tumble: number\n path: 'drift' | 'loop'\n /** Exit the scene → re-enter the opposite side (drift only). */\n respawn: boolean\n /** Half-extent of the drift travel before respawn wraps it. */\n range: number\n}\n\n/**\n * Free paper on the wind: the falling-leaf tumble core + a directional wind\n * vector + lift, so paper travels ACROSS, not just down. A pure function of\n * time and phase — instancing-safe, deterministic, loopable.\n */\nexport function flightPose(t: number, o: FlightParams, phase: number, pose: AeroPose): void {\n const g = gust(t + phase * 7.3, phase, o.gustiness)\n const time = t + phase * 11.7\n\n if (o.path === 'loop') {\n // A seamless closed circuit: travel scaled by the wind vector.\n const s = Math.max(0.2, Math.hypot(o.wind[0], o.wind[1], o.wind[2]))\n const a = time * 0.35\n pose.position[0] = Math.sin(a) * o.range * 0.8 * Math.sign(o.wind[0] || 1)\n pose.position[1] = Math.sin(a * 2) * o.range * 0.18 * s\n pose.position[2] = Math.cos(a) * o.range * 0.35\n } else {\n // Drift: travel along the wind; respawn wraps the along-wind coordinate.\n const travel = time * 0.55 * g\n const wrap = (v: number, r: number) => (o.respawn ? ((((v + r) % (2 * r)) + 2 * r) % (2 * r)) - r : v)\n pose.position[0] = wrap(o.wind[0] * travel, o.range)\n pose.position[1] = wrap(o.wind[1] * travel, o.range * 0.6) + Math.sin(time * 1.3) * 0.08 * g\n pose.position[2] = wrap(o.wind[2] * travel, o.range)\n }\n\n // The falling-leaf tumble: see-saw pitch/roll with a lift bob, gust-scaled.\n pose.rotation[0] = Math.sin(time * 0.5 + 1) * 0.65 * o.tumble\n pose.rotation[1] = Math.sin(time * 0.23) * 0.4 * o.tumble\n pose.rotation[2] = Math.sin(time * 0.7) * 0.55 * o.tumble\n pose.position[1] += Math.sin(time * 1.4) * 0.06 * o.tumble * g\n}\n\n/**\n * Carry flutter drive: how much a held paper ripples for a given drag speed\n * (world units/s). Saturates — a violent drag doesn't tear the illusion.\n */\nexport function carryDrive(speed: number): number {\n return Math.min(1, speed * 0.55)\n}\n","import { z } from 'zod'\nimport type { Behavior } from './types'\n\nexport const crumpleBehaviorOptionsSchema = z.object({\n /** 0 = flat sheet, 1 = crushed. */\n progress: z.number().min(0).max(1).default(0.55),\n /** Few big facets at 0, many small ones at 1. */\n coarseness: z.number().min(0).max(1).default(0.35),\n /** How far the sheet curls in on itself as it crushes. */\n ball: z.number().min(0).max(1).default(0.5),\n /** A different crush of the same paper. */\n seed: z.number().int().min(0).max(7).default(0),\n})\n\nexport type CrumpleBehaviorOptions = z.infer<typeof crumpleBehaviorOptionsSchema>\n\n/**\n * A sheet being screwed up in a fist.\n *\n * Two deformers, in this order for a reason: `crumple` reads the flat sheet\n * position to place its creases, so it has to run before anything that moves\n * the sheet around. Crush the paper, then curl the crushed paper — the other\n * way round would crease a curved sheet as if it were still flat.\n */\nexport const crumpleBehavior: Behavior<CrumpleBehaviorOptions> = {\n id: 'crumple',\n label: 'Crumple',\n defaults: crumpleBehaviorOptionsSchema.parse({}),\n optionsSchema: crumpleBehaviorOptionsSchema,\n signature: ['progress', 'ball', 'coarseness'],\n progressParam: 'progress',\n duration: 2.6,\n loopMode: 'yoyo',\n stack(o) {\n return [\n {\n type: 'crumple',\n options: {\n amount: o.progress,\n scale: 1.5 + o.coarseness * 4.5,\n pull: 0.5,\n seed: o.seed,\n },\n },\n // The sheet closing in on itself. Paper does not crush flat, and\n // without this the result reads as texture rather than as a ball.\n {\n type: 'bend',\n options: { curvature: o.progress * o.ball * 0.9, angle: 35 },\n },\n ]\n },\n}\n","import { z } from 'zod'\nimport type { Behavior } from './types'\n\nexport const settleOptionsSchema = z.object({\n /**\n * How long ago it landed, 0..1.\n *\n * 0 is the instant of arrival — still carrying the shape it fell in. 1 is\n * a sheet that has been lying there, where its own weight has flattened\n * out everything except what its stiffness refuses to give up.\n */\n relax: z.number().min(0).max(1).default(0.45),\n /**\n * How hard the paper resists lying flat, 0..1.\n *\n * This is the stock, not the pose: tissue surrenders completely, card\n * never does. It is the whole reason a settled sheet reads as PAPER and\n * not as a decal — at 0 the mesh is a rectangle painted on the floor.\n */\n lift: z.number().min(0).max(1).default(0.45),\n /** Which corner stayed up. */\n corner: z.enum(['top-left', 'top-right', 'bottom-left', 'bottom-right']).default('top-right'),\n /**\n * Slack across the middle — the low, long undulation of a sheet that is\n * touching a floor in two places and bridging between them.\n */\n slack: z.number().min(0).max(1).default(0.4),\n})\n\nexport type SettleOptions = z.infer<typeof settleOptionsSchema>\n\n/**\n * A sheet that has landed and relaxed.\n *\n * The library could drop paper (`fall`), fly it (`fly`, `flight`), heap it\n * (`pile`) and catch it mid-air (`spill`) — and had no way at all to show a\n * sheet that has ARRIVED. Every reference installation worth copying has\n * paper on the floor: sheets settled on concrete after the fall, ribbons\n * pooling where they meet the ground. It is the most beautiful detail in the\n * set and it appears in it twice.\n *\n * The distinction from `fall` is not the shape, it is the CLOCK. `fall`\n * flutters — its wave carries `speed: 1.3`, and it is a sheet still arguing\n * with the air. This one is over. Everything here is static, and that is the\n * point: a settled sheet that ripples is a settled sheet nobody believes.\n *\n * Which is also why it composes rather than deforming: a landed sheet is a\n * gentle curl the stiffness held on to, plus a long slack undulation where\n * it bridges the floor. Both already exist, and a deformer that can be\n * spelled out of the ones we have does not earn a GLSL twin and a parity\n * case.\n */\nexport const settle: Behavior<SettleOptions> = {\n id: 'settle',\n label: 'Settle',\n defaults: settleOptionsSchema.parse({}),\n optionsSchema: settleOptionsSchema,\n signature: ['relax', 'lift'],\n progressParam: 'relax',\n duration: 2.4,\n loopMode: 'yoyo',\n stack(o) {\n // Relaxing flattens the sheet, so `relax` SUBTRACTS. Stiffness is the\n // floor under it: however long it lies there, `lift` is what it will\n // never give back.\n const held = o.lift * (1 - o.relax * 0.55)\n return [\n {\n type: 'curl',\n options: {\n corner: o.corner,\n // A settled corner turns up gently and over a long distance. A\n // tight curl reads as a sheet being rolled, which is a hand doing\n // something to it rather than gravity having finished with it.\n // Calibrated against `fall`, which lifts a corner by `curl * 0.4`\n // — a settled sheet should keep MORE than a falling one, not less,\n // because the corner it is holding up is the one thing gravity\n // could not take from it. The first pass at 0.32 with a 0.5 radius\n // rendered a flat rectangle, which is the one outcome this\n // behavior exists to avoid.\n amount: held * 0.75,\n radius: 0.2 + (1 - held) * 0.14,\n // Off the diagonal, because a corner that lifts along its exact\n // diagonal reads as folded rather than as fallen.\n skew: 11,\n },\n },\n {\n type: 'wave',\n options: {\n amplitude: o.slack * (1 - o.relax * 0.4) * 0.085,\n // Long: one slow rise across the sheet, not a ripple. A settled\n // sheet touches the floor in a couple of places and bridges\n // between them, and that bridge is a single arc.\n wavelength: 1.6,\n // Static. This is the whole behavior.\n speed: 0,\n angle: 22,\n pinnedEdge: 'none',\n },\n },\n ]\n },\n}\n","import { z } from 'zod'\nimport type { Behavior } from './types'\n\nexport const ribbonOptionsSchema = z.object({\n /**\n * How much of the drop is lying on the floor, as a fraction of the height.\n *\n * This is the whole image. A strip that stops dead at the ground reads as\n * a strip that was cut to fit; one that arrives with a length to spare and\n * turns over reads as paper meeting a floor, which is the thing the\n * reference installations are actually about.\n */\n pool: z.number().min(0).max(0.5).default(0.16),\n /** How tightly it turns where it lands. Low is a soft slump, high is a curl. */\n curl: z.number().min(0).max(1).default(0.45),\n /** Folds running down the length. A printed strip is never a flat plane. */\n drape: z.number().min(0).max(1).default(0.5),\n})\n\nexport type RibbonOptions = z.infer<typeof ribbonOptionsSchema>\n\n/**\n * A strip hung from the ceiling that reaches the floor and keeps going.\n *\n * The single most striking image in the reference set, and the reason it\n * took until now to build is that it needs three separate things that did\n * not exist a week ago: a room with a ceiling to hang from, hardware to hang\n * BY, and type that can be set down the length of a sheet without looking\n * like a caption. It is the payoff for all of them.\n *\n * The mathematics is not new, which is the point of the contribution ladder.\n * A ribbon is a `drape` down its length and a `fold` whose hinge sits at the\n * floor line rather than at the sheet's centre — `fold.offset` has always\n * been able to say \"crease here\", and nothing had ever asked it to.\n */\nexport const ribbon: Behavior<RibbonOptions> = {\n id: 'ribbon',\n label: 'Ribbon',\n defaults: ribbonOptionsSchema.parse({}),\n optionsSchema: ribbonOptionsSchema,\n /**\n * `curl`, not `pool` — and the reason is tessellation rather than taste.\n *\n * The grid is sized by sampling this parameter from 0 to 1, so it has to\n * BE a 0..1 parameter (a `pool` that stops at 0.5 would be sampled across\n * a range it rejects), and it should be the one that drives the geometry\n * hardest. `curl` opens the crease from a right angle to a fold back on\n * itself, and the sharpest turn is exactly the case that demands the most\n * segments across the hinge.\n */\n signature: ['pool', 'curl', 'drape'],\n progressParam: 'curl',\n duration: 3,\n loopMode: 'yoyo',\n stack(o, sheet) {\n // Where the floor is, in the sheet's own coordinates — a `pool` fraction\n // above the bottom edge, so the length below that line is what turns\n // over. This is why the behavior needs the sheet at all, where most take\n // only their options.\n //\n // The hinge travels DOWNWARD (-90°), and that is not cosmetic: it is\n // what makes \"past the crease\" mean \"below the floor line\" rather than\n // \"above it\". Pointed the other way, the fold would have turned the\n // whole drop from the ceiling down.\n const floorLine = -sheet.height / 2 + sheet.height * o.pool\n\n // How soft the crease is. `curl` drives this rather than the fold angle\n // — see the fold below for why.\n const radius = Math.min(0.5, Math.max(0.02, sheet.height * (0.035 - o.curl * 0.027)))\n\n /**\n * The hinge does not turn on the spot: it wraps a cylinder of radius\n * `radius / φ`, and the flap leaves that cylinder lower than the crease\n * line by exactly that much.\n *\n * Which means placing the crease AT the floor buries the pool under it.\n * That is what was happening — the pooled length came out about 9cm\n * below the ground on the ribbon stage's own numbers, so the one thing\n * the stage exists to show was inside the floor. The crease goes up by\n * the hinge's own radius so that the POOL lands on the line, which is\n * the thing that has to be true; where the crease sits is arithmetic.\n */\n const hingeDrop = radius / (Math.PI / 2)\n\n return [\n {\n // `drape` — the deformer named after the thing this is.\n //\n // It briefly used `wave` instead, to work around a report that\n // `drape` rendered an invisible sheet on the hero path. That report\n // was wrong: it rested on counting the colours in a screenshot, and\n // a near-flat strip filling the frame has about as many colours as\n // an empty one. `deformers/draws.test.ts` now asserts on geometry\n // what the screenshot was being asked to guess at.\n //\n // `wave` was never the same picture. A wave is a sine of fixed\n // amplitude end to end, so its folds ran just as deep at the clip as\n // at the floor; a hung strip is FLAT where it is held and gathers as\n // it falls, which is exactly `falloff`, and it narrows as it gathers,\n // which is `gather`. Neither has an equivalent in `wave`.\n type: 'drape',\n options: {\n // Depth at the free end. Larger than the wave's amplitude was,\n // because this one starts at nothing under the clip rather than\n // running at full depth the whole way down.\n amplitude: o.drape * 0.1,\n // Few and long. A printed strip carries two or three slow folds\n // down its drop; more than that is a curtain, not a ribbon.\n folds: 2.5,\n // Holds the top flat and gathers the movement toward the floor,\n // which is what a strip hung from a single clip does.\n falloff: 1.5,\n // Off a pure sine, so the folds do not read as corrugation.\n irregular: 0.5,\n // Gentle. The pooled length has to lie FLAT on the floor, and a\n // hard pinch would narrow it as it went.\n gather: 0.22,\n pinnedEdge: 'top',\n },\n },\n {\n // `fold`, not `roll` — and this is the second correction the render\n // forced. A roll wraps the pooled length around a cylinder, so it\n // curls up and over and ends in the air: a hook, not a pool. Paper\n // meeting a floor does not wrap, it CREASES and then lies down.\n //\n // A hinge at the floor line with a soft radius is exactly that: the\n // drop above stays vertical, and everything below turns through\n // roughly a right angle and runs out flat along the ground.\n type: 'fold',\n options: {\n // Travel measured down the drop, so the crease line sits across\n // the ribbon and the flap below it is what turns.\n angle: -90,\n offset: -floorLine - hingeDrop,\n // Exactly a right angle, at every setting, and this is the fix\n // for the thing the ribbon stage was actually failing at.\n //\n // A hinge is one angle: whatever it turns through, the pooled\n // length leaves the crease in a straight line and holds that\n // heading. Only 90° is the floor. It shipped as `62 + curl * 46`\n // (62°..108°), so below curl 0.61 the pool went on travelling\n // downward and vanished THROUGH the floor — which is why the one\n // stage built around this behavior rendered as flat strips\n // stopping at the ground — and above it the pool tilted back UP\n // and floated. Both halves of the range were wrong, in opposite\n // directions, and only the midpoint was ever right.\n //\n // Paper with more length than floor does not rise at a constant\n // angle; it buckles and lies in an S, which one hinge cannot\n // describe and should not pretend to.\n foldAngle: 90,\n // So `curl` drives the CREASE instead, which is what its own\n // description always claimed — \"how tightly it turns where it\n // lands. Low is a soft slump, high is a curl.\" A soft radius is a\n // sheet slumping over the join; a tight one is a sheet that has\n // been creased. It scales with the sheet, because a radius that\n // reads as a fold on a short strip reads as a knife-edge on a long\n // one.\n radius,\n },\n },\n ]\n },\n}\n","import { paperConfigSchema, type PaperConfig, type PaperConfigInput } from './schema'\n\nexport { mergeConfig, mergeWithDeletes } from './merge'\n\n/** Parse anything preset-shaped (object or JSON string) into a full, defaulted config. */\nexport function parsePreset(input: PaperConfigInput | string): PaperConfig {\n const raw = typeof input === 'string' ? JSON.parse(input) : input\n return paperConfigSchema.parse(raw)\n}\n\n/** Serialize a config to `.paper` JSON. */\nexport function serializePreset(config: PaperConfig): string {\n return JSON.stringify(config, null, 2)\n}\n","import type * as THREE from 'three'\n\n/**\n * Recompute vertex normals for a sheet, straight over the typed arrays.\n *\n * Identical arithmetic to `BufferGeometry.computeVertexNormals()` — same\n * `cross(C − B, A − B)` per face, same accumulate-then-normalize — and it\n * agrees with it bit for bit (`core/normals.test.ts` asserts exact equality,\n * not a tolerance). What it does not do is go through `Vector3` and the\n * `BufferAttribute` accessors, which is three's cost and not the maths'.\n *\n * Worth having its own file because of where it sits: this runs once per\n * animated sheet per frame in hero mode, over a grid that `segments: 'auto'`\n * is allowed to take to 128 (16.6k vertices, 32.8k faces). Measured on a\n * `drape + wave` sheet at that ceiling it is 1.37 ms through three and\n * 0.18 ms here — normals were three quarters of the cost of a `roll`'s\n * frame and are now a tenth of it.\n *\n * Falls back to three for anything that is not an indexed mesh carrying a\n * normal attribute, which is the only shape this fast path knows.\n */\nexport function computeSheetNormals(geometry: THREE.BufferGeometry): void {\n const index = geometry.index\n const normalAttr = geometry.attributes.normal as THREE.BufferAttribute | undefined\n const positionAttr = geometry.attributes.position as THREE.BufferAttribute | undefined\n if (!index || !normalAttr || !positionAttr) {\n geometry.computeVertexNormals()\n return\n }\n const pos = positionAttr.array as Float32Array\n const nrm = normalAttr.array as Float32Array\n const idx = index.array as Uint16Array | Uint32Array\n\n nrm.fill(0)\n for (let i = 0, l = idx.length; i < l; i += 3) {\n const a = idx[i]! * 3\n const b = idx[i + 1]! * 3\n const c = idx[i + 2]! * 3\n const bx = pos[b]!\n const by = pos[b + 1]!\n const bz = pos[b + 2]!\n const cbx = pos[c]! - bx\n const cby = pos[c + 1]! - by\n const cbz = pos[c + 2]! - bz\n const abx = pos[a]! - bx\n const aby = pos[a + 1]! - by\n const abz = pos[a + 2]! - bz\n // The face normal, unnormalized — its length is twice the triangle's\n // area, which is the area weighting three's version also relies on.\n const nx = cby * abz - cbz * aby\n const ny = cbz * abx - cbx * abz\n const nz = cbx * aby - cby * abx\n nrm[a] = nrm[a]! + nx\n nrm[a + 1] = nrm[a + 1]! + ny\n nrm[a + 2] = nrm[a + 2]! + nz\n nrm[b] = nrm[b]! + nx\n nrm[b + 1] = nrm[b + 1]! + ny\n nrm[b + 2] = nrm[b + 2]! + nz\n nrm[c] = nrm[c]! + nx\n nrm[c + 1] = nrm[c + 1]! + ny\n nrm[c + 2] = nrm[c + 2]! + nz\n }\n\n for (let i = 0, l = nrm.length; i < l; i += 3) {\n const x = nrm[i]!\n const y = nrm[i + 1]!\n const z = nrm[i + 2]!\n // Divide rather than multiply by a reciprocal: `Vector3.normalize()`\n // divides, and one rounding difference per component is the whole\n // distance between \"bit-identical to three\" and \"close enough\", which\n // is not a claim worth weakening to save two multiplies.\n //\n // A vertex whose faces cancelled out has no normal to give. three's\n // `normalize()` divides by `length() || 1` and leaves the zero; so does\n // this, rather than dividing by zero and poisoning the lighting.\n const len = Math.sqrt(x * x + y * y + z * z) || 1\n nrm[i] = x / len\n nrm[i + 1] = y / len\n nrm[i + 2] = z / len\n }\n normalAttr.needsUpdate = true\n}\n","import { useRef } from 'react'\n\n/**\n * Deep-equality memo deps, without serializing anything.\n *\n * Several hooks here need to recompute on the CONTENT of a prop rather than\n * on its identity, because the props in question — the paper slots, a\n * preset, a content list — are rebuilt as fresh objects on every render of\n * whatever is above. The library used to spell that as\n * `[JSON.stringify(papers)]`, which reads well and is a trap: a dependency\n * array is evaluated on **every render**, so the serialization is paid every\n * render whether or not anything changed, and it is paid in garbage rather\n * than in time.\n *\n * That is affordable for a layout's options and ruinous for a paper. An\n * image slot carries its bitmap inline as a data URL, so a field of fourteen\n * photographs serialized roughly seventeen megabytes per render — and the\n * controls that render the most are the continuous ones, which is why\n * dragging a speed slider was the way to take the tab out with an\n * out-of-memory crash.\n *\n * `useStable` compares instead of serializing. Nothing is allocated, and the\n * comparison short-circuits on `Object.is` at every level, so the common\n * case — a fresh wrapper around the same inner objects — costs a handful of\n * pointer checks no matter how large the data URL underneath is.\n */\nexport function useStable<T>(value: T): T {\n const held = useRef(value)\n if (!deepEqual(held.current, value)) held.current = value\n return held.current\n}\n\n/**\n * Structural equality over JSON-shaped data, matching what the\n * `JSON.stringify` comparison it replaces considered equal.\n *\n * That last part is the reason for the `undefined` handling below: stringify\n * drops a key whose value is `undefined`, so `{a: 1, b: undefined}` and\n * `{a: 1}` used to compare equal and must go on doing so — a config that\n * spells an absent option either way should not rebuild the field.\n */\nexport function deepEqual(a: unknown, b: unknown): boolean {\n if (Object.is(a, b)) return true\n if (typeof a !== 'object' || typeof b !== 'object' || a === null || b === null) return false\n\n if (Array.isArray(a) || Array.isArray(b)) {\n if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length) return false\n for (let i = 0; i < a.length; i++) if (!deepEqual(a[i], b[i])) return false\n return true\n }\n\n const left = a as Record<string, unknown>\n const right = b as Record<string, unknown>\n // Keys carrying `undefined` do not count, on either side — see above.\n const keys = new Set<string>()\n for (const key of Object.keys(left)) if (left[key] !== undefined) keys.add(key)\n for (const key of Object.keys(right)) if (right[key] !== undefined) keys.add(key)\n for (const key of keys) if (!deepEqual(left[key], right[key])) return false\n return true\n}\n","import * as THREE from 'three'\nimport type { SheetConfig } from '../config/schema'\nimport { FLAT_SEGMENTS, LEGACY_FLAT_SEGMENTS, quantizeSegments, type SegmentPair } from './tessellation'\n\n/**\n * Resolve the subdivision grid for a sheet.\n *\n * `minSegments` is the correctness floor the active deformers require, and it\n * applies however `segments` is set. `autoSegments` is what those deformers\n * WANT for the options they are carrying, and it is what `'auto'` resolves\n * to — see `stackAutoSegments` and `core/tessellation.ts`.\n *\n * Both are per axis, because a demand is a demand along a DIRECTION. A\n * banner draped in folds across its width needs those folds resolved across\n * and needs almost nothing down its drop; a single number spread by aspect\n * ratio gives the drop the density and the folds the leftovers, which is\n * both the expensive answer and the wrong-looking one. A bare number is\n * still accepted and still means \"this many, both ways\".\n *\n * `'auto'` used to hand the long side a flat 72 whatever was on the sheet, so\n * a blank page was tessellated exactly as finely as a crumpled one and every\n * `minSegments` in the library was dead weight — nothing could ever raise a\n * grid that already started at the highest value anyone asked for. It now\n * sizes to the work, quantized onto a ladder so that dragging a slider does\n * not rebuild the mesh.\n *\n * Omitting `autoSegments` keeps the old flat 72, which is what a caller with\n * no deformer stack in hand should get — this helper is exported, and its\n * answer to an unchanged call should not have changed.\n */\nexport function resolveSegments(\n sheet: SheetConfig,\n minSegments: number | SegmentPair = 2,\n autoSegments: number | SegmentPair = LEGACY_FLAT_SEGMENTS,\n): [number, number] {\n // A bare floor is a floor both ways — it says nothing about direction.\n const [minX, minY] = typeof minSegments === 'number' ? [minSegments, minSegments] : minSegments\n if (sheet.segments !== 'auto') {\n return [Math.max(sheet.segments, minX, 2), Math.max(sheet.segments, minY, 2)]\n }\n // A bare TARGET is the old contract: one density for the long edge, spread\n // over the short one by aspect, snapped to the ladder once. Callers with a\n // stack in hand pass a pair instead, and each axis is then snapped on its\n // own — which is the point of asking per axis at all.\n const [wantX, wantY] =\n typeof autoSegments === 'number'\n ? spreadByAspect(sheet, quantizeSegments(Math.max(autoSegments, FLAT_SEGMENTS)))\n : [\n quantizeSegments(Math.max(wantOrFlat(autoSegments[0]), FLAT_SEGMENTS)),\n quantizeSegments(Math.max(wantOrFlat(autoSegments[1]), FLAT_SEGMENTS)),\n ]\n return [Math.max(wantX, minX, 2), Math.max(wantY, minY, 2)]\n}\n\nconst wantOrFlat = (n: number) => (Number.isFinite(n) ? n : FLAT_SEGMENTS)\n\nfunction spreadByAspect(sheet: SheetConfig, target: number): [number, number] {\n const long = Math.max(sheet.width, sheet.height)\n if (!(long > 0)) return [target, target]\n return [Math.round((sheet.width / long) * target), Math.round((sheet.height / long) * target)]\n}\n\n/**\n * The point on a sheet's drawn surface at `(u, v)`, in the geometry's local\n * space, written into `out`.\n *\n * `positions` is a `PlaneGeometry`-ordered grid of `cols × rows` vertices —\n * the order every sheet in the library is built in, cloth particles and strip\n * nodes included. That order runs its rows TOP first, while `v` runs from the\n * BOTTOM: `v = 0` is the bottom edge, as it is in the mesh's own `uv`\n * attribute and in row 0 of a `DamageSource`. The flip is done here, once, so\n * that nothing reading damage at a UV and asking where that is has to know.\n *\n * Interpolated across the TRIANGLE three draws, not bilinearly across the\n * cell. On a flat grid the two agree; on a deformed one they do not, and the\n * triangle is what is on screen — an ember that leaves a point a millimetre\n * inside the paper is an ember that leaves from behind it.\n *\n * `u` and `v` are clamped to the sheet.\n */\nexport function surfacePointAt(\n positions: ArrayLike<number>,\n cols: number,\n rows: number,\n u: number,\n v: number,\n out: THREE.Vector3,\n): THREE.Vector3 {\n const fx = Math.min(1, Math.max(0, u)) * (cols - 1)\n const fy = (1 - Math.min(1, Math.max(0, v))) * (rows - 1)\n const ix = Math.min(Math.floor(fx), cols - 2)\n const iy = Math.min(Math.floor(fy), rows - 2)\n const tx = fx - ix\n const ty = fy - iy\n // PlaneGeometry's cell: a (ix, iy), b (ix, iy+1), c (ix+1, iy+1),\n // d (ix+1, iy), drawn as the triangles a-b-d and b-c-d — split along b-d.\n const a = (iy * cols + ix) * 3\n const b = a + cols * 3\n const c = b + 3\n const d = a + 3\n for (let axis = 0; axis < 3; axis++) {\n const pa = positions[a + axis]!\n const pb = positions[b + axis]!\n const pc = positions[c + axis]!\n const pd = positions[d + axis]!\n const value =\n tx + ty <= 1 ? pa + tx * (pd - pa) + ty * (pb - pa) : pc + (1 - tx) * (pb - pc) + (1 - ty) * (pd - pc)\n out.setComponent(axis, value)\n }\n return out\n}\n\n/**\n * Geometry factory. The sheet lives in its local XY plane, centered on the\n * origin, facing +Z. Deformers displace these vertices; the base (flat)\n * positions are kept by the caller for re-deformation each frame.\n */\nexport function createSheetGeometry(\n sheet: SheetConfig,\n minSegments: number | SegmentPair = 2,\n autoSegments: number | SegmentPair = LEGACY_FLAT_SEGMENTS,\n): THREE.PlaneGeometry {\n const [sx, sy] = resolveSegments(sheet, minSegments, autoSegments)\n return new THREE.PlaneGeometry(sheet.width, sheet.height, sx, sy)\n}\n","import type { StockName } from '../config/schema'\n\n/**\n * A stock is a named bundle of material + geometry defaults — choosing paper\n * at a print shop. Individual controls always override; schema-wise these are\n * just defaults.\n */\nexport interface Stock {\n id: StockName\n label: string\n /** Base tint, also used as the canvas background behind content. */\n color: string\n roughness: number\n /** 0 = opaque. Vellum is translucent. */\n opacity: number\n /**\n * How much light passes THROUGH the sheet when something is behind it,\n * 0..1. Distinct from `opacity`: newsprint is fully opaque to look at and\n * still glows on a lightbox. This is what makes a backlit banner read.\n */\n translucency: number\n /** Ink multiply tint for content drawn on this stock (thermal prints grey-black). */\n inkColor: string\n /** Thermal-printer banding intensity baked into the grain effect. */\n banding: number\n /** Surface effects this stock ships with; explicit surface config overrides per key. */\n defaultSurface: { grain?: number; aging?: number }\n /** Reversed front-content ghost on the backside (thin stocks let ink show). */\n showThrough: number\n /** Glossy near-white glue underside (stickers) — forces showThrough 0. */\n adhesive: boolean\n /**\n * How hard this paper holds a crease, 0..1 — the material half of\n * {@link MemoryConfig}. Fibrous, thick stocks take a set and keep it;\n * coated and translucent ones spring most of the way back.\n *\n * Not a fraction of anything on its own: `memory.ts` scales it by\n * `MAX_SET`, so 1 here means \"as much as paper ever remembers\", not \"stays\n * exactly as folded\".\n */\n takesSet: number\n}\n\nexport const stocks: Record<StockName, Stock> = {\n printer: {\n id: 'printer',\n label: 'Printer',\n color: '#fbfaf7',\n roughness: 0.88,\n opacity: 1,\n translucency: 0.2,\n inkColor: '#222222',\n banding: 0,\n defaultSurface: { grain: 0.12 },\n showThrough: 0,\n adhesive: false,\n // Office bond creases cleanly and holds it — the reference paper.\n takesSet: 0.6,\n },\n thermal: {\n id: 'thermal',\n label: 'Thermal',\n color: '#f6f3e9',\n roughness: 0.62,\n opacity: 1,\n translucency: 0.34,\n inkColor: '#3a3a3a',\n banding: 0.35,\n defaultSurface: { aging: 0.1 },\n showThrough: 0.06,\n adhesive: false,\n // Thin and already curled off a roll; a fold in it stays folded.\n takesSet: 0.65,\n },\n kraft: {\n id: 'kraft',\n label: 'Kraft',\n color: '#c9a06c',\n roughness: 0.96,\n opacity: 1,\n translucency: 0.08,\n inkColor: '#33261a',\n banding: 0,\n defaultSurface: { grain: 0.5 },\n showThrough: 0,\n adhesive: false,\n // Thick and fibrous. The crease is a break, and it never comes back.\n takesSet: 0.85,\n },\n newsprint: {\n id: 'newsprint',\n label: 'Newsprint',\n color: '#e9e4d6',\n roughness: 0.95,\n opacity: 1,\n translucency: 0.38,\n inkColor: '#3d3a34',\n banding: 0,\n defaultSurface: { grain: 0.7, aging: 0.15 },\n showThrough: 0.06,\n adhesive: false,\n // Soft, short-fibred, and barely sprung — it crumples rather than resists.\n takesSet: 0.8,\n },\n vellum: {\n id: 'vellum',\n label: 'Vellum',\n color: '#f4f2ec',\n roughness: 0.42,\n opacity: 0.62,\n translucency: 0.86,\n inkColor: '#4a453d',\n banding: 0,\n defaultSurface: {},\n showThrough: 0.55,\n adhesive: false,\n // Translucent and plasticky: it fights the fold and mostly wins.\n takesSet: 0.25,\n },\n 'photo-gloss': {\n id: 'photo-gloss',\n label: 'Photo gloss',\n color: '#ffffff',\n roughness: 0.22,\n opacity: 1,\n translucency: 0.03,\n inkColor: '#111111',\n banding: 0,\n defaultSurface: {},\n showThrough: 0,\n adhesive: false,\n // The coating resists, then cracks white — little angle kept, lots of mark.\n takesSet: 0.3,\n },\n // Photo-gloss-like face, glossy near-white glue underside. The default\n // carrier for perforated stamp sheets.\n sticker: {\n id: 'sticker',\n label: 'Sticker',\n color: '#ffffff',\n roughness: 0.3,\n opacity: 1,\n translucency: 0.06,\n inkColor: '#1a1a1a',\n banding: 0,\n defaultSurface: {},\n showThrough: 0,\n adhesive: true,\n // A face sheet on a release liner; the liner does most of the remembering.\n takesSet: 0.5,\n },\n}\n\nexport function getStock(name: StockName): Stock {\n return stocks[name]\n}\n","import { paperConfigSchema, type PaperConfig, type PaperConfigInput } from '../schema'\n\n/**\n * Built-in `.paper` presets. A preset is the serialized closure of one Paper —\n * the unit of saving, sharing, and code export. Stored as plain JSON-safe\n * objects, validated on access.\n */\nconst builtins: Record<string, PaperConfigInput> = {\n 'receipt-unroll': {\n meta: { name: 'Receipt unroll', tags: ['receipt', 'unroll', 'hero'] },\n sheet: { width: 1, height: 2.6 },\n stock: 'thermal',\n content: {\n type: 'receipt',\n store: 'nawwara.studio',\n address: '124 Paper St',\n items: [\n { name: 'Curl, true', price: 12 },\n { name: 'Roll, tight', price: 8.5 },\n { name: 'Sheet, one', price: 0.99 },\n ],\n timestamp: '11.07.2026 18:42',\n },\n behavior: { type: 'unroll', progress: 0.55, tightness: 0.55, sway: 0.3 },\n surface: { deckle: { edges: ['bottom'], roughness: 0.6 } },\n },\n /**\n * A roll on a holder with a leaf already out, meant to be driven by scroll:\n * bind `behavior.progress` to how far down the page you are and the paper\n * pays out while the roll runs down toward its tube.\n *\n * The three parts that make it read as a real roll rather than a curled\n * sheet: `fixed` keeps the roll on its holder and moves the paper instead,\n * `tail` means there is always a leaf to take hold of, and `floor` gives\n * the drop somewhere to land — paper that reaches the ground creases and\n * lies down rather than hanging into the void forever. A `core` a third of\n * the full radius is a real cardboard tube, so the roll still looks like a\n * roll after it has been used down.\n */\n 'paper-roll': {\n meta: { name: 'Paper roll', tags: ['roll', 'unroll', 'scroll', 'hero'] },\n sheet: { width: 1, height: 5 },\n stock: 'newsprint',\n content: { type: 'blank' },\n behavior: {\n type: 'unroll',\n progress: 0.25,\n tightness: 0.8,\n sway: 0.15,\n from: 'top',\n fixed: true,\n core: 0.12,\n tail: 0.5,\n floor: 2.4,\n },\n surface: { deckle: { edges: ['bottom'], roughness: 0.5 } },\n },\n /**\n * The one that is a SIMULATION rather than a shape.\n *\n * `paper-roll` above draws this same object with a deformer stack, and for\n * a roll paying out against a wall that is the cheaper and better answer.\n * This preset exists for the half that geometry cannot reach: what happens\n * once the paper hits the ground. A deformer can bend a sheet along a curve\n * you have already chosen; it cannot discover that a strip under\n * compression buckles at its weakest hinge, and it cannot let one fold land\n * on the one beneath it. Both of those are what a pile IS.\n *\n * Bind `physics.scroll` to the page and the roll turns:\n *\n * ```tsx\n * const [scroll, setScroll] = useState(0)\n * useEffect(() => {\n * const onScroll = () => setScroll(window.scrollY / 120)\n * window.addEventListener('scroll', onScroll, { passive: true })\n * return () => window.removeEventListener('scroll', onScroll)\n * }, [])\n * <Paper preset=\"toilet-roll\" physics={{ type: 'strip', scroll }} />\n * ```\n *\n * It is a MONOTONIC world-unit number, not a 0..1 progress — the sim\n * differentiates it, so scrolling back up rewinds the roll and drags the\n * pile taut before it lifts.\n *\n * The proportions are the real object's: a panel as wide as it is long, so\n * `perforation` equals the sheet width and the strip tears into squares.\n */\n 'toilet-roll': {\n meta: { name: 'Toilet roll', tags: ['roll', 'scroll', 'simulation', 'hero'] },\n // The proportions are a real roll's, at the scale the library is viewed\n // at: `<Paper>` and the editor both look at the origin through about two\n // world units and neither fits a camera to its content, so the whole\n // composition — roll, drop and pile — has to live inside that. A panel is\n // as wide as it is long and the roll is about a panel across, which is\n // what a toilet roll is.\n //\n // Twenty-three panels of paper. Not a real roll's several hundred, but\n // enough that a full page of scrolling does not empty it: one scroll unit\n // is about one unit of paper on a fresh roll, so this is a couple of\n // screens' worth before the tube shows.\n sheet: { width: 0.6, height: 14 },\n stock: 'printer',\n content: { type: 'blank' },\n physics: {\n type: 'strip',\n scroll: 0,\n // Wound tightly enough to hold this much paper at a believable size: the\n // outer radius lands at 0.61 of the panel width against a real roll's\n // 0.57, over about nine visible turns.\n //\n // `tightness` is doing double duty and the trade is worth knowing about.\n // A layer gap IS the paper's thickness, so it also sets how far apart\n // self-collision holds two folds — wind tighter for a neater roll and\n // the pile on the floor gets flatter, looser for a fatter pile and the\n // roll coarsens. This is the middle of that.\n //\n // It is ALSO the roll's rim, and that is the reason not to raise it on\n // looks alone. A layer gap is a real space between two wound turns, so\n // the roll's end face is concentric rings with nothing between them,\n // and off head-on you see between them — a fine sawtooth around the\n // rim that winding tighter genuinely reduces. It was tried. Tightening\n // to 0.78 also moves the roll's proportion to 0.553 of a panel width,\n // nearer a real roll's 0.57 than this is, so it looked like a free win\n // — and it throws the pile 1.33 units out in x against the 0.874 a\n // square parent can see, spreading 5.9 panel-widths. Framing beats the\n // rim. The sawtooth is what a roll wound from ONE zero-thickness\n // ribbon costs; it is not tuned away, and a caller who wants it gone\n // wants a thicker `stock` or fewer, fatter turns.\n tightness: 0.65,\n // A real cardboard tube, and a floor on how tight the spiral ever winds.\n // The innermost wrap is the coarsest thing in the roll — the same\n // arc-length step spans a bigger angle the smaller the radius — so the\n // core is what stops a nearly-empty roll turning back into a polygon.\n core: 0.12,\n // A panel and a half already hanging. A roll on a holder always has a\n // leaf out; starting from a bare cylinder reads as one still wrapped.\n tail: 0.9,\n perforation: 0.6,\n // The four numbers below were chosen TOGETHER, and by worst case rather\n // than by a good-looking run. A pile is chaotic: change `crease` by\n // 0.05 and one 14-second scroll can spread 2.0 panel-widths of floor or\n // 4.2, so a single trajectory is a sample and not a measurement. These\n // are scored over nine — three scroll depths crossed with three feed\n // rates — on how far the composition ever gets from the origin.\n //\n // What that fixed: the shipped set spread 2.9 panel-widths on average\n // and 4.0 at worst, and threw paper 1.60 units out in z. It ran off the\n // side of the frame and kept going. These hold 2.2 average, 2.8 worst,\n // and 1.09 out — while keeping the pile's height (about ten layers)\n // intact, which is the thing all of this exists to show.\n //\n // The most load-bearing of them. Below about 0.6 the landed paper flops\n // over in flat panels and runs away across the floor instead of folding\n // back; high is what makes the perforations hold and the pile\n // accordion. A used roll remembering its creases is the whole effect.\n crease: 0.9,\n // Low enough that a panel buckles rather than steering the pile: at 0.5\n // the sheet was stiff enough to push the folds already down along the\n // floor ahead of it, which is what \"spreads across four panels\" was.\n stiffness: 0.4,\n // High: paper is light and broad, and this is what separates it from a\n // rope hanging off a drum. It also damps the sideways travel that\n // carried the pile out of frame.\n drag: 0.85,\n gravity: 1,\n // The drop, measured from the roll's axis. Together with the roll's own\n // radius this IS the height of the composition, which is centred on the\n // origin — so keep their sum under about 1.7 or the roll and the pile\n // fall outside the ~1.75 units `<Paper>`'s fixed camera can see.\n //\n // Shortened from 1.2, and it is the single most effective number here:\n // a longer fall is more airtime for the strip to pick a direction and\n // glide, so it landed still travelling and slid. Worst-case spread goes\n // 4.2 panel-widths to 3.1 and the pile keeps its full depth. It buys\n // vertical room as well, which is what lets the roll sit further up.\n floor: 0.85,\n inertia: 0.5,\n },\n surface: { grain: 0.25 },\n // The preset is unreadable without this, and that is not a figure of\n // speech: the strip sim folds in DEPTH, and every camera in the library\n // is fixed and head-on, so `<Paper preset=\"toilet-roll\" />` framed the\n // roll end-on and the entire accordion edge-on and rendered a blank white\n // column. This is the three-quarter view the pile actually reads from —\n // enough to see along the folds and around the roll's rim, not so much\n // that the strip's face turns away.\n //\n // The ceiling is framing, not taste. Turning swaps the pile's DEPTH for\n // WIDTH, and depth is free — the camera has plenty — while width is not.\n // Measured over fifteen scroll trajectories the pile reaches 1.27 units\n // of depth at worst, and `halfWidth·cos θ + 1.27·sin θ` crosses the 0.874\n // half-view a square parent gets at 28°. Twenty-five leaves real margin\n // (0.809) and gives up almost nothing of the angle.\n //\n // Do not raise it without re-measuring that depth: the two numbers are\n // coupled, and the pile's depth is not stable under small changes to the\n // physics — see the note on `floor`.\n //\n // A parent narrower than square still crops the pile's far edge. That is\n // the honest limit of a fixed camera, and the caller's answer is their\n // own `rotation` prop, which this composes with rather than overrides.\n scene: { turn: 25 },\n },\n 'letter-fold': {\n meta: { name: 'Letter fold', tags: ['fold', 'text'] },\n sheet: { width: 1, height: 1.4 },\n stock: 'printer',\n content: {\n type: 'text',\n text: 'Dear you,\\n\\nSome things are worth folding carefully.\\n\\nYours,\\nN.',\n },\n behavior: { type: 'letter-fold', progress: 0.4, crease: 0.3 },\n // A letter that has been folded before. These were painted-on\n // `creaseLines` until the paper could carry real ones — two marks in the\n // shader at exactly the two places the tri-fold bends, which is a good\n // impression of a crease right up until you unfold the letter and it\n // comes back perfectly flat. As memory they bend the sheet as well as\n // marking it, and folding the letter deepens the creases it already has\n // rather than drawing a second pair on top of them.\n //\n // The lines are `letterFold`'s own: travel down and up, each a sixth of\n // the sheet from the middle. Shallower than a fold leaves (printer keeps\n // about 20°) because this letter has been folded once and put away, not\n // folded and reopened in front of you.\n memory: {\n creases: [\n { angle: 270, offset: 1.4 / 6, depth: 13 },\n { angle: 90, offset: 1.4 / 6, depth: 11 },\n ],\n },\n },\n /**\n * The wash, shown rather than described.\n *\n * A `wash` is a field on every content type, which means it is reachable\n * from any preset and discoverable from none — a toggle three folders down\n * is not an argument for the feature. This is the argument: type set over\n * paint, on cotton, deckled, with the paper still showing through both.\n */\n 'washed-letter': {\n meta: { name: 'Washed letter', tags: ['wash', 'text'] },\n // Printer stock, not vellum: vellum is translucent and takes the room's\n // grey through the back of the sheet, which turns a wash the colour of\n // dishwater. Pigment needs something white behind it.\n sheet: { width: 1.05, height: 1.45 },\n stock: 'printer',\n content: {\n type: 'text',\n text: 'Painted first,\\nwritten after.',\n font: 'Georgia, \"Times New Roman\", serif',\n size: 52,\n valign: 'center',\n align: 'center',\n wash: { color: '#5b6f9a', secondary: '#c08a86', blooms: 6, spread: 0.85, intensity: 0.5, seed: 3 },\n },\n behavior: { type: 'peel', progress: 0.12, corner: 'bottom-right', radius: 0.3 },\n surface: { grain: 0.35, deckle: { edges: ['bottom', 'right'], roughness: 0.45 } },\n },\n 'vintage-note': {\n meta: { name: 'Vintage note', tags: ['aging', 'text'] },\n sheet: { width: 1.1, height: 1.4 },\n stock: 'newsprint',\n content: {\n type: 'text',\n text: 'FOUND, ONE PAPER ENGINE.\\n\\nReward if returned to the web.',\n font: 'Georgia, serif',\n size: 40,\n },\n behavior: { type: 'peel', progress: 0.18, corner: 'top-right', radius: 0.22 },\n surface: { aging: 0.55, grain: 0.6, deckle: { edges: ['top', 'bottom'], roughness: 0.4 } },\n },\n 'hero-peel': {\n meta: { name: 'Hero peel', tags: ['peel', 'card', 'hero'] },\n sheet: { width: 1.5, height: 1 },\n stock: 'photo-gloss',\n // Was a live Unsplash URL — a third-party network fetch inside one of\n // the first things anybody renders, which fails offline, behind a proxy,\n // under a strict CSP, and on the day the URL changes. The demo here is\n // the PEEL; the photograph was incidental, and a typeset card is both\n // self-contained and more on-brand for a paper library.\n content: {\n type: 'card',\n title: 'Print no. 4',\n body: 'Lift the corner.',\n note: 'Gloss, 240gsm',\n align: 'center',\n },\n behavior: { type: 'peel', progress: 0.35, corner: 'bottom-right', radius: 0.16 },\n },\n 'page-flip': {\n meta: { name: 'Page flip', tags: ['flip', 'text'] },\n sheet: { width: 1, height: 1.4 },\n stock: 'printer',\n content: {\n type: 'text',\n text: 'Chapter One\\n\\nIt was a paper town, and everything in it folded.',\n },\n behavior: { type: 'flip', progress: 0.3, spine: 'left', radius: 0.3 },\n },\n 'hanging-poster': {\n meta: { name: 'Hanging poster', tags: ['hang', 'text', 'wind'] },\n sheet: { width: 1.1, height: 1.55 },\n stock: 'printer',\n // Also de-Unsplashed. A poster is a typographic object anyway — every\n // paper installation worth the name hangs WORDS — so this shows off the\n // tracking and the optical centring rather than someone else's photo.\n content: {\n type: 'text',\n text: 'THE\\nPAPER\\nSHOW',\n size: 96,\n align: 'center',\n valign: 'center',\n tracking: 0.08,\n lineHeight: 1.15,\n },\n behavior: { type: 'hang', wind: 0.45, sag: 0.3 },\n },\n 'pinned-sheet': {\n meta: { name: 'Pinned sheet', tags: ['cloth', 'wind', 'interactive'] },\n sheet: { width: 1.2, height: 1.5 },\n stock: 'printer',\n content: {\n type: 'text',\n text: 'Grab me.\\n\\n(cloth: pinned at the top edge,\\nwind from the left)',\n size: 40,\n },\n physics: { type: 'cloth', pins: 'top-edge', wind: 0.45, stiffness: 0.8, gravity: 1, floor: -1.4 },\n },\n 'flying-note': {\n meta: { name: 'Flying note', tags: ['fly', 'tumble', 'text'] },\n sheet: { width: 1, height: 0.7 },\n stock: 'printer',\n content: {\n type: 'text',\n text: 'meet me where\\nthe paper lands',\n size: 52,\n align: 'center',\n padding: 0.16,\n },\n behavior: { type: 'fly', flutter: 0.55, curve: 0.45 },\n physics: 'tumble',\n },\n 'blank-sheet': {\n meta: { name: 'Blank sheet', tags: ['starter'] },\n stock: 'printer',\n },\n // The driving use case: one stamp of the 2×5 block. Hover peels the\n // outward-facing corner ('auto' resolves per sheet slot), pressing deepens\n // the peel; the perforation tears when it detaches (field auto-wiring).\n 'postage-stamp': {\n meta: { name: 'Postage stamp', tags: ['sticker', 'stamp', 'states', 'sheet'] },\n sheet: { width: 0.64, height: 0.78, thickness: 0.08 },\n stock: 'sticker',\n // No `src`: a stamp's art is the caller's, and the library ships no\n // assets and fetches none. The perforation, the sticker stock and the\n // peel — which is what this preset is actually here to demonstrate —\n // all read perfectly well on bare stock.\n content: { type: 'image', fit: 'cover', alt: 'A postage stamp' },\n behavior: { type: 'peel', progress: 0, corner: 'auto', radius: 0.12 },\n surface: { perforation: { edges: 'all', holeRadius: 0.014, spacing: 0.05 } },\n states: {\n initial: 'rest',\n states: {\n hover: {\n overrides: { behavior: { progress: 0.22 } },\n transition: { duration: 0.25, ease: 'power2.out' },\n },\n pressed: {\n overrides: { behavior: { progress: 0.5 } },\n transition: { duration: 0.16, ease: 'power3.out' },\n },\n // Picked is auto-choreographed at pick time (carry hanging from the\n // peeled corner); placed announces itself for a host postmark overlay.\n placed: { overrides: {}, onEnter: ['emit:postmark'] },\n },\n pickThreshold: 0.08,\n },\n },\n 'photo-print': {\n meta: { name: 'Photo print', tags: ['image', 'starter'] },\n sheet: { width: 1.2, height: 0.9 },\n stock: 'photo-gloss',\n // Same: the field starter is a CONTAINER. Its whole documented use is\n // `<PaperField images={photos} preset=\"photo-print\" />`, where the\n // photographs are the caller's.\n content: { type: 'image', fit: 'cover', alt: 'A photographic print' },\n // No print lies perfectly flat. A shade of bow is the whole difference\n // between a sheet of paper and a rectangle — and since this is the field\n // starter, it is what a layout's per-sheet bias has to scale.\n deformers: [{ type: 'bend', options: { curvature: 0.35, angle: 0 } }],\n },\n 'crumpled-note': {\n meta: { name: 'Crumpled note', tags: ['crumple', 'text', 'handled'] },\n sheet: { width: 1.1, height: 1.4 },\n stock: 'printer',\n content: {\n type: 'text',\n text: 'I wrote it out three times\\nand threw all three away.',\n size: 42,\n },\n behavior: { type: 'crumple', progress: 0.62, coarseness: 0.4, ball: 0.55 },\n // Handled paper is dirty paper: the grain is what stops the facets\n // reading as folded plastic.\n surface: { grain: 0.5, aging: 0.18 },\n },\n /**\n * The second after the fall. `fall` is a sheet still arguing with the air;\n * this one has stopped — which is the half of the story the library could\n * not tell, and the half every paper installation is actually made of.\n */\n /**\n * A strip hung the full drop of a room. Tall and narrow on purpose: the\n * proportion IS the object, and a ribbon that is not much longer than it\n * is wide is a poster.\n */\n 'paper-ribbon': {\n meta: { name: 'Paper ribbon', tags: ['ribbon', 'hang', 'text'] },\n sheet: { width: 0.85, height: 6.4 },\n stock: 'printer',\n content: {\n type: 'text',\n // Short words, set small. The measure on a 0.85-wide strip is about\n // 220px at texture resolution, and anything larger breaks mid-word —\n // a ribbon reading \"an d th e pa pe r\" is a ribbon nobody can read.\n text: 'the paper\\nkept going\\nlong after\\nthe floor\\nran out',\n size: 34,\n align: 'center',\n valign: 'center',\n lineHeight: 1.5,\n tracking: 0.02,\n },\n behavior: { type: 'ribbon', pool: 0.17, curl: 0.42, drape: 0.55 },\n surface: { grain: 0.18 },\n },\n 'settled-sheet': {\n meta: { name: 'Settled sheet', tags: ['settle', 'floor', 'text'] },\n sheet: { width: 1.2, height: 0.9 },\n stock: 'printer',\n content: {\n type: 'card',\n title: 'Found',\n body: 'on the floor, face up,\\nwhere somebody dropped it.',\n note: 'no. 31',\n },\n behavior: { type: 'settle', relax: 0.6, lift: 0.5, slack: 0.45 },\n surface: { grain: 0.2 },\n },\n 'typed-note': {\n meta: { name: 'Typed note', tags: ['text', 'starter'] },\n sheet: { width: 1, height: 1.4 },\n stock: 'printer',\n content: {\n type: 'text',\n text: 'Dear reader,\\n\\nPaper is the product. Everything else hangs off the sheet.\\n\\n— Paperlab',\n },\n },\n}\n\n/** User presets registered at runtime (the editor persists these to localStorage). */\nconst userPresets = new Map<string, PaperConfigInput>()\n\nexport function getPreset(name: string): PaperConfig {\n const raw = builtins[name] ?? userPresets.get(name)\n if (!raw) {\n throw new Error(`[paperlab] Unknown preset \"${name}\". Registered: ${listPresets().join(', ')}`)\n }\n return paperConfigSchema.parse(raw)\n}\n\n/** Register a user preset (validated). Built-in names are reserved. */\nexport function registerPreset(name: string, input: PaperConfigInput): void {\n if (name in builtins) {\n throw new Error(`[paperlab] \"${name}\" is a built-in preset — pick another name.`)\n }\n paperConfigSchema.parse(input) // fail fast on invalid configs\n userPresets.set(name, input)\n}\n\nexport function unregisterPreset(name: string): void {\n userPresets.delete(name)\n}\n\nexport function isBuiltinPreset(name: string): boolean {\n return name in builtins\n}\n\nexport function listPresets(): string[] {\n return [...Object.keys(builtins), ...userPresets.keys()]\n}\n\n/**\n * A collision-free preset name built from `base`: `base`, else `base 2`,\n * `base 3`, … The disambiguating suffix always grows from the SAME base — a\n * name derived from a synthetic base (e.g. an untitled import → \"imported\")\n * must not fall back to the original when it collides. `taken` reports whether\n * a candidate is already used (built-in or user preset).\n */\nexport function uniquePresetName(base: string, taken: (name: string) => boolean): string {\n if (!taken(base)) return base\n let n = 2\n let name = `${base} ${n}`\n while (taken(name)) name = `${base} ${++n}`\n return name\n}\n","import * as THREE from 'three'\nimport { useEffect, useState } from 'react'\nimport type { BackContentConfig, ContentConfig, SheetConfig } from '../config/schema'\nimport type { Stock } from '../core/stock'\nimport { paintReceipt } from './receipt'\nimport { paintCard } from './card'\nimport { paintWash } from './wash'\nimport { ensureFont, wrapLines } from './type'\n\n/**\n * All content is composited onto a canvas and applied as a texture — content\n * deforms with the mesh because the mesh deforms, never a 2D trick.\n * Long edge = 1024 logical px × DPR 2 so text stays crisp when curled.\n */\nconst LONG_EDGE = 1024\nconst DPR = 2\n\nexport function contentCanvasSize(sheet: SheetConfig): [number, number] {\n const long = Math.max(sheet.width, sheet.height)\n const w = Math.round((sheet.width / long) * LONG_EDGE * DPR)\n const h = Math.round((sheet.height / long) * LONG_EDGE * DPR)\n return [w, h]\n}\n\nfunction paintBackground(ctx: CanvasRenderingContext2D, w: number, h: number, stock: Stock) {\n ctx.fillStyle = stock.color\n ctx.fillRect(0, 0, w, h)\n}\n\nfunction paintImage(\n ctx: CanvasRenderingContext2D,\n w: number,\n h: number,\n img: HTMLImageElement,\n fit: 'cover' | 'contain',\n) {\n const scale =\n fit === 'cover' ? Math.max(w / img.width, h / img.height) : Math.min(w / img.width, h / img.height)\n const dw = img.width * scale\n const dh = img.height * scale\n ctx.drawImage(img, (w - dw) / 2, (h - dh) / 2, dw, dh)\n}\n\nfunction paintText(\n ctx: CanvasRenderingContext2D,\n w: number,\n h: number,\n content: Extract<ContentConfig, { type: 'text' }>,\n stock: Stock,\n) {\n const size = content.size * DPR\n const pad = content.padding * Math.min(w, h)\n const font = `${content.weight} ${size}px ${content.font}`\n ctx.font = font\n ctx.fillStyle = content.color === '#2b2620' ? stock.inkColor : content.color\n ctx.textBaseline = 'top'\n ctx.textAlign = content.align\n // Tracking is set before measuring, not after: `measureText` honours\n // `letterSpacing`, so wrapping against the untracked width would break\n // lines to a measure the painted line does not have.\n ctx.letterSpacing = `${content.tracking}em`\n\n const maxWidth = w - pad * 2\n const x = content.align === 'left' ? pad : content.align === 'right' ? w - pad : w / 2\n const lineStep = size * content.lineHeight\n\n const lines = wrapLines(ctx, content.text, maxWidth, font)\n // Re-assert: wrapLines restores the font it was handed, which drops the\n // spacing the measure was taken with.\n ctx.font = font\n ctx.letterSpacing = `${content.tracking}em`\n\n // `center` optically centres the whole block rather than hanging it from\n // the top edge — what a label or a poster wants, where `top` is what a\n // letter wants because a letter starts at the top of the page.\n const block = lines.length * lineStep\n let y = content.valign === 'center' ? Math.max(pad, (h - block) / 2) : pad\n\n for (const line of lines) {\n if (y > h - pad) break\n ctx.fillText(line, x, y)\n y += lineStep\n }\n ctx.letterSpacing = '0em'\n}\n\n/**\n * Render content to a canvas. Synchronous — image content needs a decoded\n * HTMLImageElement passed in (the hook below handles loading).\n */\nexport function renderContentToCanvas(\n content: ContentConfig | BackContentConfig,\n sheet: SheetConfig,\n stock: Stock,\n image?: HTMLImageElement,\n): HTMLCanvasElement {\n const [w, h] = contentCanvasSize(sheet)\n const canvas = document.createElement('canvas')\n canvas.width = w\n canvas.height = h\n const ctx = canvas.getContext('2d')!\n paintBackground(ctx, w, h, stock)\n // Under everything the sheet carries, and over the stock. A wash is a\n // ground: the letter is written on it, not beside it.\n if (content.wash) paintWash(ctx, w, h, content.wash)\n if (content.type === 'image' && image && content.src) paintImage(ctx, w, h, image, content.fit)\n if (content.type === 'text') paintText(ctx, w, h, content, stock)\n if (content.type === 'receipt') paintReceipt(ctx, w, h, content, stock)\n if (content.type === 'card') paintCard(ctx, w, h, content, stock, DPR)\n return canvas\n}\n\nfunction makeTexture(canvas: HTMLCanvasElement): THREE.CanvasTexture {\n const tex = new THREE.CanvasTexture(canvas)\n tex.colorSpace = THREE.SRGBColorSpace\n tex.anisotropy = 8\n tex.generateMipmaps = true\n return tex\n}\n\n/**\n * React hook: content config → texture. Re-renders only on content change,\n * never per-frame. Waits for image decode / document.fonts.ready.\n */\nexport function useContentTexture(\n content: ContentConfig | BackContentConfig | undefined,\n sheet: SheetConfig,\n stock: Stock,\n): THREE.CanvasTexture | null {\n const [texture, setTexture] = useState<THREE.CanvasTexture | null>(null)\n const key = JSON.stringify({ content: content ?? null, w: sheet.width, h: sheet.height, stock: stock.id })\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: key serializes the content, sheet and stock the canvas draws from.\n useEffect(() => {\n let disposed = false\n let tex: THREE.CanvasTexture | null = null\n\n if (!content) {\n setTexture(null)\n return\n }\n\n const commit = (canvas: HTMLCanvasElement) => {\n if (disposed) return\n tex = makeTexture(canvas)\n setTexture(tex)\n }\n\n if (content.type === 'image' && content.src) {\n const img = new Image()\n img.crossOrigin = 'anonymous'\n img.onload = () => commit(renderContentToCanvas(content, sheet, stock, img))\n // A URL that never loads must not leave the sheet textureless — it\n // still has stock, and bare stock is the honest picture of \"no image\".\n img.onerror = () => commit(renderContentToCanvas(content, sheet, stock))\n img.src = content.src\n } else if (content.type === 'text' || content.type === 'card') {\n // Ask for the face BY NAME. `document.fonts.ready` alone only waits for\n // what the document already requested, and a family named inside a\n // canvas font string was never requested by anything — so on a page\n // with no DOM element using it, `ready` resolves at once and the sheet\n // paints in the fallback.\n void ensureFont(content.font, content.size * DPR).then(() =>\n commit(renderContentToCanvas(content, sheet, stock)),\n )\n } else if (content.type === 'receipt') {\n document.fonts.ready.then(() => commit(renderContentToCanvas(content, sheet, stock)))\n } else {\n commit(renderContentToCanvas(content, sheet, stock))\n }\n\n return () => {\n disposed = true\n tex?.dispose()\n }\n }, [key])\n\n return texture\n}\n","import type { ContentConfig } from '../config/schema'\nimport type { Stock } from '../core/stock'\n\nexport type ReceiptContent = Extract<ContentConfig, { type: 'receipt' }>\n\nexport interface ReceiptTotals {\n subtotal: number\n tax: number\n total: number\n}\n\nexport function receiptTotals(content: ReceiptContent): ReceiptTotals {\n const subtotal = content.items.reduce((sum, item) => sum + item.price, 0)\n const tax = subtotal * content.taxRate\n return { subtotal, tax, total: subtotal + tax }\n}\n\n/** Deterministic bar widths from a string — stylized Code-128 look. */\nexport function barcodeBars(seed: string): number[] {\n // Not a scannable Code 128 (real encoding tracked for later) — but the\n // start/stop guard structure and 1–4 module widths match the real thing.\n let h = 2166136261\n for (let i = 0; i < seed.length; i++) {\n h ^= seed.charCodeAt(i)\n h = Math.imul(h, 16777619)\n }\n const bars: number[] = [2, 1, 1, 4] // start guard\n for (let i = 0; i < 30; i++) {\n h = Math.imul(h ^ (h >>> 15), 2246822519)\n bars.push(1 + (Math.abs(h) % 4))\n }\n bars.push(2, 3, 3, 1, 1, 2) // stop guard\n return bars\n}\n\nconst money = (v: number) => v.toFixed(2)\n\n/**\n * The procedural receipt: store header, line items, totals, barcode,\n * timestamp, footer. Pairs with `deckle: { edges: ['bottom'] }` for the\n * jagged thermal tear. One-liner meme potential by design.\n */\nexport function paintReceipt(\n ctx: CanvasRenderingContext2D,\n w: number,\n h: number,\n content: ReceiptContent,\n stock: Stock,\n): void {\n const ink = stock.inkColor\n const pad = w * 0.09\n const colWidth = w - pad * 2\n const base = Math.round(w / 15) // font size scales with receipt width\n const mono = (size: number, weight = 400) => `${weight} ${size}px ui-monospace, Menlo, Consolas, monospace`\n\n let y = h * 0.045\n const line = (step = 1.6) => (y += base * step)\n\n const center = (text: string, size = base, weight = 400) => {\n ctx.font = mono(size, weight)\n ctx.textAlign = 'center'\n ctx.fillText(text, w / 2, y)\n }\n const row = (left: string, right: string, size = base) => {\n ctx.font = mono(size)\n ctx.textAlign = 'left'\n ctx.fillText(left, pad, y)\n ctx.textAlign = 'right'\n ctx.fillText(right, w - pad, y)\n }\n const divider = () => {\n ctx.font = mono(base)\n ctx.textAlign = 'center'\n ctx.fillText('- '.repeat(Math.floor(colWidth / (base * 1.1))).trim(), w / 2, y)\n }\n\n ctx.fillStyle = ink\n ctx.textBaseline = 'top'\n\n center(content.store.toUpperCase(), base * 1.5, 700)\n line(2.4)\n center(content.address.toUpperCase())\n line(1.8)\n divider()\n line(1.8)\n\n for (const item of content.items) {\n row(item.name.toUpperCase(), money(item.price))\n line()\n }\n line(0.4)\n divider()\n line(1.8)\n\n const totals = receiptTotals(content)\n row('SUBTOTAL', money(totals.subtotal))\n line()\n row(`TAX ${(content.taxRate * 100).toFixed(0)}%`, money(totals.tax))\n line()\n row('TOTAL', money(totals.total), base * 1.15)\n line(2)\n\n center(content.timestamp ?? new Date().toLocaleString('en-GB'), base * 0.9)\n line(2.2)\n\n if (content.barcode) {\n const bars = barcodeBars(content.store)\n const modules = bars.reduce((a, b) => a + b, 0)\n const module = (colWidth * 0.85) / modules\n const barH = base * 3.2\n let x = (w - modules * module) / 2\n bars.forEach((width, i) => {\n if (i % 2 === 0) ctx.fillRect(x, y, width * module, barH)\n x += width * module\n })\n y += barH\n line(1.8)\n }\n\n center(content.footer.toUpperCase(), base * 0.9)\n}\n","/**\n * Line breaking, shared by every content type that sets prose.\n *\n * It lives on its own because `paintText` and `paintCard` were about to\n * carry two copies of it, and two copies of a line-breaker is two answers to\n * \"where does this wrap\" — which on a sheet that CURLS is not a cosmetic\n * disagreement: the reader sees the break land on a fold.\n */\n\n/**\n * Wrap a paragraph to a measure, breaking a word that cannot fit on its own.\n *\n * The last clause is the part the old loop got wrong. It appended a word\n * whenever the line was empty, on the reasonable theory that one word always\n * fits — but a long URL or a compound on a narrow banner does not, and it\n * ran off the edge of the sheet with nothing to stop it. A sheet is a\n * physical object: type that leaves it has left it.\n */\nexport function wrapLines(\n ctx: CanvasRenderingContext2D,\n text: string,\n maxWidth: number,\n font: string,\n): string[] {\n const previous = ctx.font\n ctx.font = font\n const out: string[] = []\n\n for (const paragraph of text.split('\\n')) {\n if (paragraph.trim() === '') {\n // An empty line is a paragraph break, and it should survive as one.\n out.push('')\n continue\n }\n let line = ''\n for (const word of paragraph.split(/\\s+/).filter(Boolean)) {\n const attempt = line ? `${line} ${word}` : word\n if (line && ctx.measureText(attempt).width > maxWidth) {\n out.push(line)\n line = word\n } else {\n line = attempt\n }\n // The word itself is wider than the measure: break it rather than\n // let it hang off the sheet.\n while (ctx.measureText(line).width > maxWidth && line.length > 1) {\n let cut = line.length - 1\n while (cut > 1 && ctx.measureText(line.slice(0, cut)).width > maxWidth) cut--\n out.push(line.slice(0, cut))\n line = line.slice(cut)\n }\n }\n if (line) out.push(line)\n }\n\n ctx.font = previous\n return out\n}\n\n/**\n * Ask the browser to actually load the face before painting with it.\n *\n * `document.fonts.ready` — which this library already awaited — resolves\n * when the fonts the DOCUMENT has requested have settled. A face named only\n * inside a canvas `ctx.font` string was never requested by anything, so on a\n * page where no DOM element uses it `ready` resolves immediately and the\n * canvas paints in the fallback. The sheet then renders in Times while the\n * preset says Playfair, silently and only sometimes, which is the worst\n * shape a bug can have.\n *\n * `fonts.load()` is the request. Failures are swallowed on purpose: a font\n * that will not load is a fallback, not an exception, and a sheet that\n * refuses to render is worse than one set in the wrong face.\n */\nexport async function ensureFont(font: string, size: number): Promise<void> {\n if (typeof document === 'undefined' || !document.fonts) return\n try {\n await document.fonts.load(`${size}px ${font}`)\n } catch {\n // Unparseable family list, or a face the browser will not fetch.\n }\n try {\n await document.fonts.ready\n } catch {\n // Ignored for the same reason.\n }\n}\n","import type { ContentConfig } from '../config/schema'\nimport type { Stock } from '../core/stock'\nimport { wrapLines } from './type'\n\nexport type CardContent = Extract<ContentConfig, { type: 'card' }>\n\n/**\n * The card: a tracked label, a rule, a body, and a line of small print.\n *\n * Held to the receipt's standard rather than the text block's, which is the\n * whole reason it exists. The receipt is the only content type in this\n * library anybody art-directed — it knows what a dashed rule is, what a\n * barcode looks like, and that a total belongs at the bottom — and\n * everything else went through one `fillText` loop in the system serif.\n *\n * The proportions below are the composition, and they are ratios of the body\n * size rather than numbers, so a card scales as a card instead of as a\n * paragraph that grew.\n */\n\n/** Title sits well under the body: it is a label, not a heading. */\nconst TITLE_RATIO = 0.52\n/** Small print smaller still, and the two are deliberately different sizes. */\nconst NOTE_RATIO = 0.46\n/** Tracking for the title. Uppercase at small sizes closes up without it. */\nconst TITLE_TRACKING = 0.16\nconst NOTE_TRACKING = 0.06\n\nexport function paintCard(\n ctx: CanvasRenderingContext2D,\n w: number,\n h: number,\n content: CardContent,\n stock: Stock,\n dpr: number,\n): void {\n const ink = content.color === '#2b2620' ? stock.inkColor : content.color\n const size = content.size * dpr\n const pad = content.padding * Math.min(w, h)\n const maxWidth = w - pad * 2\n const x = content.align === 'center' ? w / 2 : pad\n ctx.textAlign = content.align === 'center' ? 'center' : 'left'\n ctx.textBaseline = 'alphabetic'\n\n const titleSize = size * TITLE_RATIO\n const noteSize = size * NOTE_RATIO\n const bodyStep = size * 1.35\n\n // Measure the whole composition before drawing any of it, so the block can\n // be centred in the card. A card whose type is hung from the top edge\n // reads as a page that got cut off rather than as a card.\n const bodyLines = content.body ? wrapLines(ctx, content.body, maxWidth, `${size}px ${content.font}`) : []\n const titleBlock = content.title ? titleSize * 1.9 : 0\n const ruleBlock = content.rule && content.title ? titleSize * 0.9 : 0\n const noteBlock = content.note ? noteSize * 2.4 : 0\n const bodyBlock = bodyLines.length * bodyStep\n const total = titleBlock + ruleBlock + bodyBlock + noteBlock\n\n let y = Math.max(pad, (h - total) / 2) + size * 0.9\n\n if (content.title) {\n ctx.font = `${titleSize}px ${content.font}`\n ctx.letterSpacing = `${TITLE_TRACKING}em`\n ctx.fillStyle = ink\n ctx.globalAlpha = 0.72\n ctx.fillText(content.title.toUpperCase(), x, y - size * 0.5)\n ctx.globalAlpha = 1\n ctx.letterSpacing = '0em'\n y += titleBlock - size * 0.5\n\n if (content.rule) {\n // A hairline, not a border: it separates, it does not enclose.\n ctx.save()\n ctx.strokeStyle = ink\n ctx.globalAlpha = 0.28\n ctx.lineWidth = Math.max(1, dpr * 0.75)\n ctx.beginPath()\n ctx.moveTo(content.align === 'center' ? w / 2 - maxWidth / 2 : pad, y - titleSize * 0.5)\n ctx.lineTo(content.align === 'center' ? w / 2 + maxWidth / 2 : pad + maxWidth, y - titleSize * 0.5)\n ctx.stroke()\n ctx.restore()\n y += ruleBlock\n }\n }\n\n if (content.ruled && bodyLines.length > 0) {\n // Writing lines, drawn UNDER the type and in the stock's own ink at low\n // alpha, so they read as printed on the card rather than as underlines\n // on the words.\n ctx.save()\n ctx.strokeStyle = ink\n ctx.globalAlpha = 0.14\n ctx.lineWidth = Math.max(1, dpr * 0.6)\n for (let i = 0; i < bodyLines.length; i++) {\n const lineY = y + i * bodyStep + size * 0.28\n ctx.beginPath()\n ctx.moveTo(pad, lineY)\n ctx.lineTo(pad + maxWidth, lineY)\n ctx.stroke()\n }\n ctx.restore()\n }\n\n ctx.font = `${size}px ${content.font}`\n ctx.fillStyle = ink\n for (const line of bodyLines) {\n if (y > h - pad) break\n ctx.fillText(line, x, y)\n y += bodyStep\n }\n\n if (content.note) {\n ctx.font = `${noteSize}px ${content.font}`\n ctx.letterSpacing = `${NOTE_TRACKING}em`\n ctx.globalAlpha = 0.6\n ctx.fillText(content.note, x, Math.min(y + noteSize * 1.4, h - pad))\n ctx.globalAlpha = 1\n ctx.letterSpacing = '0em'\n }\n}\n","import type { WashConfig } from '../config/schema'\n\n/**\n * Painting a watercolour wash.\n *\n * Five things separate watercolour from a soft gradient, and this paints\n * four of them deliberately. In the order they matter:\n *\n * 1. **Edge darkening.** Pigment migrates to the boundary of a pool as the\n * water retreats and dries there in a ring. It is the signature of the\n * medium — without it any amount of blur reads as an airbrush — and it is\n * the one effect a radial gradient cannot fake, because the ring follows\n * the pool's own irregular outline rather than a circle.\n * 2. **An irregular wet edge.** A pool is not a disc. Its outline is a few\n * low harmonics riding on a radius, which is what makes lobes rather than\n * the even scallops a single frequency gives.\n * 3. **Glazing.** Two washes over each other are darker than either, and a\n * different hue from both. `multiply` is not a stylistic choice here; it\n * is what transparent pigment over transparent pigment does.\n * 4. **Granulation.** Heavy pigment settles into the tooth of the paper and\n * leaves it speckled. Confined to where there IS pigment — speckling the\n * whole sheet would be a dirty scan, not a granulating wash.\n *\n * The fifth is the paper, and this file does not paint it: the wash goes on\n * over the stock's own colour, and the surface shader's grain and aging run\n * later over everything. That ordering is the point of washing UNDER the\n * content rather than compositing a picture on top of it.\n */\n\n/**\n * Deterministic PRNG, so a seed paints the same wash forever.\n *\n * A preset that repainted itself differently on every mount would be a\n * different artwork each time the component remounted, and no screenshot,\n * share link or export would agree with any other.\n */\nfunction mulberry32(seed: number): () => number {\n let a = seed * 0x6d2b79f5 + 0x9e3779b9\n return () => {\n a |= 0\n a = (a + 0x6d2b79f5) | 0\n let t = Math.imul(a ^ (a >>> 15), 1 | a)\n t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296\n }\n}\n\n/** `#rrggbb` → `rgba(r, g, b, alpha)`. Anything unparseable paints as grey. */\nfunction rgba(hex: string, alpha: number): string {\n const m = /^#?([0-9a-f]{6})$/i.exec(hex.trim())\n const n = m ? Number.parseInt(m[1]!, 16) : 0x808080\n return `rgba(${(n >> 16) & 255}, ${(n >> 8) & 255}, ${n & 255}, ${Math.max(0, Math.min(1, alpha))})`\n}\n\n/**\n * A pool's outline, as three harmonics on a radius.\n *\n * Two would read as an ellipse and one gives a flower; three is where it\n * stops looking generated.\n *\n * Drawn from a shape decided ONCE per pool rather than from the generator,\n * because the fill, the dried edge and the granulation clip are three passes\n * over the SAME pool. Re-rolling the outline for each of them was drawing a\n * rim that belonged to a different shape than the one it was supposed to be\n * the rim of — which is why the first version had thin wandering lines\n * across it that read as pen, not pigment.\n */\ninterface BloomShape {\n phase: [number, number, number]\n amp: [number, number, number]\n}\n\nfunction bloomShape(rng: () => number): BloomShape {\n return {\n phase: [rng() * Math.PI * 2, rng() * Math.PI * 2, rng() * Math.PI * 2],\n amp: [0.18 + rng() * 0.1, 0.09 + rng() * 0.06, 0.05 + rng() * 0.04],\n }\n}\n\n/**\n * The outline, or an arc of it.\n *\n * `from`/`to` are turns, 0..1. A whole pool is one closed path; its dried\n * edge is drawn as several arcs instead, because pigment does not dry evenly\n * all the way round — a pool that sat against a tilt leaves a heavy rim on\n * one side and almost none on the other, and a rim of uniform weight is the\n * tell that a wash was generated rather than painted.\n */\nfunction bloomPath(\n ctx: CanvasRenderingContext2D,\n cx: number,\n cy: number,\n radius: number,\n shape: BloomShape,\n from = 0,\n to = 1,\n): void {\n const { phase, amp } = shape\n const STEPS = Math.max(6, Math.round(72 * (to - from)))\n ctx.beginPath()\n for (let i = 0; i <= STEPS; i++) {\n const t = (from + ((to - from) * i) / STEPS) * Math.PI * 2\n const wobble =\n amp[0]! * Math.sin(2 * t + phase[0]!) +\n amp[1]! * Math.sin(3 * t + phase[1]!) +\n amp[2]! * Math.sin(5 * t + phase[2]!)\n const r = radius * (1 + wobble)\n const x = cx + Math.cos(t) * r\n const y = cy + Math.sin(t) * r\n if (i === 0) ctx.moveTo(x, y)\n else ctx.lineTo(x, y)\n }\n if (from === 0 && to === 1) ctx.closePath()\n}\n\n/**\n * Whether this canvas can blur.\n *\n * `ctx.filter` is how the wet edge is made, and where it is missing every\n * pool would come out cut with scissors. Detected rather than assumed\n * because the answer differs between a browser and a headless canvas, and a\n * wash is not worth throwing a render away over: without it the fill still\n * lands, just harder-edged.\n */\nfunction canBlur(ctx: CanvasRenderingContext2D): boolean {\n if (!('filter' in ctx)) return false\n const before = ctx.filter\n try {\n ctx.filter = 'blur(2px)'\n const worked = ctx.filter !== 'none' && ctx.filter !== before\n ctx.filter = before\n return worked\n } catch {\n return false\n }\n}\n\nexport function paintWash(ctx: CanvasRenderingContext2D, w: number, h: number, wash: WashConfig): void {\n const rng = mulberry32(wash.seed + 1)\n const short = Math.min(w, h)\n const blurs = canBlur(ctx)\n\n ctx.save()\n // Transparent pigment over transparent pigment. Two pools crossing are\n // darker than either and a third hue; on the stock alone a pool tints the\n // paper rather than covering it.\n ctx.globalCompositeOperation = 'multiply'\n\n for (let i = 0; i < wash.blooms; i++) {\n const pigment = i % 2 === 0 ? wash.color : wash.secondary\n // Pools are allowed off the edge. A wash that stops politely inside the\n // sheet reads as a printed shape; one that runs off it reads as paint.\n const cx = (rng() * 1.5 - 0.25) * w\n const cy = (rng() * 1.5 - 0.25) * h\n const radius = short * wash.spread * (0.28 + rng() * 0.34)\n const alpha = wash.intensity * (0.35 + rng() * 0.4)\n\n // Decided before any pass draws, so all three describe one pool.\n const shape = bloomShape(rng)\n\n ctx.save()\n if (blurs) ctx.filter = `blur(${(2 + wash.bleed * 26) * (0.6 + rng() * 0.8)}px)`\n\n // The body of the pool. The gradient's centre is offset from the shape's,\n // because water pools to one side as it dries rather than evenly.\n const gx = cx + (rng() - 0.5) * radius * 0.5\n const gy = cy + (rng() - 0.5) * radius * 0.5\n const grad = ctx.createRadialGradient(gx, gy, radius * 0.05, gx, gy, radius * 1.15)\n grad.addColorStop(0, rgba(pigment, alpha * 0.55))\n grad.addColorStop(0.62, rgba(pigment, alpha))\n grad.addColorStop(1, rgba(pigment, alpha * 0.75))\n ctx.fillStyle = grad\n bloomPath(ctx, cx, cy, radius, shape)\n ctx.fill()\n\n // The dried edge, following the pool's OWN outline rather than a circle,\n // and unevenly — heavy on one side, nearly absent on another.\n if (wash.edge > 0) {\n if (blurs) ctx.filter = `blur(${(1.5 + wash.bleed * 9) * (0.6 + rng() * 0.6)}px)`\n ctx.lineWidth = Math.max(1, radius * (0.03 + wash.edge * 0.05))\n const arcs = 5\n // Arcs overlap slightly so the seams between them do not read as gaps.\n const overlap = 0.4 / arcs\n for (let a = 0; a < arcs; a++) {\n ctx.strokeStyle = rgba(pigment, alpha * wash.edge * (0.15 + rng() * 1.05))\n bloomPath(ctx, cx, cy, radius, shape, a / arcs, (a + 1) / arcs + overlap)\n ctx.stroke()\n }\n }\n ctx.restore()\n\n // Pigment in the tooth of the paper, kept inside the pool it settled out\n // of. Speckling the whole sheet would be a dirty scan, not granulation.\n if (wash.granulation > 0) {\n ctx.save()\n bloomPath(ctx, cx, cy, radius, shape)\n ctx.clip()\n const grains = Math.round(wash.granulation * 900)\n ctx.fillStyle = rgba(pigment, wash.granulation * alpha * 0.5)\n for (let g = 0; g < grains; g++) {\n const a = rng() * Math.PI * 2\n // sqrt keeps the scatter even across the disc instead of crowding\n // the centre, which is where a uniform radius puts everything.\n const d = Math.sqrt(rng()) * radius\n const size = 1 + rng() * (short * 0.004)\n ctx.fillRect(cx + Math.cos(a) * d, cy + Math.sin(a) * d, size, size)\n }\n ctx.restore()\n }\n }\n\n ctx.restore()\n}\n","import * as THREE from 'three'\nimport { computeSheetNormals } from '../core/normals'\nimport { axialSegments, type SegmentPair } from '../core/tessellation'\nimport type { AnyOptions, Deformer, DeformerContext, DeformerInstance, SheetDims } from './types'\nimport { getDeformer } from './registry'\n\n// Preallocated scratch — deformer loops are allocation-free.\nconst scratchPos = new THREE.Vector3()\nconst scratchUv = new THREE.Vector2()\n\n/**\n * The resolved stack, reused across frames: two parallel arrays rather than a\n * list of objects, refilled in place. `applyDeformerStack` runs every frame\n * for any animated sheet, and a `filter()` plus a registry lookup per vertex\n * is a per-frame allocation and 16k map probes for an answer that only\n * changes when the stack does.\n */\nconst activeFns: ((out: THREE.Vector3, uv: THREE.Vector2, o: AnyOptions, ctx: DeformerContext) => void)[] = []\nconst activeOptions: AnyOptions[] = []\n\n/**\n * Run an ordered deformer stack over a sheet geometry: each vertex starts\n * from its flat base position and flows through every enabled deformer in\n * order. Writes positions in place and recomputes normals.\n */\nexport function applyDeformerStack(\n geometry: THREE.BufferGeometry,\n basePositions: Float32Array,\n stack: DeformerInstance[],\n ctx: DeformerContext,\n): void {\n const position = geometry.attributes.position as THREE.BufferAttribute\n const uv = geometry.attributes.uv as THREE.BufferAttribute\n const array = position.array as Float32Array\n const uvArray = uv.array as Float32Array\n const count = position.count\n\n activeFns.length = 0\n activeOptions.length = 0\n for (const instance of stack) {\n if (instance.enabled === false) continue\n activeFns.push(getDeformer(instance.type).displace)\n activeOptions.push(instance.options)\n }\n\n // One deformer over every vertex, then the next — rather than every\n // deformer over one vertex, then the next. A deformer only ever reads and\n // writes the vertex it was handed, so sweeping the sheet per deformer is\n // the same composition in a different order, and it puts ONE function\n // behind the inner call site instead of the whole stack. It also costs an\n // extra pass over the position array per deformer, which is sequential and\n // measures as nothing beside what the call site buys.\n array.set(basePositions)\n for (let k = 0; k < activeFns.length; k++) {\n const displace = activeFns[k]!\n const options = activeOptions[k]\n for (let v = 0; v < count; v++) {\n const i3 = v * 3\n const i2 = v * 2\n scratchPos.set(array[i3]!, array[i3 + 1]!, array[i3 + 2]!)\n scratchUv.set(uvArray[i2]!, uvArray[i2 + 1]!)\n displace(scratchPos, scratchUv, options, ctx)\n array[i3] = scratchPos.x\n array[i3 + 1] = scratchPos.y\n array[i3 + 2] = scratchPos.z\n }\n }\n\n position.needsUpdate = true\n computeSheetNormals(geometry)\n}\n\n/** A single point through the stack — used for handle anchors and tests. */\nexport function displacePoint(\n point: THREE.Vector3,\n uvX: number,\n uvY: number,\n stack: DeformerInstance[],\n ctx: DeformerContext,\n): THREE.Vector3 {\n scratchUv.set(uvX, uvY)\n for (const instance of stack) {\n if (instance.enabled === false) continue\n getDeformer(instance.type).displace(point, scratchUv, instance.options, ctx)\n }\n return point\n}\n\n/**\n * The densest grid any deformer in the stack REQUIRES to work at all, per\n * axis — the componentwise max of every entry's floor projected onto the\n * sheet's own X and Y by the direction that entry curves in.\n */\nexport function stackMinSegments(stack: DeformerInstance[], sheet: SheetDims): SegmentPair {\n const out: SegmentPair = [2, 2]\n for (const instance of stack) {\n const deformer = getDeformer(instance.type)\n const floor = deformer.geometry?.minSegments\n if (!floor) continue\n take(out, deformer, instance.options, sheet, floor)\n }\n return out\n}\n\n/**\n * The densest grid any deformer in the stack WANTS, given the options it is\n * actually carrying — what `segments: 'auto'` resolves to, per axis.\n *\n * Disabled instances are skipped, exactly as `applyDeformerStack` skips them:\n * a deformer that is not displacing anything has no opinion about the grid.\n * (`stackMinSegments` does not skip them, and that difference is deliberate —\n * a floor is about what the stack could do, a target about what it is doing.)\n *\n * A deformer with no `autoSegments` falls back to its floor, which is the\n * right answer for one whose cost does not move with its options.\n */\nexport function stackAutoSegments(stack: DeformerInstance[], sheet: SheetDims): SegmentPair {\n const out: SegmentPair = [0, 0]\n for (const instance of stack) {\n if (instance.enabled === false) continue\n const deformer = getDeformer(instance.type)\n const geometry = deformer.geometry\n if (!geometry) continue\n const want = geometry.autoSegments\n ? geometry.autoSegments(instance.options, sheet)\n : (geometry.minSegments ?? 0)\n take(out, deformer, instance.options, sheet, want)\n }\n return out\n}\n\n/** Project one demand onto the two axes and keep it if it raises either. */\nfunction take(\n out: SegmentPair,\n deformer: Deformer<AnyOptions>,\n options: AnyOptions,\n sheet: SheetDims,\n demand: number,\n): void {\n // A community deformer whose `axis` cannot answer for these options — or\n // one that has none — falls back to spreading the demand over both axes,\n // which is the conservative half of the choice: it over-subdivides rather\n // than under-subdividing something that is actually bending.\n const declared = deformer.geometry?.axis?.(options, sheet)\n const angle = typeof declared === 'number' && Number.isFinite(declared) ? declared : null\n const [x, y] = axialSegments(sheet, angle, demand)\n if (x > out[0]) out[0] = x\n if (y > out[1]) out[1] = y\n}\n","import { z } from 'zod'\nimport type { AnyOptions, Deformer, DeformerInstance } from './types'\nimport { roll } from './roll'\nimport { curl } from './curl'\nimport { bend } from './bend'\nimport { fold } from './fold'\nimport { wave } from './wave'\nimport { drape } from './drape'\nimport { crumple } from './crumple'\n\nconst registry = new Map<string, Deformer<AnyOptions>>()\n\n/** Community deformers register here; built-ins are pre-registered. */\nexport function registerDeformer(deformer: Deformer<AnyOptions>): void {\n registry.set(deformer.id, deformer)\n}\n\nexport function getDeformer(id: string): Deformer<AnyOptions> {\n const d = registry.get(id)\n if (!d) {\n throw new Error(`[paperlab] Unknown deformer \"${id}\". Registered: ${[...registry.keys()].join(', ')}`)\n }\n return d\n}\n\nexport function listDeformers(): string[] {\n return [...registry.keys()]\n}\n\nregisterDeformer(roll)\nregisterDeformer(curl)\nregisterDeformer(bend)\nregisterDeformer(fold)\nregisterDeformer(wave)\nregisterDeformer(drape)\nregisterDeformer(crumple)\n\n/**\n * Resolve a raw `deformers` stack — the Advanced fork of a behavior — into\n * instances safe to render.\n *\n * The escape hatch used to pass its options straight through, so a preset\n * naming an option that doesn't exist (`frequency` where wave wants\n * `wavelength`) reached the GLSL builder as `undefined` and died there with\n * a message about `.length`, or reached the CPU path and quietly produced\n * NaN vertices. Parsing through each deformer's own schema turns that into\n * the validation error it always was, and fills in defaults for whatever a\n * hand-written preset left out.\n *\n * Disabled entries keep their slot: the GLSL uniform namespace is indexed by\n * position, so dropping one here would rename every uniform after it.\n */\nexport function resolveDeformerStack(\n raw: { type: string; options?: Record<string, unknown>; enabled?: boolean }[],\n): DeformerInstance[] {\n return raw.map((instance, i) => {\n const deformer = getDeformer(instance.type)\n // Strict: an unknown key here is almost always a typo for a real option,\n // and silently dropping it means the preset renders wrong with no clue\n // why. Every built-in schema is a plain object; anything exotic a\n // community deformer brings is parsed as it comes.\n const schema =\n deformer.optionsSchema instanceof z.ZodObject ? deformer.optionsSchema.strict() : deformer.optionsSchema\n const parsed = schema.safeParse(instance.options ?? {})\n if (!parsed.success) {\n const issue = parsed.error.issues[0]\n throw new Error(\n `[paperlab] deformers[${i}] (\"${instance.type}\"): ${\n issue ? `${issue.path.join('.') || 'options'} — ${issue.message}` : 'invalid options'\n }`,\n )\n }\n return {\n type: instance.type,\n options: parsed.data as Record<string, unknown>,\n enabled: instance.enabled,\n }\n })\n}\n\n/** True if any enabled instance re-deforms every frame (wave etc.). */\nexport function stackIsAnimated(stack: { type: string; enabled?: boolean }[]): boolean {\n return stack.some((i) => i.enabled !== false && registry.get(i.type)?.animated)\n}\n","import { z } from 'zod'\nimport type { Deformer } from './types'\nimport { segmentsForArc, spanAlong } from '../core/tessellation'\n\nexport const bendOptionsSchema = z.object({\n /** 1/radius in world units; sign flips the arc direction. 0 = flat. */\n curvature: z.number().min(-4).max(4).default(0.6),\n /** Bend axis direction in the sheet plane, degrees. 0 bends across x. */\n angle: z.number().min(-360).max(360).default(0),\n})\n\nexport type BendOptions = z.infer<typeof bendOptionsSchema>\n\nconst DEG = Math.PI / 180\nconst EPS = 1e-5\n\n/**\n * `sin(x) − x`, without the cancellation that eats it for small x.\n *\n * The arc's in-plane shift is `r·sin θ − d`, and `d` IS `r·θ` — so for a\n * gentle bend it is a difference of two nearly-equal large numbers, and the\n * answer is the few bits that survive. JS computes that in float64 and gets\n * away with it; the GLSL twin computes it in float32 and does not, which put\n * the two paths 6e-4 apart at low curvature — past the parity gate's epsilon.\n * The series is exact to well under a float32 ulp below |x| = 1 and both\n * implementations take the same branch, so the two paths agree by\n * construction rather than by luck.\n */\nfunction sinMinusX(x: number): number {\n if (Math.abs(x) > 1) return Math.sin(x) - x\n const x2 = x * x\n return ((-x * x2) / 6) * (1 - (x2 / 20) * (1 - (x2 / 42) * (1 - x2 / 72)))\n}\n\n/**\n * Gentle global arc around a cylinder centered on the sheet — a standing\n * paper's lean. Arc-length preserving, like roll, but symmetric about the\n * center instead of one-sided.\n *\n * Written in its cancellation-free form throughout: `r(1 − cos θ)` is\n * `2r·sin²(θ/2)`, and the in-plane shift goes through `sinMinusX`. Same arc,\n * same numbers to sixteen places — it is only the float32 half that could\n * tell the difference, and that is exactly the half the parity gate checks.\n */\nexport const bend: Deformer<BendOptions> = {\n id: 'bend',\n label: 'Bend',\n defaults: bendOptionsSchema.parse({}),\n optionsSchema: bendOptionsSchema,\n geometry: {\n minSegments: 16,\n // A pure circular arc of radius 1/curvature, so the sagitta form answers\n // this exactly. This is the deformer the old flat 72 over-served most:\n // at the default 0.6 it wants 24, and the field starter preset is a bend.\n autoSegments: (o, sheet) => segmentsForArc(spanAlong(sheet, o.angle), 1 / Math.abs(o.curvature)),\n axis: (o) => o.angle,\n },\n displace(out, _uv, o) {\n if (Math.abs(o.curvature) < EPS) return\n const dirX = Math.cos(o.angle * DEG)\n const dirY = Math.sin(o.angle * DEG)\n const d = out.x * dirX + out.y * dirY\n\n const r = 1 / o.curvature\n const theta = d * o.curvature\n const sin = Math.sin(theta)\n const halfSin = Math.sin(theta * 0.5)\n const z0 = out.z\n\n // (r − z)·sin θ − d, with d = r·θ folded in so the big terms never meet.\n const shift = r * sinMinusX(theta) - z0 * sin\n out.x += dirX * shift\n out.y += dirY * shift\n out.z = 2 * r * halfSin * halfSin + z0 * Math.cos(theta)\n },\n glsl: {\n chunk: /* glsl */ `\nfloat FN_sinm(float x) {\n if (abs(x) > 1.0) return sin(x) - x;\n float x2 = x * x;\n return (-x * x2 / 6.0) * (1.0 - (x2 / 20.0) * (1.0 - (x2 / 42.0) * (1.0 - x2 / 72.0)));\n}\n\nvoid FN(inout vec3 p, vec2 uv, float t) {\n if (abs(U_curvature) < 1e-5) return;\n vec2 dir = vec2(cos(U_angle), sin(U_angle));\n float d = dot(p.xy, dir);\n float r = 1.0 / U_curvature;\n float theta = d * U_curvature;\n float sn = sin(theta);\n float hs = sin(theta * 0.5);\n float z0 = p.z;\n float shift = r * FN_sinm(theta) - z0 * sn;\n p.xy += dir * shift;\n p.z = 2.0 * r * hs * hs + z0 * cos(theta);\n}\n`,\n strength: 'curvature',\n uniforms: (o) => ({ curvature: o.curvature, angle: o.angle * DEG }),\n },\n}\n","import { z } from 'zod'\nimport type { Deformer } from './types'\nimport { segmentsForArc, spanAlong } from '../core/tessellation'\n\nexport const foldOptionsSchema = z.object({\n /** Direction of the fold travel in the sheet plane, degrees (the crease line runs perpendicular). */\n angle: z.number().min(-360).max(360).default(90),\n /** Signed distance of the crease line from the sheet center, along the travel direction. */\n offset: z.number().min(-20).max(20).default(0),\n /** How far the flap folds over, degrees. 180 = flat against the sheet. */\n foldAngle: z.number().min(-180).max(180).default(90),\n /** Width of the soft hinge — paper never creases to a mathematical edge. */\n radius: z.number().min(0.005).max(0.5).default(0.04),\n})\n\nexport type FoldOptions = z.infer<typeof foldOptionsSchema>\n\nconst DEG = Math.PI / 180\n\n/**\n * Angular crease across a line: within the hinge width the sheet wraps a\n * small cylinder (a roll), beyond it the flap continues rigid at the full\n * fold angle. n folds = n instances stacked (half-fold, letter-fold,\n * accordion). Arc-length preserving like every Paperlab deformer.\n */\nexport const fold: Deformer<FoldOptions> = {\n id: 'fold',\n label: 'Fold',\n defaults: foldOptionsSchema.parse({}),\n optionsSchema: foldOptionsSchema,\n geometry: {\n minSegments: 48,\n // The fillet is an arc of `radius`; everything either side of it is flat.\n // The crease is small, but the grid is uniform, so the density it needs\n // is the density the whole sheet gets.\n autoSegments: (o, sheet) => segmentsForArc(spanAlong(sheet, o.angle), o.radius),\n axis: (o) => o.angle,\n },\n displace(out, _uv, o) {\n const phi = o.foldAngle * DEG\n if (Math.abs(phi) < 1e-6) return\n const dirX = Math.cos(o.angle * DEG)\n const dirY = Math.sin(o.angle * DEG)\n const d = out.x * dirX + out.y * dirY\n const s = d - o.offset\n if (s <= 0) return\n\n // Signed hinge cylinder: radius R = radius/phi carries the fold\n // direction, so one code path serves folds up and down.\n const R = o.radius / phi\n let newD: number\n let newZ: number\n if (s <= o.radius) {\n // Inside the hinge: identical to a roll of signed radius R.\n const theta = (s / o.radius) * phi\n const sin = Math.sin(theta)\n const cos = Math.cos(theta)\n newD = o.offset + (R - out.z) * sin\n newZ = R * (1 - cos) + out.z * cos\n } else {\n // Past the hinge: rigid flap continuing from the arc's end along its\n // tangent; incoming z rides the rotated surface normal.\n const rest = s - o.radius\n const sin = Math.sin(phi)\n const cos = Math.cos(phi)\n newD = o.offset + R * sin + rest * cos - out.z * sin\n newZ = R * (1 - cos) + rest * sin + out.z * cos\n }\n\n out.x += dirX * (newD - d)\n out.y += dirY * (newD - d)\n out.z = newZ\n },\n glsl: {\n chunk: /* glsl */ `\nvoid FN(inout vec3 p, vec2 uv, float t) {\n if (abs(U_foldAngle) < 1e-6) return;\n vec2 dir = vec2(cos(U_angle), sin(U_angle));\n float d = dot(p.xy, dir);\n float s = d - U_offset;\n if (s <= 0.0) return;\n float R = U_radius / U_foldAngle;\n float newD;\n float newZ;\n if (s <= U_radius) {\n float theta = (s / U_radius) * U_foldAngle;\n float sn = sin(theta);\n float cs = cos(theta);\n newD = U_offset + (R - p.z) * sn;\n newZ = R * (1.0 - cs) + p.z * cs;\n } else {\n float rest = s - U_radius;\n float sn = sin(U_foldAngle);\n float cs = cos(U_foldAngle);\n newD = U_offset + R * sn + rest * cs - p.z * sn;\n newZ = R * (1.0 - cs) + rest * sn + p.z * cs;\n }\n p.xy += dir * (newD - d);\n p.z = newZ;\n}\n`,\n strength: 'foldAngle',\n uniforms: (o) => ({\n angle: o.angle * DEG,\n offset: o.offset,\n foldAngle: o.foldAngle * DEG,\n radius: o.radius,\n }),\n },\n}\n","import { z } from 'zod'\nimport type { Deformer } from './types'\nimport { segmentsForSine, spanAlong } from '../core/tessellation'\n\nexport const waveOptionsSchema = z.object({\n amplitude: z.number().min(0).max(0.3).default(0.04),\n wavelength: z.number().min(0.05).max(2).default(0.5),\n /** Travel speed; 0 freezes the ripple. */\n speed: z.number().min(0).max(3).default(0.8),\n /** Travel direction in the sheet plane, degrees. */\n angle: z.number().min(-360).max(360).default(90),\n /** Zero the displacement at one edge (a taped/pinned edge doesn't ripple). */\n pinnedEdge: z.enum(['none', 'top', 'bottom', 'left', 'right']).default('none'),\n})\n\nexport type WaveOptions = z.infer<typeof waveOptionsSchema>\n\nconst DEG = Math.PI / 180\nconst TAU = Math.PI * 2\n\n/**\n * Traveling sine displacement with a quieter second harmonic — idle flutter\n * and wind ripple. The only time-driven deformer so far: stacks containing\n * it re-deform every frame.\n */\nexport const wave: Deformer<WaveOptions> = {\n id: 'wave',\n label: 'Wave',\n defaults: waveOptionsSchema.parse({}),\n optionsSchema: waveOptionsSchema,\n geometry: {\n minSegments: 32,\n // `displace` is sin(phase) + 0.35·sin(2.7·phase). The harmonic is a\n // third the amplitude but curvature carries the SQUARE of the frequency,\n // so 0.35 × 2.7² ≈ 2.6 — the quiet term is the one that sets the grid,\n // by a factor of two and a half. Take whichever asks for more anyway.\n autoSegments: (o, sheet) => {\n const span = spanAlong(sheet, o.angle)\n return Math.max(\n segmentsForSine(span, o.amplitude, o.wavelength),\n segmentsForSine(span, o.amplitude * 0.35, o.wavelength / 2.7),\n )\n },\n axis: (o) => o.angle,\n },\n animated: true,\n displace(out, uv, o, ctx) {\n if (o.amplitude === 0) return\n const dirX = Math.cos(o.angle * DEG)\n const dirY = Math.sin(o.angle * DEG)\n const d = out.x * dirX + out.y * dirY\n const phase = (d / o.wavelength - o.speed * ctx.t) * TAU\n let env = 1\n if (o.pinnedEdge === 'top') env = 1 - uv.y\n else if (o.pinnedEdge === 'bottom') env = uv.y\n else if (o.pinnedEdge === 'left') env = uv.x\n else if (o.pinnedEdge === 'right') env = 1 - uv.x\n out.z += o.amplitude * env * (Math.sin(phase) + 0.35 * Math.sin(phase * 2.7 + 1.3))\n },\n glsl: {\n chunk: /* glsl */ `\nvoid FN(inout vec3 p, vec2 uv, float t) {\n if (U_amplitude == 0.0) return;\n vec2 dir = vec2(cos(U_angle), sin(U_angle));\n float d = dot(p.xy, dir);\n float phase = (d / U_wavelength - U_speed * t) * 6.283185307179586;\n float env = 1.0;\n if (U_pin == 1.0) env = 1.0 - uv.y;\n else if (U_pin == 2.0) env = uv.y;\n else if (U_pin == 3.0) env = uv.x;\n else if (U_pin == 4.0) env = 1.0 - uv.x;\n p.z += U_amplitude * env * (sin(phase) + 0.35 * sin(phase * 2.7 + 1.3));\n}\n`,\n strength: 'amplitude',\n uniforms: (o) => ({\n amplitude: o.amplitude,\n wavelength: o.wavelength,\n speed: o.speed,\n angle: o.angle * DEG,\n pin: { none: 0, top: 1, bottom: 2, left: 3, right: 4 }[o.pinnedEdge],\n }),\n },\n}\n","import { z } from 'zod'\nimport type { Deformer } from './types'\nimport { segmentsForSine } from '../core/tessellation'\n\nexport const drapeOptionsSchema = z.object({\n /** Fold depth at the free edge, world units. */\n amplitude: z.number().min(0).max(0.6).default(0.12),\n /** How many folds run down the drop. */\n folds: z.number().min(0.5).max(16).default(4),\n /**\n * How fast folds deepen away from the pinned edge. 1 is linear; higher\n * holds the top flat and gathers all the movement at the free end, which\n * is what a sheet hung from a rod actually does.\n */\n falloff: z.number().min(0.3).max(4).default(1.6),\n /** How much a second, non-harmonic fold breaks the regularity. */\n irregular: z.number().min(0).max(1).default(0.45),\n /** How much the sheet narrows as its folds deepen. */\n gather: z.number().min(0).max(1).default(0.5),\n pinnedEdge: z.enum(['top', 'bottom']).default('top'),\n})\n\nexport type DrapeOptions = z.infer<typeof drapeOptionsSchema>\n\nconst TAU = Math.PI * 2\n\n/**\n * Hung paper: vertical folds running the length of the drop, shallow at the\n * fixed edge and deepening toward the free one.\n *\n * `wave` can put ripples on a sheet, but a traveling sine is a flag, not a\n * curtain — it kinks the sheet ACROSS its drop and it is uniform end to end.\n * Cloth hung from an edge does the opposite: the folds run WITH the drop and\n * they grow as they get further from whatever is holding the sheet up. Two\n * details do most of the work:\n *\n * - the folds are not harmonic. A pure sine reads as corrugated metal, so a\n * second wave at an incommensurate frequency breaks the repeat.\n * - gathered paper is narrower than flat paper. Pulling the surface toward\n * its centerline in proportion to fold depth is what stops the drape from\n * looking like a texture painted on a rectangle.\n */\nexport const drape: Deformer<DrapeOptions> = {\n id: 'drape',\n label: 'Drape',\n defaults: drapeOptionsSchema.parse({}),\n optionsSchema: drapeOptionsSchema,\n geometry: {\n minSegments: 48,\n // `folds` fold across the width, so the wavelength is width/folds, and\n // the irregular term rides at 1.7x that frequency. Same reasoning as\n // wave: the faster term usually wins despite the smaller amplitude.\n autoSegments: (o, sheet) => {\n if (o.folds <= 0) return 0\n const lambda = sheet.width / o.folds\n return Math.max(\n segmentsForSine(sheet.width, o.amplitude, lambda),\n segmentsForSine(sheet.width, o.amplitude * 0.6 * o.irregular, lambda / 1.7),\n )\n },\n // Across the width, always. `pinnedEdge` picks which end of the DROP the\n // folds grow from; it never turns the folds themselves, which run with\n // the drop and therefore vary across `uv.x`.\n axis: () => 0,\n },\n displace(out, uv, o) {\n if (o.amplitude === 0) return\n // Distance from the pinned edge, 0 at the fixing and 1 at the free end.\n const drop = o.pinnedEdge === 'top' ? 1 - uv.y : uv.y\n const depth = drop ** o.falloff\n const u = uv.x * TAU * o.folds\n const fold = Math.sin(u) + o.irregular * 0.6 * Math.sin(u * 1.7 + 2.1)\n out.z += o.amplitude * depth * fold\n const pinch = o.gather * depth * Math.min(o.amplitude * o.folds * 0.8, 0.6)\n out.x *= 1 - pinch\n },\n glsl: {\n chunk: /* glsl */ `\nvoid FN(inout vec3 p, vec2 uv, float t) {\n if (U_amplitude == 0.0) return;\n float drop = U_pin == 1.0 ? 1.0 - uv.y : uv.y;\n float depth = pow(drop, U_falloff);\n float u = uv.x * 6.283185307179586 * U_folds;\n float fold = sin(u) + U_irregular * 0.6 * sin(u * 1.7 + 2.1);\n p.z += U_amplitude * depth * fold;\n float pinch = U_gather * depth * min(U_amplitude * U_folds * 0.8, 0.6);\n p.x *= 1.0 - pinch;\n}\n`,\n strength: 'amplitude',\n uniforms: (o) => ({\n amplitude: o.amplitude,\n folds: o.folds,\n falloff: o.falloff,\n irregular: o.irregular,\n gather: o.gather,\n pin: o.pinnedEdge === 'top' ? 1 : 2,\n }),\n },\n}\n","import { z } from 'zod'\nimport type { Deformer } from './types'\n\nexport const crumpleOptionsSchema = z.object({\n /** How crushed, 0..1. Peak-to-peak height, and it drives the pull too. */\n amount: z.number().min(0).max(1).default(0.35),\n /** Facets per world unit. Higher is finer, and needs more segments to resolve. */\n scale: z.number().min(0.5).max(8).default(3),\n /**\n * How much the sheet draws in on itself. Crumpled paper occupies a smaller\n * footprint than flat paper; without this it reads as an embossed sheet\n * rather than a crushed one.\n */\n pull: z.number().min(0).max(1).default(0.4),\n /** A different crush of the same paper. */\n seed: z.number().int().min(0).max(7).default(0),\n})\n\nexport type CrumpleOptions = z.infer<typeof crumpleOptionsSchema>\n\n/**\n * GLSL's `mod`, which is not JS's `%`.\n *\n * `%` keeps the sign of the dividend, so a cell at a negative coordinate\n * hashes to a different bucket on the two paths — and the sheet is centred on\n * the origin, so HALF of every sheet is at a negative coordinate. Mirroring\n * `x - y·floor(x/y)` is the whole reason the two halves agree.\n */\nfunction mod(x: number, y: number): number {\n return x - y * Math.floor(x / y)\n}\n\n/**\n * Where the feature point of a cell sits, 0..1 within it.\n *\n * Deliberately integer arithmetic on small numbers rather than the usual\n * `fract(sin(dot(…)) * 43758.5)` hash: that one takes the sine of a large\n * argument and multiplies the result by forty thousand, which turns a\n * last-bit difference between a CPU and a GPU into a completely different\n * number. Every product here stays under 2^13, which is exact in float32 and\n * in a double alike, so the two implementations land on the same point rather\n * than on nearby ones. The pattern repeats every 64 cells — far outside any\n * sheet you would put on screen.\n */\nfunction jitter(cx: number, cy: number, seed: number): [number, number] {\n const hx = mod(cx * 37 + cy * 17 + seed * 5, 64)\n const hy = mod(cx * 23 + cy * 41 + seed * 11, 64)\n return [0.2 + (0.6 * mod(hx * 13, 7)) / 6, 0.2 + (0.6 * mod(hy * 29, 11)) / 10]\n}\n\n/**\n * `F2 − F1` tops out at 0.9315 of a cell on this jitter (measured across\n * every seed and the whole `scale` range), so this brings the field back to\n * ±amount/2 — `amount` is then a peak-to-peak height you can reason about\n * rather than an arbitrary knob. `crumple.test.ts` holds the bound.\n */\nconst NORM = 0.5366\n\n/** Which way a cell's facet is pushed — half up, half down. */\nfunction cellSign(cx: number, cy: number, seed: number): number {\n return 1 - 2 * mod(cx * 11 + cy * 7 + seed * 3, 2)\n}\n\n/**\n * Paper that has been handled.\n *\n * Six deformers and not one of them crushed a sheet — `wave` and `fold` were\n * the nearest and neither reads as crumpled. This is the missing primitive.\n *\n * The field is a jittered grid of cells, each pushed up or down, with the\n * height going to zero exactly on the boundary between them: `F2 − F1`, the\n * gap between the two nearest cell points, signed per cell. That vanishes on\n * every boundary, so the sheet stays continuous, and its gradient flips\n * across one — which is a crease. The result is an irregular polygonal\n * network of facets alternating toward and away from you, which is what a\n * sheet crushed in a fist actually is.\n *\n * **The normals matter more than the displacement here**, and getting there\n * took three tries worth recording. Three summed triangle waves: periodic,\n * an egg-crate. Plain distance-to-nearest (`F1`): irregular but smooth cone\n * tips, so it read as hammered metal. Only creases with a sign change across\n * them shade like paper.\n *\n * Both normal paths agree with that: the hero path averages vertex normals\n * over a dense grid, the field path probes two tangents a hundredth of a\n * sheet apart. Both need facets several segments wide.\n *\n * Cost, measured rather than assumed (`pnpm perf:field --soft`): a field of\n * these runs about four times longer per frame at ×20, and six at ×60, than\n * the same field of an undeformed preset. That ratio used to read 45%, and it\n * grew without this deformer getting one instruction slower — `'auto'` now\n * sizes the grid to the work, so the undeformed sheet it is measured against\n * went from 72 segments a side to 8 and got very cheap, while crumple keeps\n * the density its creases need. Which makes the point sharper than before:\n * almost none of this cost is geometry. It is the nine cell lookups per\n * probe, three probes deep for the normal.\n */\nexport const crumple: Deformer<CrumpleOptions> = {\n id: 'crumple',\n label: 'Crumple',\n defaults: crumpleOptionsSchema.parse({}),\n optionsSchema: crumpleOptionsSchema,\n // A crease the grid cannot resolve is a smooth bump, and a sheet of smooth\n // bumps is not a crumple. Measured (`pnpm perf:field`), the real cost of\n // this deformer is not geometry at all: it is nine cell evaluations per\n // probe and three probes per vertex for the normal.\n //\n // No `autoSegments` here, and that is the honest answer rather than an\n // omission. Every other deformer approximates a smooth surface, so its\n // density falls out of a radius; a crumple's creases are where the gradient\n // is MEANT to break, so there is no sagitta to bound. What it wants is\n // segments per cell, and at the default `scale: 3` across a 1.4 span that\n // works out to the 72 this floor already asks for. So crumple is the one\n // deformer `'auto'` does not make cheaper — its floor was never the no-op\n // the others' were.\n geometry: { minSegments: 72 },\n displace(out, _uv, o) {\n if (o.amount === 0) return\n const qx = out.x * o.scale\n const qy = out.y * o.scale\n const gx = Math.floor(qx)\n const gy = Math.floor(qy)\n\n // Nearest and second-nearest cell point, and which cell won.\n let f1 = 1e9\n let f2 = 1e9\n let winX = gx\n let winY = gy\n for (let dy = -1; dy <= 1; dy++) {\n for (let dx = -1; dx <= 1; dx++) {\n const cx = gx + dx\n const cy = gy + dy\n const [jx, jy] = jitter(cx, cy, o.seed)\n const ex = cx + jx - qx\n const ey = cy + jy - qy\n const dist = Math.sqrt(ex * ex + ey * ey)\n if (dist < f1) {\n f2 = f1\n f1 = dist\n winX = cx\n winY = cy\n } else if (dist < f2) {\n f2 = dist\n }\n }\n }\n\n // Zero on every cell boundary, so the sheet never tears; the sign flips\n // as you cross one, which is what makes the boundary a crease.\n out.z += cellSign(winX, winY, o.seed) * (f2 - f1) * o.amount * NORM\n // Drawing in happens after the cell lookup reads the flat position, so\n // both implementations hash the same cell.\n const pull = 1 - o.amount * o.pull * 0.35\n out.x *= pull\n out.y *= pull\n },\n glsl: {\n chunk: /* glsl */ `\nvec2 FN_jitter(float cx, float cy, float seed) {\n float hx = mod(cx * 37.0 + cy * 17.0 + seed * 5.0, 64.0);\n float hy = mod(cx * 23.0 + cy * 41.0 + seed * 11.0, 64.0);\n return vec2(0.2 + 0.6 * mod(hx * 13.0, 7.0) / 6.0, 0.2 + 0.6 * mod(hy * 29.0, 11.0) / 10.0);\n}\n\nfloat FN_sign(float cx, float cy, float seed) {\n return 1.0 - 2.0 * mod(cx * 11.0 + cy * 7.0 + seed * 3.0, 2.0);\n}\n\nvoid FN(inout vec3 p, vec2 uv, float t) {\n if (U_amount == 0.0) return;\n vec2 flat2 = p.xy;\n vec2 q = flat2 * U_scale;\n vec2 g = floor(q);\n\n float f1 = 1e9;\n float f2 = 1e9;\n vec2 win = g;\n for (int dy = -1; dy <= 1; dy++) {\n for (int dx = -1; dx <= 1; dx++) {\n vec2 c = g + vec2(float(dx), float(dy));\n float dist = length(c + FN_jitter(c.x, c.y, U_seed) - q);\n if (dist < f1) { f2 = f1; f1 = dist; win = c; }\n else if (dist < f2) { f2 = dist; }\n }\n }\n\n p.z += FN_sign(win.x, win.y, U_seed) * (f2 - f1) * U_amount * ${NORM};\n float pull = 1.0 - U_amount * U_pull * 0.35;\n p.xy = flat2 * pull;\n}\n`,\n // `amount` drives both the height and the pull, so a field instance's\n // bias scales the whole crush rather than half of it.\n strength: 'amount',\n uniforms: (o) => ({ amount: o.amount, scale: o.scale, pull: o.pull, seed: o.seed }),\n },\n}\n","import type { CreaseConfig } from '../config/schema'\nimport type { FoldOptions } from './fold'\nimport type { DeformerInstance } from './types'\n\n/**\n * Paper memory: the sheet keeps what has been done to it.\n *\n * Every deformer is a pure function of its options — a sheet folded to 180°\n * and back to 0° flows through the stack and comes out pristine. That is\n * correct for cloth and wrong for paper, which is PLASTIC: the fibres break\n * along the fold and the crease outlives it.\n *\n * The fix lives here rather than inside the deformers, and deliberately.\n * Deformer purity is load-bearing — it is what gives the GLSL twins\n * something to be identical to, what lets the field scale one instance's\n * bend by a per-sheet bias, and what `test:parity` checks. So memory sits\n * ABOVE the stack: it watches the stack the behavior built, and it rewrites\n * that stack before it runs. Nothing below this file knows it exists.\n *\n * The whole layer is hero-path only. The field composes one GLSL program for\n * every sheet in an instanced draw call, and a crease is per-sheet state —\n * so a field of a hundred papers cannot carry a hundred crease sets without\n * per-instance attributes that don't exist yet. `applyMemory` is called from\n * `PaperMesh` and from nowhere in `field/`.\n */\n\n/**\n * What a paper at `takesSet: 1` keeps of a fold, as a fraction of the angle\n * it was folded to.\n *\n * Kraft folded flat (180°) comes to rest around 30° open, which is `180 ×\n * 0.85 × 0.2`. Keeping this multiplier here rather than folding it into the\n * stock values is what lets `memory.set` and `Stock.takesSet` both be honest\n * 0..1 knobs that use their whole range, instead of designer-facing sliders\n * that do everything interesting in their bottom fifth.\n */\nexport const MAX_SET = 0.2\n\n/**\n * Hinge width of a remembered crease, world units.\n *\n * Sharper than `fold`'s own 0.04 default, because a crease is not a fold: a\n * fold bends fibres that are pushing back, a crease is the line where they\n * already gave up. It is a constant rather than a schema field because it is\n * a property of broken paper and not a thing anyone tunes — `depth` is the\n * knob, and a second one here would only ever be set wrong.\n */\nexport const CREASE_RADIUS = 0.03\n\n/**\n * How far a fold has to CLOSE, from however open it last was and at a line\n * that stays put, before it leaves a crease. Degrees.\n *\n * This is the rule that separates the two things `fold` is used for, and it\n * has to, because they are the same deformer. A crease is made by the ACT of\n * folding: the angle closes while the line is held. `unroll`'s landing hinge\n * is a fold instance that sits at exactly 90° forever while its line travels\n * down the sheet (a fixed floor is a moving line in sheet coordinates) —\n * paper coming off a roll and turning at the floor is BENT, not creased, and\n * a trail of creases left behind it would be the obvious bug. Measuring the\n * closing rather than the angle gets both right, and gets them right without\n * asking a behavior to declare anything about its own folds.\n */\nexport const CREASE_MIN_GROWTH = 45\n\n/** How far a crease line may drift and still be the same crease. World units. */\nexport const CREASE_DRIFT = 0.02\n\n/** And in degrees, for the travel direction. */\nexport const CREASE_DRIFT_ANGLE = 2\n\n/** Below this the crease is neither visible nor worth a slot. Degrees. */\nexport const MIN_DEPTH = 1\n\n/** What the crease shader carries, and so what memory may record. */\nexport const MAX_CREASES = 4\n\n/**\n * A crease line in canonical form, for identity only.\n *\n * `(angle, offset)` and `(angle + 180, -offset)` name the same line through\n * the sheet — they differ in which half `fold` treats as the flap, not in\n * where the crease is. `letter-fold` uses exactly that pair (270 at +h/6 and\n * 90 at +h/6) and they are two DIFFERENT lines; folding both into a half-turn\n * range is what keeps them apart, and what stops a residual fold being\n * stacked on top of a live one that is already there.\n */\nfunction canonicalLine(angle: number, offset: number): [number, number] {\n let a = ((angle % 360) + 360) % 360\n let o = offset\n if (a >= 180) {\n a -= 180\n o = -o\n }\n return [a, o]\n}\n\n/** Whether two folds/creases describe the same physical line on the sheet. */\nexport function sameLine(\n a: { angle: number; offset: number },\n b: { angle: number; offset: number },\n): boolean {\n const [aa, ao] = canonicalLine(a.angle, a.offset)\n const [ba, bo] = canonicalLine(b.angle, b.offset)\n // Near 0/180 the canonical angle wraps, so compare the way an angle has to be.\n const d = Math.abs(aa - ba)\n const angleClose = Math.min(d, 180 - d) <= CREASE_DRIFT_ANGLE\n return angleClose && Math.abs(ao - bo) <= CREASE_DRIFT\n}\n\n/**\n * Fold a sheet's remembered creases into the stack that is about to run.\n *\n * A crease is a FLOOR on the fold at its line, never an addition. Where the\n * behavior is already folding that line further, the crease is invisible and\n * contributes nothing; as the behavior lets go, the fold angle falls to the\n * crease's depth and stops there. That is what makes the crease appear on\n * the way back out of a fold without anything having to detect the release —\n * and it is why the residual is written INTO the live instance rather than\n * added beside it. Two folds on one line would not be a deeper crease, they\n * would be two creases a hair apart, and `fold` does not commute.\n *\n * Creases with no live fold on their line are prepended: a sheet that is\n * already creased is creased BEFORE the behavior gets hold of it, so the\n * behavior bends a creased sheet rather than the crease bending a bent one.\n */\nexport function applyMemory(stack: DeformerInstance[], creases: CreaseConfig[]): DeformerInstance[] {\n if (creases.length === 0) return stack\n\n let out = stack\n const loose: CreaseConfig[] = []\n\n for (const crease of creases) {\n if (Math.abs(crease.depth) < MIN_DEPTH) continue\n const index = out.findIndex(\n (i) => i.type === 'fold' && i.enabled !== false && sameLine(i.options as FoldOptions, crease),\n )\n if (index === -1) {\n loose.push(crease)\n continue\n }\n const live = out[index]!\n const options = live.options as FoldOptions\n if (Math.abs(options.foldAngle) >= Math.abs(crease.depth)) continue\n // Copy on first write — the stack a behavior returns is not ours to edit,\n // and on a resting sheet it is the same array every frame.\n if (out === stack) out = [...stack]\n out[index] = { ...live, options: { ...options, foldAngle: crease.depth } }\n }\n\n if (loose.length === 0) return out\n return [...loose.map(toFold), ...out]\n}\n\n/** A remembered crease as the deformer that draws it. */\nfunction toFold(crease: CreaseConfig): DeformerInstance {\n return {\n type: 'fold',\n options: {\n angle: crease.angle,\n offset: crease.offset,\n foldAngle: crease.depth,\n radius: CREASE_RADIUS,\n } satisfies FoldOptions,\n }\n}\n\ninterface Slot {\n angle: number\n offset: number\n /** The most OPEN this line has been — every closing is measured from here. */\n trough: number\n /** The largest closing it has made from a trough. */\n bestGrowth: number\n /** How far shut it was at the top of that closing — the crease's own angle. */\n bestPeak: number\n /** Which way it was folded, so the crease opens back the way it came. */\n sign: number\n}\n\n/**\n * Watches a running deformer stack and records the creases it leaves.\n *\n * One per sheet, driven from the frame loop. It is deliberately not a\n * reducer over config: recording has to happen at frame rate to catch the\n * peak of a fold, and routing sixty writes a second through React would cost\n * more than the whole rest of the feature. Instead this holds the live truth\n * and says when it has changed, and the host persists that at its own pace —\n * the same split `onBehaviorChange` already uses for handle drags.\n *\n * Slots are keyed by POSITION in the stack, which is the only stable identity\n * a fold has: a behavior's stack is a pure function of its options, so\n * `stack[1]` is the same fold from frame to frame, while its angle and offset\n * are exactly the things that may legitimately move.\n */\nexport class CreaseTracker {\n private slots = new Map<number, Slot>()\n private recorded: CreaseConfig[] = []\n private authored: CreaseConfig[] = []\n /** What `observe` last handed out, so an echo can be told from an edit. */\n private lastReported: CreaseConfig[] = []\n\n constructor(authored: CreaseConfig[] = []) {\n this.authored = authored\n }\n\n /**\n * Forget how the paper got here without forgetting the creases.\n *\n * Called when the stack is replaced wholesale (a new behavior, a new\n * sheet): the slots describe folds that no longer exist, but a crease is a\n * property of the paper and survives being put down and picked up.\n */\n reset(authored: CreaseConfig[] = this.creases): void {\n this.slots.clear()\n this.recorded = []\n this.authored = authored\n }\n\n /**\n * Take on a crease set that came from outside, and work out which kind of\n * outside it was — because the two kinds want opposite things.\n *\n * It is USUALLY this tracker's own recording coming back, a frame or two\n * after `onCrease` handed it to the host. Then the slots must survive: the\n * fold that made the crease is very likely still closing, and resetting\n * its peak on the host's echo would stall the crease halfway into the\n * fold that was making it.\n *\n * But it can also be somebody EDITING the paper — a depth dragged down in\n * a panel, a shared link opened, a state's overrides settling. Then the\n * slots are the wrong story to keep. `merge` takes the deeper of two\n * creases on a line, so a recording of 20° would quietly outvote a human\n * asking for 5° and the slider would appear not to work; and it would go\n * on outvoting it, because the fold that recorded the 20 is still sitting\n * in a slot. An edit means the paper is what it is now, and the next\n * crease has to be earned by folding it again.\n *\n * The two are told apart by what we last reported. Anything else is an\n * edit, which is the safe way round: mistaking an echo for an edit costs\n * a crease that gets re-recorded on the next fold, while mistaking an edit\n * for an echo costs a control that does not work.\n */\n adopt(creases: CreaseConfig[]): void {\n if (!same(creases, this.lastReported)) this.slots.clear()\n this.authored = creases\n this.recorded = []\n }\n\n /** Everything the sheet currently carries, authored and recorded merged. */\n get creases(): CreaseConfig[] {\n return merge(this.authored, this.recorded)\n }\n\n /**\n * Take one frame's reading. Returns true when the crease set changed by\n * enough to be worth telling anyone about.\n */\n observe(stack: DeformerInstance[], set: number): boolean {\n if (set <= 0) return false\n\n for (let i = 0; i < stack.length; i++) {\n const instance = stack[i]!\n if (instance.type !== 'fold' || instance.enabled === false) continue\n const o = instance.options as FoldOptions\n const magnitude = Math.abs(o.foldAngle)\n const slot = this.slots.get(i)\n\n // A fold we have not seen, or one whose line has travelled out from\n // under itself. Either way the paper it is bending now is not the paper\n // it was bending, so counting starts again from where it is.\n //\n // The comparison is against where the line SETTLED, never against last\n // frame — absorbing drift a frame at a time would let a slowly\n // travelling hinge creep the length of the sheet without ever tripping\n // the tolerance it exists to trip.\n if (\n !slot ||\n Math.abs(slot.angle - o.angle) > CREASE_DRIFT_ANGLE ||\n Math.abs(slot.offset - o.offset) > CREASE_DRIFT\n ) {\n this.slots.set(i, {\n angle: o.angle,\n offset: o.offset,\n trough: magnitude,\n bestGrowth: 0,\n bestPeak: magnitude,\n sign: o.foldAngle < 0 ? -1 : 1,\n })\n continue\n }\n\n // The crease is the biggest CLOSING this line has made, measured from\n // however open it last was — not from wherever we happened to start\n // watching. A letter that arrives folded and is opened has closed\n // nothing, and creases nothing; open it and fold it again and the same\n // line has now made the whole travel, and creases. Both readings fall\n // out of a running minimum and nothing else.\n if (magnitude < slot.trough) slot.trough = magnitude\n const growth = magnitude - slot.trough\n if (growth > slot.bestGrowth) {\n slot.bestGrowth = growth\n slot.bestPeak = magnitude\n slot.sign = o.foldAngle < 0 ? -1 : 1\n }\n }\n\n const next: CreaseConfig[] = []\n for (const slot of this.slots.values()) {\n if (slot.bestGrowth < CREASE_MIN_GROWTH) continue\n const depth = slot.sign * slot.bestPeak * set * MAX_SET\n if (Math.abs(depth) < MIN_DEPTH) continue\n next.push({ angle: slot.angle, offset: slot.offset, depth })\n }\n\n if (same(next, this.recorded)) return false\n this.recorded = next\n this.lastReported = this.creases\n return true\n }\n}\n\n/**\n * Merge two crease sets, deepest wins per line, capped at what the shader\n * carries.\n *\n * Recorded creases meet authored ones on the same line whenever a preset\n * ships pre-creased and then gets folded along its own crease — and the\n * answer there is the deeper of the two, not their sum: folding a creased\n * sheet along its crease does not double the crease, it just re-makes it.\n */\nfunction merge(authored: CreaseConfig[], recorded: CreaseConfig[]): CreaseConfig[] {\n const out: CreaseConfig[] = []\n for (const crease of [...recorded, ...authored]) {\n const existing = out.find((c) => sameLine(c, crease))\n if (!existing) {\n // Copied, not shared. The deeper-wins line below WRITES to whatever is\n // in `out`, and pushing the argument by reference pointed that write\n // straight back into `this.recorded` — so reading the merged view\n // rewrote the depth that had just been recorded, the next frame saw a\n // change that was nothing but its own echo, and the tracker reported\n // one every frame for as long as an authored crease sat deeper than\n // the fold could make it.\n out.push({ ...crease })\n continue\n }\n if (Math.abs(crease.depth) > Math.abs(existing.depth)) existing.depth = crease.depth\n }\n // Over the cap, the deepest creases are the ones anyone would miss.\n if (out.length > MAX_CREASES) {\n out.sort((a, b) => Math.abs(b.depth) - Math.abs(a.depth))\n out.length = MAX_CREASES\n }\n return out\n}\n\n/** Whether two crease sets are the same to within a degree of depth. */\nfunction same(a: CreaseConfig[], b: CreaseConfig[]): boolean {\n if (a.length !== b.length) return false\n return a.every((crease, i) => {\n const other = b[i]!\n return sameLine(crease, other) && Math.abs(crease.depth - other.depth) < 0.5\n })\n}\n","import type { CreaseConfig, SurfaceConfig } from '../config/schema'\nimport { spanAlong } from '../core/tessellation'\nimport { MAX_SET } from '../deformers/memory'\n\n/** How many crease lines the shader carries. */\nconst MAX_SHADED = 4\n\n/**\n * One crease in the terms the crease shader wants — which are the terms\n * {@link CreaseConfig} and the `fold` deformer already use, and no longer a\n * translation of them.\n *\n * That is the whole point of this shape now. The shader used to be handed a\n * LINE direction and a 0..1 fraction across the sheet, so a remembered crease\n * had to be converted on the way in and the shader had to re-derive a\n * direction on the way out. Both conversions divided the sheet's own aspect\n * out, which is exact for a crease square to an edge and wrong for every\n * other one: a line scored at 45° across a 1.2 × 1.5 sheet came out at 51°.\n * Nobody noticed while creases only ever arrived from the built-in folds,\n * which are all axis-aligned. A fingertip scores them at any angle at all.\n *\n * So the shader now measures in the sheet's own local space, with the same\n * `dot(p.xy, dir) - offset` that `fold` displaces by, and the two cannot\n * disagree about where a line is because they are computing the same number.\n */\nexport interface CreaseShading {\n /** Direction the fold TRAVELS, degrees. The crease line runs across it. */\n angle: number\n /** Signed distance from the sheet's centre along `angle`, in world units. */\n offset: number\n /**\n * How hard it reads, −1..1, SIGNED: positive draws a ridge and negative a\n * groove.\n *\n * A fold toward the camera leaves paper that is concave from the front,\n * which is a valley — so a positive `depth` becomes a negative strength,\n * and the same crease seen from behind reads as the ridge it is. Unsigned\n * strength is why every crease used to render as the same grey smudge\n * whichever way the paper had been folded.\n */\n strength: number\n}\n\n/**\n * Everything that should draw as a crease line, from the two places creases\n * come from.\n *\n * `surface.creaseLines` is authored SHADING: a designer saying \"put fold\n * marks here\", with no geometry behind it. `memory.creases` is what the paper\n * has actually been folded along, and it bends the sheet as well as marking\n * it. They coexist because they answer different questions, and the authored\n * ones come first so that a hand-placed mark is never the one dropped at the\n * cap.\n *\n * The authored ones are the only ones converted, because they are the only\n * ones authored in a different language: `creaseLines` places lines as\n * fractions across the sheet, which is the right thing to type by hand and\n * the wrong thing to shade with.\n */\nexport function resolveCreases(\n surface: SurfaceConfig,\n creases: CreaseConfig[],\n sheet: { width: number; height: number },\n): CreaseShading[] {\n const out: CreaseShading[] = []\n\n const lines = surface.creaseLines\n if (lines) {\n // `creaseLines.angle` is the direction of the LINE; everything downstream\n // speaks in the direction the fold travels, which is across it.\n const angle = lines.angle + 90\n const span = spanAlong(sheet, angle)\n for (const position of lines.positions) {\n out.push({ angle, offset: (position - 0.5) * span, strength: lines.strength })\n }\n }\n\n for (const crease of creases) {\n out.push(creaseShading(crease))\n }\n\n if (out.length > MAX_SHADED) out.length = MAX_SHADED\n return out\n}\n\n/**\n * A remembered crease as the fragment shader draws it — which is now the same\n * crease, with only its depth reinterpreted.\n *\n * A crease reads hardest around a right angle and then saturates: a sheet\n * folded flat and reopened is not four times the mark of one folded to 45°,\n * it is a slightly harder version of the same line. The divisor is the depth\n * a 90° fold leaves in paper that remembers everything — read off\n * {@link MAX_SET} rather than written out, so retuning how much paper keeps\n * cannot leave the shading calibrated against the old answer.\n *\n * The sign survives: see {@link CreaseShading.strength}.\n */\nexport function creaseShading(crease: CreaseConfig): CreaseShading {\n return {\n angle: crease.angle,\n offset: crease.offset,\n strength: Math.max(-1, Math.min(1, -crease.depth / (90 * MAX_SET))),\n }\n}\n","import type { AnyOptions } from '../deformers/types'\nimport type { Behavior } from './types'\nimport { peel } from './peel'\nimport { unroll } from './unroll'\nimport { flip } from './flip'\nimport { letterFold } from './letter-fold'\nimport { hang } from './hang'\nimport { fly } from './fly'\nimport { fall } from './fall'\nimport { carry } from './carry'\nimport { flight } from './flight'\nimport { crumpleBehavior } from './crumple'\nimport { settle } from './settle'\nimport { ribbon } from './ribbon'\n\nconst registry = new Map<string, Behavior<AnyOptions>>()\n\n/** Community behaviors register here; built-ins are pre-registered. */\nexport function registerBehavior(behavior: Behavior<AnyOptions>): void {\n registry.set(behavior.id, behavior)\n}\n\nexport function getBehavior(id: string): Behavior<AnyOptions> {\n const b = registry.get(id)\n if (!b) {\n throw new Error(`[paperlab] Unknown behavior \"${id}\". Registered: ${[...registry.keys()].join(', ')}`)\n }\n return b\n}\n\nexport function listBehaviors(): string[] {\n return [...registry.keys()]\n}\n\nregisterBehavior(peel)\nregisterBehavior(unroll)\nregisterBehavior(flip)\nregisterBehavior(letterFold)\nregisterBehavior(hang)\nregisterBehavior(fly)\nregisterBehavior(fall)\nregisterBehavior(carry)\nregisterBehavior(flight)\nregisterBehavior(crumpleBehavior)\nregisterBehavior(settle)\nregisterBehavior(ribbon)\n","import type { DeformerInstance } from '../deformers/types'\n\nexport const idleNames = ['float', 'tumble', 'dangle', 'taped', 'breeze'] as const\nexport type IdleName = (typeof idleNames)[number]\n\nexport interface IdlePose {\n /** Offsets added to the paper's base transform each frame. */\n position: [number, number, number]\n rotation: [number, number, number]\n}\n\n/**\n * Curated fake physics: hand-tuned motion presets, no simulation. Cheap\n * enough for both hero and field modes, and — for things like the\n * falling-leaf tumble — they read *more* real than a true sim.\n */\nexport interface IdlePreset {\n id: IdleName\n label: string\n /** Whole-sheet motion, written into `pose` (allocation-free). */\n transform?(t: number, pose: IdlePose): void\n /** Extra deformers appended after the behavior's stack. */\n stack?(): DeformerInstance[]\n}\n\nexport const idlePresets: Record<IdleName, IdlePreset> = {\n float: {\n id: 'float',\n label: 'Float',\n transform(t, pose) {\n pose.position[1] = Math.sin(t * 0.9) * 0.05\n pose.rotation[1] = Math.sin(t * 0.31) * 0.16\n pose.rotation[2] = Math.sin(t * 0.23 + 1.2) * 0.05\n },\n },\n tumble: {\n id: 'tumble',\n label: 'Tumble',\n transform(t, pose) {\n // Falling-leaf: velocity-linked lift bob + curated wobble.\n pose.rotation[0] = Math.sin(t * 0.5 + 1) * 0.6\n pose.rotation[2] = Math.sin(t * 0.7) * 0.5\n pose.position[1] = Math.sin(t * 1.4) * 0.07\n pose.position[0] = Math.sin(t * 0.35) * 0.14\n },\n stack: () => [\n {\n type: 'wave',\n options: { amplitude: 0.02, wavelength: 0.9, speed: 0.9, angle: 25, pinnedEdge: 'none' },\n },\n ],\n },\n dangle: {\n id: 'dangle',\n label: 'Dangle',\n transform(t, pose) {\n // A hung tail's pendulum sway.\n pose.rotation[2] = Math.sin(t * 1.5) * 0.06\n pose.rotation[0] = Math.sin(t * 1.1 + 0.7) * 0.03\n },\n },\n taped: {\n id: 'taped',\n label: 'Taped',\n // Taped at the top of a wall: the free bottom edge breathes.\n stack: () => [\n {\n type: 'wave',\n options: { amplitude: 0.025, wavelength: 1.2, speed: 0.45, angle: 90, pinnedEdge: 'top' },\n },\n ],\n },\n breeze: {\n id: 'breeze',\n label: 'Breeze',\n stack: () => [\n {\n type: 'wave',\n options: { amplitude: 0.035, wavelength: 0.5, speed: 1.0, angle: 20, pinnedEdge: 'none' },\n },\n ],\n },\n}\n\nexport function getIdlePreset(name: IdleName): IdlePreset {\n return idlePresets[name]\n}\n","export type PinMode = 'top-edge' | 'top-corners' | 'corner' | 'none'\n\nexport interface ClothParams {\n /** Bend-spring strength: 1 = crisp paper, 0 = silk. Fabric mode falls out for free. */\n stiffness: number\n gravity: number\n wind: number\n /** Local-space y of the ground plane; particles settle onto it. */\n floor: number\n}\n\nconst FIXED_DT = 1 / 120\nconst SOLVER_ITERATIONS = 5\n\n/**\n * How much of the wind reaches a sheet turned edge-on to it.\n *\n * Zero would be the textbook answer and the wrong one: a sheet hanging exactly\n * along the wind would then hang perfectly still forever, because the one\n * thing that could break the symmetry is the wind it is not feeling. Real air\n * is turbulent and finds it. Small enough that a sheet still visibly turns its\n * face to the wind, large enough that it never stalls.\n */\nconst AERO_TURBULENCE = 0.15\n\n/**\n * How much of the sheet a hand takes hold of, in world units.\n *\n * A grab used to move exactly ONE particle, which is a pin and not a pinch:\n * the sheet came to a point under the cursor and the rest of it hung off that\n * singularity, which is the look every cheap cloth demo has. Fingers hold a\n * patch about a centimetre across, and against a sheet whose width is one\n * world unit — call it A4 — that is about 0.05.\n *\n * Clamped at both ends where it is used. Below a cell and a half it collapses\n * back to the single particle it is replacing however fine the grid is; above\n * a fifth of the sheet a hand would be holding most of a small one.\n */\nconst GRAB_RADIUS = 0.05\n\nconst SLEEP_EPSILON = 1e-6\nconst SLEEP_FRAMES = 45\n\n/**\n * How the hold falls off across that patch: 1 at the centre, 0 at the rim.\n *\n * Not a hard patch. Pinning a disc of particles rigidly is as wrong as pinning\n * one, in the other direction — the sheet gets a stiff coin in the middle of\n * it that gravity cannot bend. A falloff means the centre is held, the rim is\n * free, and everything between is partly both, which is what the pad of a\n * finger actually does to paper.\n *\n * Smoothstep rather than linear so the weight arrives at the rim with zero\n * slope; a kink in the weight is a visible crease in the drape.\n */\nfunction grabFalloff(distance: number, radius: number): number {\n const t = Math.min(1, Math.max(0, distance / radius))\n const s = 1 - t\n return s * s * (3 - 2 * s)\n}\n\n/**\n * Verlet mass-spring grid on the sheet's own vertices — structural + shear +\n * bend springs, pins as the interface, wind as a force field, fixed timestep\n * with substeps, sleep when kinetic energy is negligible.\n *\n * Cloth solves the particles and hands them on: `PaperMesh` runs the deformer\n * stack over `positions`, so a behavior composes with the sim rather than\n * replacing it (pinned by `cloth-hosts-a-shape.test.ts`). Only the STRIP owns\n * its vertices outright — its rows are chain nodes, not the sheet's grid.\n * Pure JS, no three dependency.\n */\nexport class ClothSim {\n readonly cols: number\n readonly rows: number\n readonly count: number\n /** The sheet this grid was laid out on. Read by {@link adopt}. */\n readonly width: number\n readonly height: number\n readonly positions: Float32Array\n private readonly prev: Float32Array\n /** Where the constructor laid every particle out — what {@link restore} puts back. */\n private readonly laidOut: Float32Array\n private readonly pinned: Uint8Array\n private readonly pinTargets: Float32Array\n /**\n * The constraints, one typed array per field rather than one object each.\n *\n * Because the effects layer has to vary them across the sheet, and an\n * object with a fixed `rest` cannot be varied cheaply. Paper that chars\n * SHRINKS — that is what curls it toward the flame, not softening — which\n * is a shorter rest length on exactly the constraints the heat reached.\n * Burnt-through paper has to stop pulling on what is left, which is a\n * broken flag. A wet corner is floppier than the dry sheet above it, which\n * is a per-constraint stiffness. None of that is in this file; this file\n * only makes it possible, and at the defaults below the solve is\n * bit-identical to the object version it replaces.\n */\n readonly constraintCount: number\n readonly constraintA: Uint32Array\n readonly constraintB: Uint32Array\n /** 0 = structural, 1 = shear, 2 = bend (scaled by `stiffness` at solve time). */\n readonly constraintKind: Uint8Array\n /**\n * The length each constraint is laid out at. Never changes; the reference\n * to shrink from.\n *\n * Float64, not Float32, and that is measured rather than cautious: with\n * single-precision rest lengths every one of them rounded, and the first\n * typed-array version of this solve disagreed with the object version it\n * replaced in 476–711 of 714 coordinates after five seconds. The object\n * version held a JS number, which is a double.\n */\n readonly naturalLength: Float64Array\n /** The length it pulls toward now. `naturalLength` until something shrinks or stretches it. */\n readonly restLength: Float64Array\n /** A multiplier on the constraint's own strength. 1 is the paper as built. */\n readonly constraintStiffness: Float64Array\n /** Non-zero where the paper between two particles is gone. Skipped by the solve. */\n readonly broken: Uint8Array\n /**\n * How easily each particle is moved, 0..1: one over its mass, relative to\n * dry paper.\n *\n * Mass matters in exactly two places here, and both are wired, because a\n * \"heavier\" that touched neither would be another knob that does nothing.\n * Gravity is an acceleration, so weight alone does not make wet paper fall\n * differently. What does: the air pushes a heavy particle less (the aero\n * term is divided by mass), and the constraint solve moves a heavy particle\n * less than a light one it is tied to. Zero is infinite mass: static, moved by nothing — not the air, not the solve, and not gravity either.\n */\n readonly invMass: Float32Array\n /**\n * How far the middle of each BEND spring sits off the line between its ends\n * when relaxed, along the sheet's normal — a signed rest curvature, as a\n * sagitta in world units. Ignored on every other kind of constraint.\n *\n * Positive curls the paper toward its FRONT, the face a flat sheet turns to\n * +z — which puts the middle of each span that far BEHIND its ends. Paper\n * curling toward you is hollow on the side you see; the first cut of this\n * had the middle in front, which is a dome, and a dome's rim goes the other\n * way.\n *\n * The only lever here with a sign, and the sign is why it exists. A bend\n * spring is a distance, and a distance cannot tell paper curled toward you\n * from paper curled away: shorten it and the sheet buckles, but which way\n * is a coin toss, and gravity can flip it through later. Measured on the\n * first version, which pushed hot paper toward the front along its normal\n * and left the char to hold it — the curl held while the heat did and\n * snapped through to the BACK the moment the front had passed. Charred\n * paper stays curled toward the side that burnt because that side shrank\n * more: a curvature built into the material, which is what this is.\n *\n * Solved as a couple — the middle moves one way, the two ends half as far\n * the other — so it bends the sheet and never pushes it anywhere. A push\n * cannot do this job: it moves paper, and a uniformly curled sheet in still\n * air has no business going anywhere.\n */\n readonly restBend: Float64Array\n /** For each bend spring, the particle between its ends; -1 for every other kind. */\n readonly constraintMiddle: Int32Array\n private params: ClothParams\n private time = 0\n private accumulator = 0\n private stillFrames = 0\n private grabbedIndex = -1\n /**\n * A normal per particle, refreshed once a frame.\n *\n * The sim needs these for one thing only — how much wind each part of the\n * sheet is actually catching — and it needs its OWN rather than the mesh's,\n * because the mesh's are computed after the fact by the adapter and a\n * deformer may be running over the top of them by then. Once a frame rather\n * than once a substep: paper does not turn far in eight milliseconds, and\n * this is the only part of the step that is not a constraint solve.\n */\n private readonly normals: Float32Array\n /**\n * How hard each particle is held, 0..1. Zero for all but the handful under\n * a hand, so it doubles as the inverse mass the constraint solver wants:\n * a particle is as immovable as it is held.\n */\n private readonly grabWeights: Float32Array\n /** Just the held ones, so nothing iterates the whole sheet to find six. */\n private grabbed: number[] = []\n /** Each held particle's offset from the one under the cursor, at grab time. */\n private grabOffsets: Float32Array = new Float32Array(0)\n /** Where the hand was at the start of the last step, and how fast it moved. */\n private readonly grabAt = new Float32Array(3)\n private readonly grabWas = new Float32Array(3)\n private readonly grabVelocity = new Float32Array(3)\n /** True when the sim has settled and steps are skipped. */\n asleep = false\n\n constructor(cols: number, rows: number, width: number, height: number, pins: PinMode, params: ClothParams) {\n this.cols = cols\n this.rows = rows\n this.count = cols * rows\n this.width = width\n this.height = height\n this.params = { ...params }\n this.positions = new Float32Array(this.count * 3)\n this.prev = new Float32Array(this.count * 3)\n this.pinned = new Uint8Array(this.count)\n this.pinTargets = new Float32Array(this.count * 3)\n this.grabWeights = new Float32Array(this.count)\n this.normals = new Float32Array(this.count * 3)\n // Flat, facing the camera, until the first step measures otherwise.\n for (let i = 0; i < this.count; i++) this.normals[i * 3 + 2] = 1\n\n // Grid matches PlaneGeometry vertex order: row-major, top row first,\n // x left→right, y top→bottom (from +h/2 down).\n for (let r = 0; r < rows; r++) {\n for (let c = 0; c < cols; c++) {\n const i3 = (r * cols + c) * 3\n this.positions[i3] = (c / (cols - 1) - 0.5) * width\n this.positions[i3 + 1] = (0.5 - r / (rows - 1)) * height\n this.positions[i3 + 2] = 0\n }\n }\n this.prev.set(this.positions)\n this.laidOut = this.positions.slice()\n\n const idx = (r: number, c: number) => r * cols + c\n const links: number[] = []\n const link = (a: number, b: number, kind: 0 | 1 | 2) => {\n links.push(a, b, kind)\n }\n for (let r = 0; r < rows; r++) {\n for (let c = 0; c < cols; c++) {\n if (c + 1 < cols) link(idx(r, c), idx(r, c + 1), 0)\n if (r + 1 < rows) link(idx(r, c), idx(r + 1, c), 0)\n if (c + 1 < cols && r + 1 < rows) {\n link(idx(r, c), idx(r + 1, c + 1), 1)\n link(idx(r, c + 1), idx(r + 1, c), 1)\n }\n if (c + 2 < cols) link(idx(r, c), idx(r, c + 2), 2)\n if (r + 2 < rows) link(idx(r, c), idx(r + 2, c), 2)\n }\n }\n\n const m = links.length / 3\n this.constraintCount = m\n this.constraintA = new Uint32Array(m)\n this.constraintB = new Uint32Array(m)\n this.constraintKind = new Uint8Array(m)\n this.naturalLength = new Float64Array(m)\n this.restLength = new Float64Array(m)\n this.constraintStiffness = new Float64Array(m).fill(1)\n this.broken = new Uint8Array(m)\n this.restBend = new Float64Array(m)\n this.constraintMiddle = new Int32Array(m).fill(-1)\n for (let k = 0; k < m; k++) {\n const a = links[k * 3]!\n const b = links[k * 3 + 1]!\n this.constraintA[k] = a\n this.constraintB[k] = b\n this.constraintKind[k] = links[k * 3 + 2]!\n // A bend spring runs two cells straight along a row or a column, so the\n // particle it bends around is the one halfway between, by index too.\n if (this.constraintKind[k] === 2) this.constraintMiddle[k] = (a + b) / 2\n const dx = this.positions[a * 3]! - this.positions[b * 3]!\n const dy = this.positions[a * 3 + 1]! - this.positions[b * 3 + 1]!\n const rest = Math.hypot(dx, dy)\n this.naturalLength[k] = rest\n this.restLength[k] = rest\n }\n this.invMass = new Float32Array(this.count).fill(1)\n\n // Pins hold their rest-pose position.\n const pin = (r: number, c: number) => {\n const i = idx(r, c)\n this.pinned[i] = 1\n this.pinTargets.set(this.positions.subarray(i * 3, i * 3 + 3), i * 3)\n }\n if (pins === 'top-edge') for (let c = 0; c < cols; c++) pin(0, c)\n if (pins === 'top-corners') {\n pin(0, 0)\n pin(0, cols - 1)\n }\n if (pins === 'corner') pin(0, 0)\n }\n\n /**\n * Carry a previous sim's drape across a rebuild.\n *\n * Sheet dimensions are a GEOMETRY dependency, so changing them builds a new\n * mesh and a new sim, and a new sim starts flat — which means a draped sheet\n * snaps rigid the instant it is resized. Nothing about the physics requires\n * that; it is only that nobody had carried the state over.\n *\n * What carries is the FREE particles, scaled by how much the sheet grew:\n * the constraints' rest lengths are laid out afresh at the new size, so\n * scaling the drape by the same ratio leaves every constraint exactly as\n * violated as it was and the sim simply continues. Pinned particles keep\n * the new layout's own rest positions instead — a pin holds a CORNER, and\n * the corner is where the resized sheet says it is.\n *\n * Refused in one case only: a different grid, because there is no\n * correspondence between the two sets of particles and the nearest thing to\n * one would be a guess. Everything else carries — a resize, a change of\n * pins, a deformer appearing on top. The sheet's state belongs to the sheet,\n * and none of those is a reason to have never fallen.\n *\n * That matters most for the one that is not a resize at all: a shape\n * arriving over a simulation rebuilds the mesh (the stack has its own\n * opinion about tessellation) without touching a single thing the physics\n * knows about. Resetting there would mean the sheet snapped flat the instant\n * you tried to fold the sheet you were holding, which is the whole point of\n * being able to.\n *\n * Returns whether it took.\n */\n adopt(previous: ClothSim | null | undefined): boolean {\n if (!previous || previous.cols !== this.cols || previous.rows !== this.rows) return false\n const sx = previous.width > 0 ? this.width / previous.width : 1\n const sy = previous.height > 0 ? this.height / previous.height : 1\n // Depth has no dimension of its own to scale by. The mean keeps a\n // uniform resize uniform, which is the case worth getting exactly right.\n const sz = (sx + sy) / 2\n for (let i = 0; i < this.count; i++) {\n if (this.pinned[i]) continue\n const i3 = i * 3\n this.positions[i3] = previous.positions[i3]! * sx\n this.positions[i3 + 1] = previous.positions[i3 + 1]! * sy\n this.positions[i3 + 2] = previous.positions[i3 + 2]! * sz\n // Velocity is the gap between the two, and verlet keeps it there. Carry\n // it too, or the sheet arrives at its new size perfectly still.\n this.prev[i3] = previous.prev[i3]! * sx\n this.prev[i3 + 1] = previous.prev[i3 + 1]! * sy\n this.prev[i3 + 2] = previous.prev[i3 + 2]! * sz\n }\n this.wake()\n return true\n }\n\n setParams(params: Partial<ClothParams>): void {\n // Called every frame while cloth renders — plain numeric compare, no JSON.\n let changed = false\n for (const key of ['stiffness', 'gravity', 'wind', 'floor'] as const) {\n const value = params[key]\n if (value !== undefined && value !== this.params[key]) {\n this.params[key] = value\n changed = true\n }\n }\n if (changed) this.wake()\n }\n\n wake(): void {\n this.asleep = false\n this.stillFrames = 0\n }\n\n /**\n * Back to the sheet as it was laid out: flat, still, every particle where\n * the constructor put it. Pins, a grab and every lever are left alone.\n *\n * For a history that has been rewound — a burn played back from an earlier\n * moment, say, which hands back paper that had burnt away and paper that\n * had FALLEN, lying on the floor with its springs to the sheet suddenly\n * whole again. Solved from there, the solve hauls it up through the sheet\n * in a tangle. Laid out afresh, it is simply the sheet it is again.\n */\n restore(): void {\n this.positions.set(this.laidOut)\n this.prev.set(this.laidOut)\n this.accumulator = 0\n this.wake()\n }\n\n /**\n * Take hold of the sheet at one particle.\n *\n * Separate from {@link grabNearest} because the particle a hand grabbed is\n * not always the particle nearest the point it touched: with a deformer\n * running over the simulation, what the pointer hit was a RENDERED vertex,\n * and the vertex it hit is the particle of the same index — the stack maps\n * a point to a point and never reorders them.\n *\n * What is taken hold of is a PATCH around that particle, not the particle\n * alone — see {@link GRAB_RADIUS}. The patch is measured across the GRID\n * rather than through space, because a hand holds a piece of the sheet and\n * keeps holding the same piece: measured through space, a fold that brought\n * a far corner near the fingers would silently add it to the grip.\n */\n grab(index: number): number {\n this.grabbedIndex = index >= 0 && index < this.count ? index : -1\n this.grabWeights.fill(0)\n this.grabbed = []\n if (this.grabbedIndex < 0) {\n this.grabOffsets = new Float32Array(0)\n this.wake()\n return -1\n }\n\n // Cell size on each axis, so the patch is round in the sheet's material\n // and not in its index space — the grid is only square when the sheet is.\n const cellX = this.cols > 1 ? this.width / (this.cols - 1) : this.width\n const cellY = this.rows > 1 ? this.height / (this.rows - 1) : this.height\n const cell = Math.max(cellX, cellY, 1e-6)\n const radius = Math.min(\n Math.max(GRAB_RADIUS, cell * 1.5),\n Math.max(cell, Math.min(this.width, this.height) * 0.2),\n )\n\n const centreRow = Math.floor(this.grabbedIndex / this.cols)\n const centreCol = this.grabbedIndex % this.cols\n const spanRows = Math.ceil(radius / cellY)\n const spanCols = Math.ceil(radius / cellX)\n const offsets: number[] = []\n const anchor = this.grabbedIndex * 3\n for (let r = centreRow - spanRows; r <= centreRow + spanRows; r++) {\n if (r < 0 || r >= this.rows) continue\n for (let c = centreCol - spanCols; c <= centreCol + spanCols; c++) {\n if (c < 0 || c >= this.cols) continue\n const i = r * this.cols + c\n // A pin is already held, and a particle with no mass to move is paper\n // that is not there — a pinch on a burnt-through hole closes on air.\n if (this.pinned[i] || this.invMass[i]! <= 0) continue\n const distance = Math.hypot((c - centreCol) * cellX, (r - centreRow) * cellY)\n const weight = i === this.grabbedIndex ? 1 : grabFalloff(distance, radius)\n if (weight <= 0) continue\n this.grabWeights[i] = weight\n this.grabbed.push(i)\n // Where this one sits relative to the fingers RIGHT NOW. The patch\n // travels rigidly: a pinch drags the paper, it does not iron it.\n const i3 = i * 3\n offsets.push(\n this.positions[i3]! - this.positions[anchor]!,\n this.positions[i3 + 1]! - this.positions[anchor + 1]!,\n this.positions[i3 + 2]! - this.positions[anchor + 2]!,\n )\n }\n }\n // A pinch that closed on nothing is not a grab, and must not report\n // itself as one: a hole wider than the patch, or a patch entirely pinned,\n // leaves no particle to hold. `grabNearest`'s callers read the return to\n // decide whether anything was caught (see `StripSim`'s, and the comment\n // on it), so saying yes here would be a grab that moves nothing and never\n // lets go.\n if (this.grabbed.length === 0) {\n this.grabbedIndex = -1\n this.grabOffsets = new Float32Array(0)\n this.wake()\n return -1\n }\n this.grabOffsets = Float32Array.from(offsets)\n this.grabAt.set(this.positions.subarray(anchor, anchor + 3))\n this.grabWas.set(this.grabAt)\n this.grabVelocity.fill(0)\n this.wake()\n return this.grabbedIndex\n }\n\n /** Nearest particle to a local-space point — the grab interface. */\n grabNearest(x: number, y: number, z: number): number {\n let best = -1\n let bestDist = Infinity\n for (let i = 0; i < this.count; i++) {\n const dx = this.positions[i * 3]! - x\n const dy = this.positions[i * 3 + 1]! - y\n const dz = this.positions[i * 3 + 2]! - z\n const d = dx * dx + dy * dy + dz * dz\n if (d < bestDist) {\n bestDist = d\n best = i\n }\n }\n return this.grab(best)\n }\n\n /** How hard one particle is being held, 0..1 — for tests and for the adapter. */\n grabWeightAt(index: number): number {\n return this.grabWeights[index] ?? 0\n }\n\n /** Where the fingers are now. The patch follows, each particle by its weight. */\n moveGrab(x: number, y: number, z: number): void {\n if (this.grabbedIndex < 0) return\n this.grabAt[0] = x\n this.grabAt[1] = y\n this.grabAt[2] = z\n this.wake()\n }\n\n /**\n * Let go — and let go at SPEED.\n *\n * This used to drop the paper dead. Every held particle had its previous\n * position overwritten with its current one on the way past, and in a verlet\n * integrator the gap between those two IS the velocity, so a sheet whipped\n * across the frame and released came to a perfect standstill and then fell\n * straight down. Whatever you did with your hand, the paper had never heard\n * of it.\n *\n * The hand's velocity is measured per second (see {@link step}) and spent\n * here, converted into the one-substep gap the integrator reads it back out\n * of. Measured per second rather than per frame because a frame is not a\n * fixed length and a substep is: throwing the same sheet at the same speed\n * must not depend on what the frame rate happened to be.\n */\n release(): void {\n for (const i of this.grabbed) {\n const i3 = i * 3\n const held = this.grabWeights[i]!\n this.prev[i3] = this.positions[i3]! - this.grabVelocity[0]! * FIXED_DT * held\n this.prev[i3 + 1] = this.positions[i3 + 1]! - this.grabVelocity[1]! * FIXED_DT * held\n this.prev[i3 + 2] = this.positions[i3 + 2]! - this.grabVelocity[2]! * FIXED_DT * held\n }\n this.grabbedIndex = -1\n this.grabbed = []\n this.grabWeights.fill(0)\n this.grabVelocity.fill(0)\n this.wake()\n }\n\n step(delta: number): void {\n if (this.asleep) return\n // How fast the hand is travelling, in world units a second. Measured here\n // and not in `moveGrab`, which has no clock and is called once per frame\n // at whatever rate the frames happen to arrive; `release` spends it.\n if (this.grabbedIndex >= 0 && delta > 0) {\n for (let axis = 0; axis < 3; axis++) {\n this.grabVelocity[axis] = (this.grabAt[axis]! - this.grabWas[axis]!) / delta\n }\n this.grabWas.set(this.grabAt)\n }\n this.updateNormals()\n this.accumulator = Math.min(this.accumulator + delta, FIXED_DT * 4)\n while (this.accumulator >= FIXED_DT) {\n this.substep(FIXED_DT)\n this.accumulator -= FIXED_DT\n }\n }\n\n /**\n * Which way each part of the sheet is facing, by central difference across\n * the grid.\n *\n * Clamped at the edges rather than wrapped or skipped: an edge particle\n * takes the one-sided difference, which is the same normal its neighbour\n * has, and an edge with no normal is an edge the wind cannot push.\n *\n * Which SIDE the normal points at is deliberately not worried about. The\n * force below is `n (n·v)`, a quadratic form, and that is unchanged by\n * flipping n — which is exactly right for paper, a surface with no front as\n * far as the air is concerned.\n */\n private updateNormals(): void {\n const p = this.positions\n const n = this.normals\n for (let r = 0; r < this.rows; r++) {\n for (let c = 0; c < this.cols; c++) {\n const left = (r * this.cols + (c > 0 ? c - 1 : c)) * 3\n const right = (r * this.cols + (c < this.cols - 1 ? c + 1 : c)) * 3\n const up = ((r > 0 ? r - 1 : r) * this.cols + c) * 3\n const down = ((r < this.rows - 1 ? r + 1 : r) * this.cols + c) * 3\n const ux = p[right]! - p[left]!\n const uy = p[right + 1]! - p[left + 1]!\n const uz = p[right + 2]! - p[left + 2]!\n // Row 0 is the top of the sheet, so this one runs down it.\n const vx = p[down]! - p[up]!\n const vy = p[down + 1]! - p[up + 1]!\n const vz = p[down + 2]! - p[up + 2]!\n const nx = vy * uz - vz * uy\n const ny = vz * ux - vx * uz\n const nz = vx * uy - vy * ux\n const length = Math.sqrt(nx * nx + ny * ny + nz * nz)\n const i3 = (r * this.cols + c) * 3\n if (length > 1e-12) {\n n[i3] = nx / length\n n[i3 + 1] = ny / length\n n[i3 + 2] = nz / length\n } else {\n // Degenerate: a pinched or fully collapsed patch. Leave the last\n // honest answer rather than inventing one.\n n[i3] = 0\n n[i3 + 1] = 0\n n[i3 + 2] = 0\n }\n }\n }\n }\n\n private substep(dt: number): void {\n const { gravity, wind, stiffness, floor } = this.params\n const p = this.positions\n const damping = 0.985\n const dt2 = dt * dt\n this.time += dt\n\n let maxTravel = 0\n for (let i = 0; i < this.count; i++) {\n const i3 = i * 3\n if (this.pinned[i]) {\n p[i3] = this.pinTargets[i3]!\n p[i3 + 1] = this.pinTargets[i3 + 1]!\n p[i3 + 2] = this.pinTargets[i3 + 2]!\n this.prev[i3] = p[i3]!\n this.prev[i3 + 1] = p[i3 + 1]!\n this.prev[i3 + 2] = p[i3 + 2]!\n continue\n }\n const x = p[i3]!\n const y = p[i3 + 1]!\n const z = p[i3 + 2]!\n const vx = (x - this.prev[i3]!) * damping\n const vy = (y - this.prev[i3 + 1]!) * damping\n const vz = (z - this.prev[i3 + 2]!) * damping\n\n // Gusty wind: coherent noise over time and position, blowing along +z\n // with a sideways component.\n const gust = wind * (0.55 + 0.45 * Math.sin(this.time * 1.7 + x * 2.1 + y * 1.3)) * 0.9\n // What the sheet CATCHES, which is not the same as what is blowing.\n //\n // The wind used to be a uniform shove along +z: every particle got the\n // same push whichever way its patch of paper happened to be facing. So a\n // sheet edge-on to the wind bellied out exactly as hard as one square to\n // it, a folded flap was pushed the same way as the face it was folded\n // behind, and nothing ever turned to the wind — which is the single most\n // recognisable thing paper does in air.\n //\n // The force on a thin surface is the air it intercepts, and that is the\n // component of the RELATIVE wind along the surface normal, pushed back\n // out along that normal: `n (n · (w − v))`.\n //\n // Relative is what earns the term its keep twice over. A sheet already\n // travelling with the wind stops being pushed by it, so a blown sheet\n // settles at a speed instead of accelerating away. And with no wind at\n // all the same expression is air RESISTANCE — which is why it is not\n // behind a test for whether it is windy. Paper's whole character in air\n // is that it does not fall like a stone, and it only does not because a\n // sheet falling face-down catches the air it is falling through while\n // one falling edge-down knifes past it. That fell out of this for free\n // and used to be missing entirely.\n //\n // Velocities here are per substep; the wind is per second, so the\n // particle's has to be converted before the two can be subtracted.\n const relX = gust * 0.25 - vx / dt\n const relY = -vy / dt\n const relZ = gust - vz / dt\n const nx = this.normals[i3]!\n const ny = this.normals[i3 + 1]!\n const nz = this.normals[i3 + 2]!\n const facing = nx * relX + ny * relY + nz * relZ\n // The turbulent residue keeps a sheet lying along the wind from stalling\n // in it forever; a still room has no turbulence to add.\n const ax = nx * facing * (1 - AERO_TURBULENCE) + gust * 0.25 * AERO_TURBULENCE\n const ay = ny * facing * (1 - AERO_TURBULENCE)\n const az = nz * facing * (1 - AERO_TURBULENCE) + gust * AERO_TURBULENCE\n // The air's push is a force, so it moves a heavy particle less. Gravity\n // is an acceleration and does not care — see `invMass`.\n const im = this.invMass[i]!\n // Zero inverse mass is infinite mass, and nothing moves it — gravity\n // included. The convention every solver shares, and the one a caller\n // reaching for \"hold this particle still\" will assume. `prev` is synced\n // so it leaves the moment it was frozen carrying no velocity.\n if (im <= 0) {\n this.prev[i3] = x\n this.prev[i3 + 1] = y\n this.prev[i3 + 2] = z\n continue\n }\n this.prev[i3] = x\n this.prev[i3 + 1] = y\n this.prev[i3 + 2] = z\n p[i3] = x + vx + ax * im * dt2\n p[i3 + 1] = y + vy + (ay * im - gravity * 3.2) * dt2\n p[i3 + 2] = z + vz + az * im * dt2\n maxTravel = Math.max(maxTravel, vx * vx + vy * vy + vz * vz)\n }\n\n // The hand. Held particles are integrated like any other and THEN drawn\n // toward where the fingers put them, by however hard each one is held —\n // so the centre of the pinch arrives exactly and the rim of it only\n // leans that way, still falling under gravity while it does.\n //\n // Their `prev` is deliberately left alone. It is the only record of how\n // fast the hand is moving them, and overwriting it is what used to make\n // a thrown sheet leave at a standstill; see `release`.\n for (let k = 0; k < this.grabbed.length; k++) {\n const i = this.grabbed[k]!\n const i3 = i * 3\n const k3 = k * 3\n const held = this.grabWeights[i]!\n for (let axis = 0; axis < 3; axis++) {\n const target = this.grabAt[axis]! + this.grabOffsets[k3 + axis]!\n p[i3 + axis] = p[i3 + axis]! + (target - p[i3 + axis]!) * held\n }\n }\n\n const {\n constraintA,\n constraintB,\n constraintKind,\n restLength,\n constraintStiffness,\n broken,\n invMass,\n restBend,\n constraintMiddle,\n normals,\n } = this\n const bend = 0.25 + stiffness * 0.7\n for (let iter = 0; iter < SOLVER_ITERATIONS; iter++) {\n for (let c = 0; c < this.constraintCount; c++) {\n // Paper that is not there any more does not hold anything up.\n if (broken[c]) continue\n const kind = constraintKind[c]!\n const k = (kind === 2 ? bend : kind === 1 ? 0.85 : 1) * constraintStiffness[c]!\n const ia = constraintA[c]!\n const ib = constraintB[c]!\n const a3 = ia * 3\n const b3 = ib * 3\n const dx = p[b3]! - p[a3]!\n const dy = p[b3 + 1]! - p[a3 + 1]!\n const dz = p[b3 + 2]! - p[a3 + 2]!\n const dist = Math.sqrt(dx * dx + dy * dy + dz * dz)\n if (dist === 0) continue\n // Inverse mass: 0 is immovable, 1 is free, and a particle under the\n // soft edge of a grab is honestly somewhere between. The old 0/1/2\n // weights were this same split for the two cases it could express;\n // the ratio reproduces them exactly and covers the rest.\n const ma = this.pinned[ia] ? 0 : invMass[ia]! * (1 - this.grabWeights[ia]!)\n const mb = this.pinned[ib] ? 0 : invMass[ib]! * (1 - this.grabWeights[ib]!)\n const total = ma + mb\n if (total <= 0) continue\n const diff = ((dist - restLength[c]!) / dist / total) * k\n const aw = ma\n const bw = mb\n p[a3] = p[a3]! + dx * diff * aw\n p[a3 + 1] = p[a3 + 1]! + dy * diff * aw\n p[a3 + 2] = p[a3 + 2]! + dz * diff * aw\n p[b3] = p[b3]! - dx * diff * bw\n p[b3 + 1] = p[b3 + 1]! - dy * diff * bw\n p[b3 + 2] = p[b3 + 2]! - dz * diff * bw\n\n // The signed half of a bend — see `restBend`. After the distance, so\n // the spring's length decides how far the paper bends and this only\n // which way. Behind a test, so an uncurled sheet runs exactly the\n // arithmetic it always has.\n const sag = restBend[c]!\n if (sag !== 0) {\n const im = constraintMiddle[c]!\n const m3 = im * 3\n const nx = normals[m3]!\n const ny = normals[m3 + 1]!\n const nz = normals[m3 + 2]!\n const offset =\n (p[m3]! - (p[a3]! + p[b3]!) / 2) * nx +\n (p[m3 + 1]! - (p[a3 + 1]! + p[b3 + 1]!) / 2) * ny +\n (p[m3 + 2]! - (p[a3 + 2]! + p[b3 + 2]!) / 2) * nz\n const mm = this.pinned[im] ? 0 : invMass[im]! * (1 - this.grabWeights[im]!)\n const weight = mm + (ma + mb) / 4\n if (weight > 0) {\n // The middle belongs `sag` BEHIND its ends — see `restBend`.\n const lambda = ((-sag - offset) / weight) * k\n const along = lambda * mm\n const back = lambda / 2\n p[m3] = p[m3]! + nx * along\n p[m3 + 1] = p[m3 + 1]! + ny * along\n p[m3 + 2] = p[m3 + 2]! + nz * along\n p[a3] = p[a3]! - nx * back * ma\n p[a3 + 1] = p[a3 + 1]! - ny * back * ma\n p[a3 + 2] = p[a3 + 2]! - nz * back * ma\n p[b3] = p[b3]! - nx * back * mb\n p[b3 + 1] = p[b3 + 1]! - ny * back * mb\n p[b3 + 2] = p[b3 + 2]! - nz * back * mb\n }\n }\n }\n }\n\n // Ground plane with friction.\n for (let i = 0; i < this.count; i++) {\n const i3 = i * 3\n if (p[i3 + 1]! < floor) {\n p[i3 + 1] = floor\n this.prev[i3] = this.prev[i3]! + (p[i3]! - this.prev[i3]!) * 0.5\n this.prev[i3 + 2] = this.prev[i3 + 2]! + (p[i3 + 2]! - this.prev[i3 + 2]!) * 0.5\n }\n }\n\n // Sleep bookkeeping: wind keeps the sheet awake by design.\n if (wind === 0 && this.grabbedIndex < 0) {\n if (maxTravel < SLEEP_EPSILON) {\n if (++this.stillFrames > SLEEP_FRAMES) this.asleep = true\n } else {\n this.stillFrames = 0\n }\n }\n }\n}\n","/**\n * What damage IS, as far as a sheet is concerned. The whole seam.\n *\n * The split is by responsibility. What has happened to the paper belongs to\n * the sheet — it is shading, alpha and eventually stiffness, and only the\n * sheet can draw or simulate those. What CAUSES it belongs to `paperlab/fx`:\n * a flame, a cup of water, a pair of scissors. The main entry draws whatever\n * damage it is handed and has no idea where it came from, which is exactly\n * how `content` already works — `<Paper>` renders a texture without knowing\n * who painted it.\n *\n * The alternative was a public plugin API for the surface composer and the\n * cloth solver, so that fx could reach in. More flexible, and it would have\n * had to be supported for years before a single effect existed to justify its\n * shape. This is one interface and four constants.\n *\n * **This file imports nothing, on purpose.** `paperlab/fx` depends on it —\n * the field is a `DamageSource` and its channel offsets are these — and the\n * boundary test allows fx to reach this one file and nothing else in the\n * library. The moment it imports three, React or the config schema, fx starts\n * dragging the library in behind it.\n */\n\n/**\n * A grid of damage over the sheet's UV, as the sheet reads it.\n *\n * Satisfied structurally by `DamageField` in `paperlab/fx`, and by anything\n * else that can produce four bytes per texel — a baked texture, a recorded\n * burn played back, a test fixture.\n */\nexport interface DamageSource {\n /** Texels along each edge. The grid is square and covers the whole sheet. */\n readonly size: number\n /**\n * RGBA per texel, 0..255, row-major from v = 0 — the channels are\n * {@link DAMAGE_CHANNELS}. Read in place, never copied: the source mutates\n * it and bumps `version`.\n *\n * Eight bits, deliberately. The simulation behind it can run in float; what\n * reaches the GPU is 16 KB per changed frame at 64², against 256 KB for a\n * 128² float texture, and it does not depend on float-texture filtering,\n * which not every phone GPU guarantees.\n */\n readonly pixels: Uint8Array\n /** Bumped whenever `pixels` changes. The sheet uploads on a change and never otherwise. */\n readonly version: number\n /**\n * How ragged a burnt or cut edge is DRAWN, 0..1; omitted means 1.\n *\n * Presentation only: per-fragment noise that moves the edge within the\n * grid's soft band, finer than the grid itself can carry. The physics reads\n * the grid and never this. It is the one part of drawing damage that costs\n * per pixel, which is why it is a number a source can turn down — `paperlab/fx`\n * sets it from its quality tier.\n */\n readonly detail?: number\n /**\n * The burn's own clock, in seconds; omitted means the frame clock.\n *\n * Presentation only. The ember line on a burning edge is beaded and alive —\n * its beads flicker and crawl — and a source that can be replayed wants\n * that motion to replay too: the same moment of the same burn should draw\n * the same beads, which the frame clock cannot promise. `DamageField`\n * hands over its simulated time.\n */\n readonly time?: number\n /**\n * How a burn is DRAWN — widths, intensities and shapes the sheet's damage\n * shading reads each frame. Presentation only; the physics never sees it.\n * Anything left out takes {@link DAMAGE_LOOK_DEFAULTS}.\n */\n readonly look?: DamageLook\n}\n\n/**\n * The knobs on what a burn looks like, in the units a person tunes by —\n * millimetres of A4 and plain multipliers. Every one is optional.\n */\nexport interface DamageLook {\n /** The ember line's widest bead, mm. */\n emberWidth?: number\n /** How bright the beads burn, × the default. */\n emberIntensity?: number\n /** How much of the edge is lit at once, 0..1. */\n emberCoverage?: number\n /** How fast the beads flicker and crawl, × the default. */\n emberFlicker?: number\n /** The dim crimson glow beside the beads, reaching into the char, 0..2. */\n emberGlow?: number\n /** Specks of glowing fibre along the edge, 0..2. */\n sparkle?: number\n /** The pale ash lip's widest point, mm. */\n lipWidth?: number\n /** How pale the ash lip is, × the sampled grey. */\n lipBrightness?: number\n /** 0 is grey char, 1 is dark orange to deep brown. */\n charWarmth?: number\n /** How visible the crack network in the char is, 0..1. */\n charCracks?: number\n /** How far the scorch reaches UP past the burn, mm. */\n scorchReach?: number\n /** How dark the scorch browns go, × the sampled ramp. */\n scorchDarkness?: number\n /** How strongly the scorch front breaks into fingers, × the default. */\n fingers?: number\n /** The burnt edge's long waves, ±mm. */\n edgeWave?: number\n /** The burnt edge's small bites in and out, ±mm. */\n edgeBite?: number\n}\n\n/**\n * What every burn is drawn with unless told otherwise — the combination Noor\n * tuned in the lab's sidebar on 2026-09-12, which is the look this ships.\n */\nexport const DAMAGE_LOOK_DEFAULTS: Required<DamageLook> = {\n // §5 asks for 0.3–1 mm. 1.8 was outside it, and outside the slider's range\n // it was tuned in — a control at its limit is a report that something\n // underneath is wrong, which in this case was a fire nothing could see.\n emberWidth: 0.9,\n emberIntensity: 1.45,\n emberCoverage: 0.6,\n emberFlicker: 1.65,\n emberGlow: 1.25,\n sparkle: 0.5,\n lipWidth: 1.2,\n // Was 1.5, its slider's ceiling, which made the ash lip brighter than the\n // paper it sits on. Ash is pale GREY; the reference's lip is dimmer than\n // the sheet, not a highlight drawn on it.\n lipBrightness: 0.85,\n // Was 1, also a ceiling. At full warmth the char is milk chocolate —\n // closer to cardboard than to charcoal (§5). Burnt paper keeps a little\n // warmth in the plates and reads near black in a frame with a fire in it.\n charWarmth: 0.3,\n // Was 1, also a ceiling. The cracks are drawn as thin polygon outlines, so\n // at full strength the char reads as a mosaic rather than as broken plates.\n charCracks: 0.55,\n scorchReach: 30,\n scorchDarkness: 1.17,\n fingers: 1.25,\n edgeWave: 8.5,\n edgeBite: 3.6,\n}\n\n/**\n * Which byte of a texel means what.\n *\n * char — scorch colour, the brown halo; on cloth, shrinkage and a curl toward the front.\n * saturation — wet darkening and smoothing; on cloth, added mass.\n * heat — how hot the paper is. Drawn only where it burns: the ember line, not the sheet.\n * presence — how much paper is there at all; below half, none is drawn.\n */\nexport const DAMAGE_CHANNELS = { char: 0, saturation: 1, heat: 2, presence: 3 } as const\n","import { DAMAGE_CHANNELS, type DamageSource } from '../surface/damageContract'\nimport type { ClothSim } from './cloth'\n\n/**\n * Damage, as the cloth feels it.\n *\n * The shading layer already draws a burn; this is what makes the paper under\n * it behave like burnt paper instead of a picture of it — the four-layer\n * rule's physics row. It lives in the main entry beside the sim, not in\n * `paperlab/fx`, for the same reason the shading does: `ClothSim` is not\n * exported, and what damage DOES to a sheet belongs to the sheet. fx decides\n * what causes it.\n *\n * Read from the 8-bit `pixels`, the same bytes the GPU draws, so the physics\n * and the picture cannot disagree about where the paper is. 1/255 is finer\n * than any of these levers can be seen to move.\n *\n * Cheap at rest: nothing is read unless the source's `version` moved.\n */\n\nconst { char: CHAR, saturation: SATURATION, presence: PRESENCE } = DAMAGE_CHANNELS\n\n/**\n * Presence below this, as a byte, is paper the sheet does not draw.\n *\n * The shader cuts at `step(0.5, presence)`: drawn from 127.5/255 up, so from\n * 128. The physics uses the same line, because a particle that is drawn but\n * has left the solve hangs in the air, and one that is gone but still in it\n * pulls on paper that can see it isn't there.\n */\nconst GONE_BELOW = 128\n\n/**\n * How far fully-charred paper shrinks in its own plane.\n *\n * Char shrinks — it does not soften, which would only make the sheet droop.\n * Every kind of spring alike: the shrinking is of the paper, and the curl is\n * {@link CHAR_CURL}'s job, not a difference in how far the springs shrink.\n */\nconst CHAR_SHRINK = 0.12\n\n/**\n * The curvature fully-charred paper relaxes into, toward the sheet's front,\n * in one over world units: 6 is a curl of radius a sixth of a sheet — about\n * three and a half centimetres on A4, which is what a burnt edge rolls to.\n *\n * Char and not heat, because a burnt edge STAYS curled. The first version\n * drove the curl from heat and it held only while the heat did; see\n * `ClothSim.restBend`. Toward the front because that is the side a flame is\n * held on, and the side that chars first shrinks most.\n */\nconst CHAR_CURL = 6\n\n/**\n * How steep the char has to be across a spring — as the squared byte\n * difference over four texels — before it counts as a burn front passing.\n * 16 over four texels is four bytes a texel; a real front is ten times that,\n * and the residue a cooling field leaves behind is well under it.\n */\nconst FRONT_GRADIENT = 16 * 16\n\n/**\n * How much heavier soaked paper is: at full saturation, `1 + WET_MASS` times\n * dry. Paper holds a few times its own weight in water; three is where a\n * soaked sheet stops being carried by the air and starts to hang.\n */\nconst WET_MASS = 2\n\n/**\n * How far a triangle with burnt-away corners may stretch before it is torn,\n * as a multiple of its laid-out edge.\n *\n * Nothing that holds together gets near it. Char only ever SHORTENS paper, the\n * curl is a bend, and the corners that follow live paper keep their laid-out\n * offsets from it. What stretches a triangle that far is two things moving\n * apart that used to be side by side — a piece falling away from the sheet it\n * was cut from, or a sheet carried off from the still middle of its own hole.\n * Well past anything a solve settles into, and near enough to the tear that\n * a smear across the gap lasts a frame or two, not a fall.\n */\nconst TEAR_STRETCH = 1.5\n\n/**\n * Reads a `DamageSource` into one sheet's `ClothSim`: char into rest length\n * and rest curvature, saturation into mass, and missing paper out of the\n * solve altogether.\n *\n * Paper that is gone leaves the solve in two ways at once. Every constraint\n * touching it breaks, so it neither holds up nor pulls on what is left — a\n * sheet whose bottom half burnt away stops swinging from the weight of\n * nothing. And it loses its mass, so gravity and the air leave it alone too.\n *\n * What it does NOT do is fall. A gone particle is still a vertex, and the\n * triangles between it and the paper beside it are still drawn wherever the\n * paper is: let it drop and the burnt edge is dragged down after it in\n * streaks. So the ones next to live paper are carried along with it\n * ({@link follow}), and the ones in the middle of a hole stay where they\n * were, where nothing can see them.\n *\n * **A burn that cuts a piece loose drops it.** Nothing here makes it fall —\n * every spring across the cut is broken, so the piece is simply no longer\n * held, and the sim's gravity and air do the rest, fluttering and all. What\n * this class does is keep that honest to look at: each gone particle on the\n * cut rides with ONE piece, the one it borders most ({@link piece}), and the\n * triangles left spanning the gap are hidden once they stretch\n * ({@link tear}), so the piece leaves with its own burnt edge and no streak\n * behind it. One mesh, so the price is the other side of those triangles —\n * at most half a cloth cell of the rim they held.\n *\n * The limit, stated once: a sheet cannot come apart along a cut narrower than\n * a cloth cell. A constraint breaks only where a PARTICLE is gone, never\n * because the paper between two live ones is — breaking there would split\n * the sheet across a row of triangles that a fixed-topology mesh can only\n * draw stretched. A cut that thin separates the picture and not the paper.\n */\nexport class DamageCoupling {\n private readonly sim: ClothSim\n private source: DamageSource | null = null\n private version = -1\n private size = 0\n /** Each particle's texel, laid out for `size`. */\n private particleTexel = new Int32Array(0)\n /** Gone, per particle, as of the last read. */\n private readonly gone: Uint8Array\n /** Whether any particle has ever been gone since the last reset — nothing can tear before. */\n private holed = false\n /** The gone particles with live paper beside them. See {@link follow}. */\n private followers: number[] = []\n /**\n * Which piece of paper each particle belongs to, named by the lowest index\n * in it — or -1 in the middle of a hole.\n *\n * A piece is whatever the sim's unbroken springs still hold together, which\n * is exactly what moves as one: two pieces are two things the solve lets\n * part. A gone particle on a cut takes the piece it borders MOST — a cut a\n * single particle wide borders two, and a particle averaged between them\n * would be dragged across the gap as one piece fell, stretching both edges\n * into it.\n */\n private readonly piece: Int32Array\n /** Union-find over the particles, reused on every read. */\n private readonly parent: Int32Array\n /**\n * Per bend spring, how squarely it lies ACROSS the burn front, 0..1 — and\n * remembered once it has been.\n *\n * A burnt edge rolls about an axis along the front, like a scroll; it does\n * not dish into a bowl. Measured with the curl in every bend spring alike: a\n * burnt band settled into a saddle, its corners forward and its middle BACK\n * (+0.07, −0.06), because a surface cannot curve two ways at once without\n * stretching and paper does not stretch. Curled across the front only, the\n * same band rolled toward the viewer along its whole edge (+0.13).\n *\n * \"Across the front\" is the direction the char is changing fastest in, at\n * the moment the front passes. It has to be remembered: once the front has\n * gone by, the char behind it is uniform and says nothing about direction,\n * but the paper stays rolled the way it rolled.\n */\n private readonly curlWeight: Float32Array\n /** The mesh's index as it was built — what {@link tear} hides triangles from and mends them back to. */\n private original: Uint16Array | Uint32Array | null = null\n /** Per triangle of that index: torn, and hidden until the history is rewound. */\n private torn = new Uint8Array(0)\n /** The triangles with a gone corner — the only ones that can tear. */\n private rim: number[] = []\n private rimStale = true\n /** Every torn triangle has to be put back: the history was rewound, or the source went. */\n private mend = false\n\n constructor(sim: ClothSim) {\n this.sim = sim\n this.gone = new Uint8Array(sim.count)\n this.piece = new Int32Array(sim.count)\n this.parent = new Int32Array(sim.count)\n this.curlWeight = new Float32Array(sim.constraintCount)\n }\n\n /**\n * Bring the sim's levers up to date with `source`. Call before stepping.\n *\n * Returns whether anything was read. Free when the source has not changed,\n * and a null source hands every lever back at its default.\n */\n update(source: DamageSource | null | undefined): boolean {\n const next = source ?? null\n if (next === this.source && (next === null || next.version === this.version)) return false\n // A different source is a different sheet's history — a fresh sheet has\n // not rolled any way yet, and none of it has fallen. Even one with every\n // hole the last one had: paper coming back is not the only way a history\n // changes, and it is somebody else's burn.\n if (next !== this.source) {\n this.curlWeight.fill(0)\n if (next && this.holed) {\n this.rewind()\n this.gone.fill(0)\n }\n }\n this.source = next\n if (!next) {\n this.reset()\n return true\n }\n if (next.size !== this.size) this.layout(next.size)\n this.version = next.version\n this.read(next.pixels)\n this.sim.wake()\n return true\n }\n\n /**\n * Carry the gone particles at the edge of a hole along with the paper beside\n * them. Call after stepping.\n *\n * Each one goes where its live neighbours say it would be if the grid were\n * laid out flat around them — their positions plus its rest offset from\n * each, averaged. The triangles that straddle the burnt edge then keep\n * roughly their shape instead of stretching back to wherever the particle\n * was when it burnt. Only the neighbours in its own {@link piece} count, so\n * on a cut between two pieces it leaves with one of them.\n */\n follow(): void {\n if (this.followers.length === 0) return\n const { gone, sim } = this\n const piece = this.piece\n const p = sim.positions\n const { cols, rows } = sim\n const cellX = cols > 1 ? sim.width / (cols - 1) : 0\n const cellY = rows > 1 ? sim.height / (rows - 1) : 0\n for (const g of this.followers) {\n const r = (g / cols) | 0\n const c = g % cols\n const own = piece[g]!\n let sx = 0\n let sy = 0\n let sz = 0\n let n = 0\n for (let dr = -1; dr <= 1; dr++) {\n const nr = r + dr\n if (nr < 0 || nr >= rows) continue\n for (let dc = -1; dc <= 1; dc++) {\n const nc = c + dc\n if ((dr === 0 && dc === 0) || nc < 0 || nc >= cols) continue\n const j = nr * cols + nc\n if (gone[j] || piece[j] !== own) continue\n const j3 = j * 3\n // Rows run down the sheet, so a neighbour a row BELOW sits lower,\n // and this particle a cell above it.\n sx += p[j3]! - dc * cellX\n sy += p[j3 + 1]! + dr * cellY\n sz += p[j3 + 2]!\n n++\n }\n }\n if (n === 0) continue\n const g3 = g * 3\n p[g3] = sx / n\n p[g3 + 1] = sy / n\n p[g3 + 2] = sz / n\n }\n }\n\n /**\n * Hide the triangles a piece has torn away from. Call after {@link follow},\n * with the sheet's index buffer: it is rewritten in place, and the return\n * says whether it changed, so the caller knows to upload it.\n *\n * A triangle tears when one of its edges has stretched past\n * {@link TEAR_STRETCH} — which, among triangles with a burnt-away corner,\n * only ever happens across a gap that is opening. It is then collapsed to a\n * point, which draws nothing, casts no shadow and adds nothing to its\n * corners' normals, and it stays hidden: torn paper does not mend because\n * the two sides swing close again. Only a rewound history puts it back.\n *\n * A sheet in one piece, held, never stretches one that far — so a burn that\n * cuts nothing loose leaves this index exactly as it was built.\n */\n tear(index: Uint16Array | Uint32Array): boolean {\n if (!this.holed && !this.mend) return false\n if (!this.original || this.original.length !== index.length) {\n this.original = index.slice()\n this.torn = new Uint8Array(index.length / 3)\n this.rimStale = true\n }\n const { original, torn, gone, sim } = this\n let changed = false\n if (this.mend) {\n this.mend = false\n index.set(original)\n changed = true\n }\n if (this.rimStale) {\n this.rimStale = false\n const rim: number[] = []\n for (let t = 0; t < torn.length; t++) {\n if (gone[original[t * 3]!] || gone[original[t * 3 + 1]!] || gone[original[t * 3 + 2]!]) rim.push(t)\n }\n this.rim = rim\n }\n const p = sim.positions\n const { cols, rows } = sim\n const cellX = cols > 1 ? sim.width / (cols - 1) : 0\n const cellY = rows > 1 ? sim.height / (rows - 1) : 0\n const limit = TEAR_STRETCH * TEAR_STRETCH\n const stretched = (i: number, j: number) => {\n const dc = (i % cols) - (j % cols)\n const dr = ((i / cols) | 0) - ((j / cols) | 0)\n const rest = (dc * cellX) ** 2 + (dr * cellY) ** 2\n const i3 = i * 3\n const j3 = j * 3\n const now = (p[i3]! - p[j3]!) ** 2 + (p[i3 + 1]! - p[j3 + 1]!) ** 2 + (p[i3 + 2]! - p[j3 + 2]!) ** 2\n return now > rest * limit\n }\n for (const t of this.rim) {\n if (torn[t]) continue\n const a = original[t * 3]!\n const b = original[t * 3 + 1]!\n const c = original[t * 3 + 2]!\n if (!stretched(a, b) && !stretched(b, c) && !stretched(c, a)) continue\n torn[t] = 1\n index[t * 3 + 1] = a\n index[t * 3 + 2] = a\n changed = true\n }\n return changed\n }\n\n /** Map each particle to its texel. The damage grid's row 0 is v = 0, the sheet's BOTTOM. */\n private layout(size: number): void {\n const { cols, rows, count } = this.sim\n const last = size - 1\n this.size = size\n this.particleTexel = new Int32Array(count)\n for (let r = 0; r < rows; r++) {\n for (let c = 0; c < cols; c++) {\n const u = cols > 1 ? c / (cols - 1) : 0.5\n // The cloth's row 0 is the TOP.\n const v = rows > 1 ? 1 - r / (rows - 1) : 0.5\n this.particleTexel[r * cols + c] = Math.round(v * last) * size + Math.round(u * last)\n }\n }\n }\n\n private read(pixels: Uint8Array): void {\n const { sim, gone, particleTexel, curlWeight, size } = this\n const {\n invMass,\n restLength,\n naturalLength,\n restBend,\n broken,\n constraintA,\n constraintB,\n constraintKind,\n constraintMiddle,\n } = sim\n\n let rewound = false\n let holed = false\n for (let i = 0; i < sim.count; i++) {\n const t = particleTexel[i]! * 4\n const isGone = pixels[t + PRESENCE]! < GONE_BELOW\n // Burnt paper does not come back. When it does, this is a different\n // history — a burn played back from earlier — and not the next moment\n // of this one.\n if (gone[i] && !isGone) rewound = true\n if (isGone) holed = true\n gone[i] = isGone ? 1 : 0\n // Exactly 1 at a dry texel — an undamaged sheet must stay bit-identical\n // to one with no source at all.\n invMass[i] = isGone ? 0 : 1 / (1 + (WET_MASS * pixels[t + SATURATION]!) / 255)\n }\n if (rewound) this.rewind()\n this.holed = holed\n this.rimStale = true\n\n for (let k = 0; k < sim.constraintCount; k++) {\n const a = constraintA[k]!\n const b = constraintB[k]!\n // A bend spring over a gone particle would bridge the hole, holding the\n // two sides together through paper that is not there.\n const m = constraintMiddle[k]!\n if (gone[a] || gone[b] || (m >= 0 && gone[m])) {\n broken[k] = 1\n continue\n }\n broken[k] = 0\n let charSum = pixels[particleTexel[a]! * 4 + CHAR]! + pixels[particleTexel[b]! * 4 + CHAR]!\n let samples = 2\n if (m >= 0) {\n charSum += pixels[particleTexel[m]! * 4 + CHAR]!\n samples = 3\n }\n const char = charSum / (samples * 255)\n // Exactly the natural length, and exactly no bend, at char 0.\n restLength[k] = naturalLength[k]! * (1 - CHAR_SHRINK * char)\n if (constraintKind[k] === 2) {\n // Is a front passing here, and does this spring run across it? The\n // char gradient at the spring's middle, by central difference.\n const t = particleTexel[m]!\n const x = t % size\n const y = (t / size) | 0\n const gx =\n pixels[(y * size + Math.min(size - 1, x + 2)) * 4 + CHAR]! -\n pixels[(y * size + Math.max(0, x - 2)) * 4 + CHAR]!\n const gy =\n pixels[(Math.min(size - 1, y + 2) * size + x) * 4 + CHAR]! -\n pixels[(Math.max(0, y - 2) * size + x) * 4 + CHAR]!\n const steep = gx * gx + gy * gy\n if (steep > FRONT_GRADIENT) {\n // A spring along a row spans two columns; one down a column, two rows.\n const across = (b - a === 2 ? gx * gx : gy * gy) / steep\n if (across > curlWeight[k]!) curlWeight[k] = across\n }\n // A curvature as the sagitta of this spring's span: κL²/8.\n const span = naturalLength[k]!\n restBend[k] = (CHAR_CURL * char * curlWeight[k]! * span * span) / 8\n }\n }\n\n this.findPieces()\n }\n\n /**\n * Which piece each particle is in ({@link piece}), and which gone ones\n * follow a piece at all ({@link followers}).\n *\n * Pieces by union-find over the springs that still hold, rooted at the\n * lowest index so the same burn names the same pieces every time. Then each\n * gone particle with live paper beside it joins the piece it has the most\n * neighbours in, the lower-named on a tie.\n */\n private findPieces(): void {\n const { sim, gone } = this\n const parent = this.parent\n const piece = this.piece\n const { broken, constraintA, constraintB } = sim\n for (let i = 0; i < sim.count; i++) parent[i] = i\n const find = (i: number): number => {\n let r = i\n while (parent[r] !== r) r = parent[r]!\n // Flatten the path behind it, so the next find from here is one hop.\n while (parent[i] !== r) {\n const up = parent[i]!\n parent[i] = r\n i = up\n }\n return r\n }\n for (let k = 0; k < sim.constraintCount; k++) {\n if (broken[k]) continue\n const ra = find(constraintA[k]!)\n const rb = find(constraintB[k]!)\n if (ra < rb) parent[rb] = ra\n else if (rb < ra) parent[ra] = rb\n }\n for (let i = 0; i < sim.count; i++) piece[i] = gone[i] ? -1 : find(i)\n\n const followers: number[] = []\n const { cols, rows } = sim\n const seen: number[] = []\n const votes: number[] = []\n for (let i = 0; i < sim.count; i++) {\n if (!gone[i]) continue\n const r = (i / cols) | 0\n const c = i % cols\n seen.length = 0\n votes.length = 0\n for (let dr = -1; dr <= 1; dr++) {\n const nr = r + dr\n if (nr < 0 || nr >= rows) continue\n for (let dc = -1; dc <= 1; dc++) {\n const nc = c + dc\n if (nc < 0 || nc >= cols) continue\n const j = nr * cols + nc\n if (gone[j]) continue\n const at = seen.indexOf(piece[j]!)\n if (at < 0) {\n seen.push(piece[j]!)\n votes.push(1)\n } else {\n votes[at]!++\n }\n }\n }\n if (seen.length === 0) continue\n let best = 0\n for (let k = 1; k < seen.length; k++) {\n if (votes[k]! > votes[best]! || (votes[k] === votes[best] && seen[k]! < seen[best]!)) best = k\n }\n piece[i] = seen[best]!\n followers.push(i)\n }\n this.followers = followers\n }\n\n /**\n * A rewound history: the sheet starts over.\n *\n * Paper that had fallen away is paper again, with every spring back to the\n * sheet it was cut from — solved from where it lies, the solve would haul it\n * up off the floor through the sheet in a tangle. And the curl it rolled\n * into belonged to a front that has not passed yet.\n */\n private rewind(): void {\n this.sim.restore()\n this.curlWeight.fill(0)\n this.torn.fill(0)\n this.mend = true\n }\n\n private reset(): void {\n const { sim } = this\n if (this.holed) this.rewind()\n sim.invMass.fill(1)\n sim.restBend.fill(0)\n sim.broken.fill(0)\n sim.restLength.set(sim.naturalLength)\n this.gone.fill(0)\n this.curlWeight.fill(0)\n this.followers = []\n this.holed = false\n this.version = -1\n sim.wake()\n }\n}\n","import { rollRadius, windAngle } from '../deformers/roll'\n\n/**\n * A strip of paper paying off a roll, and the pile it makes when it lands.\n *\n * The one simulation in the library with a DRIVING BODY. Cloth is a passive\n * grid that gravity and wind act on; this is a kinematic roll that the host\n * turns, extruding paper into a chain that is then left to fall. Scroll the\n * page, the roll spins, paper pays out, and it buckles into an accordion on\n * the floor. The pile is the point — everything else here exists to make it\n * possible.\n */\nexport interface StripParams {\n /**\n * The host's scroll position, in world units of paper it would like to see.\n * MONOTONIC and unbounded — bind it to `scrollY * k`, not to a 0..1\n * progress. The sim differentiates it, so only the delta between frames is\n * read and the absolute value never matters.\n */\n scroll: number\n /** How tightly the paper is wound: thin layers and many turns, or few and fat. */\n tightness: number\n /** Radius of the cardboard tube. The roll never pays out past it. */\n core: number\n /** Paper already hanging before the first scroll — a roll always has a leaf out. */\n tail: number\n /** Spacing of the perforations, in world units. One sheet's worth of strip. */\n perforation: number\n /** How much a perforation remembers being folded. 0 = a fresh roll, 1 = a used one. */\n crease: number\n /** Bend stiffness of the paper between perforations. 1 = card, 0 = cloth. */\n stiffness: number\n /** Broadside air drag. Paper is light and wide; this is what makes it float down. */\n drag: number\n gravity: number\n /** How far below the roll the paper lands. A distance, not a signed y. */\n floor: number\n /** How long the roll coasts after the scroll stops. 0 = stops dead, 1 = free-spinning. */\n inertia: number\n}\n\nconst FIXED_DT = 1 / 120\n/** Paper is inextensible; it takes more iterations than cloth to hold that. */\nconst SOLVER_ITERATIONS = 8\nconst SLEEP_EPSILON = 1e-7\nconst SLEEP_FRAMES = 45\n\n/** Layer gap at `tightness` 0 and 1 — visible thickness, not a real 60µm ply. */\nconst LOOSE = 0.055\nconst TIGHT = 0.012\n\n/**\n * Chain nodes per perforated panel.\n *\n * The floor is about four — below that a panel is a straight line and cannot\n * buckle. The number is far above that floor because the ROLL, not the pile,\n * sets the requirement: the same nodes that fold on the floor are the ones\n * drawing the spiral, and a wound turn is only as round as the nodes spanning\n * it. At five to a panel a full roll is a visible sixteen-sided polygon and\n * the innermost turn is drawn with FOUR nodes at 85° a step, which is coarse\n * enough that the chords cut clean through the neighbouring wrap and the\n * spiral comes apart into a sawtooth. See {@link safeSpiralRadius}.\n *\n * Affordable: the preset's chain is 198 nodes and costs 0.13 ms a frame,\n * under a hundredth of a 60fps budget. The chain is one-dimensional, so\n * resolution here is cheap in a way a cloth grid's never is.\n */\nconst NODES_PER_PANEL = 16\n/** Verlet nodes are two vertices each; this is the geometry budget, not the physics one. */\nconst MAX_NODES = 440\nconst MIN_NODES = 8\n\n/**\n * The bend constraint's constants were tuned at this spacing. Panels are\n * jointed every `segment`, so a finer chain has proportionally more joints\n * bending the same panel — without scaling by this, raising the resolution\n * for the roll's sake would quietly turn every panel to cloth.\n */\nconst REFERENCE_SEGMENT = 0.0375\n\n/**\n * Arc span the broadside/along-length split is measured over, in world units.\n *\n * Deliberately a DISTANCE rather than \"the two neighbouring nodes\". The split\n * decides how much of a node's motion the air resists, so a tangent estimated\n * from whatever happens to be adjacent makes drag a function of the node\n * count: a coarse chain reads a bend as travel along its own length and\n * barely damps it, a fine one reads the same bend as broadside and damps it\n * hard. Measured over a fixed span the answer is the same at any resolution,\n * which is what lets the roll's tessellation be raised without re-tuning\n * every drag constant beneath it.\n */\nconst TANGENT_SPAN = 0.09\n\n/** Share of a pull's unmet reach the roll gives up per substep. */\nconst PULL_STIFFNESS = 0.35\n\n/**\n * Solver iterations that also push overlapping folds apart.\n *\n * Self-collision used to run once, after the constraint loop had finished,\n * which is too late to matter in a pile: separating two folds moves them off\n * their rest lengths, and with no iterations left to restore those the next\n * substep pulled them straight back through each other. Interleaving the last\n * few passes lets length and separation settle together, which is the only\n * way a heap holds its own height.\n */\nconst COLLIDING_ITERATIONS = 4\n\n/** How much of a segment overlap is resolved per collision pass. */\nconst COLLISION_RELAXATION = 0.35\n\n/**\n * Tightest radius this chain can wind to without the spiral cutting through\n * itself.\n *\n * A wrap is drawn as a polygon of `segment`-long chords, and a chord of\n * length `s` on a circle of radius `r` dips `s²/8r` inside it. Once that dip\n * exceeds half the gap between wraps, the chord crosses into the wrap\n * beneath — so `s²/8r < t/2`, and the spiral must stop at `s²/4t`.\n *\n * Sizing a roll with {@link rollRadius} lands the innermost wrap exactly on\n * the core, so a well-proportioned roll never reaches this. It is here\n * because `core`, `tightness` and the sheet's length are independent numbers\n * a caller may set to anything, and \"wound tighter than it can be drawn\" has\n * to degrade to a smooth tight coil rather than to a starburst.\n */\nfunction safeSpiralRadius(segment: number, thickness: number): number {\n return thickness > 0 ? (segment * segment) / (4 * thickness) : 0\n}\n\nexport function layerThickness(tightness: number): number {\n return LOOSE - Math.min(1, Math.max(0, tightness)) * (LOOSE - TIGHT)\n}\n\n/**\n * How many nodes a strip of this length wants. Exported because the MESH has\n * to be built before the sim is — the geometry is a 2×N quad strip and its\n * row count has to agree with the chain exactly.\n */\nexport function stripNodeCount(length: number, perforation: number): number {\n const seg = Math.max(perforation, 1e-3) / NODES_PER_PANEL\n return Math.min(MAX_NODES, Math.max(MIN_NODES, Math.round(length / seg) + 1))\n}\n\n/**\n * The longest strip this chain can still draw properly, for a given\n * perforation spacing.\n *\n * {@link stripNodeCount} is CAPPED, and the cap does not fail loudly: past it\n * the node count stops growing, so `segment` (which is `length / (count - 1)`)\n * grows instead, and every constant that was tuned per node quietly changes\n * meaning. The first thing to break is the roll — a longer chord on the same\n * radius dips further inside the wrap beneath it, so the spiral heads for the\n * {@link safeSpiralRadius} threshold and comes apart into a starburst.\n *\n * Exported because it is a UI limit as much as a physics one: a length slider\n * that runs past this hands the user a roll that visibly falls apart, and the\n * editor has no other way to know where the ceiling is. The constants that set\n * it live here, so the derivation does too.\n */\nexport function maxStripLength(perforation: number): number {\n const seg = Math.max(perforation, 1e-3) / NODES_PER_PANEL\n // count = round(L/seg) + 1 must stay <= MAX_NODES, and `round` gives half a\n // step of slack before the cap actually binds.\n return (MAX_NODES - 1 - 0.5) * seg\n}\n\n/**\n * Verlet chain in the y–z plane, extruded from a kinematic roll.\n *\n * **The chain does not grow.** Nodes are never spawned or destroyed; they are\n * RECLASSIFIED. Every node exists from the first frame, and the ones that\n * have not been paid out yet are placed analytically on the roll's spiral\n * each substep while the rest run free. The boundary between the two walks\n * along the chain as paper feeds.\n *\n * That is worth the paragraph because the obvious implementation — spawn a\n * particle at the anchor as `L` grows — needs a resizing vertex buffer, has\n * to invent a velocity for each new particle, and pops visibly at the seam.\n * Here the buffer is fixed, rewind is the same code path run backwards, and\n * the tangential velocity the spec asks new paper to inherit falls out for\n * free: a node released from the spiral was already being moved along it, so\n * its Verlet velocity is the roll's surface velocity on the frame it lets go.\n *\n * **It simulates two dimensions, not three.** The strip hangs in y, folds in\n * z, and keeps its full width in x with no twist. Toilet paper piles in the\n * plane it unrolls in, so the third axis buys almost nothing visually and\n * costs the thing that actually matters — self-collision stays a 2D query,\n * which is what lets the folds stack instead of passing through each other.\n */\nexport class StripSim {\n /** Chain length. Node 0 is the deepest wrap; node `count-1` is the free tip. */\n readonly count: number\n /** Rest spacing between neighbours, in world units. */\n readonly segment: number\n /** Node centreline, y/z interleaved. x is implicit: the strip never twists. */\n private readonly pos: Float64Array\n private readonly prev: Float64Array\n /** Arc distance from the tip, per node. */\n private readonly arc: Float64Array\n /** 1 where a perforation hinges, and the sign of the crease it remembers. */\n private readonly perforated: Int8Array\n\n /** Bend gain correction for this chain's node spacing. See {@link REFERENCE_SEGMENT}. */\n private readonly bendScale: number\n /** Half-width, in nodes, of the window the drag tangent is measured over. */\n private readonly tangentNodes: number\n private readonly halfWidth: number\n private readonly totalLength: number\n /**\n * Paper that can never be paid out, because its inner end is glued to the\n * tube — which is true of every roll you have ever used.\n *\n * Without it the roll pays out to nothing, `firstFreeIndex` reaches 0, and\n * every node the roll was made of becomes free paper and falls: the whole\n * roll drops off its holder and lands flat on the pile. One wrap held back\n * leaves a cylinder at the core radius on the holder, which is what an\n * empty roll looks like and the closest this library can get to drawing a\n * cardboard tube out of the one sheet it has.\n */\n private tubeStub: number\n private params: StripParams\n\n /** Paid-out length: how much paper is off the roll. */\n private paid: number\n /** Angular velocity of the roll, rad/s. The thing that coasts. */\n private omega = 0\n /**\n * Whether anything has turned the roll yet — a scroll delta or a hand.\n *\n * `tail` is the opening pose, and editing it should re-pose the roll; but\n * once the host has scrolled, `paid` is the simulation's own state and\n * re-posing would yank the paper back out of the pile.\n */\n private driven = false\n private lastScroll: number\n private primed = false\n\n /** Node held by the pointer, or -1. Kinematic while held, like a wound node. */\n private grabbed = -1\n private grabY = 0\n private grabZ = 0\n\n private stillFrames = 0\n private accumulator = 0\n private time = 0\n asleep = false\n\n // Spatial hash for self-collision. Sized once, refilled in place — the\n // per-substep collision pass allocates nothing.\n private readonly cellOf: Int32Array\n private readonly bucketStart: Int32Array\n private readonly bucketItems: Int32Array\n private readonly bucketFill: Int32Array\n private readonly tableSize: number\n\n constructor(length: number, width: number, params: StripParams) {\n this.params = { ...params }\n this.totalLength = length\n this.halfWidth = width / 2\n this.count = stripNodeCount(length, params.perforation)\n this.segment = length / (this.count - 1)\n this.bendScale = Math.min(1, this.segment / REFERENCE_SEGMENT)\n this.tangentNodes = Math.max(1, Math.round(TANGENT_SPAN / this.segment))\n\n this.pos = new Float64Array(this.count * 2)\n this.prev = new Float64Array(this.count * 2)\n this.arc = new Float64Array(this.count)\n this.perforated = new Int8Array(this.count)\n\n for (let i = 0; i < this.count; i++) {\n this.arc[i] = (this.count - 1 - i) * this.segment\n }\n // A perforation sits wherever the arc distance from the tip crosses a\n // multiple of the spacing. The sign alternates so the pile accordions\n // instead of curling one way forever.\n const spacing = Math.max(params.perforation, this.segment * 2)\n for (let i = 0; i < this.count - 1; i++) {\n const here = Math.floor(this.arc[i]! / spacing)\n const next = Math.floor(this.arc[i + 1]! / spacing)\n if (here !== next) this.perforated[i] = here % 2 === 0 ? 1 : -1\n }\n\n this.tableSize = 1 << Math.ceil(Math.log2(Math.max(16, this.count * 2)))\n this.cellOf = new Int32Array(this.count)\n this.bucketStart = new Int32Array(this.tableSize + 1)\n this.bucketItems = new Int32Array(this.count)\n this.bucketFill = new Int32Array(this.tableSize)\n\n this.tubeStub = this.stubFor(params.core)\n this.paid = Math.min(params.tail, this.usableLength)\n this.lastScroll = params.scroll\n this.layOut()\n }\n\n /**\n * Local-space y the pile builds on, after centring. A host placing a\n * shadow catcher or a contact shadow needs this; it cannot derive it,\n * because the composition is offset to sit on the origin.\n */\n get floorY(): number {\n return -this.params.floor + this.centreOffset\n }\n\n /**\n * How far the whole composition is lifted so that it straddles the origin.\n *\n * The roll's axis is the sim's origin, which would park a long drop\n * entirely below the frame — `<Paper>` and the editor both look at the\n * origin through about two world units, and neither fits a camera to the\n * content. `unroll` learned the same lesson and left a note about it: a\n * composition anchored anywhere but the origin needs a bespoke camera at\n * every call site.\n *\n * Measured against the FULL radius rather than the current one, so it is a\n * constant for a given config. Deriving it from the live radius would drift\n * the entire pile upward as the roll ran down.\n */\n private get centreOffset(): number {\n return (this.params.floor - this.outerRadius) / 2\n }\n\n /**\n * The same centring, along the axis the pile actually grows in.\n *\n * Everything here is built around the DROP LINE — the z the paper leaves\n * the roll at — and that line is not the origin and does not stay put. It\n * starts at 0 on a full roll and travels back to `core - outerRadius` as\n * the roll runs down (see {@link tangentZ}), because the spiral's centre is\n * fixed and the tangent point walks in toward it. The pile builds around\n * wherever the line has been, so a composition that ignores this is offset\n * by half that travel before a single fold has landed, and z is DEPTH —\n * the axis a fixed head-on camera has the least room in.\n *\n * A constant for a given config, for the reason {@link centreOffset} is:\n * derived from the live radius it would slide the whole composition\n * backwards as the roll emptied, which reads far worse than sitting still\n * slightly off centre. Centring the line's travel splits the difference\n * between a full roll and an empty one.\n */\n private get centreShift(): number {\n return (this.outerRadius - this.params.core) / 2\n }\n\n /** Outer radius of what is still wound. Shrinks to `core` as the roll empties. */\n get radius(): number {\n return rollRadius(this.totalLength - this.paid, this.params.core, layerThickness(this.params.tightness))\n }\n\n /** Radius of the full roll. Fixes the spiral's centre, which must not move. */\n private get outerRadius(): number {\n return rollRadius(this.totalLength, this.params.core, layerThickness(this.params.tightness))\n }\n\n /**\n * The wrap that never leaves: one full turn around the core, but never so\n * much of a short sheet that there is nothing left to unroll.\n *\n * A method rather than a constant because `core` is a live control. It was\n * a constructor-time `readonly`, which meant dragging `core` moved the\n * radius the spiral is drawn at while `usableLength` and the end stop kept\n * answering for the old tube — the roll would run past its own floor, or\n * stop short of it, depending on which way the slider went.\n */\n private stubFor(core: number): number {\n return Math.min(Math.PI * 2 * core, this.totalLength * 0.3)\n }\n\n /** Paper that can actually leave the roll — everything but the glued stub. */\n private get usableLength(): number {\n return this.totalLength - this.tubeStub\n }\n\n /** How much paper is left to give. `0` is down to the tube, `1` is untouched. */\n get remaining(): number {\n return 1 - this.paid / this.usableLength\n }\n\n /**\n * Where the paper leaves the roll: the frontmost point of the current\n * outer wrap. The spiral's CENTRE is fixed (a lesson the `roll` deformer\n * paid for — see its notes), so as the roll runs down the tangent point\n * travels back toward the holder and the strip hangs closer to it. That\n * drift is real and worth keeping.\n */\n private get tangentZ(): number {\n return this.radius - this.outerRadius\n }\n\n /** Place every node: the wound ones on the spiral, the free ones straight down. */\n private layOut(): void {\n const firstFree = this.firstFreeIndex()\n for (let i = 0; i < this.count; i++) {\n const p = i * 2\n if (i < firstFree) {\n this.spiralPoint(this.arc[i]! - this.paid, p, this.pos)\n } else {\n this.pos[p] = -(this.paid - this.arc[i]!)\n this.pos[p + 1] = this.tangentZ\n }\n }\n this.prev.set(this.pos)\n }\n\n /** First node that has come off the roll. Everything below it is kinematic. */\n private firstFreeIndex(): number {\n // arc[i] <= paid means node i has been paid out. arc decreases with i.\n const free = Math.ceil(this.count - 1 - this.paid / this.segment)\n return Math.min(this.count - 1, Math.max(0, free))\n }\n\n /**\n * Position of a point `wound` along the spiral from the tangent point,\n * written into `out` at offset `o`.\n *\n * Angle 0 is the tangent point at the front of the roll; winding runs up\n * over the top, which is the \"over\" hang. The radius falls by one layer\n * per turn, so the wraps are concentric and exactly a thickness apart.\n */\n private spiralPoint(wound: number, o: number, out: Float64Array): void {\n const r0 = this.radius\n const thickness = layerThickness(this.params.tightness)\n const k = thickness / (Math.PI * 2)\n const phi = windAngle(Math.max(0, wound), r0, k)\n const floor = Math.max(this.params.core, safeSpiralRadius(this.segment, thickness))\n const r = Math.max(floor, r0 - k * phi)\n out[o] = r * Math.sin(phi)\n out[o + 1] = -this.outerRadius + r * Math.cos(phi)\n }\n\n setParams(params: Partial<StripParams>): void {\n let changed = false\n const tailBefore = this.params.tail\n for (const key of [\n 'scroll',\n 'tightness',\n 'core',\n 'tail',\n 'crease',\n 'stiffness',\n 'drag',\n 'gravity',\n 'floor',\n 'inertia',\n ] as const) {\n const value = params[key]\n if (value !== undefined && value !== this.params[key]) {\n this.params[key] = value\n changed = true\n }\n }\n // `perforation` is structural — it sets the node count and the hinge map,\n // so it cannot be patched in place. PaperMesh rebuilds the sim on it.\n\n // Two params own derived state, and both are live sliders in the editor.\n // Patching `this.params` alone left that state answering for the old\n // value: `core` sizes the glued stub, and `tail` IS the paid-out length\n // on a roll nobody has scrolled yet, so without this a tail drag did\n // nothing at all and a core drag desynced the end stop from the spiral.\n if (params.core !== undefined) {\n this.tubeStub = this.stubFor(params.core)\n // A bigger stub can leave less usable paper than is already out.\n this.paid = Math.min(this.paid, this.usableLength)\n }\n if (params.tail !== undefined && tailBefore !== this.params.tail) {\n // Only while the roll is still sitting at its opening pose. Once the\n // host has scrolled, `paid` is the simulation's own state and a tail\n // edit must not yank the paper back.\n if (!this.driven) {\n this.paid = Math.min(this.params.tail, this.usableLength)\n this.layOut()\n }\n }\n if (changed) this.wake()\n }\n\n wake(): void {\n this.asleep = false\n this.stillFrames = 0\n }\n\n /**\n * Take hold of the paper at a point, in the same y–z the vertex buffer is\n * written in — mesh-local coordinates, the lift already applied. Returns the\n * node caught, or -1 when there is no free paper to catch.\n *\n * Speaking the buffer's coordinates rather than the solver's is the whole\n * contract here: a caller has a raycast hit on the mesh and nothing else,\n * and the centring lift is an internal detail it has no way to know.\n *\n * Only paper that has left the roll can be caught — a wound node belongs to\n * the spiral, and pinning one would be pinning the roll itself.\n */\n grabNearest(y: number, z: number): number {\n const firstFree = this.firstFreeIndex()\n const localY = y - this.centreOffset\n const localZ = z - this.centreShift\n let best = -1\n let bestDist = Infinity\n for (let i = firstFree; i < this.count; i++) {\n const dy = this.pos[i * 2]! - localY\n const dz = this.pos[i * 2 + 1]! - localZ\n const d = dy * dy + dz * dz\n if (d < bestDist) {\n bestDist = d\n best = i\n }\n }\n this.grabbed = best\n this.grabY = localY\n this.grabZ = localZ\n this.wake()\n return best\n }\n\n moveGrab(y: number, z: number): void {\n if (this.grabbed < 0) return\n this.grabY = y - this.centreOffset\n this.grabZ = z - this.centreShift\n this.wake()\n }\n\n release(): void {\n this.grabbed = -1\n }\n\n /** Whether a pointer currently holds the paper. */\n get held(): boolean {\n return this.grabbed >= 0\n }\n\n step(delta: number): void {\n // A scroll delta must never be dropped just because the sim had gone to\n // sleep — the whole input path is \"the number changed\".\n if (this.params.scroll !== this.lastScroll) this.wake()\n if (this.asleep) return\n this.accumulator = Math.min(this.accumulator + delta, FIXED_DT * 4)\n while (this.accumulator >= FIXED_DT) {\n this.substep(FIXED_DT)\n this.accumulator -= FIXED_DT\n }\n }\n\n private substep(dt: number): void {\n this.time += dt\n this.driveRoll(dt)\n this.pullFeed(dt)\n this.integrate(dt)\n const firstFree = this.firstFreeIndex()\n this.pinWound(firstFree)\n for (let iter = 0; iter < SOLVER_ITERATIONS; iter++) {\n this.solveDistance(firstFree)\n this.solveBend(firstFree)\n if (iter >= SOLVER_ITERATIONS - COLLIDING_ITERATIONS) {\n this.solveSelfCollision(firstFree)\n this.solveFloor(firstFree)\n }\n this.pinWound(firstFree)\n }\n this.solveFloor(firstFree)\n }\n\n /**\n * Turn the roll. Scroll enters as an angle the roll OWES, which a leaky\n * integrator spends into angular velocity — so a steady scroll gives a\n * steady spin and a flick spikes and coasts down.\n *\n * `ΔL = R·Δθ` with the CURRENT radius, which is why the radius has to be\n * read inside the loop: a nearly-empty roll spins fast and gives up very\n * little paper for the same scroll, and that is the whole tell that a roll\n * is running out.\n */\n private driveRoll(dt: number): void {\n const scroll = this.params.scroll\n if (!this.primed) {\n // First frame: adopt the host's scroll origin rather than reading it as\n // one enormous delta and firing the whole roll off at once.\n this.lastScroll = scroll\n this.primed = true\n }\n // The host asks in world units of paper; the roll answers in radians. The\n // conversion is against the FULL radius, which is a constant — so one\n // scroll unit is about one unit of paper on a fresh roll, and less and\n // less as it empties.\n //\n // Dividing by the CURRENT radius instead is the obvious way to write this\n // and is wrong twice over: `ΔL = R·Δθ` multiplies the same radius straight\n // back, so it cancels and the roll pays out the same paper however full it\n // is — the exact tell this sim exists to show — and because the divisor\n // shrinks as the roll empties, the last of the paper leaves in a runaway\n // that slams into the end stop.\n const impulse = (scroll - this.lastScroll) / this.outerRadius\n this.lastScroll = scroll\n\n // The roll is a flywheel and a scroll delta is an ANGULAR IMPULSE on it,\n // not an angle the roll owes. A damped flywheel given impulse `J` turns\n // `J·tau` in total, so scaling the impulse by `1/tau` makes the paper a\n // given scroll pays out independent of how long the roll coasts —\n // `inertia` then buys the coast and nothing else, which is the only way\n // it is usable as a knob.\n //\n // Adding the impulse to a persistent `omega` WITHOUT that scaling is the\n // trap: the decay tail spends every increment ~tau/dt times over, so the\n // roll empties in a quarter-second whatever it is asked for.\n const tau = 0.012 + this.params.inertia * 0.55\n this.omega = this.omega * Math.exp(-dt / tau) + impulse / tau\n if (Math.abs(this.omega) < 1e-6) this.omega = 0\n\n // ΔL = R·Δθ at the CURRENT radius: a nearly-empty roll spins fast and\n // gives up very little paper, which is how a roll reads as running out.\n const next = this.paid + this.radius * this.omega * dt\n if (next !== this.paid) this.driven = true\n this.paid = Math.min(this.usableLength, Math.max(0, next))\n // Down to the tube (or fully rewound): the roll cannot keep turning.\n if (this.paid === 0 || this.paid === this.usableLength) this.omega = 0\n }\n\n /**\n * Take hold of the paper and pull, and the roll turns — the interaction the\n * real object is famous for.\n *\n * It is driven by TENSION rather than by mapping hand travel to an angle.\n * Paper does not stretch, so if the hand is further from the roll than there\n * is paper to reach it, the only way the constraint can be satisfied is for\n * the roll to give up more. That one rule gets the whole behaviour for free:\n * a slow pull feeds smoothly, a fast yank spins the roll and it carries on\n * after release, and pushing the paper back toward the roll does nothing at\n * all — which is exactly right, because slack does not rewind a roll. Only\n * scrolling up does.\n */\n private pullFeed(dt: number): void {\n if (this.grabbed < 0 || this.grabbed < this.firstFreeIndex()) return\n // How far the hand is from where the paper leaves the roll, against how\n // much paper there is between those two points.\n const reach = Math.hypot(this.grabY, this.grabZ - this.tangentZ)\n const available = this.paid - this.arc[this.grabbed]!\n const over = reach - available\n if (over <= 1e-6) return\n\n const feed = Math.min(over * PULL_STIFFNESS, this.usableLength - this.paid)\n if (feed <= 0) return\n this.paid += feed\n // Keep the flywheel in step with the hand, so letting go mid-pull leaves\n // the roll spinning at the speed it was actually being pulled at.\n this.omega = feed / (this.radius * dt)\n }\n\n /**\n * Verlet with ANISOTROPIC drag. A strip of paper barely notices the air\n * when it moves along its own length and is stopped almost dead when it\n * moves broadside, which is the difference between paper that floats down\n * and a rope that drops. Damping the velocity uniformly — the obvious\n * thing, and what cloth does — gets neither.\n */\n private integrate(dt: number): void {\n const { gravity, drag } = this.params\n const p = this.pos\n const dt2 = dt * dt\n const firstFree = this.firstFreeIndex()\n // Broadside drag is strong; along-length drag is nearly nothing.\n const across = Math.exp(-(0.6 + drag * 11) * dt)\n const along = Math.exp(-(0.4 + drag * 0.8) * dt)\n\n let travel = 0\n for (let i = firstFree; i < this.count; i++) {\n const o = i * 2\n if (i === this.grabbed) {\n // The hand owns this node. Its previous position is left alone, so\n // the chain feels the hand's velocity rather than a teleport.\n p[o] = this.grabY\n p[o + 1] = this.grabZ\n continue\n }\n const y = p[o]!\n const z = p[o + 1]!\n let vy = y - this.prev[o]!\n let vz = z - this.prev[o + 1]!\n\n // Segment tangent over a fixed arc span, clamped to what exists.\n const a = Math.max(firstFree, i - this.tangentNodes) * 2\n const b = Math.min(this.count - 1, i + this.tangentNodes) * 2\n let ty = p[b]! - p[a]!\n let tz = p[b + 1]! - p[a + 1]!\n const len = Math.hypot(ty, tz)\n if (len > 1e-9) {\n ty /= len\n tz /= len\n const vt = vy * ty + vz * tz\n // Normal component is whatever is left once the tangent one is out.\n const ny = vy - vt * ty\n const nz = vz - vt * tz\n vy = vt * ty * along + ny * across\n vz = vt * tz * along + nz * across\n }\n\n this.prev[o] = y\n this.prev[o + 1] = z\n // A vertical strip is in unstable equilibrium and will never pick a\n // side to fall toward. This is the nudge that lets it choose.\n const noise = Math.sin(this.time * 2.3 + i * 1.7) * 6e-5\n p[o] = y + vy - gravity * 3.2 * dt2\n p[o + 1] = z + vz + noise\n travel = Math.max(travel, vy * vy + vz * vz)\n }\n\n if (this.omega === 0 && this.grabbed < 0) {\n if (travel < SLEEP_EPSILON) {\n if (++this.stillFrames > SLEEP_FRAMES) this.asleep = true\n } else this.stillFrames = 0\n } else this.stillFrames = 0\n }\n\n /** Wound nodes are the roll's, not the solver's: rewrite them every pass. */\n private pinWound(firstFree: number): void {\n for (let i = 0; i < firstFree; i++) {\n this.spiralPoint(this.arc[i]! - this.paid, i * 2, this.pos)\n }\n // The first two free nodes leave along the tangent, so the strip comes\n // off the roll straight instead of kinking at the anchor.\n const tz = this.tangentZ\n for (let i = firstFree; i < Math.min(this.count, firstFree + 2); i++) {\n if (i === this.grabbed) continue\n const o = i * 2\n this.pos[o + 1] = this.pos[o + 1]! + (tz - this.pos[o + 1]!) * 0.5\n }\n if (this.grabbed >= firstFree) {\n this.pos[this.grabbed * 2] = this.grabY\n this.pos[this.grabbed * 2 + 1] = this.grabZ\n }\n }\n\n /** Paper does not stretch. Distance constraints run at full strength. */\n private solveDistance(firstFree: number): void {\n const p = this.pos\n const rest = this.segment\n for (let i = Math.max(0, firstFree - 1); i < this.count - 1; i++) {\n const a = i * 2\n const b = (i + 1) * 2\n const dy = p[b]! - p[a]!\n const dz = p[b + 1]! - p[a + 1]!\n const dist = Math.hypot(dy, dz)\n if (dist < 1e-9) continue\n const diff = ((dist - rest) / dist) * 0.5\n // A wound node is the roll's and a held one is the hand's; neither\n // moves, so its partner takes the whole correction.\n const aFixed = i < firstFree || i === this.grabbed\n const bFixed = i + 1 === this.grabbed\n if (aFixed && bFixed) continue\n const aw = aFixed ? 0 : bFixed ? 2 : 1\n const bw = bFixed ? 0 : aFixed ? 2 : 1\n p[a] = p[a]! + dy * diff * aw\n p[a + 1] = p[a + 1]! + dz * diff * aw\n p[b] = p[b]! - dy * diff * bw\n p[b + 1] = p[b + 1]! - dz * diff * bw\n }\n }\n\n /**\n * The bend constraint, and the reason this is not a rope preset.\n *\n * Every joint wants to be straight. A joint AT A PERFORATION wants it far\n * less, and may want a slight fold instead — those are the hinges the pile\n * folds at, and the alternating sign is what turns a heap into an\n * accordion. Uniform stiffness gives a coil; no stiffness gives a rope.\n */\n private solveBend(firstFree: number): void {\n const p = this.pos\n const { stiffness, crease } = this.params\n const start = Math.max(firstFree + 1, 1)\n for (let i = start; i < this.count - 1; i++) {\n const hinge = this.perforated[i]!\n // A perforation keeps a small fraction of the sheet's own stiffness.\n // Scaled by the node spacing so a panel bends the same however finely\n // the chain is cut: more joints over the same panel each do less.\n const k = (hinge !== 0 ? stiffness * 0.06 : stiffness) * 0.45 * this.bendScale\n if (k <= 0) continue\n const a = (i - 1) * 2\n const m = i * 2\n const b = (i + 1) * 2\n\n let ty = (p[a]! + p[b]!) * 0.5\n let tz = (p[a + 1]! + p[b + 1]!) * 0.5\n if (hinge !== 0 && crease > 0) {\n // A used roll remembers its creases: offset the rest position off the\n // chord, on the side this perforation folded to last time.\n let cy = p[b]! - p[a]!\n let cz = p[b + 1]! - p[a + 1]!\n const len = Math.hypot(cy, cz)\n if (len > 1e-9) {\n cy /= len\n cz /= len\n const bow = crease * this.segment * 0.35 * hinge\n ty += -cz * bow\n tz += cy * bow\n }\n }\n\n const dy = (ty - p[m]!) * k\n const dz = (tz - p[m + 1]!) * k\n if (i !== this.grabbed) {\n p[m] = p[m]! + dy\n p[m + 1] = p[m + 1]! + dz\n }\n // Push the neighbours the other way so bending cannot drag the chain.\n if (i - 1 >= firstFree && i - 1 !== this.grabbed) {\n p[a] = p[a]! - dy * 0.5\n p[a + 1] = p[a + 1]! - dz * 0.5\n }\n if (i + 1 !== this.grabbed) {\n p[b] = p[b]! - dy * 0.5\n p[b + 1] = p[b + 1]! - dz * 0.5\n }\n }\n }\n\n /**\n * Folds stack on each other instead of passing through. Without this the\n * pile collapses into a single flat line on the floor and there is nothing\n * to look at, which is the entire reason the preset exists.\n *\n * **Segment against segment, not node against node.** The obvious version\n * puts a sphere on every node and pushes overlapping pairs apart, and it\n * leaks: paper is thinner than the chain is finely cut — the layer gap here\n * is 0.027 against a node spacing of 0.037 — so those spheres do not touch\n * each other, and the chain is a string of beads with gaps between them\n * rather than a continuous tube. Another fold threads straight through a\n * gap, and once it is through, the point test pushes it out the far side\n * instead of back. It shows up exactly as a sheet edge buried in a surface.\n *\n * Testing the SEGMENTS closes the gaps, because a segment is the whole\n * length of paper between two nodes and not just its ends. The cost is a\n * closest-approach solve per candidate pair instead of a subtraction, which\n * is why the hash cell is sized to `segment + d`: a pair that can possibly\n * touch has its midpoints inside that, so a 3×3 neighbourhood is a complete\n * search rather than a hopeful one.\n *\n * Spatial hash over preallocated arrays, refilled by counting sort — no\n * allocation, and it does not degrade when the whole strip lands in one\n * cell, which is exactly what a pile IS.\n */\n private solveSelfCollision(firstFree: number): void {\n this.freeFrom = firstFree\n const p = this.pos\n const d = Math.max(layerThickness(this.params.tightness), 1e-4)\n const n = this.count\n const last = n - 2 // index of the final segment (i, i+1)\n if (last < firstFree + 2) return\n const cell = this.segment + d\n const inv = 1 / cell\n const table = this.tableSize\n const mask = table - 1\n\n const starts = this.bucketStart\n const items = this.bucketItems\n const placed = this.bucketFill\n starts.fill(0)\n placed.fill(0)\n\n // Hash each segment by its midpoint.\n for (let i = firstFree; i <= last; i++) {\n const my = (p[i * 2]! + p[(i + 1) * 2]!) * 0.5\n const mz = (p[i * 2 + 1]! + p[(i + 1) * 2 + 1]!) * 0.5\n const h = (((Math.floor(my * inv) * 92837111) ^ (Math.floor(mz * inv) * 689287499)) >>> 0) & mask\n this.cellOf[i] = h\n starts[h + 1]!++\n }\n for (let c = 0; c < table; c++) starts[c + 1]! += starts[c]!\n for (let i = firstFree; i <= last; i++) {\n const h = this.cellOf[i]!\n items[starts[h]! + placed[h]!++] = i\n }\n\n for (let i = firstFree; i <= last; i++) {\n const my = (p[i * 2]! + p[(i + 1) * 2]!) * 0.5\n const mz = (p[i * 2 + 1]! + p[(i + 1) * 2 + 1]!) * 0.5\n const cy = Math.floor(my * inv)\n const cz = Math.floor(mz * inv)\n for (let oy = -1; oy <= 1; oy++) {\n for (let oz = -1; oz <= 1; oz++) {\n const h = ((((cy + oy) * 92837111) ^ ((cz + oz) * 689287499)) >>> 0) & mask\n const end = starts[h + 1]!\n for (let e = starts[h]!; e < end; e++) {\n const j = items[e]!\n // Each pair once, and never segments that share a node or sit next\n // to one — those are held by the distance and bend constraints,\n // and separating them would only fight those.\n if (j >= i + 2) this.separate(i, j, d)\n }\n }\n }\n }\n }\n\n /**\n * Push segments `(i, i+1)` and `(j, j+1)` apart to `d`, if they are closer.\n *\n * Closest approach between two 2D segments, then the correction shared over\n * the four endpoints by how near each is to the touching point — so a fold\n * caught at its middle moves bodily, and one grazed at its tip barely\n * pivots. Wound and held nodes are the roll's and the hand's, so they take\n * none of it and their partner takes the lot.\n */\n private separate(i: number, j: number, d: number): void {\n const p = this.pos\n const a = i * 2\n const b = (i + 1) * 2\n const c = j * 2\n const e = (j + 1) * 2\n\n const uy = p[b]! - p[a]!\n const uz = p[b + 1]! - p[a + 1]!\n const vy = p[e]! - p[c]!\n const vz = p[e + 1]! - p[c + 1]!\n const wy = p[a]! - p[c]!\n const wz = p[a + 1]! - p[c + 1]!\n\n const uu = uy * uy + uz * uz\n const vv = vy * vy + vz * vz\n if (uu < 1e-12 || vv < 1e-12) return\n const uv = uy * vy + uz * vz\n const uw = uy * wy + uz * wz\n const vw = vy * wy + vz * wz\n\n const denom = uu * vv - uv * uv\n let s = denom > 1e-12 ? (uv * vw - vv * uw) / denom : 0\n s = s < 0 ? 0 : s > 1 ? 1 : s\n let t = (uv * s + vw) / vv\n if (t < 0) {\n t = 0\n s = -uw / uu\n } else if (t > 1) {\n t = 1\n s = (uv - uw) / uu\n }\n s = s < 0 ? 0 : s > 1 ? 1 : s\n\n let ny = p[c]! + vy * t - (p[a]! + uy * s)\n let nz = p[c + 1]! + vz * t - (p[a + 1]! + uz * s)\n let dist = Math.hypot(ny, nz)\n if (dist >= d) return\n if (dist < 1e-9) {\n // Exactly through each other: separate along this segment's own normal,\n // which is the only direction left that means anything.\n ny = -uz\n nz = uy\n dist = Math.hypot(ny, nz)\n if (dist < 1e-12) return\n ny = -ny\n nz = -nz\n }\n\n const push = ((d - dist) / dist) * COLLISION_RELAXATION\n const gy = ny * push\n const gz = nz * push\n // Normalized so the touching point itself moves the full correction.\n const ki = 0.5 / ((1 - s) * (1 - s) + s * s)\n const kj = 0.5 / ((1 - t) * (1 - t) + t * t)\n this.nudge(i, -gy * (1 - s) * ki, -gz * (1 - s) * ki)\n this.nudge(i + 1, -gy * s * ki, -gz * s * ki)\n this.nudge(j, gy * (1 - t) * kj, gz * (1 - t) * kj)\n this.nudge(j + 1, gy * t * kj, gz * t * kj)\n }\n\n /** First free node for the substep in flight — `nudge` runs in the innermost\n * collision loop and must not recompute it per call. */\n private freeFrom = 0\n\n /** Move a node, unless the roll or the hand owns it. */\n private nudge(i: number, dy: number, dz: number): void {\n if (i === this.grabbed || i < this.freeFrom) return\n this.pos[i * 2] = this.pos[i * 2]! + dy\n this.pos[i * 2 + 1] = this.pos[i * 2 + 1]! + dz\n }\n\n /** Restitution 0, friction high. Paper lands and stays; it does not slide. */\n private solveFloor(firstFree: number): void {\n const p = this.pos\n // Sim-space: the floor is `floor` below the roll's axis. The centring\n // offset is applied on the way OUT, in writeInto, so the solver never has\n // to carry it.\n const floor = -this.params.floor\n for (let i = firstFree; i < this.count; i++) {\n const o = i * 2\n // A hand may hold paper anywhere, including below the ground line.\n if (i === this.grabbed || p[o]! >= floor) continue\n p[o] = floor\n // Kill the bounce outright, and almost all of the slide with it.\n this.prev[o] = floor\n this.prev[o + 1] = this.prev[o + 1]! + (p[o + 1]! - this.prev[o + 1]!) * 0.92\n }\n }\n\n /**\n * Write the chain into a 2×N quad strip, in PlaneGeometry vertex order:\n * row-major, top row first, x left→right. Row `i` is node `i`, so the\n * content texture runs down the strip and folds with it.\n */\n writeInto(out: Float32Array): void {\n const lift = this.centreOffset\n const shift = this.centreShift\n for (let i = 0; i < this.count; i++) {\n const o = i * 2\n const y = this.pos[o]! + lift\n const z = this.pos[o + 1]! + shift\n const v = i * 6\n out[v] = -this.halfWidth\n out[v + 1] = y\n out[v + 2] = z\n out[v + 3] = this.halfWidth\n out[v + 4] = y\n out[v + 5] = z\n }\n }\n}\n","import * as THREE from 'three'\nimport { useEffect, useMemo } from 'react'\nimport { useFrame } from '@react-three/fiber'\nimport CustomShaderMaterial from 'three-custom-shader-material'\nimport type { LightingName, SurfaceConfig } from '../config/schema'\nimport type { Stock } from '../core/stock'\nimport { composeSurface } from './compose'\nimport { resolveCreases, type CreaseShading } from './creases'\nimport { useLightRig } from '../scene/rig'\nimport { DAMAGE_LOOK_DEFAULTS, type DamageSource } from './damageContract'\nimport { useDamageTexture } from './useDamageTexture'\n\nexport interface PaperMaterialProps {\n stock: Stock\n texture: THREE.Texture | null\n /** content.back rendered on the reverse side (stock color otherwise). */\n backTexture?: THREE.Texture | null\n surface: SurfaceConfig\n thickness: number\n /** World dims — perforation holes are sized in world units. */\n sheet?: { width: number; height: number }\n /**\n * Scene lighting — transmission is measured against its key light. A\n * `<LightRig>` above this material wins over it: in a stage the paper is\n * lit by the hall, not by the preset it was authored with.\n */\n lighting?: LightingName\n /**\n * Crease lines to draw, resolved from `surface.creaseLines` plus whatever\n * the sheet remembers being folded along. Left off, only the authored ones\n * render — which is what a material with no memory behind it should do.\n */\n creases?: CreaseShading[]\n /** Char, wet, heat and missing paper over the sheet's UV. See `DamageSource`. */\n damage?: DamageSource | null\n}\n\n/**\n * The paper's skin: MeshStandardMaterial (real lighting preserved) extended\n * with the composed surface-effect chunks. Content textures are sampled by\n * OUR fragment (not material.map) so front and back faces can differ — real\n * paper doesn't mirror its front through the sheet. Programs rebuild only\n * on structure change; value edits mutate uniforms in place.\n */\nexport function PaperMaterial({\n stock,\n texture,\n backTexture,\n surface,\n thickness,\n sheet,\n lighting = 'studio',\n creases,\n damage,\n}: PaperMaterialProps) {\n const rig = useLightRig(lighting)\n const damageTexture = useDamageTexture(damage)\n const composed = composeSurface(\n surface,\n stock,\n thickness,\n {\n hasFrontMap: Boolean(texture),\n hasBackMap: Boolean(backTexture),\n hasDamage: Boolean(damageTexture),\n },\n sheet,\n rig,\n creases ?? resolveCreases(surface, [], sheet ?? { width: 1, height: 1.4 }),\n )\n\n // Uniform objects bound to the current program; stable per structure.\n // biome-ignore lint/correctness/useExhaustiveDependencies: Uniform objects are bound per shader program — rebinding on value change would drop the binding every frame.\n const bound = useMemo(() => composed.uniforms, [composed.structureKey])\n useEffect(() => {\n for (const [key, uniform] of Object.entries(composed.uniforms)) {\n if (\n !bound[key] ||\n key === 'uFrontMap' ||\n key === 'uBackMap' ||\n key === 'uDamage' ||\n key === 'uDamageDetail' ||\n key === 'uDamageTime' ||\n key.startsWith('uLook')\n ) {\n continue\n }\n if (bound[key].value instanceof THREE.Color && uniform.value instanceof THREE.Color) {\n ;(bound[key].value as THREE.Color).copy(uniform.value)\n } else {\n bound[key].value = uniform.value\n }\n }\n })\n useEffect(() => {\n if (bound.uFrontMap) bound.uFrontMap.value = texture\n if (bound.uBackMap) bound.uBackMap.value = backTexture ?? null\n if (bound.uDamage) bound.uDamage.value = damageTexture\n }, [bound, texture, backTexture, damageTexture])\n // The fray follows the quality tier, which can change at any moment, so it\n // is read off the source each frame rather than baked into the program.\n useFrame((state) => {\n if (!bound.uDamageDetail) return\n // The burn's clock when it has one, so a replayed burn's ember line\n // flickers the same way twice; the frame clock otherwise. Clamped for the\n // same reason `detail` is.\n if (bound.uDamageTime) {\n const time = damage?.time ?? state.clock.elapsedTime\n bound.uDamageTime.value = Number.isFinite(time) ? time : 0\n }\n // How the burn is drawn, from the source's look over the defaults. Read\n // each frame like `detail`, so a slider in a lab moves it live.\n if (bound.uLook0) {\n const look = { ...DAMAGE_LOOK_DEFAULTS, ...damage?.look }\n const v = (x: number, d: number) => (Number.isFinite(x) ? x : d)\n const d = DAMAGE_LOOK_DEFAULTS\n ;(bound.uLook0.value as THREE.Vector4).set(\n v(look.emberWidth, d.emberWidth),\n v(look.emberIntensity, d.emberIntensity),\n v(look.emberCoverage, d.emberCoverage),\n v(look.emberFlicker, d.emberFlicker),\n )\n ;(bound.uLook1!.value as THREE.Vector4).set(\n v(look.emberGlow, d.emberGlow),\n v(look.lipWidth, d.lipWidth),\n v(look.lipBrightness, d.lipBrightness),\n v(look.charWarmth, d.charWarmth),\n )\n ;(bound.uLook2!.value as THREE.Vector4).set(\n v(look.charCracks, d.charCracks),\n v(look.scorchReach, d.scorchReach),\n v(look.scorchDarkness, d.scorchDarkness),\n v(look.fingers, d.fingers),\n )\n ;(bound.uLook3!.value as THREE.Vector4).set(\n v(look.edgeWave, d.edgeWave),\n v(look.edgeBite, d.edgeBite),\n v(look.sparkle, d.sparkle),\n 0,\n )\n }\n // Clamped rather than trusted: `detail` is a number on a public\n // interface, and an infinite one reaching the shader is multiplied by a\n // zero somewhere in the fray and paints NaN across the whole sheet.\n const detail = damage?.detail ?? 1\n bound.uDamageDetail.value = Number.isFinite(detail) ? Math.min(1, Math.max(0, detail)) : 1\n })\n\n return (\n <>\n <CustomShaderMaterial\n key={composed.structureKey}\n baseMaterial={THREE.MeshStandardMaterial}\n vertexShader={composed.vertexShader}\n fragmentShader={composed.fragmentShader}\n uniforms={bound}\n color=\"#ffffff\"\n roughness={stock.roughness}\n metalness={0}\n transparent={stock.opacity < 1}\n opacity={stock.opacity}\n alphaTest={composed.alphaTest}\n side={THREE.DoubleSide}\n />\n {/*\n What the shadow pass draws, when this sheet removes paper — see\n `ComposedSurface.depth`. Same uniforms object as the colour program,\n so the damage texture, the deckle and the perforation state are the\n ones the viewer sees. RGBA packing, which is what three's shadow maps\n read; three copies `side` and `alphaTest` over from the colour\n material itself.\n */}\n {composed.depth ? (\n <CustomShaderMaterial\n key={`${composed.structureKey}:depth`}\n attach=\"customDepthMaterial\"\n baseMaterial={THREE.MeshDepthMaterial}\n vertexShader={composed.depth.vertexShader}\n fragmentShader={composed.depth.fragmentShader}\n uniforms={bound}\n depthPacking={THREE.RGBADepthPacking}\n />\n ) : null}\n </>\n )\n}\n","export const defaultCsmDefinitions = /* glsl */ `\r\n \r\n#ifdef IS_VERTEX\r\n vec3 csm_Position;\r\n vec4 csm_PositionRaw;\r\n vec3 csm_Normal;\r\n\r\n // csm_PointSize\r\n #ifdef IS_POINTSMATERIAL\r\n float csm_PointSize;\r\n #endif\r\n#else\r\n vec4 csm_DiffuseColor;\r\n vec4 csm_FragColor;\r\n float csm_UnlitFac;\r\n\r\n // csm_Emissive, csm_Roughness, csm_Metalness\r\n #if defined IS_MESHSTANDARDMATERIAL || defined IS_MESHPHYSICALMATERIAL\r\n vec3 csm_Emissive;\r\n float csm_Roughness;\r\n float csm_Metalness;\r\n float csm_Iridescence;\r\n \r\n #if defined IS_MESHPHYSICALMATERIAL\r\n float csm_Clearcoat;\r\n float csm_ClearcoatRoughness;\r\n vec3 csm_ClearcoatNormal;\r\n float csm_Transmission;\r\n float csm_Thickness;\r\n #endif\r\n #endif\r\n\r\n // csm_AO\r\n #if defined IS_MESHSTANDARDMATERIAL || defined IS_MESHPHYSICALMATERIAL || defined IS_MESHBASICMATERIAL || defined IS_MESHLAMBERTMATERIAL || defined IS_MESHPHONGMATERIAL || defined IS_MESHTOONMATERIAL\r\n float csm_AO;\r\n #endif\r\n\r\n // csm_FragNormal\r\n #if defined IS_MESHLAMBERTMATERIAL || defined IS_MESHMATCAPMATERIAL || defined IS_MESHNORMALMATERIAL || defined IS_MESHPHONGMATERIAL || defined IS_MESHPHYSICALMATERIAL || defined IS_MESHSTANDARDMATERIAL || defined IS_MESHTOONMATERIAL || defined IS_SHADOWMATERIAL \r\n vec3 csm_FragNormal;\r\n #endif\r\n\r\n float csm_DepthAlpha;\r\n#endif\r\n`;\r\n\r\nexport const defaultCsmMainDefinitions = /* glsl */ `\r\n\r\n#ifdef IS_VERTEX\r\n // csm_Position & csm_PositionRaw\r\n #ifdef IS_UNKNOWN\r\n csm_Position = vec3(0.0);\r\n csm_PositionRaw = vec4(0.0);\r\n csm_Normal = vec3(0.0);\r\n #else\r\n csm_Position = position;\r\n csm_PositionRaw = projectionMatrix * modelViewMatrix * vec4(position, 1.);\r\n csm_Normal = normal;\r\n #endif\r\n\r\n // csm_PointSize\r\n #ifdef IS_POINTSMATERIAL\r\n csm_PointSize = size;\r\n #endif\r\n#else\r\n csm_UnlitFac = 0.0;\r\n\r\n // csm_DiffuseColor & csm_FragColor\r\n #if defined IS_UNKNOWN || defined IS_SHADERMATERIAL || defined IS_MESHDEPTHMATERIAL || defined IS_MESHDISTANCEMATERIAL || defined IS_MESHNORMALMATERIAL || defined IS_SHADOWMATERIAL\r\n csm_DiffuseColor = vec4(1.0, 0.0, 1.0, 1.0);\r\n csm_FragColor = vec4(1.0, 0.0, 1.0, 1.0);\r\n #else\r\n #ifdef USE_MAP\r\n vec4 _csm_sampledDiffuseColor = texture2D(map, vMapUv);\r\n\r\n #ifdef DECODE_VIDEO_TEXTURE\r\n // inline sRGB decode (TODO: Remove this code when https://crbug.com/1256340 is solved)\r\n _csm_sampledDiffuseColor = vec4(mix(pow(_csm_sampledDiffuseColor.rgb * 0.9478672986 + vec3(0.0521327014), vec3(2.4)), _csm_sampledDiffuseColor.rgb * 0.0773993808, vec3(lessThanEqual(_csm_sampledDiffuseColor.rgb, vec3(0.04045)))), _csm_sampledDiffuseColor.w);\r\n #endif\r\n\r\n csm_DiffuseColor = vec4(diffuse, opacity) * _csm_sampledDiffuseColor;\r\n csm_FragColor = vec4(diffuse, opacity) * _csm_sampledDiffuseColor;\r\n #else\r\n csm_DiffuseColor = vec4(diffuse, opacity);\r\n csm_FragColor = vec4(diffuse, opacity);\r\n #endif\r\n #endif\r\n\r\n // csm_Emissive, csm_Roughness, csm_Metalness\r\n #if defined IS_MESHSTANDARDMATERIAL || defined IS_MESHPHYSICALMATERIAL\r\n csm_Emissive = emissive;\r\n csm_Roughness = roughness;\r\n csm_Metalness = metalness;\r\n\r\n #ifdef USE_IRIDESCENCE\r\n csm_Iridescence = iridescence;\r\n #else\r\n csm_Iridescence = 0.0;\r\n #endif\r\n\r\n #if defined IS_MESHPHYSICALMATERIAL\r\n #ifdef USE_CLEARCOAT\r\n csm_Clearcoat = clearcoat;\r\n csm_ClearcoatRoughness = clearcoatRoughness;\r\n #else\r\n csm_Clearcoat = 0.0;\r\n csm_ClearcoatRoughness = 0.0;\r\n #endif\r\n\r\n #ifdef USE_TRANSMISSION\r\n csm_Transmission = transmission;\r\n csm_Thickness = thickness;\r\n #else\r\n csm_Transmission = 0.0;\r\n csm_Thickness = 0.0;\r\n #endif\r\n #endif\r\n #endif\r\n\r\n // csm_AO\r\n #if defined IS_MESHSTANDARDMATERIAL || defined IS_MESHPHYSICALMATERIAL || defined IS_MESHBASICMATERIAL || defined IS_MESHLAMBERTMATERIAL || defined IS_MESHPHONGMATERIAL || defined IS_MESHTOONMATERIAL\r\n csm_AO = 0.0;\r\n #endif\r\n\r\n #if defined IS_MESHLAMBERTMATERIAL || defined IS_MESHMATCAPMATERIAL || defined IS_MESHNORMALMATERIAL || defined IS_MESHPHONGMATERIAL || defined IS_MESHPHYSICALMATERIAL || defined IS_MESHSTANDARDMATERIAL || defined IS_MESHTOONMATERIAL || defined IS_SHADOWMATERIAL \r\n #ifdef FLAT_SHADED\r\n vec3 fdx = dFdx( vViewPosition );\r\n vec3 fdy = dFdy( vViewPosition );\r\n csm_FragNormal = normalize( cross( fdx, fdy ) );\r\n #else\r\n csm_FragNormal = normalize(vNormal);\r\n #ifdef DOUBLE_SIDED\r\n csm_FragNormal *= gl_FrontFacing ? 1.0 : - 1.0;\r\n #endif\r\n #endif\r\n #endif\r\n\r\n csm_DepthAlpha = 1.0;\r\n#endif\r\n`;\r\n\r\nexport const defaultVertDefinitions = /* glsl */ `\r\n varying mat4 csm_internal_vModelViewMatrix;\r\n`;\r\n\r\nexport const defaultVertMain = /* glsl */ `\r\n csm_internal_vModelViewMatrix = modelViewMatrix;\r\n`;\r\n\r\nexport const defaultFragDefinitions = /* glsl */ `\r\n varying mat4 csm_internal_vModelViewMatrix;\r\n`;\r\n\r\nexport const defaultFragMain = /* glsl */ `\r\n \r\n`;\r\n","export const keywordMap = {\r\n // PBR (frag)\r\n diffuse: \"csm_DiffuseColor\", // Color + alpha\r\n roughness: \"csm_Roughness\", // Roughness\r\n metalness: \"csm_Metalness\", // Metalness\r\n emissive: \"csm_Emissive\", // Emissive\r\n ao: \"csm_AO\", // AO\r\n fragNormal: \"csm_FragNormal\", // Fragment Normal\r\n clearcoat: \"csm_Clearcoat\", // Clearcoat factor\r\n clearcoatRoughness: \"csm_ClearcoatRoughness\", // Clearcoat roughness\r\n clearcoatNormal: \"csm_ClearcoatNormal\", // Clearcoat normals\r\n transmission: \"csm_Transmission\", // Transmission\r\n thickness: \"csm_Thickness\", // Thickness\r\n iridescence: \"csm_Iridescence\", // Iridescence\r\n\r\n // Extras\r\n pointSize: \"csm_PointSize\", // gl_PointSize (Frag)\r\n fragColor: \"csm_FragColor\", // gl_FragColor (Frag)\r\n depthAlpha: \"csm_DepthAlpha\", // Depth (MeshDepthMaterial)\r\n unlitFac: \"csm_UnlitFac\", // Unlit factor (mix between csm_FragColor and csm_DiffuseColor)\r\n\r\n // Vert\r\n position: \"csm_Position\", // gl_Position\r\n positionRaw: \"csm_PositionRaw\", // gl_Position (without projection)\r\n normal: \"csm_Normal\", // Vertex Normal\r\n};\r\n","import { keywordMap } from \"./keywordMap\";\r\n\r\n// Map of CSM keywords to the materials they are available in\r\n// Some keywords are only available in certain materials\r\nexport const availabilityMap = {\r\n [`${keywordMap.position}`]: \"*\",\r\n [`${keywordMap.positionRaw}`]: \"*\",\r\n [`${keywordMap.normal}`]: \"*\",\r\n [`${keywordMap.depthAlpha}`]: \"*\",\r\n [`${keywordMap.pointSize}`]: [\"PointsMaterial\"],\r\n\r\n [`${keywordMap.diffuse}`]: \"*\",\r\n [`${keywordMap.fragColor}`]: \"*\",\r\n [`${keywordMap.fragNormal}`]: \"*\",\r\n [`${keywordMap.unlitFac}`]: \"*\",\r\n [`${keywordMap.emissive}`]: [\"MeshStandardMaterial\", \"MeshPhysicalMaterial\"],\r\n [`${keywordMap.roughness}`]: [\"MeshStandardMaterial\", \"MeshPhysicalMaterial\"],\r\n [`${keywordMap.metalness}`]: [\"MeshStandardMaterial\", \"MeshPhysicalMaterial\"],\r\n [`${keywordMap.iridescence}`]: [\r\n \"MeshStandardMaterial\",\r\n \"MeshPhysicalMaterial\",\r\n ],\r\n [`${keywordMap.ao}`]: [\r\n \"MeshStandardMaterial\",\r\n \"MeshPhysicalMaterial\",\r\n \"MeshBasicMaterial\",\r\n \"MeshLambertMaterial\",\r\n \"MeshPhongMaterial\",\r\n \"MeshToonMaterial\",\r\n ],\r\n [`${keywordMap.clearcoat}`]: [\"MeshPhysicalMaterial\"],\r\n [`${keywordMap.clearcoatRoughness}`]: [\"MeshPhysicalMaterial\"],\r\n [`${keywordMap.clearcoatNormal}`]: [\"MeshPhysicalMaterial\"],\r\n [`${keywordMap.transmission}`]: [\"MeshPhysicalMaterial\"],\r\n [`${keywordMap.thickness}`]: [\"MeshPhysicalMaterial\"],\r\n};\r\n","import * as THREE from \"three\";\r\nimport { CSMPatchMap } from \"../types\";\r\nimport { keywordMap } from \"./keywordMap\";\r\n\r\n// Map of CSM keywords to their substitutions\r\nexport const defaultPatchMap: CSMPatchMap = {\r\n // VERT\r\n \"*\": {\r\n \"#include <lights_physical_fragment>\":\r\n THREE.ShaderChunk.lights_physical_fragment,\r\n \"#include <transmission_fragment>\": THREE.ShaderChunk.transmission_fragment,\r\n },\r\n [`${keywordMap.normal}`]: {\r\n \"#include <beginnormal_vertex>\": `\r\n vec3 objectNormal = ${keywordMap.normal};\r\n #ifdef USE_TANGENT\r\n\t vec3 objectTangent = vec3( tangent.xyz );\r\n #endif\r\n `,\r\n },\r\n [`${keywordMap.position}`]: {\r\n \"#include <begin_vertex>\": `\r\n vec3 transformed = ${keywordMap.position};\r\n `,\r\n },\r\n [`${keywordMap.positionRaw}`]: {\r\n \"#include <project_vertex>\": `\r\n #include <project_vertex>\r\n gl_Position = ${keywordMap.positionRaw};\r\n `,\r\n },\r\n [`${keywordMap.pointSize}`]: {\r\n \"gl_PointSize = size;\": `\r\n gl_PointSize = ${keywordMap.pointSize};\r\n `,\r\n },\r\n\r\n // FRAG\r\n\r\n [`${keywordMap.diffuse}`]: {\r\n \"#include <color_fragment>\": `\r\n #include <color_fragment>\r\n diffuseColor = ${keywordMap.diffuse};\r\n `,\r\n },\r\n [`${keywordMap.fragColor}`]: {\r\n \"#include <opaque_fragment>\": `\r\n #include <opaque_fragment>\r\n gl_FragColor = mix(gl_FragColor, ${keywordMap.fragColor}, ${keywordMap.unlitFac});\r\n `,\r\n },\r\n [`${keywordMap.emissive}`]: {\r\n \"vec3 totalEmissiveRadiance = emissive;\": `\r\n vec3 totalEmissiveRadiance = ${keywordMap.emissive};\r\n `,\r\n },\r\n [`${keywordMap.roughness}`]: {\r\n \"#include <roughnessmap_fragment>\": `\r\n #include <roughnessmap_fragment>\r\n roughnessFactor = ${keywordMap.roughness};\r\n `,\r\n },\r\n [`${keywordMap.metalness}`]: {\r\n \"#include <metalnessmap_fragment>\": `\r\n #include <metalnessmap_fragment>\r\n metalnessFactor = ${keywordMap.metalness};\r\n `,\r\n },\r\n [`${keywordMap.ao}`]: {\r\n \"#include <aomap_fragment>\": `\r\n #include <aomap_fragment>\r\n reflectedLight.indirectDiffuse *= 1. - ${keywordMap.ao};\r\n `,\r\n },\r\n [`${keywordMap.fragNormal}`]: {\r\n \"#include <normal_fragment_maps>\": `\r\n #include <normal_fragment_maps>\r\n normal = ${keywordMap.fragNormal};\r\n `,\r\n },\r\n [`${keywordMap.depthAlpha}`]: {\r\n \"gl_FragColor = vec4( vec3( 1.0 - fragCoordZ ), opacity );\": `\r\n gl_FragColor = vec4( vec3( 1.0 - fragCoordZ ), opacity * 1.0 - ${keywordMap.depthAlpha} );\r\n `,\r\n \"gl_FragColor = packDepthToRGBA( fragCoordZ );\": `\r\n if(${keywordMap.depthAlpha} < 1.0) discard;\r\n gl_FragColor = packDepthToRGBA( dist );\r\n `,\r\n \"gl_FragColor = packDepthToRGBA( dist );\": `\r\n if(${keywordMap.depthAlpha} < 1.0) discard;\r\n gl_FragColor = packDepthToRGBA( dist );\r\n `,\r\n },\r\n [`${keywordMap.clearcoat}`]: {\r\n \"material.clearcoat = clearcoat;\": `material.clearcoat = ${keywordMap.clearcoat};`,\r\n },\r\n [`${keywordMap.clearcoatRoughness}`]: {\r\n \"material.clearcoatRoughness = clearcoatRoughness;\": `material.clearcoatRoughness = ${keywordMap.clearcoatRoughness};`,\r\n },\r\n [`${keywordMap.clearcoatNormal}`]: {\r\n \"#include <clearcoat_normal_fragment_begin>\": `\r\n vec3 csm_coat_internal_orthogonal = csm_ClearcoatNormal - (dot(csm_ClearcoatNormal, nonPerturbedNormal) * nonPerturbedNormal);\r\n vec3 csm_coat_internal_projectedbump = mat3(csm_internal_vModelViewMatrix) * csm_coat_internal_orthogonal;\r\n vec3 clearcoatNormal = normalize(nonPerturbedNormal - csm_coat_internal_projectedbump);\r\n `,\r\n },\r\n [`${keywordMap.transmission}`]: {\r\n \"material.transmission = transmission;\": `\r\n material.transmission = ${keywordMap.transmission};\r\n `,\r\n },\r\n [`${keywordMap.thickness}`]: {\r\n \"material.thickness = thickness;\": `\r\n material.thickness = ${keywordMap.thickness};\r\n `,\r\n },\r\n [`${keywordMap.iridescence}`]: {\r\n \"material.iridescence = iridescence;\": `\r\n material.iridescence = ${keywordMap.iridescence};\r\n `,\r\n },\r\n};\r\n","import { keywordMap } from \"./keywordMap\";\r\n\r\n/**\r\n * Map of props to their keywords\r\n * this is because Three only injects some defines if certain properties are set in the material options.\r\n *\r\n * For example, \"clearcoat\" must be set for 3js to include the #USE_CLEARCOAT define in the shader.\r\n * and thus for our custom clearcoar variant to work\r\n */\r\nexport const requiredPropsMap = {\r\n clearcoat: [\r\n keywordMap.clearcoat,\r\n keywordMap.clearcoatNormal,\r\n keywordMap.clearcoatRoughness,\r\n ],\r\n transmission: [keywordMap.transmission],\r\n iridescence: [keywordMap.iridescence],\r\n};\r\n","//https://github.com/sindresorhus/sdbm\r\n\r\nexport default function sdbm(string) {\r\n let hash = 0;\r\n\r\n for (let i = 0; i < string.length; i++) {\r\n hash = string.charCodeAt(i) + (hash << 6) + (hash << 16) - hash;\r\n }\r\n\r\n // Convert it to an unsigned 32-bit integer.\r\n const h = hash >>> 0;\r\n const str = String(h);\r\n return str;\r\n}\r\n","import { MaterialConstructor } from \"./types\";\r\n\r\n// Hacky, yikes!\r\nexport function isConstructor<T extends MaterialConstructor>(\r\n f: T | InstanceType<T>\r\n): f is T {\r\n try {\r\n // @ts-ignore\r\n new f();\r\n } catch (err) {\r\n if ((err as any).message.indexOf(\"is not a constructor\") >= 0) {\r\n return false;\r\n }\r\n }\r\n return true;\r\n}\r\n\r\n// Remove all comments in a string\r\n// both block and inline comments\r\nexport function stripComments(str: string) {\r\n return str.replace(/\\/\\*[\\s\\S]*?\\*\\/|\\/\\/.*/g, \"\");\r\n}\r\n","import * as THREE from \"three\";\r\nimport {\r\n defaultCsmDefinitions,\r\n defaultCsmMainDefinitions,\r\n defaultFragDefinitions,\r\n defaultFragMain,\r\n defaultVertDefinitions,\r\n defaultVertMain,\r\n} from \"./defaults\";\r\nimport { availabilityMap, defaultPatchMap, keywordMap } from \"./maps\";\r\nimport { requiredPropsMap } from \"./maps/requiredPropsMap\";\r\nimport hash from \"./sdbm\";\r\nimport * as TYPES from \"./types\";\r\nimport { isConstructor, stripComments } from \"./utils\";\r\n\r\nexport default class CustomShaderMaterial<\r\n T extends TYPES.MaterialConstructor = typeof THREE.Material\r\n> extends THREE.Material {\r\n uniforms: TYPES.Uniform = {};\r\n vertexShader: string = \"\";\r\n fragmentShader: string = \"\";\r\n\r\n constructor({\r\n baseMaterial,\r\n vertexShader,\r\n fragmentShader,\r\n uniforms,\r\n patchMap,\r\n cacheKey,\r\n ...opts\r\n }: TYPES.CustomShaderMaterialParameters<T>) {\r\n if (!baseMaterial) {\r\n throw new Error(\"CustomShaderMaterial: baseMaterial is required.\");\r\n }\r\n\r\n let base: THREE.Material;\r\n if (isConstructor(baseMaterial)) {\r\n // If base material is a constructor, instantiate it\r\n // if opts is empty, replace it with undefined\r\n const isEmptyOpts = Object.keys(opts).length === 0;\r\n base = new baseMaterial(isEmptyOpts ? undefined : opts);\r\n } else {\r\n // Else, use the already created instance as the base material\r\n // and copy options onto it\r\n base = baseMaterial;\r\n Object.assign(base, opts);\r\n }\r\n\r\n // Blacklist some materials that are not supported\r\n const blackList = [\"ShaderMaterial\", \"RawShaderMaterial\"];\r\n if (blackList.includes(base.type)) {\r\n throw new Error(\r\n `CustomShaderMaterial does not support ${base.type} as a base material.`\r\n );\r\n }\r\n\r\n super();\r\n\r\n // Return a proxy to the base material with CSM types and methods\r\n const extendedBase = base as typeof base & TYPES.CSMProxy<T>;\r\n extendedBase.name = `CustomShaderMaterial<${base.name || base.type}>`;\r\n extendedBase.update = this.update;\r\n extendedBase.__csm = {\r\n prevOnBeforeCompile: base.onBeforeCompile,\r\n baseMaterial: base,\r\n vertexShader,\r\n fragmentShader,\r\n uniforms,\r\n patchMap,\r\n cacheKey,\r\n };\r\n\r\n const prevUniforms = extendedBase.uniforms || {};\r\n const newUniforms = uniforms || {};\r\n const mergedUniforms = { ...prevUniforms, ...newUniforms };\r\n\r\n extendedBase.uniforms = this.uniforms = mergedUniforms;\r\n extendedBase.vertexShader = this.vertexShader = vertexShader || \"\";\r\n extendedBase.fragmentShader = this.fragmentShader = fragmentShader || \"\";\r\n\r\n // Initialize custom shaders\r\n extendedBase.update({\r\n fragmentShader: extendedBase.fragmentShader,\r\n vertexShader: extendedBase.vertexShader,\r\n uniforms: extendedBase.uniforms,\r\n patchMap,\r\n cacheKey,\r\n });\r\n\r\n // Merge \"this\" with the extended base\r\n Object.assign(this, extendedBase);\r\n\r\n // Copy getters and setters from the base material\r\n const gettersAndSetters = Object.getOwnPropertyDescriptors(\r\n Object.getPrototypeOf(extendedBase)\r\n );\r\n\r\n for (const key in gettersAndSetters) {\r\n const descriptor = gettersAndSetters[key];\r\n if (descriptor.get || descriptor.set) {\r\n Object.defineProperty(this, key, descriptor);\r\n }\r\n }\r\n\r\n // Override type setter because of this BS: https://github.com/mrdoob/three.js/blob/841ca14e89f3ec925e071a321958e49a883343c0/src/materials/Material.js#L22\r\n Object.defineProperty(this, \"type\", {\r\n get() {\r\n return base.type;\r\n },\r\n set(value) {\r\n base.type = value;\r\n },\r\n });\r\n\r\n return this;\r\n }\r\n\r\n update({\r\n fragmentShader: _fs,\r\n vertexShader: _vs,\r\n uniforms,\r\n cacheKey,\r\n patchMap,\r\n }: Omit<TYPES.CustomShaderMaterialBaseParameters<T>, \"baseMaterial\">) {\r\n // Strip comments from shaders, makes it so that commented keywords are not detected\r\n const vertexShader = stripComments(_vs || \"\");\r\n const fragmentShader = stripComments(_fs || \"\");\r\n\r\n // Get typed `this` for the proxy\r\n const self = this as typeof this & TYPES.CSMProxy<T>;\r\n\r\n // Replace the shaders if they are provided\r\n if (uniforms) self.uniforms = uniforms;\r\n if (_vs) self.vertexShader = _vs;\r\n if (_fs) self.fragmentShader = _fs;\r\n\r\n // Some keywords require certain properties to be set for their chunks to be included via #ifdef\r\n // so we must check if the shaders contain these keywords and set the properties accordingly\r\n Object.entries(requiredPropsMap).forEach(([prop, matchKeywords]) => {\r\n for (const keyword in matchKeywords) {\r\n const matchKeyword = matchKeywords[keyword];\r\n if (\r\n (fragmentShader && fragmentShader.includes(matchKeyword)) ||\r\n (vertexShader && vertexShader.includes(matchKeyword))\r\n ) {\r\n // @ts-ignore\r\n if (!self[prop]) {\r\n // @ts-ignore\r\n self[prop] = 1;\r\n }\r\n }\r\n }\r\n });\r\n\r\n // Check it the previous onBeforeCompile exists\r\n const prevOnBeforeCompile = self.__csm.prevOnBeforeCompile;\r\n\r\n // Helper function to extend the shader\r\n const extendShader = (\r\n prevShader: string,\r\n newShader?: string,\r\n isFrag?: boolean\r\n ) => {\r\n let mainBody: string | undefined;\r\n let beforeMain: string = \"\";\r\n\r\n // Prepare the main body and beforeMain\r\n if (newShader) {\r\n // Simpler approach to extract main function body\r\n const mainStartIndex = newShader.search(/void\\s+main\\s*\\(\\s*\\)\\s*{/);\r\n if (mainStartIndex !== -1) {\r\n // Get everything before main function\r\n beforeMain = newShader.slice(0, mainStartIndex);\r\n\r\n // Find the matching closing brace using brace counting\r\n let braceCount = 0;\r\n let mainEndIndex = -1;\r\n\r\n for (let i = mainStartIndex; i < newShader.length; i++) {\r\n if (newShader[i] === \"{\") braceCount++;\r\n if (newShader[i] === \"}\") {\r\n braceCount--;\r\n if (braceCount === 0) {\r\n mainEndIndex = i;\r\n break;\r\n }\r\n }\r\n }\r\n\r\n if (mainEndIndex !== -1) {\r\n // Extract main body without the outer braces\r\n const fullMain = newShader.slice(mainStartIndex, mainEndIndex + 1);\r\n mainBody = fullMain.slice(fullMain.indexOf(\"{\") + 1, -1);\r\n }\r\n } else {\r\n beforeMain = newShader;\r\n }\r\n }\r\n\r\n // Set csm_UnlitFac if csm_FragColor is used to preserve\r\n // legacy behavior.\r\n if (isFrag) {\r\n const hasFragColor = newShader\r\n ? newShader.includes(keywordMap.fragColor)\r\n : false;\r\n if (hasFragColor && mainBody) {\r\n mainBody = \"csm_UnlitFac = 1.0;\\n\" + mainBody;\r\n }\r\n }\r\n\r\n const defaultsAlreadyIncluded = prevShader.includes(\"//~CSM_DEFAULTS\");\r\n\r\n // Inject\r\n if (defaultsAlreadyIncluded) {\r\n prevShader = prevShader.replace(\r\n \"void main() {\",\r\n `\r\n // THREE-CustomShaderMaterial by Faraz Shaikh: https://github.com/FarazzShaikh/THREE-CustomShaderMaterial\r\n \r\n ${beforeMain}\r\n \r\n void main() {\r\n `\r\n );\r\n\r\n const lastMainEndIndex = prevShader.lastIndexOf(\"//~CSM_MAIN_END\");\r\n\r\n if (lastMainEndIndex !== -1) {\r\n const toAppend = `\r\n ${mainBody ? `${mainBody}` : \"\"}\r\n //~CSM_MAIN_END\r\n `;\r\n prevShader =\r\n prevShader.slice(0, lastMainEndIndex) +\r\n toAppend +\r\n prevShader.slice(lastMainEndIndex);\r\n }\r\n } else {\r\n const regex = /void\\s*main\\s*\\(\\s*\\)\\s*{/gm;\r\n\r\n prevShader = prevShader.replace(\r\n regex,\r\n `\r\n // THREE-CustomShaderMaterial by Faraz Shaikh: https://github.com/FarazzShaikh/THREE-CustomShaderMaterial\r\n \r\n //~CSM_DEFAULTS\r\n ${isFrag ? defaultFragDefinitions : defaultVertDefinitions}\r\n ${defaultCsmDefinitions}\r\n \r\n ${beforeMain}\r\n \r\n void main() {\r\n {\r\n ${defaultCsmMainDefinitions}\r\n }\r\n ${isFrag ? defaultFragMain : defaultVertMain}\r\n\r\n ${mainBody ? `${mainBody}` : \"\"}\r\n //~CSM_MAIN_END\r\n `\r\n );\r\n }\r\n\r\n return prevShader;\r\n };\r\n\r\n // Override onBeforeCompile\r\n self.onBeforeCompile = (\r\n shader: THREE.WebGLProgramParametersWithUniforms,\r\n renderer: THREE.WebGLRenderer\r\n ) => {\r\n // Apply previous onBeforeCompile\r\n prevOnBeforeCompile?.(shader, renderer);\r\n\r\n const userPatchMap = patchMap || {};\r\n // const mergedPatchMap = { ...defaultPatchMap, ...userPatchMap };\r\n\r\n // Append some defines\r\n const type = self.type;\r\n const typeDefine = type\r\n ? `#define IS_${type.toUpperCase()};\\n`\r\n : `#define IS_UNKNOWN;\\n`;\r\n shader.vertexShader =\r\n typeDefine + \"#define IS_VERTEX\\n\" + shader.vertexShader;\r\n shader.fragmentShader =\r\n typeDefine + \"#define IS_FRAGMENT\\n\" + shader.fragmentShader;\r\n\r\n // Check if the keyword is available in the current material type\r\n const runPatchMap = (_patchMap: TYPES.CSMPatchMap) => {\r\n for (const keyword in _patchMap) {\r\n const doesIncludeInVert =\r\n keyword === \"*\" || (vertexShader && vertexShader.includes(keyword));\r\n const doesIncludeInFrag =\r\n keyword === \"*\" ||\r\n (fragmentShader && fragmentShader.includes(keyword));\r\n\r\n if (doesIncludeInFrag || doesIncludeInVert) {\r\n const availableIn = availabilityMap[keyword];\r\n\r\n if (\r\n availableIn &&\r\n availableIn !== \"*\" &&\r\n (Array.isArray(availableIn)\r\n ? !availableIn.includes(type)\r\n : availableIn !== type)\r\n ) {\r\n console.error(\r\n `CustomShaderMaterial: ${keyword} is not available in ${type}. Shader cannot compile.`\r\n );\r\n return;\r\n }\r\n\r\n const patchMap = _patchMap[keyword];\r\n\r\n for (const toReplace in patchMap) {\r\n const replaceWith = patchMap[toReplace];\r\n\r\n if (typeof replaceWith === \"object\") {\r\n const type = replaceWith.type;\r\n const value = replaceWith.value;\r\n\r\n if (type === \"fs\") {\r\n shader.fragmentShader = shader.fragmentShader.replace(\r\n toReplace,\r\n value\r\n );\r\n } else if (type === \"vs\") {\r\n shader.vertexShader = shader.vertexShader.replace(\r\n toReplace,\r\n value\r\n );\r\n }\r\n } else if (replaceWith) {\r\n shader.vertexShader = shader.vertexShader.replace(\r\n toReplace,\r\n replaceWith\r\n );\r\n shader.fragmentShader = shader.fragmentShader.replace(\r\n toReplace,\r\n replaceWith\r\n );\r\n }\r\n }\r\n }\r\n }\r\n };\r\n\r\n runPatchMap(defaultPatchMap);\r\n runPatchMap(userPatchMap);\r\n\r\n // Extend the shaders\r\n shader.vertexShader = extendShader(\r\n shader.vertexShader,\r\n vertexShader,\r\n false\r\n );\r\n\r\n shader.fragmentShader = extendShader(\r\n shader.fragmentShader,\r\n fragmentShader,\r\n true\r\n );\r\n\r\n if (uniforms) {\r\n shader.uniforms = { ...shader.uniforms, ...self.uniforms };\r\n }\r\n\r\n self.uniforms = shader.uniforms;\r\n };\r\n\r\n const prevCacheKey = self.customProgramCacheKey;\r\n\r\n self.customProgramCacheKey = () => {\r\n return (\r\n (cacheKey?.() || hash((vertexShader || \"\") + (fragmentShader || \"\"))) +\r\n prevCacheKey?.call(self)\r\n );\r\n };\r\n\r\n self.needsUpdate = true;\r\n }\r\n\r\n clone() {\r\n // Get typed `this` for the proxy\r\n const self = this as typeof this & TYPES.CSMProxy<T>;\r\n\r\n // @ts-ignore\r\n const newObj = new self.constructor({\r\n baseMaterial: self.__csm.baseMaterial.clone(),\r\n vertexShader: self.__csm.vertexShader,\r\n fragmentShader: self.__csm.fragmentShader,\r\n uniforms: self.__csm.uniforms,\r\n patchMap: self.__csm.patchMap,\r\n cacheKey: self.__csm.cacheKey,\r\n });\r\n\r\n return newObj;\r\n }\r\n}\r\n\r\nexport {\r\n type CSMPatchMap,\r\n type CSMProxy,\r\n type CustomShaderMaterialParameters,\r\n type MaterialConstructor,\r\n} from \"./types\";\r\n","import { AttachType } from \"@react-three/fiber/dist/declarations/src/core/renderer\";\r\nimport * as React from \"react\";\r\nimport { Material } from \"three\";\r\nimport CustomShaderMaterialImpl, { MaterialConstructor } from \"../index\";\r\nimport { CustomShaderMaterialProps } from \"./types\";\r\n\r\nfunction useDidUpdateEffect(\r\n fn: (...opts: any[]) => any,\r\n inputs: React.DependencyList\r\n) {\r\n const didMountRef = React.useRef(false);\r\n\r\n React.useEffect(() => {\r\n if (didMountRef.current) {\r\n return fn();\r\n }\r\n didMountRef.current = true;\r\n }, inputs);\r\n}\r\n\r\nfunction CustomShaderMaterial<T extends MaterialConstructor>(\r\n {\r\n baseMaterial,\r\n vertexShader,\r\n fragmentShader,\r\n uniforms,\r\n cacheKey,\r\n patchMap,\r\n attach,\r\n ...opts\r\n }: CustomShaderMaterialProps<T>,\r\n ref: React.Ref<InstanceType<T>>\r\n) {\r\n const material = React.useMemo(() => {\r\n return new CustomShaderMaterialImpl({\r\n baseMaterial,\r\n vertexShader,\r\n fragmentShader,\r\n uniforms,\r\n cacheKey,\r\n patchMap,\r\n ...opts,\r\n });\r\n }, [baseMaterial]);\r\n\r\n useDidUpdateEffect(() => {\r\n material.dispose();\r\n material.update({\r\n vertexShader,\r\n fragmentShader,\r\n uniforms,\r\n patchMap,\r\n cacheKey,\r\n });\r\n }, [vertexShader, fragmentShader, uniforms, patchMap, cacheKey]);\r\n\r\n React.useEffect(() => () => material.dispose(), [material]);\r\n\r\n return (\r\n <primitive\r\n ref={ref}\r\n attach={attach ?? \"material\"}\r\n object={material}\r\n {...opts}\r\n />\r\n );\r\n}\r\n\r\n// export default React.forwardRef(CustomShaderMaterial) as <\r\n// T extends MaterialConstructor\r\n// >(\r\n// props: CustomShaderMaterialProps<T> & { ref?: React.Ref<InstanceType<T>> }\r\n// ) => React.ReactElement;\r\n\r\nexport default React.forwardRef(CustomShaderMaterial) as <\r\n T extends MaterialConstructor = typeof Material\r\n>(\r\n props: CustomShaderMaterialProps<T> & {\r\n ref?: React.Ref<CustomShaderMaterialImpl<T>>;\r\n attach?: AttachType;\r\n }\r\n) => React.ReactElement;\r\n\r\nexport { type CustomShaderMaterialProps } from \"./types\";\r\n","import { DAMAGE_LOOK_DEFAULTS } from './damageContract'\nimport * as THREE from 'three'\nimport {\n paperEdges as paperEdgesOrder,\n type LightingName,\n type PaperEdge,\n type SurfaceConfig,\n} from '../config/schema'\nimport type { Stock } from '../core/stock'\nimport { CREASE_RADIUS } from '../deformers/memory'\nimport { resolveCreases, type CreaseShading } from './creases'\nimport type { LightingPreset } from '../scene/lighting'\nimport {\n TRANSLUCENCY_FRAGMENT,\n TRANSLUCENCY_VARYINGS,\n translucencyUniforms,\n translucencyVertexChunk,\n} from './translucency'\n\n/**\n * Surface effects are fragment-side chunks composed into ONE shader program\n * per effect set (grain + deckle + aging = one program). Uniforms are\n * namespaced per effect; shared helpers (noise) are included once.\n */\n\n/**\n * The shaded crease's width, as a fraction of the hinge the geometry bends\n * over.\n *\n * These are two halves of one crease and they are not the same width. The\n * fold deformer rounds a remembered crease over CREASE_RADIUS of\n * world, which is as sharp as a uniform grid can be asked to be; a real crease\n * is a burnished line an order of magnitude finer than that, and the only\n * place it can live is in the normal. So the shading draws the fine line\n * INSIDE the geometric hinge and the two add up.\n *\n * Derived from the deformer's own constant rather than typed out, because the\n * failure it prevents is silent: the shader used to carry its own widths in UV\n * fractions, which agreed with the geometry at exactly one sheet size and\n * drifted apart at every other — and drifted further every time two hands\n * resized the sheet.\n */\nconst SHADED_CREASE = 0.35\n\nexport interface ComposedSurface {\n /** Distinguishes shader *structures* — same key ⇒ same program, only uniforms change. */\n structureKey: string\n vertexShader: string\n fragmentShader: string\n uniforms: Record<string, { value: unknown }>\n /**\n * Anything that removes paper discards via alphaTest rather than blending.\n * That keeps the depth buffer right for the colour pass; it never made the\n * SHADOW right on its own — three's shadow material ignores alpha computed\n * in shader code. `depth`, below, is what does.\n */\n alphaTest: number\n /**\n * A depth-only program for the SHADOW MAP, or null when nothing on this\n * sheet removes paper and three's own depth material is already right.\n *\n * Shadow maps only. drei's `ContactShadows` renders the whole scene through\n * one override material and never reads a mesh's `customDepthMaterial`, so\n * the soft contact shadow under a `<Paper>` still ignores holes — that is a\n * separate pass and a separate fix.\n */\n depth: { vertexShader: string; fragmentShader: string } | null\n}\n\n/** Which content textures exist — part of the shader structure. */\nexport interface SurfaceMaps {\n hasFrontMap: boolean\n hasBackMap: boolean\n /**\n * A damage texture is attached — see `DamageSource`. Optional and false by\n * default, so a sheet nothing has damaged compiles exactly the program it\n * always did: same chunks, same structure key, same alpha test.\n */\n hasDamage?: boolean\n}\n\nconst VERTEX = /* glsl */ `\nvarying vec2 vPaperUv;\n${TRANSLUCENCY_VARYINGS}\nvoid main() {\n vPaperUv = uv;\n${translucencyVertexChunk({ model: 'modelMatrix', position: 'position', normal: 'normal' })}\n}\n`\n\nconst HELPERS = /* glsl */ `\nvarying vec2 vPaperUv;\nuniform float uBackDarken;\nuniform vec2 uSheetSize;\n\n/**\n * Where this fragment is on the sheet, in the sheet's OWN local space —\n * the same coordinates the deformers displace, centred on the sheet.\n *\n * Every effect below measures in these rather than in UV, and the difference\n * is not cosmetic. UV divides the sheet's aspect out, so a 1.2 x 1.5 sheet is\n * a unit square as far as the shader is concerned: fibre drawn round comes out\n * stretched, a tear bites deeper into the short edge than the long one, and a\n * crease line scored at 45 degrees renders at 51. Worse, all three change when\n * the sheet is RESIZED, which makes the paper's own material a function of how\n * big the piece is. Grain is a property of the stock and a crease is a broken\n * fibre; neither knows how large a sheet it was cut from.\n */\nvec2 plLocal() {\n return (vPaperUv - 0.5) * uSheetSize;\n}\n\n/**\n * The paper's relief, in world units above the sheet the mesh describes.\n *\n * Accumulated by whichever effects have a shape as well as a colour, and\n * spent once at the end of main by {@link plPerturb}. One shared field rather\n * than a perturbation per effect, because two effects that both tilt the\n * surface tilt it TOGETHER — a crease across a grained sheet is one surface,\n * not a crease lit on top of a grain lit on top of the paper.\n */\nfloat plHeight;\n\n/**\n * The relief, turned into the normal the lighting actually runs on.\n *\n * This is the change that makes the surface effects respond to light at all.\n * They used to be painted: a crease multiplied a grey band into the albedo\n * and added a fixed white sheen beside it, so the mark looked identical from\n * every angle and under every rig, and turning the sheet under the key light\n * did nothing to it. Real creased paper is two facets meeting at a line —\n * swing it and the crease flips from a dark line to a bright one. Only a\n * normal can do that, so now the effects describe a HEIGHT and the standard\n * material lights it.\n *\n * The maths is Mikkelsen's surface-gradient bump, which is what three's own\n * perturbNormalArb implements, with one deliberate difference: three\n * normalises the screen-space position derivatives, which makes a bump map\n * look the same at any scale and is the right call for a texture. Ours is a\n * real depth in world units — a crease is as deep as it is however close you\n * stand — so the raw derivatives stay, and the ratio between them and the\n * height's is a true surface slope.\n *\n * Analytic height plus screen derivatives also anti-aliases itself for free:\n * as a crease shrinks below a pixel the derivative flattens and the mark\n * fades, rather than crawling.\n */\nvec3 plPerturb(vec3 n, float height) {\n vec2 dH = vec2(dFdx(height), dFdy(height));\n if (dH.x == 0.0 && dH.y == 0.0) return n;\n // View-space position: the varying is its negation, by three's convention.\n vec3 sigmaX = dFdx(-vViewPosition);\n vec3 sigmaY = dFdy(-vViewPosition);\n vec3 r1 = cross(sigmaY, n);\n vec3 r2 = cross(n, sigmaX);\n float det = dot(sigmaX, r1) * (gl_FrontFacing ? 1.0 : -1.0);\n if (abs(det) < 1e-12) return n;\n vec3 grad = sign(det) * (dH.x * r1 + dH.y * r2);\n return normalize(abs(det) * n - grad);\n}\n\n/**\n * A gaussian bell of unit width, pre-filtered against this fragment's own\n * footprint.\n *\n * Convolving a gaussian with the pixel broadens it and flattens it by the\n * same factor, which conserves the integral: a crease seen from across the\n * room dims instead of breaking into a dotted line. s is the distance\n * across the feature in units of its own width, so a caller only ever has to\n * decide how wide the thing is.\n */\nfloat plBell(float s) {\n float px = fwidth(s);\n float widen = sqrt(1.0 + px * px);\n return exp(-(s * s) / (widen * widen)) / widen;\n}\n\nfloat plHash(vec2 p) {\n return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);\n}\n\nfloat plNoise(vec2 p) {\n vec2 i = floor(p);\n vec2 f = fract(p);\n vec2 u = f * f * (3.0 - 2.0 * f);\n return mix(\n mix(plHash(i), plHash(i + vec2(1.0, 0.0)), u.x),\n mix(plHash(i + vec2(0.0, 1.0)), plHash(i + vec2(1.0, 1.0)), u.x),\n u.y\n );\n}\n\nfloat plFbm(vec2 p) {\n float v = 0.0;\n float a = 0.5;\n for (int i = 0; i < 4; i++) {\n v += a * plNoise(p);\n p *= 2.03;\n a *= 0.5;\n }\n return v;\n}\n`\n\nconst edgeFlags = (edges: PaperEdge[]): THREE.Vector4 =>\n new THREE.Vector4(\n edges.includes('top') ? 1 : 0,\n edges.includes('right') ? 1 : 0,\n edges.includes('bottom') ? 1 : 0,\n edges.includes('left') ? 1 : 0,\n )\n\nconst GRAIN_CHUNK = /* glsl */ `\nuniform float uGrainAmount;\nuniform float uGrainBanding;\n\n/**\n * Fibre density, per world unit.\n *\n * Per WORLD UNIT and not per UV, which is the whole fix: the fibre in a sheet\n * is the stock's, and it does not get coarser because someone cut a bigger\n * piece or stretch oval because the piece is taller than it is wide.\n *\n * The number is carried over from when it was a UV frequency, so a sheet one\n * world unit wide is unchanged across its width. Its height is not, and that\n * is the point: a 1.4-tall sheet used to fit the same 240 cycles into a\n * longer span and its fibre ran visibly coarser the other way.\n */\nconst float PL_FIBRE = 240.0;\n\n/**\n * The coarser structure underneath it — paper's tooth, the part that has a\n * SHAPE and not just a colour.\n *\n * Separate from the fibre, and much lower, for a reason worth writing down:\n * the relief is differentiated in screen space, and a field at the fibre's own\n * frequency is a few pixels per cycle at any sane viewing distance, so its\n * derivative is noise and the sheet would sparkle. The tooth is safely above\n * the sampling rate, and it is the scale at which paper actually catches a\n * raking light anyway.\n */\nconst float PL_TOOTH = 70.0;\n\n/**\n * How far the tooth stands proud, in world units, at full grain.\n *\n * Real paper's surface relief is tens of microns. Against a sheet whose width\n * is one world unit — call it A4 — 0.00035 is about 70 microns, and at the\n * tooth's wavelength that is a surface tilting by four degrees or so. Enough\n * to break a specular highlight into paper, not enough to look pebbled.\n */\nconst float PL_TOOTH_RELIEF = 0.00035;\n\nvoid plGrain(inout vec4 color, inout float rough) {\n vec2 local = plLocal();\n float fiber = plFbm(local * PL_FIBRE);\n float fleck = plNoise(local * (PL_FIBRE * 3.75));\n float g = mix(0.5, fiber * 0.75 + fleck * 0.25, uGrainAmount);\n color.rgb *= 0.92 + g * 0.16;\n rough = clamp(rough + (g - 0.5) * uGrainAmount * 0.35, 0.0, 1.0);\n // The tooth, handed to the lighting rather than drawn. A single octave: the\n // relief only needs the scale the eye reads as texture, and the fbm above\n // is already carrying everything finer as colour.\n plHeight += (plNoise(local * PL_TOOTH) - 0.5) * PL_TOOTH_RELIEF * uGrainAmount;\n // Thermal-printer banding: faint horizontal density stripes.\n if (uGrainBanding > 0.0) {\n float band = sin(vPaperUv.y * 700.0) * 0.5 + 0.5;\n color.rgb *= 1.0 - uGrainBanding * 0.05 * band;\n }\n}\n`\n\nconst DECKLE_CHUNK = /* glsl */ `\nuniform vec4 uDeckleEdges; // top, right, bottom, left\nuniform float uDeckleRoughness;\n\n/** Gnaw frequency along a torn edge, per world unit — see {@link plLocal}. */\nconst float PL_DECKLE_GNAW = 26.0;\n\nvoid plDeckle(inout vec4 color) {\n // Distance to each selected edge, gnawed by low-frequency noise.\n //\n // The depth is in world units, taken against the sheet's mean dimension.\n // Against the MEAN rather than each edge's own span, which is what UV\n // amounted to: one roughness used to bite a third deeper into the short\n // edges of a 1 x 1.4 sheet than the long ones, for no reason anybody chose.\n //\n // Still proportional to the sheet rather than absolute, which is a decision\n // and not an oversight. A real deckle is a fibre length and would be the\n // same depth on any size of sheet; roughness is a 0..1 knob someone types,\n // and an absolute one would vanish on a poster and swallow a stamp.\n float depth = (0.012 + uDeckleRoughness * 0.05) * (uSheetSize.x + uSheetSize.y) * 0.5;\n float tear = 1.0;\n float fiberBand = 0.0;\n vec4 dists = vec4(1.0 - vPaperUv.y, 1.0 - vPaperUv.x, vPaperUv.y, vPaperUv.x);\n vec4 alongs = vec4(vPaperUv.x, vPaperUv.y, vPaperUv.x, vPaperUv.y);\n vec4 distScale = vec4(uSheetSize.y, uSheetSize.x, uSheetSize.y, uSheetSize.x);\n vec4 alongScale = vec4(uSheetSize.x, uSheetSize.y, uSheetSize.x, uSheetSize.y);\n for (int e = 0; e < 4; e++) {\n if (uDeckleEdges[e] < 0.5) continue;\n float n = plFbm(vec2(alongs[e] * alongScale[e] * PL_DECKLE_GNAW, float(e) * 7.31)) - 0.5;\n float boundary = depth * (0.55 + n * 1.6);\n float d = dists[e] * distScale[e] - boundary;\n tear = min(tear, step(0.0, d));\n // Lightened fiber band just inside the tear.\n fiberBand = max(fiberBand, smoothstep(depth * 1.4, 0.0, d) * step(0.0, d));\n }\n color.a *= tear;\n color.rgb = mix(color.rgb, vec3(1.0), fiberBand * 0.35);\n}\n`\n\nconst CREASE_CHUNK = /* glsl */ `\nuniform float uCreaseAngles[4];\nuniform float uCreaseStrengths[4];\nuniform float uCreaseOffsets[4];\nuniform float uCreaseWidth;\nuniform int uCreaseCount;\n\n/**\n * Peak tilt of a crease's own facets, as a slope.\n *\n * A gaussian groove of amplitude A and width w reaches a maximum slope of\n * about 0.86 A/w, so an amplitude of 0.55 w peaks near 25 degrees — steep\n * enough that turning the sheet visibly flips the line from dark to bright,\n * shallow enough that it never reads as a fold in its own right. Held as a\n * SLOPE rather than a depth because that is the quantity the lighting\n * responds to, and the only one that stays honest when the width changes.\n */\nconst float PL_CREASE_TILT = 0.55;\n\n/** How much grime a crease traps, at full strength. */\nconst float PL_CREASE_SOIL = 0.1;\n\nvoid plCrease(inout vec4 color, inout float rough) {\n vec2 p = plLocal();\n for (int i = 0; i < 4; i++) {\n if (i >= uCreaseCount) break;\n vec2 dir = vec2(cos(uCreaseAngles[i]), sin(uCreaseAngles[i]));\n // The identical measurement the fold deformer displaces by: signed\n // distance across the line, in the sheet's own space. Shading and\n // geometry cannot place a crease differently when the number they place\n // it by is the same number.\n float s = (dot(p, dir) - uCreaseOffsets[i]) / uCreaseWidth;\n float strength = uCreaseStrengths[i];\n float bell = plBell(s);\n\n // The relief. This is the fine burnished line where the fibres broke, and\n // it is deliberately narrower than the hinge the fold deformer bends\n // over: the mesh carries the wide bend, the shader carries the crease\n // inside it, and the two add up instead of competing. Signed, so a\n // mountain stands proud and a valley cuts in — the same crease read from\n // the other side of the sheet is the other one.\n plHeight += strength * uCreaseWidth * PL_CREASE_TILT * bell;\n\n // What is left for the albedo once the lighting is doing the work: a\n // crease collects dirt and its broken fibres scatter wider. The grey band\n // and the painted-on sheen that used to live here were standing in for a\n // normal, and there is one now.\n float mark = bell * abs(strength);\n color.rgb *= 1.0 - mark * PL_CREASE_SOIL;\n rough = clamp(rough + mark * 0.3, 0.0, 1.0);\n }\n}\n`\n\nconst PERFORATION_CHUNK = /* glsl */ `\nuniform vec4 uPerfEdges; // top, right, bottom, left enabled\nuniform vec4 uPerfTorn; // 1 = ripped-through profile, 0 = clean punches\nuniform float uPerfRadius; // world units\nuniform float uPerfSpacing;\n\nvoid plPerforation(inout vec4 color) {\n // Per-edge distance/along coordinates, converted from UV to world units so\n // hole size is stable across sheet dimensions.\n vec4 dists = vec4(1.0 - vPaperUv.y, 1.0 - vPaperUv.x, vPaperUv.y, vPaperUv.x);\n vec4 alongs = vec4(vPaperUv.x, vPaperUv.y, vPaperUv.x, vPaperUv.y);\n vec4 distScale = vec4(uSheetSize.y, uSheetSize.x, uSheetSize.y, uSheetSize.x);\n vec4 alongScale = vec4(uSheetSize.x, uSheetSize.y, uSheetSize.x, uSheetSize.y);\n float fiber = 0.0;\n for (int e = 0; e < 4; e++) {\n if (uPerfEdges[e] < 0.5) continue;\n float d = dists[e] * distScale[e];\n float a = alongs[e] * alongScale[e];\n // Signed distance along the edge to the nearest hole center.\n float cell = mod(a + uPerfSpacing * 0.5, uPerfSpacing) - uPerfSpacing * 0.5;\n if (uPerfTorn[e] < 0.5) {\n // Intact: clean semicircular punches on the edge line (alphaTest, not\n // blending — shadow correctness).\n if (length(vec2(cell, d)) < uPerfRadius) color.a = 0.0;\n } else {\n // Torn: ripped profile following the hole rhythm — alternating tabs and\n // notches, gnawed by noise, with a lightened fiber band along the tear.\n float rhythm = abs(sin(a / uPerfSpacing * 3.14159265));\n float n = plNoise(vec2(a * 40.0, float(e) * 7.31)) - 0.5;\n float cut = uPerfRadius * (0.35 + rhythm * 1.35 + n * 0.9);\n if (d < cut) color.a = 0.0;\n fiber = max(fiber, smoothstep(uPerfRadius * 2.4, 0.0, d - cut) * step(cut, d));\n }\n }\n color.rgb = mix(color.rgb, vec3(1.0), fiber * 0.4);\n}\n`\n\n/**\n * What happened to the paper, read from the damage texture — the part both\n * programs need: the fray and the cut.\n *\n * Written so that an untouched field is an exact identity — char 0, wet 0,\n * presence 1 multiplies by one and mixes by zero — because attaching a field\n * to a sheet before anything has burnt it must not change a single pixel.\n *\n * Presence is cut with `step`, not multiplied into alpha. Multiplying would\n * put the edge of a hole wherever `opacity × presence` crosses the alpha test,\n * which is presence 0.5 on an opaque stock and 0.81 on the 0.62-opacity one:\n * the same burn would eat further into some papers than others.\n *\n * Shared with the shadow pass, which is why it holds only what CUTS: the\n * depth program has no view position and no lighting, and a function in here\n * that reached for either would stop it compiling. What a burn looks like is\n * `DAMAGE_SHADE_CHUNK`, colour program only.\n */\nconst DAMAGE_CHUNK = /* glsl */ `\nuniform sampler2D uDamage;\nuniform float uDamageDetail;\n// (edgeWave mm, edgeBite mm, sparkle, –) — see DamageLook.\nuniform vec4 uLook3;\n\n// The damage grid's texels sit ON the sheet — texel x at u = x / (N - 1), its\n// corners on the sheet's corners, which is how the field paints and how the\n// physics reads it. A texture puts texel x at (x + 0.5) / N. Sampled straight,\n// the picture of a burn sat up to half a texel off the burn the paper feels.\nvec2 plDamageUv(vec2 uv) {\n vec2 n = vec2(textureSize(uDamage, 0));\n // Texel space, on the field's convention: texel x at u = x / (N - 1).\n vec2 t = uv * (n - 1.0) + 0.5;\n // Quintic-smoothed texel coordinates.\n //\n // Bilinear filtering is continuous but its DERIVATIVE is not: the blend\n // weight is a straight line inside each texel and turns a corner at every\n // boundary. Magnify a 64 grid to fill a macro crop — one cell is 4.9 mm of\n // A4, about 58 px there — and those corners fall on a 58 px lattice, so\n // every ramp drawn from this field can crease along it.\n //\n // Also tried against the contour rings, and also not their cause (that was\n // the scorch fingers). Kept because it costs nothing and the crease is\n // real:\n // Bending the fractional part through a quintic (6t^5 - 15t^4 + 10t^3,\n // whose first and second derivatives vanish at both ends) makes the\n // interpolation C2 without a single extra tap: the hardware still does one\n // bilinear fetch, it is just asked for a smoothed position. The sample at a\n // texel's centre is unchanged, so the half-texel alignment this function\n // exists for still holds — and a field nothing has happened to reads 1\n // everywhere whatever the position, so the untouched-sheet identity is\n // untouched too.\n vec2 i = floor(t - 0.5) + 0.5;\n vec2 f = t - i;\n f = f * f * f * (f * (f * 6.0 - 15.0) + 10.0);\n return (i + f) / n;\n}\n\n/**\n * The four channels here, frayed finer than the grid.\n *\n * One cell of the field is ~3.3 mm of A4, and a burnt edge is jagged at the\n * scale of a fibre (0.3–2 mm) — so the grid decides roughly WHERE and this\n * decides exactly where. Stretched along the fibre (the field's default grain\n * runs along u), so a tear follows the grain. Scaled by what is already\n * there, so pristine paper (char 0, presence 1) is untouched to the bit, and\n * skipped outright at detail 0: the zones still draw on every tier, only\n * without the finest octaves.\n */\n/**\n * Where on the grid this fragment reads its damage — warped.\n *\n * A burnt hole is never a circle: paper burns unevenly, and its edge wobbles\n * in long waves with small bites in and out. The field is too coarse to hold\n * that, so the READ is displaced instead: two octaves of noise in the sheet's\n * own space, a long wave of up to ±6 mm and short bites of ±2 mm. Every zone —\n * the cut, the lip, the ember line, the char, the scorch — reads through the\n * same warp, so they all follow one uneven edge. Warping a field nothing has\n * happened to reads the same untouched value everywhere, so the identity\n * holds.\n */\nvec2 plDamageWarpAt(vec2 paperUv) {\n vec2 p = (paperUv - 0.5) * uSheetSize;\n const float mm = 1.0 / 210.0;\n vec2 wave = vec2(plFbm(p * 26.0 + 3.1), plFbm(p * 26.0 + 17.7)) - 0.5;\n vec2 bite = vec2(plNoise(p * 95.0 + 5.3), plNoise(p * 95.0 + 41.9)) - 0.5;\n vec2 shift = (wave * 2.0 * uLook3.x + bite * 2.0 * uLook3.y) * mm;\n return plDamageUv(paperUv + shift / uSheetSize);\n}\n\nvec2 plDamageWarp() {\n return plDamageWarpAt(vPaperUv);\n}\n\n/** Presence softened over five taps — see \\`plDamageRead\\`. */\nfloat plSoftPresence(vec2 uv) {\n vec2 texel = 0.75 / vec2(textureSize(uDamage, 0));\n return (2.0 * texture2D(uDamage, uv).a\n + texture2D(uDamage, uv + vec2(texel.x, 0.0)).a + texture2D(uDamage, uv - vec2(texel.x, 0.0)).a\n + texture2D(uDamage, uv + vec2(0.0, texel.y)).a + texture2D(uDamage, uv - vec2(0.0, texel.y)).a) / 6.0;\n}\n\n/** The fray and the fibre at a point of the sheet (local units), scaled by detail. */\nvec2 plFray(vec2 p) {\n return vec2(\n (plFbm(vec2(p.x * 22.0, p.y * 48.0)) - 0.47) * uDamageDetail,\n (plNoise(vec2(p.x * 140.0, p.y * 420.0)) - 0.5) * uDamageDetail\n );\n}\n\n/**\n * The presence the cut is drawn from, at any point of the paper: warped,\n * softened and frayed exactly as \\`plDamageRead\\` does it for this fragment.\n */\nfloat plDrawnPresenceAt(vec2 paperUv) {\n float a = plSoftPresence(plDamageWarpAt(paperUv));\n if (uDamageDetail > 0.0) {\n vec2 ff = plFray((paperUv - 0.5) * uSheetSize);\n a = clamp(a + (ff.x * 0.36 + ff.y * 0.05) * (1.0 - smoothstep(0.9, 1.0, a)), 0.0, 1.0);\n }\n return a;\n}\n\n// The softened presence before the fray, from the last \\`plDamageRead\\`: what\n// the distance to the cut takes its slope from (see \\`plDamage\\`).\nfloat plDamageSmooth;\n\nvec4 plDamageRead() {\n vec2 uv = plDamageWarp();\n vec4 d = texture2D(uDamage, uv);\n // The cut runs on a SOFTENED presence. Paper burns through within a single\n // texel now, so the raw field is hard-edged and its half-presence contour\n // is the grid's own staircase — the fray below can only move a line within\n // the band it is given, and a one-texel band is not enough to hide a grid.\n // Five taps round the contour; an untouched field is 1 everywhere and\n // stays exactly 1.\n d.a = plSoftPresence(uv);\n plDamageSmooth = d.a;\n if (uDamageDetail > 0.0) {\n vec2 ff = plFray(plLocal());\n float fray = ff.x;\n float fibre = ff.y;\n float edge = 1.0 - smoothstep(0.9, 1.0, d.a);\n d.r = clamp(d.r + fray * 0.3 * smoothstep(0.0, 0.15, d.r), 0.0, 1.0);\n d.a = clamp(d.a + (fray * 0.36 + fibre * 0.05) * edge, 0.0, 1.0);\n }\n return d;\n}\n\nvoid plDamageCut(inout vec4 color, vec4 d) {\n // Missing paper: gone at half presence, on every stock alike.\n color.a *= step(0.5, d.a);\n}\n`\n\n/**\n * What a burn LOOKS like: the zones of `paperlab-fx-fire-spec.md` §5, drawn\n * per fragment from a grid that is coarser than every one of them.\n *\n * From the hole outward: void · ash lip · ember line · char · scorch · paper.\n * The field says roughly where each is — presence is where the paper ends,\n * char is how far burning has got — and this measures the rest in\n * MILLIMETRES from the cut, off the presence gradient, so a 1 mm ember line\n * is 1 mm at any zoom and on any size of sheet. A4 is one world unit across,\n * which is what `PL_MM` is.\n *\n * - **Scorch** is albedo only, multiplied in so the ink under it darkens with\n * it, and PERMANENT: it reads char, which never recedes. A long slow ramp\n * through the sampled browns, then a steep jump to clean paper in its last\n * stretch — an even blur is half of what made the first version read as a\n * gradient. It reaches further ABOVE the burn than below, because hot gas\n * rises and cooks the paper over it (§4.5): world up is worked out here, in\n * the sheet's own UV, from the surface's screen derivatives.\n * - **Char** is not black: near-black in a crack network of 1–4 mm cells, a\n * dark grey body, a brown undertone toward the scorch, and plates tilted so\n * a grazing light catches them. The ink under it is gone.\n * - **The ash lip** is pale, matte, lifted toward the viewer — it is what\n * makes a hole read as a hole on a black stage, by catching light.\n * - **The ember line** is the only thing on the sheet that emits. It sits\n * between the ash lip and the char, 0.3–1 mm wide, held crisp in screen\n * space, broken into beads that flicker and crawl on the burn's own clock\n * and cool down the blackbody ramp as the heat under them goes. Written to\n * `plDamageLight` in HDR — past paper white, for `FxPost` to bloom — and\n * added after transmission, which owns `csm_Emissive`.\n *\n * Heat paints nothing anywhere else. The wide glow this chunk once drew over\n * unburnt paper was the spec's first complaint: red added to white is pink.\n */\nconst DAMAGE_SHADE_CHUNK = /* glsl */ `\nuniform float uDamageTime;\n// The look, packed — see DamageLook for what each number means.\nuniform vec4 uLook0; // emberWidth mm, emberIntensity, emberCoverage, emberFlicker\nuniform vec4 uLook1; // emberGlow, lipWidth mm, lipBrightness, charWarmth\nuniform vec4 uLook2; // charCracks, scorchReach mm, scorchDarkness, fingers\n/** The light the burn gives off from the sheet itself: the ember line, and nothing else. */\nvec3 plDamageLight;\n\n// World units per millimetre: a default sheet is one unit across, and A4 is 210 mm.\nconst float PL_MM = 1.0 / 210.0;\n\nvec3 plLinear(vec3 srgb) {\n return pow(srgb, vec3(2.2));\n}\n\n/**\n * World up, as a direction in the sheet's UV, from how this fragment's UV and\n * view position change across the screen. Must be called in uniform control\n * flow — it is all derivatives.\n */\nvec2 plUpUv() {\n vec3 dpx = dFdx(-vViewPosition);\n vec3 dpy = dFdy(-vViewPosition);\n vec2 dux = dFdx(vPaperUv);\n vec2 duy = dFdy(vPaperUv);\n float det = dux.x * duy.y - dux.y * duy.x;\n if (abs(det) < 1e-14) return vec2(0.0, 1.0);\n vec3 dPdu = (dpx * duy.y - dpy * dux.y) / det;\n vec3 dPdv = (dpy * dux.x - dpx * duy.x) / det;\n vec3 up = (viewMatrix * vec4(0.0, 1.0, 0.0, 0.0)).xyz;\n vec2 g = vec2(dot(up, dPdu) / max(dot(dPdu, dPdu), 1e-12), dot(up, dPdv) / max(dot(dPdv, dPdv), 1e-12));\n float l = length(g);\n return l > 1e-6 ? g / l : vec2(0.0, 1.0);\n}\n\n/** F1 and F2 of a cell noise — the crack network in char. */\nvec2 plVoronoi(vec2 p) {\n vec2 i = floor(p);\n vec2 f = fract(p);\n float f1 = 8.0;\n float f2 = 8.0;\n for (int y = -1; y <= 1; y++) {\n for (int x = -1; x <= 1; x++) {\n vec2 o = vec2(float(x), float(y));\n vec2 r = o + vec2(plHash(i + o), plHash(i + o + 17.31)) - f;\n float dd = dot(r, r);\n if (dd < f1) {\n f2 = f1;\n f1 = dd;\n } else if (dd < f2) {\n f2 = dd;\n }\n }\n }\n return sqrt(vec2(f1, f2));\n}\n\n/** The scorch ramp, sampled off Scorch.png and Hero.png, as a tint over paper. 0 is the leading edge. */\nvec3 plScorchTint(float t) {\n vec3 paper = plLinear(vec3(0.90, 0.885, 0.855));\n vec3 c0 = plLinear(vec3(0.843, 0.741, 0.569)); // #D7BD91\n vec3 c1 = plLinear(vec3(0.745, 0.514, 0.263)); // #BE8343\n vec3 c2 = plLinear(vec3(0.631, 0.384, 0.180)); // #A1622E\n vec3 c3 = plLinear(vec3(0.541, 0.310, 0.141)); // #8A4F24\n vec3 c4 = plLinear(vec3(0.471, 0.275, 0.149)); // #784626\n vec3 c5 = plLinear(vec3(0.380, 0.216, 0.133)); // #613722\n vec3 c6 = plLinear(vec3(0.310, 0.200, 0.137)); // #4F3323\n float s = clamp(t, 0.0, 1.0) * 6.0;\n // Each stop is blended with a SMOOTH step, not a linear one.\n //\n // Seven colours joined by six straight segments is a ramp with a corner at\n // every joint: the colour is continuous there but its rate of change is\n // not, and the eye reads a discontinuous gradient as a faint line (Mach\n // banding). smoothstep's derivative is zero at both ends of a segment, so\n // consecutive segments meet with matching slope and there is no corner.\n //\n // Cheap insurance, not a bug fix — this was tried first against the macro\n // crops' contour rings and did NOT remove them; the cause turned out to be\n // the scorch fingers below, sampled in a frame that follows the contours.\n float k = smoothstep(0.0, 1.0, clamp(s, 0.0, 1.0));\n vec3 c = mix(c0, c1, k);\n c = mix(c, c2, smoothstep(0.0, 1.0, clamp(s - 1.0, 0.0, 1.0)));\n c = mix(c, c3, smoothstep(0.0, 1.0, clamp(s - 2.0, 0.0, 1.0)));\n c = mix(c, c4, smoothstep(0.0, 1.0, clamp(s - 3.0, 0.0, 1.0)));\n c = mix(c, c5, smoothstep(0.0, 1.0, clamp(s - 4.0, 0.0, 1.0)));\n c = mix(c, c6, smoothstep(0.0, 1.0, clamp(s - 5.0, 0.0, 1.0)));\n return min(c / paper, vec3(1.0));\n}\n\n/** The ember ramp (§5 zone 3): off → #870E03 → #A12108 → #F77E14 → #FEFBE0, hottest last. */\nvec3 plEmberRamp(float t) {\n vec3 c0 = plLinear(vec3(0.529, 0.055, 0.012));\n vec3 c1 = plLinear(vec3(0.631, 0.129, 0.031));\n vec3 c2 = plLinear(vec3(0.969, 0.494, 0.078));\n vec3 c3 = plLinear(vec3(0.996, 0.984, 0.878));\n vec3 c = mix(c0, c1, smoothstep(0.0, 0.3, t));\n c = mix(c, c2, smoothstep(0.3, 0.7, t));\n return mix(c, c3, smoothstep(0.75, 1.0, t));\n}\n\nvoid plDamage(inout vec4 color, inout float roughness) {\n plDamageLight = vec3(0.0);\n vec4 d = plDamageRead();\n vec2 uv = plDamageWarp();\n vec2 texel = 1.0 / vec2(textureSize(uDamage, 0));\n\n // Everything measured off screen derivatives, up front: derivatives are\n // undefined past a branch that only some fragments of a quad take.\n vec2 upUv = plUpUv();\n vec4 e = texture2D(uDamage, uv + vec2(texel.x, 0.0));\n vec4 w = texture2D(uDamage, uv - vec2(texel.x, 0.0));\n vec4 n = texture2D(uDamage, uv + vec2(0.0, texel.y));\n vec4 s = texture2D(uDamage, uv - vec2(0.0, texel.y));\n // Per world unit: one texel step is 1 / (N - 1) of the sheet.\n vec2 perWorld = (vec2(textureSize(uDamage, 0)) - 1.0) / uSheetSize;\n vec2 gradP = vec2(e.a - w.a, n.a - s.a) * 0.5 * perWorld;\n vec2 gradC = vec2(e.r - w.r, n.r - s.r) * 0.5 * perWorld;\n // Millimetres from the cut, on the paper side — measured against the field\n // the cut is DRAWN from (softened, frayed, warped), through its own screen\n // derivatives. It used to divide by the slope of the raw texels, and since\n // paper burns through within a texel that slope is a cliff while the drawn\n // edge is spread over millimetres: a point well into the char computed as a\n // hair from the cut, and the ember line drew there — found by the gate.\n // The slope, though, is the SMOOTH presence's. The fray's fibre noise\n // changes pixel to pixel, and its slope is a cliff everywhere it touches:\n // divided by that, a point deep in the char came out a hair from the cut\n // and the ember glow drew there — the gate's stray pixels. The fray still\n // moves where the edge is; it just cannot fake how steep it is.\n float smoothA = plDamageSmooth;\n vec2 cutSlope = vec2(dFdx(smoothA), dFdy(smoothA));\n float pxFromCut = (d.a - 0.5) / max(length(cutSlope), 1e-4);\n // Millimetres per pixel ALONG the way to the cut, not across the screen's\n // x: a sheet leaning away is foreshortened vertically, so above and below a\n // hole a pixel covers more paper than beside it, and a scale taken from x\n // alone drew the ember zone too many pixels deep on the top and bottom rims.\n vec2 toCutPx = cutSlope / max(length(cutSlope), 1e-6);\n float mmPerPx = length(dFdx(-vViewPosition) * toCutPx.x + dFdy(-vViewPosition) * toCutPx.y) / PL_MM;\n float mm = pxFromCut * mmPerPx;\n // About a pixel of antialiasing, never more: where the warp makes the\n // estimate jump between neighbours, fwidth(mm) is millimetres wide, and the\n // ember's soft tail — faint, but multiplied by its light — drew stray glow\n // well out into the char.\n float aa = min(fwidth(mm), 1.5 * mmPerPx);\n // Scorch reaches ahead of the char, and further UP than anywhere else:\n // the char a centimetre below this point, and the char a few millimetres\n // around it, each lent to the scorch at a discount (§4.2, §4.5).\n vec2 mmUv = vec2(PL_MM) / uSheetSize;\n float charBelow = max(texture2D(uDamage, uv - upUv * uLook2.y * mmUv).r, texture2D(uDamage, uv - upUv * 0.5 * uLook2.y * mmUv).r);\n // A ring of eight, averaged: four diagonal maxima drew the grid back in as\n // squares wherever the scorch was magnified.\n float charWide = 0.0;\n for (int k = 0; k < 8; k++) {\n float a = float(k) * 0.7853982;\n charWide += texture2D(uDamage, uv + vec2(cos(a), sin(a)) * 7.0 * mmUv).r;\n }\n charWide /= 8.0;\n // Only paper that has a CUT beside it has an edge: a half-eaten cell out\n // in the middle of the sheet reads as \"half a presence\" too, and without\n // this the ember line and the ash lip drew on it — islands of glow on\n // paper, the painted glow by another route.\n // Eased in, not switched: a hard threshold on the neighbouring texels drew\n // the grid back into the ember glow as small squares.\n float cutNear = 1.0 - smoothstep(0.3, 0.62, min(min(e.a, w.a), min(n.a, s.a)));\n // And the cut has to really be there. \\`mm\\` extrapolates this pixel's\n // slope to half presence, and the uneven edge's warp bends the field inside\n // those few millimetres — measured: with the warp off the stray ember light\n // the gate finds all but vanishes. So step across the PAPER toward where the\n // cut should be, half a millimetre past it but never beyond the ember\n // zone's own outer edge (the lip and the widest bead — 2.5 mm at the\n // spec's numbers, §5) plus that half, and read what the cut is drawn from.\n // Still paper: this is not an edge, however close the slope said it was.\n vec2 toCutPaper = -(dFdx(vPaperUv) * toCutPx.x + dFdy(vPaperUv) * toCutPx.y);\n float reachPx = min(max(mm, 0.0) + 0.5, uLook1.y + uLook0.x + 0.5) / max(mmPerPx, 1e-6);\n float pastA = plDrawnPresenceAt(vPaperUv + toCutPaper * reachPx);\n // And a hole, not a pinhole: the fray opens specks of void finer than a\n // pixel in part-burnt paper, which the check above would take for the\n // edge. The void has to go on for another half millimetre.\n float beyondA = plDrawnPresenceAt(vPaperUv + toCutPaper * (reachPx + 0.5 / max(mmPerPx, 1e-6)));\n cutNear *= (1.0 - smoothstep(0.42, 0.55, pastA)) * (1.0 - smoothstep(0.42, 0.55, beyondA));\n\n // An untouched texel is left exactly as it was — the identity the whole\n // seam is built on. Nothing here has happened to this paper.\n if (d.r <= 0.0 && d.g <= 0.0 && d.a >= 1.0 && charBelow <= 0.0 && charWide <= 0.0 && e.a >= 1.0 && w.a >= 1.0 && n.a >= 1.0 && s.a >= 1.0) {\n return;\n }\n\n vec2 p = plLocal();\n\n // Wet paper is darker and smoother: water fills the gaps between fibres\n // that scatter light, which is both effects from one cause.\n color.rgb *= 1.0 - 0.38 * d.g;\n roughness *= 1.0 - 0.45 * d.g;\n\n // ── Scorch ──────────────────────────────────────────────────────────────\n // Fingers: irregular teeth ALONG the scorch front, plus the grain's own\n // streaks. Measured along the front's tangent so they point outward.\n vec2 tangentC = length(gradC) > 1e-4 ? normalize(vec2(-gradC.y, gradC.x)) : vec2(1.0, 0.0);\n float along = dot(p, tangentC) / (4.0 * PL_MM);\n // Only where there really IS a front.\n //\n // This noise is sampled in a frame built from the char gradient, so that\n // its teeth run across the front wherever the front happens to point. That\n // works at the front and is meaningless behind it: a few millimetres into\n // the char the gradient is almost flat, its direction is whatever the\n // eight-bit field rounded to, and the frame turns with position — which\n // makes the noise a function OF THE CONTOURS rather than of the sheet. It\n // drew closed loops following the edge, nested a cell apart: the\n // \"concentric contour lines, like a topographic map or tree rings\" the\n // review found at macro range and left unexplained. Turning this one term\n // off removes them completely and changes nothing else.\n //\n // Measured on the scripted burn's peak: the gradient runs to about 19 at\n // the front and under 1 a few millimetres behind it.\n float frontness = smoothstep(1.0, 6.0, length(gradC));\n float fingers = (plFbm(vec2(along, dot(p, vec2(tangentC.y, -tangentC.x)) / (12.0 * PL_MM))) - 0.5) * 0.28 * frontness\n + (plFbm(vec2(p.x * 9.0, p.y * 30.0)) - 0.5) * 0.08;\n fingers *= uLook2.w;\n // Fingers on the borrowed scorch too, so the outer edge is irregular\n // teeth rather than a smooth offset of the char.\n float reach = 0.75 + fingers * 4.0;\n // The scorch reads a softened char — its own texel and the four around it\n // — so a bilinear 64² field magnified shows no contours or corners. The\n // char zone keeps the sharp one: its edge is meant to be crisp.\n float soft = (2.0 * d.r + e.r + w.r + n.r + s.r) / 6.0;\n float self_ = clamp(mix(d.r, soft, 0.65) + fingers * smoothstep(0.0, 0.08, d.r), 0.0, 1.0);\n float c = 1.0 - (1.0 - self_) * (1.0 - clamp(0.62 * charBelow * reach, 0.0, 1.0)) * (1.0 - clamp(0.4 * charWide * reach, 0.0, 1.0));\n // Fibre-scale grain in the scorch, so a smooth field magnified never shows\n // its contours — real scorch is fibrous (Scorch.png), not banded.\n c = clamp(c + ((plNoise(p * 300.0) - 0.5) * 0.07 + (plNoise(p * 90.0) - 0.5) * 0.06) * smoothstep(0.0, 0.1, c), 0.0, 1.0);\n // A dither of about one and a half of the damage texture's own levels.\n //\n // The field arrives as eight bits a channel, so char comes in steps of\n // 1/255 — and the leading edge below spans 0.03 of it, which is seven and a\n // half steps. The fibre grain above would have hidden them, but it is\n // multiplied by smoothstep(0, 0.1, c), which is approximately zero exactly\n // where the leading edge lives. This is not: it applies everywhere, and\n // being finer than a level it can only ever move a value into the\n // neighbouring one.\n c = clamp(c + (plNoise(p * 900.0) - 0.5) * (1.5 / 255.0), 0.0, 1.0);\n // A steep leading edge — paper to straw in a sliver — then the long ramp.\n float lead = smoothstep(0.02, 0.05, c);\n float ramp = smoothstep(0.05, 0.7, c);\n color.rgb *= mix(vec3(1.0), pow(plScorchTint(ramp), vec3(uLook2.z)), lead);\n\n // ── Char ────────────────────────────────────────────────────────────────\n // A wide, smooth hand-over from scorch to char — the gradient is the point.\n float charZone = smoothstep(0.5, 0.9, c);\n vec2 cells = plVoronoi(p / (3.6 * PL_MM));\n // Sparse: a real crack network is broken, not a tiled floor — most cell\n // borders never split.\n float crack = (1.0 - smoothstep(0.008, 0.03, cells.y - cells.x)) * smoothstep(0.45, 0.65, plNoise(p / (7.0 * PL_MM)));\n float plate = plHash(floor(p / (3.6 * PL_MM)) + 3.7);\n // Dark orange where the char meets the scorch, deep brown toward the cut —\n // warm all the way, and fading smoothly into the scorch's lighter browns\n // rather than stopping at a grey band.\n // Warm (dark orange → deep brown) or, turned down, the sampled greys.\n vec3 body = mix(plLinear(vec3(0.255, 0.239, 0.227)), plLinear(vec3(0.165, 0.086, 0.043)), uLook1.w);\n vec3 under = mix(plLinear(vec3(0.275, 0.169, 0.090)), plLinear(vec3(0.42, 0.18, 0.06)), uLook1.w);\n vec3 cracks = plLinear(vec3(0.039, 0.024, 0.016)); // #0A0604\n vec3 charColor = mix(under, body, smoothstep(0.66, 1.0, c));\n // Mottled at the plate scale and finer, and darker than the sampled body\n // under a bright key — the reference's char reads near black in the frame.\n charColor *= (0.75 + 0.35 * plate) * (0.8 + 0.4 * plNoise(p * 260.0));\n charColor = mix(charColor, cracks, crack * uLook2.x);\n color.rgb = mix(color.rgb, charColor, charZone);\n roughness = mix(roughness, 0.6, charZone);\n // Blistered, and each plate tilted its own way, so a raking light breaks\n // the char into plates rather than lighting it as one sheet of black.\n plHeight += charZone * ((plNoise(p * 380.0) - 0.5) * 0.00008 + (plate - 0.5) * 0.00018 - crack * 0.00016);\n\n // ── Ash lip ─────────────────────────────────────────────────────────────\n // Inside the spec's zones (§5): the lip 0.5–1.5 mm, then the ember line\n // 0.3–1 mm — 2.5 mm from the cut at most, which the gate holds it to.\n // Along the rim. Both the lip and the ember line below are laid out on this,\n // and unlike the scorch fingers above it is safe to sample noise in: it is\n // used ONLY within a couple of millimetres of the cut, where the presence\n // gradient is the actual edge and points somewhere real. The fingers'\n // mistake was carrying the same idea out into flat char, where the gradient\n // is rounding error and a noise sampled in its frame draws the contours.\n vec2 tangentP = length(gradP) > 1e-4 ? normalize(vec2(-gradP.y, gradP.x)) : vec2(1.0, 0.0);\n\n float lipWidth = mix(0.4, max(uLook1.y, 0.41), plFbm(p / (2.5 * PL_MM)));\n // Broken, not a hem. Ash flakes off a cooling edge in pieces, so the lip\n // comes and goes along the rim and wanders in width where it is there. It\n // used to be a continuous band of even width with a highlight down the\n // middle of it, which read as a neon tube round the hole — the single most\n // synthetic thing at wide view.\n float lipAlong = dot(p, tangentP) / (3.2 * PL_MM);\n float lipBreak = smoothstep(0.34, 0.56, plFbm(vec2(lipAlong, 0.9)));\n float lip = (1.0 - smoothstep(lipWidth - aa, lipWidth + aa, mm)) * step(d.a, 0.999) * cutNear * lipBreak;\n vec3 ash = plLinear(mix(vec3(0.525, 0.498, 0.490), vec3(0.741, 0.725, 0.725), plNoise(p * 520.0) * 0.6 + plNoise(p * 90.0) * 0.4)) * uLook1.z;\n color.rgb = mix(color.rgb, ash, lip);\n roughness = mix(roughness, 0.99, lip);\n // Barely raised. THIS is where the highlight came from: a 0.7 mm ridge\n // running round the hole is a cylinder, and a cylinder under a key light\n // has a specular line down it however rough the surface is. Ash is a\n // fragile crust a fraction of a millimetre proud of the paper, not a bead\n // of solder — and the shape of it belongs to the broken edge above, not to\n // a smooth ramp.\n plHeight += lip * (1.0 - mm / max(lipWidth, 0.1)) * 0.00018;\n\n // ── The ember line ──────────────────────────────────────────────────────\n // Beads along the cut: position along the edge, crawling on the burn's\n // clock, with a flicker of their own. Only where it is hot — and as the\n // heat goes the threshold rises, so the line breaks into fewer, dimmer\n // beads and they go out one by one.\n float s1 = dot(p, tangentP) / (2.4 * PL_MM) - uDamageTime * 0.55 * uLook0.w;\n float bead = plNoise(vec2(s1, 0.37)) * 0.7 + plNoise(vec2(s1 * 2.3, 5.1)) * 0.3;\n float flicker = 0.62 + 0.38 * plNoise(vec2(floor(s1) * 7.13, uDamageTime * 9.0 * uLook0.w));\n // Down to a smoulder's last flicker: a spent edge keeps a little heat in\n // the texture (\\`Afterglow\\`), and a bead should glow dim red on it rather\n // than vanish while the edge still has something to give.\n // Heat softened like the cut (its texel and the four around it), so the\n // beads and the crimson glow follow the burn rather than the grid's cells.\n float heatSoft = (2.0 * d.b + e.b + w.b + n.b + s.b) / 6.0;\n float hot = smoothstep(0.012, 0.55, heatSoft);\n // Coverage slides the threshold: more of the edge lit, or less.\n float shift = (uLook0.z - 0.5) * 0.5;\n float lit = smoothstep(mix(0.82, 0.45, hot) - shift, mix(0.9, 0.58, hot) - shift, bead);\n // Each bead tapers at its ends — a bead, not a dash cut from a strip.\n float width = max(mix(0.4, max(uLook0.x, 0.41), plNoise(vec2(s1 * 0.7, 9.0))) * (0.35 + 0.65 * lit), 1.4 * aa);\n float band = smoothstep(lipWidth - aa, lipWidth + aa, mm) * (1.0 - smoothstep(lipWidth + width - aa, lipWidth + width + aa, mm)) * cutNear;\n // Mostly orange: a bead is red at its ends and yellow-white only at its\n // hottest core, which is what Ember_line.png shows. Mapped low and pushed\n // high by a power, so white is the exception rather than the line.\n // Orange through, yellow-white at the hottest cores. Dim red alone reads\n // salmon once the curve desaturates it, so the ramp starts at orange and\n // only the cooling (low heat) falls back into red.\n float t = hot * flicker * (0.45 + 0.55 * lit);\n color.rgb = mix(color.rgb, plLinear(vec3(0.12, 0.04, 0.02)), band * lit);\n // Saturated orange at orange brightness; only the hottest cores are pushed\n // high enough for the curve to roll them to white.\n plDamageLight = plEmberRamp(t) * mix(0.8, 6.0, t * t * t * t) * band * lit * hot * uLook0.y;\n\n // The rest of a real burning edge (Ember_line.png): a dim crimson glow in\n // the char beside the beads — patches of it, drifting — and specks of\n // glowing fibre that come and go. Both stay under the bloom threshold, so\n // they read as heat in the char rather than as light; both only where the\n // edge is hot, and inside the zone the beads are held to — the lip plus\n // the widest bead, measured from the cut — so the glow never reaches out\n // over paper the gate says heat must not light.\n float zoneEnd = uLook1.y + uLook0.x;\n float seam = smoothstep(lipWidth - aa, lipWidth + aa, mm) * (1.0 - smoothstep(zoneEnd - 0.6, zoneEnd, mm)) * cutNear;\n float patch_ = smoothstep(0.35, 0.72, plFbm(p / (4.0 * PL_MM) + vec2(uDamageTime * 0.15 * uLook0.w, 0.0)));\n plDamageLight += vec3(0.55, 0.06, 0.01) * seam * patch_ * hot * uLook1.x;\n float speck = step(0.985, plHash(floor(p / (0.35 * PL_MM)) + floor(uDamageTime * 8.0 * uLook0.w)));\n plDamageLight += plEmberRamp(0.9) * 1.6 * speck * seam * hot * uLook3.z;\n\n plDamageCut(color, d);\n}\n`\n\n/**\n * The sheet-space half of `HELPERS`, for the shadow pass.\n *\n * `HELPERS` is written for the colour program, and part of it cannot compile\n * anywhere else: `plPerturb` reads `vViewPosition`, which a depth material\n * does not have — and GLSL compiles a function whether or not anything calls\n * it. So the depth program gets everything the CUTTING chunks need (the UV\n * varying, the sheet size, `plLocal`, the noise) and none of the lighting.\n *\n * Carved out of the one string at load time rather than written twice, so the\n * two can never drift, and so the colour program stays byte-for-byte what it\n * was. If an anchor below ever moves, this throws on import rather than\n * compiling a shadow program that silently differs.\n */\nfunction carveDepthHelpers(helpers: string): string {\n const darken = 'uniform float uBackDarken;\\n'\n const relief = helpers.indexOf(\"/**\\n * The paper's relief\")\n const bell = helpers.lastIndexOf('/**', helpers.indexOf('float plBell('))\n if (!helpers.includes(darken) || relief < 0 || bell <= relief) {\n throw new Error('compose: HELPERS changed shape — update carveDepthHelpers')\n }\n return (helpers.slice(0, relief) + helpers.slice(bell)).replace(darken, '')\n}\n\n/** Exported for its test, which pins what the shadow pass can and cannot see. */\nexport const DEPTH_HELPERS = carveDepthHelpers(HELPERS)\n\nconst DEPTH_VERTEX = /* glsl */ `\nvarying vec2 vPaperUv;\nvoid main() {\n vPaperUv = uv;\n}\n`\n\nconst AGING_CHUNK = /* glsl */ `\nuniform float uAgingAmount;\n\nvoid plAging(inout vec4 color) {\n // Yellowing deepens toward the edges, like light exposure.\n float edge = max(abs(vPaperUv.x - 0.5), abs(vPaperUv.y - 0.5)) * 2.0;\n vec3 yellowed = color.rgb * vec3(1.0, 0.94, 0.78);\n color.rgb = mix(color.rgb, yellowed, uAgingAmount * (0.45 + edge * 0.55));\n // Foxing: sparse rusty blotches.\n float fox = plFbm(vPaperUv * 14.0 + 3.7);\n float spots = smoothstep(0.62, 0.78, fox) * uAgingAmount;\n color.rgb = mix(color.rgb, vec3(0.62, 0.45, 0.26), spots * 0.5);\n}\n`\n\n/**\n * Compose the enabled effects into one program. The shader owns the base\n * color entirely: the FRONT face samples the content texture, the BACK face\n * renders the stock (or content.back) with an optional reversed show-through\n * ghost — a single DoubleSide map would mirror the front content onto the\n * back, which real paper doesn't do.\n */\nexport function composeSurface(\n surface: SurfaceConfig,\n stock: Stock,\n thickness: number,\n maps: SurfaceMaps = { hasFrontMap: false, hasBackMap: false },\n /** World dims — perforation holes are sized in world units. */\n sheet: { width: number; height: number } = { width: 1, height: 1.4 },\n /** Whose key light transmission is measured against — a preset name or the scene's resolved rig. */\n lighting: LightingName | LightingPreset = 'studio',\n /**\n * The crease lines to draw, already resolved. Authored `surface.creaseLines`\n * and the sheet's remembered creases both arrive here as the same thing —\n * see `resolveCreases`, which is the only place that knows they came from\n * two different questions.\n */\n creases: CreaseShading[] = resolveCreases(surface, [], sheet),\n): ComposedSurface {\n const grain = surface.grain ?? stock.defaultSurface.grain\n const aging = surface.aging ?? stock.defaultSurface.aging\n const deckle = surface.deckle\n const perforation = surface.perforation\n const banding = stock.banding\n // Adhesive undersides are opaque backing-paper white — nothing shows through.\n const showThrough = stock.adhesive ? 0 : (surface.showThrough ?? stock.showThrough)\n\n const chunks: string[] = []\n const calls: string[] = []\n const uniforms: Record<string, { value: unknown }> = {\n // Backside darkening: thicker/opaque stock lets less light through.\n // Adhesive backs skip it — the glue layer is its own bright surface.\n uBackDarken: {\n value: stock.adhesive ? 1 : 1 - Math.min(0.45, 0.12 + thickness * 0.9) * stock.opacity,\n },\n uStockColor: { value: new THREE.Color(stock.color) },\n // Always present, not just when something asks for it: every effect that\n // measures anything measures in the sheet's own space now — see plLocal.\n uSheetSize: { value: new THREE.Vector2(sheet.width, sheet.height) },\n uOpacity: { value: stock.opacity },\n uShowThrough: { value: showThrough },\n // Always compiled in: the shader early-outs at zero translucency, which\n // is cheaper than carrying a second program structure for it.\n ...translucencyUniforms(surface.translucency ?? stock.translucency, lighting),\n }\n if (maps.hasFrontMap) uniforms.uFrontMap = { value: null }\n if (maps.hasBackMap) uniforms.uBackMap = { value: null }\n\n if (grain !== undefined || banding > 0) {\n chunks.push(GRAIN_CHUNK)\n calls.push('plGrain(csm_DiffuseColor, csm_Roughness);')\n uniforms.uGrainAmount = { value: grain ?? 0 }\n uniforms.uGrainBanding = { value: banding }\n }\n if (deckle) {\n chunks.push(DECKLE_CHUNK)\n calls.push('plDeckle(csm_DiffuseColor);')\n uniforms.uDeckleEdges = { value: edgeFlags(deckle.edges) }\n uniforms.uDeckleRoughness = { value: deckle.roughness }\n }\n if (perforation) {\n const edges = perforation.edges === 'all' ? [...paperEdgesOrder] : perforation.edges\n chunks.push(PERFORATION_CHUNK)\n calls.push('plPerforation(csm_DiffuseColor);')\n uniforms.uPerfEdges = { value: edgeFlags(edges) }\n uniforms.uPerfTorn = {\n value: new THREE.Vector4(\n ...paperEdgesOrder.map((e) => (edges.includes(e) && perforation.state[e] === 'torn' ? 1 : 0)),\n ),\n }\n uniforms.uPerfRadius = { value: perforation.holeRadius }\n uniforms.uPerfSpacing = { value: perforation.spacing }\n }\n if (creases.length > 0) {\n chunks.push(CREASE_CHUNK)\n calls.push('plCrease(csm_DiffuseColor, csm_Roughness);')\n uniforms.uCreaseAngles = { value: pad(creases.map((c) => (c.angle * Math.PI) / 180)) }\n uniforms.uCreaseStrengths = { value: pad(creases.map((c) => c.strength)) }\n uniforms.uCreaseOffsets = { value: pad(creases.map((c) => c.offset)) }\n uniforms.uCreaseWidth = { value: CREASE_RADIUS * SHADED_CREASE }\n uniforms.uCreaseCount = { value: Math.min(creases.length, 4) }\n }\n if (aging !== undefined) {\n chunks.push(AGING_CHUNK)\n calls.push('plAging(csm_DiffuseColor);')\n uniforms.uAgingAmount = { value: aging }\n }\n // Last, so a burn chars over the yellowing and the ink alike.\n if (maps.hasDamage) {\n chunks.push(DAMAGE_CHUNK, DAMAGE_SHADE_CHUNK)\n calls.push('plDamage(csm_DiffuseColor, csm_Roughness);')\n // Bound by `PaperMaterial` to the uploaded texture; null only until then.\n uniforms.uDamage = { value: null }\n // Set by `PaperMaterial` from the source's `detail` every frame.\n uniforms.uDamageDetail = { value: 1 }\n // The burn's clock, which the ember line's beads move on — see `DamageSource.time`.\n uniforms.uDamageTime = { value: 0 }\n // How the burn is drawn — set from `DamageSource.look` every frame.\n const look = DAMAGE_LOOK_DEFAULTS\n uniforms.uLook0 = {\n value: new THREE.Vector4(look.emberWidth, look.emberIntensity, look.emberCoverage, look.emberFlicker),\n }\n uniforms.uLook1 = {\n value: new THREE.Vector4(look.emberGlow, look.lipWidth, look.lipBrightness, look.charWarmth),\n }\n uniforms.uLook2 = {\n value: new THREE.Vector4(look.charCracks, look.scorchReach, look.scorchDarkness, look.fingers),\n }\n uniforms.uLook3 = { value: new THREE.Vector4(look.edgeWave, look.edgeBite, look.sparkle, 0) }\n }\n\n /**\n * The shadow pass, for any sheet that removes paper.\n *\n * Holes cut in the colour program by alpha are invisible to the shadow\n * map: three renders shadows with its own depth material, which alpha-tests\n * a `map` if there is one and knows nothing of alpha computed in shader\n * code. So a torn edge, a perforation and a burnt-through hole all cast a\n * solid shadow — the most obvious fake a burn can have, and one the\n * deckle and perforation had been shipping since before this seam.\n *\n * The fix is the same chunks, run again in a depth program that DISCARDS\n * wherever the colour program would have cut. Only what cuts: grain,\n * creases and ageing change colour and not coverage, and a depth program\n * pays per fragment for everything in it.\n */\n const cutting: string[] = []\n const cuts: string[] = []\n if (deckle) {\n cutting.push(DECKLE_CHUNK)\n cuts.push('plDeckle(color);')\n }\n if (perforation) {\n cutting.push(PERFORATION_CHUNK)\n cuts.push('plPerforation(color);')\n }\n if (maps.hasDamage) {\n cutting.push(DAMAGE_CHUNK)\n cuts.push('plDamageCut(color, plDamageRead());')\n }\n const depth =\n cutting.length > 0\n ? {\n vertexShader: DEPTH_VERTEX,\n fragmentShader: /* glsl */ `\n${DEPTH_HELPERS}\n${cutting.join('\\n')}\nvoid main() {\n vec4 color = vec4(1.0);\n float roughness = 1.0;\n ${cuts.join('\\n ')}\n if (color.a < 0.5) discard;\n}\n`,\n }\n : null\n\n // Whether anything above described a SHAPE and not just a colour. The\n // perturbation is one pair of screen derivatives, which is cheap but not\n // free, and a plain sheet has nothing for it to do.\n // A burn has a shape too — blistered char, a lifted ash lip — and on an\n // untouched field its height is exactly zero, which `plPerturb` returns\n // unchanged, so attaching a field still costs a sheet no pixel.\n const relief = grain !== undefined || creases.length > 0 || Boolean(maps.hasDamage)\n\n const frontExpr = maps.hasFrontMap ? 'texture2D(uFrontMap, vPaperUv).rgb' : 'uStockColor'\n // The back reads correctly when the sheet is flipped → mirror x. Adhesive\n // undersides (sticker stock) are glossy near-white regardless of the front.\n const backBaseExpr = stock.adhesive\n ? 'vec3(0.965, 0.96, 0.945)'\n : maps.hasBackMap\n ? 'texture2D(uBackMap, vec2(1.0 - vPaperUv.x, vPaperUv.y)).rgb'\n : 'uStockColor'\n\n const fragmentShader = /* glsl */ `\n${HELPERS}\nuniform vec3 uStockColor;\nuniform float uOpacity;\nuniform float uShowThrough;\n${maps.hasFrontMap ? 'uniform sampler2D uFrontMap;' : ''}\n${maps.hasBackMap && !stock.adhesive ? 'uniform sampler2D uBackMap;' : ''}\n${TRANSLUCENCY_FRAGMENT}\n${chunks.join('\\n')}\nvoid main() {\n plHeight = 0.0;\n vec3 front = ${frontExpr};\n if (gl_FrontFacing) {\n csm_DiffuseColor = vec4(front, uOpacity);\n } else {\n vec3 backBase = ${backBaseExpr};\n csm_DiffuseColor = vec4(backBase * mix(vec3(1.0), front, uShowThrough), uOpacity);\n }\n ${calls.join('\\n ')}\n${relief ? ' // The relief every effect above described, spent once — see plPerturb.\\n csm_FragNormal = plPerturb(csm_FragNormal, plHeight);' : ''}\n if (!gl_FrontFacing) csm_DiffuseColor.rgb *= uBackDarken;\n ${stock.adhesive ? '// Adhesive underside: higher specular than the printed face.\\n if (!gl_FrontFacing) csm_Roughness = 0.18;' : ''}\n // What the key light pushes through the sheet, filtered by the ink on it.\n csm_Emissive = plTransmission(front);\n${maps.hasDamage ? ' // The ember line — the only light a burn gives off from the sheet itself.\\n csm_Emissive += plDamageLight;' : ''}\n}\n`\n\n return {\n structureKey: `${[\n grain !== undefined || banding > 0 ? 'g' : '',\n deckle ? 'd' : '',\n creases.length > 0 ? 'c' : '',\n aging !== undefined ? 'a' : '',\n perforation ? 'p' : '',\n stock.adhesive ? 'A' : '',\n ].join('')}:${maps.hasFrontMap ? 'F' : ''}${maps.hasBackMap ? 'B' : ''}${maps.hasDamage ? 'D' : ''}`,\n vertexShader: VERTEX,\n fragmentShader,\n uniforms,\n // Anything that removes paper needs fragments discarded rather than\n // blended — a hole has to cut the depth buffer and the shadow too.\n alphaTest: deckle || perforation || maps.hasDamage ? 0.5 : 0,\n depth,\n }\n}\n\nfunction pad(values: number[], fill = 0): number[] {\n const out = values.slice(0, 4)\n while (out.length < 4) out.push(fill)\n return out\n}\n","import * as THREE from 'three'\nimport type { LightingName } from '../config/schema'\nimport { getLightingPreset, type LightingPreset } from '../scene/lighting'\n\n/**\n * Light passing THROUGH the paper.\n *\n * Every reference image for stage mode is lit from behind: the paper is a\n * filter, not a surface catching a key light. That single change is what\n * separates \"a render of some paper\" from the look — and it is cheap,\n * because paper is thin and diffuse. No refraction, no transmission pass,\n * no `MeshPhysicalMaterial` (which does not instance): one dot product and\n * an additive emissive term, so it works identically in the instanced field\n * path and the hero path.\n *\n * The detail that sells it is the ink filter. What comes through a backlit\n * sheet is the lamp MINUS whatever is printed on it, which is why the\n * calligraphy on a lit banner reads dark against a glowing field instead of\n * blowing out with everything else.\n */\n\n/** Declared by both stages of both pipelines. */\nexport const TRANSLUCENCY_VARYINGS = /* glsl */ `\nvarying vec3 vPlWorldNormal;\nvarying vec3 vPlViewDir;\n`\n\nexport interface TranslucencyVertexSlots {\n /** Object → world matrix expression. Instanced meshes must fold in `instanceMatrix`. */\n model: string\n /** Final object-space position expression. */\n position: string\n /** Final object-space normal expression. */\n normal: string\n}\n\n/**\n * Vertex side: publish the world-space normal and view vector. Doing this in\n * the vertex shader (rather than reconstructing from `vNormal`) keeps the\n * chunk independent of where in three's fragment pipeline it gets injected.\n */\nexport function translucencyVertexChunk(slots: TranslucencyVertexSlots): string {\n return /* glsl */ `\n {\n mat4 plModel = ${slots.model};\n vec4 plWorld = plModel * vec4(${slots.position}, 1.0);\n // Uniform scale only — layouts scale sheets evenly, so the plain 3×3 is\n // the correct normal matrix here and skips an inverse-transpose.\n vPlWorldNormal = normalize(mat3(plModel) * ${slots.normal});\n vPlViewDir = cameraPosition - plWorld.xyz;\n }\n`\n}\n\n/** How much of the incident key light a fully translucent sheet passes on. */\nexport const TRANSMISSION_GAIN = 0.5\n\n/** Fragment side: uniforms plus `plTransmission(inkFilter)`. */\nexport const TRANSLUCENCY_FRAGMENT = /* glsl */ `\nuniform float uTranslucency;\nuniform vec3 uBackLightDir;\nuniform vec3 uBackLightColor;\nuniform float uAmbientTransmission;\n${TRANSLUCENCY_VARYINGS}\n\nvec3 plTransmission(vec3 inkFilter) {\n if (uTranslucency <= 0.0) return vec3(0.0);\n vec3 n = normalize(vPlWorldNormal);\n // Sheets render double-sided; the back face needs the normal it actually shows.\n if (!gl_FrontFacing) n = -n;\n // The lamp is BEHIND this sheet when the face we are looking at points away\n // from it — that is the whole test.\n float behind = clamp(-dot(n, uBackLightDir), 0.0, 1.0);\n // A grazing view looks through more paper, and more paper passes less light.\n float thickness = abs(dot(n, normalize(vPlViewDir)));\n // Paper in a lit room glows whatever way it is turned — a sheet standing\n // edge-on to the only lamp is not black. Without this floor, a banner\n // whose face runs parallel to the key light gets neither diffuse nor\n // transmission and drops out of the picture entirely.\n vec3 arriving = uBackLightColor * behind + uAmbientTransmission;\n return arriving * uTranslucency * mix(0.25, 1.0, thickness) * inkFilter;\n}\n`\n\nexport interface TranslucencyValues {\n translucency: number\n /** Unit world direction from the scene toward the key light. */\n direction: THREE.Vector3\n color: THREE.Color\n /** Light the room passes through the sheet from every direction at once. */\n ambient: number\n}\n\n/**\n * Resolve the transmission uniforms from the paper and the scene's lighting\n * — the key light's own position and color, so translucency can never\n * disagree with the lamp casting the shadows.\n *\n * It takes a resolved rig as well as a name because a rig is no longer\n * always a preset: once the light can be moved, the lamp this sheet is\n * backlit by is the one the SCENE ended up with, not the one the paper was\n * authored against.\n */\nexport function translucencyValues(\n translucency: number,\n lighting: LightingName | LightingPreset,\n): TranslucencyValues {\n const preset = typeof lighting === 'string' ? getLightingPreset(lighting) : lighting\n const [x, y, z] = preset.key.position\n const direction = new THREE.Vector3(x, y, z)\n // A key light at the origin has no direction to give; treat it as overhead.\n if (direction.lengthSq() < 1e-12) direction.set(0, 1, 0)\n direction.normalize()\n const color = new THREE.Color(preset.key.color).multiplyScalar(preset.key.intensity * TRANSMISSION_GAIN)\n return { translucency, direction, color, ambient: preset.ambient * TRANSMISSION_GAIN }\n}\n\n/** Ready-to-bind uniform objects for a shader program. */\nexport function translucencyUniforms(\n translucency: number,\n lighting: LightingName | LightingPreset,\n): Record<string, { value: unknown }> {\n const values = translucencyValues(translucency, lighting)\n return {\n uTranslucency: { value: values.translucency },\n uBackLightDir: { value: values.direction },\n uBackLightColor: { value: values.color },\n uAmbientTransmission: { value: values.ambient },\n }\n}\n","import type { FilmName, LightOverrides, LightingName } from '../config/schema'\n\n/**\n * Lighting presets: each is a key light + ambient level + contact shadow +\n * optional gobo (a texture the key light projects — window blinds, foliage).\n * Pure data here (testable in node); textures and R3F live in\n * PaperLighting.tsx. Serialized into presets as `scene.lighting`.\n *\n * A preset is the *starting point*, not the ceiling. `lightSchema` below is\n * the art-directable half: a handful of overrides that ride on top of a\n * named preset, so \"nave, but the sun is lower and the room is dimmer\" is a\n * thing you can say — and serialize — instead of a preset you have to fork.\n */\n\nexport interface LightingPreset {\n id: LightingName\n label: string\n ambient: number\n key: { color: string; intensity: number; position: [number, number, number] }\n contactShadowOpacity: number\n /** Contact shadow blur — hard for noir, long and soft for golden hour. */\n contactShadowBlur: number\n /** Renderer tone-mapping exposure while active. */\n exposure: number\n /**\n * The tone curve the picture is printed through.\n *\n * `exposure` picks the stop; this picks the FILM, and on a subject that is\n * almost white the film is the louder of the two. Every preset ships\n * `neutral` — Khronos PBR Neutral — because it is the only one of the\n * three that keeps a clipping sheet BOTH bright and the colour it actually\n * is. See the note on `filmNames` for what the other two do to warm light.\n */\n film: FilmName\n shadow: { mapSize: number; radius: number }\n gobo?: { kind: 'blinds' | 'leaves'; drift: number; angle: number }\n /**\n * Distance haze. Depth in a deep space is staged almost entirely by fog —\n * it is what turns a row of banners into a receding colonnade instead of\n * a flat row of rectangles.\n */\n fog?: { color: string; near: number; far: number }\n /**\n * The studio light: how strongly the room itself lights the paper.\n *\n * `<ambientLight>` adds brightness with no direction at all, which is the\n * single biggest reason a surface reads flat. This is the same brightness\n * with a SHAPE — an environment built from the sky below, so a sheet\n * turned toward the bright side of the room gets more light than one\n * turned away, and paper's sheen finally has something to reflect.\n */\n studio: number\n /**\n * The room, as three colours. It grades zenith → horizon → floor, carries\n * a soft disc of the key's own colour where the key stands, and becomes\n * both the environment map and (in stage mode) the cyclorama, so the\n * light and the space it is in cannot disagree.\n */\n sky: { zenith: string; horizon: string; ground: string }\n}\n\nexport const lightingPresets: Record<LightingName, LightingPreset> = {\n studio: {\n id: 'studio',\n label: 'Studio',\n ambient: 0.28,\n key: { color: '#ffffff', intensity: 1.6, position: [2.5, 4, 3] },\n contactShadowOpacity: 0.3,\n contactShadowBlur: 2.4,\n exposure: 1,\n film: 'neutral',\n shadow: { mapSize: 1024, radius: 4 },\n studio: 0.9,\n sky: { zenith: '#f6f7f9', horizon: '#e2e2e4', ground: '#b4b1ad' },\n },\n window: {\n id: 'window',\n label: 'Window',\n ambient: 0.22,\n key: { color: '#ffe3c0', intensity: 1.9, position: [3, 2.6, 2.6] },\n contactShadowOpacity: 0.35,\n contactShadowBlur: 2.6,\n exposure: 1,\n film: 'neutral',\n shadow: { mapSize: 1024, radius: 5 },\n gobo: { kind: 'blinds', drift: 0.004, angle: 0.62 },\n studio: 0.8,\n sky: { zenith: '#cfd8e6', horizon: '#f4e6d2', ground: '#8e8478' },\n },\n leaves: {\n id: 'leaves',\n label: 'Leaves',\n ambient: 0.2,\n key: { color: '#fff2d8', intensity: 2.0, position: [2.2, 3.6, 2.4] },\n contactShadowOpacity: 0.4,\n contactShadowBlur: 2.8,\n exposure: 1,\n film: 'neutral',\n shadow: { mapSize: 1024, radius: 6 },\n gobo: { kind: 'leaves', drift: 0.012, angle: 0.7 },\n studio: 0.85,\n sky: { zenith: '#bcd3c4', horizon: '#eae2c6', ground: '#6f7a5e' },\n },\n goldenhour: {\n id: 'goldenhour',\n label: 'Golden hour',\n ambient: 0.14,\n key: { color: '#ffb066', intensity: 2.4, position: [4, 0.9, 2.2] },\n contactShadowOpacity: 0.45,\n contactShadowBlur: 3.2,\n exposure: 1.15,\n film: 'neutral',\n shadow: { mapSize: 1024, radius: 7 },\n studio: 0.7,\n sky: { zenith: '#5d6f96', horizon: '#ffbe86', ground: '#4a3a2e' },\n },\n noir: {\n id: 'noir',\n label: 'Noir',\n ambient: 0.04,\n key: { color: '#ffffff', intensity: 2.6, position: [2, 3, 1.6] },\n contactShadowOpacity: 0.7,\n contactShadowBlur: 1.1,\n exposure: 1.05,\n film: 'neutral',\n shadow: { mapSize: 2048, radius: 1 },\n studio: 0.16,\n sky: { zenith: '#0d0d10', horizon: '#26262c', ground: '#050506' },\n },\n /**\n * A hard key at a grazing angle — the light paper is photographed under.\n *\n * This is the only preset in the set whose subject is the SURFACE rather\n * than the sheet. At eight degrees above the horizon the key skims across\n * the stock instead of landing on it, so every fibre, deckle tooth and\n * crease casts a shadow the length of itself and reads as RELIEF. It is\n * how a paper merchant shoots a swatch book, and it is the only way the\n * surface effects this library ships — grain, deckle, creaseLines, aging —\n * are visible as texture rather than as tint.\n *\n * Ambient and studio are both held down on purpose. Raking light works by\n * the shadows it casts, and fill is exactly the thing that fills those in;\n * turning `studio` up here does not brighten the picture so much as erase\n * the subject.\n */\n raking: {\n id: 'raking',\n label: 'Raking',\n // Lifted from 0.06/0.25 after looking at it: at the floor the shadow\n // side of a crumple went to near-black and the relief stopped reading as\n // relief and started reading as holes. This is the least fill that still\n // leaves a facet turned away from the key legible.\n ambient: 0.09,\n key: { color: '#fff6ea', intensity: 3.2, position: [5.81, 0.84, 1.24] },\n contactShadowOpacity: 0.6,\n contactShadowBlur: 1.6,\n exposure: 1,\n film: 'neutral',\n shadow: { mapSize: 2048, radius: 2 },\n studio: 0.32,\n sky: { zenith: '#2a2a2e', horizon: '#4a4844', ground: '#141314' },\n },\n /**\n * The sheet on a lightbox: the lamp is behind the paper and level with it.\n *\n * Every other front-lit preset shows you ink ON paper. This one shows you\n * light THROUGH it — which is the most beautiful thing paper does, and\n * which the library has been able to render since `translucency` became a\n * per-stock number without a single preset ever making it the subject.\n * Vellum glows, newsprint turns to a grey lantern with its fibres showing,\n * and a printed sheet reads backwards through itself.\n *\n * Printed a stop under for the same reason `nave` is: a backlit sheet\n * carries the lamp's whole intensity as transmission, so at 1.0 the paper\n * clips to flat white and takes its own texture with it.\n */\n lightbox: {\n id: 'lightbox',\n label: 'Lightbox',\n ambient: 0.05,\n key: { color: '#fdfdff', intensity: 4.5, position: [0, 0.7, -7.97] },\n // A sheet standing on a lit panel has almost nothing to cast onto.\n contactShadowOpacity: 0.15,\n contactShadowBlur: 4,\n exposure: 0.85,\n film: 'neutral',\n shadow: { mapSize: 1024, radius: 4 },\n studio: 0.35,\n sky: { zenith: '#dfe4ec', horizon: '#f6f8fc', ground: '#b9bec8' },\n },\n nave: {\n id: 'nave',\n label: 'Nave',\n // Dim, and the key sits BEHIND the walk rather than beside it: this mode\n // is carried by light coming through the paper, not off it. Ambient is\n // nearly nothing so the only bright thing in frame is the source itself —\n // what fills the shadow side is the room, which has a direction.\n ambient: 0.03,\n key: { color: '#fff1dc', intensity: 2.8, position: [0, 7, -16] },\n contactShadowOpacity: 0.55,\n contactShadowBlur: 3.6,\n // Printed a stop under. A backlit sheet carries its lamp's whole\n // intensity as transmission, so at 1.0 every banner in the hall clipped\n // to flat white and the folds — the entire reason the paper is draped —\n // vanished into the highlight.\n exposure: 0.8,\n film: 'neutral',\n shadow: { mapSize: 2048, radius: 6 },\n // Warm and light, not black: distance in a backlit hall washes TOWARD\n // the source, which is what separates haze from murk. It has to reach\n // past the end of the walk: at `far: 38` the back half of a 36-unit\n // colonnade was uniform fog colour, so the depth cue flattened exactly\n // where depth was the picture.\n fog: { color: '#a08d72', near: 9, far: 70 },\n studio: 0.55,\n sky: { zenith: '#241c17', horizon: '#fff4e2', ground: '#0e0b09' },\n },\n}\n\nexport function getLightingPreset(name: LightingName): LightingPreset {\n return lightingPresets[name]\n}\n\n// ── The authorable half ─────────────────────────────────────────────────────\n\n// `lightSchema` and its types live in `config/schema.ts` — they are part of\n// the serialized config, and `sceneSchema` needs them, which a schema that\n// imports FROM here cannot have. Re-exported because this is where the rig\n// they describe is resolved, and a caller reaching for the overrides looks\n// for them beside `resolveLighting`.\nexport { lightSchema, type LightOverrides, type LightOverridesInput } from '../config/schema'\n\n/** Where a light stands, in the terms a person would say it in. */\nexport interface LightAngles {\n /** Degrees around the vertical: 0 = in front (+Z), 90 = right (+X), ±180 = behind. */\n azimuth: number\n /** Degrees above the horizon. */\n elevation: number\n /** Distance from the origin. Only the direction matters to a directional light; this keeps round-trips exact. */\n distance: number\n}\n\nconst DEG = 180 / Math.PI\n\n/**\n * Decompose a key light's position into the two angles the panel edits.\n *\n * A light at the origin has no direction to give, so it is reported as\n * straight overhead — the same fallback the transmission model makes, and\n * they have to agree.\n */\nexport function lightAngles(position: readonly [number, number, number]): LightAngles {\n const [x, y, z] = position\n const distance = Math.hypot(x, y, z)\n if (distance < 1e-9) return { azimuth: 0, elevation: 90, distance: 0 }\n const ground = Math.hypot(x, z)\n return {\n azimuth: ground < 1e-9 ? 0 : Math.atan2(x, z) * DEG,\n elevation: Math.atan2(y, ground) * DEG,\n distance,\n }\n}\n\n/** The inverse: put a light back where those angles say it stands. */\nexport function lightPosition(angles: LightAngles): [number, number, number] {\n const azimuth = angles.azimuth / DEG\n const elevation = angles.elevation / DEG\n const ground = Math.cos(elevation) * angles.distance\n return [Math.sin(azimuth) * ground, Math.sin(elevation) * angles.distance, Math.cos(azimuth) * ground]\n}\n\n/**\n * A preset with the overrides applied — the rig everything else reads.\n *\n * This is deliberately the ONLY way a light gets resolved. The transmission\n * uniforms, the shadow-casting lamp, the environment and the exposure all\n * come out of one object, because the bug this replaces was exactly that\n * disagreement: the banners computed their backlit glow from `studio` while\n * the hall was lit by `nave`, and a sheet lit from behind by a lamp that is\n * actually in front of it is not a subtle error.\n */\nexport function resolveLighting(\n base: LightingName | LightingPreset,\n overrides?: LightOverrides,\n): LightingPreset {\n const preset = typeof base === 'string' ? getLightingPreset(base) : base\n if (!overrides) return preset\n\n const { exposure, film, key, color, direction, height, ambient, studio, haze } = overrides\n const moved = direction !== undefined || height !== undefined\n const angles = moved ? lightAngles(preset.key.position) : null\n\n return {\n ...preset,\n ambient: ambient ?? preset.ambient,\n studio: studio ?? preset.studio,\n exposure: exposure ?? preset.exposure,\n film: film ?? preset.film,\n key: {\n color: color ?? preset.key.color,\n intensity: key ?? preset.key.intensity,\n position: angles\n ? lightPosition({\n azimuth: direction ?? angles.azimuth,\n elevation: height ?? angles.elevation,\n // A key that has been dragged onto the horizon still has to stand\n // somewhere, so a light collapsed to the origin gets a real\n // distance rather than staying at zero and losing its direction.\n distance: angles.distance || 10,\n })\n : preset.key.position,\n },\n fog: resolveFog(preset.fog, haze),\n }\n}\n\n/**\n * Haze as a multiplier on the preset's own depth cue, so one slider reads\n * \"thicker air\" rather than asking for two distances in world units. It\n * pulls both ends in together: at 2× you see half as far, and the wash\n * starts half as far out, which is what actual haze does.\n */\nfunction resolveFog(fog: LightingPreset['fog'], haze: number | undefined): LightingPreset['fog'] {\n if (!fog || haze === undefined || haze === 1) return fog\n if (haze <= 0) return undefined\n return { color: fog.color, near: fog.near / haze, far: fog.far / haze }\n}\n","import { createContext, useContext, type ReactNode } from 'react'\nimport type { LightingName } from '../config/schema'\nimport { getLightingPreset, type LightingPreset } from './lighting'\n\n/**\n * The rig in force, for anything that has to agree with the lamps.\n *\n * Transmission is the reason this exists. `translucencyValues()` reads the\n * key light's own position and colour so a sheet's backlit glow can never\n * disagree with the lamp casting its shadow — but it read it from the\n * paper's OWN `scene.lighting`, and in stage mode the banners never carried\n * one. Every banner in every stage computed its glow from `studio`, a lamp\n * up and to the right, while the hall was lit by `nave` from behind. The\n * coupling was correct and the wire was missing.\n *\n * So the scene publishes the rig it is actually using, and the paper reads\n * that in preference to its own name. Outside a stage there is no provider,\n * nothing changes, and a paper lights itself as it always did.\n */\nconst LightRigContext = createContext<LightingPreset | null>(null)\n\nexport function LightRig({ rig, children }: { rig: LightingPreset; children: ReactNode }) {\n return <LightRigContext.Provider value={rig}>{children}</LightRigContext.Provider>\n}\n\n/** The scene's rig if one is published, otherwise the paper's own preset. */\nexport function useLightRig(own: LightingName): LightingPreset {\n return useContext(LightRigContext) ?? getLightingPreset(own)\n}\n","import * as THREE from 'three'\nimport { useFrame } from '@react-three/fiber'\nimport { useEffect, useMemo } from 'react'\nimport type { DamageSource } from './damageContract'\n\n/**\n * A `DamageSource` as a texture the surface shader can sample.\n *\n * The texture wraps the source's own `pixels` array — no copy — and is\n * re-uploaded only on a frame where `version` has moved. A burning sheet\n * uploads 16 KB a frame at 64²; a sheet whose damage has stopped changing\n * uploads nothing, which is the same \"costs nothing at rest\" rule the field\n * itself follows.\n *\n * Linear filtering is what keeps a 64² grid from cutting holes as a staircase:\n * the shader cuts at presence one half, and bilinear interpolation turns that\n * into straight segments between texels. A hard-edged field still shows them\n * as facets; a graded one, which a real burn is, shows far fewer. No\n * mipmaps — the sheet is never far enough away for a 64² grid to alias.\n */\nexport function useDamageTexture(source: DamageSource | null | undefined): THREE.DataTexture | null {\n const texture = useMemo(() => {\n if (!source) return null\n const t = new THREE.DataTexture(\n source.pixels,\n source.size,\n source.size,\n THREE.RGBAFormat,\n THREE.UnsignedByteType,\n )\n t.magFilter = THREE.LinearFilter\n t.minFilter = THREE.LinearFilter\n t.wrapS = THREE.ClampToEdgeWrapping\n t.wrapT = THREE.ClampToEdgeWrapping\n t.generateMipmaps = false\n // Data, not colour. A colour-managed texture would be decoded as sRGB and\n // move every channel's midpoint — presence one half would stop being the\n // edge of the hole.\n t.colorSpace = THREE.NoColorSpace\n // Row 0 is v = 0, which is how the source writes it.\n t.flipY = false\n t.userData.version = source.version\n t.needsUpdate = true\n return t\n }, [source])\n\n // Imperatively-created, so ours to free — R3F disposes only what JSX made.\n useEffect(() => () => texture?.dispose(), [texture])\n\n useFrame(() => {\n if (!source || !texture) return\n if (texture.userData.version === source.version) return\n texture.userData.version = source.version\n texture.needsUpdate = true\n })\n\n return texture\n}\n","import { useEffect, useState } from 'react'\nimport type { PaperConfig } from '../config/schema'\nimport { getStock } from '../core/stock'\nimport { receiptTotals, type ReceiptContent } from '../content/receipt'\n\n/**\n * Accessibility layer: reduced-motion handling, a hidden DOM mirror so the\n * paper's content exists for screen readers and find-in-page, and a no-WebGL\n * DOM fallback.\n */\n\nexport function usePrefersReducedMotion(override?: boolean): boolean {\n const [system, setSystem] = useState(\n () => typeof window !== 'undefined' && window.matchMedia?.('(prefers-reduced-motion: reduce)').matches,\n )\n useEffect(() => {\n const query = window.matchMedia?.('(prefers-reduced-motion: reduce)')\n if (!query) return\n const onChange = () => setSystem(query.matches)\n query.addEventListener('change', onChange)\n return () => query.removeEventListener('change', onChange)\n }, [])\n return override ?? system\n}\n\nlet webglSupport: boolean | null = null\n\nexport function supportsWebGL(): boolean {\n if (webglSupport !== null) return webglSupport\n try {\n const canvas = document.createElement('canvas')\n webglSupport = Boolean(canvas.getContext('webgl2') ?? canvas.getContext('webgl'))\n } catch {\n webglSupport = false\n }\n return webglSupport\n}\n\n/** Human-readable text equivalent of a paper's content. */\nexport function contentText(config: PaperConfig): string {\n const content = config.content\n if (content.type === 'text') return content.text\n if (content.type === 'image') return content.alt ?? 'An image printed on paper.'\n if (content.type === 'receipt') {\n const totals = receiptTotals(content as ReceiptContent)\n const items = content.items.map((i) => `${i.name} ${i.price.toFixed(2)}`).join(', ')\n return `Receipt from ${content.store}: ${items}. Total ${totals.total.toFixed(2)}. ${content.footer}`\n }\n return 'A blank sheet of paper.'\n}\n\nconst visuallyHidden: React.CSSProperties = {\n position: 'absolute',\n width: 1,\n height: 1,\n padding: 0,\n margin: -1,\n overflow: 'hidden',\n clip: 'rect(0 0 0 0)',\n whiteSpace: 'nowrap',\n border: 0,\n}\n\n/** Hidden DOM twin of the 3D paper — screen readers read it, ctrl-F finds it. */\nexport function PaperMirror({ config }: { config: PaperConfig }) {\n return (\n <div style={visuallyHidden} aria-hidden={false}>\n {contentText(config)}\n </div>\n )\n}\n\n/** No WebGL: the paper renders flat — content on a stock-tinted card. */\nexport function PaperFallback({ config }: { config: PaperConfig }) {\n const stock = getStock(config.stock)\n const isImage = config.content.type === 'image'\n return (\n <div\n role=\"img\"\n aria-label={contentText(config)}\n style={{\n width: '100%',\n height: '100%',\n display: 'grid',\n placeItems: 'center',\n background: 'transparent',\n }}\n >\n <div\n style={{\n aspectRatio: `${config.sheet.width} / ${config.sheet.height}`,\n maxWidth: '80%',\n maxHeight: '90%',\n background: stock.color,\n color: stock.inkColor,\n boxShadow: '0 6px 24px rgba(0,0,0,0.25)',\n padding: '8%',\n overflow: 'hidden',\n fontFamily: config.content.type === 'receipt' ? 'ui-monospace, monospace' : 'Georgia, serif',\n whiteSpace: 'pre-wrap',\n fontSize: 14,\n }}\n >\n {isImage && config.content.type === 'image' ? (\n <img\n src={config.content.src}\n alt={config.content.alt ?? ''}\n style={{ width: '100%', height: '100%', objectFit: 'cover', margin: '-8%' }}\n />\n ) : (\n contentText(config)\n )}\n </div>\n </div>\n )\n}\n","/**\n * Stop-motion feel: quantize continuous time to animation \"twos\"\n * (12 steps per second, like shooting on twos at 24fps). Applies to\n * deformer time, idle motion, and behavior progress; the camera is\n * excluded by default — quantized cameras read as jank, not craft.\n */\nexport const ON_TWOS_FPS = 12\n\nexport function quantizeTime(t: number, fps: number = ON_TWOS_FPS): number {\n return Math.floor(t * fps) / fps\n}\n\n/** Snap a 0..1 progress that plays over `duration` seconds to whole frames. */\nexport function quantizeProgress(p: number, duration: number, fps: number = ON_TWOS_FPS): number {\n const steps = Math.max(1, Math.round(duration * fps))\n return Math.round(p * steps) / steps\n}\n","import { useEffect, useMemo, useRef, useState } from 'react'\nimport type { PaperConfig } from '../config/schema'\nimport { PaperStateMachine, stripStates } from './machine'\n\nexport interface UsePaperStatesResult {\n /** The config to render this frame — animated when a machine is live. */\n config: PaperConfig\n /** Current state name ('rest' when no machine). */\n state: string\n /** Send triggers through this; null when states are absent or disabled. */\n machine: PaperStateMachine | null\n}\n\n/**\n * Bind a state machine to a config with `states`. The machine survives\n * config edits via `rebase` (current state and live values are kept —\n * flipping perforation to torn mid-pick must not snap the stamp to rest);\n * it is only rebuilt when states are toggled on/off.\n *\n * `animated` holds an IMMUTABLE structural snapshot for the React tree; it\n * updates only on structural boundaries (transition start/settle, state swap,\n * rebase), not per frame. Per-tick numeric values are read straight off\n * `machine.liveConfig` by the caller's frame loop — GSAP owns values, useFrame\n * owns uploads. `machine` is returned so the caller can poll it.\n */\nexport function usePaperStates(\n config: PaperConfig,\n enabled: boolean,\n instant: boolean,\n onAction?: (event: string, state: string) => void,\n onStateChange?: (state: string) => void,\n): UsePaperStatesResult {\n const live = enabled && Boolean(config.states)\n const key = useMemo(() => JSON.stringify(config), [config])\n\n // Callbacks live in refs so machine identity doesn't churn on new closures.\n const onActionRef = useRef(onAction)\n onActionRef.current = onAction\n const onStateChangeRef = useRef(onStateChange)\n onStateChangeRef.current = onStateChange\n\n const machineRef = useRef<PaperStateMachine | null>(null)\n const lastStateRef = useRef<string>('rest')\n const [animated, setAnimated] = useState<{ config: PaperConfig; state: string } | null>(null)\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: key serializes the config — the machine rebases onto a new config instead of being rebuilt.\n useEffect(() => {\n if (!live) {\n machineRef.current?.dispose()\n machineRef.current = null\n setAnimated(null)\n return\n }\n if (machineRef.current) {\n machineRef.current.rebase(config)\n return\n }\n const machine = new PaperStateMachine(config, {\n instant,\n // Structural boundaries only (not per tick) — safe to route to React.\n onChange: (c, state) => {\n if (state !== lastStateRef.current) {\n lastStateRef.current = state\n onStateChangeRef.current?.(state)\n }\n setAnimated({ config: c, state })\n },\n onAction: (event, state) => onActionRef.current?.(event, state),\n })\n machineRef.current = machine\n lastStateRef.current = machine.state\n setAnimated({ config: machine.structuralConfig(), state: machine.state })\n }, [key, live, instant])\n\n useEffect(\n () => () => {\n machineRef.current?.dispose()\n machineRef.current = null\n },\n [],\n )\n\n return {\n config: live && animated ? animated.config : stripStates(config),\n state: live && animated ? animated.state : 'rest',\n machine: live ? machineRef.current : null,\n }\n}\n","import { gsap } from 'gsap'\nimport { mergeConfig } from '../config/merge'\nimport {\n paperConfigSchema,\n paperStatesSchema,\n stateDefSchema,\n type PaperConfig,\n type StateName,\n} from '../config/schema'\n\n/**\n * The interaction-state engine. A state is a set of parameter overrides on\n * the base preset — never a separate preset. The machine\n * resolves each state to a full config (base + overrides), keeps ONE live\n * tween target of flattened numeric leaves, and always tweens FROM CURRENT\n * VALUES: a pointer that enters/leaves rapidly retargets the same tween\n * values instead of stacking or snapping.\n *\n * Delivery split (GSAP owns values, useFrame owns uploads):\n * GSAP animates the STABLE `flat` object in place; per-tick values are polled\n * off `liveConfig` by the consumer's frame loop, never pushed through React.\n * `onChange` fires only on STRUCTURAL boundaries (a transition's start and\n * settle, a state swap, a rebase) so the React tree re-renders a handful of\n * times per interaction instead of once per frame.\n */\n\n/** Built-in trigger events (v1 — user-defined wiring is parked for editor v2). */\nexport type StateEvent = 'enter' | 'leave' | 'down' | 'up' | 'pick' | 'place' | 'return'\n\n/** The fixed v1 transition table: pointer flow + pick/drop flow. */\nexport const stateEventTransitions: Record<string, Partial<Record<StateEvent, StateName>>> = {\n rest: { enter: 'hover' },\n hover: { leave: 'rest', down: 'pressed' },\n pressed: { up: 'hover', pick: 'picked' },\n picked: { place: 'placed', return: 'rest' },\n placed: {},\n}\n\nconst DEFAULT_TRANSITION = { duration: 0.35, ease: 'power2.out' }\n\n/** The base config with `states` stripped — what a state resolves against. */\nexport function stripStates(config: PaperConfig): PaperConfig {\n if (!config.states) return config\n const { states: _states, ...rest } = config\n return rest as PaperConfig\n}\n\n/**\n * Resolve a state name to its full config: base + that state's overrides.\n * States without a recorded def (e.g. an untouched 'rest') are the base.\n * The merge re-parses so a structural override (a behavior swapped to\n * `{ type: 'carry' }`) comes back with every default filled.\n */\nexport function resolveStateConfig(base: PaperConfig, state: string): PaperConfig {\n const def = base.states?.states[state]\n const flat = stripStates(base)\n if (!def || Object.keys(def.overrides).length === 0) return flat\n return paperConfigSchema.parse(mergeConfig(flat as Record<string, unknown>, def.overrides))\n}\n\n/** Drop `undefined` leaves at every depth, and any object left empty by that. */\nfunction pruneUndefined(value: unknown): unknown {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) return value\n const out: Record<string, unknown> = {}\n for (const [key, v] of Object.entries(value as Record<string, unknown>)) {\n if (v === undefined) continue\n const pruned = pruneUndefined(v)\n const isEmptyObject =\n pruned !== null &&\n typeof pruned === 'object' &&\n !Array.isArray(pruned) &&\n Object.keys(pruned).length === 0\n if (!isEmptyObject) out[key] = pruned\n }\n return out\n}\n\n/**\n * Record a patch into ONE state's override diff (Figma's overridden\n * affordance), returning a new base config with that state updated — the base\n * params and every other state stay untouched. This is how an authoring tool\n * writes while a state chip is active. `undefined` values are dropped at every\n * depth: an override can only SET a base param, never remove one. Re-parsing\n * runs the schema's per-state validation, so an override that wouldn't merge\n * cleanly throws here.\n */\nexport function recordStateOverride(\n config: PaperConfig,\n stateName: string,\n patch: Record<string, unknown>,\n): PaperConfig {\n const cleaned = pruneUndefined(patch) as Record<string, unknown>\n const states = config.states ?? paperStatesSchema.parse({})\n const def = states.states[stateName] ?? stateDefSchema.parse({})\n const overrides = mergeConfig(def.overrides, cleaned) as Record<string, unknown>\n return paperConfigSchema.parse({\n ...config,\n states: {\n ...states,\n states: { ...states.states, [stateName]: { ...def, overrides } },\n },\n })\n}\n\n// ── Numeric flattening (dot paths, array indices included) ──────────────────\n\nexport function flattenNumeric(\n value: unknown,\n prefix = '',\n out: Record<string, number> = {},\n): Record<string, number> {\n if (typeof value === 'number') {\n if (prefix) out[prefix] = value\n return out\n }\n if (value !== null && typeof value === 'object') {\n const entries = Array.isArray(value)\n ? value.map((v, i) => [String(i), v] as const)\n : Object.entries(value)\n for (const [key, v] of entries) {\n flattenNumeric(v, prefix ? `${prefix}.${key}` : key, out)\n }\n }\n return out\n}\n\nfunction setPath(target: Record<string, unknown>, path: string, value: number): void {\n const keys = path.split('.')\n let node: Record<string, unknown> = target\n for (let i = 0; i < keys.length - 1; i++) {\n const next = node[keys[i]!]\n if (next === null || typeof next !== 'object') return // structure changed under us\n node = next as Record<string, unknown>\n }\n node[keys[keys.length - 1]!] = value\n}\n\n/** Apply the flat numeric leaves onto a config object in place (no allocation). */\nfunction applyFlat(target: Record<string, unknown>, flat: Record<string, number>): void {\n for (const path in flat) setPath(target, path, flat[path]!)\n}\n\nconst clone = <T>(v: T): T => JSON.parse(JSON.stringify(v)) as T\n\n// ── The machine ──────────────────────────────────────────────────────────────\n\nexport interface PaperStateMachineOptions {\n /** Reduced motion: every transition applies instantly (duration 0). */\n instant?: boolean\n /**\n * Fires on STRUCTURAL boundaries only — a transition's start and settle, a\n * state swap, a rebase — with an immutable config snapshot. NOT per tick;\n * per-frame numeric values are polled off `liveConfig`.\n */\n onChange?: (config: PaperConfig, state: string) => void\n /** `onEnter` actions — v1 is 'emit:<event>' only; fires after arrival. */\n onAction?: (event: string, state: string) => void\n}\n\nexport class PaperStateMachine {\n state: string\n private base: PaperConfig\n private readonly opts: PaperStateMachineOptions\n /** Structural target of the current state; numeric leaves live in `flat`. */\n private structure: PaperConfig\n /**\n * The single live tween target — flattened numeric leaves of the config.\n * STABLE IDENTITY for the machine's lifetime: `goto`/`rebase` mutate it in\n * place (add/remove/keep keys) and never reassign, so an in-flight GSAP\n * tween keeps animating the same object across a rebase instead of freezing.\n */\n private readonly flat: Record<string, number> = {}\n /** Mutable working config, polled by the consumer's frame loop via `liveConfig`. */\n private live: PaperConfig\n private tween: gsap.core.Tween | null = null\n private resolved = new Map<string, PaperConfig>()\n\n constructor(base: PaperConfig, opts: PaperStateMachineOptions = {}) {\n this.base = base\n this.opts = opts\n this.state = base.states?.initial ?? 'rest'\n const target = this.resolve(this.state)\n this.structure = clone(target)\n this.live = clone(target)\n Object.assign(this.flat, flattenNumeric(target))\n }\n\n /** World-units drag distance that flips pressed → picked. */\n get pickThreshold(): number {\n return this.base.states?.pickThreshold ?? 0.1\n }\n\n /**\n * The live config — the mutable working object with the current tween values\n * applied in place. Cheap (no allocation); meant to be polled every frame.\n * Never hand this to React; use `structuralConfig()` for an immutable snapshot.\n */\n get liveConfig(): PaperConfig {\n applyFlat(this.live as unknown as Record<string, unknown>, this.flat)\n return this.live\n }\n\n /** Back-compat alias for `liveConfig` (tests, imperative reads). */\n get config(): PaperConfig {\n return this.liveConfig\n }\n\n /** True while a transition tween is in flight — consumers gate frame work on it. */\n get transitioning(): boolean {\n return this.tween !== null\n }\n\n /** Exposed for tests: the in-flight transition tween, if any. */\n get activeTween(): gsap.core.Tween | null {\n return this.tween\n }\n\n /** An immutable structural snapshot for React consumers (never the live object). */\n structuralConfig(): PaperConfig {\n const out = clone(this.structure) as unknown as Record<string, unknown>\n applyFlat(out, this.flat)\n return out as unknown as PaperConfig\n }\n\n /** Fire a built-in trigger; returns the new state or null if it doesn't apply. */\n send(event: StateEvent): string | null {\n const next = stateEventTransitions[this.state]?.[event]\n if (!next || next === this.state) return null\n this.goto(next)\n return next\n }\n\n /**\n * Drive to 'picked' through the legal chain (rest→hover→pressed→picked),\n * each hop instant so EVERY side effect fires (behavior override, backing\n * silhouette, onChange state reports, placed onEnter chain). This is the\n * keyboard/a11y entry point — it never produced pointer hover/press events,\n * so raw `send('pick')` from 'rest' was a no-op. Returns true if it landed.\n */\n pickProgrammatic(): boolean {\n for (const event of ['enter', 'down', 'pick'] as StateEvent[]) {\n const next = stateEventTransitions[this.state]?.[event]\n if (next && next !== this.state) this.goto(next, { instant: true })\n }\n return this.state === 'picked'\n }\n\n /** Instant, legal place (picked → placed) so onEnter/emit fires. */\n placeProgrammatic(): boolean {\n return this.driveInstant('place')\n }\n\n /** Instant, legal return (picked → rest). */\n returnProgrammatic(): boolean {\n return this.driveInstant('return')\n }\n\n private driveInstant(event: StateEvent): boolean {\n const next = stateEventTransitions[this.state]?.[event]\n if (!next || next === this.state) return false\n this.goto(next, { instant: true })\n return true\n }\n\n /** Transition to a state (escape hatch for custom states; `send` for triggers). */\n goto(state: string, opts?: { instant?: boolean }): void {\n const def = this.base.states?.states[state]\n const target = this.resolve(state)\n this.state = state\n\n const targetFlat = flattenNumeric(target)\n // Structure swaps immediately (content/stock changes don't interpolate);\n // numeric leaves keep their CURRENT values and tween to the target.\n this.structure = clone(target)\n this.live = clone(target)\n const changed: Record<string, number> = {}\n // Mutate `flat` in place (stable identity): drop stale keys, keep live\n // values for shared paths, seed new paths at their target.\n for (const path in this.flat) {\n if (!(path in targetFlat)) delete this.flat[path]\n }\n for (const [path, value] of Object.entries(targetFlat)) {\n const current = this.flat[path]\n // Paths new to this structure appear at their target value — there is\n // no current value to tween from.\n if (current === undefined) this.flat[path] = value\n else if (current !== value) changed[path] = value\n }\n\n const duration =\n this.opts.instant || opts?.instant ? 0 : (def?.transition.duration ?? DEFAULT_TRANSITION.duration)\n const ease = def?.transition.ease ?? DEFAULT_TRANSITION.ease\n\n // One tween, ever — kill the previous instead of stacking. Values pick up\n // exactly where the killed tween left them (this.flat is the target).\n this.tween?.kill()\n this.tween = null\n\n const arrive = () => {\n for (const [path, value] of Object.entries(changed)) this.flat[path] = value\n this.emitStructure()\n for (const action of def?.onEnter ?? []) {\n if (action.startsWith('emit:')) this.opts.onAction?.(action.slice(5), state)\n }\n }\n\n if (duration === 0 || Object.keys(changed).length === 0) {\n arrive()\n return\n }\n // Structural boundary #1: the start of the transition (React sees the new\n // state and structure). Ticks below never emit — GSAP mutates `flat`, the\n // consumer polls `liveConfig`; #2 is the settle in `arrive`.\n this.emitStructure()\n this.tween = gsap.to(this.flat, {\n ...changed,\n duration,\n ease,\n onComplete: () => {\n this.tween = null\n arrive()\n },\n })\n }\n\n /**\n * Swap the base config without resetting the machine — parameter edits and\n * runtime patches (torn perforation on detach) keep the current state and\n * live values instead of snapping back to `initial`. An in-flight tween is\n * left running on the SAME `flat` object, so the transition continues\n * smoothly to its target across the rebase (no freeze, no snap).\n */\n rebase(base: PaperConfig): void {\n this.base = base\n this.resolved.clear()\n const target = this.resolve(this.state)\n this.structure = clone(target)\n this.live = clone(target)\n const targetFlat = flattenNumeric(target)\n // In-place, identity-preserving: drop stale keys, seed genuinely new paths\n // at target, keep every existing (possibly mid-tween) value untouched.\n for (const path in this.flat) {\n if (!(path in targetFlat)) delete this.flat[path]\n }\n for (const [path, value] of Object.entries(targetFlat)) {\n if (!(path in this.flat)) this.flat[path] = value\n }\n // Structural change (e.g. perforation flipped to torn) → re-render the\n // structure; the tween keeps animating `flat`, so values never snap.\n this.emitStructure()\n }\n\n dispose(): void {\n this.tween?.kill()\n this.tween = null\n }\n\n private resolve(state: string): PaperConfig {\n let config = this.resolved.get(state)\n if (!config) {\n config = resolveStateConfig(this.base, state)\n this.resolved.set(state, config)\n }\n return config\n }\n\n private emitStructure(): void {\n this.opts.onChange?.(this.structuralConfig(), this.state)\n }\n}\n","import * as THREE from 'three'\nimport { useEffect, useMemo, useRef } from 'react'\nimport { useFrame, useThree } from '@react-three/fiber'\nimport { ContactShadows } from '@react-three/drei'\nimport type { FilmName, LightingName } from '../config/schema'\nimport { buildEnvironment } from './environment'\nimport { resolveLighting, type LightingPreset, type LightOverrides } from './lighting'\nimport { usePrefersReducedMotion } from '../a11y'\n\n/**\n * The rig's film name, as a three constant.\n *\n * The mapping lives here rather than beside the presets because\n * `lighting.ts` is deliberately pure — it is the half that runs in node\n * under vitest, and importing three into it to name three integers would\n * trade that for nothing.\n */\nconst toneMappings: Record<FilmName, THREE.ToneMapping> = {\n agx: THREE.AgXToneMapping,\n neutral: THREE.NeutralToneMapping,\n filmic: THREE.ACESFilmicToneMapping,\n}\n\n/** Deterministic PRNG so gobos render identically everywhere. */\nfunction mulberry32(seed: number) {\n let a = seed\n return () => {\n a |= 0\n a = (a + 0x6d2b79f5) | 0\n let t = Math.imul(a ^ (a >>> 15), 1 | a)\n t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296\n }\n}\n\n/**\n * Procedural gobo textures — no binary assets in the repo. White passes\n * light, dark blocks it (SpotLight.map multiplies the beam).\n */\nexport function makeGoboTexture(kind: 'blinds' | 'leaves'): THREE.CanvasTexture {\n const size = 512\n const canvas = document.createElement('canvas')\n canvas.width = canvas.height = size\n const ctx = canvas.getContext('2d')!\n ctx.fillStyle = '#ffffff'\n ctx.fillRect(0, 0, size, size)\n\n if (kind === 'blinds') {\n // Venetian slats: soft-edged dark bars, slightly rotated.\n ctx.save()\n ctx.translate(size / 2, size / 2)\n ctx.rotate(-0.06)\n const slat = 34\n const gap = 30\n for (let y = -size; y < size; y += slat + gap) {\n const grad = ctx.createLinearGradient(0, y, 0, y + slat)\n grad.addColorStop(0, 'rgba(20,20,20,0)')\n grad.addColorStop(0.25, 'rgba(20,20,20,0.92)')\n grad.addColorStop(0.75, 'rgba(20,20,20,0.92)')\n grad.addColorStop(1, 'rgba(20,20,20,0)')\n ctx.fillStyle = grad\n ctx.fillRect(-size, y, size * 2, slat)\n }\n ctx.restore()\n } else {\n // Dappled foliage: three scales of soft dark blobs.\n const rand = mulberry32(7)\n for (const [count, radius, alpha] of [\n [26, 70, 0.75],\n [40, 38, 0.6],\n [70, 16, 0.5],\n ] as const) {\n for (let i = 0; i < count; i++) {\n const x = rand() * size\n const y = rand() * size\n const r = radius * (0.6 + rand() * 0.8)\n const grad = ctx.createRadialGradient(x, y, 0, x, y, r)\n grad.addColorStop(0, `rgba(15,20,12,${alpha})`)\n grad.addColorStop(0.7, `rgba(15,20,12,${alpha * 0.55})`)\n grad.addColorStop(1, 'rgba(15,20,12,0)')\n ctx.fillStyle = grad\n ctx.beginPath()\n ctx.ellipse(x, y, r, r * (0.6 + rand() * 0.5), rand() * Math.PI, 0, Math.PI * 2)\n ctx.fill()\n }\n }\n }\n\n const texture = new THREE.CanvasTexture(canvas)\n texture.wrapS = texture.wrapT = THREE.RepeatWrapping\n return texture\n}\n\n/**\n * The studio light: the room, prefiltered, hung on the scene.\n *\n * Mounted as its own component so the PMREM pass runs when the RIG changes\n * and not when anything else in the lighting rerenders — it is a render\n * target and a chain of blur passes, which is cheap once and silly sixty\n * times a second.\n */\nfunction StudioLight({ rig }: { rig: LightingPreset }) {\n const gl = useThree((s) => s.gl)\n const scene = useThree((s) => s.scene)\n\n // Only the colours and the key's placement change the image; intensity is\n // applied by the scene, so dragging that slider must not rebuild anything.\n const sky = `${rig.sky.zenith}|${rig.sky.horizon}|${rig.sky.ground}|${rig.key.color}|${rig.key.intensity}|${rig.key.position.join()}`\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: `sky` is the digest of everything the image is built from.\n useEffect(() => {\n const environment = buildEnvironment(gl, rig)\n const previous = scene.environment\n scene.environment = environment.texture\n return () => {\n scene.environment = previous\n environment.dispose()\n }\n }, [gl, scene, sky])\n\n useEffect(() => {\n const previous = scene.environmentIntensity\n scene.environmentIntensity = rig.studio\n return () => {\n scene.environmentIntensity = previous\n }\n }, [scene, rig.studio])\n\n return null\n}\n\n/**\n * How bright the hemisphere stand-in runs against the environment it\n * replaces. Prefiltered irradiance integrates the whole sky, and a\n * hemisphere light is one cosine term, so matching them by eye means\n * pushing the cheap one up.\n */\nconst HEMISPHERE_STAND_IN = 1.6\n\nexport interface PaperLightingProps {\n preset?: LightingName\n /**\n * Overrides on the preset — exposure, key, direction, height, ambient,\n * studio, haze. See `lightSchema`.\n */\n light?: LightOverrides\n /**\n * An already-resolved rig, which wins over `preset`/`light`. Stage mode\n * resolves once and hands the same object to the lamps and to the paper,\n * so the two cannot be resolved differently.\n */\n rig?: LightingPreset\n /** Local y of the ground the contact shadow sits on. */\n floor?: number\n /** Contact shadow footprint. */\n scale?: number\n /** Override prefers-reduced-motion (freezes gobo drift). */\n reducedMotion?: boolean\n /**\n * Shadow map resolution, overriding the preset's. 0 turns the shadow pass\n * off — it re-renders the scene's geometry, so on a weak machine it is\n * often the single most expensive thing in the frame.\n */\n shadowMapSize?: number\n /** Draw the soft contact shadow. It is its own render pass. */\n contactShadow?: boolean\n /**\n * Light the scene with the room as well as with the lamp. Off is one\n * fewer texture read per fragment and a flatter picture; it is a quality\n * knob, not an art-direction one — turn the studio light DOWN with\n * `light.studio` if you want less of it.\n */\n environment?: boolean\n}\n\n/**\n * A scene's lighting rig from one serialized name plus whatever the author\n * overrode: key light (spot with a procedural gobo, or directional), the\n * room as an environment map, ambient fill, tone-mapping exposure, distance\n * haze, and the contact shadow. Swap presets to restyle the same paper;\n * move the sliders to light it yourself.\n */\nexport function PaperLighting({\n preset = 'studio',\n light,\n rig,\n floor = -1.2,\n scale = 10,\n reducedMotion,\n shadowMapSize,\n contactShadow = true,\n environment = true,\n}: PaperLightingProps) {\n const p = useMemo(() => rig ?? resolveLighting(preset, light), [rig, preset, light])\n const mapSize = shadowMapSize ?? p.shadow.mapSize\n const castShadow = mapSize > 0\n const reduced = usePrefersReducedMotion(reducedMotion)\n const gl = useThree((s) => s.gl)\n const scene = useThree((s) => s.scene)\n\n useEffect(() => {\n const previousExposure = gl.toneMappingExposure\n const previousFilm = gl.toneMapping\n gl.toneMappingExposure = p.exposure\n gl.toneMapping = toneMappings[p.film]\n return () => {\n gl.toneMappingExposure = previousExposure\n gl.toneMapping = previousFilm\n }\n }, [gl, p.exposure, p.film])\n\n // Set imperatively rather than via <fog attach=\"fog\" />, which would bind\n // to whatever group this rig happens to be mounted under instead of the scene.\n useEffect(() => {\n if (!p.fog) return\n const previous = scene.fog\n scene.fog = new THREE.Fog(p.fog.color, p.fog.near, p.fog.far)\n return () => {\n scene.fog = previous\n }\n }, [scene, p.fog])\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: Only the gobo kind rebuilds the texture — drift and intensity animate in place.\n const goboMap = useMemo(() => (p.gobo ? makeGoboTexture(p.gobo.kind) : null), [p.gobo?.kind])\n useEffect(() => () => goboMap?.dispose(), [goboMap])\n\n const driftRef = useRef(0)\n useFrame((_, delta) => {\n if (!goboMap || !p.gobo || reduced) return\n driftRef.current += delta * p.gobo.drift\n goboMap.offset.set(driftRef.current, driftRef.current * 0.6)\n })\n\n return (\n <>\n {p.studio > 0 &&\n (environment ? (\n <StudioLight rig={p} />\n ) : (\n // The studio light degrades rather than disappearing. A hemisphere\n // is the cheap half of what the room does — light from above, a\n // different colour from below — so a machine that cannot pay for\n // the environment still gets a lit figure with a top and a bottom\n // instead of a flat cut-out.\n <hemisphereLight\n color={p.sky.horizon}\n groundColor={p.sky.ground}\n intensity={p.studio * HEMISPHERE_STAND_IN}\n />\n ))}\n <ambientLight intensity={p.ambient} />\n {p.gobo && goboMap ? (\n <spotLight\n position={p.key.position}\n color={p.key.color}\n // decay 0 keeps intensity art-directable rather than distance-driven.\n intensity={p.key.intensity * 3.2}\n angle={p.gobo.angle}\n penumbra={0.5}\n decay={0}\n castShadow={castShadow}\n map={goboMap}\n shadow-mapSize={[mapSize || 1, mapSize || 1]}\n shadow-radius={p.shadow.radius}\n shadow-normalBias={0.05}\n />\n ) : (\n <directionalLight\n position={p.key.position}\n color={p.key.color}\n intensity={p.key.intensity}\n castShadow={castShadow}\n shadow-mapSize={[mapSize || 1, mapSize || 1]}\n shadow-radius={p.shadow.radius}\n shadow-normalBias={0.05}\n />\n )}\n {contactShadow && (\n <ContactShadows\n position={[0, floor, 0]}\n opacity={p.contactShadowOpacity}\n scale={scale}\n blur={p.contactShadowBlur}\n far={3}\n />\n )}\n </>\n )\n}\n","import * as THREE from 'three'\nimport type { LightingPreset } from './lighting'\nimport { lightAngles } from './lighting'\nimport { cssColorOr } from './color'\n\n/**\n * The room, drawn as an equirectangular image so it can light things.\n *\n * Stage mode already builds a graded sky around the whole space and it lit\n * nothing — it was a gradient mesh the camera looked at. This is the same\n * three colours plus a soft disc where the key stands, turned into an\n * environment map, so the hall is lit BY the room the viewer can see. That\n * is what puts direction into the fill: a banner turned toward the source\n * picks up the source, one turned away picks up the dark end of the room,\n * and paper's sheen finally has something to reflect.\n *\n * Procedural on purpose — the repo carries no HDRI, nothing is fetched, and\n * the grade stays editable from the same numbers the lights read.\n */\n\n/** Small is fine: PMREM blurs it into mip levels anyway, and roughness eats the detail. */\nconst WIDTH = 256\nconst HEIGHT = 128\n\n/**\n * Where a direction lands in an equirectangular image, matching three's own\n * `equirectUv`: `u = atan2(z, x) / 2π + 0.5`. Our azimuth is measured from\n * +Z instead (0° in front, 90° right), which works out to `u = 0.75 − az/360`.\n * Getting this right is what puts the bright patch of sky on the same side\n * of the room as the lamp casting the shadows.\n */\nexport function skyU(azimuthDeg: number): number {\n const u = 0.75 - azimuthDeg / 360\n return ((u % 1) + 1) % 1\n}\n\n/** Elevation to image row. Row 0 is the zenith — v is flipped by the texture. */\nexport function skyV(elevationDeg: number): number {\n return 0.5 - elevationDeg / 180\n}\n\n/**\n * Paint the room. The gradient runs zenith → horizon → ground with the\n * horizon held as a band rather than a hairline, because a room's brightest\n * region is the wall, not a mathematical line through it.\n */\nexport function drawSky(ctx: CanvasRenderingContext2D, preset: LightingPreset): void {\n // Guarded: a stage's sky colours are editable text, and `addColorStop`\n // throws on anything it cannot parse. See `cssColorOr`.\n const zenith = cssColorOr(preset.sky.zenith, '#241c17')\n const horizon = cssColorOr(preset.sky.horizon, '#fff4e2')\n const ground = cssColorOr(preset.sky.ground, '#141210')\n const grade = ctx.createLinearGradient(0, 0, 0, HEIGHT)\n grade.addColorStop(0, zenith)\n grade.addColorStop(0.32, zenith)\n grade.addColorStop(0.5, horizon)\n grade.addColorStop(0.58, horizon)\n grade.addColorStop(1, ground)\n ctx.fillStyle = grade\n ctx.fillRect(0, 0, WIDTH, HEIGHT)\n\n // The key's own patch of sky. Bright, wide and soft: this is a window or a\n // softbox, not a sun, and a hard disc would make the reflections read as\n // a lamp somebody left in shot.\n const angles = lightAngles(preset.key.position)\n const x = skyU(angles.azimuth) * WIDTH\n const y = skyV(angles.elevation) * HEIGHT\n const radius = WIDTH * 0.3\n const color = new THREE.Color(preset.key.color)\n // The disc carries the key's intensity, so turning the lamp up brightens\n // the room it is standing in rather than only the shadows it casts.\n const strength = Math.min(1, preset.key.intensity / 3)\n\n // Drawn three times across the seam so a key behind the paper — where the\n // wrap falls — is not sliced in half by the edge of the image.\n for (const offset of [-WIDTH, 0, WIDTH]) {\n const glow = ctx.createRadialGradient(x + offset, y, 0, x + offset, y, radius)\n glow.addColorStop(\n 0,\n `rgba(${(color.r * 255) | 0}, ${(color.g * 255) | 0}, ${(color.b * 255) | 0}, ${strength})`,\n )\n glow.addColorStop(1, `rgba(${(color.r * 255) | 0}, ${(color.g * 255) | 0}, ${(color.b * 255) | 0}, 0)`)\n ctx.fillStyle = glow\n ctx.fillRect(x + offset - radius, y - radius, radius * 2, radius * 2)\n }\n}\n\n/** The room as a texture. Caller owns disposal. */\nexport function makeSkyEquirect(preset: LightingPreset): THREE.CanvasTexture {\n const canvas = document.createElement('canvas')\n canvas.width = WIDTH\n canvas.height = HEIGHT\n const ctx = canvas.getContext('2d')!\n drawSky(ctx, preset)\n const texture = new THREE.CanvasTexture(canvas)\n texture.mapping = THREE.EquirectangularReflectionMapping\n texture.colorSpace = THREE.SRGBColorSpace\n return texture\n}\n\n/**\n * The room, prefiltered into the mip chain a rough surface needs.\n *\n * PMREM is the expensive part and it runs ONCE per rig — a render target and\n * a handful of blur passes — after which sampling it costs a texture read.\n * Both the target and the source canvas are the caller's to dispose.\n */\nexport function buildEnvironment(\n renderer: THREE.WebGLRenderer,\n preset: LightingPreset,\n): { texture: THREE.Texture; dispose(): void } {\n const equirect = makeSkyEquirect(preset)\n const pmrem = new THREE.PMREMGenerator(renderer)\n const target = pmrem.fromEquirectangular(equirect)\n pmrem.dispose()\n equirect.dispose()\n return {\n texture: target.texture,\n dispose: () => target.dispose(),\n }\n}\n","/**\n * Colour strings that came from a person, made safe to hand to a canvas.\n *\n * Every colour in a stage — zenith, horizon, ground, the source, the room —\n * is an editable text field, and a text field emits on every keystroke. So\n * the library is handed `#f`, and `#ff`, and `not-a-colour`, in the normal\n * course of somebody typing `#ffaa22`. That is expected input, not a bug in\n * the caller.\n *\n * It matters because `addColorStop` is one of the few canvas calls that\n * **throws** rather than ignoring what it cannot parse:\n *\n * ```\n * Failed to execute 'addColorStop' on 'CanvasGradient':\n * The value provided ('not-a-colour') could not be parsed as a color.\n * ```\n *\n * and the sky is built during render, so that throw reached React as an\n * uncaught error and took the whole editor down. Three.js is the forgiving\n * one here — `new THREE.Color('nonsense')` warns and carries on — which is\n * why only the gradient path ever broke.\n *\n * Validation is the canvas's own opinion rather than a regex, because the\n * set of things CSS calls a colour is large (`rebeccapurple`, `hsl(...)`,\n * `color-mix(...)`, whatever ships next) and a regex would reject valid\n * input the gradient would have accepted.\n */\n\n/** A 1×1 scratch context, made once, used only to ask \"is this a colour?\". */\nlet probe: CanvasRenderingContext2D | null | undefined\n\nfunction probeContext(): CanvasRenderingContext2D | null {\n if (probe !== undefined) return probe\n probe = typeof document === 'undefined' ? null : document.createElement('canvas').getContext('2d')\n return probe\n}\n\n/**\n * `value` if a canvas can parse it as a colour, else `fallback`.\n *\n * The test is two assignments from two different starting colours. An\n * invalid value leaves `fillStyle` untouched, so it still reads back as\n * whichever prior it started from and the two readings disagree; a valid one\n * normalizes to the same string both times. One assignment would not do —\n * the answer would depend on what the context happened to hold.\n */\nexport function cssColorOr(value: string, fallback: string): string {\n const ctx = probeContext()\n // No DOM (SSR, tests): pass the value through rather than invent a colour.\n // Nothing is being painted, so nothing can throw.\n if (!ctx) return value\n const previous = ctx.fillStyle\n ctx.fillStyle = '#000000'\n ctx.fillStyle = value\n const fromBlack = ctx.fillStyle\n ctx.fillStyle = '#ffffff'\n ctx.fillStyle = value\n const fromWhite = ctx.fillStyle\n ctx.fillStyle = previous\n return fromBlack === fromWhite ? value : fallback\n}\n","import * as THREE from 'three'\nimport { useEffect, useState } from 'react'\nimport { useThree } from '@react-three/fiber'\nimport type { BackdropConfig } from '../config/schema'\n\n/**\n * What is behind the sheet.\n *\n * Painted onto a canvas at the viewport's own size and handed to\n * `scene.background`, rather than assigned as a texture directly. Three\n * stretches a background texture to the frame whatever shape it is, so a\n * landscape photograph behind a 9:16 export would come out squashed — and\n * the export sizes are exactly where a backdrop matters most. Painting it\n * means `cover` is really cover, and `fade` and `blur` come along for free\n * in the same pass.\n *\n * It sets the SCENE's background, so it belongs to whoever owns the canvas.\n * `<Paper>` and `<PaperField>` render it; `<PaperMesh>` deliberately does\n * not — it drops into someone else's scene, and a sheet that repainted the\n * background of the app it was embedded in would be a component doing\n * something nobody asked it to.\n */\nexport function PaperBackdrop({ backdrop }: { backdrop?: BackdropConfig }) {\n const scene = useThree((s) => s.scene)\n const size = useThree((s) => s.size)\n const [image, setImage] = useState<HTMLImageElement | null>(null)\n\n const src = backdrop?.image ?? ''\n\n useEffect(() => {\n if (!src) {\n setImage(null)\n return\n }\n let live = true\n const img = new Image()\n img.crossOrigin = 'anonymous'\n // A picture that will not load leaves the colour, which is the honest\n // rendering of \"no backdrop image\" — not a black frame and not a throw.\n img.onload = () => live && setImage(img)\n img.onerror = () => live && setImage(null)\n img.src = src\n return () => {\n live = false\n }\n }, [src])\n\n const key = JSON.stringify({ backdrop: backdrop ?? null, w: size.width, h: size.height, loaded: !!image })\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: key serializes everything the paint reads.\n useEffect(() => {\n if (!backdrop) return\n const previous = scene.background\n const texture = paintBackdrop(backdrop, size.width, size.height, image)\n scene.background = texture\n return () => {\n scene.background = previous\n texture.dispose()\n }\n }, [key])\n\n return null\n}\n\n/** Exported for the test — the painting is the part that can be wrong. */\nexport function paintBackdrop(\n backdrop: BackdropConfig,\n width: number,\n height: number,\n image: HTMLImageElement | null,\n): THREE.CanvasTexture {\n // Half resolution. It is out of focus behind the subject and it is drawn\n // once per resize, so the pixels buy nothing and the memory is real.\n const w = Math.max(2, Math.round(width / 2))\n const h = Math.max(2, Math.round(height / 2))\n const canvas = document.createElement('canvas')\n canvas.width = w\n canvas.height = h\n const ctx = canvas.getContext('2d')!\n\n ctx.fillStyle = backdrop.color\n ctx.fillRect(0, 0, w, h)\n\n if (image && image.width > 0 && image.height > 0) {\n const scale =\n backdrop.fit === 'cover'\n ? Math.max(w / image.width, h / image.height)\n : Math.min(w / image.width, h / image.height)\n const dw = image.width * scale\n const dh = image.height * scale\n ctx.save()\n // Scaled by the SHORT edge: a blur measured in pixels is a different\n // amount of blur on a phone frame than on a hero, and the backdrop\n // should sit the same distance behind the paper in both.\n if (backdrop.blur > 0) ctx.filter = `blur(${backdrop.blur * Math.min(w, h) * 0.06}px)`\n ctx.drawImage(image, (w - dw) / 2, (h - dh) / 2, dw, dh)\n ctx.restore()\n if (backdrop.fade > 0) {\n ctx.globalAlpha = backdrop.fade\n ctx.fillStyle = backdrop.color\n ctx.fillRect(0, 0, w, h)\n ctx.globalAlpha = 1\n }\n }\n\n const texture = new THREE.CanvasTexture(canvas)\n texture.colorSpace = THREE.SRGBColorSpace\n return texture\n}\n","import { useThree } from '@react-three/fiber'\nimport { useEffect } from 'react'\n\n/**\n * Hands the WebGL context back when the canvas unmounts.\n *\n * A browser gives a page about sixteen live WebGL contexts and then starts\n * killing the oldest to make room. Anything that mounts and unmounts paper as\n * it scrolls — the reference page is forty-odd cards doing exactly that — goes\n * over that ceiling not because too many sheets are on screen at once, but\n * because the ones that left never gave their context back.\n *\n * React Three Fiber disposes the renderer's own resources on unmount, and that\n * is not the same thing: the drawing context itself survives until the garbage\n * collector gets to the canvas, which is whenever it likes. `forceContextLoss`\n * is three.js's way of saying *now*, and it is the documented one.\n *\n * Measured on the reference page before this existed: one scroll to the bottom\n * produced 101 \"Too many active WebGL contexts\" warnings at a peak of thirteen\n * simultaneous canvases — comfortably under the cap, and still exhausting it.\n * Nothing was visibly blank, because a card that scrolls back into view\n * remounts and builds a fresh context; the cost was paid in that churn.\n *\n * Rendered inside a `<Canvas>`, where `useThree` can reach the renderer.\n */\nexport function ReleaseContextOnUnmount() {\n const gl = useThree((s) => s.gl)\n useEffect(\n () => () => {\n // Both, in this order. `forceContextLoss` releases the context and\n // `dispose` releases what the renderer still holds against it; calling\n // dispose alone is what leaves the context standing.\n gl.forceContextLoss()\n gl.dispose()\n },\n [gl],\n )\n return null\n}\n","import * as THREE from 'three'\nimport { gsap } from 'gsap'\nimport { Canvas, useFrame, useThree } from '@react-three/fiber'\nimport { forwardRef, useEffect, useMemo, useRef } from 'react'\nimport { sceneSchema, type PaperConfigInput, type SceneConfigInput } from './config/schema'\nimport { PaperLighting } from './scene/PaperLighting'\nimport { PaperBackdrop } from './scene/backdrop'\nimport { ReleaseContextOnUnmount } from './scene/release'\nimport { usePrefersReducedMotion } from './a11y'\nimport { DropZoneContext, DropZoneRegistry, type DropZoneConfig, type PlacedPaper } from './field/dropZones'\nimport {\n EMPTY_SET,\n effectiveFieldPapers,\n fieldIsInteractive,\n groupFieldPapers,\n type FieldPaperSlot,\n} from './field/slots'\nimport { FieldGroup, type SharedMotion } from './field/fieldGroup'\nimport { BackingSheet } from './field/backingSheet'\nimport { InteractiveField, type FieldA11yController } from './field/interactiveField'\nimport { FieldKeyboardMirror } from './field/keyboardMirror'\nimport { DEFAULT_SHEET, getLayout } from './field/layouts'\nimport { useStable } from './core/stable'\nimport type { SheetLayoutOptions } from './field/sheetGrid'\nimport { fitCamera, resolveLayoutOptions } from './field/framing'\n\n// The field system lives in field/*; this module is the public composition,\n// so it forwards only what the public API names. The rest of field/* is\n// reachable from its own module for tests and for the internals — it is not\n// re-exported here, because a re-export is how something becomes public by\n// accident.\nexport {\n DropZone,\n type DropZoneConfig,\n type DropZoneProps,\n type PlacedPaper,\n} from './field/dropZones'\nexport type { FieldPaperSlot } from './field/slots'\n\nexport interface PaperFieldMeshProps {\n /** Per-paper slots; length sets the instance count. Slot presets override the shared one. */\n papers?: FieldPaperSlot[]\n /** Sugar: image URLs → papers with image content. */\n images?: string[]\n /** Shared preset for slots that don't name their own. */\n preset?: string | PaperConfigInput\n layout?: string\n layoutOptions?: Record<string, unknown>\n motion?: { driver?: 'autoplay' | 'drag' | 'none'; speed?: number }\n entrance?: { type?: 'rise' | 'scatter' | 'none'; stagger?: number; duration?: number }\n /** Override prefers-reduced-motion (default: follow the system setting). */\n reducedMotion?: boolean\n /**\n * Per-paper interaction (hero CPU path per slot instead of one instanced\n * draw call). Defaults to true when any slot's preset carries `states` —\n * a stateful field is interactive by nature.\n */\n interactive?: boolean\n /** Fires when any slot's state machine changes state. */\n onSlotStateChange?(slot: number, state: string): void\n /**\n * Fires with a paper's index when it is clicked. Supplying it is what makes\n * the papers pickable — without a handler nothing raycasts, which matters\n * because hit-testing an instanced mesh is per-instance work on a pointer\n * move and a field is the mode with hundreds of instances in it.\n */\n onSelect?(paper: number): void\n /** Serialized drop zones (the editor's path); `<DropZone>` children also work. */\n zones?: DropZoneConfig[]\n /** Fires when a picked paper settles into any zone. */\n onPlace?(paper: PlacedPaper, zone: string): void\n /** Imperative controls for the hidden keyboard flow (wired by PaperField). */\n a11yControllerRef?: React.MutableRefObject<FieldA11yController | null>\n /**\n * Lowers what `segments: 'auto'` may ask for, per sheet. A DEVICE knob, in\n * the same sense `<PaperStage>`'s `quality` is one: it describes what the\n * machine can draw, never what the artwork is, so it does not serialize\n * into a preset or a share link. It can only ever lower the field's own\n * ceiling; nothing here can subdivide a sheet further than the library\n * would on its own.\n */\n segmentCeiling?: number\n}\n\nexport interface PaperFieldProps extends PaperFieldMeshProps {\n /**\n * Lighting — the same `{ lighting, light }` a single sheet carries.\n *\n * This component used to light itself with a bare ambient and a bare\n * directional, while the editor previewed field mode through\n * `<PaperLighting>` like everything else. So the gallery you composed and\n * the gallery the exported code produced were lit by two different rigs,\n * and the export was the one nobody had looked at.\n */\n scene?: SceneConfigInput\n children?: React.ReactNode\n className?: string\n style?: React.CSSProperties\n}\n\n/**\n * Field mode: sheets render as one instanced draw call PER DISTINCT PRESET\n * (usually one). Deformer stacks run as composed GLSL vertex chunks\n * (parity-tested against the CPU path); content lives in per-group atlases;\n * motion state (driver phase, entrance clock, layout morph) is shared so\n * mixed-preset fields move as one field.\n */\nexport const PaperFieldMesh = forwardRef<THREE.Group, PaperFieldMeshProps>(\n function PaperFieldMesh(props, ref) {\n const reduced = usePrefersReducedMotion(props.reducedMotion)\n\n const papers = useMemo<FieldPaperSlot[]>(\n () => effectiveFieldPapers(props.papers, props.images),\n [props.papers, props.images],\n )\n // Content-compared, not serialized: papers and preset are fresh objects\n // every render, and a paper can carry a whole bitmap inline. See\n // `useStable` for why stringifying these was the expensive half.\n const stablePapers = useStable(papers)\n const stablePreset = useStable(props.preset ?? null)\n const groups = useMemo(\n () => groupFieldPapers(stablePapers, stablePreset ?? undefined),\n [stablePapers, stablePreset],\n )\n const total = papers.length\n\n const layoutId = props.layout ?? 'ring'\n const layout = getLayout(layoutId)\n const firstSheet = groups[0]?.config.sheet\n const stableLayoutOptions = useStable(props.layoutOptions ?? {})\n // biome-ignore lint/correctness/useExhaustiveDependencies: `layout` is derived from layoutId, and the sheet enters by its two dimensions.\n const layoutOptions = useMemo(\n // Sheet grids size their cells from the papers themselves — gutter is\n // then literally the spacing between stamps (explicit cell dims win).\n () => resolveLayoutOptions(layoutId, layout, stableLayoutOptions, firstSheet),\n [layoutId, stableLayoutOptions, firstSheet?.width, firstSheet?.height],\n )\n\n // ── Shared motion state: one driver phase / entrance clock / morph for\n // every group, so a mixed-preset field moves as one field. ──\n const phaseRef = useRef(0)\n const dragVelRef = useRef(0)\n const mountTimeRef = useRef(-1)\n const morphRef = useRef<SharedMotion['morphRef']['current']>({ from: null, t: 1 })\n const prevLayout = useRef({ id: layoutId, options: layoutOptions })\n const gl = useThree((s) => s.gl)\n\n const driver = reduced ? 'none' : (props.motion?.driver ?? 'autoplay')\n const speed = props.motion?.speed ?? 0.5\n const entranceType = reduced ? 'none' : (props.entrance?.type ?? 'rise')\n\n useEffect(() => {\n const prev = prevLayout.current\n if (prev.id !== layoutId || JSON.stringify(prev.options) !== JSON.stringify(layoutOptions)) {\n morphRef.current = { from: prev, t: 0 }\n gsap.to(morphRef.current, { t: 1, duration: 0.9, ease: 'power2.inOut' })\n prevLayout.current = { id: layoutId, options: layoutOptions }\n }\n }, [layoutId, layoutOptions])\n\n useEffect(() => {\n if (driver !== 'drag') return\n const el = gl.domElement\n let lastX: number | null = null\n const down = (e: PointerEvent) => {\n lastX = e.clientX\n }\n const move = (e: PointerEvent) => {\n if (lastX === null) return\n const dx = e.clientX - lastX\n lastX = e.clientX\n phaseRef.current += dx * 0.0012\n dragVelRef.current = dx * 0.0012\n }\n const up = () => {\n lastX = null\n }\n el.addEventListener('pointerdown', down)\n window.addEventListener('pointermove', move)\n window.addEventListener('pointerup', up)\n return () => {\n el.removeEventListener('pointerdown', down)\n window.removeEventListener('pointermove', move)\n window.removeEventListener('pointerup', up)\n }\n }, [driver, gl])\n\n useFrame(({ clock }, delta) => {\n if (mountTimeRef.current < 0) mountTimeRef.current = clock.elapsedTime\n if (driver === 'autoplay') phaseRef.current += delta * speed * 0.02\n if (driver === 'drag') {\n phaseRef.current += dragVelRef.current * 0.5\n dragVelRef.current *= 0.94\n }\n })\n\n const shared: SharedMotion = {\n phaseRef,\n mountTimeRef,\n morphRef,\n layoutId,\n layoutOptions,\n sheet: firstSheet ?? DEFAULT_SHEET,\n entranceType,\n stagger: props.entrance?.stagger ?? 0.06,\n entranceDuration: props.entrance?.duration ?? 0.9,\n total,\n reduced,\n }\n\n // A stateful field is interactive by nature: per-paper hero path (CPU,\n // raycastable, per-slot state machines) instead of one instanced call.\n // (`groups` already resolved every preset, so reuse them for the check.)\n const interactive =\n props.interactive ?? (papers.some((s) => s.states) || groups.some((g) => Boolean(g.config.states)))\n\n const isSheet = layoutId === 'sheet'\n const sheetOptions = isSheet ? (layoutOptions as SheetLayoutOptions) : null\n\n if (interactive) {\n return (\n <group ref={ref}>\n <InteractiveField\n papers={papers}\n fallback={props.preset}\n layoutId={layoutId}\n layoutOptions={layoutOptions}\n sheetOptions={sheetOptions}\n sheet={firstSheet ?? DEFAULT_SHEET}\n reducedMotion={props.reducedMotion}\n zones={props.zones}\n onSlotStateChange={props.onSlotStateChange}\n onPlace={props.onPlace}\n a11yRef={props.a11yControllerRef}\n />\n </group>\n )\n }\n\n return (\n <group ref={ref}>\n {sheetOptions?.backing && <BackingSheet options={sheetOptions} count={total} removed={EMPTY_SET} />}\n {groups.map((group, gi) => (\n <FieldGroup\n // biome-ignore lint/suspicious/noArrayIndexKey: groups are derived from the slot list in order, so position is their only identity.\n key={`${gi}:${group.indices.length}`}\n group={group}\n shared={shared}\n onSelect={props.onSelect}\n segmentCeiling={props.segmentCeiling}\n />\n ))}\n </group>\n )\n },\n)\n\n/**\n * Frames whatever the layout actually lays out. A fixed camera can only suit\n * one layout — a `wall` of 12 runs past the top of a frame that a `pile`\n * leaves nearly empty — and layouts are pure, so the right distance is just\n * arithmetic over their poses.\n */\nfunction FitCamera(meshProps: PaperFieldMeshProps) {\n const camera = useThree((s) => s.camera)\n const width = useThree((s) => s.size.width)\n const height = useThree((s) => s.size.height)\n\n // The camera refits on prop CONTENT, not on identity — compared rather\n // than serialized, because this runs on every render of the field.\n const papersProp = useStable(meshProps.papers ?? null)\n const imagesProp = useStable(meshProps.images ?? null)\n const presetProp = useStable(meshProps.preset ?? null)\n const optionsProp = useStable(meshProps.layoutOptions ?? {})\n const field = useMemo(() => {\n const papers = effectiveFieldPapers(papersProp ?? undefined, imagesProp ?? undefined)\n const layoutId = meshProps.layout ?? 'ring'\n const layout = getLayout(layoutId)\n const sheet = groupFieldPapers(papers, presetProp ?? undefined)[0]?.config.sheet\n const options = resolveLayoutOptions(layoutId, layout, optionsProp, sheet)\n return { layout, n: papers.length, options, sheet: sheet ?? DEFAULT_SHEET }\n }, [papersProp, imagesProp, presetProp, meshProps.layout, optionsProp])\n\n useEffect(() => {\n if (!(camera instanceof THREE.PerspectiveCamera)) return\n const { position, target } = fitCamera(\n field.layout,\n field.n,\n field.options,\n field.sheet,\n camera.fov,\n width / Math.max(height, 1),\n )\n camera.position.set(...position)\n camera.lookAt(...target)\n camera.updateProjectionMatrix()\n }, [camera, width, height, field])\n\n return null\n}\n\n/** `<PaperField />` owns its own Canvas; PaperFieldMesh drops into existing scenes. */\nexport const PaperField = forwardRef<THREE.Group, PaperFieldProps>(function PaperField(\n { children, className, style, scene, ...meshProps },\n ref,\n) {\n const rig = sceneSchema.parse(scene ?? {})\n const registry = useMemo(() => new DropZoneRegistry(), [])\n const a11yRef = useRef<FieldA11yController | null>(null)\n\n // The SAME derivations PaperFieldMesh uses — a slot naming a stateful\n // preset by string, or an images-driven field, must get the keyboard\n // mirror exactly when the mesh goes interactive.\n const papers = useMemo(\n () => effectiveFieldPapers(meshProps.papers, meshProps.images),\n [meshProps.papers, meshProps.images],\n )\n const stablePapers = useStable(papers)\n const stablePreset = useStable(meshProps.preset ?? null)\n const interactive = useMemo(\n () => fieldIsInteractive(stablePapers, stablePreset ?? undefined, meshProps.interactive),\n [stablePapers, stablePreset, meshProps.interactive],\n )\n\n return (\n <div className={className} style={{ width: '100%', height: '100%', ...style }}>\n <DropZoneContext.Provider value={registry}>\n <Canvas shadows camera={{ position: [0, 0.6, 5.2], fov: 45 }} dpr={[1, 2]}>\n <FitCamera {...meshProps} />\n <PaperBackdrop backdrop={rig.backdrop} />\n {/* The floor and footprint a gallery of sheets needs — a lone sheet\n sits closer to the camera and on a tighter shadow. */}\n <PaperLighting preset={rig.lighting} light={rig.light} floor={-2.4} scale={14} />\n <PaperFieldMesh ref={ref} a11yControllerRef={a11yRef} {...meshProps} />\n {children}\n <ReleaseContextOnUnmount />\n </Canvas>\n {interactive && <FieldKeyboardMirror papers={papers} controller={a11yRef} />}\n </DropZoneContext.Provider>\n </div>\n )\n})\n","import * as THREE from 'three'\nimport { createContext, useContext, useEffect, useMemo, useRef, useSyncExternalStore } from 'react'\nimport type { PaperConfig } from '../config/schema'\n\n// ── Drop zones ─────────────────────────────────────────────────────────────\n\nexport interface DropZoneConfig {\n id: string\n /** Preset-name globs ('stamp-*'); omitted = accept all. */\n accept?: string[]\n /** World-space rect on the field plane. */\n bounds: { position: [number, number, number]; size: [number, number] }\n highlight?: 'none' | 'glow' | 'outline'\n}\n\nexport interface PlacedPaper {\n slot: number\n presetName: string\n config: PaperConfig\n}\n\nexport interface DropZoneProps extends DropZoneConfig {\n onPlace?(paper: PlacedPaper, zone: string): void\n}\n\nexport interface ZoneEntry extends DropZoneConfig {\n onPlace?: DropZoneProps['onPlace']\n}\n\n/** Shared zone state: `<DropZone>` children register; the carry loop hit-tests. */\nexport class DropZoneRegistry {\n private zones = new Map<string, ZoneEntry>()\n private hoveredId: string | null = null\n private listeners = new Set<() => void>()\n private version = 0\n\n register(zone: ZoneEntry): () => void {\n this.zones.set(zone.id, zone)\n this.notify()\n return () => {\n this.zones.delete(zone.id)\n this.notify()\n }\n }\n\n list(): ZoneEntry[] {\n return [...this.zones.values()]\n }\n\n get(id: string): ZoneEntry | undefined {\n return this.zones.get(id)\n }\n\n get hovered(): string | null {\n return this.hoveredId\n }\n\n setHovered(id: string | null): void {\n if (this.hoveredId === id) return\n this.hoveredId = id\n this.notify()\n }\n\n subscribe = (fn: () => void): (() => void) => {\n this.listeners.add(fn)\n return () => this.listeners.delete(fn)\n }\n\n getVersion = (): number => this.version\n\n private notify(): void {\n this.version++\n for (const fn of this.listeners) fn()\n }\n}\n\nexport const DropZoneContext = createContext<DropZoneRegistry | null>(null)\n\n// Compiled accept-globs, cached — zoneAccepts runs every frame in the carry\n// loop, and a fresh RegExp per glob per frame is pure GC churn.\nconst globCache = new Map<string, RegExp>()\nconst globRegExp = (glob: string): RegExp => {\n let re = globCache.get(glob)\n if (!re) {\n re = new RegExp(`^${glob.replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&').replace(/\\*/g, '.*')}$`, 'i')\n globCache.set(glob, re)\n }\n return re\n}\n\n/** True when `name` matches the zone's accept globs (all zones accept by default). */\nexport function zoneAccepts(zone: Pick<DropZoneConfig, 'accept'>, name: string): boolean {\n if (!zone.accept || zone.accept.length === 0) return true\n return zone.accept.some((glob) => globRegExp(glob).test(name))\n}\n\nexport const zoneContains = (zone: ZoneEntry, x: number, y: number): boolean =>\n Math.abs(x - zone.bounds.position[0]) <= zone.bounds.size[0] / 2 &&\n Math.abs(y - zone.bounds.position[1]) <= zone.bounds.size[1] / 2\n\n/**\n * A drop target inside a `<PaperField>`. While a paper is picked, its center\n * is tested against the bounds each frame; hovering applies the highlight\n * and release inside fires `placed` + `onPlace`.\n */\nexport function DropZone(props: DropZoneProps) {\n const registry = useContext(DropZoneContext)\n const { id, accept, bounds, highlight = 'glow', onPlace } = props\n\n // `onPlace` is a notification, not a dependency. The natural way to pass\n // one is an inline arrow, which is a new function on every render of the\n // page above — naming it here re-registered the zone on every one of those\n // renders, bumping the registry version and re-rendering every\n // `DropZoneVisual` in the field. Held in a ref, the registration depends on\n // what the zone IS, and the callback is read at the moment it fires.\n const place = useRef(onPlace)\n useEffect(() => {\n place.current = onPlace\n }, [onPlace])\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: Serialized deps — re-registering on object identity would thrash the registry.\n useEffect(() => {\n if (!registry) return\n return registry.register({\n id,\n accept,\n bounds,\n highlight,\n onPlace: (paper, zone) => place.current?.(paper, zone),\n })\n }, [registry, id, JSON.stringify(accept ?? null), JSON.stringify(bounds), highlight])\n if (!registry) return null\n return <DropZoneVisual registry={registry} config={{ id, accept, bounds, highlight }} />\n}\n\n/** The translucent target — brightens when the carried paper is over it. */\nexport function DropZoneVisual({ registry, config }: { registry: DropZoneRegistry; config: DropZoneConfig }) {\n useSyncExternalStore(registry.subscribe, registry.getVersion, registry.getVersion)\n const hovered = registry.hovered === config.id\n const style = config.highlight ?? 'glow'\n const [w, h] = config.bounds.size\n // Memoized: an inline `new THREE.PlaneGeometry` in args would rebuild (and\n // leak) the edges every render — and this re-renders on every hover change.\n const edges = useMemo(() => {\n const plane = new THREE.PlaneGeometry(w, h)\n const geo = new THREE.EdgesGeometry(plane)\n plane.dispose()\n return geo\n }, [w, h])\n useEffect(() => () => edges.dispose(), [edges])\n return (\n <group position={config.bounds.position}>\n {style !== 'outline' && (\n <mesh>\n <planeGeometry args={[w, h]} />\n <meshBasicMaterial\n color={hovered && style === 'glow' ? '#8ea8ff' : '#5c6f9e'}\n transparent\n opacity={hovered && style === 'glow' ? 0.32 : 0.14}\n depthWrite={false}\n />\n </mesh>\n )}\n <lineSegments geometry={edges}>\n <lineBasicMaterial color={hovered ? '#aebfff' : '#6b7da8'} />\n </lineSegments>\n </group>\n )\n}\n","import { z } from 'zod'\nimport type { PaperEdge } from '../config/schema'\nimport type { CurlOptions } from '../deformers/curl'\n\n/**\n * Pure grid math for the `sheet` layout — a block of stamps on a shared\n * backing. Shared by the layout's pose function, the backing silhouette\n * renderer, the outward-corner smart default, and the torn-perforation\n * auto-wiring, so they can never disagree about where a slot sits.\n */\n\nexport const sheetLayoutSchema = z.object({\n rows: z.number().int().min(1).max(12).default(2),\n columns: z.number().int().min(1).max(12).default(5),\n /** World-units gap between slots. Stamps are printed in register — no jitter. */\n gutter: z.number().min(0).max(1).default(0.08),\n /** Slot footprint in world units (the paper preset should match). */\n cellWidth: z.number().min(0.1).max(4).default(0.72),\n cellHeight: z.number().min(0.1).max(4).default(0.86),\n /** Render the shared backing sheet behind the grid. */\n backing: z.boolean().default(true),\n backingMargin: z.number().min(0).max(1).default(0.12),\n})\n\nexport type SheetLayoutOptions = z.infer<typeof sheetLayoutSchema>\n\n/** Backing thickness + ε — papers float just above the backing sheet. */\nexport const SHEET_LIFT = 0.012\n\n/**\n * Cell footprint = the paper's own sheet dims unless the user set an\n * explicit cellWidth/cellHeight — so `gutter` is literally the spacing\n * between stamps, whatever preset populates the grid.\n */\nexport function withSheetCellFromPaper(\n parsed: SheetLayoutOptions,\n rawOptions: Record<string, unknown> | undefined,\n paperDims: { width: number; height: number } | undefined,\n): SheetLayoutOptions {\n if (!paperDims) return parsed\n const hasW = rawOptions !== undefined && rawOptions.cellWidth !== undefined\n const hasH = rawOptions !== undefined && rawOptions.cellHeight !== undefined\n if (hasW && hasH) return parsed\n return {\n ...parsed,\n cellWidth: hasW ? parsed.cellWidth : paperDims.width,\n cellHeight: hasH ? parsed.cellHeight : paperDims.height,\n }\n}\n\nexport function sheetSlotXY(i: number, o: SheetLayoutOptions): { x: number; y: number } {\n const col = i % o.columns\n const row = Math.floor(i / o.columns)\n return {\n x: (col - (o.columns - 1) / 2) * (o.cellWidth + o.gutter),\n y: ((o.rows - 1) / 2 - row) * (o.cellHeight + o.gutter),\n }\n}\n\n/** Grid bounds + margin — the backing sheet's size. */\nexport function sheetBackingSize(o: SheetLayoutOptions): { width: number; height: number } {\n return {\n width: o.columns * o.cellWidth + (o.columns - 1) * o.gutter + o.backingMargin * 2,\n height: o.rows * o.cellHeight + (o.rows - 1) * o.gutter + o.backingMargin * 2,\n }\n}\n\ntype Corner = CurlOptions['corner']\n\n/**\n * The corner facing away from the sheet's center — what a thumb would find.\n * A tie (an odd grid's exact-center row/column, where the\n * cell straddles the midline) breaks outward-and-down: strict `<` on both\n * axes sends the center right and down, so a dead-center cell peels\n * bottom-right — the standalone peel default.\n */\nexport function outwardCorner(i: number, o: Pick<SheetLayoutOptions, 'rows' | 'columns'>): Corner {\n const col = i % o.columns\n const row = Math.floor(i / o.columns)\n // Row 0 renders at the top of the grid.\n const horizontal = col + 0.5 < o.columns / 2 ? 'left' : 'right'\n const vertical = row + 0.5 < o.rows / 2 ? 'top' : 'bottom'\n return `${vertical}-${horizontal}` as Corner\n}\n\n/**\n * Perforation auto-wiring on detach: edges that faced a neighboring slot tear\n * through; edges on the sheet's outer boundary keep their clean punches.\n */\nexport function tornEdgesOnDetach(\n i: number,\n o: Pick<SheetLayoutOptions, 'rows' | 'columns'>,\n): Partial<Record<PaperEdge, 'torn' | 'intact'>> {\n const col = i % o.columns\n const row = Math.floor(i / o.columns)\n return {\n top: row > 0 ? 'torn' : 'intact',\n bottom: row < o.rows - 1 ? 'torn' : 'intact',\n left: col > 0 ? 'torn' : 'intact',\n right: col < o.columns - 1 ? 'torn' : 'intact',\n }\n}\n","import {\n contentSchema,\n paperConfigSchema,\n type ContentConfig,\n type ContentConfigInput,\n type PaperConfig,\n type PaperConfigInput,\n type PaperStatesInput,\n} from '../config/schema'\nimport { mergeConfig } from '../config/merge'\nimport { resolveConfig } from '../PaperMesh'\nimport { outwardCorner, sheetLayoutSchema } from './sheetGrid'\n\n/** A field slot references a preset — the spec's component/instance model. */\nexport interface FieldPaperSlot {\n preset?: string | PaperConfigInput\n /**\n * INPUT type, not the parsed one. A slot's content is written by a caller,\n * and the parsed type demands every default be supplied — which turned a\n * two-line content literal into a type error and is exactly the failure\n * `config/props.test.ts` was added to catch on the props. Parsed here\n * (`contentSchema.parse`) so consumers downstream still get a full config.\n */\n content?: ContentConfigInput\n /** Per-instance state overrides, merged over the preset's states. */\n states?: PaperStatesInput\n}\n\nexport interface FieldGroupData {\n config: PaperConfig\n /** Global slot indices this group renders (layout poses use global i / total n). */\n indices: number[]\n contents: ContentConfig[]\n}\n\nexport const EMPTY_SET: ReadonlySet<number> = new Set()\n\n/**\n * The effective slot list: explicit `papers`, the `images` sugar, or the\n * twelve-blank default. ONE derivation shared by PaperFieldMesh and the\n * PaperField wrapper, so the mesh and the keyboard mirror always agree on\n * which papers exist.\n */\nexport function effectiveFieldPapers(papers?: FieldPaperSlot[], images?: string[]): FieldPaperSlot[] {\n if (papers) return papers\n if (images) {\n return images.map((src) => ({\n content: { type: 'image', src, fit: 'cover' } as ContentConfig,\n }))\n }\n return Array.from({ length: 12 }, () => ({}))\n}\n\n/** Group slots by resolved preset — one instanced draw call per distinct preset. */\nexport function groupFieldPapers(\n papers: FieldPaperSlot[],\n fallback?: string | PaperConfigInput,\n): FieldGroupData[] {\n const groups = new Map<string, FieldGroupData>()\n papers.forEach((slot, i) => {\n const config = resolveConfig({ preset: slot.preset ?? fallback })\n const key = JSON.stringify(config)\n let group = groups.get(key)\n if (!group) {\n group = { config, indices: [], contents: [] }\n groups.set(key, group)\n }\n group.indices.push(i)\n group.contents.push(slot.content ? contentSchema.parse(slot.content) : config.content)\n })\n return [...groups.values()]\n}\n\n/**\n * Whether a field runs the per-paper interactive path. A stateful field is\n * interactive by nature — and \"stateful\" must RESOLVE presets: a slot naming\n * a stateful preset by string counts exactly like an inline `states` object.\n * The single decision shared by PaperFieldMesh (render path) and PaperField\n * (keyboard mirror), so pointer interaction and keyboard access never diverge.\n */\nexport function fieldIsInteractive(\n papers: FieldPaperSlot[],\n fallback?: string | PaperConfigInput,\n explicit?: boolean,\n): boolean {\n if (explicit !== undefined) return explicit\n return (\n papers.some((s) => s.states) || groupFieldPapers(papers, fallback).some((g) => Boolean(g.config.states))\n )\n}\n\n/**\n * Resolve one slot to its final render config: preset (or fallback) + slot\n * content + slot-level state overrides merged over the preset's states + the\n * `sheet` smart default (an 'auto' peel corner resolves to the corner facing\n * away from the sheet's center — what a thumb would find).\n */\nexport function resolveFieldSlotConfig(\n slot: FieldPaperSlot,\n fallback: string | PaperConfigInput | undefined,\n index: number,\n layoutId: string,\n layoutOptions: Record<string, unknown>,\n): PaperConfig {\n let config = resolveConfig({ preset: slot.preset ?? fallback })\n const patch: Record<string, unknown> = {}\n if (slot.content) patch.content = slot.content\n if (slot.states) patch.states = slot.states\n if (layoutId === 'sheet' && config.behavior?.type === 'peel' && config.behavior.corner === 'auto') {\n const o = sheetLayoutSchema.parse(layoutOptions)\n patch.behavior = { corner: outwardCorner(index, o) }\n }\n if (Object.keys(patch).length > 0) {\n config = paperConfigSchema.parse(mergeConfig(config as Record<string, unknown>, patch))\n }\n return config\n}\n","import * as THREE from 'three'\nimport { gsap } from 'gsap'\nimport { useFrame } from '@react-three/fiber'\nimport { useEffect, useMemo, useRef } from 'react'\nimport CustomShaderMaterial from 'three-custom-shader-material'\nimport { getStock } from '../core/stock'\nimport { createSheetGeometry } from '../core/sheet'\nimport { getBehavior } from '../behaviors/registry'\nimport { stackAutoSegments, stackMinSegments } from '../deformers/compose'\nimport type { SegmentPair } from '../core/tessellation'\nimport type { DeformerInstance, SheetDims } from '../deformers/types'\nimport type { AeroPose } from '../physics/aero'\nimport { useContentAtlas } from '../content/atlas'\nimport {\n buildDisplacementGLSL,\n buildFieldFragmentShader,\n buildFieldVertexShader,\n stackUniformValues,\n} from './compose'\nimport { getLayout, type PaperPose } from './layouts'\nimport { translucencyUniforms, translucencyValues } from '../surface/translucency'\nimport { useLightRig } from '../scene/rig'\nimport { fieldShapeStack } from './stack'\nimport type { FieldGroupData } from './slots'\n\nconst scratchObj = new THREE.Object3D()\nconst scratchAero: AeroPose = { position: [0, 0, 0], rotation: [0, 0, 0] }\n/**\n * Caps the FLOOR a deformer stack can demand of a field instance. Field mode\n * trades a deformer's stated minimum for instance count, which hero mode\n * never does.\n */\nexport const FIELD_SEGMENT_CAP = 48\n\n/**\n * Caps what `'auto'` may ASK for in a field, as distinct from the floor above.\n *\n * It used to sit at the old flat 72 on the grounds that a field draws this\n * buffer once per instance — a real argument, made when nothing else could\n * hold the count down. Two things changed. The demand now lands on the axis\n * that bends rather than being spread over both, so a banner asking 128\n * across asks 8 down and the buffer grows on one side only. And\n * `segmentCeiling` gives the caller a working lever, which is what the\n * quality tiers now use: `low` and `medium` cap themselves well below this\n * line, so raising it only raises what a machine that measured fast enough\n * is allowed to ask for.\n *\n * 128, matching what a hero sheet was allowed before the hero ceiling moved\n * to 192. A field still asks for less than one sheet does, which is the\n * asymmetry worth keeping.\n */\nexport const FIELD_AUTO_CEILING = 128\n\n/** Mirrors the hero path's sweep sampling — see PaperMesh. */\nconst PROGRESS_SAMPLES = [0, 0.25, 0.5, 0.75, 1] as const\n\n/** Motion state shared across groups so a mixed-preset field moves as one field. */\nexport interface SharedMotion {\n phaseRef: React.MutableRefObject<number>\n mountTimeRef: React.MutableRefObject<number>\n morphRef: React.MutableRefObject<{ from: { id: string; options: unknown } | null; t: number }>\n layoutId: string\n layoutOptions: Record<string, unknown>\n /** The field's paper size — one sheet for every group, so layouts agree. */\n sheet: SheetDims\n entranceType: 'rise' | 'scatter' | 'none'\n stagger: number\n entranceDuration: number\n total: number\n reduced: boolean\n}\n\n/** Opting a mesh out of raycasting entirely — cheaper than testing and discarding. */\nconst NO_RAYCAST = () => {}\n\n/** One instanced mesh: one preset's sheet/stock/behavior across its slots. */\nexport function FieldGroup({\n group,\n shared,\n onSelect,\n segmentCeiling,\n}: {\n group: FieldGroupData\n shared: SharedMotion\n /** Called with the paper's GLOBAL index — a group only holds the slots that share its preset. */\n onSelect?: (paper: number) => void\n /** Lowers what `'auto'` may ask for on this group's sheet. Never raises it. */\n segmentCeiling?: number\n}) {\n const autoCeiling = Math.min(segmentCeiling ?? FIELD_AUTO_CEILING, FIELD_AUTO_CEILING)\n const { config, indices, contents } = group\n const count = indices.length\n const stock = getStock(config.stock)\n // The scene's rig if it publishes one — in a stage the banners are lit by\n // the hall, not by the preset each one happens to carry.\n const rig = useLightRig(config.scene.lighting)\n // A raw deformer stack is the Advanced fork of a behavior and wins over one\n // — the same precedence the hero path's buildStack applies. Field mode used\n // to read `behavior` only, so a preset shaped by `deformers` rendered flat.\n const behavior = config.behavior && !config.deformers ? getBehavior(config.behavior.type) : null\n\n const progressRef = useRef(\n behavior ? ((config.behavior as Record<string, unknown>)[behavior.progressParam] as number) : 0,\n )\n const buildStackAt = (progress: number): DeformerInstance[] => fieldShapeStack(config, progress)\n // biome-ignore lint/correctness/useExhaustiveDependencies: Serialized deps — the stack rebuilds on shape, not on identity.\n const initialStack = useMemo(\n () => buildStackAt(progressRef.current),\n [\n JSON.stringify(config.behavior ?? null),\n JSON.stringify(config.deformers ?? null),\n JSON.stringify(config.sheet),\n ],\n )\n const structureKey = initialStack.map((i) => i.type).join('|')\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: Keyed on sheet, stack structure, count and the ceiling — the only things that change the buffer.\n const geometry = useMemo(() => {\n const floor = stackMinSegments(initialStack, config.sheet)\n // Same sweep-sampling as the hero path: one buffer serves every instance\n // for the whole play, so it has to hold the densest moment of it, not the\n // current one.\n const want: SegmentPair = [0, 0]\n for (const p of PROGRESS_SAMPLES) {\n const [x, y] = stackAutoSegments(buildStackAt(p), config.sheet)\n if (x > want[0]) want[0] = x\n if (y > want[1]) want[1] = y\n }\n const geo = createSheetGeometry(\n {\n ...config.sheet,\n segments:\n config.sheet.segments === 'auto' ? 'auto' : Math.min(config.sheet.segments, FIELD_SEGMENT_CAP),\n },\n [Math.min(floor[0], FIELD_SEGMENT_CAP), Math.min(floor[1], FIELD_SEGMENT_CAP)],\n // Bounded by the auto ceiling and NOT by FIELD_SEGMENT_CAP, which is a\n // floor cap and stays one. Capping the target as well looked tidy and\n // was a visual regression: it is the only thing that could have held\n // `crumple` — whose creases have no target, only a floor of 72 — down\n // to 48 in a field, which is coarser than the deformer says it needs to\n // look like a crumple at all.\n [Math.min(want[0], autoCeiling), Math.min(want[1], autoCeiling)],\n )\n const atlasIdx = new Float32Array(count)\n const phase = new Float32Array(count)\n const bias = new Float32Array(count).fill(1)\n for (let i = 0; i < count; i++) {\n atlasIdx[i] = i\n phase[i] = ((indices[i]! * 0.618034) % 1) * 4 // golden-ratio spread by global slot\n }\n geo.setAttribute('aAtlas', new THREE.InstancedBufferAttribute(atlasIdx, 1))\n geo.setAttribute('aPhase', new THREE.InstancedBufferAttribute(phase, 1))\n // Per-sheet deformation strength, written from the layout's pose each\n // frame — how a single instanced draw call bends every sheet differently.\n geo.setAttribute('aBias', new THREE.InstancedBufferAttribute(bias, 1))\n return geo\n }, [JSON.stringify(config.sheet), structureKey, count, autoCeiling])\n\n // Imperatively created — R3F won't auto-dispose a geometry passed via args.\n useEffect(() => () => geometry.dispose(), [geometry])\n\n const atlas = useContentAtlas(contents, config.sheet, stock)\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: Keyed on the stack structure — uniforms update in place, the program does not.\n const shader = useMemo(() => {\n const composed = buildDisplacementGLSL(initialStack, config.sheet)\n const uniforms: Record<string, { value: unknown }> = {}\n for (const [name, value] of Object.entries(composed.uniforms)) {\n uniforms[name] = {\n value: Array.isArray(value) && value.length === 2 ? new THREE.Vector2(...value) : value,\n }\n }\n uniforms.uPlTime = { value: 0 }\n uniforms.uAtlas = { value: null }\n uniforms.uAtlasGrid = { value: new THREE.Vector2(1, 1) }\n uniforms.uBackDarken = {\n value: 1 - Math.min(0.45, 0.12 + config.sheet.thickness * 0.9) * stock.opacity,\n }\n uniforms.uStockColor = { value: new THREE.Color(stock.color) }\n uniforms.uShowThrough = { value: config.surface.showThrough ?? stock.showThrough }\n // Transmission reads the scene's own key light, so a backlit sheet can\n // never disagree with the lamp casting its shadow.\n Object.assign(uniforms, translucencyUniforms(config.surface.translucency ?? stock.translucency, rig))\n return {\n vertexShader: buildFieldVertexShader(composed),\n fragmentShader: buildFieldFragmentShader(),\n uniforms,\n }\n }, [\n structureKey,\n JSON.stringify(config.sheet),\n stock.id,\n config.surface.showThrough,\n config.surface.translucency,\n ])\n\n // Moving a light writes four uniforms; it must never recompile a program,\n // which is what putting the rig in the memo above would have done on every\n // frame of a slider drag.\n useEffect(() => {\n const values = translucencyValues(config.surface.translucency ?? stock.translucency, rig)\n shader.uniforms.uTranslucency!.value = values.translucency\n ;(shader.uniforms.uBackLightDir!.value as THREE.Vector3).copy(values.direction)\n ;(shader.uniforms.uBackLightColor!.value as THREE.Color).copy(values.color)\n shader.uniforms.uAmbientTransmission!.value = values.ambient\n }, [shader, rig, config.surface.translucency, stock.translucency])\n\n useEffect(() => {\n if (!atlas) return\n shader.uniforms.uAtlas!.value = atlas.texture\n ;(shader.uniforms.uAtlasGrid!.value as THREE.Vector2).set(atlas.cols, atlas.rows)\n }, [atlas, shader])\n\n // Behavior progress loops on GSAP — the field is always alive.\n // biome-ignore lint/correctness/useExhaustiveDependencies: Keyed on the behavior itself; progress lives on a ref so the tween is not restarted each render.\n useEffect(() => {\n if (!behavior || shared.reduced) return\n const state = { p: progressRef.current }\n const tween = gsap.to(state, {\n p: 1,\n duration: behavior.duration * Math.max(0.05, 1 - state.p),\n ease: 'power2.inOut',\n yoyo: behavior.loopMode === 'yoyo',\n repeat: -1,\n onUpdate: () => {\n progressRef.current = state.p\n },\n })\n return () => {\n tween.kill()\n }\n }, [structureKey, shared.reduced])\n\n const meshRef = useRef<THREE.InstancedMesh>(null)\n\n useFrame(({ clock }) => {\n const mesh = meshRef.current\n if (!mesh) return\n const elapsed = clock.elapsedTime - Math.max(shared.mountTimeRef.current, 0)\n\n shader.uniforms.uPlTime!.value = shared.reduced ? 0 : clock.elapsedTime\n if (behavior) {\n const values = stackUniformValues(buildStackAt(progressRef.current), config.sheet)\n for (const [name, value] of Object.entries(values)) {\n const uniform = shader.uniforms[name]\n if (!uniform) continue\n if (uniform.value instanceof THREE.Vector2 && Array.isArray(value)) {\n uniform.value.set(value[0]!, value[1]!)\n } else {\n uniform.value = value\n }\n }\n }\n\n const layout = getLayout(shared.layoutId)\n const morph = shared.morphRef.current\n const behaviorTransform = behavior?.transform && config.behavior ? behavior : null\n const biasAttr = geometry.getAttribute('aBias') as THREE.InstancedBufferAttribute\n const biases = biasAttr.array as Float32Array\n let biasChanged = false\n for (let j = 0; j < count; j++) {\n const i = indices[j]!\n let pose = layout.pose(i, shared.total, shared.layoutOptions, shared.phaseRef.current, shared.sheet)\n if (morph.from && morph.t < 1) {\n const prev = getLayout(morph.from.id).pose(\n i,\n shared.total,\n morph.from.options,\n shared.phaseRef.current,\n shared.sheet,\n )\n pose = lerpPose(prev, pose, easeInOut(morph.t))\n }\n if (shared.entranceType !== 'none') {\n const tIn = Math.min(1, Math.max(0, (elapsed - i * shared.stagger) / shared.entranceDuration))\n if (tIn < 1) {\n pose = lerpPose(entrancePose(shared.entranceType, i, pose), pose, easeOut(tIn))\n }\n }\n const bias = Math.min(1, Math.max(0, pose.bias ?? 1))\n if (biases[j] !== bias) {\n biases[j] = bias\n biasChanged = true\n }\n scratchObj.position.set(...pose.position)\n scratchObj.rotation.set(...pose.rotation)\n scratchObj.scale.setScalar(pose.scale)\n // Behavior whole-sheet transforms (flight) run per instance, offset in\n // time by the same golden-ratio phase the shader flutter uses — pure\n // functions of t, so instancing stays exact.\n if (behaviorTransform) {\n const pose2 = scratchAero\n pose2.position[0] = pose2.position[1] = pose2.position[2] = 0\n pose2.rotation[0] = pose2.rotation[1] = pose2.rotation[2] = 0\n const t = shared.reduced ? 0 : clock.elapsedTime + ((i * 0.618034) % 1) * 4\n behaviorTransform.transform!(\n { ...config.behavior, [behaviorTransform.progressParam]: progressRef.current },\n t,\n pose2,\n shared.sheet,\n )\n scratchObj.position.x += pose2.position[0]\n scratchObj.position.y += pose2.position[1]\n scratchObj.position.z += pose2.position[2]\n scratchObj.rotation.x += pose2.rotation[0]\n scratchObj.rotation.y += pose2.rotation[1]\n scratchObj.rotation.z += pose2.rotation[2]\n }\n scratchObj.updateMatrix()\n mesh.setMatrixAt(j, scratchObj.matrix)\n }\n mesh.instanceMatrix.needsUpdate = true\n if (biasChanged) biasAttr.needsUpdate = true\n })\n\n return (\n // biome-ignore lint/a11y/noStaticElementInteractions: An R3F <instancedMesh> is a three.js object, not a DOM node — it has no role to give and no keyboard to receive. The keyboard route into the same action is on the canvas, which `useWalk` makes focusable and drives with the arrow keys.\n <instancedMesh\n ref={meshRef}\n args={[geometry, undefined, count]}\n frustumCulled={false}\n castShadow\n receiveShadow\n // Only raycastable when somebody is listening: hit-testing an instanced\n // mesh is per-instance work on every pointer move, and this is the mode\n // that puts hundreds of instances on screen at once. Spread rather than\n // `raycast={undefined}`, which does not mean \"leave the default\" — it\n // assigns undefined over the method three is about to call.\n {...(onSelect ? {} : { raycast: NO_RAYCAST })}\n onClick={\n onSelect &&\n ((event) => {\n if (event.instanceId === undefined) return\n // `instanceId` counts within THIS group; the layout — and anything\n // that wants to know which paper was clicked — counts across all of\n // them, so the group's own index list is the translation.\n const paper = indices[event.instanceId]\n if (paper === undefined) return\n event.stopPropagation()\n onSelect(paper)\n })\n }\n >\n <CustomShaderMaterial\n key={`${structureKey}:${count}`}\n baseMaterial={THREE.MeshStandardMaterial}\n vertexShader={shader.vertexShader}\n fragmentShader={shader.fragmentShader}\n uniforms={shader.uniforms}\n roughness={stock.roughness}\n metalness={0}\n side={THREE.DoubleSide}\n />\n </instancedMesh>\n )\n}\n\nfunction entrancePose(type: 'rise' | 'scatter', i: number, target: PaperPose): PaperPose {\n if (type === 'rise') {\n return {\n position: [target.position[0], target.position[1] - 3.2, target.position[2] - 0.5],\n rotation: [target.rotation[0] - 0.7, target.rotation[1], target.rotation[2] + 0.25],\n scale: target.scale * 0.85,\n bias: target.bias,\n }\n }\n const a = i * 2.399\n return {\n position: [Math.cos(a) * 7, Math.sin(a * 1.3) * 4, Math.sin(a) * 6],\n rotation: [Math.sin(a) * 2, a, Math.cos(a) * 2],\n scale: target.scale * 0.6,\n bias: target.bias,\n }\n}\n\nfunction lerpPose(a: PaperPose, b: PaperPose, t: number): PaperPose {\n const lerp = (x: number, y: number) => x + (y - x) * t\n return {\n position: [\n lerp(a.position[0], b.position[0]),\n lerp(a.position[1], b.position[1]),\n lerp(a.position[2], b.position[2]),\n ],\n rotation: [\n lerp(a.rotation[0], b.rotation[0]),\n lerp(a.rotation[1], b.rotation[1]),\n lerp(a.rotation[2], b.rotation[2]),\n ],\n scale: lerp(a.scale, b.scale),\n bias: lerp(a.bias ?? 1, b.bias ?? 1),\n }\n}\n\nconst easeOut = (t: number) => 1 - (1 - t) ** 3\nconst easeInOut = (t: number) => (t < 0.5 ? 2 * t * t : 1 - (-2 * t + 2) ** 2 / 2)\n","import * as THREE from 'three'\nimport { useEffect, useState } from 'react'\nimport type { ContentConfig, SheetConfig } from '../config/schema'\nimport type { Stock } from '../core/stock'\nimport { useStable } from '../core/stable'\nimport { renderContentToCanvas } from './texture'\n\n/**\n * Field mode packs every paper's content into one grid atlas — one texture,\n * one draw call. Tiles keep the sheet's aspect; images redraw their tile as\n * they decode (LQIP-ish: stock tint first, pixels when ready).\n */\n\nconst MAX_ATLAS = 4096\n\n/**\n * Grid shape for `count` tiles of a given aspect (height / width).\n *\n * Square tiles want a square grid, but a stage banner is 5.7 times taller\n * than it is wide, and packing those into a square GRID makes an atlas five\n * times taller than it is wide — which then has to be squashed to fit the\n * texture budget, and the content with it. Choosing cols/rows ≈ aspect keeps\n * the atlas itself roughly square whatever shape the paper is.\n */\nexport function atlasGrid(count: number, aspect = 1): { cols: number; rows: number } {\n const cols = Math.max(1, Math.min(count, Math.ceil(Math.sqrt(count * Math.max(aspect, 0.01)))))\n return { cols, rows: Math.max(1, Math.ceil(count / cols)) }\n}\n\nexport interface ContentAtlas {\n texture: THREE.CanvasTexture\n cols: number\n rows: number\n}\n\nexport function useContentAtlas(\n contents: ContentConfig[],\n sheet: SheetConfig,\n stock: Stock,\n): ContentAtlas | null {\n const [atlas, setAtlas] = useState<ContentAtlas | null>(null)\n // Compared rather than serialized. An image tile carries its bitmap inline\n // as a data URL, and this runs on every render of the field — building a\n // cache key out of the very thing that makes the cache worth having was\n // costing more per render than the atlas it was protecting.\n const stableContents = useStable(contents)\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: the atlas is drawn from the contents, sheet and stock named below.\n useEffect(() => {\n let disposed = false\n const aspect = sheet.height / sheet.width\n const { cols, rows } = atlasGrid(contents.length, aspect)\n // Fit the tile to the budget WITHOUT breaking its aspect: a tile squashed\n // to fit renders its content squashed too. Resolution is the thing that\n // gives, never shape.\n let tileW = Math.min(1024, Math.floor(MAX_ATLAS / cols))\n let tileH = Math.round(tileW * aspect)\n if (tileH * rows > MAX_ATLAS) {\n tileH = Math.floor(MAX_ATLAS / rows)\n tileW = Math.max(1, Math.round(tileH / aspect))\n }\n\n const canvas = document.createElement('canvas')\n canvas.width = tileW * cols\n canvas.height = tileH * rows\n const ctx = canvas.getContext('2d')!\n ctx.fillStyle = stock.color\n ctx.fillRect(0, 0, canvas.width, canvas.height)\n\n const texture = new THREE.CanvasTexture(canvas)\n texture.colorSpace = THREE.SRGBColorSpace\n texture.anisotropy = 4\n setAtlas({ texture, cols, rows })\n\n const drawTile = (index: number, tile: HTMLCanvasElement) => {\n if (disposed) return\n const x = (index % cols) * tileW\n const y = Math.floor(index / cols) * tileH\n ctx.drawImage(tile, x, y, tileW, tileH)\n texture.needsUpdate = true\n }\n\n contents.forEach((content, index) => {\n if (content.type === 'image') {\n const img = new Image()\n img.crossOrigin = 'anonymous'\n img.onload = () => drawTile(index, renderContentToCanvas(content, sheet, stock, img))\n img.src = content.src\n } else if (content.type === 'text' || content.type === 'receipt') {\n document.fonts.ready.then(() => drawTile(index, renderContentToCanvas(content, sheet, stock)))\n } else {\n drawTile(index, renderContentToCanvas(content, sheet, stock))\n }\n })\n\n return () => {\n disposed = true\n texture.dispose()\n }\n }, [stableContents, sheet.width, sheet.height, stock.id])\n\n return atlas\n}\n","import type { DeformerInstance, SheetDims } from '../deformers/types'\nimport { getDeformer } from '../deformers/registry'\nimport {\n TRANSLUCENCY_FRAGMENT,\n TRANSLUCENCY_VARYINGS,\n translucencyVertexChunk,\n} from '../surface/translucency'\n\n/**\n * Compose a deformer stack into GLSL — the GPU twin of deformers/compose.ts.\n * Each stack entry gets its own uniform namespace (`uRoll0_angle`,\n * `uFold1_offset`, …) so the same deformer type can appear twice\n * (letter-fold is two folds). Golden-vector parity with the JS path is\n * enforced by the GPU harness test.\n */\n\nexport interface ComposedDisplacement {\n /** Uniform declarations + displacement functions. */\n functionsSrc: string\n /** `vec3 plDisplace(vec3 p, vec2 uv, float t)` applying the whole stack. */\n displaceSrc: string\n /** Initial uniform values, keyed by their namespaced GLSL names (uSheet included). */\n uniforms: Record<string, number | number[]>\n}\n\nfunction glslType(value: number | number[]): string {\n if (typeof value === 'number') return 'float'\n return ['float', 'vec2', 'vec3', 'vec4'][value.length - 1]!\n}\n\n/**\n * Just the uniform VALUES for a stack (same namespaced keys as\n * buildDisplacementGLSL) — cheap enough to call every frame while a behavior\n * animates. Structure (names) is stable as long as the stack's type order is.\n */\nexport function stackUniformValues(\n stack: DeformerInstance[],\n sheet: SheetDims,\n): Record<string, number | number[]> {\n const uniforms: Record<string, number | number[]> = { uSheet: [sheet.width, sheet.height] }\n stack.forEach((instance, i) => {\n if (instance.enabled === false) return\n const deformer = getDeformer(instance.type)\n if (!deformer.glsl) return\n const ns = `u${cap(instance.type)}${i}_`\n const values = deformer.glsl.uniforms(instance.options) as Record<string, number | number[]>\n for (const [key, value] of Object.entries(values)) uniforms[ns + key] = value\n })\n return uniforms\n}\n\nexport function buildDisplacementGLSL(stack: DeformerInstance[], sheet: SheetDims): ComposedDisplacement {\n const decls: string[] = ['uniform vec2 uSheet;', 'float plBias = 1.0;']\n const functions: string[] = []\n const calls: string[] = []\n const uniforms: Record<string, number | number[]> = { uSheet: [sheet.width, sheet.height] }\n\n stack.forEach((instance, i) => {\n if (instance.enabled === false) return\n const deformer = getDeformer(instance.type)\n if (!deformer.glsl) {\n throw new Error(\n `[paperlab] Deformer \"${instance.type}\" has no GLSL implementation — it can't run in field mode.`,\n )\n }\n const ns = `u${cap(instance.type)}${i}_`\n const fn = `pl_${instance.type}${i}`\n const values = deformer.glsl.uniforms(instance.options) as Record<string, number | number[]>\n for (const [key, value] of Object.entries(values)) {\n decls.push(`uniform ${glslType(value)} ${ns}${key};`)\n uniforms[ns + key] = value\n }\n const strength = deformer.glsl.strength\n functions.push(\n deformer.glsl.chunk.replaceAll('FN', fn).replace(/U_(\\w+)/g, (_, name: string) =>\n // The strength uniform reads through the per-instance bias, so one\n // instanced draw call can bend every sheet by a different amount.\n name === strength ? `(${ns}${name} * plBias)` : ns + name,\n ),\n )\n calls.push(`${fn}(q, uv, t);`)\n })\n\n const displaceSrc = /* glsl */ `\nvec3 plDisplace(vec3 p, vec2 uv, float t, float bias) {\n plBias = bias;\n vec3 q = p;\n ${calls.join('\\n ')}\n return q;\n}\n`\n\n return { functionsSrc: `${decls.join('\\n')}\\n${functions.join('\\n')}`, displaceSrc, uniforms }\n}\n\n/**\n * The field-mode CSM vertex shader: displaced position + numerically\n * recomputed normal (two tangent probes — exact normals of an arbitrary\n * stack have no closed form).\n */\nexport function buildFieldVertexShader(composed: ComposedDisplacement): string {\n return /* glsl */ `\nuniform float uPlTime;\nattribute float aPhase;\nattribute float aAtlas;\nattribute float aBias;\nvarying vec2 vPaperUv;\nvarying float vAtlas;\n${TRANSLUCENCY_VARYINGS}\n${composed.functionsSrc}\n${composed.displaceSrc}\nvoid main() {\n float t = uPlTime + aPhase;\n vec3 p = plDisplace(position, uv, t, aBias);\n vec2 step = uSheet * 0.01;\n vec3 px = plDisplace(position + vec3(step.x, 0.0, 0.0), uv + vec2(0.01, 0.0), t, aBias);\n vec3 py = plDisplace(position + vec3(0.0, step.y, 0.0), uv + vec2(0.0, 0.01), t, aBias);\n vec3 n = cross(px - p, py - p);\n csm_Normal = length(n) > 1e-12 ? normalize(n) : vec3(0.0, 0.0, 1.0);\n csm_Position = p;\n${translucencyVertexChunk({ model: 'modelMatrix * instanceMatrix', position: 'p', normal: 'csm_Normal' })}\n vPaperUv = uv;\n vAtlas = aAtlas;\n}\n`\n}\n\n/**\n * Field fragment shader: per-instance tile from the shared content atlas on\n * the FRONT face; the BACK face renders the stock with an optional reversed\n * show-through ghost (per-paper back textures are a hero-mode feature).\n */\nexport function buildFieldFragmentShader(): string {\n return /* glsl */ `\nuniform sampler2D uAtlas;\nuniform vec2 uAtlasGrid;\nuniform float uBackDarken;\nuniform vec3 uStockColor;\nuniform float uShowThrough;\nvarying vec2 vPaperUv;\nvarying float vAtlas;\n${TRANSLUCENCY_FRAGMENT}\nvoid main() {\n float col = mod(vAtlas, uAtlasGrid.x);\n float row = floor(vAtlas / uAtlasGrid.x);\n vec2 tiled = (vPaperUv + vec2(col, uAtlasGrid.y - 1.0 - row)) / uAtlasGrid;\n vec4 front = texture2D(uAtlas, tiled);\n if (gl_FrontFacing) {\n csm_DiffuseColor = front;\n } else {\n csm_DiffuseColor = vec4(uStockColor * mix(vec3(1.0), front.rgb, uShowThrough), 1.0);\n csm_DiffuseColor.rgb *= uBackDarken;\n }\n // Light coming through the sheet, filtered by what is printed on it. Same\n // ink either side — the light passes through the same fibres regardless of\n // which face happens to be turned toward the camera.\n csm_Emissive = plTransmission(front.rgb);\n}\n`\n}\n\nfunction cap(s: string): string {\n return s.charAt(0).toUpperCase() + s.slice(1).replace(/-(\\w)/g, (_, c: string) => c.toUpperCase())\n}\n","import { z } from 'zod'\nimport type { AnyOptions, SheetDims } from '../../deformers/types'\nimport { SHEET_LIFT, sheetLayoutSchema, sheetSlotXY, type SheetLayoutOptions } from '../sheetGrid'\nimport { getWalkPath, walkPathSchema } from '../../stage/path'\n\n/**\n * A layout is a pure `pose(i, n, options, phase)` function — no state, no\n * three.js. `phase` is the motion driver's continuous offset in turns\n * (0..1 = one full cycle); cyclic layouts use it, static ones ignore it.\n * Community layouts are ~30 lines.\n *\n * Every built-in names a place paper actually sits — a fanned swatch deck, a\n * slipped stack, a heap on a desk — because arrangement alone is what makes a\n * field read as a photo carousel instead of as paper. The other half of that\n * is `bias`: paper in the world does not all bend alike.\n */\n\nexport interface PaperPose {\n position: [number, number, number]\n rotation: [number, number, number]\n scale: number\n /**\n * How strongly this sheet takes the field's deformation: 1 = exactly as the\n * preset configures it, 0 = flat. Lets one instanced draw call curl the top\n * of a pile while the sheets pressed underneath stay flat. Omitted = 1.\n */\n bias?: number\n}\n\nexport interface Layout<O = Record<string, unknown>> {\n id: string\n label: string\n defaults: O\n optionsSchema: z.ZodType<O, unknown>\n /**\n * `sheet` is the field's paper size. Layouts that arrange by CONTACT —\n * edges meeting, sheets resting on each other — cannot work without it,\n * and a layout that ignores it may simply omit the parameter.\n */\n pose(i: number, n: number, o: O, phase: number, sheet: SheetDims): PaperPose\n /**\n * Where along a walk this layout put each paper, as normalized arc length,\n * in the layout's own index order.\n *\n * Only layouts that arrange along a PATH can answer, which is why it is\n * optional. Stage mode uses it to let a viewer step from one paper to the\n * next: the stops have to be where the paper actually is, and the only\n * thing that knows that is the function that placed it.\n */\n walkStops?(n: number, o: O): number[]\n}\n\n/** For the odd caller that has no papers yet to measure. */\nexport const DEFAULT_SHEET: SheetDims = { width: 1, height: 1.4 }\n\nconst TAU = Math.PI * 2\nconst DEG = Math.PI / 180\n\n/** Deterministic per-index jitter — layouts must be pure. */\nfunction jitter(seed: number, i: number): number {\n let h = Math.imul((seed * 1000 + i + 1) ^ 0x9e3779b9, 2654435761)\n h = Math.imul(h ^ (h >>> 13), 3266489917)\n return (((h ^ (h >>> 16)) >>> 0) / 4294967295) * 2 - 1\n}\n\n/** 0 at the first sheet, 1 at the last — the spine of most layouts. */\nfunction ramp(i: number, n: number): number {\n return n > 1 ? i / (n - 1) : 1\n}\n\nconst ringSchema = z.object({\n radius: z.number().min(0.5).max(12).default(2.6),\n tiltDeg: z.number().min(-45).max(45).default(8),\n})\n/** Prints pegged around a circle — the one carousel worth keeping. */\nexport const ring: Layout<z.infer<typeof ringSchema>> = {\n id: 'ring',\n label: 'Ring',\n defaults: ringSchema.parse({}),\n optionsSchema: ringSchema,\n pose(i, n, o, phase) {\n const theta = (i / n + phase) * TAU\n return {\n position: [Math.sin(theta) * o.radius, 0, Math.cos(theta) * o.radius],\n // Face radially OUTWARD so the papers nearest the camera show their\n // front (content) side — you stand outside the ring, not inside it.\n rotation: [(o.tiltDeg * Math.PI) / 180, theta, 0],\n scale: 1,\n }\n },\n}\n\nconst fanSchema = z.object({\n /** Total angular sweep from the first sheet to the last, degrees. */\n sweep: z.number().min(0).max(180).default(72),\n /** Where the shared pin sits, in half-sheet-heights below center. 1 = the bottom edge. */\n hinge: z.number().min(0).max(4).default(1.15),\n /** Thickness step so the sheets stack in order instead of z-fighting. */\n lift: z.number().min(0.002).max(0.08).default(0.012),\n /** How much flatter the middle of the fan sits than its outer sheets. */\n bow: z.number().min(0).max(1).default(0.7),\n})\n/**\n * A Pantone deck, a paint-chip book, a hand of cards: every sheet pinned at\n * one shared point and swung open. The sheets nearest the outside of the\n * sweep carry the most curl, which is what sells the hinge as a hinge.\n */\nexport const fan: Layout<z.infer<typeof fanSchema>> = {\n id: 'fan',\n label: 'Fan',\n defaults: fanSchema.parse({}),\n optionsSchema: fanSchema,\n pose(i, n, o, _phase, sheet) {\n const f = n > 1 ? i / (n - 1) : 0.5\n const theta = (f - 0.5) * o.sweep * DEG\n const hinge = (o.hinge * sheet.height) / 2\n // Swing the sheet about the shared pivot, then shift so the middle sheet\n // sits at the origin — the fan stays centered as `sweep` opens and closes.\n const open = Math.abs(f - 0.5) * 2\n return {\n position: [-Math.sin(theta) * hinge, Math.cos(theta) * hinge - hinge, i * o.lift],\n rotation: [0, 0, theta],\n scale: 1,\n bias: 1 - (1 - open) * o.bow,\n }\n },\n}\n\nconst spreadSchema = z.object({\n /** How far each sheet slides past the one below it. */\n slip: z.number().min(0.02).max(2).default(0.3),\n /** Direction of the slide, degrees. 0 slides right, 90 slides up. */\n angle: z.number().min(-180).max(180).default(28),\n lift: z.number().min(0.002).max(0.08).default(0.012),\n /** How much more the sheets at the far end of the slide bow. */\n bow: z.number().min(0).max(1).default(0.6),\n /** Nothing hand-slid is perfectly square — a touch of per-sheet rotation. */\n drift: z.number().min(0).max(1).default(0.15),\n})\n/**\n * A ream pushed sideways, or a deck dealt across a table: parallel sheets at\n * a constant offset, each one bowing a little more as it comes free of the\n * stack's weight.\n */\nexport const spread: Layout<z.infer<typeof spreadSchema>> = {\n id: 'spread',\n label: 'Spread',\n defaults: spreadSchema.parse({}),\n optionsSchema: spreadSchema,\n pose(i, n, o) {\n const centered = i - (n - 1) / 2\n const a = o.angle * DEG\n return {\n position: [Math.cos(a) * o.slip * centered, Math.sin(a) * o.slip * centered, i * o.lift],\n rotation: [0, 0, jitter(11, i) * 0.2 * o.drift],\n scale: 1,\n bias: 1 - (1 - ramp(i, n)) * o.bow,\n }\n },\n}\n\nconst pileSchema = z.object({\n /** How far sheets wander from the center of the heap. */\n scatter: z.number().min(0).max(2).default(0.22),\n /** Widest angle a sheet sits off square, degrees. */\n turn: z.number().min(0).max(180).default(24),\n lift: z.number().min(0.002).max(0.08).default(0.011),\n /** How flat the sheets underneath are pressed by the ones on top. */\n press: z.number().min(0).max(1).default(0.85),\n seed: z.number().int().min(0).max(9999).default(3),\n})\n/**\n * The heap on a desk. The physical tell no parametric curve can fake: sheets\n * rest ON each other, so only the top of the pile keeps its curl and\n * everything below is pressed flat by the weight above it.\n */\nexport const pile: Layout<z.infer<typeof pileSchema>> = {\n id: 'pile',\n label: 'Pile',\n defaults: pileSchema.parse({}),\n optionsSchema: pileSchema,\n pose(i, n, o) {\n return {\n position: [jitter(o.seed, i) * o.scatter, jitter(o.seed + 1, i) * o.scatter * 0.8, i * o.lift],\n rotation: [0, 0, jitter(o.seed + 2, i) * o.turn * DEG],\n scale: 1,\n bias: 1 - (1 - ramp(i, n)) * o.press,\n }\n },\n}\n\nconst wallSchema = z.object({\n gapX: z.number().min(0.05).max(1).default(0.22),\n gapY: z.number().min(0.05).max(1).default(0.3),\n jitterAmt: z.number().min(0).max(1).default(0.25),\n /** Spread of sag across the wall — no two pinned sheets hang alike. */\n sag: z.number().min(0).max(1).default(0.45),\n})\n/** A studio wall of pinned sheets: a grid, but nothing hangs quite square. */\nexport const wall: Layout<z.infer<typeof wallSchema>> = {\n id: 'wall',\n label: 'Wall',\n defaults: wallSchema.parse({}),\n optionsSchema: wallSchema,\n pose(i, n, o, _phase, sheet) {\n const cols = Math.ceil(Math.sqrt((n * sheet.height) / sheet.width))\n const rows = Math.ceil(n / cols)\n const col = i % cols\n const row = Math.floor(i / cols)\n // Gaps are breathing room around the real paper — a wall of 1.2×0.9\n // prints and a wall of 1×1.4 letters both want even gutters.\n const cellW = sheet.width + o.gapX\n const cellH = sheet.height + o.gapY\n return {\n position: [\n (col - (cols - 1) / 2) * cellW,\n ((rows - 1) / 2 - row) * cellH,\n jitter(5, i) * 0.04 * o.jitterAmt * 4,\n ],\n rotation: [0, 0, jitter(6, i) * 0.05 * o.jitterAmt * 4],\n scale: 1,\n bias: 1 - Math.abs(jitter(7, i)) * o.sag,\n }\n },\n}\n\nconst spillSchema = z.object({\n spreadX: z.number().min(0.5).max(8).default(2.4),\n spreadY: z.number().min(0.5).max(8).default(1.5),\n depth: z.number().min(0).max(6).default(1.6),\n /** How far sheets pitch and roll out of the picture plane. */\n tumble: z.number().min(0).max(1).default(0.5),\n /** Spread of bend across the sheets — a spill does not fold them alike. */\n vary: z.number().min(0).max(1).default(0.6),\n seed: z.number().int().min(0).max(9999).default(7),\n})\n/**\n * A dropped folder's worth of paper, mid-air — what a `pile` looks like the\n * moment before it settles. Loose in all three axes, and (the part that\n * separates it from confetti) every sheet caught at its own angle AND its\n * own amount of bend.\n */\nexport const spill: Layout<z.infer<typeof spillSchema>> = {\n id: 'spill',\n label: 'Spill',\n defaults: spillSchema.parse({}),\n optionsSchema: spillSchema,\n pose(i, _n, o) {\n const tumble = o.tumble * 2\n return {\n position: [\n jitter(o.seed, i) * o.spreadX,\n jitter(o.seed + 1, i) * o.spreadY,\n jitter(o.seed + 2, i) * o.depth,\n ],\n rotation: [\n jitter(o.seed + 3, i) * 0.4 * tumble,\n jitter(o.seed + 4, i) * 0.5 * tumble,\n jitter(o.seed + 5, i) * 0.4 * tumble,\n ],\n scale: 0.85 + Math.abs(jitter(o.seed + 6, i)) * 0.3,\n bias: 1 - Math.abs(jitter(o.seed + 7, i)) * o.vary,\n }\n },\n}\n\nconst sweepSchema = z.object({\n columns: z.number().int().min(1).max(24).default(5),\n /** Breathing room around each specimen. */\n gap: z.number().min(0).max(2).default(0.22),\n /** Deformation at the first specimen and at the last. */\n from: z.number().min(0).max(1).default(0),\n to: z.number().min(0).max(1).default(1),\n})\n/**\n * A specimen chart: the same sheet mounted in a grid, its deformation ramped\n * across the series so one image shows a curl at ten stages instead of one.\n * The layout the rest of this library exists to make possible — and the one\n * that documents every deformer for free.\n *\n * Only as legible as the preset it charts: a sheet with no behavior or\n * deformers has nothing for the ramp to scale, and every specimen comes out\n * identical.\n */\nexport const sweep: Layout<z.infer<typeof sweepSchema>> = {\n id: 'sweep',\n label: 'Sweep',\n defaults: sweepSchema.parse({}),\n optionsSchema: sweepSchema,\n pose(i, n, o, _phase, sheet) {\n const cols = Math.min(o.columns, Math.max(n, 1))\n const rows = Math.ceil(n / cols)\n const col = i % cols\n const row = Math.floor(i / cols)\n return {\n position: [\n (col - (cols - 1) / 2) * (sheet.width + o.gap),\n ((rows - 1) / 2 - row) * (sheet.height + o.gap),\n 0,\n ],\n rotation: [0, 0, 0],\n scale: 1,\n bias: o.from + (o.to - o.from) * ramp(i, n),\n }\n },\n}\n\nconst bookSchema = z.object({\n /** How far the outermost page lifts off the block, degrees. */\n spread: z.number().min(0).max(150).default(55),\n /** Fraction of the pages bound to the left. 0 = a one-sided sample book. */\n split: z.number().min(0).max(1).default(0.5),\n /** Page thickness — the gap between pages of one block. */\n lift: z.number().min(0.001).max(0.05).default(0.008),\n /** How much more a lifted page arcs than one lying flat in the block. */\n gutter: z.number().min(0).max(1).default(0.6),\n})\n/**\n * An open codex: pages hinged on a shared spine, each block splaying away\n * from the gutter. `split` slides it between the two bound forms paper takes\n * — 0.5 is a book lying open, 0 is a swatch deck or sample book bound down\n * one side. Pages lying flat in the block are pressed by the ones above;\n * only the lifted pages keep their arc.\n */\nexport const book: Layout<z.infer<typeof bookSchema>> = {\n id: 'book',\n label: 'Book',\n defaults: bookSchema.parse({}),\n optionsSchema: bookSchema,\n pose(i, n, o, _phase, sheet) {\n const half = sheet.width / 2\n const left = Math.round(n * o.split)\n const onLeft = i < left\n const count = onLeft ? left : n - left\n const k = onLeft ? i : i - left\n const f = count > 1 ? k / (count - 1) : 1\n const theta = f * o.spread * DEG\n // Swing the page about the spine at x = 0; `side` mirrors the left block.\n const side = onLeft ? -1 : 1\n const cos = Math.cos(theta)\n const sin = Math.sin(theta)\n // Stack along the page's own normal so pages standing near-vertical\n // separate sideways rather than sinking into each other.\n const offset = k * o.lift\n return {\n position: [side * (half * cos - offset * sin), 0, half * sin + offset * cos],\n rotation: [0, -side * theta, 0],\n scale: 1,\n bias: 1 - (1 - f) * o.gutter,\n }\n },\n}\n\nconst accordionSchema = z.object({\n /** How far each panel tilts off the strip's line, degrees. 0 = flat, 90 = shut. */\n angle: z.number().min(0).max(89).default(55),\n /** A concertina holds its creases — how much bow the panels keep. */\n slack: z.number().min(0).max(1).default(0.15),\n})\n/**\n * A concertina: panels alternating about creases they genuinely share, so\n * the sheets read as ONE folded strip rather than as N separate papers —\n * the only layout here where that is true. Adjacent edges are solved to\n * meet, which is why it needs the sheet's real width.\n */\nexport const accordion: Layout<z.infer<typeof accordionSchema>> = {\n id: 'accordion',\n label: 'Accordion',\n defaults: accordionSchema.parse({}),\n optionsSchema: accordionSchema,\n pose(i, n, o, _phase, sheet) {\n const theta = o.angle * DEG\n const side = i % 2 === 0 ? 1 : -1\n // Solving edge-meets-edge for alternating ±angle puts every panel center\n // on one line, spaced by the panel's foreshortened width.\n const step = sheet.width * Math.cos(theta)\n return {\n position: [(i - (n - 1) / 2) * step, 0, 0],\n rotation: [0, side * theta, 0],\n scale: 1,\n bias: o.slack,\n }\n },\n}\n\nconst rackSchema = z.object({\n /** Gap along the row, as a fraction of the paper's width. Under 1 they overlap. */\n spacing: z.number().min(0.05).max(2).default(0.82),\n /** How far a sheet leans back off vertical, degrees. */\n lean: z.number().min(0).max(70).default(16),\n /** How much that lean differs sheet to sheet — nothing propped is uniform. */\n vary: z.number().min(0).max(1).default(0.55),\n /** Small rotations off square. */\n sway: z.number().min(0).max(1).default(0.35),\n seed: z.number().int().min(0).max(9999).default(5),\n})\n/**\n * Prints stood in a row and leaning back — against a wall, in a rack, propped\n * along a shelf. The one arrangement here that RESTS on a surface rather than\n * floating: every sheet pivots on the bottom edge it actually stands on, so\n * the row shares a floor. The further a sheet has leaned, the more it bows\n * under its own weight.\n *\n * (Stacking these front-to-back the way a letter tray really holds paper is\n * physically honest and visually useless — the front sheet hides the rest.\n * A row is the arrangement you can actually see.)\n */\nexport const rack: Layout<z.infer<typeof rackSchema>> = {\n id: 'rack',\n label: 'Rack',\n defaults: rackSchema.parse({}),\n optionsSchema: rackSchema,\n pose(i, n, o, _phase, sheet) {\n const lean = o.lean * DEG * (1 + jitter(o.seed, i) * o.vary)\n const half = sheet.height / 2\n return {\n position: [\n (i - (n - 1) / 2) * sheet.width * o.spacing,\n // Standing on the floor: the bottom edge stays at y = 0 as it leans.\n half * Math.cos(lean),\n -half * Math.sin(lean) + i * 0.004,\n ],\n rotation: [-lean, jitter(o.seed + 1, i) * 0.12 * o.sway, jitter(o.seed + 2, i) * 0.06 * o.sway],\n scale: 1,\n // A sheet leaning further has more of its own weight to carry.\n bias: o.lean === 0 ? 0 : Math.min(1, lean / (o.lean * DEG * (1 + o.vary))),\n }\n },\n}\n\nconst colonnadeSchema = z.object({\n /** The walk the colonnade is built along — see `stage/path`. */\n path: walkPathSchema.prefault({}),\n /** Half-width of the clear aisle: how far each banner stands off the walk line. */\n aisle: z.number().min(0.2).max(20).default(2.4),\n /** How much that gap opens and closes along the walk. Nothing hung by hand is a corridor. */\n breathe: z.number().min(0).max(1).default(0.3),\n /** Widest angle a banner turns off square to the aisle, degrees. */\n twist: z.number().min(0).max(90).default(22),\n /** Fraction of the walk left clear at each end, so the figure has somewhere to enter from. */\n margin: z.number().min(0).max(0.45).default(0.05),\n /** Spread of banner heights, 0..1. */\n rise: z.number().min(0).max(1).default(0.28),\n /**\n * How far the banners lift off the floor, as a fraction of their height.\n *\n * NEGATIVE is allowed, and it is what pooling actually requires. At 0 a\n * banner's bottom EDGE sits on the floor — which is not the same as paper\n * pooling on it, however much the old comment here claimed otherwise. A\n * ribbon creases a pool-length above its bottom edge, so it has to hang\n * that much lower for the crease to land on the ground and the slack to\n * lie ON it rather than in mid-air parallel to it.\n *\n * The bound used to be 0, so the one thing this option documented itself\n * as doing was the one thing it could not do.\n */\n hover: z.number().min(-0.5).max(1).default(0),\n /** Spread of deformation — no two lengths of hung paper drape alike. */\n drape: z.number().min(0).max(1).default(0.5),\n seed: z.number().int().min(0).max(9999).default(2),\n})\n/**\n * A nave of hanging banners flanking a walk: paper as ARCHITECTURE rather\n * than as an object on a desk. The first layout here that arranges along a\n * path instead of around an origin, which is what lets a figure walk through\n * it — the aisle is guaranteed clear because the banners are placed off the\n * walk line, not merely near it.\n *\n * Banners alternate ranks (left, right, left…) and the two ranks are\n * staggered by a quarter step, so you pass them one at a time rather than\n * through a ladder of matched pairs. Each faces across the aisle: a banner\n * ahead of you presents its face, which is the whole reason to print\n * anything on it.\n */\n/**\n * How far along the walk banner `i` stands, before any phase offset.\n *\n * Pulled out of `pose` because two things now need it and they must not\n * disagree: the banner is PLACED here, and stage mode STOPS here when the\n * viewer steps from one paper to the next. A stop that is not where the\n * paper is would be a navigation that misses everything it aims at.\n */\nexport function colonnadeStop(i: number, n: number, margin: number): number {\n const side = i % 2 === 0 ? 1 : -1\n const pairs = Math.max(Math.ceil(n / 2), 1)\n const k = Math.floor(i / 2)\n const span = 1 - margin * 2\n const step = pairs > 1 ? span / (pairs - 1) : 0\n return margin + (pairs > 1 ? k * step : span / 2) + side * step * 0.25\n}\n\nexport const colonnade: Layout<z.infer<typeof colonnadeSchema>> = {\n id: 'colonnade',\n label: 'Colonnade',\n defaults: colonnadeSchema.parse({}),\n optionsSchema: colonnadeSchema,\n walkStops(n, o) {\n return Array.from({ length: n }, (_, i) => colonnadeStop(i, n, o.margin))\n },\n pose(i, n, o, phase, sheet) {\n const path = getWalkPath(o.path)\n const side = i % 2 === 0 ? 1 : -1\n const base = colonnadeStop(i, n, o.margin)\n // Only a closed walk can slide: on an open one, offsetting by phase would\n // teleport the far banner back to the near end mid-shot.\n const s = path.closed ? base + phase : base\n const [px, pz] = path.pointAt(s)\n const [nx, nz] = path.normalAt(s)\n const scale = 1 + jitter(o.seed, i) * o.rise * 0.5\n const offset = o.aisle * (1 + jitter(o.seed + 1, i) * o.breathe)\n const height = sheet.height * scale\n // Face the centerline: the inward direction is the aisle normal, negated\n // on whichever rank this banner stands in.\n const yaw = Math.atan2(-side * nx, -side * nz) + jitter(o.seed + 2, i) * o.twist * DEG\n return {\n position: [px + nx * side * offset, height / 2 + height * o.hover, pz + nz * side * offset],\n rotation: [0, yaw, 0],\n scale,\n bias: 1 - Math.abs(jitter(o.seed + 3, i)) * o.drape,\n }\n },\n}\n\n/**\n * A block of stamps: flat rows × columns grid in register, floating a hair\n * above the (field-rendered) backing sheet. Standard layout contract — it\n * also works standalone as a plain grid; `backing`/`backingMargin` are read\n * by the field renderer, not by `pose`.\n */\nexport const sheet: Layout<SheetLayoutOptions> = {\n id: 'sheet',\n label: 'Sheet',\n defaults: sheetLayoutSchema.parse({}),\n optionsSchema: sheetLayoutSchema,\n pose(i, _n, o) {\n const { x, y } = sheetSlotXY(i, o)\n return { position: [x, y, SHEET_LIFT], rotation: [0, 0, 0], scale: 1 }\n },\n}\n\nconst registry = new Map<string, Layout<AnyOptions>>()\n\nexport function registerLayout(layout: Layout<AnyOptions>): void {\n registry.set(layout.id, layout)\n}\n\nexport function getLayout(id: string): Layout<AnyOptions> {\n const layout = registry.get(id)\n if (!layout) {\n throw new Error(`[paperlab] Unknown layout \"${id}\". Registered: ${[...registry.keys()].join(', ')}`)\n }\n return layout\n}\n\nexport function listLayouts(): string[] {\n return [...registry.keys()]\n}\n\nregisterLayout(ring)\nregisterLayout(fan)\nregisterLayout(spread)\nregisterLayout(pile)\nregisterLayout(wall)\nregisterLayout(spill)\nregisterLayout(sweep)\nregisterLayout(book)\nregisterLayout(accordion)\nregisterLayout(rack)\nregisterLayout(colonnade)\nregisterLayout(sheet)\n","import { z } from 'zod'\n\n/**\n * The walk — a path across the ground plane that a figure follows and that\n * layouts arrange paper along. Pure 2D math (x, z on the floor, y is always\n * up), no three.js, so it tests in node and is cheap enough to call from\n * inside a layout's pure `pose`.\n *\n * Centripetal Catmull-Rom through the control points — it will not cusp or\n * overshoot when two points bunch together, which a uniform spline does —\n * resampled to a uniform arc-length polyline. That resampling is the point:\n * `pointAt(s)` advances at constant SPEED, so a figure stepping `s` forward\n * at a steady rate covers ground at a steady rate. A raw spline parameter\n * would have it sprint through the straights and crawl around the corners.\n */\n\n/** A point on the floor. */\nexport type Ground = [x: number, z: number]\n\nexport const walkPathSchema = z.object({\n /**\n * Control points on the ground plane, [x, z]. The default walks away from\n * the camera down -Z — the shot every reference image is composed on.\n */\n points: z\n .array(z.tuple([z.number(), z.number()]))\n .min(2)\n .default([\n [0, 9],\n [0, -9],\n ]),\n /** Join the last point back to the first: an endless walk, and the only form `phase` can slide. */\n closed: z.boolean().default(false),\n})\n\nexport type WalkPathOptions = z.infer<typeof walkPathSchema>\n\nexport interface WalkPath {\n /** Total arc length in world units. */\n readonly length: number\n readonly closed: boolean\n /** `s` is normalized arc length: 0 = the start, 1 = the end. Closed paths wrap, open paths clamp. */\n pointAt(s: number): Ground\n /** Unit forward direction at `s`. */\n tangentAt(s: number): Ground\n /** Unit LEFT-hand normal at `s` — the side of the aisle a walker's left hand points to. */\n normalAt(s: number): Ground\n}\n\n/** Polyline resolution. 24 per segment holds a tight curve to well under a millimetre of chord error. */\nconst SAMPLES_PER_SEGMENT = 24\n\n/** Coincident control points would collapse the knot spacing and divide by zero. */\nconst EPSILON = 1e-6\n\n/** Centripetal: alpha = 0.5. (0 would be uniform, 1 chordal.) */\nconst ALPHA = 0.5\n\nfunction knot(a: Ground, b: Ground, t: number): number {\n return t + Math.max(Math.hypot(b[0] - a[0], b[1] - a[1]), EPSILON) ** ALPHA\n}\n\n/** Linear interpolation in knot space — the Barry-Goldman building block. */\nfunction lerpKnot(a: Ground, b: Ground, ta: number, tb: number, t: number): Ground {\n const span = tb - ta\n const k = span === 0 ? 0 : (t - ta) / span\n return [a[0] + (b[0] - a[0]) * k, a[1] + (b[1] - a[1]) * k]\n}\n\n/** One centripetal Catmull-Rom segment p1→p2, `u` in 0..1. */\nfunction segmentPoint(p0: Ground, p1: Ground, p2: Ground, p3: Ground, u: number): Ground {\n const t0 = 0\n const t1 = knot(p0, p1, t0)\n const t2 = knot(p1, p2, t1)\n const t3 = knot(p2, p3, t2)\n const t = t1 + (t2 - t1) * u\n const a1 = lerpKnot(p0, p1, t0, t1, t)\n const a2 = lerpKnot(p1, p2, t1, t2, t)\n const a3 = lerpKnot(p2, p3, t2, t3, t)\n const b1 = lerpKnot(a1, a2, t0, t2, t)\n const b2 = lerpKnot(a2, a3, t1, t3, t)\n return lerpKnot(b1, b2, t1, t2, t)\n}\n\n/** The phantom control point beyond an open path's end: reflect the interior neighbor. */\nfunction reflect(end: Ground, inner: Ground): Ground {\n return [2 * end[0] - inner[0], 2 * end[1] - inner[1]]\n}\n\nexport function createWalkPath(options: WalkPathOptions): WalkPath {\n const pts = options.points as Ground[]\n const n = pts.length\n const closed = options.closed && n > 2\n const segments = closed ? n : n - 1\n\n // Resample the spline into a uniformly-indexed polyline, carrying the\n // cumulative arc length so `s` can be inverted by search.\n const samples: Ground[] = []\n const cumulative: number[] = []\n let total = 0\n for (let seg = 0; seg < segments; seg++) {\n const p1 = pts[seg]!\n const p2 = pts[(seg + 1) % n]!\n const p0 = closed ? pts[(seg - 1 + n) % n]! : seg > 0 ? pts[seg - 1]! : reflect(pts[0]!, pts[1]!)\n const p3 = closed ? pts[(seg + 2) % n]! : seg + 2 < n ? pts[seg + 2]! : reflect(pts[n - 1]!, pts[n - 2]!)\n // The last sample of a segment is the first of the next — emit it only\n // at the very end of an open path, where nothing follows to repeat it.\n const last = seg === segments - 1 && !closed ? SAMPLES_PER_SEGMENT : SAMPLES_PER_SEGMENT - 1\n for (let k = 0; k <= last; k++) {\n const point = segmentPoint(p0, p1, p2, p3, k / SAMPLES_PER_SEGMENT)\n const previous = samples[samples.length - 1]\n if (previous) total += Math.hypot(point[0] - previous[0], point[1] - previous[1])\n samples.push(point)\n cumulative.push(total)\n }\n }\n if (closed) {\n // Close the ring: the start point repeats as the final sample so a\n // search near s = 1 has a segment to land in.\n const first = samples[0]!\n const previous = samples[samples.length - 1]!\n total += Math.hypot(first[0] - previous[0], first[1] - previous[1])\n samples.push([first[0], first[1]])\n cumulative.push(total)\n }\n\n const length = total\n\n function normalize(s: number): number {\n if (!Number.isFinite(s)) return 0\n if (!closed) return Math.min(Math.max(s, 0), 1)\n const wrapped = s - Math.floor(s)\n return wrapped\n }\n\n function pointAt(s: number): Ground {\n const target = normalize(s) * length\n if (length === 0) return [samples[0]![0], samples[0]![1]]\n // Binary search for the first sample at or past the target distance.\n let low = 0\n let high = cumulative.length - 1\n while (low < high) {\n const mid = (low + high) >> 1\n if (cumulative[mid]! < target) low = mid + 1\n else high = mid\n }\n const i = Math.max(low, 1)\n const before = cumulative[i - 1]!\n const span = cumulative[i]! - before\n const k = span <= 0 ? 0 : (target - before) / span\n const a = samples[i - 1]!\n const b = samples[i]!\n return [a[0] + (b[0] - a[0]) * k, a[1] + (b[1] - a[1]) * k]\n }\n\n /** Central difference over a fixed world-space step — stable at any path length. */\n function tangentAt(s: number): Ground {\n const ds = length > 0 ? Math.min(0.01, 0.5 / length) : 0.01\n const here = normalize(s)\n const a = pointAt(closed ? here - ds : Math.max(here - ds, 0))\n const b = pointAt(closed ? here + ds : Math.min(here + ds, 1))\n const dx = b[0] - a[0]\n const dz = b[1] - a[1]\n const len = Math.hypot(dx, dz)\n // A degenerate path has no direction to report; -Z is the house forward.\n return len < EPSILON ? [0, -1] : [dx / len, dz / len]\n }\n\n function normalAt(s: number): Ground {\n const [tx, tz] = tangentAt(s)\n // Left of forward, with +Y up: right = forward × up, so left is its negation.\n return [tz, -tx]\n }\n\n return { length, closed, pointAt, tangentAt, normalAt }\n}\n\n/**\n * Building the arc-length table costs a few hundred flops, and `pose` runs\n * per sheet per frame — so paths are memoized by value. Same options in,\n * same object out, which keeps layouts pure from the outside.\n */\nconst cache = new Map<string, WalkPath>()\nconst CACHE_LIMIT = 32\n\nexport function getWalkPath(options: WalkPathOptions): WalkPath {\n const key = `${options.closed ? 'c' : 'o'}|${options.points.map((p) => `${p[0]},${p[1]}`).join(';')}`\n const hit = cache.get(key)\n if (hit) return hit\n const path = createWalkPath(options)\n if (cache.size >= CACHE_LIMIT) {\n const oldest = cache.keys().next().value\n if (oldest !== undefined) cache.delete(oldest)\n }\n cache.set(key, path)\n return path\n}\n","import { getBehavior } from '../behaviors/registry'\nimport { resolveDeformerStack } from '../deformers/registry'\nimport type { PaperConfig } from '../config/schema'\nimport type { DeformerInstance } from '../deformers/types'\n\n/**\n * The deformer stack one field group renders, at a given behavior progress.\n *\n * A raw `deformers` array is the Advanced fork of a behavior and wins over\n * one — the same precedence the hero path's `buildStack` applies. Field mode\n * once read `behavior` only, so a preset shaped by `deformers` (the way to\n * say \"this print has a permanent bow\") silently rendered flat.\n */\nexport function fieldShapeStack(config: PaperConfig, progress: number): DeformerInstance[] {\n if (config.deformers) return resolveDeformerStack(config.deformers)\n if (!config.behavior) return []\n const behavior = getBehavior(config.behavior.type)\n const options = { ...config.behavior, [behavior.progressParam]: progress }\n return behavior.stack(options, config.sheet)\n}\n","import * as THREE from 'three'\nimport { useEffect, useMemo } from 'react'\nimport { drawBacking } from '../content/backing'\nimport { sheetBackingSize, type SheetLayoutOptions } from './sheetGrid'\n\n/** Warmer than printer stock — the classic gummed backing paper. */\nconst BACKING_TINT = '#f3ecdd'\n\n/**\n * The shared sheet behind a stamp grid: one extra paper sized to the grid\n * bounds + margin, non-interactive, excluded from `papers` indices. Its\n * content is a generated canvas of ghost silhouettes, redrawn on state\n * change (never per-frame).\n */\nexport function BackingSheet({\n options,\n count,\n removed,\n}: {\n options: SheetLayoutOptions\n count: number\n removed: ReadonlySet<number>\n}) {\n const { width, height } = sheetBackingSize(options)\n const canvas = useMemo(() => {\n if (typeof document === 'undefined') return null\n const c = document.createElement('canvas')\n const scale = Math.min(1024, Math.round(360 * Math.max(width, height))) / Math.max(width, height)\n c.width = Math.max(2, Math.round(width * scale))\n c.height = Math.max(2, Math.round(height * scale))\n return c\n }, [width, height])\n const texture = useMemo(() => (canvas ? new THREE.CanvasTexture(canvas) : null), [canvas])\n\n const removedKey = [...removed].sort((a, b) => a - b).join(',')\n // biome-ignore lint/correctness/useExhaustiveDependencies: Serialized deps — options and the removed set are fresh objects every render.\n useEffect(() => {\n if (!canvas || !texture) return\n drawBacking(canvas, { options, count, tint: BACKING_TINT, removed })\n texture.needsUpdate = true\n }, [canvas, texture, JSON.stringify(options), count, removedKey])\n useEffect(() => () => texture?.dispose(), [texture])\n\n return (\n <mesh receiveShadow>\n <planeGeometry args={[width, height]} />\n <meshStandardMaterial map={texture} color=\"#ffffff\" roughness={0.92} metalness={0} />\n </mesh>\n )\n}\n","import { sheetBackingSize, sheetSlotXY, type SheetLayoutOptions } from '../field/sheetGrid'\n\n/**\n * The backing sheet's generated content: per-slot ghost silhouettes a few\n * percent lighter than the backing tint. When a slot's paper detaches\n * (picked/placed), its silhouette lightens further and gains a faint\n * adhesive-sheen gradient — the visual proof of removal. Redrawn on state\n * change, never per-frame.\n */\n\nexport interface SilhouetteRect {\n /** Canvas-UV rect (0..1, y down) of slot i on the backing sheet. */\n x: number\n y: number\n w: number\n h: number\n}\n\n/** Pure: where each slot's silhouette sits on the backing, in canvas UV. */\nexport function silhouetteRects(o: SheetLayoutOptions, count: number): SilhouetteRect[] {\n const { width, height } = sheetBackingSize(o)\n const rects: SilhouetteRect[] = []\n for (let i = 0; i < count; i++) {\n const { x, y } = sheetSlotXY(i, o)\n rects.push({\n x: (x - o.cellWidth / 2 + width / 2) / width,\n // World y up → canvas y down.\n y: (height / 2 - y - o.cellHeight / 2) / height,\n w: o.cellWidth / width,\n h: o.cellHeight / height,\n })\n }\n return rects\n}\n\n/** Lighten a hex tint toward white by `amount` (0..1). */\nexport function lightenHex(hex: string, amount: number): string {\n const n = parseInt(hex.replace('#', ''), 16)\n const ch = (shift: number) => {\n const c = (n >> shift) & 0xff\n return Math.min(255, Math.round(c + (255 - c) * amount))\n }\n return `#${((ch(16) << 16) | (ch(8) << 8) | ch(0)).toString(16).padStart(6, '0')}`\n}\n\nexport interface BackingDrawSpec {\n options: SheetLayoutOptions\n count: number\n tint: string\n /** Slot indices whose paper has been picked/placed away. */\n removed: ReadonlySet<number>\n}\n\n/** Draw the backing content onto a canvas (called on state change only). */\nexport function drawBacking(canvas: HTMLCanvasElement, spec: BackingDrawSpec): void {\n const ctx = canvas.getContext('2d')\n if (!ctx) return\n const { width: cw, height: chh } = canvas\n ctx.fillStyle = spec.tint\n ctx.fillRect(0, 0, cw, chh)\n\n const rects = silhouetteRects(spec.options, spec.count)\n rects.forEach((r, i) => {\n const removed = spec.removed.has(i)\n const x = r.x * cw\n const y = r.y * chh\n const w = r.w * cw\n const h = r.h * chh\n const radius = Math.min(w, h) * 0.06\n\n ctx.fillStyle = lightenHex(spec.tint, removed ? 0.5 : 0.07)\n roundedRect(ctx, x, y, w, h, radius)\n ctx.fill()\n\n if (removed) {\n // Faint adhesive sheen: a diagonal highlight across the bare silhouette.\n const sheen = ctx.createLinearGradient(x, y, x + w, y + h)\n sheen.addColorStop(0, 'rgba(255,255,255,0)')\n sheen.addColorStop(0.5, 'rgba(255,255,255,0.35)')\n sheen.addColorStop(1, 'rgba(255,255,255,0)')\n ctx.fillStyle = sheen\n roundedRect(ctx, x, y, w, h, radius)\n ctx.fill()\n }\n })\n}\n\nfunction roundedRect(\n ctx: CanvasRenderingContext2D,\n x: number,\n y: number,\n w: number,\n h: number,\n r: number,\n): void {\n ctx.beginPath()\n ctx.moveTo(x + r, y)\n ctx.arcTo(x + w, y, x + w, y + h, r)\n ctx.arcTo(x + w, y + h, x, y + h, r)\n ctx.arcTo(x, y + h, x, y, r)\n ctx.arcTo(x, y, x + w, y, r)\n ctx.closePath()\n}\n","import * as THREE from 'three'\nimport { gsap } from 'gsap'\nimport { useFrame, useThree, type ThreeEvent } from '@react-three/fiber'\nimport { useContext, useEffect, useMemo, useRef, useState } from 'react'\nimport { paperConfigSchema, type PaperConfigInput } from '../config/schema'\nimport { mergeConfig } from '../config/merge'\nimport { PaperMesh, type PaperHandle } from '../PaperMesh'\nimport { carryDrive, dampTo, type DampedValue } from '../physics/aero'\nimport { usePrefersReducedMotion } from '../a11y'\nimport type { SheetDims } from '../deformers/types'\nimport { getLayout, type PaperPose } from './layouts'\nimport { tornEdgesOnDetach, type SheetLayoutOptions } from './sheetGrid'\nimport {\n DropZoneContext,\n DropZoneRegistry,\n DropZoneVisual,\n zoneAccepts,\n zoneContains,\n type DropZoneConfig,\n type PlacedPaper,\n type ZoneEntry,\n} from './dropZones'\nimport { BackingSheet } from './backingSheet'\nimport { EMPTY_SET, resolveFieldSlotConfig, type FieldPaperSlot } from './slots'\n\n/** Imperative field controls for the hidden a11y keyboard flow. */\nexport interface FieldA11yController {\n pick(slot: number): boolean\n placeAtZone(slot: number, zoneId: string): void\n cancel(slot: number): void\n zoneIds(): string[]\n slotState(slot: number): string\n}\n\nexport interface InteractiveFieldProps {\n papers: FieldPaperSlot[]\n fallback?: string | PaperConfigInput\n layoutId: string\n layoutOptions: Record<string, unknown>\n sheetOptions: SheetLayoutOptions | null\n /** The field's paper size, for layouts that arrange by contact. */\n sheet: SheetDims\n reducedMotion?: boolean\n /** Serialized zones (the editor's) — merged with `<DropZone>` children. */\n zones?: DropZoneConfig[]\n onSlotStateChange?(slot: number, state: string): void\n onPlace?(paper: PlacedPaper, zone: string): void\n a11yRef?: React.MutableRefObject<FieldA11yController | null>\n}\n\n/** Behaviors with a grab point — the only ones a drag can pick. */\nconst PICK_BEHAVIORS = new Set(['peel', 'carry'])\n\ninterface CarriedPaper {\n slot: number\n pointerId: number | null\n x: DampedValue\n y: DampedValue\n targetX: number\n targetY: number\n lastX: number\n lastY: number\n homePose: PaperPose\n settling: boolean\n}\n\ninterface PressState {\n slot: number\n pointerId: number\n startX: number\n startY: number\n}\n\n/**\n * The interactive field: one hero-path PaperMesh per slot posed by the\n * layout, plus the carry controller — press past `pickThreshold` tears the\n * paper off (perforation auto-wires torn), it flies with the cursor\n * fluttering from drag velocity, zones test its center each frame, release\n * settles (snap → press → flatten) or flutters back to its slot.\n */\nexport function InteractiveField(props: InteractiveFieldProps) {\n const { papers, fallback, layoutId, layoutOptions, sheetOptions } = props\n const total = papers.length\n const layout = getLayout(layoutId)\n const reduced = usePrefersReducedMotion(props.reducedMotion)\n const contextRegistry = useContext(DropZoneContext)\n // Editor-serialized zones need hover state even without a provider.\n const registry = useMemo(() => contextRegistry ?? new DropZoneRegistry(), [contextRegistry])\n const camera = useThree((s) => s.camera)\n const gl = useThree((s) => s.gl)\n const controls = useThree((s) => s.controls) as { enabled?: boolean } | null\n\n // Once a stamp leaves its slot the silhouette stays bare — paper has\n // memory: a returned stamp sits ON its silhouette, detached.\n const [removed, setRemoved] = useState<ReadonlySet<number>>(EMPTY_SET)\n // Runtime config patches (torn perforation, carry override) — merged over\n // the slot config; the machine `rebase`s instead of resetting.\n const [slotPatches, setSlotPatches] = useState<Record<number, Record<string, unknown>>>({})\n const [slotStates, setSlotStates] = useState<Record<number, string>>({})\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: Serialized deps — slots and layout options are fresh objects every render.\n const slotConfigs = useMemo(\n () =>\n papers.map((slot, i) => {\n const config = resolveFieldSlotConfig(slot, fallback, i, layoutId, layoutOptions)\n const patch = slotPatches[i]\n return patch ? paperConfigSchema.parse(mergeConfig(config as Record<string, unknown>, patch)) : config\n }),\n [\n JSON.stringify(papers),\n JSON.stringify(fallback ?? null),\n layoutId,\n JSON.stringify(layoutOptions),\n slotPatches,\n ],\n )\n // biome-ignore lint/correctness/useExhaustiveDependencies: Serialized deps — poses depend on the layout, not on config identity.\n const poses = useMemo(\n () => slotConfigs.map((_, i) => layout.pose(i, total, layoutOptions, 0, props.sheet)),\n [layoutId, JSON.stringify(layoutOptions), total, props.sheet.width, props.sheet.height],\n )\n\n const groupRefs = useRef<(THREE.Group | null)[]>([])\n const handleRefs = useRef<(PaperHandle | null)[]>([])\n const pressRef = useRef<PressState | null>(null)\n const carriedRef = useRef<CarriedPaper | null>(null)\n\n // Registry zones can register after mount; read live in the frame loop.\n const zonesLive = (): ZoneEntry[] => [...(props.zones ?? []), ...registry.list()]\n\n const slotName = (i: number): string => {\n const preset = papers[i]?.preset ?? fallback\n return typeof preset === 'string' ? preset : (slotConfigs[i]?.meta.name ?? 'paper')\n }\n\n const onSlotState = (i: number, state: string) => {\n setSlotStates((prev) => ({ ...prev, [i]: state }))\n if (state === 'picked' || state === 'placed') {\n setRemoved((prev) => (prev.has(i) ? prev : new Set(prev).add(i)))\n }\n props.onSlotStateChange?.(i, state)\n }\n\n // ── Pointer → field-plane projection ──\n const raycaster = useMemo(() => new THREE.Raycaster(), [])\n const planeScratch = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 0, 1), 0), [])\n const pointScratch = useMemo(() => new THREE.Vector3(), [])\n const ndcScratch = useMemo(() => new THREE.Vector2(), [])\n const planePoint = (clientX: number, clientY: number, planeZ: number): [number, number] | null => {\n const rect = gl.domElement.getBoundingClientRect()\n ndcScratch.set(\n ((clientX - rect.left) / rect.width) * 2 - 1,\n -((clientY - rect.top) / rect.height) * 2 + 1,\n )\n raycaster.setFromCamera(ndcScratch, camera)\n planeScratch.constant = -planeZ\n const hit = raycaster.ray.intersectPlane(planeScratch, pointScratch)\n return hit ? [hit.x, hit.y] : null\n }\n\n // ── Pick: the tear ──\n const pick = (slot: number, atX: number, atY: number, pointerId: number | null = null): boolean => {\n const config = slotConfigs[slot]\n const handle = handleRefs.current[slot]\n const home = poses[slot]\n if (!config?.states || !handle || !home) return false\n if (!config.behavior || !PICK_BEHAVIORS.has(config.behavior.type)) return false\n if (slotStates[slot] === 'placed' || carriedRef.current) return false\n\n // Auto-wire the sticker model: perforation edges that faced neighbors\n // tear through (manual state wins), and `picked` defaults to a carry\n // hanging from the peeled corner unless the preset choreographs its own.\n const patch: Record<string, unknown> = {}\n if (sheetOptions && config.surface.perforation) {\n const auto = tornEdgesOnDetach(slot, sheetOptions)\n patch.surface = {\n perforation: { state: { ...auto, ...config.surface.perforation.state } },\n }\n }\n const pickedOverrides = config.states.states.picked?.overrides as { behavior?: unknown } | undefined\n if (!pickedOverrides?.behavior) {\n const grab =\n config.behavior.type === 'peel' && config.behavior.corner !== 'auto'\n ? config.behavior.corner\n : 'top-left'\n patch.states = {\n states: {\n picked: { overrides: { behavior: { type: 'carry', grab, drive: 0.3 } } },\n },\n }\n }\n if (Object.keys(patch).length > 0) {\n setSlotPatches((prev) => ({ ...prev, [slot]: mergeConfig(prev[slot] ?? {}, patch) }))\n }\n\n // Drive the machine through rest→hover→pressed→picked so every side effect\n // fires for BOTH pointer (already at 'pressed') and keyboard (still at\n // 'rest') entry — raw send('pick') from 'rest' was a silent no-op.\n handle.pickProgrammatic()\n carriedRef.current = {\n slot,\n pointerId,\n x: { value: atX, velocity: 0 },\n y: { value: atY, velocity: 0 },\n targetX: atX,\n targetY: atY,\n lastX: atX,\n lastY: atY,\n homePose: home,\n settling: false,\n }\n if (controls) controls.enabled = false\n return true\n }\n\n // ── The settle: the 400ms that sells everything ──\n const settleInto = (carried: CarriedPaper, zone: ZoneEntry) => {\n const group = groupRefs.current[carried.slot]\n const handle = handleRefs.current[carried.slot]\n if (!group || !handle) return\n carried.settling = true\n handle.placeProgrammatic()\n handle.set('drive', 0)\n registry.setHovered(null)\n\n const paper: PlacedPaper = {\n slot: carried.slot,\n presetName: slotName(carried.slot),\n config: slotConfigs[carried.slot]!,\n }\n const zoneZ = zone.bounds.position[2]\n const done = () => {\n carriedRef.current = null\n if (controls) controls.enabled = true\n zone.onPlace?.(paper, zone.id)\n props.onPlace?.(paper, zone.id)\n }\n if (reduced) {\n group.position.set(group.position.x, group.position.y, zoneZ + 0.005)\n group.rotation.set(0, 0, 0)\n group.scale.setScalar(1)\n done()\n return\n }\n const tl = gsap.timeline({ onComplete: done })\n // 1 · Snap — position tweens to the drop point on the zone plane.\n tl.to(group.position, { z: zoneZ + 0.005, duration: 0.12, ease: 'power3.out' }, 0)\n tl.to(group.rotation, { x: 0, y: 0, z: 0, duration: 0.12, ease: 'power3.out' }, 0)\n // 2 · Press — the paper bows into the surface, shadow tightening.\n tl.to(group.scale, { x: 1.02, y: 1.02, z: 1, duration: 0.09, ease: 'power2.in' }, 0.12)\n tl.to(group.position, { z: zoneZ + 0.001, duration: 0.18, ease: 'power2.out' }, 0.12)\n // 3 · Flatten — tiny overshoot on scale (1.0 → 0.985 → 1.0).\n tl.to(group.scale, { x: 0.985, y: 0.985, duration: 0.06, ease: 'power1.inOut' }, 0.3)\n tl.to(group.scale, { x: 1, y: 1, duration: 0.06, ease: 'power1.out' }, 0.36)\n }\n\n // ── The return: flutter back to the slot on a slight arc ──\n const returnHome = (carried: CarriedPaper) => {\n const group = groupRefs.current[carried.slot]\n const handle = handleRefs.current[carried.slot]\n if (!group || !handle) return\n carried.settling = true\n registry.setHovered(null)\n\n const home = carried.homePose\n const done = () => {\n handle.returnProgrammatic()\n carriedRef.current = null\n if (controls) controls.enabled = true\n }\n if (reduced) {\n group.position.set(...home.position)\n group.rotation.set(...home.rotation)\n group.scale.setScalar(home.scale)\n done()\n return\n }\n const from = { x: group.position.x, y: group.position.y, z: group.position.z }\n const dist = Math.hypot(from.x - home.position[0], from.y - home.position[1])\n const duration = Math.min(0.8, Math.max(0.25, dist * 0.55))\n // Curved path: a slight arc perpendicular to the travel, not linear.\n const arc = Math.min(0.35, dist * 0.25)\n const proxy = { t: 0 }\n gsap.to(proxy, {\n t: 1,\n duration,\n ease: 'power2.inOut',\n onUpdate: () => {\n const t = proxy.t\n const lift = Math.sin(t * Math.PI) * arc\n group.position.x = from.x + (home.position[0] - from.x) * t\n group.position.y = from.y + (home.position[1] - from.y) * t + lift\n group.position.z = from.z + (home.position[2] - from.z) * t\n // Flutter decays as it approaches.\n handle.set('drive', (1 - t) * 0.5)\n },\n onComplete: done,\n })\n gsap.to(group.rotation, { x: home.rotation[0], y: home.rotation[1], z: home.rotation[2], duration })\n gsap.to(group.scale, { x: home.scale, y: home.scale, z: home.scale, duration: duration * 0.5 })\n }\n\n // ── Press / drag / release wiring ──\n // Handlers close over the current render's state, so the fresh closures live\n // in refs and the window listeners attach ONCE — re-subscribing per render\n // (worst: per slot-state change mid-drag) is listener churn for nothing.\n const onPointerMoveRef = useRef<(e: PointerEvent) => void>(() => {})\n onPointerMoveRef.current = (e: PointerEvent) => {\n const press = pressRef.current\n const carried = carriedRef.current\n if (carried && !carried.settling && (carried.pointerId === null || e.pointerId === carried.pointerId)) {\n const hit = planePoint(e.clientX, e.clientY, carried.homePose.position[2] + 0.15)\n if (hit) {\n carried.targetX = hit[0]\n carried.targetY = hit[1]\n }\n return\n }\n if (!press) return\n const hit = planePoint(e.clientX, e.clientY, poses[press.slot]?.position[2] ?? 0)\n if (!hit) return\n const dist = Math.hypot(hit[0] - press.startX, hit[1] - press.startY)\n const threshold = slotConfigs[press.slot]?.states?.pickThreshold ?? 0.1\n if (dist > threshold) {\n const { slot, pointerId } = press\n pressRef.current = null\n pick(slot, hit[0], hit[1], pointerId)\n }\n }\n const onPointerUpRef = useRef<(e: PointerEvent) => void>(() => {})\n onPointerUpRef.current = (e: PointerEvent) => {\n pressRef.current = null\n const carried = carriedRef.current\n if (!carried || carried.settling) return\n if (carried.pointerId !== null && e.pointerId !== carried.pointerId) return\n const name = slotName(carried.slot)\n const zone = zonesLive().find(\n (z) => zoneContains(z, carried.x.value, carried.y.value) && zoneAccepts(z, name),\n )\n if (zone) settleInto(carried, zone)\n else returnHome(carried)\n }\n useEffect(() => {\n const move = (e: PointerEvent) => onPointerMoveRef.current(e)\n const up = (e: PointerEvent) => onPointerUpRef.current(e)\n window.addEventListener('pointermove', move)\n window.addEventListener('pointerup', up)\n return () => {\n window.removeEventListener('pointermove', move)\n window.removeEventListener('pointerup', up)\n }\n }, [])\n\n // ── The carry loop: damped follow, velocity flutter, zone hover ──\n useFrame((_, delta) => {\n const carried = carriedRef.current\n if (!carried || carried.settling) return\n const group = groupRefs.current[carried.slot]\n const handle = handleRefs.current[carried.slot]\n if (!group || !handle) return\n const dt = Math.min(delta, 1 / 30)\n\n if (reduced) {\n // Reduced motion: direct cursor-following, no flutter, no lag.\n carried.x.value = carried.lastX = carried.targetX\n carried.y.value = carried.lastY = carried.targetY\n group.position.x = carried.targetX\n group.position.y = carried.targetY\n group.position.z = carried.homePose.position[2] + 0.15\n } else {\n dampTo(carried.x, carried.targetX, 0.09, dt)\n dampTo(carried.y, carried.targetY, 0.09, dt)\n const vx = (carried.x.value - carried.lastX) / dt\n const vy = (carried.y.value - carried.lastY) / dt\n carried.lastX = carried.x.value\n carried.lastY = carried.y.value\n const speed = Math.hypot(vx, vy)\n group.position.x = carried.x.value\n group.position.y = carried.y.value\n group.position.z = carried.homePose.position[2] + 0.15\n // Drag velocity becomes flutter + rotational lag: yaw trails the drag.\n handle.set('drive', carryDrive(speed))\n const lag = 0.25\n group.rotation.y += (THREE.MathUtils.clamp(-vx * lag, -0.6, 0.6) - group.rotation.y) * 0.12\n group.rotation.x += (THREE.MathUtils.clamp(vy * lag * 0.7, -0.5, 0.5) - group.rotation.x) * 0.12\n }\n\n // Zone hover: center test each frame; scale-up is the \"this will stick\" cue.\n const name = slotName(carried.slot)\n const zone = zonesLive().find(\n (z) => zoneContains(z, group.position.x, group.position.y) && zoneAccepts(z, name),\n )\n registry.setHovered(zone?.id ?? null)\n const targetScale = (zone ? 1.03 : 1) * carried.homePose.scale\n group.scale.x += (targetScale - group.scale.x) * 0.15\n group.scale.y = group.scale.z = group.scale.x\n })\n\n // ── a11y controller: keyboard pick → move between zones → place/escape ──\n // Same ref-delegation as the pointer listeners: the real implementation is\n // rebuilt per render (fresh closures), the published object is stable.\n const a11yImplRef = useRef<FieldA11yController | null>(null)\n a11yImplRef.current = {\n pick: (slot) => {\n const home = poses[slot]\n if (!home) return false\n // pick() drives the machine (rest→…→picked) itself — no raw events.\n return pick(slot, home.position[0], home.position[1])\n },\n placeAtZone: (slot, zoneId) => {\n const carried = carriedRef.current\n const zone = zonesLive().find((z) => z.id === zoneId)\n const group = groupRefs.current[slot]\n if (!carried || carried.slot !== slot || !zone || !group) return\n group.position.x = zone.bounds.position[0]\n group.position.y = zone.bounds.position[1]\n carried.x.value = group.position.x\n carried.y.value = group.position.y\n settleInto(carried, zone)\n },\n cancel: (slot) => {\n const carried = carriedRef.current\n if (carried && carried.slot === slot && !carried.settling) returnHome(carried)\n },\n zoneIds: () => zonesLive().map((z) => z.id),\n slotState: (slot) => slotStates[slot] ?? 'rest',\n }\n useEffect(() => {\n const ref = props.a11yRef\n if (!ref) return\n ref.current = {\n pick: (slot) => a11yImplRef.current?.pick(slot) ?? false,\n placeAtZone: (slot, zoneId) => a11yImplRef.current?.placeAtZone(slot, zoneId),\n cancel: (slot) => a11yImplRef.current?.cancel(slot),\n zoneIds: () => a11yImplRef.current?.zoneIds() ?? [],\n slotState: (slot) => a11yImplRef.current?.slotState(slot) ?? 'rest',\n }\n return () => {\n ref.current = null\n }\n }, [props.a11yRef])\n\n return (\n <group>\n {sheetOptions?.backing && <BackingSheet options={sheetOptions} count={total} removed={removed} />}\n {(props.zones ?? []).map((zone) => (\n <DropZoneVisual key={zone.id} registry={registry} config={zone} />\n ))}\n {slotConfigs.map((config, i) => {\n const pose = poses[i]!\n return (\n <group\n // biome-ignore lint/suspicious/noArrayIndexKey: a slot IS its index — refs, poses, drags and drops all address a paper by slot number.\n key={i}\n ref={(g) => {\n groupRefs.current[i] = g\n }}\n position={pose.position}\n rotation={pose.rotation}\n scale={pose.scale}\n onPointerDown={(e: ThreeEvent<PointerEvent>) => {\n if (carriedRef.current) return\n const hit = planePoint(e.clientX, e.clientY, pose.position[2])\n if (!hit) return\n pressRef.current = { slot: i, pointerId: e.pointerId, startX: hit[0], startY: hit[1] }\n }}\n >\n <PaperMesh\n ref={(h) => {\n handleRefs.current[i] = h\n }}\n preset={config}\n reducedMotion={props.reducedMotion}\n onStateChange={(state) => onSlotState(i, state)}\n />\n </group>\n )\n })}\n </group>\n )\n}\n","import { useState } from 'react'\nimport { contentText } from '../a11y'\nimport { contentSchema } from '../config/schema'\nimport { resolveConfig } from '../PaperMesh'\nimport type { FieldA11yController } from './interactiveField'\nimport type { FieldPaperSlot } from './slots'\n\n/** Carry state of the hidden keyboard mirror: which paper is aloft, which zone is focused. */\nexport interface KeyboardCarry {\n slot: number\n zoneIndex: number\n}\n\n/** A keyboard step's decision: the next carry state and whether it consumed the key. */\nexport interface KeyboardStepResult {\n carry: KeyboardCarry | null\n handled: boolean\n}\n\n/**\n * The keyboard flow as a pure step (so it's testable without a DOM):\n * given the current carry state, the focused paper `slot`, and the pressed\n * `key`, it drives the field `controller` (pick → move between zones → place /\n * cancel) and returns the next carry state. All side effects go through\n * `controller`; the caller applies `carry` to its state and calls\n * `preventDefault()` when `handled` is true.\n */\nexport function fieldKeyboardStep(\n carry: KeyboardCarry | null,\n slot: number,\n key: string,\n controller: FieldA11yController,\n): KeyboardStepResult {\n if (!carry) {\n // Not carrying: Enter/Space on a focused paper picks it up.\n if (key === 'Enter' || key === ' ') {\n return { carry: controller.pick(slot) ? { slot, zoneIndex: 0 } : null, handled: true }\n }\n return { carry, handled: false }\n }\n // Carrying: only the paper actually aloft responds.\n if (carry.slot !== slot) return { carry, handled: false }\n const zoneCount = Math.max(controller.zoneIds().length, 1)\n if (key === 'ArrowRight' || key === 'ArrowDown') {\n return { carry: { ...carry, zoneIndex: (carry.zoneIndex + 1) % zoneCount }, handled: true }\n }\n if (key === 'ArrowLeft' || key === 'ArrowUp') {\n return {\n carry: { ...carry, zoneIndex: (carry.zoneIndex - 1 + zoneCount) % zoneCount },\n handled: true,\n }\n }\n if (key === 'Enter' || key === ' ') {\n const zone = controller.zoneIds()[carry.zoneIndex]\n if (zone) controller.placeAtZone(slot, zone)\n return { carry: null, handled: true }\n }\n if (key === 'Escape') {\n controller.cancel(slot)\n return { carry: null, handled: true }\n }\n return { carry, handled: false }\n}\n\nconst mirrorHidden: React.CSSProperties = {\n position: 'absolute',\n width: 1,\n height: 1,\n padding: 0,\n margin: -1,\n overflow: 'hidden',\n clip: 'rect(0 0 0 0)',\n whiteSpace: 'nowrap',\n border: 0,\n}\n\n/**\n * The hidden DOM mirror of an interactive field: each paper is a button.\n * Keyboard flow — focus a paper, Enter picks it, arrow keys move between\n * zones, Enter places, Escape returns it to its slot. The key\n * handling lives in the pure {@link fieldKeyboardStep} so it can be tested.\n */\nexport function FieldKeyboardMirror({\n papers,\n controller,\n}: {\n papers: FieldPaperSlot[]\n controller: React.MutableRefObject<FieldA11yController | null>\n}) {\n const [carrying, setCarrying] = useState<{ slot: number; zoneIndex: number } | null>(null)\n\n const paperLabel = (slot: FieldPaperSlot, i: number): string => {\n try {\n const config = resolveConfig({ preset: slot.preset })\n const content = slot.content ? contentSchema.parse(slot.content) : config.content\n return `Paper ${i + 1}: ${contentText({ ...config, content })}`\n } catch {\n return `Paper ${i + 1}`\n }\n }\n\n const onKeyDown = (i: number) => (e: React.KeyboardEvent) => {\n const ctl = controller.current\n if (!ctl) return\n const { carry, handled } = fieldKeyboardStep(carrying, i, e.key, ctl)\n if (handled) e.preventDefault()\n if (carry !== carrying) setCarrying(carry)\n }\n\n return (\n <fieldset style={mirrorHidden}>\n <legend>Interactive papers</legend>\n {papers.map((slot, i) => (\n <button\n // biome-ignore lint/suspicious/noArrayIndexKey: a slot IS its index — the carry state and every keyboard step address a paper by slot number.\n key={i}\n type=\"button\"\n onKeyDown={onKeyDown(i)}\n aria-label={paperLabel(slot, i)}\n aria-pressed={carrying?.slot === i}\n >\n {paperLabel(slot, i)}\n {carrying?.slot === i && (\n <span aria-live=\"polite\">\n {' '}\n — carrying; zone {controller.current?.zoneIds()[carrying.zoneIndex] ?? 'none'}; Enter places,\n Escape returns\n </span>\n )}\n </button>\n ))}\n </fieldset>\n )\n}\n","import type { AnyOptions, SheetDims } from '../deformers/types'\nimport type { Layout } from './layouts'\nimport { withSheetCellFromPaper, type SheetLayoutOptions } from './sheetGrid'\n\n/**\n * Framing a field is arithmetic, not guesswork: layouts are pure `pose`\n * functions, so we can just ask one where all its sheets are and put the\n * camera where they all fit. Community layouts get framed for free.\n */\n\nexport interface FieldBounds {\n center: [number, number, number]\n /** Half-extents — the box reaches `center ± half`. */\n half: [number, number, number]\n}\n\n/** Cyclic layouts sweep as `phase` advances; frame the whole cycle, not one instant. */\nconst PHASE_SAMPLES = 8\n\n/**\n * Resolve a layout's options the one way both the renderer and the camera\n * must agree on — sheet grids size their cells from the papers themselves.\n */\nexport function resolveLayoutOptions(\n layoutId: string,\n layout: Layout<AnyOptions>,\n propOptions: Record<string, unknown> | undefined,\n firstSheet: SheetDims | undefined,\n): Record<string, unknown> {\n const parsed = layout.optionsSchema.parse({\n ...layout.defaults,\n ...propOptions,\n }) as Record<string, unknown>\n if (layoutId !== 'sheet') return parsed\n return withSheetCellFromPaper(\n parsed as unknown as SheetLayoutOptions,\n propOptions,\n firstSheet,\n ) as unknown as Record<string, unknown>\n}\n\n/**\n * The box `n` sheets occupy under a layout. Each sheet is treated as a ball\n * of its half-diagonal, which covers every rotation the pose can apply\n * without having to build the pose matrices.\n */\nexport function fieldBounds(\n layout: Layout<AnyOptions>,\n n: number,\n options: unknown,\n sheet: SheetDims,\n): FieldBounds {\n const reach = Math.hypot(sheet.width, sheet.height) / 2\n if (n <= 0) return { center: [0, 0, 0], half: [reach, reach, 0] }\n\n const min = [Infinity, Infinity, Infinity]\n const max = [-Infinity, -Infinity, -Infinity]\n for (let s = 0; s < PHASE_SAMPLES; s++) {\n for (let i = 0; i < n; i++) {\n const pose = layout.pose(i, n, options, s / PHASE_SAMPLES, sheet)\n const r = reach * Math.max(pose.scale, 0)\n for (let axis = 0; axis < 3; axis++) {\n min[axis] = Math.min(min[axis]!, pose.position[axis]! - r)\n max[axis] = Math.max(max[axis]!, pose.position[axis]! + r)\n }\n }\n }\n return {\n center: [(min[0]! + max[0]!) / 2, (min[1]! + max[1]!) / 2, (min[2]! + max[2]!) / 2],\n half: [(max[0]! - min[0]!) / 2, (max[1]! - min[1]!) / 2, (max[2]! - min[2]!) / 2],\n }\n}\n\n/** The field has always been viewed from a shade above eye level — keep that. */\nconst LIFT = 0.11\nconst DEG = Math.PI / 180\n\n/**\n * Where to put a perspective camera so every sheet a layout poses lands in\n * frame. Solved per sheet at its own depth rather than against the field's\n * bounding box: a `ring`'s widest sheets sit at mid-depth, and pretending\n * that width exists at the near face would shove the camera far enough back\n * to lose the gallery entirely.\n */\nexport function fitCamera(\n layout: Layout<AnyOptions>,\n n: number,\n options: unknown,\n sheet: SheetDims,\n fovDeg: number,\n aspect: number,\n margin = 1.06,\n): { position: [number, number, number]; target: [number, number, number] } {\n const { center } = fieldBounds(layout, n, options, sheet)\n const reach = (Math.hypot(sheet.width, sheet.height) / 2) * margin\n const vTan = Math.tan((fovDeg * DEG) / 2)\n const hTan = vTan * Math.max(aspect, 0.01)\n\n let distance = 0.1\n for (let s = 0; s < PHASE_SAMPLES; s++) {\n for (let i = 0; i < Math.max(n, 0); i++) {\n const pose = layout.pose(i, n, options, s / PHASE_SAMPLES, sheet)\n const r = reach * Math.max(pose.scale, 0)\n // Depth of this sheet in front of the field's center — a sheet further\n // back needs correspondingly less distance to fit.\n const depth = pose.position[2]! - center[2]!\n distance = Math.max(\n distance,\n (Math.abs(pose.position[0]! - center[0]!) + r) / hTan + depth,\n (Math.abs(pose.position[1]! - center[1]!) + r) / vTan + depth,\n )\n }\n }\n return {\n position: [center[0], center[1] + distance * LIFT, center[2] + distance],\n target: center,\n }\n}\n","import {\n behaviorConfigSchema,\n clothConfigSchema,\n contentSchema,\n memorySchema,\n paperConfigSchema,\n sceneSchema,\n sheetSchema,\n type PaperConfig,\n type PaperConfigInput,\n} from './schema'\n\n/**\n * Presets are diffable: exports emit only non-default values, so a shared\n * `.paper` file or JSX snippet reads like intent, not like a database dump.\n */\n\nfunction isPlainObject(v: unknown): v is Record<string, unknown> {\n return typeof v === 'object' && v !== null && !Array.isArray(v)\n}\n\n/** Keys of `value` that differ from `defaults` (deep compare, shallow recurse). */\nfunction diffAgainst(\n value: Record<string, unknown>,\n defaults: Record<string, unknown>,\n keep: string[] = [],\n): Record<string, unknown> {\n const out: Record<string, unknown> = {}\n for (const [key, v] of Object.entries(value)) {\n if (keep.includes(key)) {\n out[key] = v\n continue\n }\n if (JSON.stringify(v) !== JSON.stringify(defaults[key])) {\n out[key] =\n isPlainObject(v) && isPlainObject(defaults[key])\n ? diffAgainst(v, defaults[key] as Record<string, unknown>)\n : v\n }\n }\n return out\n}\n\n/** The minimal PaperConfigInput that parses back to `config`. */\nexport function diffConfig(config: PaperConfig): PaperConfigInput {\n const base = paperConfigSchema.parse({})\n const out: Record<string, unknown> = {}\n\n const sheet = diffAgainst(config.sheet as never, sheetSchema.parse({}) as never)\n if (Object.keys(sheet).length > 0) out.sheet = sheet\n\n if (config.stock !== base.stock) out.stock = config.stock\n\n if (config.content.type !== 'blank') {\n // Defaults for this content type; required fields (image src) always kept.\n const defaults = contentSchema.parse(\n config.content.type === 'image'\n ? { type: 'image', src: config.content.src }\n : { type: config.content.type },\n ) as Record<string, unknown>\n out.content = {\n type: config.content.type,\n ...diffAgainst(config.content as never, defaults, config.content.type === 'image' ? ['src'] : []),\n }\n }\n\n if (config.behavior) {\n const defaults = behaviorConfigSchema.parse({ type: config.behavior.type }) as Record<string, unknown>\n out.behavior = { type: config.behavior.type, ...diffAgainst(config.behavior as never, defaults) }\n }\n if (config.deformers) out.deformers = config.deformers\n\n if (Object.keys(config.surface).length > 0) out.surface = config.surface\n\n // Diffed like the scene below, and for the same reason it is: `memory` is\n // going to grow fields, and a diff that names the ones it knows about\n // silently drops the next one. Without this a creased sheet exported to a\n // `.paper` file, a share link or a snippet came back flat — the editor\n // showed the creases and nothing that left the editor carried them.\n const memory = diffAgainst(config.memory as never, memorySchema.parse({}) as never)\n if (Object.keys(memory).length > 0) out.memory = memory\n\n if (typeof config.physics === 'object') {\n const defaults = clothConfigSchema.parse({ type: 'cloth' }) as Record<string, unknown>\n out.physics = { type: 'cloth', ...diffAgainst(config.physics as never, defaults) }\n } else if (config.physics !== 'none') {\n out.physics = config.physics\n }\n\n // The WHOLE scene, diffed like everything else. This used to read\n // `if (lighting !== 'studio') out.scene = { lighting }` — which was true\n // while `lighting` was the only thing in a scene, and quietly threw away\n // every field added beside it. A hand-tuned light rig and a backdrop both\n // vanished on the way into a `.paper` file, a share link and a snippet:\n // the editor showed them and nothing that left the editor carried them.\n const scene = diffAgainst(config.scene as never, sceneSchema.parse({}) as never)\n if (Object.keys(scene).length > 0) out.scene = scene\n if (config.onTwos) out.onTwos = true\n // States are already diffs on the base — emit them whole.\n if (config.states) out.states = config.states\n const meta = diffAgainst(config.meta as never, paperConfigSchema.parse({}).meta as never)\n if (Object.keys(meta).length > 0) out.meta = meta\n\n return out as PaperConfigInput\n}\n\n/** Render a value as compact JSX-attribute source. */\nfunction jsxValue(value: unknown): string {\n if (typeof value === 'string') return `\"${value}\"`\n return `{${JSON.stringify(value)}}`\n}\n\n/**\n * The same config with uploaded pictures swapped for paths.\n *\n * An uploaded image lives in a config as a data URL — a hundred kilobytes\n * and up of base64 — and there are now two places one can be: the sheet's\n * own content, and the backdrop behind it. Pasting that into somebody's\n * source file is not an export, and the reader cannot edit it, diff it, or\n * even scroll past it.\n *\n * So a code export gets a path in the same position instead, and says that\n * is what it did. A referenced URL is already something the receiver can\n * fetch and travels untouched. Emitting nothing was the other option and it\n * is worse: a sheet that silently loses its picture looks like a bug in the\n * library rather than a limit of the clipboard.\n *\n * The `.paper` file and the share link are deliberately NOT run through\n * this — a file has room for the bytes, and losing them there would lose\n * the artwork rather than reformat it.\n */\nexport function withoutUploads<T>(value: T): { value: T; replaced: number } {\n let replaced = 0\n const walk = (node: unknown): unknown => {\n if (typeof node === 'string') {\n if (!node.startsWith('data:')) return node\n replaced++\n const extension = node.startsWith('data:image/png') ? 'png' : 'jpg'\n return `/paperlab-image-${replaced}.${extension}`\n }\n if (Array.isArray(node)) return node.map(walk)\n if (node && typeof node === 'object') {\n return Object.fromEntries(Object.entries(node).map(([k, v]) => [k, walk(v)]))\n }\n return node\n }\n return { value: walk(value) as T, replaced }\n}\n\n/** The one-line warning a code export carries when it had to substitute. */\nexport const UPLOAD_NOTE =\n '// Uploaded pictures cannot travel in a snippet — the paths below are\\n// stand-ins, in order. Point them at your own files.'\n\n/**\n * A plain `<Paper />` snippet with only the non-default props — the\n * secondary export for people who read code.\n */\nexport function buildJsxSnippet(config: PaperConfig): string {\n const diffed = diffConfig(config) as Record<string, unknown>\n delete diffed.meta\n const { value: diff, replaced } = withoutUploads(diffed)\n const props = Object.entries(diff).map(([key, value]) => ` ${key}=${jsxValue(value)}`)\n if (props.length === 0) return '<Paper />'\n const snippet = `<Paper\\n${props.join('\\n')}\\n/>`\n return replaced > 0 ? `${UPLOAD_NOTE}\\n${snippet}` : snippet\n}\n","import type { PaperConfig } from './schema'\nimport { getStock } from '../core/stock'\nimport { UPLOAD_NOTE, diffConfig, withoutUploads } from './diff'\n\n/**\n * The primary export consumer is a coding agent; the human is the courier.\n * This template IS product surface: versioned, snapshot-tested, regenerated\n * from the config. Anatomy is fixed — install → inlined code → placement\n * contract → a verification step the agent can self-check → pre-empted\n * failure modes.\n */\n/**\n * v2: field exports (multi-preset galleries with inlined preset consts).\n * v3: interaction states, sheet/backing fields, drop zones, carry/flight.\n */\nexport const AGENT_PAYLOAD_VERSION = 3\n\nconst BEHAVIOR_PHRASES: Record<string, (o: Record<string, unknown>) => string> = {\n peel: (o) => `its ${String(o.corner ?? 'bottom-right').replace('-', ' ')} corner peeling up`,\n unroll: (o) =>\n (o.progress as number) < 0.35\n ? 'mostly wound into a roll at the bottom'\n : 'unrolling from a paper roll at the bottom',\n flip: () => 'mid page-turn',\n 'letter-fold': () => 'tri-folding like a letter',\n hang: () => 'hanging from its top edge, rippling',\n fly: () => 'arched and fluttering like it is airborne',\n fall: () => 'rippling with one corner lifted, like a dropped sheet',\n ribbon: (o) =>\n `hanging the full drop of the room and pooling on the floor, about ${Math.round((o as { pool: number }).pool * 100)}% of its length lying over`,\n settle: (o) =>\n (o as { relax: number }).relax > 0.7\n ? 'lying where it landed, flat but for one corner the stiffness kept'\n : 'just come to rest, still holding a little of the shape it fell in',\n carry: () => 'drooping from a pinched corner, fluttering as if being carried',\n flight: (o) =>\n o.path === 'loop' ? 'tumbling through a seamless airborne loop' : 'tumbling across the scene on the wind',\n crumple: (o) =>\n (o.progress as number) < 0.3\n ? 'lightly handled — a few soft creases across it'\n : (o.progress as number) < 0.7\n ? 'crushed into irregular creased facets, as if screwed up and flattened out again'\n : 'balled up in a fist',\n}\n\n/** One line an agent can verify against what it sees after `npm run dev`. */\nexport function describeConfig(config: PaperConfig): string {\n const stock = getStock(config.stock)\n const size = `${config.sheet.width}×${config.sheet.height}`\n\n let contentPhrase = 'a blank sheet'\n if (config.content.type === 'image') contentPhrase = 'a sheet printed with an image'\n if (config.content.type === 'text') contentPhrase = 'a sheet with typeset text'\n if (config.content.type === 'receipt') contentPhrase = `a store receipt for \"${config.content.store}\"`\n\n const parts = [`${contentPhrase} on ${stock.label.toLowerCase()} paper stock (${size})`]\n\n if (typeof config.physics === 'object') {\n const sim = config.physics\n parts.push(\n sim.type === 'strip'\n ? 'paying off a roll as the page scrolls, folding at its perforations into a pile on the floor'\n : sim.pins === 'none'\n ? 'falling and settling as cloth'\n : `pinned (${sim.pins}) and moving like cloth in wind`,\n )\n } else if (config.behavior) {\n const phrase = BEHAVIOR_PHRASES[config.behavior.type]\n if (phrase) parts.push(phrase(config.behavior as Record<string, unknown>))\n }\n\n if (config.surface.deckle) {\n parts.push(\n `torn (deckled) ${config.surface.deckle.edges.join(' and ')} edge${config.surface.deckle.edges.length > 1 ? 's' : ''}`,\n )\n }\n if ((config.surface.aging ?? 0) > 0.3) parts.push('visibly aged and yellowed')\n\n return parts.join(', ')\n}\n\nfunction componentName(config: PaperConfig): string {\n const raw = config.meta.name === 'untitled' ? 'PaperlabPaper' : config.meta.name\n const pascal = raw\n .replace(/[^a-zA-Z0-9]+(.)/g, (_, c: string) => c.toUpperCase())\n .replace(/^./, (c) => c.toUpperCase())\n .replace(/[^a-zA-Z0-9]/g, '')\n return /^[A-Za-z]/.test(pascal) ? pascal : `Paper${pascal}`\n}\n\n/** The self-contained integration brief — one paste into a coding agent. */\nexport function buildAgentPayload(config: PaperConfig): string {\n const name = componentName(config)\n // Uploaded pictures become paths: this payload is pasted into a coding\n // agent's context window, and a hundred kilobytes of base64 in there is\n // both useless and expensive.\n const { value: stripped, replaced } = withoutUploads(diffConfig(config))\n const preset = JSON.stringify(stripped, null, 2)\n const uploadNote = replaced > 0 ? `${UPLOAD_NOTE}\\n` : ''\n\n return `Integrate a Paperlab paper component into this project. (paperlab agent-payload v${AGENT_PAYLOAD_VERSION})\n\n1. Install the dependencies:\n\n npm i paperlab three @react-three/fiber gsap\n\n2. Create the component below as \\`components/${name}.tsx\\` (or the project's\n component convention). It is self-contained and owns its own <Canvas>:\n\n\\`\\`\\`tsx\nimport { Paper, type PaperConfigInput } from 'paperlab'\n\n${uploadNote}const preset = ${preset.replace(/\\n/g, '\\n')} satisfies PaperConfigInput\n\nexport function ${name}() {\n return <Paper preset={preset} />\n}\n\\`\\`\\`\n\n3. Sizing: the component fills its parent container. Place it where I ask;\n give the parent an explicit height.\n\n4. Verify: run the dev server. You should see ${describeConfig(config)}.\n If the canvas is blank, the parent container almost certainly has no height —\n give it one (this is the classic React Three Fiber integration bug, not a\n paperlab bug).\n\nConstraints: don't modify the preset values; three >= 0.160 and React 19 are\nrequired; the component needs no props.`\n}\n","import {\n sceneSchema,\n type ContentConfig,\n type PaperConfig,\n type PaperStatesInput,\n type SceneConfigInput,\n} from './schema'\nimport { diffConfig } from './diff'\nimport { AGENT_PAYLOAD_VERSION } from './agent-payload'\nimport { getLayout } from '../field/layouts'\n\n/**\n * Field-mode export. Every preset a field references is INLINED as a const —\n * receivers don't have the sender's local preset library. Same fixed payload\n * anatomy as the single-paper export, same version.\n */\n\nexport interface FieldExportPaper {\n /** Display name of the preset this slot uses (const naming + description). */\n presetName: string\n /** The RESOLVED preset config (user presets included — nothing to fetch). */\n preset: PaperConfig\n content?: ContentConfig\n /** Per-slot state overrides (slot 3's hover deeper than slot 4's). */\n states?: PaperStatesInput\n}\n\nexport interface FieldExportZone {\n id: string\n accept?: string[]\n bounds: { position: [number, number, number]; size: [number, number] }\n highlight?: 'none' | 'glow' | 'outline'\n}\n\nexport interface FieldExportInput {\n layout: string\n layoutOptions?: Record<string, unknown>\n motion?: { driver?: 'autoplay' | 'drag' | 'none'; speed?: number }\n entrance?: { type?: 'rise' | 'scatter' | 'none'; stagger?: number; duration?: number }\n papers: FieldExportPaper[]\n /** How the gallery is lit. Omitted means the schema's own default rig. */\n scene?: SceneConfigInput\n /** Drop zones — exported as `<DropZone>` children with an onPlace stub. */\n zones?: FieldExportZone[]\n}\n\nconst MOTION_DEFAULTS = { driver: 'autoplay', speed: 0.5 }\nconst ENTRANCE_DEFAULTS = { type: 'rise', stagger: 0.06, duration: 0.9 }\n\nfunction camel(name: string): string {\n const id = name.replace(/[^a-zA-Z0-9]+(.)/g, (_, c: string) => c.toUpperCase()).replace(/[^a-zA-Z0-9]/g, '')\n const safe = /^[A-Za-z]/.test(id) ? id : `preset${id}`\n return safe.charAt(0).toLowerCase() + safe.slice(1)\n}\n\ninterface DistinctPreset {\n varName: string\n presetName: string\n preset: PaperConfig\n}\n\n/** Distinct presets in slot order, with collision-safe const names. */\nexport function distinctFieldPresets(input: FieldExportInput): DistinctPreset[] {\n const byKey = new Map<string, DistinctPreset>()\n const usedNames = new Set<string>()\n for (const paper of input.papers) {\n const key = JSON.stringify(paper.preset)\n if (byKey.has(key)) continue\n let varName = camel(paper.presetName)\n while (usedNames.has(varName)) varName += '2'\n usedNames.add(varName)\n byKey.set(key, { varName, presetName: paper.presetName, preset: paper.preset })\n }\n return [...byKey.values()]\n}\n\n/**\n * The entries that differ from the defaults.\n *\n * Compared STRUCTURALLY rather than by reference. Most of what passes\n * through here is numbers and strings, where the two agree — but a layout\n * option holding an array, or a scene holding a nested rig, is never\n * reference-equal to the default it was copied from, so those exported a\n * prop that said exactly what the default already said.\n */\nfunction nonDefault<T extends Record<string, unknown>>(\n value: T | undefined,\n defaults: Record<string, unknown>,\n): Record<string, unknown> {\n const out: Record<string, unknown> = {}\n for (const [k, v] of Object.entries(value ?? {})) {\n if (v === undefined) continue\n const same = v === defaults[k] || JSON.stringify(v) === JSON.stringify(defaults[k])\n if (!same) out[k] = v\n }\n return out\n}\n\n/** The layout/motion/entrance props of the export, defaults stripped. */\nexport function diffFieldProps(input: FieldExportInput): Record<string, unknown> {\n const out: Record<string, unknown> = { layout: input.layout }\n const layout = getLayout(input.layout)\n const layoutOptions = nonDefault(input.layoutOptions ?? {}, layout.defaults as Record<string, unknown>)\n if (Object.keys(layoutOptions).length > 0) out.layoutOptions = layoutOptions\n const motion = nonDefault(input.motion, MOTION_DEFAULTS)\n if (Object.keys(motion).length > 0) out.motion = motion\n const entrance = nonDefault(input.entrance, ENTRANCE_DEFAULTS)\n if (Object.keys(entrance).length > 0) out.entrance = entrance\n // Resolved through the schema before comparing, so an input naming only\n // `lighting` is judged against a whole default rig rather than a\n // half-filled one.\n const scene = nonDefault(\n sceneSchema.parse(input.scene ?? {}) as unknown as Record<string, unknown>,\n sceneSchema.parse({}) as unknown as Record<string, unknown>,\n )\n if (Object.keys(scene).length > 0) out.scene = scene\n return out\n}\n\nconst LAYOUT_PHRASES: Record<string, string> = {\n ring: 'a ring you can see around',\n fan: 'a fanned swatch deck hinged at one corner',\n spread: 'a stack slid sideways, each sheet bowing further than the last',\n pile: 'a heap on a desk, the sheets underneath pressed flat',\n wall: 'a pinned studio wall of sheets, none hanging quite square',\n spill: 'a dropped stack caught mid-air, each sheet bent its own way',\n sweep: 'a specimen chart of one sheet at every stage of its deformation',\n book: 'an open book, its pages splayed from a shared spine',\n accordion: 'one continuous strip folded into a concertina',\n rack: 'prints stood in a row and leaning back against a wall',\n sheet: 'a stamp-block grid on a shared backing sheet',\n}\n\n/** The one-line visual an agent verifies after `npm run dev`. */\nexport function describeFieldConfig(input: FieldExportInput): string {\n const n = input.papers.length\n const stateful = input.papers.some((p) => p.preset.states || p.states)\n const zones = input.zones ?? []\n const parts: string[] = []\n\n if (input.layout === 'sheet') {\n const rows = Number(input.layoutOptions?.rows ?? 2)\n const columns = Number(input.layoutOptions?.columns ?? 5)\n parts.push(`a ${rows}×${columns} sheet of papers on a shared backing`)\n } else {\n const layoutPhrase = LAYOUT_PHRASES[input.layout] ?? `a ${input.layout} layout`\n parts.push(`${n} papers arranged in ${layoutPhrase}`)\n }\n\n const driver = input.motion?.driver ?? 'autoplay'\n if (stateful) {\n // Stateful fields render static and interactive — the motion driver is moot.\n parts.push('hovering peels/reacts per paper (interaction states)')\n if (zones.length > 0) {\n parts.push(\n `dragging one past its tear threshold detaches it to carry to the ${zones\n .map((z) => z.id)\n .join(' or ')} zone (release elsewhere flutters it back)`,\n )\n }\n } else {\n if (driver === 'autoplay') parts.push('slowly orbiting on their own')\n if (driver === 'drag') parts.push('draggable sideways with the pointer')\n if (zones.length > 0) parts.push(`${zones.length} drop zone${zones.length > 1 ? 's' : ''}`)\n }\n\n const distinct = distinctFieldPresets(input)\n if (distinct.length > 1) {\n parts.push(`mixing ${distinct.length} paper presets (${distinct.map((d) => d.presetName).join(', ')})`)\n }\n return parts.join(', ')\n}\n\n/** Component source shared by the JSX snippet and the agent payload. */\nexport function buildFieldComponentSource(input: FieldExportInput): string {\n const distinct = distinctFieldPresets(input)\n const varByKey = new Map(distinct.map((d) => [JSON.stringify(d.preset), d.varName]))\n\n // `satisfies` (not `as const`) — const-asserted arrays turn readonly and\n // stop matching the library's input types.\n const consts = distinct\n .map(\n (d) =>\n `const ${d.varName} = ${JSON.stringify(diffConfig(d.preset), null, 2)} satisfies PaperConfigInput`,\n )\n .join('\\n\\n')\n\n const slots = input.papers\n .map((paper) => {\n const varName = varByKey.get(JSON.stringify(paper.preset))!\n const content = paper.content ? `, content: ${JSON.stringify(paper.content)}` : ''\n const states = paper.states ? `, states: ${JSON.stringify(paper.states)}` : ''\n return ` { preset: ${varName}${content}${states} },`\n })\n .join('\\n')\n\n const props = Object.entries(diffFieldProps(input))\n .map(([key, value]) =>\n typeof value === 'string' ? ` ${key}=\"${value}\"` : ` ${key}={${JSON.stringify(value)}}`,\n )\n .join('\\n')\n\n const zones = input.zones ?? []\n const zoneImport = zones.length > 0 ? ', DropZone' : ''\n const zoneChildren = zones\n .map((zone) => {\n const accept = zone.accept ? ` accept={${JSON.stringify(zone.accept)}}` : ''\n const highlight = zone.highlight && zone.highlight !== 'glow' ? ` highlight=\"${zone.highlight}\"` : ''\n return ` <DropZone\n id=\"${zone.id}\"${accept}\n bounds={${JSON.stringify(zone.bounds)}}${highlight}\n onPlace={(paper, zone) => {\n // First-run smoke test — you should see this in the console on drop:\n console.log(paper.presetName, '→', zone.id)\n // Then replace it: stamp a postmark, advance the flow, persist the placement, …\n }}\n />`\n })\n .join('\\n')\n\n if (zones.length === 0) {\n return `import { PaperField, type FieldPaperSlot, type PaperConfigInput${zoneImport} } from 'paperlab'\n\n${consts}\n\nconst papers: FieldPaperSlot[] = [\n${slots}\n]\n\nexport function PaperGallery() {\n return (\n <PaperField\n papers={papers}\n${props}\n />\n )\n}`\n }\n\n return `import { PaperField, type FieldPaperSlot, type PaperConfigInput${zoneImport} } from 'paperlab'\n\n${consts}\n\nconst papers: FieldPaperSlot[] = [\n${slots}\n]\n\nexport function PaperGallery() {\n return (\n <PaperField\n papers={papers}\n${props}\n >\n${zoneChildren}\n </PaperField>\n )\n}`\n}\n\n/** The self-contained field integration brief — one paste into a coding agent. */\nexport function buildFieldAgentPayload(input: FieldExportInput): string {\n return `Integrate a Paperlab paper gallery into this project. (paperlab agent-payload v${AGENT_PAYLOAD_VERSION})\n\n1. Install the dependencies:\n\n npm i paperlab three @react-three/fiber gsap\n\n2. Create the component below as \\`components/PaperGallery.tsx\\` (or the\n project's component convention). It is self-contained — every preset it\n uses is inlined, and it owns its own <Canvas>:\n\n\\`\\`\\`tsx\n${buildFieldComponentSource(input)}\n\\`\\`\\`\n\n3. Sizing: the component fills its parent container. Place it where I ask;\n give the parent an explicit height.\n\n4. Verify: run the dev server. You should see ${describeFieldConfig(input)}.\n If the canvas is blank, the parent container almost certainly has no height —\n give it one (this is the classic React Three Fiber integration bug, not a\n paperlab bug).\n\nConstraints: don't modify the preset values; three >= 0.160 and React 19 are\nrequired; the component needs no props.`\n}\n","import * as THREE from 'three'\nimport type { DeformerInstance, SheetDims } from '../deformers/types'\nimport { displacePoint } from '../deformers/compose'\nimport { getDeformer } from '../deformers/registry'\nimport { buildDisplacementGLSL } from './compose'\n\n/**\n * Golden-vector parity: the JS (hero) and GLSL (field) implementations of a\n * deformer must produce identical displacements. This harness evaluates the\n * GLSL path on the real GPU — the stack's displacement functions run in a\n * fragment shader over an N×N grid, rendered to a float target and read\n * back — then epsilon-compares against the JS path. Browser-only (WebGL2);\n * driven by tools/parity.mjs in CI.\n */\n\nconst GRID = 48\n/** highp float + sin/cos implementation differences across GPUs. */\nexport const PARITY_EPSILON = 5e-4\n\nexport interface ParityCase {\n name: string\n stack: DeformerInstance[]\n sheet: SheetDims\n t: number\n}\n\nexport interface ParityResult {\n name: string\n maxError: number\n pass: boolean\n}\n\n/** One case per deformer feature worth guarding, both easy and adversarial. */\nexport const parityCases: ParityCase[] = [\n {\n name: 'roll: defaults',\n stack: [{ type: 'roll', options: { angle: 90, boundary: 0, radius: 0.12, thickness: 0.04 } }],\n sheet: { width: 1, height: 1.4 },\n t: 0,\n },\n {\n name: 'roll: tight receipt roll, rolling down',\n stack: [{ type: 'roll', options: { angle: 270, boundary: -0.4, radius: 0.07, thickness: 0.006 } }],\n sheet: { width: 1, height: 2.6 },\n t: 0,\n },\n {\n name: 'curl: bottom-right peel',\n stack: [{ type: 'curl', options: { corner: 'bottom-right', amount: 0.45, radius: 0.2, skew: 0 } }],\n sheet: { width: 1.5, height: 1 },\n t: 0,\n },\n {\n name: 'curl: skewed top-left',\n stack: [{ type: 'curl', options: { corner: 'top-left', amount: 0.7, radius: 0.3, skew: 15 } }],\n sheet: { width: 1, height: 1 },\n t: 0,\n },\n {\n name: 'bend: positive arc at an angle',\n stack: [{ type: 'bend', options: { curvature: 1.2, angle: 33 } }],\n sheet: { width: 1, height: 1.4 },\n t: 0,\n },\n {\n /**\n * The gentle end, which nothing used to cover: the gate only ever tried\n * |curvature| ≥ 0.6, and `photo-print` — the field starter preset — bends\n * at 0.35. That band is where the arc's float32 evaluation loses its\n * cancellation, and where the two paths were 6e-4 apart until `bend` was\n * rewritten in cancellation-free form. Keep a case down here.\n */\n name: 'bend: barely-there arc (the band photo-print lives in)',\n stack: [{ type: 'bend', options: { curvature: 0.35, angle: 0 } }],\n sheet: { width: 1.2, height: 0.9 },\n t: 0,\n },\n {\n name: 'bend: the gentlest arc the schema allows',\n stack: [{ type: 'bend', options: { curvature: 0.02, angle: 61 } }],\n sheet: { width: 2, height: 2.6 },\n t: 0,\n },\n {\n name: 'bend: negative arc',\n stack: [{ type: 'bend', options: { curvature: -0.8, angle: 0 } }],\n sheet: { width: 1, height: 1.4 },\n t: 0,\n },\n {\n name: 'fold: 90° hinge',\n stack: [{ type: 'fold', options: { angle: 90, offset: 0, foldAngle: 90, radius: 0.06 } }],\n sheet: { width: 1, height: 1.4 },\n t: 0,\n },\n {\n name: 'fold: deep fold, travelling down',\n stack: [{ type: 'fold', options: { angle: 270, offset: 0.2, foldAngle: 165, radius: 0.04 } }],\n sheet: { width: 1, height: 1.4 },\n t: 0,\n },\n {\n name: 'wave: free ripple at t=1.234',\n stack: [\n {\n type: 'wave',\n options: { amplitude: 0.05, wavelength: 0.5, speed: 1, angle: 20, pinnedEdge: 'none' },\n },\n ],\n sheet: { width: 1, height: 1 },\n t: 1.234,\n },\n {\n name: 'wave: pinned top at t=2.5',\n stack: [\n {\n type: 'wave',\n options: { amplitude: 0.04, wavelength: 0.4, speed: 1.5, angle: 80, pinnedEdge: 'top' },\n },\n ],\n sheet: { width: 1.2, height: 1.5 },\n t: 2.5,\n },\n {\n name: 'drape: banner hung from the top',\n stack: [\n {\n type: 'drape',\n options: { amplitude: 0.17, folds: 5, falloff: 1.6, irregular: 0.45, gather: 0.5, pinnedEdge: 'top' },\n },\n ],\n sheet: { width: 1.5, height: 8.5 },\n t: 0,\n },\n {\n name: 'drape: deep irregular folds pinned at the bottom',\n stack: [\n {\n type: 'drape',\n options: { amplitude: 0.55, folds: 11, falloff: 0.4, irregular: 1, gather: 1, pinnedEdge: 'bottom' },\n },\n ],\n sheet: { width: 2.2, height: 3 },\n t: 0,\n },\n {\n name: 'crumple: defaults',\n stack: [{ type: 'crumple', options: { amount: 0.35, scale: 3, pull: 0.4, seed: 0 } }],\n sheet: { width: 1, height: 1.4 },\n t: 0,\n },\n {\n // The adversarial one. `fract` is a sawtooth, so the two halves disagree\n // hardest where a crease lands exactly on a sample — a fine scale and a\n // seed whose fold directions are near-axis puts the most creases in\n // reach of the grid.\n name: 'crumple: fully crushed, fine creases, off-axis seed',\n stack: [{ type: 'crumple', options: { amount: 1, scale: 7.5, pull: 1, seed: 5 } }],\n sheet: { width: 1.3, height: 0.9 },\n t: 0,\n },\n {\n // Crush then curl, which is the order the crumple BEHAVIOR stacks them:\n // the creases have to be placed on the flat sheet, not on a bent one.\n name: 'stacked: crumple ∘ bend (the crumple behavior)',\n stack: [\n { type: 'crumple', options: { amount: 0.62, scale: 3.3, pull: 0.5, seed: 2 } },\n { type: 'bend', options: { curvature: 0.31, angle: 35 } },\n ],\n sheet: { width: 1.1, height: 1.4 },\n t: 0,\n },\n {\n name: 'stacked: letter-fold pair (fold ∘ fold)',\n stack: [\n { type: 'fold', options: { angle: 270, offset: 0.2333, foldAngle: 120, radius: 0.05 } },\n { type: 'fold', options: { angle: 90, offset: 0.2333, foldAngle: 100, radius: 0.08 } },\n ],\n sheet: { width: 1, height: 1.4 },\n t: 0,\n },\n {\n name: 'stacked: bend ∘ roll ∘ wave',\n stack: [\n { type: 'bend', options: { curvature: 0.6, angle: 0 } },\n { type: 'roll', options: { angle: 90, boundary: 0.1, radius: 0.15, thickness: 0 } },\n {\n type: 'wave',\n options: { amplitude: 0.02, wavelength: 0.6, speed: 0.7, angle: 45, pinnedEdge: 'none' },\n },\n ],\n sheet: { width: 1, height: 1.4 },\n t: 0.8,\n },\n]\n\nfunction buildParityFragment(stack: DeformerInstance[], sheet: SheetDims): string {\n const composed = buildDisplacementGLSL(stack, sheet)\n return /* glsl */ `#version 300 es\nprecision highp float;\nuniform float uPlTime;\nuniform float uPlBias;\n${composed.functionsSrc}\n${composed.displaceSrc}\nout vec4 outColor;\nvoid main() {\n vec2 uv = (gl_FragCoord.xy - 0.5) / float(${GRID - 1});\n vec3 p = vec3((uv - 0.5) * uSheet, 0.0);\n outColor = vec4(plDisplace(p, uv, uPlTime, uPlBias), 1.0);\n}\n`\n}\n\nconst VERT = `#version 300 es\nin vec2 aPos;\nvoid main() { gl_Position = vec4(aPos, 0.0, 1.0); }\n`\n\nfunction compile(gl: WebGL2RenderingContext, type: number, src: string): WebGLShader {\n const shader = gl.createShader(type)!\n gl.shaderSource(shader, src)\n gl.compileShader(shader)\n if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {\n throw new Error(`[paperlab parity] shader compile failed: ${gl.getShaderInfoLog(shader)}`)\n }\n return shader\n}\n\nfunction runCaseOnGPU(gl: WebGL2RenderingContext, c: ParityCase, bias = 1): Float32Array {\n const composed = buildDisplacementGLSL(c.stack, c.sheet)\n const program = gl.createProgram()!\n gl.attachShader(program, compile(gl, gl.VERTEX_SHADER, VERT))\n gl.attachShader(program, compile(gl, gl.FRAGMENT_SHADER, buildParityFragment(c.stack, c.sheet)))\n gl.linkProgram(program)\n if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {\n throw new Error(`[paperlab parity] link failed: ${gl.getProgramInfoLog(program)}`)\n }\n // biome-ignore lint/correctness/useHookAtTopLevel: WebGL's gl.useProgram, not a React hook\n gl.useProgram(program)\n\n for (const [name, value] of Object.entries(composed.uniforms)) {\n const loc = gl.getUniformLocation(program, name)\n if (!loc) continue\n if (typeof value === 'number') gl.uniform1f(loc, value)\n else if (value.length === 2) gl.uniform2f(loc, value[0]!, value[1]!)\n else if (value.length === 3) gl.uniform3f(loc, value[0]!, value[1]!, value[2]!)\n else gl.uniform4f(loc, value[0]!, value[1]!, value[2]!, value[3]!)\n }\n const timeLoc = gl.getUniformLocation(program, 'uPlTime')\n if (timeLoc) gl.uniform1f(timeLoc, c.t)\n const biasLoc = gl.getUniformLocation(program, 'uPlBias')\n if (biasLoc) gl.uniform1f(biasLoc, bias)\n\n const quad = gl.createBuffer()!\n gl.bindBuffer(gl.ARRAY_BUFFER, quad)\n gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 3, -1, -1, 3]), gl.STATIC_DRAW)\n const posLoc = gl.getAttribLocation(program, 'aPos')\n gl.enableVertexAttribArray(posLoc)\n gl.vertexAttribPointer(posLoc, 2, gl.FLOAT, false, 0, 0)\n\n const tex = gl.createTexture()!\n gl.bindTexture(gl.TEXTURE_2D, tex)\n gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA32F, GRID, GRID, 0, gl.RGBA, gl.FLOAT, null)\n const fbo = gl.createFramebuffer()!\n gl.bindFramebuffer(gl.FRAMEBUFFER, fbo)\n gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0)\n gl.viewport(0, 0, GRID, GRID)\n gl.drawArrays(gl.TRIANGLES, 0, 3)\n\n const out = new Float32Array(GRID * GRID * 4)\n gl.readPixels(0, 0, GRID, GRID, gl.RGBA, gl.FLOAT, out)\n gl.bindFramebuffer(gl.FRAMEBUFFER, null)\n return out\n}\n\n/**\n * The bias contract, checked on the GPU: a stack of strength-bearing\n * deformers must go completely flat at bias 0, and a stack of deformers that\n * opt out (roll) must ignore bias entirely. Parity alone can't catch this —\n * it only ever evaluates bias 1.\n */\nfunction runBiasCases(gl: WebGL2RenderingContext): ParityResult[] {\n const results: ParityResult[] = []\n for (const c of parityCases) {\n const strengths = c.stack.map((i) => getDeformer(i.type).glsl?.strength !== undefined)\n // Mixed stacks flatten only partway — nothing crisp to assert.\n if (!strengths.every((h) => h === strengths[0])) continue\n const scales = strengths[0]\n\n const at0 = runCaseOnGPU(gl, c, 0)\n const reference = scales ? null : runCaseOnGPU(gl, c, 1)\n let maxError = 0\n for (let row = 0; row < GRID; row++) {\n for (let col = 0; col < GRID; col++) {\n const i4 = (row * GRID + col) * 4\n // At bias 0 a scaling stack collapses onto the flat sheet; an opted-out\n // stack must land exactly where bias 1 put it.\n const ex = reference ? reference[i4]! : (col / (GRID - 1) - 0.5) * c.sheet.width\n const ey = reference ? reference[i4 + 1]! : (row / (GRID - 1) - 0.5) * c.sheet.height\n const ez = reference ? reference[i4 + 2]! : 0\n maxError = Math.max(\n maxError,\n Math.abs(at0[i4]! - ex),\n Math.abs(at0[i4 + 1]! - ey),\n Math.abs(at0[i4 + 2]! - ez),\n )\n }\n }\n results.push({\n name: `bias: ${c.name} → ${scales ? 'flat at 0' : 'ignores bias'}`,\n maxError,\n pass: maxError < PARITY_EPSILON,\n })\n }\n return results\n}\n\n/** Run every parity case. Requires a WebGL2 context with float render targets. */\nexport function runParityHarness(canvas?: HTMLCanvasElement): ParityResult[] {\n const cnv = canvas ?? document.createElement('canvas')\n const gl = cnv.getContext('webgl2')\n if (!gl) throw new Error('[paperlab parity] WebGL2 unavailable')\n if (!gl.getExtension('EXT_color_buffer_float')) {\n throw new Error('[paperlab parity] EXT_color_buffer_float unavailable')\n }\n\n const point = new THREE.Vector3()\n const parity = parityCases.map((c) => {\n const gpu = runCaseOnGPU(gl, c)\n let maxError = 0\n for (let row = 0; row < GRID; row++) {\n for (let col = 0; col < GRID; col++) {\n const u = col / (GRID - 1)\n const v = row / (GRID - 1)\n point.set((u - 0.5) * c.sheet.width, (v - 0.5) * c.sheet.height, 0)\n displacePoint(point, u, v, c.stack, { t: c.t, sheet: c.sheet })\n const i4 = (row * GRID + col) * 4\n maxError = Math.max(\n maxError,\n Math.abs(gpu[i4]! - point.x),\n Math.abs(gpu[i4 + 1]! - point.y),\n Math.abs(gpu[i4 + 2]! - point.z),\n )\n }\n }\n return { name: c.name, maxError, pass: maxError < PARITY_EPSILON }\n })\n return [...parity, ...runBiasCases(gl)]\n}\n"],"mappings":"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AA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAyKhC,IAAM;AAAA;AAAA,EAAgC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA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","names":["import_fiber","import_react","THREE","import_gsap","import_fiber","import_react","import_zod","b","p","import_zod","sheet","k","sheet","e","c","sheet","import_zod","import_zod","DEG","k","sheet","r","sheet","v","p","import_zod","sheet","x","import_zod","sheet","import_zod","import_zod","import_zod","import_zod","import_zod","x","v","r","import_zod","import_zod","import_zod","sheet","l","b","c","x","y","z","b","sheet","v","b","c","THREE","import_react","v","w","pad","y","b","module","x","w","pad","x","y","r","x","y","w","sheet","w","pad","x","y","THREE","import_zod","import_zod","DEG","x","x2","sheet","r","import_zod","DEG","sheet","import_zod","DEG","TAU","sheet","import_zod","TAU","sheet","fold","import_zod","x","y","k","v","sheet","x","y","b","c","sheet","registry","b","r","c","b","k","x","y","z","p","gust","bend","p","r","c","j","j3","b","v","k","x","y","FIXED_DT","SOLVER_ITERATIONS","SLEEP_EPSILON","SLEEP_FRAMES","LOOSE","TIGHT","layerThickness","p","k","r","y","z","b","c","e","j","v","THREE","import_react","import_fiber","defaultCsmDefinitions","defaultCsmMainDefinitions","defaultVertDefinitions","defaultVertMain","defaultFragDefinitions","defaultFragMain","keywordMap","availabilityMap","defaultPatchMap","requiredPropsMap","sdbm","string","hash","i","h","isConstructor","f","err","stripComments","str","CustomShaderMaterial","baseMaterial","vertexShader","fragmentShader","uniforms","patchMap","cacheKey","opts","base","isEmptyOpts","extendedBase","mergedUniforms","gettersAndSetters","key","descriptor","value","_fs","_vs","self","prop","matchKeywords","keyword","matchKeyword","prevOnBeforeCompile","extendShader","prevShader","newShader","isFrag","mainBody","beforeMain","mainStartIndex","braceCount","mainEndIndex","fullMain","lastMainEndIndex","toAppend","regex","shader","renderer","userPatchMap","type","typeDefine","runPatchMap","_patchMap","doesIncludeInVert","availableIn","toReplace","replaceWith","prevCacheKey","useDidUpdateEffect","fn","inputs","didMountRef","React","CustomShaderMaterial","baseMaterial","vertexShader","fragmentShader","uniforms","cacheKey","patchMap","attach","opts","ref","material","CustomShaderMaterialImpl","jsx","index","THREE","THREE","DEG","x","y","z","x","y","z","sheet","e","c","import_react","import_jsx_runtime","THREE","import_react","import_jsx_runtime","sheet","v","x","d","j","import_react","import_jsx_runtime","p","import_react","v","c","import_jsx_runtime","PaperMesh","c","probe","p","x","y","v","e","z","b","THREE","import_react","import_fiber","THREE","x","y","import_jsx_runtime","mulberry32","y","x","r","p","THREE","import_react","import_fiber","w","import_fiber","import_react","import_jsx_runtime","Paper","THREE","import_gsap","import_fiber","import_react","THREE","import_react","import_jsx_runtime","x","y","registry","w","import_zod","THREE","import_gsap","import_fiber","import_react","THREE","import_react","sheet","x","y","sheet","c","import_zod","import_zod","b","k","p","TAU","DEG","jitter","sheet","sweep","k","x","y","registry","import_jsx_runtime","PROGRESS_SAMPLES","p","x","y","j","b","THREE","import_react","x","y","c","r","w","import_jsx_runtime","c","b","THREE","import_gsap","import_fiber","import_react","import_jsx_runtime","registry","e","hit","z","import_react","import_jsx_runtime","carry","e","sheet","r","DEG","import_jsx_runtime","PaperFieldMesh","e","sheet","PaperField","registry","v","sheet","k","c","c","k","v","same","p","z","THREE","sheet","c","v"]}
|