Spaces:
Running
Running
Upload folder using huggingface_hub
Browse files- README.md +2 -3
- data/DYKE_DYKE_DYKE_20-09-04-15-13-14-866983543.bin +3 -0
- data/DYKE_DYKE_DYKE_20-09-04-15-23-15-571651575.bin +3 -0
- data/DYKE_FAULT_FOLD_20-09-04-15-10-34-746860823.bin +3 -0
- data/DYKE_FAULT_FOLD_20-09-04-15-27-15-271172160.bin +3 -0
- data/FAULT_FAULT_FAULT_20-09-04-15-10-55-650240871.bin +3 -0
- data/FAULT_FAULT_FAULT_20-09-04-15-11-35-249388807.bin +3 -0
- data/FOLD_FAULT_UNCONFORMITY_20-09-04-15-22-57-108968161.bin +3 -0
- data/FOLD_FAULT_UNCONFORMITY_20-09-04-15-30-27-806964861.bin +3 -0
- data/FOLD_FOLD_FOLD_20-09-04-15-10-30-738239236.bin +3 -0
- data/FOLD_FOLD_FOLD_20-09-04-15-12-01-552434953.bin +3 -0
- data/PLUG_PLUG_PLUG_20-09-04-15-22-31-290339215.bin +3 -0
- data/PLUG_PLUG_PLUG_20-09-04-15-34-27-811124008.bin +3 -0
- data/PLUG_SHEAR-ZONE_TILT_20-09-04-15-13-16-695630284.bin +3 -0
- data/PLUG_SHEAR-ZONE_TILT_20-09-04-15-20-46-049109221.bin +3 -0
- data/SHEAR-ZONE_SHEAR-ZONE_SHEAR-ZONE_20-09-04-15-11-17-868781593.bin +3 -0
- data/SHEAR-ZONE_SHEAR-ZONE_SHEAR-ZONE_20-09-04-15-12-07-100352181.bin +3 -0
- data/TILT_TILT_TILT_20-09-04-15-54-46-708920477.bin +3 -0
- data/TILT_TILT_TILT_20-09-04-16-40-18-405539396.bin +3 -0
- data/UNCONFORMITY_UNCONFORMITY_UNCONFORMITY_20-09-04-15-16-52-886739346.bin +3 -0
- data/UNCONFORMITY_UNCONFORMITY_UNCONFORMITY_20-09-04-15-41-38-711387686.bin +3 -0
- data/manifest.json +46 -0
- index.html +578 -18
README.md
CHANGED
|
@@ -1,10 +1,9 @@
|
|
| 1 |
---
|
| 2 |
title: Noddyverse Explorer
|
| 3 |
-
emoji:
|
| 4 |
colorFrom: indigo
|
| 5 |
colorTo: purple
|
| 6 |
sdk: static
|
| 7 |
pinned: false
|
|
|
|
| 8 |
---
|
| 9 |
-
|
| 10 |
-
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
|
|
|
| 1 |
---
|
| 2 |
title: Noddyverse Explorer
|
| 3 |
+
emoji: 🌍
|
| 4 |
colorFrom: indigo
|
| 5 |
colorTo: purple
|
| 6 |
sdk: static
|
| 7 |
pinned: false
|
| 8 |
+
license: cc-by-4.0
|
| 9 |
---
|
|
|
|
|
|
data/DYKE_DYKE_DYKE_20-09-04-15-13-14-866983543.bin
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:1215f1671c79daed89572026684478ad66643cfdabd58dacd5ced72b1820295a
|
| 3 |
+
size 191228
|
data/DYKE_DYKE_DYKE_20-09-04-15-23-15-571651575.bin
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:2e335c56932875fec55e217f0ebc944b062c1ab6051edf6aea668a91ed618a90
|
| 3 |
+
size 226916
|
data/DYKE_FAULT_FOLD_20-09-04-15-10-34-746860823.bin
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:c7ea625855c7681ac89e87f6cbe330adc722e3fd61d4ce14e765dd02f0949dd8
|
| 3 |
+
size 155568
|
data/DYKE_FAULT_FOLD_20-09-04-15-27-15-271172160.bin
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:4530bd3891cc3ab09fcb4c2abeda30a36daf7d70be0bf02a5434e80f302d3859
|
| 3 |
+
size 134164
|
data/FAULT_FAULT_FAULT_20-09-04-15-10-55-650240871.bin
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:741111b45dc60cb13d3f51a5aa29ab28e42d23621e49a7dbab2b9736d4a44542
|
| 3 |
+
size 98656
|
data/FAULT_FAULT_FAULT_20-09-04-15-11-35-249388807.bin
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:a6a765c66858a3ab937bb62f0857d34ce73e8c5d35d32e97cba683b5a3c1c384
|
| 3 |
+
size 166864
|
data/FOLD_FAULT_UNCONFORMITY_20-09-04-15-22-57-108968161.bin
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:0450a70a95af152ab9f99e62aa37d4ff3f51b639c6c1e731f72d043ade007d82
|
| 3 |
+
size 218080
|
data/FOLD_FAULT_UNCONFORMITY_20-09-04-15-30-27-806964861.bin
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:58731e5604c8d53d36818b5362ae81c0bca098272583990f09a056542f08b269
|
| 3 |
+
size 163704
|
data/FOLD_FOLD_FOLD_20-09-04-15-10-30-738239236.bin
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:46ae7a106e81bafa2603cb0032aca17ebe8692cd6e14eae727739067adbec43c
|
| 3 |
+
size 195044
|
data/FOLD_FOLD_FOLD_20-09-04-15-12-01-552434953.bin
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:e4023c6525926410353a891996a4ffc36280b2ac692c71052f74fa9f8b9a54fa
|
| 3 |
+
size 213584
|
data/PLUG_PLUG_PLUG_20-09-04-15-22-31-290339215.bin
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:19c185592ea6c0ef28ddfc9744c5ad11860ff8e26d7b1a2c6635ee54ce665d46
|
| 3 |
+
size 142584
|
data/PLUG_PLUG_PLUG_20-09-04-15-34-27-811124008.bin
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:b4707c4cc5b6c462478c56aae405c70f9c64834661eba11600330b410e07020f
|
| 3 |
+
size 168924
|
data/PLUG_SHEAR-ZONE_TILT_20-09-04-15-13-16-695630284.bin
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:8986ee495e0598b5f05d3e100f8e47777b9b56a11d40329383350af835de9341
|
| 3 |
+
size 160436
|
data/PLUG_SHEAR-ZONE_TILT_20-09-04-15-20-46-049109221.bin
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:2a3e20aaa5284c9cef7b4a5a1c88aef3a9d3dbb68ba7859ef717afc50d7016e9
|
| 3 |
+
size 130188
|
data/SHEAR-ZONE_SHEAR-ZONE_SHEAR-ZONE_20-09-04-15-11-17-868781593.bin
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:9cd03e94ecc4b065321005cef3cb481436ee4b382fcab3259e163e42fc3fd81d
|
| 3 |
+
size 95184
|
data/SHEAR-ZONE_SHEAR-ZONE_SHEAR-ZONE_20-09-04-15-12-07-100352181.bin
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:04b109a4d55e095ca49918095ac5dfc11a28785a23544548f625a76be7d707fd
|
| 3 |
+
size 100024
|
data/TILT_TILT_TILT_20-09-04-15-54-46-708920477.bin
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:9b041e761750f6d63541995137676fc587d4e419e123ac8436d41213b21d2b12
|
| 3 |
+
size 100544
|
data/TILT_TILT_TILT_20-09-04-16-40-18-405539396.bin
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:b6b23e2ea0239c1f354093b2935d8ee8e7a6d465d1c21a8ea8f69828de7359e2
|
| 3 |
+
size 140024
|
data/UNCONFORMITY_UNCONFORMITY_UNCONFORMITY_20-09-04-15-16-52-886739346.bin
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:a6d6c23ba5abd1e5477c9909499e3bf8c66ca92169e41366a23f2b23cb4dab0a
|
| 3 |
+
size 125824
|
data/UNCONFORMITY_UNCONFORMITY_UNCONFORMITY_20-09-04-15-41-38-711387686.bin
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:52966bdf684d2867aeaec50f294c475b83e799f16770758b2bd4281a467d0e81
|
| 3 |
+
size 139676
|
data/manifest.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"grid_size": 50,
|
| 3 |
+
"field_size": 100,
|
| 4 |
+
"types": {
|
| 5 |
+
"DYKE_DYKE_DYKE": [
|
| 6 |
+
"DYKE_DYKE_DYKE_20-09-04-15-13-14-866983543.bin",
|
| 7 |
+
"DYKE_DYKE_DYKE_20-09-04-15-23-15-571651575.bin"
|
| 8 |
+
],
|
| 9 |
+
"DYKE_FAULT_FOLD": [
|
| 10 |
+
"DYKE_FAULT_FOLD_20-09-04-15-10-34-746860823.bin",
|
| 11 |
+
"DYKE_FAULT_FOLD_20-09-04-15-27-15-271172160.bin"
|
| 12 |
+
],
|
| 13 |
+
"FAULT_FAULT_FAULT": [
|
| 14 |
+
"FAULT_FAULT_FAULT_20-09-04-15-10-55-650240871.bin",
|
| 15 |
+
"FAULT_FAULT_FAULT_20-09-04-15-11-35-249388807.bin"
|
| 16 |
+
],
|
| 17 |
+
"FOLD_FAULT_UNCONFORMITY": [
|
| 18 |
+
"FOLD_FAULT_UNCONFORMITY_20-09-04-15-22-57-108968161.bin",
|
| 19 |
+
"FOLD_FAULT_UNCONFORMITY_20-09-04-15-30-27-806964861.bin"
|
| 20 |
+
],
|
| 21 |
+
"FOLD_FOLD_FOLD": [
|
| 22 |
+
"FOLD_FOLD_FOLD_20-09-04-15-10-30-738239236.bin",
|
| 23 |
+
"FOLD_FOLD_FOLD_20-09-04-15-12-01-552434953.bin"
|
| 24 |
+
],
|
| 25 |
+
"PLUG_PLUG_PLUG": [
|
| 26 |
+
"PLUG_PLUG_PLUG_20-09-04-15-22-31-290339215.bin",
|
| 27 |
+
"PLUG_PLUG_PLUG_20-09-04-15-34-27-811124008.bin"
|
| 28 |
+
],
|
| 29 |
+
"PLUG_SHEAR-ZONE_TILT": [
|
| 30 |
+
"PLUG_SHEAR-ZONE_TILT_20-09-04-15-13-16-695630284.bin",
|
| 31 |
+
"PLUG_SHEAR-ZONE_TILT_20-09-04-15-20-46-049109221.bin"
|
| 32 |
+
],
|
| 33 |
+
"SHEAR-ZONE_SHEAR-ZONE_SHEAR-ZONE": [
|
| 34 |
+
"SHEAR-ZONE_SHEAR-ZONE_SHEAR-ZONE_20-09-04-15-11-17-868781593.bin",
|
| 35 |
+
"SHEAR-ZONE_SHEAR-ZONE_SHEAR-ZONE_20-09-04-15-12-07-100352181.bin"
|
| 36 |
+
],
|
| 37 |
+
"TILT_TILT_TILT": [
|
| 38 |
+
"TILT_TILT_TILT_20-09-04-15-54-46-708920477.bin",
|
| 39 |
+
"TILT_TILT_TILT_20-09-04-16-40-18-405539396.bin"
|
| 40 |
+
],
|
| 41 |
+
"UNCONFORMITY_UNCONFORMITY_UNCONFORMITY": [
|
| 42 |
+
"UNCONFORMITY_UNCONFORMITY_UNCONFORMITY_20-09-04-15-16-52-886739346.bin",
|
| 43 |
+
"UNCONFORMITY_UNCONFORMITY_UNCONFORMITY_20-09-04-15-41-38-711387686.bin"
|
| 44 |
+
]
|
| 45 |
+
}
|
| 46 |
+
}
|
index.html
CHANGED
|
@@ -1,19 +1,579 @@
|
|
| 1 |
-
<!
|
| 2 |
-
<html>
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 19 |
</html>
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="en">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8">
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
+
<title>Noddyverse Explorer</title>
|
| 7 |
+
<style>
|
| 8 |
+
*,*::before,*::after{margin:0;padding:0;box-sizing:border-box}
|
| 9 |
+
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
|
| 10 |
+
|
| 11 |
+
/* ── Splash screen (dark, with fluid) ── */
|
| 12 |
+
#splash{position:fixed;top:0;left:0;width:100%;height:100%;z-index:200;background:#070410;
|
| 13 |
+
display:flex;align-items:center;justify-content:center;flex-direction:column;cursor:pointer;
|
| 14 |
+
transition:opacity 0.8s ease;font-family:'Inter',system-ui,sans-serif}
|
| 15 |
+
#splash.hidden{opacity:0;pointer-events:none}
|
| 16 |
+
#fluid-canvas{position:fixed;top:0;left:0;width:100%;height:100%;z-index:201;pointer-events:none}
|
| 17 |
+
#splash-content{position:relative;z-index:202;text-align:center;color:#e0dce8;pointer-events:none;max-width:620px;padding:0 24px}
|
| 18 |
+
#splash-content h1{font-size:3rem;font-weight:700;
|
| 19 |
+
background:linear-gradient(135deg,#7c3aed,#a855f7,#6366f1);
|
| 20 |
+
-webkit-background-clip:text;-webkit-text-fill-color:transparent;margin-bottom:16px;letter-spacing:-0.03em}
|
| 21 |
+
#splash-content p{font-size:1.05rem;color:#9a92ad;line-height:1.6;margin-bottom:32px}
|
| 22 |
+
#splash-content .cta{font-size:0.85rem;color:#6366f1;letter-spacing:0.1em;text-transform:uppercase;
|
| 23 |
+
animation:pulse 2s ease-in-out infinite}
|
| 24 |
+
@keyframes pulse{0%,100%{opacity:0.5}50%{opacity:1}}
|
| 25 |
+
|
| 26 |
+
/* ── App (light theme) ── */
|
| 27 |
+
:root{--bg:#f8f9fc;--surface:#ffffff;--surface2:#f0f1f5;--border:#e2e4ea;
|
| 28 |
+
--text:#1a1a2e;--text2:#6b7084;--accent:#7c3aed;--accent2:#a855f7}
|
| 29 |
+
html,body{height:100%;overflow:hidden;font-family:'Inter',system-ui,sans-serif;background:var(--bg);color:var(--text)}
|
| 30 |
+
#app{position:relative;z-index:1;display:flex;height:100vh;opacity:0;transition:opacity 0.6s ease 0.4s}
|
| 31 |
+
#app.visible{opacity:1}
|
| 32 |
+
|
| 33 |
+
/* Sidebar */
|
| 34 |
+
#sidebar{width:270px;min-width:270px;background:var(--surface);
|
| 35 |
+
border-right:1px solid var(--border);padding:20px;display:flex;flex-direction:column;gap:14px;overflow-y:auto}
|
| 36 |
+
#sidebar h1{font-size:1.2rem;font-weight:700;background:linear-gradient(135deg,var(--accent),var(--accent2));
|
| 37 |
+
-webkit-background-clip:text;-webkit-text-fill-color:transparent;letter-spacing:-0.02em}
|
| 38 |
+
#sidebar p.sub{font-size:0.72rem;color:var(--text2);line-height:1.5;margin-top:-6px}
|
| 39 |
+
.control-group{display:flex;flex-direction:column;gap:5px}
|
| 40 |
+
.control-group label{font-size:0.65rem;text-transform:uppercase;letter-spacing:0.08em;color:var(--text2);font-weight:600}
|
| 41 |
+
select{background:var(--surface2);color:var(--text);border:1px solid var(--border);border-radius:8px;
|
| 42 |
+
padding:9px 32px 9px 10px;font-size:0.82rem;cursor:pointer;outline:none;transition:border-color 0.2s;
|
| 43 |
+
appearance:none;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='%236b7084'%3E%3Cpath d='M6 8L1 3h10z'/%3E%3C/svg%3E");
|
| 44 |
+
background-repeat:no-repeat;background-position:right 10px center}
|
| 45 |
+
select:hover,select:focus{border-color:var(--accent)}
|
| 46 |
+
|
| 47 |
+
.info-card{background:var(--surface2);border:1px solid var(--border);border-radius:10px;padding:12px;font-size:0.72rem;line-height:1.6}
|
| 48 |
+
.info-card .label{color:var(--text2);font-size:0.62rem;text-transform:uppercase;letter-spacing:0.06em}
|
| 49 |
+
.info-card .value{color:var(--text);font-weight:600}
|
| 50 |
+
.legend{display:flex;flex-wrap:wrap;gap:5px;margin-top:5px}
|
| 51 |
+
.legend-item{display:flex;align-items:center;gap:3px;font-size:0.62rem;color:var(--text2)}
|
| 52 |
+
.legend-swatch{width:10px;height:10px;border-radius:2px;border:1px solid rgba(0,0,0,0.1)}
|
| 53 |
+
|
| 54 |
+
.credits{font-size:0.58rem;color:var(--text2);line-height:1.5;margin-top:auto;padding-top:8px;border-top:1px solid var(--border)}
|
| 55 |
+
|
| 56 |
+
/* Loading */
|
| 57 |
+
#loading-bar{position:absolute;top:0;left:0;width:0%;height:3px;background:linear-gradient(90deg,var(--accent),var(--accent2));
|
| 58 |
+
z-index:50;transition:width 0.3s;border-radius:0 2px 2px 0}
|
| 59 |
+
#loading-bar.hidden{opacity:0}
|
| 60 |
+
|
| 61 |
+
/* Main content */
|
| 62 |
+
#main{flex:1;display:flex;flex-direction:column;min-width:0;position:relative}
|
| 63 |
+
#viewer-container{flex:1;position:relative;min-height:0;background:var(--surface)}
|
| 64 |
+
#three-canvas{width:100%;height:100%;display:block}
|
| 65 |
+
#viewer-label{position:absolute;top:10px;left:14px;font-size:0.68rem;color:var(--text2);
|
| 66 |
+
background:rgba(255,255,255,0.85);padding:3px 10px;border-radius:6px;backdrop-filter:blur(8px);pointer-events:none;
|
| 67 |
+
border:1px solid var(--border)}
|
| 68 |
+
|
| 69 |
+
#fields-panel{height:210px;min-height:210px;display:flex;border-top:1px solid var(--border);background:var(--surface)}
|
| 70 |
+
.field-container{flex:1;padding:10px 14px;display:flex;flex-direction:column;position:relative}
|
| 71 |
+
.field-container+.field-container{border-left:1px solid var(--border)}
|
| 72 |
+
.field-title{font-size:0.68rem;color:var(--text2);text-transform:uppercase;letter-spacing:0.06em;margin-bottom:5px;font-weight:600}
|
| 73 |
+
.field-canvas-wrap{flex:1;position:relative;display:flex;align-items:center;justify-content:center}
|
| 74 |
+
.field-canvas-wrap canvas{max-width:100%;max-height:100%;border-radius:4px;border:1px solid var(--border)}
|
| 75 |
+
.colorbar{position:absolute;right:2px;top:0;bottom:0;width:16px;display:flex;flex-direction:column;
|
| 76 |
+
align-items:center;justify-content:space-between;font-size:0.52rem;color:var(--text2)}
|
| 77 |
+
.colorbar-gradient{width:8px;flex:1;border-radius:3px;margin:2px 0;border:1px solid var(--border)}
|
| 78 |
+
</style>
|
| 79 |
+
</head>
|
| 80 |
+
<body>
|
| 81 |
+
|
| 82 |
+
<!-- ============ SPLASH SCREEN ============ -->
|
| 83 |
+
<div id="splash">
|
| 84 |
+
<canvas id="fluid-canvas"></canvas>
|
| 85 |
+
<div id="splash-content">
|
| 86 |
+
<h1>Noddyverse Explorer</h1>
|
| 87 |
+
<p>Explore 3D synthetic geological models with interactive gravity and magnetic field visualizations.
|
| 88 |
+
Built from the Noddyverse dataset — one million models generated with the Noddy modelling engine.</p>
|
| 89 |
+
<div class="cta">Click anywhere to explore</div>
|
| 90 |
+
</div>
|
| 91 |
+
</div>
|
| 92 |
+
|
| 93 |
+
<!-- ============ MAIN APP ============ -->
|
| 94 |
+
<div id="app">
|
| 95 |
+
<div id="loading-bar"></div>
|
| 96 |
+
<div id="sidebar">
|
| 97 |
+
<div>
|
| 98 |
+
<h1>Noddyverse Explorer</h1>
|
| 99 |
+
<p class="sub">Drag to rotate the 3D model. Scroll to zoom. Select different geology types below.</p>
|
| 100 |
+
</div>
|
| 101 |
+
<div class="control-group">
|
| 102 |
+
<label>Geology Type</label>
|
| 103 |
+
<select id="type-select"></select>
|
| 104 |
+
</div>
|
| 105 |
+
<div class="control-group">
|
| 106 |
+
<label>Sample</label>
|
| 107 |
+
<select id="sample-select"></select>
|
| 108 |
+
</div>
|
| 109 |
+
<div class="info-card" id="info-card">
|
| 110 |
+
<div><span class="label">Surface voxels: </span><span class="value" id="info-voxels">—</span></div>
|
| 111 |
+
<div><span class="label">Grid: </span><span class="value" id="info-grid">50 x 50 x 50</span></div>
|
| 112 |
+
<div><span class="label">Lithology classes: </span><span class="value" id="info-classes">—</span></div>
|
| 113 |
+
<div style="margin-top:6px"><span class="label">Legend</span>
|
| 114 |
+
<div class="legend" id="legend"></div>
|
| 115 |
+
</div>
|
| 116 |
+
</div>
|
| 117 |
+
<div class="credits">
|
| 118 |
+
Data: Noddyverse (Jessell et al., 2022)<br>
|
| 119 |
+
DOI: 10.25914/p91d-x082 · License: CC-BY 4.0
|
| 120 |
+
</div>
|
| 121 |
+
</div>
|
| 122 |
+
|
| 123 |
+
<div id="main">
|
| 124 |
+
<div id="viewer-container">
|
| 125 |
+
<canvas id="three-canvas"></canvas>
|
| 126 |
+
<div id="viewer-label">3D Geology Model — surface voxels colored by lithology</div>
|
| 127 |
+
</div>
|
| 128 |
+
<div id="fields-panel">
|
| 129 |
+
<div class="field-container">
|
| 130 |
+
<div class="field-title">Gravity Field (mGal)</div>
|
| 131 |
+
<div class="field-canvas-wrap">
|
| 132 |
+
<canvas id="grv-canvas"></canvas>
|
| 133 |
+
<div class="colorbar"><span id="grv-max"></span><div class="colorbar-gradient" id="grv-bar"></div><span id="grv-min"></span></div>
|
| 134 |
+
</div>
|
| 135 |
+
</div>
|
| 136 |
+
<div class="field-container">
|
| 137 |
+
<div class="field-title">Magnetic Field (nT)</div>
|
| 138 |
+
<div class="field-canvas-wrap">
|
| 139 |
+
<canvas id="mag-canvas"></canvas>
|
| 140 |
+
<div class="colorbar"><span id="mag-max"></span><div class="colorbar-gradient" id="mag-bar"></div><span id="mag-min"></span></div>
|
| 141 |
+
</div>
|
| 142 |
+
</div>
|
| 143 |
+
</div>
|
| 144 |
+
</div>
|
| 145 |
+
</div>
|
| 146 |
+
|
| 147 |
+
<script type="importmap">
|
| 148 |
+
{"imports":{"three":"https://cdn.jsdelivr.net/npm/three@0.163.0/build/three.module.js","three/addons/":"https://cdn.jsdelivr.net/npm/three@0.163.0/examples/jsm/"}}
|
| 149 |
+
</script>
|
| 150 |
+
|
| 151 |
+
<script type="module">
|
| 152 |
+
import * as THREE from 'three';
|
| 153 |
+
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
|
| 154 |
+
|
| 155 |
+
// ============================================================
|
| 156 |
+
// SPLASH → APP TRANSITION
|
| 157 |
+
// ============================================================
|
| 158 |
+
const splash = document.getElementById('splash');
|
| 159 |
+
const app = document.getElementById('app');
|
| 160 |
+
let appStarted = false;
|
| 161 |
+
|
| 162 |
+
splash.addEventListener('click', () => {
|
| 163 |
+
if (appStarted) return;
|
| 164 |
+
appStarted = true;
|
| 165 |
+
splash.classList.add('hidden');
|
| 166 |
+
app.classList.add('visible');
|
| 167 |
+
// Stop fluid rendering after transition
|
| 168 |
+
setTimeout(() => { fluidRunning = false; }, 1000);
|
| 169 |
+
loadManifest();
|
| 170 |
+
});
|
| 171 |
+
|
| 172 |
+
// ============================================================
|
| 173 |
+
// FLUID SIMULATION (WebGL, runs only on splash)
|
| 174 |
+
// ============================================================
|
| 175 |
+
let fluidRunning = true;
|
| 176 |
+
const FluidSim = (() => {
|
| 177 |
+
const canvas = document.getElementById('fluid-canvas');
|
| 178 |
+
const gl = canvas.getContext('webgl', { alpha: true, premultipliedAlpha: false });
|
| 179 |
+
if (!gl) return { init(){}, loop(){} };
|
| 180 |
+
|
| 181 |
+
const ext = gl.getExtension('OES_texture_half_float');
|
| 182 |
+
gl.getExtension('OES_texture_half_float_linear');
|
| 183 |
+
const halfFloat = ext ? ext.HALF_FLOAT_OES : gl.UNSIGNED_BYTE;
|
| 184 |
+
|
| 185 |
+
let simW = 128, simH = 128, dyeW = 512, dyeH = 512;
|
| 186 |
+
let pointer = { x: 0.5, y: 0.5, dx: 0, dy: 0, moved: false };
|
| 187 |
+
|
| 188 |
+
function resize() {
|
| 189 |
+
canvas.width = canvas.clientWidth; canvas.height = canvas.clientHeight;
|
| 190 |
+
const a = canvas.width / canvas.height;
|
| 191 |
+
simH = Math.round(128 / a); dyeH = Math.round(512 / a);
|
| 192 |
+
}
|
| 193 |
+
|
| 194 |
+
function compileShader(type, src) {
|
| 195 |
+
const s = gl.createShader(type); gl.shaderSource(s, src); gl.compileShader(s); return s;
|
| 196 |
+
}
|
| 197 |
+
function createProgram(vs, fs) {
|
| 198 |
+
const p = gl.createProgram();
|
| 199 |
+
gl.attachShader(p, compileShader(gl.VERTEX_SHADER, vs));
|
| 200 |
+
gl.attachShader(p, compileShader(gl.FRAGMENT_SHADER, fs));
|
| 201 |
+
gl.linkProgram(p);
|
| 202 |
+
const u = {}, n = gl.getProgramParameter(p, gl.ACTIVE_UNIFORMS);
|
| 203 |
+
for (let i = 0; i < n; i++) { const info = gl.getActiveUniform(p, i); u[info.name] = gl.getUniformLocation(p, info.name); }
|
| 204 |
+
return { program: p, uniforms: u };
|
| 205 |
+
}
|
| 206 |
+
|
| 207 |
+
const baseVS = `attribute vec2 aPosition;varying vec2 vUv;varying vec2 vL;varying vec2 vR;varying vec2 vT;varying vec2 vB;uniform vec2 texelSize;
|
| 208 |
+
void main(){vUv=aPosition*0.5+0.5;vL=vUv-vec2(texelSize.x,0);vR=vUv+vec2(texelSize.x,0);
|
| 209 |
+
vT=vUv+vec2(0,texelSize.y);vB=vUv-vec2(0,texelSize.y);gl_Position=vec4(aPosition,0,1);}`;
|
| 210 |
+
const splatFS = `precision highp float;varying vec2 vUv;uniform sampler2D uTarget;uniform float aspectRatio;
|
| 211 |
+
uniform vec3 color;uniform vec2 point;uniform float radius;
|
| 212 |
+
void main(){vec2 p=vUv-point;p.x*=aspectRatio;vec3 s=exp(-dot(p,p)/radius)*color;
|
| 213 |
+
gl_FragColor=vec4(texture2D(uTarget,vUv).xyz+s,1.0);}`;
|
| 214 |
+
const advFS = `precision highp float;varying vec2 vUv;uniform sampler2D uVelocity;uniform sampler2D uSource;
|
| 215 |
+
uniform vec2 texelSize;uniform float dt;uniform float dissipation;
|
| 216 |
+
void main(){vec2 c=vUv-dt*texture2D(uVelocity,vUv).xy*texelSize;gl_FragColor=dissipation*texture2D(uSource,c);gl_FragColor.a=1.0;}`;
|
| 217 |
+
const divFS = `precision highp float;varying vec2 vL;varying vec2 vR;varying vec2 vT;varying vec2 vB;uniform sampler2D uVelocity;
|
| 218 |
+
void main(){float L=texture2D(uVelocity,vL).x;float R=texture2D(uVelocity,vR).x;
|
| 219 |
+
float T=texture2D(uVelocity,vT).y;float B=texture2D(uVelocity,vB).y;gl_FragColor=vec4(0.5*(R-L+T-B),0,0,1);}`;
|
| 220 |
+
const pressFS = `precision highp float;varying vec2 vUv;varying vec2 vL;varying vec2 vR;varying vec2 vT;varying vec2 vB;
|
| 221 |
+
uniform sampler2D uPressure;uniform sampler2D uDivergence;
|
| 222 |
+
void main(){float L=texture2D(uPressure,vL).x;float R=texture2D(uPressure,vR).x;
|
| 223 |
+
float T=texture2D(uPressure,vT).x;float B=texture2D(uPressure,vB).x;
|
| 224 |
+
float d=texture2D(uDivergence,vUv).x;gl_FragColor=vec4((L+R+B+T-d)*0.25,0,0,1);}`;
|
| 225 |
+
const gradFS = `precision highp float;varying vec2 vUv;varying vec2 vL;varying vec2 vR;varying vec2 vT;varying vec2 vB;
|
| 226 |
+
uniform sampler2D uPressure;uniform sampler2D uVelocity;
|
| 227 |
+
void main(){float L=texture2D(uPressure,vL).x;float R=texture2D(uPressure,vR).x;
|
| 228 |
+
float T=texture2D(uPressure,vT).x;float B=texture2D(uPressure,vB).x;
|
| 229 |
+
vec2 v=texture2D(uVelocity,vUv).xy-vec2(R-L,T-B);gl_FragColor=vec4(v,0,1);}`;
|
| 230 |
+
const curlFS = `precision highp float;varying vec2 vL;varying vec2 vR;varying vec2 vT;varying vec2 vB;uniform sampler2D uVelocity;
|
| 231 |
+
void main(){float L=texture2D(uVelocity,vL).y;float R=texture2D(uVelocity,vR).y;
|
| 232 |
+
float T=texture2D(uVelocity,vT).x;float B=texture2D(uVelocity,vB).x;gl_FragColor=vec4(0.5*((R-L)-(T-B)),0,0,1);}`;
|
| 233 |
+
const vortFS = `precision highp float;varying vec2 vUv;varying vec2 vL;varying vec2 vR;varying vec2 vT;varying vec2 vB;
|
| 234 |
+
uniform sampler2D uVelocity;uniform sampler2D uCurl;uniform float curl;uniform vec2 texelSize;
|
| 235 |
+
void main(){float L=texture2D(uCurl,vL).x;float R=texture2D(uCurl,vR).x;
|
| 236 |
+
float T=texture2D(uCurl,vT).x;float B=texture2D(uCurl,vB).x;float C=texture2D(uCurl,vUv).x;
|
| 237 |
+
vec2 f=0.5*vec2(abs(T)-abs(B),abs(R)-abs(L));f/=length(f)+1e-5;f*=curl*C;f.y*=-1.0;
|
| 238 |
+
gl_FragColor=vec4(texture2D(uVelocity,vUv).xy+f*texelSize,0,1);}`;
|
| 239 |
+
const dispFS = `precision highp float;varying vec2 vUv;uniform sampler2D uTexture;
|
| 240 |
+
void main(){vec3 c=texture2D(uTexture,vUv).rgb;gl_FragColor=vec4(c,length(c)*0.7);}`;
|
| 241 |
+
|
| 242 |
+
let splatP, advP, divP, pressP, gradP, dispP, curlP, vortP;
|
| 243 |
+
let velocity, pressure, divergence, dye, curlFBO;
|
| 244 |
+
|
| 245 |
+
function createFBO(w, h) {
|
| 246 |
+
const t = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, t);
|
| 247 |
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
| 248 |
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
| 249 |
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
| 250 |
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
| 251 |
+
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, w, h, 0, gl.RGBA, halfFloat, null);
|
| 252 |
+
const fb = gl.createFramebuffer(); gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
|
| 253 |
+
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, t, 0);
|
| 254 |
+
gl.viewport(0, 0, w, h); gl.clear(gl.COLOR_BUFFER_BIT);
|
| 255 |
+
return { texture: t, fb, w, h };
|
| 256 |
+
}
|
| 257 |
+
function createDoubleFBO(w, h) {
|
| 258 |
+
let a = createFBO(w, h), b = createFBO(w, h);
|
| 259 |
+
return { get read(){ return a; }, get write(){ return b; }, swap(){ const t=a;a=b;b=t; } };
|
| 260 |
+
}
|
| 261 |
+
function blit(tgt) {
|
| 262 |
+
if (tgt) { gl.bindFramebuffer(gl.FRAMEBUFFER, tgt.fb); gl.viewport(0,0,tgt.w,tgt.h); }
|
| 263 |
+
else { gl.bindFramebuffer(gl.FRAMEBUFFER, null); gl.viewport(0,0,canvas.width,canvas.height); }
|
| 264 |
+
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
| 265 |
+
}
|
| 266 |
+
|
| 267 |
+
function init() {
|
| 268 |
+
resize();
|
| 269 |
+
const buf = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, buf);
|
| 270 |
+
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1,-1,1,-1,-1,1,1,1]), gl.STATIC_DRAW);
|
| 271 |
+
gl.enableVertexAttribArray(0); gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
|
| 272 |
+
splatP=createProgram(baseVS,splatFS); advP=createProgram(baseVS,advFS);
|
| 273 |
+
divP=createProgram(baseVS,divFS); pressP=createProgram(baseVS,pressFS);
|
| 274 |
+
gradP=createProgram(baseVS,gradFS); dispP=createProgram(baseVS,dispFS);
|
| 275 |
+
curlP=createProgram(baseVS,curlFS); vortP=createProgram(baseVS,vortFS);
|
| 276 |
+
velocity=createDoubleFBO(simW,simH); pressure=createDoubleFBO(simW,simH);
|
| 277 |
+
divergence=createFBO(simW,simH); curlFBO=createFBO(simW,simH); dye=createDoubleFBO(dyeW,dyeH);
|
| 278 |
+
}
|
| 279 |
+
|
| 280 |
+
function doSplat(x, y, dx, dy, color) {
|
| 281 |
+
gl.useProgram(splatP.program);
|
| 282 |
+
gl.uniform1i(splatP.uniforms.uTarget,0); gl.uniform1f(splatP.uniforms.aspectRatio,canvas.width/canvas.height);
|
| 283 |
+
gl.uniform2f(splatP.uniforms.point,x,y); gl.uniform3f(splatP.uniforms.color,dx,dy,0);
|
| 284 |
+
gl.uniform1f(splatP.uniforms.radius,0.0003);
|
| 285 |
+
gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D,velocity.read.texture);
|
| 286 |
+
blit(velocity.write); velocity.swap();
|
| 287 |
+
gl.uniform3fv(splatP.uniforms.color,color); gl.uniform1f(splatP.uniforms.radius,0.005);
|
| 288 |
+
gl.bindTexture(gl.TEXTURE_2D,dye.read.texture); blit(dye.write); dye.swap();
|
| 289 |
+
}
|
| 290 |
+
|
| 291 |
+
function step(dt) {
|
| 292 |
+
gl.disable(gl.BLEND);
|
| 293 |
+
const sTS=[1/simW,1/simH], dTS=[1/dyeW,1/dyeH];
|
| 294 |
+
// Curl
|
| 295 |
+
gl.useProgram(curlP.program); gl.uniform2fv(curlP.uniforms.texelSize,sTS);
|
| 296 |
+
gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D,velocity.read.texture);
|
| 297 |
+
gl.uniform1i(curlP.uniforms.uVelocity,0); blit(curlFBO);
|
| 298 |
+
// Vorticity
|
| 299 |
+
gl.useProgram(vortP.program); gl.uniform2fv(vortP.uniforms.texelSize,sTS); gl.uniform1f(vortP.uniforms.curl,20);
|
| 300 |
+
gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D,velocity.read.texture); gl.uniform1i(vortP.uniforms.uVelocity,0);
|
| 301 |
+
gl.activeTexture(gl.TEXTURE1); gl.bindTexture(gl.TEXTURE_2D,curlFBO.texture); gl.uniform1i(vortP.uniforms.uCurl,1);
|
| 302 |
+
blit(velocity.write); velocity.swap();
|
| 303 |
+
// Advect velocity
|
| 304 |
+
gl.useProgram(advP.program); gl.uniform2fv(advP.uniforms.texelSize,sTS);
|
| 305 |
+
gl.uniform1f(advP.uniforms.dt,dt); gl.uniform1f(advP.uniforms.dissipation,1.0);
|
| 306 |
+
gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D,velocity.read.texture); gl.uniform1i(advP.uniforms.uVelocity,0);
|
| 307 |
+
gl.activeTexture(gl.TEXTURE1); gl.bindTexture(gl.TEXTURE_2D,velocity.read.texture); gl.uniform1i(advP.uniforms.uSource,1);
|
| 308 |
+
blit(velocity.write); velocity.swap();
|
| 309 |
+
// Advect dye
|
| 310 |
+
gl.uniform2fv(advP.uniforms.texelSize,dTS); gl.uniform1f(advP.uniforms.dissipation,0.97);
|
| 311 |
+
gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D,velocity.read.texture);
|
| 312 |
+
gl.activeTexture(gl.TEXTURE1); gl.bindTexture(gl.TEXTURE_2D,dye.read.texture); gl.uniform1i(advP.uniforms.uSource,1);
|
| 313 |
+
blit(dye.write); dye.swap();
|
| 314 |
+
// Divergence
|
| 315 |
+
gl.useProgram(divP.program); gl.uniform2fv(divP.uniforms.texelSize,sTS);
|
| 316 |
+
gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D,velocity.read.texture); gl.uniform1i(divP.uniforms.uVelocity,0);
|
| 317 |
+
blit(divergence);
|
| 318 |
+
// Pressure
|
| 319 |
+
gl.useProgram(pressP.program); gl.uniform2fv(pressP.uniforms.texelSize,sTS);
|
| 320 |
+
gl.activeTexture(gl.TEXTURE1); gl.bindTexture(gl.TEXTURE_2D,divergence.texture); gl.uniform1i(pressP.uniforms.uDivergence,1);
|
| 321 |
+
for(let i=0;i<6;i++){gl.activeTexture(gl.TEXTURE0);gl.bindTexture(gl.TEXTURE_2D,pressure.read.texture);
|
| 322 |
+
gl.uniform1i(pressP.uniforms.uPressure,0);blit(pressure.write);pressure.swap();}
|
| 323 |
+
// Gradient subtract
|
| 324 |
+
gl.useProgram(gradP.program); gl.uniform2fv(gradP.uniforms.texelSize,sTS);
|
| 325 |
+
gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D,pressure.read.texture); gl.uniform1i(gradP.uniforms.uPressure,0);
|
| 326 |
+
gl.activeTexture(gl.TEXTURE1); gl.bindTexture(gl.TEXTURE_2D,velocity.read.texture); gl.uniform1i(gradP.uniforms.uVelocity,1);
|
| 327 |
+
blit(velocity.write); velocity.swap();
|
| 328 |
+
// Display
|
| 329 |
+
gl.enable(gl.BLEND); gl.blendFunc(gl.SRC_ALPHA,gl.ONE_MINUS_SRC_ALPHA);
|
| 330 |
+
gl.useProgram(dispP.program); gl.activeTexture(gl.TEXTURE0);
|
| 331 |
+
gl.bindTexture(gl.TEXTURE_2D,dye.read.texture); gl.uniform1i(dispP.uniforms.uTexture,0); blit(null);
|
| 332 |
+
}
|
| 333 |
+
|
| 334 |
+
let lastT = 0;
|
| 335 |
+
function loop(time) {
|
| 336 |
+
if (!fluidRunning) return;
|
| 337 |
+
const dt = Math.min((time - lastT) / 1000, 0.016); lastT = time;
|
| 338 |
+
if (pointer.moved) {
|
| 339 |
+
doSplat(pointer.x, pointer.y, pointer.dx*8, pointer.dy*8, [0.15, 0.0, 0.6]);
|
| 340 |
+
pointer.moved = false;
|
| 341 |
+
}
|
| 342 |
+
step(dt || 0.016);
|
| 343 |
+
requestAnimationFrame(loop);
|
| 344 |
+
}
|
| 345 |
+
|
| 346 |
+
window.addEventListener('resize', () => {
|
| 347 |
+
if (!fluidRunning) return;
|
| 348 |
+
resize(); velocity=createDoubleFBO(simW,simH); pressure=createDoubleFBO(simW,simH);
|
| 349 |
+
divergence=createFBO(simW,simH); curlFBO=createFBO(simW,simH); dye=createDoubleFBO(dyeW,dyeH);
|
| 350 |
+
});
|
| 351 |
+
document.addEventListener('mousemove', e => {
|
| 352 |
+
const x=e.clientX/canvas.width, y=1-e.clientY/canvas.height;
|
| 353 |
+
pointer.dx=(x-pointer.x)*10; pointer.dy=(y-pointer.y)*10;
|
| 354 |
+
pointer.x=x; pointer.y=y; pointer.moved=true;
|
| 355 |
+
});
|
| 356 |
+
document.addEventListener('touchmove', e => {
|
| 357 |
+
e.preventDefault(); const t=e.touches[0];
|
| 358 |
+
const x=t.clientX/canvas.width, y=1-t.clientY/canvas.height;
|
| 359 |
+
pointer.dx=(x-pointer.x)*10; pointer.dy=(y-pointer.y)*10;
|
| 360 |
+
pointer.x=x; pointer.y=y; pointer.moved=true;
|
| 361 |
+
}, { passive: false });
|
| 362 |
+
|
| 363 |
+
return { init, loop };
|
| 364 |
+
})();
|
| 365 |
+
|
| 366 |
+
FluidSim.init();
|
| 367 |
+
requestAnimationFrame(FluidSim.loop);
|
| 368 |
+
|
| 369 |
+
// ============================================================
|
| 370 |
+
// COLORS
|
| 371 |
+
// ============================================================
|
| 372 |
+
const LITH_COLORS = [
|
| 373 |
+
null,
|
| 374 |
+
[0.26,0.52,0.96],[0.94,0.40,0.27],[0.30,0.78,0.47],[0.90,0.70,0.20],
|
| 375 |
+
[0.70,0.35,0.85],[0.20,0.82,0.82],[0.92,0.50,0.70],[0.55,0.75,0.30],
|
| 376 |
+
[0.98,0.60,0.40],[0.45,0.55,0.90],[0.80,0.80,0.30],[0.40,0.70,0.70],
|
| 377 |
+
[0.85,0.45,0.55],[0.60,0.60,0.40],[0.55,0.40,0.70],[0.75,0.55,0.35],
|
| 378 |
+
[0.35,0.65,0.55],[0.80,0.35,0.35],[0.50,0.80,0.60],[0.70,0.50,0.80],
|
| 379 |
+
];
|
| 380 |
+
|
| 381 |
+
// ============================================================
|
| 382 |
+
// THREE.JS 3D VIEWER
|
| 383 |
+
// ============================================================
|
| 384 |
+
const GRID = 50;
|
| 385 |
+
const threeCanvas = document.getElementById('three-canvas');
|
| 386 |
+
const renderer = new THREE.WebGLRenderer({ canvas: threeCanvas, antialias: true });
|
| 387 |
+
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
|
| 388 |
+
renderer.setClearColor(0xf8f9fc, 1);
|
| 389 |
+
|
| 390 |
+
const scene = new THREE.Scene();
|
| 391 |
+
const camera = new THREE.PerspectiveCamera(45, 1, 0.1, 300);
|
| 392 |
+
camera.position.set(70, 55, 70);
|
| 393 |
+
const controls = new OrbitControls(camera, threeCanvas);
|
| 394 |
+
controls.enableDamping = true; controls.dampingFactor = 0.08;
|
| 395 |
+
controls.target.set(GRID/2, GRID/2, GRID/2); controls.update();
|
| 396 |
+
|
| 397 |
+
scene.add(new THREE.AmbientLight(0xffffff, 0.6));
|
| 398 |
+
const d1 = new THREE.DirectionalLight(0xffffff, 0.8); d1.position.set(60, 90, 70); scene.add(d1);
|
| 399 |
+
const d2 = new THREE.DirectionalLight(0x8888cc, 0.3); d2.position.set(-40, -20, -40); scene.add(d2);
|
| 400 |
+
|
| 401 |
+
// Wireframe bounding box
|
| 402 |
+
const boxGeo = new THREE.BoxGeometry(GRID, GRID, GRID);
|
| 403 |
+
const boxEdge = new THREE.LineSegments(
|
| 404 |
+
new THREE.EdgesGeometry(boxGeo),
|
| 405 |
+
new THREE.LineBasicMaterial({ color: 0xccccdd })
|
| 406 |
+
);
|
| 407 |
+
boxEdge.position.set(GRID/2, GRID/2, GRID/2);
|
| 408 |
+
scene.add(boxEdge);
|
| 409 |
+
|
| 410 |
+
// Axis labels
|
| 411 |
+
function makeLabel(text, pos) {
|
| 412 |
+
const c = document.createElement('canvas'); c.width=64; c.height=32;
|
| 413 |
+
const ctx = c.getContext('2d'); ctx.fillStyle='#6b7084'; ctx.font='bold 20px Inter,sans-serif';
|
| 414 |
+
ctx.textAlign='center'; ctx.textBaseline='middle'; ctx.fillText(text,32,16);
|
| 415 |
+
const tex = new THREE.CanvasTexture(c);
|
| 416 |
+
const sp = new THREE.Sprite(new THREE.SpriteMaterial({map:tex,transparent:true}));
|
| 417 |
+
sp.position.copy(pos); sp.scale.set(6,3,1); scene.add(sp);
|
| 418 |
+
}
|
| 419 |
+
makeLabel('X', new THREE.Vector3(GRID/2, -4, -4));
|
| 420 |
+
makeLabel('Y', new THREE.Vector3(-4, -4, GRID/2));
|
| 421 |
+
makeLabel('Depth', new THREE.Vector3(-6, GRID/2, -4));
|
| 422 |
+
|
| 423 |
+
let currentMesh = null;
|
| 424 |
+
|
| 425 |
+
function render3D() {
|
| 426 |
+
requestAnimationFrame(render3D); controls.update();
|
| 427 |
+
const rect = threeCanvas.parentElement.getBoundingClientRect();
|
| 428 |
+
const w = rect.width, h = rect.height;
|
| 429 |
+
if (threeCanvas.width !== w*renderer.getPixelRatio() || threeCanvas.height !== h*renderer.getPixelRatio()) {
|
| 430 |
+
renderer.setSize(w, h, false); camera.aspect = w/h; camera.updateProjectionMatrix();
|
| 431 |
+
}
|
| 432 |
+
renderer.render(scene, camera);
|
| 433 |
+
}
|
| 434 |
+
render3D();
|
| 435 |
+
|
| 436 |
+
function loadVoxels(data) {
|
| 437 |
+
if (currentMesh) { scene.remove(currentMesh); currentMesh.geometry.dispose(); currentMesh.material.dispose(); }
|
| 438 |
+
const { surfaceVoxels, nClasses } = data;
|
| 439 |
+
const n = surfaceVoxels.length / 4;
|
| 440 |
+
const geo = new THREE.BoxGeometry(1, 1, 1);
|
| 441 |
+
const mat = new THREE.MeshPhongMaterial({ vertexColors: true, shininess: 40 });
|
| 442 |
+
const mesh = new THREE.InstancedMesh(geo, mat, n);
|
| 443 |
+
const dummy = new THREE.Object3D();
|
| 444 |
+
const color = new THREE.Color();
|
| 445 |
+
|
| 446 |
+
for (let i = 0; i < n; i++) {
|
| 447 |
+
// Binary stores: [dim0, dim1, dim2, class]
|
| 448 |
+
// dim0 = depth layers (0=top), dim1 = northing(Y), dim2 = easting(X)
|
| 449 |
+
// Three.js: X=easting, Y=up(inverted depth), Z=northing
|
| 450 |
+
const dim0 = surfaceVoxels[i * 4]; // depth
|
| 451 |
+
const dim1 = surfaceVoxels[i * 4 + 1]; // northing
|
| 452 |
+
const dim2 = surfaceVoxels[i * 4 + 2]; // easting
|
| 453 |
+
const cls = surfaceVoxels[i * 4 + 3];
|
| 454 |
+
|
| 455 |
+
dummy.position.set(dim2 + 0.5, (GRID - 1 - dim0) + 0.5, dim1 + 0.5);
|
| 456 |
+
dummy.updateMatrix();
|
| 457 |
+
mesh.setMatrixAt(i, dummy.matrix);
|
| 458 |
+
const c = LITH_COLORS[cls] || [0.5, 0.5, 0.5];
|
| 459 |
+
color.setRGB(c[0], c[1], c[2]);
|
| 460 |
+
mesh.setColorAt(i, color);
|
| 461 |
+
}
|
| 462 |
+
mesh.instanceMatrix.needsUpdate = true;
|
| 463 |
+
mesh.instanceColor.needsUpdate = true;
|
| 464 |
+
scene.add(mesh);
|
| 465 |
+
currentMesh = mesh;
|
| 466 |
+
|
| 467 |
+
document.getElementById('info-voxels').textContent = n.toLocaleString();
|
| 468 |
+
document.getElementById('info-classes').textContent = nClasses;
|
| 469 |
+
const legend = document.getElementById('legend'); legend.innerHTML = '';
|
| 470 |
+
for (let i = 1; i <= nClasses; i++) {
|
| 471 |
+
const c = LITH_COLORS[i] || [0.5,0.5,0.5];
|
| 472 |
+
const div = document.createElement('div'); div.className = 'legend-item';
|
| 473 |
+
div.innerHTML = `<span class="legend-swatch" style="background:rgb(${c[0]*255|0},${c[1]*255|0},${c[2]*255|0})"></span>${i}`;
|
| 474 |
+
legend.appendChild(div);
|
| 475 |
+
}
|
| 476 |
+
}
|
| 477 |
+
|
| 478 |
+
// ============================================================
|
| 479 |
+
// HEATMAPS
|
| 480 |
+
// ============================================================
|
| 481 |
+
function viridis(t) {
|
| 482 |
+
t = Math.max(0, Math.min(1, t));
|
| 483 |
+
return [Math.max(0,Math.min(255,(68+t*(1-t)*600-t*t*350)|0)),
|
| 484 |
+
Math.max(0,Math.min(255,(2+t*330-t*t*130)|0)),
|
| 485 |
+
Math.max(0,Math.min(255,(85+t*180-t*t*350+t*t*t*200)|0))];
|
| 486 |
+
}
|
| 487 |
+
function magma(t) {
|
| 488 |
+
t = Math.max(0, Math.min(1, t));
|
| 489 |
+
return [Math.max(0,Math.min(255,(1+t*780-t*t*500+t*t*t*200)|0)),
|
| 490 |
+
Math.max(0,Math.min(255,(0+t*50+t*t*500-t*t*t*350)|0)),
|
| 491 |
+
Math.max(0,Math.min(255,(40+t*560-t*t*900+t*t*t*550)|0))];
|
| 492 |
+
}
|
| 493 |
+
|
| 494 |
+
function renderHeatmap(canvasId, data, rows, cols, cmap, barId, minId, maxId) {
|
| 495 |
+
const canvas = document.getElementById(canvasId);
|
| 496 |
+
canvas.width = cols; canvas.height = rows;
|
| 497 |
+
const ctx = canvas.getContext('2d');
|
| 498 |
+
const img = ctx.createImageData(cols, rows);
|
| 499 |
+
let min = Infinity, max = -Infinity;
|
| 500 |
+
for (let i = 0; i < data.length; i++) { if(data[i]<min)min=data[i]; if(data[i]>max)max=data[i]; }
|
| 501 |
+
const range = max - min || 1;
|
| 502 |
+
for (let i = 0; i < data.length; i++) {
|
| 503 |
+
const [r,g,b] = cmap((data[i]-min)/range);
|
| 504 |
+
img.data[i*4]=r; img.data[i*4+1]=g; img.data[i*4+2]=b; img.data[i*4+3]=255;
|
| 505 |
+
}
|
| 506 |
+
ctx.putImageData(img, 0, 0);
|
| 507 |
+
document.getElementById(minId).textContent = min.toFixed(1);
|
| 508 |
+
document.getElementById(maxId).textContent = max.toFixed(1);
|
| 509 |
+
const bar = document.getElementById(barId);
|
| 510 |
+
let grad = 'linear-gradient(to bottom,';
|
| 511 |
+
for (let i = 0; i <= 20; i++) {
|
| 512 |
+
const [r,g,b] = cmap(1-i/20);
|
| 513 |
+
grad += `rgb(${r},${g},${b})${i<20?',':''}`;
|
| 514 |
+
}
|
| 515 |
+
bar.style.background = grad + ')';
|
| 516 |
+
}
|
| 517 |
+
|
| 518 |
+
// ============================================================
|
| 519 |
+
// DATA LOADING
|
| 520 |
+
// ============================================================
|
| 521 |
+
let manifest = null;
|
| 522 |
+
|
| 523 |
+
async function loadManifest() {
|
| 524 |
+
const resp = await fetch('data/manifest.json');
|
| 525 |
+
manifest = await resp.json();
|
| 526 |
+
const typeSelect = document.getElementById('type-select');
|
| 527 |
+
Object.keys(manifest.types).forEach(type => {
|
| 528 |
+
const opt = document.createElement('option'); opt.value = type;
|
| 529 |
+
opt.textContent = type.replace(/_/g, ' \u2192 ').replace(/SHEAR-ZONE/g,'SHEAR ZONE');
|
| 530 |
+
typeSelect.appendChild(opt);
|
| 531 |
+
});
|
| 532 |
+
typeSelect.addEventListener('change', populateSamples);
|
| 533 |
+
document.getElementById('sample-select').addEventListener('change', loadSample);
|
| 534 |
+
populateSamples();
|
| 535 |
+
}
|
| 536 |
+
|
| 537 |
+
function populateSamples() {
|
| 538 |
+
const type = document.getElementById('type-select').value;
|
| 539 |
+
const sel = document.getElementById('sample-select'); sel.innerHTML = '';
|
| 540 |
+
manifest.types[type].forEach((name, i) => {
|
| 541 |
+
const opt = document.createElement('option'); opt.value = name;
|
| 542 |
+
opt.textContent = `Sample ${i+1}`; sel.appendChild(opt);
|
| 543 |
+
});
|
| 544 |
+
loadSample();
|
| 545 |
+
}
|
| 546 |
+
|
| 547 |
+
async function loadSample() {
|
| 548 |
+
const fileName = document.getElementById('sample-select').value;
|
| 549 |
+
if (!fileName) return;
|
| 550 |
+
const bar = document.getElementById('loading-bar');
|
| 551 |
+
bar.classList.remove('hidden'); bar.style.width = '30%';
|
| 552 |
+
|
| 553 |
+
try {
|
| 554 |
+
const resp = await fetch(`data/${fileName}`);
|
| 555 |
+
bar.style.width = '70%';
|
| 556 |
+
const buf = await resp.arrayBuffer();
|
| 557 |
+
bar.style.width = '90%';
|
| 558 |
+
const view = new DataView(buf);
|
| 559 |
+
let off = 0;
|
| 560 |
+
const nSurface = view.getUint32(off,true); off+=4;
|
| 561 |
+
const grvR = view.getUint32(off,true); off+=4;
|
| 562 |
+
const grvC = view.getUint32(off,true); off+=4;
|
| 563 |
+
const magR = view.getUint32(off,true); off+=4;
|
| 564 |
+
const magC = view.getUint32(off,true); off+=4;
|
| 565 |
+
const nCls = view.getUint32(off,true); off+=4;
|
| 566 |
+
const sv = new Uint8Array(buf, off, nSurface*4); off += nSurface*4;
|
| 567 |
+
const grv = new Float32Array(buf, off, grvR*grvC); off += grvR*grvC*4;
|
| 568 |
+
const mag = new Float32Array(buf, off, magR*magC);
|
| 569 |
+
|
| 570 |
+
loadVoxels({ surfaceVoxels: sv, nClasses: nCls });
|
| 571 |
+
renderHeatmap('grv-canvas', grv, grvR, grvC, viridis, 'grv-bar', 'grv-min', 'grv-max');
|
| 572 |
+
renderHeatmap('mag-canvas', mag, magR, magC, magma, 'mag-bar', 'mag-min', 'mag-max');
|
| 573 |
+
bar.style.width = '100%';
|
| 574 |
+
} catch(e) { console.error('Load failed:', e); }
|
| 575 |
+
setTimeout(() => { bar.style.width = '0%'; bar.classList.add('hidden'); }, 400);
|
| 576 |
+
}
|
| 577 |
+
</script>
|
| 578 |
+
</body>
|
| 579 |
</html>
|