bravais 0.1.4 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"bravais.js","names":["source","vestaCutoffs","UP","elementColors","CifSyntaxError","line","message","isWhitespace","char","classify","lower","word","tokenizeCif","tokens","lines","text","index","lineNumber","content","closed","candidate","position","end","next","after","tagList","tags","CifBlock","name","tag","value","loop","entry","loopColumn","column","row","isCifPlaceholder","parseCifNumber","isLoopTerminator","token","parseCif","blocks","block","saveFrameDepth","requireBlock","target","values","rows","start","ELEMENT_SYMBOLS","ELEMENTS","isElementSymbol","symbol","capitalize","elementFromCifSymbol","letters","raw","two","one","chemicalElement","EQUIVALENT_TOLERANCE","NEAR_ONE","wrap","wrapped","nearOne","wrapVector","fractional","samePosition","axis","delta","p","q","tolerance","BUCKETS","bucketOf","bucketKey","x","y","z","PositionIndex","key","bucket","found","dx","bx","dy","by","dz","bz","left","right","applyOperation","r","operation","t","DEGREES","clamp","max","min","latticeFromParameters","parameters","alpha","beta","gamma","cosAlpha","cosBeta","cosGamma","sinAlpha","sinBeta","gammaStar","vectorA","a","vectorB","b","vectorC","c","latticeFromVectors","vectors","length","v","angle","u","fractionalToCartesian","va","vb","vc","lattice","distance","CifStructureError","AXES","parseCoefficient","fraction","parseSymmetryOperator","components","part","rotation","translation","component","terms","shift","term","coefficient","SITE_MERGE_TOLERANCE","OPERATOR_TAGS","SPACE_GROUP_NUMBER_TAGS","HERMANN_MAUGUIN_TAGS","HALL_TAGS","requireNumber","mergeSpecies","existing","species","element","occupancy","scaleOverfullSites","site","sites","total","sum","readSites","xs","ys","zs","labels","typeSymbols","occupancies","positions","label","typeSymbol","shared","readOperations","single","operations","readSpaceGroup","numberText","number","hallSymbol","isStructureBlock","parseCifStructure","listingClosure","preExpanded","hits","hit","self","IDENTITY_OPERATION","bindings","loading","loadMoyo","module","error","moyo","SpaceGroupLookupError","hallEntries","ensureMoyo","fromMoyoOperation","allHallEntries","normalizeSymbol","splitHermannMauguin","trimmed","colon","trailing","preferStandard","first","entries","standard","entriesForSymbol","info","wanted","byHall","bySymbol","base","setting","bySetting","describe","operationSettings","operations_from_number","operationsForSpaceGroup","SAME_LENGTH","SAME_ANGLE","misfit","assertFits","closure","axesOfCell","sameLength","sameAngle","resolveOperations","parsed","spaceGroup","settings","only","closures","fitting","axes","expandStructure","kept","structure","DEFAULT_SYMPREC","SymmetryAnalysisError","labelSpecies","labelByKey","speciesByLabel","standardStructure","basis","dataset","counts","count","symmetryDataset","expanded","cell","analyze_cell","options","hall_symbol_entry","type","space_group_type","SUBSCRIPT_DIGITS","COMBINING_OVERLINE","subscript","digit","typesetSymbol","body","suffix","order","match","CUTOFFS","SHORTEST_BOND","bondCutoff","elementA","elementB","findBonds","kinds","kindOf","atoms","kind","atom","elements","cutoffs","longest","cutoff","second","cubes","low","high","cube","ny","nz","cubeKey","grid","bonds","other","BOUNDARY_TOLERANCE","periodicAtoms","includeImages","boundaryAxes","subsetCount","subset","image","bit","structureElements","buildScene","majority","_changeEvent","_startEvent","_endEvent","_EPS","_STATE","_v2","Vector2","_mouseChange","_objectUp","Vector3","_pan","_axis","_quaternion","Quaternion","_eyeDirection","_objectUpDirection","_objectSidewaysDirection","_moveDirection","TrackballControls","Controls","object","domElement","MOUSE","onPointerMove","onPointerDown","onPointerUp","onPointerCancel","onContextMenu","onMouseWheel","onKeyDown","onKeyUp","onTouchStart","onTouchMove","onTouchEnd","onMouseDown","onMouseMove","onMouseUp","box","d","positionChanged","rollChanged","zoomChanged","scale_x","scale_y","pointerIds","positionFirst","positionSecond","rollAngle","factor","MathUtils","pageX","pageY","event","i","pointer","mouseAction","state","NAUMANN_HORIZONTAL_RATIO","NAUMANN_VERTICAL_RATIO","PROJECTED_FIT_PADDING_RATIO","EPSILON","CAMERA_FORWARD","CAMERA_UP","projectPerpendicular","projected","vector","stablePerpendicular","standardViewVectors","vertical","basalReference","basalRight","outward","cameraDistance","span","standardQuaternion","up","correctedUp","Matrix4","standardView","quaternionTuple","applyViewState","quaternion","view","forward","camera","projectedSize","minX","maxX","minY","maxY","bounds","corner","px","py","fitZoom","availableLength","width","height","projectedLength","applyPixelFrustum","METALNESS","ROUGHNESS","AMBIENT_LIGHT_INTENSITY","HEADLIGHT_INTENSITY","HEADLIGHT_OFFSET","BACKGROUND_COLOR","CELL_FRAME_COLOR","VACANCY_COLOR","VACANCY_OPACITY","TWO_PI","patchShader","patches","include","code","source","shader","atomVertexShader","atomFragmentShader","createAtomMaterial","transparent","opacity","hasVacancies","material","MeshStandardMaterial","sectorTexture","bondVertexShader","bondFragmentShader","createBondMaterial","capRadius","createCellFrameMaterial","LineBasicMaterial","createGizmoMaterial","DoubleSide","AlwaysStencilFunc","ReplaceStencilOp","AXIS_COLORS","SHAFT_LENGTH","SHAFT_RADIUS","CONE_LENGTH","CONE_RADIUS","ORIGIN_RADIUS","LABEL_DISTANCE","LABEL_SCALE","LABEL_TEXTURE_SIZE","LABEL_COLOR","LABEL_COLOR_OVER_AXES","VIEW_EXTENT","UP$1","labelTexture","canvas","context","fontSize","fontFamily","texture","CanvasTexture","SRGBColorSpace","LinearFilter","LinearMipmapLinearFilter","createAxisArrow","arrow","Group","color","shaft","Mesh","CylinderGeometry","cone","ConeGeometry","passes","NotEqualStencilFunc","EqualStencilFunc","labelColor","stencilFunc","labelSprite","Sprite","SpriteMaterial","AxesGizmo","Scene","OrthographicCamera","DirectionalLight","AmbientLight","origin","SphereGeometry","cameraQuaternion","half","previousAutoClear","renderer","size","element_colors_default","\"H\"","\"D\"","\"He\"","\"Li\"","\"Be\"","\"B\"","\"C\"","\"N\"","\"O\"","\"F\"","\"Ne\"","\"Na\"","\"Mg\"","\"Al\"","\"Si\"","\"P\"","\"S\"","\"Cl\"","\"Ar\"","\"K\"","\"Ca\"","\"Sc\"","\"Ti\"","\"V\"","\"Cr\"","\"Mn\"","\"Fe\"","\"Co\"","\"Ni\"","\"Cu\"","\"Zn\"","\"Ga\"","\"Ge\"","\"As\"","\"Se\"","\"Br\"","\"Kr\"","\"Rb\"","\"Sr\"","\"Y\"","\"Zr\"","\"Nb\"","\"Mo\"","\"Tc\"","\"Ru\"","\"Rh\"","\"Pd\"","\"Ag\"","\"Cd\"","\"In\"","\"Sn\"","\"Sb\"","\"Te\"","\"I\"","\"Xe\"","\"Cs\"","\"Ba\"","\"La\"","\"Ce\"","\"Pr\"","\"Nd\"","\"Pm\"","\"Sm\"","\"Eu\"","\"Gd\"","\"Tb\"","\"Dy\"","\"Ho\"","\"Er\"","\"Tm\"","\"Yb\"","\"Lu\"","\"Hf\"","\"Ta\"","\"W\"","\"Re\"","\"Os\"","\"Ir\"","\"Pt\"","\"Au\"","\"Hg\"","\"Tl\"","\"Pb\"","\"Bi\"","\"Po\"","\"At\"","\"Rn\"","\"Fr\"","\"Ra\"","\"Ac\"","\"Th\"","\"Pa\"","\"U\"","\"Np\"","\"Pu\"","\"Am\"","\"XX\"","srgbToLinear","channel","linearToSrgb","hexToOklab","hex","g","l","m","oklabToLinearRgb","lab","s","isInGamut","oklabToHex","srgb","oklabToOklch","C","h","oklchToOklab","radians","lch","clampChromaToGamut","step","middle","BASE_COLORS","ANCHOR_REFINEMENTS","PRIORITY","PRIORITY_RANK","MIN_DISTANCE","LIGHTNESS_WEIGHT","BAND","GREY_CHROMA","TINT_CHROMA","TINT_DARKENING","HUE_OFFSETS","LIGHTNESS_OFFSETS","VIVIDNESS_OFFSETS","TINT_HUES","HUE_STEP","LIGHTNESS_STEP","VIVIDNESS_STEP","BRIGHTENING_PENALTY","TINT_COST","weightedDistance","dL","hashString","hash","anchorHex","anchorColor","atomicNumber","priorityRank","listed","withinBand","maxChroma","banded","candidatesAround","candidates","anchor","lightnessOffset","lightnessCost","hue","vividness","hueOffset","vividnessOffset","L","cost","assigned","choose","taken","assignment","separationFrom","minimum","anchorLab","best","bestSeparation","bestCost","fallback","fallbackSeparation","separation","chosen","ensureElementColors","newcomers","elementColor","elementColorAssignments","resetElementColors","STYLE_ID","STYLES","ensureViewerStyles","root","style","swatchBackground","ElementLegend","item","swatch","ATOM_RADIUS","BOND_RADIUS","CAP_RADIUS","BOND_START","UP","cellCorners","cellCenter","CELL_EDGES","createCellFrame","corners","from","to","geometry","BufferGeometry","Float32BufferAttribute","LineSegments","createSectorTexture","data","vacancy","Color","offset","written","cumulative","DataTexture","RGBAFormat","FloatType","NearestFilter","colorLookup","colors","createAtoms","PlaneGeometry","sectors","mesh","InstancedMesh","matrix","colorOf","createBonds","scene","BoxGeometry","placeholder","Object3D","direction","startAtom","bond","endAtom","halves","slot","createSceneModel","layers","layer","center","group","Box3","disposables","extent","frame","createStage","WebGLRenderer","ACESFilmicToneMapping","headlight","lightDistance","FOG_AMOUNT","FOG_START","FOG_FRONT_PADDING_RATIO","ROTATE_SPEED","ZOOM_SPEED","DAMPING","REFERENCE_WIDTH_PX","MIN_SCALE","MAX_SCALE","IDLE_FRAMES","MOTION_EPSILON","NOTIFY_EVERY_FRAMES","GIZMO_SIDE_RATIO","GIZMO_MIN_PX","GIZMO_MAX_PX","depthFog","front","back","model","depth","backOffset","frontOffset","frontPadding","firstStart","near","far","Fog","createViewer","container","legend","gizmo","controls","fitted","loopActive","idleFrames","dragging","framesSinceNotify","notifyPending","canvasSize","lastQuaternion","lastZoom","lastTarget","listeners","notify","listener","render","updateHeadlight","measure","rect","refit","cameraMoved","moved","tick","wake","stopLoop","resize","scale","observer","applyView","viewer","createThumbnailRenderer","cache","modelFor","cached","pose","readCif","document"],"sources":["../src/cif/tokenizer.ts","../src/cif/parser.ts","../src/structure/elements.ts","../src/structure/fractional.ts","../src/structure/lattice.ts","../src/cif/errors.ts","../src/cif/symmetry-operators.ts","../src/cif/structure.ts","../src/structure/closure.ts","../src/structure/types.ts","../src/symmetry/moyo-loader.ts","../src/symmetry/moyo.ts","../src/symmetry/resolve.ts","../src/structure/expand.ts","../src/symmetry/dataset.ts","../src/symmetry/symbol.ts","../src/data/vesta-cutoffs.json","../src/structure/bonds.ts","../src/structure/images.ts","../src/scene/build.ts","../node_modules/three/examples/jsm/controls/TrackballControls.js","../src/render/camera.ts","../src/render/materials.ts","../src/render/gizmo.ts","../src/data/element-colors.json","../src/render/oklab.ts","../src/render/palette.ts","../src/render/legend.ts","../src/render/model.ts","../src/render/stage.ts","../src/render/viewer.ts","../src/render/thumbnails.ts","../src/index.ts"],"sourcesContent":["export type CifTokenKind = \"tag\" | \"value\" | \"loop\" | \"data\" | \"save\" | \"stop\";\n\nexport interface CifToken {\n kind: CifTokenKind;\n text: string;\n line: number;\n}\n\n/** The text is not CIF the tokenizer and parser accept. */\nexport class CifSyntaxError extends Error {\n /** 1-based line of the problem. */\n readonly line: number;\n\n constructor(message: string, line: number) {\n super(`CIF line ${line}: ${message}`);\n this.name = \"CifSyntaxError\";\n this.line = line;\n }\n}\n\nfunction isWhitespace(char: string): boolean {\n return char === \" \" || char === \"\\t\" || char === \"\\r\" || char === \"\\n\";\n}\n\nfunction classify(word: string, line: number): CifToken {\n const lower = word.toLowerCase();\n if (word.startsWith(\"_\")) {\n return { kind: \"tag\", text: word, line };\n }\n if (lower.startsWith(\"data_\")) {\n return { kind: \"data\", text: word.slice(5), line };\n }\n if (lower === \"loop_\") {\n return { kind: \"loop\", text: word, line };\n }\n if (lower.startsWith(\"save_\")) {\n return { kind: \"save\", text: word.slice(5), line };\n }\n if (lower === \"stop_\") {\n return { kind: \"stop\", text: word, line };\n }\n return { kind: \"value\", text: word, line };\n}\n\n/**\n * Split CIF 1.1 text into tokens. Comments are dropped; quoted strings and\n * semicolon text fields become single value tokens holding their content.\n */\nexport function tokenizeCif(text: string): CifToken[] {\n const tokens: CifToken[] = [];\n const lines = text.split(/\\r\\n|\\r|\\n/);\n let index = 0;\n\n while (index < lines.length) {\n const line = lines[index] ?? \"\";\n const lineNumber = index + 1;\n\n // AMCSD and RRUFF files close with a bare END line.\n if (line.trim().toUpperCase() === \"END\") {\n break;\n }\n\n if (line.startsWith(\";\")) {\n // A text field runs from this line to the next line starting with \";\".\n const content = [line.slice(1)];\n index += 1;\n let closed = false;\n while (index < lines.length) {\n const candidate = lines[index] ?? \"\";\n if (candidate.startsWith(\";\")) {\n closed = true;\n break;\n }\n content.push(candidate);\n index += 1;\n }\n if (!closed) {\n throw new CifSyntaxError(\"unterminated text field\", lineNumber);\n }\n tokens.push({\n kind: \"value\",\n text: content.join(\"\\n\"),\n line: lineNumber,\n });\n // The closing \";\" may be followed by more tokens on the same line.\n lines[index] = \" \" + (lines[index] ?? \"\").slice(1);\n continue;\n }\n\n let position = 0;\n while (position < line.length) {\n const char = line.charAt(position);\n if (isWhitespace(char)) {\n position += 1;\n continue;\n }\n if (char === \"#\") {\n break;\n }\n if (char === \"'\" || char === '\"') {\n // The string ends at a matching quote followed by whitespace or the\n // end of the line (CIF 1.1), so an apostrophe inside stays.\n let end = position + 1;\n while (end < line.length) {\n const next = line.indexOf(char, end);\n if (next === -1) {\n throw new CifSyntaxError(\"unterminated quoted string\", lineNumber);\n }\n const after = line.charAt(next + 1);\n if (next + 1 >= line.length || isWhitespace(after)) {\n end = next;\n break;\n }\n end = next + 1;\n }\n if (end >= line.length) {\n throw new CifSyntaxError(\"unterminated quoted string\", lineNumber);\n }\n tokens.push({\n kind: \"value\",\n text: line.slice(position + 1, end),\n line: lineNumber,\n });\n position = end + 1;\n continue;\n }\n let end = position;\n while (end < line.length && !isWhitespace(line.charAt(end))) {\n end += 1;\n }\n tokens.push(classify(line.slice(position, end), lineNumber));\n position = end;\n }\n index += 1;\n }\n\n return tokens;\n}\n","import { CifSyntaxError, tokenizeCif, type CifToken } from \"./tokenizer.js\";\n\nexport interface CifLoop {\n /** Lowercase tags, in column order. */\n tags: string[];\n /** One array of values per row, in `tags` order. */\n rows: string[][];\n}\n\n/** `tags` as a list: a single tag, or several aliases tried in order. */\nfunction tagList(tags: string | string[]): string[] {\n return typeof tags === \"string\" ? [tags] : tags;\n}\n\n/** One `data_` block: single-value items and loops. Tags are matched case-insensitively. */\nexport class CifBlock {\n readonly name: string;\n readonly items = new Map<string, string>();\n readonly loops: CifLoop[] = [];\n\n constructor(name: string) {\n this.name = name;\n }\n\n /** Raw value of the first present single-value item among `tags`, or null. */\n get(tags: string | string[]): string | null {\n for (const tag of tagList(tags)) {\n const value = this.items.get(tag.toLowerCase());\n if (value !== undefined) {\n return value;\n }\n }\n return null;\n }\n\n /** The first loop holding any of `tags`, or null. */\n findLoop(tags: string | string[]): CifLoop | null {\n for (const tag of tagList(tags)) {\n const lower = tag.toLowerCase();\n const loop = this.loops.find((entry) => entry.tags.includes(lower));\n if (loop) {\n return loop;\n }\n }\n return null;\n }\n}\n\n/** The data blocks of a CIF, in file order. */\nexport interface CifDocument {\n blocks: CifBlock[];\n}\n\n/** Column values of the first of `tags` present in `loop`, or null when none is. */\nexport function loopColumn(\n loop: CifLoop,\n tags: string | string[],\n): string[] | null {\n for (const tag of tagList(tags)) {\n const column = loop.tags.indexOf(tag.toLowerCase());\n if (column !== -1) {\n return loop.rows.map((row) => row[column] ?? \"?\");\n }\n }\n return null;\n}\n\n/** True for the CIF placeholders `?` (unknown) and `.` (inapplicable). */\nexport function isCifPlaceholder(value: string): boolean {\n return value === \"?\" || value === \".\";\n}\n\n/**\n * Parse a CIF number such as `0.012(1)`, dropping the standard uncertainty.\n * Placeholders and non-numbers give null.\n */\nexport function parseCifNumber(\n value: string | null | undefined,\n): number | null {\n if (value === null || value === undefined || isCifPlaceholder(value)) {\n return null;\n }\n const text = value.replace(/\\(\\d+\\)$/, \"\").trim();\n if (!/^[+-]?(\\d+\\.?\\d*|\\.\\d+)([eE][+-]?\\d+)?$/.test(text)) {\n return null;\n }\n return Number(text);\n}\n\nfunction isLoopTerminator(token: CifToken | undefined): boolean {\n return token === undefined || token.kind !== \"value\";\n}\n\n/** Parse CIF text into its data blocks. Save frames (dictionary files) are skipped. */\nexport function parseCif(text: string): CifDocument {\n const tokens = tokenizeCif(text);\n const blocks: CifBlock[] = [];\n let block: CifBlock | null = null;\n let index = 0;\n let saveFrameDepth = 0;\n\n const requireBlock = (token: CifToken): CifBlock => {\n if (!block) {\n // Items before any data_ heading belong to an unnamed block.\n block = new CifBlock(\"\");\n blocks.push(block);\n }\n if (saveFrameDepth > 0) {\n throw new CifSyntaxError(\n `unexpected ${token.kind} inside a save frame`,\n token.line,\n );\n }\n return block;\n };\n\n while (index < tokens.length) {\n const token = tokens[index];\n if (!token) {\n break;\n }\n switch (token.kind) {\n case \"data\": {\n block = new CifBlock(token.text);\n blocks.push(block);\n saveFrameDepth = 0;\n index += 1;\n break;\n }\n case \"save\": {\n saveFrameDepth =\n token.text === \"\"\n ? Math.max(0, saveFrameDepth - 1)\n : saveFrameDepth + 1;\n index += 1;\n break;\n }\n case \"stop\": {\n index += 1;\n break;\n }\n case \"tag\": {\n if (saveFrameDepth > 0) {\n index += 2;\n break;\n }\n const target = requireBlock(token);\n const value = tokens[index + 1];\n if (!value || value.kind !== \"value\") {\n throw new CifSyntaxError(\n `tag ${token.text} has no value`,\n token.line,\n );\n }\n target.items.set(token.text.toLowerCase(), value.text);\n index += 2;\n break;\n }\n case \"loop\": {\n const tags: string[] = [];\n index += 1;\n while (tokens[index]?.kind === \"tag\") {\n tags.push((tokens[index] as CifToken).text.toLowerCase());\n index += 1;\n }\n if (tags.length === 0) {\n throw new CifSyntaxError(\"loop_ without tags\", token.line);\n }\n const values: string[] = [];\n while (!isLoopTerminator(tokens[index])) {\n values.push((tokens[index] as CifToken).text);\n index += 1;\n }\n if (saveFrameDepth > 0) {\n break;\n }\n if (values.length % tags.length !== 0) {\n throw new CifSyntaxError(\n `loop with ${tags.length} tags has ${values.length} values`,\n token.line,\n );\n }\n const rows: string[][] = [];\n for (let start = 0; start < values.length; start += tags.length) {\n rows.push(values.slice(start, start + tags.length));\n }\n requireBlock(token).loops.push({ tags, rows });\n break;\n }\n case \"value\": {\n throw new CifSyntaxError(\n `unexpected value ${JSON.stringify(token.text)}`,\n token.line,\n );\n }\n }\n }\n\n return { blocks };\n}\n","/** Element symbols in atomic-number order. */\nexport const ELEMENT_SYMBOLS = [\n \"H\",\n \"He\",\n \"Li\",\n \"Be\",\n \"B\",\n \"C\",\n \"N\",\n \"O\",\n \"F\",\n \"Ne\",\n \"Na\",\n \"Mg\",\n \"Al\",\n \"Si\",\n \"P\",\n \"S\",\n \"Cl\",\n \"Ar\",\n \"K\",\n \"Ca\",\n \"Sc\",\n \"Ti\",\n \"V\",\n \"Cr\",\n \"Mn\",\n \"Fe\",\n \"Co\",\n \"Ni\",\n \"Cu\",\n \"Zn\",\n \"Ga\",\n \"Ge\",\n \"As\",\n \"Se\",\n \"Br\",\n \"Kr\",\n \"Rb\",\n \"Sr\",\n \"Y\",\n \"Zr\",\n \"Nb\",\n \"Mo\",\n \"Tc\",\n \"Ru\",\n \"Rh\",\n \"Pd\",\n \"Ag\",\n \"Cd\",\n \"In\",\n \"Sn\",\n \"Sb\",\n \"Te\",\n \"I\",\n \"Xe\",\n \"Cs\",\n \"Ba\",\n \"La\",\n \"Ce\",\n \"Pr\",\n \"Nd\",\n \"Pm\",\n \"Sm\",\n \"Eu\",\n \"Gd\",\n \"Tb\",\n \"Dy\",\n \"Ho\",\n \"Er\",\n \"Tm\",\n \"Yb\",\n \"Lu\",\n \"Hf\",\n \"Ta\",\n \"W\",\n \"Re\",\n \"Os\",\n \"Ir\",\n \"Pt\",\n \"Au\",\n \"Hg\",\n \"Tl\",\n \"Pb\",\n \"Bi\",\n \"Po\",\n \"At\",\n \"Rn\",\n \"Fr\",\n \"Ra\",\n \"Ac\",\n \"Th\",\n \"Pa\",\n \"U\",\n \"Np\",\n \"Pu\",\n \"Am\",\n \"Cm\",\n \"Bk\",\n \"Cf\",\n \"Es\",\n \"Fm\",\n \"Md\",\n \"No\",\n \"Lr\",\n \"Rf\",\n \"Db\",\n \"Sg\",\n \"Bh\",\n \"Hs\",\n \"Mt\",\n \"Ds\",\n \"Rg\",\n \"Cn\",\n \"Nh\",\n \"Fl\",\n \"Mc\",\n \"Lv\",\n \"Ts\",\n \"Og\",\n];\n\nconst ELEMENTS = new Set(ELEMENT_SYMBOLS);\n\n/** Deuterium keeps its own symbol for display and counts as hydrogen. */\nexport const DEUTERIUM = \"D\";\n\nexport function isElementSymbol(symbol: string): boolean {\n return ELEMENTS.has(symbol) || symbol === DEUTERIUM;\n}\n\nfunction capitalize(text: string): string {\n return text.charAt(0).toUpperCase() + text.slice(1).toLowerCase();\n}\n\n/**\n * The element behind a CIF atom label or type symbol: `Fe3+`, `O2-`, `Co1`,\n * `OW`, `fe` and `Wat` all resolve. Null when no element symbol fits.\n */\nexport function elementFromCifSymbol(raw: string): string | null {\n const letters = raw.match(/^[A-Za-z]{1,2}/)?.[0];\n if (!letters) {\n return null;\n }\n const two = capitalize(letters);\n if (letters.length === 2 && isElementSymbol(two)) {\n return two;\n }\n const one = letters.charAt(0).toUpperCase();\n return isElementSymbol(one) ? one : null;\n}\n\n/** The chemical element, with deuterium reported as hydrogen. */\nexport function chemicalElement(symbol: string): string {\n return symbol === DEUTERIUM ? \"H\" : symbol;\n}\n","import type { SymmetryOperation, Vec3 } from \"./types.js\";\n\n/** Generated equivalents this close in fractional coordinates are one atom. */\nexport const EQUIVALENT_TOLERANCE = 1e-3;\n\n/** A wrapped coordinate this close below 1 is rounding; it belongs at 0. */\nconst NEAR_ONE = 1e-9;\n\n/** Fold a coordinate into [0, 1); a value within `nearOne` below 1 becomes 0. */\nexport function wrap(value: number, nearOne = NEAR_ONE): number {\n const wrapped = value - Math.floor(value);\n return wrapped >= 1 - nearOne ? 0 : wrapped;\n}\n\n/** Fold a fractional position into the cell. */\nexport function wrapVector(fractional: Vec3): Vec3 {\n return [wrap(fractional[0]), wrap(fractional[1]), wrap(fractional[2])];\n}\n\n/** Periodic distance of two fractional positions, per axis, below `tolerance`. */\nexport function samePosition(p: Vec3, q: Vec3, tolerance: number): boolean {\n for (let axis = 0; axis < 3; axis += 1) {\n let delta = Math.abs((p[axis] as number) - (q[axis] as number));\n delta -= Math.round(delta);\n if (Math.abs(delta) > tolerance) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * Buckets per cell edge. A bucket is wider than any tolerance used with\n * them, so a match lies in a position's own bucket or a neighbouring one.\n */\nconst BUCKETS = 100;\n\nfunction bucketOf(value: number): number {\n return Math.floor(wrap(value) * BUCKETS) % BUCKETS;\n}\n\nfunction bucketKey(x: number, y: number, z: number): number {\n return (x * BUCKETS + y) * BUCKETS + z;\n}\n\n/**\n * Fractional positions bucketed by where they fall in the cell, so finding\n * those within a tolerance of a position, across the periodic boundaries,\n * takes a few comparisons instead of one per position. The tolerance is per\n * axis, as in `samePosition`, and must stay below 1 / BUCKETS.\n */\nexport class PositionIndex {\n private readonly buckets = new Map<number, number[]>();\n private readonly positions: Vec3[] = [];\n\n constructor(private readonly tolerance: number) {}\n\n /** Add a position; its index counts up from 0 in the order added. */\n add(position: Vec3): number {\n const index = this.positions.length;\n this.positions.push(position);\n const key = bucketKey(\n bucketOf(position[0]),\n bucketOf(position[1]),\n bucketOf(position[2]),\n );\n const bucket = this.buckets.get(key);\n if (bucket) {\n bucket.push(index);\n } else {\n this.buckets.set(key, [index]);\n }\n return index;\n }\n\n /** Indices of the positions within tolerance of `position`, ascending. */\n near(position: Vec3): number[] {\n const wrapped = wrapVector(position);\n const [x, y, z] = wrapped.map(bucketOf) as Vec3;\n const found: number[] = [];\n for (let dx = -1; dx <= 1; dx += 1) {\n const bx = (x + dx + BUCKETS) % BUCKETS;\n for (let dy = -1; dy <= 1; dy += 1) {\n const by = (y + dy + BUCKETS) % BUCKETS;\n for (let dz = -1; dz <= 1; dz += 1) {\n const bz = (z + dz + BUCKETS) % BUCKETS;\n for (const index of this.buckets.get(bucketKey(bx, by, bz)) ?? []) {\n if (samePosition(this.positions[index]!, wrapped, this.tolerance)) {\n found.push(index);\n }\n }\n }\n }\n }\n return found.sort((left, right) => left - right);\n }\n}\n\n/** Apply an operation to fractional coordinates (no wrapping). */\nexport function applyOperation(\n operation: SymmetryOperation,\n fractional: Vec3,\n): Vec3 {\n const r = operation.rotation;\n const [x, y, z] = fractional;\n const t = operation.translation;\n return [\n (r[0] ?? 0) * x + (r[1] ?? 0) * y + (r[2] ?? 0) * z + t[0],\n (r[3] ?? 0) * x + (r[4] ?? 0) * y + (r[5] ?? 0) * z + t[1],\n (r[6] ?? 0) * x + (r[7] ?? 0) * y + (r[8] ?? 0) * z + t[2],\n ];\n}\n","import type { Lattice, LatticeParameters, Mat3, Vec3 } from \"./types.js\";\n\nconst DEGREES = Math.PI / 180;\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, value));\n}\n\n/**\n * A lattice from cell lengths in ångström and angles in degrees. The c axis\n * points along z and a lies in the xz plane, as in pymatgen.\n */\nexport function latticeFromParameters(parameters: LatticeParameters): Lattice {\n const { a, b, c } = parameters;\n const alpha = parameters.alpha * DEGREES;\n const beta = parameters.beta * DEGREES;\n const gamma = parameters.gamma * DEGREES;\n const cosAlpha = Math.cos(alpha);\n const cosBeta = Math.cos(beta);\n const cosGamma = Math.cos(gamma);\n const sinAlpha = Math.sin(alpha);\n const sinBeta = Math.sin(beta);\n const gammaStar = Math.acos(\n clamp((cosAlpha * cosBeta - cosGamma) / (sinAlpha * sinBeta), -1, 1),\n );\n const vectorA: Vec3 = [a * sinBeta, 0, a * cosBeta];\n const vectorB: Vec3 = [\n -b * sinAlpha * Math.cos(gammaStar),\n b * sinAlpha * Math.sin(gammaStar),\n b * cosAlpha,\n ];\n const vectorC: Vec3 = [0, 0, c];\n return { ...parameters, vectors: [vectorA, vectorB, vectorC] };\n}\n\n/** A lattice from its three cell vectors, in ångström. */\nexport function latticeFromVectors(vectors: Mat3): Lattice {\n const [a, b, c] = vectors;\n const length = (v: Vec3) => Math.hypot(v[0], v[1], v[2]);\n const angle = (u: Vec3, v: Vec3) =>\n Math.acos(\n clamp(\n (u[0] * v[0] + u[1] * v[1] + u[2] * v[2]) / (length(u) * length(v)),\n -1,\n 1,\n ),\n ) / DEGREES;\n return {\n a: length(a),\n b: length(b),\n c: length(c),\n alpha: angle(b, c),\n beta: angle(a, c),\n gamma: angle(a, b),\n vectors,\n };\n}\n\nexport function fractionalToCartesian(\n lattice: Lattice,\n fractional: Vec3,\n): Vec3 {\n const [va, vb, vc] = lattice.vectors;\n const [x, y, z] = fractional;\n return [\n x * va[0] + y * vb[0] + z * vc[0],\n x * va[1] + y * vb[1] + z * vc[1],\n x * va[2] + y * vb[2] + z * vc[2],\n ];\n}\n\nexport function distance(p: Vec3, q: Vec3): number {\n const dx = p[0] - q[0];\n const dy = p[1] - q[1];\n const dz = p[2] - q[2];\n return Math.sqrt(dx * dx + dy * dy + dz * dz);\n}\n","/** The CIF parses but does not describe a structure this package can use. */\nexport class CifStructureError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"CifStructureError\";\n }\n}\n","import { wrap } from \"../structure/fractional.js\";\nimport type { SymmetryOperation, Vec3 } from \"../structure/types.js\";\nimport { CifStructureError } from \"./errors.js\";\n\nconst AXES = [\"x\", \"y\", \"z\"] as const;\n\nfunction parseCoefficient(text: string): number {\n if (text === \"\" || text === \"+\") {\n return 1;\n }\n if (text === \"-\") {\n return -1;\n }\n const fraction = text.match(/^([+-]?\\d+)\\/(\\d+)$/);\n const value = fraction\n ? Number(fraction[1]) / Number(fraction[2])\n : Number(text);\n if (!Number.isFinite(value)) {\n throw new CifStructureError(\n `Cannot read the number ${JSON.stringify(text)} in a symmetry operator.`,\n );\n }\n return value;\n}\n\n/**\n * Parse a symmetry operation as CIF files write it, such as\n * `-x+1/2, y, -z+1/2`, into a rotation matrix and translation.\n */\nexport function parseSymmetryOperator(text: string): SymmetryOperation {\n // Only signs, digits, fractions, decimals and x, y, z can belong to an\n // operator; stray letters such as the \"t\" some exports append are dropped.\n const components = text\n .split(\",\")\n .map((part) => part.toLowerCase().replace(/[^xyz0-9./+-]/g, \"\"));\n if (components.length !== 3) {\n throw new CifStructureError(\n `A symmetry operator needs three components: ${JSON.stringify(text)}.`,\n );\n }\n const rotation: number[] = [];\n const translation: number[] = [];\n\n for (const component of components) {\n const terms = component.match(/[+-]?[^+-]+/g);\n if (!terms || terms.join(\"\") !== component) {\n throw new CifStructureError(\n `Cannot read the symmetry operator ${JSON.stringify(text)}.`,\n );\n }\n const row = [0, 0, 0];\n let shift = 0;\n for (const term of terms) {\n const axis = AXES.findIndex((candidate) => term.includes(candidate));\n if (axis === -1) {\n shift += parseCoefficient(term);\n } else {\n const coefficient = parseCoefficient(\n term.replace(AXES[axis] as string, \"\").replace(/\\*$/, \"\"),\n );\n row[axis] = (row[axis] ?? 0) + coefficient;\n }\n }\n rotation.push(...row);\n translation.push(wrap(shift));\n }\n\n return { rotation, translation: translation as Vec3 };\n}\n","import { elementFromCifSymbol } from \"../structure/elements.js\";\nimport { PositionIndex, wrap } from \"../structure/fractional.js\";\nimport { latticeFromParameters } from \"../structure/lattice.js\";\nimport type {\n Lattice,\n Site,\n SpaceGroupInfo,\n Species,\n SymmetryOperation,\n Vec3,\n} from \"../structure/types.js\";\nimport {\n isCifPlaceholder,\n loopColumn,\n parseCifNumber,\n type CifBlock,\n} from \"./parser.js\";\nimport { CifStructureError } from \"./errors.js\";\nimport { parseSymmetryOperator } from \"./symmetry-operators.js\";\n\nexport { CifStructureError };\n\n/** Rows this close in fractional coordinates describe one site. */\nconst SITE_MERGE_TOLERANCE = 1e-4;\n\nconst OPERATOR_TAGS = [\n \"_space_group_symop_operation_xyz\",\n \"_symmetry_equiv_pos_as_xyz\",\n];\nconst SPACE_GROUP_NUMBER_TAGS = [\n \"_space_group_it_number\",\n \"_symmetry_int_tables_number\",\n];\nconst HERMANN_MAUGUIN_TAGS = [\n \"_space_group_name_h-m_alt\",\n \"_symmetry_space_group_name_h-m\",\n \"_space_group_name_h-m_full\",\n];\nconst HALL_TAGS = [\"_space_group_name_hall\", \"_symmetry_space_group_name_hall\"];\n\nexport interface ParsedCifStructure {\n lattice: Lattice;\n sites: Site[];\n /** Null when the file lists no operators; see `spaceGroup` then. */\n operations: SymmetryOperation[] | null;\n spaceGroup: SpaceGroupInfo;\n}\n\nfunction requireNumber(block: CifBlock, tag: string): number {\n const value = parseCifNumber(block.get(tag));\n if (value === null) {\n throw new CifStructureError(\n `${block.name || \"The CIF\"} has no usable ${tag}.`,\n );\n }\n return value;\n}\n\nfunction mergeSpecies(\n species: Species[],\n element: string,\n occupancy: number,\n): void {\n const existing = species.find((entry) => entry.element === element);\n if (existing) {\n existing.occupancy += occupancy;\n } else {\n species.push({ element, occupancy });\n }\n species.sort((left, right) => right.occupancy - left.occupancy);\n}\n\n/** Totals this far above 1 are more than rounding. */\nconst OVERFULL_TOLERANCE = 1e-6;\n\n/**\n * A site holds at most one atom. Refined occupancies sometimes add up to a\n * little more, and some files list far more; either way the species are\n * scaled down to a full site, the rule pymatgen applies within its\n * tolerance, so the drawn atom makes sense.\n */\nfunction scaleOverfullSites(sites: Site[]): void {\n for (const site of sites) {\n const total = site.species.reduce(\n (sum, species) => sum + species.occupancy,\n 0,\n );\n if (total > 1 + OVERFULL_TOLERANCE) {\n for (const species of site.species) {\n species.occupancy /= total;\n }\n }\n }\n}\n\nfunction readSites(block: CifBlock): Site[] {\n const loop = block.findLoop(\"_atom_site_fract_x\");\n if (!loop) {\n throw new CifStructureError(\n `${block.name || \"The CIF\"} has no atom sites.`,\n );\n }\n const xs = loopColumn(loop, \"_atom_site_fract_x\") ?? [];\n const ys = loopColumn(loop, \"_atom_site_fract_y\") ?? [];\n const zs = loopColumn(loop, \"_atom_site_fract_z\") ?? [];\n const labels = loopColumn(loop, \"_atom_site_label\");\n const typeSymbols = loopColumn(loop, \"_atom_site_type_symbol\");\n const occupancies = loopColumn(loop, \"_atom_site_occupancy\");\n const sites: Site[] = [];\n const positions = new PositionIndex(SITE_MERGE_TOLERANCE);\n\n for (let row = 0; row < loop.rows.length; row += 1) {\n const x = parseCifNumber(xs[row]);\n const y = parseCifNumber(ys[row]);\n const z = parseCifNumber(zs[row]);\n if (x === null || y === null || z === null) {\n continue;\n }\n const label = labels?.[row] ?? typeSymbols?.[row] ?? `site${row + 1}`;\n const typeSymbol = typeSymbols?.[row];\n const element =\n (typeSymbol && !isCifPlaceholder(typeSymbol)\n ? elementFromCifSymbol(typeSymbol)\n : null) ?? elementFromCifSymbol(label);\n if (!element) {\n throw new CifStructureError(\n `Atom site ${JSON.stringify(label)} names no element (type symbol ${JSON.stringify(typeSymbol ?? \"\")}).`,\n );\n }\n const occupancy = parseCifNumber(occupancies?.[row]) ?? 1;\n const fractional: Vec3 = [wrap(x), wrap(y), wrap(z)];\n // The first site listed at this position, if any.\n const [shared] = positions.near(fractional);\n if (shared !== undefined) {\n mergeSpecies(sites[shared]!.species, element, occupancy);\n } else {\n positions.add(fractional);\n sites.push({ label, species: [{ element, occupancy }], fractional });\n }\n }\n\n if (sites.length === 0) {\n throw new CifStructureError(\n `${block.name || \"The CIF\"} has no atom sites with coordinates.`,\n );\n }\n scaleOverfullSites(sites);\n return sites;\n}\n\nfunction readOperations(block: CifBlock): SymmetryOperation[] | null {\n const loop = block.findLoop(OPERATOR_TAGS);\n if (!loop) {\n const single = block.get(OPERATOR_TAGS);\n return single === null ? null : [parseSymmetryOperator(single)];\n }\n const column = loopColumn(loop, OPERATOR_TAGS) ?? [];\n const operations = column\n .filter((text) => !isCifPlaceholder(text))\n .map(parseSymmetryOperator);\n return operations.length > 0 ? operations : null;\n}\n\nfunction readSpaceGroup(block: CifBlock): SpaceGroupInfo {\n const numberText = block.get(SPACE_GROUP_NUMBER_TAGS);\n const number = numberText === null ? null : parseCifNumber(numberText);\n const symbol = block.get(HERMANN_MAUGUIN_TAGS);\n const hallSymbol = block.get(HALL_TAGS);\n return {\n number:\n number !== null &&\n Number.isInteger(number) &&\n number >= 1 &&\n number <= 230\n ? number\n : null,\n symbol: symbol !== null && !isCifPlaceholder(symbol) ? symbol.trim() : null,\n hallSymbol:\n hallSymbol !== null && !isCifPlaceholder(hallSymbol)\n ? hallSymbol.trim()\n : null,\n };\n}\n\n/** True when the block carries atom coordinates (the one a viewer wants). */\nexport function isStructureBlock(block: CifBlock): boolean {\n return block.findLoop(\"_atom_site_fract_x\") !== null;\n}\n\n/** Lattice, merged sites, operators and space-group tags of one data block. */\nexport function parseCifStructure(block: CifBlock): ParsedCifStructure {\n const lattice = latticeFromParameters({\n a: requireNumber(block, \"_cell_length_a\"),\n b: requireNumber(block, \"_cell_length_b\"),\n c: requireNumber(block, \"_cell_length_c\"),\n alpha: requireNumber(block, \"_cell_angle_alpha\"),\n beta: requireNumber(block, \"_cell_angle_beta\"),\n gamma: requireNumber(block, \"_cell_angle_gamma\"),\n });\n return {\n lattice,\n sites: readSites(block),\n operations: readOperations(block),\n spaceGroup: readSpaceGroup(block),\n };\n}\n","import {\n EQUIVALENT_TOLERANCE,\n PositionIndex,\n applyOperation,\n} from \"./fractional.js\";\nimport type { Site, SymmetryOperation } from \"./types.js\";\n\nexport interface ListingClosure {\n /** Some listed site is a symmetry image of another: the list is already expanded, fully or partly. */\n preExpanded: boolean;\n /** Every image of every listed site is itself a listed site. */\n closed: boolean;\n}\n\n/**\n * How the listed sites relate to the operations. An asymmetric unit lists\n * no site that is an image of another, and its images are new positions,\n * as they should be. A list that is already expanded repeats such images,\n * and then the operations must map the list onto itself, or they are not\n * the symmetry of these atoms.\n */\nexport function listingClosure(\n sites: Site[],\n operations: SymmetryOperation[],\n): ListingClosure {\n const index = new PositionIndex(EQUIVALENT_TOLERANCE);\n for (const site of sites) {\n index.add(site.fractional);\n }\n let preExpanded = false;\n let closed = true;\n sites.forEach((site, self) => {\n for (const operation of operations) {\n const hits = index.near(applyOperation(operation, site.fractional));\n if (hits.some((hit) => hit !== self)) {\n preExpanded = true;\n }\n if (hits.length === 0) {\n closed = false;\n }\n }\n });\n return { preExpanded, closed };\n}\n","/** Three Cartesian or fractional components. */\nexport type Vec3 = [number, number, number];\n\n/** Three row vectors. */\nexport type Mat3 = [Vec3, Vec3, Vec3];\n\nexport interface LatticeParameters {\n a: number;\n b: number;\n c: number;\n /** Degrees. */\n alpha: number;\n beta: number;\n gamma: number;\n}\n\nexport interface Lattice extends LatticeParameters {\n /** Row vectors a, b, c in Cartesian ångström. */\n vectors: Mat3;\n}\n\nexport interface Species {\n /** Element symbol, such as \"Fe\"; \"D\" for deuterium. */\n element: string;\n /** Share of the site this species occupies, 0 to 1; a site's shares add up to at most 1. */\n occupancy: number;\n}\n\n/** One crystallographic site; several species share it when disordered. */\nexport interface Site {\n label: string;\n /** Sorted by descending occupancy. */\n species: Species[];\n fractional: Vec3;\n}\n\n/** x' = R x + t on fractional coordinates; `rotation` is row-major. */\nexport interface SymmetryOperation {\n rotation: number[];\n translation: Vec3;\n}\n\n/** What a CIF says about its space group; null for what it leaves out. */\nexport interface SpaceGroupInfo {\n /** Number in the International Tables, 1 to 230. */\n number: number | null;\n /** Hermann-Mauguin symbol as written in the file. */\n symbol: string | null;\n /** Hall symbol as written in the file. */\n hallSymbol: string | null;\n}\n\nexport interface Structure {\n lattice: Lattice;\n sites: Site[];\n /** Operations that generate the full cell from `sites`; the identity alone once expanded. */\n operations: SymmetryOperation[];\n spaceGroup: SpaceGroupInfo;\n}\n\nexport const IDENTITY_OPERATION: SymmetryOperation = {\n rotation: [1, 0, 0, 0, 1, 0, 0, 0, 1],\n translation: [0, 0, 0],\n};\n","import type * as MoyoBindings from \"./moyo-wasm.js\";\n\n// Kept apart from moyo.ts so the published declarations never refer to the\n// bindings, whose types come from a package consumers do not install.\n\nlet bindings: typeof MoyoBindings | null = null;\nlet loading: Promise<void> | null = null;\n\n/**\n * Import the moyo chunk and instantiate its module, once. A failed attempt\n * is not kept: the next call tries again.\n */\nexport function loadMoyo(): Promise<void> {\n if (!loading) {\n loading = import(\"./moyo-wasm.js\")\n .then(async (module) => {\n await module.instantiate();\n bindings = module;\n })\n .catch((error: unknown) => {\n loading = null;\n throw error;\n });\n }\n return loading;\n}\n\n/** The moyo bindings, once `loadMoyo` has resolved. */\nexport function moyo(): typeof MoyoBindings {\n if (!bindings) {\n throw new Error(\"moyo is not loaded yet; await ensureMoyo() first.\");\n }\n return bindings;\n}\n","import type { MoyoHallSymbolEntry } from \"@spglib/moyo-wasm\";\n\nimport type { SpaceGroupInfo, SymmetryOperation } from \"../structure/types.js\";\nimport { loadMoyo, moyo } from \"./moyo-loader.js\";\n\n/** The named space group is not in the symmetry table. */\nexport class SpaceGroupLookupError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"SpaceGroupLookupError\";\n }\n}\n\nlet hallEntries: MoyoHallSymbolEntry[] | null = null;\n\n/**\n * Load moyo, the symmetry library, ahead of first use. This is optional:\n * everything that needs moyo loads it. If loading fails, the next call tries\n * again.\n */\nexport function ensureMoyo(): Promise<void> {\n return loadMoyo();\n}\n\n/**\n * An operation as moyo returns it. Declared here rather than imported so the\n * published declarations do not depend on @spglib/moyo-wasm, which is bundled\n * at build time and not installed by consumers.\n */\nexport interface MoyoOperationLike {\n /** Nine integers, column-major. */\n rotation: readonly [\n number,\n number,\n number,\n number,\n number,\n number,\n number,\n number,\n number,\n ];\n translation: readonly [number, number, number];\n}\n\n/** moyo stores matrices column-major: element (i, j) sits at i + 3j. */\nexport function fromMoyoOperation(\n operation: MoyoOperationLike,\n): SymmetryOperation {\n const r = operation.rotation;\n return {\n rotation: [r[0], r[3], r[6], r[1], r[4], r[7], r[2], r[5], r[8]],\n translation: [\n operation.translation[0],\n operation.translation[1],\n operation.translation[2],\n ],\n };\n}\n\nfunction allHallEntries(): MoyoHallSymbolEntry[] {\n if (!hallEntries) {\n hallEntries = [];\n for (let number = 1; number <= 230; number += 1) {\n hallEntries.push(...moyo().hall_symbol_entries_from_number(number));\n }\n }\n return hallEntries;\n}\n\n/** Spaces and the screw-axis underscore carry no meaning when matching symbols. */\nfunction normalizeSymbol(symbol: string): string {\n return symbol.replace(/[\\s_]/g, \"\").toLowerCase();\n}\n\n/**\n * Split a CIF Hermann-Mauguin symbol into its symbol and setting suffix:\n * `R -3 m :H` and `R -3 m H` give `r-3m` and `h`; `P 1 21/c 1` gives\n * `p121/c1` and null, its trailing 1 being part of the full symbol.\n */\nfunction splitHermannMauguin(symbol: string): {\n base: string;\n setting: string | null;\n} {\n const trimmed = symbol.trim();\n const colon = trimmed.match(/^(.*?)\\s*:\\s*(\\S+)$/);\n if (colon && colon[1] && colon[2]) {\n return { base: normalizeSymbol(colon[1]), setting: colon[2].toLowerCase() };\n }\n const trailing = trimmed.match(/^(.*\\S)\\s+([HRhr])$/);\n if (trailing && trailing[1] && trailing[2]) {\n return {\n base: normalizeSymbol(trailing[1]),\n setting: trailing[2].toLowerCase(),\n };\n }\n return { base: normalizeSymbol(trimmed), setting: null };\n}\n\n/** The entry spglib treats as the standard setting, first among `entries`. */\nfunction preferStandard(entries: MoyoHallSymbolEntry[]): MoyoHallSymbolEntry[] {\n const first = entries[0];\n if (!first) {\n return entries;\n }\n const standard = moyo().space_group_type(first.number).hall_number;\n return [...entries].sort((left, right) => {\n return (\n Number(right.hall_number === standard) -\n Number(left.hall_number === standard)\n );\n });\n}\n\nfunction entriesForSymbol(info: SpaceGroupInfo): MoyoHallSymbolEntry[] {\n const entries = allHallEntries().filter(\n (entry) => info.number === null || entry.number === info.number,\n );\n if (info.hallSymbol) {\n const wanted = normalizeSymbol(info.hallSymbol);\n const byHall = entries.filter(\n (entry) => normalizeSymbol(entry.hall_symbol) === wanted,\n );\n if (byHall.length > 0) {\n return byHall;\n }\n }\n if (info.symbol) {\n const { base, setting } = splitHermannMauguin(info.symbol);\n const bySymbol = entries.filter(\n (entry) =>\n normalizeSymbol(entry.hm_short) === base ||\n normalizeSymbol(entry.hm_full) === base,\n );\n if (setting) {\n const bySetting = bySymbol.filter(\n (entry) => entry.setting.toLowerCase() === setting,\n );\n if (bySetting.length > 0) {\n return bySetting;\n }\n }\n return preferStandard(bySymbol);\n }\n return [];\n}\n\nfunction describe(info: SpaceGroupInfo): string {\n return [info.hallSymbol, info.symbol, info.number]\n .filter((part) => part !== null)\n .join(\" / \");\n}\n\nexport interface OperationSetting {\n /** moyo's name for the setting, such as \"H\", \"R\" or \"b1\"; \"\" when the group has one. */\n setting: string;\n /** Operations of the conventional cell in that setting. */\n operations: SymmetryOperation[];\n}\n\n/**\n * Every setting the space group a CIF names admits, spglib's standard one\n * first: one for most symbols, several for a short symbol such as `P 21/c`\n * or a rhombohedral symbol without `:H` or `:R`. A bare number gives the\n * standard setting alone.\n */\nexport async function operationSettings(\n info: SpaceGroupInfo,\n): Promise<OperationSetting[]> {\n await ensureMoyo();\n const { operations_from_number } = moyo();\n if (info.hallSymbol || info.symbol) {\n const entries = entriesForSymbol(info);\n if (entries.length === 0) {\n throw new SpaceGroupLookupError(\n `Space group ${describe(info)} is not in the symmetry table.`,\n );\n }\n return entries.map((entry) => ({\n setting: entry.setting,\n operations: operations_from_number(\n entry.number,\n { type: \"HallNumber\", value: entry.hall_number },\n false,\n ).map(fromMoyoOperation),\n }));\n }\n if (info.number === null) {\n throw new SpaceGroupLookupError(\"The CIF names no space group.\");\n }\n return [\n {\n setting: \"\",\n operations: operations_from_number(\n info.number,\n { type: \"Spglib\" },\n false,\n ).map(fromMoyoOperation),\n },\n ];\n}\n\n/**\n * The symmetry operations of a space group given by Hall symbol,\n * Hermann-Mauguin symbol or number, in the setting a suffix such as `:H`\n * names, or else the standard setting. Throws `SpaceGroupLookupError` for\n * an unknown group.\n */\nexport async function operationsForSpaceGroup(\n info: SpaceGroupInfo,\n): Promise<SymmetryOperation[]> {\n const [first] = await operationSettings(info);\n return first!.operations;\n}\n","import {\n CifStructureError,\n type ParsedCifStructure,\n} from \"../cif/structure.js\";\nimport { listingClosure } from \"../structure/closure.js\";\nimport {\n IDENTITY_OPERATION,\n type LatticeParameters,\n type Site,\n type SymmetryOperation,\n} from \"../structure/types.js\";\nimport { operationSettings } from \"./moyo.js\";\n\n/** Lengths within this fraction, and angles within this many degrees, are equal. */\nconst SAME_LENGTH = 1e-3;\nconst SAME_ANGLE = 0.01;\n\nfunction misfit(): CifStructureError {\n return new CifStructureError(\n \"The symmetry does not fit the listed atoms: they are already expanded, yet the operations generate positions the file does not list.\",\n );\n}\n\nfunction assertFits(sites: Site[], operations: SymmetryOperation[]): void {\n const closure = listingClosure(sites, operations);\n if (closure.preExpanded && !closure.closed) {\n throw misfit();\n }\n}\n\n/** The axes a cell is set on when its shape says so: rhombohedral or hexagonal. */\nfunction axesOfCell({\n a,\n b,\n c,\n alpha,\n beta,\n gamma,\n}: LatticeParameters): \"H\" | \"R\" | null {\n const sameLength = (x: number, y: number) =>\n Math.abs(x - y) <= SAME_LENGTH * Math.max(x, y);\n const sameAngle = (x: number, y: number) => Math.abs(x - y) <= SAME_ANGLE;\n if (\n sameLength(a, b) &&\n sameLength(b, c) &&\n sameAngle(alpha, beta) &&\n sameAngle(beta, gamma) &&\n !sameAngle(alpha, 90)\n ) {\n return \"R\";\n }\n if (\n sameLength(a, b) &&\n sameAngle(alpha, 90) &&\n sameAngle(beta, 90) &&\n sameAngle(gamma, 120)\n ) {\n return \"H\";\n }\n return null;\n}\n\n/**\n * The operations a parsed CIF's atoms are expanded with: the file's own\n * loop, checked to fit the atoms, or else the setting of its space group\n * that fits them. A symbol admitting several settings, such as a\n * rhombohedral group with no `:H` or `:R`, is settled by the atoms when the\n * list is already expanded, since only the right setting maps it onto\n * itself, and otherwise by the cell shape, then by the standard setting.\n */\nexport async function resolveOperations(\n parsed: ParsedCifStructure,\n): Promise<SymmetryOperation[]> {\n if (parsed.operations) {\n assertFits(parsed.sites, parsed.operations);\n return parsed.operations;\n }\n const { spaceGroup } = parsed;\n if (\n spaceGroup.hallSymbol === null &&\n spaceGroup.symbol === null &&\n spaceGroup.number === null\n ) {\n return [IDENTITY_OPERATION];\n }\n const settings = await operationSettings(spaceGroup);\n if (settings.length === 1) {\n const [only] = settings;\n assertFits(parsed.sites, only!.operations);\n return only!.operations;\n }\n const closures = settings.map((setting) =>\n listingClosure(parsed.sites, setting.operations),\n );\n const fitting = settings.find(\n (_, index) => closures[index]!.preExpanded && closures[index]!.closed,\n );\n if (fitting) {\n return fitting.operations;\n }\n if (closures.some((closure) => closure.preExpanded)) {\n throw misfit();\n }\n const axes = axesOfCell(parsed.lattice);\n const byCell =\n axes === null\n ? undefined\n : settings.find((setting) => setting.setting.toUpperCase() === axes);\n return (byCell ?? settings[0]!).operations;\n}\n","import {\n EQUIVALENT_TOLERANCE,\n PositionIndex,\n applyOperation,\n wrapVector,\n} from \"./fractional.js\";\nimport { IDENTITY_OPERATION, type Site, type Structure } from \"./types.js\";\n\n/**\n * Fill the unit cell: apply every symmetry operation to every site and keep\n * each distinct position once. The result lists every atom, with the\n * identity as its only operation.\n */\nexport function expandStructure(structure: Structure): Structure {\n const sites: Site[] = [];\n const kept = new PositionIndex(EQUIVALENT_TOLERANCE);\n for (const site of structure.sites) {\n for (const operation of structure.operations) {\n const fractional = wrapVector(applyOperation(operation, site.fractional));\n if (kept.near(fractional).length === 0) {\n kept.add(fractional);\n sites.push({ label: site.label, species: site.species, fractional });\n }\n }\n }\n return { ...structure, sites, operations: [IDENTITY_OPERATION] };\n}\n","import type {\n MoyoCell,\n MoyoDataset,\n MoyoHallSymbolEntry,\n} from \"@spglib/moyo-wasm\";\n\nimport { expandStructure } from \"../structure/expand.js\";\nimport { wrapVector } from \"../structure/fractional.js\";\nimport { latticeFromVectors } from \"../structure/lattice.js\";\nimport {\n IDENTITY_OPERATION,\n type Mat3,\n type Site,\n type Species,\n type Structure,\n type SymmetryOperation,\n} from \"../structure/types.js\";\nimport { ensureMoyo, fromMoyoOperation } from \"./moyo.js\";\nimport { moyo } from \"./moyo-loader.js\";\n\n/**\n * Distance tolerance of the symmetry search, in ångström: pymatgen's\n * default, loose enough for coordinates rounded to four decimals.\n */\nconst DEFAULT_SYMPREC = 0.01;\n\n/** moyo could not analyse the structure. */\nexport class SymmetryAnalysisError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"SymmetryAnalysisError\";\n }\n}\n\nexport interface SymmetryOptions {\n /** Distance tolerance in ångström. Default 0.01. */\n symprec?: number;\n}\n\n/** What moyo finds when it analyses the atoms of a structure. */\nexport interface SymmetryDataset {\n /** Space-group number in the International Tables. */\n number: number;\n /** Short Hermann-Mauguin symbol of the standard setting, as moyo writes it. */\n symbol: string;\n /** Full Hermann-Mauguin symbol of that setting. */\n fullSymbol: string;\n /** Hall symbol of that setting. */\n hallSymbol: string;\n /** Hall number of that setting, 1 to 530, as spglib counts them. */\n hallNumber: number;\n /** Setting of the Hall entry: \"2\" for origin choice 2, \"H\" for hexagonal axes, \"\" when there is one setting. */\n setting: string;\n /** The crystal system, as moyo names it. */\n crystalSystem: string;\n /** Operations of the analysed cell, in its own basis. */\n operations: SymmetryOperation[];\n /** Wyckoff letter of every site of `structure`, in its order. */\n wyckoffs: string[];\n /** Site-symmetry symbol of every site of `structure`, in its order. */\n siteSymmetries: string[];\n /** The expanded structure the analysis ran on. */\n structure: Structure;\n /** The same crystal in moyo's standard setting: a symmetry-refined conventional cell listing every atom. */\n standard: Structure;\n}\n\n/**\n * moyo tells sites apart by an integer label. Every distinct species list,\n * occupancies included, gets a label of its own, the way pymatgen types\n * sites, so a half-occupied sodium site never matches a full one and the\n * standard cell maps back to exactly the species it was given.\n */\nfunction labelSpecies(sites: Site[]): {\n numbers: number[];\n speciesByLabel: Map<number, Species[]>;\n} {\n const labelByKey = new Map<string, number>();\n const speciesByLabel = new Map<number, Species[]>();\n const numbers = sites.map((site) => {\n const key = JSON.stringify(site.species);\n let label = labelByKey.get(key);\n if (label === undefined) {\n label = labelByKey.size + 1;\n labelByKey.set(key, label);\n speciesByLabel.set(label, site.species);\n }\n return label;\n });\n return { numbers, speciesByLabel };\n}\n\n/** moyo's standardized cell as a structure, every atom listed. */\nfunction standardStructure(\n dataset: MoyoDataset,\n speciesByLabel: Map<number, Species[]>,\n entry: MoyoHallSymbolEntry,\n): Structure {\n const basis = dataset.std_cell.lattice.basis;\n const vectors: Mat3 = [\n [basis[0], basis[1], basis[2]],\n [basis[3], basis[4], basis[5]],\n [basis[6], basis[7], basis[8]],\n ];\n const counts = new Map<string, number>();\n const sites = dataset.std_cell.positions.map((position, index) => {\n const label = dataset.std_cell.numbers[index] ?? 0;\n const species = speciesByLabel.get(label) ?? [];\n const element = species[0]?.element ?? \"X\";\n const count = (counts.get(element) ?? 0) + 1;\n counts.set(element, count);\n return {\n label: `${element}${count}`,\n species,\n fractional: wrapVector(position),\n };\n });\n return {\n lattice: latticeFromVectors(vectors),\n sites,\n operations: [IDENTITY_OPERATION],\n spaceGroup: {\n number: dataset.number,\n symbol: dataset.hm_symbol,\n hallSymbol: entry.hall_symbol,\n },\n };\n}\n\n/**\n * Find the space group of a structure from its atoms alone, whatever the\n * file says. See `SymmetryDataset` for what the result holds.\n */\nexport async function symmetryDataset(\n structure: Structure,\n options: SymmetryOptions = {},\n): Promise<SymmetryDataset> {\n await ensureMoyo();\n const { analyze_cell, hall_symbol_entry, space_group_type } = moyo();\n const expanded = expandStructure(structure);\n const { numbers, speciesByLabel } = labelSpecies(expanded.sites);\n const [a, b, c] = expanded.lattice.vectors;\n const cell: MoyoCell = {\n lattice: { basis: [...a, ...b, ...c] },\n positions: expanded.sites.map((site) => site.fractional),\n numbers,\n };\n let dataset: MoyoDataset;\n try {\n dataset = analyze_cell(\n JSON.stringify(cell),\n options.symprec ?? DEFAULT_SYMPREC,\n \"Standard\",\n );\n } catch (error) {\n throw new SymmetryAnalysisError(\n `moyo could not analyse the structure: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n const entry = hall_symbol_entry(dataset.hall_number);\n const type = space_group_type(dataset.number);\n const standard = standardStructure(dataset, speciesByLabel, entry);\n return {\n number: dataset.number,\n symbol: dataset.hm_symbol,\n fullSymbol: entry.hm_full,\n hallSymbol: entry.hall_symbol,\n hallNumber: dataset.hall_number,\n setting: entry.setting,\n crystalSystem: type.crystal_system,\n operations: dataset.operations.map(fromMoyoOperation),\n wyckoffs: dataset.wyckoffs,\n siteSymmetries: dataset.site_symmetry_symbols,\n structure: expanded,\n standard,\n };\n}\n","const SUBSCRIPT_DIGITS = \"₀₁₂₃₄₅₆₇₈₉\";\nconst COMBINING_OVERLINE = \"̅\";\n\nfunction subscript(digit: string): string {\n return SUBSCRIPT_DIGITS[Number(digit)] ?? digit;\n}\n\n/**\n * Write a space-group symbol the way textbooks print it: `F m -3 m` becomes\n * Fm3̅m and `P 2_1/c` becomes P2₁/c. A setting suffix such as `:H` is kept.\n * A screw axis written as two digits, as CIF files do (`P 1 21/c 1`), is\n * recognised only when the symbol has spaces, since in `F432` the digits\n * are separate axes.\n */\nexport function typesetSymbol(symbol: string): string {\n const trimmed = symbol.trim();\n const colon = trimmed.indexOf(\":\");\n const body = colon === -1 ? trimmed : trimmed.slice(0, colon).trim();\n const suffix = colon === -1 ? \"\" : ` ${trimmed.slice(colon)}`;\n const tokens = body.split(/\\s+/);\n const typeset = tokens\n .map((token) =>\n tokens.length > 1\n ? token.replace(\n /^([2346])([1-5])(?=$|\\/)/,\n (match, axis: string, order: string) =>\n Number(order) < Number(axis) ? axis + subscript(order) : match,\n )\n : token,\n )\n .join(\"\")\n .replace(\n /(\\d)_(\\d)/g,\n (_, axis: string, order: string) => axis + subscript(order),\n )\n .replace(/-(\\d)/g, (_, axis: string) => axis + COMBINING_OVERLINE);\n return typeset + suffix;\n}\n","{\n \"source\": \"VESTA bond-search cutoffs (K. Momma and F. Izumi), as distributed in pymatgen's vesta_cutoffs.yaml (MIT). Where VESTA lists a pair twice (H-O, D-O), the shorter cutoff is kept.\",\n \"pairs\": {\n \"Ac-Br\": 3.22726,\n \"Ac-Cl\": 3.08646,\n \"Ac-F\": 2.58646,\n \"Ac-O\": 2.7326,\n \"Ag-As\": 2.45642,\n \"Ag-Br\": 2.37642,\n \"Ag-Cl\": 3.05939,\n \"Ag-F\": 2.76939,\n \"Ag-H\": 1.65642,\n \"Ag-I\": 2.53642,\n \"Ag-N\": 2.00642,\n \"Ag-O\": 2.81139,\n \"Ag-P\": 2.37642,\n \"Ag-S\": 3.08839,\n \"Ag-Se\": 2.41642,\n \"Ag-Te\": 2.66642,\n \"Al-As\": 2.75646,\n \"Al-Br\": 2.65646,\n \"Al-Cl\": 2.48846,\n \"Al-F\": 2.00146,\n \"Al-H\": 1.90646,\n \"Al-I\": 2.86646,\n \"Al-N\": 2.24646,\n \"Al-O\": 2.1074,\n \"Al-P\": 2.69646,\n \"Al-S\": 2.66646,\n \"Al-Se\": 2.72646,\n \"Al-Te\": 2.93646,\n \"Am-Br\": 3.22944,\n \"Am-Cl\": 3.08945,\n \"Am-F\": 2.61945,\n \"Am-O\": 2.71649,\n \"As-Au\": 2.26998,\n \"As-B\": 2.42646,\n \"As-Ba\": 3.69,\n \"As-Be\": 2.60649,\n \"As-Bi\": 2.87642,\n \"As-Br\": 2.80646,\n \"As-C\": 2.38646,\n \"As-Ca\": 3.48295,\n \"As-Cd\": 3.29295,\n \"As-Ce\": 3.08644,\n \"As-Cl\": 2.61646,\n \"As-Co\": 2.43642,\n \"As-Cr\": 2.49642,\n \"As-Cs\": 4.15942,\n \"As-Cu\": 2.71895,\n \"As-Dy\": 3.14,\n \"As-Er\": 3.18,\n \"As-Eu\": 2.93898,\n \"As-F\": 2.15646,\n \"As-Fe\": 2.50642,\n \"As-Ga\": 2.38998,\n \"As-Gd\": 3.18,\n \"As-Ge\": 2.47998,\n \"As-Hf\": 2.71642,\n \"As-Hg\": 2.65642,\n \"As-Ho\": 2.87898,\n \"As-I\": 3.03646,\n \"As-In\": 2.66642,\n \"As-Ir\": 2.58998,\n \"As-K\": 3.94942,\n \"As-La\": 3.51293,\n \"As-Lu\": 3.19649,\n \"As-Mg\": 3.09293,\n \"As-Mn\": 2.51642,\n \"As-Mo\": 2.62701,\n \"As-Na\": 3.64942,\n \"As-Nb\": 2.69642,\n \"As-Ni\": 2.28998,\n \"As-O\": 2.24546,\n \"As-P\": 2.29998,\n \"As-Pb\": 3.02644,\n \"As-Pd\": 2.34998,\n \"As-Pr\": 3.35649,\n \"As-Pt\": 2.30998,\n \"As-Rb\": 4.04645,\n \"As-Re\": 2.61998,\n \"As-Rh\": 2.41998,\n \"As-Ru\": 2.40998,\n \"As-S\": 2.84649,\n \"As-Sb\": 2.64998,\n \"As-Sc\": 3.04291,\n \"As-Se\": 2.98649,\n \"As-Si\": 2.66002,\n \"As-Sm\": 3.30649,\n \"As-Sn\": 2.77642,\n \"As-Sr\": 3.62295,\n \"As-Ta\": 2.70642,\n \"As-Tb\": 3.26649,\n \"As-Te\": 3.10646,\n \"As-Th\": 3.40649,\n \"As-Ti\": 2.87642,\n \"As-Tl\": 3.09644,\n \"As-Tm\": 3.22649,\n \"As-U\": 3.02644,\n \"As-V\": 2.54642,\n \"As-W\": 2.58998,\n \"As-Y\": 3.24649,\n \"As-Yb\": 3.19649,\n \"As-Zn\": 2.95293,\n \"As-Zr\": 3.07004,\n \"Au-Br\": 2.77646,\n \"Au-Cl\": 2.88295,\n \"Au-F\": 2.34646,\n \"Au-H\": 1.41998,\n \"Au-I\": 3.21295,\n \"Au-N\": 2.3826,\n \"Au-O\": 2.34646,\n \"Au-P\": 2.18998,\n \"Au-S\": 2.8326,\n \"Au-Se\": 2.22998,\n \"Au-Te\": 2.45998,\n \"B-B\": 1.85846,\n \"B-Br\": 2.33646,\n \"B-Cl\": 2.19646,\n \"B-F\": 1.76646,\n \"B-H\": 1.59646,\n \"B-I\": 2.55646,\n \"B-N\": 1.93846,\n \"B-O\": 1.82746,\n \"B-P\": 2.37646,\n \"B-S\": 2.27646,\n \"B-Se\": 2.40646,\n \"B-Te\": 2.65646,\n \"Ba-Br\": 3.74295,\n \"Ba-Cl\": 3.55295,\n \"Ba-F\": 3.05095,\n \"Ba-H\": 3.08295,\n \"Ba-I\": 3.99295,\n \"Ba-N\": 3.33295,\n \"Ba-O\": 3.14795,\n \"Ba-P\": 3.48295,\n \"Ba-S\": 3.66195,\n \"Ba-Se\": 3.74295,\n \"Ba-Te\": 3.94295,\n \"Be-Br\": 2.50649,\n \"Be-Cl\": 2.36649,\n \"Be-F\": 1.88749,\n \"Be-H\": 1.71649,\n \"Be-I\": 2.70649,\n \"Be-N\": 2.10649,\n \"Be-O\": 1.98749,\n \"Be-P\": 2.55649,\n \"Be-S\": 2.43649,\n \"Be-Se\": 2.57649,\n \"Be-Te\": 2.81649,\n \"Bi-Br\": 3.17993,\n \"Bi-Cl\": 3.04291,\n \"Bi-F\": 2.55291,\n \"Bi-H\": 2.12642,\n \"Bi-I\": 3.38291,\n \"Bi-N\": 2.56329,\n \"Bi-O\": 2.6608,\n \"Bi-P\": 2.78642,\n \"Bi-S\": 3.13291,\n \"Bi-Se\": 3.24329,\n \"Bi-Te\": 3.02642,\n \"Bk-Br\": 3.15233,\n \"Bk-Cl\": 3.02291,\n \"Bk-F\": 2.54233,\n \"Bk-O\": 2.64329,\n \"Br-C\": 2.26002,\n \"Br-Ca\": 3.36995,\n \"Br-Cd\": 3.21295,\n \"Br-Ce\": 3.40452,\n \"Br-Cf\": 3.14233,\n \"Br-Cl\": 2.33296,\n \"Br-Co\": 2.33642,\n \"Br-Cr\": 2.97293,\n \"Br-Cs\": 4.06942,\n \"Br-Cu\": 2.89295,\n \"Br-Dy\": 3.16945,\n \"Br-Er\": 3.14945,\n \"Br-Eu\": 3.46549,\n \"Br-F\": 2.20646,\n \"Br-Fe\": 2.8952,\n \"Br-Ga\": 2.6426,\n \"Br-Gd\": 3.19945,\n \"Br-Ge\": 2.34998,\n \"Br-Hf\": 2.62642,\n \"Br-Hg\": 3.09293,\n \"Br-Ho\": 3.20159,\n \"Br-In\": 3.05329,\n \"Br-Ir\": 2.49998,\n \"Br-K\": 3.8513,\n \"Br-La\": 3.43293,\n \"Br-Li\": 3.11654,\n \"Br-Lu\": 3.11945,\n \"Br-Mg\": 2.99293,\n \"Br-Mn\": 3.05293,\n \"Br-Mo\": 2.8535,\n \"Br-Na\": 3.57715,\n \"Br-Nb\": 3.07646,\n \"Br-Nd\": 3.37293,\n \"Br-Ni\": 2.80649,\n \"Br-Np\": 3.21233,\n \"Br-O\": 2.35646,\n \"Br-Os\": 2.72002,\n \"Br-P\": 2.44293,\n \"Br-Pa\": 3.18437,\n \"Br-Pb\": 3.62451,\n \"Br-Pd\": 2.80649,\n \"Br-Pm\": 3.18233,\n \"Br-Pr\": 3.27649,\n \"Br-Pt\": 2.94191,\n \"Br-Pu\": 3.19233,\n \"Br-Rb\": 4.05498,\n \"Br-Re\": 2.70002,\n \"Br-Rh\": 2.7126,\n \"Br-Ru\": 2.30998,\n \"Br-S\": 2.21998,\n \"Br-Sb\": 2.96646,\n \"Br-Sc\": 2.94291,\n \"Br-Se\": 2.78002,\n \"Br-Si\": 2.55002,\n \"Br-Sm\": 3.26649,\n \"Br-Sn\": 3.2152,\n \"Br-Sr\": 3.54295,\n \"Br-Ta\": 2.60642,\n \"Br-Tb\": 3.18649,\n \"Br-Te\": 2.90002,\n \"Br-Th\": 3.31945,\n \"Br-Ti\": 3.20293,\n \"Br-Tl\": 3.80942,\n \"Br-Tm\": 3.13945,\n \"Br-U\": 3.39452,\n \"Br-V\": 2.87329,\n \"Br-W\": 2.49998,\n \"Br-Y\": 3.15649,\n \"Br-Yb\": 3.12945,\n \"Br-Zn\": 2.86293,\n \"Br-Zr\": 2.98004,\n \"C-C\": 1.89002,\n \"C-Cl\": 2.11002,\n \"C-Co\": 2.19691,\n \"C-Cu\": 2.32649,\n \"C-F\": 1.76002,\n \"C-Fe\": 2.25191,\n \"C-H\": 1.2,\n \"C-I\": 2.16998,\n \"C-N\": 1.79202,\n \"C-O\": 1.97249,\n \"C-P\": 1.93998,\n \"C-Pd\": 2.33649,\n \"C-Pt\": 2.36649,\n \"C-S\": 2.15002,\n \"C-Se\": 2.01998,\n \"C-Si\": 2.23302,\n \"C-Te\": 2.25998,\n \"Ca-Cl\": 3.23295,\n \"Ca-F\": 2.70495,\n \"Ca-H\": 2.69295,\n \"Ca-I\": 3.58295,\n \"Ca-N\": 3.00295,\n \"Ca-O\": 2.83062,\n \"Ca-P\": 3.41295,\n \"Ca-S\": 3.31295,\n \"Ca-Se\": 3.42295,\n \"Ca-Te\": 3.62295,\n \"Cd-Cl\": 3.09295,\n \"Cd-F\": 2.67395,\n \"Cd-H\": 2.52295,\n \"Cd-I\": 3.46295,\n \"Cd-N\": 2.82295,\n \"Cd-O\": 2.76695,\n \"Cd-P\": 3.20295,\n \"Cd-S\": 3.16695,\n \"Cd-Se\": 3.26295,\n \"Cd-Te\": 3.45295,\n \"Ce-Cl\": 3.25293,\n \"Ce-F\": 2.75452,\n \"Ce-H\": 2.34644,\n \"Ce-I\": 3.62452,\n \"Ce-N\": 2.78549,\n \"Ce-O\": 2.86393,\n \"Ce-P\": 3.00644,\n \"Ce-S\": 3.36293,\n \"Ce-Se\": 3.04644,\n \"Ce-Te\": 3.22644,\n \"Cf-Cl\": 3.01291,\n \"Cf-F\": 2.53233,\n \"Cf-O\": 2.63291,\n \"Cl-Cl\": 2.14296,\n \"Cl-Cm\": 3.18291,\n \"Cl-Co\": 2.74593,\n \"Cl-Cr\": 2.80293,\n \"Cl-Cs\": 3.91042,\n \"Cl-Cu\": 2.75295,\n \"Cl-D\": 1.5,\n \"Cl-Dy\": 3.01945,\n \"Cl-Er\": 2.99944,\n \"Cl-Eu\": 3.32549,\n \"Cl-F\": 2.14646,\n \"Cl-Fe\": 2.86293,\n \"Cl-Ga\": 2.52646,\n \"Cl-Gd\": 3.06349,\n \"Cl-Ge\": 2.49002,\n \"Cl-H\": 1.5,\n \"Cl-Hf\": 2.75646,\n \"Cl-Hg\": 3.24939,\n \"Cl-Ho\": 3.05159,\n \"Cl-I\": 3.33295,\n \"Cl-In\": 3.52939,\n \"Cl-Ir\": 2.56746,\n \"Cl-K\": 3.65976,\n \"Cl-La\": 3.33452,\n \"Cl-Li\": 2.91814,\n \"Cl-Lu\": 2.96944,\n \"Cl-Mg\": 2.79293,\n \"Cl-Mn\": 2.84593,\n \"Cl-Mo\": 2.80447,\n \"Cl-N\": 2.20646,\n \"Cl-NH\": 3.48195,\n \"Cl-Na\": 3.39412,\n \"Cl-Nb\": 2.76291,\n \"Cl-Nd\": 3.22493,\n \"Cl-Ni\": 2.62649,\n \"Cl-Np\": 3.07233,\n \"Cl-O\": 2.16646,\n \"Cl-Os\": 2.54002,\n \"Cl-P\": 2.28746,\n \"Cl-Pa\": 3.01437,\n \"Cl-Pb\": 3.39295,\n \"Cl-Pd\": 2.65649,\n \"Cl-Pm\": 3.41233,\n \"Cl-Pr\": 3.12749,\n \"Cl-Pt\": 2.75646,\n \"Cl-Pu\": 3.05233,\n \"Cl-Rb\": 3.86664,\n \"Cl-Re\": 3.44712,\n \"Cl-Rh\": 2.62646,\n \"Cl-Ru\": 2.70646,\n \"Cl-S\": 2.37002,\n \"Cl-Sb\": 2.80646,\n \"Cl-Sc\": 2.92291,\n \"Cl-Se\": 2.57002,\n \"Cl-Si\": 2.38002,\n \"Cl-Sm\": 3.08749,\n \"Cl-Sn\": 3.13111,\n \"Cl-Sr\": 3.37295,\n \"Cl-Ta\": 2.6739,\n \"Cl-Tb\": 3.04349,\n \"Cl-Tc\": 2.56002,\n \"Cl-Te\": 2.73906,\n \"Cl-Th\": 3.15945,\n \"Cl-Ti\": 3.02293,\n \"Cl-Tl\": 3.72942,\n \"Cl-Tm\": 2.98944,\n \"Cl-U\": 3.24452,\n \"Cl-V\": 3.15293,\n \"Cl-W\": 2.47,\n \"Cl-Y\": 3.00649,\n \"Cl-Yb\": 2.98249,\n \"Cl-Zn\": 2.72293,\n \"Cl-Zr\": 3.33651,\n \"Cm-F\": 2.68291,\n \"Cm-O\": 2.79291,\n \"Co-F\": 2.35293,\n \"Co-H\": 1.9278,\n \"Co-I\": 2.52878,\n \"Co-In\": 3.13629,\n \"Co-N\": 2.36293,\n \"Co-O\": 2.40493,\n \"Co-P\": 2.36642,\n \"Co-S\": 2.65293,\n \"Co-Se\": 2.39642,\n \"Co-Te\": 2.61642,\n \"Cr-F\": 2.45293,\n \"Cr-H\": 1.67642,\n \"Cr-I\": 3.19293,\n \"Cr-N\": 2.5152,\n \"Cr-O\": 2.44293,\n \"Cr-P\": 2.42642,\n \"Cr-S\": 2.72491,\n \"Cr-Se\": 2.44642,\n \"Cr-Te\": 2.67642,\n \"Cs-F\": 3.49942,\n \"Cs-H\": 3.55942,\n \"Cs-I\": 4.40942,\n \"Cs-N\": 3.94942,\n \"Cs-O\": 3.53642,\n \"Cs-P\": 3.64194,\n \"Cs-S\": 4.24942,\n \"Cs-Se\": 4.21655,\n \"Cs-Te\": 4.4631,\n \"Cu-F\": 2.46295,\n \"Cu-H\": 1.81649,\n \"Cu-I\": 3.01795,\n \"Cu-N\": 2.49295,\n \"Cu-O\": 2.47295,\n \"Cu-P\": 2.65649,\n \"Cu-S\": 2.76095,\n \"Cu-Se\": 2.76295,\n \"Cu-Te\": 2.87649,\n \"D-F\": 1.1,\n \"D-N\": 1.2,\n \"D-O\": 1.2,\n \"Dy-F\": 2.52944,\n \"Dy-H\": 2.09,\n \"Dy-I\": 3.39945,\n \"Dy-N\": 2.38,\n \"Dy-O\": 2.65651,\n \"Dy-P\": 2.77,\n \"Dy-S\": 2.823,\n \"Dy-Se\": 2.81,\n \"Dy-Te\": 3.22,\n \"Er-F\": 2.51049,\n \"Er-H\": 2.06,\n \"Er-I\": 3.38945,\n \"Er-N\": 2.36,\n \"Er-O\": 2.63651,\n \"Er-P\": 2.75,\n \"Er-S\": 3.27651,\n \"Er-Se\": 3.18649,\n \"Er-Te\": 3.22,\n \"Es-O\": 2.70139,\n \"Eu-F\": 2.83549,\n \"Eu-H\": 2.18898,\n \"Eu-I\": 3.69549,\n \"Eu-N\": 2.95549,\n \"Eu-O\": 2.94249,\n \"Eu-P\": 2.85898,\n \"Eu-S\": 3.37949,\n \"Eu-Se\": 2.89898,\n \"Eu-Te\": 3.08898,\n \"F-Fe\": 2.36293,\n \"F-Ga\": 2.14646,\n \"F-Gd\": 3.15651,\n \"F-Ge\": 2.01002,\n \"F-H\": 1.1,\n \"F-Hf\": 3.18291,\n \"F-Hg\": 2.88293,\n \"F-Ho\": 2.56159,\n \"F-I\": 3.18295,\n \"F-In\": 2.35491,\n \"F-Ir\": 2.15002,\n \"F-K\": 3.11142,\n \"F-Kr\": 2.67549,\n \"F-La\": 2.79293,\n \"F-Li\": 2.34276,\n \"F-Lu\": 2.48249,\n \"F-Mg\": 2.29093,\n \"F-Mn\": 2.41093,\n \"F-Mo\": 2.2998,\n \"F-N\": 1.82646,\n \"F-NH\": 2.99195,\n \"F-Na\": 2.80398,\n \"F-Nb\": 2.35646,\n \"F-Nd\": 2.73452,\n \"F-Ni\": 2.20249,\n \"F-Np\": 2.59233,\n \"F-Os\": 2.07746,\n \"F-P\": 2.01002,\n \"F-Pa\": 2.54437,\n \"F-Pb\": 2.92045,\n \"F-Pd\": 2.34649,\n \"F-Pm\": 2.55233,\n \"F-Po\": 2.83646,\n \"F-Pr\": 2.62945,\n \"F-Pt\": 2.54002,\n \"F-Pu\": 2.58233,\n \"F-Rb\": 3.37645,\n \"F-Re\": 2.16002,\n \"F-Rh\": 2.16646,\n \"F-Ru\": 2.57646,\n \"F-S\": 1.95002,\n \"F-Sb\": 2.35646,\n \"F-Sc\": 2.32291,\n \"F-Se\": 2.08002,\n \"F-Si\": 1.93002,\n \"F-Sm\": 2.60649,\n \"F-Sn\": 2.63793,\n \"F-Sr\": 2.88195,\n \"F-Ta\": 2.2539,\n \"F-Tb\": 2.54249,\n \"F-Tc\": 2.24219,\n \"F-Te\": 2.22002,\n \"F-Th\": 2.68945,\n \"F-Ti\": 2.86293,\n \"F-Tl\": 3.26942,\n \"F-Tm\": 2.51649,\n \"F-U\": 2.80293,\n \"F-V\": 2.87293,\n \"F-W\": 2.03,\n \"F-Xe\": 2.62649,\n \"F-Y\": 2.51049,\n \"F-Yb\": 2.50649,\n \"F-Zn\": 2.38293,\n \"F-Zr\": 2.99651,\n \"Fe-H\": 1.68642,\n \"Fe-I\": 3.1552,\n \"Fe-N\": 2.48193,\n \"Fe-O\": 2.44693,\n \"Fe-P\": 2.42642,\n \"Fe-S\": 2.83793,\n \"Fe-Se\": 2.43642,\n \"Fe-Te\": 2.68642,\n \"Ga-H\": 1.55998,\n \"Ga-I\": 2.91646,\n \"Ga-N\": 1.96,\n \"Ga-O\": 2.18646,\n \"Ga-P\": 2.46998,\n \"Ga-S\": 2.61946,\n \"Ga-Se\": 3.41295,\n \"Ga-Te\": 2.58998,\n \"Gd-H\": 2.13,\n \"Gd-I\": 3.41945,\n \"Gd-N\": 2.42,\n \"Gd-O\": 2.76651,\n \"Gd-P\": 2.81,\n \"Gd-S\": 3.13649,\n \"Gd-Se\": 2.85,\n \"Gd-Te\": 3.24,\n \"Ge-Ge\": 2.6,\n \"Ge-H\": 1.59998,\n \"Ge-I\": 2.54998,\n \"Ge-N\": 1.92998,\n \"Ge-O\": 2.09802,\n \"Ge-P\": 2.36998,\n \"Ge-S\": 2.56702,\n \"Ge-Se\": 2.70002,\n \"Ge-Te\": 2.60998,\n \"H-Hf\": 1.93642,\n \"H-Hg\": 1.86642,\n \"H-Ho\": 2.11898,\n \"H-In\": 1.87642,\n \"H-Ir\": 1.80998,\n \"H-K\": 3.21942,\n \"H-La\": 2.77293,\n \"H-Lu\": 2.42649,\n \"H-Mg\": 2.24293,\n \"H-Mn\": 1.70642,\n \"H-Mo\": 1.83701,\n \"H-N\": 1.2,\n \"H-Na\": 2.79942,\n \"H-Nb\": 1.90642,\n \"H-Ni\": 1.44998,\n \"H-O\": 1.2,\n \"H-P\": 1.45998,\n \"H-Pb\": 2.27644,\n \"H-Pd\": 1.51998,\n \"H-Pr\": 2.62649,\n \"H-Pt\": 1.44998,\n \"H-Rb\": 3.43645,\n \"H-Re\": 1.79998,\n \"H-Rh\": 1.59998,\n \"H-Ru\": 1.65998,\n \"H-S\": 1.42998,\n \"H-Sb\": 2.81998,\n \"H-Sc\": 2.24291,\n \"H-Se\": 1.58998,\n \"H-Si\": 1.82002,\n \"H-Sm\": 2.56649,\n \"H-Sn\": 2.00642,\n \"H-Sr\": 2.87295,\n \"H-Ta\": 1.91642,\n \"H-Tb\": 2.51649,\n \"H-Te\": 1.87998,\n \"H-Th\": 2.67649,\n \"H-Ti\": 1.76642,\n \"H-Tl\": 2.35644,\n \"H-Tm\": 2.45649,\n \"H-U\": 2.27644,\n \"H-V\": 1.73642,\n \"H-W\": 1.80998,\n \"H-Y\": 2.46649,\n \"H-Yb\": 2.42649,\n \"H-Zn\": 2.13293,\n \"H-Zr\": 2.29004,\n \"Hf-I\": 2.83642,\n \"Hf-N\": 2.24642,\n \"Hf-O\": 2.37946,\n \"Hf-P\": 2.63642,\n \"Hf-S\": 2.64642,\n \"Hf-Se\": 2.67642,\n \"Hf-Te\": 2.87642,\n \"Hg-Hg\": 3.1952,\n \"Hg-I\": 3.33293,\n \"Hg-N\": 2.17642,\n \"Hg-O\": 2.86939,\n \"Hg-P\": 2.57642,\n \"Hg-S\": 3.42093,\n \"Hg-Se\": 2.82642,\n \"Hg-Te\": 2.76642,\n \"Ho-I\": 3.44159,\n \"Ho-N\": 2.41898,\n \"Ho-O\": 2.67047,\n \"Ho-P\": 2.79898,\n \"Ho-S\": 3.13547,\n \"Ho-Se\": 2.84898,\n \"Ho-Te\": 3.03898,\n \"I-I\": 2.4,\n \"I-In\": 3.19291,\n \"I-Ir\": 2.70998,\n \"I-K\": 4.11717,\n \"I-La\": 3.64293,\n \"I-Li\": 3.37676,\n \"I-Lu\": 3.36945,\n \"I-Mg\": 3.17293,\n \"I-Mn\": 3.23293,\n \"I-Mo\": 2.74701,\n \"I-Na\": 3.88251,\n \"I-Nb\": 3.1439,\n \"I-Nd\": 3.59452,\n \"I-Ni\": 3.00649,\n \"I-Np\": 3.44233,\n \"I-O\": 2.47646,\n \"I-P\": 2.44998,\n \"I-Pb\": 3.69562,\n \"I-Pd\": 2.96649,\n \"I-Pr\": 3.49649,\n \"I-Pt\": 2.41998,\n \"I-Pu\": 3.43233,\n \"I-Rb\": 4.33462,\n \"I-Re\": 2.65998,\n \"I-Rh\": 2.52998,\n \"I-Ru\": 2.52998,\n \"I-S\": 2.40998,\n \"I-Sb\": 3.21646,\n \"I-Sc\": 3.15291,\n \"I-Se\": 2.58998,\n \"I-Si\": 2.76002,\n \"I-Sm\": 3.44649,\n \"I-Sn\": 3.52293,\n \"I-Sr\": 3.74295,\n \"I-Ta\": 2.81642,\n \"I-Tb\": 3.40945,\n \"I-Te\": 3.13702,\n \"I-Th\": 3.56649,\n \"I-Ti\": 3.08291,\n \"I-Tl\": 3.94142,\n \"I-Tm\": 3.37945,\n \"I-U\": 3.62452,\n \"I-V\": 2.66642,\n \"I-W\": 2.70998,\n \"I-Y\": 3.37649,\n \"I-Yb\": 3.37945,\n \"I-Zn\": 3.07293,\n \"I-Zr\": 3.19004,\n \"In-Mn\": 3.14729,\n \"In-N\": 2.18642,\n \"In-O\": 2.46491,\n \"In-P\": 2.68642,\n \"In-S\": 2.93291,\n \"In-Se\": 2.62642,\n \"In-Te\": 2.84642,\n \"Ir-N\": 2.10998,\n \"Ir-O\": 2.27746,\n \"Ir-P\": 2.50998,\n \"Ir-S\": 2.42998,\n \"Ir-Se\": 2.55998,\n \"Ir-Te\": 2.75998,\n \"K-N\": 3.41942,\n \"K-O\": 3.25142,\n \"K-P\": 3.44942,\n \"K-S\": 3.79285,\n \"K-Se\": 4.00186,\n \"K-Te\": 4.23284,\n \"La-N\": 3.05293,\n \"La-O\": 2.90983,\n \"La-P\": 3.32293,\n \"La-S\": 3.35593,\n \"La-Se\": 3.45293,\n \"La-Te\": 3.65293,\n \"Li-N\": 2.66213,\n \"Li-O\": 2.60087,\n \"Li-S\": 3.02481,\n \"Li-Se\": 3.2433,\n \"Li-Te\": 3.42496,\n \"Lu-N\": 2.71649,\n \"Lu-O\": 2.57749,\n \"Lu-P\": 3.11649,\n \"Lu-S\": 3.03649,\n \"Lu-Se\": 3.16649,\n \"Lu-Te\": 3.35649,\n \"Mg-N\": 2.56293,\n \"Mg-O\": 2.41824,\n \"Mg-P\": 3.00293,\n \"Mg-S\": 2.89293,\n \"Mg-Se\": 3.03293,\n \"Mg-Te\": 3.24293,\n \"Mn-N\": 2.56193,\n \"Mn-O\": 2.51652,\n \"Mn-P\": 2.39642,\n \"Mn-S\": 2.93293,\n \"Mn-Se\": 2.47642,\n \"Mn-Te\": 2.70642,\n \"Mo-N\": 2.4735,\n \"Mo-O\": 2.3475,\n \"Mo-P\": 2.54701,\n \"Mo-S\": 2.80067,\n \"Mo-Se\": 2.59701,\n \"Mo-Te\": 2.79701,\n \"N-N\": 1.8826,\n \"N-Na\": 3.12942,\n \"N-Nb\": 2.46046,\n \"N-Nd\": 3.01293,\n \"N-Ni\": 2.30649,\n \"N-O\": 1.81746,\n \"N-P\": 1.97146,\n \"N-Pb\": 3.0967,\n \"N-Pd\": 2.40451,\n \"N-Pr\": 2.90649,\n \"N-Pt\": 2.41649,\n \"N-Rb\": 3.79645,\n \"N-Re\": 2.10998,\n \"N-Rh\": 2.2626,\n \"N-Ru\": 2.2626,\n \"N-S\": 2.28849,\n \"N-Sb\": 2.56446,\n \"N-Sc\": 2.54291,\n \"N-Se\": 2.1,\n \"N-Si\": 2.12002,\n \"N-Sm\": 3.02351,\n \"N-Sn\": 2.7152,\n \"N-Sr\": 3.09295,\n \"N-Ta\": 2.16642,\n \"N-Tb\": 2.80649,\n \"N-Te\": 2.16998,\n \"N-Th\": 2.94649,\n \"N-Ti\": 2.08642,\n \"N-Tl\": 2.59644,\n \"N-Tm\": 2.74649,\n \"N-U\": 2.78649,\n \"N-V\": 2.38329,\n \"N-W\": 2.10998,\n \"N-Y\": 2.77649,\n \"N-Yb\": 2.84851,\n \"N-Zn\": 2.43293,\n \"N-Zr\": 2.65004,\n \"NH-O\": 3.08895,\n \"Na-O\": 2.95693,\n \"Na-P\": 3.47942,\n \"Na-S\": 3.57685,\n \"Na-Se\": 3.71593,\n \"Na-Te\": 3.95459,\n \"Nb-O\": 2.45329,\n \"Nb-P\": 2.61642,\n \"Nb-S\": 2.74,\n \"Nb-Se\": 2.66642,\n \"Nb-Te\": 2.85642,\n \"Nd-O\": 2.8587,\n \"Nd-S\": 3.42712,\n \"Nd-Se\": 3.42293,\n \"Nd-Te\": 3.60293,\n \"Ni-O\": 2.28149,\n \"Ni-P\": 2.31998,\n \"Ni-S\": 2.58649,\n \"Ni-Se\": 2.18998,\n \"Ni-Te\": 2.47998,\n \"Np-O\": 2.63646,\n \"Np-S\": 3.2,\n \"O-O\": 1.7,\n \"O-Os\": 2.23,\n \"O-P\": 2.08646,\n \"O-Pa\": 2.63383,\n \"O-Pb\": 3.04096,\n \"O-Pd\": 2.39849,\n \"O-Po\": 2.64646,\n \"O-Pr\": 2.74449,\n \"O-Pt\": 2.40649,\n \"O-Pu\": 2.68329,\n \"O-Rb\": 3.43945,\n \"O-Re\": 2.3426,\n \"O-Rh\": 2.24946,\n \"O-Ru\": 2.22646,\n \"O-S\": 1.8,\n \"O-Sb\": 2.45237,\n \"O-Sc\": 2.42029,\n \"O-Se\": 2.16102,\n \"O-Si\": 1.99002,\n \"O-Sm\": 2.88251,\n \"O-Sn\": 2.82146,\n \"O-Sr\": 2.98095,\n \"O-Ta\": 2.74646,\n \"O-Tb\": 2.65549,\n \"O-Tc\": 2.22446,\n \"O-Te\": 2.3334,\n \"O-Th\": 2.77349,\n \"O-Ti\": 2.35391,\n \"O-Tl\": 3.36945,\n \"O-Tm\": 2.60649,\n \"O-U\": 2.94295,\n \"O-V\": 2.84939,\n \"O-W\": 2.20102,\n \"O-Xe\": 2.63451,\n \"O-Y\": 2.62549,\n \"O-Yb\": 2.74551,\n \"O-Zn\": 2.41693,\n \"O-Zr\": 3.09651,\n \"Os-S\": 2.56002,\n \"P-P\": 2.48381,\n \"P-Pb\": 2.94644,\n \"P-Pd\": 2.46998,\n \"P-Pr\": 3.28649,\n \"P-Pt\": 2.23998,\n \"P-Rb\": 3.50645,\n \"P-Re\": 2.50998,\n \"P-Rh\": 2.43998,\n \"P-Ru\": 2.33998,\n \"P-S\": 2.57646,\n \"P-Sb\": 2.56998,\n \"P-Sc\": 2.96291,\n \"P-Se\": 2.69646,\n \"P-Si\": 2.58002,\n \"P-Sm\": 3.23649,\n \"P-Sn\": 2.60642,\n \"P-Sr\": 3.43295,\n \"P-Ta\": 2.62642,\n \"P-Tb\": 3.19649,\n \"P-Te\": 2.56998,\n \"P-Th\": 3.33649,\n \"P-Ti\": 2.51642,\n \"P-Tl\": 3.01644,\n \"P-Tm\": 3.13649,\n \"P-U\": 2.94644,\n \"P-V\": 2.46642,\n \"P-W\": 2.50998,\n \"P-Y\": 3.17649,\n \"P-Yb\": 3.13649,\n \"P-Zn\": 2.86293,\n \"P-Zr\": 3.02004,\n \"Pb-S\": 3.40395,\n \"Pb-Se\": 3.55295,\n \"Pb-Te\": 3.14644,\n \"Pd-S\": 2.69649,\n \"Pd-Se\": 2.26998,\n \"Pd-Te\": 2.52998,\n \"Pr-S\": 3.20649,\n \"Pr-Se\": 3.32649,\n \"Pr-Te\": 3.50649,\n \"Pt-S\": 2.76649,\n \"Pt-Se\": 2.23998,\n \"Pt-Te\": 2.49998,\n \"Pu-S\": 3.3,\n \"Rb-S\": 3.97645,\n \"Rb-Se\": 4.13773,\n \"Rb-Te\": 4.28802,\n \"Re-S\": 2.61998,\n \"Re-Se\": 2.54998,\n \"Re-Te\": 2.74998,\n \"Rh-S\": 2.19998,\n \"Rh-Se\": 2.37998,\n \"Rh-Te\": 2.59998,\n \"Ru-S\": 2.6426,\n \"Ru-Se\": 2.69451,\n \"Ru-Te\": 2.58998,\n \"S-S\": 2.2,\n \"S-Sb\": 3.05,\n \"S-Sc\": 2.88391,\n \"S-Se\": 2.81649,\n \"S-Si\": 2.47602,\n \"S-Sm\": 3.15649,\n \"S-Sn\": 3.15293,\n \"S-Sr\": 3.51295,\n \"S-Ta\": 2.8439,\n \"S-Tb\": 3.11649,\n \"S-Te\": 2.79002,\n \"S-Th\": 3.24649,\n \"S-Ti\": 2.74646,\n \"S-Tl\": 3.66442,\n \"S-Tm\": 3.05649,\n \"S-U\": 3.25293,\n \"S-V\": 2.82293,\n \"S-W\": 2.43998,\n \"S-Y\": 3.08649,\n \"S-Yb\": 3.03649,\n \"S-Zn\": 2.80293,\n \"S-Zr\": 2.91004,\n \"Sb-Se\": 3.05646,\n \"Sb-Te\": 2.82998,\n \"Sc-Se\": 3.00291,\n \"Sc-Te\": 3.20291,\n \"Se-Se\": 2.93649,\n \"Se-Si\": 2.61002,\n \"Se-Sm\": 3.27649,\n \"Se-Sn\": 2.96646,\n \"Se-Sr\": 3.58295,\n \"Se-Ta\": 2.66642,\n \"Se-Tb\": 3.23649,\n \"Se-Te\": 2.57998,\n \"Se-Th\": 3.36649,\n \"Se-Ti\": 2.53642,\n \"Se-Tl\": 3.00644,\n \"Se-Tm\": 3.18649,\n \"Se-U\": 3.00644,\n \"Se-V\": 2.48642,\n \"Se-W\": 2.55998,\n \"Se-Y\": 3.21649,\n \"Se-Yb\": 3.16649,\n \"Se-Zn\": 2.93293,\n \"Se-Zr\": 3.03004,\n \"Si-Si\": 2.6,\n \"Si-Te\": 2.84002,\n \"Sm-Te\": 3.46649,\n \"Sn-Te\": 2.91642,\n \"Sr-Te\": 3.73295,\n \"Ta-Te\": 2.85642,\n \"Tb-Te\": 3.42649,\n \"Te-Te\": 2.80998,\n \"Te-Th\": 3.54649,\n \"Te-Ti\": 2.95642,\n \"Te-Tl\": 3.23644,\n \"Te-Tm\": 3.37649,\n \"Te-U\": 3.16644,\n \"Te-V\": 2.72642,\n \"Te-W\": 2.75998,\n \"Te-Y\": 3.40649,\n \"Te-Yb\": 3.36649,\n \"Te-Zn\": 3.16293,\n \"Te-Zr\": 3.17004\n }\n}\n","import vestaCutoffs from \"../data/vesta-cutoffs.json\";\nimport { distance } from \"./lattice.js\";\nimport type { Vec3 } from \"./types.js\";\n\nconst CUTOFFS = vestaCutoffs.pairs as Record<string, number>;\n/** Two atoms closer than this are the alternatives of a split site, not bonded. */\nconst SHORTEST_BOND = 0.4;\n\nexport interface BondedAtom {\n element: string;\n position: Vec3;\n}\n\n/** A bond between two entries of `StructureScene.atoms`. */\nexport interface Bond {\n /** Index of one atom. */\n start: number;\n /** Index of the other. */\n end: number;\n /** Distance between them in ångström. */\n length: number;\n}\n\n/** VESTA's bond-search maximum for an element pair, or null when VESTA draws none. */\nexport function bondCutoff(elementA: string, elementB: string): number | null {\n const key =\n elementA < elementB ? `${elementA}-${elementB}` : `${elementB}-${elementA}`;\n return CUTOFFS[key] ?? null;\n}\n\n/**\n * Bonds between the given atoms by VESTA's cutoff table. Only pairs VESTA\n * lists get bonds, so no metal-metal or anion-anion sticks appear. The bonds\n * are ordered by `start`, then `end`, and `start` is the lower index.\n */\nexport function findBonds(atoms: readonly BondedAtom[]): Bond[] {\n // Elements become small numbers and the cutoff of every pair present is\n // looked up once, 0 for a pair VESTA does not bond.\n const kinds = new Map<string, number>();\n const kindOf = atoms.map((atom) => {\n let kind = kinds.get(atom.element);\n if (kind === undefined) {\n kind = kinds.size;\n kinds.set(atom.element, kind);\n }\n return kind;\n });\n const elements = [...kinds.keys()];\n const cutoffs = new Float64Array(elements.length * elements.length);\n let longest = 0;\n elements.forEach((first, row) => {\n elements.forEach((second, column) => {\n const cutoff = bondCutoff(first, second) ?? 0;\n cutoffs[row * elements.length + column] = cutoff;\n longest = Math.max(longest, cutoff);\n });\n });\n if (longest < SHORTEST_BOND) {\n return [];\n }\n\n // Cubes as wide as the longest cutoff present: a bonded pair lies in one\n // cube or in two neighbouring ones. Keys count from one cube below the\n // lowest on each axis, so every neighbour of an occupied cube has its own.\n const cubes = atoms.map(\n (atom) =>\n atom.position.map((value) => Math.floor(value / longest) | 0) as Vec3,\n );\n const low: Vec3 = [Infinity, Infinity, Infinity];\n const high: Vec3 = [-Infinity, -Infinity, -Infinity];\n for (const cube of cubes) {\n for (let axis = 0; axis < 3; axis += 1) {\n low[axis] = Math.min(low[axis]!, cube[axis]!);\n high[axis] = Math.max(high[axis]!, cube[axis]!);\n }\n }\n const ny = high[1] - low[1] + 3;\n const nz = high[2] - low[2] + 3;\n const cubeKey = (x: number, y: number, z: number) =>\n ((x - low[0] + 1) * ny + (y - low[1] + 1)) * nz + (z - low[2] + 1);\n const grid = new Map<number, number[]>();\n cubes.forEach(([x, y, z], index) => {\n const key = cubeKey(x, y, z);\n const bucket = grid.get(key);\n if (bucket) {\n bucket.push(index);\n } else {\n grid.set(key, [index]);\n }\n });\n\n const bonds: Bond[] = [];\n const found: Bond[] = [];\n atoms.forEach((atom, index) => {\n const [x, y, z] = cubes[index]!;\n const row = kindOf[index]! * elements.length;\n found.length = 0;\n for (let dx = -1; dx <= 1; dx += 1) {\n for (let dy = -1; dy <= 1; dy += 1) {\n for (let dz = -1; dz <= 1; dz += 1) {\n for (const other of grid.get(cubeKey(x + dx, y + dy, z + dz)) ?? []) {\n const cutoff = cutoffs[row + kindOf[other]!]!;\n if (other <= index || cutoff < SHORTEST_BOND) {\n continue;\n }\n const length = distance(atom.position, atoms[other]!.position);\n if (length >= SHORTEST_BOND && length <= cutoff) {\n found.push({ start: index, end: other, length });\n }\n }\n }\n }\n }\n bonds.push(...found.sort((left, right) => left.end - right.end));\n });\n return bonds;\n}\n","import { wrap } from \"./fractional.js\";\nimport type { Site, Vec3 } from \"./types.js\";\n\n/** A coordinate this close to 0 or 1 sits on the cell boundary. */\nconst BOUNDARY_TOLERANCE = 1e-4;\n\nexport interface PeriodicAtom {\n siteIndex: number;\n fractional: Vec3;\n /** True for a copy of a boundary site on the opposite face, edge or corner. */\n isImage: boolean;\n}\n\n/**\n * The sites of a cell, each folded into [0, 1), plus the image atoms of\n * every boundary site when requested: a corner site appears at all eight\n * corners, an edge site at four edges, a face site on both faces.\n */\nexport function periodicAtoms(\n sites: Site[],\n includeImages: boolean,\n): PeriodicAtom[] {\n const atoms: PeriodicAtom[] = [];\n sites.forEach((site, siteIndex) => {\n const fractional = site.fractional.map((value) =>\n wrap(value, BOUNDARY_TOLERANCE),\n ) as Vec3;\n atoms.push({ siteIndex, fractional, isImage: false });\n if (!includeImages) {\n return;\n }\n const boundaryAxes = ([0, 1, 2] as const).filter(\n (axis) => fractional[axis] < BOUNDARY_TOLERANCE,\n );\n const subsetCount = 1 << boundaryAxes.length;\n for (let subset = 1; subset < subsetCount; subset += 1) {\n const image: Vec3 = [fractional[0], fractional[1], fractional[2]];\n boundaryAxes.forEach((axis, bit) => {\n if (subset & (1 << bit)) {\n image[axis] += 1;\n }\n });\n atoms.push({ siteIndex, fractional: image, isImage: true });\n }\n });\n return atoms;\n}\n","import { findBonds, type Bond } from \"../structure/bonds.js\";\nimport { chemicalElement } from \"../structure/elements.js\";\nimport { periodicAtoms } from \"../structure/images.js\";\nimport { fractionalToCartesian } from \"../structure/lattice.js\";\nimport type { Mat3, Species, Structure, Vec3 } from \"../structure/types.js\";\n\nexport interface SceneAtom {\n /** Index into `Structure.sites` of the site this atom belongs to. */\n siteIndex: number;\n /** The species with the largest occupancy; what colours the atom. */\n element: string;\n /** Every species on the site, by descending occupancy. */\n species: Species[];\n /** Cartesian position in ångström. */\n position: Vec3;\n /** Fractional position; image atoms lie on the far faces, edges or corners. */\n fractional: Vec3;\n /** True for a boundary site repeated on the opposite face, edge or corner. */\n isImage: boolean;\n}\n\nexport interface StructureScene {\n /** Cell row vectors in Cartesian ångström. */\n cell: Mat3;\n atoms: SceneAtom[];\n /** Bonds between entries of `atoms`. */\n bonds: Bond[];\n /** Elements present, in order of first appearance, deuterium as hydrogen. */\n elements: string[];\n}\n\n/** One structure to draw. A viewer can overlay several, each with its own opacity. */\nexport interface SceneLayer {\n scene: StructureScene;\n /**\n * From 0 to 1; default 1. Below 1 the layer is drawn see-through over the\n * others. At 0 it is not drawn but still counts when fitting the view, so\n * switching between two versions of a structure keeps the same framing.\n */\n opacity?: number;\n}\n\nexport interface BuildSceneOptions {\n /** Repeat atoms on the cell's faces, edges and corners on the opposite side too. Default true. */\n imageAtoms?: boolean;\n}\n\n/** Every chemical element on any site, in order of first appearance. */\nexport function structureElements(structure: Structure): string[] {\n const elements: string[] = [];\n for (const site of structure.sites) {\n for (const species of site.species) {\n const element = chemicalElement(species.element);\n if (!elements.includes(element)) {\n elements.push(element);\n }\n }\n }\n return elements;\n}\n\n/**\n * Prepare a structure for drawing: its atoms, bonds and cell. Sites are\n * drawn as listed; pass `expandStructure(structure)` to draw the whole cell.\n */\nexport function buildScene(\n structure: Structure,\n options: BuildSceneOptions = {},\n): StructureScene {\n const atoms: SceneAtom[] = periodicAtoms(\n structure.sites,\n options.imageAtoms ?? true,\n ).map((atom) => {\n const site = structure.sites[atom.siteIndex];\n if (!site) {\n throw new Error(`Site ${atom.siteIndex} is missing.`);\n }\n const majority = site.species[0];\n if (!majority) {\n throw new Error(`Site ${site.label} has no species.`);\n }\n return {\n siteIndex: atom.siteIndex,\n element: majority.element,\n species: site.species,\n position: fractionalToCartesian(structure.lattice, atom.fractional),\n fractional: atom.fractional,\n isImage: atom.isImage,\n };\n });\n return {\n cell: structure.lattice.vectors,\n atoms,\n bonds: findBonds(atoms),\n elements: structureElements(structure),\n };\n}\n","import {\n\tControls,\n\tMathUtils,\n\tMOUSE,\n\tQuaternion,\n\tVector2,\n\tVector3\n} from 'three';\n\n/**\n * Fires when the camera has been transformed by the controls.\n *\n * @event TrackballControls#change\n * @type {Object}\n */\nconst _changeEvent = { type: 'change' };\n\n/**\n * Fires when an interaction was initiated.\n *\n * @event TrackballControls#start\n * @type {Object}\n */\nconst _startEvent = { type: 'start' };\n\n/**\n * Fires when an interaction has finished.\n *\n * @event TrackballControls#end\n * @type {Object}\n */\nconst _endEvent = { type: 'end' };\n\nconst _EPS = 0.000001;\nconst _STATE = { NONE: - 1, ROTATE: 0, ZOOM: 1, PAN: 2, TOUCH_ROTATE: 3, TOUCH_ZOOM_PAN: 4 };\n\nconst _v2 = new Vector2();\nconst _mouseChange = new Vector2();\nconst _objectUp = new Vector3();\nconst _pan = new Vector3();\nconst _axis = new Vector3();\nconst _quaternion = new Quaternion();\nconst _eyeDirection = new Vector3();\nconst _objectUpDirection = new Vector3();\nconst _objectSidewaysDirection = new Vector3();\nconst _moveDirection = new Vector3();\n\n/**\n * This class is similar to {@link OrbitControls}. However, it does not maintain a constant camera\n * `up` vector. That means if the camera orbits over the “north” and “south” poles, it does not flip\n * to stay \"right side up\".\n *\n * @augments Controls\n * @three_import import { TrackballControls } from 'three/addons/controls/TrackballControls.js';\n */\nclass TrackballControls extends Controls {\n\n\t/**\n\t * Constructs a new controls instance.\n\t *\n\t * @param {Object3D} object - The object that is managed by the controls.\n\t * @param {?HTMLElement} domElement - The HTML element used for event listeners.\n\t */\n\tconstructor( object, domElement = null ) {\n\n\t\tsuper( object, domElement );\n\n\t\t/**\n\t\t * Represents the properties of the screen. Automatically set when `handleResize()` is called.\n\t\t *\n\t\t * @type {Object}\n\t\t * @readonly\n\t\t */\n\t\tthis.screen = { left: 0, top: 0, width: 0, height: 0 };\n\n\t\t/**\n\t\t * The rotation speed.\n\t\t *\n\t\t * @type {number}\n\t\t * @default 1\n\t\t */\n\t\tthis.rotateSpeed = 1.0;\n\n\t\t/**\n\t\t * The zoom speed.\n\t\t *\n\t\t * @type {number}\n\t\t * @default 1.2\n\t\t */\n\t\tthis.zoomSpeed = 1.2;\n\n\t\t/**\n\t\t * The pan speed.\n\t\t *\n\t\t * @type {number}\n\t\t * @default 0.3\n\t\t */\n\t\tthis.panSpeed = 0.3;\n\n\t\t/**\n\t\t * The roll speed used for multi-touch roll.\n\t\t *\n\t\t * @type {number}\n\t\t * @default 1\n\t\t */\n\t\tthis.rollSpeed = 1.0;\n\n\t\t/**\n\t\t * Whether rotation is disabled or not.\n\t\t *\n\t\t * @type {boolean}\n\t\t * @default false\n\t\t */\n\t\tthis.noRotate = false;\n\n\t\t/**\n\t\t * Whether zooming is disabled or not.\n\t\t *\n\t\t * @type {boolean}\n\t\t * @default false\n\t\t */\n\t\tthis.noZoom = false;\n\n\t\t/**\n\t\t * Whether panning is disabled or not.\n\t\t *\n\t\t * @type {boolean}\n\t\t * @default false\n\t\t */\n\t\tthis.noPan = false;\n\n\t\t/**\n\t\t * Whether two finger twist gesture rolls\n\t\t * the camera around its view axis or not.\n\t\t *\n\t\t * @type {boolean}\n\t\t * @default false\n\t\t */\n\t\tthis.multiTouchRoll = false;\n\n\t\t/**\n\t\t * Whether damping is disabled or not.\n\t\t *\n\t\t * @type {boolean}\n\t\t * @default false\n\t\t */\n\t\tthis.staticMoving = false;\n\n\t\t/**\n\t\t * Defines the intensity of damping. Only considered if `staticMoving` is set to `false`.\n\t\t *\n\t\t * @type {number}\n\t\t * @default 0.2\n\t\t */\n\t\tthis.dynamicDampingFactor = 0.2;\n\n\t\t/**\n\t\t * How far you can dolly in (perspective camera only).\n\t\t *\n\t\t * @type {number}\n\t\t * @default 0\n\t\t */\n\t\tthis.minDistance = 0;\n\n\t\t/**\n\t\t * How far you can dolly out (perspective camera only).\n\t\t *\n\t\t * @type {number}\n\t\t * @default Infinity\n\t\t */\n\t\tthis.maxDistance = Infinity;\n\n\t\t/**\n\t\t * How far you can zoom in (orthographic camera only).\n\t\t *\n\t\t * @type {number}\n\t\t * @default 0\n\t\t */\n\t\tthis.minZoom = 0;\n\n\t\t/**\n\t\t * How far you can zoom out (orthographic camera only).\n\t\t *\n\t\t * @type {number}\n\t\t * @default Infinity\n\t\t */\n\t\tthis.maxZoom = Infinity;\n\n\t\t/**\n\t\t * This array holds keycodes for controlling interactions.\n\t\t *\n\t\t * - When the first defined key is pressed, all mouse interactions (left, middle, right) performs orbiting.\n\t\t * - When the second defined key is pressed, all mouse interactions (left, middle, right) performs zooming.\n\t\t * - When the third defined key is pressed, all mouse interactions (left, middle, right) performs panning.\n\t\t *\n\t\t * Default is *KeyA, KeyS, KeyD* which represents A, S, D.\n\t\t *\n\t\t * @type {Array<string>}\n\t\t */\n\t\tthis.keys = [ 'KeyA' /*A*/, 'KeyS' /*S*/, 'KeyD' /*D*/ ];\n\n\t\t/**\n\t\t * This object contains references to the mouse actions used by the controls.\n\t\t *\n\t\t * ```js\n\t\t * controls.mouseButtons = {\n\t\t * \tLEFT: THREE.MOUSE.ROTATE,\n\t\t * \tMIDDLE: THREE.MOUSE.DOLLY,\n\t\t * \tRIGHT: THREE.MOUSE.PAN\n\t\t * }\n\t\t * ```\n\t\t * @type {Object}\n\t\t */\n\t\tthis.mouseButtons = { LEFT: MOUSE.ROTATE, MIDDLE: MOUSE.DOLLY, RIGHT: MOUSE.PAN };\n\n\t\t/**\n\t\t * The focus point of the controls.\n\t\t *\n\t\t * @type {Vector3}\n\t\t */\n\t\tthis.target = new Vector3();\n\n\t\t// internals\n\n\t\tthis.state = _STATE.NONE;\n\t\tthis.keyState = _STATE.NONE;\n\n\t\tthis._lastPosition = new Vector3();\n\t\tthis._lastUp = new Vector3();\n\t\tthis._lastZoom = 1;\n\t\tthis._touchZoomDistanceStart = 0;\n\t\tthis._touchZoomDistanceEnd = 0;\n\t\tthis._touchRollAngle = 0;\n\t\tthis._touchRollPointerIds = '';\n\t\tthis._lastAngle = 0;\n\t\tthis._lastRollAngle = 0;\n\n\t\tthis._eye = new Vector3();\n\n\t\tthis._movePrev = new Vector2();\n\t\tthis._moveCurr = new Vector2();\n\n\t\tthis._lastAxis = new Vector3();\n\n\t\tthis._zoomStart = new Vector2();\n\t\tthis._zoomEnd = new Vector2();\n\n\t\tthis._panStart = new Vector2();\n\t\tthis._panEnd = new Vector2();\n\n\t\tthis._pointers = [];\n\t\tthis._pointerPositions = {};\n\n\t\t// event listeners\n\n\t\tthis._onPointerMove = onPointerMove.bind( this );\n\t\tthis._onPointerDown = onPointerDown.bind( this );\n\t\tthis._onPointerUp = onPointerUp.bind( this );\n\t\tthis._onPointerCancel = onPointerCancel.bind( this );\n\t\tthis._onContextMenu = onContextMenu.bind( this );\n\t\tthis._onMouseWheel = onMouseWheel.bind( this );\n\t\tthis._onKeyDown = onKeyDown.bind( this );\n\t\tthis._onKeyUp = onKeyUp.bind( this );\n\n\t\tthis._onTouchStart = onTouchStart.bind( this );\n\t\tthis._onTouchMove = onTouchMove.bind( this );\n\t\tthis._onTouchEnd = onTouchEnd.bind( this );\n\n\t\tthis._onMouseDown = onMouseDown.bind( this );\n\t\tthis._onMouseMove = onMouseMove.bind( this );\n\t\tthis._onMouseUp = onMouseUp.bind( this );\n\n\t\t// for reset\n\n\t\tthis._target0 = this.target.clone();\n\t\tthis._position0 = this.object.position.clone();\n\t\tthis._up0 = this.object.up.clone();\n\t\tthis._zoom0 = this.object.zoom;\n\n\t\tif ( domElement !== null ) {\n\n\t\t\tthis.connect( domElement );\n\n\t\t\tthis.handleResize();\n\n\t\t}\n\n\t\t// force an update at start\n\t\tthis.update();\n\n\t}\n\n\tconnect( element ) {\n\n\t\tsuper.connect( element );\n\n\t\twindow.addEventListener( 'keydown', this._onKeyDown );\n\t\twindow.addEventListener( 'keyup', this._onKeyUp );\n\n\t\tthis.domElement.addEventListener( 'pointerdown', this._onPointerDown );\n\t\tthis.domElement.addEventListener( 'pointercancel', this._onPointerCancel );\n\t\tthis.domElement.addEventListener( 'wheel', this._onMouseWheel, { passive: false } );\n\t\tthis.domElement.addEventListener( 'contextmenu', this._onContextMenu );\n\n\t\tthis.domElement.style.touchAction = 'none'; // Disable touch scroll\n\n\t}\n\n\tdisconnect() {\n\n\t\twindow.removeEventListener( 'keydown', this._onKeyDown );\n\t\twindow.removeEventListener( 'keyup', this._onKeyUp );\n\n\t\tthis.domElement.removeEventListener( 'pointerdown', this._onPointerDown );\n\t\tthis.domElement.ownerDocument.removeEventListener( 'pointermove', this._onPointerMove );\n\t\tthis.domElement.ownerDocument.removeEventListener( 'pointerup', this._onPointerUp );\n\t\tthis.domElement.removeEventListener( 'pointercancel', this._onPointerCancel );\n\t\tthis.domElement.removeEventListener( 'wheel', this._onMouseWheel );\n\t\tthis.domElement.removeEventListener( 'contextmenu', this._onContextMenu );\n\n\t\tthis.domElement.style.touchAction = ''; // Restore touch scroll\n\n\t}\n\n\tdispose() {\n\n\t\tthis.disconnect();\n\n\t}\n\n\t/**\n\t * Must be called if the application window is resized.\n\t */\n\thandleResize() {\n\n\t\tconst box = this.domElement.getBoundingClientRect();\n\t\t// adjustments come from similar code in the jquery offset() function\n\t\tconst d = this.domElement.ownerDocument.documentElement;\n\n\t\tthis.screen.left = box.left + window.pageXOffset - d.clientLeft;\n\t\tthis.screen.top = box.top + window.pageYOffset - d.clientTop;\n\t\tthis.screen.width = box.width;\n\t\tthis.screen.height = box.height;\n\n\t}\n\n\tupdate() {\n\n\t\tthis._eye.subVectors( this.object.position, this.target );\n\n\t\tif ( ! this.noRotate ) {\n\n\t\t\tthis._rotateCamera();\n\n\t\t\tif ( this.multiTouchRoll === true ) {\n\n\t\t\t\tthis._rollCamera();\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( ! this.noZoom ) {\n\n\t\t\tthis._zoomCamera();\n\n\t\t}\n\n\t\tif ( ! this.noPan ) {\n\n\t\t\tthis._panCamera();\n\n\t\t}\n\n\t\tthis.object.position.addVectors( this.target, this._eye );\n\n\t\tif ( this.object.isPerspectiveCamera ) {\n\n\t\t\tthis._checkDistances();\n\n\t\t\tthis.object.lookAt( this.target );\n\n\t\t\tconst positionChanged = this._lastPosition.distanceToSquared( this.object.position ) > _EPS;\n\t\t\tconst rollChanged = this._lastUp.distanceToSquared( this.object.up ) > _EPS;\n\n\t\t\tif ( positionChanged || rollChanged ) {\n\n\t\t\t\tthis.dispatchEvent( _changeEvent );\n\n\t\t\t\tthis._lastPosition.copy( this.object.position );\n\t\t\t\tthis._lastUp.copy( this.object.up );\n\n\t\t\t}\n\n\t\t} else if ( this.object.isOrthographicCamera ) {\n\n\t\t\tthis.object.lookAt( this.target );\n\n\t\t\tconst positionChanged = this._lastPosition.distanceToSquared( this.object.position ) > _EPS;\n\t\t\tconst rollChanged = this._lastUp.distanceToSquared( this.object.up ) > _EPS;\n\t\t\tconst zoomChanged = this._lastZoom !== this.object.zoom;\n\n\t\t\tif ( positionChanged || rollChanged || zoomChanged ) {\n\n\t\t\t\tthis.dispatchEvent( _changeEvent );\n\n\t\t\t\tthis._lastPosition.copy( this.object.position );\n\t\t\t\tthis._lastUp.copy( this.object.up );\n\t\t\t\tthis._lastZoom = this.object.zoom;\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tconsole.warn( 'THREE.TrackballControls: Unsupported camera type.' );\n\n\t\t}\n\n\t}\n\n\t/**\n\t * Resets the controls to its initial state.\n\t */\n\treset() {\n\n\t\tthis.state = _STATE.NONE;\n\t\tthis.keyState = _STATE.NONE;\n\n\t\tthis.target.copy( this._target0 );\n\t\tthis.object.position.copy( this._position0 );\n\t\tthis.object.up.copy( this._up0 );\n\t\tthis.object.zoom = this._zoom0;\n\n\t\tthis.object.updateProjectionMatrix();\n\n\t\tthis._eye.subVectors( this.object.position, this.target );\n\n\t\tthis.object.lookAt( this.target );\n\n\t\tthis.dispatchEvent( _changeEvent );\n\n\t\tthis._lastPosition.copy( this.object.position );\n\t\tthis._lastUp.copy( this.object.up );\n\t\tthis._lastZoom = this.object.zoom;\n\n\t}\n\n\t_panCamera() {\n\n\t\t_mouseChange.copy( this._panEnd ).sub( this._panStart );\n\n\t\tif ( _mouseChange.lengthSq() ) {\n\n\t\t\tif ( this.object.isOrthographicCamera ) {\n\n\t\t\t\tconst scale_x = ( this.object.right - this.object.left ) / this.object.zoom / this.domElement.clientWidth;\n\t\t\t\tconst scale_y = ( this.object.top - this.object.bottom ) / this.object.zoom / this.domElement.clientWidth;\n\n\t\t\t\t_mouseChange.x *= scale_x;\n\t\t\t\t_mouseChange.y *= scale_y;\n\n\t\t\t}\n\n\t\t\t_mouseChange.multiplyScalar( this._eye.length() * this.panSpeed );\n\n\t\t\t_pan.copy( this._eye ).cross( this.object.up ).setLength( _mouseChange.x );\n\t\t\t_pan.add( _objectUp.copy( this.object.up ).setLength( _mouseChange.y ) );\n\n\t\t\tthis.object.position.add( _pan );\n\t\t\tthis.target.add( _pan );\n\n\t\t\tif ( this.staticMoving ) {\n\n\t\t\t\tthis._panStart.copy( this._panEnd );\n\n\t\t\t} else {\n\n\t\t\t\tthis._panStart.add( _mouseChange.subVectors( this._panEnd, this._panStart ).multiplyScalar( this.dynamicDampingFactor ) );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t_rotateCamera() {\n\n\t\t_moveDirection.set( this._moveCurr.x - this._movePrev.x, this._moveCurr.y - this._movePrev.y, 0 );\n\t\tlet angle = _moveDirection.length();\n\n\t\tif ( angle ) {\n\n\t\t\tthis._eye.copy( this.object.position ).sub( this.target );\n\n\t\t\t_eyeDirection.copy( this._eye ).normalize();\n\t\t\t_objectUpDirection.copy( this.object.up ).normalize();\n\t\t\t_objectSidewaysDirection.crossVectors( _objectUpDirection, _eyeDirection ).normalize();\n\n\t\t\t_objectUpDirection.setLength( this._moveCurr.y - this._movePrev.y );\n\t\t\t_objectSidewaysDirection.setLength( this._moveCurr.x - this._movePrev.x );\n\n\t\t\t_moveDirection.copy( _objectUpDirection.add( _objectSidewaysDirection ) );\n\n\t\t\t_axis.crossVectors( _moveDirection, this._eye ).normalize();\n\n\t\t\tangle *= this.rotateSpeed;\n\t\t\t_quaternion.setFromAxisAngle( _axis, angle );\n\n\t\t\tthis._eye.applyQuaternion( _quaternion );\n\t\t\tthis.object.up.applyQuaternion( _quaternion );\n\n\t\t\tthis._lastAxis.copy( _axis );\n\t\t\tthis._lastAngle = angle;\n\n\t\t} else if ( ! this.staticMoving && this._lastAngle ) {\n\n\t\t\tthis._lastAngle *= Math.sqrt( 1.0 - this.dynamicDampingFactor );\n\t\t\tthis._eye.copy( this.object.position ).sub( this.target );\n\t\t\t_quaternion.setFromAxisAngle( this._lastAxis, this._lastAngle );\n\t\t\tthis._eye.applyQuaternion( _quaternion );\n\t\t\tthis.object.up.applyQuaternion( _quaternion );\n\n\t\t}\n\n\t\tthis._movePrev.copy( this._moveCurr );\n\n\t}\n\n\t_rollCamera() {\n\n\t\tconst angle = this._getTouchRollAngle();\n\n\t\tif ( angle ) {\n\n\t\t\tthis._lastRollAngle = angle * this.rollSpeed;\n\n\t\t} else if ( ! this.staticMoving && this._lastRollAngle ) {\n\n\t\t\tthis._lastRollAngle *= Math.sqrt( 1.0 - this.dynamicDampingFactor );\n\n\t\t} else {\n\n\t\t\treturn;\n\n\t\t}\n\n\t\t_eyeDirection.copy( this._eye ).normalize();\n\t\t_quaternion.setFromAxisAngle( _eyeDirection, this._lastRollAngle );\n\n\t\tthis.object.up.applyQuaternion( _quaternion );\n\n\t}\n\n\t_getTouchRollAngle() {\n\n\t\tconst first = this._pointers[ 0 ];\n\t\tconst second = this._pointers[ 1 ];\n\n\t\tif ( second === undefined || first.pointerType !== 'touch' || second.pointerType !== 'touch' ) {\n\n\t\t\tthis._touchRollPointerIds = '';\n\t\t\treturn 0;\n\n\t\t}\n\n\t\tconst pointerIds = `${ first.pointerId },${ second.pointerId }`;\n\n\t\tconst positionFirst = this._pointerPositions[ first.pointerId ];\n\t\tconst positionSecond = this._pointerPositions[ second.pointerId ];\n\n\t\tconst rollAngle = Math.atan2( positionSecond.y - positionFirst.y, positionSecond.x - positionFirst.x );\n\n\t\t// fingers changed or new gesture started\n\t\tif ( pointerIds !== this._touchRollPointerIds ) {\n\n\t\t\tthis._touchRollPointerIds = pointerIds;\n\t\t\tthis._touchRollAngle = rollAngle;\n\t\t\treturn 0;\n\n\t\t}\n\n\t\tlet angle = rollAngle - this._touchRollAngle;\n\t\tthis._touchRollAngle = rollAngle;\n\n\t\tif ( angle > Math.PI ) {\n\n\t\t\tangle -= 2 * Math.PI;\n\n\t\t} else if ( angle < - Math.PI ) {\n\n\t\t\tangle += 2 * Math.PI;\n\n\t\t}\n\n\t\treturn angle;\n\n\t}\n\n\t_zoomCamera() {\n\n\t\tlet factor;\n\n\t\tif ( this.state === _STATE.TOUCH_ZOOM_PAN ) {\n\n\t\t\tfactor = this._touchZoomDistanceStart / this._touchZoomDistanceEnd;\n\t\t\tthis._touchZoomDistanceStart = this._touchZoomDistanceEnd;\n\n\t\t\tif ( this.object.isPerspectiveCamera ) {\n\n\t\t\t\tthis._eye.multiplyScalar( factor );\n\n\t\t\t} else if ( this.object.isOrthographicCamera ) {\n\n\t\t\t\tthis.object.zoom = MathUtils.clamp( this.object.zoom / factor, this.minZoom, this.maxZoom );\n\n\t\t\t\tif ( this._lastZoom !== this.object.zoom ) {\n\n\t\t\t\t\tthis.object.updateProjectionMatrix();\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tconsole.warn( 'THREE.TrackballControls: Unsupported camera type' );\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tfactor = 1.0 + ( this._zoomEnd.y - this._zoomStart.y ) * this.zoomSpeed;\n\n\t\t\tif ( factor !== 1.0 && factor > 0.0 ) {\n\n\t\t\t\tif ( this.object.isPerspectiveCamera ) {\n\n\t\t\t\t\tthis._eye.multiplyScalar( factor );\n\n\t\t\t\t} else if ( this.object.isOrthographicCamera ) {\n\n\t\t\t\t\tthis.object.zoom = MathUtils.clamp( this.object.zoom / factor, this.minZoom, this.maxZoom );\n\n\t\t\t\t\tif ( this._lastZoom !== this.object.zoom ) {\n\n\t\t\t\t\t\tthis.object.updateProjectionMatrix();\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\tconsole.warn( 'THREE.TrackballControls: Unsupported camera type' );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( this.staticMoving ) {\n\n\t\t\t\tthis._zoomStart.copy( this._zoomEnd );\n\n\t\t\t} else {\n\n\t\t\t\tthis._zoomStart.y += ( this._zoomEnd.y - this._zoomStart.y ) * this.dynamicDampingFactor;\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t_getMouseOnScreen( pageX, pageY ) {\n\n\t\t_v2.set(\n\t\t\t( pageX - this.screen.left ) / this.screen.width,\n\t\t\t( pageY - this.screen.top ) / this.screen.height\n\t\t);\n\n\t\treturn _v2;\n\n\t}\n\n\t_getMouseOnCircle( pageX, pageY ) {\n\n\t\t_v2.set(\n\t\t\t( ( pageX - this.screen.width * 0.5 - this.screen.left ) / ( this.screen.width * 0.5 ) ),\n\t\t\t( ( this.screen.height + 2 * ( this.screen.top - pageY ) ) / this.screen.width ) // screen.width intentional\n\t\t);\n\n\t\treturn _v2;\n\n\t}\n\n\t_addPointer( event ) {\n\n\t\tthis._pointers.push( event );\n\n\t}\n\n\t_removePointer( event ) {\n\n\t\tdelete this._pointerPositions[ event.pointerId ];\n\n\t\tfor ( let i = 0; i < this._pointers.length; i ++ ) {\n\n\t\t\tif ( this._pointers[ i ].pointerId == event.pointerId ) {\n\n\t\t\t\tthis._pointers.splice( i, 1 );\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t_trackPointer( event ) {\n\n\t\tlet position = this._pointerPositions[ event.pointerId ];\n\n\t\tif ( position === undefined ) {\n\n\t\t\tposition = new Vector2();\n\t\t\tthis._pointerPositions[ event.pointerId ] = position;\n\n\t\t}\n\n\t\tposition.set( event.pageX, event.pageY );\n\n\t}\n\n\t_getSecondPointerPosition( event ) {\n\n\t\tconst pointer = ( event.pointerId === this._pointers[ 0 ].pointerId ) ? this._pointers[ 1 ] : this._pointers[ 0 ];\n\n\t\treturn this._pointerPositions[ pointer.pointerId ];\n\n\t}\n\n\t_checkDistances() {\n\n\t\tif ( ! this.noZoom || ! this.noPan ) {\n\n\t\t\tif ( this._eye.lengthSq() > this.maxDistance * this.maxDistance ) {\n\n\t\t\t\tthis.object.position.addVectors( this.target, this._eye.setLength( this.maxDistance ) );\n\t\t\t\tthis._zoomStart.copy( this._zoomEnd );\n\n\t\t\t}\n\n\t\t\tif ( this._eye.lengthSq() < this.minDistance * this.minDistance ) {\n\n\t\t\t\tthis.object.position.addVectors( this.target, this._eye.setLength( this.minDistance ) );\n\t\t\t\tthis._zoomStart.copy( this._zoomEnd );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n\nfunction onPointerDown( event ) {\n\n\tif ( this.enabled === false ) return;\n\n\tif ( this._pointers.length === 0 ) {\n\n\t\tthis.domElement.setPointerCapture( event.pointerId );\n\n\t\tthis.domElement.ownerDocument.addEventListener( 'pointermove', this._onPointerMove );\n\t\tthis.domElement.ownerDocument.addEventListener( 'pointerup', this._onPointerUp );\n\n\t}\n\n\t//\n\n\tthis._addPointer( event );\n\n\tif ( event.pointerType === 'touch' ) {\n\n\t\tthis._onTouchStart( event );\n\n\t} else {\n\n\t\tthis._onMouseDown( event );\n\n\t}\n\n}\n\nfunction onPointerMove( event ) {\n\n\tif ( this.enabled === false ) return;\n\n\tif ( event.pointerType === 'touch' ) {\n\n\t\tthis._onTouchMove( event );\n\n\t} else {\n\n\t\tthis._onMouseMove( event );\n\n\t}\n\n}\n\nfunction onPointerUp( event ) {\n\n\tif ( this.enabled === false ) return;\n\n\tif ( event.pointerType === 'touch' ) {\n\n\t\tthis._onTouchEnd( event );\n\n\t} else {\n\n\t\tthis._onMouseUp();\n\n\t}\n\n\t//\n\n\tthis._removePointer( event );\n\n\tif ( this._pointers.length === 0 ) {\n\n\t\tthis.domElement.releasePointerCapture( event.pointerId );\n\n\t\tthis.domElement.ownerDocument.removeEventListener( 'pointermove', this._onPointerMove );\n\t\tthis.domElement.ownerDocument.removeEventListener( 'pointerup', this._onPointerUp );\n\n\t}\n\n}\n\nfunction onPointerCancel( event ) {\n\n\tthis._removePointer( event );\n\n}\n\nfunction onKeyUp() {\n\n\tif ( this.enabled === false ) return;\n\n\tthis.keyState = _STATE.NONE;\n\n\twindow.addEventListener( 'keydown', this._onKeyDown );\n\n}\n\nfunction onKeyDown( event ) {\n\n\tif ( this.enabled === false ) return;\n\n\twindow.removeEventListener( 'keydown', this._onKeyDown );\n\n\tif ( this.keyState !== _STATE.NONE ) {\n\n\t\treturn;\n\n\t} else if ( event.code === this.keys[ _STATE.ROTATE ] && ! this.noRotate ) {\n\n\t\tthis.keyState = _STATE.ROTATE;\n\n\t} else if ( event.code === this.keys[ _STATE.ZOOM ] && ! this.noZoom ) {\n\n\t\tthis.keyState = _STATE.ZOOM;\n\n\t} else if ( event.code === this.keys[ _STATE.PAN ] && ! this.noPan ) {\n\n\t\tthis.keyState = _STATE.PAN;\n\n\t}\n\n}\n\nfunction onMouseDown( event ) {\n\n\tlet mouseAction;\n\n\tswitch ( event.button ) {\n\n\t\tcase 0:\n\t\t\tmouseAction = this.mouseButtons.LEFT;\n\t\t\tbreak;\n\n\t\tcase 1:\n\t\t\tmouseAction = this.mouseButtons.MIDDLE;\n\t\t\tbreak;\n\n\t\tcase 2:\n\t\t\tmouseAction = this.mouseButtons.RIGHT;\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tmouseAction = - 1;\n\n\t}\n\n\tswitch ( mouseAction ) {\n\n\t\tcase MOUSE.DOLLY:\n\t\t\tthis.state = _STATE.ZOOM;\n\t\t\tbreak;\n\n\t\tcase MOUSE.ROTATE:\n\t\t\tthis.state = _STATE.ROTATE;\n\t\t\tbreak;\n\n\t\tcase MOUSE.PAN:\n\t\t\tthis.state = _STATE.PAN;\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tthis.state = _STATE.NONE;\n\n\t}\n\n\tconst state = ( this.keyState !== _STATE.NONE ) ? this.keyState : this.state;\n\n\tif ( state === _STATE.ROTATE && ! this.noRotate ) {\n\n\t\tthis._moveCurr.copy( this._getMouseOnCircle( event.pageX, event.pageY ) );\n\t\tthis._movePrev.copy( this._moveCurr );\n\n\t} else if ( state === _STATE.ZOOM && ! this.noZoom ) {\n\n\t\tthis._zoomStart.copy( this._getMouseOnScreen( event.pageX, event.pageY ) );\n\t\tthis._zoomEnd.copy( this._zoomStart );\n\n\t} else if ( state === _STATE.PAN && ! this.noPan ) {\n\n\t\tthis._panStart.copy( this._getMouseOnScreen( event.pageX, event.pageY ) );\n\t\tthis._panEnd.copy( this._panStart );\n\n\t}\n\n\tthis.dispatchEvent( _startEvent );\n\n}\n\nfunction onMouseMove( event ) {\n\n\tconst state = ( this.keyState !== _STATE.NONE ) ? this.keyState : this.state;\n\n\tif ( state === _STATE.ROTATE && ! this.noRotate ) {\n\n\t\tthis._moveCurr.copy( this._getMouseOnCircle( event.pageX, event.pageY ) );\n\n\t} else if ( state === _STATE.ZOOM && ! this.noZoom ) {\n\n\t\tthis._zoomEnd.copy( this._getMouseOnScreen( event.pageX, event.pageY ) );\n\n\t} else if ( state === _STATE.PAN && ! this.noPan ) {\n\n\t\tthis._panEnd.copy( this._getMouseOnScreen( event.pageX, event.pageY ) );\n\n\t}\n\n}\n\nfunction onMouseUp() {\n\n\tthis.state = _STATE.NONE;\n\n\tthis.dispatchEvent( _endEvent );\n\n}\n\nfunction onMouseWheel( event ) {\n\n\tif ( this.enabled === false ) return;\n\n\tif ( this.noZoom === true ) return;\n\n\tevent.preventDefault();\n\n\tswitch ( event.deltaMode ) {\n\n\t\tcase 2:\n\t\t\t// Zoom in pages\n\t\t\tthis._zoomStart.y -= event.deltaY * 0.025;\n\t\t\tbreak;\n\n\t\tcase 1:\n\t\t\t// Zoom in lines\n\t\t\tthis._zoomStart.y -= event.deltaY * 0.01;\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\t// undefined, 0, assume pixels\n\t\t\tthis._zoomStart.y -= event.deltaY * 0.00025;\n\t\t\tbreak;\n\n\t}\n\n\tthis.dispatchEvent( _startEvent );\n\tthis.dispatchEvent( _endEvent );\n\n}\n\nfunction onContextMenu( event ) {\n\n\tif ( this.enabled === false ) return;\n\n\tevent.preventDefault();\n\n}\n\nfunction onTouchStart( event ) {\n\n\tthis._trackPointer( event );\n\n\tswitch ( this._pointers.length ) {\n\n\t\tcase 1:\n\t\t\tthis.state = _STATE.TOUCH_ROTATE;\n\t\t\tthis._moveCurr.copy( this._getMouseOnCircle( this._pointers[ 0 ].pageX, this._pointers[ 0 ].pageY ) );\n\t\t\tthis._movePrev.copy( this._moveCurr );\n\t\t\tbreak;\n\n\t\tdefault: // 2 or more\n\t\t\tthis.state = _STATE.TOUCH_ZOOM_PAN;\n\t\t\tconst dx = this._pointers[ 0 ].pageX - this._pointers[ 1 ].pageX;\n\t\t\tconst dy = this._pointers[ 0 ].pageY - this._pointers[ 1 ].pageY;\n\t\t\tthis._touchZoomDistanceEnd = this._touchZoomDistanceStart = Math.sqrt( dx * dx + dy * dy );\n\n\t\t\tconst x = ( this._pointers[ 0 ].pageX + this._pointers[ 1 ].pageX ) / 2;\n\t\t\tconst y = ( this._pointers[ 0 ].pageY + this._pointers[ 1 ].pageY ) / 2;\n\t\t\tthis._panStart.copy( this._getMouseOnScreen( x, y ) );\n\t\t\tthis._panEnd.copy( this._panStart );\n\t\t\tbreak;\n\n\t}\n\n\tthis.dispatchEvent( _startEvent );\n\n}\n\nfunction onTouchMove( event ) {\n\n\tthis._trackPointer( event );\n\n\tswitch ( this._pointers.length ) {\n\n\t\tcase 1:\n\t\t\tthis._moveCurr.copy( this._getMouseOnCircle( event.pageX, event.pageY ) );\n\t\t\tbreak;\n\n\t\tdefault: // 2 or more\n\n\t\t\tconst position = this._getSecondPointerPosition( event );\n\n\t\t\tconst dx = event.pageX - position.x;\n\t\t\tconst dy = event.pageY - position.y;\n\t\t\tthis._touchZoomDistanceEnd = Math.sqrt( dx * dx + dy * dy );\n\n\t\t\tconst x = ( event.pageX + position.x ) / 2;\n\t\t\tconst y = ( event.pageY + position.y ) / 2;\n\t\t\tthis._panEnd.copy( this._getMouseOnScreen( x, y ) );\n\t\t\tbreak;\n\n\t}\n\n}\n\nfunction onTouchEnd( event ) {\n\n\tswitch ( this._pointers.length ) {\n\n\t\tcase 0:\n\t\t\tthis.state = _STATE.NONE;\n\t\t\tbreak;\n\n\t\tcase 1:\n\t\t\tthis.state = _STATE.TOUCH_ROTATE;\n\t\t\tthis._moveCurr.copy( this._getMouseOnCircle( event.pageX, event.pageY ) );\n\t\t\tthis._movePrev.copy( this._moveCurr );\n\t\t\tbreak;\n\n\t\tcase 2:\n\t\t\tthis.state = _STATE.TOUCH_ZOOM_PAN;\n\n\t\t\tfor ( let i = 0; i < this._pointers.length; i ++ ) {\n\n\t\t\t\tif ( this._pointers[ i ].pointerId !== event.pointerId ) {\n\n\t\t\t\t\tconst position = this._pointerPositions[ this._pointers[ i ].pointerId ];\n\t\t\t\t\tthis._moveCurr.copy( this._getMouseOnCircle( position.x, position.y ) );\n\t\t\t\t\tthis._movePrev.copy( this._moveCurr );\n\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tbreak;\n\n\t}\n\n\tthis.dispatchEvent( _endEvent );\n\n}\n\nexport { TrackballControls };\n","import { Box3, Matrix4, OrthographicCamera, Quaternion, Vector3 } from \"three\";\n\nimport type { Mat3 } from \"../structure/types.js\";\nimport type { ViewState } from \"./view-state.js\";\n\n/**\n * The standard view is Naumann's clinographic projection, the convention of\n * crystal drawings and Pretty Lattice's default: c vertical, the crystal\n * turned by arctan(1/3) about c and tilted toward the viewer by arctan(1/6).\n */\nconst NAUMANN_HORIZONTAL_RATIO = 1 / 3;\nconst NAUMANN_VERTICAL_RATIO = 1 / 6;\n/** The projected cell takes half the viewport's geometric mean size. */\nconst PROJECTED_FIT_PADDING_RATIO = 2;\nconst EPSILON = 1e-12;\nconst CAMERA_FORWARD = new Vector3(0, 0, -1);\nconst CAMERA_UP = new Vector3(0, 1, 0);\n\nfunction projectPerpendicular(vector: Vector3, axis: Vector3): Vector3 | null {\n const projected = vector\n .clone()\n .sub(axis.clone().multiplyScalar(vector.dot(axis)));\n return projected.lengthSq() < EPSILON ? null : projected.normalize();\n}\n\nfunction stablePerpendicular(axis: Vector3): Vector3 {\n for (const candidate of [\n new Vector3(0, 0, 1),\n new Vector3(0, 1, 0),\n new Vector3(1, 0, 0),\n ]) {\n const projected = projectPerpendicular(candidate, axis);\n if (projected) {\n return projected;\n }\n }\n return new Vector3(0, 1, 0);\n}\n\n/** Camera outward direction and up vector of the standard view of a cell. */\nexport function standardViewVectors(cell: Mat3): {\n outward: Vector3;\n up: Vector3;\n} {\n const a = new Vector3(...cell[0]);\n const b = new Vector3(...cell[1]);\n const vertical = new Vector3(...cell[2]).normalize();\n const basalReference =\n projectPerpendicular(a, vertical) ??\n projectPerpendicular(b, vertical) ??\n stablePerpendicular(vertical);\n const basalRight = vertical.clone().cross(basalReference).normalize();\n const outward = basalReference\n .clone()\n .add(basalRight.multiplyScalar(NAUMANN_HORIZONTAL_RATIO))\n .add(vertical.clone().multiplyScalar(NAUMANN_VERTICAL_RATIO))\n .normalize();\n const up =\n projectPerpendicular(vertical, outward) ?? stablePerpendicular(outward);\n return { outward, up };\n}\n\n/** Distance of the orthographic camera from its target; only the clipping depends on it. */\nexport function cameraDistance(span: number): number {\n return Math.max(4, span * 4);\n}\n\nexport function standardQuaternion(cell: Mat3): Quaternion {\n const { outward, up } = standardViewVectors(cell);\n const right = up.clone().cross(outward).normalize();\n const correctedUp = outward.clone().cross(right).normalize();\n const basis = new Matrix4().makeBasis(right, correctedUp, outward);\n return new Quaternion().setFromRotationMatrix(basis).normalize();\n}\n\n/** The standard view of a cell as a view state: standard orientation, centred, fitted. */\nexport function standardView(cell: Mat3): ViewState {\n return {\n quaternion: quaternionTuple(standardQuaternion(cell)),\n target: [0, 0, 0],\n scale: 1,\n };\n}\n\n/** Pose a camera from a view state. */\nexport function applyViewState(\n camera: OrthographicCamera,\n view: Pick<ViewState, \"quaternion\" | \"target\">,\n distance: number,\n span: number,\n): void {\n const quaternion = new Quaternion(...view.quaternion).normalize();\n const target = new Vector3(...view.target);\n const forward = CAMERA_FORWARD.clone().applyQuaternion(quaternion);\n camera.position.copy(target).sub(forward.multiplyScalar(distance));\n camera.up.copy(CAMERA_UP.clone().applyQuaternion(quaternion));\n camera.quaternion.copy(quaternion);\n camera.near = 0.01;\n camera.far = Math.max(1000, distance + span * 8);\n camera.updateProjectionMatrix();\n}\n\n/** The orientation of a camera as a view-state quaternion. */\nexport function quaternionTuple(\n quaternion: Quaternion,\n): [number, number, number, number] {\n return [quaternion.x, quaternion.y, quaternion.z, quaternion.w];\n}\n\n/** Size of `bounds` projected on the screen plane of `quaternion`. */\nexport function projectedSize(\n bounds: Box3,\n quaternion: Quaternion,\n): { width: number; height: number } {\n const right = new Vector3(1, 0, 0).applyQuaternion(quaternion);\n const up = new Vector3(0, 1, 0).applyQuaternion(quaternion);\n let minX = Infinity;\n let maxX = -Infinity;\n let minY = Infinity;\n let maxY = -Infinity;\n for (const x of [bounds.min.x, bounds.max.x]) {\n for (const y of [bounds.min.y, bounds.max.y]) {\n for (const z of [bounds.min.z, bounds.max.z]) {\n const corner = new Vector3(x, y, z);\n const px = corner.dot(right);\n const py = corner.dot(up);\n minX = Math.min(minX, px);\n maxX = Math.max(maxX, px);\n minY = Math.min(minY, py);\n maxY = Math.max(maxY, py);\n }\n }\n }\n return { width: Math.max(1, maxX - minX), height: Math.max(1, maxY - minY) };\n}\n\n/** Orthographic zoom (pixels per ångström) that fits `bounds` in the viewport. */\nexport function fitZoom(\n bounds: Box3,\n quaternion: Quaternion,\n width: number,\n height: number,\n): number {\n const projected = projectedSize(bounds, quaternion);\n const availableLength = Math.sqrt(Math.max(1, width) * Math.max(1, height));\n const projectedLength = Math.sqrt(projected.width * projected.height);\n return Math.max(\n 0.01,\n availableLength / (projectedLength * PROJECTED_FIT_PADDING_RATIO),\n );\n}\n\n/** Frustum of an orthographic camera in pixel units, so `zoom` is pixels per ångström. */\nexport function applyPixelFrustum(\n camera: OrthographicCamera,\n width: number,\n height: number,\n): void {\n camera.left = -width / 2;\n camera.right = width / 2;\n camera.top = height / 2;\n camera.bottom = -height / 2;\n camera.updateProjectionMatrix();\n}\n","import {\n AlwaysStencilFunc,\n DataTexture,\n DoubleSide,\n LineBasicMaterial,\n MeshStandardMaterial,\n ReplaceStencilOp,\n} from \"three\";\n\n// Material and lighting currently follow Pretty Lattice's default (its\n// \"modern matte\" preset).\nexport const METALNESS = 0.1;\nexport const ROUGHNESS = 0.6;\nexport const AMBIENT_LIGHT_INTENSITY = 0.8;\nexport const HEADLIGHT_INTENSITY = 2.2;\nexport const HEADLIGHT_OFFSET: readonly [number, number, number] = [\n 0.3, 0.2, 0,\n];\nexport const BACKGROUND_COLOR = \"#fafafa\";\nexport const CELL_FRAME_COLOR = \"#444444\";\n/** The part of a partially occupied site nobody occupies: a faint, see-through tint. */\nexport const VACANCY_COLOR = \"#f2f2f2\";\nexport const VACANCY_OPACITY = 0.3;\n/** Added to a vacancy texel's start fraction so the shader can tell it apart. */\nexport const VACANCY_FLAG = 2;\n\nconst TWO_PI = \"6.28318530718\";\n\n/**\n * Insert code at includes of a three.js built-in shader, each `[include,\n * code]` replacing the include. A three.js release that renames or drops\n * one fails here by name, instead of drawing flat squares.\n */\nfunction patchShader(\n shader: string,\n patches: [include: string, code: string][],\n): string {\n return patches.reduce((source, [include, code]) => {\n if (!source.includes(include)) {\n throw new Error(\n `bravais cannot draw with this three.js: its shader has no ${include}.`,\n );\n }\n return source.replace(include, code);\n }, shader);\n}\n\n/**\n * Occupancy sectors live in a texture: each site owns a run of texels, each\n * holding the colour of one sector and the angle fraction where it begins.\n * The first sector takes the instance colour; the rest, and the vacancy,\n * come from the texels. Unused texels start at 1, which no angle reaches.\n */\nexport const SECTOR_TEXELS_PER_SITE = 8;\nexport const SECTOR_SITES_PER_ROW = 256;\n\n/**\n * Atoms are ray-cast spheres. Each instance is a camera-facing quad of the\n * sphere's size; the fragment shader finds where the pixel's view ray meets\n * the sphere, writes that depth and shades with the sphere's normal. The\n * outline, and the cut where a bond enters, are then exact at any zoom, for\n * four vertices per atom. The cameras are orthographic, so the view ray is\n * the view z axis and the depth is linear in view z.\n */\nfunction atomVertexShader(shader: string): string {\n return patchShader(shader, [\n [\n \"#include <common>\",\n `#include <common>\nflat varying int vSectorSite;\nflat varying vec3 vSphereCenter;\nflat varying float vSphereRadius;\nflat varying vec2 vDepthCoefficients;\nvarying vec3 vSpherePoint;`,\n ],\n [\n \"#include <project_vertex>\",\n `mat4 sphereMatrix = modelViewMatrix * instanceMatrix;\nvSphereCenter = sphereMatrix[3].xyz;\nvSphereRadius = length(sphereMatrix[0].xyz);\nvSpherePoint = vSphereCenter + vec3(position.xy * vSphereRadius, 0.0);\nvDepthCoefficients = vec2(projectionMatrix[2][2], projectionMatrix[3][2]);\nvSectorSite = gl_InstanceID;\nvec4 mvPosition = vec4(vSpherePoint, 1.0);\ngl_Position = projectionMatrix * mvPosition;`,\n ],\n ]);\n}\n\nfunction atomFragmentShader(shader: string): string {\n return patchShader(shader, [\n [\n \"#include <common>\",\n `#include <common>\nuniform sampler2D sectorTexture;\nuniform float vacancyOpacity;\nflat varying int vSectorSite;\nflat varying vec3 vSphereCenter;\nflat varying float vSphereRadius;\nflat varying vec2 vDepthCoefficients;\nvarying vec3 vSpherePoint;`,\n ],\n [\n \"#include <clipping_planes_fragment>\",\n `// Where the view ray meets the sphere. The outline is smoothed over one\n// pixel through the alpha: sample coverage, or blending in a see-through layer.\nvec2 sphereOffset = vSpherePoint.xy - vSphereCenter.xy;\nfloat sphereDistance = length(sphereOffset);\nfloat sphereCoverage = clamp(\n (vSphereRadius - sphereDistance) / max(fwidth(sphereDistance), 1e-6) + 0.5,\n 0.0,\n 1.0\n);\nif (sphereCoverage <= 0.0) {\n discard;\n}\nfloat sphereHeight = sqrt(\n max(0.0, vSphereRadius * vSphereRadius - dot(sphereOffset, sphereOffset))\n);\nvec3 sphereNormal = vec3(sphereOffset, sphereHeight) / vSphereRadius;\nfloat sphereZ = vSphereCenter.z + sphereHeight;\ngl_FragDepth = (vDepthCoefficients.x * sphereZ + vDepthCoefficients.y) * 0.5 + 0.5;\n#include <clipping_planes_fragment>`,\n ],\n [\n \"#include <color_fragment>\",\n `#include <color_fragment>\n{\n // A pie chart facing the viewer, like VESTA's occupancy pies: the instance\n // colour fills the first sector from 12 o'clock clockwise, then each\n // texel's colour from its stop on.\n float sectorAngle = fract(atan(sphereOffset.x, sphereOffset.y) / ${TWO_PI});\n vec3 sectorColor = vColor.rgb;\n float sectorOpacity = 1.0;\n int sectorRow = vSectorSite / ${SECTOR_SITES_PER_ROW};\n int sectorColumn = (vSectorSite - sectorRow * ${SECTOR_SITES_PER_ROW}) * ${SECTOR_TEXELS_PER_SITE};\n for (int k = 0; k < ${SECTOR_TEXELS_PER_SITE}; k++) {\n vec4 sector = texelFetch(sectorTexture, ivec2(sectorColumn + k, sectorRow), 0);\n bool vacant = sector.a >= ${VACANCY_FLAG}.0;\n float start = vacant ? sector.a - ${VACANCY_FLAG}.0 : sector.a;\n if (sectorAngle >= start) {\n sectorColor = sector.rgb;\n sectorOpacity = vacant ? vacancyOpacity : 1.0;\n }\n }\n diffuseColor.rgb = diffuse * sectorColor;\n diffuseColor.a *= sectorOpacity * sphereCoverage;\n}`,\n ],\n [\n \"#include <normal_fragment_begin>\",\n `#include <normal_fragment_begin>\nnormal = sphereNormal;\nnonPerturbedNormal = normal;`,\n ],\n ]);\n}\n\n/**\n * Atom material: the matte preset drawing ray-cast spheres with occupancy\n * sectors read from `sectorTexture`. A layer with vacancies is blended so\n * their sectors show what lies behind; one without stays on the opaque path\n * and smooths its outlines through sample coverage.\n */\nexport function createAtomMaterial(\n opacity: number,\n sectorTexture: DataTexture,\n hasVacancies: boolean,\n): MeshStandardMaterial {\n const transparent = opacity < 1 || hasVacancies;\n const material = new MeshStandardMaterial({\n color: \"#ffffff\",\n metalness: METALNESS,\n roughness: ROUGHNESS,\n opacity,\n transparent,\n alphaToCoverage: !transparent,\n });\n material.onBeforeCompile = (shader) => {\n shader.uniforms.sectorTexture = { value: sectorTexture };\n shader.uniforms.vacancyOpacity = { value: VACANCY_OPACITY };\n shader.vertexShader = atomVertexShader(shader.vertexShader);\n shader.fragmentShader = atomFragmentShader(shader.fragmentShader);\n };\n material.customProgramCacheKey = () => \"bravais-atom-spheres\";\n return material;\n}\n\n/**\n * Bonds are ray-cast tubes, one half per instance. Each instance is the box\n * around its half; the fragment shader finds where the pixel's view ray\n * enters the solid tube, which is cut on the atom's sphere at the atom end\n * and flat at the bond midpoint, writes that depth and shades with the\n * surface normal. The wall, the cut where a tube meets its sphere and every\n * crossing with another sphere are then exact at any zoom.\n */\nfunction bondVertexShader(shader: string): string {\n return patchShader(shader, [\n [\n \"#include <common>\",\n `#include <common>\nuniform float capRadius;\nflat varying vec3 vTubeCenter;\nflat varying vec3 vTubeAxis;\nflat varying vec3 vAtomCenter;\nflat varying float vTubeRadius;\nflat varying float vTubeHalfLength;\nflat varying vec2 vDepthCoefficients;\nvarying vec3 vBoxPoint;`,\n ],\n [\n \"#include <project_vertex>\",\n `mat4 tubeMatrix = modelViewMatrix * instanceMatrix;\nfloat tubeLength = max(length(tubeMatrix[1].xyz), 1e-6);\nvTubeRadius = length(tubeMatrix[0].xyz);\nvTubeHalfLength = tubeLength * 0.5;\nvTubeCenter = tubeMatrix[3].xyz;\nvTubeAxis = tubeMatrix[1].xyz / tubeLength;\nfloat rim = sqrt(max(0.0, capRadius * capRadius - vTubeRadius * vTubeRadius));\nvAtomCenter = vTubeCenter - vTubeAxis * (rim + vTubeHalfLength);\nvDepthCoefficients = vec2(projectionMatrix[2][2], projectionMatrix[3][2]);\nvec4 mvPosition = tubeMatrix * vec4(position, 1.0);\nvBoxPoint = mvPosition.xyz;\ngl_Position = projectionMatrix * mvPosition;`,\n ],\n ]);\n}\n\nfunction bondFragmentShader(shader: string): string {\n return patchShader(shader, [\n [\n \"#include <common>\",\n `#include <common>\nuniform float capRadius;\nflat varying vec3 vTubeCenter;\nflat varying vec3 vTubeAxis;\nflat varying vec3 vAtomCenter;\nflat varying float vTubeRadius;\nflat varying float vTubeHalfLength;\nflat varying vec2 vDepthCoefficients;\nvarying vec3 vBoxPoint;`,\n ],\n [\n \"#include <clipping_planes_fragment>\",\n `// The view ray through this pixel runs down view z. The tube's surface is\n// the nearest of: the wall outside the atom's sphere, the sphere's far side\n// inside the tube (the cut face) and the midpoint disc. Along the ray,\n// q(z) = p(z) - centre has q.a = k + (z - cz) a.z and |q|^2 = u + (z - cz)^2.\nvec2 tubePixel = vBoxPoint.xy;\nvec2 tubeOffset = tubePixel - vTubeCenter.xy;\nfloat tubeK = dot(tubeOffset, vTubeAxis.xy);\nfloat tubeU = dot(tubeOffset, tubeOffset);\nfloat axisZ = vTubeAxis.z;\nfloat quadA = 1.0 - axisZ * axisZ;\nfloat quadB = -2.0 * tubeK * axisZ;\nfloat quadC = tubeU - tubeK * tubeK - vTubeRadius * vTubeRadius;\nfloat tubeRadius2 = vTubeRadius * vTubeRadius;\n// The ray's closest approach to the axis, for the outline's coverage.\nfloat axisDistance2 = tubeU - tubeK * tubeK;\nif (quadA > 1e-6) {\n axisDistance2 -= quadB * quadB / (4.0 * quadA);\n}\nfloat axisDistance = sqrt(max(0.0, axisDistance2));\nfloat tubeCoverage = clamp(\n (vTubeRadius - axisDistance) / max(fwidth(axisDistance), 1e-6) + 0.5,\n 0.0,\n 1.0\n);\nif (tubeCoverage <= 0.0) {\n discard;\n}\nfloat tubeHitZ = -1e30;\nvec3 tubeNormal = vec3(0.0, 0.0, 1.0);\nif (quadA > 1e-6) {\n float discriminant = quadB * quadB - 4.0 * quadA * quadC;\n if (discriminant >= 0.0) {\n float z = vTubeCenter.z + (-quadB + sqrt(discriminant)) / (2.0 * quadA);\n vec3 d = vec3(tubePixel, z) - vTubeCenter;\n float s = dot(d, vTubeAxis);\n if (abs(s) <= vTubeHalfLength && distance(vec3(tubePixel, z), vAtomCenter) >= capRadius) {\n tubeHitZ = z;\n tubeNormal = (d - s * vTubeAxis) / vTubeRadius;\n }\n }\n}\nif (axisZ > 1e-6) {\n float z = vTubeCenter.z + (vTubeHalfLength - tubeK) / axisZ;\n vec3 d = vec3(tubePixel, z) - vTubeCenter;\n if (dot(d, d) - vTubeHalfLength * vTubeHalfLength <= tubeRadius2 && z > tubeHitZ &&\n distance(vec3(tubePixel, z), vAtomCenter) >= capRadius) {\n tubeHitZ = z;\n tubeNormal = vTubeAxis;\n }\n}\n{\n vec2 m = tubePixel - vAtomCenter.xy;\n float inside = capRadius * capRadius - dot(m, m);\n if (inside >= 0.0) {\n float z = vAtomCenter.z - sqrt(inside);\n vec3 d = vec3(tubePixel, z) - vTubeCenter;\n float s = dot(d, vTubeAxis);\n if (abs(s) <= vTubeHalfLength && dot(d, d) - s * s <= tubeRadius2 && z > tubeHitZ) {\n tubeHitZ = z;\n tubeNormal = (vAtomCenter - vec3(tubePixel, z)) / capRadius;\n }\n }\n}\nif (tubeHitZ < -1e29) {\n discard;\n}\ngl_FragDepth = (vDepthCoefficients.x * tubeHitZ + vDepthCoefficients.y) * 0.5 + 0.5;\n#include <clipping_planes_fragment>`,\n ],\n [\n \"#include <color_fragment>\",\n `#include <color_fragment>\ndiffuseColor.a *= tubeCoverage;`,\n ],\n [\n \"#include <normal_fragment_begin>\",\n `#include <normal_fragment_begin>\nnormal = tubeNormal;\nnonPerturbedNormal = normal;`,\n ],\n ]);\n}\n\n/**\n * Bond material: the matte preset drawing ray-cast tubes cut on their atoms'\n * spheres of radius `capRadius`.\n */\nexport function createBondMaterial(\n opacity: number,\n capRadius: number,\n): MeshStandardMaterial {\n const transparent = opacity < 1;\n const material = new MeshStandardMaterial({\n color: \"#ffffff\",\n metalness: METALNESS,\n roughness: ROUGHNESS,\n opacity,\n transparent,\n alphaToCoverage: !transparent,\n });\n material.onBeforeCompile = (shader) => {\n shader.uniforms.capRadius = { value: capRadius };\n shader.vertexShader = bondVertexShader(shader.vertexShader);\n shader.fragmentShader = bondFragmentShader(shader.fragmentShader);\n };\n material.customProgramCacheKey = () => \"bravais-bond-tubes\";\n return material;\n}\n\nexport function createCellFrameMaterial(opacity: number): LineBasicMaterial {\n return new LineBasicMaterial({\n color: CELL_FRAME_COLOR,\n opacity,\n transparent: true,\n fog: false,\n });\n}\n\n/** Stencil value the gizmo's arrows leave on every pixel they cover. */\nexport const GIZMO_AXIS_STENCIL = 1;\n\n/**\n * A gizmo surface. `stencilRef` is written wherever the surface is the one\n * seen: GIZMO_AXIS_STENCIL for the arrows, 0 for the origin ball, so the\n * axis letters can tell what they are drawn over.\n */\nexport function createGizmoMaterial(\n color: string,\n stencilRef: number,\n): MeshStandardMaterial {\n return new MeshStandardMaterial({\n color,\n metalness: 0,\n roughness: 0.8,\n side: DoubleSide,\n stencilWrite: true,\n stencilRef,\n stencilFunc: AlwaysStencilFunc,\n stencilZPass: ReplaceStencilOp,\n });\n}\n","import {\n AmbientLight,\n CanvasTexture,\n ConeGeometry,\n CylinderGeometry,\n DirectionalLight,\n EqualStencilFunc,\n Group,\n LinearFilter,\n LinearMipmapLinearFilter,\n Mesh,\n NotEqualStencilFunc,\n OrthographicCamera,\n Quaternion,\n SRGBColorSpace,\n Scene,\n Sprite,\n SpriteMaterial,\n SphereGeometry,\n Vector3,\n type WebGLRenderer,\n} from \"three\";\n\nimport type { Mat3 } from \"../structure/types.js\";\nimport { GIZMO_AXIS_STENCIL, createGizmoMaterial } from \"./materials.js\";\n\n/** Axis colours and proportions currently follow Pretty Lattice's gizmo. */\nconst AXIS_COLORS = { a: \"#d27686\", b: \"#80c393\", c: \"#75a4dd\" } as const;\nconst SHAFT_LENGTH = 0.82;\nconst SHAFT_RADIUS = 0.055;\nconst CONE_LENGTH = 0.24;\nconst CONE_RADIUS = 0.13;\nconst ORIGIN_RADIUS = 0.13;\nconst LABEL_DISTANCE = 1.3;\nconst LABEL_SCALE = 0.5;\n/** Label texture size, a little above its size on screen, mipmapped down. */\nconst LABEL_TEXTURE_SIZE = 128;\n/**\n * Each letter is drawn twice, dark over the background and white over an\n * arrow, the two told apart by the stencil mark the arrows leave, so a\n * letter stays readable where it crosses an arrow.\n */\nconst LABEL_COLOR = \"#2a2a2a\";\nconst LABEL_COLOR_OVER_AXES = \"#ffffff\";\n/** World units visible across the gizmo viewport. */\nconst VIEW_EXTENT = 3.2;\nconst UP = new Vector3(0, 1, 0);\n\n/** The plain italic letter of an axis, in the interface's font, drawn white for the sprite to tint. */\nfunction labelTexture(label: string, fontFamily: string): CanvasTexture {\n const canvas = document.createElement(\"canvas\");\n canvas.width = LABEL_TEXTURE_SIZE;\n canvas.height = LABEL_TEXTURE_SIZE;\n const context = canvas.getContext(\"2d\");\n if (context) {\n const fontSize = LABEL_TEXTURE_SIZE * 0.68;\n context.clearRect(0, 0, canvas.width, canvas.height);\n context.font = `italic 600 ${fontSize}px ${fontFamily}`;\n context.textAlign = \"center\";\n context.textBaseline = \"middle\";\n context.fillStyle = \"#ffffff\";\n context.fillText(label, canvas.width / 2, canvas.height / 2);\n }\n const texture = new CanvasTexture(canvas);\n texture.colorSpace = SRGBColorSpace;\n texture.premultiplyAlpha = true;\n texture.magFilter = LinearFilter;\n texture.minFilter = LinearMipmapLinearFilter;\n return texture;\n}\n\n/** An arrow along +y with its letter at the tip; `setCell` turns it to its axis. */\nfunction createAxisArrow(\n color: string,\n label: string,\n fontFamily: string,\n): Group {\n const arrow = new Group();\n const material = createGizmoMaterial(color, GIZMO_AXIS_STENCIL);\n const shaft = new Mesh(\n new CylinderGeometry(SHAFT_RADIUS, SHAFT_RADIUS, SHAFT_LENGTH, 24),\n material,\n );\n shaft.position.y = SHAFT_LENGTH / 2;\n const cone = new Mesh(\n new ConeGeometry(CONE_RADIUS, CONE_LENGTH, 32),\n material,\n );\n cone.position.y = SHAFT_LENGTH + CONE_LENGTH / 2;\n arrow.add(shaft, cone);\n\n const texture = labelTexture(label, fontFamily);\n const passes = [\n [LABEL_COLOR, NotEqualStencilFunc],\n [LABEL_COLOR_OVER_AXES, EqualStencilFunc],\n ] as const;\n for (const [labelColor, stencilFunc] of passes) {\n const labelSprite = new Sprite(\n new SpriteMaterial({\n map: texture,\n color: labelColor,\n depthTest: false,\n depthWrite: false,\n transparent: true,\n stencilWrite: true,\n stencilRef: GIZMO_AXIS_STENCIL,\n stencilFunc,\n }),\n );\n labelSprite.scale.set(LABEL_SCALE, LABEL_SCALE, 1);\n labelSprite.position.y = LABEL_DISTANCE;\n labelSprite.renderOrder = 10;\n arrow.add(labelSprite);\n }\n return arrow;\n}\n\n/** The a, b, c axes of the cell drawn in a corner, following the camera. */\nexport class AxesGizmo {\n readonly scene = new Scene();\n readonly camera = new OrthographicCamera(-1, 1, 1, -1, 0.1, 20);\n private readonly axes = new Group();\n /** The a, b and c arrows, built once and turned to each new cell. */\n private readonly arrows: Group[];\n private readonly headlight = new DirectionalLight(\"#ffffff\", 1.78);\n private readonly inverse = new Quaternion();\n private readonly direction = new Vector3();\n\n /** `fontFamily` is the interface font the axis letters are drawn in. */\n constructor(fontFamily: string) {\n this.camera.position.set(0, 0, 5);\n this.camera.lookAt(0, 0, 0);\n this.scene.add(new AmbientLight(\"#ffffff\", 0.68));\n this.headlight.position.set(1.6, 1.1, 5);\n this.scene.add(this.headlight);\n this.arrows = ([\"a\", \"b\", \"c\"] as const).map((label) =>\n createAxisArrow(AXIS_COLORS[label], label, fontFamily),\n );\n const origin = new Mesh(\n new SphereGeometry(ORIGIN_RADIUS, 32, 16),\n createGizmoMaterial(\"#f3f2ee\", 0),\n );\n this.axes.add(...this.arrows, origin);\n this.scene.add(this.axes);\n }\n\n /** Point the arrows along the cell's a, b and c axes. */\n setCell(cell: Mat3): void {\n this.arrows.forEach((arrow, axis) => {\n arrow.quaternion.setFromUnitVectors(\n UP,\n this.direction.set(...cell[axis]!).normalize(),\n );\n });\n }\n\n /** Draw into the bottom-left `size` pixels of a renderer whose main pass is done. */\n render(\n renderer: WebGLRenderer,\n cameraQuaternion: Quaternion,\n size: number,\n ): void {\n this.axes.quaternion.copy(this.inverse.copy(cameraQuaternion).invert());\n const half = VIEW_EXTENT / 2;\n this.camera.left = -half;\n this.camera.right = half;\n this.camera.top = half;\n this.camera.bottom = -half;\n this.camera.updateProjectionMatrix();\n const previousAutoClear = renderer.autoClear;\n renderer.autoClear = false;\n renderer.setViewport(0, 0, size, size);\n renderer.setScissor(0, 0, size, size);\n renderer.setScissorTest(true);\n renderer.clear(false, true, true);\n renderer.render(this.scene, this.camera);\n renderer.setScissorTest(false);\n renderer.autoClear = previousAutoClear;\n }\n\n dispose(): void {\n this.axes.traverse((object) => {\n if (object instanceof Mesh || object instanceof Sprite) {\n object.geometry.dispose();\n const material = object.material;\n if (\"map\" in material && material.map) {\n material.map.dispose();\n }\n material.dispose();\n }\n });\n this.axes.clear();\n }\n}\n","{\n \"source\": \"VESTA's element colours, softened.\",\n \"elements\": {\n \"H\": \"#f2c0c0\",\n \"D\": \"#c2c1f4\",\n \"He\": \"#ecd9c0\",\n \"Li\": \"#8cd37e\",\n \"Be\": \"#71cc83\",\n \"B\": \"#509f47\",\n \"C\": \"#8d5434\",\n \"N\": \"#a9b3df\",\n \"O\": \"#e15949\",\n \"F\": \"#a9b3df\",\n \"Ne\": \"#e266ac\",\n \"Na\": \"#e7d15f\",\n \"Mg\": \"#eb8442\",\n \"Al\": \"#7dafd2\",\n \"Si\": \"#3a61cf\",\n \"P\": \"#be99c0\",\n \"S\": \"#e7e569\",\n \"Cl\": \"#87e17c\",\n \"Ar\": \"#bfedb5\",\n \"K\": \"#975cd1\",\n \"Ca\": \"#5d98c0\",\n \"Sc\": \"#b66aac\",\n \"Ti\": \"#74c2f5\",\n \"V\": \"#d2523f\",\n \"Cr\": \"#274fb1\",\n \"Mn\": \"#a34399\",\n \"Fe\": \"#b67822\",\n \"Co\": \"#254fb4\",\n \"Ni\": \"#b2b6b8\",\n \"Cu\": \"#3b5fc6\",\n \"Zn\": \"#919284\",\n \"Ga\": \"#9ed77c\",\n \"Ge\": \"#8374ac\",\n \"As\": \"#81c56c\",\n \"Se\": \"#a4dc6c\",\n \"Br\": \"#8c411c\",\n \"Kr\": \"#eeb6e7\",\n \"Rb\": \"#e05c97\",\n \"Sr\": \"#84e381\",\n \"Y\": \"#699a90\",\n \"Zr\": \"#86e27f\",\n \"Nb\": \"#57b079\",\n \"Mo\": \"#b486b0\",\n \"Tc\": \"#c7a9c5\",\n \"Ru\": \"#c8b1a7\",\n \"Rh\": \"#c4c8a1\",\n \"Pd\": \"#babcb1\",\n \"Ag\": \"#b2b6b8\",\n \"Cd\": \"#d565c3\",\n \"In\": \"#d282b8\",\n \"Sn\": \"#9b8fba\",\n \"Sb\": \"#d48455\",\n \"Te\": \"#aba153\",\n \"I\": \"#923e8e\",\n \"Xe\": \"#999ff0\",\n \"Cs\": \"#58ecb4\",\n \"Ba\": \"#7cd978\",\n \"La\": \"#6fbb63\",\n \"Ce\": \"#c9e871\",\n \"Pr\": \"#e8d55c\",\n \"Nd\": \"#ec913d\",\n \"Pm\": \"#2653c3\",\n \"Sm\": \"#e05984\",\n \"Eu\": \"#d964be\",\n \"Gd\": \"#ad60d3\",\n \"Tb\": \"#7156cf\",\n \"Dy\": \"#3f56ca\",\n \"Ho\": \"#3664d1\",\n \"Er\": \"#527c44\",\n \"Tm\": \"#224db9\",\n \"Yb\": \"#47ece4\",\n \"Lu\": \"#5ceab1\",\n \"Hf\": \"#b0b05b\",\n \"Ta\": \"#b69a56\",\n \"W\": \"#918c82\",\n \"Re\": \"#afad8a\",\n \"Os\": \"#c4ac74\",\n \"Ir\": \"#c0c670\",\n \"Pt\": \"#c3bdb6\",\n \"Au\": \"#efae4b\",\n \"Hg\": \"#cbb1c4\",\n \"Tl\": \"#998b6f\",\n \"Pb\": \"#5f5f67\",\n \"Bi\": \"#bd67d4\",\n \"Po\": \"#2956c7\",\n \"At\": \"#2956c7\",\n \"Rn\": \"#e4e669\",\n \"Fr\": \"#585858\",\n \"Ra\": \"#72a960\",\n \"Ac\": \"#66a075\",\n \"Th\": \"#7ae692\",\n \"Pa\": \"#83e17f\",\n \"U\": \"#7aa2aa\",\n \"Np\": \"#595959\",\n \"Pu\": \"#595959\",\n \"Am\": \"#595959\",\n \"XX\": \"#595959\"\n }\n}\n","/**\n * OKLab and OKLCH (Björn Ottosson, 2020): a colour space where Euclidean\n * distance tracks perceived difference, so the palette can reason about\n * \"clearly different\" colours.\n */\nexport interface Oklab {\n L: number;\n a: number;\n b: number;\n}\n\n/** Lightness, chroma and hue in degrees. */\nexport interface Oklch {\n L: number;\n C: number;\n h: number;\n}\n\nfunction srgbToLinear(channel: number): number {\n return channel <= 0.04045\n ? channel / 12.92\n : ((channel + 0.055) / 1.055) ** 2.4;\n}\n\nfunction linearToSrgb(channel: number): number {\n return channel <= 0.0031308\n ? channel * 12.92\n : 1.055 * channel ** (1 / 2.4) - 0.055;\n}\n\nexport function hexToOklab(hex: string): Oklab {\n const value = Number.parseInt(hex.slice(1), 16);\n const r = srgbToLinear(((value >> 16) & 255) / 255);\n const g = srgbToLinear(((value >> 8) & 255) / 255);\n const b = srgbToLinear((value & 255) / 255);\n const l = Math.cbrt(0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b);\n const m = Math.cbrt(0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b);\n const s = Math.cbrt(0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b);\n return {\n L: 0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s,\n a: 1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s,\n b: 0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s,\n };\n}\n\n/** Linear sRGB of an OKLab colour; channels may fall outside [0, 1]. */\nfunction oklabToLinearRgb(lab: Oklab): [number, number, number] {\n const l = (lab.L + 0.3963377774 * lab.a + 0.2158037573 * lab.b) ** 3;\n const m = (lab.L - 0.1055613458 * lab.a - 0.0638541728 * lab.b) ** 3;\n const s = (lab.L - 0.0894841775 * lab.a - 1.291485548 * lab.b) ** 3;\n return [\n 4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s,\n -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s,\n -0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s,\n ];\n}\n\nexport function isInGamut(lab: Oklab): boolean {\n return oklabToLinearRgb(lab).every(\n (channel) => channel >= -1e-4 && channel <= 1 + 1e-4,\n );\n}\n\nexport function oklabToHex(lab: Oklab): string {\n const hex = oklabToLinearRgb(lab).map((channel) => {\n const srgb = linearToSrgb(Math.min(1, Math.max(0, channel)));\n return Math.round(srgb * 255)\n .toString(16)\n .padStart(2, \"0\");\n });\n return `#${hex.join(\"\")}`;\n}\n\nexport function oklabToOklch(lab: Oklab): Oklch {\n const C = Math.hypot(lab.a, lab.b);\n const h = ((Math.atan2(lab.b, lab.a) * 180) / Math.PI + 360) % 360;\n return { L: lab.L, C, h };\n}\n\nexport function oklchToOklab(lch: Oklch): Oklab {\n const radians = (lch.h * Math.PI) / 180;\n return {\n L: lch.L,\n a: lch.C * Math.cos(radians),\n b: lch.C * Math.sin(radians),\n };\n}\n\n/** The same hue and lightness with the chroma reduced until sRGB can show it. */\nexport function clampChromaToGamut(lch: Oklch): Oklch {\n if (isInGamut(oklchToOklab(lch))) {\n return lch;\n }\n let low = 0;\n let high = lch.C;\n for (let step = 0; step < 24; step += 1) {\n const middle = (low + high) / 2;\n if (isInGamut(oklchToOklab({ ...lch, C: middle }))) {\n low = middle;\n } else {\n high = middle;\n }\n }\n return { ...lch, C: low };\n}\n","import elementColors from \"../data/element-colors.json\";\nimport { ELEMENT_SYMBOLS } from \"../structure/elements.js\";\nimport {\n clampChromaToGamut,\n hexToOklab,\n oklabToHex,\n oklabToOklch,\n oklchToOklab,\n type Oklab,\n type Oklch,\n} from \"./oklab.js\";\n\nconst BASE_COLORS = elementColors.elements as Record<string, string>;\n\n/**\n * The base table gives a few elements that usually share a structure one and\n * the same colour: chromium and cobalt, vanadium and oxygen, fluorine and\n * nitrogen. The less common one of each pair gets a fixed refinement in the\n * same key, so those structures need no automatic adjustment. Every other\n * clash is left to the session palette below, since any further fixed\n * choice would clash with some other common partner.\n */\nconst ANCHOR_REFINEMENTS: Record<string, string> = {\n // Steel periwinkle, against cobalt's deep blue.\n Cr: \"#6d87c9\",\n // Crimson rose, against oxygen's red.\n V: \"#bf4b62\",\n // Pale aqua, against nitrogen's lavender.\n F: \"#9bd7d0\",\n};\n\n/**\n * Elements by how often they appear in refined inorganic structures. When\n * colours collide inside one structure, the earlier element keeps its\n * anchor and the later one moves. Elements not listed follow by atomic\n * number.\n */\nconst PRIORITY = [\n \"O\",\n \"Li\",\n \"Na\",\n \"K\",\n \"Mg\",\n \"Ca\",\n \"Sr\",\n \"Ba\",\n \"Al\",\n \"Si\",\n \"Ti\",\n \"Mn\",\n \"Fe\",\n \"Co\",\n \"Ni\",\n \"Cu\",\n \"Zn\",\n \"V\",\n \"Cr\",\n \"Ga\",\n \"Ge\",\n \"Y\",\n \"Zr\",\n \"Nb\",\n \"Mo\",\n \"Ru\",\n \"Ag\",\n \"Cd\",\n \"In\",\n \"Sn\",\n \"Sb\",\n \"La\",\n \"Ce\",\n \"Nd\",\n \"Sm\",\n \"Gd\",\n \"Ta\",\n \"W\",\n \"Pt\",\n \"Au\",\n \"Pb\",\n \"Bi\",\n \"H\",\n \"C\",\n \"N\",\n \"F\",\n \"P\",\n \"S\",\n \"Cl\",\n \"Se\",\n \"Te\",\n \"I\",\n \"Br\",\n \"B\",\n \"Sc\",\n \"Rb\",\n \"Cs\",\n \"Hf\",\n \"Re\",\n \"Ir\",\n \"Pd\",\n \"Rh\",\n \"Os\",\n \"Pr\",\n \"Eu\",\n \"Tb\",\n \"Dy\",\n \"Ho\",\n \"Er\",\n \"Tm\",\n \"Yb\",\n \"Lu\",\n \"Th\",\n \"U\",\n];\nconst PRIORITY_RANK = new Map(\n PRIORITY.map((element, index) => [element, index]),\n);\n\n/** Two colours closer than this, in weighted OKLab, read as one. */\nconst MIN_DISTANCE = 0.1;\n/** Shading already varies lightness on a sphere, so hue and chroma count more. */\nconst LIGHTNESS_WEIGHT = 0.7;\n/** Adjusted colours stay in the palette's pastel band: never near white or black, never garish. */\nconst BAND = { minL: 0.45, maxL: 0.88, maxC: 0.2 };\n/** Below this chroma a colour is a grey, whose hue means nothing. */\nconst GREY_CHROMA = 0.025;\n/** A grey that must differ takes a dusty tint: this much chroma, this much darker. */\nconst TINT_CHROMA = 0.09;\nconst TINT_DARKENING = 0.1;\n\nconst HUE_OFFSETS = [\n 0, 10, -10, 20, -20, 30, -30, 45, -45, 60, -60, 80, -80, 100, -100, 120, -120,\n 150, -150, 180,\n];\nconst LIGHTNESS_OFFSETS = [0, -0.05, 0.05, -0.1, 0.1, -0.15, 0.15, -0.2, 0.2];\n/** Changes of vividness, as fractions of the chroma sRGB can show at a hue. */\nconst VIVIDNESS_OFFSETS = [0, 0.15, -0.15, 0.3];\nconst TINT_HUES = [0, 30, 60, 90, 120, 150, 180, 210, 240, 270, 300, 330];\n/** Cost of one step in hue (degrees), lightness, and vividness. */\nconst HUE_STEP = 30;\nconst LIGHTNESS_STEP = 0.08;\nconst VIVIDNESS_STEP = 0.15;\n/** Brightening a grey toward the background reads worse than darkening it. */\nconst BRIGHTENING_PENALTY = 1.5;\n/** A grey darkens before it takes a tint: more than one darkening step, less than two. */\nconst TINT_COST = 2;\n\ninterface Candidate {\n lch: Oklch;\n lab: Oklab;\n cost: number;\n}\n\nfunction weightedDistance(p: Oklab, q: Oklab): number {\n const dL = (p.L - q.L) * LIGHTNESS_WEIGHT;\n return Math.hypot(dL, p.a - q.a, p.b - q.b);\n}\n\nfunction hashString(text: string): number {\n let hash = 2166136261;\n for (let index = 0; index < text.length; index += 1) {\n hash = Math.imul(hash ^ text.charCodeAt(index), 16777619) >>> 0;\n }\n return hash;\n}\n\n/**\n * The anchor of an element: its refinement, else its base colour, else a\n * hue spread by the golden angle over the atomic number, so an element the\n * base table lacks still gets the same colour every time.\n */\nfunction anchorHex(element: string): string | null {\n return ANCHOR_REFINEMENTS[element] ?? BASE_COLORS[element] ?? null;\n}\n\nfunction anchorColor(element: string): Oklch {\n const hex = anchorHex(element);\n if (hex) {\n return oklabToOklch(hexToOklab(hex));\n }\n const atomicNumber = ELEMENT_SYMBOLS.indexOf(element) + 1;\n const seed = atomicNumber > 0 ? atomicNumber : hashString(element);\n return { L: 0.68, C: 0.12, h: (seed * 137.508) % 360 };\n}\n\nfunction priorityRank(element: string): number {\n const listed = PRIORITY_RANK.get(element);\n if (listed !== undefined) {\n return listed;\n }\n const atomicNumber = ELEMENT_SYMBOLS.indexOf(element);\n return (\n PRIORITY.length +\n (atomicNumber >= 0 ? atomicNumber : ELEMENT_SYMBOLS.length)\n );\n}\n\nfunction withinBand(lch: Oklch): Oklch {\n return clampChromaToGamut({\n L: Math.min(BAND.maxL, Math.max(BAND.minL, lch.L)),\n C: Math.min(BAND.maxC, Math.max(0, lch.C)),\n h: ((lch.h % 360) + 360) % 360,\n });\n}\n\n/** The largest chroma sRGB can show at a lightness and hue. */\nfunction maxChroma(L: number, h: number): number {\n return clampChromaToGamut({ L, C: 0.5, h }).C;\n}\n\nfunction candidate(lch: Oklch, cost: number): Candidate {\n const banded = withinBand(lch);\n return { lch: banded, lab: oklchToOklab(banded), cost };\n}\n\n/**\n * Colours near an anchor, cheapest first. A hue turn is cheaper than a\n * lightness step, which is cheaper than a change of vividness, so an\n * element keeps its character for as long as the palette allows. Turning\n * the hue keeps the anchor's vividness relative to what sRGB can show at\n * the new hue, so a soft green turns into a soft teal, not a loud one. A\n * grey anchor has no hue to turn; it darkens first, then takes a dusty tint.\n */\nfunction candidatesAround(anchor: Oklch): Candidate[] {\n const candidates: Candidate[] = [];\n if (anchor.C < GREY_CHROMA) {\n for (const lightnessOffset of LIGHTNESS_OFFSETS) {\n const lightnessCost =\n (Math.abs(lightnessOffset) / LIGHTNESS_STEP) *\n (lightnessOffset > 0 ? BRIGHTENING_PENALTY : 1);\n candidates.push(\n candidate({ ...anchor, L: anchor.L + lightnessOffset }, lightnessCost),\n );\n for (const hue of TINT_HUES) {\n candidates.push(\n candidate(\n {\n L: anchor.L - TINT_DARKENING + lightnessOffset,\n C: TINT_CHROMA,\n h: hue,\n },\n TINT_COST + lightnessCost + hue / 3600,\n ),\n );\n }\n }\n return candidates.sort((left, right) => left.cost - right.cost);\n }\n const vividness = anchor.C / Math.max(1e-6, maxChroma(anchor.L, anchor.h));\n for (const hueOffset of HUE_OFFSETS) {\n for (const lightnessOffset of LIGHTNESS_OFFSETS) {\n for (const vividnessOffset of VIVIDNESS_OFFSETS) {\n const L = Math.min(\n BAND.maxL,\n Math.max(BAND.minL, anchor.L + lightnessOffset),\n );\n const h = anchor.h + hueOffset;\n const C =\n Math.min(1, Math.max(0.1, vividness + vividnessOffset)) *\n maxChroma(L, h);\n const cost =\n Math.abs(hueOffset) / HUE_STEP +\n Math.abs(lightnessOffset) / LIGHTNESS_STEP +\n Math.abs(vividnessOffset) / VIVIDNESS_STEP;\n candidates.push(candidate({ L, C, h }, cost));\n }\n }\n }\n return candidates.sort((left, right) => left.cost - right.cost);\n}\n\ninterface Assignment {\n hex: string;\n lab: Oklab;\n}\n\n/**\n * The colours of the elements shown in this session. An element keeps its\n * colour from the moment it first appears, so a structure loaded later can\n * never recolour one loaded earlier; a newcomer whose anchor is too close to\n * a colour already on screen takes the nearest clearly different colour.\n * The outcome depends only on the order in which elements first appeared.\n */\nconst assigned = new Map<string, Assignment>();\n\n/**\n * The anchor itself when it is clearly different from every colour on\n * screen; otherwise the cheapest candidate that is, taking the better\n * separated of equally cheap ones; otherwise the best separated of all.\n */\nfunction choose(hex: string | null, anchor: Oklch): Assignment {\n const taken = [...assigned.values()].map((assignment) => assignment.lab);\n const separationFrom = (lab: Oklab) =>\n taken.reduce(\n (minimum, other) => Math.min(minimum, weightedDistance(lab, other)),\n Infinity,\n );\n const anchorLab = oklchToOklab(anchor);\n if (separationFrom(anchorLab) >= MIN_DISTANCE) {\n return { hex: hex ?? oklabToHex(anchorLab), lab: anchorLab };\n }\n let best: Candidate | null = null;\n let bestSeparation = -Infinity;\n let bestCost = Infinity;\n let fallback: Candidate | null = null;\n let fallbackSeparation = -Infinity;\n for (const entry of candidatesAround(anchor)) {\n const separation = separationFrom(entry.lab);\n if (separation >= MIN_DISTANCE) {\n if (\n entry.cost < bestCost - 1e-9 ||\n (Math.abs(entry.cost - bestCost) <= 1e-9 && separation > bestSeparation)\n ) {\n best = entry;\n bestCost = entry.cost;\n bestSeparation = separation;\n }\n if (entry.cost > bestCost + 1e-9) {\n break;\n }\n } else if (separation > fallbackSeparation) {\n fallback = entry;\n fallbackSeparation = separation;\n }\n }\n const chosen = best ?? fallback ?? { lab: anchorLab, lch: anchor, cost: 0 };\n return { hex: oklabToHex(chosen.lab), lab: chosen.lab };\n}\n\n/** Give these elements their colours now, the more common ones first, so colours do not depend on drawing order. */\nexport function ensureElementColors(elements: readonly string[]): void {\n const newcomers = [...new Set(elements)]\n .filter((element) => !assigned.has(element))\n .sort((left, right) => priorityRank(left) - priorityRank(right));\n for (const element of newcomers) {\n assigned.set(element, choose(anchorHex(element), anchorColor(element)));\n }\n}\n\n/** The colour of an element as a hex string such as `#e15949`, given on first use. */\nexport function elementColor(element: string): string {\n const assignment = assigned.get(element);\n if (assignment) {\n return assignment.hex;\n }\n ensureElementColors([element]);\n return (assigned.get(element) as Assignment).hex;\n}\n\n/** Every element given a colour so far, with its colour, in the order given. */\nexport function elementColorAssignments(): [string, string][] {\n return [...assigned].map(([element, assignment]) => [\n element,\n assignment.hex,\n ]);\n}\n\n/**\n * Forget every colour given so far, for example when all structures are\n * closed. Viewers and thumbnails pick up new colours at their next draw.\n */\nexport function resetElementColors(): void {\n assigned.clear();\n}\n","import { elementColor } from \"./palette.js\";\n\nconst STYLE_ID = \"bravais-styles\";\n\n/** Styles for the viewer's overlay elements, injected once per document. */\nconst STYLES = `\n.bravais-viewer {\n position: relative;\n overflow: hidden;\n}\n.bravais-canvas {\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n display: block;\n touch-action: none;\n}\n.bravais-legend {\n position: absolute;\n left: 50%;\n bottom: 20px;\n transform: translateX(-50%);\n display: flex;\n flex-wrap: wrap;\n justify-content: center;\n gap: 8px 16px;\n max-width: calc(100% - 32px);\n padding: 8px 16px;\n border: 1px solid rgba(40, 40, 40, 0.1);\n border-radius: 999px;\n background: rgba(255, 255, 255, 0.72);\n backdrop-filter: blur(24px) saturate(150%);\n box-shadow: 0 10px 15px -3px rgba(40, 40, 40, 0.1);\n font-family: inherit;\n font-size: 0.95rem;\n line-height: 1;\n color: #282828;\n pointer-events: none;\n}\n.bravais-legend[hidden] {\n display: none;\n}\n.bravais-legend-item {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.bravais-legend-swatch {\n width: 18px;\n height: 18px;\n border-radius: 50%;\n border: 1px solid rgba(40, 40, 40, 0.1);\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);\n}\n`;\n\nexport function ensureViewerStyles(root: Document): void {\n if (root.getElementById(STYLE_ID)) {\n return;\n }\n const style = root.createElement(\"style\");\n style.id = STYLE_ID;\n style.textContent = STYLES;\n root.head.appendChild(style);\n}\n\n// The lit-sphere swatch currently follows Pretty Lattice's legend.\nfunction swatchBackground(color: string): string {\n return `linear-gradient(135deg, rgba(255, 255, 255, 0.38) 0 14%, rgba(255, 255, 255, 0) 42%), ${color}`;\n}\n\n/** The element legend pill at the bottom of the viewer. */\nexport class ElementLegend {\n readonly element: HTMLElement;\n\n constructor(root: Document) {\n this.element = root.createElement(\"div\");\n this.element.className = \"bravais-legend\";\n this.element.hidden = true;\n }\n\n setElements(elements: string[]): void {\n this.element.replaceChildren();\n for (const symbol of elements) {\n const item = this.element.ownerDocument.createElement(\"span\");\n item.className = \"bravais-legend-item\";\n const swatch = this.element.ownerDocument.createElement(\"span\");\n swatch.className = \"bravais-legend-swatch\";\n swatch.style.background = swatchBackground(elementColor(symbol));\n const label = this.element.ownerDocument.createElement(\"span\");\n label.textContent = symbol;\n item.append(swatch, label);\n this.element.appendChild(item);\n }\n this.element.hidden = elements.length === 0;\n }\n}\n","import {\n Box3,\n BoxGeometry,\n BufferGeometry,\n Color,\n DataTexture,\n Float32BufferAttribute,\n FloatType,\n Group,\n InstancedMesh,\n LineSegments,\n Matrix4,\n NearestFilter,\n Object3D,\n PlaneGeometry,\n Quaternion,\n RGBAFormat,\n Vector3,\n} from \"three\";\n\nimport type { SceneAtom, SceneLayer, StructureScene } from \"../scene/build.js\";\nimport type { Mat3, Vec3 } from \"../structure/types.js\";\nimport {\n SECTOR_SITES_PER_ROW,\n SECTOR_TEXELS_PER_SITE,\n VACANCY_COLOR,\n VACANCY_FLAG,\n createAtomMaterial,\n createBondMaterial,\n createCellFrameMaterial,\n} from \"./materials.js\";\nimport { elementColor, ensureElementColors } from \"./palette.js\";\n\n/** Every atom is drawn at this radius, in ångström: one size for all. */\nconst ATOM_RADIUS = 0.4;\n/** Bond tube radius in ångström. */\nconst BOND_RADIUS = 0.1;\n/**\n * A bond half ends on a sphere this much smaller than its atom's, so the\n * atom's surface lies in front of the tube's cap and rim: they are hidden\n * by an occupied sector, faintly tinted through a vacant one, and never\n * fight it for depth.\n */\nconst BOND_INSET = 0.002;\n/** Radius of the sphere a bond half ends on. */\nconst CAP_RADIUS = ATOM_RADIUS - BOND_INSET;\n/** Along-axis distance from an atom's centre to the rim of a bond half. */\nconst BOND_START = Math.sqrt(\n CAP_RADIUS * CAP_RADIUS - BOND_RADIUS * BOND_RADIUS,\n);\nconst UP = new Vector3(0, 1, 0);\n\nexport interface SceneModel {\n group: Group;\n /** Cell row vectors of the first layer, the frame everything is centred on. */\n cell: Mat3;\n /** Centre of that cell, which `group` moves to the origin. */\n center: Vec3;\n /** Bounds of every atom and cell corner of every layer, in the centred frame. */\n bounds: Box3;\n /** Largest cell edge length of any layer. */\n span: number;\n /** Elements of the drawn layers. */\n elements: string[];\n dispose(): void;\n}\n\nfunction cellCorners(cell: Mat3): Vector3[] {\n const [a, b, c] = cell.map((row) => new Vector3(...row)) as [\n Vector3,\n Vector3,\n Vector3,\n ];\n const origin = new Vector3();\n return [\n origin,\n a.clone(),\n b.clone(),\n c.clone(),\n a.clone().add(b),\n a.clone().add(c),\n b.clone().add(c),\n a.clone().add(b).add(c),\n ];\n}\n\nexport function cellCenter(cell: Mat3): Vec3 {\n const [a, b, c] = cell;\n return [\n (a[0] + b[0] + c[0]) / 2,\n (a[1] + b[1] + c[1]) / 2,\n (a[2] + b[2] + c[2]) / 2,\n ];\n}\n\nconst CELL_EDGES: [number, number][] = [\n [0, 1],\n [0, 2],\n [0, 3],\n [1, 4],\n [1, 5],\n [2, 4],\n [2, 6],\n [3, 5],\n [3, 6],\n [4, 7],\n [5, 7],\n [6, 7],\n];\n\nfunction createCellFrame(cell: Mat3, opacity: number): LineSegments {\n const corners = cellCorners(cell);\n const positions: number[] = [];\n for (const [start, end] of CELL_EDGES) {\n const from = corners[start] as Vector3;\n const to = corners[end] as Vector3;\n positions.push(from.x, from.y, from.z, to.x, to.y, to.z);\n }\n const geometry = new BufferGeometry();\n geometry.setAttribute(\"position\", new Float32BufferAttribute(positions, 3));\n return new LineSegments(geometry, createCellFrameMaterial(opacity));\n}\n\n/**\n * The sector texture of a layer: per site, up to SECTOR_TEXELS_PER_SITE\n * texels of (colour, start fraction). The first species is the instance\n * colour and needs no texel; a vacant share ends the run in the vacancy\n * colour; species past the available texels extend the last sector.\n */\nfunction createSectorTexture(atoms: SceneAtom[]): {\n texture: DataTexture;\n hasVacancies: boolean;\n} {\n const width = SECTOR_SITES_PER_ROW * SECTOR_TEXELS_PER_SITE;\n const height = Math.max(1, Math.ceil(atoms.length / SECTOR_SITES_PER_ROW));\n const data = new Float32Array(width * height * 4).fill(1);\n const vacancy = new Color(VACANCY_COLOR);\n const color = new Color();\n let hasVacancies = false;\n atoms.forEach((atom, index) => {\n const row = Math.floor(index / SECTOR_SITES_PER_ROW);\n const column = (index % SECTOR_SITES_PER_ROW) * SECTOR_TEXELS_PER_SITE;\n let offset = (row * width + column) * 4;\n let written = 0;\n let cumulative = Math.min(1, atom.species[0]?.occupancy ?? 1);\n for (const entry of atom.species.slice(1)) {\n if (written < SECTOR_TEXELS_PER_SITE - 1) {\n color.set(elementColor(entry.element)).toArray(data, offset);\n data[offset + 3] = cumulative;\n offset += 4;\n written += 1;\n }\n cumulative = Math.min(1, cumulative + entry.occupancy);\n }\n if (cumulative < 1 - 1e-6) {\n vacancy.toArray(data, offset);\n data[offset + 3] = cumulative + VACANCY_FLAG;\n hasVacancies = true;\n }\n });\n const texture = new DataTexture(data, width, height, RGBAFormat, FloatType);\n texture.magFilter = NearestFilter;\n texture.minFilter = NearestFilter;\n texture.generateMipmaps = false;\n texture.needsUpdate = true;\n return { texture, hasVacancies };\n}\n\n/** Session colours as three.js colours, each parsed once. */\nfunction colorLookup(): (element: string) => Color {\n const colors = new Map<string, Color>();\n return (element) => {\n let color = colors.get(element);\n if (!color) {\n color = new Color(elementColor(element));\n colors.set(element, color);\n }\n return color;\n };\n}\n\nfunction createAtoms(atoms: SceneAtom[], opacity: number): InstancedMesh {\n // One camera-facing quad per atom; the material draws the sphere on it.\n const geometry = new PlaneGeometry(2, 2);\n const sectors = createSectorTexture(atoms);\n const mesh = new InstancedMesh(\n geometry,\n createAtomMaterial(opacity, sectors.texture, sectors.hasVacancies),\n atoms.length,\n );\n const matrix = new Matrix4();\n const colorOf = colorLookup();\n atoms.forEach((atom, index) => {\n matrix.makeScale(ATOM_RADIUS, ATOM_RADIUS, ATOM_RADIUS);\n matrix.setPosition(atom.position[0], atom.position[1], atom.position[2]);\n mesh.setMatrixAt(index, matrix);\n mesh.setColorAt(index, colorOf(atom.element));\n });\n mesh.instanceMatrix.needsUpdate = true;\n if (mesh.instanceColor) {\n mesh.instanceColor.needsUpdate = true;\n }\n mesh.userData.sectorTexture = sectors.texture;\n return mesh;\n}\n\n/**\n * Two half tubes per bond, each in its atom's colour, from the atom's sphere\n * to the midpoint. Each instance is the box around its half; the material\n * draws the tube inside it, cut on the atom's sphere.\n */\nfunction createBonds(\n scene: StructureScene,\n opacity: number,\n): InstancedMesh | null {\n if (scene.bonds.length === 0) {\n return null;\n }\n const geometry = new BoxGeometry(2, 1, 2);\n const mesh = new InstancedMesh(\n geometry,\n createBondMaterial(opacity, CAP_RADIUS),\n scene.bonds.length * 2,\n );\n const placeholder = new Object3D();\n const start = new Vector3();\n const end = new Vector3();\n const direction = new Vector3();\n const quaternion = new Quaternion();\n const colorOf = colorLookup();\n scene.bonds.forEach((bond, index) => {\n const startAtom = scene.atoms[bond.start] as SceneAtom;\n const endAtom = scene.atoms[bond.end] as SceneAtom;\n start.set(...startAtom.position);\n end.set(...endAtom.position);\n direction.subVectors(end, start);\n const half = direction.length() / 2;\n direction.normalize();\n quaternion.setFromUnitVectors(UP, direction);\n const halves: [number, SceneAtom, number, number][] = [\n [0, startAtom, BOND_START, half],\n [1, endAtom, half, 2 * half - BOND_START],\n ];\n for (const [slot, atom, from, to] of halves) {\n const length = Math.max(0, to - from);\n placeholder.position\n .copy(start)\n .addScaledVector(direction, from + length / 2);\n placeholder.quaternion.copy(quaternion);\n placeholder.scale.set(BOND_RADIUS, length, BOND_RADIUS);\n placeholder.updateMatrix();\n mesh.setMatrixAt(index * 2 + slot, placeholder.matrix);\n mesh.setColorAt(index * 2 + slot, colorOf(atom.element));\n }\n });\n mesh.instanceMatrix.needsUpdate = true;\n if (mesh.instanceColor) {\n mesh.instanceColor.needsUpdate = true;\n }\n return mesh;\n}\n\n/**\n * Build the three.js objects for the layers, centred on the first cell. A\n * layer at opacity 0 is not drawn but still counts toward the centre, the\n * bounds and the span.\n */\nexport function createSceneModel(layers: SceneLayer[]): SceneModel {\n const first = layers[0];\n if (!first) {\n throw new Error(\"A scene model needs at least one layer.\");\n }\n // Colours are settled for the whole set in one go, most common element\n // first, so the result depends neither on the order atoms are drawn in nor\n // on which layers are drawn.\n ensureElementColors(\n layers.flatMap((layer) => [\n ...layer.scene.elements,\n ...layer.scene.atoms.map((atom) => atom.element),\n ]),\n );\n const center = cellCenter(first.scene.cell);\n const group = new Group();\n group.position.set(-center[0], -center[1], -center[2]);\n const bounds = new Box3();\n const elements: string[] = [];\n let span = 1;\n const disposables: (InstancedMesh | LineSegments)[] = [];\n const offset = new Vector3(...center);\n const position = new Vector3();\n const extent = new Vector3();\n\n for (const layer of layers) {\n for (const corner of cellCorners(layer.scene.cell)) {\n bounds.expandByPoint(corner.sub(offset));\n }\n for (const atom of layer.scene.atoms) {\n position.set(...atom.position).sub(offset);\n bounds.expandByPoint(extent.copy(position).addScalar(ATOM_RADIUS));\n bounds.expandByPoint(extent.copy(position).subScalar(ATOM_RADIUS));\n }\n for (const row of layer.scene.cell) {\n span = Math.max(span, Math.hypot(...row));\n }\n const opacity = layer.opacity ?? 1;\n if (opacity <= 0) {\n continue;\n }\n const atoms = createAtoms(layer.scene.atoms, opacity);\n group.add(atoms);\n disposables.push(atoms);\n const bonds = createBonds(layer.scene, opacity);\n if (bonds) {\n group.add(bonds);\n disposables.push(bonds);\n }\n const frame = createCellFrame(layer.scene.cell, opacity);\n group.add(frame);\n disposables.push(frame);\n for (const element of layer.scene.elements) {\n if (!elements.includes(element)) {\n elements.push(element);\n }\n }\n }\n\n return {\n group,\n cell: first.scene.cell,\n center,\n bounds,\n span,\n elements,\n dispose() {\n // The materials are left to the garbage collector. Disposing the last\n // material of a shader makes three.js delete the compiled shader, and\n // the next structure would have to compile it again.\n for (const object of disposables) {\n object.geometry.dispose();\n const sectors = object.userData.sectorTexture;\n if (sectors instanceof DataTexture) {\n sectors.dispose();\n }\n }\n group.clear();\n },\n };\n}\n","import {\n ACESFilmicToneMapping,\n AmbientLight,\n DirectionalLight,\n OrthographicCamera,\n Scene,\n Vector3,\n WebGLRenderer,\n} from \"three\";\n\nimport {\n AMBIENT_LIGHT_INTENSITY,\n BACKGROUND_COLOR,\n HEADLIGHT_INTENSITY,\n HEADLIGHT_OFFSET,\n} from \"./materials.js\";\n\n/** The renderer, scene, camera and lights the viewer and the thumbnail renderer share. */\nexport interface Stage {\n renderer: WebGLRenderer;\n scene: Scene;\n camera: OrthographicCamera;\n /** Move the headlight along with the camera; call before each render. */\n updateHeadlight(): void;\n}\n\nexport function createStage(options: { stencil?: boolean } = {}): Stage {\n const renderer = new WebGLRenderer({\n antialias: true,\n alpha: true,\n stencil: options.stencil ?? false,\n });\n renderer.setClearColor(BACKGROUND_COLOR, 1);\n renderer.toneMapping = ACESFilmicToneMapping;\n const scene = new Scene();\n const camera = new OrthographicCamera(-1, 1, 1, -1, 0.01, 1000);\n const headlight = new DirectionalLight(\"#ffffff\", HEADLIGHT_INTENSITY);\n scene.add(\n new AmbientLight(\"#ffffff\", AMBIENT_LIGHT_INTENSITY),\n headlight,\n headlight.target,\n );\n const offset = new Vector3();\n return {\n renderer,\n scene,\n camera,\n updateHeadlight() {\n const lightDistance = Math.max(camera.position.length(), 4);\n offset\n .set(...HEADLIGHT_OFFSET)\n .multiplyScalar(lightDistance)\n .applyQuaternion(camera.quaternion);\n headlight.position.copy(camera.position).add(offset);\n },\n };\n}\n","import { Fog, MOUSE, Quaternion, Vector2, Vector3 } from \"three\";\nimport { TrackballControls } from \"three/addons/controls/TrackballControls.js\";\n\nimport {\n applyPixelFrustum,\n applyViewState,\n cameraDistance,\n fitZoom,\n quaternionTuple,\n standardQuaternion,\n standardView,\n} from \"./camera.js\";\nimport { AxesGizmo } from \"./gizmo.js\";\nimport { ElementLegend, ensureViewerStyles } from \"./legend.js\";\nimport { BACKGROUND_COLOR } from \"./materials.js\";\nimport { createSceneModel, type SceneModel } from \"./model.js\";\nimport { createStage } from \"./stage.js\";\nimport type { ViewState } from \"./view-state.js\";\nimport type { SceneLayer } from \"../scene/build.js\";\n\nexport interface ViewerOptions {\n /** Show the element legend. Default true. */\n legend?: boolean;\n /** Show the a, b, c axes in the corner. Default true. */\n gizmo?: boolean;\n}\n\nexport interface Viewer {\n /**\n * Draw these scenes from `buildScene`, replacing what was shown. The view\n * resets to the standard orientation unless `view` is given.\n */\n setLayers(layers: SceneLayer[], view?: ViewState | null): void;\n /** Remove everything drawn. */\n clear(): void;\n /** The current view, or null while nothing is shown. */\n getView(): ViewState | null;\n /** Restore a view from `getView`, of this or another viewer. */\n setView(view: ViewState): void;\n /** Back to the standard orientation, fitted to the viewport. */\n resetView(): void;\n /** Fit the canvas to the container again; the viewer does this itself when the container resizes. */\n resize(): void;\n /** Draw a frame now. */\n render(): void;\n /** Call `listener` when the user rotates or zooms. Returns a function that removes it. */\n onInteraction(listener: () => void): () => void;\n /** Remove the viewer from its container and free its WebGL resources. */\n dispose(): void;\n}\n\n/** Depth fading currently follows Pretty Lattice's default (amount and start 40%). */\nconst FOG_AMOUNT = 0.4;\nconst FOG_START = 0.4;\nconst FOG_FRONT_PADDING_RATIO = 0.4;\n/** Trackball feel currently follows Pretty Lattice's: inertia on, no panning. */\nconst ROTATE_SPEED = 2;\nconst ZOOM_SPEED = 1.2;\nconst DAMPING = 0.2;\n/**\n * TrackballControls turns the structure by pointer motion over half the\n * canvas width, so a narrow pane feels twitchier than a full window. The\n * rotate speed is scaled to the feel of a window this wide, whatever the\n * pane size.\n */\nconst REFERENCE_WIDTH_PX = 1500;\nconst MIN_SCALE = 0.2;\nconst MAX_SCALE = 5;\nconst IDLE_FRAMES = 3;\nconst MOTION_EPSILON = 1e-5;\n/** Interaction listeners run every few rendered frames, and once more when motion stops. */\nconst NOTIFY_EVERY_FRAMES = 4;\n/** Gizmo size as a share of the viewer's smaller side, within limits. */\nconst GIZMO_SIDE_RATIO = 0.35;\nconst GIZMO_MIN_PX = 110;\nconst GIZMO_MAX_PX = 180;\n\nfunction depthFog(\n model: SceneModel,\n distance: number,\n quaternion: Quaternion,\n): Fog {\n // The fog spans the structure's depth range along the standard view: it\n // starts a little in front of the farthest point and reaches full strength\n // at (back - near) / amount behind the start.\n const outward = new Vector3(0, 0, 1).applyQuaternion(quaternion);\n let front = 0;\n let back = 0;\n const corner = new Vector3();\n for (const x of [model.bounds.min.x, model.bounds.max.x]) {\n for (const y of [model.bounds.min.y, model.bounds.max.y]) {\n for (const z of [model.bounds.min.z, model.bounds.max.z]) {\n const depth = corner.set(x, y, z).dot(outward);\n front = Math.max(front, depth);\n back = Math.min(back, depth);\n }\n }\n }\n const span = Math.max(1, model.span);\n const backOffset = Math.max(0.01 * span, -back);\n const frontOffset = Math.min(backOffset, -front);\n const frontPadding = span * FOG_FRONT_PADDING_RATIO;\n const firstStart = frontOffset - frontPadding;\n const lastStart = Math.max(firstStart, backOffset - frontPadding);\n const startOffset = firstStart + (lastStart - firstStart) * FOG_START;\n const near = distance + startOffset;\n const far = near + (distance + backOffset - near) / FOG_AMOUNT;\n return new Fog(BACKGROUND_COLOR, near, far);\n}\n\n/**\n * Create a viewer inside `container`. It fills the container and follows\n * its size, so give the container a height. Adds the class `bravais-viewer`\n * to the container and one small stylesheet to the page.\n */\nexport function createViewer(\n container: HTMLElement,\n options: ViewerOptions = {},\n): Viewer {\n const root = container.ownerDocument;\n ensureViewerStyles(root);\n container.classList.add(\"bravais-viewer\");\n\n // The stencil buffer is for the gizmo: its letters change colour over the axes.\n const { renderer, scene, camera, updateHeadlight } = createStage({\n stencil: true,\n });\n renderer.setPixelRatio(root.defaultView?.devicePixelRatio ?? 1);\n renderer.domElement.className = \"bravais-canvas\";\n container.appendChild(renderer.domElement);\n\n const legend = options.legend === false ? null : new ElementLegend(root);\n if (legend) {\n container.appendChild(legend.element);\n }\n // The axis letters are drawn in the font of the element the viewer sits in,\n // like the legend, so both match the surrounding interface.\n const fontFamily =\n root.defaultView?.getComputedStyle(container).fontFamily ?? \"sans-serif\";\n const gizmo = options.gizmo === false ? null : new AxesGizmo(fontFamily);\n\n const controls = new TrackballControls(camera, renderer.domElement);\n controls.rotateSpeed = ROTATE_SPEED;\n controls.zoomSpeed = ZOOM_SPEED;\n controls.dynamicDampingFactor = DAMPING;\n controls.staticMoving = false;\n controls.noPan = true;\n controls.mouseButtons.LEFT = MOUSE.ROTATE;\n controls.mouseButtons.MIDDLE = MOUSE.DOLLY;\n controls.mouseButtons.RIGHT = null;\n\n let model: SceneModel | null = null;\n let distance = 4;\n let fitted = 1;\n let width = 1;\n let height = 1;\n let frame: number | null = null;\n /** True from a wake until the loop decides to stop; a wake never starts a second loop. */\n let loopActive = false;\n let idleFrames = 0;\n /** A pointer button is down on the canvas; the loop must outlive idle frames. */\n let dragging = false;\n let framesSinceNotify = 0;\n let notifyPending = false;\n const canvasSize = new Vector2();\n const lastQuaternion = new Quaternion();\n let lastZoom = 0;\n const lastTarget = new Vector3();\n const listeners = new Set<() => void>();\n\n function notify(): void {\n framesSinceNotify = 0;\n notifyPending = false;\n for (const listener of listeners) {\n listener();\n }\n }\n\n function render(): void {\n updateHeadlight();\n renderer.setViewport(0, 0, width, height);\n renderer.render(scene, camera);\n if (gizmo && model) {\n const size = Math.round(\n Math.min(\n GIZMO_MAX_PX,\n Math.max(GIZMO_MIN_PX, Math.min(width, height) * GIZMO_SIDE_RATIO),\n ),\n );\n gizmo.render(renderer, camera.quaternion, size);\n }\n }\n\n function measure(): void {\n const rect = container.getBoundingClientRect();\n width = Math.max(1, Math.round(rect.width));\n height = Math.max(1, Math.round(rect.height));\n // Resizing the canvas reallocates its drawing buffer: only on a change.\n const size = renderer.getSize(canvasSize);\n if (size.x !== width || size.y !== height) {\n renderer.setSize(width, height, false);\n }\n applyPixelFrustum(camera, width, height);\n // The trackball maps pointer motion through the canvas size it last saw.\n controls.handleResize();\n controls.rotateSpeed = ROTATE_SPEED * (width / REFERENCE_WIDTH_PX);\n }\n\n function refit(quaternion: Quaternion): void {\n if (!model) {\n return;\n }\n fitted = fitZoom(model.bounds, quaternion, width, height);\n controls.minZoom = fitted * MIN_SCALE;\n controls.maxZoom = fitted * MAX_SCALE;\n }\n\n function cameraMoved(): boolean {\n const moved =\n lastQuaternion.angleTo(camera.quaternion) > MOTION_EPSILON ||\n Math.abs(lastZoom - camera.zoom) > MOTION_EPSILON * fitted ||\n lastTarget.distanceToSquared(controls.target) > MOTION_EPSILON;\n lastQuaternion.copy(camera.quaternion);\n lastZoom = camera.zoom;\n lastTarget.copy(controls.target);\n return moved;\n }\n\n // TrackballControls needs frames while a button is down and while it\n // damps afterwards; run a loop for exactly that long.\n function tick(): void {\n frame = null;\n // update() emits \"change\" when the camera moved; the wake that handles\n // it must not schedule a second loop, hence loopActive.\n controls.update();\n if (cameraMoved()) {\n idleFrames = 0;\n render();\n framesSinceNotify += 1;\n notifyPending = true;\n if (framesSinceNotify >= NOTIFY_EVERY_FRAMES) {\n notify();\n }\n } else {\n idleFrames += 1;\n }\n if (dragging || idleFrames < IDLE_FRAMES) {\n frame = requestAnimationFrame(tick);\n return;\n }\n loopActive = false;\n if (notifyPending) {\n notify();\n }\n }\n\n function wake(): void {\n idleFrames = 0;\n if (!loopActive) {\n loopActive = true;\n frame = requestAnimationFrame(tick);\n }\n }\n\n function stopLoop(): void {\n if (frame !== null) {\n cancelAnimationFrame(frame);\n frame = null;\n }\n loopActive = false;\n }\n\n controls.addEventListener(\"start\", () => {\n dragging = true;\n wake();\n });\n controls.addEventListener(\"end\", () => {\n dragging = false;\n wake();\n });\n controls.addEventListener(\"change\", wake);\n\n /** Refit to the container's size, keeping the zoom relative to the fit. */\n function resize(): void {\n const scale = fitted > 0 ? camera.zoom / fitted : 1;\n measure();\n refit(camera.quaternion);\n camera.zoom = fitted * scale;\n camera.updateProjectionMatrix();\n render();\n }\n\n const observer =\n typeof ResizeObserver === \"undefined\" ? null : new ResizeObserver(resize);\n observer?.observe(container);\n measure();\n\n function applyView(view: ViewState): void {\n if (!model) {\n return;\n }\n applyViewState(camera, view, distance, model.span);\n controls.target.set(...view.target);\n refit(camera.quaternion);\n camera.zoom = fitted * view.scale;\n camera.updateProjectionMatrix();\n controls.update();\n cameraMoved();\n }\n\n const viewer: Viewer = {\n setLayers(layers, view = null) {\n viewer.clear();\n if (layers.length === 0) {\n return;\n }\n model = createSceneModel(layers);\n scene.add(model.group);\n distance = cameraDistance(model.span);\n scene.fog = depthFog(model, distance, standardQuaternion(model.cell));\n legend?.setElements(model.elements);\n gizmo?.setCell(model.cell);\n measure();\n applyView(view ?? standardView(model.cell));\n render();\n },\n clear() {\n stopLoop();\n if (model) {\n scene.remove(model.group);\n model.dispose();\n model = null;\n }\n scene.fog = null;\n legend?.setElements([]);\n renderer.setViewport(0, 0, width, height);\n renderer.clear();\n },\n getView() {\n if (!model) {\n return null;\n }\n return {\n quaternion: quaternionTuple(camera.quaternion),\n target: [controls.target.x, controls.target.y, controls.target.z],\n scale: fitted > 0 ? camera.zoom / fitted : 1,\n };\n },\n setView(view) {\n applyView(view);\n render();\n },\n resetView() {\n if (model) {\n applyView(standardView(model.cell));\n }\n render();\n notify();\n },\n resize,\n render,\n onInteraction(listener) {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n dispose() {\n viewer.clear();\n dragging = false;\n observer?.disconnect();\n controls.dispose();\n gizmo?.dispose();\n renderer.dispose();\n renderer.domElement.remove();\n legend?.element.remove();\n container.classList.remove(\"bravais-viewer\");\n },\n };\n\n return viewer;\n}\n","import { Quaternion } from \"three\";\n\nimport {\n applyPixelFrustum,\n applyViewState,\n cameraDistance,\n fitZoom,\n standardView,\n} from \"./camera.js\";\nimport { createSceneModel, type SceneModel } from \"./model.js\";\nimport { createStage } from \"./stage.js\";\nimport type { ViewState } from \"./view-state.js\";\nimport type { SceneLayer } from \"../scene/build.js\";\n\nexport interface ThumbnailRenderer {\n /**\n * Draw `layers` into `canvas` with `view`, or the standard view when null.\n * Models are cached by `key` and rebuilt when the layers array changes.\n */\n render(\n key: string,\n layers: SceneLayer[],\n view: ViewState | null,\n canvas: HTMLCanvasElement,\n ): void;\n /** Forget the cached model of `key`. */\n release(key: string): void;\n /** Free the shared WebGL context and every cached model. */\n dispose(): void;\n}\n\ninterface CachedModel {\n layers: SceneLayer[];\n model: SceneModel;\n}\n\n/**\n * Draw small previews into ordinary canvases from one shared WebGL context,\n * so a list of structures does not need a context for each.\n */\nexport function createThumbnailRenderer(): ThumbnailRenderer {\n const { renderer, scene, camera, updateHeadlight } = createStage();\n const cache = new Map<string, CachedModel>();\n\n function modelFor(key: string, layers: SceneLayer[]): SceneModel {\n const cached = cache.get(key);\n if (cached && cached.layers === layers) {\n return cached.model;\n }\n cached?.model.dispose();\n const model = createSceneModel(layers);\n cache.set(key, { layers, model });\n return model;\n }\n\n return {\n render(key, layers, view, canvas) {\n const context = canvas.getContext(\"2d\");\n if (!context || layers.length === 0) {\n return;\n }\n const model = modelFor(key, layers);\n const width = Math.max(1, canvas.width);\n const height = Math.max(1, canvas.height);\n // Resizing a WebGL canvas recreates its drawing buffer; only do it on change.\n if (\n renderer.domElement.width !== width ||\n renderer.domElement.height !== height\n ) {\n renderer.setSize(width, height, false);\n }\n applyPixelFrustum(camera, width, height);\n const distance = cameraDistance(model.span);\n const pose = view ?? standardView(model.cell);\n applyViewState(camera, pose, distance, model.span);\n camera.zoom =\n fitZoom(\n model.bounds,\n new Quaternion(...pose.quaternion),\n width,\n height,\n ) * pose.scale;\n camera.updateProjectionMatrix();\n updateHeadlight();\n\n scene.add(model.group);\n renderer.render(scene, camera);\n scene.remove(model.group);\n context.clearRect(0, 0, width, height);\n context.drawImage(renderer.domElement, 0, 0, width, height);\n },\n release(key) {\n cache.get(key)?.model.dispose();\n cache.delete(key);\n },\n dispose() {\n for (const cached of cache.values()) {\n cached.model.dispose();\n }\n cache.clear();\n renderer.dispose();\n },\n };\n}\n","import { parseCif } from \"./cif/parser.js\";\nimport {\n CifStructureError,\n isStructureBlock,\n parseCifStructure,\n} from \"./cif/structure.js\";\nimport { resolveOperations } from \"./symmetry/resolve.js\";\nimport type { Structure } from \"./structure/types.js\";\n\nexport {\n parseCif,\n type CifBlock,\n type CifDocument,\n type CifLoop,\n} from \"./cif/parser.js\";\nexport { CifSyntaxError } from \"./cif/tokenizer.js\";\nexport {\n CifStructureError,\n parseCifStructure,\n type ParsedCifStructure,\n} from \"./cif/structure.js\";\nexport { parseSymmetryOperator } from \"./cif/symmetry-operators.js\";\nexport {\n SpaceGroupLookupError,\n ensureMoyo,\n operationsForSpaceGroup,\n} from \"./symmetry/moyo.js\";\nexport {\n SymmetryAnalysisError,\n symmetryDataset,\n type SymmetryDataset,\n type SymmetryOptions,\n} from \"./symmetry/dataset.js\";\nexport { typesetSymbol } from \"./symmetry/symbol.js\";\nexport { expandStructure } from \"./structure/expand.js\";\nexport {\n latticeFromParameters,\n latticeFromVectors,\n} from \"./structure/lattice.js\";\nexport { buildScene, structureElements } from \"./scene/build.js\";\nexport {\n createViewer,\n type Viewer,\n type ViewerOptions,\n} from \"./render/viewer.js\";\nexport {\n createThumbnailRenderer,\n type ThumbnailRenderer,\n} from \"./render/thumbnails.js\";\nexport type { SceneLayer } from \"./scene/build.js\";\nexport type { ViewState } from \"./render/view-state.js\";\nexport {\n elementColor,\n elementColorAssignments,\n ensureElementColors,\n resetElementColors,\n} from \"./render/palette.js\";\nexport type {\n BuildSceneOptions,\n SceneAtom,\n StructureScene,\n} from \"./scene/build.js\";\nexport type { Bond } from \"./structure/bonds.js\";\nexport type {\n Lattice,\n LatticeParameters,\n Mat3,\n Site,\n SpaceGroupInfo,\n Species,\n Structure,\n SymmetryOperation,\n Vec3,\n} from \"./structure/types.js\";\n\n/**\n * Read the first structure in a CIF file. Its symmetry comes from the\n * file's list of symmetry operations or, without one, from its space-group\n * symbol or number; a file with neither is read as listing every atom.\n *\n * Throws `CifSyntaxError` for text that is not valid CIF,\n * `CifStructureError` for a file without a usable structure, and\n * `SpaceGroupLookupError` for an unknown space group.\n */\nexport async function readCif(text: string): Promise<Structure> {\n const document = parseCif(text);\n const block = document.blocks.find(isStructureBlock) ?? document.blocks[0];\n if (!block) {\n throw new CifStructureError(\"The CIF has no data block.\");\n }\n const parsed = parseCifStructure(block);\n return {\n lattice: parsed.lattice,\n sites: parsed.sites,\n operations: await resolveOperations(parsed),\n spaceGroup: parsed.spaceGroup,\n };\n}\n"],"ignoreList":[20],"mappings":"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"}
1
+ {"version":3,"file":"bravais.js","names":["source","vestaCutoffs","UP","elementColors","CifSyntaxError","line","message","isWhitespace","char","classify","lower","word","tokenizeCif","tokens","lines","text","index","lineNumber","content","closed","candidate","position","end","next","after","tagList","tags","CifBlock","name","tag","value","loop","entry","loopColumn","column","row","isCifPlaceholder","parseCifNumber","isLoopTerminator","token","parseCif","blocks","block","saveFrameDepth","requireBlock","target","values","rows","start","ELEMENT_SYMBOLS","ELEMENTS","isElementSymbol","symbol","capitalize","elementFromCifSymbol","letters","raw","two","one","chemicalElement","EQUIVALENT_TOLERANCE","NEAR_ONE","wrap","wrapped","nearOne","wrapVector","fractional","samePosition","axis","delta","p","q","tolerance","BUCKETS","bucketOf","bucketKey","x","y","z","PositionIndex","key","bucket","found","dx","bx","dy","by","dz","bz","left","right","applyOperation","r","operation","t","DEGREES","clamp","max","min","latticeFromParameters","parameters","alpha","beta","gamma","cosAlpha","cosBeta","cosGamma","sinAlpha","sinBeta","gammaStar","vectorA","a","vectorB","b","vectorC","c","latticeFromVectors","vectors","length","v","angle","u","fractionalToCartesian","va","vb","vc","lattice","distance","CifStructureError","AXES","parseCoefficient","fraction","parseSymmetryOperator","components","part","rotation","translation","component","terms","shift","term","coefficient","SITE_MERGE_TOLERANCE","OPERATOR_TAGS","SPACE_GROUP_NUMBER_TAGS","HERMANN_MAUGUIN_TAGS","HALL_TAGS","requireNumber","mergeSpecies","existing","species","element","occupancy","scaleOverfullSites","site","sites","total","sum","readSites","xs","ys","zs","labels","typeSymbols","occupancies","positions","label","typeSymbol","shared","readOperations","single","operations","readSpaceGroup","numberText","number","hallSymbol","isStructureBlock","parseCifStructure","listingClosure","preExpanded","hits","hit","self","IDENTITY_OPERATION","bindings","loading","loadMoyo","module","error","moyo","SpaceGroupLookupError","hallEntries","ensureMoyo","fromMoyoOperation","allHallEntries","normalizeSymbol","splitHermannMauguin","trimmed","colon","trailing","preferStandard","first","entries","standard","entriesForSymbol","info","wanted","byHall","bySymbol","base","setting","bySetting","describe","operationSettings","operations_from_number","operationsForSpaceGroup","SAME_LENGTH","SAME_ANGLE","misfit","assertFits","closure","axesOfCell","sameLength","sameAngle","resolveOperations","parsed","spaceGroup","settings","only","closures","fitting","axes","expandStructure","kept","structure","DEFAULT_SYMPREC","SymmetryAnalysisError","labelSpecies","labelByKey","speciesByLabel","standardStructure","basis","dataset","counts","count","symmetryDataset","expanded","cell","analyze_cell","options","hall_symbol_entry","type","space_group_type","SUBSCRIPT_DIGITS","COMBINING_OVERLINE","subscript","digit","typesetSymbol","body","suffix","order","match","CUTOFFS","SHORTEST_BOND","bondCutoff","elementA","elementB","findBonds","kinds","kindOf","atoms","kind","atom","elements","cutoffs","longest","cutoff","second","cubes","low","high","cube","ny","nz","cubeKey","grid","bonds","other","BOUNDARY_TOLERANCE","periodicAtoms","includeImages","boundaryAxes","subsetCount","subset","image","bit","structureElements","buildScene","majority","_changeEvent","_startEvent","_endEvent","_EPS","_STATE","_v2","Vector2","_mouseChange","_objectUp","Vector3","_pan","_axis","_quaternion","Quaternion","_eyeDirection","_objectUpDirection","_objectSidewaysDirection","_moveDirection","TrackballControls","Controls","object","domElement","MOUSE","onPointerMove","onPointerDown","onPointerUp","onPointerCancel","onContextMenu","onMouseWheel","onKeyDown","onKeyUp","onTouchStart","onTouchMove","onTouchEnd","onMouseDown","onMouseMove","onMouseUp","box","d","positionChanged","rollChanged","zoomChanged","scale_x","scale_y","pointerIds","positionFirst","positionSecond","rollAngle","factor","MathUtils","pageX","pageY","event","i","pointer","mouseAction","state","NAUMANN_HORIZONTAL_RATIO","NAUMANN_VERTICAL_RATIO","PROJECTED_FIT_PADDING_RATIO","EPSILON","CAMERA_FORWARD","CAMERA_UP","projectPerpendicular","projected","vector","stablePerpendicular","standardViewVectors","vertical","basalReference","basalRight","outward","cameraDistance","span","standardQuaternion","up","correctedUp","Matrix4","standardView","quaternionTuple","applyViewState","quaternion","view","forward","camera","projectedSize","minX","maxX","minY","maxY","bounds","corner","px","py","fitZoom","availableLength","width","height","projectedLength","applyPixelFrustum","METALNESS","ROUGHNESS","AMBIENT_LIGHT_INTENSITY","HEADLIGHT_INTENSITY","HEADLIGHT_OFFSET","BACKGROUND_COLOR","CELL_FRAME_COLOR","VACANCY_COLOR","VACANCY_OPACITY","TWO_PI","patchShader","patches","include","code","source","shader","atomVertexShader","atomFragmentShader","createAtomMaterial","transparent","opacity","hasVacancies","material","MeshStandardMaterial","sectorTexture","bondVertexShader","bondFragmentShader","createBondMaterial","capRadius","createCellFrameMaterial","LineBasicMaterial","createGizmoMaterial","DoubleSide","AlwaysStencilFunc","ReplaceStencilOp","AXIS_COLORS","SHAFT_LENGTH","SHAFT_RADIUS","CONE_LENGTH","CONE_RADIUS","ORIGIN_RADIUS","LABEL_DISTANCE","LABEL_SCALE","LABEL_TEXTURE_SIZE","LABEL_COLOR","LABEL_COLOR_OVER_AXES","VIEW_EXTENT","UP$1","labelTexture","canvas","context","fontSize","fontFamily","texture","CanvasTexture","SRGBColorSpace","LinearFilter","LinearMipmapLinearFilter","createAxisArrow","arrow","Group","color","shaft","Mesh","CylinderGeometry","cone","ConeGeometry","passes","NotEqualStencilFunc","EqualStencilFunc","labelColor","stencilFunc","labelSprite","Sprite","SpriteMaterial","AxesGizmo","Scene","OrthographicCamera","DirectionalLight","AmbientLight","origin","SphereGeometry","cameraQuaternion","half","previousAutoClear","renderer","size","element_colors_default","\"H\"","\"D\"","\"He\"","\"Li\"","\"Be\"","\"B\"","\"C\"","\"N\"","\"O\"","\"F\"","\"Ne\"","\"Na\"","\"Mg\"","\"Al\"","\"Si\"","\"P\"","\"S\"","\"Cl\"","\"Ar\"","\"K\"","\"Ca\"","\"Sc\"","\"Ti\"","\"V\"","\"Cr\"","\"Mn\"","\"Fe\"","\"Co\"","\"Ni\"","\"Cu\"","\"Zn\"","\"Ga\"","\"Ge\"","\"As\"","\"Se\"","\"Br\"","\"Kr\"","\"Rb\"","\"Sr\"","\"Y\"","\"Zr\"","\"Nb\"","\"Mo\"","\"Tc\"","\"Ru\"","\"Rh\"","\"Pd\"","\"Ag\"","\"Cd\"","\"In\"","\"Sn\"","\"Sb\"","\"Te\"","\"I\"","\"Xe\"","\"Cs\"","\"Ba\"","\"La\"","\"Ce\"","\"Pr\"","\"Nd\"","\"Pm\"","\"Sm\"","\"Eu\"","\"Gd\"","\"Tb\"","\"Dy\"","\"Ho\"","\"Er\"","\"Tm\"","\"Yb\"","\"Lu\"","\"Hf\"","\"Ta\"","\"W\"","\"Re\"","\"Os\"","\"Ir\"","\"Pt\"","\"Au\"","\"Hg\"","\"Tl\"","\"Pb\"","\"Bi\"","\"Po\"","\"At\"","\"Rn\"","\"Fr\"","\"Ra\"","\"Ac\"","\"Th\"","\"Pa\"","\"U\"","\"Np\"","\"Pu\"","\"Am\"","\"XX\"","srgbToLinear","channel","linearToSrgb","hexToOklab","hex","g","l","m","oklabToLinearRgb","lab","s","isInGamut","oklabToHex","srgb","oklabToOklch","C","h","oklchToOklab","radians","lch","clampChromaToGamut","step","middle","BASE_COLORS","ANCHOR_REFINEMENTS","PRIORITY","PRIORITY_RANK","MIN_DISTANCE","LIGHTNESS_WEIGHT","BAND","GREY_CHROMA","TINT_CHROMA","TINT_DARKENING","HUE_OFFSETS","LIGHTNESS_OFFSETS","VIVIDNESS_OFFSETS","TINT_HUES","HUE_STEP","LIGHTNESS_STEP","VIVIDNESS_STEP","BRIGHTENING_PENALTY","TINT_COST","weightedDistance","dL","hashString","hash","anchorHex","anchorColor","atomicNumber","priorityRank","listed","withinBand","maxChroma","banded","candidatesAround","candidates","anchor","lightnessOffset","lightnessCost","hue","vividness","hueOffset","vividnessOffset","L","cost","assigned","choose","taken","assignment","separationFrom","minimum","anchorLab","best","bestSeparation","bestCost","fallback","fallbackSeparation","separation","chosen","ensureElementColors","newcomers","elementColor","elementColorAssignments","resetElementColors","STYLE_ID","STYLES","ensureViewerStyles","root","style","swatchBackground","ElementLegend","item","swatch","ATOM_RADIUS","BOND_RADIUS","CAP_RADIUS","BOND_START","UP","cellCorners","cellCenter","CELL_EDGES","createCellFrame","corners","from","to","geometry","BufferGeometry","Float32BufferAttribute","LineSegments","createSectorTexture","data","vacancy","Color","offset","written","cumulative","DataTexture","RGBAFormat","FloatType","NearestFilter","colorLookup","colors","createAtoms","PlaneGeometry","sectors","mesh","InstancedMesh","matrix","colorOf","createBonds","scene","BoxGeometry","placeholder","Object3D","direction","startAtom","bond","endAtom","halves","slot","createSceneModel","layers","layer","center","group","Box3","disposables","extent","frame","disposeGeometry","objects","WARMUP_SCENE","createShaderWarmup","white","createStage","WebGLRenderer","ACESFilmicToneMapping","headlight","lightDistance","FOG_AMOUNT","FOG_START","FOG_FRONT_PADDING_RATIO","ROTATE_SPEED","ZOOM_SPEED","DAMPING","REFERENCE_WIDTH_PX","MIN_SCALE","MAX_SCALE","IDLE_FRAMES","MOTION_EPSILON","NOTIFY_EVERY_FRAMES","GIZMO_SIDE_RATIO","GIZMO_MIN_PX","GIZMO_MAX_PX","depthFog","front","back","model","depth","backOffset","frontOffset","frontPadding","firstStart","near","far","Fog","createViewer","container","legend","gizmo","controls","compiling","fitted","loopActive","idleFrames","dragging","framesSinceNotify","notifyPending","canvasSize","lastQuaternion","lastZoom","lastTarget","listeners","notify","listener","render","updateHeadlight","measure","rect","refit","cameraMoved","moved","tick","wake","stopLoop","resize","scale","observer","warmup","warming","warmed","applyView","viewer","createThumbnailRenderer","cache","modelFor","cached","pose","readCif","document"],"sources":["../src/cif/tokenizer.ts","../src/cif/parser.ts","../src/structure/elements.ts","../src/structure/fractional.ts","../src/structure/lattice.ts","../src/cif/errors.ts","../src/cif/symmetry-operators.ts","../src/cif/structure.ts","../src/structure/closure.ts","../src/structure/types.ts","../src/symmetry/moyo-loader.ts","../src/symmetry/moyo.ts","../src/symmetry/resolve.ts","../src/structure/expand.ts","../src/symmetry/dataset.ts","../src/symmetry/symbol.ts","../src/data/vesta-cutoffs.json","../src/structure/bonds.ts","../src/structure/images.ts","../src/scene/build.ts","../node_modules/three/examples/jsm/controls/TrackballControls.js","../src/render/camera.ts","../src/render/materials.ts","../src/render/gizmo.ts","../src/data/element-colors.json","../src/render/oklab.ts","../src/render/palette.ts","../src/render/legend.ts","../src/render/model.ts","../src/render/stage.ts","../src/render/viewer.ts","../src/render/thumbnails.ts","../src/index.ts"],"sourcesContent":["export type CifTokenKind = \"tag\" | \"value\" | \"loop\" | \"data\" | \"save\" | \"stop\";\n\nexport interface CifToken {\n kind: CifTokenKind;\n text: string;\n line: number;\n}\n\n/** The text is not CIF the tokenizer and parser accept. */\nexport class CifSyntaxError extends Error {\n /** 1-based line of the problem. */\n readonly line: number;\n\n constructor(message: string, line: number) {\n super(`CIF line ${line}: ${message}`);\n this.name = \"CifSyntaxError\";\n this.line = line;\n }\n}\n\nfunction isWhitespace(char: string): boolean {\n return char === \" \" || char === \"\\t\" || char === \"\\r\" || char === \"\\n\";\n}\n\nfunction classify(word: string, line: number): CifToken {\n const lower = word.toLowerCase();\n if (word.startsWith(\"_\")) {\n return { kind: \"tag\", text: word, line };\n }\n if (lower.startsWith(\"data_\")) {\n return { kind: \"data\", text: word.slice(5), line };\n }\n if (lower === \"loop_\") {\n return { kind: \"loop\", text: word, line };\n }\n if (lower.startsWith(\"save_\")) {\n return { kind: \"save\", text: word.slice(5), line };\n }\n if (lower === \"stop_\") {\n return { kind: \"stop\", text: word, line };\n }\n return { kind: \"value\", text: word, line };\n}\n\n/**\n * Split CIF 1.1 text into tokens. Comments are dropped; quoted strings and\n * semicolon text fields become single value tokens holding their content.\n */\nexport function tokenizeCif(text: string): CifToken[] {\n const tokens: CifToken[] = [];\n const lines = text.split(/\\r\\n|\\r|\\n/);\n let index = 0;\n\n while (index < lines.length) {\n const line = lines[index] ?? \"\";\n const lineNumber = index + 1;\n\n // AMCSD and RRUFF files close with a bare END line.\n if (line.trim().toUpperCase() === \"END\") {\n break;\n }\n\n if (line.startsWith(\";\")) {\n // A text field runs from this line to the next line starting with \";\".\n const content = [line.slice(1)];\n index += 1;\n let closed = false;\n while (index < lines.length) {\n const candidate = lines[index] ?? \"\";\n if (candidate.startsWith(\";\")) {\n closed = true;\n break;\n }\n content.push(candidate);\n index += 1;\n }\n if (!closed) {\n throw new CifSyntaxError(\"unterminated text field\", lineNumber);\n }\n tokens.push({\n kind: \"value\",\n text: content.join(\"\\n\"),\n line: lineNumber,\n });\n // The closing \";\" may be followed by more tokens on the same line.\n lines[index] = \" \" + (lines[index] ?? \"\").slice(1);\n continue;\n }\n\n let position = 0;\n while (position < line.length) {\n const char = line.charAt(position);\n if (isWhitespace(char)) {\n position += 1;\n continue;\n }\n if (char === \"#\") {\n break;\n }\n if (char === \"'\" || char === '\"') {\n // The string ends at a matching quote followed by whitespace or the\n // end of the line (CIF 1.1), so an apostrophe inside stays.\n let end = position + 1;\n while (end < line.length) {\n const next = line.indexOf(char, end);\n if (next === -1) {\n throw new CifSyntaxError(\"unterminated quoted string\", lineNumber);\n }\n const after = line.charAt(next + 1);\n if (next + 1 >= line.length || isWhitespace(after)) {\n end = next;\n break;\n }\n end = next + 1;\n }\n if (end >= line.length) {\n throw new CifSyntaxError(\"unterminated quoted string\", lineNumber);\n }\n tokens.push({\n kind: \"value\",\n text: line.slice(position + 1, end),\n line: lineNumber,\n });\n position = end + 1;\n continue;\n }\n let end = position;\n while (end < line.length && !isWhitespace(line.charAt(end))) {\n end += 1;\n }\n tokens.push(classify(line.slice(position, end), lineNumber));\n position = end;\n }\n index += 1;\n }\n\n return tokens;\n}\n","import { CifSyntaxError, tokenizeCif, type CifToken } from \"./tokenizer.js\";\n\nexport interface CifLoop {\n /** Lowercase tags, in column order. */\n tags: string[];\n /** One array of values per row, in `tags` order. */\n rows: string[][];\n}\n\n/** `tags` as a list: a single tag, or several aliases tried in order. */\nfunction tagList(tags: string | string[]): string[] {\n return typeof tags === \"string\" ? [tags] : tags;\n}\n\n/** One `data_` block: single-value items and loops. Tags are matched case-insensitively. */\nexport class CifBlock {\n readonly name: string;\n readonly items = new Map<string, string>();\n readonly loops: CifLoop[] = [];\n\n constructor(name: string) {\n this.name = name;\n }\n\n /** Raw value of the first present single-value item among `tags`, or null. */\n get(tags: string | string[]): string | null {\n for (const tag of tagList(tags)) {\n const value = this.items.get(tag.toLowerCase());\n if (value !== undefined) {\n return value;\n }\n }\n return null;\n }\n\n /** The first loop holding any of `tags`, or null. */\n findLoop(tags: string | string[]): CifLoop | null {\n for (const tag of tagList(tags)) {\n const lower = tag.toLowerCase();\n const loop = this.loops.find((entry) => entry.tags.includes(lower));\n if (loop) {\n return loop;\n }\n }\n return null;\n }\n}\n\n/** The data blocks of a CIF, in file order. */\nexport interface CifDocument {\n blocks: CifBlock[];\n}\n\n/** Column values of the first of `tags` present in `loop`, or null when none is. */\nexport function loopColumn(\n loop: CifLoop,\n tags: string | string[],\n): string[] | null {\n for (const tag of tagList(tags)) {\n const column = loop.tags.indexOf(tag.toLowerCase());\n if (column !== -1) {\n return loop.rows.map((row) => row[column] ?? \"?\");\n }\n }\n return null;\n}\n\n/** True for the CIF placeholders `?` (unknown) and `.` (inapplicable). */\nexport function isCifPlaceholder(value: string): boolean {\n return value === \"?\" || value === \".\";\n}\n\n/**\n * Parse a CIF number such as `0.012(1)`, dropping the standard uncertainty.\n * Placeholders and non-numbers give null.\n */\nexport function parseCifNumber(\n value: string | null | undefined,\n): number | null {\n if (value === null || value === undefined || isCifPlaceholder(value)) {\n return null;\n }\n const text = value.replace(/\\(\\d+\\)$/, \"\").trim();\n if (!/^[+-]?(\\d+\\.?\\d*|\\.\\d+)([eE][+-]?\\d+)?$/.test(text)) {\n return null;\n }\n return Number(text);\n}\n\nfunction isLoopTerminator(token: CifToken | undefined): boolean {\n return token === undefined || token.kind !== \"value\";\n}\n\n/** Parse CIF text into its data blocks. Save frames (dictionary files) are skipped. */\nexport function parseCif(text: string): CifDocument {\n const tokens = tokenizeCif(text);\n const blocks: CifBlock[] = [];\n let block: CifBlock | null = null;\n let index = 0;\n let saveFrameDepth = 0;\n\n const requireBlock = (token: CifToken): CifBlock => {\n if (!block) {\n // Items before any data_ heading belong to an unnamed block.\n block = new CifBlock(\"\");\n blocks.push(block);\n }\n if (saveFrameDepth > 0) {\n throw new CifSyntaxError(\n `unexpected ${token.kind} inside a save frame`,\n token.line,\n );\n }\n return block;\n };\n\n while (index < tokens.length) {\n const token = tokens[index];\n if (!token) {\n break;\n }\n switch (token.kind) {\n case \"data\": {\n block = new CifBlock(token.text);\n blocks.push(block);\n saveFrameDepth = 0;\n index += 1;\n break;\n }\n case \"save\": {\n saveFrameDepth =\n token.text === \"\"\n ? Math.max(0, saveFrameDepth - 1)\n : saveFrameDepth + 1;\n index += 1;\n break;\n }\n case \"stop\": {\n index += 1;\n break;\n }\n case \"tag\": {\n if (saveFrameDepth > 0) {\n index += 2;\n break;\n }\n const target = requireBlock(token);\n const value = tokens[index + 1];\n if (!value || value.kind !== \"value\") {\n throw new CifSyntaxError(\n `tag ${token.text} has no value`,\n token.line,\n );\n }\n target.items.set(token.text.toLowerCase(), value.text);\n index += 2;\n break;\n }\n case \"loop\": {\n const tags: string[] = [];\n index += 1;\n while (tokens[index]?.kind === \"tag\") {\n tags.push((tokens[index] as CifToken).text.toLowerCase());\n index += 1;\n }\n if (tags.length === 0) {\n throw new CifSyntaxError(\"loop_ without tags\", token.line);\n }\n const values: string[] = [];\n while (!isLoopTerminator(tokens[index])) {\n values.push((tokens[index] as CifToken).text);\n index += 1;\n }\n if (saveFrameDepth > 0) {\n break;\n }\n if (values.length % tags.length !== 0) {\n throw new CifSyntaxError(\n `loop with ${tags.length} tags has ${values.length} values`,\n token.line,\n );\n }\n const rows: string[][] = [];\n for (let start = 0; start < values.length; start += tags.length) {\n rows.push(values.slice(start, start + tags.length));\n }\n requireBlock(token).loops.push({ tags, rows });\n break;\n }\n case \"value\": {\n throw new CifSyntaxError(\n `unexpected value ${JSON.stringify(token.text)}`,\n token.line,\n );\n }\n }\n }\n\n return { blocks };\n}\n","/** Element symbols in atomic-number order. */\nexport const ELEMENT_SYMBOLS = [\n \"H\",\n \"He\",\n \"Li\",\n \"Be\",\n \"B\",\n \"C\",\n \"N\",\n \"O\",\n \"F\",\n \"Ne\",\n \"Na\",\n \"Mg\",\n \"Al\",\n \"Si\",\n \"P\",\n \"S\",\n \"Cl\",\n \"Ar\",\n \"K\",\n \"Ca\",\n \"Sc\",\n \"Ti\",\n \"V\",\n \"Cr\",\n \"Mn\",\n \"Fe\",\n \"Co\",\n \"Ni\",\n \"Cu\",\n \"Zn\",\n \"Ga\",\n \"Ge\",\n \"As\",\n \"Se\",\n \"Br\",\n \"Kr\",\n \"Rb\",\n \"Sr\",\n \"Y\",\n \"Zr\",\n \"Nb\",\n \"Mo\",\n \"Tc\",\n \"Ru\",\n \"Rh\",\n \"Pd\",\n \"Ag\",\n \"Cd\",\n \"In\",\n \"Sn\",\n \"Sb\",\n \"Te\",\n \"I\",\n \"Xe\",\n \"Cs\",\n \"Ba\",\n \"La\",\n \"Ce\",\n \"Pr\",\n \"Nd\",\n \"Pm\",\n \"Sm\",\n \"Eu\",\n \"Gd\",\n \"Tb\",\n \"Dy\",\n \"Ho\",\n \"Er\",\n \"Tm\",\n \"Yb\",\n \"Lu\",\n \"Hf\",\n \"Ta\",\n \"W\",\n \"Re\",\n \"Os\",\n \"Ir\",\n \"Pt\",\n \"Au\",\n \"Hg\",\n \"Tl\",\n \"Pb\",\n \"Bi\",\n \"Po\",\n \"At\",\n \"Rn\",\n \"Fr\",\n \"Ra\",\n \"Ac\",\n \"Th\",\n \"Pa\",\n \"U\",\n \"Np\",\n \"Pu\",\n \"Am\",\n \"Cm\",\n \"Bk\",\n \"Cf\",\n \"Es\",\n \"Fm\",\n \"Md\",\n \"No\",\n \"Lr\",\n \"Rf\",\n \"Db\",\n \"Sg\",\n \"Bh\",\n \"Hs\",\n \"Mt\",\n \"Ds\",\n \"Rg\",\n \"Cn\",\n \"Nh\",\n \"Fl\",\n \"Mc\",\n \"Lv\",\n \"Ts\",\n \"Og\",\n];\n\nconst ELEMENTS = new Set(ELEMENT_SYMBOLS);\n\n/** Deuterium keeps its own symbol for display and counts as hydrogen. */\nexport const DEUTERIUM = \"D\";\n\nexport function isElementSymbol(symbol: string): boolean {\n return ELEMENTS.has(symbol) || symbol === DEUTERIUM;\n}\n\nfunction capitalize(text: string): string {\n return text.charAt(0).toUpperCase() + text.slice(1).toLowerCase();\n}\n\n/**\n * The element behind a CIF atom label or type symbol: `Fe3+`, `O2-`, `Co1`,\n * `OW`, `fe` and `Wat` all resolve. Null when no element symbol fits.\n */\nexport function elementFromCifSymbol(raw: string): string | null {\n const letters = raw.match(/^[A-Za-z]{1,2}/)?.[0];\n if (!letters) {\n return null;\n }\n const two = capitalize(letters);\n if (letters.length === 2 && isElementSymbol(two)) {\n return two;\n }\n const one = letters.charAt(0).toUpperCase();\n return isElementSymbol(one) ? one : null;\n}\n\n/** The chemical element, with deuterium reported as hydrogen. */\nexport function chemicalElement(symbol: string): string {\n return symbol === DEUTERIUM ? \"H\" : symbol;\n}\n","import type { SymmetryOperation, Vec3 } from \"./types.js\";\n\n/** Generated equivalents this close in fractional coordinates are one atom. */\nexport const EQUIVALENT_TOLERANCE = 1e-3;\n\n/** A wrapped coordinate this close below 1 is rounding; it belongs at 0. */\nconst NEAR_ONE = 1e-9;\n\n/** Fold a coordinate into [0, 1); a value within `nearOne` below 1 becomes 0. */\nexport function wrap(value: number, nearOne = NEAR_ONE): number {\n const wrapped = value - Math.floor(value);\n return wrapped >= 1 - nearOne ? 0 : wrapped;\n}\n\n/** Fold a fractional position into the cell. */\nexport function wrapVector(fractional: Vec3): Vec3 {\n return [wrap(fractional[0]), wrap(fractional[1]), wrap(fractional[2])];\n}\n\n/** Periodic distance of two fractional positions, per axis, below `tolerance`. */\nexport function samePosition(p: Vec3, q: Vec3, tolerance: number): boolean {\n for (let axis = 0; axis < 3; axis += 1) {\n let delta = Math.abs((p[axis] as number) - (q[axis] as number));\n delta -= Math.round(delta);\n if (Math.abs(delta) > tolerance) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * Buckets per cell edge. A bucket is wider than any tolerance used with\n * them, so a match lies in a position's own bucket or a neighbouring one.\n */\nconst BUCKETS = 100;\n\nfunction bucketOf(value: number): number {\n return Math.floor(wrap(value) * BUCKETS) % BUCKETS;\n}\n\nfunction bucketKey(x: number, y: number, z: number): number {\n return (x * BUCKETS + y) * BUCKETS + z;\n}\n\n/**\n * Fractional positions bucketed by where they fall in the cell, so finding\n * those within a tolerance of a position, across the periodic boundaries,\n * takes a few comparisons instead of one per position. The tolerance is per\n * axis, as in `samePosition`, and must stay below 1 / BUCKETS.\n */\nexport class PositionIndex {\n private readonly buckets = new Map<number, number[]>();\n private readonly positions: Vec3[] = [];\n\n constructor(private readonly tolerance: number) {}\n\n /** Add a position; its index counts up from 0 in the order added. */\n add(position: Vec3): number {\n const index = this.positions.length;\n this.positions.push(position);\n const key = bucketKey(\n bucketOf(position[0]),\n bucketOf(position[1]),\n bucketOf(position[2]),\n );\n const bucket = this.buckets.get(key);\n if (bucket) {\n bucket.push(index);\n } else {\n this.buckets.set(key, [index]);\n }\n return index;\n }\n\n /** Indices of the positions within tolerance of `position`, ascending. */\n near(position: Vec3): number[] {\n const wrapped = wrapVector(position);\n const [x, y, z] = wrapped.map(bucketOf) as Vec3;\n const found: number[] = [];\n for (let dx = -1; dx <= 1; dx += 1) {\n const bx = (x + dx + BUCKETS) % BUCKETS;\n for (let dy = -1; dy <= 1; dy += 1) {\n const by = (y + dy + BUCKETS) % BUCKETS;\n for (let dz = -1; dz <= 1; dz += 1) {\n const bz = (z + dz + BUCKETS) % BUCKETS;\n for (const index of this.buckets.get(bucketKey(bx, by, bz)) ?? []) {\n if (samePosition(this.positions[index]!, wrapped, this.tolerance)) {\n found.push(index);\n }\n }\n }\n }\n }\n return found.sort((left, right) => left - right);\n }\n}\n\n/** Apply an operation to fractional coordinates (no wrapping). */\nexport function applyOperation(\n operation: SymmetryOperation,\n fractional: Vec3,\n): Vec3 {\n const r = operation.rotation;\n const [x, y, z] = fractional;\n const t = operation.translation;\n return [\n (r[0] ?? 0) * x + (r[1] ?? 0) * y + (r[2] ?? 0) * z + t[0],\n (r[3] ?? 0) * x + (r[4] ?? 0) * y + (r[5] ?? 0) * z + t[1],\n (r[6] ?? 0) * x + (r[7] ?? 0) * y + (r[8] ?? 0) * z + t[2],\n ];\n}\n","import type { Lattice, LatticeParameters, Mat3, Vec3 } from \"./types.js\";\n\nconst DEGREES = Math.PI / 180;\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, value));\n}\n\n/**\n * A lattice from cell lengths in ångström and angles in degrees. The c axis\n * points along z and a lies in the xz plane, as in pymatgen.\n */\nexport function latticeFromParameters(parameters: LatticeParameters): Lattice {\n const { a, b, c } = parameters;\n const alpha = parameters.alpha * DEGREES;\n const beta = parameters.beta * DEGREES;\n const gamma = parameters.gamma * DEGREES;\n const cosAlpha = Math.cos(alpha);\n const cosBeta = Math.cos(beta);\n const cosGamma = Math.cos(gamma);\n const sinAlpha = Math.sin(alpha);\n const sinBeta = Math.sin(beta);\n const gammaStar = Math.acos(\n clamp((cosAlpha * cosBeta - cosGamma) / (sinAlpha * sinBeta), -1, 1),\n );\n const vectorA: Vec3 = [a * sinBeta, 0, a * cosBeta];\n const vectorB: Vec3 = [\n -b * sinAlpha * Math.cos(gammaStar),\n b * sinAlpha * Math.sin(gammaStar),\n b * cosAlpha,\n ];\n const vectorC: Vec3 = [0, 0, c];\n return { ...parameters, vectors: [vectorA, vectorB, vectorC] };\n}\n\n/** A lattice from its three cell vectors, in ångström. */\nexport function latticeFromVectors(vectors: Mat3): Lattice {\n const [a, b, c] = vectors;\n const length = (v: Vec3) => Math.hypot(v[0], v[1], v[2]);\n const angle = (u: Vec3, v: Vec3) =>\n Math.acos(\n clamp(\n (u[0] * v[0] + u[1] * v[1] + u[2] * v[2]) / (length(u) * length(v)),\n -1,\n 1,\n ),\n ) / DEGREES;\n return {\n a: length(a),\n b: length(b),\n c: length(c),\n alpha: angle(b, c),\n beta: angle(a, c),\n gamma: angle(a, b),\n vectors,\n };\n}\n\nexport function fractionalToCartesian(\n lattice: Lattice,\n fractional: Vec3,\n): Vec3 {\n const [va, vb, vc] = lattice.vectors;\n const [x, y, z] = fractional;\n return [\n x * va[0] + y * vb[0] + z * vc[0],\n x * va[1] + y * vb[1] + z * vc[1],\n x * va[2] + y * vb[2] + z * vc[2],\n ];\n}\n\nexport function distance(p: Vec3, q: Vec3): number {\n const dx = p[0] - q[0];\n const dy = p[1] - q[1];\n const dz = p[2] - q[2];\n return Math.sqrt(dx * dx + dy * dy + dz * dz);\n}\n","/** The CIF parses but does not describe a structure this package can use. */\nexport class CifStructureError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"CifStructureError\";\n }\n}\n","import { wrap } from \"../structure/fractional.js\";\nimport type { SymmetryOperation, Vec3 } from \"../structure/types.js\";\nimport { CifStructureError } from \"./errors.js\";\n\nconst AXES = [\"x\", \"y\", \"z\"] as const;\n\nfunction parseCoefficient(text: string): number {\n if (text === \"\" || text === \"+\") {\n return 1;\n }\n if (text === \"-\") {\n return -1;\n }\n const fraction = text.match(/^([+-]?\\d+)\\/(\\d+)$/);\n const value = fraction\n ? Number(fraction[1]) / Number(fraction[2])\n : Number(text);\n if (!Number.isFinite(value)) {\n throw new CifStructureError(\n `Cannot read the number ${JSON.stringify(text)} in a symmetry operator.`,\n );\n }\n return value;\n}\n\n/**\n * Parse a symmetry operation as CIF files write it, such as\n * `-x+1/2, y, -z+1/2`, into a rotation matrix and translation.\n */\nexport function parseSymmetryOperator(text: string): SymmetryOperation {\n // Only signs, digits, fractions, decimals and x, y, z can belong to an\n // operator; stray letters such as the \"t\" some exports append are dropped.\n const components = text\n .split(\",\")\n .map((part) => part.toLowerCase().replace(/[^xyz0-9./+-]/g, \"\"));\n if (components.length !== 3) {\n throw new CifStructureError(\n `A symmetry operator needs three components: ${JSON.stringify(text)}.`,\n );\n }\n const rotation: number[] = [];\n const translation: number[] = [];\n\n for (const component of components) {\n const terms = component.match(/[+-]?[^+-]+/g);\n if (!terms || terms.join(\"\") !== component) {\n throw new CifStructureError(\n `Cannot read the symmetry operator ${JSON.stringify(text)}.`,\n );\n }\n const row = [0, 0, 0];\n let shift = 0;\n for (const term of terms) {\n const axis = AXES.findIndex((candidate) => term.includes(candidate));\n if (axis === -1) {\n shift += parseCoefficient(term);\n } else {\n const coefficient = parseCoefficient(\n term.replace(AXES[axis] as string, \"\").replace(/\\*$/, \"\"),\n );\n row[axis] = (row[axis] ?? 0) + coefficient;\n }\n }\n rotation.push(...row);\n translation.push(wrap(shift));\n }\n\n return { rotation, translation: translation as Vec3 };\n}\n","import { elementFromCifSymbol } from \"../structure/elements.js\";\nimport { PositionIndex, wrap } from \"../structure/fractional.js\";\nimport { latticeFromParameters } from \"../structure/lattice.js\";\nimport type {\n Lattice,\n Site,\n SpaceGroupInfo,\n Species,\n SymmetryOperation,\n Vec3,\n} from \"../structure/types.js\";\nimport {\n isCifPlaceholder,\n loopColumn,\n parseCifNumber,\n type CifBlock,\n} from \"./parser.js\";\nimport { CifStructureError } from \"./errors.js\";\nimport { parseSymmetryOperator } from \"./symmetry-operators.js\";\n\nexport { CifStructureError };\n\n/** Rows this close in fractional coordinates describe one site. */\nconst SITE_MERGE_TOLERANCE = 1e-4;\n\nconst OPERATOR_TAGS = [\n \"_space_group_symop_operation_xyz\",\n \"_symmetry_equiv_pos_as_xyz\",\n];\nconst SPACE_GROUP_NUMBER_TAGS = [\n \"_space_group_it_number\",\n \"_symmetry_int_tables_number\",\n];\nconst HERMANN_MAUGUIN_TAGS = [\n \"_space_group_name_h-m_alt\",\n \"_symmetry_space_group_name_h-m\",\n \"_space_group_name_h-m_full\",\n];\nconst HALL_TAGS = [\"_space_group_name_hall\", \"_symmetry_space_group_name_hall\"];\n\nexport interface ParsedCifStructure {\n lattice: Lattice;\n sites: Site[];\n /** Null when the file lists no operators; see `spaceGroup` then. */\n operations: SymmetryOperation[] | null;\n spaceGroup: SpaceGroupInfo;\n}\n\nfunction requireNumber(block: CifBlock, tag: string): number {\n const value = parseCifNumber(block.get(tag));\n if (value === null) {\n throw new CifStructureError(\n `${block.name || \"The CIF\"} has no usable ${tag}.`,\n );\n }\n return value;\n}\n\nfunction mergeSpecies(\n species: Species[],\n element: string,\n occupancy: number,\n): void {\n const existing = species.find((entry) => entry.element === element);\n if (existing) {\n existing.occupancy += occupancy;\n } else {\n species.push({ element, occupancy });\n }\n species.sort((left, right) => right.occupancy - left.occupancy);\n}\n\n/** Totals this far above 1 are more than rounding. */\nconst OVERFULL_TOLERANCE = 1e-6;\n\n/**\n * A site holds at most one atom. Refined occupancies sometimes add up to a\n * little more, and some files list far more; either way the species are\n * scaled down to a full site, the rule pymatgen applies within its\n * tolerance, so the drawn atom makes sense.\n */\nfunction scaleOverfullSites(sites: Site[]): void {\n for (const site of sites) {\n const total = site.species.reduce(\n (sum, species) => sum + species.occupancy,\n 0,\n );\n if (total > 1 + OVERFULL_TOLERANCE) {\n for (const species of site.species) {\n species.occupancy /= total;\n }\n }\n }\n}\n\nfunction readSites(block: CifBlock): Site[] {\n const loop = block.findLoop(\"_atom_site_fract_x\");\n if (!loop) {\n throw new CifStructureError(\n `${block.name || \"The CIF\"} has no atom sites.`,\n );\n }\n const xs = loopColumn(loop, \"_atom_site_fract_x\") ?? [];\n const ys = loopColumn(loop, \"_atom_site_fract_y\") ?? [];\n const zs = loopColumn(loop, \"_atom_site_fract_z\") ?? [];\n const labels = loopColumn(loop, \"_atom_site_label\");\n const typeSymbols = loopColumn(loop, \"_atom_site_type_symbol\");\n const occupancies = loopColumn(loop, \"_atom_site_occupancy\");\n const sites: Site[] = [];\n const positions = new PositionIndex(SITE_MERGE_TOLERANCE);\n\n for (let row = 0; row < loop.rows.length; row += 1) {\n const x = parseCifNumber(xs[row]);\n const y = parseCifNumber(ys[row]);\n const z = parseCifNumber(zs[row]);\n if (x === null || y === null || z === null) {\n continue;\n }\n const label = labels?.[row] ?? typeSymbols?.[row] ?? `site${row + 1}`;\n const typeSymbol = typeSymbols?.[row];\n const element =\n (typeSymbol && !isCifPlaceholder(typeSymbol)\n ? elementFromCifSymbol(typeSymbol)\n : null) ?? elementFromCifSymbol(label);\n if (!element) {\n throw new CifStructureError(\n `Atom site ${JSON.stringify(label)} names no element (type symbol ${JSON.stringify(typeSymbol ?? \"\")}).`,\n );\n }\n const occupancy = parseCifNumber(occupancies?.[row]) ?? 1;\n const fractional: Vec3 = [wrap(x), wrap(y), wrap(z)];\n // The first site listed at this position, if any.\n const [shared] = positions.near(fractional);\n if (shared !== undefined) {\n mergeSpecies(sites[shared]!.species, element, occupancy);\n } else {\n positions.add(fractional);\n sites.push({ label, species: [{ element, occupancy }], fractional });\n }\n }\n\n if (sites.length === 0) {\n throw new CifStructureError(\n `${block.name || \"The CIF\"} has no atom sites with coordinates.`,\n );\n }\n scaleOverfullSites(sites);\n return sites;\n}\n\nfunction readOperations(block: CifBlock): SymmetryOperation[] | null {\n const loop = block.findLoop(OPERATOR_TAGS);\n if (!loop) {\n const single = block.get(OPERATOR_TAGS);\n return single === null ? null : [parseSymmetryOperator(single)];\n }\n const column = loopColumn(loop, OPERATOR_TAGS) ?? [];\n const operations = column\n .filter((text) => !isCifPlaceholder(text))\n .map(parseSymmetryOperator);\n return operations.length > 0 ? operations : null;\n}\n\nfunction readSpaceGroup(block: CifBlock): SpaceGroupInfo {\n const numberText = block.get(SPACE_GROUP_NUMBER_TAGS);\n const number = numberText === null ? null : parseCifNumber(numberText);\n const symbol = block.get(HERMANN_MAUGUIN_TAGS);\n const hallSymbol = block.get(HALL_TAGS);\n return {\n number:\n number !== null &&\n Number.isInteger(number) &&\n number >= 1 &&\n number <= 230\n ? number\n : null,\n symbol: symbol !== null && !isCifPlaceholder(symbol) ? symbol.trim() : null,\n hallSymbol:\n hallSymbol !== null && !isCifPlaceholder(hallSymbol)\n ? hallSymbol.trim()\n : null,\n };\n}\n\n/** True when the block carries atom coordinates (the one a viewer wants). */\nexport function isStructureBlock(block: CifBlock): boolean {\n return block.findLoop(\"_atom_site_fract_x\") !== null;\n}\n\n/** Lattice, merged sites, operators and space-group tags of one data block. */\nexport function parseCifStructure(block: CifBlock): ParsedCifStructure {\n const lattice = latticeFromParameters({\n a: requireNumber(block, \"_cell_length_a\"),\n b: requireNumber(block, \"_cell_length_b\"),\n c: requireNumber(block, \"_cell_length_c\"),\n alpha: requireNumber(block, \"_cell_angle_alpha\"),\n beta: requireNumber(block, \"_cell_angle_beta\"),\n gamma: requireNumber(block, \"_cell_angle_gamma\"),\n });\n return {\n lattice,\n sites: readSites(block),\n operations: readOperations(block),\n spaceGroup: readSpaceGroup(block),\n };\n}\n","import {\n EQUIVALENT_TOLERANCE,\n PositionIndex,\n applyOperation,\n} from \"./fractional.js\";\nimport type { Site, SymmetryOperation } from \"./types.js\";\n\nexport interface ListingClosure {\n /** Some listed site is a symmetry image of another: the list is already expanded, fully or partly. */\n preExpanded: boolean;\n /** Every image of every listed site is itself a listed site. */\n closed: boolean;\n}\n\n/**\n * How the listed sites relate to the operations. An asymmetric unit lists\n * no site that is an image of another, and its images are new positions,\n * as they should be. A list that is already expanded repeats such images,\n * and then the operations must map the list onto itself, or they are not\n * the symmetry of these atoms.\n */\nexport function listingClosure(\n sites: Site[],\n operations: SymmetryOperation[],\n): ListingClosure {\n const index = new PositionIndex(EQUIVALENT_TOLERANCE);\n for (const site of sites) {\n index.add(site.fractional);\n }\n let preExpanded = false;\n let closed = true;\n sites.forEach((site, self) => {\n for (const operation of operations) {\n const hits = index.near(applyOperation(operation, site.fractional));\n if (hits.some((hit) => hit !== self)) {\n preExpanded = true;\n }\n if (hits.length === 0) {\n closed = false;\n }\n }\n });\n return { preExpanded, closed };\n}\n","/** Three Cartesian or fractional components. */\nexport type Vec3 = [number, number, number];\n\n/** Three row vectors. */\nexport type Mat3 = [Vec3, Vec3, Vec3];\n\nexport interface LatticeParameters {\n a: number;\n b: number;\n c: number;\n /** Degrees. */\n alpha: number;\n beta: number;\n gamma: number;\n}\n\nexport interface Lattice extends LatticeParameters {\n /** Row vectors a, b, c in Cartesian ångström. */\n vectors: Mat3;\n}\n\nexport interface Species {\n /** Element symbol, such as \"Fe\"; \"D\" for deuterium. */\n element: string;\n /** Share of the site this species occupies, 0 to 1; a site's shares add up to at most 1. */\n occupancy: number;\n}\n\n/** One crystallographic site; several species share it when disordered. */\nexport interface Site {\n label: string;\n /** Sorted by descending occupancy. */\n species: Species[];\n fractional: Vec3;\n}\n\n/** x' = R x + t on fractional coordinates; `rotation` is row-major. */\nexport interface SymmetryOperation {\n rotation: number[];\n translation: Vec3;\n}\n\n/** What a CIF says about its space group; null for what it leaves out. */\nexport interface SpaceGroupInfo {\n /** Number in the International Tables, 1 to 230. */\n number: number | null;\n /** Hermann-Mauguin symbol as written in the file. */\n symbol: string | null;\n /** Hall symbol as written in the file. */\n hallSymbol: string | null;\n}\n\nexport interface Structure {\n lattice: Lattice;\n sites: Site[];\n /** Operations that generate the full cell from `sites`; the identity alone once expanded. */\n operations: SymmetryOperation[];\n spaceGroup: SpaceGroupInfo;\n}\n\nexport const IDENTITY_OPERATION: SymmetryOperation = {\n rotation: [1, 0, 0, 0, 1, 0, 0, 0, 1],\n translation: [0, 0, 0],\n};\n","import type * as MoyoBindings from \"./moyo-wasm.js\";\n\n// Kept apart from moyo.ts so the published declarations never refer to the\n// bindings, whose types come from a package consumers do not install.\n\nlet bindings: typeof MoyoBindings | null = null;\nlet loading: Promise<void> | null = null;\n\n/**\n * Import the moyo chunk and instantiate its module, once. A failed attempt\n * is not kept: the next call tries again.\n */\nexport function loadMoyo(): Promise<void> {\n if (!loading) {\n loading = import(\"./moyo-wasm.js\")\n .then(async (module) => {\n await module.instantiate();\n bindings = module;\n })\n .catch((error: unknown) => {\n loading = null;\n throw error;\n });\n }\n return loading;\n}\n\n/** The moyo bindings, once `loadMoyo` has resolved. */\nexport function moyo(): typeof MoyoBindings {\n if (!bindings) {\n throw new Error(\"moyo is not loaded yet; await ensureMoyo() first.\");\n }\n return bindings;\n}\n","import type { MoyoHallSymbolEntry } from \"@spglib/moyo-wasm\";\n\nimport type { SpaceGroupInfo, SymmetryOperation } from \"../structure/types.js\";\nimport { loadMoyo, moyo } from \"./moyo-loader.js\";\n\n/** The named space group is not in the symmetry table. */\nexport class SpaceGroupLookupError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"SpaceGroupLookupError\";\n }\n}\n\nlet hallEntries: MoyoHallSymbolEntry[] | null = null;\n\n/**\n * Load moyo, the symmetry library, ahead of first use. This is optional:\n * everything that needs moyo loads it. If loading fails, the next call tries\n * again.\n */\nexport function ensureMoyo(): Promise<void> {\n return loadMoyo();\n}\n\n/**\n * An operation as moyo returns it. Declared here rather than imported so the\n * published declarations do not depend on @spglib/moyo-wasm, which is bundled\n * at build time and not installed by consumers.\n */\nexport interface MoyoOperationLike {\n /** Nine integers, column-major. */\n rotation: readonly [\n number,\n number,\n number,\n number,\n number,\n number,\n number,\n number,\n number,\n ];\n translation: readonly [number, number, number];\n}\n\n/** moyo stores matrices column-major: element (i, j) sits at i + 3j. */\nexport function fromMoyoOperation(\n operation: MoyoOperationLike,\n): SymmetryOperation {\n const r = operation.rotation;\n return {\n rotation: [r[0], r[3], r[6], r[1], r[4], r[7], r[2], r[5], r[8]],\n translation: [\n operation.translation[0],\n operation.translation[1],\n operation.translation[2],\n ],\n };\n}\n\nfunction allHallEntries(): MoyoHallSymbolEntry[] {\n if (!hallEntries) {\n hallEntries = [];\n for (let number = 1; number <= 230; number += 1) {\n hallEntries.push(...moyo().hall_symbol_entries_from_number(number));\n }\n }\n return hallEntries;\n}\n\n/** Spaces and the screw-axis underscore carry no meaning when matching symbols. */\nfunction normalizeSymbol(symbol: string): string {\n return symbol.replace(/[\\s_]/g, \"\").toLowerCase();\n}\n\n/**\n * Split a CIF Hermann-Mauguin symbol into its symbol and setting suffix:\n * `R -3 m :H` and `R -3 m H` give `r-3m` and `h`; `P 1 21/c 1` gives\n * `p121/c1` and null, its trailing 1 being part of the full symbol.\n */\nfunction splitHermannMauguin(symbol: string): {\n base: string;\n setting: string | null;\n} {\n const trimmed = symbol.trim();\n const colon = trimmed.match(/^(.*?)\\s*:\\s*(\\S+)$/);\n if (colon && colon[1] && colon[2]) {\n return { base: normalizeSymbol(colon[1]), setting: colon[2].toLowerCase() };\n }\n const trailing = trimmed.match(/^(.*\\S)\\s+([HRhr])$/);\n if (trailing && trailing[1] && trailing[2]) {\n return {\n base: normalizeSymbol(trailing[1]),\n setting: trailing[2].toLowerCase(),\n };\n }\n return { base: normalizeSymbol(trimmed), setting: null };\n}\n\n/** The entry spglib treats as the standard setting, first among `entries`. */\nfunction preferStandard(entries: MoyoHallSymbolEntry[]): MoyoHallSymbolEntry[] {\n const first = entries[0];\n if (!first) {\n return entries;\n }\n const standard = moyo().space_group_type(first.number).hall_number;\n return [...entries].sort((left, right) => {\n return (\n Number(right.hall_number === standard) -\n Number(left.hall_number === standard)\n );\n });\n}\n\nfunction entriesForSymbol(info: SpaceGroupInfo): MoyoHallSymbolEntry[] {\n const entries = allHallEntries().filter(\n (entry) => info.number === null || entry.number === info.number,\n );\n if (info.hallSymbol) {\n const wanted = normalizeSymbol(info.hallSymbol);\n const byHall = entries.filter(\n (entry) => normalizeSymbol(entry.hall_symbol) === wanted,\n );\n if (byHall.length > 0) {\n return byHall;\n }\n }\n if (info.symbol) {\n const { base, setting } = splitHermannMauguin(info.symbol);\n const bySymbol = entries.filter(\n (entry) =>\n normalizeSymbol(entry.hm_short) === base ||\n normalizeSymbol(entry.hm_full) === base,\n );\n if (setting) {\n const bySetting = bySymbol.filter(\n (entry) => entry.setting.toLowerCase() === setting,\n );\n if (bySetting.length > 0) {\n return bySetting;\n }\n }\n return preferStandard(bySymbol);\n }\n return [];\n}\n\nfunction describe(info: SpaceGroupInfo): string {\n return [info.hallSymbol, info.symbol, info.number]\n .filter((part) => part !== null)\n .join(\" / \");\n}\n\nexport interface OperationSetting {\n /** moyo's name for the setting, such as \"H\", \"R\" or \"b1\"; \"\" when the group has one. */\n setting: string;\n /** Operations of the conventional cell in that setting. */\n operations: SymmetryOperation[];\n}\n\n/**\n * Every setting the space group a CIF names admits, spglib's standard one\n * first: one for most symbols, several for a short symbol such as `P 21/c`\n * or a rhombohedral symbol without `:H` or `:R`. A bare number gives the\n * standard setting alone.\n */\nexport async function operationSettings(\n info: SpaceGroupInfo,\n): Promise<OperationSetting[]> {\n await ensureMoyo();\n const { operations_from_number } = moyo();\n if (info.hallSymbol || info.symbol) {\n const entries = entriesForSymbol(info);\n if (entries.length === 0) {\n throw new SpaceGroupLookupError(\n `Space group ${describe(info)} is not in the symmetry table.`,\n );\n }\n return entries.map((entry) => ({\n setting: entry.setting,\n operations: operations_from_number(\n entry.number,\n { type: \"HallNumber\", value: entry.hall_number },\n false,\n ).map(fromMoyoOperation),\n }));\n }\n if (info.number === null) {\n throw new SpaceGroupLookupError(\"The CIF names no space group.\");\n }\n return [\n {\n setting: \"\",\n operations: operations_from_number(\n info.number,\n { type: \"Spglib\" },\n false,\n ).map(fromMoyoOperation),\n },\n ];\n}\n\n/**\n * The symmetry operations of a space group given by Hall symbol,\n * Hermann-Mauguin symbol or number, in the setting a suffix such as `:H`\n * names, or else the standard setting. Throws `SpaceGroupLookupError` for\n * an unknown group.\n */\nexport async function operationsForSpaceGroup(\n info: SpaceGroupInfo,\n): Promise<SymmetryOperation[]> {\n const [first] = await operationSettings(info);\n return first!.operations;\n}\n","import {\n CifStructureError,\n type ParsedCifStructure,\n} from \"../cif/structure.js\";\nimport { listingClosure } from \"../structure/closure.js\";\nimport {\n IDENTITY_OPERATION,\n type LatticeParameters,\n type Site,\n type SymmetryOperation,\n} from \"../structure/types.js\";\nimport { operationSettings } from \"./moyo.js\";\n\n/** Lengths within this fraction, and angles within this many degrees, are equal. */\nconst SAME_LENGTH = 1e-3;\nconst SAME_ANGLE = 0.01;\n\nfunction misfit(): CifStructureError {\n return new CifStructureError(\n \"The symmetry does not fit the listed atoms: they are already expanded, yet the operations generate positions the file does not list.\",\n );\n}\n\nfunction assertFits(sites: Site[], operations: SymmetryOperation[]): void {\n const closure = listingClosure(sites, operations);\n if (closure.preExpanded && !closure.closed) {\n throw misfit();\n }\n}\n\n/** The axes a cell is set on when its shape says so: rhombohedral or hexagonal. */\nfunction axesOfCell({\n a,\n b,\n c,\n alpha,\n beta,\n gamma,\n}: LatticeParameters): \"H\" | \"R\" | null {\n const sameLength = (x: number, y: number) =>\n Math.abs(x - y) <= SAME_LENGTH * Math.max(x, y);\n const sameAngle = (x: number, y: number) => Math.abs(x - y) <= SAME_ANGLE;\n if (\n sameLength(a, b) &&\n sameLength(b, c) &&\n sameAngle(alpha, beta) &&\n sameAngle(beta, gamma) &&\n !sameAngle(alpha, 90)\n ) {\n return \"R\";\n }\n if (\n sameLength(a, b) &&\n sameAngle(alpha, 90) &&\n sameAngle(beta, 90) &&\n sameAngle(gamma, 120)\n ) {\n return \"H\";\n }\n return null;\n}\n\n/**\n * The operations a parsed CIF's atoms are expanded with: the file's own\n * loop, checked to fit the atoms, or else the setting of its space group\n * that fits them. A symbol admitting several settings, such as a\n * rhombohedral group with no `:H` or `:R`, is settled by the atoms when the\n * list is already expanded, since only the right setting maps it onto\n * itself, and otherwise by the cell shape, then by the standard setting.\n */\nexport async function resolveOperations(\n parsed: ParsedCifStructure,\n): Promise<SymmetryOperation[]> {\n if (parsed.operations) {\n assertFits(parsed.sites, parsed.operations);\n return parsed.operations;\n }\n const { spaceGroup } = parsed;\n if (\n spaceGroup.hallSymbol === null &&\n spaceGroup.symbol === null &&\n spaceGroup.number === null\n ) {\n return [IDENTITY_OPERATION];\n }\n const settings = await operationSettings(spaceGroup);\n if (settings.length === 1) {\n const [only] = settings;\n assertFits(parsed.sites, only!.operations);\n return only!.operations;\n }\n const closures = settings.map((setting) =>\n listingClosure(parsed.sites, setting.operations),\n );\n const fitting = settings.find(\n (_, index) => closures[index]!.preExpanded && closures[index]!.closed,\n );\n if (fitting) {\n return fitting.operations;\n }\n if (closures.some((closure) => closure.preExpanded)) {\n throw misfit();\n }\n const axes = axesOfCell(parsed.lattice);\n const byCell =\n axes === null\n ? undefined\n : settings.find((setting) => setting.setting.toUpperCase() === axes);\n return (byCell ?? settings[0]!).operations;\n}\n","import {\n EQUIVALENT_TOLERANCE,\n PositionIndex,\n applyOperation,\n wrapVector,\n} from \"./fractional.js\";\nimport { IDENTITY_OPERATION, type Site, type Structure } from \"./types.js\";\n\n/**\n * Fill the unit cell: apply every symmetry operation to every site and keep\n * each distinct position once. The result lists every atom, with the\n * identity as its only operation.\n */\nexport function expandStructure(structure: Structure): Structure {\n const sites: Site[] = [];\n const kept = new PositionIndex(EQUIVALENT_TOLERANCE);\n for (const site of structure.sites) {\n for (const operation of structure.operations) {\n const fractional = wrapVector(applyOperation(operation, site.fractional));\n if (kept.near(fractional).length === 0) {\n kept.add(fractional);\n sites.push({ label: site.label, species: site.species, fractional });\n }\n }\n }\n return { ...structure, sites, operations: [IDENTITY_OPERATION] };\n}\n","import type {\n MoyoCell,\n MoyoDataset,\n MoyoHallSymbolEntry,\n} from \"@spglib/moyo-wasm\";\n\nimport { expandStructure } from \"../structure/expand.js\";\nimport { wrapVector } from \"../structure/fractional.js\";\nimport { latticeFromVectors } from \"../structure/lattice.js\";\nimport {\n IDENTITY_OPERATION,\n type Mat3,\n type Site,\n type Species,\n type Structure,\n type SymmetryOperation,\n} from \"../structure/types.js\";\nimport { ensureMoyo, fromMoyoOperation } from \"./moyo.js\";\nimport { moyo } from \"./moyo-loader.js\";\n\n/**\n * Distance tolerance of the symmetry search, in ångström: pymatgen's\n * default, loose enough for coordinates rounded to four decimals.\n */\nconst DEFAULT_SYMPREC = 0.01;\n\n/** moyo could not analyse the structure. */\nexport class SymmetryAnalysisError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"SymmetryAnalysisError\";\n }\n}\n\nexport interface SymmetryOptions {\n /** Distance tolerance in ångström. Default 0.01. */\n symprec?: number;\n}\n\n/** What moyo finds when it analyses the atoms of a structure. */\nexport interface SymmetryDataset {\n /** Space-group number in the International Tables. */\n number: number;\n /** Short Hermann-Mauguin symbol of the standard setting, as moyo writes it. */\n symbol: string;\n /** Full Hermann-Mauguin symbol of that setting. */\n fullSymbol: string;\n /** Hall symbol of that setting. */\n hallSymbol: string;\n /** Hall number of that setting, 1 to 530, as spglib counts them. */\n hallNumber: number;\n /** Setting of the Hall entry: \"2\" for origin choice 2, \"H\" for hexagonal axes, \"\" when there is one setting. */\n setting: string;\n /** The crystal system, as moyo names it. */\n crystalSystem: string;\n /** Operations of the analysed cell, in its own basis. */\n operations: SymmetryOperation[];\n /** Wyckoff letter of every site of `structure`, in its order. */\n wyckoffs: string[];\n /** Site-symmetry symbol of every site of `structure`, in its order. */\n siteSymmetries: string[];\n /** The expanded structure the analysis ran on. */\n structure: Structure;\n /** The same crystal in moyo's standard setting: a symmetry-refined conventional cell listing every atom. */\n standard: Structure;\n}\n\n/**\n * moyo tells sites apart by an integer label. Every distinct species list,\n * occupancies included, gets a label of its own, the way pymatgen types\n * sites, so a half-occupied sodium site never matches a full one and the\n * standard cell maps back to exactly the species it was given.\n */\nfunction labelSpecies(sites: Site[]): {\n numbers: number[];\n speciesByLabel: Map<number, Species[]>;\n} {\n const labelByKey = new Map<string, number>();\n const speciesByLabel = new Map<number, Species[]>();\n const numbers = sites.map((site) => {\n const key = JSON.stringify(site.species);\n let label = labelByKey.get(key);\n if (label === undefined) {\n label = labelByKey.size + 1;\n labelByKey.set(key, label);\n speciesByLabel.set(label, site.species);\n }\n return label;\n });\n return { numbers, speciesByLabel };\n}\n\n/** moyo's standardized cell as a structure, every atom listed. */\nfunction standardStructure(\n dataset: MoyoDataset,\n speciesByLabel: Map<number, Species[]>,\n entry: MoyoHallSymbolEntry,\n): Structure {\n const basis = dataset.std_cell.lattice.basis;\n const vectors: Mat3 = [\n [basis[0], basis[1], basis[2]],\n [basis[3], basis[4], basis[5]],\n [basis[6], basis[7], basis[8]],\n ];\n const counts = new Map<string, number>();\n const sites = dataset.std_cell.positions.map((position, index) => {\n const label = dataset.std_cell.numbers[index] ?? 0;\n const species = speciesByLabel.get(label) ?? [];\n const element = species[0]?.element ?? \"X\";\n const count = (counts.get(element) ?? 0) + 1;\n counts.set(element, count);\n return {\n label: `${element}${count}`,\n species,\n fractional: wrapVector(position),\n };\n });\n return {\n lattice: latticeFromVectors(vectors),\n sites,\n operations: [IDENTITY_OPERATION],\n spaceGroup: {\n number: dataset.number,\n symbol: dataset.hm_symbol,\n hallSymbol: entry.hall_symbol,\n },\n };\n}\n\n/**\n * Find the space group of a structure from its atoms alone, whatever the\n * file says. See `SymmetryDataset` for what the result holds.\n */\nexport async function symmetryDataset(\n structure: Structure,\n options: SymmetryOptions = {},\n): Promise<SymmetryDataset> {\n await ensureMoyo();\n const { analyze_cell, hall_symbol_entry, space_group_type } = moyo();\n const expanded = expandStructure(structure);\n const { numbers, speciesByLabel } = labelSpecies(expanded.sites);\n const [a, b, c] = expanded.lattice.vectors;\n const cell: MoyoCell = {\n lattice: { basis: [...a, ...b, ...c] },\n positions: expanded.sites.map((site) => site.fractional),\n numbers,\n };\n let dataset: MoyoDataset;\n try {\n dataset = analyze_cell(\n JSON.stringify(cell),\n options.symprec ?? DEFAULT_SYMPREC,\n \"Standard\",\n );\n } catch (error) {\n throw new SymmetryAnalysisError(\n `moyo could not analyse the structure: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n const entry = hall_symbol_entry(dataset.hall_number);\n const type = space_group_type(dataset.number);\n const standard = standardStructure(dataset, speciesByLabel, entry);\n return {\n number: dataset.number,\n symbol: dataset.hm_symbol,\n fullSymbol: entry.hm_full,\n hallSymbol: entry.hall_symbol,\n hallNumber: dataset.hall_number,\n setting: entry.setting,\n crystalSystem: type.crystal_system,\n operations: dataset.operations.map(fromMoyoOperation),\n wyckoffs: dataset.wyckoffs,\n siteSymmetries: dataset.site_symmetry_symbols,\n structure: expanded,\n standard,\n };\n}\n","const SUBSCRIPT_DIGITS = \"₀₁₂₃₄₅₆₇₈₉\";\nconst COMBINING_OVERLINE = \"̅\";\n\nfunction subscript(digit: string): string {\n return SUBSCRIPT_DIGITS[Number(digit)] ?? digit;\n}\n\n/**\n * Write a space-group symbol the way textbooks print it: `F m -3 m` becomes\n * Fm3̅m and `P 2_1/c` becomes P2₁/c. A setting suffix such as `:H` is kept.\n * A screw axis written as two digits, as CIF files do (`P 1 21/c 1`), is\n * recognised only when the symbol has spaces, since in `F432` the digits\n * are separate axes.\n */\nexport function typesetSymbol(symbol: string): string {\n const trimmed = symbol.trim();\n const colon = trimmed.indexOf(\":\");\n const body = colon === -1 ? trimmed : trimmed.slice(0, colon).trim();\n const suffix = colon === -1 ? \"\" : ` ${trimmed.slice(colon)}`;\n const tokens = body.split(/\\s+/);\n const typeset = tokens\n .map((token) =>\n tokens.length > 1\n ? token.replace(\n /^([2346])([1-5])(?=$|\\/)/,\n (match, axis: string, order: string) =>\n Number(order) < Number(axis) ? axis + subscript(order) : match,\n )\n : token,\n )\n .join(\"\")\n .replace(\n /(\\d)_(\\d)/g,\n (_, axis: string, order: string) => axis + subscript(order),\n )\n .replace(/-(\\d)/g, (_, axis: string) => axis + COMBINING_OVERLINE);\n return typeset + suffix;\n}\n","{\n \"source\": \"VESTA bond-search cutoffs (K. Momma and F. Izumi), as distributed in pymatgen's vesta_cutoffs.yaml (MIT). Where VESTA lists a pair twice (H-O, D-O), the shorter cutoff is kept.\",\n \"pairs\": {\n \"Ac-Br\": 3.22726,\n \"Ac-Cl\": 3.08646,\n \"Ac-F\": 2.58646,\n \"Ac-O\": 2.7326,\n \"Ag-As\": 2.45642,\n \"Ag-Br\": 2.37642,\n \"Ag-Cl\": 3.05939,\n \"Ag-F\": 2.76939,\n \"Ag-H\": 1.65642,\n \"Ag-I\": 2.53642,\n \"Ag-N\": 2.00642,\n \"Ag-O\": 2.81139,\n \"Ag-P\": 2.37642,\n \"Ag-S\": 3.08839,\n \"Ag-Se\": 2.41642,\n \"Ag-Te\": 2.66642,\n \"Al-As\": 2.75646,\n \"Al-Br\": 2.65646,\n \"Al-Cl\": 2.48846,\n \"Al-F\": 2.00146,\n \"Al-H\": 1.90646,\n \"Al-I\": 2.86646,\n \"Al-N\": 2.24646,\n \"Al-O\": 2.1074,\n \"Al-P\": 2.69646,\n \"Al-S\": 2.66646,\n \"Al-Se\": 2.72646,\n \"Al-Te\": 2.93646,\n \"Am-Br\": 3.22944,\n \"Am-Cl\": 3.08945,\n \"Am-F\": 2.61945,\n \"Am-O\": 2.71649,\n \"As-Au\": 2.26998,\n \"As-B\": 2.42646,\n \"As-Ba\": 3.69,\n \"As-Be\": 2.60649,\n \"As-Bi\": 2.87642,\n \"As-Br\": 2.80646,\n \"As-C\": 2.38646,\n \"As-Ca\": 3.48295,\n \"As-Cd\": 3.29295,\n \"As-Ce\": 3.08644,\n \"As-Cl\": 2.61646,\n \"As-Co\": 2.43642,\n \"As-Cr\": 2.49642,\n \"As-Cs\": 4.15942,\n \"As-Cu\": 2.71895,\n \"As-Dy\": 3.14,\n \"As-Er\": 3.18,\n \"As-Eu\": 2.93898,\n \"As-F\": 2.15646,\n \"As-Fe\": 2.50642,\n \"As-Ga\": 2.38998,\n \"As-Gd\": 3.18,\n \"As-Ge\": 2.47998,\n \"As-Hf\": 2.71642,\n \"As-Hg\": 2.65642,\n \"As-Ho\": 2.87898,\n \"As-I\": 3.03646,\n \"As-In\": 2.66642,\n \"As-Ir\": 2.58998,\n \"As-K\": 3.94942,\n \"As-La\": 3.51293,\n \"As-Lu\": 3.19649,\n \"As-Mg\": 3.09293,\n \"As-Mn\": 2.51642,\n \"As-Mo\": 2.62701,\n \"As-Na\": 3.64942,\n \"As-Nb\": 2.69642,\n \"As-Ni\": 2.28998,\n \"As-O\": 2.24546,\n \"As-P\": 2.29998,\n \"As-Pb\": 3.02644,\n \"As-Pd\": 2.34998,\n \"As-Pr\": 3.35649,\n \"As-Pt\": 2.30998,\n \"As-Rb\": 4.04645,\n \"As-Re\": 2.61998,\n \"As-Rh\": 2.41998,\n \"As-Ru\": 2.40998,\n \"As-S\": 2.84649,\n \"As-Sb\": 2.64998,\n \"As-Sc\": 3.04291,\n \"As-Se\": 2.98649,\n \"As-Si\": 2.66002,\n \"As-Sm\": 3.30649,\n \"As-Sn\": 2.77642,\n \"As-Sr\": 3.62295,\n \"As-Ta\": 2.70642,\n \"As-Tb\": 3.26649,\n \"As-Te\": 3.10646,\n \"As-Th\": 3.40649,\n \"As-Ti\": 2.87642,\n \"As-Tl\": 3.09644,\n \"As-Tm\": 3.22649,\n \"As-U\": 3.02644,\n \"As-V\": 2.54642,\n \"As-W\": 2.58998,\n \"As-Y\": 3.24649,\n \"As-Yb\": 3.19649,\n \"As-Zn\": 2.95293,\n \"As-Zr\": 3.07004,\n \"Au-Br\": 2.77646,\n \"Au-Cl\": 2.88295,\n \"Au-F\": 2.34646,\n \"Au-H\": 1.41998,\n \"Au-I\": 3.21295,\n \"Au-N\": 2.3826,\n \"Au-O\": 2.34646,\n \"Au-P\": 2.18998,\n \"Au-S\": 2.8326,\n \"Au-Se\": 2.22998,\n \"Au-Te\": 2.45998,\n \"B-B\": 1.85846,\n \"B-Br\": 2.33646,\n \"B-Cl\": 2.19646,\n \"B-F\": 1.76646,\n \"B-H\": 1.59646,\n \"B-I\": 2.55646,\n \"B-N\": 1.93846,\n \"B-O\": 1.82746,\n \"B-P\": 2.37646,\n \"B-S\": 2.27646,\n \"B-Se\": 2.40646,\n \"B-Te\": 2.65646,\n \"Ba-Br\": 3.74295,\n \"Ba-Cl\": 3.55295,\n \"Ba-F\": 3.05095,\n \"Ba-H\": 3.08295,\n \"Ba-I\": 3.99295,\n \"Ba-N\": 3.33295,\n \"Ba-O\": 3.14795,\n \"Ba-P\": 3.48295,\n \"Ba-S\": 3.66195,\n \"Ba-Se\": 3.74295,\n \"Ba-Te\": 3.94295,\n \"Be-Br\": 2.50649,\n \"Be-Cl\": 2.36649,\n \"Be-F\": 1.88749,\n \"Be-H\": 1.71649,\n \"Be-I\": 2.70649,\n \"Be-N\": 2.10649,\n \"Be-O\": 1.98749,\n \"Be-P\": 2.55649,\n \"Be-S\": 2.43649,\n \"Be-Se\": 2.57649,\n \"Be-Te\": 2.81649,\n \"Bi-Br\": 3.17993,\n \"Bi-Cl\": 3.04291,\n \"Bi-F\": 2.55291,\n \"Bi-H\": 2.12642,\n \"Bi-I\": 3.38291,\n \"Bi-N\": 2.56329,\n \"Bi-O\": 2.6608,\n \"Bi-P\": 2.78642,\n \"Bi-S\": 3.13291,\n \"Bi-Se\": 3.24329,\n \"Bi-Te\": 3.02642,\n \"Bk-Br\": 3.15233,\n \"Bk-Cl\": 3.02291,\n \"Bk-F\": 2.54233,\n \"Bk-O\": 2.64329,\n \"Br-C\": 2.26002,\n \"Br-Ca\": 3.36995,\n \"Br-Cd\": 3.21295,\n \"Br-Ce\": 3.40452,\n \"Br-Cf\": 3.14233,\n \"Br-Cl\": 2.33296,\n \"Br-Co\": 2.33642,\n \"Br-Cr\": 2.97293,\n \"Br-Cs\": 4.06942,\n \"Br-Cu\": 2.89295,\n \"Br-Dy\": 3.16945,\n \"Br-Er\": 3.14945,\n \"Br-Eu\": 3.46549,\n \"Br-F\": 2.20646,\n \"Br-Fe\": 2.8952,\n \"Br-Ga\": 2.6426,\n \"Br-Gd\": 3.19945,\n \"Br-Ge\": 2.34998,\n \"Br-Hf\": 2.62642,\n \"Br-Hg\": 3.09293,\n \"Br-Ho\": 3.20159,\n \"Br-In\": 3.05329,\n \"Br-Ir\": 2.49998,\n \"Br-K\": 3.8513,\n \"Br-La\": 3.43293,\n \"Br-Li\": 3.11654,\n \"Br-Lu\": 3.11945,\n \"Br-Mg\": 2.99293,\n \"Br-Mn\": 3.05293,\n \"Br-Mo\": 2.8535,\n \"Br-Na\": 3.57715,\n \"Br-Nb\": 3.07646,\n \"Br-Nd\": 3.37293,\n \"Br-Ni\": 2.80649,\n \"Br-Np\": 3.21233,\n \"Br-O\": 2.35646,\n \"Br-Os\": 2.72002,\n \"Br-P\": 2.44293,\n \"Br-Pa\": 3.18437,\n \"Br-Pb\": 3.62451,\n \"Br-Pd\": 2.80649,\n \"Br-Pm\": 3.18233,\n \"Br-Pr\": 3.27649,\n \"Br-Pt\": 2.94191,\n \"Br-Pu\": 3.19233,\n \"Br-Rb\": 4.05498,\n \"Br-Re\": 2.70002,\n \"Br-Rh\": 2.7126,\n \"Br-Ru\": 2.30998,\n \"Br-S\": 2.21998,\n \"Br-Sb\": 2.96646,\n \"Br-Sc\": 2.94291,\n \"Br-Se\": 2.78002,\n \"Br-Si\": 2.55002,\n \"Br-Sm\": 3.26649,\n \"Br-Sn\": 3.2152,\n \"Br-Sr\": 3.54295,\n \"Br-Ta\": 2.60642,\n \"Br-Tb\": 3.18649,\n \"Br-Te\": 2.90002,\n \"Br-Th\": 3.31945,\n \"Br-Ti\": 3.20293,\n \"Br-Tl\": 3.80942,\n \"Br-Tm\": 3.13945,\n \"Br-U\": 3.39452,\n \"Br-V\": 2.87329,\n \"Br-W\": 2.49998,\n \"Br-Y\": 3.15649,\n \"Br-Yb\": 3.12945,\n \"Br-Zn\": 2.86293,\n \"Br-Zr\": 2.98004,\n \"C-C\": 1.89002,\n \"C-Cl\": 2.11002,\n \"C-Co\": 2.19691,\n \"C-Cu\": 2.32649,\n \"C-F\": 1.76002,\n \"C-Fe\": 2.25191,\n \"C-H\": 1.2,\n \"C-I\": 2.16998,\n \"C-N\": 1.79202,\n \"C-O\": 1.97249,\n \"C-P\": 1.93998,\n \"C-Pd\": 2.33649,\n \"C-Pt\": 2.36649,\n \"C-S\": 2.15002,\n \"C-Se\": 2.01998,\n \"C-Si\": 2.23302,\n \"C-Te\": 2.25998,\n \"Ca-Cl\": 3.23295,\n \"Ca-F\": 2.70495,\n \"Ca-H\": 2.69295,\n \"Ca-I\": 3.58295,\n \"Ca-N\": 3.00295,\n \"Ca-O\": 2.83062,\n \"Ca-P\": 3.41295,\n \"Ca-S\": 3.31295,\n \"Ca-Se\": 3.42295,\n \"Ca-Te\": 3.62295,\n \"Cd-Cl\": 3.09295,\n \"Cd-F\": 2.67395,\n \"Cd-H\": 2.52295,\n \"Cd-I\": 3.46295,\n \"Cd-N\": 2.82295,\n \"Cd-O\": 2.76695,\n \"Cd-P\": 3.20295,\n \"Cd-S\": 3.16695,\n \"Cd-Se\": 3.26295,\n \"Cd-Te\": 3.45295,\n \"Ce-Cl\": 3.25293,\n \"Ce-F\": 2.75452,\n \"Ce-H\": 2.34644,\n \"Ce-I\": 3.62452,\n \"Ce-N\": 2.78549,\n \"Ce-O\": 2.86393,\n \"Ce-P\": 3.00644,\n \"Ce-S\": 3.36293,\n \"Ce-Se\": 3.04644,\n \"Ce-Te\": 3.22644,\n \"Cf-Cl\": 3.01291,\n \"Cf-F\": 2.53233,\n \"Cf-O\": 2.63291,\n \"Cl-Cl\": 2.14296,\n \"Cl-Cm\": 3.18291,\n \"Cl-Co\": 2.74593,\n \"Cl-Cr\": 2.80293,\n \"Cl-Cs\": 3.91042,\n \"Cl-Cu\": 2.75295,\n \"Cl-D\": 1.5,\n \"Cl-Dy\": 3.01945,\n \"Cl-Er\": 2.99944,\n \"Cl-Eu\": 3.32549,\n \"Cl-F\": 2.14646,\n \"Cl-Fe\": 2.86293,\n \"Cl-Ga\": 2.52646,\n \"Cl-Gd\": 3.06349,\n \"Cl-Ge\": 2.49002,\n \"Cl-H\": 1.5,\n \"Cl-Hf\": 2.75646,\n \"Cl-Hg\": 3.24939,\n \"Cl-Ho\": 3.05159,\n \"Cl-I\": 3.33295,\n \"Cl-In\": 3.52939,\n \"Cl-Ir\": 2.56746,\n \"Cl-K\": 3.65976,\n \"Cl-La\": 3.33452,\n \"Cl-Li\": 2.91814,\n \"Cl-Lu\": 2.96944,\n \"Cl-Mg\": 2.79293,\n \"Cl-Mn\": 2.84593,\n \"Cl-Mo\": 2.80447,\n \"Cl-N\": 2.20646,\n \"Cl-NH\": 3.48195,\n \"Cl-Na\": 3.39412,\n \"Cl-Nb\": 2.76291,\n \"Cl-Nd\": 3.22493,\n \"Cl-Ni\": 2.62649,\n \"Cl-Np\": 3.07233,\n \"Cl-O\": 2.16646,\n \"Cl-Os\": 2.54002,\n \"Cl-P\": 2.28746,\n \"Cl-Pa\": 3.01437,\n \"Cl-Pb\": 3.39295,\n \"Cl-Pd\": 2.65649,\n \"Cl-Pm\": 3.41233,\n \"Cl-Pr\": 3.12749,\n \"Cl-Pt\": 2.75646,\n \"Cl-Pu\": 3.05233,\n \"Cl-Rb\": 3.86664,\n \"Cl-Re\": 3.44712,\n \"Cl-Rh\": 2.62646,\n \"Cl-Ru\": 2.70646,\n \"Cl-S\": 2.37002,\n \"Cl-Sb\": 2.80646,\n \"Cl-Sc\": 2.92291,\n \"Cl-Se\": 2.57002,\n \"Cl-Si\": 2.38002,\n \"Cl-Sm\": 3.08749,\n \"Cl-Sn\": 3.13111,\n \"Cl-Sr\": 3.37295,\n \"Cl-Ta\": 2.6739,\n \"Cl-Tb\": 3.04349,\n \"Cl-Tc\": 2.56002,\n \"Cl-Te\": 2.73906,\n \"Cl-Th\": 3.15945,\n \"Cl-Ti\": 3.02293,\n \"Cl-Tl\": 3.72942,\n \"Cl-Tm\": 2.98944,\n \"Cl-U\": 3.24452,\n \"Cl-V\": 3.15293,\n \"Cl-W\": 2.47,\n \"Cl-Y\": 3.00649,\n \"Cl-Yb\": 2.98249,\n \"Cl-Zn\": 2.72293,\n \"Cl-Zr\": 3.33651,\n \"Cm-F\": 2.68291,\n \"Cm-O\": 2.79291,\n \"Co-F\": 2.35293,\n \"Co-H\": 1.9278,\n \"Co-I\": 2.52878,\n \"Co-In\": 3.13629,\n \"Co-N\": 2.36293,\n \"Co-O\": 2.40493,\n \"Co-P\": 2.36642,\n \"Co-S\": 2.65293,\n \"Co-Se\": 2.39642,\n \"Co-Te\": 2.61642,\n \"Cr-F\": 2.45293,\n \"Cr-H\": 1.67642,\n \"Cr-I\": 3.19293,\n \"Cr-N\": 2.5152,\n \"Cr-O\": 2.44293,\n \"Cr-P\": 2.42642,\n \"Cr-S\": 2.72491,\n \"Cr-Se\": 2.44642,\n \"Cr-Te\": 2.67642,\n \"Cs-F\": 3.49942,\n \"Cs-H\": 3.55942,\n \"Cs-I\": 4.40942,\n \"Cs-N\": 3.94942,\n \"Cs-O\": 3.53642,\n \"Cs-P\": 3.64194,\n \"Cs-S\": 4.24942,\n \"Cs-Se\": 4.21655,\n \"Cs-Te\": 4.4631,\n \"Cu-F\": 2.46295,\n \"Cu-H\": 1.81649,\n \"Cu-I\": 3.01795,\n \"Cu-N\": 2.49295,\n \"Cu-O\": 2.47295,\n \"Cu-P\": 2.65649,\n \"Cu-S\": 2.76095,\n \"Cu-Se\": 2.76295,\n \"Cu-Te\": 2.87649,\n \"D-F\": 1.1,\n \"D-N\": 1.2,\n \"D-O\": 1.2,\n \"Dy-F\": 2.52944,\n \"Dy-H\": 2.09,\n \"Dy-I\": 3.39945,\n \"Dy-N\": 2.38,\n \"Dy-O\": 2.65651,\n \"Dy-P\": 2.77,\n \"Dy-S\": 2.823,\n \"Dy-Se\": 2.81,\n \"Dy-Te\": 3.22,\n \"Er-F\": 2.51049,\n \"Er-H\": 2.06,\n \"Er-I\": 3.38945,\n \"Er-N\": 2.36,\n \"Er-O\": 2.63651,\n \"Er-P\": 2.75,\n \"Er-S\": 3.27651,\n \"Er-Se\": 3.18649,\n \"Er-Te\": 3.22,\n \"Es-O\": 2.70139,\n \"Eu-F\": 2.83549,\n \"Eu-H\": 2.18898,\n \"Eu-I\": 3.69549,\n \"Eu-N\": 2.95549,\n \"Eu-O\": 2.94249,\n \"Eu-P\": 2.85898,\n \"Eu-S\": 3.37949,\n \"Eu-Se\": 2.89898,\n \"Eu-Te\": 3.08898,\n \"F-Fe\": 2.36293,\n \"F-Ga\": 2.14646,\n \"F-Gd\": 3.15651,\n \"F-Ge\": 2.01002,\n \"F-H\": 1.1,\n \"F-Hf\": 3.18291,\n \"F-Hg\": 2.88293,\n \"F-Ho\": 2.56159,\n \"F-I\": 3.18295,\n \"F-In\": 2.35491,\n \"F-Ir\": 2.15002,\n \"F-K\": 3.11142,\n \"F-Kr\": 2.67549,\n \"F-La\": 2.79293,\n \"F-Li\": 2.34276,\n \"F-Lu\": 2.48249,\n \"F-Mg\": 2.29093,\n \"F-Mn\": 2.41093,\n \"F-Mo\": 2.2998,\n \"F-N\": 1.82646,\n \"F-NH\": 2.99195,\n \"F-Na\": 2.80398,\n \"F-Nb\": 2.35646,\n \"F-Nd\": 2.73452,\n \"F-Ni\": 2.20249,\n \"F-Np\": 2.59233,\n \"F-Os\": 2.07746,\n \"F-P\": 2.01002,\n \"F-Pa\": 2.54437,\n \"F-Pb\": 2.92045,\n \"F-Pd\": 2.34649,\n \"F-Pm\": 2.55233,\n \"F-Po\": 2.83646,\n \"F-Pr\": 2.62945,\n \"F-Pt\": 2.54002,\n \"F-Pu\": 2.58233,\n \"F-Rb\": 3.37645,\n \"F-Re\": 2.16002,\n \"F-Rh\": 2.16646,\n \"F-Ru\": 2.57646,\n \"F-S\": 1.95002,\n \"F-Sb\": 2.35646,\n \"F-Sc\": 2.32291,\n \"F-Se\": 2.08002,\n \"F-Si\": 1.93002,\n \"F-Sm\": 2.60649,\n \"F-Sn\": 2.63793,\n \"F-Sr\": 2.88195,\n \"F-Ta\": 2.2539,\n \"F-Tb\": 2.54249,\n \"F-Tc\": 2.24219,\n \"F-Te\": 2.22002,\n \"F-Th\": 2.68945,\n \"F-Ti\": 2.86293,\n \"F-Tl\": 3.26942,\n \"F-Tm\": 2.51649,\n \"F-U\": 2.80293,\n \"F-V\": 2.87293,\n \"F-W\": 2.03,\n \"F-Xe\": 2.62649,\n \"F-Y\": 2.51049,\n \"F-Yb\": 2.50649,\n \"F-Zn\": 2.38293,\n \"F-Zr\": 2.99651,\n \"Fe-H\": 1.68642,\n \"Fe-I\": 3.1552,\n \"Fe-N\": 2.48193,\n \"Fe-O\": 2.44693,\n \"Fe-P\": 2.42642,\n \"Fe-S\": 2.83793,\n \"Fe-Se\": 2.43642,\n \"Fe-Te\": 2.68642,\n \"Ga-H\": 1.55998,\n \"Ga-I\": 2.91646,\n \"Ga-N\": 1.96,\n \"Ga-O\": 2.18646,\n \"Ga-P\": 2.46998,\n \"Ga-S\": 2.61946,\n \"Ga-Se\": 3.41295,\n \"Ga-Te\": 2.58998,\n \"Gd-H\": 2.13,\n \"Gd-I\": 3.41945,\n \"Gd-N\": 2.42,\n \"Gd-O\": 2.76651,\n \"Gd-P\": 2.81,\n \"Gd-S\": 3.13649,\n \"Gd-Se\": 2.85,\n \"Gd-Te\": 3.24,\n \"Ge-Ge\": 2.6,\n \"Ge-H\": 1.59998,\n \"Ge-I\": 2.54998,\n \"Ge-N\": 1.92998,\n \"Ge-O\": 2.09802,\n \"Ge-P\": 2.36998,\n \"Ge-S\": 2.56702,\n \"Ge-Se\": 2.70002,\n \"Ge-Te\": 2.60998,\n \"H-Hf\": 1.93642,\n \"H-Hg\": 1.86642,\n \"H-Ho\": 2.11898,\n \"H-In\": 1.87642,\n \"H-Ir\": 1.80998,\n \"H-K\": 3.21942,\n \"H-La\": 2.77293,\n \"H-Lu\": 2.42649,\n \"H-Mg\": 2.24293,\n \"H-Mn\": 1.70642,\n \"H-Mo\": 1.83701,\n \"H-N\": 1.2,\n \"H-Na\": 2.79942,\n \"H-Nb\": 1.90642,\n \"H-Ni\": 1.44998,\n \"H-O\": 1.2,\n \"H-P\": 1.45998,\n \"H-Pb\": 2.27644,\n \"H-Pd\": 1.51998,\n \"H-Pr\": 2.62649,\n \"H-Pt\": 1.44998,\n \"H-Rb\": 3.43645,\n \"H-Re\": 1.79998,\n \"H-Rh\": 1.59998,\n \"H-Ru\": 1.65998,\n \"H-S\": 1.42998,\n \"H-Sb\": 2.81998,\n \"H-Sc\": 2.24291,\n \"H-Se\": 1.58998,\n \"H-Si\": 1.82002,\n \"H-Sm\": 2.56649,\n \"H-Sn\": 2.00642,\n \"H-Sr\": 2.87295,\n \"H-Ta\": 1.91642,\n \"H-Tb\": 2.51649,\n \"H-Te\": 1.87998,\n \"H-Th\": 2.67649,\n \"H-Ti\": 1.76642,\n \"H-Tl\": 2.35644,\n \"H-Tm\": 2.45649,\n \"H-U\": 2.27644,\n \"H-V\": 1.73642,\n \"H-W\": 1.80998,\n \"H-Y\": 2.46649,\n \"H-Yb\": 2.42649,\n \"H-Zn\": 2.13293,\n \"H-Zr\": 2.29004,\n \"Hf-I\": 2.83642,\n \"Hf-N\": 2.24642,\n \"Hf-O\": 2.37946,\n \"Hf-P\": 2.63642,\n \"Hf-S\": 2.64642,\n \"Hf-Se\": 2.67642,\n \"Hf-Te\": 2.87642,\n \"Hg-Hg\": 3.1952,\n \"Hg-I\": 3.33293,\n \"Hg-N\": 2.17642,\n \"Hg-O\": 2.86939,\n \"Hg-P\": 2.57642,\n \"Hg-S\": 3.42093,\n \"Hg-Se\": 2.82642,\n \"Hg-Te\": 2.76642,\n \"Ho-I\": 3.44159,\n \"Ho-N\": 2.41898,\n \"Ho-O\": 2.67047,\n \"Ho-P\": 2.79898,\n \"Ho-S\": 3.13547,\n \"Ho-Se\": 2.84898,\n \"Ho-Te\": 3.03898,\n \"I-I\": 2.4,\n \"I-In\": 3.19291,\n \"I-Ir\": 2.70998,\n \"I-K\": 4.11717,\n \"I-La\": 3.64293,\n \"I-Li\": 3.37676,\n \"I-Lu\": 3.36945,\n \"I-Mg\": 3.17293,\n \"I-Mn\": 3.23293,\n \"I-Mo\": 2.74701,\n \"I-Na\": 3.88251,\n \"I-Nb\": 3.1439,\n \"I-Nd\": 3.59452,\n \"I-Ni\": 3.00649,\n \"I-Np\": 3.44233,\n \"I-O\": 2.47646,\n \"I-P\": 2.44998,\n \"I-Pb\": 3.69562,\n \"I-Pd\": 2.96649,\n \"I-Pr\": 3.49649,\n \"I-Pt\": 2.41998,\n \"I-Pu\": 3.43233,\n \"I-Rb\": 4.33462,\n \"I-Re\": 2.65998,\n \"I-Rh\": 2.52998,\n \"I-Ru\": 2.52998,\n \"I-S\": 2.40998,\n \"I-Sb\": 3.21646,\n \"I-Sc\": 3.15291,\n \"I-Se\": 2.58998,\n \"I-Si\": 2.76002,\n \"I-Sm\": 3.44649,\n \"I-Sn\": 3.52293,\n \"I-Sr\": 3.74295,\n \"I-Ta\": 2.81642,\n \"I-Tb\": 3.40945,\n \"I-Te\": 3.13702,\n \"I-Th\": 3.56649,\n \"I-Ti\": 3.08291,\n \"I-Tl\": 3.94142,\n \"I-Tm\": 3.37945,\n \"I-U\": 3.62452,\n \"I-V\": 2.66642,\n \"I-W\": 2.70998,\n \"I-Y\": 3.37649,\n \"I-Yb\": 3.37945,\n \"I-Zn\": 3.07293,\n \"I-Zr\": 3.19004,\n \"In-Mn\": 3.14729,\n \"In-N\": 2.18642,\n \"In-O\": 2.46491,\n \"In-P\": 2.68642,\n \"In-S\": 2.93291,\n \"In-Se\": 2.62642,\n \"In-Te\": 2.84642,\n \"Ir-N\": 2.10998,\n \"Ir-O\": 2.27746,\n \"Ir-P\": 2.50998,\n \"Ir-S\": 2.42998,\n \"Ir-Se\": 2.55998,\n \"Ir-Te\": 2.75998,\n \"K-N\": 3.41942,\n \"K-O\": 3.25142,\n \"K-P\": 3.44942,\n \"K-S\": 3.79285,\n \"K-Se\": 4.00186,\n \"K-Te\": 4.23284,\n \"La-N\": 3.05293,\n \"La-O\": 2.90983,\n \"La-P\": 3.32293,\n \"La-S\": 3.35593,\n \"La-Se\": 3.45293,\n \"La-Te\": 3.65293,\n \"Li-N\": 2.66213,\n \"Li-O\": 2.60087,\n \"Li-S\": 3.02481,\n \"Li-Se\": 3.2433,\n \"Li-Te\": 3.42496,\n \"Lu-N\": 2.71649,\n \"Lu-O\": 2.57749,\n \"Lu-P\": 3.11649,\n \"Lu-S\": 3.03649,\n \"Lu-Se\": 3.16649,\n \"Lu-Te\": 3.35649,\n \"Mg-N\": 2.56293,\n \"Mg-O\": 2.41824,\n \"Mg-P\": 3.00293,\n \"Mg-S\": 2.89293,\n \"Mg-Se\": 3.03293,\n \"Mg-Te\": 3.24293,\n \"Mn-N\": 2.56193,\n \"Mn-O\": 2.51652,\n \"Mn-P\": 2.39642,\n \"Mn-S\": 2.93293,\n \"Mn-Se\": 2.47642,\n \"Mn-Te\": 2.70642,\n \"Mo-N\": 2.4735,\n \"Mo-O\": 2.3475,\n \"Mo-P\": 2.54701,\n \"Mo-S\": 2.80067,\n \"Mo-Se\": 2.59701,\n \"Mo-Te\": 2.79701,\n \"N-N\": 1.8826,\n \"N-Na\": 3.12942,\n \"N-Nb\": 2.46046,\n \"N-Nd\": 3.01293,\n \"N-Ni\": 2.30649,\n \"N-O\": 1.81746,\n \"N-P\": 1.97146,\n \"N-Pb\": 3.0967,\n \"N-Pd\": 2.40451,\n \"N-Pr\": 2.90649,\n \"N-Pt\": 2.41649,\n \"N-Rb\": 3.79645,\n \"N-Re\": 2.10998,\n \"N-Rh\": 2.2626,\n \"N-Ru\": 2.2626,\n \"N-S\": 2.28849,\n \"N-Sb\": 2.56446,\n \"N-Sc\": 2.54291,\n \"N-Se\": 2.1,\n \"N-Si\": 2.12002,\n \"N-Sm\": 3.02351,\n \"N-Sn\": 2.7152,\n \"N-Sr\": 3.09295,\n \"N-Ta\": 2.16642,\n \"N-Tb\": 2.80649,\n \"N-Te\": 2.16998,\n \"N-Th\": 2.94649,\n \"N-Ti\": 2.08642,\n \"N-Tl\": 2.59644,\n \"N-Tm\": 2.74649,\n \"N-U\": 2.78649,\n \"N-V\": 2.38329,\n \"N-W\": 2.10998,\n \"N-Y\": 2.77649,\n \"N-Yb\": 2.84851,\n \"N-Zn\": 2.43293,\n \"N-Zr\": 2.65004,\n \"NH-O\": 3.08895,\n \"Na-O\": 2.95693,\n \"Na-P\": 3.47942,\n \"Na-S\": 3.57685,\n \"Na-Se\": 3.71593,\n \"Na-Te\": 3.95459,\n \"Nb-O\": 2.45329,\n \"Nb-P\": 2.61642,\n \"Nb-S\": 2.74,\n \"Nb-Se\": 2.66642,\n \"Nb-Te\": 2.85642,\n \"Nd-O\": 2.8587,\n \"Nd-S\": 3.42712,\n \"Nd-Se\": 3.42293,\n \"Nd-Te\": 3.60293,\n \"Ni-O\": 2.28149,\n \"Ni-P\": 2.31998,\n \"Ni-S\": 2.58649,\n \"Ni-Se\": 2.18998,\n \"Ni-Te\": 2.47998,\n \"Np-O\": 2.63646,\n \"Np-S\": 3.2,\n \"O-O\": 1.7,\n \"O-Os\": 2.23,\n \"O-P\": 2.08646,\n \"O-Pa\": 2.63383,\n \"O-Pb\": 3.04096,\n \"O-Pd\": 2.39849,\n \"O-Po\": 2.64646,\n \"O-Pr\": 2.74449,\n \"O-Pt\": 2.40649,\n \"O-Pu\": 2.68329,\n \"O-Rb\": 3.43945,\n \"O-Re\": 2.3426,\n \"O-Rh\": 2.24946,\n \"O-Ru\": 2.22646,\n \"O-S\": 1.8,\n \"O-Sb\": 2.45237,\n \"O-Sc\": 2.42029,\n \"O-Se\": 2.16102,\n \"O-Si\": 1.99002,\n \"O-Sm\": 2.88251,\n \"O-Sn\": 2.82146,\n \"O-Sr\": 2.98095,\n \"O-Ta\": 2.74646,\n \"O-Tb\": 2.65549,\n \"O-Tc\": 2.22446,\n \"O-Te\": 2.3334,\n \"O-Th\": 2.77349,\n \"O-Ti\": 2.35391,\n \"O-Tl\": 3.36945,\n \"O-Tm\": 2.60649,\n \"O-U\": 2.94295,\n \"O-V\": 2.84939,\n \"O-W\": 2.20102,\n \"O-Xe\": 2.63451,\n \"O-Y\": 2.62549,\n \"O-Yb\": 2.74551,\n \"O-Zn\": 2.41693,\n \"O-Zr\": 3.09651,\n \"Os-S\": 2.56002,\n \"P-P\": 2.48381,\n \"P-Pb\": 2.94644,\n \"P-Pd\": 2.46998,\n \"P-Pr\": 3.28649,\n \"P-Pt\": 2.23998,\n \"P-Rb\": 3.50645,\n \"P-Re\": 2.50998,\n \"P-Rh\": 2.43998,\n \"P-Ru\": 2.33998,\n \"P-S\": 2.57646,\n \"P-Sb\": 2.56998,\n \"P-Sc\": 2.96291,\n \"P-Se\": 2.69646,\n \"P-Si\": 2.58002,\n \"P-Sm\": 3.23649,\n \"P-Sn\": 2.60642,\n \"P-Sr\": 3.43295,\n \"P-Ta\": 2.62642,\n \"P-Tb\": 3.19649,\n \"P-Te\": 2.56998,\n \"P-Th\": 3.33649,\n \"P-Ti\": 2.51642,\n \"P-Tl\": 3.01644,\n \"P-Tm\": 3.13649,\n \"P-U\": 2.94644,\n \"P-V\": 2.46642,\n \"P-W\": 2.50998,\n \"P-Y\": 3.17649,\n \"P-Yb\": 3.13649,\n \"P-Zn\": 2.86293,\n \"P-Zr\": 3.02004,\n \"Pb-S\": 3.40395,\n \"Pb-Se\": 3.55295,\n \"Pb-Te\": 3.14644,\n \"Pd-S\": 2.69649,\n \"Pd-Se\": 2.26998,\n \"Pd-Te\": 2.52998,\n \"Pr-S\": 3.20649,\n \"Pr-Se\": 3.32649,\n \"Pr-Te\": 3.50649,\n \"Pt-S\": 2.76649,\n \"Pt-Se\": 2.23998,\n \"Pt-Te\": 2.49998,\n \"Pu-S\": 3.3,\n \"Rb-S\": 3.97645,\n \"Rb-Se\": 4.13773,\n \"Rb-Te\": 4.28802,\n \"Re-S\": 2.61998,\n \"Re-Se\": 2.54998,\n \"Re-Te\": 2.74998,\n \"Rh-S\": 2.19998,\n \"Rh-Se\": 2.37998,\n \"Rh-Te\": 2.59998,\n \"Ru-S\": 2.6426,\n \"Ru-Se\": 2.69451,\n \"Ru-Te\": 2.58998,\n \"S-S\": 2.2,\n \"S-Sb\": 3.05,\n \"S-Sc\": 2.88391,\n \"S-Se\": 2.81649,\n \"S-Si\": 2.47602,\n \"S-Sm\": 3.15649,\n \"S-Sn\": 3.15293,\n \"S-Sr\": 3.51295,\n \"S-Ta\": 2.8439,\n \"S-Tb\": 3.11649,\n \"S-Te\": 2.79002,\n \"S-Th\": 3.24649,\n \"S-Ti\": 2.74646,\n \"S-Tl\": 3.66442,\n \"S-Tm\": 3.05649,\n \"S-U\": 3.25293,\n \"S-V\": 2.82293,\n \"S-W\": 2.43998,\n \"S-Y\": 3.08649,\n \"S-Yb\": 3.03649,\n \"S-Zn\": 2.80293,\n \"S-Zr\": 2.91004,\n \"Sb-Se\": 3.05646,\n \"Sb-Te\": 2.82998,\n \"Sc-Se\": 3.00291,\n \"Sc-Te\": 3.20291,\n \"Se-Se\": 2.93649,\n \"Se-Si\": 2.61002,\n \"Se-Sm\": 3.27649,\n \"Se-Sn\": 2.96646,\n \"Se-Sr\": 3.58295,\n \"Se-Ta\": 2.66642,\n \"Se-Tb\": 3.23649,\n \"Se-Te\": 2.57998,\n \"Se-Th\": 3.36649,\n \"Se-Ti\": 2.53642,\n \"Se-Tl\": 3.00644,\n \"Se-Tm\": 3.18649,\n \"Se-U\": 3.00644,\n \"Se-V\": 2.48642,\n \"Se-W\": 2.55998,\n \"Se-Y\": 3.21649,\n \"Se-Yb\": 3.16649,\n \"Se-Zn\": 2.93293,\n \"Se-Zr\": 3.03004,\n \"Si-Si\": 2.6,\n \"Si-Te\": 2.84002,\n \"Sm-Te\": 3.46649,\n \"Sn-Te\": 2.91642,\n \"Sr-Te\": 3.73295,\n \"Ta-Te\": 2.85642,\n \"Tb-Te\": 3.42649,\n \"Te-Te\": 2.80998,\n \"Te-Th\": 3.54649,\n \"Te-Ti\": 2.95642,\n \"Te-Tl\": 3.23644,\n \"Te-Tm\": 3.37649,\n \"Te-U\": 3.16644,\n \"Te-V\": 2.72642,\n \"Te-W\": 2.75998,\n \"Te-Y\": 3.40649,\n \"Te-Yb\": 3.36649,\n \"Te-Zn\": 3.16293,\n \"Te-Zr\": 3.17004\n }\n}\n","import vestaCutoffs from \"../data/vesta-cutoffs.json\";\nimport { distance } from \"./lattice.js\";\nimport type { Vec3 } from \"./types.js\";\n\nconst CUTOFFS = vestaCutoffs.pairs as Record<string, number>;\n/** Two atoms closer than this are the alternatives of a split site, not bonded. */\nconst SHORTEST_BOND = 0.4;\n\nexport interface BondedAtom {\n element: string;\n position: Vec3;\n}\n\n/** A bond between two entries of `StructureScene.atoms`. */\nexport interface Bond {\n /** Index of one atom. */\n start: number;\n /** Index of the other. */\n end: number;\n /** Distance between them in ångström. */\n length: number;\n}\n\n/** VESTA's bond-search maximum for an element pair, or null when VESTA draws none. */\nexport function bondCutoff(elementA: string, elementB: string): number | null {\n const key =\n elementA < elementB ? `${elementA}-${elementB}` : `${elementB}-${elementA}`;\n return CUTOFFS[key] ?? null;\n}\n\n/**\n * Bonds between the given atoms by VESTA's cutoff table. Only pairs VESTA\n * lists get bonds, so no metal-metal or anion-anion sticks appear. The bonds\n * are ordered by `start`, then `end`, and `start` is the lower index.\n */\nexport function findBonds(atoms: readonly BondedAtom[]): Bond[] {\n // Elements become small numbers and the cutoff of every pair present is\n // looked up once, 0 for a pair VESTA does not bond.\n const kinds = new Map<string, number>();\n const kindOf = atoms.map((atom) => {\n let kind = kinds.get(atom.element);\n if (kind === undefined) {\n kind = kinds.size;\n kinds.set(atom.element, kind);\n }\n return kind;\n });\n const elements = [...kinds.keys()];\n const cutoffs = new Float64Array(elements.length * elements.length);\n let longest = 0;\n elements.forEach((first, row) => {\n elements.forEach((second, column) => {\n const cutoff = bondCutoff(first, second) ?? 0;\n cutoffs[row * elements.length + column] = cutoff;\n longest = Math.max(longest, cutoff);\n });\n });\n if (longest < SHORTEST_BOND) {\n return [];\n }\n\n // Cubes as wide as the longest cutoff present: a bonded pair lies in one\n // cube or in two neighbouring ones. Keys count from one cube below the\n // lowest on each axis, so every neighbour of an occupied cube has its own.\n const cubes = atoms.map(\n (atom) =>\n atom.position.map((value) => Math.floor(value / longest) | 0) as Vec3,\n );\n const low: Vec3 = [Infinity, Infinity, Infinity];\n const high: Vec3 = [-Infinity, -Infinity, -Infinity];\n for (const cube of cubes) {\n for (let axis = 0; axis < 3; axis += 1) {\n low[axis] = Math.min(low[axis]!, cube[axis]!);\n high[axis] = Math.max(high[axis]!, cube[axis]!);\n }\n }\n const ny = high[1] - low[1] + 3;\n const nz = high[2] - low[2] + 3;\n const cubeKey = (x: number, y: number, z: number) =>\n ((x - low[0] + 1) * ny + (y - low[1] + 1)) * nz + (z - low[2] + 1);\n const grid = new Map<number, number[]>();\n cubes.forEach(([x, y, z], index) => {\n const key = cubeKey(x, y, z);\n const bucket = grid.get(key);\n if (bucket) {\n bucket.push(index);\n } else {\n grid.set(key, [index]);\n }\n });\n\n const bonds: Bond[] = [];\n const found: Bond[] = [];\n atoms.forEach((atom, index) => {\n const [x, y, z] = cubes[index]!;\n const row = kindOf[index]! * elements.length;\n found.length = 0;\n for (let dx = -1; dx <= 1; dx += 1) {\n for (let dy = -1; dy <= 1; dy += 1) {\n for (let dz = -1; dz <= 1; dz += 1) {\n for (const other of grid.get(cubeKey(x + dx, y + dy, z + dz)) ?? []) {\n const cutoff = cutoffs[row + kindOf[other]!]!;\n if (other <= index || cutoff < SHORTEST_BOND) {\n continue;\n }\n const length = distance(atom.position, atoms[other]!.position);\n if (length >= SHORTEST_BOND && length <= cutoff) {\n found.push({ start: index, end: other, length });\n }\n }\n }\n }\n }\n bonds.push(...found.sort((left, right) => left.end - right.end));\n });\n return bonds;\n}\n","import { wrap } from \"./fractional.js\";\nimport type { Site, Vec3 } from \"./types.js\";\n\n/** A coordinate this close to 0 or 1 sits on the cell boundary. */\nconst BOUNDARY_TOLERANCE = 1e-4;\n\nexport interface PeriodicAtom {\n siteIndex: number;\n fractional: Vec3;\n /** True for a copy of a boundary site on the opposite face, edge or corner. */\n isImage: boolean;\n}\n\n/**\n * The sites of a cell, each folded into [0, 1), plus the image atoms of\n * every boundary site when requested: a corner site appears at all eight\n * corners, an edge site at four edges, a face site on both faces.\n */\nexport function periodicAtoms(\n sites: Site[],\n includeImages: boolean,\n): PeriodicAtom[] {\n const atoms: PeriodicAtom[] = [];\n sites.forEach((site, siteIndex) => {\n const fractional = site.fractional.map((value) =>\n wrap(value, BOUNDARY_TOLERANCE),\n ) as Vec3;\n atoms.push({ siteIndex, fractional, isImage: false });\n if (!includeImages) {\n return;\n }\n const boundaryAxes = ([0, 1, 2] as const).filter(\n (axis) => fractional[axis] < BOUNDARY_TOLERANCE,\n );\n const subsetCount = 1 << boundaryAxes.length;\n for (let subset = 1; subset < subsetCount; subset += 1) {\n const image: Vec3 = [fractional[0], fractional[1], fractional[2]];\n boundaryAxes.forEach((axis, bit) => {\n if (subset & (1 << bit)) {\n image[axis] += 1;\n }\n });\n atoms.push({ siteIndex, fractional: image, isImage: true });\n }\n });\n return atoms;\n}\n","import { findBonds, type Bond } from \"../structure/bonds.js\";\nimport { chemicalElement } from \"../structure/elements.js\";\nimport { periodicAtoms } from \"../structure/images.js\";\nimport { fractionalToCartesian } from \"../structure/lattice.js\";\nimport type { Mat3, Species, Structure, Vec3 } from \"../structure/types.js\";\n\nexport interface SceneAtom {\n /** Index into `Structure.sites` of the site this atom belongs to. */\n siteIndex: number;\n /** The species with the largest occupancy; what colours the atom. */\n element: string;\n /** Every species on the site, by descending occupancy. */\n species: Species[];\n /** Cartesian position in ångström. */\n position: Vec3;\n /** Fractional position; image atoms lie on the far faces, edges or corners. */\n fractional: Vec3;\n /** True for a boundary site repeated on the opposite face, edge or corner. */\n isImage: boolean;\n}\n\nexport interface StructureScene {\n /** Cell row vectors in Cartesian ångström. */\n cell: Mat3;\n atoms: SceneAtom[];\n /** Bonds between entries of `atoms`. */\n bonds: Bond[];\n /** Elements present, in order of first appearance, deuterium as hydrogen. */\n elements: string[];\n}\n\n/** One structure to draw. A viewer can overlay several, each with its own opacity. */\nexport interface SceneLayer {\n scene: StructureScene;\n /**\n * From 0 to 1; default 1. Below 1 the layer is drawn see-through over the\n * others. At 0 it is not drawn but still counts when fitting the view, so\n * switching between two versions of a structure keeps the same framing.\n */\n opacity?: number;\n}\n\nexport interface BuildSceneOptions {\n /** Repeat atoms on the cell's faces, edges and corners on the opposite side too. Default true. */\n imageAtoms?: boolean;\n}\n\n/** Every chemical element on any site, in order of first appearance. */\nexport function structureElements(structure: Structure): string[] {\n const elements: string[] = [];\n for (const site of structure.sites) {\n for (const species of site.species) {\n const element = chemicalElement(species.element);\n if (!elements.includes(element)) {\n elements.push(element);\n }\n }\n }\n return elements;\n}\n\n/**\n * Prepare a structure for drawing: its atoms, bonds and cell. Sites are\n * drawn as listed; pass `expandStructure(structure)` to draw the whole cell.\n */\nexport function buildScene(\n structure: Structure,\n options: BuildSceneOptions = {},\n): StructureScene {\n const atoms: SceneAtom[] = periodicAtoms(\n structure.sites,\n options.imageAtoms ?? true,\n ).map((atom) => {\n const site = structure.sites[atom.siteIndex];\n if (!site) {\n throw new Error(`Site ${atom.siteIndex} is missing.`);\n }\n const majority = site.species[0];\n if (!majority) {\n throw new Error(`Site ${site.label} has no species.`);\n }\n return {\n siteIndex: atom.siteIndex,\n element: majority.element,\n species: site.species,\n position: fractionalToCartesian(structure.lattice, atom.fractional),\n fractional: atom.fractional,\n isImage: atom.isImage,\n };\n });\n return {\n cell: structure.lattice.vectors,\n atoms,\n bonds: findBonds(atoms),\n elements: structureElements(structure),\n };\n}\n","import {\n\tControls,\n\tMathUtils,\n\tMOUSE,\n\tQuaternion,\n\tVector2,\n\tVector3\n} from 'three';\n\n/**\n * Fires when the camera has been transformed by the controls.\n *\n * @event TrackballControls#change\n * @type {Object}\n */\nconst _changeEvent = { type: 'change' };\n\n/**\n * Fires when an interaction was initiated.\n *\n * @event TrackballControls#start\n * @type {Object}\n */\nconst _startEvent = { type: 'start' };\n\n/**\n * Fires when an interaction has finished.\n *\n * @event TrackballControls#end\n * @type {Object}\n */\nconst _endEvent = { type: 'end' };\n\nconst _EPS = 0.000001;\nconst _STATE = { NONE: - 1, ROTATE: 0, ZOOM: 1, PAN: 2, TOUCH_ROTATE: 3, TOUCH_ZOOM_PAN: 4 };\n\nconst _v2 = new Vector2();\nconst _mouseChange = new Vector2();\nconst _objectUp = new Vector3();\nconst _pan = new Vector3();\nconst _axis = new Vector3();\nconst _quaternion = new Quaternion();\nconst _eyeDirection = new Vector3();\nconst _objectUpDirection = new Vector3();\nconst _objectSidewaysDirection = new Vector3();\nconst _moveDirection = new Vector3();\n\n/**\n * This class is similar to {@link OrbitControls}. However, it does not maintain a constant camera\n * `up` vector. That means if the camera orbits over the “north” and “south” poles, it does not flip\n * to stay \"right side up\".\n *\n * @augments Controls\n * @three_import import { TrackballControls } from 'three/addons/controls/TrackballControls.js';\n */\nclass TrackballControls extends Controls {\n\n\t/**\n\t * Constructs a new controls instance.\n\t *\n\t * @param {Object3D} object - The object that is managed by the controls.\n\t * @param {?HTMLElement} domElement - The HTML element used for event listeners.\n\t */\n\tconstructor( object, domElement = null ) {\n\n\t\tsuper( object, domElement );\n\n\t\t/**\n\t\t * Represents the properties of the screen. Automatically set when `handleResize()` is called.\n\t\t *\n\t\t * @type {Object}\n\t\t * @readonly\n\t\t */\n\t\tthis.screen = { left: 0, top: 0, width: 0, height: 0 };\n\n\t\t/**\n\t\t * The rotation speed.\n\t\t *\n\t\t * @type {number}\n\t\t * @default 1\n\t\t */\n\t\tthis.rotateSpeed = 1.0;\n\n\t\t/**\n\t\t * The zoom speed.\n\t\t *\n\t\t * @type {number}\n\t\t * @default 1.2\n\t\t */\n\t\tthis.zoomSpeed = 1.2;\n\n\t\t/**\n\t\t * The pan speed.\n\t\t *\n\t\t * @type {number}\n\t\t * @default 0.3\n\t\t */\n\t\tthis.panSpeed = 0.3;\n\n\t\t/**\n\t\t * The roll speed used for multi-touch roll.\n\t\t *\n\t\t * @type {number}\n\t\t * @default 1\n\t\t */\n\t\tthis.rollSpeed = 1.0;\n\n\t\t/**\n\t\t * Whether rotation is disabled or not.\n\t\t *\n\t\t * @type {boolean}\n\t\t * @default false\n\t\t */\n\t\tthis.noRotate = false;\n\n\t\t/**\n\t\t * Whether zooming is disabled or not.\n\t\t *\n\t\t * @type {boolean}\n\t\t * @default false\n\t\t */\n\t\tthis.noZoom = false;\n\n\t\t/**\n\t\t * Whether panning is disabled or not.\n\t\t *\n\t\t * @type {boolean}\n\t\t * @default false\n\t\t */\n\t\tthis.noPan = false;\n\n\t\t/**\n\t\t * Whether two finger twist gesture rolls\n\t\t * the camera around its view axis or not.\n\t\t *\n\t\t * @type {boolean}\n\t\t * @default false\n\t\t */\n\t\tthis.multiTouchRoll = false;\n\n\t\t/**\n\t\t * Whether damping is disabled or not.\n\t\t *\n\t\t * @type {boolean}\n\t\t * @default false\n\t\t */\n\t\tthis.staticMoving = false;\n\n\t\t/**\n\t\t * Defines the intensity of damping. Only considered if `staticMoving` is set to `false`.\n\t\t *\n\t\t * @type {number}\n\t\t * @default 0.2\n\t\t */\n\t\tthis.dynamicDampingFactor = 0.2;\n\n\t\t/**\n\t\t * How far you can dolly in (perspective camera only).\n\t\t *\n\t\t * @type {number}\n\t\t * @default 0\n\t\t */\n\t\tthis.minDistance = 0;\n\n\t\t/**\n\t\t * How far you can dolly out (perspective camera only).\n\t\t *\n\t\t * @type {number}\n\t\t * @default Infinity\n\t\t */\n\t\tthis.maxDistance = Infinity;\n\n\t\t/**\n\t\t * How far you can zoom in (orthographic camera only).\n\t\t *\n\t\t * @type {number}\n\t\t * @default 0\n\t\t */\n\t\tthis.minZoom = 0;\n\n\t\t/**\n\t\t * How far you can zoom out (orthographic camera only).\n\t\t *\n\t\t * @type {number}\n\t\t * @default Infinity\n\t\t */\n\t\tthis.maxZoom = Infinity;\n\n\t\t/**\n\t\t * This array holds keycodes for controlling interactions.\n\t\t *\n\t\t * - When the first defined key is pressed, all mouse interactions (left, middle, right) performs orbiting.\n\t\t * - When the second defined key is pressed, all mouse interactions (left, middle, right) performs zooming.\n\t\t * - When the third defined key is pressed, all mouse interactions (left, middle, right) performs panning.\n\t\t *\n\t\t * Default is *KeyA, KeyS, KeyD* which represents A, S, D.\n\t\t *\n\t\t * @type {Array<string>}\n\t\t */\n\t\tthis.keys = [ 'KeyA' /*A*/, 'KeyS' /*S*/, 'KeyD' /*D*/ ];\n\n\t\t/**\n\t\t * This object contains references to the mouse actions used by the controls.\n\t\t *\n\t\t * ```js\n\t\t * controls.mouseButtons = {\n\t\t * \tLEFT: THREE.MOUSE.ROTATE,\n\t\t * \tMIDDLE: THREE.MOUSE.DOLLY,\n\t\t * \tRIGHT: THREE.MOUSE.PAN\n\t\t * }\n\t\t * ```\n\t\t * @type {Object}\n\t\t */\n\t\tthis.mouseButtons = { LEFT: MOUSE.ROTATE, MIDDLE: MOUSE.DOLLY, RIGHT: MOUSE.PAN };\n\n\t\t/**\n\t\t * The focus point of the controls.\n\t\t *\n\t\t * @type {Vector3}\n\t\t */\n\t\tthis.target = new Vector3();\n\n\t\t// internals\n\n\t\tthis.state = _STATE.NONE;\n\t\tthis.keyState = _STATE.NONE;\n\n\t\tthis._lastPosition = new Vector3();\n\t\tthis._lastUp = new Vector3();\n\t\tthis._lastZoom = 1;\n\t\tthis._touchZoomDistanceStart = 0;\n\t\tthis._touchZoomDistanceEnd = 0;\n\t\tthis._touchRollAngle = 0;\n\t\tthis._touchRollPointerIds = '';\n\t\tthis._lastAngle = 0;\n\t\tthis._lastRollAngle = 0;\n\n\t\tthis._eye = new Vector3();\n\n\t\tthis._movePrev = new Vector2();\n\t\tthis._moveCurr = new Vector2();\n\n\t\tthis._lastAxis = new Vector3();\n\n\t\tthis._zoomStart = new Vector2();\n\t\tthis._zoomEnd = new Vector2();\n\n\t\tthis._panStart = new Vector2();\n\t\tthis._panEnd = new Vector2();\n\n\t\tthis._pointers = [];\n\t\tthis._pointerPositions = {};\n\n\t\t// event listeners\n\n\t\tthis._onPointerMove = onPointerMove.bind( this );\n\t\tthis._onPointerDown = onPointerDown.bind( this );\n\t\tthis._onPointerUp = onPointerUp.bind( this );\n\t\tthis._onPointerCancel = onPointerCancel.bind( this );\n\t\tthis._onContextMenu = onContextMenu.bind( this );\n\t\tthis._onMouseWheel = onMouseWheel.bind( this );\n\t\tthis._onKeyDown = onKeyDown.bind( this );\n\t\tthis._onKeyUp = onKeyUp.bind( this );\n\n\t\tthis._onTouchStart = onTouchStart.bind( this );\n\t\tthis._onTouchMove = onTouchMove.bind( this );\n\t\tthis._onTouchEnd = onTouchEnd.bind( this );\n\n\t\tthis._onMouseDown = onMouseDown.bind( this );\n\t\tthis._onMouseMove = onMouseMove.bind( this );\n\t\tthis._onMouseUp = onMouseUp.bind( this );\n\n\t\t// for reset\n\n\t\tthis._target0 = this.target.clone();\n\t\tthis._position0 = this.object.position.clone();\n\t\tthis._up0 = this.object.up.clone();\n\t\tthis._zoom0 = this.object.zoom;\n\n\t\tif ( domElement !== null ) {\n\n\t\t\tthis.connect( domElement );\n\n\t\t\tthis.handleResize();\n\n\t\t}\n\n\t\t// force an update at start\n\t\tthis.update();\n\n\t}\n\n\tconnect( element ) {\n\n\t\tsuper.connect( element );\n\n\t\twindow.addEventListener( 'keydown', this._onKeyDown );\n\t\twindow.addEventListener( 'keyup', this._onKeyUp );\n\n\t\tthis.domElement.addEventListener( 'pointerdown', this._onPointerDown );\n\t\tthis.domElement.addEventListener( 'pointercancel', this._onPointerCancel );\n\t\tthis.domElement.addEventListener( 'wheel', this._onMouseWheel, { passive: false } );\n\t\tthis.domElement.addEventListener( 'contextmenu', this._onContextMenu );\n\n\t\tthis.domElement.style.touchAction = 'none'; // Disable touch scroll\n\n\t}\n\n\tdisconnect() {\n\n\t\twindow.removeEventListener( 'keydown', this._onKeyDown );\n\t\twindow.removeEventListener( 'keyup', this._onKeyUp );\n\n\t\tthis.domElement.removeEventListener( 'pointerdown', this._onPointerDown );\n\t\tthis.domElement.ownerDocument.removeEventListener( 'pointermove', this._onPointerMove );\n\t\tthis.domElement.ownerDocument.removeEventListener( 'pointerup', this._onPointerUp );\n\t\tthis.domElement.removeEventListener( 'pointercancel', this._onPointerCancel );\n\t\tthis.domElement.removeEventListener( 'wheel', this._onMouseWheel );\n\t\tthis.domElement.removeEventListener( 'contextmenu', this._onContextMenu );\n\n\t\tthis.domElement.style.touchAction = ''; // Restore touch scroll\n\n\t}\n\n\tdispose() {\n\n\t\tthis.disconnect();\n\n\t}\n\n\t/**\n\t * Must be called if the application window is resized.\n\t */\n\thandleResize() {\n\n\t\tconst box = this.domElement.getBoundingClientRect();\n\t\t// adjustments come from similar code in the jquery offset() function\n\t\tconst d = this.domElement.ownerDocument.documentElement;\n\n\t\tthis.screen.left = box.left + window.pageXOffset - d.clientLeft;\n\t\tthis.screen.top = box.top + window.pageYOffset - d.clientTop;\n\t\tthis.screen.width = box.width;\n\t\tthis.screen.height = box.height;\n\n\t}\n\n\tupdate() {\n\n\t\tthis._eye.subVectors( this.object.position, this.target );\n\n\t\tif ( ! this.noRotate ) {\n\n\t\t\tthis._rotateCamera();\n\n\t\t\tif ( this.multiTouchRoll === true ) {\n\n\t\t\t\tthis._rollCamera();\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( ! this.noZoom ) {\n\n\t\t\tthis._zoomCamera();\n\n\t\t}\n\n\t\tif ( ! this.noPan ) {\n\n\t\t\tthis._panCamera();\n\n\t\t}\n\n\t\tthis.object.position.addVectors( this.target, this._eye );\n\n\t\tif ( this.object.isPerspectiveCamera ) {\n\n\t\t\tthis._checkDistances();\n\n\t\t\tthis.object.lookAt( this.target );\n\n\t\t\tconst positionChanged = this._lastPosition.distanceToSquared( this.object.position ) > _EPS;\n\t\t\tconst rollChanged = this._lastUp.distanceToSquared( this.object.up ) > _EPS;\n\n\t\t\tif ( positionChanged || rollChanged ) {\n\n\t\t\t\tthis.dispatchEvent( _changeEvent );\n\n\t\t\t\tthis._lastPosition.copy( this.object.position );\n\t\t\t\tthis._lastUp.copy( this.object.up );\n\n\t\t\t}\n\n\t\t} else if ( this.object.isOrthographicCamera ) {\n\n\t\t\tthis.object.lookAt( this.target );\n\n\t\t\tconst positionChanged = this._lastPosition.distanceToSquared( this.object.position ) > _EPS;\n\t\t\tconst rollChanged = this._lastUp.distanceToSquared( this.object.up ) > _EPS;\n\t\t\tconst zoomChanged = this._lastZoom !== this.object.zoom;\n\n\t\t\tif ( positionChanged || rollChanged || zoomChanged ) {\n\n\t\t\t\tthis.dispatchEvent( _changeEvent );\n\n\t\t\t\tthis._lastPosition.copy( this.object.position );\n\t\t\t\tthis._lastUp.copy( this.object.up );\n\t\t\t\tthis._lastZoom = this.object.zoom;\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tconsole.warn( 'THREE.TrackballControls: Unsupported camera type.' );\n\n\t\t}\n\n\t}\n\n\t/**\n\t * Resets the controls to its initial state.\n\t */\n\treset() {\n\n\t\tthis.state = _STATE.NONE;\n\t\tthis.keyState = _STATE.NONE;\n\n\t\tthis.target.copy( this._target0 );\n\t\tthis.object.position.copy( this._position0 );\n\t\tthis.object.up.copy( this._up0 );\n\t\tthis.object.zoom = this._zoom0;\n\n\t\tthis.object.updateProjectionMatrix();\n\n\t\tthis._eye.subVectors( this.object.position, this.target );\n\n\t\tthis.object.lookAt( this.target );\n\n\t\tthis.dispatchEvent( _changeEvent );\n\n\t\tthis._lastPosition.copy( this.object.position );\n\t\tthis._lastUp.copy( this.object.up );\n\t\tthis._lastZoom = this.object.zoom;\n\n\t}\n\n\t_panCamera() {\n\n\t\t_mouseChange.copy( this._panEnd ).sub( this._panStart );\n\n\t\tif ( _mouseChange.lengthSq() ) {\n\n\t\t\tif ( this.object.isOrthographicCamera ) {\n\n\t\t\t\tconst scale_x = ( this.object.right - this.object.left ) / this.object.zoom / this.domElement.clientWidth;\n\t\t\t\tconst scale_y = ( this.object.top - this.object.bottom ) / this.object.zoom / this.domElement.clientWidth;\n\n\t\t\t\t_mouseChange.x *= scale_x;\n\t\t\t\t_mouseChange.y *= scale_y;\n\n\t\t\t}\n\n\t\t\t_mouseChange.multiplyScalar( this._eye.length() * this.panSpeed );\n\n\t\t\t_pan.copy( this._eye ).cross( this.object.up ).setLength( _mouseChange.x );\n\t\t\t_pan.add( _objectUp.copy( this.object.up ).setLength( _mouseChange.y ) );\n\n\t\t\tthis.object.position.add( _pan );\n\t\t\tthis.target.add( _pan );\n\n\t\t\tif ( this.staticMoving ) {\n\n\t\t\t\tthis._panStart.copy( this._panEnd );\n\n\t\t\t} else {\n\n\t\t\t\tthis._panStart.add( _mouseChange.subVectors( this._panEnd, this._panStart ).multiplyScalar( this.dynamicDampingFactor ) );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t_rotateCamera() {\n\n\t\t_moveDirection.set( this._moveCurr.x - this._movePrev.x, this._moveCurr.y - this._movePrev.y, 0 );\n\t\tlet angle = _moveDirection.length();\n\n\t\tif ( angle ) {\n\n\t\t\tthis._eye.copy( this.object.position ).sub( this.target );\n\n\t\t\t_eyeDirection.copy( this._eye ).normalize();\n\t\t\t_objectUpDirection.copy( this.object.up ).normalize();\n\t\t\t_objectSidewaysDirection.crossVectors( _objectUpDirection, _eyeDirection ).normalize();\n\n\t\t\t_objectUpDirection.setLength( this._moveCurr.y - this._movePrev.y );\n\t\t\t_objectSidewaysDirection.setLength( this._moveCurr.x - this._movePrev.x );\n\n\t\t\t_moveDirection.copy( _objectUpDirection.add( _objectSidewaysDirection ) );\n\n\t\t\t_axis.crossVectors( _moveDirection, this._eye ).normalize();\n\n\t\t\tangle *= this.rotateSpeed;\n\t\t\t_quaternion.setFromAxisAngle( _axis, angle );\n\n\t\t\tthis._eye.applyQuaternion( _quaternion );\n\t\t\tthis.object.up.applyQuaternion( _quaternion );\n\n\t\t\tthis._lastAxis.copy( _axis );\n\t\t\tthis._lastAngle = angle;\n\n\t\t} else if ( ! this.staticMoving && this._lastAngle ) {\n\n\t\t\tthis._lastAngle *= Math.sqrt( 1.0 - this.dynamicDampingFactor );\n\t\t\tthis._eye.copy( this.object.position ).sub( this.target );\n\t\t\t_quaternion.setFromAxisAngle( this._lastAxis, this._lastAngle );\n\t\t\tthis._eye.applyQuaternion( _quaternion );\n\t\t\tthis.object.up.applyQuaternion( _quaternion );\n\n\t\t}\n\n\t\tthis._movePrev.copy( this._moveCurr );\n\n\t}\n\n\t_rollCamera() {\n\n\t\tconst angle = this._getTouchRollAngle();\n\n\t\tif ( angle ) {\n\n\t\t\tthis._lastRollAngle = angle * this.rollSpeed;\n\n\t\t} else if ( ! this.staticMoving && this._lastRollAngle ) {\n\n\t\t\tthis._lastRollAngle *= Math.sqrt( 1.0 - this.dynamicDampingFactor );\n\n\t\t} else {\n\n\t\t\treturn;\n\n\t\t}\n\n\t\t_eyeDirection.copy( this._eye ).normalize();\n\t\t_quaternion.setFromAxisAngle( _eyeDirection, this._lastRollAngle );\n\n\t\tthis.object.up.applyQuaternion( _quaternion );\n\n\t}\n\n\t_getTouchRollAngle() {\n\n\t\tconst first = this._pointers[ 0 ];\n\t\tconst second = this._pointers[ 1 ];\n\n\t\tif ( second === undefined || first.pointerType !== 'touch' || second.pointerType !== 'touch' ) {\n\n\t\t\tthis._touchRollPointerIds = '';\n\t\t\treturn 0;\n\n\t\t}\n\n\t\tconst pointerIds = `${ first.pointerId },${ second.pointerId }`;\n\n\t\tconst positionFirst = this._pointerPositions[ first.pointerId ];\n\t\tconst positionSecond = this._pointerPositions[ second.pointerId ];\n\n\t\tconst rollAngle = Math.atan2( positionSecond.y - positionFirst.y, positionSecond.x - positionFirst.x );\n\n\t\t// fingers changed or new gesture started\n\t\tif ( pointerIds !== this._touchRollPointerIds ) {\n\n\t\t\tthis._touchRollPointerIds = pointerIds;\n\t\t\tthis._touchRollAngle = rollAngle;\n\t\t\treturn 0;\n\n\t\t}\n\n\t\tlet angle = rollAngle - this._touchRollAngle;\n\t\tthis._touchRollAngle = rollAngle;\n\n\t\tif ( angle > Math.PI ) {\n\n\t\t\tangle -= 2 * Math.PI;\n\n\t\t} else if ( angle < - Math.PI ) {\n\n\t\t\tangle += 2 * Math.PI;\n\n\t\t}\n\n\t\treturn angle;\n\n\t}\n\n\t_zoomCamera() {\n\n\t\tlet factor;\n\n\t\tif ( this.state === _STATE.TOUCH_ZOOM_PAN ) {\n\n\t\t\tfactor = this._touchZoomDistanceStart / this._touchZoomDistanceEnd;\n\t\t\tthis._touchZoomDistanceStart = this._touchZoomDistanceEnd;\n\n\t\t\tif ( this.object.isPerspectiveCamera ) {\n\n\t\t\t\tthis._eye.multiplyScalar( factor );\n\n\t\t\t} else if ( this.object.isOrthographicCamera ) {\n\n\t\t\t\tthis.object.zoom = MathUtils.clamp( this.object.zoom / factor, this.minZoom, this.maxZoom );\n\n\t\t\t\tif ( this._lastZoom !== this.object.zoom ) {\n\n\t\t\t\t\tthis.object.updateProjectionMatrix();\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tconsole.warn( 'THREE.TrackballControls: Unsupported camera type' );\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tfactor = 1.0 + ( this._zoomEnd.y - this._zoomStart.y ) * this.zoomSpeed;\n\n\t\t\tif ( factor !== 1.0 && factor > 0.0 ) {\n\n\t\t\t\tif ( this.object.isPerspectiveCamera ) {\n\n\t\t\t\t\tthis._eye.multiplyScalar( factor );\n\n\t\t\t\t} else if ( this.object.isOrthographicCamera ) {\n\n\t\t\t\t\tthis.object.zoom = MathUtils.clamp( this.object.zoom / factor, this.minZoom, this.maxZoom );\n\n\t\t\t\t\tif ( this._lastZoom !== this.object.zoom ) {\n\n\t\t\t\t\t\tthis.object.updateProjectionMatrix();\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\tconsole.warn( 'THREE.TrackballControls: Unsupported camera type' );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( this.staticMoving ) {\n\n\t\t\t\tthis._zoomStart.copy( this._zoomEnd );\n\n\t\t\t} else {\n\n\t\t\t\tthis._zoomStart.y += ( this._zoomEnd.y - this._zoomStart.y ) * this.dynamicDampingFactor;\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t_getMouseOnScreen( pageX, pageY ) {\n\n\t\t_v2.set(\n\t\t\t( pageX - this.screen.left ) / this.screen.width,\n\t\t\t( pageY - this.screen.top ) / this.screen.height\n\t\t);\n\n\t\treturn _v2;\n\n\t}\n\n\t_getMouseOnCircle( pageX, pageY ) {\n\n\t\t_v2.set(\n\t\t\t( ( pageX - this.screen.width * 0.5 - this.screen.left ) / ( this.screen.width * 0.5 ) ),\n\t\t\t( ( this.screen.height + 2 * ( this.screen.top - pageY ) ) / this.screen.width ) // screen.width intentional\n\t\t);\n\n\t\treturn _v2;\n\n\t}\n\n\t_addPointer( event ) {\n\n\t\tthis._pointers.push( event );\n\n\t}\n\n\t_removePointer( event ) {\n\n\t\tdelete this._pointerPositions[ event.pointerId ];\n\n\t\tfor ( let i = 0; i < this._pointers.length; i ++ ) {\n\n\t\t\tif ( this._pointers[ i ].pointerId == event.pointerId ) {\n\n\t\t\t\tthis._pointers.splice( i, 1 );\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t_trackPointer( event ) {\n\n\t\tlet position = this._pointerPositions[ event.pointerId ];\n\n\t\tif ( position === undefined ) {\n\n\t\t\tposition = new Vector2();\n\t\t\tthis._pointerPositions[ event.pointerId ] = position;\n\n\t\t}\n\n\t\tposition.set( event.pageX, event.pageY );\n\n\t}\n\n\t_getSecondPointerPosition( event ) {\n\n\t\tconst pointer = ( event.pointerId === this._pointers[ 0 ].pointerId ) ? this._pointers[ 1 ] : this._pointers[ 0 ];\n\n\t\treturn this._pointerPositions[ pointer.pointerId ];\n\n\t}\n\n\t_checkDistances() {\n\n\t\tif ( ! this.noZoom || ! this.noPan ) {\n\n\t\t\tif ( this._eye.lengthSq() > this.maxDistance * this.maxDistance ) {\n\n\t\t\t\tthis.object.position.addVectors( this.target, this._eye.setLength( this.maxDistance ) );\n\t\t\t\tthis._zoomStart.copy( this._zoomEnd );\n\n\t\t\t}\n\n\t\t\tif ( this._eye.lengthSq() < this.minDistance * this.minDistance ) {\n\n\t\t\t\tthis.object.position.addVectors( this.target, this._eye.setLength( this.minDistance ) );\n\t\t\t\tthis._zoomStart.copy( this._zoomEnd );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n\nfunction onPointerDown( event ) {\n\n\tif ( this.enabled === false ) return;\n\n\tif ( this._pointers.length === 0 ) {\n\n\t\tthis.domElement.setPointerCapture( event.pointerId );\n\n\t\tthis.domElement.ownerDocument.addEventListener( 'pointermove', this._onPointerMove );\n\t\tthis.domElement.ownerDocument.addEventListener( 'pointerup', this._onPointerUp );\n\n\t}\n\n\t//\n\n\tthis._addPointer( event );\n\n\tif ( event.pointerType === 'touch' ) {\n\n\t\tthis._onTouchStart( event );\n\n\t} else {\n\n\t\tthis._onMouseDown( event );\n\n\t}\n\n}\n\nfunction onPointerMove( event ) {\n\n\tif ( this.enabled === false ) return;\n\n\tif ( event.pointerType === 'touch' ) {\n\n\t\tthis._onTouchMove( event );\n\n\t} else {\n\n\t\tthis._onMouseMove( event );\n\n\t}\n\n}\n\nfunction onPointerUp( event ) {\n\n\tif ( this.enabled === false ) return;\n\n\tif ( event.pointerType === 'touch' ) {\n\n\t\tthis._onTouchEnd( event );\n\n\t} else {\n\n\t\tthis._onMouseUp();\n\n\t}\n\n\t//\n\n\tthis._removePointer( event );\n\n\tif ( this._pointers.length === 0 ) {\n\n\t\tthis.domElement.releasePointerCapture( event.pointerId );\n\n\t\tthis.domElement.ownerDocument.removeEventListener( 'pointermove', this._onPointerMove );\n\t\tthis.domElement.ownerDocument.removeEventListener( 'pointerup', this._onPointerUp );\n\n\t}\n\n}\n\nfunction onPointerCancel( event ) {\n\n\tthis._removePointer( event );\n\n}\n\nfunction onKeyUp() {\n\n\tif ( this.enabled === false ) return;\n\n\tthis.keyState = _STATE.NONE;\n\n\twindow.addEventListener( 'keydown', this._onKeyDown );\n\n}\n\nfunction onKeyDown( event ) {\n\n\tif ( this.enabled === false ) return;\n\n\twindow.removeEventListener( 'keydown', this._onKeyDown );\n\n\tif ( this.keyState !== _STATE.NONE ) {\n\n\t\treturn;\n\n\t} else if ( event.code === this.keys[ _STATE.ROTATE ] && ! this.noRotate ) {\n\n\t\tthis.keyState = _STATE.ROTATE;\n\n\t} else if ( event.code === this.keys[ _STATE.ZOOM ] && ! this.noZoom ) {\n\n\t\tthis.keyState = _STATE.ZOOM;\n\n\t} else if ( event.code === this.keys[ _STATE.PAN ] && ! this.noPan ) {\n\n\t\tthis.keyState = _STATE.PAN;\n\n\t}\n\n}\n\nfunction onMouseDown( event ) {\n\n\tlet mouseAction;\n\n\tswitch ( event.button ) {\n\n\t\tcase 0:\n\t\t\tmouseAction = this.mouseButtons.LEFT;\n\t\t\tbreak;\n\n\t\tcase 1:\n\t\t\tmouseAction = this.mouseButtons.MIDDLE;\n\t\t\tbreak;\n\n\t\tcase 2:\n\t\t\tmouseAction = this.mouseButtons.RIGHT;\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tmouseAction = - 1;\n\n\t}\n\n\tswitch ( mouseAction ) {\n\n\t\tcase MOUSE.DOLLY:\n\t\t\tthis.state = _STATE.ZOOM;\n\t\t\tbreak;\n\n\t\tcase MOUSE.ROTATE:\n\t\t\tthis.state = _STATE.ROTATE;\n\t\t\tbreak;\n\n\t\tcase MOUSE.PAN:\n\t\t\tthis.state = _STATE.PAN;\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tthis.state = _STATE.NONE;\n\n\t}\n\n\tconst state = ( this.keyState !== _STATE.NONE ) ? this.keyState : this.state;\n\n\tif ( state === _STATE.ROTATE && ! this.noRotate ) {\n\n\t\tthis._moveCurr.copy( this._getMouseOnCircle( event.pageX, event.pageY ) );\n\t\tthis._movePrev.copy( this._moveCurr );\n\n\t} else if ( state === _STATE.ZOOM && ! this.noZoom ) {\n\n\t\tthis._zoomStart.copy( this._getMouseOnScreen( event.pageX, event.pageY ) );\n\t\tthis._zoomEnd.copy( this._zoomStart );\n\n\t} else if ( state === _STATE.PAN && ! this.noPan ) {\n\n\t\tthis._panStart.copy( this._getMouseOnScreen( event.pageX, event.pageY ) );\n\t\tthis._panEnd.copy( this._panStart );\n\n\t}\n\n\tthis.dispatchEvent( _startEvent );\n\n}\n\nfunction onMouseMove( event ) {\n\n\tconst state = ( this.keyState !== _STATE.NONE ) ? this.keyState : this.state;\n\n\tif ( state === _STATE.ROTATE && ! this.noRotate ) {\n\n\t\tthis._moveCurr.copy( this._getMouseOnCircle( event.pageX, event.pageY ) );\n\n\t} else if ( state === _STATE.ZOOM && ! this.noZoom ) {\n\n\t\tthis._zoomEnd.copy( this._getMouseOnScreen( event.pageX, event.pageY ) );\n\n\t} else if ( state === _STATE.PAN && ! this.noPan ) {\n\n\t\tthis._panEnd.copy( this._getMouseOnScreen( event.pageX, event.pageY ) );\n\n\t}\n\n}\n\nfunction onMouseUp() {\n\n\tthis.state = _STATE.NONE;\n\n\tthis.dispatchEvent( _endEvent );\n\n}\n\nfunction onMouseWheel( event ) {\n\n\tif ( this.enabled === false ) return;\n\n\tif ( this.noZoom === true ) return;\n\n\tevent.preventDefault();\n\n\tswitch ( event.deltaMode ) {\n\n\t\tcase 2:\n\t\t\t// Zoom in pages\n\t\t\tthis._zoomStart.y -= event.deltaY * 0.025;\n\t\t\tbreak;\n\n\t\tcase 1:\n\t\t\t// Zoom in lines\n\t\t\tthis._zoomStart.y -= event.deltaY * 0.01;\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\t// undefined, 0, assume pixels\n\t\t\tthis._zoomStart.y -= event.deltaY * 0.00025;\n\t\t\tbreak;\n\n\t}\n\n\tthis.dispatchEvent( _startEvent );\n\tthis.dispatchEvent( _endEvent );\n\n}\n\nfunction onContextMenu( event ) {\n\n\tif ( this.enabled === false ) return;\n\n\tevent.preventDefault();\n\n}\n\nfunction onTouchStart( event ) {\n\n\tthis._trackPointer( event );\n\n\tswitch ( this._pointers.length ) {\n\n\t\tcase 1:\n\t\t\tthis.state = _STATE.TOUCH_ROTATE;\n\t\t\tthis._moveCurr.copy( this._getMouseOnCircle( this._pointers[ 0 ].pageX, this._pointers[ 0 ].pageY ) );\n\t\t\tthis._movePrev.copy( this._moveCurr );\n\t\t\tbreak;\n\n\t\tdefault: // 2 or more\n\t\t\tthis.state = _STATE.TOUCH_ZOOM_PAN;\n\t\t\tconst dx = this._pointers[ 0 ].pageX - this._pointers[ 1 ].pageX;\n\t\t\tconst dy = this._pointers[ 0 ].pageY - this._pointers[ 1 ].pageY;\n\t\t\tthis._touchZoomDistanceEnd = this._touchZoomDistanceStart = Math.sqrt( dx * dx + dy * dy );\n\n\t\t\tconst x = ( this._pointers[ 0 ].pageX + this._pointers[ 1 ].pageX ) / 2;\n\t\t\tconst y = ( this._pointers[ 0 ].pageY + this._pointers[ 1 ].pageY ) / 2;\n\t\t\tthis._panStart.copy( this._getMouseOnScreen( x, y ) );\n\t\t\tthis._panEnd.copy( this._panStart );\n\t\t\tbreak;\n\n\t}\n\n\tthis.dispatchEvent( _startEvent );\n\n}\n\nfunction onTouchMove( event ) {\n\n\tthis._trackPointer( event );\n\n\tswitch ( this._pointers.length ) {\n\n\t\tcase 1:\n\t\t\tthis._moveCurr.copy( this._getMouseOnCircle( event.pageX, event.pageY ) );\n\t\t\tbreak;\n\n\t\tdefault: // 2 or more\n\n\t\t\tconst position = this._getSecondPointerPosition( event );\n\n\t\t\tconst dx = event.pageX - position.x;\n\t\t\tconst dy = event.pageY - position.y;\n\t\t\tthis._touchZoomDistanceEnd = Math.sqrt( dx * dx + dy * dy );\n\n\t\t\tconst x = ( event.pageX + position.x ) / 2;\n\t\t\tconst y = ( event.pageY + position.y ) / 2;\n\t\t\tthis._panEnd.copy( this._getMouseOnScreen( x, y ) );\n\t\t\tbreak;\n\n\t}\n\n}\n\nfunction onTouchEnd( event ) {\n\n\tswitch ( this._pointers.length ) {\n\n\t\tcase 0:\n\t\t\tthis.state = _STATE.NONE;\n\t\t\tbreak;\n\n\t\tcase 1:\n\t\t\tthis.state = _STATE.TOUCH_ROTATE;\n\t\t\tthis._moveCurr.copy( this._getMouseOnCircle( event.pageX, event.pageY ) );\n\t\t\tthis._movePrev.copy( this._moveCurr );\n\t\t\tbreak;\n\n\t\tcase 2:\n\t\t\tthis.state = _STATE.TOUCH_ZOOM_PAN;\n\n\t\t\tfor ( let i = 0; i < this._pointers.length; i ++ ) {\n\n\t\t\t\tif ( this._pointers[ i ].pointerId !== event.pointerId ) {\n\n\t\t\t\t\tconst position = this._pointerPositions[ this._pointers[ i ].pointerId ];\n\t\t\t\t\tthis._moveCurr.copy( this._getMouseOnCircle( position.x, position.y ) );\n\t\t\t\t\tthis._movePrev.copy( this._moveCurr );\n\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tbreak;\n\n\t}\n\n\tthis.dispatchEvent( _endEvent );\n\n}\n\nexport { TrackballControls };\n","import { Box3, Matrix4, OrthographicCamera, Quaternion, Vector3 } from \"three\";\n\nimport type { Mat3 } from \"../structure/types.js\";\nimport type { ViewState } from \"./view-state.js\";\n\n/**\n * The standard view is Naumann's clinographic projection, the convention of\n * crystal drawings and Pretty Lattice's default: c vertical, the crystal\n * turned by arctan(1/3) about c and tilted toward the viewer by arctan(1/6).\n */\nconst NAUMANN_HORIZONTAL_RATIO = 1 / 3;\nconst NAUMANN_VERTICAL_RATIO = 1 / 6;\n/** The projected cell takes half the viewport's geometric mean size. */\nconst PROJECTED_FIT_PADDING_RATIO = 2;\nconst EPSILON = 1e-12;\nconst CAMERA_FORWARD = new Vector3(0, 0, -1);\nconst CAMERA_UP = new Vector3(0, 1, 0);\n\nfunction projectPerpendicular(vector: Vector3, axis: Vector3): Vector3 | null {\n const projected = vector\n .clone()\n .sub(axis.clone().multiplyScalar(vector.dot(axis)));\n return projected.lengthSq() < EPSILON ? null : projected.normalize();\n}\n\nfunction stablePerpendicular(axis: Vector3): Vector3 {\n for (const candidate of [\n new Vector3(0, 0, 1),\n new Vector3(0, 1, 0),\n new Vector3(1, 0, 0),\n ]) {\n const projected = projectPerpendicular(candidate, axis);\n if (projected) {\n return projected;\n }\n }\n return new Vector3(0, 1, 0);\n}\n\n/** Camera outward direction and up vector of the standard view of a cell. */\nexport function standardViewVectors(cell: Mat3): {\n outward: Vector3;\n up: Vector3;\n} {\n const a = new Vector3(...cell[0]);\n const b = new Vector3(...cell[1]);\n const vertical = new Vector3(...cell[2]).normalize();\n const basalReference =\n projectPerpendicular(a, vertical) ??\n projectPerpendicular(b, vertical) ??\n stablePerpendicular(vertical);\n const basalRight = vertical.clone().cross(basalReference).normalize();\n const outward = basalReference\n .clone()\n .add(basalRight.multiplyScalar(NAUMANN_HORIZONTAL_RATIO))\n .add(vertical.clone().multiplyScalar(NAUMANN_VERTICAL_RATIO))\n .normalize();\n const up =\n projectPerpendicular(vertical, outward) ?? stablePerpendicular(outward);\n return { outward, up };\n}\n\n/** Distance of the orthographic camera from its target; only the clipping depends on it. */\nexport function cameraDistance(span: number): number {\n return Math.max(4, span * 4);\n}\n\nexport function standardQuaternion(cell: Mat3): Quaternion {\n const { outward, up } = standardViewVectors(cell);\n const right = up.clone().cross(outward).normalize();\n const correctedUp = outward.clone().cross(right).normalize();\n const basis = new Matrix4().makeBasis(right, correctedUp, outward);\n return new Quaternion().setFromRotationMatrix(basis).normalize();\n}\n\n/** The standard view of a cell as a view state: standard orientation, centred, fitted. */\nexport function standardView(cell: Mat3): ViewState {\n return {\n quaternion: quaternionTuple(standardQuaternion(cell)),\n target: [0, 0, 0],\n scale: 1,\n };\n}\n\n/** Pose a camera from a view state. */\nexport function applyViewState(\n camera: OrthographicCamera,\n view: Pick<ViewState, \"quaternion\" | \"target\">,\n distance: number,\n span: number,\n): void {\n const quaternion = new Quaternion(...view.quaternion).normalize();\n const target = new Vector3(...view.target);\n const forward = CAMERA_FORWARD.clone().applyQuaternion(quaternion);\n camera.position.copy(target).sub(forward.multiplyScalar(distance));\n camera.up.copy(CAMERA_UP.clone().applyQuaternion(quaternion));\n camera.quaternion.copy(quaternion);\n camera.near = 0.01;\n camera.far = Math.max(1000, distance + span * 8);\n camera.updateProjectionMatrix();\n}\n\n/** The orientation of a camera as a view-state quaternion. */\nexport function quaternionTuple(\n quaternion: Quaternion,\n): [number, number, number, number] {\n return [quaternion.x, quaternion.y, quaternion.z, quaternion.w];\n}\n\n/** Size of `bounds` projected on the screen plane of `quaternion`. */\nexport function projectedSize(\n bounds: Box3,\n quaternion: Quaternion,\n): { width: number; height: number } {\n const right = new Vector3(1, 0, 0).applyQuaternion(quaternion);\n const up = new Vector3(0, 1, 0).applyQuaternion(quaternion);\n let minX = Infinity;\n let maxX = -Infinity;\n let minY = Infinity;\n let maxY = -Infinity;\n for (const x of [bounds.min.x, bounds.max.x]) {\n for (const y of [bounds.min.y, bounds.max.y]) {\n for (const z of [bounds.min.z, bounds.max.z]) {\n const corner = new Vector3(x, y, z);\n const px = corner.dot(right);\n const py = corner.dot(up);\n minX = Math.min(minX, px);\n maxX = Math.max(maxX, px);\n minY = Math.min(minY, py);\n maxY = Math.max(maxY, py);\n }\n }\n }\n return { width: Math.max(1, maxX - minX), height: Math.max(1, maxY - minY) };\n}\n\n/** Orthographic zoom (pixels per ångström) that fits `bounds` in the viewport. */\nexport function fitZoom(\n bounds: Box3,\n quaternion: Quaternion,\n width: number,\n height: number,\n): number {\n const projected = projectedSize(bounds, quaternion);\n const availableLength = Math.sqrt(Math.max(1, width) * Math.max(1, height));\n const projectedLength = Math.sqrt(projected.width * projected.height);\n return Math.max(\n 0.01,\n availableLength / (projectedLength * PROJECTED_FIT_PADDING_RATIO),\n );\n}\n\n/** Frustum of an orthographic camera in pixel units, so `zoom` is pixels per ångström. */\nexport function applyPixelFrustum(\n camera: OrthographicCamera,\n width: number,\n height: number,\n): void {\n camera.left = -width / 2;\n camera.right = width / 2;\n camera.top = height / 2;\n camera.bottom = -height / 2;\n camera.updateProjectionMatrix();\n}\n","import {\n AlwaysStencilFunc,\n DataTexture,\n DoubleSide,\n LineBasicMaterial,\n MeshStandardMaterial,\n ReplaceStencilOp,\n} from \"three\";\n\n// Material and lighting currently follow Pretty Lattice's default (its\n// \"modern matte\" preset).\nexport const METALNESS = 0.1;\nexport const ROUGHNESS = 0.6;\nexport const AMBIENT_LIGHT_INTENSITY = 0.8;\nexport const HEADLIGHT_INTENSITY = 2.2;\nexport const HEADLIGHT_OFFSET: readonly [number, number, number] = [\n 0.3, 0.2, 0,\n];\nexport const BACKGROUND_COLOR = \"#fafafa\";\nexport const CELL_FRAME_COLOR = \"#444444\";\n/** The part of a partially occupied site nobody occupies: a faint, see-through tint. */\nexport const VACANCY_COLOR = \"#f2f2f2\";\nexport const VACANCY_OPACITY = 0.3;\n/** Added to a vacancy texel's start fraction so the shader can tell it apart. */\nexport const VACANCY_FLAG = 2;\n\nconst TWO_PI = \"6.28318530718\";\n\n/**\n * Insert code at includes of a three.js built-in shader, each `[include,\n * code]` replacing the include. A three.js release that renames or drops\n * one fails here by name, instead of drawing flat squares.\n */\nfunction patchShader(\n shader: string,\n patches: [include: string, code: string][],\n): string {\n return patches.reduce((source, [include, code]) => {\n if (!source.includes(include)) {\n throw new Error(\n `bravais cannot draw with this three.js: its shader has no ${include}.`,\n );\n }\n return source.replace(include, code);\n }, shader);\n}\n\n/**\n * Occupancy sectors live in a texture: each site owns a run of texels, each\n * holding the colour of one sector and the angle fraction where it begins.\n * The first sector takes the instance colour; the rest, and the vacancy,\n * come from the texels. Unused texels start at 1, which no angle reaches.\n */\nexport const SECTOR_TEXELS_PER_SITE = 8;\nexport const SECTOR_SITES_PER_ROW = 256;\n\n/**\n * Atoms are ray-cast spheres. Each instance is a camera-facing quad of the\n * sphere's size; the fragment shader finds where the pixel's view ray meets\n * the sphere, writes that depth and shades with the sphere's normal. The\n * outline, and the cut where a bond enters, are then exact at any zoom, for\n * four vertices per atom. The cameras are orthographic, so the view ray is\n * the view z axis and the depth is linear in view z.\n */\nfunction atomVertexShader(shader: string): string {\n return patchShader(shader, [\n [\n \"#include <common>\",\n `#include <common>\nflat varying int vSectorSite;\nflat varying vec3 vSphereCenter;\nflat varying float vSphereRadius;\nflat varying vec2 vDepthCoefficients;\nvarying vec3 vSpherePoint;`,\n ],\n [\n \"#include <project_vertex>\",\n `mat4 sphereMatrix = modelViewMatrix * instanceMatrix;\nvSphereCenter = sphereMatrix[3].xyz;\nvSphereRadius = length(sphereMatrix[0].xyz);\nvSpherePoint = vSphereCenter + vec3(position.xy * vSphereRadius, 0.0);\nvDepthCoefficients = vec2(projectionMatrix[2][2], projectionMatrix[3][2]);\nvSectorSite = gl_InstanceID;\nvec4 mvPosition = vec4(vSpherePoint, 1.0);\ngl_Position = projectionMatrix * mvPosition;`,\n ],\n ]);\n}\n\nfunction atomFragmentShader(shader: string): string {\n return patchShader(shader, [\n [\n \"#include <common>\",\n `#include <common>\nuniform sampler2D sectorTexture;\nuniform float vacancyOpacity;\nflat varying int vSectorSite;\nflat varying vec3 vSphereCenter;\nflat varying float vSphereRadius;\nflat varying vec2 vDepthCoefficients;\nvarying vec3 vSpherePoint;`,\n ],\n [\n \"#include <clipping_planes_fragment>\",\n `// Where the view ray meets the sphere. The outline is smoothed over one\n// pixel through the alpha: sample coverage, or blending in a see-through layer.\nvec2 sphereOffset = vSpherePoint.xy - vSphereCenter.xy;\nfloat sphereDistance = length(sphereOffset);\nfloat sphereCoverage = clamp(\n (vSphereRadius - sphereDistance) / max(fwidth(sphereDistance), 1e-6) + 0.5,\n 0.0,\n 1.0\n);\nif (sphereCoverage <= 0.0) {\n discard;\n}\nfloat sphereHeight = sqrt(\n max(0.0, vSphereRadius * vSphereRadius - dot(sphereOffset, sphereOffset))\n);\nvec3 sphereNormal = vec3(sphereOffset, sphereHeight) / vSphereRadius;\nfloat sphereZ = vSphereCenter.z + sphereHeight;\ngl_FragDepth = (vDepthCoefficients.x * sphereZ + vDepthCoefficients.y) * 0.5 + 0.5;\n#include <clipping_planes_fragment>`,\n ],\n [\n \"#include <color_fragment>\",\n `#include <color_fragment>\n{\n // A pie chart facing the viewer, like VESTA's occupancy pies: the instance\n // colour fills the first sector from 12 o'clock clockwise, then each\n // texel's colour from its stop on.\n float sectorAngle = fract(atan(sphereOffset.x, sphereOffset.y) / ${TWO_PI});\n vec3 sectorColor = vColor.rgb;\n float sectorOpacity = 1.0;\n int sectorRow = vSectorSite / ${SECTOR_SITES_PER_ROW};\n int sectorColumn = (vSectorSite - sectorRow * ${SECTOR_SITES_PER_ROW}) * ${SECTOR_TEXELS_PER_SITE};\n for (int k = 0; k < ${SECTOR_TEXELS_PER_SITE}; k++) {\n vec4 sector = texelFetch(sectorTexture, ivec2(sectorColumn + k, sectorRow), 0);\n bool vacant = sector.a >= ${VACANCY_FLAG}.0;\n float start = vacant ? sector.a - ${VACANCY_FLAG}.0 : sector.a;\n if (sectorAngle >= start) {\n sectorColor = sector.rgb;\n sectorOpacity = vacant ? vacancyOpacity : 1.0;\n }\n }\n diffuseColor.rgb = diffuse * sectorColor;\n diffuseColor.a *= sectorOpacity * sphereCoverage;\n}`,\n ],\n [\n \"#include <normal_fragment_begin>\",\n `#include <normal_fragment_begin>\nnormal = sphereNormal;\nnonPerturbedNormal = normal;`,\n ],\n ]);\n}\n\n/**\n * Atom material: the matte preset drawing ray-cast spheres with occupancy\n * sectors read from `sectorTexture`. A layer with vacancies is blended so\n * their sectors show what lies behind; one without stays on the opaque path\n * and smooths its outlines through sample coverage.\n */\nexport function createAtomMaterial(\n opacity: number,\n sectorTexture: DataTexture,\n hasVacancies: boolean,\n): MeshStandardMaterial {\n const transparent = opacity < 1 || hasVacancies;\n const material = new MeshStandardMaterial({\n color: \"#ffffff\",\n metalness: METALNESS,\n roughness: ROUGHNESS,\n opacity,\n transparent,\n alphaToCoverage: !transparent,\n });\n material.onBeforeCompile = (shader) => {\n shader.uniforms.sectorTexture = { value: sectorTexture };\n shader.uniforms.vacancyOpacity = { value: VACANCY_OPACITY };\n shader.vertexShader = atomVertexShader(shader.vertexShader);\n shader.fragmentShader = atomFragmentShader(shader.fragmentShader);\n };\n material.customProgramCacheKey = () => \"bravais-atom-spheres\";\n return material;\n}\n\n/**\n * Bonds are ray-cast tubes, one half per instance. Each instance is the box\n * around its half; the fragment shader finds where the pixel's view ray\n * enters the solid tube, which is cut on the atom's sphere at the atom end\n * and flat at the bond midpoint, writes that depth and shades with the\n * surface normal. The wall, the cut where a tube meets its sphere and every\n * crossing with another sphere are then exact at any zoom.\n */\nfunction bondVertexShader(shader: string): string {\n return patchShader(shader, [\n [\n \"#include <common>\",\n `#include <common>\nuniform float capRadius;\nflat varying vec3 vTubeCenter;\nflat varying vec3 vTubeAxis;\nflat varying vec3 vAtomCenter;\nflat varying float vTubeRadius;\nflat varying float vTubeHalfLength;\nflat varying vec2 vDepthCoefficients;\nvarying vec3 vBoxPoint;`,\n ],\n [\n \"#include <project_vertex>\",\n `mat4 tubeMatrix = modelViewMatrix * instanceMatrix;\nfloat tubeLength = max(length(tubeMatrix[1].xyz), 1e-6);\nvTubeRadius = length(tubeMatrix[0].xyz);\nvTubeHalfLength = tubeLength * 0.5;\nvTubeCenter = tubeMatrix[3].xyz;\nvTubeAxis = tubeMatrix[1].xyz / tubeLength;\nfloat rim = sqrt(max(0.0, capRadius * capRadius - vTubeRadius * vTubeRadius));\nvAtomCenter = vTubeCenter - vTubeAxis * (rim + vTubeHalfLength);\nvDepthCoefficients = vec2(projectionMatrix[2][2], projectionMatrix[3][2]);\nvec4 mvPosition = tubeMatrix * vec4(position, 1.0);\nvBoxPoint = mvPosition.xyz;\ngl_Position = projectionMatrix * mvPosition;`,\n ],\n ]);\n}\n\nfunction bondFragmentShader(shader: string): string {\n return patchShader(shader, [\n [\n \"#include <common>\",\n `#include <common>\nuniform float capRadius;\nflat varying vec3 vTubeCenter;\nflat varying vec3 vTubeAxis;\nflat varying vec3 vAtomCenter;\nflat varying float vTubeRadius;\nflat varying float vTubeHalfLength;\nflat varying vec2 vDepthCoefficients;\nvarying vec3 vBoxPoint;`,\n ],\n [\n \"#include <clipping_planes_fragment>\",\n `// The view ray through this pixel runs down view z. The tube's surface is\n// the nearest of: the wall outside the atom's sphere, the sphere's far side\n// inside the tube (the cut face) and the midpoint disc. Along the ray,\n// q(z) = p(z) - centre has q.a = k + (z - cz) a.z and |q|^2 = u + (z - cz)^2.\nvec2 tubePixel = vBoxPoint.xy;\nvec2 tubeOffset = tubePixel - vTubeCenter.xy;\nfloat tubeK = dot(tubeOffset, vTubeAxis.xy);\nfloat tubeU = dot(tubeOffset, tubeOffset);\nfloat axisZ = vTubeAxis.z;\nfloat quadA = 1.0 - axisZ * axisZ;\nfloat quadB = -2.0 * tubeK * axisZ;\nfloat quadC = tubeU - tubeK * tubeK - vTubeRadius * vTubeRadius;\nfloat tubeRadius2 = vTubeRadius * vTubeRadius;\n// The ray's closest approach to the axis, for the outline's coverage.\nfloat axisDistance2 = tubeU - tubeK * tubeK;\nif (quadA > 1e-6) {\n axisDistance2 -= quadB * quadB / (4.0 * quadA);\n}\nfloat axisDistance = sqrt(max(0.0, axisDistance2));\nfloat tubeCoverage = clamp(\n (vTubeRadius - axisDistance) / max(fwidth(axisDistance), 1e-6) + 0.5,\n 0.0,\n 1.0\n);\nif (tubeCoverage <= 0.0) {\n discard;\n}\nfloat tubeHitZ = -1e30;\nvec3 tubeNormal = vec3(0.0, 0.0, 1.0);\nif (quadA > 1e-6) {\n float discriminant = quadB * quadB - 4.0 * quadA * quadC;\n if (discriminant >= 0.0) {\n float z = vTubeCenter.z + (-quadB + sqrt(discriminant)) / (2.0 * quadA);\n vec3 d = vec3(tubePixel, z) - vTubeCenter;\n float s = dot(d, vTubeAxis);\n if (abs(s) <= vTubeHalfLength && distance(vec3(tubePixel, z), vAtomCenter) >= capRadius) {\n tubeHitZ = z;\n tubeNormal = (d - s * vTubeAxis) / vTubeRadius;\n }\n }\n}\nif (axisZ > 1e-6) {\n float z = vTubeCenter.z + (vTubeHalfLength - tubeK) / axisZ;\n vec3 d = vec3(tubePixel, z) - vTubeCenter;\n if (dot(d, d) - vTubeHalfLength * vTubeHalfLength <= tubeRadius2 && z > tubeHitZ &&\n distance(vec3(tubePixel, z), vAtomCenter) >= capRadius) {\n tubeHitZ = z;\n tubeNormal = vTubeAxis;\n }\n}\n{\n vec2 m = tubePixel - vAtomCenter.xy;\n float inside = capRadius * capRadius - dot(m, m);\n if (inside >= 0.0) {\n float z = vAtomCenter.z - sqrt(inside);\n vec3 d = vec3(tubePixel, z) - vTubeCenter;\n float s = dot(d, vTubeAxis);\n if (abs(s) <= vTubeHalfLength && dot(d, d) - s * s <= tubeRadius2 && z > tubeHitZ) {\n tubeHitZ = z;\n tubeNormal = (vAtomCenter - vec3(tubePixel, z)) / capRadius;\n }\n }\n}\nif (tubeHitZ < -1e29) {\n discard;\n}\ngl_FragDepth = (vDepthCoefficients.x * tubeHitZ + vDepthCoefficients.y) * 0.5 + 0.5;\n#include <clipping_planes_fragment>`,\n ],\n [\n \"#include <color_fragment>\",\n `#include <color_fragment>\ndiffuseColor.a *= tubeCoverage;`,\n ],\n [\n \"#include <normal_fragment_begin>\",\n `#include <normal_fragment_begin>\nnormal = tubeNormal;\nnonPerturbedNormal = normal;`,\n ],\n ]);\n}\n\n/**\n * Bond material: the matte preset drawing ray-cast tubes cut on their atoms'\n * spheres of radius `capRadius`.\n */\nexport function createBondMaterial(\n opacity: number,\n capRadius: number,\n): MeshStandardMaterial {\n const transparent = opacity < 1;\n const material = new MeshStandardMaterial({\n color: \"#ffffff\",\n metalness: METALNESS,\n roughness: ROUGHNESS,\n opacity,\n transparent,\n alphaToCoverage: !transparent,\n });\n material.onBeforeCompile = (shader) => {\n shader.uniforms.capRadius = { value: capRadius };\n shader.vertexShader = bondVertexShader(shader.vertexShader);\n shader.fragmentShader = bondFragmentShader(shader.fragmentShader);\n };\n material.customProgramCacheKey = () => \"bravais-bond-tubes\";\n return material;\n}\n\nexport function createCellFrameMaterial(opacity: number): LineBasicMaterial {\n return new LineBasicMaterial({\n color: CELL_FRAME_COLOR,\n opacity,\n transparent: true,\n fog: false,\n });\n}\n\n/** Stencil value the gizmo's arrows leave on every pixel they cover. */\nexport const GIZMO_AXIS_STENCIL = 1;\n\n/**\n * A gizmo surface. `stencilRef` is written wherever the surface is the one\n * seen: GIZMO_AXIS_STENCIL for the arrows, 0 for the origin ball, so the\n * axis letters can tell what they are drawn over.\n */\nexport function createGizmoMaterial(\n color: string,\n stencilRef: number,\n): MeshStandardMaterial {\n return new MeshStandardMaterial({\n color,\n metalness: 0,\n roughness: 0.8,\n side: DoubleSide,\n stencilWrite: true,\n stencilRef,\n stencilFunc: AlwaysStencilFunc,\n stencilZPass: ReplaceStencilOp,\n });\n}\n","import {\n AmbientLight,\n CanvasTexture,\n ConeGeometry,\n CylinderGeometry,\n DirectionalLight,\n EqualStencilFunc,\n Group,\n LinearFilter,\n LinearMipmapLinearFilter,\n Mesh,\n NotEqualStencilFunc,\n OrthographicCamera,\n Quaternion,\n SRGBColorSpace,\n Scene,\n Sprite,\n SpriteMaterial,\n SphereGeometry,\n Vector3,\n type WebGLRenderer,\n} from \"three\";\n\nimport type { Mat3 } from \"../structure/types.js\";\nimport { GIZMO_AXIS_STENCIL, createGizmoMaterial } from \"./materials.js\";\n\n/** Axis colours and proportions currently follow Pretty Lattice's gizmo. */\nconst AXIS_COLORS = { a: \"#d27686\", b: \"#80c393\", c: \"#75a4dd\" } as const;\nconst SHAFT_LENGTH = 0.82;\nconst SHAFT_RADIUS = 0.055;\nconst CONE_LENGTH = 0.24;\nconst CONE_RADIUS = 0.13;\nconst ORIGIN_RADIUS = 0.13;\nconst LABEL_DISTANCE = 1.3;\nconst LABEL_SCALE = 0.5;\n/** Label texture size, a little above its size on screen, mipmapped down. */\nconst LABEL_TEXTURE_SIZE = 128;\n/**\n * Each letter is drawn twice, dark over the background and white over an\n * arrow, the two told apart by the stencil mark the arrows leave, so a\n * letter stays readable where it crosses an arrow.\n */\nconst LABEL_COLOR = \"#2a2a2a\";\nconst LABEL_COLOR_OVER_AXES = \"#ffffff\";\n/** World units visible across the gizmo viewport. */\nconst VIEW_EXTENT = 3.2;\nconst UP = new Vector3(0, 1, 0);\n\n/** The plain italic letter of an axis, in the interface's font, drawn white for the sprite to tint. */\nfunction labelTexture(label: string, fontFamily: string): CanvasTexture {\n const canvas = document.createElement(\"canvas\");\n canvas.width = LABEL_TEXTURE_SIZE;\n canvas.height = LABEL_TEXTURE_SIZE;\n const context = canvas.getContext(\"2d\");\n if (context) {\n const fontSize = LABEL_TEXTURE_SIZE * 0.68;\n context.clearRect(0, 0, canvas.width, canvas.height);\n context.font = `italic 600 ${fontSize}px ${fontFamily}`;\n context.textAlign = \"center\";\n context.textBaseline = \"middle\";\n context.fillStyle = \"#ffffff\";\n context.fillText(label, canvas.width / 2, canvas.height / 2);\n }\n const texture = new CanvasTexture(canvas);\n texture.colorSpace = SRGBColorSpace;\n texture.premultiplyAlpha = true;\n texture.magFilter = LinearFilter;\n texture.minFilter = LinearMipmapLinearFilter;\n return texture;\n}\n\n/** An arrow along +y with its letter at the tip; `setCell` turns it to its axis. */\nfunction createAxisArrow(\n color: string,\n label: string,\n fontFamily: string,\n): Group {\n const arrow = new Group();\n const material = createGizmoMaterial(color, GIZMO_AXIS_STENCIL);\n const shaft = new Mesh(\n new CylinderGeometry(SHAFT_RADIUS, SHAFT_RADIUS, SHAFT_LENGTH, 24),\n material,\n );\n shaft.position.y = SHAFT_LENGTH / 2;\n const cone = new Mesh(\n new ConeGeometry(CONE_RADIUS, CONE_LENGTH, 32),\n material,\n );\n cone.position.y = SHAFT_LENGTH + CONE_LENGTH / 2;\n arrow.add(shaft, cone);\n\n const texture = labelTexture(label, fontFamily);\n const passes = [\n [LABEL_COLOR, NotEqualStencilFunc],\n [LABEL_COLOR_OVER_AXES, EqualStencilFunc],\n ] as const;\n for (const [labelColor, stencilFunc] of passes) {\n const labelSprite = new Sprite(\n new SpriteMaterial({\n map: texture,\n color: labelColor,\n depthTest: false,\n depthWrite: false,\n transparent: true,\n stencilWrite: true,\n stencilRef: GIZMO_AXIS_STENCIL,\n stencilFunc,\n }),\n );\n labelSprite.scale.set(LABEL_SCALE, LABEL_SCALE, 1);\n labelSprite.position.y = LABEL_DISTANCE;\n labelSprite.renderOrder = 10;\n arrow.add(labelSprite);\n }\n return arrow;\n}\n\n/** The a, b, c axes of the cell drawn in a corner, following the camera. */\nexport class AxesGizmo {\n readonly scene = new Scene();\n readonly camera = new OrthographicCamera(-1, 1, 1, -1, 0.1, 20);\n private readonly axes = new Group();\n /** The a, b and c arrows, built once and turned to each new cell. */\n private readonly arrows: Group[];\n private readonly headlight = new DirectionalLight(\"#ffffff\", 1.78);\n private readonly inverse = new Quaternion();\n private readonly direction = new Vector3();\n\n /** `fontFamily` is the interface font the axis letters are drawn in. */\n constructor(fontFamily: string) {\n this.camera.position.set(0, 0, 5);\n this.camera.lookAt(0, 0, 0);\n this.scene.add(new AmbientLight(\"#ffffff\", 0.68));\n this.headlight.position.set(1.6, 1.1, 5);\n this.scene.add(this.headlight);\n this.arrows = ([\"a\", \"b\", \"c\"] as const).map((label) =>\n createAxisArrow(AXIS_COLORS[label], label, fontFamily),\n );\n const origin = new Mesh(\n new SphereGeometry(ORIGIN_RADIUS, 32, 16),\n createGizmoMaterial(\"#f3f2ee\", 0),\n );\n this.axes.add(...this.arrows, origin);\n this.scene.add(this.axes);\n }\n\n /** Point the arrows along the cell's a, b and c axes. */\n setCell(cell: Mat3): void {\n this.arrows.forEach((arrow, axis) => {\n arrow.quaternion.setFromUnitVectors(\n UP,\n this.direction.set(...cell[axis]!).normalize(),\n );\n });\n }\n\n /** Draw into the bottom-left `size` pixels of a renderer whose main pass is done. */\n render(\n renderer: WebGLRenderer,\n cameraQuaternion: Quaternion,\n size: number,\n ): void {\n this.axes.quaternion.copy(this.inverse.copy(cameraQuaternion).invert());\n const half = VIEW_EXTENT / 2;\n this.camera.left = -half;\n this.camera.right = half;\n this.camera.top = half;\n this.camera.bottom = -half;\n this.camera.updateProjectionMatrix();\n const previousAutoClear = renderer.autoClear;\n renderer.autoClear = false;\n renderer.setViewport(0, 0, size, size);\n renderer.setScissor(0, 0, size, size);\n renderer.setScissorTest(true);\n renderer.clear(false, true, true);\n renderer.render(this.scene, this.camera);\n renderer.setScissorTest(false);\n renderer.autoClear = previousAutoClear;\n }\n\n dispose(): void {\n this.axes.traverse((object) => {\n if (object instanceof Mesh || object instanceof Sprite) {\n object.geometry.dispose();\n const material = object.material;\n if (\"map\" in material && material.map) {\n material.map.dispose();\n }\n material.dispose();\n }\n });\n this.axes.clear();\n }\n}\n","{\n \"source\": \"VESTA's element colours, softened.\",\n \"elements\": {\n \"H\": \"#f2c0c0\",\n \"D\": \"#c2c1f4\",\n \"He\": \"#ecd9c0\",\n \"Li\": \"#8cd37e\",\n \"Be\": \"#71cc83\",\n \"B\": \"#509f47\",\n \"C\": \"#8d5434\",\n \"N\": \"#a9b3df\",\n \"O\": \"#e15949\",\n \"F\": \"#a9b3df\",\n \"Ne\": \"#e266ac\",\n \"Na\": \"#e7d15f\",\n \"Mg\": \"#eb8442\",\n \"Al\": \"#7dafd2\",\n \"Si\": \"#3a61cf\",\n \"P\": \"#be99c0\",\n \"S\": \"#e7e569\",\n \"Cl\": \"#87e17c\",\n \"Ar\": \"#bfedb5\",\n \"K\": \"#975cd1\",\n \"Ca\": \"#5d98c0\",\n \"Sc\": \"#b66aac\",\n \"Ti\": \"#74c2f5\",\n \"V\": \"#d2523f\",\n \"Cr\": \"#274fb1\",\n \"Mn\": \"#a34399\",\n \"Fe\": \"#b67822\",\n \"Co\": \"#254fb4\",\n \"Ni\": \"#b2b6b8\",\n \"Cu\": \"#3b5fc6\",\n \"Zn\": \"#919284\",\n \"Ga\": \"#9ed77c\",\n \"Ge\": \"#8374ac\",\n \"As\": \"#81c56c\",\n \"Se\": \"#a4dc6c\",\n \"Br\": \"#8c411c\",\n \"Kr\": \"#eeb6e7\",\n \"Rb\": \"#e05c97\",\n \"Sr\": \"#84e381\",\n \"Y\": \"#699a90\",\n \"Zr\": \"#86e27f\",\n \"Nb\": \"#57b079\",\n \"Mo\": \"#b486b0\",\n \"Tc\": \"#c7a9c5\",\n \"Ru\": \"#c8b1a7\",\n \"Rh\": \"#c4c8a1\",\n \"Pd\": \"#babcb1\",\n \"Ag\": \"#b2b6b8\",\n \"Cd\": \"#d565c3\",\n \"In\": \"#d282b8\",\n \"Sn\": \"#9b8fba\",\n \"Sb\": \"#d48455\",\n \"Te\": \"#aba153\",\n \"I\": \"#923e8e\",\n \"Xe\": \"#999ff0\",\n \"Cs\": \"#58ecb4\",\n \"Ba\": \"#7cd978\",\n \"La\": \"#6fbb63\",\n \"Ce\": \"#c9e871\",\n \"Pr\": \"#e8d55c\",\n \"Nd\": \"#ec913d\",\n \"Pm\": \"#2653c3\",\n \"Sm\": \"#e05984\",\n \"Eu\": \"#d964be\",\n \"Gd\": \"#ad60d3\",\n \"Tb\": \"#7156cf\",\n \"Dy\": \"#3f56ca\",\n \"Ho\": \"#3664d1\",\n \"Er\": \"#527c44\",\n \"Tm\": \"#224db9\",\n \"Yb\": \"#47ece4\",\n \"Lu\": \"#5ceab1\",\n \"Hf\": \"#b0b05b\",\n \"Ta\": \"#b69a56\",\n \"W\": \"#918c82\",\n \"Re\": \"#afad8a\",\n \"Os\": \"#c4ac74\",\n \"Ir\": \"#c0c670\",\n \"Pt\": \"#c3bdb6\",\n \"Au\": \"#efae4b\",\n \"Hg\": \"#cbb1c4\",\n \"Tl\": \"#998b6f\",\n \"Pb\": \"#5f5f67\",\n \"Bi\": \"#bd67d4\",\n \"Po\": \"#2956c7\",\n \"At\": \"#2956c7\",\n \"Rn\": \"#e4e669\",\n \"Fr\": \"#585858\",\n \"Ra\": \"#72a960\",\n \"Ac\": \"#66a075\",\n \"Th\": \"#7ae692\",\n \"Pa\": \"#83e17f\",\n \"U\": \"#7aa2aa\",\n \"Np\": \"#595959\",\n \"Pu\": \"#595959\",\n \"Am\": \"#595959\",\n \"XX\": \"#595959\"\n }\n}\n","/**\n * OKLab and OKLCH (Björn Ottosson, 2020): a colour space where Euclidean\n * distance tracks perceived difference, so the palette can reason about\n * \"clearly different\" colours.\n */\nexport interface Oklab {\n L: number;\n a: number;\n b: number;\n}\n\n/** Lightness, chroma and hue in degrees. */\nexport interface Oklch {\n L: number;\n C: number;\n h: number;\n}\n\nfunction srgbToLinear(channel: number): number {\n return channel <= 0.04045\n ? channel / 12.92\n : ((channel + 0.055) / 1.055) ** 2.4;\n}\n\nfunction linearToSrgb(channel: number): number {\n return channel <= 0.0031308\n ? channel * 12.92\n : 1.055 * channel ** (1 / 2.4) - 0.055;\n}\n\nexport function hexToOklab(hex: string): Oklab {\n const value = Number.parseInt(hex.slice(1), 16);\n const r = srgbToLinear(((value >> 16) & 255) / 255);\n const g = srgbToLinear(((value >> 8) & 255) / 255);\n const b = srgbToLinear((value & 255) / 255);\n const l = Math.cbrt(0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b);\n const m = Math.cbrt(0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b);\n const s = Math.cbrt(0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b);\n return {\n L: 0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s,\n a: 1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s,\n b: 0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s,\n };\n}\n\n/** Linear sRGB of an OKLab colour; channels may fall outside [0, 1]. */\nfunction oklabToLinearRgb(lab: Oklab): [number, number, number] {\n const l = (lab.L + 0.3963377774 * lab.a + 0.2158037573 * lab.b) ** 3;\n const m = (lab.L - 0.1055613458 * lab.a - 0.0638541728 * lab.b) ** 3;\n const s = (lab.L - 0.0894841775 * lab.a - 1.291485548 * lab.b) ** 3;\n return [\n 4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s,\n -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s,\n -0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s,\n ];\n}\n\nexport function isInGamut(lab: Oklab): boolean {\n return oklabToLinearRgb(lab).every(\n (channel) => channel >= -1e-4 && channel <= 1 + 1e-4,\n );\n}\n\nexport function oklabToHex(lab: Oklab): string {\n const hex = oklabToLinearRgb(lab).map((channel) => {\n const srgb = linearToSrgb(Math.min(1, Math.max(0, channel)));\n return Math.round(srgb * 255)\n .toString(16)\n .padStart(2, \"0\");\n });\n return `#${hex.join(\"\")}`;\n}\n\nexport function oklabToOklch(lab: Oklab): Oklch {\n const C = Math.hypot(lab.a, lab.b);\n const h = ((Math.atan2(lab.b, lab.a) * 180) / Math.PI + 360) % 360;\n return { L: lab.L, C, h };\n}\n\nexport function oklchToOklab(lch: Oklch): Oklab {\n const radians = (lch.h * Math.PI) / 180;\n return {\n L: lch.L,\n a: lch.C * Math.cos(radians),\n b: lch.C * Math.sin(radians),\n };\n}\n\n/** The same hue and lightness with the chroma reduced until sRGB can show it. */\nexport function clampChromaToGamut(lch: Oklch): Oklch {\n if (isInGamut(oklchToOklab(lch))) {\n return lch;\n }\n let low = 0;\n let high = lch.C;\n for (let step = 0; step < 24; step += 1) {\n const middle = (low + high) / 2;\n if (isInGamut(oklchToOklab({ ...lch, C: middle }))) {\n low = middle;\n } else {\n high = middle;\n }\n }\n return { ...lch, C: low };\n}\n","import elementColors from \"../data/element-colors.json\";\nimport { ELEMENT_SYMBOLS } from \"../structure/elements.js\";\nimport {\n clampChromaToGamut,\n hexToOklab,\n oklabToHex,\n oklabToOklch,\n oklchToOklab,\n type Oklab,\n type Oklch,\n} from \"./oklab.js\";\n\nconst BASE_COLORS = elementColors.elements as Record<string, string>;\n\n/**\n * The base table gives a few elements that usually share a structure one and\n * the same colour: chromium and cobalt, vanadium and oxygen, fluorine and\n * nitrogen. The less common one of each pair gets a fixed refinement in the\n * same key, so those structures need no automatic adjustment. Every other\n * clash is left to the session palette below, since any further fixed\n * choice would clash with some other common partner.\n */\nconst ANCHOR_REFINEMENTS: Record<string, string> = {\n // Steel periwinkle, against cobalt's deep blue.\n Cr: \"#6d87c9\",\n // Crimson rose, against oxygen's red.\n V: \"#bf4b62\",\n // Pale aqua, against nitrogen's lavender.\n F: \"#9bd7d0\",\n};\n\n/**\n * Elements by how often they appear in refined inorganic structures. When\n * colours collide inside one structure, the earlier element keeps its\n * anchor and the later one moves. Elements not listed follow by atomic\n * number.\n */\nconst PRIORITY = [\n \"O\",\n \"Li\",\n \"Na\",\n \"K\",\n \"Mg\",\n \"Ca\",\n \"Sr\",\n \"Ba\",\n \"Al\",\n \"Si\",\n \"Ti\",\n \"Mn\",\n \"Fe\",\n \"Co\",\n \"Ni\",\n \"Cu\",\n \"Zn\",\n \"V\",\n \"Cr\",\n \"Ga\",\n \"Ge\",\n \"Y\",\n \"Zr\",\n \"Nb\",\n \"Mo\",\n \"Ru\",\n \"Ag\",\n \"Cd\",\n \"In\",\n \"Sn\",\n \"Sb\",\n \"La\",\n \"Ce\",\n \"Nd\",\n \"Sm\",\n \"Gd\",\n \"Ta\",\n \"W\",\n \"Pt\",\n \"Au\",\n \"Pb\",\n \"Bi\",\n \"H\",\n \"C\",\n \"N\",\n \"F\",\n \"P\",\n \"S\",\n \"Cl\",\n \"Se\",\n \"Te\",\n \"I\",\n \"Br\",\n \"B\",\n \"Sc\",\n \"Rb\",\n \"Cs\",\n \"Hf\",\n \"Re\",\n \"Ir\",\n \"Pd\",\n \"Rh\",\n \"Os\",\n \"Pr\",\n \"Eu\",\n \"Tb\",\n \"Dy\",\n \"Ho\",\n \"Er\",\n \"Tm\",\n \"Yb\",\n \"Lu\",\n \"Th\",\n \"U\",\n];\nconst PRIORITY_RANK = new Map(\n PRIORITY.map((element, index) => [element, index]),\n);\n\n/** Two colours closer than this, in weighted OKLab, read as one. */\nconst MIN_DISTANCE = 0.1;\n/** Shading already varies lightness on a sphere, so hue and chroma count more. */\nconst LIGHTNESS_WEIGHT = 0.7;\n/** Adjusted colours stay in the palette's pastel band: never near white or black, never garish. */\nconst BAND = { minL: 0.45, maxL: 0.88, maxC: 0.2 };\n/** Below this chroma a colour is a grey, whose hue means nothing. */\nconst GREY_CHROMA = 0.025;\n/** A grey that must differ takes a dusty tint: this much chroma, this much darker. */\nconst TINT_CHROMA = 0.09;\nconst TINT_DARKENING = 0.1;\n\nconst HUE_OFFSETS = [\n 0, 10, -10, 20, -20, 30, -30, 45, -45, 60, -60, 80, -80, 100, -100, 120, -120,\n 150, -150, 180,\n];\nconst LIGHTNESS_OFFSETS = [0, -0.05, 0.05, -0.1, 0.1, -0.15, 0.15, -0.2, 0.2];\n/** Changes of vividness, as fractions of the chroma sRGB can show at a hue. */\nconst VIVIDNESS_OFFSETS = [0, 0.15, -0.15, 0.3];\nconst TINT_HUES = [0, 30, 60, 90, 120, 150, 180, 210, 240, 270, 300, 330];\n/** Cost of one step in hue (degrees), lightness, and vividness. */\nconst HUE_STEP = 30;\nconst LIGHTNESS_STEP = 0.08;\nconst VIVIDNESS_STEP = 0.15;\n/** Brightening a grey toward the background reads worse than darkening it. */\nconst BRIGHTENING_PENALTY = 1.5;\n/** A grey darkens before it takes a tint: more than one darkening step, less than two. */\nconst TINT_COST = 2;\n\ninterface Candidate {\n lch: Oklch;\n lab: Oklab;\n cost: number;\n}\n\nfunction weightedDistance(p: Oklab, q: Oklab): number {\n const dL = (p.L - q.L) * LIGHTNESS_WEIGHT;\n return Math.hypot(dL, p.a - q.a, p.b - q.b);\n}\n\nfunction hashString(text: string): number {\n let hash = 2166136261;\n for (let index = 0; index < text.length; index += 1) {\n hash = Math.imul(hash ^ text.charCodeAt(index), 16777619) >>> 0;\n }\n return hash;\n}\n\n/**\n * The anchor of an element: its refinement, else its base colour, else a\n * hue spread by the golden angle over the atomic number, so an element the\n * base table lacks still gets the same colour every time.\n */\nfunction anchorHex(element: string): string | null {\n return ANCHOR_REFINEMENTS[element] ?? BASE_COLORS[element] ?? null;\n}\n\nfunction anchorColor(element: string): Oklch {\n const hex = anchorHex(element);\n if (hex) {\n return oklabToOklch(hexToOklab(hex));\n }\n const atomicNumber = ELEMENT_SYMBOLS.indexOf(element) + 1;\n const seed = atomicNumber > 0 ? atomicNumber : hashString(element);\n return { L: 0.68, C: 0.12, h: (seed * 137.508) % 360 };\n}\n\nfunction priorityRank(element: string): number {\n const listed = PRIORITY_RANK.get(element);\n if (listed !== undefined) {\n return listed;\n }\n const atomicNumber = ELEMENT_SYMBOLS.indexOf(element);\n return (\n PRIORITY.length +\n (atomicNumber >= 0 ? atomicNumber : ELEMENT_SYMBOLS.length)\n );\n}\n\nfunction withinBand(lch: Oklch): Oklch {\n return clampChromaToGamut({\n L: Math.min(BAND.maxL, Math.max(BAND.minL, lch.L)),\n C: Math.min(BAND.maxC, Math.max(0, lch.C)),\n h: ((lch.h % 360) + 360) % 360,\n });\n}\n\n/** The largest chroma sRGB can show at a lightness and hue. */\nfunction maxChroma(L: number, h: number): number {\n return clampChromaToGamut({ L, C: 0.5, h }).C;\n}\n\nfunction candidate(lch: Oklch, cost: number): Candidate {\n const banded = withinBand(lch);\n return { lch: banded, lab: oklchToOklab(banded), cost };\n}\n\n/**\n * Colours near an anchor, cheapest first. A hue turn is cheaper than a\n * lightness step, which is cheaper than a change of vividness, so an\n * element keeps its character for as long as the palette allows. Turning\n * the hue keeps the anchor's vividness relative to what sRGB can show at\n * the new hue, so a soft green turns into a soft teal, not a loud one. A\n * grey anchor has no hue to turn; it darkens first, then takes a dusty tint.\n */\nfunction candidatesAround(anchor: Oklch): Candidate[] {\n const candidates: Candidate[] = [];\n if (anchor.C < GREY_CHROMA) {\n for (const lightnessOffset of LIGHTNESS_OFFSETS) {\n const lightnessCost =\n (Math.abs(lightnessOffset) / LIGHTNESS_STEP) *\n (lightnessOffset > 0 ? BRIGHTENING_PENALTY : 1);\n candidates.push(\n candidate({ ...anchor, L: anchor.L + lightnessOffset }, lightnessCost),\n );\n for (const hue of TINT_HUES) {\n candidates.push(\n candidate(\n {\n L: anchor.L - TINT_DARKENING + lightnessOffset,\n C: TINT_CHROMA,\n h: hue,\n },\n TINT_COST + lightnessCost + hue / 3600,\n ),\n );\n }\n }\n return candidates.sort((left, right) => left.cost - right.cost);\n }\n const vividness = anchor.C / Math.max(1e-6, maxChroma(anchor.L, anchor.h));\n for (const hueOffset of HUE_OFFSETS) {\n for (const lightnessOffset of LIGHTNESS_OFFSETS) {\n for (const vividnessOffset of VIVIDNESS_OFFSETS) {\n const L = Math.min(\n BAND.maxL,\n Math.max(BAND.minL, anchor.L + lightnessOffset),\n );\n const h = anchor.h + hueOffset;\n const C =\n Math.min(1, Math.max(0.1, vividness + vividnessOffset)) *\n maxChroma(L, h);\n const cost =\n Math.abs(hueOffset) / HUE_STEP +\n Math.abs(lightnessOffset) / LIGHTNESS_STEP +\n Math.abs(vividnessOffset) / VIVIDNESS_STEP;\n candidates.push(candidate({ L, C, h }, cost));\n }\n }\n }\n return candidates.sort((left, right) => left.cost - right.cost);\n}\n\ninterface Assignment {\n hex: string;\n lab: Oklab;\n}\n\n/**\n * The colours of the elements shown in this session. An element keeps its\n * colour from the moment it first appears, so a structure loaded later can\n * never recolour one loaded earlier; a newcomer whose anchor is too close to\n * a colour already on screen takes the nearest clearly different colour.\n * The outcome depends only on the order in which elements first appeared.\n */\nconst assigned = new Map<string, Assignment>();\n\n/**\n * The anchor itself when it is clearly different from every colour on\n * screen; otherwise the cheapest candidate that is, taking the better\n * separated of equally cheap ones; otherwise the best separated of all.\n */\nfunction choose(hex: string | null, anchor: Oklch): Assignment {\n const taken = [...assigned.values()].map((assignment) => assignment.lab);\n const separationFrom = (lab: Oklab) =>\n taken.reduce(\n (minimum, other) => Math.min(minimum, weightedDistance(lab, other)),\n Infinity,\n );\n const anchorLab = oklchToOklab(anchor);\n if (separationFrom(anchorLab) >= MIN_DISTANCE) {\n return { hex: hex ?? oklabToHex(anchorLab), lab: anchorLab };\n }\n let best: Candidate | null = null;\n let bestSeparation = -Infinity;\n let bestCost = Infinity;\n let fallback: Candidate | null = null;\n let fallbackSeparation = -Infinity;\n for (const entry of candidatesAround(anchor)) {\n const separation = separationFrom(entry.lab);\n if (separation >= MIN_DISTANCE) {\n if (\n entry.cost < bestCost - 1e-9 ||\n (Math.abs(entry.cost - bestCost) <= 1e-9 && separation > bestSeparation)\n ) {\n best = entry;\n bestCost = entry.cost;\n bestSeparation = separation;\n }\n if (entry.cost > bestCost + 1e-9) {\n break;\n }\n } else if (separation > fallbackSeparation) {\n fallback = entry;\n fallbackSeparation = separation;\n }\n }\n const chosen = best ?? fallback ?? { lab: anchorLab, lch: anchor, cost: 0 };\n return { hex: oklabToHex(chosen.lab), lab: chosen.lab };\n}\n\n/** Give these elements their colours now, the more common ones first, so colours do not depend on drawing order. */\nexport function ensureElementColors(elements: readonly string[]): void {\n const newcomers = [...new Set(elements)]\n .filter((element) => !assigned.has(element))\n .sort((left, right) => priorityRank(left) - priorityRank(right));\n for (const element of newcomers) {\n assigned.set(element, choose(anchorHex(element), anchorColor(element)));\n }\n}\n\n/** The colour of an element as a hex string such as `#e15949`, given on first use. */\nexport function elementColor(element: string): string {\n const assignment = assigned.get(element);\n if (assignment) {\n return assignment.hex;\n }\n ensureElementColors([element]);\n return (assigned.get(element) as Assignment).hex;\n}\n\n/** Every element given a colour so far, with its colour, in the order given. */\nexport function elementColorAssignments(): [string, string][] {\n return [...assigned].map(([element, assignment]) => [\n element,\n assignment.hex,\n ]);\n}\n\n/**\n * Forget every colour given so far, for example when all structures are\n * closed. Viewers and thumbnails pick up new colours at their next draw.\n */\nexport function resetElementColors(): void {\n assigned.clear();\n}\n","import { elementColor } from \"./palette.js\";\n\nconst STYLE_ID = \"bravais-styles\";\n\n/** Styles for the viewer's overlay elements, injected once per document. */\nconst STYLES = `\n.bravais-viewer {\n position: relative;\n overflow: hidden;\n}\n.bravais-canvas {\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n display: block;\n touch-action: none;\n}\n.bravais-legend {\n position: absolute;\n left: 50%;\n bottom: 20px;\n transform: translateX(-50%);\n display: flex;\n flex-wrap: wrap;\n justify-content: center;\n gap: 8px 16px;\n max-width: calc(100% - 32px);\n padding: 8px 16px;\n border: 1px solid rgba(40, 40, 40, 0.1);\n border-radius: 999px;\n background: rgba(255, 255, 255, 0.72);\n backdrop-filter: blur(24px) saturate(150%);\n box-shadow: 0 10px 15px -3px rgba(40, 40, 40, 0.1);\n font-family: inherit;\n font-size: 0.95rem;\n line-height: 1;\n color: #282828;\n pointer-events: none;\n}\n.bravais-legend[hidden] {\n display: none;\n}\n.bravais-legend-item {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.bravais-legend-swatch {\n width: 18px;\n height: 18px;\n border-radius: 50%;\n border: 1px solid rgba(40, 40, 40, 0.1);\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);\n}\n`;\n\nexport function ensureViewerStyles(root: Document): void {\n if (root.getElementById(STYLE_ID)) {\n return;\n }\n const style = root.createElement(\"style\");\n style.id = STYLE_ID;\n style.textContent = STYLES;\n root.head.appendChild(style);\n}\n\n// The lit-sphere swatch currently follows Pretty Lattice's legend.\nfunction swatchBackground(color: string): string {\n return `linear-gradient(135deg, rgba(255, 255, 255, 0.38) 0 14%, rgba(255, 255, 255, 0) 42%), ${color}`;\n}\n\n/** The element legend pill at the bottom of the viewer. */\nexport class ElementLegend {\n readonly element: HTMLElement;\n\n constructor(root: Document) {\n this.element = root.createElement(\"div\");\n this.element.className = \"bravais-legend\";\n this.element.hidden = true;\n }\n\n setElements(elements: string[]): void {\n this.element.replaceChildren();\n for (const symbol of elements) {\n const item = this.element.ownerDocument.createElement(\"span\");\n item.className = \"bravais-legend-item\";\n const swatch = this.element.ownerDocument.createElement(\"span\");\n swatch.className = \"bravais-legend-swatch\";\n swatch.style.background = swatchBackground(elementColor(symbol));\n const label = this.element.ownerDocument.createElement(\"span\");\n label.textContent = symbol;\n item.append(swatch, label);\n this.element.appendChild(item);\n }\n this.element.hidden = elements.length === 0;\n }\n}\n","import {\n Box3,\n BoxGeometry,\n BufferGeometry,\n Color,\n DataTexture,\n Float32BufferAttribute,\n FloatType,\n Group,\n InstancedMesh,\n LineSegments,\n Matrix4,\n NearestFilter,\n Object3D,\n PlaneGeometry,\n Quaternion,\n RGBAFormat,\n Vector3,\n} from \"three\";\n\nimport type { SceneAtom, SceneLayer, StructureScene } from \"../scene/build.js\";\nimport type { Mat3, Vec3 } from \"../structure/types.js\";\nimport {\n SECTOR_SITES_PER_ROW,\n SECTOR_TEXELS_PER_SITE,\n VACANCY_COLOR,\n VACANCY_FLAG,\n createAtomMaterial,\n createBondMaterial,\n createCellFrameMaterial,\n} from \"./materials.js\";\nimport { elementColor, ensureElementColors } from \"./palette.js\";\n\n/** Every atom is drawn at this radius, in ångström: one size for all. */\nconst ATOM_RADIUS = 0.4;\n/** Bond tube radius in ångström. */\nconst BOND_RADIUS = 0.1;\n/**\n * A bond half ends on a sphere this much smaller than its atom's, so the\n * atom's surface lies in front of the tube's cap and rim: they are hidden\n * by an occupied sector, faintly tinted through a vacant one, and never\n * fight it for depth.\n */\nconst BOND_INSET = 0.002;\n/** Radius of the sphere a bond half ends on. */\nconst CAP_RADIUS = ATOM_RADIUS - BOND_INSET;\n/** Along-axis distance from an atom's centre to the rim of a bond half. */\nconst BOND_START = Math.sqrt(\n CAP_RADIUS * CAP_RADIUS - BOND_RADIUS * BOND_RADIUS,\n);\nconst UP = new Vector3(0, 1, 0);\n\nexport interface SceneModel {\n group: Group;\n /** Cell row vectors of the first layer, the frame everything is centred on. */\n cell: Mat3;\n /** Centre of that cell, which `group` moves to the origin. */\n center: Vec3;\n /** Bounds of every atom and cell corner of every layer, in the centred frame. */\n bounds: Box3;\n /** Largest cell edge length of any layer. */\n span: number;\n /** Elements of the drawn layers. */\n elements: string[];\n dispose(): void;\n}\n\nfunction cellCorners(cell: Mat3): Vector3[] {\n const [a, b, c] = cell.map((row) => new Vector3(...row)) as [\n Vector3,\n Vector3,\n Vector3,\n ];\n const origin = new Vector3();\n return [\n origin,\n a.clone(),\n b.clone(),\n c.clone(),\n a.clone().add(b),\n a.clone().add(c),\n b.clone().add(c),\n a.clone().add(b).add(c),\n ];\n}\n\nexport function cellCenter(cell: Mat3): Vec3 {\n const [a, b, c] = cell;\n return [\n (a[0] + b[0] + c[0]) / 2,\n (a[1] + b[1] + c[1]) / 2,\n (a[2] + b[2] + c[2]) / 2,\n ];\n}\n\nconst CELL_EDGES: [number, number][] = [\n [0, 1],\n [0, 2],\n [0, 3],\n [1, 4],\n [1, 5],\n [2, 4],\n [2, 6],\n [3, 5],\n [3, 6],\n [4, 7],\n [5, 7],\n [6, 7],\n];\n\nfunction createCellFrame(cell: Mat3, opacity: number): LineSegments {\n const corners = cellCorners(cell);\n const positions: number[] = [];\n for (const [start, end] of CELL_EDGES) {\n const from = corners[start] as Vector3;\n const to = corners[end] as Vector3;\n positions.push(from.x, from.y, from.z, to.x, to.y, to.z);\n }\n const geometry = new BufferGeometry();\n geometry.setAttribute(\"position\", new Float32BufferAttribute(positions, 3));\n return new LineSegments(geometry, createCellFrameMaterial(opacity));\n}\n\n/**\n * The sector texture of a layer: per site, up to SECTOR_TEXELS_PER_SITE\n * texels of (colour, start fraction). The first species is the instance\n * colour and needs no texel; a vacant share ends the run in the vacancy\n * colour; species past the available texels extend the last sector.\n */\nfunction createSectorTexture(atoms: SceneAtom[]): {\n texture: DataTexture;\n hasVacancies: boolean;\n} {\n const width = SECTOR_SITES_PER_ROW * SECTOR_TEXELS_PER_SITE;\n const height = Math.max(1, Math.ceil(atoms.length / SECTOR_SITES_PER_ROW));\n const data = new Float32Array(width * height * 4).fill(1);\n const vacancy = new Color(VACANCY_COLOR);\n const color = new Color();\n let hasVacancies = false;\n atoms.forEach((atom, index) => {\n const row = Math.floor(index / SECTOR_SITES_PER_ROW);\n const column = (index % SECTOR_SITES_PER_ROW) * SECTOR_TEXELS_PER_SITE;\n let offset = (row * width + column) * 4;\n let written = 0;\n let cumulative = Math.min(1, atom.species[0]?.occupancy ?? 1);\n for (const entry of atom.species.slice(1)) {\n if (written < SECTOR_TEXELS_PER_SITE - 1) {\n color.set(elementColor(entry.element)).toArray(data, offset);\n data[offset + 3] = cumulative;\n offset += 4;\n written += 1;\n }\n cumulative = Math.min(1, cumulative + entry.occupancy);\n }\n if (cumulative < 1 - 1e-6) {\n vacancy.toArray(data, offset);\n data[offset + 3] = cumulative + VACANCY_FLAG;\n hasVacancies = true;\n }\n });\n const texture = new DataTexture(data, width, height, RGBAFormat, FloatType);\n texture.magFilter = NearestFilter;\n texture.minFilter = NearestFilter;\n texture.generateMipmaps = false;\n texture.needsUpdate = true;\n return { texture, hasVacancies };\n}\n\n/** Session colours as three.js colours, each parsed once. */\nfunction colorLookup(): (element: string) => Color {\n const colors = new Map<string, Color>();\n return (element) => {\n let color = colors.get(element);\n if (!color) {\n color = new Color(elementColor(element));\n colors.set(element, color);\n }\n return color;\n };\n}\n\nfunction createAtoms(\n atoms: SceneAtom[],\n opacity: number,\n colorOf: (element: string) => Color = colorLookup(),\n): InstancedMesh {\n // One camera-facing quad per atom; the material draws the sphere on it.\n const geometry = new PlaneGeometry(2, 2);\n const sectors = createSectorTexture(atoms);\n const mesh = new InstancedMesh(\n geometry,\n createAtomMaterial(opacity, sectors.texture, sectors.hasVacancies),\n atoms.length,\n );\n const matrix = new Matrix4();\n atoms.forEach((atom, index) => {\n matrix.makeScale(ATOM_RADIUS, ATOM_RADIUS, ATOM_RADIUS);\n matrix.setPosition(atom.position[0], atom.position[1], atom.position[2]);\n mesh.setMatrixAt(index, matrix);\n mesh.setColorAt(index, colorOf(atom.element));\n });\n mesh.instanceMatrix.needsUpdate = true;\n if (mesh.instanceColor) {\n mesh.instanceColor.needsUpdate = true;\n }\n mesh.userData.sectorTexture = sectors.texture;\n return mesh;\n}\n\n/**\n * Two half tubes per bond, each in its atom's colour, from the atom's sphere\n * to the midpoint. Each instance is the box around its half; the material\n * draws the tube inside it, cut on the atom's sphere.\n */\nfunction createBonds(\n scene: StructureScene,\n opacity: number,\n colorOf: (element: string) => Color = colorLookup(),\n): InstancedMesh | null {\n if (scene.bonds.length === 0) {\n return null;\n }\n const geometry = new BoxGeometry(2, 1, 2);\n const mesh = new InstancedMesh(\n geometry,\n createBondMaterial(opacity, CAP_RADIUS),\n scene.bonds.length * 2,\n );\n const placeholder = new Object3D();\n const start = new Vector3();\n const end = new Vector3();\n const direction = new Vector3();\n const quaternion = new Quaternion();\n scene.bonds.forEach((bond, index) => {\n const startAtom = scene.atoms[bond.start] as SceneAtom;\n const endAtom = scene.atoms[bond.end] as SceneAtom;\n start.set(...startAtom.position);\n end.set(...endAtom.position);\n direction.subVectors(end, start);\n const half = direction.length() / 2;\n direction.normalize();\n quaternion.setFromUnitVectors(UP, direction);\n const halves: [number, SceneAtom, number, number][] = [\n [0, startAtom, BOND_START, half],\n [1, endAtom, half, 2 * half - BOND_START],\n ];\n for (const [slot, atom, from, to] of halves) {\n const length = Math.max(0, to - from);\n placeholder.position\n .copy(start)\n .addScaledVector(direction, from + length / 2);\n placeholder.quaternion.copy(quaternion);\n placeholder.scale.set(BOND_RADIUS, length, BOND_RADIUS);\n placeholder.updateMatrix();\n mesh.setMatrixAt(index * 2 + slot, placeholder.matrix);\n mesh.setColorAt(index * 2 + slot, colorOf(atom.element));\n }\n });\n mesh.instanceMatrix.needsUpdate = true;\n if (mesh.instanceColor) {\n mesh.instanceColor.needsUpdate = true;\n }\n return mesh;\n}\n\n/**\n * Build the three.js objects for the layers, centred on the first cell. A\n * layer at opacity 0 is not drawn but still counts toward the centre, the\n * bounds and the span.\n */\nexport function createSceneModel(layers: SceneLayer[]): SceneModel {\n const first = layers[0];\n if (!first) {\n throw new Error(\"A scene model needs at least one layer.\");\n }\n // Colours are settled for the whole set in one go, most common element\n // first, so the result depends neither on the order atoms are drawn in nor\n // on which layers are drawn.\n ensureElementColors(\n layers.flatMap((layer) => [\n ...layer.scene.elements,\n ...layer.scene.atoms.map((atom) => atom.element),\n ]),\n );\n const center = cellCenter(first.scene.cell);\n const group = new Group();\n group.position.set(-center[0], -center[1], -center[2]);\n const bounds = new Box3();\n const elements: string[] = [];\n let span = 1;\n const disposables: (InstancedMesh | LineSegments)[] = [];\n const offset = new Vector3(...center);\n const position = new Vector3();\n const extent = new Vector3();\n\n for (const layer of layers) {\n for (const corner of cellCorners(layer.scene.cell)) {\n bounds.expandByPoint(corner.sub(offset));\n }\n for (const atom of layer.scene.atoms) {\n position.set(...atom.position).sub(offset);\n bounds.expandByPoint(extent.copy(position).addScalar(ATOM_RADIUS));\n bounds.expandByPoint(extent.copy(position).subScalar(ATOM_RADIUS));\n }\n for (const row of layer.scene.cell) {\n span = Math.max(span, Math.hypot(...row));\n }\n const opacity = layer.opacity ?? 1;\n if (opacity <= 0) {\n continue;\n }\n const atoms = createAtoms(layer.scene.atoms, opacity);\n group.add(atoms);\n disposables.push(atoms);\n const bonds = createBonds(layer.scene, opacity);\n if (bonds) {\n group.add(bonds);\n disposables.push(bonds);\n }\n const frame = createCellFrame(layer.scene.cell, opacity);\n group.add(frame);\n disposables.push(frame);\n for (const element of layer.scene.elements) {\n if (!elements.includes(element)) {\n elements.push(element);\n }\n }\n }\n\n return {\n group,\n cell: first.scene.cell,\n center,\n bounds,\n span,\n elements,\n dispose() {\n disposeGeometry(disposables);\n group.clear();\n },\n };\n}\n\n/**\n * Free the geometry and textures of `objects`. The materials are left to the\n * garbage collector: disposing the last material of a shader makes three.js\n * delete the compiled shader, and the next structure would compile it again.\n */\nfunction disposeGeometry(objects: (InstancedMesh | LineSegments)[]): void {\n for (const object of objects) {\n object.geometry.dispose();\n const sectors = object.userData.sectorTexture;\n if (sectors instanceof DataTexture) {\n sectors.dispose();\n }\n }\n}\n\n/** Two atoms 2 Å apart and the bond between them. */\nconst WARMUP_SCENE: StructureScene = {\n cell: [\n [1, 0, 0],\n [0, 1, 0],\n [0, 0, 1],\n ],\n atoms: [0, 2].map((z, siteIndex) => ({\n siteIndex,\n element: \"X\",\n species: [{ element: \"X\", occupancy: 1 }],\n position: [0, 0, z],\n fractional: [0, 0, z],\n isImage: false,\n })),\n bonds: [{ start: 0, end: 1, length: 2 }],\n elements: [],\n};\n\n/**\n * A placeholder atom, bond and cell frame in every material a structure is\n * drawn with, opaque and see-through, so their shaders can compile before\n * the first structure arrives. It gives no element a colour.\n */\nexport function createShaderWarmup(): { group: Group; dispose(): void } {\n const white = new Color(\"#ffffff\");\n const objects: (InstancedMesh | LineSegments)[] = [];\n for (const opacity of [1, 0.5]) {\n objects.push(\n createAtoms(WARMUP_SCENE.atoms, opacity, () => white),\n createBonds(WARMUP_SCENE, opacity, () => white) as InstancedMesh,\n );\n }\n objects.push(createCellFrame(WARMUP_SCENE.cell, 1));\n const group = new Group();\n group.add(...objects);\n return { group, dispose: () => disposeGeometry(objects) };\n}\n","import {\n ACESFilmicToneMapping,\n AmbientLight,\n DirectionalLight,\n OrthographicCamera,\n Scene,\n Vector3,\n WebGLRenderer,\n} from \"three\";\n\nimport {\n AMBIENT_LIGHT_INTENSITY,\n BACKGROUND_COLOR,\n HEADLIGHT_INTENSITY,\n HEADLIGHT_OFFSET,\n} from \"./materials.js\";\n\n/** The renderer, scene, camera and lights the viewer and the thumbnail renderer share. */\nexport interface Stage {\n renderer: WebGLRenderer;\n scene: Scene;\n camera: OrthographicCamera;\n /** Move the headlight along with the camera; call before each render. */\n updateHeadlight(): void;\n}\n\nexport function createStage(options: { stencil?: boolean } = {}): Stage {\n const renderer = new WebGLRenderer({\n antialias: true,\n alpha: true,\n stencil: options.stencil ?? false,\n });\n renderer.setClearColor(BACKGROUND_COLOR, 1);\n renderer.toneMapping = ACESFilmicToneMapping;\n const scene = new Scene();\n const camera = new OrthographicCamera(-1, 1, 1, -1, 0.01, 1000);\n const headlight = new DirectionalLight(\"#ffffff\", HEADLIGHT_INTENSITY);\n scene.add(\n new AmbientLight(\"#ffffff\", AMBIENT_LIGHT_INTENSITY),\n headlight,\n headlight.target,\n );\n const offset = new Vector3();\n return {\n renderer,\n scene,\n camera,\n updateHeadlight() {\n const lightDistance = Math.max(camera.position.length(), 4);\n offset\n .set(...HEADLIGHT_OFFSET)\n .multiplyScalar(lightDistance)\n .applyQuaternion(camera.quaternion);\n headlight.position.copy(camera.position).add(offset);\n },\n };\n}\n","import { Fog, MOUSE, Quaternion, Vector2, Vector3 } from \"three\";\nimport { TrackballControls } from \"three/addons/controls/TrackballControls.js\";\n\nimport {\n applyPixelFrustum,\n applyViewState,\n cameraDistance,\n fitZoom,\n quaternionTuple,\n standardQuaternion,\n standardView,\n} from \"./camera.js\";\nimport { AxesGizmo } from \"./gizmo.js\";\nimport { ElementLegend, ensureViewerStyles } from \"./legend.js\";\nimport { BACKGROUND_COLOR } from \"./materials.js\";\nimport {\n createSceneModel,\n createShaderWarmup,\n type SceneModel,\n} from \"./model.js\";\nimport { createStage } from \"./stage.js\";\nimport type { ViewState } from \"./view-state.js\";\nimport type { SceneLayer } from \"../scene/build.js\";\n\nexport interface ViewerOptions {\n /** Show the element legend. Default true. */\n legend?: boolean;\n /** Show the a, b, c axes in the corner. Default true. */\n gizmo?: boolean;\n}\n\nexport interface Viewer {\n /**\n * Draw these scenes from `buildScene`, replacing what was shown. The view\n * resets to the standard orientation unless `view` is given.\n */\n setLayers(layers: SceneLayer[], view?: ViewState | null): void;\n /** Remove everything drawn. */\n clear(): void;\n /** The current view, or null while nothing is shown. */\n getView(): ViewState | null;\n /** Restore a view from `getView`, of this or another viewer. */\n setView(view: ViewState): void;\n /** Back to the standard orientation, fitted to the viewport. */\n resetView(): void;\n /** Fit the canvas to the container again; the viewer does this itself when the container resizes. */\n resize(): void;\n /** Draw a frame now, or as soon as the shaders finish compiling. */\n render(): void;\n /** Call `listener` when the user rotates or zooms. Returns a function that removes it. */\n onInteraction(listener: () => void): () => void;\n /** Remove the viewer from its container and free its WebGL resources. */\n dispose(): void;\n}\n\n/** Depth fading currently follows Pretty Lattice's default (amount and start 40%). */\nconst FOG_AMOUNT = 0.4;\nconst FOG_START = 0.4;\nconst FOG_FRONT_PADDING_RATIO = 0.4;\n/** Trackball feel currently follows Pretty Lattice's: inertia on, no panning. */\nconst ROTATE_SPEED = 2;\nconst ZOOM_SPEED = 1.2;\nconst DAMPING = 0.2;\n/**\n * TrackballControls turns the structure by pointer motion over half the\n * canvas width, so a narrow pane feels twitchier than a full window. The\n * rotate speed is scaled to the feel of a window this wide, whatever the\n * pane size.\n */\nconst REFERENCE_WIDTH_PX = 1500;\nconst MIN_SCALE = 0.2;\nconst MAX_SCALE = 5;\nconst IDLE_FRAMES = 3;\nconst MOTION_EPSILON = 1e-5;\n/** Interaction listeners run every few rendered frames, and once more when motion stops. */\nconst NOTIFY_EVERY_FRAMES = 4;\n/** Gizmo size as a share of the viewer's smaller side, within limits. */\nconst GIZMO_SIDE_RATIO = 0.35;\nconst GIZMO_MIN_PX = 110;\nconst GIZMO_MAX_PX = 180;\n\nfunction depthFog(\n model: SceneModel,\n distance: number,\n quaternion: Quaternion,\n): Fog {\n // The fog spans the structure's depth range along the standard view: it\n // starts a little in front of the farthest point and reaches full strength\n // at (back - near) / amount behind the start.\n const outward = new Vector3(0, 0, 1).applyQuaternion(quaternion);\n let front = 0;\n let back = 0;\n const corner = new Vector3();\n for (const x of [model.bounds.min.x, model.bounds.max.x]) {\n for (const y of [model.bounds.min.y, model.bounds.max.y]) {\n for (const z of [model.bounds.min.z, model.bounds.max.z]) {\n const depth = corner.set(x, y, z).dot(outward);\n front = Math.max(front, depth);\n back = Math.min(back, depth);\n }\n }\n }\n const span = Math.max(1, model.span);\n const backOffset = Math.max(0.01 * span, -back);\n const frontOffset = Math.min(backOffset, -front);\n const frontPadding = span * FOG_FRONT_PADDING_RATIO;\n const firstStart = frontOffset - frontPadding;\n const lastStart = Math.max(firstStart, backOffset - frontPadding);\n const startOffset = firstStart + (lastStart - firstStart) * FOG_START;\n const near = distance + startOffset;\n const far = near + (distance + backOffset - near) / FOG_AMOUNT;\n return new Fog(BACKGROUND_COLOR, near, far);\n}\n\n/**\n * Create a viewer inside `container`. It fills the container and follows\n * its size, so give the container a height. Adds the class `bravais-viewer`\n * to the container and one small stylesheet to the page. Its shaders start\n * compiling in the background at once, and drawing waits until they are\n * ready.\n */\nexport function createViewer(\n container: HTMLElement,\n options: ViewerOptions = {},\n): Viewer {\n const root = container.ownerDocument;\n ensureViewerStyles(root);\n container.classList.add(\"bravais-viewer\");\n\n // The stencil buffer is for the gizmo: its letters change colour over the axes.\n const { renderer, scene, camera, updateHeadlight } = createStage({\n stencil: true,\n });\n renderer.setPixelRatio(root.defaultView?.devicePixelRatio ?? 1);\n renderer.domElement.className = \"bravais-canvas\";\n container.appendChild(renderer.domElement);\n\n const legend = options.legend === false ? null : new ElementLegend(root);\n if (legend) {\n container.appendChild(legend.element);\n }\n // The axis letters are drawn in the font of the element the viewer sits in,\n // like the legend, so both match the surrounding interface.\n const fontFamily =\n root.defaultView?.getComputedStyle(container).fontFamily ?? \"sans-serif\";\n const gizmo = options.gizmo === false ? null : new AxesGizmo(fontFamily);\n\n const controls = new TrackballControls(camera, renderer.domElement);\n controls.rotateSpeed = ROTATE_SPEED;\n controls.zoomSpeed = ZOOM_SPEED;\n controls.dynamicDampingFactor = DAMPING;\n controls.staticMoving = false;\n controls.noPan = true;\n controls.mouseButtons.LEFT = MOUSE.ROTATE;\n controls.mouseButtons.MIDDLE = MOUSE.DOLLY;\n controls.mouseButtons.RIGHT = null;\n\n let model: SceneModel | null = null;\n /** Shaders still compiling in the background; drawing waits for them. */\n let compiling: Promise<unknown> | null = null;\n let distance = 4;\n let fitted = 1;\n let width = 1;\n let height = 1;\n let frame: number | null = null;\n /** True from a wake until the loop decides to stop; a wake never starts a second loop. */\n let loopActive = false;\n let idleFrames = 0;\n /** A pointer button is down on the canvas; the loop must outlive idle frames. */\n let dragging = false;\n let framesSinceNotify = 0;\n let notifyPending = false;\n const canvasSize = new Vector2();\n const lastQuaternion = new Quaternion();\n let lastZoom = 0;\n const lastTarget = new Vector3();\n const listeners = new Set<() => void>();\n\n function notify(): void {\n framesSinceNotify = 0;\n notifyPending = false;\n for (const listener of listeners) {\n listener();\n }\n }\n\n function render(): void {\n if (compiling) {\n return;\n }\n updateHeadlight();\n renderer.setViewport(0, 0, width, height);\n renderer.render(scene, camera);\n if (gizmo && model) {\n const size = Math.round(\n Math.min(\n GIZMO_MAX_PX,\n Math.max(GIZMO_MIN_PX, Math.min(width, height) * GIZMO_SIDE_RATIO),\n ),\n );\n gizmo.render(renderer, camera.quaternion, size);\n }\n }\n\n function measure(): void {\n const rect = container.getBoundingClientRect();\n width = Math.max(1, Math.round(rect.width));\n height = Math.max(1, Math.round(rect.height));\n // Resizing the canvas reallocates its drawing buffer: only on a change.\n const size = renderer.getSize(canvasSize);\n if (size.x !== width || size.y !== height) {\n renderer.setSize(width, height, false);\n }\n applyPixelFrustum(camera, width, height);\n // The trackball maps pointer motion through the canvas size it last saw.\n controls.handleResize();\n controls.rotateSpeed = ROTATE_SPEED * (width / REFERENCE_WIDTH_PX);\n }\n\n function refit(quaternion: Quaternion): void {\n if (!model) {\n return;\n }\n fitted = fitZoom(model.bounds, quaternion, width, height);\n controls.minZoom = fitted * MIN_SCALE;\n controls.maxZoom = fitted * MAX_SCALE;\n }\n\n function cameraMoved(): boolean {\n const moved =\n lastQuaternion.angleTo(camera.quaternion) > MOTION_EPSILON ||\n Math.abs(lastZoom - camera.zoom) > MOTION_EPSILON * fitted ||\n lastTarget.distanceToSquared(controls.target) > MOTION_EPSILON;\n lastQuaternion.copy(camera.quaternion);\n lastZoom = camera.zoom;\n lastTarget.copy(controls.target);\n return moved;\n }\n\n // TrackballControls needs frames while a button is down and while it\n // damps afterwards; run a loop for exactly that long.\n function tick(): void {\n frame = null;\n // update() emits \"change\" when the camera moved; the wake that handles\n // it must not schedule a second loop, hence loopActive.\n controls.update();\n if (cameraMoved()) {\n idleFrames = 0;\n render();\n framesSinceNotify += 1;\n notifyPending = true;\n if (framesSinceNotify >= NOTIFY_EVERY_FRAMES) {\n notify();\n }\n } else {\n idleFrames += 1;\n }\n if (dragging || idleFrames < IDLE_FRAMES) {\n frame = requestAnimationFrame(tick);\n return;\n }\n loopActive = false;\n if (notifyPending) {\n notify();\n }\n }\n\n function wake(): void {\n idleFrames = 0;\n if (!loopActive) {\n loopActive = true;\n frame = requestAnimationFrame(tick);\n }\n }\n\n function stopLoop(): void {\n if (frame !== null) {\n cancelAnimationFrame(frame);\n frame = null;\n }\n loopActive = false;\n }\n\n controls.addEventListener(\"start\", () => {\n dragging = true;\n wake();\n });\n controls.addEventListener(\"end\", () => {\n dragging = false;\n wake();\n });\n controls.addEventListener(\"change\", wake);\n\n /** Refit to the container's size, keeping the zoom relative to the fit. */\n function resize(): void {\n const scale = fitted > 0 ? camera.zoom / fitted : 1;\n measure();\n refit(camera.quaternion);\n camera.zoom = fitted * scale;\n camera.updateProjectionMatrix();\n render();\n }\n\n const observer =\n typeof ResizeObserver === \"undefined\" ? null : new ResizeObserver(resize);\n observer?.observe(container);\n measure();\n\n // Compile every shader now, all at once, so the driver can compile them in\n // parallel while the page loads its structure, instead of one by one at the\n // first draw with the page frozen.\n const warmup = createShaderWarmup();\n scene.add(warmup.group);\n // Structures are drawn in depth fog, which is part of their shaders.\n scene.fog = new Fog(BACKGROUND_COLOR, 1, 2);\n const warming = Promise.all([\n renderer.compileAsync(scene, camera),\n gizmo && renderer.compileAsync(gizmo.scene, gizmo.camera),\n ]);\n scene.remove(warmup.group);\n scene.fog = null;\n warmup.dispose();\n compiling = warming;\n const warmed = () => {\n if (compiling === warming) {\n compiling = null;\n render();\n }\n };\n warming.then(warmed, warmed);\n\n function applyView(view: ViewState): void {\n if (!model) {\n return;\n }\n applyViewState(camera, view, distance, model.span);\n controls.target.set(...view.target);\n refit(camera.quaternion);\n camera.zoom = fitted * view.scale;\n camera.updateProjectionMatrix();\n controls.update();\n cameraMoved();\n }\n\n const viewer: Viewer = {\n setLayers(layers, view = null) {\n viewer.clear();\n if (layers.length === 0) {\n return;\n }\n model = createSceneModel(layers);\n scene.add(model.group);\n distance = cameraDistance(model.span);\n scene.fog = depthFog(model, distance, standardQuaternion(model.cell));\n legend?.setElements(model.elements);\n gizmo?.setCell(model.cell);\n measure();\n applyView(view ?? standardView(model.cell));\n render();\n },\n clear() {\n stopLoop();\n if (model) {\n scene.remove(model.group);\n model.dispose();\n model = null;\n }\n scene.fog = null;\n legend?.setElements([]);\n renderer.setViewport(0, 0, width, height);\n renderer.clear();\n },\n getView() {\n if (!model) {\n return null;\n }\n return {\n quaternion: quaternionTuple(camera.quaternion),\n target: [controls.target.x, controls.target.y, controls.target.z],\n scale: fitted > 0 ? camera.zoom / fitted : 1,\n };\n },\n setView(view) {\n applyView(view);\n render();\n },\n resetView() {\n if (model) {\n applyView(standardView(model.cell));\n }\n render();\n notify();\n },\n resize,\n render,\n onInteraction(listener) {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n dispose() {\n viewer.clear();\n compiling = null;\n dragging = false;\n observer?.disconnect();\n controls.dispose();\n gizmo?.dispose();\n renderer.dispose();\n renderer.domElement.remove();\n legend?.element.remove();\n container.classList.remove(\"bravais-viewer\");\n },\n };\n\n return viewer;\n}\n","import { Quaternion } from \"three\";\n\nimport {\n applyPixelFrustum,\n applyViewState,\n cameraDistance,\n fitZoom,\n standardView,\n} from \"./camera.js\";\nimport {\n createSceneModel,\n createShaderWarmup,\n type SceneModel,\n} from \"./model.js\";\nimport { createStage } from \"./stage.js\";\nimport type { ViewState } from \"./view-state.js\";\nimport type { SceneLayer } from \"../scene/build.js\";\n\nexport interface ThumbnailRenderer {\n /**\n * Draw `layers` into `canvas` with `view`, or the standard view when null.\n * Models are cached by `key` and rebuilt when the layers array changes.\n */\n render(\n key: string,\n layers: SceneLayer[],\n view: ViewState | null,\n canvas: HTMLCanvasElement,\n ): void;\n /** Forget the cached model of `key`. */\n release(key: string): void;\n /** Free the shared WebGL context and every cached model. */\n dispose(): void;\n}\n\ninterface CachedModel {\n layers: SceneLayer[];\n model: SceneModel;\n}\n\n/**\n * Draw small previews into ordinary canvases from one shared WebGL context,\n * so a list of structures does not need a context for each.\n */\nexport function createThumbnailRenderer(): ThumbnailRenderer {\n const { renderer, scene, camera, updateHeadlight } = createStage();\n const cache = new Map<string, CachedModel>();\n\n // Compile every shader now, all at once, so the driver can compile them in\n // parallel instead of one by one at the first thumbnail.\n const warmup = createShaderWarmup();\n scene.add(warmup.group);\n renderer.compile(scene, camera);\n scene.remove(warmup.group);\n warmup.dispose();\n\n function modelFor(key: string, layers: SceneLayer[]): SceneModel {\n const cached = cache.get(key);\n if (cached && cached.layers === layers) {\n return cached.model;\n }\n cached?.model.dispose();\n const model = createSceneModel(layers);\n cache.set(key, { layers, model });\n return model;\n }\n\n return {\n render(key, layers, view, canvas) {\n const context = canvas.getContext(\"2d\");\n if (!context || layers.length === 0) {\n return;\n }\n const model = modelFor(key, layers);\n const width = Math.max(1, canvas.width);\n const height = Math.max(1, canvas.height);\n // Resizing a WebGL canvas recreates its drawing buffer; only do it on change.\n if (\n renderer.domElement.width !== width ||\n renderer.domElement.height !== height\n ) {\n renderer.setSize(width, height, false);\n }\n applyPixelFrustum(camera, width, height);\n const distance = cameraDistance(model.span);\n const pose = view ?? standardView(model.cell);\n applyViewState(camera, pose, distance, model.span);\n camera.zoom =\n fitZoom(\n model.bounds,\n new Quaternion(...pose.quaternion),\n width,\n height,\n ) * pose.scale;\n camera.updateProjectionMatrix();\n updateHeadlight();\n\n scene.add(model.group);\n renderer.render(scene, camera);\n scene.remove(model.group);\n context.clearRect(0, 0, width, height);\n context.drawImage(renderer.domElement, 0, 0, width, height);\n },\n release(key) {\n cache.get(key)?.model.dispose();\n cache.delete(key);\n },\n dispose() {\n for (const cached of cache.values()) {\n cached.model.dispose();\n }\n cache.clear();\n renderer.dispose();\n },\n };\n}\n","import { parseCif } from \"./cif/parser.js\";\nimport {\n CifStructureError,\n isStructureBlock,\n parseCifStructure,\n} from \"./cif/structure.js\";\nimport { resolveOperations } from \"./symmetry/resolve.js\";\nimport type { Structure } from \"./structure/types.js\";\n\nexport {\n parseCif,\n type CifBlock,\n type CifDocument,\n type CifLoop,\n} from \"./cif/parser.js\";\nexport { CifSyntaxError } from \"./cif/tokenizer.js\";\nexport {\n CifStructureError,\n parseCifStructure,\n type ParsedCifStructure,\n} from \"./cif/structure.js\";\nexport { parseSymmetryOperator } from \"./cif/symmetry-operators.js\";\nexport {\n SpaceGroupLookupError,\n ensureMoyo,\n operationsForSpaceGroup,\n} from \"./symmetry/moyo.js\";\nexport {\n SymmetryAnalysisError,\n symmetryDataset,\n type SymmetryDataset,\n type SymmetryOptions,\n} from \"./symmetry/dataset.js\";\nexport { typesetSymbol } from \"./symmetry/symbol.js\";\nexport { expandStructure } from \"./structure/expand.js\";\nexport {\n latticeFromParameters,\n latticeFromVectors,\n} from \"./structure/lattice.js\";\nexport { buildScene, structureElements } from \"./scene/build.js\";\nexport {\n createViewer,\n type Viewer,\n type ViewerOptions,\n} from \"./render/viewer.js\";\nexport {\n createThumbnailRenderer,\n type ThumbnailRenderer,\n} from \"./render/thumbnails.js\";\nexport type { SceneLayer } from \"./scene/build.js\";\nexport type { ViewState } from \"./render/view-state.js\";\nexport {\n elementColor,\n elementColorAssignments,\n ensureElementColors,\n resetElementColors,\n} from \"./render/palette.js\";\nexport type {\n BuildSceneOptions,\n SceneAtom,\n StructureScene,\n} from \"./scene/build.js\";\nexport type { Bond } from \"./structure/bonds.js\";\nexport type {\n Lattice,\n LatticeParameters,\n Mat3,\n Site,\n SpaceGroupInfo,\n Species,\n Structure,\n SymmetryOperation,\n Vec3,\n} from \"./structure/types.js\";\n\n/**\n * Read the first structure in a CIF file. Its symmetry comes from the\n * file's list of symmetry operations or, without one, from its space-group\n * symbol or number; a file with neither is read as listing every atom.\n *\n * Throws `CifSyntaxError` for text that is not valid CIF,\n * `CifStructureError` for a file without a usable structure, and\n * `SpaceGroupLookupError` for an unknown space group.\n */\nexport async function readCif(text: string): Promise<Structure> {\n const document = parseCif(text);\n const block = document.blocks.find(isStructureBlock) ?? document.blocks[0];\n if (!block) {\n throw new CifStructureError(\"The CIF has no data block.\");\n }\n const parsed = parseCifStructure(block);\n return {\n lattice: parsed.lattice,\n sites: parsed.sites,\n operations: await resolveOperations(parsed),\n spaceGroup: parsed.spaceGroup,\n };\n}\n"],"ignoreList":[20],"mappings":"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"}