diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ba8bdcc8d60643d99a0ff7e377b0fcc6d63540f..7d483b2215463bd1b8602150df5c693d0f8c41df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,12 +6,18 @@ Note that since we don't clearly distinguish between a public and private interf ## [Unreleased] +- Expose inter-bonds compute params in structure +- Improve performance of inter/intra-bonds compute - Fix defaultAttribs handling in Canvas3DContext.fromCanvas -- Add custom labels to Confal pyramids -- Improve naming of some internal types in Confal pyramids extension coordinate -- Add example mmCIF file with categories necessary to display Confal pyramids -- Change the lookup logic of NtC steps from residues +- Confal pyramids extension improvements + - Add custom labels to Confal pyramids + - Improve naming of some internal types in Confal pyramids extension coordinate + - Add example mmCIF file with categories necessary to display Confal pyramids + - Change the lookup logic of NtC steps from residues - Add support for download of gzipped files +- Don't filter IndexPairBonds by element-based rules in MOL/SDF and MOL2 (without symmetry) models +- Fix Glycam Saccharide Names used by default +- Prefer WebGL1 for more Safari versions to avoid broken GPU surfaces rendering - Add ``fov`` (Field of View) Canvas3D parameter - Add ``sceneRadiusFactor`` Canvas3D parameter - Add background pass (skybox, image, horizontal/radial gradient) diff --git a/package-lock.json b/package-lock.json index 574466fb80e296362a8edd3ffa07466f61cfabde..c576a0d1a68232eecbf5d39f757c3d21893a3af5 100644 Binary files a/package-lock.json and b/package-lock.json differ diff --git a/package.json b/package.json index 4ef0af12c3397cc1b2ba736997436aab1d76f45e..7e827994e88b9caab3066949355685d559f866b9 100644 --- a/package.json +++ b/package.json @@ -75,7 +75,9 @@ "node_modules", "lib" ], - "testURL": "http://localhost/", + "testEnvironmentOptions": { + "url": "http://localhost/" + }, "testRegex": "\\.spec\\.ts$" }, "author": "Mol* Contributors", @@ -91,30 +93,30 @@ ], "license": "MIT", "devDependencies": { - "@graphql-codegen/add": "^3.2.0", - "@graphql-codegen/cli": "^2.9.1", - "@graphql-codegen/time": "^3.2.0", - "@graphql-codegen/typescript": "^2.7.2", - "@graphql-codegen/typescript-graphql-files-modules": "^2.2.0", - "@graphql-codegen/typescript-graphql-request": "^4.5.2", - "@graphql-codegen/typescript-operations": "^2.5.2", + "@graphql-codegen/add": "^3.2.1", + "@graphql-codegen/cli": "^2.11.6", + "@graphql-codegen/time": "^3.2.1", + "@graphql-codegen/typescript": "^2.7.3", + "@graphql-codegen/typescript-graphql-files-modules": "^2.2.1", + "@graphql-codegen/typescript-graphql-request": "^4.5.3", + "@graphql-codegen/typescript-operations": "^2.5.3", "@types/cors": "^2.8.12", "@types/gl": "^4.1.1", - "@types/jest": "^28.1.6", - "@types/react": "^18.0.15", + "@types/jest": "^28.1.7", + "@types/react": "^18.0.17", "@types/react-dom": "^18.0.6", - "@typescript-eslint/eslint-plugin": "^5.30.7", - "@typescript-eslint/parser": "^5.30.7", + "@typescript-eslint/eslint-plugin": "^5.33.1", + "@typescript-eslint/parser": "^5.33.1", "benchmark": "^2.1.4", "concurrently": "^7.3.0", "cpx2": "^4.2.0", "crypto-browserify": "^3.12.0", "css-loader": "^6.7.1", - "eslint": "^8.20.0", + "eslint": "^8.22.0", "extra-watch-webpack-plugin": "^1.0.3", "file-loader": "^6.2.0", "fs-extra": "^10.1.0", - "graphql": "^16.5.0", + "graphql": "^16.6.0", "http-server": "^14.1.1", "jest": "^28.1.3", "mini-css-extract-plugin": "^2.6.1", @@ -122,14 +124,14 @@ "raw-loader": "^4.0.2", "react": "^18.2.0", "react-dom": "^18.2.0", - "sass": "^1.54.0", + "sass": "^1.54.4", "sass-loader": "^13.0.2", - "simple-git": "^3.10.0", + "simple-git": "^3.12.0", "stream-browserify": "^3.0.0", "style-loader": "^3.3.1", - "ts-jest": "^28.0.7", + "ts-jest": "^28.0.8", "typescript": "^4.7.4", - "webpack": "^5.73.0", + "webpack": "^5.74.0", "webpack-cli": "^4.10.0" }, "dependencies": { @@ -137,7 +139,7 @@ "@types/benchmark": "^2.1.1", "@types/compression": "1.7.2", "@types/express": "^4.17.13", - "@types/node": "^16.11.45", + "@types/node": "^16.11.49", "@types/node-fetch": "^2.6.2", "@types/swagger-ui-dist": "3.30.1", "argparse": "^2.0.1", @@ -150,7 +152,7 @@ "immutable": "^4.1.0", "node-fetch": "^2.6.7", "rxjs": "^7.5.6", - "swagger-ui-dist": "^4.13.0", + "swagger-ui-dist": "^4.14.0", "tslib": "^2.4.0", "util.promisify": "^1.1.1", "xhr2": "^0.2.1" diff --git a/src/mol-gl/shader/chunks/color-frag-params.glsl.ts b/src/mol-gl/shader/chunks/color-frag-params.glsl.ts index 4027046f94f18175e895cf440b82aa6623e470ae..b5802f3688be2243b93853b1556226235d1af0bb 100644 --- a/src/mol-gl/shader/chunks/color-frag-params.glsl.ts +++ b/src/mol-gl/shader/chunks/color-frag-params.glsl.ts @@ -36,7 +36,6 @@ uniform float uBumpiness; varying vec4 vColor; #endif #else - // avoid flat until EXT_provoking_vertex is supported #ifdef requiredDrawBuffers flat in vec4 vObject; flat in vec4 vInstance; diff --git a/src/mol-gl/shader/chunks/color-vert-params.glsl.ts b/src/mol-gl/shader/chunks/color-vert-params.glsl.ts index 0b4c5c45f230aa15a3e846936d23596ae0312ee6..30a830ad73651982363871cbb3fe8b1fcc20d431 100644 --- a/src/mol-gl/shader/chunks/color-vert-params.glsl.ts +++ b/src/mol-gl/shader/chunks/color-vert-params.glsl.ts @@ -64,7 +64,6 @@ uniform float uBumpiness; varying vec4 vColor; #endif #else - // avoid flat until EXT_provoking_vertex is supported #ifdef requiredDrawBuffers flat out vec4 vObject; flat out vec4 vInstance; diff --git a/src/mol-gl/shader/chunks/common-frag-params.glsl.ts b/src/mol-gl/shader/chunks/common-frag-params.glsl.ts index 5722cb8a2c3ed77e340bcf3354fee9b771f5fdf5..3d694f3e2601c37631439f9e2d5a7f640aa3315b 100644 --- a/src/mol-gl/shader/chunks/common-frag-params.glsl.ts +++ b/src/mol-gl/shader/chunks/common-frag-params.glsl.ts @@ -17,7 +17,6 @@ uniform int uMarkingType; #if __VERSION__ == 100 || defined(dClippingType_instance) || !defined(dVaryingGroup) varying float vClipping; #else - // avoid flat until EXT_provoking_vertex is supported flat in float vClipping; #endif #endif @@ -36,7 +35,6 @@ uniform int uMarkingType; #if __VERSION__ == 100 || defined(dMarkerType_instance) || !defined(dVaryingGroup) varying float vMarker; #else - // avoid flat until EXT_provoking_vertex is supported flat in float vMarker; #endif #endif diff --git a/src/mol-gl/shader/chunks/common-vert-params.glsl.ts b/src/mol-gl/shader/chunks/common-vert-params.glsl.ts index 2e391530c42fd9340e6bf3af92c1d379bccfe787..10a7c27ed698a4cd83be892f31bbd34dcc78e5ef 100644 --- a/src/mol-gl/shader/chunks/common-vert-params.glsl.ts +++ b/src/mol-gl/shader/chunks/common-vert-params.glsl.ts @@ -24,7 +24,6 @@ uniform int uPickType; #if __VERSION__ == 100 || defined(dClippingType_instance) || !defined(dVaryingGroup) varying float vClipping; #else - // avoid flat until EXT_provoking_vertex is supported flat out float vClipping; #endif #endif @@ -37,7 +36,6 @@ uniform int uPickType; #if __VERSION__ == 100 || defined(dMarkerType_instance) || !defined(dVaryingGroup) varying float vMarker; #else - // avoid flat until EXT_provoking_vertex is supported flat out float vMarker; #endif #endif diff --git a/src/mol-math/geometry/primitives/box3d.ts b/src/mol-math/geometry/primitives/box3d.ts index d701ae18085f5b45feb9f29cb7cdd5682e9104f9..fff4923615107fddbbe9be77febc27b070182889 100644 --- a/src/mol-math/geometry/primitives/box3d.ts +++ b/src/mol-math/geometry/primitives/box3d.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author David Sehnal <david.sehnal@gmail.com> * @author Alexander Rose <alexander.rose@weirdbyte.de> @@ -124,11 +124,19 @@ namespace Box3D { } export function containsVec3(box: Box3D, v: Vec3) { - return ( + return !( v[0] < box.min[0] || v[0] > box.max[0] || v[1] < box.min[1] || v[1] > box.max[1] || v[2] < box.min[2] || v[2] > box.max[2] - ) ? false : true; + ); + } + + export function overlaps(a: Box3D, b: Box3D) { + return !( + a.max[0] < b.min[0] || a.min[0] > b.max[0] || + a.max[1] < b.min[1] || a.min[1] > b.max[1] || + a.max[2] < b.min[2] || a.min[2] > b.max[2] + ); } } diff --git a/src/mol-model-formats/structure/mol.ts b/src/mol-model-formats/structure/mol.ts index 942f24a597cd0c8bbb18c564d571536e9310f49f..f32849f738b1bb31f4a9aca641bbe2a55adf1e91 100644 --- a/src/mol-model-formats/structure/mol.ts +++ b/src/mol-model-formats/structure/mol.ts @@ -80,7 +80,10 @@ export async function getMolModels(mol: MolFile, format: ModelFormat<any> | unde const indexA = Column.ofIntArray(Column.mapToArray(bonds.atomIdxA, x => x - 1, Int32Array)); const indexB = Column.ofIntArray(Column.mapToArray(bonds.atomIdxB, x => x - 1, Int32Array)); const order = Column.asArrayColumn(bonds.order, Int32Array); - const pairBonds = IndexPairBonds.fromData({ pairs: { indexA, indexB, order }, count: atoms.count }); + const pairBonds = IndexPairBonds.fromData( + { pairs: { indexA, indexB, order }, count: atoms.count }, + { maxDistance: Infinity } + ); IndexPairBonds.Provider.set(models.representative, pairBonds); } diff --git a/src/mol-model-formats/structure/mol2.ts b/src/mol-model-formats/structure/mol2.ts index ac8b4e75c1119a06afa11a91d18709f888129418..19723a6fd1987e77bb382bafb2621f98e95bfbeb 100644 --- a/src/mol-model-formats/structure/mol2.ts +++ b/src/mol-model-formats/structure/mol2.ts @@ -113,7 +113,10 @@ async function getModels(mol2: Mol2File, ctx: RuntimeContext) { return BondType.Flag.Covalent; } }, Int8Array)); - const pairBonds = IndexPairBonds.fromData({ pairs: { key, indexA, indexB, order, flag }, count: atoms.count }); + const pairBonds = IndexPairBonds.fromData( + { pairs: { key, indexA, indexB, order, flag }, count: atoms.count }, + { maxDistance: crysin ? -1 : Infinity } + ); const first = _models.representative; IndexPairBonds.Provider.set(first, pairBonds); diff --git a/src/mol-model/structure/structure/carbohydrates/constants.ts b/src/mol-model/structure/structure/carbohydrates/constants.ts index bc9e49e728e386db75c92dfd118ee3e875d3de9d..aeb5fd82a1c2515becfcf439750f9fb7ccb35d8d 100644 --- a/src/mol-model/structure/structure/carbohydrates/constants.ts +++ b/src/mol-model/structure/structure/carbohydrates/constants.ts @@ -386,16 +386,6 @@ const DefaultSaccharideCompIdMap = (function () { map.set(charmm[j], saccharide); } } - - const glycam = GlycamSaccharideNames[saccharide.abbr]; - if (glycam) { - for (let j = 0, jl = glycam.length; j < jl; ++j) { - // On collision, use PDB name as default. - if (!map.has(glycam[j])) { - map.set(glycam[j], saccharide); - } - } - } } SaccharideNames.forEach(name => { if (!map.has(name)) map.set(name, UnknownSaccharideComponent); diff --git a/src/mol-model/structure/structure/structure.ts b/src/mol-model/structure/structure/structure.ts index 81f84f447fa5c17191641c2d8c3b81594bcdc08d..3c2dfdc6322d5895bf82dbd5c6689c78b58d4bae 100644 --- a/src/mol-model/structure/structure/structure.ts +++ b/src/mol-model/structure/structure/structure.ts @@ -23,7 +23,7 @@ import { Carbohydrates } from './carbohydrates/data'; import { computeCarbohydrates } from './carbohydrates/compute'; import { Vec3, Mat4 } from '../../../mol-math/linear-algebra'; import { idFactory } from '../../../mol-util/id-factory'; -import { GridLookup3D } from '../../../mol-math/geometry'; +import { Box3D, GridLookup3D } from '../../../mol-math/geometry'; import { UUID } from '../../../mol-util'; import { CustomProperties } from '../../custom-property'; import { AtomicHierarchy } from '../model/properties/atomic'; @@ -43,6 +43,8 @@ type State = { lookup3d?: StructureLookup3D, interUnitBonds?: InterUnitBonds, dynamicBonds: boolean, + interBondsValidUnit?: (unit: Unit) => boolean, + interBondsValidUnitPair?: (structure: Structure, unitA: Unit, unitB: Unit) => boolean, unitSymmetryGroups?: ReadonlyArray<Unit.SymmetryGroup>, unitSymmetryGroupsIndexMap?: IntMap<number>, unitsSortedByVolume?: ReadonlyArray<Unit>; @@ -241,6 +243,8 @@ class Structure { this.state.interUnitBonds = computeInterUnitBonds(this, { ignoreWater: !this.dynamicBonds, ignoreIon: !this.dynamicBonds, + validUnit: this.state.interBondsValidUnit, + validUnitPair: this.state.interBondsValidUnitPair, }); } return this.state.interUnitBonds; @@ -250,6 +254,14 @@ class Structure { return this.state.dynamicBonds; } + get interBondsValidUnit() { + return this.state.interBondsValidUnit; + } + + get interBondsValidUnitPair() { + return this.state.interBondsValidUnitPair; + } + get unitSymmetryGroups(): ReadonlyArray<Unit.SymmetryGroup> { if (this.state.unitSymmetryGroups) return this.state.unitSymmetryGroups; this.state.unitSymmetryGroups = StructureSymmetry.computeTransformGroups(this); @@ -380,7 +392,12 @@ class Structure { parent: parent?.remapModel(m), label: this.label, interUnitBonds: dynamicBonds ? undefined : interUnitBonds, - dynamicBonds + dynamicBonds, + interBondsValidUnit: this.state.interBondsValidUnit, + interBondsValidUnitPair: this.state.interBondsValidUnitPair, + coordinateSystem: this.state.coordinateSystem, + masterModel: this.state.masterModel, + representativeModel: this.state.representativeModel, }); } @@ -428,7 +445,6 @@ class Structure { function cmpUnits(units: ArrayLike<Unit>, i: number, j: number) { return units[i].id - units[j].id; - } function getModels(s: Structure) { @@ -634,6 +650,8 @@ namespace Structure { * Also enables calculation of inter-unit bonds in water molecules. */ dynamicBonds?: boolean, + interBondsValidUnit?: (unit: Unit) => boolean, + interBondsValidUnitPair?: (structure: Structure, unitA: Unit, unitB: Unit) => boolean, coordinateSystem?: SymmetryOperator label?: string /** Master model for structures of a protein model and multiple ligand models */ @@ -722,6 +740,12 @@ namespace Structure { if (props.parent) state.parent = props.parent.parent || props.parent; if (props.interUnitBonds) state.interUnitBonds = props.interUnitBonds; + if (props.interBondsValidUnit) state.interBondsValidUnit = props.interBondsValidUnit; + else if (props.parent) state.interBondsValidUnit = props.parent.interBondsValidUnit; + + if (props.interBondsValidUnitPair) state.interBondsValidUnitPair = props.interBondsValidUnitPair; + else if (props.parent) state.interBondsValidUnitPair = props.parent.interBondsValidUnitPair; + if (props.dynamicBonds) state.dynamicBonds = props.dynamicBonds; else if (props.parent) state.dynamicBonds = props.parent.dynamicBonds; @@ -1180,7 +1204,7 @@ namespace Structure { /** * Iterate over all unit pairs of a structure and invokes callback for valid units - * and unit pairs if within a max distance. + * and unit pairs if their boundaries are within a max distance. */ export function eachUnitPair(structure: Structure, callback: (unitA: Unit, unitB: Unit) => void, props: EachUnitPairProps) { const { maxRadius, validUnit, validUnitPair } = props; @@ -1188,15 +1212,19 @@ namespace Structure { const lookup = structure.lookup3d; const imageCenter = Vec3(); + const bbox = Box3D(); + const rvec = Vec3.create(maxRadius, maxRadius, maxRadius); for (const unit of structure.units) { if (!validUnit(unit)) continue; const bs = unit.boundary.sphere; + Box3D.expand(bbox, unit.boundary.box, rvec); Vec3.transformMat4(imageCenter, bs.center, unit.conformation.operator.matrix); const closeUnits = lookup.findUnitIndices(imageCenter[0], imageCenter[1], imageCenter[2], bs.radius + maxRadius); for (let i = 0; i < closeUnits.count; i++) { const other = structure.units[closeUnits.indices[i]]; + if (!Box3D.overlaps(bbox, other.boundary.box)) continue; if (!validUnit(other) || unit.id >= other.id || !validUnitPair(unit, other)) continue; if (other.elements.length >= unit.elements.length) callback(unit, other); diff --git a/src/mol-model/structure/structure/unit/bonds/inter-compute.ts b/src/mol-model/structure/structure/unit/bonds/inter-compute.ts index 535a6d09bca596e00119faffd2cf2fcefafd9344..ba0327c3fc2ffaecbc25b4abe2ed8b434a40373d 100644 --- a/src/mol-model/structure/structure/unit/bonds/inter-compute.ts +++ b/src/mol-model/structure/structure/unit/bonds/inter-compute.ts @@ -21,12 +21,18 @@ import { StructConn } from '../../../../../mol-model-formats/structure/property/ import { equalEps } from '../../../../../mol-math/linear-algebra/3d/common'; import { Model } from '../../../model'; +// avoiding namespace lookup improved performance in Chrome (Aug 2020) +const v3distance = Vec3.distance; +const v3set = Vec3.set; +const v3squaredDistance = Vec3.squaredDistance; +const v3transformMat4 = Vec3.transformMat4; + const tmpDistVecA = Vec3(); const tmpDistVecB = Vec3(); function getDistance(unitA: Unit.Atomic, indexA: ElementIndex, unitB: Unit.Atomic, indexB: ElementIndex) { unitA.conformation.position(indexA, tmpDistVecA); unitB.conformation.position(indexB, tmpDistVecB); - return Vec3.distance(tmpDistVecA, tmpDistVecB); + return v3distance(tmpDistVecA, tmpDistVecB); } const _imageTransform = Mat4(); @@ -68,22 +74,22 @@ function findPairBonds(unitA: Unit.Atomic, unitB: Unit.Atomic, props: BondComput for (let _aI = 0 as StructureElement.UnitIndex; _aI < atomCount; _aI++) { const aI = atomsA[_aI]; - Vec3.set(_imageA, xA[aI], yA[aI], zA[aI]); - if (isNotIdentity) Vec3.transformMat4(_imageA, _imageA, imageTransform); - if (Vec3.squaredDistance(_imageA, bCenter) > testDistanceSq) continue; + v3set(_imageA, xA[aI], yA[aI], zA[aI]); + if (isNotIdentity) v3transformMat4(_imageA, _imageA, imageTransform); + if (v3squaredDistance(_imageA, bCenter) > testDistanceSq) continue; if (!props.forceCompute && indexPairs) { const { maxDistance } = indexPairs; const { offset, b, edgeProps: { order, distance, flag } } = indexPairs.bonds; const srcA = sourceIndex.value(aI); + const aeI = getElementIdx(type_symbolA.value(aI)); for (let i = offset[srcA], il = offset[srcA + 1]; i < il; ++i) { const bI = invertedIndex![b[i]]; const _bI = SortedArray.indexOf(unitB.elements, bI) as StructureElement.UnitIndex; if (_bI < 0) continue; - const aeI = getElementIdx(type_symbolA.value(aI)); const beI = getElementIdx(type_symbolA.value(bI)); const d = distance[i]; @@ -191,6 +197,7 @@ function findPairBonds(unitA: Unit.Atomic, unitB: Unit.Atomic, props: BondComput } export interface InterBondComputationProps extends BondComputationProps { + validUnit: (unit: Unit) => boolean validUnitPair: (structure: Structure, unitA: Unit, unitB: Unit) => boolean ignoreWater: boolean ignoreIon: boolean @@ -215,7 +222,7 @@ function findBonds(structure: Structure, props: InterBondComputationProps) { findPairBonds(unitA as Unit.Atomic, unitB as Unit.Atomic, props, builder); }, { maxRadius: props.maxRadius, - validUnit: (unit: Unit) => Unit.isAtomic(unit), + validUnit: (unit: Unit) => props.validUnit(unit), validUnitPair: (unitA: Unit, unitB: Unit) => props.validUnitPair(structure, unitA, unitB) }); @@ -226,6 +233,7 @@ function computeInterUnitBonds(structure: Structure, props?: Partial<InterBondCo const p = { ...DefaultInterBondComputationProps, ...props }; return findBonds(structure, { ...p, + validUnit: (props && props.validUnit) || (u => Unit.isAtomic(u)), validUnitPair: (props && props.validUnitPair) || ((s, a, b) => { const mtA = a.model.atomicHierarchy.derived.residue.moleculeType; const mtB = b.model.atomicHierarchy.derived.residue.moleculeType; diff --git a/src/mol-model/structure/structure/unit/bonds/intra-compute.ts b/src/mol-model/structure/structure/unit/bonds/intra-compute.ts index 105347895b27c9080d7e5daeca079c975cbb6261..a4be859321bf19f44ea5c7902fff9d373e7565d8 100644 --- a/src/mol-model/structure/structure/unit/bonds/intra-compute.ts +++ b/src/mol-model/structure/structure/unit/bonds/intra-compute.ts @@ -21,6 +21,9 @@ import { ElementIndex } from '../../../model/indexing'; import { equalEps } from '../../../../../mol-math/linear-algebra/3d/common'; import { Model } from '../../../model/model'; +// avoiding namespace lookup improved performance in Chrome (Aug 2020) +const v3distance = Vec3.distance; + function getGraph(atomA: StructureElement.UnitIndex[], atomB: StructureElement.UnitIndex[], _order: number[], _flags: number[], atomCount: number, canRemap: boolean): IntraUnitBonds { const builder = new IntAdjacencyGraph.EdgeBuilder(atomCount, atomA, atomB); const flags = new Uint16Array(builder.slotCount); @@ -39,7 +42,7 @@ const tmpDistVecB = Vec3(); function getDistance(unit: Unit.Atomic, indexA: ElementIndex, indexB: ElementIndex) { unit.conformation.position(indexA, tmpDistVecA); unit.conformation.position(indexB, tmpDistVecB); - return Vec3.distance(tmpDistVecA, tmpDistVecB); + return v3distance(tmpDistVecA, tmpDistVecB); } const __structConnAdded = new Set<StructureElement.UnitIndex>(); diff --git a/src/mol-plugin/features.ts b/src/mol-plugin/features.ts index ad04c71c6287bbae2ca4f8439632503403ea3b71..df2c7f2e3371cfd5a82ce5c71dfc7230e98838f7 100644 --- a/src/mol-plugin/features.ts +++ b/src/mol-plugin/features.ts @@ -1,7 +1,8 @@ /** - * Copyright (c) 2021 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2021-2022 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author David Sehnal <david.sehnal@gmail.com> + * @author Alexander Rose <alexander.rose@weirdbyte.de> */ export const PluginFeatureDetection = { @@ -13,7 +14,11 @@ export const PluginFeatureDetection = { const unpportedSafariVersions = [ 'Version/15.1 Safari', 'Version/15.2 Safari', - 'Version/15.3 Safari' + 'Version/15.3 Safari', + // the following 'only' break GPU surfaces + 'Version/15.4 Safari', + 'Version/15.5 Safari', + 'Version/16.0 Safari', ]; if (unpportedSafariVersions.some(v => navigator.userAgent.indexOf(v) > 0)) { return true;