diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 2d739a43d1e0784d5d0852a8d20ff77791ceb09b..7cc6fad00f3cf9a30bb4f9582787bd3cea96076c 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -398,35 +398,26 @@ webassembly:test:
         - webassembly:build
 
 ## Webassembly package
-webassembly-wheel:package:
+webassembly:package:
     extends:
         - .webassembly
-        - .cmake_package_webassembly_wheel_linux
+        - .cmake_package_webassembly_linux
         - .linux_packager_tags
-        - .cmake_webassembly_wheel_artifacts
+        - .cmake_webassembly_artifacts
         - .run_automatically
     dependencies:
         - webassembly:build
     needs:
         - webassembly:build
 
-webassembly-wheel:pypi:upload:
+webassembly:vtk:upload:
     extends:
-        - .pypi_webassembly_upload
-        - .tag_only
-    dependencies:
-        - webassembly-wheel:package
-    needs:
-        - webassembly-wheel:package
-
-webassembly-wheel:vtk:upload:
-    extends:
-        - .pypi_webassembly_vtk_upload
+        - .generic_webassembly_vtk_upload
         - .weekly_upload_only
     dependencies:
-        - webassembly-wheel:package
+        - webassembly:package
     needs:
-        - webassembly-wheel:package
+        - webassembly:package
 
 ## Python wheel builds
 
diff --git a/.gitlab/artifacts.yml b/.gitlab/artifacts.yml
index fe11fba8bf2effc1a9215074f562971eb41b8586..7dbc0b48762e0b94954ef6d017671bdbcc63255a 100644
--- a/.gitlab/artifacts.yml
+++ b/.gitlab/artifacts.yml
@@ -73,9 +73,6 @@
             # SPDX files
             - build/**/*.spdx
 
-            # WebAssembly
-            - build/Web/WebAssembly/
-
 .cmake_junit_artifacts:
     artifacts:
         expire_in: 1d
@@ -151,13 +148,12 @@
             - build/*-wheel-sdk-*.tar.xz
             - build/cdash-build-id
 
-.cmake_webassembly_wheel_artifacts:
+.cmake_webassembly_artifacts:
     artifacts:
         expire_in: 1d
         when: always
         paths:
-            - build/Web/WebAssembly/Wheel/dist/*.whl
-            - build/Web/WebAssembly/Wheel/dist/*.tar.gz
+            - build/bin/vtk-wasm*.tar.gz
 
 .cmake_release_artifacts:
     artifacts:
diff --git a/.gitlab/ci/create_webassembly_archive.sh b/.gitlab/ci/create_webassembly_archive.sh
new file mode 100755
index 0000000000000000000000000000000000000000..2b8385a865424bef21b66e0bbd47088244a4305c
--- /dev/null
+++ b/.gitlab/ci/create_webassembly_archive.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+set -e
+set -x
+
+version=$( node --eval "import('./build/bin/vtkWasmSceneManager.mjs').then(m => m.default().then(i => console.log(i.getVTKVersion())))" )
+readonly version
+
+cd build/bin
+tar -cvzf "vtk-wasm.$version.tar.gz" ./vtkWasmSceneManager.*
+cd ../../
diff --git a/.gitlab/ci/upload_webassembly_archive.sh b/.gitlab/ci/upload_webassembly_archive.sh
new file mode 100755
index 0000000000000000000000000000000000000000..6faecd351d2ba0a1e87bcc64f1d423128c2bac23
--- /dev/null
+++ b/.gitlab/ci/upload_webassembly_archive.sh
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+set -e
+set -x
+
+version=$( node --eval "import('./build/bin/vtkWasmSceneManager.mjs').then(m => m.default().then(i => console.log(i.getVTKVersion())))" )
+readonly version
+readonly package_name="vtk-wasm"
+
+cd build/bin
+curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file "$package_name.$version.tar.gz" "$CI_API_V4_URL/projects/$CI_PROJECT_ID/packages/generic/$package_name/$version/$package_name.$version.tar.gz"
+cd ../../
diff --git a/.gitlab/os-linux.yml b/.gitlab/os-linux.yml
index 9d0efd4928d9426a551c21c6346acef13c719dbb..cfb6bd84c0a2696f3c0b1a15946ba2ae3a98eaea 100644
--- a/.gitlab/os-linux.yml
+++ b/.gitlab/os-linux.yml
@@ -699,19 +699,11 @@
 
     interruptible: true
 
-.cmake_package_webassembly_wheel_linux:
+.cmake_package_webassembly_linux:
     stage: package
 
     script:
-        - apt update
-        - apt install -y python3.10-venv
-        - find build/bin/ -regex '.*\.\(js\|mjs\|wasm\)$' -exec cp -v {} build/Web/WebAssembly/Wheel/vtk_wasm/ \;
-        - cd build/Web/WebAssembly/Wheel
-        - python -m venv venv
-        - . venv/bin/activate
-        - python -m pip install --upgrade --no-cache-dir pip setuptools
-        - python -m pip install build
-        - python -m build .
+        - .gitlab/ci/create_webassembly_archive.sh
 
     interruptible: true
 
diff --git a/.gitlab/upload.yml b/.gitlab/upload.yml
index 7752d16d2a1b4d99b200225ce507f0a63910a60a..06c25235b13da577825e65e2cf36787ac2f478a5 100644
--- a/.gitlab/upload.yml
+++ b/.gitlab/upload.yml
@@ -71,23 +71,7 @@
         - dnf install -y --setopt=install_weak_deps=False twine
         - twine upload -u gitlab-ci-token -p $CI_JOB_TOKEN --repository-url https://gitlab.kitware.com/api/v4/projects/$CI_PROJECT_ID/packages/pypi dist/*
 
-.pypi_webassembly_upload:
-    image: "fedora:34"
-    stage: upload
-    tags:
-        - docker
-        - linux-x86_64
-        - build
-    environment:
-        name: pypi-upload
-
-    script:
-        - cd build/Web/WebAssembly/Wheel
-        - ls dist
-        - dnf install -y --setopt=install_weak_deps=False twine
-        - twine upload -u __token__ -p $PYPI_UPLOAD_TOKEN dist/* # can the same token be used?
-
-.pypi_webassembly_vtk_upload:
+.generic_webassembly_vtk_upload:
     image: "fedora:34"
     stage: upload
     tags:
@@ -96,7 +80,4 @@
         - build
 
     script:
-        - cd build/Web/WebAssembly/Wheel
-        - ls dist
-        - dnf install -y --setopt=install_weak_deps=False twine
-        - twine upload -u gitlab-ci-token -p $CI_JOB_TOKEN --repository-url https://gitlab.kitware.com/api/v4/projects/$CI_PROJECT_ID/packages/pypi dist/*
+        - .gitlab/ci/upload_webassembly_archive.sh
diff --git a/Web/WebAssembly/CMakeLists.txt b/Web/WebAssembly/CMakeLists.txt
index 7f33f84bf3a32c35c95d11c36302f41cf1a46fc4..8b13e97b4eaccc3956130e1f4c1de7210bb95c61 100644
--- a/Web/WebAssembly/CMakeLists.txt
+++ b/Web/WebAssembly/CMakeLists.txt
@@ -11,17 +11,6 @@ vtk_module_add_module(VTK::WebAssembly
 
 vtk_add_test_mangling(VTK::WebAssembly)
 
-configure_file("Packaging/Wheel/__init__.py.in"
-  "${CMAKE_CURRENT_BINARY_DIR}/Wheel/vtk_wasm/__init__.py")
-configure_file("Packaging/Wheel/MANIFEST.in.in"
-  "${CMAKE_CURRENT_BINARY_DIR}/Wheel/MANIFEST.in")
-configure_file("Packaging/Wheel/README.md.in"
-  "${CMAKE_CURRENT_BINARY_DIR}/Wheel/README.md")
-configure_file("Packaging/Wheel/setup.cfg.in"
-  "${CMAKE_CURRENT_BINARY_DIR}/Wheel/setup.cfg")
-configure_file("Packaging/Wheel/setup.py.in"
-  "${CMAKE_CURRENT_BINARY_DIR}/Wheel/setup.py")
-
 # -----------------------------------------------------------------------------
 # Emscripten compile+link options
 # -----------------------------------------------------------------------------
@@ -107,10 +96,10 @@ target_link_options(WasmSceneManager
     ${emscripten_debug_options})
 set_target_properties(WasmSceneManager
   PROPERTIES
+  OUTPUT_NAME "vtkWasmSceneManager"
   SUFFIX ".mjs")
 # [cmake/cmake#20745](https://gitlab.kitware.com/cmake/cmake/-/issues/20745)
 # CMake doesn't install multiple files associated with an executable target.
-get_target_property(_vtk_scene_manager_version_suffix WebAssembly VERSION)
 install(FILES
-  "$<TARGET_FILE_DIR:WasmSceneManager>/vtkWasmSceneManager-${_vtk_scene_manager_version_suffix}.wasm"
+  "$<TARGET_FILE_DIR:WasmSceneManager>/vtkWasmSceneManager.wasm"
   DESTINATION ${CMAKE_INSTALL_BINDIR})
diff --git a/Web/WebAssembly/Packaging/Wheel/MANIFEST.in.in b/Web/WebAssembly/Packaging/Wheel/MANIFEST.in.in
deleted file mode 100644
index 7ad8585a49c324dfefc81a2666783b7d7d75ef36..0000000000000000000000000000000000000000
--- a/Web/WebAssembly/Packaging/Wheel/MANIFEST.in.in
+++ /dev/null
@@ -1 +0,0 @@
-graft vtk_wasm
diff --git a/Web/WebAssembly/Packaging/Wheel/README.md.in b/Web/WebAssembly/Packaging/Wheel/README.md.in
deleted file mode 100644
index 0f177166f7afadb686094f2db55038a39692b9a0..0000000000000000000000000000000000000000
--- a/Web/WebAssembly/Packaging/Wheel/README.md.in
+++ /dev/null
@@ -1,3 +0,0 @@
-# vtk-wasm
-
-VTK WebAssembly binaries with glue javacript libraries.
diff --git a/Web/WebAssembly/Packaging/Wheel/__init__.py.in b/Web/WebAssembly/Packaging/Wheel/__init__.py.in
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/Web/WebAssembly/Packaging/Wheel/setup.cfg.in b/Web/WebAssembly/Packaging/Wheel/setup.cfg.in
deleted file mode 100644
index 63da35c0a04d468fd6803d21d721b73a49ee3281..0000000000000000000000000000000000000000
--- a/Web/WebAssembly/Packaging/Wheel/setup.cfg.in
+++ /dev/null
@@ -1,30 +0,0 @@
-[metadata]
-name = vtk-wasm
-version = @VTK_VERSION@
-description = VTK WebAssembly binaries with glue javacript libraries
-long_description = file: README.md
-long_description_content_type = text/x-md
-author = Kitware Inc.
-license = BSD License
-classifiers =
-    Environment :: Web Environment
-    License :: OSI Approved :: BSD License
-    Natural Language :: English
-    Operating System :: OS Independent
-    Programming Language :: JavaScript
-    Programming Language :: C++
-    Topic :: Software Development :: Libraries :: Application Frameworks
-    Topic :: Software Development :: Libraries :: Python Modules
-keywords =
-    WebAssembly
-    Web
-    Visualization
-
-[options]
-packages = find:
-include_package_data = True
-install_requires =
-    vtk==@VTK_MAJOR_VERSION@.@VTK_MINOR_VERSION@.*
-
-[semantic_release]
-version_pattern = setup.cfg:version = (\d+\.\d+\.\d+)
diff --git a/Web/WebAssembly/Packaging/Wheel/setup.py.in b/Web/WebAssembly/Packaging/Wheel/setup.py.in
deleted file mode 100644
index 606849326a4002007fd42060b51e69a19c18675c..0000000000000000000000000000000000000000
--- a/Web/WebAssembly/Packaging/Wheel/setup.py.in
+++ /dev/null
@@ -1,3 +0,0 @@
-from setuptools import setup
-
-setup()
diff --git a/Web/WebAssembly/Testing/JavaScript/CMakeLists.txt b/Web/WebAssembly/Testing/JavaScript/CMakeLists.txt
index 9e45a96cd06c06b9e79404a709870a535f57843d..57f2ece1e23cf38771f6edf0542ca7d40fd6bf16 100644
--- a/Web/WebAssembly/Testing/JavaScript/CMakeLists.txt
+++ b/Web/WebAssembly/Testing/JavaScript/CMakeLists.txt
@@ -3,7 +3,7 @@ find_package(NodeJS "${vtk_nodejs_min_version}" REQUIRED)
 set(_vtk_testing_nodejs_exe "${NodeJS_INTERPRETER}")
 
 set(_vtk_node_args
-  --import "${PROJECT_BINARY_DIR}/bin/vtkWasmSceneManager-${VTK_MAJOR_VERSION}.${VTK_MINOR_VERSION}.mjs")
+  --import "${PROJECT_BINARY_DIR}/bin/vtkWasmSceneManager.mjs")
 vtk_add_test_module_javascript_node(
   testInitialize.mjs,NO_DATA
   testBlobs.mjs,
diff --git a/Web/WebAssembly/vtkWasmSceneManagerEmBinding.cxx b/Web/WebAssembly/vtkWasmSceneManagerEmBinding.cxx
index 5c19ef16237a866aa7ec01a892b0f79fe15819a0..dcd19e40564c2af43491fb417326263049b5cefb 100644
--- a/Web/WebAssembly/vtkWasmSceneManagerEmBinding.cxx
+++ b/Web/WebAssembly/vtkWasmSceneManagerEmBinding.cxx
@@ -6,6 +6,7 @@
 #include "vtkDataArrayRange.h"
 #include "vtkOpenGLPolyDataMapper.h"
 #include "vtkTypeUInt8Array.h"
+#include "vtkVersion.h"
 #include "vtkWasmSceneManager.h"
 
 namespace
@@ -206,6 +207,18 @@ bool removeObserver(vtkTypeUInt32 identifier, unsigned long tag)
   return Manager->RemoveObserver(identifier, tag);
 }
 
+//-------------------------------------------------------------------------------
+std::string getVTKVersion()
+{
+  return vtkVersion::GetVTKVersion();
+}
+
+//-------------------------------------------------------------------------------
+std::string getVTKVersionFull()
+{
+  return vtkVersion::GetVTKVersionFull();
+}
+
 } // namespace
 
 EMSCRIPTEN_BINDINGS(vtkWasmSceneManager)
@@ -242,6 +255,9 @@ EMSCRIPTEN_BINDINGS(vtkWasmSceneManager)
 
   function("addObserver", ::addObserver);
   function("removeObserver", ::removeObserver);
+
+  function("getVTKVersion", ::getVTKVersion);
+  function("getVTKVersionFull", ::getVTKVersionFull);
 }
 
 int main()