mirror of
https://github.com/molstar/molstar.git
synced 2026-06-04 21:34:23 +08:00
Compare commits
897 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
93a3eba66d | ||
|
|
41b8584fb7 | ||
|
|
523b17dfde | ||
|
|
c47b4d6078 | ||
|
|
b94073b96f | ||
|
|
905eb3ec2f | ||
|
|
3ae72e5c60 | ||
|
|
055dfd4946 | ||
|
|
2601d2ba63 | ||
|
|
340806d774 | ||
|
|
18ad848de2 | ||
|
|
9de8334af5 | ||
|
|
57580a5e6b | ||
|
|
7da4a85459 | ||
|
|
b7c380fd90 | ||
|
|
bcd304d058 | ||
|
|
fd50a8f8e0 | ||
|
|
27f251e8e4 | ||
|
|
8d2a44983e | ||
|
|
f806ac1444 | ||
|
|
63a585d88a | ||
|
|
a4b5a16fcd | ||
|
|
86bf859a63 | ||
|
|
1b8117d3f1 | ||
|
|
400e2bbc45 | ||
|
|
e2e26c7e9c | ||
|
|
5ca9020cbf | ||
|
|
ea4c411d5c | ||
|
|
ba7e3fe827 | ||
|
|
8f20571a17 | ||
|
|
c25a4247e6 | ||
|
|
1071d3d8ba | ||
|
|
e8dc046570 | ||
|
|
27f9c2aa67 | ||
|
|
a4962231c8 | ||
|
|
8833f29ce5 | ||
|
|
40b6038380 | ||
|
|
59e16e0187 | ||
|
|
ca5a50bd53 | ||
|
|
bccf54fabe | ||
|
|
57a790544c | ||
|
|
df0669598c | ||
|
|
fb912036af | ||
|
|
9efb5cd126 | ||
|
|
08a56ad6ab | ||
|
|
2c2bd6adda | ||
|
|
b010298acb | ||
|
|
7033a1e0b2 | ||
|
|
8ad617acdf | ||
|
|
31ab6aa93e | ||
|
|
0a2dbe14d7 | ||
|
|
89d305aaa1 | ||
|
|
dbb6b90fbc | ||
|
|
c57150f09f | ||
|
|
0b30c7344b | ||
|
|
d7ad5a6e9f | ||
|
|
86a74d1cc2 | ||
|
|
3f0f24cb99 | ||
|
|
b8ddc142ea | ||
|
|
cccaa48589 | ||
|
|
3ad355ad40 | ||
|
|
918186eb24 | ||
|
|
db4742cebf | ||
|
|
19fec3bbc1 | ||
|
|
7d6c77b3bd | ||
|
|
dfcc4e400d | ||
|
|
c9734d83a2 | ||
|
|
93943cc27b | ||
|
|
25836b2de0 | ||
|
|
c6874c922d | ||
|
|
0937c84f47 | ||
|
|
6a7f892d60 | ||
|
|
b4cd2d0a11 | ||
|
|
2067f02830 | ||
|
|
6d86ada6b4 | ||
|
|
f656cf09b7 | ||
|
|
a891b4c551 | ||
|
|
ded844c936 | ||
|
|
44b36637fd | ||
|
|
f590bd0f0a | ||
|
|
9474c80673 | ||
|
|
7b48d691c8 | ||
|
|
b03146852f | ||
|
|
9345f3584a | ||
|
|
4d058aa1a8 | ||
|
|
e7da6092aa | ||
|
|
94f6b864b0 | ||
|
|
6e90447511 | ||
|
|
b91030c4bd | ||
|
|
31819dbf16 | ||
|
|
1665dd7d00 | ||
|
|
9716fecdb9 | ||
|
|
684fd2d237 | ||
|
|
9432b9a7a7 | ||
|
|
3a37c95c17 | ||
|
|
6040b99c19 | ||
|
|
83bef0f0e7 | ||
|
|
95bb3a1f81 | ||
|
|
be677f47cb | ||
|
|
43bf69d09c | ||
|
|
b6cc626431 | ||
|
|
931fdfca9b | ||
|
|
1c10db5656 | ||
|
|
c4ccd8758f | ||
|
|
6c99c575bc | ||
|
|
ae2493b6e3 | ||
|
|
bcd50c294f | ||
|
|
9c0024dbab | ||
|
|
c15b3603c0 | ||
|
|
70647ba972 | ||
|
|
8d19357845 | ||
|
|
8e9817c4d1 | ||
|
|
b16147b88c | ||
|
|
9840d8f816 | ||
|
|
d892ccab4c | ||
|
|
65f88b3293 | ||
|
|
9e6e5eb795 | ||
|
|
2f755efeec | ||
|
|
012e616ec4 | ||
|
|
007d0e7608 | ||
|
|
bf313073b9 | ||
|
|
293928f3de | ||
|
|
2404f398b6 | ||
|
|
43ff6e24c8 | ||
|
|
9e62112366 | ||
|
|
026d6fc618 | ||
|
|
95fcd942dc | ||
|
|
805481db14 | ||
|
|
39175df025 | ||
|
|
cd0f451f6b | ||
|
|
fe1aa1a9bf | ||
|
|
fcfb6e6d5a | ||
|
|
c548c94575 | ||
|
|
2d45f4a77c | ||
|
|
a5ae887842 | ||
|
|
e4b53cdc6a | ||
|
|
c53940e67e | ||
|
|
6d61745f0f | ||
|
|
46d86d93b0 | ||
|
|
11772b64fb | ||
|
|
dbc8ab00c6 | ||
|
|
015fad4371 | ||
|
|
71a484586f | ||
|
|
f0b06ee746 | ||
|
|
b0694b886b | ||
|
|
eaf47b3169 | ||
|
|
ad9046fcf2 | ||
|
|
eabe4d46bc | ||
|
|
003c5f8fb7 | ||
|
|
68748a4a94 | ||
|
|
9bd6b8195d | ||
|
|
05848b651c | ||
|
|
0a8f87dd9f | ||
|
|
925aaa701d | ||
|
|
5be599bad4 | ||
|
|
e22ce53e65 | ||
|
|
4c49431027 | ||
|
|
4192d82ef3 | ||
|
|
ce220737f2 | ||
|
|
eeb7cd2c52 | ||
|
|
748111beb2 | ||
|
|
1f7d41c653 | ||
|
|
b9430ff387 | ||
|
|
6591bab035 | ||
|
|
4da446aec2 | ||
|
|
25c170e36d | ||
|
|
eba18d1dce | ||
|
|
2c87d01a5e | ||
|
|
e41a2baa32 | ||
|
|
c297017749 | ||
|
|
9a0fc1faa6 | ||
|
|
424513f23c | ||
|
|
895d672589 | ||
|
|
0c6253ed16 | ||
|
|
da97cd20aa | ||
|
|
ca6d73e048 | ||
|
|
88b79deefa | ||
|
|
d756e2e195 | ||
|
|
2ce126a8f5 | ||
|
|
01e95dada0 | ||
|
|
1c024f0943 | ||
|
|
5901e3d6a1 | ||
|
|
0cfe1cec66 | ||
|
|
c1930e4142 | ||
|
|
71375d908f | ||
|
|
728b87d4e4 | ||
|
|
9c17698a8a | ||
|
|
625381c446 | ||
|
|
da949a245e | ||
|
|
7000bdd15d | ||
|
|
adcf6a6fa8 | ||
|
|
b70af9f178 | ||
|
|
e5bdcfd781 | ||
|
|
6049705224 | ||
|
|
273d50d403 | ||
|
|
333ea724d6 | ||
|
|
e96dca91ef | ||
|
|
41a0048f64 | ||
|
|
5e97b05bd2 | ||
|
|
ebc6b2acce | ||
|
|
8372408d9c | ||
|
|
2c6822f5ab | ||
|
|
7efbf46e7a | ||
|
|
b6d6a518d3 | ||
|
|
2d690268f9 | ||
|
|
e0c794b557 | ||
|
|
f91f445631 | ||
|
|
1cc367c8d8 | ||
|
|
8c6969206d | ||
|
|
c0479e3d46 | ||
|
|
22e92b38c6 | ||
|
|
5741709023 | ||
|
|
2265fc02cc | ||
|
|
64180bef36 | ||
|
|
be3caef6e9 | ||
|
|
71a2f71866 | ||
|
|
3c6152054e | ||
|
|
080d649bf9 | ||
|
|
2852b09c77 | ||
|
|
5e53467541 | ||
|
|
42dc579ddb | ||
|
|
890c758585 | ||
|
|
e6c77069df | ||
|
|
e7ecf98f13 | ||
|
|
70ad32f62d | ||
|
|
69fe452055 | ||
|
|
9edeb84f4e | ||
|
|
e1db3114c8 | ||
|
|
8724badcb6 | ||
|
|
d413f74526 | ||
|
|
6752108c5f | ||
|
|
9302fdadb9 | ||
|
|
f7048c7535 | ||
|
|
3252a3f0f3 | ||
|
|
6805194d48 | ||
|
|
acf0dceb47 | ||
|
|
c53f500da6 | ||
|
|
defc04278e | ||
|
|
aa4d5e78a7 | ||
|
|
df3a432afd | ||
|
|
1b339d18cc | ||
|
|
c4650c91a8 | ||
|
|
e3c4f19563 | ||
|
|
85780a5d6a | ||
|
|
aab70e2ff0 | ||
|
|
e859f497f1 | ||
|
|
6a9fed56f3 | ||
|
|
d7c2505852 | ||
|
|
754dfeab91 | ||
|
|
d3b02df5b9 | ||
|
|
3d95ed729c | ||
|
|
9cbb4414e0 | ||
|
|
79fcfe50bc | ||
|
|
216d16456b | ||
|
|
822aaa99b0 | ||
|
|
2c683ab77d | ||
|
|
2ef5af6881 | ||
|
|
36f18be042 | ||
|
|
f093a3ab37 | ||
|
|
74cd42117b | ||
|
|
bb4a4e6102 | ||
|
|
24a3167f9b | ||
|
|
214e1c20ca | ||
|
|
33cab6ddad | ||
|
|
f4b2826bc7 | ||
|
|
ebaa9f2e56 | ||
|
|
812b75a034 | ||
|
|
3b02a5f5ec | ||
|
|
657d2eb1c5 | ||
|
|
25d87dd14d | ||
|
|
d2605e6e3d | ||
|
|
b21ebe0f55 | ||
|
|
2693fe8b7e | ||
|
|
45279a6520 | ||
|
|
22f9b1a7a1 | ||
|
|
8325a58e25 | ||
|
|
0acc508a8f | ||
|
|
2af0cd9d6f | ||
|
|
304858fcba | ||
|
|
ade027911c | ||
|
|
a97e647f7a | ||
|
|
008bed0233 | ||
|
|
bb4c04f3b9 | ||
|
|
62997e5972 | ||
|
|
a20e7bb40d | ||
|
|
2acfac4c85 | ||
|
|
a1a9d87a54 | ||
|
|
1ab71cc487 | ||
|
|
a8b19f5f3c | ||
|
|
4661a4a5f0 | ||
|
|
2c40abc808 | ||
|
|
10d7bcf4c0 | ||
|
|
5f8e4e6913 | ||
|
|
94fa9f124a | ||
|
|
3e70251f38 | ||
|
|
66ed6cfa94 | ||
|
|
d82b6e8d0d | ||
|
|
5a5f6867b9 | ||
|
|
5cd5fc09f5 | ||
|
|
17528d5ca2 | ||
|
|
e658a11947 | ||
|
|
4ac6f5c202 | ||
|
|
5726515707 | ||
|
|
f2ee7d1470 | ||
|
|
4140412e06 | ||
|
|
44ed142521 | ||
|
|
1ae0bbc150 | ||
|
|
8213611293 | ||
|
|
2697634a9f | ||
|
|
d7ba9e0c61 | ||
|
|
c99c4342b7 | ||
|
|
f410e27d1a | ||
|
|
e6d54412cf | ||
|
|
6238684819 | ||
|
|
ea07cd89de | ||
|
|
a7330f40d7 | ||
|
|
92c55ffe35 | ||
|
|
c21ba08fc7 | ||
|
|
ba3a716900 | ||
|
|
3133dc1543 | ||
|
|
fe2541f9e8 | ||
|
|
27af73f97f | ||
|
|
e9a442ca6e | ||
|
|
e86e282bb4 | ||
|
|
213506dff0 | ||
|
|
bc7aa7c9aa | ||
|
|
b234bf8890 | ||
|
|
36b4dcf7a8 | ||
|
|
0e843c20cc | ||
|
|
ecaf19c5fb | ||
|
|
f024aeef2c | ||
|
|
9d9985f117 | ||
|
|
a0f7349ef6 | ||
|
|
01407427d2 | ||
|
|
3dee03d9b6 | ||
|
|
737f6593be | ||
|
|
068e10dd40 | ||
|
|
c1ba5248b0 | ||
|
|
4af0f22ac0 | ||
|
|
25a67e1176 | ||
|
|
a8fcd501d6 | ||
|
|
573ee92889 | ||
|
|
2558d6fada | ||
|
|
2cf3f8d62b | ||
|
|
589d89b0d5 | ||
|
|
7cc7b77460 | ||
|
|
e8a9995bef | ||
|
|
74ff283e00 | ||
|
|
1ecb960b82 | ||
|
|
387d59f97b | ||
|
|
d993082f24 | ||
|
|
5eaa73d56d | ||
|
|
b9428fd3cd | ||
|
|
97d180b79d | ||
|
|
25bd915ea5 | ||
|
|
f8fdffdc44 | ||
|
|
d11aa6ea77 | ||
|
|
fc3c7997ea | ||
|
|
b3aecf8de4 | ||
|
|
f3581e62ef | ||
|
|
88e7fe508f | ||
|
|
98049ed02d | ||
|
|
194092ed67 | ||
|
|
e96157c890 | ||
|
|
a028c1ef42 | ||
|
|
ad2b5e687d | ||
|
|
8ba19f0be4 | ||
|
|
bccc68f6df | ||
|
|
026a05d03d | ||
|
|
2b4741c8ee | ||
|
|
7960ee06d4 | ||
|
|
f73f5af131 | ||
|
|
3123110aa4 | ||
|
|
154063638d | ||
|
|
a720b98365 | ||
|
|
d4a2937e0b | ||
|
|
b0ca7ffbb7 | ||
|
|
c42b738abe | ||
|
|
ab0d0fec53 | ||
|
|
8d96131962 | ||
|
|
95bbcd8b24 | ||
|
|
a21f5c2c23 | ||
|
|
94b7b1281c | ||
|
|
16dba586df | ||
|
|
72b761f959 | ||
|
|
943d81cbf9 | ||
|
|
2ecdc0eafa | ||
|
|
dccfd35c7a | ||
|
|
9e81a4f7a6 | ||
|
|
6f6cc73ce9 | ||
|
|
c248ae11bf | ||
|
|
742be03901 | ||
|
|
00009ef198 | ||
|
|
1cb617524d | ||
|
|
e2e348240b | ||
|
|
b54908492c | ||
|
|
33172862bd | ||
|
|
c5f2767efc | ||
|
|
66f5a81a5d | ||
|
|
9e90e11bfc | ||
|
|
ab372a89d6 | ||
|
|
ea612c3acb | ||
|
|
a1308645e5 | ||
|
|
c6506d515f | ||
|
|
794b705184 | ||
|
|
66264abe50 | ||
|
|
7d0f84ff72 | ||
|
|
31495ab02a | ||
|
|
853ad5c916 | ||
|
|
51fc525215 | ||
|
|
92d1c446d4 | ||
|
|
f2a0ff448b | ||
|
|
0ec096a980 | ||
|
|
44a5b83c1c | ||
|
|
46c5184d40 | ||
|
|
7c46306929 | ||
|
|
d7fe32d000 | ||
|
|
d7beb288c3 | ||
|
|
fb5da1b4d0 | ||
|
|
d89e254555 | ||
|
|
99e11317e1 | ||
|
|
3dc6c4452d | ||
|
|
3a627a878b | ||
|
|
6f9fed180d | ||
|
|
5ecd176f20 | ||
|
|
dff3837df6 | ||
|
|
e42eb31b73 | ||
|
|
721c117309 | ||
|
|
216715b2d5 | ||
|
|
412d4d5bcd | ||
|
|
2734d5754a | ||
|
|
c10f9d8c78 | ||
|
|
7140135cbe | ||
|
|
b5969945b4 | ||
|
|
7f5b3bc16c | ||
|
|
5cf7b6624b | ||
|
|
56225b337d | ||
|
|
79b6ad6f48 | ||
|
|
d0df53dd02 | ||
|
|
3b97bfd9b6 | ||
|
|
9b12623131 | ||
|
|
425370d63e | ||
|
|
1666c89222 | ||
|
|
a7dd4fc555 | ||
|
|
9f1760fbf2 | ||
|
|
d7fb040b77 | ||
|
|
2d7c1bcea2 | ||
|
|
a08c434f35 | ||
|
|
45d402bb9f | ||
|
|
4556544043 | ||
|
|
921d700761 | ||
|
|
9605783f41 | ||
|
|
f23329dc68 | ||
|
|
5f4ac6b2c0 | ||
|
|
f0c2961e95 | ||
|
|
2bdaa565b4 | ||
|
|
ab2bcde794 | ||
|
|
0b9674e14c | ||
|
|
07cbeb524e | ||
|
|
8ff75ea2ab | ||
|
|
6f5db94b2f | ||
|
|
2637957141 | ||
|
|
c1bb6f3987 | ||
|
|
d8df904951 | ||
|
|
a7ca7c922d | ||
|
|
f257992a5a | ||
|
|
62f9f6077d | ||
|
|
e4edb67f62 | ||
|
|
185ccf5ca6 | ||
|
|
bdd1805620 | ||
|
|
29f2722851 | ||
|
|
b38f8b08da | ||
|
|
6d02889f84 | ||
|
|
b864634f1d | ||
|
|
248662b95c | ||
|
|
0eb28bd89e | ||
|
|
e466bf9ba9 | ||
|
|
a14c4faefd | ||
|
|
b87a7f069e | ||
|
|
674a56e2f3 | ||
|
|
521d8cb4f8 | ||
|
|
bd1d85e927 | ||
|
|
4d62b928f8 | ||
|
|
014c9607d9 | ||
|
|
98ef24fc9e | ||
|
|
c04580377b | ||
|
|
a492b38368 | ||
|
|
518f21531e | ||
|
|
36fd40ee09 | ||
|
|
6b8c604762 | ||
|
|
c10382d1fb | ||
|
|
0e968ae59c | ||
|
|
1286a9e560 | ||
|
|
bf73712781 | ||
|
|
53922db113 | ||
|
|
799037d657 | ||
|
|
5cb7a3cc8e | ||
|
|
c14cbb258d | ||
|
|
8a860497f1 | ||
|
|
77d4d0007c | ||
|
|
005824eb24 | ||
|
|
259e04a6ce | ||
|
|
966bc14c67 | ||
|
|
f752b7e155 | ||
|
|
255b8b9ac3 | ||
|
|
15c4fb3c01 | ||
|
|
9fba0c08b2 | ||
|
|
f08dd0255d | ||
|
|
42d969bbeb | ||
|
|
fdc33e44dc | ||
|
|
b0aa889a0a | ||
|
|
4d7bd53231 | ||
|
|
c11cf665c9 | ||
|
|
a4b09d3a0c | ||
|
|
6e488b0f80 | ||
|
|
2cef723483 | ||
|
|
6164281a50 | ||
|
|
c74a014ab7 | ||
|
|
4bbf1dc8aa | ||
|
|
6e53621e01 | ||
|
|
2db7171e2a | ||
|
|
edfc094952 | ||
|
|
b3e1e2900b | ||
|
|
ba2bc206cc | ||
|
|
1e498d535a | ||
|
|
6ed969cd1b | ||
|
|
27bb4f4bca | ||
|
|
6ce2139272 | ||
|
|
856eff5127 | ||
|
|
13cf6613a6 | ||
|
|
52b141c4fa | ||
|
|
701844ca7c | ||
|
|
bcc572bd18 | ||
|
|
c5bb13e295 | ||
|
|
34c8257848 | ||
|
|
fcbf39c935 | ||
|
|
46c8150b2b | ||
|
|
af1a864daa | ||
|
|
3babd9399a | ||
|
|
e57564486f | ||
|
|
464a91ac29 | ||
|
|
4b58ce94ee | ||
|
|
16b0374eac | ||
|
|
67e63dccb4 | ||
|
|
2cc600cc52 | ||
|
|
27fa50a5de | ||
|
|
1e323f18f7 | ||
|
|
2685b2b77d | ||
|
|
d71b47a515 | ||
|
|
88cc720dd2 | ||
|
|
201433cc91 | ||
|
|
8582303491 | ||
|
|
655c3edadd | ||
|
|
a4323a4bd8 | ||
|
|
1b5a7d9546 | ||
|
|
f165cc4629 | ||
|
|
cb499ce42e | ||
|
|
db247d6fbd | ||
|
|
23701bf8e8 | ||
|
|
2e1f2e7eec | ||
|
|
fdb3ff54f1 | ||
|
|
d5fd56718d | ||
|
|
0698ac6dd5 | ||
|
|
825b59ab1e | ||
|
|
3086d1a5c8 | ||
|
|
138796862b | ||
|
|
1b236f1ae5 | ||
|
|
b6c2e25395 | ||
|
|
b7816986aa | ||
|
|
437c70a75a | ||
|
|
de85e0fbae | ||
|
|
8f7fda4919 | ||
|
|
470ccd333f | ||
|
|
2b6d067b0e | ||
|
|
0b928888a5 | ||
|
|
28edfd44cb | ||
|
|
3391c6de07 | ||
|
|
12b7951700 | ||
|
|
c527b59782 | ||
|
|
3bbbac66c7 | ||
|
|
c0980bf18a | ||
|
|
45eab19493 | ||
|
|
1e2a5a5bfd | ||
|
|
45edfa8014 | ||
|
|
899203c855 | ||
|
|
ef823b066b | ||
|
|
33dc2015df | ||
|
|
fcf5ea420b | ||
|
|
8d97327f8d | ||
|
|
cbc0e857fc | ||
|
|
01ce306405 | ||
|
|
a39a49e884 | ||
|
|
887a39dde9 | ||
|
|
abc7ebba3e | ||
|
|
73d593907e | ||
|
|
84a45fabdc | ||
|
|
0dc05e1138 | ||
|
|
dd11cacae4 | ||
|
|
ea17902aa6 | ||
|
|
b503259758 | ||
|
|
1e98741e16 | ||
|
|
f879519700 | ||
|
|
c6e175e5da | ||
|
|
add75bf9c9 | ||
|
|
57cbcd5fbf | ||
|
|
50a820b0ae | ||
|
|
0a33936e06 | ||
|
|
2abbb843f8 | ||
|
|
32179f31c2 | ||
|
|
7291025e09 | ||
|
|
0cb2c3621b | ||
|
|
86da258280 | ||
|
|
477a80d1ca | ||
|
|
86b68018a9 | ||
|
|
da095d6ef9 | ||
|
|
dc304b9e08 | ||
|
|
c905fa17c4 | ||
|
|
a06c64e8e0 | ||
|
|
f5441290dd | ||
|
|
9f23124317 | ||
|
|
8299cd638c | ||
|
|
50cb08e74d | ||
|
|
89552652ba | ||
|
|
37ce577813 | ||
|
|
4d9a003141 | ||
|
|
6f0311a53f | ||
|
|
bfd2d6b055 | ||
|
|
3072e60709 | ||
|
|
62ed8d10e3 | ||
|
|
13d3c34864 | ||
|
|
cac433efca | ||
|
|
b25ffe7151 | ||
|
|
31074dc74c | ||
|
|
c98c01a076 | ||
|
|
8966fc9396 | ||
|
|
fdbdc551e8 | ||
|
|
bb232ac3a4 | ||
|
|
735c25ef8d | ||
|
|
298043313a | ||
|
|
77cd181b91 | ||
|
|
b5bee042e8 | ||
|
|
4faf17ddc7 | ||
|
|
28774b2277 | ||
|
|
6a7444f44e | ||
|
|
15bfa8416a | ||
|
|
e6895ec833 | ||
|
|
2099ad728a | ||
|
|
72ae3fae65 | ||
|
|
bb5ad78681 | ||
|
|
f10e88612f | ||
|
|
a2e582d4a9 | ||
|
|
572874f4ae | ||
|
|
b9c0347497 | ||
|
|
089148198f | ||
|
|
6fc04c3294 | ||
|
|
dc55577e22 | ||
|
|
f7ba7c0511 | ||
|
|
ed5374fab9 | ||
|
|
9a04b4f0df | ||
|
|
9350e539b6 | ||
|
|
c38377af46 | ||
|
|
9804febd95 | ||
|
|
7936dc1840 | ||
|
|
a033a8be36 | ||
|
|
4b84c6dcba | ||
|
|
309d792fdb | ||
|
|
c437254680 | ||
|
|
6fbf7c7a22 | ||
|
|
86a7520b90 | ||
|
|
cd10043447 | ||
|
|
146e95cb23 | ||
|
|
13b1e5d59c | ||
|
|
ae3efa53d6 | ||
|
|
2e67fbe870 | ||
|
|
56df6f82a7 | ||
|
|
fdd874b7a6 | ||
|
|
f142c3ef1b | ||
|
|
978b53e7d8 | ||
|
|
2f3197479d | ||
|
|
6536d0ab91 | ||
|
|
3bee224e7d | ||
|
|
3e63137977 | ||
|
|
38d6bc6c27 | ||
|
|
fafe22d56b | ||
|
|
a6a92bcf91 | ||
|
|
82c681f445 | ||
|
|
fbbd58b4db | ||
|
|
2dc13f082c | ||
|
|
ab5eb5993d | ||
|
|
2384003f5d | ||
|
|
3675c0afe0 | ||
|
|
d9bae488e9 | ||
|
|
e31e5321ba | ||
|
|
8c7f8b8a56 | ||
|
|
e4dfb5148c | ||
|
|
39e2591b60 | ||
|
|
f8a5237024 | ||
|
|
6c2d5b9da7 | ||
|
|
e128d85356 | ||
|
|
08a929bb2f | ||
|
|
5a54b3ef66 | ||
|
|
a0c897547a | ||
|
|
89ce8394fd | ||
|
|
ea0331e95c | ||
|
|
9f220b55c2 | ||
|
|
acf248d58f | ||
|
|
c83b859766 | ||
|
|
33a2564893 | ||
|
|
d409c4f5ea | ||
|
|
ab61e31230 | ||
|
|
ae9c2dd9d8 | ||
|
|
c17edb4928 | ||
|
|
528377eb47 | ||
|
|
c9819369d0 | ||
|
|
cdbbbfa6dd | ||
|
|
a1e31c79e9 | ||
|
|
e027fe46c1 | ||
|
|
05c4006e9d | ||
|
|
191ea65c9d | ||
|
|
3c1ee16376 | ||
|
|
9ac34ee13b | ||
|
|
6778452d07 | ||
|
|
7e01af1e0d | ||
|
|
85469cbf28 | ||
|
|
299bdc72cd | ||
|
|
ae9f879139 | ||
|
|
b50d83d6ea | ||
|
|
2d99d8a1d0 | ||
|
|
ea00cca1c8 | ||
|
|
27c3b4e698 | ||
|
|
52942e7021 | ||
|
|
5904f694b5 | ||
|
|
92c0b82784 | ||
|
|
e1226fa384 | ||
|
|
ac2f7d1c38 | ||
|
|
ae1742f68e | ||
|
|
04e2da86fd | ||
|
|
510182ff60 | ||
|
|
4e1da19bdd | ||
|
|
a3eae15446 | ||
|
|
4334f4d1fa | ||
|
|
e33ed54121 | ||
|
|
ae8f037192 | ||
|
|
01271941dd | ||
|
|
7f8be5b8c6 | ||
|
|
2ab6e4b2e7 | ||
|
|
aa22840b12 | ||
|
|
c1e33fac94 | ||
|
|
a7336095ca | ||
|
|
4a88546181 | ||
|
|
edbc70cf6e | ||
|
|
c22ad2910c | ||
|
|
28a2b52e3c | ||
|
|
449d572ed5 | ||
|
|
470227af43 | ||
|
|
a0ccf46939 | ||
|
|
0ce8931fc5 | ||
|
|
3ddb29fc6f | ||
|
|
1a0c65df21 | ||
|
|
daad1923ea | ||
|
|
f34f879cf1 | ||
|
|
f47b76c8af | ||
|
|
6ee9eb8b60 | ||
|
|
915703a46d | ||
|
|
61c3c19ae3 | ||
|
|
6da9557531 | ||
|
|
29e6d69d21 | ||
|
|
6b2b87e6c5 | ||
|
|
5299d5c0c4 | ||
|
|
7bab95f4cc | ||
|
|
35e78ce638 | ||
|
|
3abbcb6949 | ||
|
|
c3fc893ad0 | ||
|
|
80415a2771 | ||
|
|
bfef69e2e4 | ||
|
|
a265a579be | ||
|
|
c2af1b0b22 | ||
|
|
b739876726 | ||
|
|
56851cc328 | ||
|
|
b719568555 | ||
|
|
f842f19912 | ||
|
|
d6b0dd910c | ||
|
|
395eb8e8d0 | ||
|
|
e4376c6737 | ||
|
|
6f23fcba8a | ||
|
|
7d19bfdb9b | ||
|
|
6e4065f779 | ||
|
|
c42a68b560 | ||
|
|
c86d913b83 | ||
|
|
0f6fa5fe15 | ||
|
|
f664cb02b1 | ||
|
|
00a53de6e2 | ||
|
|
b1ce5c158e | ||
|
|
26826b61f9 | ||
|
|
f44f954a76 | ||
|
|
78aae8a2b4 | ||
|
|
92267d3264 | ||
|
|
73ed45564e | ||
|
|
8bc2ebbeff | ||
|
|
5306d5d15a | ||
|
|
3c3fb461c8 | ||
|
|
62b3281282 | ||
|
|
e85fadf15b | ||
|
|
a8a84e1dbf | ||
|
|
153599ef89 | ||
|
|
b67eda7cb5 | ||
|
|
8b431c50be | ||
|
|
e195b048a1 | ||
|
|
ae5bb81b27 | ||
|
|
8c04c57bc5 | ||
|
|
ec46a444f1 | ||
|
|
559e0326b6 | ||
|
|
82b93bc2a8 | ||
|
|
62f940bc48 | ||
|
|
4e0be8e7b4 | ||
|
|
128502edf0 | ||
|
|
aad4d4a86c | ||
|
|
9bc7e27243 | ||
|
|
a5111356c1 | ||
|
|
9b11f7ffde | ||
|
|
93ce6d2807 | ||
|
|
5c9d5d3a3d | ||
|
|
f40307db39 | ||
|
|
4e6000fa6c | ||
|
|
26e5817bf2 | ||
|
|
8469be80d0 | ||
|
|
029edc95c8 | ||
|
|
dd9aaf055f | ||
|
|
fcfb2d940c | ||
|
|
f5b5109d0f | ||
|
|
ca99c800f1 | ||
|
|
dbd5570370 | ||
|
|
3f805c7a82 | ||
|
|
12c71dc5ba | ||
|
|
2fe3a926aa | ||
|
|
60c2096575 | ||
|
|
f4e9df5e4d | ||
|
|
c304b82772 | ||
|
|
9edd171350 | ||
|
|
f7d1bd7c04 | ||
|
|
7422c255ab | ||
|
|
5497215784 | ||
|
|
577bf1c77c | ||
|
|
c9bddccaf7 | ||
|
|
ac292f9267 | ||
|
|
f0b8d75b10 | ||
|
|
0dacbcb3bc | ||
|
|
0789241ea3 | ||
|
|
ddb0799dc4 | ||
|
|
cbfa341fa3 | ||
|
|
1c19bd90df | ||
|
|
300e5c8985 | ||
|
|
0861a78db6 | ||
|
|
a8e403ad85 | ||
|
|
4e350496b2 | ||
|
|
dd21ddcc80 | ||
|
|
a88121f779 | ||
|
|
1ab91d1979 | ||
|
|
267788388d | ||
|
|
43c0333be3 | ||
|
|
3b90a269b0 | ||
|
|
4aa5e1d7fc | ||
|
|
679db48938 | ||
|
|
2f96b42df7 | ||
|
|
dd6f3bd76e | ||
|
|
f1b7e478c7 | ||
|
|
416442aa27 | ||
|
|
a5f65b6e6f | ||
|
|
938ac0cc8f | ||
|
|
7dacf60478 | ||
|
|
9cdb8a3a92 | ||
|
|
242982e661 | ||
|
|
6da20a6989 | ||
|
|
f27b651230 | ||
|
|
7c818c0cc9 | ||
|
|
e7d7ba26b0 | ||
|
|
7e64121059 | ||
|
|
894bba1d3a | ||
|
|
d9db775fe8 | ||
|
|
a7fbc7b4c4 | ||
|
|
c0596298d6 | ||
|
|
8f32dde599 | ||
|
|
4d8f00900d | ||
|
|
9f3c617945 | ||
|
|
f920188cdc | ||
|
|
68b73503bb | ||
|
|
e776138ecd | ||
|
|
bbacd5a9dd | ||
|
|
289ecef1d7 | ||
|
|
52fc3ef750 | ||
|
|
dffe40ac1d | ||
|
|
f834e39ce4 | ||
|
|
2bc9c6fb57 | ||
|
|
6e42c11f5e | ||
|
|
d48feeaa94 | ||
|
|
fd0ca75fc1 | ||
|
|
a270dcb5f5 |
@@ -1,4 +0,0 @@
|
||||
node_modules/*
|
||||
build/*
|
||||
docs/site/*
|
||||
lib/*
|
||||
122
.eslintrc.json
122
.eslintrc.json
@@ -1,122 +0,0 @@
|
||||
{
|
||||
"env": {
|
||||
"browser": true,
|
||||
"node": true
|
||||
},
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2018,
|
||||
"sourceType": "module",
|
||||
"ecmaFeatures": {
|
||||
"impliedStrict": true
|
||||
}
|
||||
},
|
||||
"rules": {
|
||||
"indent": "off",
|
||||
"arrow-parens": [
|
||||
"off",
|
||||
"as-needed"
|
||||
],
|
||||
"brace-style": "off",
|
||||
"comma-spacing": "off",
|
||||
"space-infix-ops": "off",
|
||||
"comma-dangle": "off",
|
||||
"eqeqeq": [
|
||||
"error",
|
||||
"smart"
|
||||
],
|
||||
"import/order": "off",
|
||||
"no-eval": "warn",
|
||||
"no-new-wrappers": "warn",
|
||||
"no-trailing-spaces": "error",
|
||||
"no-unsafe-finally": "warn",
|
||||
"no-var": "error",
|
||||
"spaced-comment": "error",
|
||||
"semi": "warn",
|
||||
"no-restricted-syntax": [
|
||||
"error",
|
||||
{
|
||||
"selector": "ExportDefaultDeclaration",
|
||||
"message": "Default exports are not allowed"
|
||||
}
|
||||
],
|
||||
"no-throw-literal": "error",
|
||||
"key-spacing": "error",
|
||||
"object-curly-spacing": ["error", "always"],
|
||||
"array-bracket-spacing": "error",
|
||||
"space-in-parens": "error",
|
||||
"computed-property-spacing": "error",
|
||||
"prefer-const": ["error", {
|
||||
"destructuring": "all",
|
||||
"ignoreReadBeforeAssign": false
|
||||
}],
|
||||
"space-before-function-paren": "off",
|
||||
"func-call-spacing": "off",
|
||||
"no-multi-spaces": "error",
|
||||
"block-spacing": "error",
|
||||
"keyword-spacing": "off",
|
||||
"space-before-blocks": "error",
|
||||
"semi-spacing": "error",
|
||||
"no-constant-binary-expression": "error"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["**/*.ts", "**/*.tsx"],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"project": ["tsconfig.json", "tsconfig.commonjs.json"],
|
||||
"sourceType": "module"
|
||||
},
|
||||
"plugins": [
|
||||
"@typescript-eslint"
|
||||
],
|
||||
"rules": {
|
||||
"@typescript-eslint/ban-types": "off",
|
||||
"@typescript-eslint/class-name-casing": "off",
|
||||
"@typescript-eslint/indent": [
|
||||
"error",
|
||||
4
|
||||
],
|
||||
"@typescript-eslint/member-delimiter-style": [
|
||||
"off",
|
||||
{
|
||||
"multiline": {
|
||||
"delimiter": "none",
|
||||
"requireLast": true
|
||||
},
|
||||
"singleline": {
|
||||
"delimiter": "semi",
|
||||
"requireLast": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"@typescript-eslint/prefer-namespace-keyword": "warn",
|
||||
"@typescript-eslint/quotes": [
|
||||
"error",
|
||||
"single",
|
||||
{
|
||||
"avoidEscape": true,
|
||||
"allowTemplateLiterals": true
|
||||
}
|
||||
],
|
||||
"@typescript-eslint/semi": [
|
||||
"off",
|
||||
null
|
||||
],
|
||||
"@typescript-eslint/type-annotation-spacing": "error",
|
||||
"@typescript-eslint/brace-style": [
|
||||
"error",
|
||||
"1tbs", { "allowSingleLine": true }
|
||||
],
|
||||
"@typescript-eslint/comma-spacing": "error",
|
||||
"@typescript-eslint/space-infix-ops": "error",
|
||||
"@typescript-eslint/space-before-function-paren": ["error", {
|
||||
"anonymous": "always",
|
||||
"named": "never",
|
||||
"asyncArrow": "always"
|
||||
}],
|
||||
"@typescript-eslint/func-call-spacing": ["error"],
|
||||
"@typescript-eslint/keyword-spacing": ["error"]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
14
.git-blame-ignore-revs
Normal file
14
.git-blame-ignore-revs
Normal file
@@ -0,0 +1,14 @@
|
||||
# added semicolons to linting rules
|
||||
fb0634a0f4aab3764b7e6368e38d8dea7615e591
|
||||
|
||||
# new linting rules (no default exports, no named tuples)
|
||||
6c5224f33e9de20fe9967a82536c269bacf29738
|
||||
|
||||
# lint: add space-in-parens rule
|
||||
1d21787e7ea1971817813c008351541e4640c261
|
||||
|
||||
# lint: add object-curly-spacing rule
|
||||
b31302ba3ad4ab7f98aedd500b762be642374ff0
|
||||
|
||||
# fix eslint warnings
|
||||
3b1513adc0048dc4879f1d70874b3e56aaffd10e
|
||||
2
.github/workflows/node.yml
vendored
2
.github/workflows/node.yml
vendored
@@ -13,7 +13,7 @@ jobs:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 18
|
||||
node-version: 20
|
||||
- run: npm ci
|
||||
- run: sudo apt-get install xvfb
|
||||
- name: Lint
|
||||
|
||||
7
.gitignore
vendored
7
.gitignore
vendored
@@ -1,4 +1,5 @@
|
||||
build/
|
||||
deploy/
|
||||
lib/
|
||||
docs/site/
|
||||
|
||||
@@ -11,4 +12,8 @@ tsconfig.commonjs.tsbuildinfo
|
||||
*.sublime-workspace
|
||||
.idea
|
||||
|
||||
.DS_Store
|
||||
.DS_Store
|
||||
tmp/
|
||||
|
||||
dev.pem
|
||||
dev-key.pem
|
||||
|
||||
5
.vscode/settings.json
vendored
5
.vscode/settings.json
vendored
@@ -6,9 +6,4 @@
|
||||
"*.vert.ts": "glsl",
|
||||
"*.gql.ts": "graphql"
|
||||
},
|
||||
"eslint.options": {
|
||||
"overrideConfig": {
|
||||
"ignorePatterns": ["webpack.config.js", "scripts/*"],
|
||||
},
|
||||
}
|
||||
}
|
||||
546
CHANGELOG.md
546
CHANGELOG.md
@@ -4,6 +4,548 @@ All notable changes to this project will be documented in this file, following t
|
||||
Note that since we don't clearly distinguish between a public and private interfaces there will be changes in non-major versions that are potentially breaking. If we make breaking changes to less used interfaces we will highlight it in here.
|
||||
|
||||
## [Unreleased]
|
||||
- Fix exported image artifacts on transparent background with emissive, bloom, or antialiasing
|
||||
- Fix cel-shaded ambient color being stripped to luminance (now uses full RGB, matching the classic lighting path)
|
||||
- Fix empty transforms default in `ShapeFromPly`
|
||||
- Use morton order for spheres in dot visual with lod-levels
|
||||
- Add `Camera.changed` event and rotation/translation setter/getter
|
||||
- Add `instanceGranularity: 'auto'` as a memory guard
|
||||
- Honor `instanceGranularity` in `Visual.getLoci`
|
||||
- Add mesoscale representation preset
|
||||
- Add presets option to `ObjectList` param definition
|
||||
- Fix memory leak in `State.dispose()` not invoking transformer `dispose` callbacks for live cells
|
||||
- Fix bugs in ModelServer surroundingLigands endpoint, resulting in omitWater not honored
|
||||
- Fix `Volume` and `Isosurface` getBoundingSphere ignoring instances
|
||||
- Fix aromatic ring detection not accounting for hybridization
|
||||
- Add axis param to camera spin/rock animation
|
||||
- Fix SSAO half/quarter resolution textures for multi-scale
|
||||
- Non-covalent interactions: water bridge support
|
||||
|
||||
## [v5.9.0] - 2026-05-03
|
||||
- Fix edge case when `PluginSpec.animations` is empty
|
||||
- Add 8K UHD option to `ViewportScreenshotHelper`
|
||||
- Handle MRC files with empty length header fields
|
||||
- Handle CCD bonds with Deuterium atoms
|
||||
- [Breaking] ComponentBond.Entry.map now returns ComponentBond.Pairs
|
||||
- Fix volume slice marking performance regression
|
||||
- Add GPU procedural animation (wiggle & tumble)
|
||||
- Per-vertex wiggle via fbm noise (position & group mode)
|
||||
- Per-instance tumble via fbm noise (rotation + translation)
|
||||
- `Wiggle` theme layer for data-driven per-group wiggle
|
||||
- `enableAnimation` Canvas3D param for global toggle
|
||||
- Add `AnimateTime` built-in for, e.g., exporting procedural animation
|
||||
- Add Procedural Animation panels
|
||||
- Viewer: structure dynamics & uncertainty
|
||||
- Mesoscale Explorer: entity dynamics
|
||||
- Fix `GraphQLClient` missing required headers
|
||||
- [Breaking] Use Record instead of Array for headers (assets & data-source utils)
|
||||
|
||||
## [v5.8.0] - 2026-04-03
|
||||
- Dependencies: remove `utils.promisify`, `node-fetch` (#1797)
|
||||
- Fix circular dependency which causes crash in bundlers (#1791)
|
||||
- Add `putty` as a mol-view-spec representation.
|
||||
- Fix detecting sidechain-only structures as coarse-grained (#1420)
|
||||
- Fix clip-object transform due to missing axis normalization
|
||||
- Sequence alignment: Fix return type & improve scoring for unknown residues
|
||||
- Use PDB SEQRES block to show unresolved residues in Sequence toolbar
|
||||
- Canvas3D debug-helpers
|
||||
- [Breaking] Move helpers to an extension as a PluginBehavior (params are no longer part of Canvas3D)
|
||||
- Add helpers for clip-object, direct-volume, image, mesh
|
||||
- Fix StructureComponent node update throwing error when substructure empty
|
||||
- CSS: Avoid tooltip box flickering when hovering something under it
|
||||
- Volume slice visual
|
||||
- Fix support for volume instances
|
||||
- Fix plane mode: ensure normalized & correctly oriented
|
||||
- MolViewSpec
|
||||
- Add `VolumeStreamingExtension` (`molstar_volume_streaming` custom property)
|
||||
- Fix focusing empty selections
|
||||
- Avoid re-calculating static model properties for trajectories
|
||||
|
||||
## [v5.7.0] - 2026-02-28
|
||||
- Text label improvements
|
||||
- Improve label background vertical centering
|
||||
- Handle label depth variant for correct transparent background
|
||||
- Draw border under text using fragment depth to prevent overlap on adjacent characters
|
||||
- Clamp border width to avoid exceeding SDF range
|
||||
- Increase font atlas quality (2x font size multiplier)
|
||||
- TM-align performance improvements (#1745)
|
||||
- Disable transparent outline close to opaque elements
|
||||
- Add axis param to trackball spin & rock animation
|
||||
- Color smoothing fixes (#1747)
|
||||
- Use correct instance for non instance-type
|
||||
- Never transform for non instance-type
|
||||
- Add extra radius to gaussian surface boundingsphere
|
||||
- MolViewSpec
|
||||
- Add `MVSData.toMVSX` function and `mvs-mvsj-to-mvsx.js` CLI utility
|
||||
- [Breaking] Add PQR file format support (#157)
|
||||
- Replace `isPdbqt` with `variant` param in `TrajectoryFromPDB`
|
||||
- Add `CustomVolumeProperty` (like for models and structures)
|
||||
- Geometry export
|
||||
- Fix missing `usePalette` support
|
||||
- Fix vertex-based coloring for non-mesh geometries
|
||||
- Support line-strips
|
||||
- Support vertex-based sizing
|
||||
- Support memory efficient line-strips in Lines geometry,
|
||||
- Add `StripLinesBuilder`
|
||||
- Add `computeFrenetFrames` helper
|
||||
- Streamlines support
|
||||
- Add basic calculation method
|
||||
- Add custom-volume-property
|
||||
- Add representation with lines and tube-mesh visuals
|
||||
- Fix `TextCtrl` always moving cursor to end position
|
||||
- Add `vertex` and `vertexInstance` granularity support for size themes
|
||||
- Add `transform` and `domain` parameters to volume-value size theme
|
||||
- Fix parsing of single charge type_symbols (e.g., N+) in cif-core
|
||||
- Detect metal-coordination when parsing pdb
|
||||
- Handle additional elements in `guessElementSymbol*` (As, Li, Ga)
|
||||
- Add more element-pair thresholds for bonding (Ag-S, CoSb, Ga-F)
|
||||
- Add `metalCoordination` style param (dashed, solid) for bonds
|
||||
- Fix `unitSymmetryGroups` for representations with `includeParent` enabled
|
||||
- Add `convexHull` helper
|
||||
- Add `Structure.coordination` sites
|
||||
- Add `Polyhedron` representation showing coordination sites
|
||||
- Guard against `xr-spatial-tracking` blocked in `Permissions-Policy`
|
||||
|
||||
## [v5.6.1] - 2026-01-23
|
||||
- Disable occlusion culling in `ImagePass` (#1758)
|
||||
- MolViewSpec
|
||||
- Fix `MVSAnnotationStructureComponent` not updating properly when parent structure changes
|
||||
|
||||
## [v5.6.0] - 2026-01-18
|
||||
- Handle Hex codes that are submitted with alpha channels by ignoring the alpha channel (#1746)
|
||||
- Only show "already registered transformer" warnings in non-production builds
|
||||
- Fix `label_seq_id` assignment in PDB parser to use 1-based linear indexing (#1730) if:
|
||||
- when insertion codes are present
|
||||
- `SEQRES` records are present
|
||||
- Viewer app
|
||||
- Add `action: 'focus'` support to `Viewer.structureInteractivity`
|
||||
- Add `viewportFocusBehavior: 'secondary-zoom'`
|
||||
- MolViewSpec
|
||||
- Validation treats `undefined` same as missing value
|
||||
- Increase default size of `carbohydrate` representation
|
||||
- `color_from_uri` and `color_from_source` take `selector` parameter
|
||||
- Add `keepCameraOrientation` option for loading functions
|
||||
- `label_from_*` and `tooltip_from_*` take `text_format` parameter
|
||||
- `label_from_*` take `group_by_fields` parameter
|
||||
- Tweak Gaussian Density smoothness default range (less artefacts)
|
||||
- Support `includeParent` for Gaussian Surface (disables GPU support)
|
||||
- Support floodfill before surface extraction (`off`, `interior`, `exterior`)
|
||||
- For Isosurface, Molecular Surface, Gaussian Surface
|
||||
- Fix `to_mmCIF` writing duplicate categories under certain conditions (#1738)
|
||||
- Add stable random number generator (PCG)
|
||||
- ME grayscale colors; dot offset; SSAO hemisphere vectors
|
||||
- Use blue noise for SSAO hemisphere vectors
|
||||
- Fix SSAO darkening when sampling background/offscreen pixels
|
||||
- Adding structure wireframe visuals on molecular and gaussian surfaces
|
||||
- Fix caching of `__srcIndexArray__`
|
||||
- Prevent self-occlusion on quaternary amine
|
||||
- Fix outline postprocessing artifacts (black bands) on membrane layers at grazing view angles in Illustrative mode (#1749)
|
||||
- Remove fence from `Canvas3D.render` to not interfer with `requestAnimationFrame`
|
||||
- Fix boundingSphere reuse in structure visuals (was triggering extra calculation)
|
||||
- Use PDB seqres record to deduce entity information
|
||||
- Add lipid components names used in amber ff
|
||||
|
||||
## [v5.5.0] - 2025-12-22
|
||||
- Viewer app
|
||||
- Move viewer extensions, options, and presets to a separate file
|
||||
- Add `molstar.lib` export providing access to a wide range of functionality previously not available from the compiled bundle
|
||||
- Add `Viewer.subscribe` method that keeps track of subscribed plugin events and disposes them together with the parent viewer
|
||||
- Add `Viewer.structureInteractivity` that makes it easy to highlight/select elements on the loaded structure
|
||||
- Add `viewportBackgroundColor` and `viewportFocusBehavior` options
|
||||
- Add `mvs.html` example to showcase the new functionality combined with MolViewSpec
|
||||
- Add dark and blue color theme support (import `theme/dark.css` or `theme/blue.css` instead of the default `molstar.css`)
|
||||
- MolViewSpec extension
|
||||
- Add `tryGetPrimitivesFromLoci` that makes it easier to access primitive element data from hover/click interactions
|
||||
- Add `getCurrentMVSSnapshot` to obtain source data for the currently displayed snapshot
|
||||
- Add TM-align structure-based protein alignment algorithm
|
||||
- New `TMAlign` namespace in `mol-math/linear-algebra/3d/tm-align.ts`
|
||||
- New `tmAlign` function in `mol-model/structure/structure/util/tm-align.ts`
|
||||
- Returns TM-score, RMSD, alignment mapping, and transformation matrix
|
||||
- Molecular Surface
|
||||
- Fix "auto" quality params not hidden
|
||||
- Fix calculation when probe diameter is smaller then resolution
|
||||
- Fix webgl1 shader syntax
|
||||
- Fix program not compiled for sync picking
|
||||
- Fix missing `gl.flush` for async picking (needed for Safari)
|
||||
- Add Residue Charge color scheme (#1722)
|
||||
- Add dropdown indicator for mapped parameter definitions and adjust "more options" icon
|
||||
- Fix `flipSided` for meshes
|
||||
- [Breaking] Interior coloring
|
||||
- Remove global `interiorDarkening`, `interiorColorFlag`, `interiorColor`
|
||||
- Add per-geometry `interiorColor`, `interiorSubstance`
|
||||
- Add `label/auth_comp_id` to `StructureProperties.residue`
|
||||
- Previously, this has been only been present on `.atom` (since residue name can alter on per-atom basis), but this has been a bit confusing for the general use-case
|
||||
- Move canvas "checkered background" logic to `canvas3d.ts` and only apply it when `transparentBackground` is on
|
||||
- This prevents ugly flickering during plugin initialization
|
||||
- Fix unit hash collision issues (#1721)
|
||||
|
||||
## [v5.4.2] - 2025-12-07
|
||||
- Fix postprocessing issues with SSAO and outlines for large structures (#1387)
|
||||
- Reduce automatic quality on standalone HMD devices
|
||||
|
||||
## [v5.4.1] - 2025-11-16
|
||||
- Fix ugly camera clipping in snapshot transitions
|
||||
- Add viewport button to toggle illumination mode
|
||||
- Fix bounding sphere computation for 3D text
|
||||
- Structure bounding sphere includes atom VDW radii / coarse sphere radii
|
||||
- Relax camera limits to allow focusing any selection with >1 atom
|
||||
- MolViewSpec
|
||||
- Fix `appendSnapshots` when loading MVSX
|
||||
- Fix all-selector color not applying on substructure
|
||||
- Fix primitives in root not being transformed with reference structure
|
||||
- Color themes do not prefer smoothing (improves performance in animations)
|
||||
- Allow canvas background interpolation
|
||||
- Fix `direct-volume` not drawn in illumination mode
|
||||
- Fix default trackball animated spin speed
|
||||
- Use `PluginCommands` to set canvas3d props in camera behavior
|
||||
- Volume improvements
|
||||
- Add `Volume.periodicity`
|
||||
- Wrap isosurfaces for periodic volumes
|
||||
- Fix dimensions for slices
|
||||
- Add support for Input Method Editor (IME) to text params input
|
||||
- Update `guessCifVariant` to detect density files not generated by the VolumeServer
|
||||
|
||||
## [v5.3.0] - 2025-11-05
|
||||
- Update loading message in MVS Stories Viewer
|
||||
- Add `Canvas3D.setAttribs`
|
||||
- Fix `normalizeWheel` "spin" calculation fallback
|
||||
- MolViewSpec
|
||||
- Add support for "topology" formats (TOP, PRMTOP, PSF)
|
||||
- Add support for additional "coordiates" formats (NCTRAJ, DCD, TRR)
|
||||
- Fix coarse structure selection
|
||||
- Fix missing default param values in `primitives_from_uri`
|
||||
|
||||
## [v5.2.0] - 2025-10-31
|
||||
- Handle transparency updates on ImagePass
|
||||
- Fix CIF parser edge case when the last token is escaped
|
||||
- MolViewSpec
|
||||
- Fix tooltips persisting across snapshots
|
||||
- Fix CIF annotations with no selector columns being ignored
|
||||
- Fix trackpad lock when camera up parallel to direction
|
||||
- Add clipping support for primitives
|
||||
- Support near camera distance
|
||||
|
||||
## [v5.1.2] - 2025-10-25
|
||||
- Fix createColorScaleByType when offsets are available
|
||||
- Get bond orders from non-standard CONECT records in PDB files
|
||||
- Remove outdated `gl_FrontFacing` workaround for buggy drivers
|
||||
- Fix clip objects for direct-volume rendering
|
||||
- Support "magic window" style AR (via WebXR)
|
||||
- Fix `PluginState.getStateTransitionFrameIndex`
|
||||
- Update `GlycamSaccharideNames` and `Monosaccharides` in `carbohydrates/constants.ts`
|
||||
- Support custom ref resolvers in `State`
|
||||
- Add full-screen mode support to layout manager
|
||||
- Add `show-toggle-fullscreen` URL param option to Viewer app
|
||||
- MolViewSpec
|
||||
- Support accessing Mol* State nodes by MVS-provided ref
|
||||
- Add support for DX map format
|
||||
- Better support for coarse structures in MVS:
|
||||
- Support for MVS annotations on coarse structures (color_from_*, tooltip_from_*)
|
||||
- Support for MVS labels on coarse structures (label, label_from_*)
|
||||
- (Other things already worked on coarse structures before: tooltip, color,component, primitives, component_from_*, primitives_from_*)
|
||||
- Tidy up MVS builder:
|
||||
- Add `sphere` and `angle` methods
|
||||
- [Breaking] Rename builder method primitives_from_uri -> primitivesFromUri
|
||||
|
||||
## [v5.0.0] - 2025-09-28
|
||||
- [Breaking] Renamed some color schemes ('inferno' -> 'inferno-no-black', 'magma' -> 'magma-no-black', 'turbo' -> 'turbo-no-black', 'rainbow' -> 'simple-rainbow')
|
||||
- [Breaking] `Box3D.nearestIntersectionWithRay` -> `Ray3D.intersectBox3D`
|
||||
- [Breaking] `Plane3D.distanceToSpher3D` -> `distanceToSphere3D` (fix spelling)
|
||||
- [Breaking] fix typo `MarchinCubes` -> `MarchingCubes`
|
||||
- [Breaking] `PluginContext.initViewer/initContainer/mount` are now async and have been renamed to include `Async` postfix
|
||||
- [Breaking] Add `Volume.instances` support and a `VolumeInstances` transform to dynamically assign it
|
||||
- This change is breaking because all volume objects require the `instances` field now.
|
||||
- [Breaking] `Canvas3D.identify` now expects `Vec2` or `Ray3D`
|
||||
- [Breaking] `TrackballControlsParams.animate.spin.speed` now means "Number of rotations per second" instead of "radians per second"
|
||||
- [Breaking] `PluginStateSnapshotManager.play` now accepts an options object instead of a single boolean value
|
||||
- Update production build to use `esbuild`
|
||||
- Emit explicit paths in `import`s in `lib/`
|
||||
- Fix outlines on opaque elements using illumination mode
|
||||
- Change `Representation.Empty` to a lazy property to avoid issue with some bundlers
|
||||
- MolViewSpec extension:
|
||||
- Generic color schemes (`palette` parameter for color_from_* nodes)
|
||||
- Annotation field remapping (`field_remapping` parameter for color_from_* nodes)
|
||||
- `representation` node: support custom property `molstar_representation_params`
|
||||
- Add `backbone` and `line` representation types
|
||||
- `primitives` node: support custom property `molstar_mesh/label/line_params`
|
||||
- `canvas` node: support custom property `molstar_postprocessing` with the ability to customize outline, depth of field, bloom, shadow, occlusion (SSAO), fog, and background
|
||||
- `clip` node support for structure and volume representations
|
||||
- `grid_slice` representation support for volumes
|
||||
- Support tethers and background for primitive labels
|
||||
- Support `snapshot_key` parameter on primitives that enables transition between states via clicking on 3D objects
|
||||
- Inline selectors and MVS annotations support `instance_id`
|
||||
- Support `matrix` on transform params
|
||||
- Support `surface_type` (`molecular` / `gaussian`) on for `surface` representation nodes
|
||||
- Add `instance` node type
|
||||
- Add `transform.rotation_center` property that enables rotating an object around its centroid or a specific point
|
||||
- Support transforming and instancing of structures, components, and volumes
|
||||
- Use params hash for node version for more performant tree diffs
|
||||
- Add `Snapshot.animation` support that enables animating almost every property in a given tree
|
||||
- Add `createMVSX` helper function
|
||||
- Support Mol* trackball animation via `animation.custom.molstar_trackball`
|
||||
- MVSX - use Murmur hash instead of FNV in archive URI
|
||||
- Support additional file formats (pdbqt, gro, xyz, mol, sdf, mol2, xtc, lammpstrj)
|
||||
- Support loading trajectory coordinates from separate nodes
|
||||
- Trigger markdown commands from primitives using `molstar_markdown_commands` custom extensions
|
||||
- Support `molstar_on_load_markdown_commands` custom state on the `root` node
|
||||
- Print tree validation errors to plugin log
|
||||
- Added new color schemes, synchronized with D3.js ('inferno', 'magma', 'turbo', 'rainbow', 'sinebow', 'warm', 'cool', 'cubehelix-default', 'category-10', 'observable-10', 'tableau-10')
|
||||
- Snapshot Markdown improvements
|
||||
- Add `MarkdownExtensionManager` (`PluginContext.managers.markdownExtensions`)
|
||||
- Support custom markdown commands to control the plugin via the `[link](!command)` pattern
|
||||
- Support rendering custom elements via the `` pattern
|
||||
- Support tables
|
||||
- Support loading images and audio from MVSX files
|
||||
- Indicate external links with ⤴
|
||||
- Audio support
|
||||
- Add `PluginState.Snapshot.onLoadMarkdownCommands`
|
||||
- Avoid calculating rings for coarse-grained structures
|
||||
- Fix isosurface compute shader normals when transformation matrix is applied to volume
|
||||
- Symmetry operator naming for spacegroup symmetry - parenthesize multi-character indices (1_111-1 -> 1_(11)1(-1))
|
||||
- Add `SymmetryOperator.instanceId` that corresponds to a canonical operator name (e.g. ASM-1, ASM-X0-1 for assemblies, 1_555, 1_(11)1(-1) for crystals)
|
||||
- Mol2 Reader
|
||||
- Fix column count parsing
|
||||
- Add support for substructure
|
||||
- Fix shader error when clipping flags are set without clip objects present
|
||||
- Fix wrong group count calculation on geometry update (#1562)
|
||||
- Fix wrong instance index in `calcMeshColorSmoothing`
|
||||
- Add `Ray3D` object and helpers
|
||||
- Volume slice representation: add `relativeX/Y/Z` options for dimension
|
||||
- Add `StructureInstances` transform
|
||||
- `mvs-stories` app
|
||||
- Add `story-id` URL arg support
|
||||
- Add `story-session-url` URL arg support
|
||||
- Add "Download MVS State" link
|
||||
- Add "Open in Mol*" link
|
||||
- Add "Edit in MolViewStories" link for story states
|
||||
- Add ray-based picking
|
||||
- Render narrow view of scene scene from ray origin & direction to a few pixel sized viewport
|
||||
- Cast ray on every input as opposed to the standard "whole screen" picking
|
||||
- Can be enabled with new `Canvas3dInteractionHelperParams.convertCoordsToRay` param
|
||||
- Allows to have input methods that are 3D pointers in the scene
|
||||
- Add `ray: Ray3D` property to `DragInput`, `ClickInput`, and `MoveInput`
|
||||
- Add async, non-blocking picking (only WebGL2)
|
||||
- Refactor `Canvas3dInteractionHelper` internals to use async picking for move events
|
||||
- Add `enable` param for post-processing effects. If false, no effects are applied.
|
||||
- Dot volume representation improvements
|
||||
- Add positional perturbation to avoid camera artifacts
|
||||
- Fix handling of negative isoValues by considering only volume cells with values lower than isoValue (#1559)
|
||||
- Fix volume-value size theme
|
||||
- Change the parsing of residue names in PDB files from 3-letter to 4-letter.
|
||||
- Support versioning transform using a hash function in `mol-state`
|
||||
- Support for "state snapshot transitions"
|
||||
- Add `PluginState.Snapshot.transition` that enables associating a state snapshot with a list states that can be animated
|
||||
- Add `AnimateStateSnapshotTransition` animation
|
||||
- Update the snapshots UI to support this feature
|
||||
- Use "proper time" in the animation loop to prevent animation skips during blocking operations (e.g., shader complication)
|
||||
- Add `Hsl` and (normalized) `Rgb` color spaces
|
||||
- Add `Color.interpolateHsl`
|
||||
- Add `rotationCenter` property to `TransformParam`
|
||||
- Add Monolayer transparency (exploiting dpoit).
|
||||
- Add plugin config item ShowReset (shows/hides "Reset Zoom" button)
|
||||
- Fix transform params not being normalized when used together with param hash version
|
||||
- Replace `immer` with `mutative`
|
||||
- Fix renderer transparency check
|
||||
- Add outlines improvements
|
||||
- VolumeServer & "VolumeCIF": default to P 1 spacegroup
|
||||
- Fix `ColorScale` for continuous case without offsets (broke in v4.13.0)
|
||||
- Experimental: support for custom color themes in Sequence Panel
|
||||
- Switch files.rcsb.org validation report URL to new endpoint /validation/view
|
||||
- Improve picking of objects with too many groups, pick whole instance/object
|
||||
- Add WebXR support
|
||||
- Requires immersive AR/VR headset
|
||||
- Supplements non-XR: enter/exit XR anytime and see (mostly) the same scene
|
||||
- Add `Canvas3D.xr` for managing XR sessions
|
||||
- Add `PointerHelper` for rendering XR input devices
|
||||
- Add XR button to Viewer and Mesoscale Explorer
|
||||
- Add XR button to render-structure in tests/browser
|
||||
- Fix illumination denoising with transparency on transparent background
|
||||
- Change the `to_mmCIF` function parameter from `structure` to `structures` to support either a single structure or an array of structures
|
||||
- ModelServer and VolumeServer: add configurable robots.txt
|
||||
- Adaptive parallel shader compilation
|
||||
- Split shader compilation into linking and finalizing
|
||||
- Start linking as early as possible and wait with finalizing to avoid blocking main thread
|
||||
- Use of `KHR_parallel_shader_compile` extension when available to check status
|
||||
- Add `ShaderManager` to compile shaders based on `Canvas3D` params and `Scene` content
|
||||
- Draw `Scene` only when shaders are ready
|
||||
- Fix incorrect animation loop handling in the screenshot code
|
||||
|
||||
## [v4.18.0] - 2025-06-08
|
||||
- MolViewSpec extension:
|
||||
- Support for label_comp_id and auth_comp_id in annotations
|
||||
- Geometric primitives - do not render if position refers to empty substructure
|
||||
- Primitive arrow - nicer default cap size (relative to tube_radius)
|
||||
- Primitive angle_measurement - added vector_radius param
|
||||
- Fix MVSX file assets being disposed in multi-snapshot states
|
||||
- Add `mol-utils/camera.ts` with `fovAdjustedPosition` and `fovNormalizedCameraPosition`
|
||||
- Show FOV normalized position in `CameraInfo` UI and use it in "Copy MVS State"
|
||||
- Support static resources in `AssetManager`
|
||||
- General:
|
||||
- Use `isolatedModules` tsconfig flag
|
||||
- Fix TurboPack build when using ES6 modules
|
||||
- Support `pickingAlphaThreshold` when `xrayShaded` is enabled
|
||||
- Support sampling from arbitrary planes for structure plane and volume slice representations
|
||||
- Refactor SCSS to not use `@import` (fixes deprecation warnings)
|
||||
|
||||
## [v4.17.0] - 2025-05-22
|
||||
- Remove `xhr2` dependency for NodeJS, use `fetch`
|
||||
- Add `mvs-stories` app included in the `molstar` NPM package
|
||||
- Use the app in the corresponding example
|
||||
- Interactions extension: remove `salt-bridge` interaction kind (since `ionic` is supported too)
|
||||
|
||||
## [v4.16.0] - 2025-05-20
|
||||
- Load potentially big text files as `StringLike` to bypass string size limit
|
||||
- MolViewSpec extension:
|
||||
- Load single-state MVS as if it were multi-state with one state
|
||||
- Merged `loadMVS` options `keepCamera` and `keepSnapshotCamera` -> `keepCamera`
|
||||
- Removed `loadMVS` option `replaceExisting` (is now default)
|
||||
- Added `loadMVS` option `appendSnapshots`
|
||||
- Fix camera not being interpolated in MP4 export due to updates in WebGL ContextLost handling
|
||||
|
||||
## [v4.15.0] - 2025-05-19
|
||||
- IHM improvements:
|
||||
- Disable volume streaming
|
||||
- Disable validation report visualization
|
||||
- Enable assembly symmetry for integrative models
|
||||
- Fix transparency rendering with occlusion in NodeJS
|
||||
- mmCIF Support
|
||||
- Add custom `molstar_bond_site` category that enables serializing explicit bonds by referencing `atom_site.id`
|
||||
- Add `includeCategoryNames`, `keepAtomSiteId`, `exportExplicitBonds`, `encoder` properties to `to_mmCIF` exporter
|
||||
- Add support for attachment points property (`M APO`) to the MOL V2000 parser
|
||||
- Add `json-cif` extension that should pave way towards structure editing capabilities in Mol\*
|
||||
- JSON-based encoding of the CIF data format
|
||||
- `JSONCifLigandGraph` that enables editing of small molecules via modifying `atom_site` and `molstar_bond_site` categories
|
||||
- Add `ligand-editor` example that showcases possible use-cases of the `json-cif` extension
|
||||
- Breaking (minor): Changed `atom_site.id` indexing to 1-based in `mol-model-formats/structure/mol.ts::getMolModels`.
|
||||
- WebGL ContextLost handling
|
||||
- Fix missing framebuffer & drawbuffer re-attachments
|
||||
- Fix missing cube texture re-initialization
|
||||
- Fix missing extensions reset
|
||||
- Fix timer clearing edge case
|
||||
- Add reset support for geometry generated on the GPU
|
||||
|
||||
## [v4.14.1] - 2025-05-09
|
||||
- Do not raise error when creating duplicate state transformers and print console warning instead
|
||||
|
||||
## [v4.14.0] - 2025-05-07
|
||||
- Fix `Viewer.loadTrajectory` when loading a topology file
|
||||
- Fix `StructConn.residueCantorPairs` to not include identity pairs
|
||||
- Add format selection option to image export UI (PNG, WebP, JPEG)
|
||||
- Add `StateBuilder.To.updateState`
|
||||
- MVS:
|
||||
- Support updating transform states
|
||||
- Add support for `is_hidden` custom state as an extension
|
||||
- Add `queryMVSRef` and `createMVSRefMap` utility functions
|
||||
- Adjust max resolution of surfaces for auto quality (#1501)
|
||||
- Fix switching representation type in Volume UI
|
||||
- VolumeServer: Avoid grid expansion when requiring unit cell (avoids including an extra layer of cells outside the unit cell query box)
|
||||
|
||||
## [v4.13.0] - 2025-04-14
|
||||
- Support `--host` option for build-dev.mjs script
|
||||
- Add `Viewer.loadFiles` to open supported files
|
||||
- Support installing the viewer as a Progressive Web App (PWA)
|
||||
- `ihm-restraints` example: show entity labels
|
||||
- Fix `element-point` visual not using child unit
|
||||
- Ignore `renderables` with empty draw count
|
||||
- Add experimental support for `esbuild` for development
|
||||
- Use `npm run dev` for faster development builds
|
||||
- Use `StructureElement.Bundle` instead of expressions to serialize measurement elements
|
||||
- Fixes measurements not being supported for coarse models
|
||||
- Implementation of `ColorScale.createDiscrete` (#1458)
|
||||
- Add `ColorScale.createDiscrete` to the `uncertainty` color theme
|
||||
- Fix color palette shown in the UI (for non-gradient palettes)
|
||||
- Fix colors description in the UI (when using custom thresholds)
|
||||
- Fix an edge case in the UI when the user deletes all colors from the color list
|
||||
- Add `interactions` extension and a corresponding example that utilizes it
|
||||
- Add element source index to default atomic granularity hover labels
|
||||
- Add `StructureElement.Schema` based on corresponding MolViewSpec implementation that allows data-driven selection of structural elements
|
||||
- Add `StructureElement.Loci/Bundle.fromExpression/Query/Schema` helper functions
|
||||
- Add `addLinkCylinderMesh` (from `createLinkCylinderMesh`)
|
||||
- Add `Unit.transientCache` and `Unit.getCopy`
|
||||
- Fix `ElementBondIterator` indices mapping logic for inter-unit bonds
|
||||
- Fix `pickPadding` and `pickScale` not updating `PickHelper`
|
||||
- MolViewSpec extension: support loading extensions when loading multistate files
|
||||
- Do not add bonds for pairs of residues that have a `struct_conn` entry
|
||||
- Improved `ma_qa_metric` support
|
||||
- Parse all local metrics
|
||||
- Ability to select alternate metrics in the pLDDT/qmean themes
|
||||
- Do not assume PAE plot is symmetric
|
||||
- Added `PluginConfig.Viewport.ShowScreenshotControls` to control visibility of screenshot controls
|
||||
- Fix MolViewSpec builder for volumes.
|
||||
- Generalize `mvs-kinase-story` example to `mvs-stories`
|
||||
- Add TATA-binding protein story
|
||||
- Improve the Kinase story
|
||||
- Fix alpha orbitals example
|
||||
|
||||
## [v4.12.0] - 2025-02-28
|
||||
|
||||
- Fix PDBj structure data URL
|
||||
- Improve logic when to cull in renderer
|
||||
- Add `atom.ihm.has-seq-id` and `atom.ihm.overlaps-seq-id-range` symbol to the query language
|
||||
- MolViewSpec extension:
|
||||
- Add box, arrow, ellipse, ellipsoid, angle primitives
|
||||
- Add basic support for volumetric data (map, Volume Server)
|
||||
- Add support for `molstar_color_theme_name` custom extension
|
||||
- Better IH/M support:
|
||||
- Support `coarse` components
|
||||
- Support `spacefill` representation
|
||||
- Support `carbohydrate` representation
|
||||
- Support for `custom.molstar_use_default_coloring` property on Color node.
|
||||
- Use `atom.ihm.has-seq-id` and `atom.ihm.overlaps-seq-id-range` for matching `label_seq_id` locations to support querying coarse elements.
|
||||
- Add ihm-restraints example
|
||||
- Add `mvs-kinase-story` example
|
||||
- Remove static uses of `ColorTheme` and `SizeTheme` fields. Should resolvent "undefined" errors in certain builds
|
||||
- Add `transform` property to clip objects
|
||||
- Add support for trimming `image` geometry to a box
|
||||
- Improve/fix iso-level support of `slice` representation
|
||||
- Add support for rotating `slice` representation around an axis
|
||||
- Add default color support for palette based themes
|
||||
- Add `plane` structure representation
|
||||
- Can be colored with any structure theme
|
||||
- Can be colored with the `external-volume` theme
|
||||
- Can show atoms as a cutout
|
||||
- Supports principal axes and bounding box as a reference frame
|
||||
- Add `Camera` section to "Screenshot / State" controls
|
||||
- Add `CoarseIndex` for fast lookup of coarse elements
|
||||
|
||||
## [v4.11.0] - 2025-01-26
|
||||
|
||||
- Fix for tubular helices issue (Fixes #1422)
|
||||
- Volume UI improvements
|
||||
- Render all volume entries instead of selecting them one-by-one
|
||||
- Toggle visibility of all volumes
|
||||
- More accessible iso value control
|
||||
- Support wheel event on sliders
|
||||
- MolViewSpec extension:
|
||||
- Add validation for discriminated union params
|
||||
- Primitives: remove triangle_colors, line_colors, have implicit grouping instead; rename many parameters
|
||||
- UI configuration options
|
||||
- Support removal of independent selection controls in the viewport
|
||||
- Support custom selection controls
|
||||
- Support for custom granularity dropdown options
|
||||
- Support for custom Sequence Viewer mode options
|
||||
- Add `external-structure` theme that colors any geometry by structure properties
|
||||
- Support float and half-float data type for direct-volume rendering and GPU isosurface extraction
|
||||
- Minor documentation updates
|
||||
- Add support for position-location to `volume-value` color theme
|
||||
- Add support for color themes to `slice` representation
|
||||
- Improve/fix palette support in volume color themes
|
||||
- Fix `Plane3D.projectPoint`
|
||||
- Fix marking related `image` rendering issues
|
||||
- Handle pixels without a group
|
||||
- Take fog into account
|
||||
- MolViewSpec extension: Initial support for customizable representation parameters
|
||||
- Quick Styles section reorganized
|
||||
- UI color improvements (scrollbar contrast, toggle button hover color)
|
||||
- Add `overrideWater` param for entity-id color theme
|
||||
- Renames PDB-Dev to PDB-IHM and adjusts data source
|
||||
- Fix vertex based themes for spheres shader
|
||||
- Add volume dot representation
|
||||
- Add volume-value size theme
|
||||
- Sequence panel: Mark focused loci (bold+underline)
|
||||
- Change modifier key behavior in Normal Mode (default = select only, Ctrl/Cmd = add to selection, Shift = extend last selected range)
|
||||
- Handle Firefox's limit on vertex ids per draw (#1116)
|
||||
- Fix behavior of `Vec3.makeRotation(out, a, b)` when `a ≈ -b`
|
||||
|
||||
## [v4.10.0] - 2024-12-15
|
||||
|
||||
@@ -71,7 +613,7 @@ Note that since we don't clearly distinguish between a public and private interf
|
||||
- Fix `findPredecessorIndex` bug when repeating values
|
||||
- MolViewSpec: Support for transparency and custom properties
|
||||
- MolViewSpec: MVP Support for geometrical primitives (mesh, lines, line, label, distance measurement)
|
||||
- Mesoscale Explorer: Add support for 4-character PDB IDs (e.g., 8ZZC) in PDB-Dev loader
|
||||
- Mesoscale Explorer: Add support for 4-character PDB IDs (e.g., 8ZZC) in PDB-IHM/PDB-Dev loader
|
||||
- Fix Sequence View in Safari 18
|
||||
- Improve performance of `IndexPairBonds` assignment when operator keys are available
|
||||
- ModelArchive QualityAssessment extension:
|
||||
@@ -124,7 +666,7 @@ Note that since we don't clearly distinguish between a public and private interf
|
||||
- Improve entity-id coloring for structures with multiple models from the same source (#1221)
|
||||
- Wrap screenshot & image generation in a `Task`
|
||||
- AlphaFold DB: Add BinaryCIF support when fetching data
|
||||
- PDB-Dev: Add support for 4-character PDB IDs (e.g., 8ZZC)
|
||||
- PDB-IHM/PDB-Dev: Add support for 4-character PDB IDs (e.g., 8ZZC)
|
||||
- Fix polymer-gap visual coloring with cartoon theme
|
||||
- Add formal-charge color theme (#328)
|
||||
- Add more coloring options to cartoon theme
|
||||
|
||||
27
README.md
27
README.md
@@ -84,7 +84,16 @@ Wipes the `build` and `lib` directories and `.tsbuildinfo` files.
|
||||
|
||||
Runs the cleanup script prior to building the project, forcing a full rebuild of the project.
|
||||
|
||||
Use these commands to resolve occassional build failures which may arise after some dependency updates. Once done, `npm run build` should work again. Note that full rebuilds take more time to complete.
|
||||
Use these commands to resolve occasional build failures which may arise after some dependency updates. Once done, `npm run build` should work again. Note that full rebuilds take more time to complete.
|
||||
|
||||
### Develop with `esbuild`
|
||||
|
||||
Experimental support for faster builds with `esbuild`
|
||||
- `npm run dev:all` - watch mode for all apps and examples
|
||||
- `npm run dev:viewer` - watch mode for viewer
|
||||
- `npm run dev:apps` - watch mode for all apps
|
||||
- `npm run dev:examples` - watch mode for all examples
|
||||
- `npm run dev -- -a <app name 1> <app name 2> -e <example name 1> ...` - watch mode for specified apps/examples. `-a`/`-e` with without any names will build everything.
|
||||
|
||||
### Build for production:
|
||||
NODE_ENV=production npm run build
|
||||
@@ -103,7 +112,6 @@ From the root of the project:
|
||||
|
||||
and navigate to `build/viewer`
|
||||
|
||||
|
||||
### Code generation
|
||||
**CIF schemas**
|
||||
|
||||
@@ -118,16 +126,16 @@ and navigate to `build/viewer`
|
||||
|
||||
**Ion names**
|
||||
|
||||
node --max-old-space-size=4096 lib/commonjs/cli/chem-comp-dict/create-ions.js src/mol-model/structure/model/types/ions.ts
|
||||
node --max-old-space-size=8192 lib/commonjs/cli/chem-comp-dict/create-ions.js src/mol-model/structure/model/types/ions.ts
|
||||
|
||||
**Saccharide names**
|
||||
|
||||
node --max-old-space-size=4096 lib/commonjs/cli/chem-comp-dict/create-saccharides.js src/mol-model/structure/model/types/saccharides.ts
|
||||
node --max-old-space-size=8192 lib/commonjs/cli/chem-comp-dict/create-saccharides.js src/mol-model/structure/model/types/saccharides.ts
|
||||
|
||||
### Other scripts
|
||||
**Create chem comp bond table**
|
||||
|
||||
node --max-old-space-size=4096 lib/commonjs/cli/chem-comp-dict/create-table.js build/data/ccb.bcif -b
|
||||
node --max-old-space-size=8192 lib/commonjs/cli/chem-comp-dict/create-table.js build/data/ccb.bcif -b
|
||||
|
||||
**Test model server**
|
||||
|
||||
@@ -182,9 +190,14 @@ To get syntax highlighting for shader files add the following to Visual Code's s
|
||||
npm publish
|
||||
|
||||
## Deploy
|
||||
To prepare apps and demos for https://molstar.org deploy, run:
|
||||
|
||||
npm run test
|
||||
npm run build
|
||||
node ./scripts/deploy.js # currently updates the viewer on molstar.org/viewer
|
||||
npm run deploy:local
|
||||
|
||||
To commit these changes remotely to the `molstar/molstar.github.io` repo:
|
||||
|
||||
npm run deploy:remote
|
||||
|
||||
## Contributing
|
||||
Just open an issue or make a pull request. All contributions are welcome.
|
||||
|
||||
1
breaking-v6-changes.md
Normal file
1
breaking-v6-changes.md
Normal file
@@ -0,0 +1 @@
|
||||
- Remove `checkeredCanvasBackground` from `PluginContext` and `PluginContainer`
|
||||
@@ -14,6 +14,7 @@ chemical.melting_point
|
||||
|
||||
chemical_formula.moiety
|
||||
chemical_formula.sum
|
||||
chemical_formula.iupac
|
||||
chemical_formula.weight
|
||||
|
||||
atom_type.symbol
|
||||
@@ -25,6 +26,8 @@ atom_type_scat.source
|
||||
|
||||
space_group.crystal_system
|
||||
space_group.name_h-m_full
|
||||
space_group.name_h-m_alt
|
||||
space_group.name_hall
|
||||
space_group.it_number
|
||||
space_group_symop.operation_xyz
|
||||
|
||||
|
||||
|
15
data/pwa/README.md
Normal file
15
data/pwa/README.md
Normal file
@@ -0,0 +1,15 @@
|
||||
|
||||
The files in this directory are used for deploying the Mol* Viewer as a PWA (Progressive Web App) at https://molstar.org/viewer/. They may serve as an example for creating your own PWA but wont work as-is. See `/script/deploy.js` for where these files are copied and how they are transformed during deployment.
|
||||
|
||||
|
||||
## PWA features
|
||||
|
||||
- The Service Worker will cache static resources so the Viewer can be used without internet access. This works without installing, i.e., also in Firefox.
|
||||
- Once installed, file types listed in the Manifest can be opened from, e.g., the Windows File Explorer.
|
||||
|
||||
|
||||
## Notes for development
|
||||
|
||||
In Chrome you can see a list of installed PWAs at chrome://apps/. A right-click opens a menu with an option uninstall.
|
||||
|
||||
The Chrome Dev Tools have a section 'Application' to inspect and manage PWA aspects like the Manifest and Service Workers.
|
||||
BIN
data/pwa/logo-144.png
Normal file
BIN
data/pwa/logo-144.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.2 KiB |
39
data/pwa/manifest.webmanifest
Normal file
39
data/pwa/manifest.webmanifest
Normal file
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"id": "https://molstar.org/viewer/",
|
||||
"name": "Mol* Viewer",
|
||||
"short_name": "Mol*",
|
||||
"description": "Mol* Viewer: a modern web app for 3D visualization and analysis of large biomolecular structures.",
|
||||
"start_url": "./index.html",
|
||||
"theme_color": "#eeece7",
|
||||
"background_color": "#eeece7",
|
||||
"display": "standalone",
|
||||
"icons": [
|
||||
{
|
||||
"src": "favicon.ico",
|
||||
"sizes": "48x48"
|
||||
},
|
||||
{
|
||||
"src": "logo-144.png",
|
||||
"sizes": "144x144"
|
||||
}
|
||||
],
|
||||
"file_handlers": [
|
||||
{
|
||||
"action": "./index.html",
|
||||
"accept": {
|
||||
"application/vnd.molstar": [".molx", ".molj"],
|
||||
"text/plain": [
|
||||
".mol", ".mol2", ".sdf", ".sd", ".pdb", ".ent", ".pdbqt", ".cif", ".mcif", ".mmcif", ".xyz", ".gro", ".lammpstrj",
|
||||
".cub", ".cube", ".dx"
|
||||
],
|
||||
"application/octet-stream": [
|
||||
".bcif",
|
||||
".dxbin", ".ccp4", ".mrc", ".map", ".dsn6", ".brix"
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"launch_handler": {
|
||||
"client_mode": ["auto"]
|
||||
}
|
||||
}
|
||||
44
data/pwa/pwa.js
Normal file
44
data/pwa/pwa.js
Normal file
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* Copyright (c) 2025 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Andy Turner <agdturner@gmail.com>
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
window.addEventListener('molstarViewerCreated', e => {
|
||||
const viewer = e.detail.viewer;
|
||||
|
||||
// Handle incoming files
|
||||
if ('launchQueue' in window) {
|
||||
launchQueue.setConsumer((launchParams) => {
|
||||
if (!launchParams.files.length) return;
|
||||
|
||||
const files = [];
|
||||
for (const fileHandle of launchParams.files) {
|
||||
files.push(fileHandle.getFile());
|
||||
}
|
||||
|
||||
Promise.all(files).then((files) => {
|
||||
viewer.loadFiles(files);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Register Progressive Web App service worker.
|
||||
if ('serviceWorker' in navigator) {
|
||||
window.addEventListener('load', function () {
|
||||
navigator.serviceWorker.register('./sw.js')
|
||||
.then(function (registration) {
|
||||
// Registration was successful
|
||||
if (molstar.isDebugMode) {
|
||||
console.log('ServiceWorker registration successful with scope: ', registration.scope);
|
||||
}
|
||||
}, function (err) {
|
||||
// registration failed :(
|
||||
if (molstar.isDebugMode) {
|
||||
console.error('ServiceWorker registration failed: ', err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
60
data/pwa/sw.js
Normal file
60
data/pwa/sw.js
Normal file
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* Copyright (c) 2025 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Andy Turner <agdturner@gmail.com>
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
/** version from package.json, to be filled in during deployment */
|
||||
const VERSION = '__MOLSTAR_VERSION__';
|
||||
|
||||
const CACHE_NAME = `molstar-viewer-${VERSION}`;
|
||||
|
||||
// The static resources that the app needs to function.
|
||||
const APP_STATIC_RESOURCES = [
|
||||
'favicon.ico',
|
||||
'index.html',
|
||||
'molstar.css',
|
||||
'molstar.js',
|
||||
'manifest.webmanifest',
|
||||
'logo-144.png',
|
||||
'pwa.js'
|
||||
];
|
||||
|
||||
async function cacheStaticResources() {
|
||||
const cache = await caches.open(CACHE_NAME);
|
||||
await cache.addAll(APP_STATIC_RESOURCES);
|
||||
await self.skipWaiting(); // Ensures the new service worker takes control immediately.
|
||||
}
|
||||
|
||||
async function deleteOldCaches() {
|
||||
const keys = await caches.keys();
|
||||
await Promise.all(
|
||||
keys.map((key) => {
|
||||
if (key !== CACHE_NAME) {
|
||||
return caches.delete(key);
|
||||
}
|
||||
}),
|
||||
);
|
||||
await self.clients.claim(); // Ensures the new service worker takes control immediately.
|
||||
}
|
||||
|
||||
async function respondWithCacheFirst(request) {
|
||||
// Try to match the request with the cache
|
||||
const cachedResponse = await caches.match(request);
|
||||
return cachedResponse || fetch(request);
|
||||
}
|
||||
|
||||
self.addEventListener('install', (event) => {
|
||||
// console.log(`Service Worker version ${VERSION} installed.`);
|
||||
event.waitUntil(cacheStaticResources());
|
||||
});
|
||||
|
||||
self.addEventListener('activate', (event) => {
|
||||
// console.log(`Service Worker version ${VERSION} activated.`);
|
||||
event.waitUntil(deleteOldCaches());
|
||||
});
|
||||
|
||||
self.addEventListener('fetch', (event) => {
|
||||
event.respondWith(respondWithCacheFirst(event.request));
|
||||
});
|
||||
@@ -24,7 +24,7 @@ npm install
|
||||
Afterwards, build the project source:
|
||||
|
||||
```
|
||||
npm run build-tsc
|
||||
npm run build:lib
|
||||
```
|
||||
|
||||
and run the server by
|
||||
|
||||
4
docs/docs/extensions/interactions.md
Normal file
4
docs/docs/extensions/interactions.md
Normal file
@@ -0,0 +1,4 @@
|
||||
# Interactions extension
|
||||
|
||||
The Interactions extension enables computing or providing custom interactions between multiple selections/structures.
|
||||
For usage, see the [example source code](https://github.com/molstar/molstar/tree/master/src/examples/interactions).
|
||||
@@ -94,7 +94,7 @@ The extension uses several transformations to process and visualize tunnel data:
|
||||
To help users understand how to use these transformations in practice, include detailed examples:
|
||||
|
||||
### Visualizing Multiple Tunnels
|
||||
This example ([runVisualizeTunnels](../../../src/extensions/sb-ncbr/tunnels/examples.ts#L19)) demonstrates how to visualize multiple tunnels from a fetched dataset.
|
||||
This example (see `src/extensions/sb-ncbr/tunnels/examples.ts#L19`) demonstrates how to visualize multiple tunnels from a fetched dataset.
|
||||
```typescript
|
||||
update.toRoot()
|
||||
.apply(TunnelsFromRawData, { data: tunnels })
|
||||
@@ -104,7 +104,7 @@ update.toRoot()
|
||||
```
|
||||
|
||||
### Visualizing a Single Tunnel
|
||||
This example ([runVisualizeTunnel](../../../src/extensions/sb-ncbr/tunnels/examples.ts#L46)) shows how to visualize a single tunnel.
|
||||
This example (see `src/extensions/sb-ncbr/tunnels/examples.ts#L46`) shows how to visualize a single tunnel.
|
||||
```typescript
|
||||
update.toRoot()
|
||||
.apply(TunnelFromRawData, {
|
||||
|
||||
@@ -25,7 +25,7 @@ import { PluginContext } from 'molstar/lib/mol-plugin/context';
|
||||
git clone https://github.com/molstar/molstar.git
|
||||
cd molstar
|
||||
npm install
|
||||
npm build
|
||||
npm run build
|
||||
```
|
||||
|
||||
--------------------
|
||||
@@ -33,11 +33,11 @@ npm build
|
||||
For a watch task to automatically rebuild the source code on changes, run
|
||||
|
||||
```
|
||||
npm run watch
|
||||
npm run dev
|
||||
```
|
||||
|
||||
or if working just with the Viewer app for better performance
|
||||
|
||||
```
|
||||
npm run watch-viewer
|
||||
npm run dev:viewer
|
||||
```
|
||||
|
||||
@@ -48,4 +48,7 @@
|
||||
* CLR (e.g. 3GKI) - four fused rings
|
||||
* Assembly symmetries
|
||||
* 5M30 (Assembly 1, C3 local and pseudo)
|
||||
* 1RB8 (Assembly 1, I global)
|
||||
* 1RB8 (Assembly 1, I global)
|
||||
* Deuterium atoms
|
||||
* 3CWH (XUL with D and DOD)
|
||||
* 8TT8 (HOH and other with D)
|
||||
@@ -1,6 +1,6 @@
|
||||
# Building a Custom Library
|
||||
|
||||
This page goes over creating a custom Mol\* based library usable inside a `<script>` tag in an HTML page.
|
||||
This page goes over creating a custom Mol\* based library usable inside a `<script>` tag in an HTML page using the `esbuild` tool.
|
||||
|
||||
## Setup
|
||||
|
||||
@@ -141,7 +141,7 @@ export async function loadStructure(plugin: PluginUIContext, url: string, option
|
||||
```
|
||||
- Create `src/style.scss`:
|
||||
```scss
|
||||
@import '../node_modules/molstar/lib/mol-plugin-ui/skin/light.scss';
|
||||
@use '../node_modules/molstar/lib/mol-plugin-ui/skin/light.scss';
|
||||
```
|
||||
- Create `build/ui.html`:
|
||||
```html
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
What is a plugin? A plugin is a collection of modules that provide functionality to the `Mol*` UI. The plugin is responsible for managing the state of the viewer, internal and user interactions. It has been a previous point of confusion for new users of `Mol*` to associate the __viewer__ part of the library with what is further referred to as the __plugin__. These two are closely connected in the `molstar-plugin-ui` module, which is the user-facing part of the library and ultimately provides the viewer, but they are ultimately distinct.
|
||||
|
||||
|
||||
It is recommended that you inspect the general class structure of [`PluginInitWrapper`](https://github.com/molstar/molstar/blob/6edbae80db340134341631f669eec86543a0f1a8/src/mol-plugin-ui/plugin.tsx#L41), [`PluginUIContext`](https://github.com/molstar/molstar/blob/6edbae80db340134341631f669eec86543a0f1a8/src/mol-plugin/context.ts#L71) and [`PluginUIComponent`](https://github.com/molstar/molstar/blob/6edbae80db340134341631f669eec86543a0f1a8/src/mol-plugin-ui/base.tsx#L16) to better understand the flow of data and events in the plugin.
|
||||
It is recommended that you inspect the general class structure of [`PluginInitWrapper`](https://github.com/molstar/molstar/blob/6edbae80db340134341631f669eec86543a0f1a8/src/mol-plugin-ui/plugin.tsx#L41), [`PluginUIContext`](https://github.com/molstar/molstar/blob/6edbae80db340134341631f669eec86543a0f1a8/src/mol-plugin-ui/context.ts#L12) and [`PluginUIComponent`](https://github.com/molstar/molstar/blob/6edbae80db340134341631f669eec86543a0f1a8/src/mol-plugin-ui/base.tsx#L16) to better understand the flow of data and events in the plugin.
|
||||
A passing analogy is that a [ `PluginContext` ](https://github.com/molstar/molstar/blob/6edbae80db340134341631f669eec86543a0f1a8/src/mol-plugin/context.ts#L71) is the engine that powers computation, rendering, events and subscriptions inside the molstar UI. All UI components depend on `PluginContext`.
|
||||
|
||||
|
||||
@@ -15,10 +15,33 @@ There are 4 basic ways of instantiating the Mol* plugin.
|
||||
|
||||
## ``Viewer`` wrapper
|
||||
|
||||
- The most basic usage is to use the ``Viewer`` wrapper. This is best suited for use cases that do not require much custom behavior and are mostly about just displaying a structure.
|
||||
- See ``Viewer`` class is defined in [src/apps/viewer/app.ts](https://github.com/molstar/molstar/blob/master/src/apps/viewer/app.ts) for available methods and options.
|
||||
- The most basic usage is to use the ``Viewer`` wrapper. This is best suited for use cases that do not require custom behavior and are mostly about just displaying a structure.
|
||||
- See ``Viewer`` class is defined in [src/apps/viewer/app.ts](https://github.com/molstar/molstar/blob/master/src/apps/viewer/app.ts) for available methods
|
||||
- See [options.ts](https://github.com/molstar/molstar/blob/master/src/apps/viewer/options.ts) for available plugin options
|
||||
- See [embedded.html](https://github.com/molstar/molstar/blob/master/src/apps/viewer/embedded.html) and [mvs.html](https://github.com/molstar/molstar/blob/master/src/apps/viewer/mvs.html) for example usage
|
||||
- Importing `molstar.js` will expose `molstar.lib` namespace that allow accessing various functionality without a bundler such as WebPack or esbuild. See the `mvs` example above for basic usage.
|
||||
- Alternative color themes can be used by importing `theme/dark.css` (or `light/blue`) instead of `molstar.css`
|
||||
|
||||
Example usage without using WebPack:
|
||||
### molstar.js and molstar.css sources
|
||||
|
||||
- Download `molstar` NPM package and use the files from `build/viewer` diractory
|
||||
- Use `jsdelivr` CDN
|
||||
- `<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/molstar@latest/build/viewer/molstar.js" />`
|
||||
- `<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/molstar@latest/build/viewer/molstar.css" />`
|
||||
- `@latest` can be replaced by a specific Mol* version, e.g., `@5.4.2`
|
||||
- Clone & build the GitHub repository
|
||||
- This option allows for quite straightforward extension customization, e.g., not including movie export, which reduces the bundle size by ~0.5MB
|
||||
|
||||
### Bundle size
|
||||
|
||||
By default, the `Viewer` includes all the available extensions. This increases the bundle size significantly, especially by including the `mp4-export`, which is responsible for almost `0.5MB` of compressed bundle size.
|
||||
It is quite easy to reduce this bundle size by cloning the Mol\* repository, editing [extensions.ts](https://github.com/molstar/molstar/blob/master/src/apps/viewer/options.ts) and rebuilding it with `npm run build:apps`. The new build will be available
|
||||
in the `build/viewer` directory (the JS file you will find there is uncompressed, but your hosting setup should include automatic gzip compression, significantly reducing the size).
|
||||
|
||||
Alternatively, you can explore building your own "viewer" using the base Mol\* library. For this, see the options below.
|
||||
|
||||
|
||||
### Example
|
||||
|
||||
```HTML
|
||||
<style>
|
||||
@@ -35,7 +58,7 @@ Example usage without using WebPack:
|
||||
- the folder build/viewer after cloning and building the molstar package
|
||||
- from the build/viewer folder in the Mol* NPM package
|
||||
-->
|
||||
<link rel="stylesheet" type="text/css" href="molstar.css" />
|
||||
<link rel="stylesheet" type="text/css" href="./molstar.css" />
|
||||
<script type="text/javascript" src="./molstar.js"></script>
|
||||
|
||||
<div id="app"></div>
|
||||
@@ -62,13 +85,15 @@ Example usage without using WebPack:
|
||||
</script>
|
||||
```
|
||||
|
||||
When using WebPack (or possibly other build tool) with the Mol* NPM package installed, the viewer class can be imported using
|
||||
### Using WebPack/esbuild/...
|
||||
|
||||
When using WebPack (or other bundler) with the Mol* NPM package installed, the viewer class can be imported using
|
||||
|
||||
```ts
|
||||
import { Viewer } from 'molstar/build/viewer/molstar'
|
||||
import { Viewer } from 'molstar/lib/apps/viewer/app'
|
||||
|
||||
function initViewer(target: string | HTMLElement) {
|
||||
return new Viewer(target, { /* options */})
|
||||
return Viewer.create(target, { /* options */}) // returns a Promise
|
||||
}
|
||||
```
|
||||
|
||||
@@ -139,6 +164,8 @@ export function MolStarWrapper() {
|
||||
// In debug mode of react's strict mode, this code will
|
||||
// be called twice in a row, which might result in unexpected behavior.
|
||||
useEffect(() => {
|
||||
// By default, react will call each useEffect twice if using Strict mode in
|
||||
// debug build, it is recommended to disable strict mode for this reason if possible
|
||||
async function init() {
|
||||
window.molstar = await createPluginUI({
|
||||
target: parent.current as HTMLDivElement,
|
||||
@@ -247,7 +274,7 @@ async function init() {
|
||||
const canvas = <HTMLCanvasElement> document.getElementById('molstar-canvas');
|
||||
const parent = <HTMLDivElement> document.getElementById('molstar-parent');
|
||||
|
||||
if (!plugin.initViewer(canvas, parent)) {
|
||||
if (!(await plugin.initViewerAsync(canvas, parent))) {
|
||||
console.error('Failed to init Mol*');
|
||||
return;
|
||||
}
|
||||
|
||||
107
docs/docs/plugin/managers/markdown-extensions.md
Normal file
107
docs/docs/plugin/managers/markdown-extensions.md
Normal file
@@ -0,0 +1,107 @@
|
||||
# Markdown Extension Manager
|
||||
|
||||
The `markdownExtensions` manager in `PluginContext.manager` allows customizing
|
||||
the `Markdown` React component to enable executing commands and rendering custom content.
|
||||
|
||||
The main use case of this is enriching [MolViewSpec](`https://molstar.org/mol-view-spec`) support.
|
||||
|
||||
## API
|
||||
|
||||
- `PluginContext.manager.markdownExtensions.register*` functions can be used to register extensions and state/data resolvers to make the the manager work with plugin extension
|
||||
- `PluginContext.manager.markdownExtensions.remove*` can be used to dynamically remove the above
|
||||
|
||||
## Commands
|
||||
|
||||
Extends Markdown Hyperlink syntax to support expressions of the form `[title](!c1=v1&c2=v2&...)` into an executable command. The command can be executed either on click, mouse enter, or mouse leave.
|
||||
|
||||
Generally, the command should be URL encoded, e.g., `a b` => `a%20b` (in JS, `encodeURIComponent`, in Python `urllib.parse.quote_plus/urlencode`).
|
||||
|
||||
### Built-in Commands
|
||||
|
||||
- `center-camera` - Centers the camera
|
||||
- `apply-snapshot=key` - Loads snapshots with the provided key
|
||||
- `next-snapshot[=-1|1]` - Loads next/previous snapshot, the direction is optional and default to `1`
|
||||
- `play-snapshots` - Starts playback of state snapshots
|
||||
- `play-transition` - Plays an animation associated with the given snapshot
|
||||
- `stop-animation` - Stops currently playing animation
|
||||
- `focus-refs=ref1,ref2,...` - On click, focuses nodes with the provided refs
|
||||
- `highlight-refs=ref1,ref2,...` - On mouse over, highlights the provided refs
|
||||
- `query=...&lang=...&action=highlight,focus&focus-radius=...`
|
||||
- `query` is an expression (e.g., `resn HEM` when using PyMol syntax)
|
||||
- (optional) `lang` is one of `mol-script` (default), `pymol`, `vmd`, `jmol`
|
||||
- (optional) `action` is an array of `highlight` (default), `focus` (multiple actions can be specified)
|
||||
- (optional) `focus-radius` is extra distance applied when focusing the selection (default is `3`)
|
||||
- Example: `[HEM](!query=resn%20HEM%26lang=pymol&action=highlight,focus)` highlights or focuses the HEM residue (the query must be URL encoded because it contains spaces and possibly other special characters)
|
||||
- `play-audio=src`, `toggle-audio[=src]`, `stop-audio`, `pause-audio`, `dispose-audio` - Audio playback support
|
||||
|
||||
## Custom Content
|
||||
|
||||
Extends Markdown Image syntax to support expressions of the form `` to render custom elements instead.
|
||||
|
||||
### Built-in Custom Content
|
||||
- `color-swatch=color` - Renders a box with the provided color
|
||||
- Color palettes:
|
||||
- `color-palette-name=name` - Renders a gradient with the provided named color palette (see `mol-util/color/lists.ts` for supported color schemes)
|
||||
- `color-palette-colors=color1,color2` - Renders a gradient with the provided colors
|
||||
- `color-palette-width=CCS-value` - Specifies the width of the element, defaults to `150px`
|
||||
- `color-palette-height=CCS-value` - Specified the height of the element, defaults to `0.5em`
|
||||
- `color-palette-discrete` - Renders discrete color list instead of interpolating
|
||||
|
||||
|
||||
## Example
|
||||
|
||||
```markdown
|
||||
### Highlight/Focus:
|
||||
-  [polymer](!highlight-refs=polymer&focus-refs=polymer)
|
||||
-  [ligand](!highlight-refs=ligand&focus-refs=ligand)
|
||||
- [both](!highlight-refs=polymer,ligand&focus-refs=polymer,ligand)
|
||||
|
||||
### Color Palettes
|
||||
|name|visual|
|
||||
|---:|---|
|
||||
|viridis||
|
||||
|rainbow (discrete)||
|
||||
|custom|)|
|
||||
|
||||
### Camera controls
|
||||
- [center](!center-camera)
|
||||
|
||||
### Image embedded in MVSX file
|
||||

|
||||
```
|
||||
|
||||
This works with the MolViewSpec state built by:
|
||||
|
||||
```py
|
||||
import molviewspec as mvs
|
||||
|
||||
builder = mvs.create_builder()
|
||||
|
||||
assets = {
|
||||
"1cbs.cif": "https://files.wwpdb.org/download/1cbs.cif",
|
||||
"logo.png": "https://molstar.org/img/molstar-logo.png",
|
||||
}
|
||||
|
||||
model = (
|
||||
builder.download(url="1cbs.cif")
|
||||
.parse(format="mmcif")
|
||||
.model_structure()
|
||||
)
|
||||
(
|
||||
model.component(selector="polymer")
|
||||
.representation(ref="polymer")
|
||||
.color(color="blue")
|
||||
)
|
||||
(
|
||||
model.component(selector="ligand")
|
||||
.representation(ref="ligand")
|
||||
.color(color="red")
|
||||
)
|
||||
|
||||
mvsx = mvs.MVSX(
|
||||
data=builder.get_state(
|
||||
description="""...""" # inline the code above
|
||||
),
|
||||
assets=assets
|
||||
)
|
||||
```
|
||||
@@ -1,11 +1,136 @@
|
||||
# Selections
|
||||
|
||||
|
||||
Assuming you have a model already loaded into the plugin (see [Creating Plugin Instance](./instance.md)), these are some of the following method you can select structural data.
|
||||
## Basic Concepts
|
||||
|
||||
### Selecting directly from the `hierarchy` manager
|
||||
### Location
|
||||
|
||||
One can select a subcomponent's data directly from the plugin manager.
|
||||
The selection model in Mol\* is based on a generic concept called *location*. A location is a pointer to a selectable element within a scene. For example:
|
||||
|
||||
- A structure element location (an atom or a coarse element) is an object composed of `{ structure: Structure, unit: Unit, element: UnitIndex }` (you can think of a `Unit` as a generalized chain)
|
||||
- A bond location is very similar to structure element, requiring pointers to two units and elements
|
||||
- A "shape" (generally a mesh) location consists of pointer to the parent shape and a group of triangles
|
||||
|
||||
### Loci
|
||||
|
||||
Structures and other renderable elements generally consist of many locations and simply using a list of locations would be
|
||||
prohibitively expensive (e.g., large selections in structures with hundreds of thousands of atoms).
|
||||
|
||||
This is why Mol\* introduces
|
||||
the concept of `Loci` — a compressed representation of multiple locations. Instead of having a list of structure element locations (`{ structure: Structure, unit: Unit, element: UnitIndex }[]`), the representation becomes (simplified) `{ structure: Structure, unit: Unit, elements: OrderedSet<UnitIndex> }`. The ordered set can be further compressed for continuous ranges, keeping only the index of the 1st and last element.
|
||||
|
||||
### Bundle
|
||||
|
||||
Locations and loci point to the raw JavaScript data structures representing the underlying molecules, making them not serializable in JSON. A *bundle* is a serializable version of the loci.
|
||||
|
||||
### Structure Queries
|
||||
|
||||
Defining selections directly using the loci would be very cumbersome. For this reason, Mol\* includes the [MolQl query language](https://molql.org) to help define selections.
|
||||
|
||||
|
||||
## Selection Methods
|
||||
|
||||
Assuming you have a model already loaded into the plugin (see [Creating Plugin Instance](./instance.md)), these are some of the methods you can use to create selections.
|
||||
|
||||
### MolQL (`mol-script`) language
|
||||
|
||||
[MolQL](https://molql.org) (`mol-script`) is a language for addressing crystallographic structures and is a part of the Mol* library found at `https://github.com/molstar/molstar/tree/master/src/mol-script`. It can be used against the Molstar plugin as a query language and transpiled against multiple external molecular visualization libraries(see [here](https://github.com/molstar/molstar/tree/master/src/mol-script/transpilers)).
|
||||
|
||||
**Example:** Querying a structure for a specific chain and residue range
|
||||
|
||||
Select residues with `12<res_id<200 of chain with auth_asym_id=A`
|
||||
|
||||
```typescript
|
||||
import { compileIdListSelection } from 'molstar/lib/mol-script/util/id-list'
|
||||
|
||||
const query = compileIdListSelection('A 12-200', 'auth');
|
||||
window.molstar?.managers.structure.selection.fromCompiledQuery('add',query);
|
||||
```
|
||||
|
||||
### Selection Queries
|
||||
|
||||
Another way to create a selection is via a `SelectionQuery` object. This is a more programmatic way to create a selection. The following example shows how to select a chain and a residue range using a `SelectionQuery` object.
|
||||
This relies on the concept of `Expression` which is basically a intermediate representation between a Molscript statement and a selection query.
|
||||
|
||||
**Example:** Select residues 10-15 of chains A and F in a structure using a `SelectionQuery` object
|
||||
|
||||
```typescript
|
||||
import { MolScriptBuilder as MS, MolScriptBuilder } from 'molstar/lib/mol-script/language/builder';
|
||||
import { Expression } from 'molstar/lib/mol-script/language/expression';
|
||||
import { StructureSelectionQuery } from 'molstar/lib/mol-plugin-state/helpers/structure-selection-query'
|
||||
|
||||
|
||||
export function select_multiple() {
|
||||
|
||||
const args = [['A', 10, 15], ['F', 10, 15]]
|
||||
const groups: Expression[] = [];
|
||||
for (var chain of args) {
|
||||
groups.push(MS.struct.generator.atomGroups({
|
||||
'chain-test': MS.core.rel.eq([MolScriptBuilder.struct.atomProperty.macromolecular.auth_asym_id(), chain[0]]),
|
||||
'residue-test': MS.core.rel.inRange([MolScriptBuilder.struct.atomProperty.macromolecular.label_seq_id(), chain[1], chain[2]])
|
||||
}));
|
||||
}
|
||||
var sq = StructureSelectionQuery('residue_range_10_15_in_A_and_F', MS.struct.combinator.merge(groups))
|
||||
mstar.managers.structure.selection.fromSelectionQuery('set', sq)
|
||||
}
|
||||
```
|
||||
|
||||
Complex queries can be constructed by combining primitive queries at the level of [`chain-test`, `residue-test`, `entity-test`, etc] (https://github.com/molstar/molstar/blob/6edbae80db340134341631f669eec86543a0f1a8/src/mol-script/language/symbol-table/structure-query.ts#L88C4-L94C112) by combining them via logical connectives provided in the `MolscriptBuilder.core.rel` as above.
|
||||
|
||||
Inspect these examples to get a better feeling for this syntax: `https://github.com/molstar/molstar/blob/6edbae80db340134341631f669eec86543a0f1a8/src/mol-plugin-state/helpers/structure-selection-query.ts#L88-L580`
|
||||
|
||||
|
||||
Furthermore, a query made this way can be converted to a `Loci` object which is important in many parts of the libary:
|
||||
```typescript
|
||||
// Select residue 124 of chain A and convert to Loci
|
||||
const Q = MolScriptBuilder;
|
||||
var sel = Script.getStructureSelection(Q => Q.struct.generator.atomGroups({
|
||||
'chain-test': Q.core.rel.eq([Q.struct.atomProperty.macromolecular.auth_asym_id(), A]),
|
||||
'residue-test': Q.core.rel.eq([Q.struct.atomProperty.macromolecular.label_seq_id(), 124]),
|
||||
}), objdata)
|
||||
|
||||
let loci = StructureSelection.toLociWithSourceUnits(sel);
|
||||
```
|
||||
|
||||
### Query Functions
|
||||
|
||||
Instead of building expressions, query functions can be created directly, e.g.:
|
||||
|
||||
```ts
|
||||
import { atoms } from 'mol-model/structure/query/queries/generators';
|
||||
|
||||
const query = atoms({
|
||||
residueTest: ctx => {
|
||||
const seqId = StructureProperties.residue.label_seq_id(ctx.element);
|
||||
return seqId > 10 && seqId < 25;
|
||||
},
|
||||
});
|
||||
|
||||
const selection = query(new QueryContext(structure));
|
||||
// ...
|
||||
```
|
||||
|
||||
### Selection Schema
|
||||
|
||||
For simple selections, the `StructureElement.Schema` can be used to reference elements within a protein structure using mmCIF `atom_site` field names, e.g.:
|
||||
|
||||
```ts
|
||||
const ala121: StructureElement.Schema = { label_asym_id: 'A', label_seq_id: 121 };
|
||||
const residues: StructureElement.Schema = {
|
||||
items: {
|
||||
auth_asym_id: ['A', 'B'],
|
||||
auth_seq_id: [10, 11],
|
||||
}
|
||||
};
|
||||
|
||||
const loci = StructureElement.Loci.fromSchema(structure, residues);
|
||||
```
|
||||
|
||||
Usually, a code editor such as VS Code will auto-suggest all the available field names.
|
||||
|
||||
### Using the `hierarchy` manager
|
||||
|
||||
It is possible to select a subcomponent's data directly from the plugin manager.
|
||||
|
||||
```typescript
|
||||
import { Structure } from '../mol-model/structure';
|
||||
@@ -17,7 +142,7 @@ plugin.managers.camera.focusLoci(ligandLoci);
|
||||
plugin.managers.interactivity.lociSelects.select({ loci: ligandLoci });
|
||||
```
|
||||
|
||||
## Selection callbacks
|
||||
## Selection Events
|
||||
If you want to subscribe to selection events (e.g. to change external state in your application based on a user selection), you can use: `plugin.behaviors.interaction.click.subscribe`
|
||||
|
||||
Here's an example of passing in a React "set" function to update selected residue positions.
|
||||
@@ -49,62 +174,17 @@ plugin.behaviors.interaction.click.subscribe(
|
||||
)
|
||||
```
|
||||
|
||||
### `Molscript` language
|
||||
## Helper Functions
|
||||
|
||||
Molscript is a language for addressing crystallographic structures and is a part of the Mol* library found at `https://github.com/molstar/molstar/tree/master/src/mol-script`. It can be used against the Molstar plugin as a query language and transpiled against multiple external molecular visualization libraries(see [here](https://github.com/molstar/molstar/tree/master/src/mol-script/transpilers)).
|
||||
Given an `Expression`, `QueryFn`, or `StructureElement.Schema` it is possible to use `fromExpression/Query/Schema` functions on `StructureElement.Loci` and `StructureElement.Bundle`.
|
||||
|
||||
### Querying a structure for a specific chain and residue range (select residues with 12<res_id<200 of chain with auth_asym_id==A) :
|
||||
### `Viewer` app
|
||||
|
||||
```typescript
|
||||
import { compileIdListSelection } from 'molstar/lib/mol-script/util/id-list'
|
||||
The `Viewer` app provides the `structureInteractivity` function which allows easy selection/highlighting of the loaded structure. For example:
|
||||
|
||||
const query = compileIdListSelection('A 12-200', 'auth');
|
||||
window.molstar?.managers.structure.selection.fromCompiledQuery('add',query);
|
||||
```
|
||||
|
||||
## Selection Queries
|
||||
|
||||
Another way to create a selection is via a `SelectionQuery` object. This is a more programmatic way to create a selection. The following example shows how to select a chain and a residue range using a `SelectionQuery` object.
|
||||
This relies on the concept of `Expression` which is basically a intermediate representation between a Molscript statement and a selection query.
|
||||
|
||||
### Select residues 10-15 of chains A and F in a structure using a `SelectionQuery` object:
|
||||
|
||||
```typescript
|
||||
|
||||
import { MolScriptBuilder as MS, MolScriptBuilder } from 'molstar/lib/mol-script/language/builder';
|
||||
import { Expression } from 'molstar/lib/mol-script/language/expression';
|
||||
import { StructureSelectionQuery } from 'molstar/lib/mol-plugin-state/helpers/structure-selection-query'
|
||||
|
||||
|
||||
export function select_multiple() {
|
||||
|
||||
const args = [['A', 10, 15], ['F', 10, 15]]
|
||||
const groups: Expression[] = [];
|
||||
for (var chain of args) {
|
||||
groups.push(MS.struct.generator.atomGroups({
|
||||
"chain-test": MS.core.rel.eq([MolScriptBuilder.struct.atomProperty.macromolecular.auth_asym_id(), chain[0]]),
|
||||
"residue-test": MS.core.rel.inRange([MolScriptBuilder.struct.atomProperty.macromolecular.label_seq_id(), chain[1], chain[2]])
|
||||
}));
|
||||
}
|
||||
var sq = StructureSelectionQuery('residue_range_10_15_in_A_and_F', MS.struct.combinator.merge(groups))
|
||||
mstar.managers.structure.selection.fromSelectionQuery('set', sq)
|
||||
}
|
||||
```
|
||||
|
||||
Complex queries can be constructed by combining primitive queries at the level of [`chain-test`, `residue-test`, `entity-test`, etc] (https://github.com/molstar/molstar/blob/6edbae80db340134341631f669eec86543a0f1a8/src/mol-script/language/symbol-table/structure-query.ts#L88C4-L94C112) by combining them via logical connectives provided in the `MolscriptBuilder.core.rel` as above.
|
||||
|
||||
Inspect these examples to get a better feeling for this syntax: `https://github.com/molstar/molstar/blob/6edbae80db340134341631f669eec86543a0f1a8/src/mol-plugin-state/helpers/structure-selection-query.ts#L88-L580`
|
||||
|
||||
|
||||
Furthermore, a query made this way can be converted to a `Loci` object which is important in many parts of the libary:
|
||||
```typescript
|
||||
|
||||
// Select residue 124 of chain A and convert to Loci
|
||||
const Q = MolScriptBuilder;
|
||||
var sel = Script.getStructureSelection(Q => Q.struct.generator.atomGroups({
|
||||
'chain-test' : Q.core.rel.eq([Q.struct.atomProperty.macromolecular.auth_asym_id(), A]),
|
||||
"residue-test": Q.core.rel.eq([Q.struct.atomProperty.macromolecular.label_seq_id(), 124]),
|
||||
}), objdata)
|
||||
|
||||
let loci = StructureSelection.toLociWithSourceUnits(sel);
|
||||
```
|
||||
```ts
|
||||
viewer.structureInteractivity({
|
||||
elements: { beg_auth_seq_id: 10, end_auth_seq_id: 50 },
|
||||
action: 'select',
|
||||
});
|
||||
```
|
||||
152
docs/docs/plugin/superposition.md
Normal file
152
docs/docs/plugin/superposition.md
Normal file
@@ -0,0 +1,152 @@
|
||||
# Structure Superposition
|
||||
|
||||
Mol* provides utilities for superposing protein structures, including both sequence-independent (RMSD-based) and structure-based (TM-align) methods.
|
||||
|
||||
## RMSD-based Superposition
|
||||
|
||||
The basic superposition method uses the Kabsch algorithm to minimize RMSD between corresponding atoms:
|
||||
|
||||
```typescript
|
||||
import { superpose } from 'molstar/lib/mol-model/structure/structure/util/superposition';
|
||||
import { StructureSelection, QueryContext } from 'molstar/lib/mol-model/structure';
|
||||
import { compile } from 'molstar/lib/mol-script/runtime/query/compiler';
|
||||
import { MolScriptBuilder as MS } from 'molstar/lib/mol-script/language/builder';
|
||||
|
||||
// Create a query for C-alpha atoms
|
||||
const caQuery = compile<StructureSelection>(MS.struct.generator.atomGroups({
|
||||
'atom-test': MS.core.rel.eq([MS.struct.atomProperty.macromolecular.label_atom_id(), 'CA'])
|
||||
}));
|
||||
|
||||
// Get selections from two structures
|
||||
const sel1 = StructureSelection.toLociWithCurrentUnits(caQuery(new QueryContext(structure1)));
|
||||
const sel2 = StructureSelection.toLociWithCurrentUnits(caQuery(new QueryContext(structure2)));
|
||||
|
||||
// Compute superposition (returns transformation matrices)
|
||||
const transforms = superpose([sel1, sel2]);
|
||||
|
||||
// transforms[0].bTransform contains the Mat4 to superpose structure2 onto structure1
|
||||
```
|
||||
|
||||
## TM-align Superposition
|
||||
|
||||
TM-align is a structure-based alignment algorithm that produces the TM-score, a length-independent metric for comparing protein structures. Unlike RMSD, TM-score is normalized to [0, 1] and is more robust for comparing proteins of different sizes.
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```typescript
|
||||
import { tmAlign } from 'molstar/lib/mol-model/structure/structure/util/tm-align';
|
||||
import { StructureElement } from 'molstar/lib/mol-model/structure';
|
||||
|
||||
// Get C-alpha Loci from two structures (see selection examples above)
|
||||
const loci1: StructureElement.Loci = /* ... */;
|
||||
const loci2: StructureElement.Loci = /* ... */;
|
||||
|
||||
// Run TM-align
|
||||
const result = tmAlign(loci1, loci2);
|
||||
|
||||
console.log('TM-score (normalized by structure 1):', result.tmScoreA);
|
||||
console.log('TM-score (normalized by structure 2):', result.tmScoreB);
|
||||
console.log('RMSD:', result.rmsd);
|
||||
console.log('Aligned residues:', result.alignedLength);
|
||||
|
||||
// result.bTransform is a Mat4 to transform structure2 onto structure1
|
||||
```
|
||||
|
||||
### TM-align Result
|
||||
|
||||
The `tmAlign` function returns a `TMAlignResult` object with the following properties:
|
||||
|
||||
| Property | Type | Description |
|
||||
|----------|------|-------------|
|
||||
| `bTransform` | `Mat4` | Transformation matrix to superpose structure B onto A |
|
||||
| `tmScoreA` | `number` | TM-score normalized by length of structure A |
|
||||
| `tmScoreB` | `number` | TM-score normalized by length of structure B |
|
||||
| `rmsd` | `number` | RMSD of aligned residue pairs (in Angstroms) |
|
||||
| `alignedLength` | `number` | Number of aligned residue pairs |
|
||||
| `sequenceIdentity` | `number` | Sequence identity of aligned residues (0-1) |
|
||||
| `alignmentA` | `number[]` | Indices of aligned residues in structure A |
|
||||
| `alignmentB` | `number[]` | Indices of aligned residues in structure B |
|
||||
|
||||
### Understanding TM-score
|
||||
|
||||
The TM-score is calculated as:
|
||||
|
||||
$$\text{TM-score} = \frac{1}{L} \sum_{i=1}^{L_{ali}} \frac{1}{1 + (d_i/d_0)^2}$$
|
||||
|
||||
Where:
|
||||
- $L$ is the length of the reference protein
|
||||
- $L_{ali}$ is the number of aligned residues
|
||||
- $d_i$ is the distance between the $i$-th pair of aligned residues after superposition
|
||||
- $d_0 = 1.24 \sqrt[3]{L - 15} - 1.8$ is a length-dependent normalization factor
|
||||
|
||||
**TM-score interpretation:**
|
||||
- TM-score > 0.5: Generally indicates proteins with the same fold
|
||||
- TM-score > 0.17: Generally indicates proteins with random structural similarity
|
||||
|
||||
### Low-level API
|
||||
|
||||
For direct coordinate-based alignment without structures, use the `TMAlign` namespace:
|
||||
|
||||
```typescript
|
||||
import { TMAlign } from 'molstar/lib/mol-math/linear-algebra/3d/tm-align';
|
||||
|
||||
// Create position arrays
|
||||
const posA = TMAlign.Positions.empty(lengthA);
|
||||
const posB = TMAlign.Positions.empty(lengthB);
|
||||
|
||||
// Fill in coordinates
|
||||
for (let i = 0; i < lengthA; i++) {
|
||||
posA.x[i] = /* x coordinate */;
|
||||
posA.y[i] = /* y coordinate */;
|
||||
posA.z[i] = /* z coordinate */;
|
||||
}
|
||||
// ... similarly for posB
|
||||
|
||||
// Compute alignment
|
||||
const result = TMAlign.compute({ a: posA, b: posB });
|
||||
```
|
||||
|
||||
### Complete Example: Aligning Two PDB Structures
|
||||
|
||||
```typescript
|
||||
import { PluginContext } from 'molstar/lib/mol-plugin/context';
|
||||
import { MolScriptBuilder as MS } from 'molstar/lib/mol-script/language/builder';
|
||||
import { compile } from 'molstar/lib/mol-script/runtime/query/compiler';
|
||||
import { StructureSelection, QueryContext, StructureElement } from 'molstar/lib/mol-model/structure';
|
||||
import { tmAlign } from 'molstar/lib/mol-model/structure/structure/util/tm-align';
|
||||
import { StateTransforms } from 'molstar/lib/mol-plugin-state/transforms';
|
||||
import { Mat4 } from 'molstar/lib/mol-math/linear-algebra';
|
||||
|
||||
async function alignStructures(plugin: PluginContext, structure1: any, structure2: any) {
|
||||
// Query for C-alpha atoms in chain A
|
||||
const caQuery = compile<StructureSelection>(MS.struct.generator.atomGroups({
|
||||
'chain-test': MS.core.rel.eq([MS.struct.atomProperty.macromolecular.auth_asym_id(), 'A']),
|
||||
'atom-test': MS.core.rel.eq([MS.struct.atomProperty.macromolecular.label_atom_id(), 'CA'])
|
||||
}));
|
||||
|
||||
// Get structure data
|
||||
const data1 = structure1.cell?.obj?.data;
|
||||
const data2 = structure2.cell?.obj?.data;
|
||||
|
||||
// Create selections
|
||||
const sel1 = StructureSelection.toLociWithCurrentUnits(caQuery(new QueryContext(data1)));
|
||||
const sel2 = StructureSelection.toLociWithCurrentUnits(caQuery(new QueryContext(data2)));
|
||||
|
||||
// Run TM-align
|
||||
const result = tmAlign(sel1, sel2);
|
||||
|
||||
// Apply transformation to structure2
|
||||
const b = plugin.state.data.build().to(structure2)
|
||||
.insert(StateTransforms.Model.TransformStructureConformation, {
|
||||
transform: { name: 'matrix', params: { data: result.bTransform, transpose: false } }
|
||||
});
|
||||
await plugin.runTask(plugin.state.data.updateTree(b));
|
||||
|
||||
return result;
|
||||
}
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- Zhang Y, Skolnick J. "TM-align: a protein structure alignment algorithm based on the TM-score." *Nucleic Acids Research* 33, 2302-2309 (2005). DOI: [10.1093/nar/gki524](https://doi.org/10.1093/nar/gki524)
|
||||
- Kabsch W. "A solution for the best rotation to relate two sets of vectors." *Acta Crystallographica* A32, 922-923 (1976).
|
||||
@@ -25,7 +25,6 @@ markdown_extensions:
|
||||
generic: true
|
||||
# Scripts for rendering Latex equations (in addition to pymdownx.arithmatex):
|
||||
extra_javascript:
|
||||
- https://polyfill.io/v3/polyfill.min.js?features=es6
|
||||
- https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js
|
||||
nav:
|
||||
- 'index.md'
|
||||
@@ -34,10 +33,13 @@ nav:
|
||||
- Examples: plugin/examples.md
|
||||
- Custom Library: 'plugin/custom-library.md'
|
||||
- Selections: 'plugin/selections.md'
|
||||
- Superposition: 'plugin/superposition.md'
|
||||
- Viewer State: 'plugin/viewer-state.md'
|
||||
- Data State: 'plugin/data-state.md'
|
||||
- File Formats: 'plugin/file-formats.md'
|
||||
- CIF Schemas: 'plugin/cif-schemas.md'
|
||||
- Managers:
|
||||
- Markdown Extensions: 'plugin/managers/markdown-extensions.md'
|
||||
- State Transforms:
|
||||
- Custom Trajectory: 'plugin/transforms/custom-trajectory.md'
|
||||
- Custom Conformation: 'plugin/transforms/custom-conformation.md'
|
||||
@@ -56,7 +58,8 @@ nav:
|
||||
- MolViewSpec: 'extensions/mvs/index.md'
|
||||
- wwPDB StructConn: 'extensions/struct-conn.md'
|
||||
- Tunnels: 'extensions/tunnels.md'
|
||||
- Interactions: 'extensions/interactions.md'
|
||||
- Misc:
|
||||
- Interesting PDB entries: misc/interesting-pdb-entries.md
|
||||
- Exporting component data: exporting-components.md
|
||||
- Exporting component data: misc/exporting-components.md
|
||||
repo_url: https://github.com/molstar/docs
|
||||
|
||||
111
eslint.config.mjs
Normal file
111
eslint.config.mjs
Normal file
@@ -0,0 +1,111 @@
|
||||
import { defineConfig } from "eslint/config";
|
||||
import globals from "globals";
|
||||
import typescriptEslint from "@typescript-eslint/eslint-plugin";
|
||||
import tsParser from "@typescript-eslint/parser";
|
||||
|
||||
export default defineConfig([{
|
||||
ignores: [
|
||||
"node_modules/*",
|
||||
"build/*",
|
||||
"deploy/*",
|
||||
"docs/site/*",
|
||||
"lib/*",
|
||||
"eslint.config.mjs",
|
||||
"build.mjs",
|
||||
]
|
||||
},{
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.browser,
|
||||
...globals.node,
|
||||
},
|
||||
|
||||
ecmaVersion: 2018,
|
||||
sourceType: "module",
|
||||
|
||||
parserOptions: {
|
||||
ecmaFeatures: {
|
||||
impliedStrict: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
rules: {
|
||||
indent: "off",
|
||||
"arrow-parens": ["off", "as-needed"],
|
||||
"brace-style": ["error", "1tbs", {
|
||||
allowSingleLine: true,
|
||||
}],
|
||||
"comma-spacing": "off",
|
||||
"space-infix-ops": "off",
|
||||
"comma-dangle": "off",
|
||||
quotes: ["warn", "single", { "allowTemplateLiterals": true, "avoidEscape": true }],
|
||||
eqeqeq: ["error", "smart"],
|
||||
"import/order": "off",
|
||||
"no-eval": "warn",
|
||||
"no-extend-native": "warn",
|
||||
"no-new-wrappers": "warn",
|
||||
"no-trailing-spaces": "error",
|
||||
"no-unsafe-finally": "warn",
|
||||
"no-self-compare": "warn",
|
||||
"no-var": "error",
|
||||
"spaced-comment": "error",
|
||||
semi: "warn",
|
||||
"no-restricted-syntax": ["error", {
|
||||
selector: "ExportDefaultDeclaration",
|
||||
message: "Default exports are not allowed",
|
||||
}],
|
||||
"no-throw-literal": "error",
|
||||
"key-spacing": "error",
|
||||
"object-curly-spacing": ["error", "always"],
|
||||
"array-bracket-spacing": "error",
|
||||
"space-in-parens": "error",
|
||||
"computed-property-spacing": "error",
|
||||
"prefer-const": ["error", {
|
||||
destructuring: "all",
|
||||
ignoreReadBeforeAssign: false,
|
||||
}],
|
||||
"space-before-function-paren": "off",
|
||||
"func-call-spacing": "off",
|
||||
"no-multi-spaces": "error",
|
||||
"block-spacing": "error",
|
||||
"keyword-spacing": "warn",
|
||||
"space-before-blocks": "error",
|
||||
"semi-spacing": "error",
|
||||
"no-constant-binary-expression": "error",
|
||||
},
|
||||
}, {
|
||||
files: ["**/*.ts", "**/*.tsx"],
|
||||
|
||||
plugins: {
|
||||
"@typescript-eslint": typescriptEslint,
|
||||
},
|
||||
|
||||
languageOptions: {
|
||||
parser: tsParser,
|
||||
ecmaVersion: 5,
|
||||
sourceType: "module",
|
||||
|
||||
parserOptions: {
|
||||
project: ["tsconfig.eslint.json"],
|
||||
},
|
||||
},
|
||||
|
||||
rules: {
|
||||
"@typescript-eslint/ban-types": "off",
|
||||
"@typescript-eslint/class-name-casing": "off",
|
||||
"@typescript-eslint/member-delimiter-style": ["off", {
|
||||
multiline: {
|
||||
delimiter: "none",
|
||||
requireLast: true,
|
||||
},
|
||||
|
||||
singleline: {
|
||||
delimiter: "semi",
|
||||
requireLast: false,
|
||||
},
|
||||
}],
|
||||
"@typescript-eslint/prefer-namespace-keyword": "warn",
|
||||
"@typescript-eslint/semi": ["off", null],
|
||||
},
|
||||
}]);
|
||||
BIN
examples/audio/AudioMOM1_A.mp3
Normal file
BIN
examples/audio/AudioMOM1_A.mp3
Normal file
Binary file not shown.
BIN
examples/audio/AudioMOM1_B.mp3
Normal file
BIN
examples/audio/AudioMOM1_B.mp3
Normal file
Binary file not shown.
BIN
examples/audio/AudioMOM1_C.mp3
Normal file
BIN
examples/audio/AudioMOM1_C.mp3
Normal file
Binary file not shown.
BIN
examples/audio/AudioMOM1_D.mp3
Normal file
BIN
examples/audio/AudioMOM1_D.mp3
Normal file
Binary file not shown.
456
examples/docking/ligands_1.sdf
Normal file
456
examples/docking/ligands_1.sdf
Normal file
@@ -0,0 +1,456 @@
|
||||
forcefield_3904
|
||||
RDKit 3D
|
||||
|
||||
49 52 0 0 0 0 0 0 0 0999 V2000
|
||||
7.1950 23.7840 6.1780 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
5.7810 23.6440 6.1320 O 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
5.0380 24.7500 6.4550 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
4.8270 25.8570 5.6380 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
4.0460 26.9150 6.0970 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
3.4760 26.8670 7.3710 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
3.6720 25.7630 8.2160 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
3.0720 25.7780 9.4800 N 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
1.8090 25.4470 9.9650 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0.8080 26.1730 9.4160 N 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-0.4770 25.9480 9.8040 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-1.5110 26.6810 9.2540 O 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-1.0950 27.9270 8.6960 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-2.1890 28.9860 8.9110 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-1.6300 30.4110 8.7600 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-2.7130 31.4650 8.9780 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-3.4040 31.2910 10.3270 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-3.9520 29.8780 10.4990 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-2.8690 28.8240 10.2810 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-0.7400 24.9710 10.7610 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-1.8850 24.4940 11.3660 N 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-1.4690 23.5570 12.1930 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-0.1090 23.4080 12.1480 N 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0.3700 24.3040 11.2380 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
1.6480 24.4860 10.8910 N 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
4.4600 24.7130 7.7330 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
7.5263 23.8168 7.2264 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
7.6649 22.9280 5.6716 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
7.4879 24.7155 5.6716 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
5.2751 25.8961 4.6342 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
3.8776 27.7913 5.4538 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
2.8616 27.7104 7.7192 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
3.6420 26.0930 10.2520 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-0.1673 28.2555 9.1874 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-0.9189 27.8009 7.6175 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-2.9466 28.8274 8.1294 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-0.8310 30.5615 9.5009 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-1.2424 30.5222 7.7366 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-2.2524 32.4632 8.9392 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-3.4689 31.3496 8.1873 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-2.6781 31.4924 11.1285 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-4.2475 31.9954 10.3749 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-4.3529 29.7723 11.5179 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-4.7404 29.7213 9.7481 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-2.1096 28.9239 11.0705 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-3.3427 27.8318 10.3148 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-2.1334 22.9663 12.8408 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0.4510 22.7600 12.6820 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
4.6312 23.8345 8.3724 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
1 2 1 0
|
||||
2 3 1 0
|
||||
3 4 2 0
|
||||
4 5 1 0
|
||||
5 6 2 0
|
||||
6 7 1 0
|
||||
7 8 1 0
|
||||
8 9 1 0
|
||||
9 10 2 0
|
||||
10 11 1 0
|
||||
11 12 1 0
|
||||
12 13 1 0
|
||||
13 14 1 0
|
||||
14 15 1 0
|
||||
15 16 1 0
|
||||
16 17 1 0
|
||||
17 18 1 0
|
||||
18 19 1 0
|
||||
11 20 2 0
|
||||
20 21 1 0
|
||||
21 22 2 0
|
||||
22 23 1 0
|
||||
23 24 1 0
|
||||
24 25 2 0
|
||||
7 26 2 0
|
||||
26 3 1 0
|
||||
25 9 1 0
|
||||
19 14 1 0
|
||||
24 20 1 0
|
||||
1 27 1 0
|
||||
1 28 1 0
|
||||
1 29 1 0
|
||||
4 30 1 0
|
||||
5 31 1 0
|
||||
6 32 1 0
|
||||
8 33 1 0
|
||||
13 34 1 0
|
||||
13 35 1 0
|
||||
14 36 1 0
|
||||
15 37 1 0
|
||||
15 38 1 0
|
||||
16 39 1 0
|
||||
16 40 1 0
|
||||
17 41 1 0
|
||||
17 42 1 0
|
||||
18 43 1 0
|
||||
18 44 1 0
|
||||
19 45 1 0
|
||||
19 46 1 0
|
||||
22 47 1 0
|
||||
23 48 1 0
|
||||
26 49 1 0
|
||||
M END
|
||||
> <ligandCode> (1)
|
||||
forcefield_3904
|
||||
|
||||
> <ligandName> (1)
|
||||
klr_22
|
||||
|
||||
$$$$
|
||||
forcefield_3905
|
||||
RDKit 3D
|
||||
|
||||
49 52 0 0 0 0 0 0 0 0999 V2000
|
||||
6.5460 25.1350 3.8360 N 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
5.2550 25.5560 3.9960 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
4.5630 25.8360 3.0240 O 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
4.7190 25.6170 5.3820 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
4.0120 26.7570 5.7730 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
3.4880 26.8570 7.0690 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
3.6630 25.8340 8.0050 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
3.1640 25.8720 9.3110 N 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
1.9510 25.5250 9.9030 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0.8900 26.1930 9.3960 N 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-0.3560 25.9480 9.8850 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-1.4490 26.6220 9.3800 O 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-1.1050 27.7730 8.6070 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-1.7010 29.0180 9.2810 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-1.5340 30.2520 8.3770 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-2.5490 31.3650 8.6570 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-3.0430 31.3400 10.0950 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-3.7320 30.0170 10.4330 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-3.1730 28.8170 9.6630 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-0.5160 25.0110 10.9050 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-1.5980 24.5310 11.6140 N 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-1.0930 23.6490 12.4490 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0.2630 23.5390 12.3140 N 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0.6490 24.4020 11.3310 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
1.8910 24.6070 10.8850 N 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
4.3890 24.7010 7.5990 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
4.9170 24.5890 6.3060 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
7.0340 24.6220 4.5560 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
6.8360 24.9760 2.8790 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
3.8658 27.5811 5.0592 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
2.9275 27.7591 7.3554 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
3.7800 26.2290 10.0270 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-0.0105 27.8693 8.5543 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-1.5056 27.6720 7.5875 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-1.1446 29.1858 10.2149 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-0.5231 30.6584 8.5280 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-1.7027 29.9170 7.3429 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-2.0722 32.3370 8.4626 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-3.4156 31.2068 7.9983 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-2.1848 31.4776 10.7693 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-3.7762 32.1504 10.2201 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-3.6091 29.8266 11.5094 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-4.7879 30.1213 10.1428 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-3.2575 27.9194 10.2932 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-3.7539 28.7064 8.7355 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-1.6897 23.0698 13.1690 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0.8800 22.9330 12.8360 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
4.5467 23.8809 8.3150 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
5.4866 23.6927 6.0193 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
1 2 1 0
|
||||
2 3 2 0
|
||||
2 4 1 0
|
||||
4 5 2 0
|
||||
5 6 1 0
|
||||
6 7 2 0
|
||||
7 8 1 0
|
||||
8 9 1 0
|
||||
9 10 2 0
|
||||
10 11 1 0
|
||||
11 12 1 0
|
||||
12 13 1 0
|
||||
13 14 1 0
|
||||
14 15 1 0
|
||||
15 16 1 0
|
||||
16 17 1 0
|
||||
17 18 1 0
|
||||
18 19 1 0
|
||||
11 20 2 0
|
||||
20 21 1 0
|
||||
21 22 2 0
|
||||
22 23 1 0
|
||||
23 24 1 0
|
||||
24 25 2 0
|
||||
7 26 1 0
|
||||
26 27 2 0
|
||||
27 4 1 0
|
||||
25 9 1 0
|
||||
19 14 1 0
|
||||
24 20 1 0
|
||||
1 28 1 0
|
||||
1 29 1 0
|
||||
5 30 1 0
|
||||
6 31 1 0
|
||||
8 32 1 0
|
||||
13 33 1 0
|
||||
13 34 1 0
|
||||
14 35 1 0
|
||||
15 36 1 0
|
||||
15 37 1 0
|
||||
16 38 1 0
|
||||
16 39 1 0
|
||||
17 40 1 0
|
||||
17 41 1 0
|
||||
18 42 1 0
|
||||
18 43 1 0
|
||||
19 44 1 0
|
||||
19 45 1 0
|
||||
22 46 1 0
|
||||
23 47 1 0
|
||||
26 48 1 0
|
||||
27 49 1 0
|
||||
M END
|
||||
> <ligandCode> (2)
|
||||
forcefield_3905
|
||||
|
||||
> <ligandName> (2)
|
||||
1oiy-1
|
||||
|
||||
$$$$
|
||||
forcefield_14264
|
||||
RDKit 3D
|
||||
|
||||
50 53 0 0 0 0 0 0 0 0999 V2000
|
||||
4.9220 23.4040 3.0090 N 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
5.8970 24.7200 3.4040 S 0 0 0 0 0 6 0 0 0 0 0 0
|
||||
7.2120 24.2200 3.7260 O 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
5.6670 25.6980 2.3670 O 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
5.1310 25.2890 4.8970 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
4.3720 26.4580 4.8910 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
3.7730 26.8990 6.0760 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
3.9290 26.1970 7.2780 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
3.3430 26.5790 8.4890 N 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
2.1400 26.2820 9.1290 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
1.0830 26.9670 8.6370 N 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-0.1520 26.7740 9.1730 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-1.2430 27.4630 8.6800 O 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-0.9280 28.7750 8.2140 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-2.2060 29.6320 8.2420 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-3.2120 29.0810 9.2730 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-4.1810 30.1570 9.7450 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-3.4520 31.3060 10.4440 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-2.0250 31.5210 9.9360 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-1.8770 31.1190 8.4740 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-0.3060 25.8730 10.2240 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-1.3770 25.4460 10.9810 N 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-0.8720 24.5730 11.8270 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0.4750 24.4190 11.6520 N 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0.8530 25.2430 10.6320 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
2.0880 25.3990 10.1410 N 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
4.7090 25.0260 7.2550 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
5.3130 24.5730 6.0780 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
4.1960 23.3080 3.7210 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
5.4460 22.5390 2.8810 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
4.2447 27.0304 3.9603 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
3.1666 27.8167 6.0634 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
3.8380 27.2640 9.0420 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-0.1661 29.2261 8.8668 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-0.5358 28.7227 7.1876 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-2.6885 29.5690 7.2555 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-3.7847 28.2635 8.8106 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-2.6467 28.7218 10.1456 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-4.7231 30.5555 8.8747 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-4.8753 29.7014 10.4664 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-4.0232 32.2317 10.2804 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-3.3803 31.0434 11.5098 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-1.7667 32.5851 10.0403 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-1.3511 30.8895 10.5336 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-2.5603 31.7316 7.8675 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-0.8284 31.2816 8.1841 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-1.4619 24.0333 12.5825 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
1.0910 23.8110 12.1720 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
4.8468 24.4538 8.1843 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
5.9261 23.6598 6.0846 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
1 2 1 0
|
||||
2 3 2 0
|
||||
2 4 2 0
|
||||
2 5 1 0
|
||||
5 6 2 0
|
||||
6 7 1 0
|
||||
7 8 2 0
|
||||
8 9 1 0
|
||||
9 10 1 0
|
||||
10 11 2 0
|
||||
11 12 1 0
|
||||
12 13 1 0
|
||||
13 14 1 0
|
||||
14 15 1 0
|
||||
15 16 1 0
|
||||
16 17 1 0
|
||||
17 18 1 0
|
||||
18 19 1 0
|
||||
19 20 1 0
|
||||
12 21 2 0
|
||||
21 22 1 0
|
||||
22 23 2 0
|
||||
23 24 1 0
|
||||
24 25 1 0
|
||||
25 26 2 0
|
||||
8 27 1 0
|
||||
27 28 2 0
|
||||
28 5 1 0
|
||||
26 10 1 0
|
||||
20 15 1 0
|
||||
25 21 1 0
|
||||
1 29 1 0
|
||||
1 30 1 0
|
||||
6 31 1 0
|
||||
7 32 1 0
|
||||
9 33 1 0
|
||||
14 34 1 0
|
||||
14 35 1 0
|
||||
15 36 1 0
|
||||
16 37 1 0
|
||||
16 38 1 0
|
||||
17 39 1 0
|
||||
17 40 1 0
|
||||
18 41 1 0
|
||||
18 42 1 0
|
||||
19 43 1 0
|
||||
19 44 1 0
|
||||
20 45 1 0
|
||||
20 46 1 0
|
||||
23 47 1 0
|
||||
24 48 1 0
|
||||
27 49 1 0
|
||||
28 50 1 0
|
||||
M END
|
||||
> <ligandCode> (3)
|
||||
forcefield_14264
|
||||
|
||||
> <ligandName> (3)
|
||||
1h1s
|
||||
|
||||
$$$$
|
||||
forcefield_14265
|
||||
RDKit 3D
|
||||
|
||||
50 53 0 0 0 0 0 0 0 0999 V2000
|
||||
5.9560 25.0880 4.1850 N 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
5.6880 24.2300 5.6100 S 0 0 0 0 0 6 0 0 0 0 0 0
|
||||
4.9010 23.0800 5.2270 O 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
6.9470 24.1160 6.3060 O 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
4.6500 25.3510 6.5050 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
4.3190 26.5790 5.9340 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
3.4970 27.4490 6.6410 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
3.0220 27.0950 7.9100 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
3.3680 25.8770 8.5100 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
2.9060 25.4620 9.7630 N 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
1.6520 25.1280 10.2760 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0.6590 25.9320 9.8350 N 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-0.6150 25.7270 10.2650 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-1.6410 26.5420 9.8330 O 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-1.2650 27.5510 8.8940 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-1.4150 28.9670 9.4830 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-2.0650 29.8960 8.4420 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-2.7130 31.1080 9.0990 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-3.8410 30.6980 10.0490 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-3.6490 29.3080 10.6570 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-2.1750 28.9600 10.8270 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-0.8720 24.6910 11.1610 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-2.0060 24.2140 11.7870 N 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-1.5910 23.2030 12.5210 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-0.2430 23.0050 12.3980 N 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0.2320 23.9470 11.5330 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
1.5000 24.1080 11.1380 N 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
4.1890 25.0030 7.7800 C 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
6.4350 24.4790 3.5180 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
5.1080 25.4920 3.7910 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
4.7020 26.8549 4.9404 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
3.2187 28.4186 6.2023 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
2.3612 27.7900 8.4488 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
3.5640 25.4960 10.5280 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-0.2150 27.3950 8.6054 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-1.9312 27.4715 8.0223 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-0.4134 29.3591 9.7135 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-1.2920 30.2413 7.7397 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-2.8482 29.3296 7.9168 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-1.9484 31.6568 9.6685 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-3.1423 31.7400 8.3076 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-3.8921 31.4320 10.8667 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-4.7682 30.6682 9.4579 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-4.1367 29.2806 11.6426 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-4.0960 28.5721 9.9724 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-1.7122 29.6974 11.4994 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-2.1140 27.9439 11.2440 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
-2.2486 22.5915 13.1563 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0.3120 22.2980 12.8550 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
4.4733 24.0335 8.2150 H 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
1 2 1 0
|
||||
2 3 2 0
|
||||
2 4 2 0
|
||||
2 5 1 0
|
||||
5 6 2 0
|
||||
6 7 1 0
|
||||
7 8 2 0
|
||||
8 9 1 0
|
||||
9 10 1 0
|
||||
10 11 1 0
|
||||
11 12 2 0
|
||||
12 13 1 0
|
||||
13 14 1 0
|
||||
14 15 1 0
|
||||
15 16 1 0
|
||||
16 17 1 0
|
||||
17 18 1 0
|
||||
18 19 1 0
|
||||
19 20 1 0
|
||||
20 21 1 0
|
||||
13 22 2 0
|
||||
22 23 1 0
|
||||
23 24 2 0
|
||||
24 25 1 0
|
||||
25 26 1 0
|
||||
26 27 2 0
|
||||
9 28 2 0
|
||||
28 5 1 0
|
||||
27 11 1 0
|
||||
21 16 1 0
|
||||
26 22 1 0
|
||||
1 29 1 0
|
||||
1 30 1 0
|
||||
6 31 1 0
|
||||
7 32 1 0
|
||||
8 33 1 0
|
||||
10 34 1 0
|
||||
15 35 1 0
|
||||
15 36 1 0
|
||||
16 37 1 0
|
||||
17 38 1 0
|
||||
17 39 1 0
|
||||
18 40 1 0
|
||||
18 41 1 0
|
||||
19 42 1 0
|
||||
19 43 1 0
|
||||
20 44 1 0
|
||||
20 45 1 0
|
||||
21 46 1 0
|
||||
21 47 1 0
|
||||
24 48 1 0
|
||||
25 49 1 0
|
||||
28 50 1 0
|
||||
M END
|
||||
> <ligandCode> (4)
|
||||
forcefield_14265
|
||||
|
||||
> <ligandName> (4)
|
||||
1oiu
|
||||
|
||||
$$$$
|
||||
9013
examples/docking/receptor_1.pdb
Normal file
9013
examples/docking/receptor_1.pdb
Normal file
File diff suppressed because it is too large
Load Diff
4052
examples/mvs/kinase-story.mvsj
Normal file
4052
examples/mvs/kinase-story.mvsj
Normal file
File diff suppressed because it is too large
Load Diff
BIN
examples/trajectory/protein.dcd
Normal file
BIN
examples/trajectory/protein.dcd
Normal file
Binary file not shown.
BIN
examples/trajectory/protein.nc
Normal file
BIN
examples/trajectory/protein.nc
Normal file
Binary file not shown.
264
examples/trajectory/protein.parm7
Normal file
264
examples/trajectory/protein.parm7
Normal file
@@ -0,0 +1,264 @@
|
||||
%VERSION VERSION_STAMP = V0001.000 DATE = 11/04/25 11:55:47
|
||||
%FLAG TITLE
|
||||
%FORMAT(20a4)
|
||||
alanine-dipeptide.solvated.pdb
|
||||
%FLAG POINTERS
|
||||
%FORMAT(10I8)
|
||||
22 7 12 9 25 11 39 19 0 0
|
||||
99 3 9 11 19 7 11 20 0 0
|
||||
0 0 0 0 0 0 0 1 10 0
|
||||
0 1
|
||||
%FLAG ATOM_NAME
|
||||
%FORMAT(20a4)
|
||||
H1 CH3 H2 H3 C O N H CA HA CB HB1 HB2 HB3 C O N H C H1
|
||||
H2 H3
|
||||
%FLAG ATOMIC_NUMBER
|
||||
%FORMAT(10I8)
|
||||
1 6 1 1 6 8 7 1 6 1
|
||||
6 1 1 1 6 8 7 1 6 1
|
||||
1 1
|
||||
%FLAG RESIDUE_LABEL
|
||||
%FORMAT(20a4)
|
||||
ACE ALA NME
|
||||
%FLAG RESIDUE_POINTER
|
||||
%FORMAT(10I8)
|
||||
1 7 17
|
||||
%FLAG RESIDUE_NUMBER
|
||||
%FORMAT(20I4)
|
||||
1 2 3
|
||||
%FLAG RESIDUE_ICODE
|
||||
%FORMAT(20a4)
|
||||
|
||||
%FLAG RESIDUE_CHAINID
|
||||
%FORMAT(20a4)
|
||||
B B B
|
||||
%FLAG SOLVENT_POINTERS
|
||||
%FORMAT(3I8)
|
||||
0 1 0
|
||||
%FLAG ATOMS_PER_MOLECULE
|
||||
%FORMAT(10I8)
|
||||
22
|
||||
%FLAG MASS
|
||||
%FORMAT(5E16.8)
|
||||
3.02400000E+00 5.96200000E+00 3.02400000E+00 3.02400000E+00 1.20100000E+01
|
||||
1.60000000E+01 1.19940000E+01 3.02400000E+00 9.99400000E+00 3.02400000E+00
|
||||
5.96200000E+00 3.02400000E+00 3.02400000E+00 3.02400000E+00 1.20100000E+01
|
||||
1.60000000E+01 1.19940000E+01 3.02400000E+00 5.96200000E+00 3.02400000E+00
|
||||
3.02400000E+00 3.02400000E+00
|
||||
%FLAG CHARGE
|
||||
%FORMAT(5E16.8)
|
||||
2.04636429E+00 -6.67300626E+00 2.04636429E+00 2.04636429E+00 1.08823576E+01
|
||||
-1.03484442E+01 -7.57501011E+00 4.95464337E+00 6.14091510E-01 1.49969529E+00
|
||||
-3.32556975E+00 1.09880469E+00 1.09880469E+00 1.09880469E+00 1.08841798E+01
|
||||
-1.03484442E+01 -7.57501011E+00 4.95464337E+00 -2.71512270E+00 1.77849648E+00
|
||||
1.77849648E+00 1.77849648E+00
|
||||
%FLAG AMBER_ATOM_TYPE
|
||||
%FORMAT(20a4)
|
||||
a0 a1 a0 a0 a2 a3 a4 a5 a1 a6 a1 a0 a0 a0 a2 a3 a4 a5 a1 a6
|
||||
a6 a6
|
||||
%FLAG ATOM_TYPE_INDEX
|
||||
%FORMAT(10I8)
|
||||
1 2 1 1 3 4 5 6 2 7
|
||||
2 1 1 1 3 4 5 6 2 7
|
||||
7 7
|
||||
%FLAG NONBONDED_PARM_INDEX
|
||||
%FORMAT(10I8)
|
||||
1 2 4 7 11 16 22 2 3 5
|
||||
8 12 17 23 4 5 6 9 13 18
|
||||
24 7 8 9 10 14 19 25 11 12
|
||||
13 14 15 20 26 16 17 18 19 20
|
||||
21 27 22 23 24 25 26 27 28
|
||||
%FLAG LENNARD_JONES_ACOEF
|
||||
%FORMAT(5E16.8)
|
||||
7.51607703E+03 9.71708117E+04 1.04308023E+06 8.61541883E+04 9.24822269E+05
|
||||
8.19971662E+05 5.44261042E+04 6.47841732E+05 5.74393458E+05 3.79876399E+05
|
||||
8.96776989E+04 9.95480466E+05 8.82619071E+05 6.06829343E+05 9.44293233E+05
|
||||
1.07193645E+02 2.56678134E+03 2.27577560E+03 1.02595236E+03 2.12601181E+03
|
||||
1.39982777E-01 4.98586847E+03 6.78771368E+04 6.01816484E+04 3.69471530E+04
|
||||
6.20665998E+04 5.94667299E+01 3.25969625E+03
|
||||
%FLAG LENNARD_JONES_BCOEF
|
||||
%FORMAT(5E16.8)
|
||||
2.17257828E+01 1.26919150E+02 6.75612247E+02 1.12529845E+02 5.99015525E+02
|
||||
5.31102864E+02 1.11805549E+02 6.26720080E+02 5.55666449E+02 5.64885984E+02
|
||||
1.36131731E+02 7.36907417E+02 6.53361429E+02 6.77220874E+02 8.01323529E+02
|
||||
2.59456373E+00 2.06278363E+01 1.82891803E+01 1.53505284E+01 2.09604198E+01
|
||||
9.37598976E-02 1.76949863E+01 1.06076943E+02 9.40505981E+01 9.21192137E+01
|
||||
1.13252062E+02 1.93248820E+00 1.43076527E+01
|
||||
%FLAG NUMBER_EXCLUDED_ATOMS
|
||||
%FORMAT(10I8)
|
||||
6 7 4 3 7 3 10 4 10 7
|
||||
6 3 2 1 7 3 5 4 3 2
|
||||
1 1
|
||||
%FLAG EXCLUDED_ATOMS_LIST
|
||||
%FORMAT(10I8)
|
||||
2 3 4 5 6 7 3 4 5 6
|
||||
7 8 9 4 5 6 7 5 6 7
|
||||
6 7 8 9 10 11 15 7 8 9
|
||||
8 9 10 11 12 13 14 15 16 17
|
||||
9 10 11 15 10 11 12 13 14 15
|
||||
16 17 18 19 11 12 13 14 15 16
|
||||
17 12 13 14 15 16 17 13 14 15
|
||||
14 15 15 16 17 18 19 20 21 22
|
||||
17 18 19 18 19 20 21 22 19 20
|
||||
21 22 20 21 22 21 22 22 0
|
||||
%FLAG BOND_FORCE_CONSTANT
|
||||
%FORMAT(5E16.8)
|
||||
3.40000000E+02 4.34000000E+02 3.17000000E+02 5.70000000E+02 4.90000000E+02
|
||||
3.37000000E+02 3.10000000E+02
|
||||
%FLAG BOND_EQUIL_VALUE
|
||||
%FORMAT(5E16.8)
|
||||
1.09000000E+00 1.01000000E+00 1.52200000E+00 1.22900000E+00 1.33500000E+00
|
||||
1.44900000E+00 1.52600000E+00
|
||||
%FLAG BONDS_INC_HYDROGEN
|
||||
%FORMAT(10I8)
|
||||
0 3 1 3 6 1 3 9 1 18
|
||||
21 2 24 27 1 30 33 1 30 36
|
||||
1 30 39 1 48 51 2 54 57 1
|
||||
54 60 1 54 63 1
|
||||
%FLAG BONDS_WITHOUT_HYDROGEN
|
||||
%FORMAT(10I8)
|
||||
3 12 3 12 15 4 12 18 5 18
|
||||
24 6 24 42 3 24 30 7 42 48
|
||||
5 42 45 4 48 54 6
|
||||
%FLAG ANGLE_FORCE_CONSTANT
|
||||
%FORMAT(5E16.8)
|
||||
3.50000000E+01 5.00000000E+01 5.00000000E+01 5.00000000E+01 8.00000000E+01
|
||||
7.00000000E+01 5.00000000E+01 8.00000000E+01 8.00000000E+01 6.30000000E+01
|
||||
6.30000000E+01
|
||||
%FLAG ANGLE_EQUIL_VALUE
|
||||
%FORMAT(5E16.8)
|
||||
1.91113553E+00 1.91113553E+00 2.09439510E+00 2.06018665E+00 2.10137642E+00
|
||||
2.03505391E+00 2.12755636E+00 2.14500965E+00 1.91462619E+00 1.92160751E+00
|
||||
1.93906080E+00
|
||||
%FLAG ANGLES_INC_HYDROGEN
|
||||
%FORMAT(10I8)
|
||||
0 3 6 1 0 3 9 1 0 3
|
||||
12 2 6 3 9 1 6 3 12 2
|
||||
9 3 12 2 12 18 21 3 18 24
|
||||
27 2 21 18 24 4 24 30 33 2
|
||||
24 30 36 2 24 30 39 2 27 24
|
||||
30 2 27 24 42 2 33 30 36 1
|
||||
33 30 39 1 36 30 39 1 42 48
|
||||
51 3 48 54 57 2 48 54 60 2
|
||||
48 54 63 2 51 48 54 4 57 54
|
||||
60 1 57 54 63 1 60 54 63 1
|
||||
%FLAG ANGLES_WITHOUT_HYDROGEN
|
||||
%FORMAT(10I8)
|
||||
3 12 15 5 3 12 18 6 12 18
|
||||
24 7 15 12 18 8 18 24 30 9
|
||||
18 24 42 10 24 42 45 5 24 42
|
||||
48 6 30 24 42 11 42 48 54 7
|
||||
45 42 48 8
|
||||
%FLAG DIHEDRAL_FORCE_CONSTANT
|
||||
%FORMAT(5E16.8)
|
||||
8.00000000E-01 8.00000000E-02 2.50000000E+00 2.50000000E+00 2.00000000E+00
|
||||
1.55555556E-01 1.10000000E+00 0.00000000E+00 0.00000000E+00 8.00000000E-01
|
||||
1.80000000E+00 4.20000000E-01 2.70000000E-01 5.50000000E-01 1.58000000E+00
|
||||
4.50000000E-01 4.00000000E-01 2.00000000E-01 2.00000000E-01 1.05000000E+01
|
||||
%FLAG DIHEDRAL_PERIODICITY
|
||||
%FORMAT(5E16.8)
|
||||
1.00000000E+00 3.00000000E+00 2.00000000E+00 2.00000000E+00 1.00000000E+00
|
||||
3.00000000E+00 2.00000000E+00 1.00000000E+00 1.00000000E+00 3.00000000E+00
|
||||
2.00000000E+00 3.00000000E+00 2.00000000E+00 3.00000000E+00 2.00000000E+00
|
||||
1.00000000E+00 3.00000000E+00 2.00000000E+00 1.00000000E+00 2.00000000E+00
|
||||
%FLAG DIHEDRAL_PHASE
|
||||
%FORMAT(5E16.8)
|
||||
0.00000000E+00 3.14159265E+00 3.14159265E+00 3.14159265E+00 0.00000000E+00
|
||||
0.00000000E+00 3.14159265E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00
|
||||
0.00000000E+00 0.00000000E+00 0.00000000E+00 3.14159265E+00 3.14159265E+00
|
||||
3.14159265E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 3.14159265E+00
|
||||
%FLAG SCEE_SCALE_FACTOR
|
||||
%FORMAT(5E16.8)
|
||||
1.20000000E+00 0.00000000E+00 1.20000000E+00 1.20000000E+00 0.00000000E+00
|
||||
1.20000000E+00 0.00000000E+00 1.20000000E+00 1.20000000E+00 1.20000000E+00
|
||||
0.00000000E+00 1.20000000E+00 0.00000000E+00 1.20000000E+00 0.00000000E+00
|
||||
0.00000000E+00 1.20000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00
|
||||
%FLAG SCNB_SCALE_FACTOR
|
||||
%FORMAT(5E16.8)
|
||||
2.00000000E+00 0.00000000E+00 2.00000000E+00 2.00000000E+00 0.00000000E+00
|
||||
2.00000000E+00 0.00000000E+00 2.00000000E+00 2.00000000E+00 2.00000000E+00
|
||||
0.00000000E+00 2.00000000E+00 0.00000000E+00 2.00000000E+00 0.00000000E+00
|
||||
0.00000000E+00 2.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00
|
||||
%FLAG DIHEDRALS_INC_HYDROGEN
|
||||
%FORMAT(10I8)
|
||||
0 3 12 15 1 0 3 -12 15 2
|
||||
3 12 18 21 3 6 3 12 15 1
|
||||
6 3 -12 15 2 9 3 12 15 1
|
||||
9 3 -12 15 2 15 12 18 21 4
|
||||
15 12 -18 21 5 18 24 30 33 6
|
||||
18 24 30 36 6 18 24 30 39 6
|
||||
24 42 48 51 3 27 24 30 33 6
|
||||
27 24 30 36 6 27 24 30 39 6
|
||||
27 24 42 45 1 27 24 -42 45 2
|
||||
42 24 30 33 6 42 24 30 36 6
|
||||
42 24 30 39 6 45 42 48 51 4
|
||||
45 42 -48 51 5 21 18 -24 -12 7
|
||||
51 48 -54 -42 7 51 48 54 60 8
|
||||
21 18 24 30 8 42 48 54 57 8
|
||||
6 3 12 18 9 42 48 54 63 8
|
||||
51 48 54 57 8 21 18 24 42 8
|
||||
0 3 12 18 9 42 48 54 60 8
|
||||
27 24 42 48 8 21 18 24 27 8
|
||||
51 48 54 63 8 9 3 12 18 9
|
||||
12 18 24 27 8
|
||||
%FLAG DIHEDRALS_WITHOUT_HYDROGEN
|
||||
%FORMAT(10I8)
|
||||
3 12 18 24 3 12 18 24 30 10
|
||||
12 18 -24 30 11 12 18 -24 30 5
|
||||
12 18 24 42 12 12 18 -24 42 13
|
||||
15 12 18 24 3 18 24 42 48 14
|
||||
18 24 -42 48 15 18 24 -42 48 16
|
||||
24 42 48 54 3 30 24 42 48 17
|
||||
30 24 -42 48 18 30 24 -42 48 19
|
||||
45 42 48 54 3 15 12 -18 -3 20
|
||||
45 42 -48 -24 20 18 24 42 45 8
|
||||
30 24 42 45 8
|
||||
%FLAG SOLTY
|
||||
%FORMAT(5E16.8)
|
||||
|
||||
%FLAG HBOND_ACOEF
|
||||
%FORMAT(5E16.8)
|
||||
|
||||
%FLAG HBOND_BCOEF
|
||||
%FORMAT(5E16.8)
|
||||
|
||||
%FLAG HBCUT
|
||||
%FORMAT(5E16.8)
|
||||
|
||||
%FLAG TREE_CHAIN_CLASSIFICATION
|
||||
%FORMAT(20a4)
|
||||
BLA BLA BLA BLA BLA BLA BLA BLA BLA BLA BLA BLA BLA BLA BLA BLA BLA BLA BLA BLA
|
||||
BLA BLA
|
||||
%FLAG JOIN_ARRAY
|
||||
%FORMAT(10I8)
|
||||
0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0
|
||||
0 0
|
||||
%FLAG IROTAT
|
||||
%FORMAT(10I8)
|
||||
0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0
|
||||
0 0
|
||||
%FLAG BOX_DIMENSIONS
|
||||
%FORMAT(5E16.8)
|
||||
9.00000000E+01 3.00000000E+01 3.00000000E+01 3.00000000E+01
|
||||
%FLAG RADIUS_SET
|
||||
%FORMAT(1a80)
|
||||
0
|
||||
%FLAG RADII
|
||||
%FORMAT(5E16.8)
|
||||
0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00
|
||||
0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00
|
||||
0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00
|
||||
0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00
|
||||
0.00000000E+00 0.00000000E+00
|
||||
%FLAG SCREEN
|
||||
%FORMAT(5E16.8)
|
||||
0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00
|
||||
0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00
|
||||
0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00
|
||||
0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00
|
||||
0.00000000E+00 0.00000000E+00
|
||||
%FLAG IPOL
|
||||
%FORMAT(1I8)
|
||||
0
|
||||
26
examples/trajectory/protein.pdb
Normal file
26
examples/trajectory/protein.pdb
Normal file
@@ -0,0 +1,26 @@
|
||||
CRYST1 30.000 30.000 30.000 90.00 90.00 90.00 P 1 1
|
||||
ATOM 1 H1 ACE A 1 2.000 1.000 -0.000 0.00 0.00 H
|
||||
ATOM 2 CH3 ACE A 1 2.000 2.090 0.000 0.00 0.00 C
|
||||
ATOM 3 H2 ACE A 1 1.486 2.454 0.890 0.00 0.00 H
|
||||
ATOM 4 H3 ACE A 1 1.486 2.454 -0.890 0.00 0.00 H
|
||||
ATOM 5 C ACE A 1 3.427 2.641 -0.000 0.00 0.00 C
|
||||
ATOM 6 O ACE A 1 4.391 1.877 -0.000 0.00 0.00 O
|
||||
ATOM 7 N ALA A 2 3.555 3.970 -0.000 0.00 0.00 N
|
||||
ATOM 8 H ALA A 2 2.733 4.556 -0.000 0.00 0.00 H
|
||||
ATOM 9 CA ALA A 2 4.853 4.614 -0.000 0.00 0.00 C
|
||||
ATOM 10 HA ALA A 2 5.408 4.316 0.890 0.00 0.00 H
|
||||
ATOM 11 CB ALA A 2 5.661 4.221 -1.232 0.00 0.00 C
|
||||
ATOM 12 HB1 ALA A 2 5.123 4.521 -2.131 0.00 0.00 H
|
||||
ATOM 13 HB2 ALA A 2 6.630 4.719 -1.206 0.00 0.00 H
|
||||
ATOM 14 HB3 ALA A 2 5.809 3.141 -1.241 0.00 0.00 H
|
||||
ATOM 15 C ALA A 2 4.713 6.129 0.000 0.00 0.00 C
|
||||
ATOM 16 O ALA A 2 3.601 6.653 0.000 0.00 0.00 O
|
||||
ATOM 17 N NME A 3 5.846 6.835 0.000 0.00 0.00 N
|
||||
ATOM 18 H NME A 3 6.737 6.359 -0.000 0.00 0.00 H
|
||||
ATOM 19 C NME A 3 5.846 8.284 0.000 0.00 0.00 C
|
||||
ATOM 20 H1 NME A 3 4.819 8.648 0.000 0.00 0.00 H
|
||||
ATOM 21 H2 NME A 3 6.360 8.648 0.890 0.00 0.00 H
|
||||
ATOM 22 H3 NME A 3 6.360 8.648 -0.890 0.00 0.00 H
|
||||
TER 23 NME A 3
|
||||
CONECT 5 7
|
||||
CONECT 15 17
|
||||
14
examples/trajectory/protein.rst7
Normal file
14
examples/trajectory/protein.rst7
Normal file
@@ -0,0 +1,14 @@
|
||||
alanine-dipeptide.solvated.pdb
|
||||
22
|
||||
0.7494821 1.2436848 0.8743532 1.0856344 2.2423820 0.5955986
|
||||
0.4304414 2.9747953 1.0671825 1.0497815 2.3544810 -0.4880289
|
||||
2.5015950 2.4471725 1.0820421 3.1003812 1.5343071 1.6479120
|
||||
3.0220696 3.6519467 0.8741013 2.4411554 4.3533213 0.4373955
|
||||
4.3920715 4.0500473 1.2160543 4.7674596 3.4172266 2.0202454
|
||||
5.2805058 3.8202998 -0.0180103 4.9565949 4.4537317 -0.8438106
|
||||
6.3180425 4.0583459 0.2164072 5.2327259 2.7740601 -0.3200050
|
||||
4.4431625 5.5106563 1.7135265 3.4307644 6.2198007 1.6891606
|
||||
5.6170320 5.9613562 2.1744082 6.3997462 5.3231585 2.1616313
|
||||
5.8784762 7.3296314 2.6320299 5.1056278 8.0184146 2.2908769
|
||||
5.9253575 7.3544224 3.7207393 6.8360338 7.6745804 2.2419090
|
||||
30.0000000 30.0000000 30.0000000 90.0000000 90.0000000 90.0000000
|
||||
21683
package-lock.json
generated
21683
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
130
package.json
130
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "molstar",
|
||||
"version": "4.10.0",
|
||||
"version": "5.9.0",
|
||||
"description": "A comprehensive macromolecular library.",
|
||||
"homepage": "https://github.com/molstar/molstar#readme",
|
||||
"repository": {
|
||||
@@ -10,29 +10,30 @@
|
||||
"bugs": {
|
||||
"url": "https://github.com/molstar/molstar/issues"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=22.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"lint": "eslint .",
|
||||
"lint-fix": "eslint . --fix",
|
||||
"test": "npm install --no-save \"gl@^6.0.2\" && npm run lint && jest",
|
||||
"jest": "jest",
|
||||
"build": "npm run build-tsc && npm run build-extra && npm run build-webpack",
|
||||
"clean": "node ./scripts/clean.js",
|
||||
"clean": "node ./scripts/clean.js --all",
|
||||
"clean:build": "node ./scripts/clean.js --build",
|
||||
"build": "npm run build:apps && npm run build:lib",
|
||||
"build:apps": "node ./scripts/build.mjs -a -e --prd",
|
||||
"build:lib": "concurrently \"tsc --incremental\" \"tsc --build tsconfig.commonjs.json --incremental\" && npm run build:lib-extra",
|
||||
"build:lib-extra": "node scripts/write-version.mjs && cpx \"src/**/*.{scss,html,ico,jpg}\" lib/ && cpx \"src/**/*.{scss,html,ico,jpg}\" lib/commonjs/ && tsc-alias -p tsconfig.json",
|
||||
"rebuild": "npm run clean && npm run build",
|
||||
"build-viewer": "npm run build-tsc && npm run build-extra && npm run build-webpack-viewer",
|
||||
"build-tsc": "concurrently \"tsc --incremental\" \"tsc --build tsconfig.commonjs.json --incremental\"",
|
||||
"build-extra": "cpx \"src/**/*.{scss,html,ico,jpg}\" lib/",
|
||||
"build-webpack": "webpack --mode production --config ./webpack.config.production.js",
|
||||
"build-webpack-viewer": "webpack --mode production --config ./webpack.config.viewer.js",
|
||||
"watch": "concurrently -c \"green,green,gray,gray\" --names \"tsc,srv,ext,wpc\" --kill-others \"npm:watch-tsc\" \"npm:watch-servers\" \"npm:watch-extra\" \"npm:watch-webpack\"",
|
||||
"watch-viewer": "concurrently -c \"green,gray,gray\" --names \"tsc,ext,wpc\" --kill-others \"npm:watch-tsc\" \"npm:watch-extra\" \"npm:watch-webpack-viewer\"",
|
||||
"watch-viewer-debug": "concurrently -c \"green,gray,gray\" --names \"tsc,ext,wpc\" --kill-others \"npm:watch-tsc\" \"npm:watch-extra\" \"npm:watch-webpack-viewer-debug\"",
|
||||
"watch-tsc": "tsc --watch --incremental",
|
||||
"watch-servers": "tsc --build tsconfig.commonjs.json --watch --incremental",
|
||||
"watch-extra": "cpx \"src/**/*.{scss,html,ico,jpg}\" lib/ --watch",
|
||||
"watch-webpack": "webpack -w --mode development --stats minimal",
|
||||
"watch-webpack-viewer": "webpack -w --mode development --stats minimal --config ./webpack.config.viewer.js",
|
||||
"watch-webpack-viewer-debug": "webpack -w --mode development --stats minimal --config ./webpack.config.viewer.debug.js",
|
||||
"dev": "node ./scripts/build.mjs",
|
||||
"dev:all": "node ./scripts/build.mjs -a -e -bt",
|
||||
"dev:viewer": "node ./scripts/build.mjs -a viewer",
|
||||
"dev:apps": "node ./scripts/build.mjs -a",
|
||||
"dev:examples": "node ./scripts/build.mjs -e",
|
||||
"dev:browser-tests": "node ./scripts/build.mjs -bt",
|
||||
"serve": "http-server -p 1338 -g",
|
||||
"deploy:local": "npm run clean:build && npm run build:apps && node ./scripts/deploy.js --local",
|
||||
"deploy:remote": "npm run clean:build && npm run build:apps && node ./scripts/deploy.js",
|
||||
"model-server": "node lib/commonjs/servers/model/server.js",
|
||||
"model-server-watch": "nodemon --watch lib lib/commonjs/servers/model/server.js",
|
||||
"volume-server-test": "node lib/commonjs/servers/volume/server.js --idMap em 'test/${id}.mdb' --defaultPort 1336",
|
||||
@@ -43,7 +44,8 @@
|
||||
},
|
||||
"files": [
|
||||
"lib/",
|
||||
"build/viewer/"
|
||||
"build/viewer/",
|
||||
"build/mvs-stories/"
|
||||
],
|
||||
"bin": {
|
||||
"cif2bcif": "lib/commonjs/cli/cif2bcif/index.js",
|
||||
@@ -72,7 +74,7 @@
|
||||
"js"
|
||||
],
|
||||
"transform": {
|
||||
"\\.ts$": "ts-jest"
|
||||
"\\.ts$": ["esbuild-jest-transform", { "tsconfigRaw": "{\"compilerOptions\":{\"useDefineForClassFields\":false}}" }]
|
||||
},
|
||||
"moduleDirectories": [
|
||||
"node_modules",
|
||||
@@ -114,68 +116,68 @@
|
||||
"Eric E <etongfu@outlook.com>",
|
||||
"Xavier Martinez <xavier.martinez.xm@gmail.com>",
|
||||
"Alex Chan <smalldirkalex@gmail.com>",
|
||||
"Simeon Borko <simeon.borko@gmail.com>"
|
||||
"Simeon Borko <simeon.borko@gmail.com>",
|
||||
"Ventura Rivera <venturaxrivera@gmail.com>",
|
||||
"Andy Turner <agdturner@gmail.com>",
|
||||
"Lukáš Polák <admin@lukaspolak.cz>",
|
||||
"Chetan Mishra <chetan.s115@gmail.com>",
|
||||
"Zach Charlop-Powers <zach.charlop.powers@gmail.com>",
|
||||
"Kim Juho <juho_kim@outlook.com>",
|
||||
"Victoria Doshchenko <doshchenko.victoria@gmail.com>",
|
||||
"Diego del Alamo <diego.delalamo@gmail.com>",
|
||||
"Tianzhen Lin (Tangent) <tangent@usa.net>"
|
||||
],
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/cors": "^2.8.17",
|
||||
"@types/cors": "^2.8.19",
|
||||
"@types/gl": "^6.0.5",
|
||||
"@types/jest": "^29.5.14",
|
||||
"@types/jest": "^30.0.0",
|
||||
"@types/pngjs": "^6.0.5",
|
||||
"@types/react": "^18.3.16",
|
||||
"@types/react-dom": "^18.3.5",
|
||||
"@typescript-eslint/eslint-plugin": "^7.18.0",
|
||||
"@typescript-eslint/parser": "^7.18.0",
|
||||
"@types/react": "^18.3.28",
|
||||
"@types/react-dom": "^18.3.7",
|
||||
"@types/webxr": "^0.5.24",
|
||||
"@typescript-eslint/eslint-plugin": "^8.59.1",
|
||||
"@typescript-eslint/parser": "^8.59.1",
|
||||
"benchmark": "^2.1.4",
|
||||
"concurrently": "^9.1.0",
|
||||
"cpx2": "^8.0.0",
|
||||
"crypto-browserify": "^3.12.1",
|
||||
"css-loader": "^7.1.2",
|
||||
"eslint": "^8.57.1",
|
||||
"extra-watch-webpack-plugin": "^1.0.3",
|
||||
"file-loader": "^6.2.0",
|
||||
"fs-extra": "^11.2.0",
|
||||
"concurrently": "^9.2.1",
|
||||
"cpx2": "^8.0.2",
|
||||
"css-loader": "^7.1.4",
|
||||
"esbuild": "^0.28.0",
|
||||
"esbuild-jest-transform": "^2.0.1",
|
||||
"esbuild-sass-plugin": "^3.7.0",
|
||||
"eslint": "^10.3.0",
|
||||
"fs-extra": "^11.3.4",
|
||||
"globals": "^17.6.0",
|
||||
"http-server": "^14.1.1",
|
||||
"jest": "^29.7.0",
|
||||
"jest": "^30.3.0",
|
||||
"jpeg-js": "^0.4.4",
|
||||
"mini-css-extract-plugin": "^2.9.2",
|
||||
"path-browserify": "^1.0.1",
|
||||
"raw-loader": "^4.0.2",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"sass": "^1.83.0",
|
||||
"sass-loader": "^16.0.4",
|
||||
"simple-git": "^3.27.0",
|
||||
"stream-browserify": "^3.0.0",
|
||||
"style-loader": "^4.0.0",
|
||||
"ts-jest": "^29.2.5",
|
||||
"typescript": "^5.7.2",
|
||||
"webpack": "^5.97.1",
|
||||
"webpack-cli": "^5.1.4"
|
||||
"sass": "^1.99.0",
|
||||
"simple-git": "^3.36.0",
|
||||
"tsc-alias": "^1.8.17",
|
||||
"typescript": "^6.0.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/argparse": "^2.0.17",
|
||||
"@types/benchmark": "^2.1.5",
|
||||
"@types/compression": "1.7.5",
|
||||
"@types/express": "^5.0.0",
|
||||
"@types/node": "^18.19.68",
|
||||
"@types/node-fetch": "^2.6.12",
|
||||
"@types/swagger-ui-dist": "3.30.5",
|
||||
"@types/compression": "1.8.1",
|
||||
"@types/express": "^5.0.6",
|
||||
"@types/node": "^22.19.17",
|
||||
"@types/swagger-ui-dist": "3.30.6",
|
||||
"argparse": "^2.0.1",
|
||||
"compression": "^1.7.5",
|
||||
"cors": "^2.8.5",
|
||||
"express": "^5.0.1",
|
||||
"compression": "^1.8.1",
|
||||
"cors": "^2.8.6",
|
||||
"express": "^5.2.1",
|
||||
"h264-mp4-encoder": "^1.0.12",
|
||||
"immer": "^10.1.1",
|
||||
"immutable": "^5.0.3",
|
||||
"immutable": "^5.1.5",
|
||||
"io-ts": "^2.2.22",
|
||||
"node-fetch": "^2.7.0",
|
||||
"react-markdown": "^9.0.1",
|
||||
"rxjs": "^7.8.1",
|
||||
"swagger-ui-dist": "^5.18.2",
|
||||
"tslib": "^2.8.1",
|
||||
"util.promisify": "^1.1.2",
|
||||
"xhr2": "^0.2.1"
|
||||
"mutative": "^1.3.0",
|
||||
"react-markdown": "^10.1.0",
|
||||
"remark-gfm": "^4.0.1",
|
||||
"rxjs": "^7.8.2",
|
||||
"swagger-ui-dist": "^5.32.5",
|
||||
"tslib": "^2.8.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@google-cloud/storage": "^7.14.0",
|
||||
|
||||
350
scripts/build.mjs
Normal file
350
scripts/build.mjs
Normal file
@@ -0,0 +1,350 @@
|
||||
/**
|
||||
* Copyright (c) 2017-2025 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
* @author Eric E <etongfu@@outlook.com>
|
||||
*/
|
||||
import * as esbuild from 'esbuild';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as argparse from 'argparse';
|
||||
import { sassPlugin } from 'esbuild-sass-plugin';
|
||||
import * as os from 'os';
|
||||
|
||||
const Apps = [
|
||||
// Apps
|
||||
{ kind: 'app', name: 'viewer', themes: ['light', 'dark', 'blue'] },
|
||||
{ kind: 'app', name: 'docking-viewer' },
|
||||
{ kind: 'app', name: 'mesoscale-explorer' },
|
||||
{ kind: 'app', name: 'mvs-stories', globalName: 'mvsStories', filename: 'mvs-stories.js' },
|
||||
|
||||
// Examples
|
||||
{ kind: 'example', name: 'proteopedia-wrapper' },
|
||||
{ kind: 'example', name: 'basic-wrapper' },
|
||||
{ kind: 'example', name: 'lighting' },
|
||||
{ kind: 'example', name: 'alpha-orbitals' },
|
||||
{ kind: 'example', name: 'alphafolddb-pae' },
|
||||
{ kind: 'example', name: 'mvs-stories' },
|
||||
{ kind: 'example', name: 'ihm-restraints' },
|
||||
{ kind: 'example', name: 'interactions' },
|
||||
{ kind: 'example', name: 'ligand-editor' },
|
||||
];
|
||||
|
||||
function findApp(name, kind) {
|
||||
return Apps.find(a => a.name === name && a.kind === kind);
|
||||
}
|
||||
|
||||
function mkDir(dir) {
|
||||
try {
|
||||
if (!fs.existsSync(dir)) {
|
||||
fs.mkdirSync(dir, { recursive: true });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Failed to create directory ${dir}:`, error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
function handleFileError(error, operation, path) {
|
||||
console.error(`Failed to ${operation} ${path}:`, error);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
function fileLoaderPlugin(options) {
|
||||
mkDir(options.out);
|
||||
|
||||
return {
|
||||
name: 'file-loader',
|
||||
setup(build) {
|
||||
build.onLoad({ filter: /\.jpg$/ }, async (args) => {
|
||||
try {
|
||||
const name = path.basename(args.path);
|
||||
mkDir(path.resolve(options.out, 'images'));
|
||||
await fs.promises.copyFile(args.path, path.resolve(options.out, 'images', name));
|
||||
return {
|
||||
contents: `images/${name}`,
|
||||
loader: 'text',
|
||||
};
|
||||
} catch (error) {
|
||||
handleFileError(error, 'copy', args.path);
|
||||
}
|
||||
});
|
||||
build.onLoad({ filter: /\.(html|ico)$/ }, async (args) => {
|
||||
const name = path.basename(args.path);
|
||||
await fs.promises.copyFile(args.path, path.resolve(options.out, name));
|
||||
return {
|
||||
contents: '',
|
||||
loader: 'empty',
|
||||
};
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function examplesCssRenamePlugin({ root }) {
|
||||
return {
|
||||
name: 'example-css-rename',
|
||||
setup(build) {
|
||||
build.onEnd(async () => {
|
||||
if (fs.existsSync(path.resolve(root, 'index.css'))) {
|
||||
await fs.promises.rename(
|
||||
path.resolve(root, 'index.css'),
|
||||
path.resolve(root, 'molstar.css')
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function resolveEntryPath(path) {
|
||||
if (!fs.existsSync(path)) {
|
||||
return path + 'x'; // fallback to .tsx
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
function getPaths(app) {
|
||||
if (app.kind === 'app') {
|
||||
return {
|
||||
prefix: `./build/${app.name}`,
|
||||
entry: resolveEntryPath(`./src/apps/${app.name}/index.ts`),
|
||||
outfile: `./build/${app.name}/${app.filename || 'molstar.js'}`,
|
||||
};
|
||||
}
|
||||
if (app.kind === 'example') {
|
||||
return {
|
||||
prefix: `./build/examples/${app.name}`,
|
||||
entry: resolveEntryPath(`./src/examples/${app.name}/index.ts`),
|
||||
outfile: `./build/examples/${app.name}/${app.filename || 'index.js'}`,
|
||||
};
|
||||
}
|
||||
if (app.kind === 'browser-test') {
|
||||
return {
|
||||
prefix: `./build/tests/browser`,
|
||||
entry: resolveEntryPath(`./src/tests/browser/${app.name}.ts`),
|
||||
outfile: `./build/tests/browser/${app.name}.js`,
|
||||
};
|
||||
}
|
||||
throw new Error(`Unknown app kind: ${app.kind}`);
|
||||
}
|
||||
|
||||
async function createBundle(app) {
|
||||
const { name, kind } = app;
|
||||
const { prefix, entry, outfile } = getPaths(app);
|
||||
|
||||
const ctx = await esbuild.context({
|
||||
entryPoints: [entry],
|
||||
tsconfig: './tsconfig.json',
|
||||
bundle: true,
|
||||
minify: isProduction,
|
||||
minifyIdentifiers: false,
|
||||
sourcemap: includeSourceMap,
|
||||
globalName: app.globalName || 'molstar',
|
||||
outfile,
|
||||
plugins: [
|
||||
fileLoaderPlugin({ out: prefix }),
|
||||
sassPlugin({
|
||||
type: 'css',
|
||||
silenceDeprecations: ['import'],
|
||||
logger: {
|
||||
warn: (msg) => console.warn(msg),
|
||||
debug: () => { },
|
||||
}
|
||||
}),
|
||||
...(kind === 'example' ? [examplesCssRenamePlugin({ root: prefix })] : []),
|
||||
],
|
||||
external: ['crypto', 'fs', 'path', 'stream'],
|
||||
loader: {
|
||||
},
|
||||
color: true,
|
||||
logLevel: 'info',
|
||||
define: {
|
||||
'process.env.NODE_ENV': JSON.stringify(NODE_ENV_PRD ? 'production' : 'development'),
|
||||
'process.env.DEBUG': JSON.stringify(process.env.DEBUG || false),
|
||||
__MOLSTAR_PLUGIN_VERSION__: JSON.stringify(VERSION),
|
||||
__MOLSTAR_BUILD_TIMESTAMP__: `${TIMESTAMP}`,
|
||||
},
|
||||
});
|
||||
|
||||
await ctx.rebuild();
|
||||
|
||||
if (!isProduction) await ctx.watch();
|
||||
}
|
||||
|
||||
async function createTheme(appName, themeName) {
|
||||
// const { prefix, entry, outfile } = getPaths(app);
|
||||
|
||||
const ctx = await esbuild.context({
|
||||
entryPoints: [resolveEntryPath(`./src/apps/${appName}/theme/${themeName}.ts`)],
|
||||
tsconfig: './tsconfig.json',
|
||||
bundle: true,
|
||||
minify: isProduction,
|
||||
minifyIdentifiers: false,
|
||||
sourcemap: false,
|
||||
outfile: `./build/${appName}/theme/${themeName}.js`,
|
||||
plugins: [
|
||||
// fileLoaderPlugin({ out: prefix }),
|
||||
sassPlugin({
|
||||
type: 'css',
|
||||
silenceDeprecations: ['import'],
|
||||
logger: {
|
||||
warn: (msg) => console.warn(msg),
|
||||
debug: () => { },
|
||||
}
|
||||
}),
|
||||
],
|
||||
color: true,
|
||||
logLevel: 'info',
|
||||
define: {
|
||||
'process.env.NODE_ENV': JSON.stringify(NODE_ENV_PRD ? 'production' : 'development'),
|
||||
'process.env.DEBUG': JSON.stringify(process.env.DEBUG || false),
|
||||
},
|
||||
});
|
||||
|
||||
await ctx.rebuild();
|
||||
|
||||
if (!isProduction) await ctx.watch();
|
||||
}
|
||||
|
||||
function findBrowserTests(names) {
|
||||
const dir = path.resolve('./src', 'tests', 'browser');
|
||||
let files = fs.readdirSync(dir).filter(file => file.endsWith('.ts')).map(file => file.replace('.ts', ''));
|
||||
if (names.length) {
|
||||
files = files.filter(file => names.includes(file));
|
||||
}
|
||||
return files.map(name => ({ kind: 'browser-test', name }));
|
||||
}
|
||||
|
||||
const argParser = new argparse.ArgumentParser({
|
||||
add_help: true,
|
||||
description: 'Mol* Build'
|
||||
});
|
||||
argParser.add_argument('--prd', {
|
||||
help: 'Create a production build.',
|
||||
required: false,
|
||||
action: 'store_true',
|
||||
});
|
||||
argParser.add_argument('--no-src-map', {
|
||||
help: 'Do not include source map.',
|
||||
required: false,
|
||||
action: 'store_true',
|
||||
});
|
||||
argParser.add_argument('--apps', '-a', {
|
||||
help: 'Apps to build.',
|
||||
required: false,
|
||||
nargs: '*',
|
||||
});
|
||||
argParser.add_argument('--examples', '-e', {
|
||||
help: 'Examples to build.',
|
||||
required: false,
|
||||
nargs: '*',
|
||||
});
|
||||
argParser.add_argument('--browser-tests', '-bt', {
|
||||
help: 'Browser Tests to build.',
|
||||
required: false,
|
||||
nargs: '*',
|
||||
});
|
||||
argParser.add_argument('--port', '-p', {
|
||||
help: 'Port.',
|
||||
required: false,
|
||||
default: 1338,
|
||||
type: 'int',
|
||||
});
|
||||
|
||||
argParser.add_argument('--host', {
|
||||
help: 'Show all available host addresses.',
|
||||
required: false,
|
||||
action: 'store_true',
|
||||
});
|
||||
|
||||
const args = argParser.parse_args();
|
||||
|
||||
|
||||
const isProduction = !!args.prd;
|
||||
const includeSourceMap = !args.no_src_map;
|
||||
|
||||
const NODE_ENV_PRD = isProduction || process.env.NODE_ENV === 'production';
|
||||
const VERSION = isProduction ? JSON.parse(fs.readFileSync('./package.json', 'utf8')).version : '(dev build)';
|
||||
const TIMESTAMP = Date.now();
|
||||
|
||||
const apps = (!args.apps ? [] : (args.apps.length ? args.apps.map(a => findApp(a, 'app')).filter(a => a) : Apps.filter(a => a.kind === 'app')));
|
||||
const examples = (!args.examples ? [] : (args.examples.length ? args.examples.map(e => findApp(e, 'example')).filter(a => a) : Apps.filter(a => a.kind === 'example')));
|
||||
const browserTests = (!args.browser_tests ? [] : findBrowserTests(args.browser_tests));
|
||||
|
||||
console.log('Apps:', apps.map(a => a.name));
|
||||
console.log('Examples:', examples.map(e => e.name));
|
||||
console.log('Browser Tests', browserTests.map(e => e.name));
|
||||
console.log('');
|
||||
|
||||
function getLocalIPs() {
|
||||
const interfaces = os.networkInterfaces();
|
||||
const ips = [];
|
||||
|
||||
for (const name of Object.keys(interfaces)) {
|
||||
for (const iface of interfaces[name]) {
|
||||
// Skip internal and non-IPv4 addresses
|
||||
if (iface.internal || iface.family !== 'IPv4') continue;
|
||||
ips.push(iface.address);
|
||||
}
|
||||
}
|
||||
|
||||
return ips;
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const promises = [];
|
||||
console.log(isProduction ? 'Building apps...' : 'Initial build...');
|
||||
|
||||
for (const app of apps) {
|
||||
promises.push(createBundle(app));
|
||||
if (app.themes) {
|
||||
for (const theme of app.themes) {
|
||||
promises.push(createTheme(app.name, theme));
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const example of examples) promises.push(createBundle(example));
|
||||
for (const browserTest of browserTests) promises.push(createBundle(browserTest));
|
||||
|
||||
await Promise.all(promises);
|
||||
|
||||
if (isProduction) {
|
||||
console.log('Done.');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
console.log('Initial build complete.');
|
||||
|
||||
const certfile = './dev.pem';
|
||||
const keyfile = './dev-key.pem';
|
||||
|
||||
const sslEnabled = fs.existsSync(certfile) && fs.existsSync(keyfile);
|
||||
const protocol = sslEnabled ? 'https' : 'http';
|
||||
|
||||
const ctx = await esbuild.context({});
|
||||
ctx.serve({
|
||||
servedir: './',
|
||||
port: args.port,
|
||||
host: '0.0.0.0', // Always listen on all interfaces
|
||||
certfile: sslEnabled ? certfile : undefined,
|
||||
keyfile: sslEnabled ? keyfile : undefined,
|
||||
});
|
||||
|
||||
console.log('');
|
||||
console.log(`Server URL: ${protocol}://localhost:${args.port}`);
|
||||
if (args.host) {
|
||||
console.log('Available host addresses:');
|
||||
const ips = getLocalIPs();
|
||||
ips.forEach(ip => console.log(` ${protocol}://${ip}:${args.port}`));
|
||||
}
|
||||
console.log('');
|
||||
console.log('Watching for changes...');
|
||||
console.log('');
|
||||
console.log('Press Ctrl+C to stop.');
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const argparse = require('argparse');
|
||||
|
||||
function removeDir(dirPath) {
|
||||
for (const ent of fs.readdirSync(dirPath)) {
|
||||
@@ -24,11 +25,29 @@ function remove(entryPath) {
|
||||
fs.unlinkSync(entryPath);
|
||||
}
|
||||
|
||||
const toClean = [
|
||||
path.resolve(__dirname, '../build'),
|
||||
path.resolve(__dirname, '../lib'),
|
||||
path.resolve(__dirname, '../tsconfig.tsbuildinfo'),
|
||||
];
|
||||
const argParser = new argparse.ArgumentParser({
|
||||
add_help: true,
|
||||
description: 'Clean Script'
|
||||
});
|
||||
argParser.add_argument('--build', { required: false, action: 'store_true' });
|
||||
argParser.add_argument('--lib', { required: false, action: 'store_true' });
|
||||
argParser.add_argument('--all', { required: false, action: 'store_true' });
|
||||
const args = argParser.parse_args();
|
||||
|
||||
const toClean = [];
|
||||
|
||||
if (args.build || args.all) {
|
||||
toClean.push(path.resolve(__dirname, '../build'));
|
||||
toClean.push(path.resolve(__dirname, '../deploy/data'));
|
||||
}
|
||||
if (args.lib || args.all) {
|
||||
toClean.push(
|
||||
path.resolve(__dirname, '../lib'),
|
||||
path.resolve(__dirname, '../tsconfig.tsbuildinfo'),
|
||||
);
|
||||
}
|
||||
|
||||
console.log('\n###', 'cleaning', toClean.join(', '));
|
||||
|
||||
toClean.forEach(ph => {
|
||||
if (fs.existsSync(ph)) {
|
||||
|
||||
@@ -1,22 +1,35 @@
|
||||
/**
|
||||
* Copyright (c) 2019-2024 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2019-2025 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
const git = require('simple-git');
|
||||
const path = require('path');
|
||||
const fs = require("fs");
|
||||
const fse = require("fs-extra");
|
||||
const fs = require('fs');
|
||||
const fse = require('fs-extra');
|
||||
const argparse = require('argparse');
|
||||
|
||||
const remoteUrl = "https://github.com/molstar/molstar.github.io.git";
|
||||
const VERSION = require(path.resolve(__dirname, '../package.json')).version;
|
||||
const MVS_STORIES_VERSION = require(path.resolve(__dirname, '../src/apps/mvs-stories/version.ts')).VERSION;
|
||||
|
||||
const remoteUrl = 'https://github.com/molstar/molstar.github.io.git';
|
||||
const dataDir = path.resolve(__dirname, '../data/');
|
||||
const buildDir = path.resolve(__dirname, '../build/');
|
||||
const deployDir = path.resolve(buildDir, 'deploy/');
|
||||
const localPath = path.resolve(deployDir, 'molstar.github.io/');
|
||||
const deployDir = path.resolve(__dirname, '../deploy/');
|
||||
const localPath = path.resolve(deployDir, 'data/');
|
||||
const repositoryPath = path.resolve(deployDir, 'molstar.github.io/');
|
||||
|
||||
const analyticsTag = /<!-- __MOLSTAR_ANALYTICS__ -->/g;
|
||||
const analyticsCode = `<!-- Cloudflare Web Analytics --><script defer src='https://static.cloudflareinsights.com/beacon.min.js' data-cf-beacon='{"token": "c414cbae2d284ea995171a81e4a3e721"}'></script><!-- End Cloudflare Web Analytics --><iframe src="https://web3dsurvey.com/collector-iframe.html" style="width: 1px; height: 1px;"></iframe>`;
|
||||
|
||||
const manifestTag = /<!-- __MOLSTAR_MANIFEST__ -->/g;
|
||||
const manifestCode = `<link rel="manifest" href="./manifest.webmanifest">`;
|
||||
|
||||
const pwaTag = /<!-- __MOLSTAR_PWA__ -->/g;
|
||||
const pwaCode = `<script src='./pwa.js'></script>`;
|
||||
|
||||
function log(command, stdout, stderr) {
|
||||
if (command) {
|
||||
console.log('\n###', command);
|
||||
@@ -31,39 +44,117 @@ function addAnalytics(path) {
|
||||
fs.writeFileSync(path, result, 'utf8');
|
||||
}
|
||||
|
||||
function addManifest(path) {
|
||||
const data = fs.readFileSync(path, 'utf8');
|
||||
const result = data.replace(manifestTag, manifestCode);
|
||||
fs.writeFileSync(path, result, 'utf8');
|
||||
}
|
||||
|
||||
function addPwa(path) {
|
||||
const data = fs.readFileSync(path, 'utf8');
|
||||
const result = data.replace(pwaTag, pwaCode);
|
||||
fs.writeFileSync(path, result, 'utf8');
|
||||
}
|
||||
|
||||
function addVersion(path) {
|
||||
const data = fs.readFileSync(path, 'utf8');
|
||||
const result = data.replace('__MOLSTAR_VERSION__', VERSION);
|
||||
fs.writeFileSync(path, result, 'utf8');
|
||||
}
|
||||
|
||||
function copyViewer() {
|
||||
console.log('\n###', 'copy viewer files');
|
||||
const viewerBuildPath = path.resolve(buildDir, '../build/viewer/');
|
||||
const viewerBuildPath = path.resolve(buildDir, 'viewer/');
|
||||
const viewerDeployPath = path.resolve(localPath, 'viewer/');
|
||||
fse.copySync(viewerBuildPath, viewerDeployPath, { overwrite: true });
|
||||
addAnalytics(path.resolve(viewerDeployPath, 'index.html'));
|
||||
addManifest(path.resolve(viewerDeployPath, 'index.html'));
|
||||
addPwa(path.resolve(viewerDeployPath, 'index.html'));
|
||||
|
||||
const pwaDataPath = path.resolve(dataDir, 'pwa/');
|
||||
fse.copySync(pwaDataPath, viewerDeployPath, { overwrite: true });
|
||||
addVersion(path.resolve(viewerDeployPath, 'sw.js'));
|
||||
}
|
||||
|
||||
function copyMe() {
|
||||
console.log('\n###', 'copy me files');
|
||||
const meBuildPath = path.resolve(buildDir, '../build/mesoscale-explorer/');
|
||||
const meBuildPath = path.resolve(buildDir, 'mesoscale-explorer/');
|
||||
const meDeployPath = path.resolve(localPath, 'me/viewer/');
|
||||
fse.copySync(meBuildPath, meDeployPath, { overwrite: true });
|
||||
addAnalytics(path.resolve(meDeployPath, 'index.html'));
|
||||
}
|
||||
|
||||
function copyMVSStories() {
|
||||
console.log('\n###', 'copy MVS stories files');
|
||||
const mvsStoriesBuildPath = path.resolve(buildDir, 'mvs-stories/');
|
||||
const mvsStoriesDeployPath = path.resolve(localPath, `stories-viewer/v${MVS_STORIES_VERSION}/`);
|
||||
fse.copySync(mvsStoriesBuildPath, mvsStoriesDeployPath, { overwrite: true });
|
||||
addAnalytics(path.resolve(mvsStoriesDeployPath, 'index.html'));
|
||||
|
||||
// TODO: add PWA
|
||||
// addManifest(path.resolve(mvsStoriesDeployPath, 'index.html'));
|
||||
// addPwa(path.resolve(mvsStoriesDeployPath, 'index.html'));
|
||||
}
|
||||
|
||||
function copyDemo(name) {
|
||||
console.log('\n###', `copy demo files for ${name}`);
|
||||
const demoBuildPath = path.resolve(buildDir, `examples/${name}/`);
|
||||
const demoDeployPath = path.resolve(localPath, `demos/${name}/`);
|
||||
fse.copySync(demoBuildPath, demoDeployPath, { overwrite: true });
|
||||
addAnalytics(path.resolve(demoDeployPath, 'index.html'));
|
||||
}
|
||||
|
||||
function copyDemos() {
|
||||
console.log('\n###', 'copy demos files');
|
||||
const lightingBuildPath = path.resolve(buildDir, '../build/examples/lighting/');
|
||||
const lightingDeployPath = path.resolve(localPath, 'demos/lighting/');
|
||||
fse.copySync(lightingBuildPath, lightingDeployPath, { overwrite: true });
|
||||
addAnalytics(path.resolve(lightingDeployPath, 'index.html'));
|
||||
|
||||
const orbitalsBuildPath = path.resolve(buildDir, '../build/examples/alpha-orbitals/');
|
||||
const orbitalsDeployPath = path.resolve(localPath, 'demos/alpha-orbitals/');
|
||||
fse.copySync(orbitalsBuildPath, orbitalsDeployPath, { overwrite: true });
|
||||
addAnalytics(path.resolve(orbitalsDeployPath, 'index.html'));
|
||||
copyDemo('lighting');
|
||||
copyDemo('alpha-orbitals');
|
||||
copyDemo('mvs-stories');
|
||||
}
|
||||
|
||||
function copyFiles() {
|
||||
copyViewer();
|
||||
copyMe();
|
||||
copyDemos();
|
||||
try {
|
||||
copyViewer();
|
||||
copyMe();
|
||||
copyMVSStories();
|
||||
copyDemos();
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
function copyToRepository() {
|
||||
console.log('\n###', 'copy repository files');
|
||||
fse.copySync(localPath, repositoryPath, { overwrite: true });
|
||||
}
|
||||
|
||||
function syncRepository() {
|
||||
console.log('\n###', 'sync repository');
|
||||
if (!fs.existsSync(path.resolve(repositoryPath, '.git/'))) {
|
||||
console.log('\n###', 'clone repository');
|
||||
git()
|
||||
.outputHandler(log)
|
||||
.clone(remoteUrl, repositoryPath)
|
||||
.fetch(['--all'])
|
||||
.exec(copyToRepository);
|
||||
} else {
|
||||
console.log('\n###', 'update repository');
|
||||
git()
|
||||
.outputHandler(log)
|
||||
.fetch(['--all'])
|
||||
.reset(['--hard', 'origin/master'])
|
||||
.exec(copyToRepository);
|
||||
}
|
||||
}
|
||||
|
||||
function commit() {
|
||||
console.log('\n###', 'commit changes');
|
||||
git()
|
||||
.outputHandler(log)
|
||||
.add(['-A'])
|
||||
.commit(`Updated Apps and Demos
|
||||
- Mol* version: ${VERSION}
|
||||
- MVS Stories version: ${MVS_STORIES_VERSION}`)
|
||||
.push();
|
||||
}
|
||||
|
||||
if (!fs.existsSync(localPath)) {
|
||||
@@ -71,26 +162,28 @@ if (!fs.existsSync(localPath)) {
|
||||
fs.mkdirSync(localPath, { recursive: true });
|
||||
}
|
||||
|
||||
process.chdir(localPath);
|
||||
const argParser = new argparse.ArgumentParser({
|
||||
add_help: true,
|
||||
description: 'Mol* Deploy'
|
||||
});
|
||||
argParser.add_argument('--local',{
|
||||
help: 'Do not commit to remote repository.',
|
||||
required: false,
|
||||
action: 'store_true',
|
||||
});
|
||||
const args = argParser.parse_args();
|
||||
|
||||
if (!fs.existsSync(path.resolve(localPath, '.git/'))) {
|
||||
console.log('\n###', 'clone repository');
|
||||
git()
|
||||
.outputHandler(log)
|
||||
.clone(remoteUrl, localPath)
|
||||
.fetch(['--all'])
|
||||
.exec(copyFiles)
|
||||
.add(['-A'])
|
||||
.commit('updated viewer & demos')
|
||||
.push();
|
||||
} else {
|
||||
console.log('\n###', 'update repository');
|
||||
git()
|
||||
.outputHandler(log)
|
||||
.fetch(['--all'])
|
||||
.reset(['--hard', 'origin/master'])
|
||||
.exec(copyFiles)
|
||||
.add(['-A'])
|
||||
.commit('updated viewer & demos')
|
||||
.push();
|
||||
}
|
||||
copyFiles();
|
||||
|
||||
if (args.local) {
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
if (!fs.existsSync(repositoryPath)) {
|
||||
console.log('\n###', 'create repositoryPath');
|
||||
fs.mkdirSync(repositoryPath, { recursive: true });
|
||||
}
|
||||
|
||||
process.chdir(repositoryPath);
|
||||
syncRepository();
|
||||
commit();
|
||||
16
scripts/write-version.mjs
Normal file
16
scripts/write-version.mjs
Normal file
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* Copyright (c) 2025 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
import * as fs from 'fs';
|
||||
|
||||
const VERSION = JSON.parse(fs.readFileSync('./package.json', 'utf8')).version;
|
||||
const TIMESTAMP = Date.now();
|
||||
const file = `export var PLUGIN_VERSION = '${VERSION}';\nexport var PLUGIN_VERSION_DATE = new Date(${TIMESTAMP})`;
|
||||
const files = ['./lib/mol-plugin/version.js', './lib/commonjs/mol-plugin/version.js'];
|
||||
for (const f of files) {
|
||||
if (!fs.existsSync(f)) continue;
|
||||
fs.writeFileSync(f, file);
|
||||
}
|
||||
@@ -27,7 +27,7 @@ import { ObjectKeys } from '../../mol-util/type-helpers';
|
||||
import './index.html';
|
||||
import { ShowButtons, StructurePreset, ViewportComponent } from './viewport';
|
||||
|
||||
require('mol-plugin-ui/skin/light.scss');
|
||||
import '../../mol-plugin-ui/skin/light.scss';
|
||||
|
||||
export { PLUGIN_VERSION as version } from '../../mol-plugin/version';
|
||||
export { setDebugMode, setProductionMode } from '../../mol-util/debug';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2022-2024 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2022-2025 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -25,7 +25,7 @@ import { MesoFocusLoci } from './behavior/camera';
|
||||
import { GraphicsMode, MesoscaleState } from './data/state';
|
||||
import { MesoSelectLoci } from './behavior/select';
|
||||
import { Transparency } from '../../mol-gl/webgl/render-item';
|
||||
import { LoadModel, loadExampleEntry, loadPdb, loadPdbDev, loadUrl, openState } from './ui/states';
|
||||
import { LoadModel, loadExampleEntry, loadPdb, loadPdbIhm, loadUrl, openState } from './ui/states';
|
||||
import { Asset } from '../../mol-util/assets';
|
||||
import { AnimateCameraSpin } from '../../mol-plugin-state/animation/built-in/camera-spin';
|
||||
import { AnimateCameraRock } from '../../mol-plugin-state/animation/built-in/camera-rock';
|
||||
@@ -85,7 +85,7 @@ const DefaultMesoscaleExplorerOptions = {
|
||||
viewportShowExpand: PluginConfig.Viewport.ShowExpand.defaultValue,
|
||||
viewportShowControls: PluginConfig.Viewport.ShowControls.defaultValue,
|
||||
viewportShowSettings: PluginConfig.Viewport.ShowSettings.defaultValue,
|
||||
viewportShowSelectionMode: false,
|
||||
viewportShowSelectionMode: true,
|
||||
viewportShowAnimation: false,
|
||||
viewportShowTrajectoryControls: false,
|
||||
pluginStateServer: PluginConfig.State.DefaultServer.defaultValue,
|
||||
@@ -120,8 +120,15 @@ export class MesoscaleExplorer {
|
||||
await loadPdb(this.plugin, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Scheduled for removal in v5. Use {@link loadPdbIhm | loadPdbIhm(id: string)} instead.
|
||||
*/
|
||||
async loadPdbDev(id: string) {
|
||||
await loadPdbDev(this.plugin, id);
|
||||
await this.loadPdbIhm(id);
|
||||
}
|
||||
|
||||
async loadPdbIhm(id: string) {
|
||||
await loadPdbIhm(this.plugin, id);
|
||||
}
|
||||
|
||||
static async create(elementOrId: string | HTMLElement, options: Partial<MesoscaleExplorerOptions> = {}) {
|
||||
@@ -140,10 +147,11 @@ export class MesoscaleExplorer {
|
||||
behaviors: [
|
||||
PluginSpec.Behavior(PluginBehaviors.Camera.CameraAxisHelper),
|
||||
PluginSpec.Behavior(PluginBehaviors.Camera.CameraControls),
|
||||
PluginSpec.Behavior(PluginBehaviors.State.SnapshotControls),
|
||||
|
||||
PluginSpec.Behavior(MesoFocusLoci),
|
||||
PluginSpec.Behavior(MesoSelectLoci),
|
||||
|
||||
PluginSpec.Behavior(PluginBehaviors.Representation.SelectLoci),
|
||||
...o.extensions.map(e => Extensions[e]),
|
||||
],
|
||||
animations: [
|
||||
@@ -245,6 +253,10 @@ export class MesoscaleExplorer {
|
||||
},
|
||||
cameraFog: { name: 'off', params: {} },
|
||||
hiZ: { enabled: true },
|
||||
xr: {
|
||||
disablePostprocessing: false,
|
||||
sceneRadiusInMeters: 0.75,
|
||||
},
|
||||
});
|
||||
|
||||
plugin.representation.structure.registry.clear();
|
||||
@@ -254,7 +266,6 @@ export class MesoscaleExplorer {
|
||||
image: true,
|
||||
componentManager: false,
|
||||
structureSelection: true,
|
||||
behavior: true,
|
||||
});
|
||||
|
||||
plugin.managers.lociLabels.clearProviders();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2023-2025 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -21,6 +21,7 @@ const Key = Binding.TriggerKey;
|
||||
const DefaultMesoFocusLociBindings = {
|
||||
clickCenter: Binding([
|
||||
Trigger(B.Flag.Primary, M.create()),
|
||||
Trigger(B.Flag.Trigger),
|
||||
], 'Camera center', 'Click element using ${triggers}'),
|
||||
clickCenterFocus: Binding([
|
||||
Trigger(B.Flag.Secondary, M.create()),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2023-2025 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -24,7 +24,8 @@ const Trigger = Binding.Trigger;
|
||||
|
||||
const DefaultMesoSelectLociBindings = {
|
||||
click: Binding([
|
||||
Trigger(B.Flag.Primary, M.create())
|
||||
Trigger(B.Flag.Primary, M.create()),
|
||||
Trigger(B.Flag.Trigger),
|
||||
], 'Click', 'Click element using ${triggers}'),
|
||||
clickToggleSelect: Binding([
|
||||
Trigger(B.Flag.Primary, M.create({ shift: true })),
|
||||
@@ -73,7 +74,7 @@ export const MesoSelectLoci = PluginBehavior.create<MesoSelectLociProps>({
|
||||
this.ctx.managers.interactivity.lociSelects.deselectAll();
|
||||
return;
|
||||
}
|
||||
const loci = Loci.normalize(current.loci, modifiers.control ? 'entity' : 'chain');
|
||||
const loci = Loci.normalize(current.loci, modifiers.control ? 'entity' : this.ctx.managers.interactivity.props.granularity);
|
||||
this.ctx.managers.interactivity.lociSelects.toggle({ loci }, false);
|
||||
if (StructureElement.Loci.is(current.loci)) {
|
||||
const cell = this.ctx.helpers.substructureParent.get(current.loci.structure);
|
||||
@@ -116,7 +117,7 @@ export const MesoSelectLoci = PluginBehavior.create<MesoSelectLociProps>({
|
||||
if (modifiers.control) {
|
||||
this.ctx.managers.interactivity.lociHighlights.highlightOnly({ repr: current.repr, loci: EveryLoci }, false);
|
||||
} else {
|
||||
const loci = Loci.normalize(current.loci, 'chain');
|
||||
const loci = Loci.normalize(current.loci, this.ctx.managers.interactivity.props.granularity);
|
||||
this.ctx.managers.interactivity.lociHighlights.highlightOnly({ repr: current.repr, loci }, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2019-2024 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2019-2026 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
* @author Ludovic Autin <ludovic.autin@gmail.com>
|
||||
@@ -36,6 +36,12 @@ function getSpacefillParams(color: Color, sizeFactor: number, graphics: Graphics
|
||||
approximate: gmp.approximate,
|
||||
alphaThickness: gmp.alphaThickness,
|
||||
visuals: [merge ? 'structure-element-sphere' : 'element-sphere'],
|
||||
interior: {
|
||||
color: Color.fromNormalizedRgb(0, 0, 0),
|
||||
colorStrength: 0.15,
|
||||
substance: { metalness: 0.0, roughness: 1.0, bumpiness: 0.0 },
|
||||
substanceStrength: 1,
|
||||
}
|
||||
},
|
||||
},
|
||||
colorTheme: {
|
||||
@@ -49,7 +55,7 @@ function getSpacefillParams(color: Color, sizeFactor: number, graphics: Graphics
|
||||
sizeTheme: {
|
||||
name: 'physical',
|
||||
params: {
|
||||
value: 1,
|
||||
scale: 1,
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2023-2024 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2023-2025 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -50,6 +50,12 @@ function getSpacefillParams(color: Color, sizeFactor: number, graphics: Graphics
|
||||
clipPrimitive: true,
|
||||
approximate: gmp.approximate,
|
||||
alphaThickness: gmp.alphaThickness,
|
||||
interior: {
|
||||
color: Color.fromNormalizedRgb(0, 0, 0),
|
||||
colorStrength: 0.15,
|
||||
substance: { metalness: 0.0, roughness: 1.0, bumpiness: 0.0 },
|
||||
substanceStrength: 1,
|
||||
}
|
||||
},
|
||||
},
|
||||
colorTheme: {
|
||||
@@ -192,12 +198,13 @@ export async function createGenericHierarchy(plugin: PluginContext, file: Asset.
|
||||
const t = isBinary ? d : utf8Read(d, 0, d.length);
|
||||
const file = Asset.File(new File([t], ent.file));
|
||||
|
||||
const color = ColorNames.skyblue;
|
||||
const color = (ent.color) ? Color.fromRgb(ent.color[0], ent.color[1], ent.color[2]) : ColorNames.skyblue;
|
||||
|
||||
const sizeFactor = ent.sizeFactor || 1;
|
||||
const tags = ent.groups.map(({ id, root }) => `${root}:${id}`);
|
||||
const instances = ent.instances && getAssetInstances(ent.instances);
|
||||
const description = ent.description;
|
||||
|
||||
const label = ent.label || ent.file.split('.')[0];
|
||||
build = build
|
||||
.toRoot()
|
||||
@@ -300,6 +307,7 @@ type GenericEntity = {
|
||||
file: string
|
||||
label?: string
|
||||
description?: string
|
||||
color?: number[]
|
||||
groups: {
|
||||
/** reference to `${GenericGroup.id}` */
|
||||
id: string,
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
/**
|
||||
* Copyright (c) 2023-2024 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2023-2026 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { MmcifFormat } from '../../../../mol-model-formats/structure/mmcif';
|
||||
import { Model } from '../../../../mol-model/structure/model/model';
|
||||
import { PluginStateObject } from '../../../../mol-plugin-state/objects';
|
||||
import { StructureRepresentation3D } from '../../../../mol-plugin-state/transforms/representation';
|
||||
import { PluginContext } from '../../../../mol-plugin/context';
|
||||
@@ -40,6 +41,12 @@ function getSpacefillParams(color: Color, scaleFactor: number, graphics: Graphic
|
||||
clipPrimitive: true,
|
||||
approximate: gmp.approximate,
|
||||
alphaThickness: gmp.alphaThickness,
|
||||
interior: {
|
||||
color: Color.fromNormalizedRgb(0, 0, 0),
|
||||
colorStrength: 0.15,
|
||||
substance: { metalness: 0.0, roughness: 1.0, bumpiness: 0.0 },
|
||||
substanceStrength: 1,
|
||||
}
|
||||
},
|
||||
},
|
||||
colorTheme: {
|
||||
@@ -53,7 +60,7 @@ function getSpacefillParams(color: Color, scaleFactor: number, graphics: Graphic
|
||||
sizeTheme: {
|
||||
name: 'physical',
|
||||
params: {
|
||||
value: 1,
|
||||
scale: scaleFactor,
|
||||
}
|
||||
},
|
||||
};
|
||||
@@ -96,6 +103,8 @@ export async function createMmcifHierarchy(plugin: PluginContext, trajectory: St
|
||||
});
|
||||
}
|
||||
|
||||
const coarseGrained = Model.isCoarseGrained(model.data!);
|
||||
|
||||
const entGroups = new Map<string, StateObjectSelector>();
|
||||
const entIds = new Map<string, { idx: number, members: Map<number, number> }>();
|
||||
const entColors = new Map<string, Color[]>();
|
||||
@@ -164,7 +173,7 @@ export async function createMmcifHierarchy(plugin: PluginContext, trajectory: St
|
||||
for (let i = 0; i < entities._rowCount; i++) {
|
||||
const t = getEntityType(i);
|
||||
const color = entColors.get(t)![entIds.get(t)!.members.get(i)!];
|
||||
const scaleFactor = spheresAvgRadius.get(entities.id.value(i)) || 1;
|
||||
const scaleFactor = spheresAvgRadius.get(entities.id.value(i)) || (coarseGrained ? 2 : 1);
|
||||
|
||||
build = build
|
||||
.toRoot()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2022-2024 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2022-2025 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -35,6 +35,12 @@ function getSpacefillParams(color: Color, graphics: GraphicsMode) {
|
||||
clipPrimitive: true,
|
||||
approximate: gmp.approximate,
|
||||
alphaThickness: gmp.alphaThickness,
|
||||
interior: {
|
||||
color: Color.fromNormalizedRgb(0, 0, 0),
|
||||
colorStrength: 0.15,
|
||||
substance: { metalness: 0.0, roughness: 1.0, bumpiness: 0.0 },
|
||||
substanceStrength: 1,
|
||||
}
|
||||
},
|
||||
},
|
||||
colorTheme: {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2023-2024 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2023-2026 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -10,9 +10,10 @@ import { ParamDefinition as PD } from '../../../mol-util/param-definition';
|
||||
import { Task } from '../../../mol-task';
|
||||
import { Color } from '../../../mol-util/color';
|
||||
import { Spheres } from '../../../mol-geo/geometry/spheres/spheres';
|
||||
import { getAnimationParam } from '../../../mol-geo/geometry/animation';
|
||||
import { Clip } from '../../../mol-util/clip';
|
||||
import { escapeRegExp, stringToWords } from '../../../mol-util/string';
|
||||
import { Vec3 } from '../../../mol-math/linear-algebra';
|
||||
import { Mat4, Vec3 } from '../../../mol-math/linear-algebra';
|
||||
import { ParamMapping } from '../../../mol-util/param-mapping';
|
||||
import { EntityNode } from '../ui/entities';
|
||||
import { DistinctColorsProps, distinctColors } from '../../../mol-util/color/distinct';
|
||||
@@ -21,10 +22,10 @@ import { Hcl } from '../../../mol-util/color/spaces/hcl';
|
||||
import { StateObjectCell, StateObjectRef, StateSelection } from '../../../mol-state';
|
||||
import { ShapeRepresentation3D, StructureRepresentation3D } from '../../../mol-plugin-state/transforms/representation';
|
||||
import { SpacefillRepresentationProvider } from '../../../mol-repr/structure/representation/spacefill';
|
||||
import { assertUnreachable } from '../../../mol-util/type-helpers';
|
||||
import { MesoscaleExplorerState } from '../app';
|
||||
import { saturate } from '../../../mol-math/interpolate';
|
||||
import { Material } from '../../../mol-util/material';
|
||||
import { PCG } from '../../../mol-data/util/hash-functions';
|
||||
|
||||
function getHueRange(hue: number, variability: number) {
|
||||
let min = hue - variability;
|
||||
@@ -37,10 +38,11 @@ function getHueRange(hue: number, variability: number) {
|
||||
|
||||
function getGrayscaleColors(count: number, luminance: number, variability: number) {
|
||||
const out: Color[] = [];
|
||||
const pcg = new PCG();
|
||||
for (let i = 0; i < count; ++ i) {
|
||||
const l = saturate(luminance / 100);
|
||||
const v = saturate(variability / 180) * Math.random();
|
||||
const s = Math.random() > 0.5 ? 1 : -1;
|
||||
const v = saturate(variability / 180) * pcg.float();
|
||||
const s = pcg.float() > 0.5 ? 1 : -1;
|
||||
const d = Math.abs(l + s * v) % 1;
|
||||
out[i] = Color.fromNormalizedRgb(d, d, d);
|
||||
}
|
||||
@@ -172,6 +174,8 @@ export const LodParams = {
|
||||
approximate: Spheres.Params.approximate,
|
||||
};
|
||||
|
||||
export const AnimationParams = getAnimationParam().params;
|
||||
|
||||
export const SimpleClipParams = {
|
||||
type: PD.Select('none', PD.objectToOptions(Clip.Type, t => stringToWords(t))),
|
||||
invert: PD.Boolean(false),
|
||||
@@ -211,7 +215,8 @@ export function getClipObjects(values: SimpleClipProps, boundingSphere: Sphere3D
|
||||
invert: values.invert,
|
||||
position,
|
||||
scale,
|
||||
rotation: values.rotation
|
||||
rotation: values.rotation,
|
||||
transform: Mat4.identity(),
|
||||
}];
|
||||
}
|
||||
|
||||
@@ -278,6 +283,7 @@ export const MesoscaleGroupParams = {
|
||||
emissive: PD.Numeric(0, { min: 0, max: 1, step: 0.01 }),
|
||||
lod: PD.Group(LodParams),
|
||||
clip: PD.Group(SimpleClipParams),
|
||||
animation: PD.Group(AnimationParams),
|
||||
};
|
||||
export type MesoscaleGroupProps = PD.Values<typeof MesoscaleGroupParams>;
|
||||
|
||||
@@ -315,38 +321,7 @@ export function getMesoscaleGroupParams(graphicsMode: GraphicsMode): MesoscaleGr
|
||||
export type LodLevels = typeof SpacefillRepresentationProvider.defaultValues['lodLevels']
|
||||
|
||||
export function getLodLevels(graphicsMode: Exclude<GraphicsMode, 'custom'>): LodLevels {
|
||||
switch (graphicsMode) {
|
||||
case 'performance':
|
||||
return [
|
||||
{ minDistance: 1, maxDistance: 300, overlap: 0, stride: 1, scaleBias: 1 },
|
||||
{ minDistance: 300, maxDistance: 2000, overlap: 0, stride: 40, scaleBias: 3 },
|
||||
{ minDistance: 2000, maxDistance: 6000, overlap: 0, stride: 150, scaleBias: 3 },
|
||||
{ minDistance: 6000, maxDistance: 10000000, overlap: 0, stride: 300, scaleBias: 2.5 },
|
||||
];
|
||||
case 'balanced':
|
||||
return [
|
||||
{ minDistance: 1, maxDistance: 500, overlap: 0, stride: 1, scaleBias: 1 },
|
||||
{ minDistance: 500, maxDistance: 2000, overlap: 0, stride: 15, scaleBias: 3 },
|
||||
{ minDistance: 2000, maxDistance: 6000, overlap: 0, stride: 70, scaleBias: 2.7 },
|
||||
{ minDistance: 6000, maxDistance: 10000000, overlap: 0, stride: 200, scaleBias: 2.5 },
|
||||
];
|
||||
case 'quality':
|
||||
return [
|
||||
{ minDistance: 1, maxDistance: 1000, overlap: 0, stride: 1, scaleBias: 1 },
|
||||
{ minDistance: 1000, maxDistance: 4000, overlap: 0, stride: 10, scaleBias: 3 },
|
||||
{ minDistance: 4000, maxDistance: 10000, overlap: 0, stride: 50, scaleBias: 2.7 },
|
||||
{ minDistance: 10000, maxDistance: 10000000, overlap: 0, stride: 200, scaleBias: 2.3 },
|
||||
];
|
||||
case 'ultra':
|
||||
return [
|
||||
{ minDistance: 1, maxDistance: 5000, overlap: 0, stride: 1, scaleBias: 1 },
|
||||
{ minDistance: 5000, maxDistance: 10000, overlap: 0, stride: 10, scaleBias: 3 },
|
||||
{ minDistance: 10000, maxDistance: 30000, overlap: 0, stride: 50, scaleBias: 2.5 },
|
||||
{ minDistance: 30000, maxDistance: 10000000, overlap: 0, stride: 200, scaleBias: 2 },
|
||||
];
|
||||
default:
|
||||
assertUnreachable(graphicsMode);
|
||||
}
|
||||
return Spheres.LodLevelsPresets[graphicsMode];
|
||||
}
|
||||
|
||||
export type GraphicsMode = 'ultra' | 'quality' | 'balanced' | 'performance' | 'custom';
|
||||
|
||||
@@ -93,9 +93,15 @@
|
||||
return;
|
||||
}
|
||||
|
||||
var pdbihm = getParam('pdbihm', '[^&]+').trim();
|
||||
if (pdbihm) {
|
||||
me.loadPdbIhm(pdbihm);
|
||||
return;
|
||||
}
|
||||
// support for deprecated pdb-dev param
|
||||
var pdbdev = getParam('pdbdev', '[^&]+').trim();
|
||||
if (pdbdev) {
|
||||
me.loadPdbDev(pdbdev);
|
||||
me.loadPdbIhm(pdbdev);
|
||||
return;
|
||||
}
|
||||
window.addEventListener('unload', () => {
|
||||
|
||||
@@ -6,5 +6,5 @@
|
||||
|
||||
import './favicon.ico';
|
||||
import './index.html';
|
||||
require('./style.scss');
|
||||
import './style.scss';
|
||||
export * from './app';
|
||||
|
||||
@@ -1,32 +1,28 @@
|
||||
@use "sass:color";
|
||||
|
||||
$default-background: #2D3E50;
|
||||
$font-color: #EDF1F2;
|
||||
$hover-font-color: #3B9AD9;
|
||||
$entity-current-font-color: #FFFFFF;
|
||||
$msp-btn-remove-background: #BF3A31;
|
||||
$msp-btn-remove-hover-font-color:#ffffff;
|
||||
$msp-btn-commit-on-font-color: #ffffff;
|
||||
$entity-badge-font-color: #ccd4e0;
|
||||
@use '../../mol-plugin-ui/skin/base/colors' with (
|
||||
$default-background: #2D3E50,
|
||||
$font-color: #EDF1F2,
|
||||
$hover-font-color: #3B9AD9,
|
||||
$entity-current-font-color: #FFFFFF,
|
||||
$msp-btn-remove-background: #BF3A31,
|
||||
$msp-btn-remove-hover-font-color:#ffffff,
|
||||
$msp-btn-commit-on-font-color: #ffffff,
|
||||
$entity-badge-font-color: #ccd4e0,
|
||||
|
||||
// used in LOG
|
||||
$log-message: #0CCA5D;
|
||||
$log-info: #5E3673;
|
||||
$log-warning: #FCC937;
|
||||
$log-error: #FD354B;
|
||||
// used in LOG
|
||||
$log-message: #0CCA5D,
|
||||
$log-info: #5E3673,
|
||||
$log-warning: #FCC937,
|
||||
$log-error: #FD354B,
|
||||
|
||||
$logo-background: rgba(0,0,0,0.75);
|
||||
$logo-background: rgba(0,0,0,0.75),
|
||||
|
||||
@function color-lower-contrast($color, $amount) {
|
||||
@return color.adjust($color, $lightness: -$amount, $space: hsl);
|
||||
}
|
||||
$color-adjust-sign: -1,
|
||||
);
|
||||
|
||||
@function color-increase-contrast($color, $amount) {
|
||||
@return color.adjust($color, $lightness: $amount, $space: hsl);
|
||||
}
|
||||
|
||||
@import 'mol-plugin-ui/skin/base/base';
|
||||
@import 'mol-plugin-ui/skin/base/variables';
|
||||
@use '../../mol-plugin-ui/skin/base/base';
|
||||
@use '../../mol-plugin-ui/skin/base/vars' as *;
|
||||
|
||||
a {
|
||||
color: $font-color;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2022-2024 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2022-2026 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -18,7 +18,7 @@ import { CombinedColorControl } from '../../../mol-plugin-ui/controls/color';
|
||||
import { MarkerAction } from '../../../mol-util/marker-action';
|
||||
import { EveryLoci, Loci } from '../../../mol-model/loci';
|
||||
import { deepEqual } from '../../../mol-util';
|
||||
import { ColorValueParam, ColorParams, ColorProps, DimLightness, LightnessParams, LodParams, MesoscaleGroup, MesoscaleGroupProps, OpacityParams, SimpleClipParams, SimpleClipProps, createClipMapping, getClipObjects, getDistinctGroupColors, RootParams, MesoscaleState, getRoots, getAllGroups, getAllLeafGroups, getFilteredEntities, getAllFilteredEntities, getGroups, getEntities, getAllEntities, getEntityLabel, updateColors, getGraphicsModeProps, GraphicsMode, MesoscaleStateParams, setGraphicsCanvas3DProps, PatternParams, expandAllGroups, EmissiveParams, IllustrativeParams, getCellDescription, getEntityDescription, getEveryEntity } from '../data/state';
|
||||
import { ColorValueParam, ColorParams, ColorProps, DimLightness, LightnessParams, LodParams, AnimationParams, MesoscaleGroup, MesoscaleGroupProps, OpacityParams, SimpleClipParams, SimpleClipProps, createClipMapping, getClipObjects, getDistinctGroupColors, RootParams, MesoscaleState, getRoots, getAllGroups, getAllLeafGroups, getFilteredEntities, getAllFilteredEntities, getGroups, getEntities, getAllEntities, getEntityLabel, updateColors, getGraphicsModeProps, GraphicsMode, MesoscaleStateParams, setGraphicsCanvas3DProps, PatternParams, expandAllGroups, EmissiveParams, IllustrativeParams, getCellDescription, getEntityDescription, getEveryEntity } from '../data/state';
|
||||
import React, { useState } from 'react';
|
||||
import { MesoscaleExplorerState } from '../app';
|
||||
import { StructureElement } from '../../../mol-model/structure/structure/element';
|
||||
@@ -29,6 +29,7 @@ import { Sphere3D } from '../../../mol-math/geometry';
|
||||
import { MesoFocusLoci } from '../behavior/camera';
|
||||
import Markdown from 'react-markdown';
|
||||
import { combineLatest } from 'rxjs';
|
||||
import { ColorLoaderControls } from './states';
|
||||
|
||||
function centerLoci(plugin: PluginContext, loci: Loci, durationMs = 250) {
|
||||
const { canvas3d } = plugin;
|
||||
@@ -619,6 +620,7 @@ class Node<P extends {}, S extends { isDisabled: boolean }> extends PluginUIComp
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class GroupNode extends Node<{ filter: string }, { isCollapsed: boolean, action?: 'color' | 'clip' | 'root', isDisabled: boolean }> {
|
||||
state = {
|
||||
isCollapsed: !!this.props.cell.state.isCollapsed,
|
||||
@@ -826,6 +828,26 @@ export class GroupNode extends Node<{ filter: string }, { isCollapsed: boolean,
|
||||
update.commit();
|
||||
};
|
||||
|
||||
updateAnimation = (values: PD.Values) => {
|
||||
const update = this.plugin.state.data.build();
|
||||
|
||||
for (const r of this.allFilteredEntities) {
|
||||
update.to(r).update(old => {
|
||||
if (old.type) {
|
||||
old.type.params.animation = values;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for (const g of this.allGroups) {
|
||||
update.to(g).update(old => {
|
||||
old.animation = values;
|
||||
});
|
||||
}
|
||||
|
||||
update.commit();
|
||||
};
|
||||
|
||||
update = (props: MesoscaleGroupProps) => {
|
||||
this.plugin.state.data.build().to(this.ref).update(props);
|
||||
};
|
||||
@@ -863,6 +885,7 @@ export class GroupNode extends Node<{ filter: string }, { isCollapsed: boolean,
|
||||
const rootValue = this.cell.params?.values.color;
|
||||
const clipValue = this.cell.params?.values.clip;
|
||||
const lodValue = this.cell.params?.values.lod;
|
||||
const animationValue = this.cell.params?.values.animation;
|
||||
const isRoot = this.cell.params?.values.root;
|
||||
|
||||
const groups = this.groups;
|
||||
@@ -881,12 +904,13 @@ export class GroupNode extends Node<{ filter: string }, { isCollapsed: boolean,
|
||||
const root = (isRoot && this.allGroups.length > 1) && <IconButton svg={BrushSvg} toggleState={false} disabled={disabled} small onClick={this.toggleRoot} />;
|
||||
const clip = <IconButton svg={ContentCutSvg} toggleState={false} disabled={disabled} small onClick={this.toggleClip} />;
|
||||
const visibility = <IconButton svg={state.isHidden ? VisibilityOffOutlinedSvg : VisibilityOutlinedSvg} toggleState={false} disabled={disabled} small onClick={this.toggleVisible} />;
|
||||
|
||||
const loadColorButton = (depth === 0) && <ColorLoaderControls plugin={this.plugin} />;
|
||||
return <>
|
||||
<div className={`msp-flex-row`} style={{ margin: `1px 5px 1px ${depth * 10 + 5}px` }}>
|
||||
{expand}
|
||||
{label}
|
||||
{root || color}
|
||||
{loadColorButton}
|
||||
{clip}
|
||||
{visibility}
|
||||
</div>
|
||||
@@ -901,6 +925,7 @@ export class GroupNode extends Node<{ filter: string }, { isCollapsed: boolean,
|
||||
topRightIcon={CloseSvg} noTopMargin childrenClassName='msp-viewport-controls-panel-controls'>
|
||||
<ParameterControls params={SimpleClipParams} values={clipValue} onChangeValues={this.updateClip} />
|
||||
<ParameterControls params={LodParams} values={lodValue} onChangeValues={this.updateLod} />
|
||||
<ParameterControls params={AnimationParams} values={animationValue} onChangeValues={this.updateAnimation} />
|
||||
</ControlGroup>
|
||||
</div>}
|
||||
{this.state.action === 'root' && <div style={{ marginRight: 5 }} className='msp-accent-offset'>
|
||||
@@ -1077,6 +1102,19 @@ export class EntityNode extends Node<{}, { action?: 'color' | 'clip', isDisabled
|
||||
};
|
||||
}
|
||||
|
||||
get animationValue(): PD.Values<typeof AnimationParams> | undefined {
|
||||
const p = this.cell.transform.params?.type?.params?.animation;
|
||||
if (!p) return;
|
||||
return {
|
||||
wiggleMode: p.wiggleMode,
|
||||
wiggleSpeed: p.wiggleSpeed,
|
||||
wiggleAmplitude: p.wiggleAmplitude,
|
||||
wiggleFrequency: p.wiggleFrequency,
|
||||
tumbleSpeed: p.tumbleSpeed,
|
||||
tumbleAmplitude: p.tumbleAmplitude,
|
||||
};
|
||||
}
|
||||
|
||||
get patternValue(): { amplitude: number, frequency: number } | undefined {
|
||||
const p = this.cell.transform.params;
|
||||
if (p.type) return;
|
||||
@@ -1191,6 +1229,15 @@ export class EntityNode extends Node<{}, { action?: 'color' | 'clip', isDisabled
|
||||
}
|
||||
};
|
||||
|
||||
updateAnimation = (values: PD.Values) => {
|
||||
const params = this.cell.transform.params as StateTransformer.Params<StructureRepresentation3D>;
|
||||
if (!params.type) return;
|
||||
|
||||
this.plugin.build().to(this.ref).update(old => {
|
||||
old.type.params.animation = values;
|
||||
}).commit();
|
||||
};
|
||||
|
||||
updatePattern = (values: PD.Values) => {
|
||||
return this.plugin.build().to(this.ref).update(old => {
|
||||
if (!old.type) {
|
||||
@@ -1210,6 +1257,7 @@ export class EntityNode extends Node<{}, { action?: 'color' | 'clip', isDisabled
|
||||
const opacityValue = this.opacityValue;
|
||||
const emissiveValue = this.emissiveValue;
|
||||
const lodValue = this.lodValue;
|
||||
const animationValue = this.animationValue;
|
||||
const patternValue = this.patternValue;
|
||||
|
||||
const l = getEntityLabel(this.plugin, this.cell);
|
||||
@@ -1248,6 +1296,7 @@ export class EntityNode extends Node<{}, { action?: 'color' | 'clip', isDisabled
|
||||
topRightIcon={CloseSvg} noTopMargin childrenClassName='msp-viewport-controls-panel-controls'>
|
||||
<ParameterMappingControl mapping={this.clipMapping} />
|
||||
{lodValue && <ParameterControls params={LodParams} values={lodValue} onChangeValues={this.updateLod} />}
|
||||
{animationValue && <ParameterControls params={AnimationParams} values={animationValue} onChangeValues={this.updateAnimation} />}
|
||||
</ControlGroup>
|
||||
</div>}
|
||||
</>;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2022-2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2022-2026 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -13,17 +13,19 @@ import { StructureMeasurementsControls } from '../../../mol-plugin-ui/structure/
|
||||
import { MesoscaleExplorerState } from '../app';
|
||||
import { MesoscaleState } from '../data/state';
|
||||
import { EntityControls, FocusInfo, ModelInfo, SelectionInfo } from './entities';
|
||||
import { LoaderControls, ExampleControls, SessionControls, SnapshotControls, DatabaseControls, MesoQuickStylesControls, ExplorerInfo } from './states';
|
||||
import { LoaderControls, ExampleControls, SessionControls, SnapshotControls, DatabaseControls, MesoQuickStylesControls, MesoProceduralAnimationControls, ExplorerInfo } from './states';
|
||||
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
|
||||
import { TuneSvg } from '../../../mol-plugin-ui/controls/icons';
|
||||
import { RendererParams } from '../../../mol-gl/renderer';
|
||||
import { TrackballControlsParams } from '../../../mol-canvas3d/controls/trackball';
|
||||
import { XRManagerParams } from '../../../mol-canvas3d/helper/xr-manager';
|
||||
|
||||
const Spacer = () => <div style={{ height: '2em' }} />;
|
||||
|
||||
const ViewportParams = {
|
||||
renderer: PD.Group(RendererParams),
|
||||
trackball: PD.Group(TrackballControlsParams),
|
||||
xr: PD.Group(XRManagerParams, { label: 'XR' }),
|
||||
};
|
||||
|
||||
class ViewportSettingsUI extends CollapsableControls<{}, {}> {
|
||||
@@ -143,6 +145,7 @@ export class RightPanel extends PluginUIComponent<{}, { isDisabled: boolean }> {
|
||||
<StructureMeasurementsControls initiallyCollapsed={true}/>
|
||||
</>
|
||||
<MesoQuickStylesControls />
|
||||
<MesoProceduralAnimationControls />
|
||||
<Spacer />
|
||||
<SectionHeader title='Entities' />
|
||||
<EntityControls />
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2022-2024 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2022-2026 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -8,7 +8,7 @@ import { MmcifFormat } from '../../../mol-model-formats/structure/mmcif';
|
||||
import { MmcifProvider } from '../../../mol-plugin-state/formats/trajectory';
|
||||
import { PluginStateObject } from '../../../mol-plugin-state/objects';
|
||||
import { Button, ExpandGroup, IconButton } from '../../../mol-plugin-ui/controls/common';
|
||||
import { GetAppSvg, HelpOutlineSvg, MagicWandSvg, TourSvg, Icon, OpenInBrowserSvg } from '../../../mol-plugin-ui/controls/icons';
|
||||
import { AnimationSvg, GetAppSvg, HelpOutlineSvg, MagicWandSvg, TourSvg, Icon, OpenInBrowserSvg } from '../../../mol-plugin-ui/controls/icons';
|
||||
import { CollapsableControls, PluginUIComponent } from '../../../mol-plugin-ui/base';
|
||||
import { ApplyActionControl } from '../../../mol-plugin-ui/state/apply-action';
|
||||
import { LocalStateSnapshotList, LocalStateSnapshotParams, LocalStateSnapshots } from '../../../mol-plugin-ui/state/snapshots';
|
||||
@@ -24,9 +24,10 @@ import { createCellpackHierarchy } from '../data/cellpack/preset';
|
||||
import { createGenericHierarchy } from '../data/generic/preset';
|
||||
import { createMmcifHierarchy } from '../data/mmcif/preset';
|
||||
import { createPetworldHierarchy } from '../data/petworld/preset';
|
||||
import { MesoscaleState, MesoscaleStateObject, setGraphicsCanvas3DProps, updateStyle } from '../data/state';
|
||||
import { getAllEntities, getAllGroups, getEntityLabel, MesoscaleState, MesoscaleStateObject, setGraphicsCanvas3DProps, updateStyle } from '../data/state';
|
||||
import { isTimingMode } from '../../../mol-util/debug';
|
||||
import { now } from '../../../mol-util/now';
|
||||
import { readFromFile } from '../../../mol-util/data-source';
|
||||
|
||||
function adjustPluginProps(ctx: PluginContext) {
|
||||
const customState = ctx.customState as MesoscaleExplorerState;
|
||||
@@ -45,8 +46,6 @@ function adjustPluginProps(ctx: PluginContext) {
|
||||
dimColor: Color(0xffffff),
|
||||
dimStrength: 1,
|
||||
markerPriority: 2,
|
||||
interiorColorFlag: false,
|
||||
interiorDarkening: 0.15,
|
||||
exposure: 1.1,
|
||||
xrayEdgeFalloff: 3,
|
||||
},
|
||||
@@ -211,27 +210,53 @@ export async function loadPdb(ctx: PluginContext, id: string) {
|
||||
await createHierarchy(ctx, data.ref);
|
||||
}
|
||||
|
||||
export async function loadPdbDev(ctx: PluginContext, id: string) {
|
||||
export async function loadPdbIhm(ctx: PluginContext, id: string) {
|
||||
await reset(ctx);
|
||||
let url: string;
|
||||
// 4 character PDB id, TODO: support extended PDB ID
|
||||
if (id.match(/^[1-9][A-Z0-9]{3}$/i) !== null) {
|
||||
url = `https://pdb-dev.wwpdb.org/bcif/${id.toLowerCase()}.bcif`;
|
||||
url = `https://pdb-ihm.org/bcif/${id.toLowerCase()}.bcif`;
|
||||
} else {
|
||||
const nId = id.toUpperCase().startsWith('PDBDEV_') ? id : `PDBDEV_${id.padStart(8, '0')}`;
|
||||
url = `https://pdb-dev.wwpdb.org/bcif/${nId.toUpperCase()}.bcif`;
|
||||
url = `https://pdb-ihm.org/bcif/${nId.toUpperCase()}.bcif`;
|
||||
}
|
||||
const data = await ctx.builders.data.download({ url, isBinary: true });
|
||||
await createHierarchy(ctx, data.ref);
|
||||
}
|
||||
|
||||
async function loadColors(ctx: PluginContext, file: File) {
|
||||
const colorData = await ctx.runTask(readFromFile(file, 'json'));
|
||||
|
||||
const update = ctx.state.data.build();
|
||||
const allEntities = getAllEntities(ctx);
|
||||
|
||||
for (const entityCell of allEntities) {
|
||||
const label = getEntityLabel(ctx, entityCell);
|
||||
const tags = entityCell.transform.tags;
|
||||
const fullname = (tags?.[0].replace('comp:', '') ?? '') + '.' + label;
|
||||
// test each tag, siwtch to uniform color
|
||||
if (fullname in colorData) {
|
||||
const { x, y, z } = colorData[fullname];
|
||||
const color = Color.fromRgb(x, y, z);
|
||||
update.to(entityCell).update(old => {
|
||||
if (old.type) {
|
||||
old.colorTheme = { name: 'uniform', params: { value: color, lightness: old.colorTheme.params.lightness } };
|
||||
old.type.params.color = color;
|
||||
} else if (old.coloring) {
|
||||
old.coloring.params.color = color;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
await update.commit();
|
||||
}
|
||||
//
|
||||
|
||||
export const LoadDatabase = StateAction.build({
|
||||
display: { name: 'Database', description: 'Load from Database' },
|
||||
params: (a, ctx: PluginContext) => {
|
||||
return {
|
||||
source: PD.Select('pdb', PD.objectToOptions({ pdb: 'PDB', pdbDev: 'PDB-Dev' })),
|
||||
source: PD.Select('pdb', PD.objectToOptions({ pdb: 'PDB', pdbIhm: 'PDB-IHM' })),
|
||||
entry: PD.Text(''),
|
||||
};
|
||||
},
|
||||
@@ -239,8 +264,8 @@ export const LoadDatabase = StateAction.build({
|
||||
})(({ params }, ctx: PluginContext) => Task.create('Loading from database...', async taskCtx => {
|
||||
if (params.source === 'pdb') {
|
||||
await loadPdb(ctx, params.entry);
|
||||
} else if (params.source === 'pdbDev') {
|
||||
await loadPdbDev(ctx, params.entry);
|
||||
} else if (params.source === 'pdbIhm') {
|
||||
await loadPdbIhm(ctx, params.entry);
|
||||
}
|
||||
}));
|
||||
|
||||
@@ -299,7 +324,6 @@ export const LoadModel = StateAction.build({
|
||||
}
|
||||
}));
|
||||
|
||||
//
|
||||
|
||||
export class DatabaseControls extends PluginUIComponent {
|
||||
componentDidMount() {
|
||||
@@ -337,6 +361,30 @@ export class ExampleControls extends PluginUIComponent {
|
||||
}
|
||||
}
|
||||
|
||||
export function ColorLoaderControls({ plugin }: { plugin: PluginContext }) {
|
||||
const triggerLoadColors = () => {
|
||||
const input = document.createElement('input');
|
||||
input.type = 'file';
|
||||
input.accept = '.json';
|
||||
input.onchange = async (e) => {
|
||||
const input = e.target as HTMLInputElement;
|
||||
if (!input.files || !input.files[0]) return;
|
||||
const file = input.files[0];
|
||||
await loadColors(plugin, new File([file], file.name));
|
||||
};
|
||||
input.click();
|
||||
};
|
||||
|
||||
return (
|
||||
<IconButton
|
||||
svg={OpenInBrowserSvg}
|
||||
title="Load Colors"
|
||||
onClick={triggerLoadColors}
|
||||
small
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export async function openState(ctx: PluginContext, file: File) {
|
||||
const customState = ctx.customState as MesoscaleExplorerState;
|
||||
delete customState.stateRef;
|
||||
@@ -426,7 +474,7 @@ export class ExplorerInfo extends PluginUIComponent<{}, { isDisabled: boolean, s
|
||||
driver.setSteps([
|
||||
// Left panel
|
||||
{ element: '#explorerinfo', popover: { title: 'Explorer Header Info', description: 'This section displays the explorer header with version information, documentation access, and tour navigation. Use the right and left arrow keys to navigate the tour.', side: 'left', align: 'start' } },
|
||||
{ element: '#database', popover: { title: 'Import from PDB', description: 'Load structures directly from PDB and PDB-DEV databases.', side: 'bottom', align: 'start' } },
|
||||
{ element: '#database', popover: { title: 'Import from PDB', description: 'Load structures directly from PDB and PDB-IHM databases.', side: 'bottom', align: 'start' } },
|
||||
{ element: '#loader', popover: { title: 'Import from File', description: 'Load local files (.molx, .molj, .zip, .cif, .bcif) using this option.', side: 'bottom', align: 'start' } },
|
||||
{ element: '#example', popover: { title: 'Example Models and Tours', description: 'Select from a range of example models and tours provided.', side: 'left', align: 'start' } },
|
||||
{ element: '#session', popover: { title: 'Session Management', description: 'Download the current session in .molx format.', side: 'top', align: 'start' } },
|
||||
@@ -486,7 +534,6 @@ export class ExplorerInfo extends PluginUIComponent<{}, { isDisabled: boolean, s
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class MesoQuickStylesControls extends CollapsableControls {
|
||||
defaultState() {
|
||||
return {
|
||||
@@ -732,3 +779,110 @@ export class MesoQuickStyles extends PluginUIComponent {
|
||||
</>;
|
||||
}
|
||||
}
|
||||
|
||||
export class MesoProceduralAnimationControls extends CollapsableControls {
|
||||
defaultState() {
|
||||
return {
|
||||
isCollapsed: true,
|
||||
header: 'Procedural Animation',
|
||||
brand: { accent: 'gray' as const, svg: AnimationSvg }
|
||||
};
|
||||
}
|
||||
|
||||
renderControls() {
|
||||
return <>
|
||||
<MesoProceduralAnimation />
|
||||
</>;
|
||||
}
|
||||
}
|
||||
|
||||
class MesoProceduralAnimation extends PluginUIComponent {
|
||||
private isMembrane(cell: { transform: { tags?: string[] } }) {
|
||||
return cell.transform.tags?.some(t => t.includes('mem')) ?? false;
|
||||
}
|
||||
|
||||
async dynamics() {
|
||||
const update = this.plugin.state.data.build();
|
||||
const entities = getAllEntities(this.plugin);
|
||||
const groups = getAllGroups(this.plugin);
|
||||
|
||||
for (const entity of entities) {
|
||||
const membrane = this.isMembrane(entity);
|
||||
update.to(entity).update(old => {
|
||||
if (old.type) {
|
||||
old.type.params.animation = {
|
||||
...old.type.params.animation,
|
||||
wiggleMode: 'position',
|
||||
wiggleSpeed: 7,
|
||||
wiggleAmplitude: 1,
|
||||
wiggleFrequency: 0.2,
|
||||
tumbleSpeed: 1,
|
||||
tumbleAmplitude: membrane ? 0 : 4,
|
||||
tumbleFrequency: 0.2,
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for (const group of groups) {
|
||||
const membrane = this.isMembrane(group);
|
||||
update.to(group).update(old => {
|
||||
old.animation = {
|
||||
...old.animation,
|
||||
wiggleMode: 'position',
|
||||
wiggleSpeed: 7,
|
||||
wiggleAmplitude: 1,
|
||||
wiggleFrequency: 0.2,
|
||||
tumbleSpeed: 1,
|
||||
tumbleAmplitude: membrane ? 0 : 4,
|
||||
tumbleFrequency: 0.2,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
await update.commit();
|
||||
}
|
||||
|
||||
async clear() {
|
||||
const update = this.plugin.state.data.build();
|
||||
const entities = getAllEntities(this.plugin);
|
||||
const groups = getAllGroups(this.plugin);
|
||||
|
||||
for (const entity of entities) {
|
||||
update.to(entity).update(old => {
|
||||
if (old.type) {
|
||||
old.type.params.animation = {
|
||||
...old.type.params.animation,
|
||||
wiggleAmplitude: 0,
|
||||
tumbleAmplitude: 0,
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for (const group of groups) {
|
||||
update.to(group).update(old => {
|
||||
old.animation = {
|
||||
...old.animation,
|
||||
wiggleAmplitude: 0,
|
||||
tumbleAmplitude: 0,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
await update.commit();
|
||||
}
|
||||
|
||||
render() {
|
||||
return <>
|
||||
<div className='msp-flex-row'>
|
||||
<Button noOverflow title='Enable wiggle for all entities and tumble for non-membrane entities' onClick={() => this.dynamics()} style={{ width: 'auto' }}>
|
||||
Dynamics
|
||||
</Button>
|
||||
<Button noOverflow title='Set wiggle and tumble amplitude to zero for all entities' onClick={() => this.clear()} style={{ width: 'auto' }}>
|
||||
Clear
|
||||
</Button>
|
||||
</div>
|
||||
</>;
|
||||
}
|
||||
}
|
||||
|
||||
39
src/apps/mvs-stories/context.ts
Normal file
39
src/apps/mvs-stories/context.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Copyright (c) 2025 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { MVSData } from '../../extensions/mvs/mvs-data';
|
||||
import type { MVSStoriesViewerModel } from './elements/viewer';
|
||||
|
||||
export type MVSStoriesCommand =
|
||||
| { kind: 'load-mvs', format?: 'mvsj' | 'mvsx', url?: string, data?: MVSData | string | Uint8Array<ArrayBuffer> }
|
||||
|
||||
|
||||
export class MVSStoriesContext {
|
||||
commands = new BehaviorSubject<MVSStoriesCommand | undefined>(undefined);
|
||||
state = {
|
||||
viewers: new BehaviorSubject<{ name?: string, model: MVSStoriesViewerModel }[]>([]),
|
||||
currentStoryData: new BehaviorSubject<string | Uint8Array<ArrayBuffer> | undefined>(undefined),
|
||||
isLoading: new BehaviorSubject(false),
|
||||
};
|
||||
|
||||
dispatch(command: MVSStoriesCommand) {
|
||||
this.commands.next(command);
|
||||
}
|
||||
|
||||
constructor(public name?: string) {
|
||||
}
|
||||
}
|
||||
|
||||
export function getMVSStoriesContext(options?: { name?: string, container?: object }): MVSStoriesContext {
|
||||
const container: any = options?.container ?? window;
|
||||
container.componentContexts ??= {};
|
||||
const name = options?.name ?? '<default>';
|
||||
if (!container.componentContexts[name]) {
|
||||
container.componentContexts[name] = new MVSStoriesContext(options?.name);
|
||||
}
|
||||
return container.componentContexts[name];
|
||||
}
|
||||
2
src/apps/mvs-stories/elements/index.ts
Normal file
2
src/apps/mvs-stories/elements/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
import './snapshot-markdown';
|
||||
import './viewer';
|
||||
152
src/apps/mvs-stories/elements/snapshot-markdown.tsx
Normal file
152
src/apps/mvs-stories/elements/snapshot-markdown.tsx
Normal file
@@ -0,0 +1,152 @@
|
||||
/**
|
||||
* Copyright (c) 2025 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
import { BehaviorSubject, distinctUntilChanged, map } from 'rxjs';
|
||||
import { PluginComponent } from '../../../mol-plugin-state/component';
|
||||
import { getMVSStoriesContext, MVSStoriesContext } from '../context';
|
||||
import { MVSStoriesViewerModel } from './viewer';
|
||||
import { useBehavior } from '../../../mol-plugin-ui/hooks/use-behavior';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import { PluginStateSnapshotManager } from '../../../mol-plugin-state/manager/snapshots';
|
||||
import { PluginReactContext } from '../../../mol-plugin-ui/base';
|
||||
import { CSSProperties, useEffect, useState } from 'react';
|
||||
import { Markdown } from '../../../mol-plugin-ui/controls/markdown';
|
||||
|
||||
export class MVSStoriesSnapshotMarkdownModel extends PluginComponent {
|
||||
readonly context: MVSStoriesContext;
|
||||
root: HTMLElement | undefined = undefined;
|
||||
|
||||
state = new BehaviorSubject<{
|
||||
entry?: PluginStateSnapshotManager.Entry,
|
||||
index?: number,
|
||||
all: PluginStateSnapshotManager.Entry[],
|
||||
}>({ all: [] });
|
||||
|
||||
get viewer() {
|
||||
return this.context.state.viewers.value?.find(v => this.options?.viewerName === v.name);
|
||||
}
|
||||
|
||||
sync() {
|
||||
const mng = this.viewer?.model.plugin?.managers.snapshot;
|
||||
this.state.next({
|
||||
entry: mng?.current,
|
||||
index: mng?.current ? mng?.getIndex(mng.current) : undefined,
|
||||
all: mng?.state.entries.toArray() ?? [],
|
||||
});
|
||||
}
|
||||
|
||||
async mount(root: HTMLElement) {
|
||||
this.root = root;
|
||||
|
||||
createRoot(root).render(<MVSStoriesSnapshotMarkdownUI model={this} />);
|
||||
|
||||
let currentViewer: MVSStoriesViewerModel | undefined = undefined;
|
||||
let sub: { unsubscribe: () => void } | undefined = undefined;
|
||||
this.subscribe(this.context.state.viewers.pipe(
|
||||
map(xs => xs.find(v => this.options?.viewerName === v.name)),
|
||||
distinctUntilChanged((a, b) => a?.model === b?.model)
|
||||
), viewer => {
|
||||
if (currentViewer !== viewer) {
|
||||
currentViewer = viewer?.model;
|
||||
sub?.unsubscribe();
|
||||
}
|
||||
if (!viewer) return;
|
||||
sub = this.subscribe(viewer.model.plugin?.managers.snapshot.events.changed, () => {
|
||||
this.sync();
|
||||
});
|
||||
this.sync();
|
||||
});
|
||||
|
||||
this.sync();
|
||||
}
|
||||
|
||||
constructor(private options?: { context?: { name?: string, container?: object }, viewerName?: string }) {
|
||||
super();
|
||||
|
||||
this.context = getMVSStoriesContext(options?.context);
|
||||
}
|
||||
}
|
||||
|
||||
function Loading() {
|
||||
return <div>
|
||||
<div style={{ marginBottom: 16 }}><i>Loading times may vary depending on the story size, your internet connection, and device performance</i></div>
|
||||
<div>Fetching data<Dots /></div>
|
||||
<div>Generating animations<Dots /></div>
|
||||
<div>Preparing visuals<Dots /></div>
|
||||
</div>;
|
||||
}
|
||||
|
||||
function Dots() {
|
||||
const [dots, setDots] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
const interval = setInterval(() => {
|
||||
setDots(d => (d + 1) % 4);
|
||||
}, Math.random() * 500 + 300);
|
||||
return () => clearInterval(interval);
|
||||
}, []);
|
||||
|
||||
return <span>{'.'.repeat(dots)}</span>;
|
||||
}
|
||||
|
||||
export function MVSStoriesSnapshotMarkdownUI({ model }: { model: MVSStoriesSnapshotMarkdownModel }) {
|
||||
const state = useBehavior(model.state);
|
||||
const isLoading = useBehavior(model.context.state.isLoading);
|
||||
|
||||
const style: CSSProperties = { display: 'flex', flexDirection: 'column', height: '100%' };
|
||||
const className = 'mvs-stories-markdown-explanation';
|
||||
|
||||
if (isLoading) {
|
||||
return <div style={style} className={className}>
|
||||
<h3>The story will be ready momentarily</h3>
|
||||
<Loading />
|
||||
</div>;
|
||||
}
|
||||
|
||||
if (state.all.length === 0) {
|
||||
return <div style={style} className={className}>
|
||||
<i>No snapshot loaded or no description available</i>
|
||||
</div>;
|
||||
}
|
||||
|
||||
return <div style={style} className={className}>
|
||||
<div style={{ display: 'flex', flexDirection: 'row', width: '100%', gap: '8px' }}>
|
||||
<span style={{ lineHeight: '38px', minWidth: 60, maxWidth: 60, flexShrink: 0 }}>{typeof state.index === 'number' ? state.index + 1 : '-'}/{state.all.length}</span>
|
||||
<button onClick={() => model.viewer?.model.plugin?.managers.snapshot.applyNext(-1)} style={{ flexGrow: 1, flexShrink: 0 }}>Prev</button>
|
||||
<button onClick={() => model.viewer?.model.plugin?.managers.snapshot.applyNext(1)} style={{ flexGrow: 1, flexShrink: 0 }}>Next</button>
|
||||
</div>
|
||||
<div style={{ flexGrow: 1, overflow: 'hidden', overflowY: 'auto', position: 'relative' }}>
|
||||
<div style={{ position: 'absolute', inset: 0 }}>
|
||||
<PluginReactContext.Provider value={model.viewer?.model.plugin as any}>
|
||||
<Markdown>{state.entry?.description ?? 'Description not available'}</Markdown>
|
||||
</PluginReactContext.Provider>
|
||||
</div>
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
|
||||
export class MVSStoriesSnapshotMarkdownViewer extends HTMLElement {
|
||||
private model: MVSStoriesSnapshotMarkdownModel | undefined = undefined;
|
||||
|
||||
async connectedCallback() {
|
||||
this.model = new MVSStoriesSnapshotMarkdownModel({
|
||||
context: { name: this.getAttribute('context-name') ?? undefined },
|
||||
viewerName: this.getAttribute('viewer-name') ?? undefined,
|
||||
});
|
||||
await this.model.mount(this);
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
this.model?.dispose();
|
||||
this.model = undefined;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
window.customElements.define('mvs-stories-snapshot-markdown', MVSStoriesSnapshotMarkdownViewer);
|
||||
131
src/apps/mvs-stories/elements/viewer.tsx
Normal file
131
src/apps/mvs-stories/elements/viewer.tsx
Normal file
@@ -0,0 +1,131 @@
|
||||
/**
|
||||
* Copyright (c) 2025 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
import { MolViewSpec } from '../../../extensions/mvs/behavior';
|
||||
import { loadMVSData } from '../../../extensions/mvs/components/formats';
|
||||
import { MVSData } from '../../../extensions/mvs/mvs-data';
|
||||
import { StringLike } from '../../../mol-io/common/string-like';
|
||||
import { PluginComponent } from '../../../mol-plugin-state/component';
|
||||
import { createPluginUI } from '../../../mol-plugin-ui';
|
||||
import { renderReact18 } from '../../../mol-plugin-ui/react18';
|
||||
import { DefaultPluginUISpec } from '../../../mol-plugin-ui/spec';
|
||||
import { PluginCommands } from '../../../mol-plugin/commands';
|
||||
import { PluginConfig } from '../../../mol-plugin/config';
|
||||
import { PluginContext } from '../../../mol-plugin/context';
|
||||
import { PluginSpec } from '../../../mol-plugin/spec';
|
||||
import { getMVSStoriesContext, MVSStoriesContext } from '../context';
|
||||
|
||||
export class MVSStoriesViewerModel extends PluginComponent {
|
||||
readonly context: MVSStoriesContext;
|
||||
plugin?: PluginContext = undefined;
|
||||
|
||||
async mount(root: HTMLElement) {
|
||||
const spec = DefaultPluginUISpec();
|
||||
this.plugin = await createPluginUI({
|
||||
target: root,
|
||||
render: renderReact18,
|
||||
spec: {
|
||||
...spec,
|
||||
layout: {
|
||||
initial: {
|
||||
isExpanded: false,
|
||||
showControls: false,
|
||||
controlsDisplay: 'landscape',
|
||||
},
|
||||
},
|
||||
components: {
|
||||
remoteState: 'none',
|
||||
viewport: {
|
||||
snapshotDescription: EmptyDescription,
|
||||
}
|
||||
},
|
||||
behaviors: [
|
||||
...spec.behaviors,
|
||||
PluginSpec.Behavior(MolViewSpec)
|
||||
],
|
||||
config: [
|
||||
[PluginConfig.Viewport.ShowAnimation, false],
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
this.subscribe(this.context.commands, async (cmd) => {
|
||||
if (!cmd || !this.plugin) return;
|
||||
|
||||
try {
|
||||
this.context.state.isLoading.next(true);
|
||||
if (cmd.kind === 'load-mvs') {
|
||||
let loadedData: MVSData | StringLike | Uint8Array | undefined;
|
||||
if (cmd.url) {
|
||||
const data = await this.plugin.runTask(this.plugin.fetch({ url: cmd.url, type: cmd.format === 'mvsx' ? 'binary' : 'string' }));
|
||||
loadedData = await loadMVSData(this.plugin, data, cmd.format ?? 'mvsj', { sourceUrl: cmd.url });
|
||||
} else if (cmd.data) {
|
||||
loadedData = await loadMVSData(this.plugin, cmd.data, cmd.format ?? 'mvsj');
|
||||
}
|
||||
if (StringLike.is(loadedData) || loadedData instanceof Uint8Array) {
|
||||
this.context.state.currentStoryData.next(loadedData as string | Uint8Array<ArrayBuffer>);
|
||||
} else if (loadedData) {
|
||||
this.context.state.currentStoryData.next(JSON.stringify(loadedData));
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
PluginCommands.Toast.Show(
|
||||
this.plugin,
|
||||
{ key: '<mvsload>', title: 'Error', message: e?.message ? `${e?.message}` : `${e}`, timeoutMs: 10000 }
|
||||
);
|
||||
} finally {
|
||||
this.context.state.isLoading.next(false);
|
||||
}
|
||||
});
|
||||
|
||||
const viewers = this.context.state.viewers.value;
|
||||
const next = [...viewers, { name: this.options?.name, model: this }];
|
||||
this.context.state.viewers.next(next);
|
||||
}
|
||||
|
||||
constructor(private options?: { context?: { name?: string, container?: object }, name?: string }) {
|
||||
super();
|
||||
|
||||
this.context = getMVSStoriesContext(options?.context);
|
||||
|
||||
const viewers = this.context.state.viewers.value;
|
||||
const index = viewers.findIndex(v => v.name === options?.name);
|
||||
if (index >= 0) {
|
||||
const next = [...viewers];
|
||||
next[index].model.dispose();
|
||||
next.splice(index, 0);
|
||||
this.context.state.viewers.next(next);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function EmptyDescription() {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
export class MVSStoriesViewer extends HTMLElement {
|
||||
private model: MVSStoriesViewerModel | undefined = undefined;
|
||||
|
||||
async connectedCallback() {
|
||||
this.model = new MVSStoriesViewerModel({
|
||||
name: this.getAttribute('name') ?? undefined,
|
||||
context: { name: this.getAttribute('context-name') ?? undefined },
|
||||
});
|
||||
await this.model.mount(this);
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
this.model?.dispose();
|
||||
this.model = undefined;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
window.customElements.define('mvs-stories-viewer', MVSStoriesViewer);
|
||||
BIN
src/apps/mvs-stories/favicon.ico
Normal file
BIN
src/apps/mvs-stories/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
148
src/apps/mvs-stories/index.html
Normal file
148
src/apps/mvs-stories/index.html
Normal file
@@ -0,0 +1,148 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
|
||||
<link rel="icon" href="./favicon.ico" type="image/x-icon">
|
||||
<title>Molecular Stories</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
#viewer {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 34%;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
#controls {
|
||||
position: absolute;
|
||||
left: 66%;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
padding: 16px;
|
||||
padding-bottom: 20px;
|
||||
border: 1px solid #ccc;
|
||||
border-left: none;
|
||||
background: #F6F5F3;
|
||||
z-index: -2;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
#links {
|
||||
position: absolute;
|
||||
bottom: 4px;
|
||||
right: 8px;
|
||||
font-family: "Raleway", "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
font-size: 0.6rem;
|
||||
z-index: -1;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
#links a {
|
||||
color: #666;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#links .sep {
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
@media (orientation:portrait) {
|
||||
#viewer {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 40%;
|
||||
}
|
||||
|
||||
#controls {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 60%;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
.msp-viewport-controls-buttons {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" type="text/css" href="mvs-stories.css" />
|
||||
<script type="text/javascript" src="mvs-stories.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<!-- the context-name parameter is optional and useful when embedding multiple stories in a single page -->
|
||||
<div id="viewer">
|
||||
<mvs-stories-viewer context-name="story1" ></mvs-stories-viewer>
|
||||
</div>
|
||||
<div id="controls">
|
||||
<mvs-stories-snapshot-markdown context-name="story1" style="flex-grow: 1;" ></mvs-stories-snapshot-markdown>
|
||||
</div>
|
||||
|
||||
<div id="links">
|
||||
<span id="open-in-stories" style="display: none;"><a href="#" id="open-in-stories-link" target="_blank" rel="noopener noreferrer" title="Open and edit the story in the MolViewStories app">Edit in MolViewStories</a> <span class="sep">•</span></span>
|
||||
<span id="open-in-molstar" style="display: none;"><a href="#" id="open-in-molstar-link" target="_blank" rel="noopener noreferrer" title="Open the story in the Mol* Viewer app. Enables exporting an animation.">Open in Mol* Viewer</a> <span class="sep">•</span></span>
|
||||
<a href="#" id="mvs-data" title="MolViewSpec State for this story. Can be opened in the Mol* app.">Download MVS</a> <span class="sep">•</span> <a href="https://github.com/molstar/molstar/tree/master/src/apps/mvs-stories" id="mvs-data" target="_blank" rel="noopener noreferrer">Source Code</a>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
var urlParams = new URLSearchParams(window.location.search);
|
||||
var storyId = urlParams.get('story-id');
|
||||
var storyUrl = urlParams.get('story-url');
|
||||
var storySessionUrl = urlParams.get('story-session-url');
|
||||
var format = urlParams.get('data-format');
|
||||
|
||||
// For testing purposes:
|
||||
// if (!storyUrl) {
|
||||
// storyUrl = 'https://raw.githubusercontent.com/molstar/molstar/master/examples/mvs/kinase-story.mvsj';
|
||||
// }
|
||||
|
||||
var molstarDataLink = storyUrl;
|
||||
var editInStoriesUrl = undefined;
|
||||
|
||||
if (storyId) {
|
||||
mvsStories.loadFromID(storyId, { format: format || 'mvsj', contextName: 'story1' });
|
||||
editInStoriesUrl = 'https://molstar.org/mol-view-stories/builder?published-session-id=' + storyId;
|
||||
molstarDataLink = 'https://stories.molstar.org/api/story/' + storyId + '/data';
|
||||
} else if (storyUrl) {
|
||||
mvsStories.loadFromURL(storyUrl, { format: format || 'mvsj', contextName: 'story1' });
|
||||
}
|
||||
|
||||
if (!editInStoriesUrl && storySessionUrl) {
|
||||
editInStoriesUrl = 'https://molstar.org/mol-view-stories/builder?session-url=' + encodeURIComponent(storySessionUrl);
|
||||
}
|
||||
|
||||
if (molstarDataLink) {
|
||||
var molstarLink = 'https://molstar.org/viewer?mvs-url=' + encodeURIComponent(molstarDataLink) + '&mvs-format=' + encodeURIComponent(format || 'mvsj');
|
||||
document.getElementById('open-in-molstar-link').setAttribute('href', molstarLink);
|
||||
document.getElementById('open-in-molstar').style.display = 'inline';
|
||||
}
|
||||
|
||||
if (editInStoriesUrl) {
|
||||
document.getElementById('open-in-stories-link').setAttribute('href', editInStoriesUrl);
|
||||
document.getElementById('open-in-stories').style.display = 'inline';
|
||||
}
|
||||
|
||||
document.getElementById('mvs-data').addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
mvsStories.downloadCurrentStory({ contextName: 'story1' });
|
||||
});
|
||||
</script>
|
||||
<!-- __MOLSTAR_ANALYTICS__ -->
|
||||
</body>
|
||||
|
||||
</html>
|
||||
64
src/apps/mvs-stories/index.tsx
Normal file
64
src/apps/mvs-stories/index.tsx
Normal file
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* Copyright (c) 2025 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
import { getMVSStoriesContext } from './context';
|
||||
import './elements';
|
||||
import { MVSData } from '../../extensions/mvs/mvs-data';
|
||||
import { download } from '../../mol-util/download';
|
||||
|
||||
import './favicon.ico';
|
||||
import '../../mol-plugin-ui/skin/light.scss';
|
||||
import './styles.scss';
|
||||
import './index.html';
|
||||
|
||||
export function getContext(name?: string) {
|
||||
return getMVSStoriesContext({ name });
|
||||
}
|
||||
|
||||
export function loadFromURL(url: string, options?: { format: 'mvsx' | 'mvsj', contextName?: string }) {
|
||||
setTimeout(() => {
|
||||
getContext(options?.contextName).dispatch({
|
||||
kind: 'load-mvs',
|
||||
format: options?.format ?? 'mvsj',
|
||||
url,
|
||||
});
|
||||
}, 0);
|
||||
}
|
||||
|
||||
export function loadFromData(data: MVSData | string | Uint8Array<ArrayBuffer>, options?: { format: 'mvsx' | 'mvsj', contextName?: string }) {
|
||||
setTimeout(() => {
|
||||
getContext(options?.contextName).dispatch({
|
||||
kind: 'load-mvs',
|
||||
format: options?.format ?? 'mvsj',
|
||||
data,
|
||||
});
|
||||
}, 0);
|
||||
}
|
||||
|
||||
function getStoryUrlFromId(id: string, format: 'mvsx' | 'mvsj' = 'mvsj') {
|
||||
return `https://stories.molstar.org/api/story/${id}/data`;
|
||||
}
|
||||
|
||||
export function loadFromID(id: string, options?: { format?: 'mvsx' | 'mvsj', contextName?: string }) {
|
||||
loadFromURL(
|
||||
getStoryUrlFromId(id, options?.format),
|
||||
{ format: options?.format ?? 'mvsj', contextName: options?.contextName },
|
||||
);
|
||||
}
|
||||
|
||||
export function downloadCurrentStory(options?: { contextName?: string, filename?: string }) {
|
||||
const story = getContext(options?.contextName).state.currentStoryData.value;
|
||||
if (!story) return;
|
||||
|
||||
const isMVSJ = typeof story === 'string';
|
||||
const filename = `${options?.filename ?? 'story'}.${isMVSJ ? 'mvsj' : 'mvsx'}`;
|
||||
download(
|
||||
new Blob([typeof story === 'string' ? story : story.buffer], { type: isMVSJ ? 'application/json' : 'application/octet-stream' }),
|
||||
filename
|
||||
);
|
||||
};
|
||||
|
||||
export { MVSData };
|
||||
66
src/apps/mvs-stories/readme.md
Normal file
66
src/apps/mvs-stories/readme.md
Normal file
@@ -0,0 +1,66 @@
|
||||
# MolViewSpec Stories App
|
||||
|
||||
An app that defines `mvs-stories-snapshot-markdown` and `mvs-stories-viewer` web components that can be used to view MolViewSpec molecular stories.
|
||||
|
||||
See the [mvs-stories](../../examples/mvs-stories) example that includes specific stories.
|
||||
|
||||
### Usage
|
||||
|
||||
- Get `mvs-stories.css` and `mvs-stories.js` from `build/mvs-stories` and include these to your HTML page
|
||||
|
||||
```html
|
||||
<link rel="stylesheet" type="text/css" href="mvs-stories.css" />
|
||||
<script type="text/javascript" src="mvs-stories.js"></script>
|
||||
```
|
||||
|
||||
Can also use `https://cdn.jsdelivr.net/npm/molstar@latest/build/mvs-stories/mvs-stories.js` (and `.css`). `latest` can be substituted by specific version.
|
||||
|
||||
- Place the components in your page wrapper in `<div>` elements to set up positioning:
|
||||
|
||||
```html
|
||||
<div class="viewer">
|
||||
<mvs-stories-viewer />
|
||||
</div>
|
||||
<div class="snapshot">
|
||||
<mvs-stories-snapshot-markdown />
|
||||
</div>
|
||||
```
|
||||
|
||||
- Load MolViewSpec state:
|
||||
|
||||
```html
|
||||
<script>
|
||||
mvsStories.loadFromURL('https://raw.githubusercontent.com/molstar/molstar/master/examples/mvs/1cbs.mvsj');
|
||||
</script>
|
||||
```
|
||||
|
||||
- See [index.html](./index.html) for full example of how to embed the app.
|
||||
|
||||
- For interactive development build (for production use `npm run build`) of the example that immediately reflects changes use:
|
||||
|
||||
```bash
|
||||
npm run dev -- -a mvs-stories
|
||||
```
|
||||
|
||||
### Multiple Stories on a Single Page
|
||||
|
||||
To support multiple instances of stories, use the `context-name='unique-name'` attribute on the `mvs-` components together with `loadFromURL/Data(..., { contextName: 'unique-name' })`.
|
||||
|
||||
For example (simplified to not include layout):
|
||||
|
||||
```html
|
||||
<div>
|
||||
<mvs-stories-viewer context-name="1" />
|
||||
<mvs-stories-snapshot-markdown context-name="1" />
|
||||
</div>
|
||||
<div>
|
||||
<mvs-stories-viewer context-name="2" />
|
||||
<mvs-stories-snapshot-markdown context-name="2" />
|
||||
</div>
|
||||
|
||||
<script>
|
||||
mvsStories.loadFromURL('1.mvsj', { format: 'mvsj', contextName: '1' });
|
||||
mvsStories.loadFromURL('2.mvsj', { format: 'mvsj', contextName: '2' });
|
||||
</script>
|
||||
|
||||
```
|
||||
204
src/apps/mvs-stories/styles.scss
Normal file
204
src/apps/mvs-stories/styles.scss
Normal file
@@ -0,0 +1,204 @@
|
||||
@use '../../mol-plugin-ui/skin/base/components/markdown.scss';
|
||||
|
||||
.mvs-stories-markdown-explanation {
|
||||
// Adapted from skeleton.css, The MIT License (MIT), Copyright (c) 2011-2014 Dave Gamache
|
||||
line-height: 1.4;
|
||||
font-weight: 400;
|
||||
font-family: "Raleway", "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
color: #222;
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 3rem;
|
||||
line-height: 1.2;
|
||||
letter-spacing: -.1rem;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 2.6rem;
|
||||
line-height: 1.25;
|
||||
letter-spacing: -.1rem;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 2rem;
|
||||
line-height: 1.3;
|
||||
letter-spacing: -.1rem;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 1.7rem;
|
||||
line-height: 1.35;
|
||||
letter-spacing: -.08rem;
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size: 1.4rem;
|
||||
line-height: 1.5;
|
||||
letter-spacing: -.05rem;
|
||||
}
|
||||
|
||||
h6 {
|
||||
font-size: 1.1rem;
|
||||
line-height: 1.6;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
|
||||
button {
|
||||
display: inline-block;
|
||||
height: 38px;
|
||||
padding: 0 24px;
|
||||
color: #555;
|
||||
text-align: center;
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
line-height: 38px;
|
||||
letter-spacing: .1rem;
|
||||
text-transform: uppercase;
|
||||
text-decoration: none;
|
||||
white-space: nowrap;
|
||||
background-color: transparent;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #bbb;
|
||||
cursor: pointer;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: circle inside;
|
||||
}
|
||||
|
||||
ol {
|
||||
list-style: decimal inside;
|
||||
}
|
||||
|
||||
ol,
|
||||
ul {
|
||||
padding-left: 0;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
ul ul,
|
||||
ul ol,
|
||||
ol ol,
|
||||
ol ul {
|
||||
margin: 1.5rem 0 1.5rem 3rem;
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
li {
|
||||
margin-bottom: 0.2rem;
|
||||
}
|
||||
|
||||
code {
|
||||
padding: .2rem .5rem;
|
||||
margin: 0 .2rem;
|
||||
font-size: 90%;
|
||||
white-space: nowrap;
|
||||
background: #F1F1F1;
|
||||
border: 1px solid #E1E1E1;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
pre>code {
|
||||
display: block;
|
||||
padding: 1rem 1.5rem;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
th,
|
||||
td {
|
||||
padding: 12px 15px;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid #E1E1E1;
|
||||
}
|
||||
|
||||
th:first-child,
|
||||
td:first-child {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
th:last-child,
|
||||
td:last-child {
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
button,
|
||||
.button {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
input,
|
||||
textarea,
|
||||
select,
|
||||
fieldset {
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
pre,
|
||||
blockquote,
|
||||
dl,
|
||||
figure,
|
||||
table,
|
||||
p,
|
||||
ul,
|
||||
ol,
|
||||
form {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
hr {
|
||||
margin-top: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
border-width: 0;
|
||||
border-top: 1px solid #E1E1E1;
|
||||
}
|
||||
|
||||
table {
|
||||
border: 1px solid #E1E1E1;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
th {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
th, td {
|
||||
border: 1px solid #E1E1E1;
|
||||
padding: 4px 8px;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: #1d4ed7;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (orientation:portrait) {
|
||||
.mvs-stories-markdown-explanation {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.mvs-stories-markdown-explanation h3 {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}
|
||||
7
src/apps/mvs-stories/version.ts
Normal file
7
src/apps/mvs-stories/version.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
/**
|
||||
* Copyright (c) 2025 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
export const VERSION = 1;
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2024 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2018-2025 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>
|
||||
@@ -7,35 +7,20 @@
|
||||
* @author Adam Midlik <midlik@gmail.com>
|
||||
*/
|
||||
|
||||
import { ANVILMembraneOrientation } from '../../extensions/anvil/behavior';
|
||||
import { Backgrounds } from '../../extensions/backgrounds';
|
||||
import { DnatcoNtCs } from '../../extensions/dnatco';
|
||||
import { G3DFormat, G3dProvider } from '../../extensions/g3d/format';
|
||||
import { GeometryExport } from '../../extensions/geo-export';
|
||||
import { MAQualityAssessment, MAQualityAssessmentConfig, QualityAssessmentPLDDTPreset, QualityAssessmentQmeanPreset } from '../../extensions/model-archive/quality-assessment/behavior';
|
||||
import { QualityAssessment } from '../../extensions/model-archive/quality-assessment/prop';
|
||||
import { ModelExport } from '../../extensions/model-export';
|
||||
import { Mp4Export } from '../../extensions/mp4-export';
|
||||
import { MolViewSpec } from '../../extensions/mvs/behavior';
|
||||
import { loadMVSX } from '../../extensions/mvs/components/formats';
|
||||
import { AssemblySymmetryConfig } from '../../extensions/assembly-symmetry';
|
||||
import { loadMVSData, loadMVSX } from '../../extensions/mvs/components/formats';
|
||||
import { loadMVS, MolstarLoadingExtension } from '../../extensions/mvs/load';
|
||||
import { MVSData } from '../../extensions/mvs/mvs-data';
|
||||
import { PDBeStructureQualityReport } from '../../extensions/pdbe';
|
||||
import { RCSBValidationReport } from '../../extensions/rcsb';
|
||||
import { AssemblySymmetry, AssemblySymmetryConfig } from '../../extensions/assembly-symmetry';
|
||||
import { SbNcbrPartialCharges, SbNcbrPartialChargesPreset, SbNcbrPartialChargesPropertyProvider, SbNcbrTunnels } from '../../extensions/sb-ncbr';
|
||||
import { Volseg, VolsegVolumeServerConfig } from '../../extensions/volumes-and-segmentations';
|
||||
import { wwPDBChemicalComponentDictionary } from '../../extensions/wwpdb/ccd/behavior';
|
||||
import { wwPDBStructConnExtensionFunctions } from '../../extensions/wwpdb/struct-conn';
|
||||
import { ZenodoImport } from '../../extensions/zenodo';
|
||||
import { SaccharideCompIdMapType } from '../../mol-model/structure/structure/carbohydrates/constants';
|
||||
import { StringLike } from '../../mol-io/common/string-like';
|
||||
import { Structure, StructureElement } from '../../mol-model/structure';
|
||||
import { Volume } from '../../mol-model/volume';
|
||||
import { OpenFiles } from '../../mol-plugin-state/actions/file';
|
||||
import { DownloadStructure, PdbDownloadProvider } from '../../mol-plugin-state/actions/structure';
|
||||
import { DownloadDensity } from '../../mol-plugin-state/actions/volume';
|
||||
import { PresetTrajectoryHierarchy } from '../../mol-plugin-state/builder/structure/hierarchy-preset';
|
||||
import { PresetStructureRepresentations, StructureRepresentationPresetProvider } from '../../mol-plugin-state/builder/structure/representation-preset';
|
||||
import { StructureRepresentationPresetProvider } from '../../mol-plugin-state/builder/structure/representation-preset';
|
||||
import { PluginComponent } from '../../mol-plugin-state/component';
|
||||
import { BuiltInCoordinatesFormat } from '../../mol-plugin-state/formats/coordinates';
|
||||
import { DataFormatProvider } from '../../mol-plugin-state/formats/provider';
|
||||
import { BuiltInTopologyFormat } from '../../mol-plugin-state/formats/topology';
|
||||
import { BuiltInTrajectoryFormat } from '../../mol-plugin-state/formats/trajectory';
|
||||
import { BuildInVolumeFormat } from '../../mol-plugin-state/formats/volume';
|
||||
@@ -43,95 +28,39 @@ import { createVolumeRepresentationParams } from '../../mol-plugin-state/helpers
|
||||
import { PluginStateObject } from '../../mol-plugin-state/objects';
|
||||
import { StateTransforms } from '../../mol-plugin-state/transforms';
|
||||
import { TrajectoryFromModelAndCoordinates } from '../../mol-plugin-state/transforms/model';
|
||||
import { PluginUIContext } from '../../mol-plugin-ui/context';
|
||||
import { createPluginUI } from '../../mol-plugin-ui';
|
||||
import { PluginUIContext } from '../../mol-plugin-ui/context';
|
||||
import { renderReact18 } from '../../mol-plugin-ui/react18';
|
||||
import { DefaultPluginUISpec, PluginUISpec } from '../../mol-plugin-ui/spec';
|
||||
import { PluginBehaviors } from '../../mol-plugin/behavior';
|
||||
import { PluginCommands } from '../../mol-plugin/commands';
|
||||
import { PluginConfig, PluginConfigItem } from '../../mol-plugin/config';
|
||||
import { PluginLayoutControlsDisplay } from '../../mol-plugin/layout';
|
||||
import { PluginSpec } from '../../mol-plugin/spec';
|
||||
import { PluginConfig } from '../../mol-plugin/config';
|
||||
import { PluginState } from '../../mol-plugin/state';
|
||||
import { StateObjectRef, StateObjectSelector } from '../../mol-state';
|
||||
import { MolScriptBuilder } from '../../mol-script/language/builder';
|
||||
import { Expression } from '../../mol-script/language/expression';
|
||||
import { StateObjectSelector } from '../../mol-state';
|
||||
import { Task } from '../../mol-task';
|
||||
import { Asset } from '../../mol-util/assets';
|
||||
import { Color } from '../../mol-util/color';
|
||||
import '../../mol-util/polyfill';
|
||||
import { ObjectKeys } from '../../mol-util/type-helpers';
|
||||
import { ExtensionMap } from './extensions';
|
||||
import { DefaultViewerOptions, ViewerOptions } from './options';
|
||||
|
||||
export { PLUGIN_VERSION as version } from '../../mol-plugin/version';
|
||||
export { consoleStats, setDebugMode, setProductionMode, setTimingMode } from '../../mol-util/debug';
|
||||
export { consoleStats, isDebugMode, isProductionMode, isTimingMode, setDebugMode, setProductionMode, setTimingMode } from '../../mol-util/debug';
|
||||
|
||||
const CustomFormats = [
|
||||
['g3d', G3dProvider] as const
|
||||
];
|
||||
|
||||
export const ExtensionMap = {
|
||||
'volseg': PluginSpec.Behavior(Volseg),
|
||||
'backgrounds': PluginSpec.Behavior(Backgrounds),
|
||||
'dnatco-ntcs': PluginSpec.Behavior(DnatcoNtCs),
|
||||
'pdbe-structure-quality-report': PluginSpec.Behavior(PDBeStructureQualityReport),
|
||||
'assembly-symmetry': PluginSpec.Behavior(AssemblySymmetry),
|
||||
'rcsb-validation-report': PluginSpec.Behavior(RCSBValidationReport),
|
||||
'anvil-membrane-orientation': PluginSpec.Behavior(ANVILMembraneOrientation),
|
||||
'g3d': PluginSpec.Behavior(G3DFormat),
|
||||
'model-export': PluginSpec.Behavior(ModelExport),
|
||||
'mp4-export': PluginSpec.Behavior(Mp4Export),
|
||||
'geo-export': PluginSpec.Behavior(GeometryExport),
|
||||
'ma-quality-assessment': PluginSpec.Behavior(MAQualityAssessment),
|
||||
'zenodo-import': PluginSpec.Behavior(ZenodoImport),
|
||||
'sb-ncbr-partial-charges': PluginSpec.Behavior(SbNcbrPartialCharges),
|
||||
'wwpdb-chemical-component-dictionary': PluginSpec.Behavior(wwPDBChemicalComponentDictionary),
|
||||
'mvs': PluginSpec.Behavior(MolViewSpec),
|
||||
'tunnels': PluginSpec.Behavior(SbNcbrTunnels),
|
||||
};
|
||||
|
||||
const DefaultViewerOptions = {
|
||||
customFormats: CustomFormats as [string, DataFormatProvider][],
|
||||
extensions: ObjectKeys(ExtensionMap),
|
||||
disabledExtensions: [] as string[],
|
||||
layoutIsExpanded: true,
|
||||
layoutShowControls: true,
|
||||
layoutShowRemoteState: true,
|
||||
layoutControlsDisplay: 'reactive' as PluginLayoutControlsDisplay,
|
||||
layoutShowSequence: true,
|
||||
layoutShowLog: true,
|
||||
layoutShowLeftPanel: true,
|
||||
collapseLeftPanel: false,
|
||||
collapseRightPanel: false,
|
||||
disableAntialiasing: PluginConfig.General.DisableAntialiasing.defaultValue,
|
||||
pixelScale: PluginConfig.General.PixelScale.defaultValue,
|
||||
pickScale: PluginConfig.General.PickScale.defaultValue,
|
||||
transparency: PluginConfig.General.Transparency.defaultValue,
|
||||
preferWebgl1: PluginConfig.General.PreferWebGl1.defaultValue,
|
||||
allowMajorPerformanceCaveat: PluginConfig.General.AllowMajorPerformanceCaveat.defaultValue,
|
||||
powerPreference: PluginConfig.General.PowerPreference.defaultValue,
|
||||
resolutionMode: PluginConfig.General.ResolutionMode.defaultValue,
|
||||
illumination: false,
|
||||
|
||||
viewportShowExpand: PluginConfig.Viewport.ShowExpand.defaultValue,
|
||||
viewportShowControls: PluginConfig.Viewport.ShowControls.defaultValue,
|
||||
viewportShowSettings: PluginConfig.Viewport.ShowSettings.defaultValue,
|
||||
viewportShowSelectionMode: PluginConfig.Viewport.ShowSelectionMode.defaultValue,
|
||||
viewportShowAnimation: PluginConfig.Viewport.ShowAnimation.defaultValue,
|
||||
viewportShowTrajectoryControls: PluginConfig.Viewport.ShowTrajectoryControls.defaultValue,
|
||||
pluginStateServer: PluginConfig.State.DefaultServer.defaultValue,
|
||||
volumeStreamingServer: PluginConfig.VolumeStreaming.DefaultServer.defaultValue,
|
||||
volumeStreamingDisabled: !PluginConfig.VolumeStreaming.Enabled.defaultValue,
|
||||
pdbProvider: PluginConfig.Download.DefaultPdbProvider.defaultValue,
|
||||
emdbProvider: PluginConfig.Download.DefaultEmdbProvider.defaultValue,
|
||||
saccharideCompIdMapType: 'default' as SaccharideCompIdMapType,
|
||||
volumesAndSegmentationsDefaultServer: VolsegVolumeServerConfig.DefaultServer.defaultValue,
|
||||
rcsbAssemblySymmetryDefaultServerType: AssemblySymmetryConfig.DefaultServerType.defaultValue,
|
||||
rcsbAssemblySymmetryDefaultServerUrl: AssemblySymmetryConfig.DefaultServerUrl.defaultValue,
|
||||
rcsbAssemblySymmetryApplyColors: AssemblySymmetryConfig.ApplyColors.defaultValue,
|
||||
|
||||
config: [] as [PluginConfigItem, any][],
|
||||
};
|
||||
type ViewerOptions = typeof DefaultViewerOptions;
|
||||
import { decodeColor } from '../../mol-util/color/utils';
|
||||
import '../../mol-util/polyfill';
|
||||
import { ViewerAutoPreset } from './presets';
|
||||
import { CameraFocusOptions } from '../../mol-plugin-state/manager/camera';
|
||||
import { PluginSpec } from '../../mol-plugin/spec';
|
||||
import { NoPrimaryFocusLociBindings } from '../../mol-plugin/behavior/dynamic/camera';
|
||||
|
||||
export class Viewer {
|
||||
constructor(public plugin: PluginUIContext) {
|
||||
private _events = new PluginComponent();
|
||||
public readonly plugin: PluginUIContext;
|
||||
|
||||
constructor(plugin: PluginUIContext) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
static async create(elementOrId: string | HTMLElement, options: Partial<ViewerOptions> = {}) {
|
||||
@@ -146,11 +75,31 @@ export class Viewer {
|
||||
const defaultSpec = DefaultPluginUISpec();
|
||||
|
||||
const disabledExtension = new Set(o.disabledExtensions ?? []);
|
||||
let baseBehaviors = defaultSpec.behaviors;
|
||||
|
||||
if (o.viewportFocusBehavior === 'disabled') {
|
||||
baseBehaviors = baseBehaviors.filter(b =>
|
||||
b.transformer !== PluginBehaviors.Camera.FocusLoci
|
||||
&& b.transformer !== PluginBehaviors.Representation.FocusLoci
|
||||
);
|
||||
} else if (o.viewportFocusBehavior === 'secondary-zoom') {
|
||||
baseBehaviors = baseBehaviors.filter(b =>
|
||||
b.transformer !== PluginBehaviors.Camera.FocusLoci
|
||||
&& b.transformer !== PluginBehaviors.Representation.FocusLoci
|
||||
);
|
||||
|
||||
baseBehaviors.push(PluginSpec.Behavior(PluginBehaviors.Camera.FocusLoci, {
|
||||
bindings: NoPrimaryFocusLociBindings
|
||||
}));
|
||||
}
|
||||
|
||||
const spec: PluginUISpec = {
|
||||
canvas3d: {
|
||||
...defaultSpec.canvas3d,
|
||||
},
|
||||
actions: defaultSpec.actions,
|
||||
behaviors: [
|
||||
...defaultSpec.behaviors,
|
||||
...baseBehaviors,
|
||||
...o.extensions.filter(e => !disabledExtension.has(e)).map(e => ExtensionMap[e]),
|
||||
],
|
||||
animations: [...defaultSpec.animations || []],
|
||||
@@ -188,8 +137,11 @@ export class Viewer {
|
||||
[PluginConfig.General.AllowMajorPerformanceCaveat, o.allowMajorPerformanceCaveat],
|
||||
[PluginConfig.General.PowerPreference, o.powerPreference],
|
||||
[PluginConfig.General.ResolutionMode, o.resolutionMode],
|
||||
[PluginConfig.Viewport.ShowExpand, o.viewportShowExpand],
|
||||
[PluginConfig.Viewport.ShowReset, o.viewportShowReset],
|
||||
[PluginConfig.Viewport.ShowScreenshotControls, o.viewportShowScreenshotControls],
|
||||
[PluginConfig.Viewport.ShowControls, o.viewportShowControls],
|
||||
[PluginConfig.Viewport.ShowExpand, o.viewportShowExpand],
|
||||
[PluginConfig.Viewport.ShowToggleFullscreen, o.viewportShowToggleFullscreen],
|
||||
[PluginConfig.Viewport.ShowSettings, o.viewportShowSettings],
|
||||
[PluginConfig.Viewport.ShowSelectionMode, o.viewportShowSelectionMode],
|
||||
[PluginConfig.Viewport.ShowAnimation, o.viewportShowAnimation],
|
||||
@@ -202,7 +154,6 @@ export class Viewer {
|
||||
[PluginConfig.Download.DefaultEmdbProvider, o.emdbProvider],
|
||||
[PluginConfig.Structure.DefaultRepresentationPreset, ViewerAutoPreset.id],
|
||||
[PluginConfig.Structure.SaccharideCompIdMapType, o.saccharideCompIdMapType],
|
||||
[VolsegVolumeServerConfig.DefaultServer, o.volumesAndSegmentationsDefaultServer],
|
||||
[AssemblySymmetryConfig.DefaultServerType, o.rcsbAssemblySymmetryDefaultServerType],
|
||||
[AssemblySymmetryConfig.DefaultServerUrl, o.rcsbAssemblySymmetryDefaultServerUrl],
|
||||
[AssemblySymmetryConfig.ApplyColors, o.rcsbAssemblySymmetryApplyColors],
|
||||
@@ -224,10 +175,23 @@ export class Viewer {
|
||||
plugin.builders.structure.representation.registerPreset(ViewerAutoPreset);
|
||||
}
|
||||
});
|
||||
|
||||
plugin.canvas3d?.setProps({ illumination: { enabled: o.illumination } });
|
||||
if (o.viewportBackgroundColor) {
|
||||
const backgroundColor = decodeColor(o.viewportBackgroundColor);
|
||||
if (typeof backgroundColor === 'number') {
|
||||
plugin.canvas3d?.setProps({ renderer: { backgroundColor } });
|
||||
}
|
||||
}
|
||||
return new Viewer(plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows subscribing to rxjs observables in the context of the viewer.
|
||||
* All subscriptions will be disposed of when the viewer is destroyed.
|
||||
*/
|
||||
subscribe = this._events.subscribe.bind(this._events);
|
||||
|
||||
setRemoteSnapshot(id: string) {
|
||||
const url = `${this.plugin.config.get(PluginConfig.State.CurrentServer)}/get/${id}`;
|
||||
return PluginCommands.State.Snapshots.Fetch(this.plugin, { url });
|
||||
@@ -288,14 +252,21 @@ export class Viewer {
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Scheduled for removal in v5. Use {@link loadPdbIhm | loadPdbIhm(pdbIhm: string)} instead.
|
||||
*/
|
||||
loadPdbDev(pdbDev: string) {
|
||||
return this.loadPdbIhm(pdbDev);
|
||||
}
|
||||
|
||||
loadPdbIhm(pdbIhm: string) {
|
||||
const params = DownloadStructure.createDefaultParams(this.plugin.state.data.root.obj!, this.plugin);
|
||||
return this.plugin.runTask(this.plugin.state.data.applyAction(DownloadStructure, {
|
||||
source: {
|
||||
name: 'pdb-dev' as const,
|
||||
name: 'pdb-ihm' as const,
|
||||
params: {
|
||||
provider: {
|
||||
id: pdbDev,
|
||||
id: pdbIhm,
|
||||
encoding: 'bcif',
|
||||
},
|
||||
options: params.source.params.options,
|
||||
@@ -489,7 +460,8 @@ export class Viewer {
|
||||
: await plugin.builders.data.download({ url: params.model.url, isBinary: params.model.isBinary, label: params.modelLabel });
|
||||
|
||||
const provider = plugin.dataFormats.get(params.model.format);
|
||||
model = await provider!.parse(plugin, data);
|
||||
const parsed = await provider!.parse(plugin, data);
|
||||
model = parsed.topology;
|
||||
}
|
||||
|
||||
const data = params.coordinates.kind === 'coordinates-data'
|
||||
@@ -511,15 +483,15 @@ export class Viewer {
|
||||
return { model, coords, preset };
|
||||
}
|
||||
|
||||
async loadMvsFromUrl(url: string, format: 'mvsj' | 'mvsx', options?: { replaceExisting?: boolean, keepCamera?: boolean, extensions?: MolstarLoadingExtension<any>[] }) {
|
||||
async loadMvsFromUrl(url: string, format: 'mvsj' | 'mvsx', options?: { appendSnapshots?: boolean, keepCamera?: boolean, keepCameraOrientation?: boolean, extensions?: MolstarLoadingExtension<any>[] }) {
|
||||
if (format === 'mvsj') {
|
||||
const data = await this.plugin.runTask(this.plugin.fetch({ url, type: 'string' }));
|
||||
const mvsData = MVSData.fromMVSJ(data);
|
||||
const mvsData = MVSData.fromMVSJ(StringLike.toString(data));
|
||||
await loadMVS(this.plugin, mvsData, { sanityChecks: true, sourceUrl: url, ...options });
|
||||
} else if (format === 'mvsx') {
|
||||
const data = await this.plugin.runTask(this.plugin.fetch({ url, type: 'binary' }));
|
||||
await this.plugin.runTask(Task.create('Load MVSX file', async ctx => {
|
||||
const parsed = await loadMVSX(this.plugin, ctx, data);
|
||||
const parsed = await loadMVSX(this.plugin, ctx, data, { doNotClearAssets: options?.appendSnapshots });
|
||||
await loadMVS(this.plugin, parsed.mvsData, { sanityChecks: true, sourceUrl: parsed.sourceUrl, ...options });
|
||||
}));
|
||||
} else {
|
||||
@@ -530,26 +502,24 @@ export class Viewer {
|
||||
/** Load MolViewSpec from `data`.
|
||||
* If `format` is 'mvsj', `data` must be a string or a Uint8Array containing a UTF8-encoded string.
|
||||
* If `format` is 'mvsx', `data` must be a Uint8Array or a string containing base64-encoded binary data prefixed with 'base64,'. */
|
||||
async loadMvsData(data: string | Uint8Array, format: 'mvsj' | 'mvsx', options?: { replaceExisting?: boolean, keepCamera?: boolean, extensions?: MolstarLoadingExtension<any>[] }) {
|
||||
if (typeof data === 'string' && data.startsWith('base64')) {
|
||||
data = Uint8Array.from(atob(data.substring(7)), c => c.charCodeAt(0)); // Decode base64 string to Uint8Array
|
||||
}
|
||||
if (format === 'mvsj') {
|
||||
if (typeof data !== 'string') {
|
||||
data = new TextDecoder().decode(data); // Decode Uint8Array to string using UTF8
|
||||
}
|
||||
const mvsData = MVSData.fromMVSJ(data);
|
||||
await loadMVS(this.plugin, mvsData, { sanityChecks: true, sourceUrl: undefined, ...options });
|
||||
} else if (format === 'mvsx') {
|
||||
if (typeof data === 'string') {
|
||||
throw new Error("loadMvsData: if `format` is 'mvsx', then `data` must be a Uint8Array or a base64-encoded string prefixed with 'base64,'.");
|
||||
}
|
||||
await this.plugin.runTask(Task.create('Load MVSX file', async ctx => {
|
||||
const parsed = await loadMVSX(this.plugin, ctx, data as Uint8Array);
|
||||
await loadMVS(this.plugin, parsed.mvsData, { sanityChecks: true, sourceUrl: parsed.sourceUrl, ...options });
|
||||
}));
|
||||
loadMvsData(data: string | Uint8Array<ArrayBuffer>, format: 'mvsj' | 'mvsx', options?: { appendSnapshots?: boolean, keepCamera?: boolean, keepCameraOrientation?: boolean, extensions?: MolstarLoadingExtension<any>[] }) {
|
||||
return loadMVSData(this.plugin, data, format, options);
|
||||
}
|
||||
|
||||
loadFiles(files: File[]) {
|
||||
const sessions = files.filter(f => {
|
||||
const fn = f.name.toLowerCase();
|
||||
return fn.endsWith('.molx') || fn.endsWith('.molj');
|
||||
});
|
||||
|
||||
if (sessions.length > 0) {
|
||||
return PluginCommands.State.Snapshots.OpenFile(this.plugin, { file: sessions[0] });
|
||||
} else {
|
||||
throw new Error(`Unknown MolViewSpec format: ${format}`);
|
||||
return this.plugin.runTask(this.plugin.state.data.applyAction(OpenFiles, {
|
||||
files: files.map(f => Asset.File(f)),
|
||||
format: { name: 'auto', params: {} },
|
||||
visuals: true
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -557,7 +527,56 @@ export class Viewer {
|
||||
this.plugin.layout.events.updated.next(void 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers structure element selection or highlighting based on the provided
|
||||
* MolScript expression or StructureElement schema. Focus action will only apply to the
|
||||
* first structure that matches the criteria.
|
||||
*
|
||||
* If neither `expression` nor `elements` are provided, all selections/highlights
|
||||
* will be cleared based on the specified `action`.
|
||||
*/
|
||||
structureInteractivity({ expression, elements, action, applyGranularity = false, filterStructure, focusOptions }: {
|
||||
expression?: (queryBuilder: typeof MolScriptBuilder) => Expression,
|
||||
elements?: StructureElement.Schema,
|
||||
action: 'highlight' | 'select' | 'focus',
|
||||
applyGranularity?: boolean,
|
||||
filterStructure?: (structure: Structure) => boolean,
|
||||
focusOptions?: Partial<CameraFocusOptions>
|
||||
}) {
|
||||
const plugin = this.plugin;
|
||||
|
||||
if (!expression && !elements) {
|
||||
if (action === 'select') {
|
||||
plugin.managers.interactivity.lociSelects.deselectAll();
|
||||
} else if (action === 'highlight') {
|
||||
plugin.managers.interactivity.lociHighlights.clearHighlights();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const structures = this.plugin.state.data.selectQ(Q => Q.rootsOfType(PluginStateObject.Molecule.Structure));
|
||||
for (const s of structures) {
|
||||
if (!s.obj?.data) continue;
|
||||
|
||||
if (filterStructure && !filterStructure(s.obj.data)) continue;
|
||||
|
||||
const loci = expression
|
||||
? StructureElement.Loci.fromExpression(s.obj.data, expression)
|
||||
: StructureElement.Loci.fromSchema(s.obj.data, elements!);
|
||||
|
||||
if (action === 'select') {
|
||||
plugin.managers.interactivity.lociSelects.select({ loci }, applyGranularity);
|
||||
} else if (action === 'highlight') {
|
||||
plugin.managers.interactivity.lociHighlights.highlight({ loci }, applyGranularity);
|
||||
} else if (action === 'focus' && !StructureElement.Loci.isEmpty(loci)) {
|
||||
plugin.managers.camera.focusLoci(loci, focusOptions);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this._events.dispose();
|
||||
this.plugin.dispose();
|
||||
}
|
||||
}
|
||||
@@ -576,52 +595,12 @@ export interface VolumeIsovalueInfo {
|
||||
|
||||
export interface LoadTrajectoryParams {
|
||||
model: { kind: 'model-url', url: string, format?: BuiltInTrajectoryFormat /* mmcif */, isBinary?: boolean }
|
||||
| { kind: 'model-data', data: string | number[] | ArrayBuffer | Uint8Array, format?: BuiltInTrajectoryFormat /* mmcif */ }
|
||||
| { kind: 'model-data', data: string | number[] | ArrayBuffer | Uint8Array<ArrayBuffer>, format?: BuiltInTrajectoryFormat /* mmcif */ }
|
||||
| { kind: 'topology-url', url: string, format: BuiltInTopologyFormat, isBinary?: boolean }
|
||||
| { kind: 'topology-data', data: string | number[] | ArrayBuffer | Uint8Array, format: BuiltInTopologyFormat },
|
||||
| { kind: 'topology-data', data: string | number[] | ArrayBuffer | Uint8Array<ArrayBuffer>, format: BuiltInTopologyFormat },
|
||||
modelLabel?: string,
|
||||
coordinates: { kind: 'coordinates-url', url: string, format: BuiltInCoordinatesFormat, isBinary?: boolean }
|
||||
| { kind: 'coordinates-data', data: string | number[] | ArrayBuffer | Uint8Array, format: BuiltInCoordinatesFormat },
|
||||
| { kind: 'coordinates-data', data: string | number[] | ArrayBuffer | Uint8Array<ArrayBuffer>, format: BuiltInCoordinatesFormat },
|
||||
coordinatesLabel?: string,
|
||||
preset?: keyof PresetTrajectoryHierarchy
|
||||
}
|
||||
|
||||
export const ViewerAutoPreset = StructureRepresentationPresetProvider({
|
||||
id: 'preset-structure-representation-viewer-auto',
|
||||
display: {
|
||||
name: 'Automatic (w/ Annotation)', group: 'Annotation',
|
||||
description: 'Show standard automatic representation but colored by quality assessment (if available in the model).'
|
||||
},
|
||||
isApplicable(a) {
|
||||
return (
|
||||
!!a.data.models.some(m => QualityAssessment.isApplicable(m, 'pLDDT')) ||
|
||||
!!a.data.models.some(m => QualityAssessment.isApplicable(m, 'qmean'))
|
||||
);
|
||||
},
|
||||
params: () => StructureRepresentationPresetProvider.CommonParams,
|
||||
async apply(ref, params, plugin) {
|
||||
const structureCell = StateObjectRef.resolveAndCheck(plugin.state.data, ref);
|
||||
const structure = structureCell?.obj?.data;
|
||||
if (!structureCell || !structure) return {};
|
||||
|
||||
if (!!structure.models.some(m => QualityAssessment.isApplicable(m, 'pLDDT'))) {
|
||||
return await QualityAssessmentPLDDTPreset.apply(ref, params, plugin);
|
||||
} else if (!!structure.models.some(m => QualityAssessment.isApplicable(m, 'qmean'))) {
|
||||
return await QualityAssessmentQmeanPreset.apply(ref, params, plugin);
|
||||
} else if (!!structure.models.some(m => SbNcbrPartialChargesPropertyProvider.isApplicable(m))) {
|
||||
return await SbNcbrPartialChargesPreset.apply(ref, params, plugin);
|
||||
} else {
|
||||
return await PresetStructureRepresentations.auto.apply(ref, params, plugin);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export const PluginExtensions = {
|
||||
wwPDBStructConn: wwPDBStructConnExtensionFunctions,
|
||||
mvs: { MVSData, loadMVS },
|
||||
modelArchive: {
|
||||
qualityAssessment: {
|
||||
config: MAQualityAssessmentConfig
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
71
src/apps/viewer/extensions.ts
Normal file
71
src/apps/viewer/extensions.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2026 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>
|
||||
* @author Adam Midlik <midlik@gmail.com>
|
||||
*/
|
||||
|
||||
import { ANVILMembraneOrientation } from '../../extensions/anvil/behavior';
|
||||
import { AssemblySymmetry } from '../../extensions/assembly-symmetry';
|
||||
import { Backgrounds } from '../../extensions/backgrounds';
|
||||
import { DebugHelpers } from '../../extensions/debug-helpers';
|
||||
import { DnatcoNtCs } from '../../extensions/dnatco';
|
||||
import { G3DFormat } from '../../extensions/g3d/format';
|
||||
import { GeometryExport } from '../../extensions/geo-export';
|
||||
import { MAQualityAssessment, MAQualityAssessmentConfig } from '../../extensions/model-archive/quality-assessment/behavior';
|
||||
import { ModelExport } from '../../extensions/model-export';
|
||||
import { Mp4Export } from '../../extensions/mp4-export';
|
||||
import { loadMVS } from '../../extensions/mvs';
|
||||
import { MolViewSpec } from '../../extensions/mvs/behavior';
|
||||
import { loadMVSData } from '../../extensions/mvs/components/formats';
|
||||
import { PDBeStructureQualityReport } from '../../extensions/pdbe';
|
||||
import { RCSBValidationReport } from '../../extensions/rcsb';
|
||||
import { SbNcbrPartialCharges, SbNcbrTunnels } from '../../extensions/sb-ncbr';
|
||||
import { wwPDBChemicalComponentDictionary } from '../../extensions/wwpdb/ccd/behavior';
|
||||
import { wwPDBStructConnExtensionFunctions } from '../../extensions/wwpdb/struct-conn';
|
||||
import { ZenodoImport } from '../../extensions/zenodo';
|
||||
import { PluginSpec } from '../../mol-plugin/spec';
|
||||
import { MVSData } from '../../extensions/mvs/mvs-data';
|
||||
import * as MVSUtil from '../../extensions/mvs/util';
|
||||
|
||||
export const ExtensionMap = {
|
||||
// Mol* built-in extensions
|
||||
'mvs': PluginSpec.Behavior(MolViewSpec),
|
||||
'backgrounds': PluginSpec.Behavior(Backgrounds),
|
||||
'debug-helpers': PluginSpec.Behavior(DebugHelpers),
|
||||
'model-export': PluginSpec.Behavior(ModelExport),
|
||||
'mp4-export': PluginSpec.Behavior(Mp4Export),
|
||||
'geo-export': PluginSpec.Behavior(GeometryExport),
|
||||
'zenodo-import': PluginSpec.Behavior(ZenodoImport),
|
||||
'wwpdb-chemical-component-dictionary': PluginSpec.Behavior(wwPDBChemicalComponentDictionary),
|
||||
|
||||
// 3rd party extensions
|
||||
'pdbe-structure-quality-report': PluginSpec.Behavior(PDBeStructureQualityReport),
|
||||
'dnatco-ntcs': PluginSpec.Behavior(DnatcoNtCs),
|
||||
'assembly-symmetry': PluginSpec.Behavior(AssemblySymmetry),
|
||||
'rcsb-validation-report': PluginSpec.Behavior(RCSBValidationReport),
|
||||
'anvil-membrane-orientation': PluginSpec.Behavior(ANVILMembraneOrientation),
|
||||
'g3d': PluginSpec.Behavior(G3DFormat), // TODO: consider removing this for Mol* 6.0
|
||||
'ma-quality-assessment': PluginSpec.Behavior(MAQualityAssessment),
|
||||
'sb-ncbr-partial-charges': PluginSpec.Behavior(SbNcbrPartialCharges),
|
||||
'tunnels': PluginSpec.Behavior(SbNcbrTunnels),
|
||||
};
|
||||
|
||||
export const PluginExtensions = {
|
||||
wwPDBStructConn: wwPDBStructConnExtensionFunctions,
|
||||
mvs: {
|
||||
MVSData,
|
||||
createBuilder: MVSData.createBuilder,
|
||||
loadMVS,
|
||||
loadMVSData,
|
||||
util: {
|
||||
...MVSUtil
|
||||
}
|
||||
},
|
||||
modelArchive: {
|
||||
qualityAssessment: {
|
||||
config: MAQualityAssessmentConfig
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -28,13 +28,14 @@
|
||||
}
|
||||
#app {
|
||||
position: absolute;
|
||||
left: 100px;
|
||||
top: 100px;
|
||||
width: 800px;
|
||||
height: 600px;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" type="text/css" href="molstar.css" />
|
||||
<!-- __MOLSTAR_MANIFEST__ -->
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
@@ -65,6 +66,7 @@
|
||||
var powerPreference = getParam('power-preference', '[^&]+').trim().toLowerCase();
|
||||
var illumination = getParam('illumination', '[^&]+').trim() === '1';
|
||||
var resolutionMode = getParam('resolution-mode', '[^&]+').trim().toLowerCase();
|
||||
var viewportShowToggleFullscreen = getParam('show-toggle-fullscreen', '[^&]+').trim() === '1';
|
||||
|
||||
// console.log('Available extensions: ', Object.keys(molstar.ExtensionMap));
|
||||
|
||||
@@ -72,6 +74,7 @@
|
||||
disabledExtensions: [], // anything from Object.keys(molstar.ExtensionMap)
|
||||
layoutShowControls: !hideControls,
|
||||
viewportShowExpand: false,
|
||||
viewportShowToggleFullscreen: viewportShowToggleFullscreen,
|
||||
collapseLeftPanel: collapseLeftPanel,
|
||||
pdbProvider: pdbProvider || 'pdbe',
|
||||
emdbProvider: emdbProvider || 'pdbe',
|
||||
@@ -86,7 +89,7 @@
|
||||
allowMajorPerformanceCaveat: allowMajorPerformanceCaveat,
|
||||
powerPreference: powerPreference || 'high-performance',
|
||||
illumination: illumination,
|
||||
resolutionMode: resolutionMode || 'auto'
|
||||
resolutionMode: resolutionMode || 'auto',
|
||||
}).then(viewer => {
|
||||
var snapshotId = getParam('snapshot-id', '[^&]+').trim();
|
||||
if (snapshotId) viewer.setRemoteSnapshot(snapshotId);
|
||||
@@ -111,8 +114,11 @@
|
||||
var pdb = getParam('pdb', '[^&]+').trim();
|
||||
if (pdb) viewer.loadPdb(pdb);
|
||||
|
||||
var pdbIhm = getParam('pdb-ihm', '[^&]+').trim();
|
||||
if (pdbIhm) viewer.loadPdbIhm(pdbIhm);
|
||||
// support for deprecated pdb-dev param
|
||||
var pdbDev = getParam('pdb-dev', '[^&]+').trim();
|
||||
if (pdbDev) viewer.loadPdbDev(pdbDev);
|
||||
if (pdbDev) viewer.loadPdbIhm(pdbDev);
|
||||
|
||||
var emdb = getParam('emdb', '[^&]+').trim();
|
||||
if (emdb) viewer.loadEmdb(emdb);
|
||||
@@ -127,8 +133,12 @@
|
||||
// to aid GC
|
||||
viewer.dispose();
|
||||
});
|
||||
|
||||
const event = new CustomEvent("molstarViewerCreated", { detail: { viewer } });
|
||||
window.dispatchEvent(event);
|
||||
});
|
||||
</script>
|
||||
<!-- __MOLSTAR_PWA__ -->
|
||||
<!-- __MOLSTAR_ANALYTICS__ -->
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,12 +1,16 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2018-2025 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>
|
||||
*/
|
||||
|
||||
import './mvs.html';
|
||||
import './embedded.html';
|
||||
import './favicon.ico';
|
||||
import './index.html';
|
||||
require('mol-plugin-ui/skin/light.scss');
|
||||
import '../../mol-plugin-ui/skin/light.scss';
|
||||
export * from './lib';
|
||||
export * from './extensions';
|
||||
export * from './app';
|
||||
export * from './presets';
|
||||
|
||||
58
src/apps/viewer/lib.ts
Normal file
58
src/apps/viewer/lib.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* Copyright (c) 2025 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
import * as Structure from '../../mol-model/structure';
|
||||
import { DataLoci, EveryLoci, Loci } from '../../mol-model/loci';
|
||||
import { Volume } from '../../mol-model/volume';
|
||||
import { Shape, ShapeGroup } from '../../mol-model/shape';
|
||||
import * as LinearAlgebra3D from '../../mol-math/linear-algebra/3d';
|
||||
import { PluginContext } from '../../mol-plugin/context';
|
||||
import { PluginConfig } from '../../mol-plugin/config';
|
||||
import { PluginBehavior } from '../../mol-plugin/behavior';
|
||||
import { DefaultPluginSpec, PluginSpec } from '../../mol-plugin/spec';
|
||||
import { DefaultPluginUISpec } from '../../mol-plugin-ui/spec';
|
||||
import { PluginStateObject, PluginStateTransform } from '../../mol-plugin-state/objects';
|
||||
import { StateTransforms } from '../../mol-plugin-state/transforms';
|
||||
import { StateActions } from '../../mol-plugin-state/actions';
|
||||
import { PluginExtensions } from './extensions';
|
||||
|
||||
export const lib = {
|
||||
structure: {
|
||||
...Structure,
|
||||
},
|
||||
volume: {
|
||||
Volume,
|
||||
},
|
||||
shape: {
|
||||
Shape,
|
||||
ShapeGroup,
|
||||
},
|
||||
loci: {
|
||||
Loci,
|
||||
DataLoci,
|
||||
EveryLoci,
|
||||
},
|
||||
math: {
|
||||
LinearAlgebra: {
|
||||
...LinearAlgebra3D,
|
||||
}
|
||||
},
|
||||
plugin: {
|
||||
PluginContext,
|
||||
PluginConfig,
|
||||
PluginBehavior,
|
||||
PluginSpec,
|
||||
PluginStateObject,
|
||||
PluginStateTransform,
|
||||
StateTransforms,
|
||||
StateActions,
|
||||
DefaultPluginSpec,
|
||||
DefaultPluginUISpec,
|
||||
},
|
||||
extensions: {
|
||||
...PluginExtensions
|
||||
}
|
||||
};
|
||||
179
src/apps/viewer/mvs.html
Normal file
179
src/apps/viewer/mvs.html
Normal file
@@ -0,0 +1,179 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
|
||||
<link rel="icon" href="./favicon.ico" type="image/x-icon">
|
||||
<title>Mol* Viewer MolViewSpec Example</title>
|
||||
<style>
|
||||
body {
|
||||
background: #111318;
|
||||
}
|
||||
|
||||
#app {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#controls {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-family: sans-serif;
|
||||
gap: 8px;
|
||||
left: 10px;
|
||||
top: 10px;
|
||||
z-index: 10;
|
||||
background-color: #111318;
|
||||
padding: 10px;
|
||||
color: white;
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" type="text/css" href="theme/dark.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<div id="controls">
|
||||
<button onmouseenter="interactivy('highlight')" onmouseleave="interactivy('clear-highlight')" onclick="interactivy('select')">Select Residues 45-50</button>
|
||||
<button onmouseenter="interactivy('highlight')" onmouseleave="interactivy('clear-highlight')" onclick="interactivy('focus')">Focus</button>
|
||||
<button onclick="interactivy('clear-select')">Clear Selection</button>
|
||||
<div id="selection-info"></div>
|
||||
</div>
|
||||
<script type="text/javascript" src="molstar.js"></script>
|
||||
<script type="text/javascript">
|
||||
function interactivy(action) {
|
||||
if (action === 'clear-highlight') {
|
||||
viewer.structureInteractivity({ action: 'highlight' });
|
||||
} else if (action === 'clear-select') {
|
||||
viewer.structureInteractivity({ action: 'select' });
|
||||
} else if (action === 'highlight' || action === 'select' || action === 'focus') {
|
||||
viewer.structureInteractivity({
|
||||
elements: { beg_auth_seq_id: 45, end_auth_seq_id: 50 },
|
||||
action,
|
||||
focusOptions: { extraRadius: 3 }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function clearSelection() {
|
||||
viewer.structureInteractivity({ action: 'select' });
|
||||
}
|
||||
|
||||
molstar.Viewer.create('app', {
|
||||
layoutIsExpanded: true,
|
||||
layoutShowControls: false,
|
||||
layoutShowRemoteState: false,
|
||||
layoutShowSequence: true,
|
||||
layoutShowLog: false,
|
||||
layoutShowLeftPanel: true,
|
||||
|
||||
viewportShowExpand: true,
|
||||
viewportShowSelectionMode: false,
|
||||
viewportShowControls: false,
|
||||
viewportShowAnimation: false,
|
||||
viewportFocusBehavior: 'secondary-zoom',
|
||||
viewportBackgroundColor: '#111318',
|
||||
|
||||
pdbProvider: 'rcsb',
|
||||
emdbProvider: 'rcsb',
|
||||
}).then(viewer => {
|
||||
// Make the viewer accessible globally for the demo buttons
|
||||
window.viewer = viewer;
|
||||
|
||||
// Build MVS state
|
||||
const builder = molstar.lib.extensions.mvs.createBuilder();
|
||||
const structure = builder
|
||||
.download({ url: 'https://www.ebi.ac.uk/pdbe/entry-files/1cbs.bcif' })
|
||||
.parse({ format: 'bcif' })
|
||||
.modelStructure({});
|
||||
structure
|
||||
.component({ selector: 'polymer' })
|
||||
.representation({ type: 'cartoon' })
|
||||
.color({ color: 'green' });
|
||||
structure
|
||||
.component({ selector: 'ligand' })
|
||||
.representation({ type: 'ball_and_stick' })
|
||||
.color({ color: '#cc3399' });
|
||||
|
||||
// Extra data can be passed to the MVS snapshot via custom state
|
||||
// and later accessed it using getCurrentMVSSnapshot() (see hover handler below)
|
||||
// Each node can have custom data as well, but generally could be harder to access
|
||||
// This example is a little contrived to demonstrate the concept
|
||||
builder.extendRootCustomState({
|
||||
extraResidueAnnotations: {
|
||||
'REA': 'Ligand'
|
||||
}
|
||||
})
|
||||
|
||||
builder.canvas({
|
||||
background_color: "#111318",
|
||||
})
|
||||
|
||||
structure.primitives()
|
||||
.sphere({
|
||||
center: { label_comp_id: 'REA' },
|
||||
radius: 3,
|
||||
custom: { action: 'Action 1' },
|
||||
})
|
||||
.label({
|
||||
text: '1',
|
||||
position: { label_comp_id: 'REA' },
|
||||
label_size: 2.5,
|
||||
label_color: 'blue',
|
||||
});
|
||||
|
||||
structure.primitives()
|
||||
.sphere({
|
||||
center: { label_seq_id: 2 },
|
||||
radius: 3,
|
||||
custom: { action: 'Action 2' },
|
||||
})
|
||||
.label({
|
||||
text: '2',
|
||||
position: { label_seq_id: 2 },
|
||||
label_size: 2.5,
|
||||
label_color: 'blue',
|
||||
});
|
||||
|
||||
const mvsData = builder.getState();
|
||||
|
||||
viewer.loadMvsData(mvsData, 'mvsj');
|
||||
|
||||
// Show current residue interaction
|
||||
viewer.subscribe(viewer.plugin.behaviors.interaction.hover, e => {
|
||||
const infoElement = document.getElementById('selection-info');
|
||||
if (!infoElement) return;
|
||||
|
||||
if (molstar.lib.structure.StructureElement.Loci.is(e.current.loci)) {
|
||||
molstar.lib.structure.StructureElement.Loci.forEachLocation(e.current.loci, location => {
|
||||
const props = molstar.lib.structure.StructureProperties;
|
||||
let label = `Hovered Residue: ${props.chain.label_asym_id(location)} ${props.residue.label_seq_id(location)}`;
|
||||
|
||||
const compId = props.residue.label_comp_id(location);
|
||||
const snapshot = molstar.lib.extensions.mvs.util.getCurrentMVSSnapshot(viewer.plugin);
|
||||
if (snapshot && snapshot.root.custom && snapshot.root.custom.extraResidueAnnotations) {
|
||||
const extra = snapshot.root.custom.extraResidueAnnotations[compId];
|
||||
if (extra) label += ` (${extra})`;
|
||||
}
|
||||
|
||||
infoElement.innerText = label;
|
||||
});
|
||||
} else {
|
||||
infoElement.innerText = '';
|
||||
}
|
||||
});
|
||||
|
||||
// Show clicked primitive action
|
||||
viewer.subscribe(viewer.plugin.behaviors.interaction.click, e => {
|
||||
const nodes = molstar.lib.extensions.mvs.util.tryGetPrimitivesFromLoci(e.current.loci);
|
||||
if (nodes?.length) {
|
||||
alert('Clicked on: ' + (nodes[0].custom?.action || 'unknown'));
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
72
src/apps/viewer/options.ts
Normal file
72
src/apps/viewer/options.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2025 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>
|
||||
*/
|
||||
|
||||
import { AssemblySymmetryConfig } from '../../extensions/assembly-symmetry';
|
||||
import { G3dProvider } from '../../extensions/g3d/format';
|
||||
import { SaccharideCompIdMapType } from '../../mol-model/structure/structure/carbohydrates/constants';
|
||||
import { DataFormatProvider } from '../../mol-plugin-state/formats/provider';
|
||||
import { PluginConfig, PluginConfigItem } from '../../mol-plugin/config';
|
||||
import { PluginLayoutControlsDisplay } from '../../mol-plugin/layout';
|
||||
import '../../mol-util/polyfill';
|
||||
import { ObjectKeys } from '../../mol-util/type-helpers';
|
||||
import { ExtensionMap } from './extensions';
|
||||
|
||||
const CustomFormats: [string, DataFormatProvider][] = [
|
||||
['g3d', G3dProvider] as const
|
||||
];
|
||||
|
||||
export const DefaultViewerOptions = {
|
||||
customFormats: CustomFormats as [string, DataFormatProvider][],
|
||||
extensions: ObjectKeys(ExtensionMap),
|
||||
disabledExtensions: [] as string[],
|
||||
layoutIsExpanded: true,
|
||||
layoutShowControls: true,
|
||||
layoutShowRemoteState: true,
|
||||
layoutControlsDisplay: 'reactive' as PluginLayoutControlsDisplay,
|
||||
layoutShowSequence: true,
|
||||
layoutShowLog: true,
|
||||
layoutShowLeftPanel: true,
|
||||
collapseLeftPanel: false,
|
||||
collapseRightPanel: false,
|
||||
disableAntialiasing: PluginConfig.General.DisableAntialiasing.defaultValue,
|
||||
pixelScale: PluginConfig.General.PixelScale.defaultValue,
|
||||
pickScale: PluginConfig.General.PickScale.defaultValue,
|
||||
transparency: PluginConfig.General.Transparency.defaultValue,
|
||||
preferWebgl1: PluginConfig.General.PreferWebGl1.defaultValue,
|
||||
allowMajorPerformanceCaveat: PluginConfig.General.AllowMajorPerformanceCaveat.defaultValue,
|
||||
powerPreference: PluginConfig.General.PowerPreference.defaultValue,
|
||||
resolutionMode: PluginConfig.General.ResolutionMode.defaultValue,
|
||||
illumination: false,
|
||||
|
||||
viewportShowReset: PluginConfig.Viewport.ShowReset.defaultValue,
|
||||
viewportShowScreenshotControls: PluginConfig.Viewport.ShowScreenshotControls.defaultValue,
|
||||
viewportShowControls: PluginConfig.Viewport.ShowControls.defaultValue,
|
||||
viewportShowExpand: PluginConfig.Viewport.ShowExpand.defaultValue,
|
||||
viewportShowToggleFullscreen: PluginConfig.Viewport.ShowToggleFullscreen.defaultValue,
|
||||
viewportShowSettings: PluginConfig.Viewport.ShowSettings.defaultValue,
|
||||
viewportShowSelectionMode: PluginConfig.Viewport.ShowSelectionMode.defaultValue,
|
||||
viewportShowAnimation: PluginConfig.Viewport.ShowAnimation.defaultValue,
|
||||
viewportShowTrajectoryControls: PluginConfig.Viewport.ShowTrajectoryControls.defaultValue,
|
||||
// default: zoom & show structure interaction
|
||||
// secondary-zoom: zoom only, doesn't use primary mouse button
|
||||
// disabled: no automatic zoom or interaction on focus
|
||||
viewportFocusBehavior: 'default' as 'default' | 'secondary-zoom' | 'disabled',
|
||||
viewportBackgroundColor: undefined as string | undefined,
|
||||
|
||||
pluginStateServer: PluginConfig.State.DefaultServer.defaultValue,
|
||||
volumeStreamingServer: PluginConfig.VolumeStreaming.DefaultServer.defaultValue,
|
||||
volumeStreamingDisabled: !PluginConfig.VolumeStreaming.Enabled.defaultValue,
|
||||
pdbProvider: PluginConfig.Download.DefaultPdbProvider.defaultValue,
|
||||
emdbProvider: PluginConfig.Download.DefaultEmdbProvider.defaultValue,
|
||||
saccharideCompIdMapType: 'default' as SaccharideCompIdMapType,
|
||||
rcsbAssemblySymmetryDefaultServerType: AssemblySymmetryConfig.DefaultServerType.defaultValue,
|
||||
rcsbAssemblySymmetryDefaultServerUrl: AssemblySymmetryConfig.DefaultServerUrl.defaultValue,
|
||||
rcsbAssemblySymmetryApplyColors: AssemblySymmetryConfig.ApplyColors.defaultValue,
|
||||
|
||||
config: [] as [PluginConfigItem, any][],
|
||||
};
|
||||
export type ViewerOptions = typeof DefaultViewerOptions;
|
||||
42
src/apps/viewer/presets.ts
Normal file
42
src/apps/viewer/presets.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Copyright (c) 2025 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
import { QualityAssessmentPLDDTPreset, QualityAssessmentQmeanPreset } from '../../extensions/model-archive/quality-assessment/behavior';
|
||||
import { QualityAssessment } from '../../extensions/model-archive/quality-assessment/prop';
|
||||
import { SbNcbrPartialChargesPreset, SbNcbrPartialChargesPropertyProvider } from '../../extensions/sb-ncbr';
|
||||
import { PresetStructureRepresentations, StructureRepresentationPresetProvider } from '../../mol-plugin-state/builder/structure/representation-preset';
|
||||
import { StateObjectRef } from '../../mol-state';
|
||||
|
||||
export const ViewerAutoPreset = StructureRepresentationPresetProvider({
|
||||
id: 'preset-structure-representation-viewer-auto',
|
||||
display: {
|
||||
name: 'Automatic (w/ Annotation)', group: 'Annotation',
|
||||
description: 'Show standard automatic representation but colored by quality assessment (if available in the model).'
|
||||
},
|
||||
isApplicable(a) {
|
||||
return (
|
||||
!!a.data.models.some(m => QualityAssessment.isApplicable(m, 'pLDDT')) ||
|
||||
!!a.data.models.some(m => QualityAssessment.isApplicable(m, 'qmean'))
|
||||
);
|
||||
},
|
||||
params: () => StructureRepresentationPresetProvider.CommonParams,
|
||||
async apply(ref, params, plugin) {
|
||||
const structureCell = StateObjectRef.resolveAndCheck(plugin.state.data, ref);
|
||||
const structure = structureCell?.obj?.data;
|
||||
if (!structureCell || !structure) return {};
|
||||
|
||||
if (!!structure.models.some(m => QualityAssessment.isApplicable(m, 'pLDDT'))) {
|
||||
return await QualityAssessmentPLDDTPreset.apply(ref, params, plugin);
|
||||
} else if (!!structure.models.some(m => QualityAssessment.isApplicable(m, 'qmean'))) {
|
||||
return await QualityAssessmentQmeanPreset.apply(ref, params, plugin);
|
||||
} else if (!!structure.models.some(m => SbNcbrPartialChargesPropertyProvider.isApplicable(m))) {
|
||||
return await SbNcbrPartialChargesPreset.apply(ref, params, plugin);
|
||||
} else {
|
||||
return await PresetStructureRepresentations.auto.apply(ref, params, plugin);
|
||||
}
|
||||
}
|
||||
});
|
||||
7
src/apps/viewer/theme/blue.ts
Normal file
7
src/apps/viewer/theme/blue.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
/**
|
||||
* Copyright (c) 2025 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
import '../../../mol-plugin-ui/skin/blue.scss';
|
||||
7
src/apps/viewer/theme/dark.ts
Normal file
7
src/apps/viewer/theme/dark.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
/**
|
||||
* Copyright (c) 2025 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
import '../../../mol-plugin-ui/skin/dark.scss';
|
||||
7
src/apps/viewer/theme/light.ts
Normal file
7
src/apps/viewer/theme/light.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
/**
|
||||
* Copyright (c) 2025 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
*/
|
||||
|
||||
import '../../../mol-plugin-ui/skin/light.scss';
|
||||
@@ -1,17 +1,16 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Copyright (c) 2020-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2020-2026 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Josh McMenemy <josh.mcmenemy@gmail.com>
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
* @author Paul Pillot <paul.pillot@tandemai.com>
|
||||
*/
|
||||
|
||||
import * as argparse from 'argparse';
|
||||
import * as path from 'path';
|
||||
import util from 'util';
|
||||
import fs from 'fs';
|
||||
require('util.promisify').shim();
|
||||
const writeFile = util.promisify(fs.writeFile);
|
||||
const writeFileAsync = fs.promises.writeFile;
|
||||
|
||||
import { DatabaseCollection } from '../../mol-data/db';
|
||||
import { CCD_Schema } from '../../mol-io/reader/cif/schema/ccd';
|
||||
@@ -32,7 +31,7 @@ function extractIonNames(ccd: DatabaseCollection<CCD_Schema>) {
|
||||
|
||||
function writeIonNamesFile(filePath: string, ionNames: string[]) {
|
||||
const output = `/**
|
||||
* Copyright (c) 2020-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2020-2026 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* Code-generated ion names params file. Names extracted from CCD components.
|
||||
*
|
||||
@@ -41,7 +40,7 @@ function writeIonNamesFile(filePath: string, ionNames: string[]) {
|
||||
|
||||
export const IonNames = new Set(${JSON.stringify(ionNames).replace(/"/g, "'").replace(/,/g, ', ')});
|
||||
`;
|
||||
writeFile(filePath, output);
|
||||
writeFileAsync(filePath, output);
|
||||
}
|
||||
|
||||
async function run(out: string, options = DefaultDataOptions) {
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Copyright (c) 2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2022-2026 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
* @author Paul Pillot <paul.pillot@tandemai.com>
|
||||
*/
|
||||
|
||||
import * as argparse from 'argparse';
|
||||
import * as path from 'path';
|
||||
import util from 'util';
|
||||
import fs from 'fs';
|
||||
require('util.promisify').shim();
|
||||
const writeFile = util.promisify(fs.writeFile);
|
||||
const writeFileAsync = fs.promises.writeFile;
|
||||
|
||||
import { DatabaseCollection } from '../../mol-data/db';
|
||||
import { CCD_Schema } from '../../mol-io/reader/cif/schema/ccd';
|
||||
@@ -44,7 +43,7 @@ function writeSaccharideNamesFile(filePath: string, ionNames: string[]) {
|
||||
|
||||
export const SaccharideNames = new Set(${JSON.stringify(ionNames).replace(/"/g, "'").replace(/,/g, ', ')});
|
||||
`;
|
||||
writeFile(filePath, output);
|
||||
writeFileAsync(filePath, output);
|
||||
}
|
||||
|
||||
async function run(out: string, options = DefaultDataOptions) {
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2018-2026 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
* @author Paul Pillot <paul.pillot@tandemai.com>
|
||||
*/
|
||||
|
||||
import * as argparse from 'argparse';
|
||||
import * as util from 'util';
|
||||
import * as path from 'path';
|
||||
import * as fs from 'fs';
|
||||
require('util.promisify').shim();
|
||||
const writeFile = util.promisify(fs.writeFile);
|
||||
const writeFileAsync = fs.promises.writeFile;
|
||||
|
||||
import { Database, Table, DatabaseCollection } from '../../mol-data/db';
|
||||
import { CCD_Schema } from '../../mol-io/reader/cif/schema/ccd';
|
||||
@@ -250,14 +249,14 @@ async function run(out: string, binary = false, options = DefaultDataOptions, cc
|
||||
if (!fs.existsSync(path.dirname(out))) {
|
||||
fs.mkdirSync(path.dirname(out));
|
||||
}
|
||||
writeFile(out, ccbCif);
|
||||
writeFileAsync(out, ccbCif);
|
||||
|
||||
if (!!ccaOut) {
|
||||
const ccaCif = getEncodedCif(CCA_TABLE_NAME, atoms, binary);
|
||||
if (!fs.existsSync(path.dirname(ccaOut))) {
|
||||
fs.mkdirSync(path.dirname(ccaOut));
|
||||
}
|
||||
writeFile(ccaOut, ccaCif);
|
||||
writeFileAsync(ccaOut, ccaCif);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2018-2026 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
* @author Paul Pillot <paul.pillot@tandemai.com>
|
||||
*/
|
||||
|
||||
import * as util from 'util';
|
||||
import * as path from 'path';
|
||||
import * as fs from 'fs';
|
||||
import * as zlib from 'zlib';
|
||||
import fetch from 'node-fetch';
|
||||
require('util.promisify').shim();
|
||||
const readFile = util.promisify(fs.readFile);
|
||||
const writeFile = util.promisify(fs.writeFile);
|
||||
const readFileAsync = fs.promises.readFile;
|
||||
const writeFileAsync = fs.promises.writeFile;
|
||||
|
||||
import { Progress } from '../../mol-task';
|
||||
import { Database } from '../../mol-data/db';
|
||||
@@ -27,9 +25,9 @@ export async function ensureAvailable(path: string, url: string, forceDownload =
|
||||
fs.mkdirSync(DATA_DIR);
|
||||
}
|
||||
if (url.endsWith('.gz')) {
|
||||
await writeFile(path, zlib.gunzipSync(await data.buffer()));
|
||||
await writeFileAsync(path, zlib.gunzipSync(await data.arrayBuffer()));
|
||||
} else {
|
||||
await writeFile(path, await data.text());
|
||||
await writeFileAsync(path, await data.text());
|
||||
}
|
||||
console.log(`done downloading ${url}`);
|
||||
}
|
||||
@@ -41,7 +39,7 @@ export async function ensureDataAvailable(options: DataOptions) {
|
||||
}
|
||||
|
||||
export async function readFileAsCollection<S extends Database.Schema>(path: string, schema: S) {
|
||||
const parsed = await parseCif(await readFile(path, 'utf8'));
|
||||
const parsed = await parseCif(await readFileAsync(path, 'utf8'));
|
||||
return CIF.toDatabaseCollection(schema, parsed.result);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
/**
|
||||
* Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2017-2026 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
* @author Sebastian Bittrich <sebastian.bittrich@rcsb.org>
|
||||
* @author Paul Pillot <paul.pillot@tandemai.com>
|
||||
*/
|
||||
|
||||
import { CIF, CifCategory, getCifFieldType, CifField, CifFile } from '../../mol-io/reader/cif';
|
||||
@@ -15,30 +16,27 @@ import { classifyFloatArray, classifyIntArray } from '../../mol-io/common/binary
|
||||
import { BinaryEncodingProvider } from '../../mol-io/writer/cif/encoder/binary';
|
||||
import { Category } from '../../mol-io/writer/cif/encoder';
|
||||
import { ReaderResult } from '../../mol-io/reader/result';
|
||||
import { utf8ReadLong } from '../../mol-io/common/utf8';
|
||||
|
||||
function showProgress(p: Progress) {
|
||||
process.stdout.write(`\r${new Array(80).join(' ')}`);
|
||||
process.stdout.write(`\r${Progress.format(p)}`);
|
||||
}
|
||||
|
||||
const readFileAsync = util.promisify(fs.readFile);
|
||||
const readFileAsync = fs.promises.readFile;
|
||||
const unzipAsync = util.promisify<zlib.InputType, Buffer>(zlib.unzip);
|
||||
|
||||
async function readFile(ctx: RuntimeContext, filename: string): Promise<ReaderResult<CifFile>> {
|
||||
const isGz = /\.gz$/i.test(filename);
|
||||
if (filename.match(/\.bcif/)) {
|
||||
let input = await readFileAsync(filename);
|
||||
if (isGz) input = await unzipAsync(input);
|
||||
if (isGz) input = await unzipAsync(input) as NonSharedBuffer;
|
||||
return await CIF.parseBinary(new Uint8Array(input)).runInContext(ctx);
|
||||
} else {
|
||||
let str: string;
|
||||
if (isGz) {
|
||||
const data = await unzipAsync(await readFileAsync(filename));
|
||||
str = data.toString('utf8');
|
||||
} else {
|
||||
str = await readFileAsync(filename, 'utf8');
|
||||
}
|
||||
return await CIF.parseText(str).runInContext(ctx);
|
||||
const data = isGz ? await unzipAsync(await readFileAsync(filename)) : await readFileAsync(filename);
|
||||
const str = utf8ReadLong(data);
|
||||
const cif = await CIF.parseText(str).runInContext(ctx);
|
||||
return cif;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ import * as fs from 'fs';
|
||||
import * as zlib from 'zlib';
|
||||
import { convert } from './converter';
|
||||
|
||||
require('util.promisify').shim();
|
||||
|
||||
async function process(srcPath: string, outPath: string, configPath?: string, filterPath?: string) {
|
||||
const config = configPath ? JSON.parse(fs.readFileSync(configPath, 'utf8')) : void 0;
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Copyright (c) 2017-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2017-2026 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
* @author Paul Pillot <paul.pillot@tandemai.com>
|
||||
*/
|
||||
|
||||
import * as argparse from 'argparse';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import fetch from 'node-fetch';
|
||||
|
||||
import { parseCsv } from '../../mol-io/reader/csv/parser';
|
||||
import { CifFrame, CifBlock } from '../../mol-io/reader/cif';
|
||||
@@ -166,9 +166,9 @@ const MA_DIC_URL = 'https://raw.githubusercontent.com/ihmwg/ModelCIF/master/dist
|
||||
const CIF_CORE_DIC_PATH = `${DIC_DIR}/cif_core.dic`;
|
||||
const CIF_CORE_DIC_URL = 'https://raw.githubusercontent.com/COMCIFS/cif_core/master/cif_core.dic';
|
||||
const CIF_CORE_ENUM_PATH = `${DIC_DIR}/templ_enum.cif`;
|
||||
const CIF_CORE_ENUM_URL = 'https://raw.githubusercontent.com/COMCIFS/cif_core/master/templ_enum.cif';
|
||||
const CIF_CORE_ENUM_URL = 'https://raw.githubusercontent.com/COMCIFS/Enumeration_Templates/refs/heads/main/templ_enum.cif';
|
||||
const CIF_CORE_ATTR_PATH = `${DIC_DIR}/templ_attr.cif`;
|
||||
const CIF_CORE_ATTR_URL = 'https://raw.githubusercontent.com/COMCIFS/cif_core/master/templ_attr.cif';
|
||||
const CIF_CORE_ATTR_URL = 'https://raw.githubusercontent.com/COMCIFS/Attribute_Templates/refs/heads/main/templ_attr.cif';
|
||||
|
||||
const parser = new argparse.ArgumentParser({
|
||||
add_help: true,
|
||||
|
||||
@@ -93,6 +93,7 @@ export function getFieldType(type: string, description: string, values?: string[
|
||||
case 'Implied':
|
||||
case 'Word':
|
||||
case 'Uri':
|
||||
case 'Iri':
|
||||
return wrapContainer('str', ',', description, container);
|
||||
case 'Real':
|
||||
return wrapContainer('float', ',', description, container);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2017-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2017-2026 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -65,7 +65,9 @@ function getTypeDef(c: Column): string {
|
||||
case 'float': return 'float';
|
||||
case 'coord': return 'coord';
|
||||
case 'enum':
|
||||
return `Aliased<'${c.values.map(v => v.replace(/'/g, '\\\'')).join(`' | '`)}'>(${c.subType})`;
|
||||
return c.subType === 'int'
|
||||
? `Aliased<${c.values.join(' | ')}>(${c.subType})`
|
||||
: `Aliased<'${c.values.map(v => v.replace(/'/g, '\\\'')).join(`' | '`)}'>(${c.subType})`;
|
||||
case 'matrix':
|
||||
return `Matrix(${c.rows}, ${c.columns})`;
|
||||
case 'vector':
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2020-2026 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
* @author Paul Pillot <paul.pillot@tandemai.com>
|
||||
*/
|
||||
|
||||
import * as argparse from 'argparse';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import fetch from 'node-fetch';
|
||||
import { UniqueArray } from '../../mol-data/generic';
|
||||
|
||||
const LIPIDS_DIR = path.resolve(__dirname, '../../../../build/lipids/');
|
||||
@@ -33,6 +33,14 @@ async function ensureLipidsAvailable() { await ensureAvailable(MARTINI_LIPIDS_PA
|
||||
|
||||
const extraLipids = ['DMPC'];
|
||||
const v2lipids = ['DAPC', 'DBPC', 'DFPC', 'DGPC', 'DIPC', 'DLPC', 'DNPC', 'DOPC', 'DPPC', 'DRPC', 'DTPC', 'DVPC', 'DXPC', 'DYPC', 'LPPC', 'PAPC', 'PEPC', 'PGPC', 'PIPC', 'POPC', 'PRPC', 'PUPC', 'DAPE', 'DBPE', 'DFPE', 'DGPE', 'DIPE', 'DLPE', 'DNPE', 'DOPE', 'DPPE', 'DRPE', 'DTPE', 'DUPE', 'DVPE', 'DXPE', 'DYPE', 'LPPE', 'PAPE', 'PGPE', 'PIPE', 'POPE', 'PQPE', 'PRPE', 'PUPE', 'DAPS', 'DBPS', 'DFPS', 'DGPS', 'DIPS', 'DLPS', 'DNPS', 'DOPS', 'DPPS', 'DRPS', 'DTPS', 'DUPS', 'DVPS', 'DXPS', 'DYPS', 'LPPS', 'PAPS', 'PGPS', 'PIPS', 'POPS', 'PQPS', 'PRPS', 'PUPS', 'DAPG', 'DBPG', 'DFPG', 'DGPG', 'DIPG', 'DLPG', 'DNPG', 'DOPG', 'DPPG', 'DRPG', 'DTPG', 'DVPG', 'DXPG', 'DYPG', 'LPPG', 'PAPG', 'PGPG', 'PIPG', 'POPG', 'PRPG', 'DAPA', 'DBPA', 'DFPA', 'DGPA', 'DIPA', 'DLPA', 'DNPA', 'DOPA', 'DPPA', 'DRPA', 'DTPA', 'DVPA', 'DXPA', 'DYPA', 'LPPA', 'PAPA', 'PGPA', 'PIPA', 'POPA', 'PRPA', 'PUPA', 'DPP', 'DPPI', 'PAPI', 'PIPI', 'POP', 'POPI', 'PUPI', 'PVP', 'PVPI', 'PADG', 'PIDG', 'PODG', 'PUDG', 'PVDG', 'APC', 'CPC', 'IPC', 'LPC', 'OPC', 'PPC', 'TPC', 'UPC', 'VPC', 'BNSM', 'DBSM', 'DPSM', 'DXSM', 'PGSM', 'PNSM', 'POSM', 'PVSM', 'XNSM', 'DPCE', 'DXCE', 'PNCE', 'XNCE'];
|
||||
const amberLipids = [
|
||||
// acyl chains
|
||||
'PA', 'ST', 'OL', 'LEO', 'LEN', 'AR', 'DHA',
|
||||
// head groups
|
||||
'PC', 'PE', 'PS', 'PH-', 'P2-', 'PGR', 'PGS', 'PI',
|
||||
// other
|
||||
'CHL'
|
||||
];
|
||||
|
||||
async function run(out: string) {
|
||||
await ensureLipidsAvailable();
|
||||
@@ -55,13 +63,17 @@ async function run(out: string) {
|
||||
UniqueArray.add(lipids, v, v);
|
||||
}
|
||||
|
||||
for (const v of amberLipids) {
|
||||
UniqueArray.add(lipids, v, v);
|
||||
}
|
||||
|
||||
const lipidNames = JSON.stringify(lipids.array);
|
||||
|
||||
if (out) {
|
||||
const output = `/**
|
||||
* Copyright (c) 2024 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2020-2026 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* Code-generated lipid params file. Names extracted from Martini FF lipids itp.
|
||||
* Code-generated lipid params file. Names from Martini FF and Amber.
|
||||
*
|
||||
* @author molstar/lipid-params cli
|
||||
*/
|
||||
|
||||
60
src/cli/mvs/mvs-mvsj-to-mvsx.ts
Normal file
60
src/cli/mvs/mvs-mvsj-to-mvsx.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Copyright (c) 2026 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Adam Midlik <midlik@gmail.com>
|
||||
*
|
||||
* Command-line application for converting MolViewSpec MVSJ into MSVX files
|
||||
* Build: npm run build
|
||||
* Run: node lib/commonjs/cli/mvs/mvs-mvsj-to-mvsx -i examples/mvs/1cbs.mvsj -o tmp/1cbs.mvsx
|
||||
*/
|
||||
|
||||
import { ArgumentParser } from 'argparse';
|
||||
import fs from 'fs';
|
||||
import { MVSData } from '../../extensions/mvs/mvs-data';
|
||||
import { setFSModule } from '../../mol-util/data-source';
|
||||
|
||||
|
||||
setFSModule(fs);
|
||||
|
||||
/** Command line argument values for `main` */
|
||||
interface Args {
|
||||
input: string[],
|
||||
output: string[] | undefined,
|
||||
base_uri: string | undefined,
|
||||
skip_external: boolean,
|
||||
}
|
||||
|
||||
/** Return parsed command line arguments for `main` */
|
||||
function parseArguments(): Args {
|
||||
const parser = new ArgumentParser({ description: 'Command-line application for converting MolViewSpec MVSJ into MSVX files' });
|
||||
parser.add_argument('-i', '--input', { required: true, nargs: '+', help: 'Input file(s) in .mvsj format.' });
|
||||
parser.add_argument('-o', '--output', { required: false, nargs: '+', help: 'File path(s) for output files in .mvsx format (one output path for each input file). If ommitted, filenames will be created automatically by replacing file extension.' });
|
||||
parser.add_argument('--base-uri', { help: 'Base URI/path used to resolve relative URIs in the input file (default: path of the input file itself). Use `--base-uri .` for using the current working directory as base URI.' });
|
||||
parser.add_argument('--skip-external', { action: 'store_true', help: 'Do not include external resources (i.e. absolute URIs) in the MVSX.' });
|
||||
const args: Args = parser.parse_args();
|
||||
if (args.output && args.output.length !== args.input.length) {
|
||||
parser.error(`argument: --output: must specify the same number of input and output file paths (specified ${args.input.length} input path${args.input.length !== 1 ? 's' : ''} but ${args.output.length} output path${args.output.length !== 1 ? 's' : ''})`);
|
||||
}
|
||||
return { ...args };
|
||||
}
|
||||
|
||||
/** Main workflow for converting MVSJ to MVSX files. */
|
||||
async function main(args: Args): Promise<void> {
|
||||
const cache = {};
|
||||
for (let i = 0; i < args.input.length; i++) {
|
||||
const input = args.input[i];
|
||||
const output = args.output?.[i] ?? input.replace(/(\.mvsj)?$/i, '.mvsx');
|
||||
console.log(`Processing ${input} -> ${output}`);
|
||||
const mvsj = fs.readFileSync(input, { encoding: 'utf8' });
|
||||
const mvsData = MVSData.fromMVSJ(mvsj);
|
||||
const mvsx = await MVSData.toMVSX(mvsData, {
|
||||
baseUri: args.base_uri ?? input,
|
||||
skipExternal: args.skip_external,
|
||||
cache,
|
||||
});
|
||||
fs.writeFileSync(output, mvsx);
|
||||
}
|
||||
}
|
||||
|
||||
main(parseArguments());
|
||||
@@ -11,8 +11,7 @@
|
||||
*/
|
||||
|
||||
import { ArgumentParser } from 'argparse';
|
||||
import { treeSchemaToMarkdown, treeSchemaToString } from '../../extensions/mvs/tree/generic/tree-schema';
|
||||
import { MVSDefaults } from '../../extensions/mvs/tree/mvs/mvs-defaults';
|
||||
import { treeSchemaToMarkdown, treeSchemaToString } from '../../extensions/mvs/tree/generic/tree-validation';
|
||||
import { MVSTreeSchema } from '../../extensions/mvs/tree/mvs/mvs-tree';
|
||||
|
||||
|
||||
@@ -32,9 +31,9 @@ function parseArguments(): Args {
|
||||
/** Main workflow for printing MolViewSpec tree schema. */
|
||||
function main(args: Args) {
|
||||
if (args.markdown) {
|
||||
console.log(treeSchemaToMarkdown(MVSTreeSchema, MVSDefaults));
|
||||
console.log(treeSchemaToMarkdown(MVSTreeSchema));
|
||||
} else {
|
||||
console.log(treeSchemaToString(MVSTreeSchema, MVSDefaults));
|
||||
console.log(treeSchemaToString(MVSTreeSchema));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@ async function main(args: Args): Promise<void> {
|
||||
} else {
|
||||
throw new Error(`Input file name must end with .mvsj or .mvsx: ${input}`);
|
||||
}
|
||||
await loadMVS(plugin, mvsData, { sanityChecks: true, replaceExisting: true, sourceUrl: sourceUrl, extensions: args.no_extensions ? [] : undefined });
|
||||
await loadMVS(plugin, mvsData, { sanityChecks: true, sourceUrl: sourceUrl, extensions: args.no_extensions ? [] : undefined });
|
||||
|
||||
fs.mkdirSync(path.dirname(output), { recursive: true });
|
||||
if (args.molj) {
|
||||
|
||||
@@ -43,7 +43,7 @@ function paramInfo(param: PD.Any, offset: number): string {
|
||||
}
|
||||
}
|
||||
|
||||
function oToS(options: readonly (readonly [string, string] | readonly [string, string, string | undefined])[]) {
|
||||
function oToS(options: readonly PD.SelectOption<any>[]) {
|
||||
return options.map(o => `'${o[0]}'`).join(', ');
|
||||
}
|
||||
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
/**
|
||||
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2018-2026 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author David Sehnal <david.sehnal@gmail.com>
|
||||
* @author Paul Pillot <paul.pillot@tandemai.com>
|
||||
*/
|
||||
|
||||
import * as util from 'util';
|
||||
import * as fs from 'fs';
|
||||
import fetch from 'node-fetch';
|
||||
require('util.promisify').shim();
|
||||
|
||||
import { CIF } from '../../mol-io/reader/cif';
|
||||
import { Progress } from '../../mol-task';
|
||||
|
||||
const readFileAsync = util.promisify(fs.readFile);
|
||||
const readFileAsync = fs.promises.readFile;
|
||||
|
||||
async function readFile(path: string) {
|
||||
if (path.match(/\.bcif$/)) {
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
*/
|
||||
|
||||
import * as argparse from 'argparse';
|
||||
require('util.promisify').shim();
|
||||
|
||||
import { CifFrame } from '../../mol-io/reader/cif';
|
||||
import { Model, Structure, StructureElement, Unit, StructureProperties, UnitRing, Trajectory } from '../../mol-model/structure';
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2018-2026 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>
|
||||
* @author Paul Pillot <paul.pillot@tandemai.com>
|
||||
*/
|
||||
|
||||
import * as fs from 'fs';
|
||||
import * as argparse from 'argparse';
|
||||
import * as util from 'util';
|
||||
|
||||
import { Volume } from '../../mol-model/volume';
|
||||
import { downloadCif } from './helpers';
|
||||
@@ -19,8 +20,7 @@ import { createVolumeIsosurfaceMesh } from '../../mol-repr/volume/isosurface';
|
||||
import { Theme } from '../../mol-theme/theme';
|
||||
import { volumeFromDensityServerData, DscifFormat } from '../../mol-model-formats/volume/density-server';
|
||||
|
||||
require('util.promisify').shim();
|
||||
const writeFileAsync = util.promisify(fs.writeFile);
|
||||
const writeFileAsync = fs.promises.writeFile;
|
||||
|
||||
async function getVolume(url: string): Promise<Volume> {
|
||||
const cif = await downloadCif(url, true);
|
||||
@@ -38,7 +38,7 @@ function print(volume: Volume) {
|
||||
}
|
||||
|
||||
async function doMesh(volume: Volume, filename: string) {
|
||||
const mesh = await Task.create('', runtime => createVolumeIsosurfaceMesh({ runtime }, volume, -1, Theme.createEmpty(), { isoValue: Volume.IsoValue.absolute(1.5) })).run();
|
||||
const mesh = await Task.create('', runtime => createVolumeIsosurfaceMesh({ runtime }, volume, -1, Theme.createEmpty(), { isoValue: Volume.IsoValue.absolute(1.5), wrap: 'auto', floodfill: 'off' })).run();
|
||||
console.log({ vc: mesh.vertexCount, tc: mesh.triangleCount });
|
||||
|
||||
// Export the mesh in OBJ format.
|
||||
|
||||
@@ -47,8 +47,8 @@
|
||||
<div id="app"></div>
|
||||
<div id='controls'></div>
|
||||
<div id='sponsor'>
|
||||
<a href='https://www.entos.ai/envision' target="_blank" rel="noopener">
|
||||
<svg class="makeStyles-root-46" viewBox="0 0 190 36" xmlns="http://www.w3.org/2000/svg"><path d="M32.2591 28.6707C32.2591 32.3914 29.2421 35.407 25.5214 35.407C22.0752 35.407 19.2338 32.8206 18.8325 29.4831V29.4775C18.8143 29.3312 18.8018 29.1835 18.7934 29.0344C18.7934 29.0316 18.7921 29.0274 18.7921 29.0246V29.0177C18.7865 28.902 18.7837 28.7864 18.7837 28.6707C18.7837 26.2557 20.0532 24.1389 21.9609 22.9503C21.9623 22.9489 21.9651 22.9489 21.9665 22.9475C22.0933 22.8666 22.2243 22.7914 22.3581 22.7203C22.3581 22.7203 22.3595 22.7203 22.3595 22.7189C23.3029 22.2173 24.3787 21.933 25.5214 21.933C29.2421 21.933 32.2591 24.9486 32.2591 28.6707Z"></path><path d="M25.5214 14.0692C29.2421 14.0692 32.2591 11.0522 32.2591 7.33146C32.2591 3.61074 29.2421 0.59375 25.5214 0.59375C22.0529 0.59375 19.1962 3.21637 18.8255 6.58592C18.8185 6.67092 18.8116 6.75454 18.8018 6.83815C18.7893 7.00119 18.7837 7.16563 18.7837 7.33146C18.7837 9.73669 20.0434 11.8465 21.94 13.038C22.0891 13.116 22.2355 13.201 22.3776 13.2916C22.3783 13.2923 22.379 13.2926 22.3797 13.293C22.3804 13.2933 22.3811 13.2937 22.3818 13.2944C23.3196 13.7891 24.3871 14.0692 25.5214 14.0692Z"></path><path d="M19.3645 12.4113C20.2926 12.4113 21.1694 12.638 21.94 13.038C20.0434 11.8465 18.7837 9.73669 18.7837 7.33146C18.7837 7.16563 18.7893 7.00119 18.8018 6.83815C18.4688 9.76455 16.1385 12.0866 13.2065 12.4044C13.8545 13.1193 14.3785 13.9484 14.745 14.857C15.7497 13.3798 17.4443 12.4113 19.3645 12.4113Z"></path><path d="M14.7312 21.1249V21.1236C14.1279 20.2331 13.7767 19.1587 13.7767 18.0007V17.9728C13.7767 15.3084 12.2285 13.0035 9.9835 11.911C9.98141 11.9103 9.97967 11.9096 9.97793 11.9089C9.97619 11.9082 9.97444 11.9075 9.97235 11.9068C9.96817 11.904 9.96538 11.9026 9.9612 11.9012C9.95981 11.9012 9.95981 11.8998 9.95981 11.8998C9.9417 11.8915 9.92394 11.8831 9.90618 11.8747C9.8884 11.8664 9.87063 11.858 9.85251 11.8497C9.82046 11.8343 9.78701 11.819 9.75357 11.8051L9.74521 11.8009C8.91745 11.4372 8.0019 11.2351 7.03898 11.2351C3.31826 11.2351 0.30127 14.2521 0.30127 17.9728C0.30127 21.6935 3.31826 24.7105 7.03898 24.7105C7.98797 24.7105 8.89098 24.514 9.71037 24.1601C9.71246 24.1594 9.7142 24.1583 9.71594 24.1573C9.71768 24.1562 9.71943 24.1552 9.72152 24.1545C9.8107 24.1169 9.8985 24.0765 9.9849 24.0333L9.98629 24.0319C10.7625 23.6919 11.6181 23.5037 12.5197 23.5037C12.7524 23.5037 12.9824 23.5163 13.2081 23.54C13.2082 23.5399 13.2081 23.54 13.2081 23.54C15.0168 23.7365 16.5971 24.695 17.6185 26.0885C17.9195 25.1688 18.3752 24.3201 18.9563 23.5732C17.1964 23.4464 15.6635 22.5058 14.7312 21.1249Z"></path><g clip-path="url(#clip0)"><path d="M106.391 18.0021C106.391 11.3724 101.039 6 94.4389 6H88.4585C81.8581 6 76.5061 11.3724 76.5061 18.0021V30.0042H81.2845V18.0021C81.2845 14.0268 84.4941 10.8008 88.4585 10.8008H94.4347C98.395 10.8008 101.609 14.0226 101.609 18.0021V30.0042H106.391V18.0021Z"></path><path d="M149.432 6H142.258C135.653 6 130.301 11.3724 130.301 18.0021C130.301 24.6319 135.653 30.0042 142.258 30.0042H149.432C156.036 30.0042 161.388 24.6319 161.388 18.0021C161.388 11.3724 156.032 6 149.432 6ZM149.432 25.1992H142.258C138.297 25.1992 135.084 21.9774 135.084 17.9979C135.084 14.0183 138.293 10.7966 142.258 10.7966H149.432C153.392 10.7966 156.606 14.0183 156.606 17.9979C156.606 21.9774 153.392 25.1992 149.432 25.1992Z"></path><path d="M74.1151 25.1992H58.5736C55.4526 25.1992 52.804 23.1924 51.8171 20.3983H74.1151V17.9979C74.1151 17.1808 74.1868 16.3807 74.3175 15.5975H51.8171C52.804 12.8033 55.4526 10.7966 58.5736 10.7966H76.0383C77.1475 8.87458 78.6911 7.22773 80.5299 6H58.5736C51.969 6 46.6169 11.3724 46.6169 18.0021C46.6169 24.6276 51.969 30 58.5736 30H74.1151V25.1992Z"></path><path d="M120.74 6H115.958H102.369C104.212 7.22773 105.751 8.87458 106.861 10.8008H115.958V30H120.74V10.8008H129.838C130.947 8.87458 132.486 7.22773 134.329 6H120.74Z"></path><path d="M182.906 15.6017H169.756C168.436 15.6017 167.365 14.5264 167.365 13.2013C167.365 11.8762 168.436 10.8008 169.756 10.8008H188.882V6H169.756C165.796 6 162.582 9.22173 162.582 13.2013C162.582 17.1808 165.791 20.4025 169.756 20.4025H182.906C184.226 20.4025 185.297 21.4779 185.297 22.803C185.297 24.1281 184.226 25.2034 182.906 25.2034H161.852C160.743 27.1297 159.199 28.7765 157.361 30.0042H182.906C186.866 30.0042 190.08 26.7825 190.08 22.803C190.08 18.8234 186.866 15.6017 182.906 15.6017Z"></path></g><defs><clipPath id="clip0"><rect width="190" height="24" fill="white" transform="translate(0 6)"></rect></clipPath></defs></svg>
|
||||
<a href='https://www.iambic-envision.com/' target="_blank" rel="noopener">
|
||||
<svg viewBox="0 0 190 36" xmlns="http://www.w3.org/2000/svg"><path d="M32.2591 28.6707C32.2591 32.3914 29.2421 35.407 25.5214 35.407C22.0752 35.407 19.2338 32.8206 18.8325 29.4831V29.4775C18.8143 29.3312 18.8018 29.1835 18.7934 29.0344C18.7934 29.0316 18.7921 29.0274 18.7921 29.0246V29.0177C18.7865 28.902 18.7837 28.7864 18.7837 28.6707C18.7837 26.2557 20.0532 24.1389 21.9609 22.9503C21.9623 22.9489 21.9651 22.9489 21.9665 22.9475C22.0933 22.8666 22.2243 22.7914 22.3581 22.7203C22.3581 22.7203 22.3595 22.7203 22.3595 22.7189C23.3029 22.2173 24.3787 21.933 25.5214 21.933C29.2421 21.933 32.2591 24.9486 32.2591 28.6707Z"></path><path d="M25.5214 14.0692C29.2421 14.0692 32.2591 11.0522 32.2591 7.33146C32.2591 3.61074 29.2421 0.59375 25.5214 0.59375C22.0529 0.59375 19.1962 3.21637 18.8255 6.58592C18.8185 6.67092 18.8116 6.75454 18.8018 6.83815C18.7893 7.00119 18.7837 7.16563 18.7837 7.33146C18.7837 9.73669 20.0434 11.8465 21.94 13.038C22.0891 13.116 22.2355 13.201 22.3776 13.2916C22.3783 13.2923 22.379 13.2926 22.3797 13.293C22.3804 13.2933 22.3811 13.2937 22.3818 13.2944C23.3196 13.7891 24.3871 14.0692 25.5214 14.0692Z"></path><path d="M19.3645 12.4113C20.2926 12.4113 21.1694 12.638 21.94 13.038C20.0434 11.8465 18.7837 9.73669 18.7837 7.33146C18.7837 7.16563 18.7893 7.00119 18.8018 6.83815C18.4688 9.76455 16.1385 12.0866 13.2065 12.4044C13.8545 13.1193 14.3785 13.9484 14.745 14.857C15.7497 13.3798 17.4443 12.4113 19.3645 12.4113Z"></path><path d="M14.7312 21.1249V21.1236C14.1279 20.2331 13.7767 19.1587 13.7767 18.0007V17.9728C13.7767 15.3084 12.2285 13.0035 9.9835 11.911C9.98141 11.9103 9.97967 11.9096 9.97793 11.9089C9.97619 11.9082 9.97444 11.9075 9.97235 11.9068C9.96817 11.904 9.96538 11.9026 9.9612 11.9012C9.95981 11.9012 9.95981 11.8998 9.95981 11.8998C9.9417 11.8915 9.92394 11.8831 9.90618 11.8747C9.8884 11.8664 9.87063 11.858 9.85251 11.8497C9.82046 11.8343 9.78701 11.819 9.75357 11.8051L9.74521 11.8009C8.91745 11.4372 8.0019 11.2351 7.03898 11.2351C3.31826 11.2351 0.30127 14.2521 0.30127 17.9728C0.30127 21.6935 3.31826 24.7105 7.03898 24.7105C7.98797 24.7105 8.89098 24.514 9.71037 24.1601C9.71246 24.1594 9.7142 24.1583 9.71594 24.1573C9.71768 24.1562 9.71943 24.1552 9.72152 24.1545C9.8107 24.1169 9.8985 24.0765 9.9849 24.0333L9.98629 24.0319C10.7625 23.6919 11.6181 23.5037 12.5197 23.5037C12.7524 23.5037 12.9824 23.5163 13.2081 23.54C13.2082 23.5399 13.2081 23.54 13.2081 23.54C15.0168 23.7365 16.5971 24.695 17.6185 26.0885C17.9195 25.1688 18.3752 24.3201 18.9563 23.5732C17.1964 23.4464 15.6635 22.5058 14.7312 21.1249Z"></path><g clip-path="url(#clip0)"><path d="M106.391 18.0021C106.391 11.3724 101.039 6 94.4389 6H88.4585C81.8581 6 76.5061 11.3724 76.5061 18.0021V30.0042H81.2845V18.0021C81.2845 14.0268 84.4941 10.8008 88.4585 10.8008H94.4347C98.395 10.8008 101.609 14.0226 101.609 18.0021V30.0042H106.391V18.0021Z"></path><path d="M149.432 6H142.258C135.653 6 130.301 11.3724 130.301 18.0021C130.301 24.6319 135.653 30.0042 142.258 30.0042H149.432C156.036 30.0042 161.388 24.6319 161.388 18.0021C161.388 11.3724 156.032 6 149.432 6ZM149.432 25.1992H142.258C138.297 25.1992 135.084 21.9774 135.084 17.9979C135.084 14.0183 138.293 10.7966 142.258 10.7966H149.432C153.392 10.7966 156.606 14.0183 156.606 17.9979C156.606 21.9774 153.392 25.1992 149.432 25.1992Z"></path><path d="M74.1151 25.1992H58.5736C55.4526 25.1992 52.804 23.1924 51.8171 20.3983H74.1151V17.9979C74.1151 17.1808 74.1868 16.3807 74.3175 15.5975H51.8171C52.804 12.8033 55.4526 10.7966 58.5736 10.7966H76.0383C77.1475 8.87458 78.6911 7.22773 80.5299 6H58.5736C51.969 6 46.6169 11.3724 46.6169 18.0021C46.6169 24.6276 51.969 30 58.5736 30H74.1151V25.1992Z"></path><path d="M120.74 6H115.958H102.369C104.212 7.22773 105.751 8.87458 106.861 10.8008H115.958V30H120.74V10.8008H129.838C130.947 8.87458 132.486 7.22773 134.329 6H120.74Z"></path><path d="M182.906 15.6017H169.756C168.436 15.6017 167.365 14.5264 167.365 13.2013C167.365 11.8762 168.436 10.8008 169.756 10.8008H188.882V6H169.756C165.796 6 162.582 9.22173 162.582 13.2013C162.582 17.1808 165.791 20.4025 169.756 20.4025H182.906C184.226 20.4025 185.297 21.4779 185.297 22.803C185.297 24.1281 184.226 25.2034 182.906 25.2034H161.852C160.743 27.1297 159.199 28.7765 157.361 30.0042H182.906C186.866 30.0042 190.08 26.7825 190.08 22.803C190.08 18.8234 186.866 15.6017 182.906 15.6017Z"></path></g><defs><clipPath id="clip0"><rect width="190" height="24" fill="white" transform="translate(0 6)"></rect></clipPath></defs></svg>
|
||||
<div>
|
||||
Entos Envision
|
||||
</div>
|
||||
|
||||
@@ -24,7 +24,7 @@ import { ParamDefinition } from '../../mol-util/param-definition';
|
||||
import { mountControls } from './controls';
|
||||
import { DemoMoleculeSDF, DemoOrbitals } from './example-data';
|
||||
import './index.html';
|
||||
require('mol-plugin-ui/skin/light.scss');
|
||||
import '../../mol-plugin-ui/skin/light.scss';
|
||||
|
||||
import { setDebugMode, setTimingMode, consoleStats } from '../../mol-util/debug';
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user