diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2c81ac4b737a6634723a2fff3385b2d4c1b1c6fc..30a70dba939cb14353dc2a9b39ec351ebfaaf2f6 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -12,49 +12,51 @@ set(CMAKE_CXX_STANDARD 11)
 set(CMAKE_CXX_STANDARD_REQUIRED ON)
 
 find_package(
-  QT NAMES Qt6
-  COMPONENTS Core
-  REQUIRED)
+    QT NAMES Qt6
+    COMPONENTS Core
+    REQUIRED
+)
+
 find_package(
-  Qt6
-  COMPONENTS Core Widgets Quick Gui Qml
-  REQUIRED)
+    Qt6
+    COMPONENTS Core Widgets Quick Gui Qml
+    REQUIRED
+)
 
 set(QT_MINIMUM_VERSION 6.3.0)
 if(QT_VERSION VERSION_LESS QT_MINIMUM_VERSION)
-  message(FATAL_ERROR "Minimum supported Qt version: ${QT_MINIMUM_VERSION}")
+    message(FATAL_ERROR "Minimum supported Qt version: ${QT_MINIMUM_VERSION}")
 endif()
 
 qt_add_executable(${PROJECT_NAME}
-  design-viewer/importdummy_wasm.qml
-  design-viewer/src/main.cpp
-  design-viewer/src/dv_android.cpp design-viewer/src/dv_android.h
-  design-viewer/src/dv_wasm.cpp design-viewer/src/dv_wasm.h
-  design-viewer/src/dv_base.cpp design-viewer/src/dv_base.h
+    design-viewer/importdummy_wasm.qml
+    design-viewer/src/main.cpp
+    design-viewer/src/dv_android.cpp design-viewer/src/dv_android.h
+    design-viewer/src/dv_wasm.cpp design-viewer/src/dv_wasm.h
+    design-viewer/src/dv_base.cpp design-viewer/src/dv_base.h
 )
 
 target_link_libraries(${PROJECT_NAME} PRIVATE
-  Qt6::Core Qt6::Widgets
-  Qt6::Quick Qt6::Gui
-  Qt6::Qml Qt6::GuiPrivate
+    Qt6::Core Qt6::Widgets
+    Qt6::Quick Qt6::Gui
+    Qt6::Qml Qt6::GuiPrivate
 )
 
 set_property(TARGET ${PROJECT_NAME}
-  APPEND PROPERTY QT_WASM_INITIAL_MEMORY "50MB"
+    APPEND PROPERTY QT_WASM_INITIAL_MEMORY "50MB"
 )
 
 set_property(TARGET ${PROJECT_NAME}
-  APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/design-viewer/android
+APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/design-viewer/android
 )
 
 if (ANDROID)
-    set(ANDROID_OPENSSL_PATH ${ANDROID_SDK_ROOT}/android_openssl/ssl_3/arm64-v8a)
     if(EXISTS ${ANDROID_OPENSSL_PATH})
-        message(STATUS "Linking OpenSSL for Android. Path: ${ANDROID_OPENSSL_PATH}")
-          set_property(TARGET ${PROJECT_NAME} PROPERTY QT_ANDROID_EXTRA_LIBS
-              ${ANDROID_OPENSSL_PATH}/libcrypto_3.so
-              ${ANDROID_OPENSSL_PATH}/libssl_3.so)
-    else()
+        message(STATUS "Found OpenSSL for Android. Path: ${ANDROID_OPENSSL_PATH}")
+        set_property(TARGET ${PROJECT_NAME} PROPERTY QT_ANDROID_EXTRA_LIBS
+        ${ANDROID_OPENSSL_PATH}/libcrypto_3.so
+        ${ANDROID_OPENSSL_PATH}/libssl_3.so)
+        else()
         message(WARNING "Cannot find OpenSSL for Android.")
     endif()
 endif()
@@ -76,4 +78,3 @@ install(
 set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${CMAKE_INSTALL_PREFIX})
 
 qt6_import_qml_plugins(${PROJECT_NAME})
-
diff --git a/README.md b/README.md
index eafbc4e0195a23a489438bd4df55336679ebb9c0..e2cf06116054eef1afa85ad50bf88a5c7d2f6c3a 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,103 @@ Launch [Design Studio](https://www.qt.io/ui-design-tools) projects in Your web b
 
 Qt Design Viewer works in a variety of web browsers which support WebAssembly, on Desktop and even on mobile.
 
+## Prerequisites
+
+* CMake 3.16 or newer
+* Android
+    * Qt6.5.0 or newer
+    * OpenSSL (<https://github.com/KDAB/android_openssl>)
+    * Android SDK and NDK (<https://developer.android.com/studio>)
+* WebAssembly
+    * Qt6.4.3 or newer
+    * EMSDK (<https://emscripten.org/docs/getting_started/downloads.html>)
+
+## Building
+
+Build instructions are provided for Linux, macOS hosts and for Android and WebAssembly targets. Windows should work as well but is not tested.
+> Note:
+> If you're building in a Docker container and you've mounted the source directory into the container, you may need to change the build path pointing out somewhere out of the source directory. Otherwise you may get errors like the following;
+> `CMake Error at /opt/qt-v.6.5.0/android-arm64-v8a/lib/cmake/Qt6/QtSyncQtHelpers.cmake:235 (message): syncqt.cpp failed for module QtQuickStudioApplication: Unable to remove file ...`
+
+### Android
+
+> Note:
+> Android build instructions can also be used on desktop (or host) for testing purposes. Just replace the `CMAKE_TOOLCHAIN_FILE` path with the path to your Qt host installation.
+
+First build and install QtQuickDesigner Components for Android:
+
+```bash
+cd qtquickdesigner-components
+cmake \
+    -S . \
+    -B build \
+    -G Ninja \
+    -DCMAKE_TOOLCHAIN_FILE=<qt-android-path>/lib/cmake/Qt6/qt.toolchain.cmake \
+    -DANDROID_SDK_ROOT=<android-sdk-path> \
+    -DANDROID_NDK_ROOT=<android-sdk-path>/ndk/<ndk-version> \
+    -DANDROID_OPENSSL_PATH=<openssl-path>
+
+cmake --build build
+cmake --install build
+cd ..
+```
+
+Then build the Qt Design Viewer:
+
+```bash
+cmake \
+    -S . \
+    -B build \
+    -G Ninja \
+    -DCMAKE_TOOLCHAIN_FILE=<qt-android-path>/lib/cmake/Qt6/qt.toolchain.cmake \
+    -DANDROID_SDK_ROOT=<android-sdk-path> \
+    -DANDROID_NDK_ROOT=<android-sdk-path>/ndk/<ndk-version> \
+    -DANDROID_OPENSSL_PATH=<openssl-path>
+
+cmake --build build
+```
+
+### WebAssembly
+
+First activate the correct EMSDK version:
+
+```bash
+cd emsdk
+./emsdk install <emsdk-version>
+./emsdk activate <emsdk-version>
+source ./emsdk_env.sh
+cd ..
+```
+
+Then build and install QtQuickDesigner Components for Android:
+
+```bash
+cd qtquickdesigner-components
+cmake \
+    -S . \
+    -B build \
+    -G Ninja \
+    -DCMAKE_TOOLCHAIN_FILE=<qt-wasm-path>/wasm/lib/cmake/Qt6/qt.toolchain.cmake
+
+cmake --build build
+cmake --install build
+cd ..
+```
+
+Then build the Qt Design Viewer:
+
+```bash
+cmake \
+    -S . \
+    -B build \
+    -G Ninja \
+    -DCMAKE_TOOLCHAIN_FILE=<qt-wasm-path>/wasm/lib/cmake/Qt6/qt.toolchain.cmake
+
+cmake --build build
+```
+
 ## Usage
+
 Compress Your Qml project as a _.zip_ file, ideally including a _.qmlproject_ file. Or use the _Build -> Generate Resource File_ feature of Qt Design Studio 1.3+ to pack Your project in a _.qmlrc_ file.
 
 The Qt Design Viewer lets You drop the _.zip_/_.qmlrc_, or load it via a file selector.
@@ -13,12 +109,15 @@ The Qt Design Viewer lets You drop the _.zip_/_.qmlrc_, or load it via a file se
 ![Qt Design Viewer in action](screenshot.png "Qt Design Viewer in action")
 
 You can also select one of the premade examples. If you host the Qt Design Viewer on Your web server, You can offer your own examples. Direct links to hosted examples can be sent like this:
-* https://qt-webassembly.io/designviewer/#ClusterTutorial.qmlrc
-* https://qt-webassembly.io/designviewer/#CoffeeMachine.qmlrc
-* https://qt-webassembly.io/designviewer/#SideMenu.qmlrc
+
+* <https://qt-webassembly.io/designviewer/#ClusterTutorial.qmlrc>
+* <https://qt-webassembly.io/designviewer/#CoffeeMachine.qmlrc>
+* <https://qt-webassembly.io/designviewer/#SideMenu.qmlrc>
 
 ## Note
+
 This is a static web page. The Qml application that You load runs and remains locally in Your browser, nothing gets uploaded into the cloud.
 
 ## Live version
+
 Check out the [live version](https://qt-webassembly.io/designviewer/) of the Qt Design Viewer.
diff --git a/.github/workflows/build-apks.yml b/cicd/github/workflows/build-apks.yml
similarity index 100%
rename from .github/workflows/build-apks.yml
rename to cicd/github/workflows/build-apks.yml
diff --git a/.github/workflows/build-wasm.yml b/cicd/github/workflows/build-wasm.yml
similarity index 100%
rename from .github/workflows/build-wasm.yml
rename to cicd/github/workflows/build-wasm.yml
diff --git a/cicd/gitlab/gitlab-ci.yml b/cicd/gitlab/gitlab-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..a629d58c23bb7e83ae0ab44c46eaa3e47b737225
--- /dev/null
+++ b/cicd/gitlab/gitlab-ci.yml
@@ -0,0 +1,22 @@
+# QDS_CI_BUILD_QT_VERSION_ANDROID and QDS_CI_BUILD_QT_VERSION_WASM are the tags for the docker images.
+# https://git.qt.io/design-studio/maintenance/docker-images/container_registry
+
+variables:
+  QDS_CI_QT_VERSION:
+    value: "643"
+    options:
+      - "643"
+      - "652"
+    description: "Qt version for build"
+  QDS_CI_REGISTRY_IMAGE: "git.qt.io:4567/design-studio/maintenance/docker-images"
+  QDS_CI_ARTIFACTS_PATH: "${CI_PROJECT_DIR}/artifacts"
+  DEBIAN_FRONTEND: non-interactive
+  GIT_SUBMODULE_STRATEGY: recursive
+
+stages:
+  - build
+  - deploy
+  - release
+
+include:
+  - local: "cicd/gitlab/stages/*"
diff --git a/cicd/gitlab/stages/build.yml b/cicd/gitlab/stages/build.yml
new file mode 100644
index 0000000000000000000000000000000000000000..adb70d623cedd74d2fe01c42fe2df2f8dc931b74
--- /dev/null
+++ b/cicd/gitlab/stages/build.yml
@@ -0,0 +1,119 @@
+.build-common:
+  stage: build
+  tags:
+    - linux-blade
+  rules:
+    - if: $CI_PIPELINE_SOURCE == "push" || $CI_PIPELINE_SOURCE == "web"
+  variables:
+    QDS_BUILD_PATH: "${CI_PROJECT_DIR}/outdir/build"
+    QDS_CI_JOB_ARTIFACTS_PATH: ${QDS_CI_ARTIFACTS_PATH}/${QDS_CI_JOB_TARGET_PLATFORM}/${QDS_CI_JOB_TARGET_ARCH}
+  artifacts:
+    name: design-viewer-${CI_JOB_ID}-${QDS_CI_JOB_TARGET_PLATFORM}-${QDS_CI_JOB_TARGET_ARCH}
+    expose_as: "build-artifacts"
+    paths:
+      - ${QDS_CI_ARTIFACTS_PATH}
+  before_script:
+    - mkdir -p ${QDS_CI_JOB_ARTIFACTS_PATH}
+
+build-android-multiarch:
+  extends: .build-common
+  image: "${QDS_CI_REGISTRY_IMAGE}/${QDS_CI_JOB_TARGET_PLATFORM}:${QDS_CI_QT_VERSION}-${QDS_CI_JOB_TARGET_PLATFORM}-${QDS_CI_JOB_TARGET_ARCH}"
+  variables:
+    QDS_CI_JOB_TARGET_PLATFORM: "android"
+  rules:
+    - if: $QDS_CI_QT_VERSION_ANDROID != "none"
+  parallel:
+    matrix:
+      - QDS_CI_JOB_TARGET_ARCH:
+        - "arm64_v8a"
+        - "armv7"
+        - "x86"
+        - "x86_64"
+  script:
+    - cd qtquickdesigner-components
+    - |
+      cmake \
+      -S . \
+      -G Ninja \
+      -DCMAKE_BUILD_TYPE=Debug \
+      -DCMAKE_TOOLCHAIN_FILE=${QT_PATH}/${QT_VERSION}/${QDS_CI_JOB_TARGET_PLATFORM}_${QDS_CI_JOB_TARGET_ARCH}/lib/cmake/Qt6/qt.toolchain.cmake \
+      -DANDROID_SDK_ROOT=/opt/android \
+      -DANDROID_NDK_ROOT=/opt/android/ndk/25.2.9519653 \
+      -DQT_HOST_PATH=${QT_PATH}/${QT_VERSION}/gcc_64 \
+      -DCMAKE_INSTALL_PREFIX=${QT_PATH}/${QT_VERSION}/${QDS_CI_JOB_TARGET_PLATFORM}_${QDS_CI_JOB_TARGET_ARCH} \
+      -DANDROID_OPENSSL_PATH=/opt/openssl/ssl_3/${QDS_CI_JOB_TARGET_ARCH}
+    - cmake --build .
+    - cmake --install .
+    - cd ..
+    - |
+      cmake \
+      -S . \
+      -B ${QDS_BUILD_PATH} \
+      -G Ninja \
+      -DCMAKE_BUILD_TYPE=Debug \
+      -DCMAKE_TOOLCHAIN_FILE=${QT_PATH}/${QT_VERSION}/${QDS_CI_JOB_TARGET_PLATFORM}_${QDS_CI_JOB_TARGET_ARCH}/lib/cmake/Qt6/qt.toolchain.cmake \
+      -DANDROID_SDK_ROOT=/opt/android \
+      -DANDROID_NDK_ROOT=/opt/android/ndk/25.2.9519653 \
+      -DQT_HOST_PATH=${QT_PATH}/${QT_VERSION}/gcc_64 \
+      -DCMAKE_INSTALL_PREFIX=${QT_PATH}/${QT_VERSION}/${QDS_CI_JOB_TARGET_PLATFORM}_${QDS_CI_JOB_TARGET_ARCH} \
+      -DANDROID_OPENSSL_PATH=/opt/openssl/ssl_3/${QDS_CI_JOB_TARGET_ARCH}
+    - cmake --build ${QDS_BUILD_PATH} --target all
+    - cp -r ${QDS_BUILD_PATH}/android-build/build/outputs/apk/debug/* ${QDS_CI_JOB_ARTIFACTS_PATH}
+
+.build-wasm-common:
+  extends: .build-common
+  image: "${QDS_CI_REGISTRY_IMAGE}/${QDS_CI_JOB_TARGET_PLATFORM}:${QDS_CI_QT_VERSION}-${QDS_CI_JOB_TARGET_PLATFORM}_${QDS_CI_JOB_TARGET_ARCH}"
+  variables:
+    QDS_CI_JOB_TARGET_PLATFORM: "wasm"
+  script:
+    - |
+      if [[ ${QDS_CI_QT_VERSION} == "643" ]]; then
+        EMSDK_VERSION="3.1.14"
+      elif [[ ${QDS_CI_QT_VERSION} == "652" ]]; then
+        EMSDK_VERSION="3.1.25"
+      fi
+    - |
+      cd emsdk
+      ./emsdk install ${EMSDK_VERSION}
+      ./emsdk activate ${EMSDK_VERSION}
+      source emsdk_env.sh
+      cd ..
+    - |
+      cd qtquickdesigner-components
+      cmake \
+      -S . \
+      -G Ninja \
+      -DCMAKE_TOOLCHAIN_FILE=${QT_PATH}/${QT_VERSION}/${QDS_CI_JOB_TARGET_PLATFORM}_${QDS_CI_JOB_TARGET_ARCH}/lib/cmake/Qt6/qt.toolchain.cmake \
+      -DQT_HOST_PATH=${QT_PATH}/${QT_VERSION}/gcc_64 \
+      -DCMAKE_C_COMPILER=${EMSDK}/upstream/emscripten/emcc  \
+      -DCMAKE_CXX_COMPILER=${EMSDK}/upstream/emscripten/em++ \
+      -DCMAKE_INSTALL_PREFIX=${QT_PATH}/${QT_VERSION}/${QDS_CI_JOB_TARGET_PLATFORM}_${QDS_CI_JOB_TARGET_ARCH}
+    - cmake --build .
+    - cmake --install .
+    - cd ..
+    - |
+      cmake \
+      -S . \
+      -B ${QDS_BUILD_PATH} \
+      -G Ninja \
+      -DCMAKE_BUILD_TYPE=Debug \
+      -DCMAKE_TOOLCHAIN_FILE=${QT_PATH}/${QT_VERSION}/${QDS_CI_JOB_TARGET_PLATFORM}_${QDS_CI_JOB_TARGET_ARCH}/lib/cmake/Qt6/qt.toolchain.cmake \
+      -DQT_HOST_PATH=${QT_PATH}/${QT_VERSION}/gcc_64 \
+      -DCMAKE_C_COMPILER=${EMSDK}/upstream/emscripten/emcc  \
+      -DCMAKE_CXX_COMPILER=${EMSDK}/upstream/emscripten/em++ \
+      -DCMAKE_INSTALL_PREFIX=${QDS_CI_JOB_ARTIFACTS_PATH}
+    - cmake --build ${QDS_BUILD_PATH}
+    - cmake --install ${QDS_BUILD_PATH}
+
+build-wasm_multiarch:
+  extends: .build-wasm-common
+  rules:
+    - if: $QDS_CI_QT_VERSION == "643" && $QDS_CI_JOB_TARGET_ARCH == "32"
+    - if: $QDS_CI_QT_VERSION != "643" && $QDS_CI_JOB_TARGET_ARCH == "singlethread"
+    - if: $QDS_CI_QT_VERSION != "643" && $QDS_CI_JOB_TARGET_ARCH == "multithread"
+  parallel:
+    matrix:
+      - QDS_CI_JOB_TARGET_ARCH:
+        - "32"
+        - "singlethread"
+        - "multithread"
diff --git a/cicd/gitlab/stages/release.yml b/cicd/gitlab/stages/release.yml
new file mode 100644
index 0000000000000000000000000000000000000000..a18d029440966afe175866ebaf1741ed6a1f3f3b
--- /dev/null
+++ b/cicd/gitlab/stages/release.yml
@@ -0,0 +1,70 @@
+create-packages:
+  stage: release
+  image: alpine:latest
+  tags:
+    - linux-blade
+  rules:
+    - if: $CI_COMMIT_TAG
+  needs:
+    - job: build-android-multiarch
+      optional: false
+      artifacts: true
+    - job: build-wasm_multiarch
+      optional: true
+      artifacts: true
+  variables:
+    QDS_PACKAGE_URL: "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/design-viewer/${CI_COMMIT_TAG}"
+  script:
+    - apk add tar curl
+    - cd ${QDS_CI_ARTIFACTS_PATH}
+    - |
+      for platform in $(ls); do
+        echo "Creating packages for platform $platform"
+        cd "$platform"
+        for arch in $(ls); do
+            echo "Running for $platform-$arch. Compressing..."
+            cd "$arch"
+            tar -czf "$platform-$arch.tar.gz" *
+            echo "Uploading $platform-$arch.tar.gz to GitLab Package Registry"
+            curl --header "JOB-TOKEN: ${CI_JOB_TOKEN}" --upload-file "${platform}-${arch}.tar.gz" ${QDS_PACKAGE_URL}/design_viewer-${CI_COMMIT_TAG}-qt${QDS_CI_QT_VERSION}-${platform}-${arch}.tar.gz
+            cd ..
+        done
+        cd ..
+      done
+  artifacts:
+    name: design-viewer-${CI_JOB_ID}-qt${QDS_CI_QT_VERSION}
+    paths:
+      - ${QDS_CI_ARTIFACTS_PATH}
+    expire_in: 1 week
+
+create-release:
+  stage: release
+  image: registry.gitlab.com/gitlab-org/release-cli:latest
+  tags:
+    - linux-blade
+  rules:
+    - if: $CI_COMMIT_TAG
+  needs:
+    - job: create-packages
+      artifacts: true
+  variables:
+    QDS_PACKAGE_URL: "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/design-viewer/${CI_COMMIT_TAG}"
+    QDS_RELEASE_NAME: "Design Viewer - ${CI_COMMIT_TAG}"
+    QDS_RELEASE_DESCRIPTION: "This version is built with Qt-${QDS_CI_QT_VERSION}."
+  release:
+    name: ${QDS_RELEASE_NAME}
+    description: ${QDS_RELEASE_DESCRIPTION}
+    tag_name: ${CI_COMMIT_TAG}
+    assets:
+      links:
+        - name: "Binary Packages"
+          url: "https://git.qt.io/design-studio/cloud-services/design-viewer-app/-/packages"
+          link_type: "package"
+        - name: "Docker Images - Android"
+          url: "https://git.qt.io/design-studio/maintenance/docker-images/container_registry/143"
+          link_type: "image"
+        - name: "Docker Images - WASM"
+          url: "https://git.qt.io/design-studio/maintenance/docker-images/container_registry/142"
+          link_type: "image"
+  script:
+    - echo "Releasing ${QDS_RELEASE_NAME}"