[education/blinken] /: Add android support for blinken

Albert Astals Cid null at kde.org
Thu Oct 31 08:18:08 GMT 2024


Git commit b7794593d70b0a8ea90e8c793baa297901440060 by Albert Astals Cid, on behalf of hanyang zhang.
Committed on 31/10/2024 at 08:17.
Pushed by aacid into branch 'master'.

Add android support for blinken

use QML to draw ui, and origin blinken logic file

M  +2    -0    .gitlab-ci.yml
M  +11   -1    .kde-ci.yml
M  +45   -13   CMakeLists.txt
M  +2    -1    doc/CMakeLists.txt
M  +3    -0    doc/index.docbook
M  +9    -2    fonts/CMakeLists.txt
M  +9    -10   icons/CMakeLists.txt
M  +44   -1    images/CMakeLists.txt
A  +168  -0    images/color/blue.svg
A  +140  -0    images/color/blue_highlight.svg
A  +145  -0    images/color/green.svg
A  +164  -0    images/color/green_highlight.svg
A  +188  -0    images/color/red.svg
A  +188  -0    images/color/red_highlight.svg
A  +165  -0    images/color/yellow.svg
A  +164  -0    images/color/yellow_highlight.svg
A  +100  -0    images/numbers/0.svg
A  +89   -0    images/numbers/1.svg
A  +100  -0    images/numbers/2.svg
A  +100  -0    images/numbers/3.svg
A  +84   -0    images/numbers/4.svg
A  +100  -0    images/numbers/5.svg
A  +104  -0    images/numbers/6.svg
A  +76   -0    images/numbers/7.svg
A  +108  -0    images/numbers/8.svg
A  +104  -0    images/numbers/9.svg
A  +45   -0    images/numbers/blackBlock.svg
A  +124  -0    images/numbers/blank.svg
A  +124  -0    images/numbers/full.svg
A  +45   -0    images/numbers/redBlock.svg
A  +149  -0    images/ui/background.svg
A  +10   -0    images/ui/downArrow.svg
A  +59   -0    images/ui/exit.svg
A  +62   -0    images/ui/exit_highlight.svg
A  +83   -0    images/ui/highScore.svg
A  +83   -0    images/ui/highScore_highlight.svg
A  +59   -0    images/ui/menu.svg
A  +185  -0    images/ui/menu_list.svg
A  +10   -0    images/ui/rightArrow.svg
M  +16   -1    sounds/CMakeLists.txt
M  +99   -39   src/CMakeLists.txt
A  +44   -0    src/android/AndroidManifest.xml
A  +-    --    src/android/res/drawable-hdpi/icon.png
A  +-    --    src/android/res/drawable-ldpi/icon.png
A  +-    --    src/android/res/drawable-mdpi/icon.png
A  +-    --    src/android/res/drawable-xhdpi/icon.png
A  +-    --    src/android/res/drawable-xxhdpi/icon.png
A  +-    --    src/android/res/drawable-xxxhdpi/icon.png
A  +8    -0    src/android/res/values/styles.xml
M  +65   -64   src/blinken.cpp
M  +4    -4    src/blinken.h
M  +6    -6    src/blinken.kcfg
M  +41   -41   src/blinkengame.cpp
M  +50   -32   src/blinkengame.h
M  +9    -9    src/button.cpp
M  +2    -2    src/button.h
A  +103  -0    src/highScoreManager.cpp     [License: GPL(v2.0+)]
A  +38   -0    src/highScoreManager.h     [License: GPL(v2.0+)]
M  +4    -92   src/highscoredialog.cpp
M  +1    -21   src/highscoredialog.h
M  +40   -8    src/main.cpp
A  +143  -0    src/maskedmousearea.cpp     [License: BSD]
A  +109  -0    src/maskedmousearea.h     [License: BSD]
M  +3    -1    src/settings.kcfgc
M  +97   -11   src/soundsplayer.cpp
M  +19   -3    src/soundsplayer.h
A  +323  -0    src/ui/Blinken.qml     [License: GPL(v2.0+)]
A  +131  -0    src/ui/BlinkenMenu.qml     [License: GPL(v2.0+)]
A  +37   -0    src/ui/ExitButton.qml     [License: GPL(v2.0+)]
A  +43   -0    src/ui/GameButton.qml     [License: GPL(v2.0+)]
A  +118  -0    src/ui/GameButtons.qml     [License: GPL(v2.0+)]
A  +218  -0    src/ui/GameOptions.qml     [License: GPL(v2.0+)]
A  +35   -0    src/ui/HighScoreButton.qml     [License: GPL(v2.0+)]
A  +95   -0    src/ui/HighScoreLists.qml     [License: GPL(v2.0+)]
A  +42   -0    src/ui/Numbers.qml     [License: GPL(v2.0+)]
A  +114  -0    src/ui/ScoreAndCounter.qml     [License: GPL(v2.0+)]
A  +72   -0    src/ui/ScoreList.qml     [License: GPL(v2.0+)]

https://invent.kde.org/education/blinken/-/commit/b7794593d70b0a8ea90e8c793baa297901440060

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index e665009..5607a73 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -9,3 +9,5 @@ include:
       - /gitlab-templates/windows-qt6.yml
       - /gitlab-templates/flatpak.yml
       - /gitlab-templates/craft-windows-x86-64-qt6.yml
+      - /gitlab-templates/android-qt6.yml
+      - /gitlab-templates/craft-android-qt6-apks.yml
diff --git a/.kde-ci.yml b/.kde-ci.yml
index 0fc85bd..4e48645 100644
--- a/.kde-ci.yml
+++ b/.kde-ci.yml
@@ -6,8 +6,18 @@ Dependencies:
   'require':
     'frameworks/extra-cmake-modules': '@latest-kf6'
     'frameworks/ki18n': '@latest-kf6'
-    'frameworks/kxmlgui': '@latest-kf6'
     'frameworks/kguiaddons': '@latest-kf6'
+
+- 'on': ['Android/Qt6']
+  'require':
+    'frameworks/kconfig': '@latest-kf6'
+    'frameworks/kconfigwidgets': '@latest-kf6'
+    'frameworks/kirigami': '@latest-kf6'
+    'libraries/kirigami-addons': '@latest-kf6'
+
+- 'on': ['Linux/Qt6', 'FreeBSD/Qt6', 'Windows/Qt6']
+  'require':
+    'frameworks/kxmlgui': '@latest-kf6'
     'frameworks/kdoctools': '@latest-kf6'
     'frameworks/kdbusaddons': '@latest-kf6'
     'frameworks/kcrash': '@latest-kf6'
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 63250a3..7706104 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -8,6 +8,14 @@ set(RELEASE_SERVICE_VERSION "${RELEASE_SERVICE_VERSION_MAJOR}.${RELEASE_SERVICE_
 
 project(blinken VERSION ${RELEASE_SERVICE_VERSION})
 
+option(QML_VERSION_FOR_DESKTOP "enable QML version for desktop" OFF)
+
+if(ANDROID OR QML_VERSION_FOR_DESKTOP)
+    set(QML_VERSION ON)
+else()
+    set(QML_VERSION OFF)
+endif()
+
 # minimal Qt requirement
 set(QT_MIN_VERSION "6.5.0")
 set(KF_MIN_VERSION "6.0.0")
@@ -28,33 +36,57 @@ include(ECMSetupVersion)
 include(FeatureSummary)
 include(ECMDeprecationSettings)
 
-find_package (Qt6 ${QT_MIN_VERSION} CONFIG REQUIRED Core Widgets Svg)
-
-find_package (KF6 ${KF_MIN_VERSION} REQUIRED COMPONENTS
-    CoreAddons I18n XmlGui GuiAddons DocTools DBusAddons Crash
-)
+if(ANDROID)
+    include(ECMAddAndroidApk)
+endif()
 
-find_package (Phonon4Qt6 REQUIRED)
+if(QML_VERSION)
+    add_compile_definitions(QML_VERSION)
+    include(ECMQmlModule)
+
+    find_package (Qt6 ${QT_MIN_VERSION} REQUIRED COMPONENTS 
+        Core Quick Gui Qml Multimedia
+    )
+    find_package (KF6 ${KF_MIN_VERSION} REQUIRED COMPONENTS
+        CoreAddons I18n GuiAddons Kirigami 
+    )
+    find_package(KF6Config ${KF_MIN_VERSION} REQUIRED)
+    find_package(KF6ConfigWidgets ${KF_MIN_VERSION} REQUIRED)
+    find_package(KF6KirigamiAddons 1.0 REQUIRED)
+
+else()
+
+    find_package (Qt6 ${QT_MIN_VERSION} CONFIG REQUIRED 
+        Core Widgets Svg Qml
+    )
+    find_package (KF6 ${KF_MIN_VERSION} REQUIRED COMPONENTS
+        CoreAddons I18n XmlGui GuiAddons DocTools DBusAddons Crash
+    )
+    find_package (Phonon4Qt6 REQUIRED)
+
+    add_subdirectory( doc )
+endif()
 
 # global include directories
 include_directories (${CMAKE_CURRENT_BINARY_DIR})
 ecm_set_disabled_deprecation_versions(QT 6.8.0  KF 6.5.0)
 
-add_subdirectory( doc )
-add_subdirectory( src ) 
-add_subdirectory( images ) 
-add_subdirectory( icons ) 
-add_subdirectory( sounds ) 
-add_subdirectory( fonts ) 
+
+add_subdirectory( src )
+add_subdirectory( images )
+add_subdirectory( sounds )
+add_subdirectory( icons )
+add_subdirectory( fonts )
 
 ########### install files ###############
 
 ki18n_install(po)
+
 if (KF6DocTools_FOUND)
     kdoctools_install(po)
 endif()
+
 install( FILES README.packagers  DESTINATION  ${KDE_INSTALL_DATADIR}/blinken/ )
 install( FILES org.kde.blinken.appdata.xml DESTINATION ${KDE_INSTALL_METAINFODIR} )
 
 feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES)
-
diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt
index 3ed0857..14af1dd 100644
--- a/doc/CMakeLists.txt
+++ b/doc/CMakeLists.txt
@@ -1,4 +1,5 @@
 ########### install files ###############
 #
-
+if(NOT ANDROID)
 kdoctools_create_handbook(index.docbook INSTALL_DESTINATION ${KDE_INSTALL_DOCBUNDLEDIR}/en SUBDIR blinken)
+endif()
diff --git a/doc/index.docbook b/doc/index.docbook
index 05710e2..8087008 100644
--- a/doc/index.docbook
+++ b/doc/index.docbook
@@ -309,6 +309,9 @@ Contributors:
 <para>"Steve" font: Steve Jordi
 <email>steve at sjordi.com</email>
 </para>
+<para>Android port: zhang hanyang
+<email>hanyangzhang at qq.com</email>
+</para>
 </listitem>
 </itemizedlist>
 
diff --git a/fonts/CMakeLists.txt b/fonts/CMakeLists.txt
index ba3edad..f683b94 100644
--- a/fonts/CMakeLists.txt
+++ b/fonts/CMakeLists.txt
@@ -1,2 +1,9 @@
-install( FILES steve.ttf  DESTINATION  ${KDE_INSTALL_DATADIR}/blinken/fonts )
-
+if(QML_VERSION)
+    qt_add_resources(blinken "fonts"
+        PREFIX "/"
+        FILES
+            steve.ttf
+    )
+else()
+    install( FILES steve.ttf  DESTINATION  ${KDE_INSTALL_DATADIR}/blinken/fonts )
+endif()
diff --git a/icons/CMakeLists.txt b/icons/CMakeLists.txt
index edc7a8f..f2e92e2 100644
--- a/icons/CMakeLists.txt
+++ b/icons/CMakeLists.txt
@@ -1,11 +1,10 @@
-ecm_install_icons( ICONS
-	128-apps-blinken.png
-	16-apps-blinken.png
-	22-apps-blinken.png
-	32-apps-blinken.png
-	48-apps-blinken.png
-	64-apps-blinken.png
-	sc-apps-blinken.svgz
-	DESTINATION ${KDE_INSTALL_ICONDIR} THEME hicolor
+ecm_install_icons(ICONS
+        128-apps-blinken.png
+        16-apps-blinken.png
+        22-apps-blinken.png
+        32-apps-blinken.png
+        48-apps-blinken.png
+        64-apps-blinken.png
+        sc-apps-blinken.svgz
+        DESTINATION ${KDE_INSTALL_ICONDIR} THEME hicolor
 )
-
diff --git a/images/CMakeLists.txt b/images/CMakeLists.txt
index ea2325c..b74cc8c 100644
--- a/images/CMakeLists.txt
+++ b/images/CMakeLists.txt
@@ -1,2 +1,45 @@
-install( FILES blinken.svg DESTINATION  ${KDE_INSTALL_DATADIR}/blinken/images )
+if(QML_VERSION)
+    set(IMAGES 
+        ui/background.svg 
+        ui/exit_highlight.svg 
+        ui/exit.svg 
+        ui/highScore_highlight.svg
+        ui/highScore.svg
+        ui/menu_list.svg
+        ui/menu.svg
+        ui/rightArrow.svg
+        ui/downArrow.svg
 
+        numbers/0.svg
+        numbers/1.svg
+        numbers/2.svg
+        numbers/3.svg
+        numbers/4.svg
+        numbers/5.svg
+        numbers/6.svg
+        numbers/7.svg
+        numbers/8.svg
+        numbers/9.svg
+        numbers/blackBlock.svg
+        numbers/redBlock.svg
+        numbers/blank.svg
+        numbers/full.svg
+
+        color/blue_highlight.svg
+        color/blue.svg
+        color/green_highlight.svg
+        color/green.svg
+        color/red_highlight.svg
+        color/red.svg
+        color/yellow_highlight.svg
+        color/yellow.svg
+    )
+
+    qt_add_resources(blinken "images"
+        PREFIX "/"
+        FILES
+            ${IMAGES}
+    )
+else()
+    install( FILES blinken.svg DESTINATION  ${KDE_INSTALL_DATADIR}/blinken/images )
+endif()
diff --git a/images/color/blue.svg b/images/color/blue.svg
new file mode 100644
index 0000000..92b9e08
--- /dev/null
+++ b/images/color/blue.svg
@@ -0,0 +1,168 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   version="1.1"
+   id="layer_1"
+   x="0px"
+   y="0px"
+   viewBox="0 0 374.25 250"
+   xml:space="preserve"
+   sodipodi:docname="blue.svg"
+   width="374.25"
+   height="250"
+   inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg"><defs
+   id="defs11"><radialGradient
+     inkscape:collect="always"
+     xlink:href="#path28332_00000125561446015486516160000013323403246331414440_"
+     id="radialGradient1"
+     gradientUnits="userSpaceOnUse"
+     gradientTransform="matrix(1,0,0,-0.6673,-104.4855,1225.2798)"
+     cx="476.89981"
+     cy="607.03003"
+     r="186.75" /><radialGradient
+     inkscape:collect="always"
+     xlink:href="#path28314_00000060023190442832720600000004055112189393602459_"
+     id="radialGradient2"
+     gradientUnits="userSpaceOnUse"
+     gradientTransform="matrix(1,0,0,-0.6673,-104.4162,1225.3611)"
+     cx="609.42731"
+     cy="459.7796"
+     r="186.75" /><radialGradient
+     inkscape:collect="always"
+     xlink:href="#path27394_00000092452723319382642570000013502502858929694891_"
+     id="radialGradient3"
+     gradientUnits="userSpaceOnUse"
+     gradientTransform="matrix(1,0,0,-0.6743,-803.0044,1910.8429)"
+     cx="1479.2612"
+     cy="1691.2972"
+     r="381.78589" /></defs><sodipodi:namedview
+   id="namedview11"
+   pagecolor="#ffffff"
+   bordercolor="#000000"
+   borderopacity="0.25"
+   inkscape:showpageshadow="2"
+   inkscape:pageopacity="0.0"
+   inkscape:pagecheckerboard="0"
+   inkscape:deskcolor="#d1d1d1"
+   inkscape:zoom="1.2924837"
+   inkscape:cx="396.13652"
+   inkscape:cy="305.99999"
+   inkscape:window-width="1920"
+   inkscape:window-height="1001"
+   inkscape:window-x="1911"
+   inkscape:window-y="-9"
+   inkscape:window-maximized="1"
+   inkscape:current-layer="layer_1" />
+<style
+   type="text/css"
+   id="style1">
+	.st0{fill-rule:evenodd;clip-rule:evenodd;fill:#0453A2;}
+	.st1{fill-rule:evenodd;clip-rule:evenodd;fill:url(#path28332_00000091704882182657372600000015056983348821855904_);}
+	.st2{fill-rule:evenodd;clip-rule:evenodd;fill:url(#path28314_00000165933956259879055950000003512389886847918734_);}
+	
+		.st3{fill-rule:evenodd;clip-rule:evenodd;fill:url(#path27394_00000020386733222620888540000007405472570404088469_);stroke:#040000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:0.331;}
+	.st4{opacity:0.0493;fill-rule:evenodd;clip-rule:evenodd;fill:#FFFFFF;enable-background:new    ;}
+</style>
+<g
+   id="blue_normal"
+   transform="matrix(1.002437,0,0,0.99931661,-300.59003,-772.82554)">
+	<path
+   id="path27386"
+   class="st0"
+   d="m 300.78,774.59 c 2.03,67.31 43.48,128.35 109.94,173.02 67.03,45.06 159.39,73.27 261.56,74.2 V 973.18 C 563.93,970.46 476.43,882.95 473.72,774.59 Z" />
+	
+		<radialGradient
+   id="path28332_00000125561446015486516160000013323403246331414440_"
+   cx="476.89981"
+   cy="607.03003"
+   r="186.75"
+   gradientTransform="matrix(1,0,0,-0.6673,-104.4855,1225.2798)"
+   gradientUnits="userSpaceOnUse">
+		<stop
+   offset="0"
+   style="stop-color:#5F8CC3;stop-opacity:0.9609"
+   id="stop1" />
+		<stop
+   offset="1"
+   style="stop-color:#004182;stop-opacity:0"
+   id="stop2" />
+	</radialGradient>
+	
+		<path
+   id="path28332"
+   style="clip-rule:evenodd;fill:url(#radialGradient1);fill-rule:evenodd"
+   d="m 300.91,774.32 c 2.03,67.31 43.48,128.36 109.94,173.03 67.03,45.06 159.39,73.26 261.56,74.19 V 972.92 C 564.06,970.2 476.56,882.69 473.85,774.33 H 300.91 Z" />
+	
+		<radialGradient
+   id="path28314_00000060023190442832720600000004055112189393602459_"
+   cx="609.42731"
+   cy="459.7796"
+   r="186.75"
+   gradientTransform="matrix(1,0,0,-0.6673,-104.4162,1225.3611)"
+   gradientUnits="userSpaceOnUse">
+		<stop
+   offset="0"
+   style="stop-color:#004182"
+   id="stop3" />
+		<stop
+   offset="1"
+   style="stop-color:#004182;stop-opacity:0"
+   id="stop4" />
+	</radialGradient>
+	
+		<path
+   id="path28314"
+   style="clip-rule:evenodd;fill:url(#radialGradient2);fill-rule:evenodd"
+   d="m 300.98,774.4 c 2.03,67.31 43.48,128.36 109.94,173.03 67.03,45.06 159.39,73.26 261.56,74.19 V 973 C 564.13,970.28 476.63,882.77 473.92,774.41 H 300.98 Z" />
+	
+		<radialGradient
+   id="path27394_00000092452723319382642570000013502502858929694891_"
+   cx="1479.2612"
+   cy="1691.2972"
+   r="381.78589"
+   gradientTransform="matrix(1,0,0,-0.6743,-803.0044,1910.8429)"
+   gradientUnits="userSpaceOnUse">
+		<stop
+   offset="0"
+   style="stop-color:#323232"
+   id="stop5" />
+		<stop
+   offset="0.0769"
+   style="stop-color:#D2E5F6"
+   id="stop6" />
+		<stop
+   offset="0.2629"
+   style="stop-color:#004182;stop-opacity:0"
+   id="stop7" />
+		<stop
+   offset="0.5"
+   style="stop-color:#0453A2;stop-opacity:0.3455"
+   id="stop8" />
+		<stop
+   offset="0.782"
+   style="stop-color:#2E6CB5;stop-opacity:0.5455"
+   id="stop9" />
+		<stop
+   offset="0.9006"
+   style="stop-color:#004182;stop-opacity:0.4818"
+   id="stop10" />
+		<stop
+   offset="1"
+   style="stop-color:#393A3A"
+   id="stop11" />
+	</radialGradient>
+	
+		<path
+   id="path27394"
+   style="clip-rule:evenodd;fill:url(#radialGradient3);fill-rule:evenodd;stroke:#040000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:0.331"
+   d="m 300.77,774.39 c 2.03,67.31 43.48,128.36 109.94,173.03 67.03,45.06 159.39,73.26 261.56,74.19 V 972.99 C 563.92,970.27 476.42,882.76 473.71,774.4 H 300.77 Z" />
+	<path
+   id="path48021"
+   class="st4"
+   d="m 358.2,774.4 c 36.58,44.37 87.28,80.31 146.84,103.44 C 486.03,847.75 474.65,812.36 473.7,774.4 Z" />
+</g>
+</svg>
diff --git a/images/color/blue_highlight.svg b/images/color/blue_highlight.svg
new file mode 100644
index 0000000..be1ce86
--- /dev/null
+++ b/images/color/blue_highlight.svg
@@ -0,0 +1,140 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   version="1.1"
+   id="layer_1"
+   x="0px"
+   y="0px"
+   viewBox="0 0 374.39001 250"
+   xml:space="preserve"
+   sodipodi:docname="blue_highlight.svg"
+   width="374.39001"
+   height="250"
+   inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg"><defs
+   id="defs11" /><sodipodi:namedview
+   id="namedview11"
+   pagecolor="#ffffff"
+   bordercolor="#000000"
+   borderopacity="0.25"
+   inkscape:showpageshadow="2"
+   inkscape:pageopacity="0.0"
+   inkscape:pagecheckerboard="0"
+   inkscape:deskcolor="#d1d1d1"
+   inkscape:zoom="1.2924837"
+   inkscape:cx="396.13652"
+   inkscape:cy="305.99999"
+   inkscape:window-width="1920"
+   inkscape:window-height="1001"
+   inkscape:window-x="1911"
+   inkscape:window-y="-9"
+   inkscape:window-maximized="1"
+   inkscape:current-layer="layer_1" />
+<style
+   type="text/css"
+   id="style1">
+	.st0{fill-rule:evenodd;clip-rule:evenodd;fill:#2C62AE;}
+	
+		.st1{opacity:0.5845;fill-rule:evenodd;clip-rule:evenodd;fill:url(#path49064_00000098217621103341813630000007278829100273501864_);enable-background:new    ;}
+	
+		.st2{opacity:0.5;fill-rule:evenodd;clip-rule:evenodd;fill:url(#path49066_00000115500165207928487450000000296612667821403266_);stroke:#040000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:0.331;enable-background:new    ;}
+	
+		.st3{opacity:0.1761;fill-rule:evenodd;clip-rule:evenodd;fill:url(#path49068_00000046319246402669846160000015837282477196382394_);enable-background:new    ;}
+</style>
+<g
+   id="blue_highlight"
+   transform="matrix(1.0020002,0,0,1.0031611,-363.47443,-1310.5561)">
+	<path
+   id="path49060"
+   class="st0"
+   d="m 363.75,1307.05 c 2.03,67.31 43.48,128.35 109.94,173.02 67.03,45.06 159.39,73.27 261.56,74.2 v -48.63 C 626.9,1502.92 539.4,1415.41 536.69,1307.05 Z" />
+	
+		<radialGradient
+   id="path49064_00000056415399061775253280000000693924165062618256_"
+   cx="705.51837"
+   cy="189.58881"
+   r="186.75"
+   gradientTransform="matrix(1,0,0,-0.6673,-138.1061,1577.5394)"
+   gradientUnits="userSpaceOnUse">
+		<stop
+   offset="0"
+   style="stop-color:#004182"
+   id="stop1" />
+		<stop
+   offset="1"
+   style="stop-color:#004182;stop-opacity:0"
+   id="stop2" />
+	</radialGradient>
+	
+		<path
+   id="path49064"
+   style="clip-rule:evenodd;opacity:0.5845;fill:url(#path49064_00000056415399061775253280000000693924165062618256_);fill-rule:evenodd;enable-background:new"
+   d="m 363.38,1306.86 c 2.03,67.31 43.48,128.36 109.94,173.03 67.03,45.06 159.39,73.26 261.56,74.19 v -48.62 C 626.53,1502.74 539.03,1415.23 536.32,1306.87 H 363.38 Z" />
+	
+		<radialGradient
+   id="path49066_00000127744913500451459760000002731960833579333554_"
+   cx="1575.3523"
+   cy="1429.4684"
+   r="381.78589"
+   gradientTransform="matrix(1,0,0,-0.6743,-836.1231,2267.3208)"
+   gradientUnits="userSpaceOnUse">
+		<stop
+   offset="0"
+   style="stop-color:#323232"
+   id="stop3" />
+		<stop
+   offset="0.0769"
+   style="stop-color:#D2E5F6"
+   id="stop4" />
+		<stop
+   offset="0.2629"
+   style="stop-color:#004182;stop-opacity:0"
+   id="stop5" />
+		<stop
+   offset="0.5"
+   style="stop-color:#0453A2;stop-opacity:0.3455"
+   id="stop6" />
+		<stop
+   offset="0.782"
+   style="stop-color:#2E6CB5;stop-opacity:0.5455"
+   id="stop7" />
+		<stop
+   offset="0.9006"
+   style="stop-color:#004182;stop-opacity:0.4818"
+   id="stop8" />
+		<stop
+   offset="1"
+   style="stop-color:#393A3A"
+   id="stop9" />
+	</radialGradient>
+	
+		<path
+   id="path49066"
+   style="clip-rule:evenodd;opacity:0.5;fill:url(#path49066_00000127744913500451459760000002731960833579333554_);fill-rule:evenodd;stroke:#040000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:0.331;enable-background:new"
+   d="m 363.75,1307.42 c 2.03,67.31 43.48,128.36 109.94,173.03 67.03,45.06 159.39,73.26 261.56,74.19 v -48.62 C 626.9,1503.3 539.4,1415.79 536.69,1307.43 H 363.75 Z" />
+	
+		<radialGradient
+   id="path49068_00000054258629456709708870000006354480002332805544_"
+   cx="824.01111"
+   cy="783.3656"
+   r="379.28589"
+   gradientTransform="matrix(1,-0.00226167,-0.00301218,-1.3318,-134.1685,2142.1609)"
+   gradientUnits="userSpaceOnUse">
+		<stop
+   offset="0"
+   style="stop-color:#FFFFFF"
+   id="stop10" />
+		<stop
+   offset="1"
+   style="stop-color:#FFFFFF;stop-opacity:0"
+   id="stop11" />
+	</radialGradient>
+	
+		<path
+   id="path49068"
+   style="clip-rule:evenodd;opacity:0.1761;fill:url(#path49068_00000054258629456709708870000006354480002332805544_);fill-rule:evenodd;enable-background:new"
+   d="m 421.17,1306.87 c 36.58,44.37 87.28,80.31 146.84,103.44 -19.01,-30.09 -30.39,-65.48 -31.34,-103.44 z" />
+</g>
+</svg>
diff --git a/images/color/green.svg b/images/color/green.svg
new file mode 100644
index 0000000..c939632
--- /dev/null
+++ b/images/color/green.svg
@@ -0,0 +1,145 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   version="1.1"
+   id="layer_1"
+   x="0px"
+   y="0px"
+   viewBox="0 0 374.25 250"
+   xml:space="preserve"
+   sodipodi:docname="green.svg"
+   width="374.25"
+   height="250"
+   inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg"><defs
+   id="defs11" /><sodipodi:namedview
+   id="namedview11"
+   pagecolor="#ffffff"
+   bordercolor="#000000"
+   borderopacity="0.25"
+   inkscape:showpageshadow="2"
+   inkscape:pageopacity="0.0"
+   inkscape:pagecheckerboard="0"
+   inkscape:deskcolor="#d1d1d1"
+   inkscape:zoom="1.2924837"
+   inkscape:cx="396.13652"
+   inkscape:cy="305.99999"
+   inkscape:window-width="1920"
+   inkscape:window-height="1001"
+   inkscape:window-x="1911"
+   inkscape:window-y="-9"
+   inkscape:window-maximized="1"
+   inkscape:current-layer="layer_1" />
+<style
+   type="text/css"
+   id="style1">
+	.st0{fill-rule:evenodd;clip-rule:evenodd;fill:#11843B;}
+	
+		.st1{fill-rule:evenodd;clip-rule:evenodd;fill:url(#path27392_00000124867452088018918330000003393700036090762903_);stroke:#040000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:0.331;}
+	
+		.st2{opacity:0.5246;fill-rule:evenodd;clip-rule:evenodd;fill:url(#path34613_00000078738337522360425190000001563085163484979900_);enable-background:new    ;}
+	
+		.st3{opacity:0.5035;fill-rule:evenodd;clip-rule:evenodd;fill:url(#path33718_00000044863439465072258580000012064167419240576138_);enable-background:new    ;}
+	.st4{opacity:0.0246;fill-rule:evenodd;clip-rule:evenodd;fill:#FFFFFF;enable-background:new    ;}
+</style>
+<g
+   id="green_normal"
+   transform="matrix(1.0020068,0,0,1.0031495,-308.76536,-759.91368)">
+	<path
+   id="path27384"
+   class="st0"
+   d="M 507.59,758.58 C 504.87,866.94 417.4,954.45 309.06,957.17 v 48.63 c 102.17,-0.93 194.53,-29.14 261.56,-74.2 66.46,-44.68 107.9,-105.71 109.94,-173.02 z" />
+	
+		<radialGradient
+   id="path27392_00000092433464702926929160000008609019140570630580_"
+   cx="1109.6371"
+   cy="1714.4271"
+   r="381.78589"
+   gradientTransform="matrix(1,0,0,-0.6743,-806.9696,1910.636)"
+   gradientUnits="userSpaceOnUse">
+		<stop
+   offset="0"
+   style="stop-color:#323232"
+   id="stop1" />
+		<stop
+   offset="0.0769"
+   style="stop-color:#D4EADA"
+   id="stop2" />
+		<stop
+   offset="0.2629"
+   style="stop-color:#11843B;stop-opacity:0"
+   id="stop3" />
+		<stop
+   offset="0.5"
+   style="stop-color:#1DA550;stop-opacity:0.3451"
+   id="stop4" />
+		<stop
+   offset="0.782"
+   style="stop-color:#46B46B;stop-opacity:0.5451"
+   id="stop5" />
+		<stop
+   offset="0.9006"
+   style="stop-color:#11843B;stop-opacity:0.4727"
+   id="stop6" />
+		<stop
+   offset="1"
+   style="stop-color:#393A3A"
+   id="stop7" />
+	</radialGradient>
+	
+		<path
+   id="path27392"
+   style="clip-rule:evenodd;fill:url(#path27392_00000092433464702926929160000008609019140570630580_);fill-rule:evenodd;stroke:#040000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:0.331"
+   d="M 507.59,758.58 C 504.87,866.94 417.4,954.46 309.06,957.17 v 48.62 c 102.17,-0.93 194.53,-29.13 261.56,-74.19 66.46,-44.68 107.9,-105.72 109.94,-173.03 H 507.59 Z" />
+	
+		<radialGradient
+   id="path34613_00000071560101637334869520000014430612806751397306_"
+   cx="699.02087"
+   cy="634.14789"
+   r="185.75"
+   gradientTransform="matrix(0.9939,-0.1716,-0.0766,-0.4438,-129.6354,1180.7937)"
+   gradientUnits="userSpaceOnUse">
+		<stop
+   offset="0"
+   style="stop-color:#095C31"
+   id="stop8" />
+		<stop
+   offset="1"
+   style="stop-color:#095C31;stop-opacity:0"
+   id="stop9" />
+	</radialGradient>
+	
+		<path
+   id="path34613"
+   style="clip-rule:evenodd;opacity:0.5246;fill:url(#path34613_00000071560101637334869520000014430612806751397306_);fill-rule:evenodd;enable-background:new"
+   d="M 507.59,758.58 C 504.87,866.94 417.4,954.46 309.06,957.17 v 48.62 c 102.17,-0.93 194.53,-29.13 261.56,-74.19 66.46,-44.68 107.9,-105.72 109.94,-173.03 H 507.59 Z" />
+	
+		<radialGradient
+   id="path33718_00000052075961771307649480000014218016242397967769_"
+   cx="897.86963"
+   cy="417.7084"
+   r="185.75"
+   gradientTransform="matrix(0.7679,-0.1027,-0.0491,-0.367,-249.5514,1195.1643)"
+   gradientUnits="userSpaceOnUse">
+		<stop
+   offset="0"
+   style="stop-color:#095C31"
+   id="stop10" />
+		<stop
+   offset="1"
+   style="stop-color:#095C31;stop-opacity:0"
+   id="stop11" />
+	</radialGradient>
+	
+		<path
+   id="path33718"
+   style="clip-rule:evenodd;opacity:0.5035;fill:url(#path33718_00000052075961771307649480000014218016242397967769_);fill-rule:evenodd;enable-background:new"
+   d="M 507.59,758.58 C 504.87,866.94 417.4,954.46 309.06,957.17 v 48.62 c 102.17,-0.93 194.53,-29.13 261.56,-74.19 66.46,-44.68 107.9,-105.72 109.94,-173.03 H 507.59 Z" />
+	<path
+   id="path48055"
+   class="st4"
+   d="m 507.58,758.59 c -0.75,29.81 -7.91,58.05 -20.16,83.38 40.73,-21.91 75.78,-50.3 103,-83.38 z" />
+</g>
+</svg>
diff --git a/images/color/green_highlight.svg b/images/color/green_highlight.svg
new file mode 100644
index 0000000..5f6c355
--- /dev/null
+++ b/images/color/green_highlight.svg
@@ -0,0 +1,164 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   version="1.1"
+   id="layer_1"
+   x="0px"
+   y="0px"
+   viewBox="0 0 374.25 250"
+   xml:space="preserve"
+   sodipodi:docname="green_highlight.svg"
+   width="374.25"
+   height="250"
+   inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg"><defs
+   id="defs13" /><sodipodi:namedview
+   id="namedview13"
+   pagecolor="#ffffff"
+   bordercolor="#000000"
+   borderopacity="0.25"
+   inkscape:showpageshadow="2"
+   inkscape:pageopacity="0.0"
+   inkscape:pagecheckerboard="0"
+   inkscape:deskcolor="#d1d1d1"
+   inkscape:zoom="1.2924837"
+   inkscape:cx="396.13652"
+   inkscape:cy="305.99999"
+   inkscape:window-width="1920"
+   inkscape:window-height="1001"
+   inkscape:window-x="1911"
+   inkscape:window-y="-9"
+   inkscape:window-maximized="1"
+   inkscape:current-layer="layer_1" />
+<style
+   type="text/css"
+   id="style1">
+	.st0{fill-rule:evenodd;clip-rule:evenodd;fill:#6AB82D;}
+	
+		.st1{opacity:0.5;fill-rule:evenodd;clip-rule:evenodd;fill:url(#path49074_00000098198372180388715100000000457878385575343777_);stroke:#040000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:0.331;enable-background:new    ;}
+	
+		.st2{opacity:0.5246;fill-rule:evenodd;clip-rule:evenodd;fill:url(#path49076_00000097502808370843341640000017387398230225104549_);enable-background:new    ;}
+	
+		.st3{opacity:0.5035;fill-rule:evenodd;clip-rule:evenodd;fill:url(#path49078_00000057845661951333102590000011645076166096498875_);enable-background:new    ;}
+	
+		.st4{opacity:0.1761;fill-rule:evenodd;clip-rule:evenodd;fill:url(#path49080_00000067958334669141494030000003199325611023958696_);enable-background:new    ;}
+</style>
+<g
+   id="green_highlight"
+   transform="matrix(1.0019982,0,0,1.0031389,-357.40011,-1299.9594)">
+	<path
+   id="path49072"
+   class="st0"
+   d="m 556.13,1296.35 c -2.72,108.36 -90.19,195.87 -198.53,198.59 v 48.63 c 102.17,-0.93 194.53,-29.14 261.56,-74.2 66.46,-44.68 107.9,-105.71 109.94,-173.02 z" />
+	
+		<radialGradient
+   id="path49074_00000061442800080391003520000014261525934452600236_"
+   cx="1186.5231"
+   cy="1444.7301"
+   r="381.78589"
+   gradientTransform="matrix(1,0,0,-0.6743,-835.3149,2267.1147)"
+   gradientUnits="userSpaceOnUse">
+		<stop
+   offset="0"
+   style="stop-color:#323232"
+   id="stop1" />
+		<stop
+   offset="0.0769"
+   style="stop-color:#D4EADA"
+   id="stop2" />
+		<stop
+   offset="0.2629"
+   style="stop-color:#11843B;stop-opacity:0"
+   id="stop3" />
+		<stop
+   offset="0.5"
+   style="stop-color:#1DA550;stop-opacity:0.3451"
+   id="stop4" />
+		<stop
+   offset="0.782"
+   style="stop-color:#46B46B;stop-opacity:0.5451"
+   id="stop5" />
+		<stop
+   offset="0.9006"
+   style="stop-color:#11843B;stop-opacity:0.4727"
+   id="stop6" />
+		<stop
+   offset="1"
+   style="stop-color:#393A3A"
+   id="stop7" />
+	</radialGradient>
+	
+		<path
+   id="path49074"
+   style="clip-rule:evenodd;opacity:0.5;fill:url(#path49074_00000061442800080391003520000014261525934452600236_);fill-rule:evenodd;stroke:#040000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:0.331;enable-background:new"
+   d="m 556.13,1296.92 c -2.72,108.36 -90.19,195.88 -198.53,198.59 v 48.62 c 102.17,-0.93 194.53,-29.13 261.56,-74.19 66.46,-44.68 107.9,-105.72 109.94,-173.03 H 556.13 Z" />
+	
+		<radialGradient
+   id="path49076_00000099625125967241823390000000860723222905392771_"
+   cx="684.05322"
+   cy="-33.007"
+   r="185.75"
+   gradientTransform="matrix(0.9939,-0.1716,-0.0766,-0.4438,-117.3536,1420.475)"
+   gradientUnits="userSpaceOnUse">
+		<stop
+   offset="0"
+   style="stop-color:#095C31"
+   id="stop8" />
+		<stop
+   offset="1"
+   style="stop-color:#095C31;stop-opacity:0"
+   id="stop9" />
+	</radialGradient>
+	
+		<path
+   id="path49076"
+   style="clip-rule:evenodd;opacity:0.5246;fill:url(#path49076_00000099625125967241823390000000860723222905392771_);fill-rule:evenodd;enable-background:new"
+   d="m 556.13,1296.92 c -2.72,108.36 -90.19,195.88 -198.53,198.59 v 48.62 c 102.17,-0.93 194.53,-29.13 261.56,-74.19 66.46,-44.68 107.9,-105.72 109.94,-173.03 H 556.13 Z" />
+	
+		<radialGradient
+   id="path49078_00000079487091142516674360000016431458055873060514_"
+   cx="896.26221"
+   cy="-511.24689"
+   r="185.75"
+   gradientTransform="matrix(0.7679,-0.1027,-0.0491,-0.367,-245.3972,1391.8029)"
+   gradientUnits="userSpaceOnUse">
+		<stop
+   offset="0"
+   style="stop-color:#095C31"
+   id="stop10" />
+		<stop
+   offset="1"
+   style="stop-color:#095C31;stop-opacity:0"
+   id="stop11" />
+	</radialGradient>
+	
+		<path
+   id="path49078"
+   style="clip-rule:evenodd;opacity:0.5035;fill:url(#path49078_00000079487091142516674360000016431458055873060514_);fill-rule:evenodd;enable-background:new"
+   d="m 556.13,1296.35 c -2.72,108.36 -90.19,195.88 -198.53,198.59 v 48.62 c 102.17,-0.93 194.53,-29.13 261.56,-74.19 66.46,-44.68 107.9,-105.72 109.94,-173.03 H 556.13 Z" />
+	
+		<radialGradient
+   id="path49080_00000166663580299678216930000005496189042077002885_"
+   cx="435.20721"
+   cy="791.75293"
+   r="379.28589"
+   gradientTransform="matrix(1,-0.00226167,-0.00301218,-1.3318,-134.1685,2142.1609)"
+   gradientUnits="userSpaceOnUse">
+		<stop
+   offset="0"
+   style="stop-color:#FFFFFF"
+   id="stop12" />
+		<stop
+   offset="1"
+   style="stop-color:#FFFFFF;stop-opacity:0"
+   id="stop13" />
+	</radialGradient>
+	
+		<path
+   id="path49080"
+   style="clip-rule:evenodd;opacity:0.1761;fill:url(#path49080_00000166663580299678216930000005496189042077002885_);fill-rule:evenodd;enable-background:new"
+   d="m 556.12,1296.36 c -0.75,29.81 -7.91,58.05 -20.16,83.38 40.73,-21.91 75.78,-50.3 103,-83.38 z" />
+</g>
+</svg>
diff --git a/images/color/red.svg b/images/color/red.svg
new file mode 100644
index 0000000..91ee446
--- /dev/null
+++ b/images/color/red.svg
@@ -0,0 +1,188 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   version="1.1"
+   id="layer_1"
+   x="0px"
+   y="0px"
+   viewBox="0 0 347.25 250"
+   xml:space="preserve"
+   sodipodi:docname="red.svg"
+   width="347.25"
+   height="250"
+   inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg"><defs
+   id="defs15" /><sodipodi:namedview
+   id="namedview15"
+   pagecolor="#ffffff"
+   bordercolor="#000000"
+   borderopacity="0.25"
+   inkscape:showpageshadow="2"
+   inkscape:pageopacity="0.0"
+   inkscape:pagecheckerboard="0"
+   inkscape:deskcolor="#d1d1d1"
+   inkscape:zoom="1.2924837"
+   inkscape:cx="396.13652"
+   inkscape:cy="305.99999"
+   inkscape:window-width="1920"
+   inkscape:window-height="1001"
+   inkscape:window-x="1911"
+   inkscape:window-y="-9"
+   inkscape:window-maximized="1"
+   inkscape:current-layer="layer_1" />
+<style
+   type="text/css"
+   id="style1">
+	.st0{fill-rule:evenodd;clip-rule:evenodd;fill:#B41D23;}
+	
+		.st1{fill-rule:evenodd;clip-rule:evenodd;fill:url(#path27390_00000001642420658109818190000009090763747277451910_);stroke:#040000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:0.331;}
+	
+		.st2{opacity:0.5352;fill-rule:evenodd;clip-rule:evenodd;fill:url(#path40850_00000018925456596390428630000007889162573793817486_);enable-background:new    ;}
+	
+		.st3{opacity:0.5352;fill-rule:evenodd;clip-rule:evenodd;fill:url(#path41745_00000029009028376141733640000007089464836489597070_);enable-background:new    ;}
+	
+		.st4{opacity:0.1761;fill-rule:evenodd;clip-rule:evenodd;fill:url(#path48052_00000026869060482806714020000006704680069684470917_);enable-background:new    ;}
+	
+		.st5{opacity:0.1972;fill-rule:evenodd;clip-rule:evenodd;fill:url(#path48078_00000138555999722409553480000007210567485955704966_);enable-background:new    ;}
+</style>
+<g
+   id="red_normal"
+   transform="matrix(0.92971834,0,0,0.99869999,-291.34624,-748.87085)">
+	<path
+   id="path27382"
+   class="st0"
+   d="m 314.33,750.83 v 48.66 c 108.36,2.72 195.83,90.2 198.53,198.56 H 685.83 C 683.81,930.73 642.36,869.73 575.89,825.05 508.86,779.99 416.5,751.75 314.33,750.83 Z" />
+	
+		<radialGradient
+   id="path27390_00000137113957019434214490000004953697350998814607_"
+   cx="1114.9054"
+   cy="1341.5286"
+   r="381.78589"
+   gradientTransform="matrix(1,0,0,-0.6743,-806.9696,1908.9574)"
+   gradientUnits="userSpaceOnUse">
+		<stop
+   offset="0"
+   style="stop-color:#323232"
+   id="stop1" />
+		<stop
+   offset="0.0769"
+   style="stop-color:#F9D1D2"
+   id="stop2" />
+		<stop
+   offset="0.2629"
+   style="stop-color:#831A1F;stop-opacity:0"
+   id="stop3" />
+		<stop
+   offset="0.5"
+   style="stop-color:#A31F24;stop-opacity:0.3451"
+   id="stop4" />
+		<stop
+   offset="0.782"
+   style="stop-color:#BD2E31;stop-opacity:0.5451"
+   id="stop5" />
+		<stop
+   offset="0.9006"
+   style="stop-color:#841B1F;stop-opacity:0.4824"
+   id="stop6" />
+		<stop
+   offset="1"
+   style="stop-color:#393A3A"
+   id="stop7" />
+	</radialGradient>
+	
+		<path
+   id="path27390"
+   style="clip-rule:evenodd;fill:url(#path27390_00000137113957019434214490000004953697350998814607_);fill-rule:evenodd;stroke:#040000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:0.331"
+   d="m 314.33,750.82 v 48.66 c 108.36,2.72 195.83,90.2 198.53,198.56 H 685.83 C 683.81,930.72 642.36,869.72 575.89,825.04 508.86,779.99 416.5,751.75 314.33,750.82 Z" />
+	
+		<radialGradient
+   id="path40850_00000053507904088158860120000009903788965790649002_"
+   cx="666.93323"
+   cy="336.80301"
+   r="185.75"
+   gradientTransform="matrix(1,0,0,-0.6655,-108.5895,1137.4078)"
+   gradientUnits="userSpaceOnUse">
+		<stop
+   offset="0"
+   style="stop-color:#821A1F"
+   id="stop8" />
+		<stop
+   offset="1"
+   style="stop-color:#821A1F;stop-opacity:0"
+   id="stop9" />
+	</radialGradient>
+	
+		<path
+   id="path40850"
+   style="clip-rule:evenodd;opacity:0.5352;fill:url(#path40850_00000053507904088158860120000009903788965790649002_);fill-rule:evenodd;enable-background:new"
+   d="m 314.33,750.82 v 48.66 c 108.36,2.72 195.83,90.2 198.53,198.56 H 685.83 C 683.81,930.72 642.36,869.72 575.89,825.04 508.86,779.99 416.5,751.75 314.33,750.82 Z" />
+	
+		<radialGradient
+   id="path41745_00000105395135201026400770000004294659394890368675_"
+   cx="1471.5319"
+   cy="515.90259"
+   r="185.75"
+   gradientTransform="matrix(0.5746,-0.00460262,-0.00331358,-0.4137,-406.6095,1072.9193)"
+   gradientUnits="userSpaceOnUse">
+		<stop
+   offset="0"
+   style="stop-color:#821A1F"
+   id="stop10" />
+		<stop
+   offset="1"
+   style="stop-color:#821A1F;stop-opacity:0"
+   id="stop11" />
+	</radialGradient>
+	
+		<path
+   id="path41745"
+   style="clip-rule:evenodd;opacity:0.5352;fill:url(#path41745_00000105395135201026400770000004294659394890368675_);fill-rule:evenodd;enable-background:new"
+   d="m 314.33,750.82 v 48.66 c 108.36,2.72 195.83,90.2 198.53,198.56 H 685.83 C 683.81,930.72 642.36,869.72 575.89,825.04 508.86,779.99 416.5,751.75 314.33,750.82 Z" />
+	
+		<radialGradient
+   id="path48052_00000165937496115156358410000014152596680545459391_"
+   cx="364.24109"
+   cy="477.77121"
+   r="379.28589"
+   gradientTransform="matrix(1,-0.00226167,-0.00301218,-1.3318,-107.4204,1435.8314)"
+   gradientUnits="userSpaceOnUse">
+		<stop
+   offset="0"
+   style="stop-color:#FFFFFF"
+   id="stop12" />
+		<stop
+   offset="1"
+   style="stop-color:#FFFFFF;stop-opacity:0"
+   id="stop13" />
+	</radialGradient>
+	
+		<path
+   id="path48052"
+   style="clip-rule:evenodd;opacity:0.1761;fill:url(#path48052_00000165937496115156358410000014152596680545459391_);fill-rule:evenodd;enable-background:new"
+   d="m 314.32,750.83 v 48.66 c 108.36,2.72 195.83,90.2 198.53,198.56 h 90.97 C 626.61,967.74 643,933.86 651.41,897.67 632.73,870.56 607.06,846 575.88,825.05 508.85,779.99 416.49,751.76 314.32,750.83 Z" />
+	
+		<radialGradient
+   id="path48078_00000011753432873456411560000001982600393105500593_"
+   cx="486.67181"
+   cy="453.44189"
+   r="185.75"
+   gradientTransform="matrix(1,0,0,-0.6655,-108.5895,1137.4092)"
+   gradientUnits="userSpaceOnUse">
+		<stop
+   offset="0"
+   style="stop-color:#FFFFFF"
+   id="stop14" />
+		<stop
+   offset="1"
+   style="stop-color:#FFFFFF;stop-opacity:0"
+   id="stop15" />
+	</radialGradient>
+	
+		<path
+   id="path48078"
+   style="clip-rule:evenodd;opacity:0.1972;fill:url(#path48078_00000011753432873456411560000001982600393105500593_);fill-rule:evenodd;enable-background:new"
+   d="m 314.32,750.83 v 12.03 c 6.33,-0.21 12.69,-0.31 19.09,-0.31 190.55,0 317.63,102.5 331.22,235.5 h 21.19 C 683.8,930.73 642.35,869.73 575.88,825.05 508.85,779.99 416.49,751.76 314.32,750.83 Z" />
+</g>
+</svg>
diff --git a/images/color/red_highlight.svg b/images/color/red_highlight.svg
new file mode 100644
index 0000000..43504e3
--- /dev/null
+++ b/images/color/red_highlight.svg
@@ -0,0 +1,188 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   version="1.1"
+   id="layer_1"
+   x="0px"
+   y="0px"
+   viewBox="0 0 347.25 250"
+   xml:space="preserve"
+   sodipodi:docname="red_highlight.svg"
+   width="347.25"
+   height="250"
+   inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg"><defs
+   id="defs15" /><sodipodi:namedview
+   id="namedview15"
+   pagecolor="#ffffff"
+   bordercolor="#000000"
+   borderopacity="0.25"
+   inkscape:showpageshadow="2"
+   inkscape:pageopacity="0.0"
+   inkscape:pagecheckerboard="0"
+   inkscape:deskcolor="#d1d1d1"
+   inkscape:zoom="1.2924837"
+   inkscape:cx="396.13652"
+   inkscape:cy="305.99999"
+   inkscape:window-width="1920"
+   inkscape:window-height="1001"
+   inkscape:window-x="1911"
+   inkscape:window-y="-9"
+   inkscape:window-maximized="1"
+   inkscape:current-layer="layer_1" />
+<style
+   type="text/css"
+   id="style1">
+	.st0{fill-rule:evenodd;clip-rule:evenodd;fill:#E7211A;}
+	
+		.st1{opacity:0.5;fill-rule:evenodd;clip-rule:evenodd;fill:url(#path49086_00000007400659765346506100000009882442648106408633_);stroke:#040000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:0.331;enable-background:new    ;}
+	
+		.st2{opacity:0.5352;fill-rule:evenodd;clip-rule:evenodd;fill:url(#path49088_00000154402871267858631560000011123965789897339313_);enable-background:new    ;}
+	
+		.st3{opacity:0.2394;fill-rule:evenodd;clip-rule:evenodd;fill:url(#path49090_00000059995565381919725410000002489727941950454416_);enable-background:new    ;}
+	
+		.st4{opacity:0.1761;fill-rule:evenodd;clip-rule:evenodd;fill:url(#path49092_00000085250855370913651110000004514189976051801730_);enable-background:new    ;}
+	
+		.st5{opacity:0.1972;fill-rule:evenodd;clip-rule:evenodd;fill:url(#path49094_00000029727046107930941000000014102528012560749698_);enable-background:new    ;}
+</style>
+<g
+   id="red_highlight"
+   transform="matrix(0.92971832,0,0,0.99996388,-324.86218,-602.33824)">
+	<path
+   id="path49084"
+   class="st0"
+   d="m 350.42,603.37 v 48.66 c 108.36,2.72 195.83,90.2 198.53,198.56 H 721.92 C 719.9,783.27 678.45,722.27 611.98,677.59 544.96,632.53 452.59,604.29 350.42,603.37 Z" />
+	
+		<radialGradient
+   id="path49086_00000088123563754489200550000014464248633402128799_"
+   cx="1179.3438"
+   cy="381.48999"
+   r="381.78589"
+   gradientTransform="matrix(1,0,0,-0.6743,-835.3151,1114.1246)"
+   gradientUnits="userSpaceOnUse">
+		<stop
+   offset="0"
+   style="stop-color:#323232"
+   id="stop1" />
+		<stop
+   offset="0.0769"
+   style="stop-color:#F9D1D2"
+   id="stop2" />
+		<stop
+   offset="0.2629"
+   style="stop-color:#831A1F;stop-opacity:0"
+   id="stop3" />
+		<stop
+   offset="0.5"
+   style="stop-color:#A31F24;stop-opacity:0.3451"
+   id="stop4" />
+		<stop
+   offset="0.782"
+   style="stop-color:#BD2E31;stop-opacity:0.5451"
+   id="stop5" />
+		<stop
+   offset="0.9006"
+   style="stop-color:#841B1F;stop-opacity:0.4824"
+   id="stop6" />
+		<stop
+   offset="1"
+   style="stop-color:#393A3A"
+   id="stop7" />
+	</radialGradient>
+	
+		<path
+   id="path49086"
+   style="clip-rule:evenodd;opacity:0.5;fill:url(#path49086_00000088123563754489200550000014464248633402128799_);fill-rule:evenodd;stroke:#040000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:0.331;enable-background:new"
+   d="m 350.42,603.36 v 48.66 c 108.36,2.72 195.83,90.2 198.53,198.56 H 721.92 C 719.9,783.26 678.45,722.26 611.98,677.58 544.95,632.53 452.59,604.29 350.42,603.36 Z" />
+	
+		<radialGradient
+   id="path49088_00000009579967759151284600000014993876448802444697_"
+   cx="731.37152"
+   cy="-633.9104"
+   r="185.75"
+   gradientTransform="matrix(1,0,0,-0.6655,-136.935,343.4033)"
+   gradientUnits="userSpaceOnUse">
+		<stop
+   offset="0"
+   style="stop-color:#821A1F"
+   id="stop8" />
+		<stop
+   offset="1"
+   style="stop-color:#821A1F;stop-opacity:0"
+   id="stop9" />
+	</radialGradient>
+	
+		<path
+   id="path49088"
+   style="clip-rule:evenodd;opacity:0.5352;fill:url(#path49088_00000009579967759151284600000014993876448802444697_);fill-rule:evenodd;enable-background:new"
+   d="m 350.42,602.79 v 48.66 c 108.36,2.72 195.83,90.2 198.53,198.56 H 721.92 C 719.9,782.69 678.45,721.69 611.98,677.01 544.95,631.96 452.59,603.72 350.42,602.79 Z" />
+	
+		<radialGradient
+   id="path49090_00000105422793748167587710000008537505370322311835_"
+   cx="1552.7554"
+   cy="-950.00238"
+   r="185.75"
+   gradientTransform="matrix(0.5746,-0.00460262,-0.00331358,-0.4137,-422.046,318.8405)"
+   gradientUnits="userSpaceOnUse">
+		<stop
+   offset="0"
+   style="stop-color:#821A1F"
+   id="stop10" />
+		<stop
+   offset="1"
+   style="stop-color:#821A1F;stop-opacity:0"
+   id="stop11" />
+	</radialGradient>
+	
+		<path
+   id="path49090"
+   style="clip-rule:evenodd;opacity:0.2394;fill:url(#path49090_00000105422793748167587710000008537505370322311835_);fill-rule:evenodd;enable-background:new"
+   d="m 350.42,602.79 v 48.66 c 108.36,2.72 195.83,90.2 198.53,198.56 H 721.92 C 719.9,782.69 678.45,721.69 611.98,677.01 544.95,631.96 452.59,603.72 350.42,602.79 Z" />
+	
+		<radialGradient
+   id="path49092_00000126319401202548710930000000408607587414488252_"
+   cx="427.45599"
+   cy="-86.358398"
+   r="379.28589"
+   gradientTransform="matrix(1,-0.00226167,-0.00301218,-1.3318,-136.2418,537.1832)"
+   gradientUnits="userSpaceOnUse">
+		<stop
+   offset="0"
+   style="stop-color:#FFFFFF"
+   id="stop12" />
+		<stop
+   offset="1"
+   style="stop-color:#FFFFFF;stop-opacity:0"
+   id="stop13" />
+	</radialGradient>
+	
+		<path
+   id="path49092"
+   style="clip-rule:evenodd;opacity:0.1761;fill:url(#path49092_00000126319401202548710930000000408607587414488252_);fill-rule:evenodd;enable-background:new"
+   d="m 350.41,603.37 v 48.66 c 108.36,2.72 195.83,90.2 198.53,198.56 h 90.97 C 662.7,820.28 679.09,786.4 687.5,750.21 668.82,723.1 643.15,698.54 611.97,677.59 544.94,632.53 452.58,604.3 350.41,603.37 Z" />
+	
+		<radialGradient
+   id="path49094_00000155847793702457443990000014782902820458712458_"
+   cx="338.34149"
+   cy="-567.78027"
+   r="379.28589"
+   gradientTransform="matrix(1,0.00594694,0.00301218,-0.5065,-137.6906,351.3566)"
+   gradientUnits="userSpaceOnUse">
+		<stop
+   offset="0"
+   style="stop-color:#FFFFFF"
+   id="stop14" />
+		<stop
+   offset="1"
+   style="stop-color:#FFFFFF;stop-opacity:0"
+   id="stop15" />
+	</radialGradient>
+	
+		<path
+   id="path49094"
+   style="clip-rule:evenodd;opacity:0.1972;fill:url(#path49094_00000155847793702457443990000014782902820458712458_);fill-rule:evenodd;enable-background:new"
+   d="m 350.41,603.37 v 12.03 c 6.33,-0.21 12.69,-0.31 19.09,-0.31 190.55,0 317.63,102.5 331.22,235.5 h 21.19 C 719.89,783.27 678.44,722.27 611.97,677.59 544.94,632.53 452.58,604.3 350.41,603.37 Z" />
+</g>
+</svg>
diff --git a/images/color/yellow.svg b/images/color/yellow.svg
new file mode 100644
index 0000000..e5d7aa6
--- /dev/null
+++ b/images/color/yellow.svg
@@ -0,0 +1,165 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   version="1.1"
+   id="layer_1"
+   x="0px"
+   y="0px"
+   viewBox="0 0 347.25 250"
+   xml:space="preserve"
+   sodipodi:docname="yellow.svg"
+   width="347.25"
+   height="250"
+   inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg"><defs
+   id="defs13" /><sodipodi:namedview
+   id="namedview13"
+   pagecolor="#ffffff"
+   bordercolor="#000000"
+   borderopacity="0.25"
+   inkscape:showpageshadow="2"
+   inkscape:pageopacity="0.0"
+   inkscape:pagecheckerboard="0"
+   inkscape:deskcolor="#d1d1d1"
+   inkscape:zoom="1.2924837"
+   inkscape:cx="396.13652"
+   inkscape:cy="305.99999"
+   inkscape:window-width="1920"
+   inkscape:window-height="1001"
+   inkscape:window-x="1911"
+   inkscape:window-y="-9"
+   inkscape:window-maximized="1"
+   inkscape:current-layer="layer_1" />
+<style
+   type="text/css"
+   id="style1">
+	.st0{fill-rule:evenodd;clip-rule:evenodd;fill:#E9BD1B;}
+	
+		.st1{fill-rule:evenodd;clip-rule:evenodd;fill:url(#path27388_00000007390922995376802790000014288275829239385521_);stroke:#040000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:0.331;}
+	
+		.st2{opacity:0.4754;fill-rule:evenodd;clip-rule:evenodd;fill:url(#path41749_00000121257938634359593800000012126117125210795192_);enable-background:new    ;}
+	
+		.st3{opacity:0.1021;fill-rule:evenodd;clip-rule:evenodd;fill:url(#path47998_00000117666679933676951420000008818754639384450459_);enable-background:new    ;}
+	
+		.st4{opacity:0.257;fill-rule:evenodd;clip-rule:evenodd;fill:url(#path48007_00000118393246674199960730000008031841035827927466_);enable-background:new    ;}
+</style>
+<g
+   id="yellow_normal"
+   transform="matrix(0.92971834,0,0,0.99867763,-303.19045,-755.22)">
+	<path
+   id="path27380"
+   class="st0"
+   d="m 698.62,757.22 c -102.17,0.93 -194.53,29.16 -261.56,74.22 -66.47,44.68 -107.92,105.68 -109.94,173 h 172.94 c 2.7,-108.36 90.21,-195.85 198.56,-198.56 z" />
+	
+		<radialGradient
+   id="path27388_00000028319886440632200980000010314327820123833228_"
+   cx="1504.7948"
+   cy="1329.6599"
+   r="381.78589"
+   gradientTransform="matrix(1,0,0,-0.6743,-802.1964,1907.3481)"
+   gradientUnits="userSpaceOnUse">
+		<stop
+   offset="0"
+   style="stop-color:#323232"
+   id="stop1" />
+		<stop
+   offset="0.0769"
+   style="stop-color:#FBF9D3"
+   id="stop2" />
+		<stop
+   offset="0.2629"
+   style="stop-color:#867D2A;stop-opacity:0"
+   id="stop3" />
+		<stop
+   offset="0.5"
+   style="stop-color:#A89E1C;stop-opacity:0.3451"
+   id="stop4" />
+		<stop
+   offset="0.782"
+   style="stop-color:#C0B734;stop-opacity:0.5451"
+   id="stop5" />
+		<stop
+   offset="0.9006"
+   style="stop-color:#86802B;stop-opacity:0.4824"
+   id="stop6" />
+		<stop
+   offset="1"
+   style="stop-color:#393A3A"
+   id="stop7" />
+	</radialGradient>
+	
+		<path
+   id="path27388"
+   style="clip-rule:evenodd;fill:url(#path27388_00000028319886440632200980000010314327820123833228_);fill-rule:evenodd;stroke:#040000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:0.331"
+   d="m 698.61,757.22 c -102.17,0.93 -194.53,29.16 -261.56,74.22 -66.47,44.68 -107.92,105.68 -109.94,173 h 172.94 c 2.7,-108.36 90.21,-195.85 198.56,-198.56 z" />
+	
+		<radialGradient
+   id="path41749_00000145770143306937822660000003621301476068107694_"
+   cx="1115.5029"
+   cy="446.57941"
+   r="185.7502"
+   gradientTransform="matrix(0.7416,0,0,-0.4871,-331.5229,1098.3711)"
+   gradientUnits="userSpaceOnUse">
+		<stop
+   offset="0"
+   style="stop-color:#9A7A26"
+   id="stop8" />
+		<stop
+   offset="1"
+   style="stop-color:#9A7A26;stop-opacity:0"
+   id="stop9" />
+	</radialGradient>
+	
+		<path
+   id="path41749"
+   style="clip-rule:evenodd;opacity:0.4754;fill:url(#path41749_00000145770143306937822660000003621301476068107694_);fill-rule:evenodd;enable-background:new"
+   d="m 698.61,757.22 c -102.17,0.93 -194.53,29.16 -261.56,74.22 -66.47,44.68 -107.92,105.68 -109.94,173 h 172.94 c 2.7,-108.36 90.21,-195.85 198.56,-198.56 z" />
+	
+		<linearGradient
+   id="path47998_00000090994483967329618330000008837402008167169467_"
+   gradientUnits="userSpaceOnUse"
+   x1="612.53223"
+   y1="428.63049"
+   x2="653.7757"
+   y2="152.2146"
+   gradientTransform="matrix(1,0,0,-1,-103.8162,1206.0718)">
+		<stop
+   offset="0"
+   style="stop-color:#FFFFFF"
+   id="stop10" />
+		<stop
+   offset="1"
+   style="stop-color:#FFFFFF;stop-opacity:0"
+   id="stop11" />
+	</linearGradient>
+	
+		<path
+   id="path47998"
+   style="clip-rule:evenodd;opacity:0.1021;fill:url(#path47998_00000090994483967329618330000008837402008167169467_);fill-rule:evenodd;enable-background:new"
+   d="m 698.61,757.22 c -102.17,0.92 -194.53,28.96 -261.56,73.7 -45.54,30.4 -79.3,68.4 -96.72,110.82 8.89,21.53 20.7,41.97 35.09,60.98 h 124.62 c 2.7,-107.61 90.21,-194.49 198.56,-197.19 v -48.31 z" />
+	
+		<radialGradient
+   id="path48007_00000088851671310769822710000017053448804128889783_"
+   cx="-1134.6531"
+   cy="1600.9248"
+   r="170.04691"
+   gradientTransform="matrix(-0.2203,1.7096,1.3676,0.1762,-1910.7996,2330.0566)"
+   gradientUnits="userSpaceOnUse">
+		<stop
+   offset="0"
+   style="stop-color:#FFFFFF"
+   id="stop12" />
+		<stop
+   offset="1"
+   style="stop-color:#FFFFFF;stop-opacity:0"
+   id="stop13" />
+	</radialGradient>
+	
+		<path
+   id="path48007"
+   style="clip-rule:evenodd;opacity:0.257;fill:url(#path48007_00000088851671310769822710000017053448804128889783_);fill-rule:evenodd;enable-background:new"
+   d="m 698.61,757.22 c -34.61,0.31 -68.09,3.76 -99.84,9.94 -140.62,32.31 -230.34,129.3 -240.25,237.28 h 2.28 C 371.11,874.58 517.16,779.07 698.61,769.69 Z" />
+</g>
+</svg>
diff --git a/images/color/yellow_highlight.svg b/images/color/yellow_highlight.svg
new file mode 100644
index 0000000..5e63b0a
--- /dev/null
+++ b/images/color/yellow_highlight.svg
@@ -0,0 +1,164 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   version="1.1"
+   id="layer_1"
+   x="0px"
+   y="0px"
+   viewBox="0 0 374.25 250"
+   xml:space="preserve"
+   sodipodi:docname="yellow_highlight.svg"
+   width="374.25"
+   height="250"
+   inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg"><defs
+   id="defs13" /><sodipodi:namedview
+   id="namedview13"
+   pagecolor="#ffffff"
+   bordercolor="#000000"
+   borderopacity="0.25"
+   inkscape:showpageshadow="2"
+   inkscape:pageopacity="0.0"
+   inkscape:pagecheckerboard="0"
+   inkscape:deskcolor="#d1d1d1"
+   inkscape:zoom="1.2924837"
+   inkscape:cx="396.13652"
+   inkscape:cy="305.99999"
+   inkscape:window-width="1920"
+   inkscape:window-height="1001"
+   inkscape:window-x="1911"
+   inkscape:window-y="-9"
+   inkscape:window-maximized="1"
+   inkscape:current-layer="layer_1" />
+<style
+   type="text/css"
+   id="style1">
+	.st0{fill-rule:evenodd;clip-rule:evenodd;fill:#EFEA3C;}
+	
+		.st1{opacity:0.5;fill-rule:evenodd;clip-rule:evenodd;fill:url(#path49050_00000020390923318355770340000002833857294862892682_);stroke:#040000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:0.331;enable-background:new    ;}
+	
+		.st2{opacity:0.1866;fill-rule:evenodd;clip-rule:evenodd;fill:url(#path49052_00000137839318039913439300000010321817807017620115_);enable-background:new    ;}
+	
+		.st3{opacity:0.1761;fill-rule:evenodd;clip-rule:evenodd;fill:url(#path49054_00000075879811142468609280000004259611817696555674_);enable-background:new    ;}
+	
+		.st4{opacity:0.1972;fill-rule:evenodd;clip-rule:evenodd;fill:url(#path49056_00000103248099191378228130000014001420832639859134_);enable-background:new    ;}
+</style>
+<g
+   id="yellow_highlight"
+   transform="matrix(1.0024858,0,0,1.0003079,-352.20334,-1286.586)">
+	<path
+   id="path49048"
+   class="st0"
+   d="m 723.83,1287.76 c -102.17,0.93 -194.53,29.16 -261.56,74.22 -66.47,44.68 -107.92,105.68 -109.94,173 h 172.94 c 2.7,-108.36 90.21,-195.85 198.56,-198.56 z" />
+	
+		<radialGradient
+   id="path49050_00000057148608972308723630000017212283753461938588_"
+   cx="1563.701"
+   cy="1078.0957"
+   r="381.78589"
+   gradientTransform="matrix(1,0,0,-0.6743,-835.8862,2267.6858)"
+   gradientUnits="userSpaceOnUse">
+		<stop
+   offset="0"
+   style="stop-color:#323232"
+   id="stop1" />
+		<stop
+   offset="0.0769"
+   style="stop-color:#FBF9D3"
+   id="stop2" />
+		<stop
+   offset="0.2629"
+   style="stop-color:#867D2A;stop-opacity:0"
+   id="stop3" />
+		<stop
+   offset="0.5"
+   style="stop-color:#A89E1C;stop-opacity:0.3451"
+   id="stop4" />
+		<stop
+   offset="0.782"
+   style="stop-color:#C0B734;stop-opacity:0.5451"
+   id="stop5" />
+		<stop
+   offset="0.9006"
+   style="stop-color:#86802B;stop-opacity:0.4824"
+   id="stop6" />
+		<stop
+   offset="1"
+   style="stop-color:#393A3A"
+   id="stop7" />
+	</radialGradient>
+	
+		<path
+   id="path49050"
+   style="clip-rule:evenodd;opacity:0.5;fill:url(#path49050_00000057148608972308723630000017212283753461938588_);fill-rule:evenodd;stroke:#040000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:0.331;enable-background:new"
+   d="m 723.83,1287.19 c -102.17,0.93 -194.53,29.16 -261.56,74.22 -66.47,44.68 -107.92,105.68 -109.94,173 h 172.94 c 2.7,-108.36 90.21,-195.85 198.56,-198.56 z" />
+	
+		<radialGradient
+   id="path49052_00000055697574590528709220000012556362571328177082_"
+   cx="1183.3948"
+   cy="-106.3397"
+   r="185.7502"
+   gradientTransform="matrix(0.7416,0,0,-0.4871,-356.6549,1359.5702)"
+   gradientUnits="userSpaceOnUse">
+		<stop
+   offset="0"
+   style="stop-color:#9A7A26"
+   id="stop8" />
+		<stop
+   offset="1"
+   style="stop-color:#9A7A26;stop-opacity:0"
+   id="stop9" />
+	</radialGradient>
+	
+		<path
+   id="path49052"
+   style="clip-rule:evenodd;opacity:0.1866;fill:url(#path49052_00000055697574590528709220000012556362571328177082_);fill-rule:evenodd;enable-background:new"
+   d="m 723.83,1287.76 c -102.17,0.93 -194.53,29.16 -261.56,74.22 -66.47,44.68 -107.92,105.68 -109.94,173 h 172.94 c 2.7,-108.36 90.21,-195.85 198.56,-198.56 z" />
+	
+		<radialGradient
+   id="path49054_00000043449575703102263510000017721467983082905518_"
+   cx="811.82397"
+   cy="605.48419"
+   r="379.28589"
+   gradientTransform="matrix(1,-0.00226167,-0.00301218,-1.3318,-134.7397,2143.3032)"
+   gradientUnits="userSpaceOnUse">
+		<stop
+   offset="0"
+   style="stop-color:#FFFFFF"
+   id="stop10" />
+		<stop
+   offset="1"
+   style="stop-color:#FFFFFF;stop-opacity:0"
+   id="stop11" />
+	</radialGradient>
+	
+		<path
+   id="path49054"
+   style="clip-rule:evenodd;opacity:0.1761;fill:url(#path49054_00000043449575703102263510000017721467983082905518_);fill-rule:evenodd;enable-background:new"
+   d="m 723.82,1287.2 c -102.17,0.93 -194.53,29.16 -261.56,74.22 -45.54,30.61 -79.3,68.88 -96.72,111.59 8.89,21.68 20.7,42.26 35.09,61.41 h 124.63 c 2.7,-108.36 90.21,-195.85 198.56,-198.56 z" />
+	
+		<radialGradient
+   id="path49056_00000024724300295543902210000014960781455240754344_"
+   cx="722.65881"
+   cy="136.13049"
+   r="379.28589"
+   gradientTransform="matrix(1,0.00594694,0.00301218,-0.5065,-140.3351,1390.573)"
+   gradientUnits="userSpaceOnUse">
+		<stop
+   offset="0"
+   style="stop-color:#FFFFFF"
+   id="stop12" />
+		<stop
+   offset="1"
+   style="stop-color:#FFFFFF;stop-opacity:0"
+   id="stop13" />
+	</radialGradient>
+	
+		<path
+   id="path49056"
+   style="clip-rule:evenodd;opacity:0.1972;fill:url(#path49056_00000024724300295543902210000014960781455240754344_);fill-rule:evenodd;enable-background:new"
+   d="m 723.82,1288.34 c -34.61,0.31 -68.09,3.76 -99.84,9.94 -140.62,32.31 -230.34,129.3 -240.25,237.28 h 2.28 c 10.31,-129.86 156.36,-225.37 337.81,-234.75 z" />
+</g>
+</svg>
diff --git a/images/numbers/0.svg b/images/numbers/0.svg
new file mode 100644
index 0000000..b3080ec
--- /dev/null
+++ b/images/numbers/0.svg
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   version="1.1"
+   id="layer_1"
+   x="0px"
+   y="0px"
+   viewBox="0 0 62.999999 78.000003"
+   xml:space="preserve"
+   sodipodi:docname="0.svg"
+   width="63"
+   height="78"
+   inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg"><defs
+   id="defs1" /><sodipodi:namedview
+   id="namedview1"
+   pagecolor="#ffffff"
+   bordercolor="#000000"
+   borderopacity="0.25"
+   inkscape:showpageshadow="2"
+   inkscape:pageopacity="0.0"
+   inkscape:pagecheckerboard="0"
+   inkscape:deskcolor="#d1d1d1"
+   inkscape:zoom="10.106044"
+   inkscape:cx="31.46632"
+   inkscape:cy="39.134998"
+   inkscape:window-width="1920"
+   inkscape:window-height="1001"
+   inkscape:window-x="1911"
+   inkscape:window-y="-9"
+   inkscape:window-maximized="1"
+   inkscape:current-layer="layer_1" />
+<style
+   type="text/css"
+   id="style1">
+	.st0{fill:#E7211A;}
+</style>
+<g
+   id="zero"
+   transform="matrix(1.8600531,0,0,1.8288394,-27.045173,-32.57163)">
+	<path
+   id="path3957"
+   class="st0"
+   d="m 23.33,25.31 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path3965"
+   class="st0"
+   d="m 32.12,25.31 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path3969"
+   class="st0"
+   d="m 40.91,42.88 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path3971"
+   class="st0"
+   d="m 40.91,34.1 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path3973"
+   class="st0"
+   d="m 40.91,25.31 v -7.5 h 3.75 l 3.75,3.75 v 3.75 z" />
+	<path
+   id="path3975"
+   class="st0"
+   d="m 40.91,51.67 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path3977"
+   class="st0"
+   d="m 14.54,42.88 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path3979"
+   class="st0"
+   d="m 14.54,34.1 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path3981"
+   class="st0"
+   d="m 14.54,25.31 v -3.75 l 3.75,-3.75 h 3.75 v 7.5 z" />
+	<path
+   id="path3983"
+   class="st0"
+   d="m 14.54,51.67 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path3985"
+   class="st0"
+   d="m 23.33,60.46 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path3987"
+   class="st0"
+   d="m 32.12,60.46 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path3989"
+   class="st0"
+   d="m 40.91,60.46 v -7.5 h 7.5 v 3.75 l -3.75,3.75 z" />
+	<path
+   id="path3991"
+   class="st0"
+   d="m 14.54,56.71 v -3.75 h 7.5 v 7.5 h -3.75 z" />
+</g>
+</svg>
diff --git a/images/numbers/1.svg b/images/numbers/1.svg
new file mode 100644
index 0000000..97cef4e
--- /dev/null
+++ b/images/numbers/1.svg
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   version="1.1"
+   id="layer_1"
+   x="0px"
+   y="0px"
+   viewBox="0 0 62.999999 78.000003"
+   xml:space="preserve"
+   sodipodi:docname="1.svg"
+   width="63"
+   height="78"
+   inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg"><defs
+   id="defs1" /><sodipodi:namedview
+   id="namedview1"
+   pagecolor="#ffffff"
+   bordercolor="#000000"
+   borderopacity="0.25"
+   inkscape:showpageshadow="2"
+   inkscape:pageopacity="0.0"
+   inkscape:pagecheckerboard="0"
+   inkscape:deskcolor="#d1d1d1"
+   inkscape:zoom="10.106044"
+   inkscape:cx="31.46632"
+   inkscape:cy="39.134998"
+   inkscape:window-width="1920"
+   inkscape:window-height="1001"
+   inkscape:window-x="1911"
+   inkscape:window-y="-9"
+   inkscape:window-maximized="1"
+   inkscape:current-layer="layer_1" />
+<style
+   type="text/css"
+   id="style1">
+	.st0{fill:#E7211A;}
+	.st1{fill:#E7211A;fill-opacity:0;}
+</style>
+<g
+   id="one"
+   transform="matrix(1.8545776,0,0,1.8275539,-37.555196,-31.068416)">
+	<g
+   id="g3091"
+   transform="translate(-16.7872)">
+		<path
+   id="path2994"
+   class="st0"
+   d="m 45.93,42.11 v -7.5 h 7.5 v 7.5 z" />
+		<path
+   id="path2996"
+   class="st0"
+   d="m 45.93,33.32 v -7.5 h 7.5 v 7.5 z" />
+		<path
+   id="path2998"
+   class="st0"
+   d="m 45.93,24.54 v -7.5 h 7.5 v 7.5 z" />
+		<path
+   id="path3000"
+   class="st0"
+   d="m 45.93,50.9 v -7.5 h 7.5 v 7.5 z" />
+		<path
+   id="path2978"
+   class="st0"
+   d="m 37.14,24.54 v -3.75 l 3.75,-3.75 h 3.75 v 7.5 z" />
+		<path
+   id="path3045"
+   class="st0"
+   d="m 45.93,59.68 v -7.5 h 7.5 v 7.5 z" />
+	</g>
+	<path
+   id="path3060"
+   class="st1"
+   d="M 29.04,24.5 V 17 h 7.5 v 7.5 z" />
+	<path
+   id="path3062"
+   class="st1"
+   d="M 20.25,24.5 V 17 h 7.5 v 7.5 z" />
+	<path
+   id="path3058"
+   class="st1"
+   d="m 37.93,24.54 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path2170"
+   class="st1"
+   d="m 46.72,24.54 v -7.5 h 7.5 v 7.5 z" />
+</g>
+</svg>
diff --git a/images/numbers/2.svg b/images/numbers/2.svg
new file mode 100644
index 0000000..fee8bfa
--- /dev/null
+++ b/images/numbers/2.svg
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   version="1.1"
+   id="layer_1"
+   x="0px"
+   y="0px"
+   viewBox="0 0 62.999999 78.000003"
+   xml:space="preserve"
+   sodipodi:docname="2.svg"
+   width="63"
+   height="78"
+   inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg"><defs
+   id="defs1" /><sodipodi:namedview
+   id="namedview1"
+   pagecolor="#ffffff"
+   bordercolor="#000000"
+   borderopacity="0.25"
+   inkscape:showpageshadow="2"
+   inkscape:pageopacity="0.0"
+   inkscape:pagecheckerboard="0"
+   inkscape:deskcolor="#d1d1d1"
+   inkscape:zoom="10.106044"
+   inkscape:cx="31.46632"
+   inkscape:cy="39.134998"
+   inkscape:window-width="1920"
+   inkscape:window-height="1001"
+   inkscape:window-x="1911"
+   inkscape:window-y="-9"
+   inkscape:window-maximized="1"
+   inkscape:current-layer="layer_1" />
+<style
+   type="text/css"
+   id="style1">
+	.st0{fill:#E7211A;}
+</style>
+<g
+   id="two"
+   transform="matrix(1.8606025,0,0,1.8288394,-30.699941,-27.816647)">
+	<path
+   id="path4051"
+   class="st0"
+   d="m 25.29,40.29 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4055"
+   class="st0"
+   d="m 25.29,22.71 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4059"
+   class="st0"
+   d="m 34.07,40.29 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4063"
+   class="st0"
+   d="m 34.07,22.71 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4067"
+   class="st0"
+   d="m 42.86,40.29 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4069"
+   class="st0"
+   d="M 42.86,31.5 V 24 h 7.5 v 7.5 z" />
+	<path
+   id="path4071"
+   class="st0"
+   d="m 42.86,22.71 v -7.5 h 3.75 l 3.75,3.75 v 3.75 z" />
+	<path
+   id="path4075"
+   class="st0"
+   d="m 16.5,40.29 v -7.5 H 24 v 7.5 z" />
+	<path
+   id="path4079"
+   class="st0"
+   d="m 16.5,22.71 v -3.75 l 3.75,-3.75 H 24 v 7.5 z" />
+	<path
+   id="path4081"
+   class="st0"
+   d="m 16.5,49.07 v -7.5 H 24 v 7.5 z" />
+	<path
+   id="path4083"
+   class="st0"
+   d="m 25.29,57.86 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4085"
+   class="st0"
+   d="m 34.07,57.86 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4087"
+   class="st0"
+   d="m 42.86,57.86 v -7.5 h 7.5 v 3.75 l -3.75,3.75 z" />
+	<path
+   id="path4089"
+   class="st0"
+   d="M 16.5,54.11 V 50.36 H 24 v 7.5 h -3.75 z" />
+</g>
+</svg>
diff --git a/images/numbers/3.svg b/images/numbers/3.svg
new file mode 100644
index 0000000..8e6da7f
--- /dev/null
+++ b/images/numbers/3.svg
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   version="1.1"
+   id="layer_1"
+   x="0px"
+   y="0px"
+   viewBox="0 0 62.999999 78.000003"
+   xml:space="preserve"
+   sodipodi:docname="3.svg"
+   width="63"
+   height="78"
+   inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg"><defs
+   id="defs1" /><sodipodi:namedview
+   id="namedview1"
+   pagecolor="#ffffff"
+   bordercolor="#000000"
+   borderopacity="0.25"
+   inkscape:showpageshadow="2"
+   inkscape:pageopacity="0.0"
+   inkscape:pagecheckerboard="0"
+   inkscape:deskcolor="#d1d1d1"
+   inkscape:zoom="10.106044"
+   inkscape:cx="31.46632"
+   inkscape:cy="39.134998"
+   inkscape:window-width="1920"
+   inkscape:window-height="1001"
+   inkscape:window-x="1911"
+   inkscape:window-y="-9"
+   inkscape:window-maximized="1"
+   inkscape:current-layer="layer_1" />
+<style
+   type="text/css"
+   id="style1">
+	.st0{fill:#E7211A;}
+</style>
+<g
+   id="three"
+   transform="matrix(1.8606025,0,0,1.8288394,-25.992618,-27.816647)">
+	<path
+   id="path4129"
+   class="st0"
+   d="m 22.76,40.29 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4133"
+   class="st0"
+   d="m 22.76,22.71 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4137"
+   class="st0"
+   d="m 31.55,40.29 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4141"
+   class="st0"
+   d="m 31.55,22.71 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4145"
+   class="st0"
+   d="m 40.33,40.29 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4147"
+   class="st0"
+   d="M 40.33,31.5 V 24 h 7.5 v 7.5 z" />
+	<path
+   id="path4149"
+   class="st0"
+   d="m 40.33,22.71 v -7.5 h 3.75 l 3.75,3.75 v 3.75 z" />
+	<path
+   id="path4151"
+   class="st0"
+   d="m 40.33,49.07 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4153"
+   class="st0"
+   d="m 13.97,40.29 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4157"
+   class="st0"
+   d="m 13.97,22.71 v -3.75 l 3.75,-3.75 h 3.75 v 7.5 z" />
+	<path
+   id="path4161"
+   class="st0"
+   d="m 22.76,57.86 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4163"
+   class="st0"
+   d="m 31.55,57.86 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4165"
+   class="st0"
+   d="m 40.33,57.86 v -7.5 h 7.5 v 3.75 l -3.75,3.75 z" />
+	<path
+   id="path4167"
+   class="st0"
+   d="m 13.97,54.11 v -3.75 h 7.5 v 7.5 h -3.75 z" />
+</g>
+</svg>
diff --git a/images/numbers/4.svg b/images/numbers/4.svg
new file mode 100644
index 0000000..240edfa
--- /dev/null
+++ b/images/numbers/4.svg
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   version="1.1"
+   id="layer_1"
+   x="0px"
+   y="0px"
+   viewBox="0 0 62.999999 78.000003"
+   xml:space="preserve"
+   sodipodi:docname="4.svg"
+   width="63"
+   height="78"
+   inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg"><defs
+   id="defs1" /><sodipodi:namedview
+   id="namedview1"
+   pagecolor="#ffffff"
+   bordercolor="#000000"
+   borderopacity="0.25"
+   inkscape:showpageshadow="2"
+   inkscape:pageopacity="0.0"
+   inkscape:pagecheckerboard="0"
+   inkscape:deskcolor="#d1d1d1"
+   inkscape:zoom="10.106044"
+   inkscape:cx="31.46632"
+   inkscape:cy="39.134998"
+   inkscape:window-width="1920"
+   inkscape:window-height="1001"
+   inkscape:window-x="1911"
+   inkscape:window-y="-9"
+   inkscape:window-maximized="1"
+   inkscape:current-layer="layer_1" />
+<style
+   type="text/css"
+   id="style1">
+	.st0{fill:#E7211A;}
+</style>
+<g
+   id="four"
+   transform="matrix(1.8606025,0,0,1.8288394,-30.699941,-27.194842)">
+	<path
+   id="path4213"
+   class="st0"
+   d="m 25.29,39.95 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4221"
+   class="st0"
+   d="m 34.07,39.95 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4223"
+   class="st0"
+   d="m 42.86,39.95 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4225"
+   class="st0"
+   d="m 42.86,31.16 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4227"
+   class="st0"
+   d="m 42.86,22.37 v -7.5 h 3.75 l 3.75,3.75 v 3.75 z" />
+	<path
+   id="path4229"
+   class="st0"
+   d="m 42.86,48.73 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4231"
+   class="st0"
+   d="m 16.5,39.95 v -7.5 H 24 v 7.5 z" />
+	<path
+   id="path4233"
+   class="st0"
+   d="m 16.5,31.16 v -7.5 H 24 v 7.5 z" />
+	<path
+   id="path4235"
+   class="st0"
+   d="m 16.5,22.37 v -3.75 l 3.75,-3.75 H 24 v 7.5 z" />
+	<path
+   id="path4243"
+   class="st0"
+   d="m 42.86,57.52 v -7.5 h 7.5 v 3.75 l -3.75,3.75 z" />
+</g>
+</svg>
diff --git a/images/numbers/5.svg b/images/numbers/5.svg
new file mode 100644
index 0000000..82b3bb5
--- /dev/null
+++ b/images/numbers/5.svg
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   version="1.1"
+   id="layer_1"
+   x="0px"
+   y="0px"
+   viewBox="0 0 62.999999 78.000003"
+   xml:space="preserve"
+   sodipodi:docname="5.svg"
+   width="63"
+   height="78"
+   inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg"><defs
+   id="defs1" /><sodipodi:namedview
+   id="namedview1"
+   pagecolor="#ffffff"
+   bordercolor="#000000"
+   borderopacity="0.25"
+   inkscape:showpageshadow="2"
+   inkscape:pageopacity="0.0"
+   inkscape:pagecheckerboard="0"
+   inkscape:deskcolor="#d1d1d1"
+   inkscape:zoom="10.106044"
+   inkscape:cx="31.46632"
+   inkscape:cy="39.134998"
+   inkscape:window-width="1920"
+   inkscape:window-height="1001"
+   inkscape:window-x="1911"
+   inkscape:window-y="-9"
+   inkscape:window-maximized="1"
+   inkscape:current-layer="layer_1" />
+<style
+   type="text/css"
+   id="style1">
+	.st0{fill:#E7211A;}
+</style>
+<g
+   id="five"
+   transform="matrix(1.8606025,0,0,1.8288394,-30.699941,-27.011958)">
+	<path
+   id="path4287"
+   class="st0"
+   d="m 25.29,39.85 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4291"
+   class="st0"
+   d="m 25.29,22.27 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4295"
+   class="st0"
+   d="m 34.07,39.85 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4299"
+   class="st0"
+   d="m 34.07,22.27 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4303"
+   class="st0"
+   d="m 42.86,39.85 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4307"
+   class="st0"
+   d="m 42.86,22.27 v -7.5 h 3.75 l 3.75,3.75 v 3.75 z" />
+	<path
+   id="path4309"
+   class="st0"
+   d="m 42.86,48.63 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4311"
+   class="st0"
+   d="m 16.5,39.85 v -7.5 H 24 v 7.5 z" />
+	<path
+   id="path4313"
+   class="st0"
+   d="m 16.5,31.06 v -7.5 H 24 v 7.5 z" />
+	<path
+   id="path4315"
+   class="st0"
+   d="m 16.5,22.27 v -3.75 l 3.75,-3.75 H 24 v 7.5 z" />
+	<path
+   id="path4319"
+   class="st0"
+   d="m 25.29,57.42 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4321"
+   class="st0"
+   d="m 34.07,57.42 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4323"
+   class="st0"
+   d="m 42.86,57.42 v -7.5 h 7.5 v 3.75 l -3.75,3.75 z" />
+	<path
+   id="path4325"
+   class="st0"
+   d="M 16.5,53.67 V 49.92 H 24 v 7.5 h -3.75 z" />
+</g>
+</svg>
diff --git a/images/numbers/6.svg b/images/numbers/6.svg
new file mode 100644
index 0000000..c40a7d0
--- /dev/null
+++ b/images/numbers/6.svg
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   version="1.1"
+   id="layer_1"
+   x="0px"
+   y="0px"
+   viewBox="0 0 62.999999 78.000003"
+   xml:space="preserve"
+   sodipodi:docname="6.svg"
+   width="63"
+   height="78"
+   inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg"><defs
+   id="defs1" /><sodipodi:namedview
+   id="namedview1"
+   pagecolor="#ffffff"
+   bordercolor="#000000"
+   borderopacity="0.25"
+   inkscape:showpageshadow="2"
+   inkscape:pageopacity="0.0"
+   inkscape:pagecheckerboard="0"
+   inkscape:deskcolor="#d1d1d1"
+   inkscape:zoom="10.106044"
+   inkscape:cx="31.46632"
+   inkscape:cy="39.134998"
+   inkscape:window-width="1920"
+   inkscape:window-height="1001"
+   inkscape:window-x="1911"
+   inkscape:window-y="-9"
+   inkscape:window-maximized="1"
+   inkscape:current-layer="layer_1" />
+<style
+   type="text/css"
+   id="style1">
+	.st0{fill:#E7211A;}
+</style>
+<g
+   id="six"
+   transform="matrix(1.8606025,0,0,1.8288394,-31.890727,-27.816647)">
+	<path
+   id="path4365"
+   class="st0"
+   d="m 25.93,40.29 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4369"
+   class="st0"
+   d="m 25.93,22.71 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4373"
+   class="st0"
+   d="m 34.72,40.29 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4377"
+   class="st0"
+   d="m 34.72,22.71 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4382"
+   class="st0"
+   d="m 43.5,40.29 v -7.5 H 51 v 7.5 z" />
+	<path
+   id="path4386"
+   class="st0"
+   d="m 43.5,22.71 v -7.5 h 3.75 L 51,18.96 v 3.75 z" />
+	<path
+   id="path4388"
+   class="st0"
+   d="m 43.5,49.07 v -7.5 H 51 v 7.5 z" />
+	<path
+   id="path4390"
+   class="st0"
+   d="m 17.14,40.29 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4392"
+   class="st0"
+   d="M 17.14,31.5 V 24 h 7.5 v 7.5 z" />
+	<path
+   id="path4394"
+   class="st0"
+   d="m 17.14,22.71 v -3.75 l 3.75,-3.75 h 3.75 v 7.5 z" />
+	<path
+   id="path4396"
+   class="st0"
+   d="m 17.14,49.07 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4398"
+   class="st0"
+   d="m 25.93,57.86 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4400"
+   class="st0"
+   d="m 34.72,57.86 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4402"
+   class="st0"
+   d="m 43.5,57.86 v -7.5 H 51 v 3.75 l -3.75,3.75 z" />
+	<path
+   id="path4404"
+   class="st0"
+   d="m 17.14,54.11 v -3.75 h 7.5 v 7.5 h -3.75 z" />
+</g>
+</svg>
diff --git a/images/numbers/7.svg b/images/numbers/7.svg
new file mode 100644
index 0000000..8cbba40
--- /dev/null
+++ b/images/numbers/7.svg
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   version="1.1"
+   id="layer_1"
+   x="0px"
+   y="0px"
+   viewBox="0 0 62.999999 78.000003"
+   xml:space="preserve"
+   sodipodi:docname="7.svg"
+   width="63"
+   height="78"
+   inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg"><defs
+   id="defs1" /><sodipodi:namedview
+   id="namedview1"
+   pagecolor="#ffffff"
+   bordercolor="#000000"
+   borderopacity="0.25"
+   inkscape:showpageshadow="2"
+   inkscape:pageopacity="0.0"
+   inkscape:pagecheckerboard="0"
+   inkscape:deskcolor="#d1d1d1"
+   inkscape:zoom="10.106044"
+   inkscape:cx="31.46632"
+   inkscape:cy="39.134998"
+   inkscape:window-width="1920"
+   inkscape:window-height="1001"
+   inkscape:window-x="1911"
+   inkscape:window-y="-9"
+   inkscape:window-maximized="1"
+   inkscape:current-layer="layer_1" />
+<style
+   type="text/css"
+   id="style1">
+	.st0{fill:#E7211A;}
+</style>
+<g
+   id="seven"
+   transform="matrix(1.8600531,0,0,1.8288394,-27.045173,-29.1517)">
+	<path
+   id="path4449"
+   class="st0"
+   d="m 23.33,23.44 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4457"
+   class="st0"
+   d="m 32.12,23.44 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4461"
+   class="st0"
+   d="m 40.91,41.02 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4463"
+   class="st0"
+   d="m 40.91,32.23 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4465"
+   class="st0"
+   d="m 40.91,23.44 v -7.5 h 3.75 l 3.75,3.75 v 3.75 z" />
+	<path
+   id="path4467"
+   class="st0"
+   d="m 40.91,49.81 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4473"
+   class="st0"
+   d="m 14.54,23.44 v -3.75 l 3.75,-3.75 h 3.75 v 7.5 z" />
+	<path
+   id="path4481"
+   class="st0"
+   d="m 40.91,58.59 v -7.5 h 7.5 v 3.75 l -3.75,3.75 z" />
+</g>
+</svg>
diff --git a/images/numbers/8.svg b/images/numbers/8.svg
new file mode 100644
index 0000000..0db9fed
--- /dev/null
+++ b/images/numbers/8.svg
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   version="1.1"
+   id="layer_1"
+   x="0px"
+   y="0px"
+   viewBox="0 0 62.999999 78.000003"
+   xml:space="preserve"
+   sodipodi:docname="8.svg"
+   width="63"
+   height="78"
+   inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg"><defs
+   id="defs1" /><sodipodi:namedview
+   id="namedview1"
+   pagecolor="#ffffff"
+   bordercolor="#000000"
+   borderopacity="0.25"
+   inkscape:showpageshadow="2"
+   inkscape:pageopacity="0.0"
+   inkscape:pagecheckerboard="0"
+   inkscape:deskcolor="#d1d1d1"
+   inkscape:zoom="10.106044"
+   inkscape:cx="31.46632"
+   inkscape:cy="39.134998"
+   inkscape:window-width="1920"
+   inkscape:window-height="1001"
+   inkscape:window-x="1911"
+   inkscape:window-y="-9"
+   inkscape:window-maximized="1"
+   inkscape:current-layer="layer_1" />
+<style
+   type="text/css"
+   id="style1">
+	.st0{fill:#E7211A;}
+</style>
+<g
+   id="eight"
+   transform="matrix(1.8606025,0,0,1.8288394,-32.709392,-27.816647)">
+	<path
+   id="path4517"
+   class="st0"
+   d="m 26.37,40.29 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4521"
+   class="st0"
+   d="m 26.37,22.71 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4525"
+   class="st0"
+   d="m 35.16,40.29 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4529"
+   class="st0"
+   d="m 35.16,22.71 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4533"
+   class="st0"
+   d="m 43.94,40.29 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4535"
+   class="st0"
+   d="M 43.94,31.5 V 24 h 7.5 v 7.5 z" />
+	<path
+   id="path4537"
+   class="st0"
+   d="m 43.94,22.71 v -7.5 h 3.75 l 3.75,3.75 v 3.75 z" />
+	<path
+   id="path4539"
+   class="st0"
+   d="m 43.94,49.07 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4541"
+   class="st0"
+   d="m 17.58,40.29 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4543"
+   class="st0"
+   d="M 17.58,31.5 V 24 h 7.5 v 7.5 z" />
+	<path
+   id="path4545"
+   class="st0"
+   d="m 17.58,22.71 v -3.75 l 3.75,-3.75 h 3.75 v 7.5 z" />
+	<path
+   id="path4547"
+   class="st0"
+   d="m 17.58,49.07 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4549"
+   class="st0"
+   d="m 26.37,57.86 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4551"
+   class="st0"
+   d="m 35.16,57.86 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4553"
+   class="st0"
+   d="m 43.94,57.86 v -7.5 h 7.5 v 3.75 l -3.75,3.75 z" />
+	<path
+   id="path4555"
+   class="st0"
+   d="m 17.58,54.11 v -3.75 h 7.5 v 7.5 h -3.75 z" />
+</g>
+</svg>
diff --git a/images/numbers/9.svg b/images/numbers/9.svg
new file mode 100644
index 0000000..d39f80a
--- /dev/null
+++ b/images/numbers/9.svg
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   version="1.1"
+   id="layer_1"
+   x="0px"
+   y="0px"
+   viewBox="0 0 62.999999 78.000003"
+   xml:space="preserve"
+   sodipodi:docname="9.svg"
+   width="63"
+   height="78"
+   inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg"><defs
+   id="defs1" /><sodipodi:namedview
+   id="namedview1"
+   pagecolor="#ffffff"
+   bordercolor="#000000"
+   borderopacity="0.25"
+   inkscape:showpageshadow="2"
+   inkscape:pageopacity="0.0"
+   inkscape:pagecheckerboard="0"
+   inkscape:deskcolor="#d1d1d1"
+   inkscape:zoom="10.106044"
+   inkscape:cx="31.46632"
+   inkscape:cy="39.134998"
+   inkscape:window-width="1920"
+   inkscape:window-height="1001"
+   inkscape:window-x="1911"
+   inkscape:window-y="-9"
+   inkscape:window-maximized="1"
+   inkscape:current-layer="layer_1" />
+<style
+   type="text/css"
+   id="style1">
+	.st0{fill:#E7211A;}
+</style>
+<g
+   id="nine"
+   transform="matrix(1.8606025,0,0,1.8288394,-30.346426,-30.322157)">
+	<path
+   id="path4597"
+   class="st0"
+   d="m 25.1,41.65 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4601"
+   class="st0"
+   d="m 25.1,24.08 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4605"
+   class="st0"
+   d="m 33.89,41.65 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4610"
+   class="st0"
+   d="m 33.89,24.08 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4614"
+   class="st0"
+   d="m 42.67,41.65 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4616"
+   class="st0"
+   d="m 42.67,32.87 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4618"
+   class="st0"
+   d="m 42.67,24.08 v -7.5 h 3.75 l 3.75,3.75 v 3.75 z" />
+	<path
+   id="path4620"
+   class="st0"
+   d="m 42.67,50.44 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4622"
+   class="st0"
+   d="m 16.31,41.65 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4624"
+   class="st0"
+   d="m 16.31,32.87 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4626"
+   class="st0"
+   d="m 16.31,24.08 v -3.75 l 3.75,-3.75 h 3.75 v 7.5 z" />
+	<path
+   id="path4630"
+   class="st0"
+   d="m 25.1,59.23 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4632"
+   class="st0"
+   d="m 33.89,59.23 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4634"
+   class="st0"
+   d="m 42.67,59.23 v -7.5 h 7.5 v 3.75 l -3.75,3.75 z" />
+	<path
+   id="path4636"
+   class="st0"
+   d="m 16.31,55.48 v -3.75 h 7.5 v 7.5 h -3.75 z" />
+</g>
+</svg>
diff --git a/images/numbers/blackBlock.svg b/images/numbers/blackBlock.svg
new file mode 100644
index 0000000..0d4b3d9
--- /dev/null
+++ b/images/numbers/blackBlock.svg
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   version="1.1"
+   id="layer_1"
+   x="0px"
+   y="0px"
+   viewBox="0 0 80 59.999998"
+   xml:space="preserve"
+   sodipodi:docname="my_blackBlock.svg"
+   width="80"
+   height="60"
+   inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg"><defs
+   id="defs1" /><sodipodi:namedview
+   id="namedview1"
+   pagecolor="#ffffff"
+   bordercolor="#000000"
+   borderopacity="0.25"
+   inkscape:showpageshadow="2"
+   inkscape:pageopacity="0.0"
+   inkscape:pagecheckerboard="0"
+   inkscape:deskcolor="#d1d1d1"
+   inkscape:zoom="10.102171"
+   inkscape:cx="31.478383"
+   inkscape:cy="39.150002"
+   inkscape:window-width="1920"
+   inkscape:window-height="1001"
+   inkscape:window-x="1911"
+   inkscape:window-y="-9"
+   inkscape:window-maximized="1"
+   inkscape:current-layer="layer_1" />
+<style
+   type="text/css"
+   id="style1">
+	.st0{fill:#373737;}
+</style>
+<path
+   id="led_on"
+   class="st0"
+   d="M 0,60 V 0 h 80 v 60 z"
+   style="stroke-width:5.56038" />
+</svg>
diff --git a/images/numbers/blank.svg b/images/numbers/blank.svg
new file mode 100644
index 0000000..f2f6d4a
--- /dev/null
+++ b/images/numbers/blank.svg
@@ -0,0 +1,124 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   version="1.1"
+   id="layer_1"
+   x="0px"
+   y="0px"
+   viewBox="0 0 62.999999 78.000003"
+   xml:space="preserve"
+   sodipodi:docname="blank.svg"
+   width="63"
+   height="78"
+   inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg"><defs
+   id="defs1" /><sodipodi:namedview
+   id="namedview1"
+   pagecolor="#ffffff"
+   bordercolor="#000000"
+   borderopacity="0.25"
+   inkscape:showpageshadow="2"
+   inkscape:pageopacity="0.0"
+   inkscape:pagecheckerboard="0"
+   inkscape:deskcolor="#d1d1d1"
+   inkscape:zoom="10.106044"
+   inkscape:cx="31.46632"
+   inkscape:cy="39.134998"
+   inkscape:window-width="1920"
+   inkscape:window-height="1001"
+   inkscape:window-x="1911"
+   inkscape:window-y="-9"
+   inkscape:window-maximized="1"
+   inkscape:current-layer="layer_1" />
+<style
+   type="text/css"
+   id="style1">
+	.st0{fill:#373737;}
+</style>
+<g
+   id="all_off"
+   transform="matrix(1.8606025,0,0,1.8288394,-31.890727,-31.126846)">
+	<path
+   id="path2984"
+   class="st0"
+   d="m 25.93,42.09 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path2986"
+   class="st0"
+   d="m 25.93,33.3 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path2988"
+   class="st0"
+   d="m 25.93,24.52 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path2990"
+   class="st0"
+   d="m 25.93,50.88 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4005"
+   class="st0"
+   d="m 34.72,42.09 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4007"
+   class="st0"
+   d="m 34.72,33.3 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4009"
+   class="st0"
+   d="m 34.72,24.52 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4011"
+   class="st0"
+   d="m 34.72,50.88 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path3004"
+   class="st0"
+   d="m 43.5,42.09 v -7.5 H 51 v 7.5 z" />
+	<path
+   id="path3006"
+   class="st0"
+   d="M 43.5,33.3 V 25.8 H 51 v 7.5 z" />
+	<path
+   id="path3008"
+   class="st0"
+   d="m 43.5,24.52 v -7.5 h 3.75 L 51,20.77 v 3.75 z" />
+	<path
+   id="path3010"
+   class="st0"
+   d="m 43.5,50.88 v -7.5 H 51 v 7.5 z" />
+	<path
+   id="path2974"
+   class="st0"
+   d="m 17.14,42.09 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path2976"
+   class="st0"
+   d="m 17.14,33.3 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4019"
+   class="st0"
+   d="m 17.14,24.52 v -3.75 l 3.75,-3.75 h 3.75 v 7.5 z" />
+	<path
+   id="path2980"
+   class="st0"
+   d="m 17.14,50.88 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path3043"
+   class="st0"
+   d="m 25.93,59.67 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path4023"
+   class="st0"
+   d="m 34.72,59.67 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path3047"
+   class="st0"
+   d="m 43.5,59.67 v -7.5 H 51 v 3.75 l -3.75,3.75 z" />
+	<path
+   id="path3049"
+   class="st0"
+   d="m 17.14,55.92 v -3.75 h 7.5 v 7.5 h -3.75 z" />
+</g>
+</svg>
diff --git a/images/numbers/full.svg b/images/numbers/full.svg
new file mode 100644
index 0000000..7829e00
--- /dev/null
+++ b/images/numbers/full.svg
@@ -0,0 +1,124 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   version="1.1"
+   id="layer_1"
+   x="0px"
+   y="0px"
+   viewBox="0 0 62.999999 78.000003"
+   xml:space="preserve"
+   sodipodi:docname="full.svg"
+   width="63"
+   height="78"
+   inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg"><defs
+   id="defs1" /><sodipodi:namedview
+   id="namedview1"
+   pagecolor="#ffffff"
+   bordercolor="#000000"
+   borderopacity="0.25"
+   inkscape:showpageshadow="2"
+   inkscape:pageopacity="0.0"
+   inkscape:pagecheckerboard="0"
+   inkscape:deskcolor="#d1d1d1"
+   inkscape:zoom="10.106044"
+   inkscape:cx="31.46632"
+   inkscape:cy="39.134998"
+   inkscape:window-width="1920"
+   inkscape:window-height="1001"
+   inkscape:window-x="1911"
+   inkscape:window-y="-9"
+   inkscape:window-maximized="1"
+   inkscape:current-layer="layer_1" />
+<style
+   type="text/css"
+   id="style1">
+	.st0{fill:#E7211A;}
+</style>
+<g
+   id="all_on"
+   transform="matrix(1.8606025,0,0,1.8288394,-28.169522,-30.17585)">
+	<path
+   id="path6515"
+   class="st0"
+   d="m 23.93,41.57 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path6517"
+   class="st0"
+   d="m 23.93,32.79 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path6519"
+   class="st0"
+   d="m 23.93,24 v -7.5 h 7.5 V 24 Z" />
+	<path
+   id="path6521"
+   class="st0"
+   d="m 23.93,50.36 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path6523"
+   class="st0"
+   d="m 32.72,41.57 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path6525"
+   class="st0"
+   d="m 32.72,32.79 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path6527"
+   class="st0"
+   d="m 32.72,24 v -7.5 h 7.5 V 24 Z" />
+	<path
+   id="path6529"
+   class="st0"
+   d="m 32.72,50.36 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path6531"
+   class="st0"
+   d="m 41.5,41.57 v -7.5 H 49 v 7.5 z" />
+	<path
+   id="path6533"
+   class="st0"
+   d="m 41.5,32.79 v -7.5 H 49 v 7.5 z" />
+	<path
+   id="path6535"
+   class="st0"
+   d="m 41.5,24 v -7.5 h 3.75 L 49,20.25 V 24 Z" />
+	<path
+   id="path6537"
+   class="st0"
+   d="m 41.5,50.36 v -7.5 H 49 v 7.5 z" />
+	<path
+   id="path6539"
+   class="st0"
+   d="m 15.14,41.57 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path6541"
+   class="st0"
+   d="m 15.14,32.79 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path6543"
+   class="st0"
+   d="m 15.14,24 v -3.75 l 3.75,-3.75 h 3.75 V 24 Z" />
+	<path
+   id="path6545"
+   class="st0"
+   d="m 15.14,50.36 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path6547"
+   class="st0"
+   d="m 23.93,59.15 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path6549"
+   class="st0"
+   d="m 32.72,59.15 v -7.5 h 7.5 v 7.5 z" />
+	<path
+   id="path6551"
+   class="st0"
+   d="m 41.5,59.15 v -7.5 H 49 v 3.75 l -3.75,3.75 z" />
+	<path
+   id="path6553"
+   class="st0"
+   d="m 15.14,55.4 v -3.75 h 7.5 v 7.5 h -3.75 z" />
+</g>
+</svg>
diff --git a/images/numbers/redBlock.svg b/images/numbers/redBlock.svg
new file mode 100644
index 0000000..5e66cf7
--- /dev/null
+++ b/images/numbers/redBlock.svg
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   version="1.1"
+   id="layer_1"
+   x="0px"
+   y="0px"
+   viewBox="0 0 80 59.999998"
+   xml:space="preserve"
+   sodipodi:docname="my_redBlock.svg"
+   width="80"
+   height="60"
+   inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg"><defs
+   id="defs1" /><sodipodi:namedview
+   id="namedview1"
+   pagecolor="#ffffff"
+   bordercolor="#000000"
+   borderopacity="0.25"
+   inkscape:showpageshadow="2"
+   inkscape:pageopacity="0.0"
+   inkscape:pagecheckerboard="0"
+   inkscape:deskcolor="#d1d1d1"
+   inkscape:zoom="10.102171"
+   inkscape:cx="31.478383"
+   inkscape:cy="39.150002"
+   inkscape:window-width="1920"
+   inkscape:window-height="1001"
+   inkscape:window-x="1911"
+   inkscape:window-y="-9"
+   inkscape:window-maximized="1"
+   inkscape:current-layer="layer_1" />
+<style
+   type="text/css"
+   id="style1">
+	.st0{fill:#FF0000;}
+</style>
+<path
+   id="led_off"
+   class="st0"
+   d="M 0,60 V 0 h 80 v 60 z"
+   style="stroke-width:5.56038" />
+</svg>
diff --git a/images/ui/background.svg b/images/ui/background.svg
new file mode 100644
index 0000000..a08e908
--- /dev/null
+++ b/images/ui/background.svg
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg version="1.1"
+	 id="svg1" inkscape:output_extension="org.inkscape.output.svg.inkscape" sodipodi:docbase="/home/kdesvn/kdeedu/blinken/images" xmlns:cc="http://web.resource.org/cc/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:svg="http://www.w3.org/2000/svg"
+	 xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 812.5 694.5"
+	 style="enable-background:new 0 0 812.5 694.5;" xml:space="preserve">
+<style type="text/css">
+	.st0{fill-rule:evenodd;clip-rule:evenodd;fill:url(#rect1709_00000064334702873236885670000004241528755142738327_);}
+	.st1{fill:none;stroke:#383838;stroke-width:10;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:0.1886;}
+	.st2{fill-rule:evenodd;clip-rule:evenodd;fill-opacity:0.502;}
+	.st3{fill-rule:evenodd;clip-rule:evenodd;fill:#F5F5F5;}
+	.st4{fill-rule:evenodd;clip-rule:evenodd;fill:#2B71B2;}
+	.st5{fill-rule:evenodd;clip-rule:evenodd;fill:#C30303;}
+	.st6{fill:none;stroke:#CCCCCC;stroke-width:3.125;stroke-linecap:round;stroke-linejoin:round;}
+	
+		.st7{opacity:0.7746;fill-rule:evenodd;clip-rule:evenodd;fill:url(#path1727_00000155124340099948612670000014066227957154663350_);enable-background:new    ;}
+	.st8{fill-rule:evenodd;clip-rule:evenodd;fill:#7F7F7F;}
+	
+		.st9{fill-rule:evenodd;clip-rule:evenodd;fill:url(#path5399_00000114045329996181949210000008322080954425342640_);stroke:#000000;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:0.331;}
+	.st10{fill-rule:evenodd;clip-rule:evenodd;stroke:#000000;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;}
+	
+		.st11{opacity:0.1972;fill-rule:evenodd;clip-rule:evenodd;fill:url(#path48097_00000182516336237710819470000015777076019582871464_);enable-background:new    ;}
+	
+		.st12{opacity:0.3838;fill-rule:evenodd;clip-rule:evenodd;fill:url(#path48099_00000101825511418332618270000003415598852090494867_);enable-background:new    ;}
+	.st13{fill:url(#logo_00000181797632872633696110000012755291667149670561_);}
+</style>
+<sodipodi:namedview  bordercolor="#666666" borderopacity="1.0" gridtolerance="10.0" guidetolerance="10.0" height="694.5px" id="base" inkscape:current-layer="svg1" inkscape:cx="770.60061" inkscape:cy="500.01047" inkscape:pageopacity="0" inkscape:pageshadow="2" inkscape:window-height="712" inkscape:window-width="1024" inkscape:window-x="0" inkscape:window-y="236" inkscape:zoom="0.2962773" objecttolerance="10.0" pagecolor="#ff61ff" width="812.5px">
+	</sodipodi:namedview>
+<g id="layer1">
+</g>
+<g id="blinkenBase" inkscape:label="#g3578">
+	
+		<radialGradient id="rect1709_00000018956041742066813540000017622318366510112674_" cx="-275.8941" cy="1163.557" r="406.25" gradientTransform="matrix(-1.169554e-02 1.4328 1.7777 1.451054e-02 -1857.3894 506.3183)" gradientUnits="userSpaceOnUse">
+		<stop  offset="0" style="stop-color:#BF0303"/>
+		<stop  offset="1" style="stop-color:#8C0000"/>
+	</radialGradient>
+	
+		<path id="rect1709" sodipodi:nodetypes="ccccc" style="fill-rule:evenodd;clip-rule:evenodd;fill:url(#rect1709_00000018956041742066813540000017622318366510112674_);" d="
+		M0,0v694.5h812.5V0H0z"/>
+	<path id="path13986" class="st1" d="M787.4,278.8c0,140.7-169.9,254.9-379.3,254.9S28.8,419.5,28.8,278.8S198.8,23.8,408.1,23.8
+		S787.4,138,787.4,278.8z"/>
+	<g id="g4811" transform="translate(0,2)">
+		<path id="path8373" class="st2" d="M530.4,358.6L0,386.5v306.4h549.8L530.4,358.6z"/>
+		<path id="rect1087" class="st3" d="M522.9,353.6L0,381.1v311.8h542.7L522.9,353.6z"/>
+		<g id="g3543" transform="translate(0,32)">
+			<path id="path1711" class="st4" d="M526,374.6L0,405.2v1.2l526.1-30.6L526,374.6z M527.9,408.2L0,438.9v1.2l528-30.7L527.9,408.2
+				z M529.9,441.7L0,472.5v1.3l530-30.8L529.9,441.7z M531.8,475.2L0,506.2v1.2l531.9-30.9L531.8,475.2z M533.8,508.8L0,539.8v1.2
+				L533.9,510L533.8,508.8z M535.8,542.3L0,573.5v1.2l535.8-31.2L535.8,542.3z M537.7,575.9L0,607.2v1.2l537.8-31.3L537.7,575.9z
+				 M539.7,609.4L0,640.8v1.2l539.7-31.4L539.7,609.4z M541.6,643l-309.2,18h21.3l287.9-16.8L541.6,643z"/>
+			<path id="path1710" class="st5" d="M14.9,346.1l-1.2,0.1L32,660.9h1.2L14.9,346.1z"/>
+		</g>
+		<path id="rect2359" class="st6" d="M542.7,692.9l-19.8-339.4L0,381.1"/>
+	</g>
+	
+		<radialGradient id="path1727_00000074401396513925399320000013085088147146445490_" cx="328.1548" cy="303.5868" r="233.3452" gradientTransform="matrix(1.6254 0 0 -1.0926 -138.7977 625.4459)" gradientUnits="userSpaceOnUse">
+		<stop  offset="0" style="stop-color:#000000"/>
+		<stop  offset="0.9545" style="stop-color:#000000"/>
+		<stop  offset="1" style="stop-color:#000000;stop-opacity:0"/>
+	</radialGradient>
+	
+		<path id="path1727" style="opacity:0.7746;fill-rule:evenodd;clip-rule:evenodd;fill:url(#path1727_00000074401396513925399320000013085088147146445490_);enable-background:new    ;" d="
+		M773.9,293.8c0,140.7-169.9,254.9-379.3,254.9S15.3,434.5,15.3,293.8S185.2,38.8,394.6,38.8S773.9,153,773.9,293.8z"/>
+	<path id="path1758" class="st8" d="M787.4,278.8c0,140.7-169.9,254.9-379.3,254.9S28.8,419.5,28.8,278.8S198.8,23.8,408.1,23.8
+		S787.4,138,787.4,278.8z"/>
+	
+		<radialGradient id="path5399_00000028297224035011499380000005891762418215496840_" cx="402.1226" cy="322.9481" r="381.7858" gradientTransform="matrix(1 0 0 -0.6743 6 496.527)" gradientUnits="userSpaceOnUse">
+		<stop  offset="0" style="stop-color:#323232"/>
+		<stop  offset="7.692308e-02" style="stop-color:#DFE1E1"/>
+		<stop  offset="0.2629" style="stop-color:#B6B1B1"/>
+		<stop  offset="0.5" style="stop-color:#8D8282"/>
+		<stop  offset="0.782" style="stop-color:#FFFFFF"/>
+		<stop  offset="0.9006" style="stop-color:#DFD9DF"/>
+		<stop  offset="1" style="stop-color:#3A3A3A"/>
+	</radialGradient>
+	
+		<path id="path5399" style="fill-rule:evenodd;clip-rule:evenodd;fill:url(#path5399_00000028297224035011499380000005891762418215496840_);stroke:#000000;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:0.331;" d="
+		M787.4,278.8c0,140.7-169.9,254.9-379.3,254.9S28.8,419.5,28.8,278.8S198.8,23.8,408.1,23.8S787.4,138,787.4,278.8z"/>
+	<path id="path6043" class="st10" d="M598.4,278.8c0,105-85.3,190.3-190.3,190.3s-190.3-85.3-190.3-190.3S303.1,88.5,408.1,88.5
+		S598.4,173.7,598.4,278.8z"/>
+	<g id="g48095" transform="translate(705.567,-1080.3135)">
+		
+			<radialGradient id="path48097_00000006706562918716039730000010635923123959617412_" cx="-1145.7865" cy="558.0082" r="379.2859" gradientTransform="matrix(1 5.946939e-03 3.012183e-03 -0.5065 702.7335 1432.4973)" gradientUnits="userSpaceOnUse">
+			<stop  offset="0" style="stop-color:#FFFFFF"/>
+			<stop  offset="1" style="stop-color:#FFFFFF;stop-opacity:0"/>
+		</radialGradient>
+		
+			<path id="path48097" sodipodi:nodetypes="ccccscsc" style="opacity:0.1972;fill-rule:evenodd;clip-rule:evenodd;fill:url(#path48097_00000006706562918716039730000010635923123959617412_);enable-background:new    ;" d="
+			M-296.2,1104c-209.4,0-345,127.9-345,268.6c1.6,13.1,5.3,18.4,2.6-5.3c0-144.4,166.1-250.2,367.9-250.2
+			c201.8,0,332.5,115,332.5,259.4c0,46.7-17.2,90.5-47.2,128.5C57.7,1463.7,83,1413.3,83,1359C83,1218.2-86.9,1104-296.2,1104z"/>
+		
+			<radialGradient id="path48099_00000121990157961290319960000000628075532797803941_" cx="-1054.8149" cy="770.1763" r="379.2859" gradientTransform="matrix(1 -2.261666e-03 -3.012183e-03 -1.3318 708.3231 2176.6987)" gradientUnits="userSpaceOnUse">
+			<stop  offset="0" style="stop-color:#FFFFFF"/>
+			<stop  offset="1" style="stop-color:#FFFFFF;stop-opacity:0"/>
+		</radialGradient>
+		
+			<path id="path48099" style="opacity:0.3838;fill-rule:evenodd;clip-rule:evenodd;fill:url(#path48099_00000121990157961290319960000000628075532797803941_);enable-background:new    ;" d="
+			M-296.2,1104c-172.2,0-317.8,77.3-364,183.1c47.1,120.8,185.3,208.3,348.3,208.3c178.8,0,327.8-105.3,359.4-244.2
+			C-13,1164.3-144.2,1104-296.2,1104z"/>
+	</g>
+	
+		<linearGradient id="logo_00000051365927271445851430000016307207654751142796_" gradientUnits="userSpaceOnUse" x1="242.0625" y1="416.4688" x2="562.0625" y2="416.4688" gradientTransform="matrix(1 0 0 -1 6 694.4375)">
+		<stop  offset="0" style="stop-color:#FFFFFF"/>
+		<stop  offset="0.5" style="stop-color:#BBBBBB"/>
+		<stop  offset="0.75" style="stop-color:#747474"/>
+		<stop  offset="1" style="stop-color:#FFFFFF"/>
+	</linearGradient>
+	<path id="logo" style="fill:url(#logo_00000051365927271445851430000016307207654751142796_);" d="M257.2,246.1
+		c-2.5,0-4.7,0.9-6.5,2.7c-1.7,1.7-2.6,3.9-2.6,6.4v29.2c0,2.5,0.9,4.7,2.6,6.5c1.8,1.7,4,2.6,6.5,2.6h29.2c2.5,0,4.7-0.9,6.4-2.6
+		c1.8-1.8,2.7-3.9,2.7-6.5v-10.9c0-1.3-0.2-2.5-0.7-3.7c0.5-1.1,0.7-2.3,0.7-3.6v-10.9c0-2.5-0.9-4.7-2.7-6.4
+		c-1.7-1.8-3.9-2.7-6.4-2.7H257.2z M308.3,246.1c-2.5,0-4.7,0.9-6.5,2.7c-1.7,1.7-2.6,3.9-2.6,6.4v29.2c0,2.5,0.9,4.7,2.6,6.5
+		c1.8,1.7,4,2.6,6.5,2.6h29.1c2.5,0,4.7-0.9,6.4-2.6c1.8-1.8,2.7-3.9,2.7-6.5c0-2.5-0.9-4.7-2.7-6.4c-1.7-1.8-3.9-2.7-6.4-2.7h-20
+		v-20c0-2.5-0.9-4.7-2.7-6.4C313,247,310.8,246.1,308.3,246.1z M359.4,246.1c-2.5,0-4.7,0.9-6.5,2.7c-1.7,1.7-2.6,3.9-2.6,6.4
+		c0,3.1,1.2,5.5,3.6,7.3c-2.4,1.8-3.6,4.3-3.6,7.3v14.6c0,2.5,0.8,4.7,2.6,6.5c1.8,1.7,4,2.6,6.5,2.6s4.7-0.9,6.4-2.6
+		c1.8-1.8,2.7-3.9,2.7-6.5v-14.6c0-3-1.3-5.4-3.7-7.3c2.4-1.8,3.7-4.2,3.7-7.3c0-2.5-0.9-4.7-2.7-6.4
+		C364.1,247,361.9,246.1,359.4,246.1z M381.3,246.1c-2.5,0-4.7,0.9-6.5,2.7c-1.7,1.7-2.6,3.9-2.6,6.4v29.2c0,2.5,0.9,4.7,2.6,6.5
+		c1.8,1.7,3.9,2.6,6.5,2.6c2.5,0,4.7-0.9,6.5-2.6c1.8-1.8,2.7-3.9,2.7-6.5v-20h10.9v20c0,2.5,0.9,4.7,2.6,6.5c1.8,1.7,4,2.6,6.5,2.6
+		c1,0,1.9-0.2,2.8-0.4l-3.8,4.9l4.6,4.4l6.8-4.7c1.7,1,5,2.3,6.9,2.8l2.1,9.4h5.6l1.7-9.2c1.9-0.5,6-1.7,7.7-2.6l7.2,5.1l4.8-5.2
+		l-0.7-1.6l-3.6,1.5l-4-5.4c-3.3,4.3-10.1,7.1-16.1,7.1c-10,0-20.4-9.9-20.4-19.5c0-4.9,2.6-10.5,6.3-14.3h1.2v-1.1
+		c1.1-1,2.3-1.8,3.5-2.4v-1.4c-0.9,0.3-0.4,0.2-1.2,0.6l-2.3-1.5v-4.7c0-2.5-0.9-4.7-2.7-6.4c-1.7-1.8-3.8-2.7-6.4-2.7H381.3z
+		 M478.7,246.1c-2.5,0-4.7,0.9-6.5,2.7c-1.7,1.7-2.6,3.9-2.6,6.4c0,3,1.3,5.4,3.7,7.3c-2.4,1.8-3.7,4.2-3.7,7.3v14.6
+		c0,2.5,0.9,4.7,2.6,6.5c1.8,1.7,4,2.6,6.5,2.6h29.1c2.5,0,4.7-0.9,6.4-2.6c1.8-1.8,2.7-3.9,2.7-6.5c0-3.1-1.2-5.5-3.6-7.3
+		c2.4-1.8,3.6-4.3,3.6-7.3c0-3.1-1.2-5.5-3.6-7.3c2.4-1.8,3.6-4.3,3.6-7.3c0-2.5-0.9-4.7-2.7-6.4c-1.7-1.8-3.9-2.7-6.4-2.7H478.7z
+		 M529.8,246.1c-2.5,0-4.7,0.9-6.5,2.7c-1.7,1.7-2.6,3.9-2.6,6.4v29.2c0,2.5,0.8,4.7,2.6,6.5c1.8,1.7,4,2.6,6.5,2.6s4.7-0.9,6.4-2.6
+		c1.8-1.8,2.7-3.9,2.7-6.5v-20h10.9v20c0,2.5,0.9,4.7,2.6,6.5c1.8,1.7,3.9,2.6,6.5,2.6c2.5,0,4.7-0.9,6.4-2.6
+		c1.8-1.8,2.7-3.9,2.7-6.5v-29.2c0-2.5-0.9-4.7-2.7-6.4c-1.7-1.8-3.9-2.7-6.4-2.7H529.8z M453.2,248l-13.6,18.5l0.5-18.3l-11.1,1.2
+		v41.5l11.1-0.8l0.1-17.6l13.6,19.2L465,288l-13.9-18.9v-0.2l13.4-17.3L453.2,248z M256.6,249.8c0.2,0,0.4,0,0.6,0h29.2
+		c1.5,0,2.8,0.5,3.9,1.6c1.1,1.1,1.6,2.3,1.6,3.8v10.9c0,1.5-0.5,2.7-1.4,3.6c0.9,1,1.4,2.2,1.4,3.7v10.9c0,1.5-0.5,2.8-1.6,3.8
+		c-1.1,1.1-2.4,1.6-3.9,1.6h-29.2c-1.5,0-2.8-0.6-3.9-1.6s-1.6-2.3-1.6-3.8v-29.2c0-1.5,0.5-2.8,1.6-3.8
+		C254.2,250.5,255.4,249.9,256.6,249.8z M307.8,249.8c0.2,0,0.4,0,0.6,0c1.5,0,2.8,0.5,3.8,1.6c1.1,1.1,1.6,2.3,1.6,3.8v23.7h23.7
+		c1.5,0,2.8,0.6,3.9,1.7c1.1,1.1,1.6,2.3,1.6,3.8c0,1.5-0.5,2.8-1.6,3.8c-1.1,1.1-2.4,1.6-3.9,1.6h-29.1c-1.5,0-2.8-0.6-3.9-1.6
+		c-1.1-1.1-1.6-2.3-1.6-3.8v-29.2c0-1.5,0.5-2.8,1.6-3.8C305.4,250.5,306.5,249.9,307.8,249.8z M358.9,249.8c0.2,0,0.3,0,0.5,0
+		c1.5,0,2.8,0.5,3.8,1.6c1.1,1.1,1.6,2.3,1.6,3.8c0,1.5-0.5,2.8-1.6,3.9c-1.1,1.1-2.3,1.6-3.8,1.6c-1.5,0-2.8-0.5-3.9-1.6
+		c-1.1-1.1-1.6-2.4-1.6-3.9c0-1.5,0.5-2.8,1.6-3.8C356.5,250.5,357.6,249.9,358.9,249.8z M380.8,249.8c0.2,0,0.3,0,0.5,0h29.2
+		c1.5,0,2.8,0.5,3.8,1.6c1.1,1.1,1.6,2.3,1.6,3.8v2.3l-1.3-0.9l-4.8,4.1l5.6,8.2c-0.9,1.4-2.5,4-3,5.6l-7.4,1.8v-15.7h-18.2v23.7
+		c0,1.5-0.5,2.8-1.6,3.8c-1.1,1.1-2.4,1.6-3.9,1.6s-2.8-0.6-3.8-1.6s-1.6-2.3-1.6-3.8v-29.2c0-1.5,0.5-2.8,1.6-3.8
+		C378.4,250.5,379.5,249.9,380.8,249.8z M478.2,249.8c0.2,0,0.4,0,0.6,0h29.1c1.5,0,2.8,0.5,3.9,1.6c1.1,1.1,1.6,2.3,1.6,3.8
+		c0,1.5-0.5,2.8-1.6,3.9c-1.1,1.1-2.4,1.6-3.9,1.6h-29.1c-1.5,0-2.8-0.5-3.9-1.6c-1.1-1.1-1.6-2.4-1.6-3.9c0-1.5,0.5-2.8,1.6-3.8
+		C475.8,250.5,476.9,249.9,478.2,249.8z M529.2,249.8c0.2,0,0.4,0,0.6,0h29.1c1.5,0,2.8,0.5,3.9,1.6c1.1,1.1,1.6,2.3,1.6,3.8v29.2
+		c0,1.5-0.5,2.8-1.6,3.8c-1.1,1.1-2.4,1.6-3.9,1.6c-1.5,0-2.8-0.6-3.8-1.6c-1.1-1.1-1.6-2.3-1.6-3.8v-23.7h-18.2v23.7
+		c0,1.5-0.5,2.8-1.6,3.8c-1.1,1.1-2.3,1.6-3.8,1.6s-2.8-0.6-3.9-1.6c-1.1-1.1-1.6-2.3-1.6-3.8v-29.2c0-1.5,0.5-2.8,1.6-3.8
+		C526.9,250.5,528,249.9,529.2,249.8z M262.7,260.7v3.7h18.2v-3.7H262.7z M359.4,264.4c1.5,0,2.8,0.5,3.8,1.6
+		c1.1,1.1,1.6,2.3,1.6,3.8v14.6c0,1.5-0.5,2.8-1.6,3.8c-1.1,1.1-2.3,1.6-3.8,1.6s-2.8-0.6-3.9-1.6c-1.1-1.1-1.6-2.3-1.6-3.8v-14.6
+		c0-1.5,0.5-2.8,1.6-3.8C356.6,264.9,357.9,264.4,359.4,264.4z M478.7,264.4h29.1c1.5,0,2.8,0.5,3.9,1.6c1.1,1.1,1.6,2.3,1.6,3.8
+		c0,1.5-0.5,2.8-1.6,3.9c-1.1,1.1-2.4,1.6-3.9,1.6h-23.7v3.6h23.7c1.5,0,2.8,0.6,3.9,1.7c1.1,1.1,1.6,2.3,1.6,3.8
+		c0,1.5-0.5,2.8-1.6,3.8c-1.1,1.1-2.4,1.6-3.9,1.6h-29.1c-1.5,0-2.8-0.6-3.9-1.6s-1.6-2.3-1.6-3.8v-14.6c0-1.5,0.5-2.8,1.6-3.8
+		C475.9,264.9,477.2,264.4,478.7,264.4z M262.7,275.3v3.6h18.2v-3.6H262.7z M405,283l6.9,2.2c0.3,0.9,1,2.3,1.7,3.6
+		c-0.9,0.7-1.9,1.1-3.1,1.1c-1.5,0-2.8-0.6-3.9-1.6c-1.1-1.1-1.6-2.3-1.6-3.8V283z M414.3,289.9c0.2,0.3,0.4,0.8,0.6,1.1l-0.6,0.8
+		V289.9z"/>
+</g>
+</svg>
diff --git a/images/ui/downArrow.svg b/images/ui/downArrow.svg
new file mode 100644
index 0000000..16ff09e
--- /dev/null
+++ b/images/ui/downArrow.svg
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg version="1.1" id="layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 792 612" style="enable-background:new 0 0 792 612;" xml:space="preserve">
+<style type="text/css">
+	.st0{fill:#B73822;}
+</style>
+<path id="arrow_down" class="st0" d="M386.71,291.69c-1.37,0.14-2.56,1.02-3.08,2.29s-0.32,2.73,0.55,3.8l16.26,20.02
+	c0.71,0.87,1.78,1.38,2.91,1.38c1.13,0,2.2-0.51,2.91-1.38l16.26-20.02c0.9-1.12,1.08-2.66,0.46-3.96c-0.62-1.3-1.93-2.13-3.37-2.14
+	h-32.52C386.96,291.69,386.83,291.69,386.71,291.69z"/>
+</svg>
diff --git a/images/ui/exit.svg b/images/ui/exit.svg
new file mode 100644
index 0000000..2f63e44
--- /dev/null
+++ b/images/ui/exit.svg
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   version="1.1"
+   id="layer_1"
+   x="0px"
+   y="0px"
+   viewBox="0 0 600 600"
+   xml:space="preserve"
+   sodipodi:docname="exit.svg"
+   width="600"
+   height="600"
+   inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg"><defs
+   id="defs1" /><sodipodi:namedview
+   id="namedview1"
+   pagecolor="#ffffff"
+   bordercolor="#000000"
+   borderopacity="0.25"
+   inkscape:showpageshadow="2"
+   inkscape:pageopacity="0.0"
+   inkscape:pagecheckerboard="0"
+   inkscape:deskcolor="#d1d1d1"
+   inkscape:zoom="1.2924837"
+   inkscape:cx="396.13654"
+   inkscape:cy="306"
+   inkscape:window-width="1920"
+   inkscape:window-height="1001"
+   inkscape:window-x="1911"
+   inkscape:window-y="-9"
+   inkscape:window-maximized="1"
+   inkscape:current-layer="layer_1"
+   inkscape:clip-to-page="false" />
+<style
+   type="text/css"
+   id="style1">
+	.st0{fill:#972C23;}
+	.st1{fill-rule:evenodd;clip-rule:evenodd;fill:#B73822;}
+	.st2{fill:none;stroke:#B73822;stroke-width:7.5;stroke-linecap:round;stroke-linejoin:round;}
+</style>
+<g
+   id="quit_normal"
+   transform="matrix(6.6666654,0,0,6.6666667,-1539.4663,-1804.0667)">
+	<path
+   id="rect5194"
+   class="st0"
+   d="m 240.59,270.61 h 70.66 c 5.34,0 9.67,4.33 9.67,9.67 v 70.66 c 0,5.34 -4.33,9.67 -9.67,9.67 h -70.66 c -5.34,0 -9.67,-4.33 -9.67,-9.67 v -70.66 c -0.01,-5.34 4.32,-9.67 9.67,-9.67 z" />
+	<path
+   id="path696"
+   class="st1"
+   d="m 286.6,288.78 v 11.15 c 8.64,4.57 13.55,14.18 11.82,24.07 -1.92,11.06 -11.49,19 -22.72,18.9 -11.23,-0.1 -20.65,-8.27 -22.38,-19.37 -1.52,-9.8 3.39,-19.25 11.91,-23.73 v -10.98 c -11.28,3.87 -19.39,13.4 -21.7,24.58 -0.78,3.77 -0.87,7.71 -0.25,11.7 2.48,15.94 16.2,27.87 32.34,28.01 16.14,0.14 30.08,-11.52 32.84,-27.42 2.77,-15.9 -6.46,-31.56 -21.7,-36.87 -0.05,-0.02 -0.11,-0.03 -0.16,-0.04 z" />
+	<path
+   id="path701"
+   class="st2"
+   d="M 275.92,281.87 V 316.8" />
+</g>
+</svg>
diff --git a/images/ui/exit_highlight.svg b/images/ui/exit_highlight.svg
new file mode 100644
index 0000000..a405f34
--- /dev/null
+++ b/images/ui/exit_highlight.svg
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   version="1.1"
+   id="layer_1"
+   x="0px"
+   y="0px"
+   viewBox="0 0 600 600"
+   xml:space="preserve"
+   sodipodi:docname="my_exit_highlight.svg"
+   width="600"
+   height="600"
+   inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg"><defs
+   id="defs1" /><sodipodi:namedview
+   id="namedview1"
+   pagecolor="#ffffff"
+   bordercolor="#000000"
+   borderopacity="0.25"
+   inkscape:showpageshadow="2"
+   inkscape:pageopacity="0.0"
+   inkscape:pagecheckerboard="0"
+   inkscape:deskcolor="#d1d1d1"
+   inkscape:zoom="1.2924837"
+   inkscape:cx="396.13654"
+   inkscape:cy="306"
+   inkscape:window-width="1920"
+   inkscape:window-height="1001"
+   inkscape:window-x="1911"
+   inkscape:window-y="-9"
+   inkscape:window-maximized="1"
+   inkscape:current-layer="layer_1" />
+<style
+   type="text/css"
+   id="style1">
+	.st0{fill:#B73822;}
+	.st1{fill-rule:evenodd;clip-rule:evenodd;fill:#972C23;}
+	.st2{fill:none;stroke:#972C23;stroke-width:7.5;stroke-linecap:round;stroke-linejoin:round;}
+</style>
+<g
+   id="quit_hover"
+   transform="matrix(6.6666667,0,0,6.6666667,-922.26667,-1002.9333)">
+	<path
+   id="rect1564"
+   class="st0"
+   d="m 148.01,150.44 h 70.66 c 5.34,0 9.67,4.33 9.67,9.67 v 70.66 c 0,5.34 -4.33,9.67 -9.67,9.67 h -70.66 c -5.34,0 -9.67,-4.33 -9.67,-9.67 v -70.66 c 0,-5.34 4.33,-9.67 9.67,-9.67 z" />
+	<g
+   id="g1362"
+   transform="translate(2.70918,-121.0568)">
+		<path
+   id="path1567"
+   class="st1"
+   d="m 191.31,289.66 v 11.15 c 8.64,4.57 13.55,14.18 11.82,24.07 -1.92,11.06 -11.49,19 -22.72,18.9 -11.23,-0.1 -20.65,-8.27 -22.38,-19.37 -1.52,-9.8 3.39,-19.25 11.91,-23.73 V 289.7 c -11.28,3.87 -19.39,13.4 -21.7,24.58 -0.78,3.77 -0.87,7.71 -0.25,11.7 2.48,15.94 16.2,27.87 32.34,28.01 16.14,0.14 30.08,-11.52 32.84,-27.42 2.77,-15.9 -6.46,-31.56 -21.7,-36.87 -0.04,-0.02 -0.1,-0.02 -0.16,-0.04 z" />
+		<path
+   id="path1569"
+   class="st2"
+   d="m 180.63,282.75 v 34.93" />
+	</g>
+</g>
+</svg>
diff --git a/images/ui/highScore.svg b/images/ui/highScore.svg
new file mode 100644
index 0000000..3d6886e
--- /dev/null
+++ b/images/ui/highScore.svg
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   version="1.1"
+   id="layer_1"
+   x="0px"
+   y="0px"
+   viewBox="0 0 600 600"
+   xml:space="preserve"
+   sodipodi:docname="highScore.svg"
+   width="600"
+   height="600"
+   inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg"><defs
+   id="defs1" /><sodipodi:namedview
+   id="namedview1"
+   pagecolor="#ffffff"
+   bordercolor="#000000"
+   borderopacity="0.25"
+   inkscape:showpageshadow="2"
+   inkscape:pageopacity="0.0"
+   inkscape:pagecheckerboard="0"
+   inkscape:deskcolor="#d1d1d1"
+   inkscape:zoom="1.2924837"
+   inkscape:cx="396.13654"
+   inkscape:cy="306"
+   inkscape:window-width="1920"
+   inkscape:window-height="1001"
+   inkscape:window-x="1911"
+   inkscape:window-y="-9"
+   inkscape:window-maximized="1"
+   inkscape:current-layer="layer_1" />
+<style
+   type="text/css"
+   id="style1">
+	.st0{fill:#972C23;}
+	
+		.st1{fill-rule:evenodd;clip-rule:evenodd;fill:#B73822;stroke:#B73822;stroke-width:3.125;stroke-linecap:round;stroke-linejoin:round;}
+	.st2{fill:none;stroke:#B73822;stroke-width:7.5;stroke-linecap:round;stroke-linejoin:round;}
+</style>
+<g
+   id="highscore_normal"
+   transform="matrix(6.6666667,0,0,6.6666667,4027.7333,-1136.2667)">
+	<path
+   id="rect5192"
+   class="st0"
+   d="m -594.49,170.44 h 70.66 c 5.34,0 9.67,4.33 9.67,9.67 v 70.66 c 0,5.34 -4.33,9.67 -9.67,9.67 h -70.66 c -5.34,0 -9.67,-4.33 -9.67,-9.67 v -70.66 c 0,-5.34 4.33,-9.67 9.67,-9.67 z" />
+	<g
+   id="g2366"
+   transform="translate(-140.8411,-59.62938)">
+		<path
+   id="path2345"
+   class="st1"
+   d="m -452.03,239.13 h 12.52 c 1.23,0 2.22,0.99 2.22,2.21 v 12.45 c 0,1.22 -0.99,2.21 -2.22,2.21 h -12.52 c -1.23,0 -2.22,-0.99 -2.22,-2.21 v -12.45 c 0,-1.22 0.99,-2.21 2.22,-2.21 z" />
+		<path
+   id="path2349"
+   class="st1"
+   d="m -452.03,266.64 h 12.52 c 1.23,0 2.22,0.99 2.22,2.21 v 12.45 c 0,1.22 -0.99,2.21 -2.22,2.21 h -12.52 c -1.23,0 -2.22,-0.99 -2.22,-2.21 v -12.45 c 0,-1.23 0.99,-2.21 2.22,-2.21 z" />
+		<g
+   id="g2361"
+   transform="translate(-1.25)">
+			<path
+   id="path2343"
+   class="st2"
+   d="m -422.59,247.57 h 36.36" />
+			<path
+   id="path2347"
+   class="st2"
+   d="m -422.59,275.07 h 29.82" />
+			<path
+   id="path2351"
+   class="st2"
+   d="m -422.59,302.57 h 39.27" />
+		</g>
+		<path
+   id="path2353"
+   class="st1"
+   d="m -452.03,294.14 h 12.52 c 1.23,0 2.22,0.99 2.22,2.21 v 12.45 c 0,1.22 -0.99,2.21 -2.22,2.21 h -12.52 c -1.23,0 -2.22,-0.99 -2.22,-2.21 v -12.45 c 0,-1.23 0.99,-2.21 2.22,-2.21 z" />
+	</g>
+</g>
+</svg>
diff --git a/images/ui/highScore_highlight.svg b/images/ui/highScore_highlight.svg
new file mode 100644
index 0000000..2fb817f
--- /dev/null
+++ b/images/ui/highScore_highlight.svg
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   version="1.1"
+   id="layer_1"
+   x="0px"
+   y="0px"
+   viewBox="0 0 600 600"
+   xml:space="preserve"
+   sodipodi:docname="highScore_highlight.svg"
+   width="600"
+   height="600"
+   inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg"><defs
+   id="defs1" /><sodipodi:namedview
+   id="namedview1"
+   pagecolor="#ffffff"
+   bordercolor="#000000"
+   borderopacity="0.25"
+   inkscape:showpageshadow="2"
+   inkscape:pageopacity="0.0"
+   inkscape:pagecheckerboard="0"
+   inkscape:deskcolor="#d1d1d1"
+   inkscape:zoom="1.2924837"
+   inkscape:cx="396.13654"
+   inkscape:cy="306"
+   inkscape:window-width="1920"
+   inkscape:window-height="1001"
+   inkscape:window-x="1911"
+   inkscape:window-y="-9"
+   inkscape:window-maximized="1"
+   inkscape:current-layer="layer_1" />
+<style
+   type="text/css"
+   id="style1">
+	.st0{fill:#B73822;}
+	
+		.st1{fill-rule:evenodd;clip-rule:evenodd;fill:#972C23;stroke:#972C23;stroke-width:3.125;stroke-linecap:round;stroke-linejoin:round;}
+	.st2{fill:none;stroke:#972C23;stroke-width:7.5;stroke-linecap:round;stroke-linejoin:round;}
+</style>
+<g
+   id="highscore_hover"
+   transform="matrix(6.6666667,0,0,6.6666667,3761.0667,-336.26667)">
+	<path
+   id="rect2331"
+   class="st0"
+   d="m -554.49,50.44 h 70.66 c 5.34,0 9.67,4.33 9.67,9.67 v 70.66 c 0,5.34 -4.33,9.67 -9.67,9.67 h -70.66 c -5.34,0 -9.67,-4.33 -9.67,-9.67 V 60.11 c 0,-5.34 4.33,-9.67 9.67,-9.67 z" />
+	<g
+   id="g4377"
+   transform="translate(-0.841086,-179.6294)">
+		<path
+   id="path4379"
+   class="st1"
+   d="m -552.03,239.13 h 12.52 c 1.23,0 2.22,0.99 2.22,2.21 v 12.45 c 0,1.22 -0.99,2.21 -2.22,2.21 h -12.52 c -1.23,0 -2.22,-0.99 -2.22,-2.21 v -12.45 c 0,-1.22 0.99,-2.21 2.22,-2.21 z" />
+		<path
+   id="path4381"
+   class="st1"
+   d="m -552.03,266.64 h 12.52 c 1.23,0 2.22,0.99 2.22,2.21 v 12.45 c 0,1.22 -0.99,2.21 -2.22,2.21 h -12.52 c -1.23,0 -2.22,-0.99 -2.22,-2.21 v -12.45 c 0,-1.23 0.99,-2.21 2.22,-2.21 z" />
+		<g
+   id="g4383"
+   transform="translate(-1.25)">
+			<path
+   id="path4385"
+   class="st2"
+   d="m -522.59,247.57 h 36.36" />
+			<path
+   id="path4387"
+   class="st2"
+   d="m -522.59,275.07 h 29.82" />
+			<path
+   id="path4389"
+   class="st2"
+   d="m -522.59,302.57 h 39.27" />
+		</g>
+		<path
+   id="path4391"
+   class="st1"
+   d="m -552.03,294.14 h 12.52 c 1.23,0 2.22,0.99 2.22,2.21 v 12.45 c 0,1.22 -0.99,2.21 -2.22,2.21 h -12.52 c -1.23,0 -2.22,-0.99 -2.22,-2.21 v -12.45 c 0,-1.23 0.99,-2.21 2.22,-2.21 z" />
+	</g>
+</g>
+</svg>
diff --git a/images/ui/menu.svg b/images/ui/menu.svg
new file mode 100644
index 0000000..29d2479
--- /dev/null
+++ b/images/ui/menu.svg
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   version="1.1"
+   id="layer_1"
+   x="0px"
+   y="0px"
+   viewBox="0 0 600 600"
+   xml:space="preserve"
+   sodipodi:docname="menu.svg"
+   width="600"
+   height="600"
+   inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg"><defs
+   id="defs1" /><sodipodi:namedview
+   id="namedview1"
+   pagecolor="#ffffff"
+   bordercolor="#000000"
+   borderopacity="0.25"
+   inkscape:showpageshadow="2"
+   inkscape:pageopacity="0.0"
+   inkscape:pagecheckerboard="0"
+   inkscape:deskcolor="#d1d1d1"
+   inkscape:zoom="1.2924837"
+   inkscape:cx="396.13652"
+   inkscape:cy="305.99999"
+   inkscape:window-width="1920"
+   inkscape:window-height="1001"
+   inkscape:window-x="1911"
+   inkscape:window-y="-9"
+   inkscape:window-maximized="1"
+   inkscape:current-layer="layer_1" />
+<style
+   type="text/css"
+   id="style1">
+	.st0{fill:#972C23;}
+	
+		.st1{fill-rule:evenodd;clip-rule:evenodd;fill:#B73822;stroke:#B73822;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;}
+	.st2{fill-rule:evenodd;clip-rule:evenodd;fill:#972C23;stroke:#972C23;stroke-width:1.7442;stroke-linejoin:round;}
+</style>
+<g
+   id="help_normal"
+   transform="matrix(2.6666667,0,0,2.6666667,-273.57334,-1303.1734)">
+	<path
+   id="path4462"
+   class="st0"
+   d="m 248.01,624.44 h 70.66 c 5.36,0 9.67,4.31 9.67,9.67 v 70.66 c 0,5.36 -4.31,9.67 -9.67,9.67 h -70.66 c -5.36,0 -9.67,-4.31 -9.67,-9.67 v -70.66 c 0,-5.36 4.32,-9.67 9.67,-9.67 z" />
+	<path
+   id="path839"
+   class="st1"
+   d="m 283.34,634.44 c -19.32,0 -35,15.68 -35,35 0,19.32 15.68,35 35,35 19.32,0 35,-15.68 35,-35 0,-19.32 -15.68,-35 -35,-35 z" />
+	<path
+   id="path2224"
+   class="st2"
+   d="m 282.67,642.43 c 2.34,0 4.56,0.36 6.58,1.05 2.03,0.69 3.81,1.68 5.37,3.02 1.56,1.34 2.78,2.95 3.65,4.86 0.89,1.89 1.3,4.04 1.3,6.37 0,4.18 -1.03,7.41 -3.14,9.73 -2.09,2.29 -4.96,3.81 -8.64,4.57 v 1.34 c 0,1.07 -0.25,2.03 -0.71,2.85 -0.45,0.8 -1.11,1.42 -1.93,1.89 -0.8,0.45 -1.7,0.67 -2.73,0.67 -1.02,0 -1.94,-0.23 -2.77,-0.67 -0.8,-0.47 -1.42,-1.09 -1.89,-1.89 -0.45,-0.82 -0.67,-1.78 -0.67,-2.85 v -5.49 c 0,-1.14 0.2,-2.04 0.67,-2.64 0.47,-0.6 1.05,-0.99 1.72,-1.22 0.67,-0.22 1.68,-0.47 3.02,-0.71 3.47,-0.65 5.2,-2.39 5.2,-5.24 0,-1.16 -0.49,-2.19 -1.43,-3.1 -0.91,-0.93 -2.11,-1.38 -3.61,-1.38 -1.38,0 -2.47,0.26 -3.27,0.8 -0.78,0.53 -1.53,1.32 -2.31,2.35 -0.76,1 -1.51,1.77 -2.22,2.31 -0.69,0.51 -1.65,0.75 -2.85,0.75 -1.36,0 -2.5,-0.53 -3.48,-1.55 -0.96,-1.05 -1.43,-2.25 -1.43,-3.65 0,-2.45 0.79,-4.61 2.39,-6.46 1.6,-1.85 3.59,-3.26 6,-4.23 2.42,-1 4.8,-1.48 7.18,-1.48 z m -0.33,41.99 c 1.05,0 2.02,0.28 2.93,0.84 0.91,0.56 1.6,1.29 2.14,2.22 0.56,0.91 0.84,1.91 0.84,2.98 0,1.09 -0.28,2.13 -0.84,3.06 -0.53,0.91 -1.25,1.6 -2.18,2.14 -0.91,0.53 -1.87,0.8 -2.89,0.8 -1.02,0 -2,-0.26 -2.93,-0.8 -0.91,-0.53 -1.67,-1.23 -2.22,-2.14 -0.53,-0.93 -0.8,-1.97 -0.8,-3.06 0,-1.07 0.26,-2.06 0.8,-2.98 0.56,-0.93 1.31,-1.67 2.22,-2.22 0.9,-0.56 1.88,-0.84 2.93,-0.84 z" />
+</g>
+</svg>
diff --git a/images/ui/menu_list.svg b/images/ui/menu_list.svg
new file mode 100644
index 0000000..b027061
--- /dev/null
+++ b/images/ui/menu_list.svg
@@ -0,0 +1,185 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   version="1.1"
+   id="layer_1"
+   x="0px"
+   y="0px"
+   viewBox="0 0 600 600"
+   xml:space="preserve"
+   sodipodi:docname="menu_list.svg"
+   width="600"
+   height="600"
+   inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg"><defs
+   id="defs1" /><sodipodi:namedview
+   id="namedview1"
+   pagecolor="#ffffff"
+   bordercolor="#000000"
+   borderopacity="0.25"
+   inkscape:showpageshadow="2"
+   inkscape:pageopacity="0.0"
+   inkscape:pagecheckerboard="0"
+   inkscape:deskcolor="#d1d1d1"
+   inkscape:zoom="1.2924837"
+   inkscape:cx="396.13652"
+   inkscape:cy="305.99999"
+   inkscape:window-width="1920"
+   inkscape:window-height="1001"
+   inkscape:window-x="1911"
+   inkscape:window-y="-9"
+   inkscape:window-maximized="1"
+   inkscape:current-layer="layer_1" />
+<style
+   type="text/css"
+   id="style1">
+	.st0{fill:#B73822;}
+	
+		.st1{fill-rule:evenodd;clip-rule:evenodd;fill:#972C23;stroke:#972C23;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:5.531;}
+	
+		.st2{fill-rule:evenodd;clip-rule:evenodd;fill:#B73822;stroke:#B73822;stroke-width:1.7442;stroke-linejoin:round;stroke-miterlimit:5.531;}
+	.st3{fill-rule:evenodd;clip-rule:evenodd;fill:#972C23;}
+	.st4{fill-rule:evenodd;clip-rule:evenodd;fill:#B73822;}
+	.st5{fill:none;stroke:#972C23;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;}
+	.st6{fill:none;stroke:#972C23;stroke-width:33.4712;stroke-linecap:round;stroke-linejoin:round;}
+	.st7{fill:none;stroke:#972C23;stroke-width:2.5;stroke-miterlimit:3.8072;}
+	.st8{fill:#972C23;}
+	
+		.st9{fill-rule:evenodd;clip-rule:evenodd;fill:#B73822;stroke:#972C23;stroke-width:5;stroke-linejoin:round;stroke-miterlimit:3.8974;}
+	.st10{fill:none;stroke:#972C23;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;}
+</style>
+
+<g
+   id="help_hover-9"
+   inkscape:label="#g3538"
+   transform="matrix(2.6666665,0,0,2.6666667,-1784.7408,-2075.0857)"><path
+     d="m 678.9501,935.65713 h 136.1555 v 67.49997 H 678.9501 c -5.35843,0 -9.67225,-4.31379 -9.67225,-9.67222 v -48.1555 c 0,-5.35843 4.31382,-9.67225 9.67225,-9.67225 z"
+     style="color:#000000;display:block;visibility:visible;fill:#c0351d;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
+     id="path3101-6" /><path
+     d="m 894.27785,787.82938 v 136.1555 h -67.5 v -136.1555 c 0,-5.35843 4.31382,-9.67225 9.67225,-9.67225 h 48.15545 c 5.3585,0 9.6723,4.31382 9.6723,9.67225 z"
+     style="color:#000000;display:block;visibility:visible;fill:#c0351d;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
+     id="path3105-9" /><g
+     inkscape:label="#help_hover"
+     transform="translate(97.852176,324.58283)"
+     id="help_2-4"><path
+       id="path3107-8"
+       style="color:#000000;display:block;visibility:visible;fill:#c0351d;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
+       d="m 716.09793,588.5743 h 70.65544 c 5.3585,0 9.6723,4.31383 9.6723,9.67226 v 70.65548 c 0,5.35843 -4.3138,9.67226 -9.6723,9.67226 h -70.65544 c -5.35843,0 -9.67226,-4.31383 -9.67226,-9.67226 v -70.65548 c 0,-5.35843 4.31383,-9.67226 9.67226,-9.67226 z" /><g
+       id="g3109-3"
+       transform="matrix(1.382752,0,0,1.382752,-554.83363,121.5393)"><path
+         id="path3111-1"
+         style="font-size:12px;fill:#9e2800;fill-opacity:1;fill-rule:evenodd;stroke:#9e2800;stroke-width:3.61598;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1"
+         d="m 944.68089,344.98856 c -13.9699,0 -25.3129,11.34303 -25.3129,25.31286 0,13.96983 11.343,25.31286 25.3129,25.31286 13.9698,0 25.3128,-11.34303 25.3128,-25.31286 0,-13.96983 -11.343,-25.31286 -25.3128,-25.31286 z" /><path
+         id="path3113-6"
+         style="font-size:12px;fill:#c0351d;fill-opacity:1;fill-rule:evenodd;stroke:#c0351d;stroke-width:1.26137;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1"
+         d="m 944.19579,350.76624 c 1.6898,0 3.2955,0.25906 4.7601,0.75798 1.4645,0.49891 2.7542,1.21732 3.8808,2.18297 1.1266,0.96565 2.0101,2.13293 2.6378,3.51702 0.6437,1.368 0.9399,2.91863 0.9399,4.60851 0,3.0257 -0.745,5.36025 -2.274,7.03404 -1.5128,1.6577 -3.5902,2.75759 -6.2457,3.30479 v 0.97021 c 0,0.77252 -0.1775,1.46621 -0.5154,2.0617 -0.3219,0.57939 -0.7992,1.02639 -1.3947,1.36436 -0.5794,0.32189 -1.2304,0.48511 -1.9708,0.48511 -0.7403,0 -1.4055,-0.16323 -2.001,-0.48511 -0.5794,-0.33797 -1.0264,-0.78497 -1.3644,-1.36436 -0.3219,-0.59549 -0.4851,-1.28918 -0.4851,-2.0617 v -3.97181 c 0,-0.8208 0.1471,-1.47556 0.4851,-1.9101 0.338,-0.43454 0.7603,-0.71832 1.2431,-0.87926 0.4828,-0.16094 1.2173,-0.33839 2.183,-0.51542 2.5107,-0.46673 3.7596,-1.72985 3.7596,-3.78989 0,-0.8369 -0.3549,-1.58376 -1.0309,-2.24362 -0.6599,-0.67596 -1.5291,-1.00053 -2.6074,-1.00053 -0.9979,0 -1.7855,0.1898 -2.3649,0.57606 -0.5633,0.38626 -1.1043,0.95754 -1.6676,1.69787 -0.5472,0.72424 -1.0919,1.2813 -1.6069,1.66756 -0.4989,0.37016 -1.1926,0.54574 -2.0617,0.54574 -0.9817,0 -1.8084,-0.38148 -2.5165,-1.12181 -0.692,-0.75642 -1.0308,-1.62383 -1.0308,-2.63776 0,-1.77036 0.5694,-3.33334 1.7281,-4.66915 1.1588,-1.33582 2.5975,-2.35409 4.3357,-3.06223 1.7381,-0.70814 3.4625,-1.06117 5.1846,-1.06117 z m -0.2426,30.36877 c 0.7564,0 1.4625,0.20402 2.1223,0.60638 0.6599,0.40235 1.1601,0.93096 1.5463,1.60691 0.4024,0.65987 0.6064,1.38014 0.6064,2.15266 0,0.78861 -0.204,1.53734 -0.6064,2.2133 -0.3862,0.65986 -0.9006,1.16002 -1.5766,1.54628 -0.6598,0.38626 -1.3517,0.57606 -2.092,0.57606 -0.7403,0 -1.4464,-0.1898 -2.1223,-0.57606 -0.6599,-0.38626 -1.2046,-0.88642 -1.607,-1.54628 -0.3862,-0.67596 -0.576,-1.42469 -0.576,-2.2133 0,-0.77252 0.1898,-1.49279 0.576,-2.15266 0.4024,-0.67595 0.9471,-1.20455 1.607,-1.60691 0.6598,-0.40236 1.3659,-0.60638 2.1223,-0.60638 z" /></g></g><g
+     transform="translate(97.852176,324.58283)"
+     id="g2683-8"><rect
+       id="rect3103-3"
+       style="color:#000000;display:block;visibility:visible;fill:#c0351d;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
+       y="611.07428"
+       x="571.42566"
+       ry="9.6722517"
+       rx="9.6722517"
+       height="67.5"
+       width="67.5" /><g
+       id="g3119-0"
+       transform="matrix(0.19122,0,0,0.186277,554.15057,579.624)"><path
+         id="path3121-5"
+         style="fill:#9e2800;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+         d="m 182.8125,241.875 -25.90625,25.9375 22.625,35.90625 c -3.81735,6.61524 -6.85829,13.71659 -9.0625,21.1875 l -40.90625,10.5625 v 33.09375 l 41.125,12.875 c 2.12042,6.95968 5.00463,13.56753 8.53125,19.78125 l -23.75,32.125 27.34375,27.34375 30.53125,-24.15625 c 7.44407,4.59257 15.51144,8.22743 24.09375,10.71875 l 9.4375,43.6875 h 34.5625 l 7.3125,-42.71875 c 8.66254,-2.16693 16.85304,-5.51868 24.4375,-9.8125 L 345.5,462.125 l 25.90625,-28.78125 -5.33043,-14.22336 -16.21875,6.84375 -19.95082,-25.74539 c -14.6732,20.04461 -38.30889,33.125 -65.03125,33.125 -44.49989,0 -80.625,-36.12511 -80.625,-80.625 0,-31.55572 18.22047,-58.80241 44.65625,-72.03125 V 261.125 c -3.87571,1.52469 -7.60008,3.32993 -11.21875,5.3125 z" /><path
+         id="path3123-1"
+         style="fill:#9e2800;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+         d="m 237.17711,215.20644 v 197.9869 l 51.40534,-3.56274 0.50896,-83.97902 63.11151,91.61347 51.9143,-17.30476 -64.6384,-90.08659 v -1.01793 l 62.60255,-82.45213 -52.93223,-17.30476 -63.11151,88.05073 2.5,-87.54177 z" /></g></g><g
+     transform="translate(97.852176,324.58283)"
+     id="g2666-2"><rect
+       id="rect3115-1"
+       style="color:#000000;display:block;visibility:visible;fill:#c0351d;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
+       y="611.07428"
+       x="638.92566"
+       ry="9.6722517"
+       rx="9.6722517"
+       height="67.5"
+       width="67.5" /><g
+       id="g3125-0"
+       transform="matrix(0.951792,0,0,0.951792,644.12217,616.2705)"><path
+         id="path3127-4"
+         style="color:#000000;fill:#c0351d;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
+         transform="matrix(0.103616,0.05982302,-0.04021123,0.06964794,-9.616397,-30.8242)"
+         d="m 774.28194,408.68011 c 0,128.80657 -104.53867,233.34523 -233.34523,233.34523 -128.80657,0 -233.34523,-104.53866 -233.34523,-233.34523 0,-128.80656 104.53866,-233.34523 233.34523,-233.34523 128.80656,0 233.34523,104.53867 233.34523,233.34523 z" /><path
+         id="path3129-7"
+         style="color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#9e2800;stroke-width:38.2315;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
+         transform="matrix(0.05949876,0.0343516,-0.0343516,0.05949876,10.50202,-13.95859)"
+         d="m 781.353,412.21564 c 0,119.0485 -96.61908,215.66757 -215.66758,215.66757 -119.04849,0 -215.66757,-96.61907 -215.66757,-215.66757 0,-119.0485 96.61908,-215.66757 215.66757,-215.66757 119.0485,0 215.66758,96.61907 215.66758,215.66757 z" /><path
+         id="path3131-4"
+         style="color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#9e2800;stroke-width:33.4712;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
+         transform="matrix(0.103616,0.05982302,-0.04021123,0.06964794,-9.616397,-30.8242)"
+         d="m 774.28194,408.68011 c 0,128.80657 -104.53867,233.34523 -233.34523,233.34523 -128.80657,0 -233.34523,-104.53866 -233.34523,-233.34523 0,-128.80656 104.53866,-233.34523 233.34523,-233.34523 128.80656,0 233.34523,104.53867 233.34523,233.34523 z" /><path
+         id="path3133-1"
+         style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#9e2800;stroke-width:2.62663;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1"
+         d="m 20.587041,46.30389 2.218451,-3.842473" /><path
+         id="path3135-3"
+         style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#9e2800;stroke-width:2.62663;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1"
+         d="m 37.194684,17.538588 2.21845,-3.84247" /><path
+         id="path3137-9"
+         style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#9e2800;stroke-width:2.62663;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1"
+         d="m 5.7609455,16.005538 11.7777275,6.79987" /><path
+         id="path3139-5"
+         style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#9e2800;stroke-width:2.62663;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1"
+         d="M 42.461503,37.1946 54.23923,43.994469" /><g
+         id="g3141-9"
+         transform="matrix(0.383581,0.221461,-0.221461,0.383581,8.370102,-2.862335)"><path
+           id="path3144-6"
+           style="font-size:24px;font-family:'VAG Rounded Black SSi';fill:#9e2800;fill-opacity:1;stroke-width:1pt"
+           d="M 74.967284,42.730939 V 21.67593 c 0,-0.775896 0.252754,-1.422477 0.758263,-1.939741 0.505509,-0.517265 1.157967,-0.775897 1.95737,-0.775897 0.799412,0 1.445993,0.240999 1.939745,0.722995 0.505518,0.481996 0.758263,1.14621 0.758263,1.992643 v 7.864769 l 8.887539,-9.557634 c 0.623068,-0.681848 1.322546,-1.022773 2.098453,-1.022773 0.717114,0 1.340182,0.246876 1.869204,0.740629 0.540779,0.481996 0.81116,1.11682 0.81116,1.904473 0,0.446728 -0.141073,0.887579 -0.423211,1.322551 -0.282137,0.423217 -0.734749,0.946358 -1.357817,1.569426 l -6.824365,6.789095 8.340891,8.799371 c 0.481995,0.458485 0.852308,0.905213 1.110932,1.340186 0.27039,0.423216 0.405593,0.893456 0.405593,1.410721 0,0.82292 -0.270398,1.451866 -0.811168,1.886838 -0.540779,0.423217 -1.210866,0.634825 -2.010277,0.634825 -0.470238,0 -0.899336,-0.129316 -1.287285,-0.387948 -0.376193,-0.258633 -0.858187,-0.693605 -1.445985,-1.304917 L 80.380925,33.437815 v 9.293124 c 0,0.740629 -0.252745,1.363697 -0.758263,1.869205 -0.505499,0.505509 -1.152081,0.758263 -1.939745,0.758263 -0.787655,0 -1.440111,-0.240998 -1.95737,-0.722995 -0.505509,-0.481996 -0.758263,-1.116819 -0.758263,-1.904473 z" /><path
+           id="path3146-9"
+           style="font-size:12px;fill:#9e2800;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.592158;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1"
+           d="m 61.699541,52.988338 3.46878,3.633952 5.616089,-3.799151 4.459855,1.982189 1.486616,6.510433 4.752861,0.0027 1.358774,-6.726702 4.459853,-1.768591 5.616085,3.633983 2.642874,-3.633983 -6.373569,-6.014866 C 72.851667,61.791746 58.734768,38.698541 72.766573,29.037295 l -1.8e-5,-3.468781 -1.651782,0.825896 -5.120569,-3.255228 -3.537201,2.904804 3.206844,5.470982 -1.816972,4.459848 -6.257519,1.039474 -0.01931,4.741815 6.442017,1.651798 1.775676,4.335986 z" /></g><path
+         id="path3148-4"
+         style="fill:#9e2800;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+         d="m 19.965042,8.6470185 4.44735,7.7258455 c 0.353344,-0.144114 0.691878,-0.339608 1.054821,-0.456138 L 21.27644,8.6755271 c -0.432996,0.00221 -0.887398,-0.050745 -1.311398,-0.028509 z m 3.677617,0.085526 3.934194,6.7565515 c 0.391859,-0.06569 0.77218,-0.165171 1.168855,-0.199561 L 25.039583,8.8750877 C 24.568468,8.81779 24.106979,8.7679947 23.642659,8.7325445 Z M 17.769875,8.932105 c -0.403196,0.057638 -0.805774,0.093852 -1.197363,0.171052 l 5.046032,8.752157 c 0.312028,-0.214042 0.614774,-0.438587 0.940786,-0.62719 z m 9.863996,0.3706126 3.535073,6.1008524 c 0.446082,0.03397 0.895476,0.01055 1.339907,0.08553 L 29.087812,9.5592955 C 28.594356,9.4374818 28.123428,9.4016357 27.633871,9.3027176 Z M 14.519889,9.5878041 c -0.37117,0.1130223 -0.698094,0.2948745 -1.054821,0.4276299 l 5.73024,9.921012 c 0.265219,-0.284424 0.542678,-0.538328 0.826751,-0.798242 z m 17.447297,0.9122769 3.39253,5.872783 c 0.563326,0.219731 1.137292,0.360838 1.682011,0.655699 L 33.59218,11.041746 C 33.0478,10.832311 32.510958,10.681892 31.967186,10.500081 Z M 11.52648,10.756659 c -0.343688,0.176736 -0.615964,0.428916 -0.940786,0.62719 l 6.528482,11.317937 c 0.02135,-0.03772 0.03531,-0.07643 0.05702,-0.114035 0.191804,-0.332214 0.471212,-0.572396 0.684207,-0.883768 z m -2.6227966,1.796045 c -0.2876989,0.237355 -0.5895433,0.453963 -0.8552597,0.712717 l 3.6776163,6.385939 1.938589,1.111837 z" /><path
+         id="path3150-3"
+         style="fill:#9e2800;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+         d="m 42.771967,37.497779 c -0.18885,0.294778 -0.430565,0.539783 -0.62719,0.826751 l 3.249986,12.116179 c 0.381015,-0.114345 0.717348,-0.292549 1.083329,-0.42763 L 43.199597,37.754357 Z m 1.168855,0.684207 3.107443,11.603023 c 0.354471,-0.144693 0.745174,-0.234159 1.083329,-0.399121 L 45.337746,39.008737 Z m -2.252184,0.798243 c -0.289457,0.377179 -0.564314,0.769337 -0.883768,1.111837 l 2.879374,10.747764 c 0.37093,-0.0778 0.780961,-0.07542 1.140346,-0.171052 z m 4.418842,0.456138 2.594288,9.692943 c 0.370016,-0.198123 0.650504,-0.489058 0.997802,-0.712716 L 47.504404,40.23461 Z m -5.815766,1.111838 c -0.307817,0.300483 -0.611032,0.613876 -0.940786,0.883768 l 2.594288,9.692943 c 0.386889,-0.05044 0.763746,-0.102707 1.140346,-0.171052 z m 7.953915,0.114034 1.995606,7.383742 c 0.334548,-0.237285 0.688177,-0.450042 0.997803,-0.712716 L 49.671062,41.48899 Z m -27.054715,1.140347 1.453942,5.445153 c 0.452854,0.229569 0.913502,0.445682 1.368415,0.655699 l -1.339907,-5.046032 c -0.02654,-0.01511 -0.05904,-0.01322 -0.08553,-0.02851 -0.511693,-0.295426 -0.93457,-0.681545 -1.396924,-1.026311 z m 17.646858,0.08553 c -0.326701,0.24298 -0.682679,0.413233 -1.026311,0.62719 l 2.366218,8.837684 c 0.393447,-0.02251 0.755591,-0.102721 1.140347,-0.142544 z m 11.574515,0.02851 1.368415,5.046032 c 0.345565,-0.322805 0.575415,-0.754568 0.883769,-1.111837 l -0.826751,-3.10745 z m -13.142491,0.940786 c -0.350871,0.197748 -0.690252,0.402132 -1.05482,0.570173 l 2.109641,7.896898 c 0.406886,0.0039 0.826568,0.01365 1.225872,0 z m 15.309149,0.313595 0.570173,2.109641 c 0.292345,-0.381241 0.633437,-0.723795 0.883768,-1.140346 l -0.02851,-0.171052 z m -29.192864,0.02851 1.368415,5.074541 c 0.448409,0.196186 0.890806,0.421343 1.339907,0.598681 l -1.339907,-5.07454 c -0.461193,-0.175502 -0.91895,-0.37367 -1.368415,-0.598682 z m 12.258722,0.42763 c -0.354373,0.146261 -0.719205,0.28075 -1.083329,0.399121 l 1.938589,7.241199 c 0.407214,0.02942 0.79627,0.01591 1.197363,0.02851 z m -10.206099,0.456138 1.368415,5.017524 c 0.438344,0.163361 0.873599,0.282142 1.311399,0.42763 l -1.396924,-5.160067 c -0.425709,-0.09708 -0.862757,-0.148783 -1.28289,-0.285087 z m 8.552597,0.171052 c -0.374921,0.105124 -0.758189,0.152563 -1.140346,0.228069 l 1.767536,6.5855 c 0.417585,0.05556 0.841861,0.161094 1.254381,0.199561 z m -6.5855,0.285087 1.396924,5.217084 c 0.437208,0.136162 0.875912,0.309264 1.311399,0.42763 l -1.48245,-5.473662 c -0.410556,-0.03801 -0.816999,-0.09811 -1.225873,-0.171052 z m 4.846472,0.02851 c -0.383528,0.05965 -0.75248,0.170031 -1.140346,0.199561 l 1.596484,5.986818 c 0.420157,0.08077 0.838096,0.135663 1.254381,0.19956 z m -2.9649,0.171052 1.510958,5.673223 c 0.426295,0.107043 0.830876,0.138099 1.254381,0.228069 l -1.567976,-5.872783 c -0.400007,0.0135 -0.795822,-0.0094 -1.197363,-0.02851 z" /><path
+         id="path3152-8"
+         style="fill:#9e2800;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+         d="m 38.011021,17.598737 c 0.542572,0.350359 1.057977,0.732777 1.539468,1.140346 h 6.585499 c -0.425394,-0.382895 -0.833107,-0.770531 -1.282889,-1.140346 z m 3.934195,3.649108 c 0.265926,0.362893 0.453852,0.757106 0.684208,1.140346 h 7.041638 C 49.351173,22.005945 49.04412,21.622497 48.701768,21.247845 Z m 1.881571,3.649108 c 0.139643,0.379207 0.319304,0.751338 0.42763,1.140346 h 8.06795 C 52.087489,25.65696 51.8949,25.273401 51.638159,24.896953 Z m 0.883769,3.649108 c 0.03797,0.380432 0.04852,0.756961 0.05702,1.140346 h 9.436365 c -0.158945,-0.377879 -0.24645,-0.763417 -0.42763,-1.140346 z m -0.08553,3.649108 c -0.05725,0.381122 -0.16877,0.761873 -0.256578,1.140346 h 11.03285 c -0.08562,-0.380199 -0.118242,-0.758318 -0.22807,-1.140346 z m -1.083329,3.649108 c -0.164919,0.382192 -0.313311,0.767211 -0.513156,1.140346 h 12.857404 c -0.0041,-0.378581 -0.05437,-0.756802 -0.08553,-1.140346 z m 3.249987,3.649108 c -0.344308,0.411191 1.823608,0.77443 1.442538,1.140346 h 7.252602 c 0.09342,-0.372151 0.109054,-0.75927 0.171052,-1.140346 z" /></g></g><g
+     transform="translate(97.852176,257.08279)"
+     id="g4852-6"><rect
+       id="rect3117-1"
+       style="color:#000000;display:block;visibility:visible;fill:#c0351d;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
+       y="521.07434"
+       x="728.92566"
+       ry="9.6722517"
+       rx="9.6722517"
+       height="67.5"
+       width="67.5" /><g
+       id="g3154-6"
+       transform="matrix(0.974352,0,0,0.974352,734.36497,524.5912)"><path
+         id="path3156-6"
+         style="font-size:12px;fill:#c0351d;fill-opacity:1;fill-rule:evenodd;stroke:#9e2800;stroke-width:5.13162;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+         d="m 30.955756,15.427747 c -1.087318,0.510106 -1.96266,1.889245 -1.96266,3.092241 v 35.444461 c 0,1.203005 0.875342,1.760821 1.96266,1.250725 l 18.300763,-8.585527 c 1.087316,-0.510097 1.96266,-1.889236 1.96266,-3.092241 V 8.092949 c 0,-1.2030017 -0.875344,-1.7608261 -1.96266,-1.2507279 z" /><path
+         id="path3158-0"
+         style="font-size:12px;fill:#c0351d;fill-opacity:1;fill-rule:evenodd;stroke:#9e2800;stroke-width:5.13162;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+         d="m 27.156248,15.428044 c 1.087317,0.510099 1.962671,1.887649 1.962671,3.088674 v 35.451591 c 0,1.201024 -0.875354,1.757258 -1.962671,1.247159 L 8.8554464,46.629917 C 7.7681288,46.119817 6.8927769,44.742267 6.8927769,43.541243 V 8.0896519 c 0,-1.2010253 0.8753519,-1.7572579 1.9626695,-1.2471589 z" /></g></g><g
+     transform="translate(137.85218,392.08282)"
+     id="g4858-8"><rect
+       id="rect3189-7"
+       style="color:#000000;display:block;visibility:visible;fill:#c0351d;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
+       y="453.57431"
+       x="688.92566"
+       ry="9.6722517"
+       rx="9.6722517"
+       height="67.5"
+       width="67.5" /><g
+       id="g4741-5"
+       transform="translate(-42.608491,3.9217495)"><path
+         sodipodi:nodetypes="cccc"
+         id="path3764-3"
+         d="m 755.1875,488.15625 -13.65625,14.8125 m 9.65625,4.1875 11.40625,-12.40625"
+         style="font-size:12px;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#9e2800;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1" /><path
+         style="font-size:12px;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#9e2800;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1"
+         d="m 753.04993,483.66441 c 3.03987,9.74125 13.37683,15.16112 23.11808,12.12125 7.40643,-2.31126 12.2725,-8.85067 12.86904,-16.13948 l -18.24287,5.69289 -4.26082,-13.65382 18.0729,-5.63985 c -4.66921,-5.38092 -12.22063,-7.81259 -19.45276,-5.55572 -9.74125,3.03986 -15.14344,13.43349 -12.10357,23.17473 z"
+         id="path586-4" /></g></g></g></svg>
diff --git a/images/ui/rightArrow.svg b/images/ui/rightArrow.svg
new file mode 100644
index 0000000..28a12e7
--- /dev/null
+++ b/images/ui/rightArrow.svg
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg version="1.1" id="layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 792 612" style="enable-background:new 0 0 792 612;" xml:space="preserve">
+<style type="text/css">
+	.st0{fill:#B73822;}
+</style>
+<path id="arrow_right" class="st0" d="M393.28,285.32c-2.05,0.03-3.69,1.7-3.69,3.75v32.52c0.01,1.44,0.84,2.75,2.14,3.37
+	s2.83,0.44,3.96-0.46l20.03-16.26c0.87-0.71,1.38-1.78,1.38-2.91s-0.51-2.2-1.38-2.91l-20.03-16.26
+	C395.01,285.61,394.15,285.31,393.28,285.32L393.28,285.32z"/>
+</svg>
diff --git a/sounds/CMakeLists.txt b/sounds/CMakeLists.txt
index 4238d0d..c879625 100644
--- a/sounds/CMakeLists.txt
+++ b/sounds/CMakeLists.txt
@@ -1,2 +1,17 @@
-install( FILES 1.wav 2.wav 3.wav 4.wav lose.wav  DESTINATION  ${KDE_INSTALL_DATADIR}/blinken/sounds )
+set(SOUND_FILES
+    1.wav
+    2.wav
+    3.wav
+    4.wav
+    lose.wav
+)
 
+if(QML_VERSION)
+    qt_add_resources(blinken "sounds"
+        PREFIX "/"
+        FILES
+            ${SOUND_FILES}
+    )
+else()
+    install( FILES  ${SOUND_FILES} DESTINATION  ${KDE_INSTALL_DATADIR}/blinken/sounds )
+endif()
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index db46c9d..2a224cc 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,47 +1,107 @@
+if(QML_VERSION)
+    ecm_setup_version(${RELEASE_SERVICE_VERSION} VARIABLE_PREFIX BLINKEN VERSION_HEADER blinken_version.h)
+    set(BLINKEN_SRCS
+        main.cpp
+        maskedmousearea.cpp
+        blinkengame.cpp
+        soundsplayer.cpp
+        highScoreManager.cpp
+        settings.cpp
+    )
+    kconfig_add_kcfg_files(BLINKEN_SRCS settings.kcfgc 
+        GENERATE_MOC
+    )
+    set(BLINKEN_QML_UI_SRCS 
+        ui/Blinken.qml
+        ui/BlinkenMenu.qml
+        ui/ExitButton.qml
+        ui/HighScoreButton.qml
+        ui/ScoreAndCounter.qml
+        ui/Numbers.qml
+        ui/ScoreList.qml
+        ui/HighScoreLists.qml
+        ui/GameOptions.qml
+        ui/GameButtons.qml
+        ui/GameButton.qml
+    )
 
-########### next target ###############
-
-ecm_setup_version(${RELEASE_SERVICE_VERSION} VARIABLE_PREFIX BLINKEN VERSION_HEADER blinken_version.h)
-
-set(blinken_SRCS 
-    blinken.cpp
-    blinkengame.cpp
-    blinkengame.h
-    blinken.h
-    button.cpp
-    button.h
-    counter.cpp
-    counter.h
-    highscoredialog.cpp
-    highscoredialog.h
-    main.cpp
-    number.cpp
-    number.h
-    soundsplayer.cpp
-    soundsplayer.h )
-
-kconfig_add_kcfg_files(blinken_SRCS settings.kcfgc )
-
-file(GLOB ICON_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/../icons/*-apps-blinken.png")
-ecm_add_app_icon(blinken_SRCS ICONS ${ICON_SRCS})
-add_executable(blinken ${blinken_SRCS})
-
-target_link_libraries(blinken
-    KF6::CoreAddons
-    KF6::I18n
-    KF6::XmlGui
-    KF6::GuiAddons
-    Qt::Svg
-    KF6::DBusAddons
-    KF6::Crash
-    Phonon::phonon4qt6
+    add_executable(blinken
+        ${BLINKEN_SRCS}
     )
+    target_compile_definitions(blinken PRIVATE QML_VERSION)
 
-install(TARGETS blinken EXPORT blinken ${KDE_INSTALL_TARGETS_DEFAULT_ARGS} )
+    ecm_add_qml_module(blinken
+        URI "org.kde.blinken"
+        VERSION 1.0
+    )
+    ecm_target_qml_sources(blinken SOURCES
+        ${BLINKEN_QML_UI_SRCS}
+        VERSION 1.0
+    )
+    if(ANDROID)
+        include(ECMAddAndroidApk)
+        ecm_add_android_apk(blinken ANDROID_DIR ${CMAKE_CURRENT_SOURCE_DIR}/android)
+    endif()
+    
+    target_link_libraries(blinken PRIVATE
+        Qt6::Quick
+        Qt6::Core
+        Qt6::Gui
+        Qt6::Qml
+        Qt6::Multimedia
+        
+        KF6::CoreAddons
+        KF6::I18n
+        KF6::GuiAddons
+        KF6::Kirigami
+        KF6::ConfigCore
+        KF6::ConfigWidgets 
+    )
 
+else()
+    ecm_setup_version(${RELEASE_SERVICE_VERSION} VARIABLE_PREFIX BLINKEN VERSION_HEADER blinken_version.h)
 
-########### install files ###############
+    set(blinken_SRCS 
+        blinken.cpp
+        blinkengame.cpp
+        blinkengame.h
+        blinken.h
+        button.cpp
+        button.h
+        counter.cpp
+        counter.h
+        highscoredialog.cpp
+        highscoredialog.h
+        highScoreManager.cpp
+        highScoreManager.h
+        main.cpp
+        number.cpp
+        number.h
+        soundsplayer.cpp
+        soundsplayer.h )
+
+    kconfig_add_kcfg_files(blinken_SRCS settings.kcfgc GENERATE_MOC)
 
+    file(GLOB ICON_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/../icons/*-apps-blinken.png")
+    ecm_add_app_icon(blinken_SRCS ICONS ${ICON_SRCS})
+    add_executable(blinken ${blinken_SRCS})
+
+    target_link_libraries(blinken
+        KF6::CoreAddons
+        KF6::I18n
+        KF6::XmlGui
+        KF6::GuiAddons
+        Qt::Svg
+        Qt6::Qml
+        KF6::DBusAddons
+        KF6::Crash
+        Phonon::phonon4qt6
+    )
+
+endif()
+
+install(TARGETS blinken EXPORT blinken ${KDE_INSTALL_TARGETS_DEFAULT_ARGS} )
+
+########### install files ###############
 install( PROGRAMS org.kde.blinken.desktop  DESTINATION  ${KDE_INSTALL_APPDIR} )
 install( FILES blinken.kcfg  DESTINATION  ${KDE_INSTALL_KCFGDIR} )
-
diff --git a/src/android/AndroidManifest.xml b/src/android/AndroidManifest.xml
new file mode 100644
index 0000000..b3742ad
--- /dev/null
+++ b/src/android/AndroidManifest.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.kde.blinken" android:installLocation="auto" android:versionCode="-- %%INSERT_VERSION_CODE%% --" android:versionName="-- %%INSERT_VERSION_NAME%% --">
+    <!-- %%INSERT_PERMISSIONS -->
+    <!-- %%INSERT_FEATURES -->
+    <supports-screens android:anyDensity="true" android:largeScreens="true" android:normalScreens="true" android:smallScreens="true"/>
+    <application
+        android:name="org.qtproject.qt.android.bindings.QtApplication" 
+        android:hardwareAccelerated="true" 
+        android:label="blinken" 
+        android:requestLegacyExternalStorage="true" 
+        android:appCategory="game" 
+        android:allowBackup="true" 
+        android:fullBackupOnly="false" 
+        android:icon="@drawable/icon"
+        android:theme="@style/FullScreen"
+        >
+        <activity 
+            android:name="org.qtproject.qt.android.bindings.QtActivity" 
+            android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density" 
+            android:launchMode="singleTop" 
+            android:screenOrientation="sensorLandscape" 
+            android:exported="true" 
+            android:label="blinken"
+        >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+            <meta-data android:name="android.app.lib_name" android:value="-- %%INSERT_APP_LIB_NAME%% --"/>
+            <meta-data android:name="android.app.arguments" android:value="-- %%INSERT_APP_ARGUMENTS%% --"/>
+
+            <!-- Background running -->
+            <meta-data android:name="android.app.background_running" android:value="false"/>
+
+            <!-- auto screen scale factor -->
+            <meta-data android:name="android.app.auto_screen_scale_factor" android:value="true"/>
+
+        </activity>
+
+        <provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.qtprovider" android:exported="false" android:grantUriPermissions="true">
+            <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/qtprovider_paths"/>
+        </provider>
+    </application>
+</manifest>
diff --git a/src/android/res/drawable-hdpi/icon.png b/src/android/res/drawable-hdpi/icon.png
new file mode 100644
index 0000000..c6af5ad
Binary files /dev/null and b/src/android/res/drawable-hdpi/icon.png differ
diff --git a/src/android/res/drawable-ldpi/icon.png b/src/android/res/drawable-ldpi/icon.png
new file mode 100644
index 0000000..f6ab491
Binary files /dev/null and b/src/android/res/drawable-ldpi/icon.png differ
diff --git a/src/android/res/drawable-mdpi/icon.png b/src/android/res/drawable-mdpi/icon.png
new file mode 100644
index 0000000..311cacd
Binary files /dev/null and b/src/android/res/drawable-mdpi/icon.png differ
diff --git a/src/android/res/drawable-xhdpi/icon.png b/src/android/res/drawable-xhdpi/icon.png
new file mode 100644
index 0000000..09f0db1
Binary files /dev/null and b/src/android/res/drawable-xhdpi/icon.png differ
diff --git a/src/android/res/drawable-xxhdpi/icon.png b/src/android/res/drawable-xxhdpi/icon.png
new file mode 100644
index 0000000..9e69adf
Binary files /dev/null and b/src/android/res/drawable-xxhdpi/icon.png differ
diff --git a/src/android/res/drawable-xxxhdpi/icon.png b/src/android/res/drawable-xxxhdpi/icon.png
new file mode 100644
index 0000000..480e41a
Binary files /dev/null and b/src/android/res/drawable-xxxhdpi/icon.png differ
diff --git a/src/android/res/values/styles.xml b/src/android/res/values/styles.xml
new file mode 100644
index 0000000..640090a
--- /dev/null
+++ b/src/android/res/values/styles.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <style name="FullScreen" >
+        <item name="android:windowNoTitle">true</item>
+        <item name="android:windowFullscreen">true</item>
+        <item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
+    </style>
+</resources>
\ No newline at end of file
diff --git a/src/blinken.cpp b/src/blinken.cpp
index fa5f7b2..b7aff87 100644
--- a/src/blinken.cpp
+++ b/src/blinken.cpp
@@ -25,6 +25,7 @@
 #include "counter.h"
 #include "number.h"
 #include "highscoredialog.h"
+#include "highScoreManager.h"
 #include "settings.h"
 
 static const double centerX = 2.0;
@@ -36,14 +37,14 @@ static const double ellipseBigAxisY = 2.74;
 static const double nonButtonRibbonX = 150.0;
 static const double nonButtonRibbonY = 125.0;
 
-blinken::blinken() : m_overHighscore(false), m_overQuit(false), m_overCentralText(false), m_overMenu(false), m_overAboutKDE(false), m_overAboutBlinken(false), m_overSettings(false), m_overManual(false), m_overCentralLetters(false), m_overCounter(false), m_overFont(false), m_overSound(false), m_showPreferences(false), m_updateButtonHighlighting(false), m_highlighted(blinkenGame::none)
+blinken::blinken() : m_overHighscore(false), m_overQuit(false), m_overCentralText(false), m_overMenu(false), m_overAboutKDE(false), m_overAboutBlinken(false), m_overSettings(false), m_overManual(false), m_overCentralLetters(false), m_overCounter(false), m_overFont(false), m_overSound(false), m_showPreferences(false), m_updateButtonHighlighting(false), m_highlighted(BlinkenGame::None)
 {
 	m_renderer = new QSvgRenderer(QStandardPaths::locate(QStandardPaths::AppLocalDataLocation, QStringLiteral("images/blinken.svg")));
 	
-	m_buttons[0] = new button(blinkenGame::blue);
-	m_buttons[1] = new button(blinkenGame::yellow);
-	m_buttons[2] = new button(blinkenGame::red);
-	m_buttons[3] = new button(blinkenGame::green);
+	m_buttons[0] = new button(BlinkenGame::Blue);
+	m_buttons[1] = new button(BlinkenGame::Yellow);
+	m_buttons[2] = new button(BlinkenGame::Red);
+	m_buttons[3] = new button(BlinkenGame::Green);
 	
 	m_fillColor = QColor(40, 40, 40);
 	m_fontColor = QColor(126, 126, 126);
@@ -56,9 +57,9 @@ blinken::blinken() : m_overHighscore(false), m_overQuit(false), m_overCentralTex
 	m_unhighlighter = new QTimer(this);
 	connect(m_unhighlighter, &QTimer::timeout, this, &blinken::unhighlight);
 	
-	connect(&m_game, &blinkenGame::gameEnded, this, &blinken::checkHS);
+	connect(&m_game, &BlinkenGame::gameEnded, this, &blinken::checkHS);
 	connect(&m_game, SIGNAL(phaseChanged()), this, SLOT(update()));
-	connect(&m_game, &blinkenGame::highlight, this, &blinken::highlight);
+	connect(&m_game, &BlinkenGame::highlight, this, &blinken::highlight);
 	
 	m_helpMenu = new KHelpMenu(this, KAboutData::applicationData());
 	m_helpMenu->menu(); // ensures the actions are created
@@ -112,16 +113,16 @@ void blinken::paintEvent(QPaintEvent *)
 
 	const auto sz = QSize((int)(width() * xScaleButtons), (int)(height() * yScaleButtons));
 
-	auto getPixmapFor = [this, sz](blinkenGame::color color, const QString& pixmapName) -> QPixmap {
+	auto getPixmapFor = [this, sz](BlinkenGame::Color color, const QString& pixmapName) -> QPixmap {
 		return getPixmap( m_highlighted & color ?
 			QStringLiteral("%1_highlight").arg(pixmapName) :
 			QStringLiteral("%1_normal").arg(pixmapName), sz);
 	};
 
-	p.drawPixmap(QPointF(width() / 1.975, height() / 28.0), getPixmapFor(blinkenGame::red, QStringLiteral("red")));
-	p.drawPixmap(QPointF(width() / 1.975, height() / 2.45), getPixmapFor(blinkenGame::green, QStringLiteral("green")));
-	p.drawPixmap(QPointF(width() / 30.0, height() / 28.0), getPixmapFor(blinkenGame::yellow, QStringLiteral("yellow")));
-	p.drawPixmap(QPointF(width() / 30.0, height() / 2.45), getPixmapFor(blinkenGame::blue, QStringLiteral("blue")));
+	p.drawPixmap(QPointF(width() / 1.975, height() / 28.0), getPixmapFor(BlinkenGame::Red, QStringLiteral("red")));
+	p.drawPixmap(QPointF(width() / 1.975, height() / 2.45), getPixmapFor(BlinkenGame::Green, QStringLiteral("green")));
+	p.drawPixmap(QPointF(width() / 30.0, height() / 28.0), getPixmapFor(BlinkenGame::Yellow, QStringLiteral("yellow")));
+	p.drawPixmap(QPointF(width() / 30.0, height() / 2.45), getPixmapFor(BlinkenGame::Blue, QStringLiteral("blue")));
 
 	drawMenuQuit(p);
 	p.resetTransform();
@@ -157,7 +158,7 @@ void blinken::paintEvent(QPaintEvent *)
 		m_soundRect = QRect(181, 197, 25, 25);
 		m_fontRect = QRect(432, 197, 25, 25);
 		p.drawRect(m_soundRect);
-		if (blinkenSettings::playSounds())
+		if (BlinkenSettings::playSounds())
 		{
 			p.drawLine(186, 202, 201, 217);
 			p.drawLine(186, 217, 201, 202);
@@ -165,7 +166,7 @@ void blinken::paintEvent(QPaintEvent *)
 		if (!m_alwaysUseNonCoolFont)
 		{
 			p.drawRect(m_fontRect);
-			if (blinkenSettings::customFont())
+			if (BlinkenSettings::customFont())
 			{
 				p.drawLine(437, 202, 452, 217);
 				p.drawLine(437, 217, 452, 202);
@@ -219,19 +220,19 @@ void blinken::paintEvent(QPaintEvent *)
 	aux4 = (double)height() / 105.0;
 	switch (m_game.phase())
 	{
-		case blinkenGame::starting:
+		case BlinkenGame::Starting:
 			drawText(p, i18nc("@action:button Start a new game", "Start"), QPointF(aux1, aux2), true, aux3, aux4, &m_centralTextRect, m_overCentralText, true);
 		break;
 		
-		case blinkenGame::choosingLevel:
+		case BlinkenGame::ChoosingLevel:
 			drawLevel(p);
 		break;
 		
-		case blinkenGame::waiting3:
-		case blinkenGame::waiting2:
-		case blinkenGame::waiting1:
-		case blinkenGame::learningTheSequence:
-		case blinkenGame::typingTheSequence:
+		case BlinkenGame::Waiting3:
+		case BlinkenGame::Waiting2:
+		case BlinkenGame::Waiting1:
+		case BlinkenGame::LearningTheSequence:
+		case BlinkenGame::TypingTheSequence:
 			drawText(p, i18n("Restart"), QPointF(aux1, aux2), true, aux3, aux4, &m_centralTextRect, m_overCentralText, true);
 		break;
 	}
@@ -279,7 +280,7 @@ void blinken::keyPressEvent(QKeyEvent *e)
 	}
 	else
 	{
-		if (m_game.phase() == blinkenGame::starting)
+		if (m_game.phase() == BlinkenGame::Starting)
 		{
 			if (e -> key() == Qt::Key_Return || e -> key() == Qt::Key_Enter)
 			{
@@ -287,7 +288,7 @@ void blinken::keyPressEvent(QKeyEvent *e)
 				return;
 			}
 		}
-		else if (m_game.phase() == blinkenGame::choosingLevel)
+		else if (m_game.phase() == BlinkenGame::ChoosingLevel)
 		{
 			if (e -> key() == Qt::Key_1)
 			{
@@ -306,10 +307,10 @@ void blinken::keyPressEvent(QKeyEvent *e)
 			}
 		}
 		
-		if (e -> key() == m_buttons[0] -> key()) pressedColor(blinkenGame::color::blue);
-		else if (e -> key() == m_buttons[1] -> key()) pressedColor(blinkenGame::color::yellow);
-		else if (e -> key() == m_buttons[2] -> key()) pressedColor(blinkenGame::color::red);
-		else if (e -> key() == m_buttons[3] -> key()) pressedColor(blinkenGame::color::green);
+		if (e -> key() == m_buttons[0] -> key()) pressedColor(BlinkenGame::Color::Blue);
+		else if (e -> key() == m_buttons[1] -> key()) pressedColor(BlinkenGame::Color::Yellow);
+		else if (e -> key() == m_buttons[2] -> key()) pressedColor(BlinkenGame::Color::Red);
+		else if (e -> key() == m_buttons[3] -> key()) pressedColor(BlinkenGame::Color::Green);
 	}
 }
 
@@ -325,7 +326,7 @@ void blinken::keyReleaseEvent(QKeyEvent *e)
 
 void blinken::togglePreferences()
 {
-	if (m_game.phase() == blinkenGame::starting || m_game.phase() == blinkenGame::choosingLevel)
+	if (m_game.phase() == BlinkenGame::Starting || m_game.phase() == BlinkenGame::ChoosingLevel)
 	{
 		m_showPreferences = !m_showPreferences;
 		for (int i = 0; i < 4; i++) m_buttons[i] -> setSelected(false);
@@ -349,14 +350,14 @@ void blinken::mousePressEvent(QMouseEvent *e)
 	}
 	else if (m_showPreferences && m_fontRect.contains(e -> pos()) && !m_alwaysUseNonCoolFont)
 	{
-		blinkenSettings::setCustomFont(!blinkenSettings::customFont());
-		blinkenSettings::self()->save();
+		BlinkenSettings::setCustomFont(!BlinkenSettings::customFont());
+		BlinkenSettings::self()->save();
 		update();
 	}
 	else if (m_showPreferences && m_soundRect.contains(e -> pos()))
 	{
-		blinkenSettings::setPlaySounds(!blinkenSettings::playSounds());
-		blinkenSettings::self()->save();
+		BlinkenSettings::setPlaySounds(!BlinkenSettings::playSounds());
+		BlinkenSettings::self()->save();
 		update();
 	}
 	else if (m_overQuit) qApp->quit();
@@ -364,11 +365,11 @@ void blinken::mousePressEvent(QMouseEvent *e)
 	else if (m_overAboutKDE) m_helpMenu -> aboutKDE();
 	else if (m_overSettings) togglePreferences();
 	else if (m_overManual) m_helpMenu -> appHelpActivated();
-	else if (m_game.phase() != blinkenGame::choosingLevel && m_overCentralText)
+	else if (m_game.phase() != BlinkenGame::ChoosingLevel && m_overCentralText)
 	{
 		startGamePressed();
 	}
-	else if (m_game.phase() == blinkenGame::choosingLevel)
+	else if (m_game.phase() == BlinkenGame::ChoosingLevel)
 	{
 		int level = 0;
 		if (m_levelsRect[1].contains(e -> pos())) level = 1;
@@ -385,28 +386,28 @@ void blinken::mousePressEvent(QMouseEvent *e)
 	if (insideGreen(p))
 	{
 		if (m_showPreferences) selectButton(3);
-		else pressedColor(blinkenGame::color::green);
+		else pressedColor(BlinkenGame::Color::Green);
 	}
 	else if (insideBlue(p))
 	{
 		if (m_showPreferences) selectButton(0);
-		else pressedColor(blinkenGame::color::blue);
+		else pressedColor(BlinkenGame::Color::Blue);
 	}
 	else if (insideYellow(p))
 	{
 		if (m_showPreferences) selectButton(1);
-		else pressedColor(blinkenGame::color::yellow);
+		else pressedColor(BlinkenGame::Color::Yellow);
 	}
 	else if (insideRed(p))
 	{
 		if (m_showPreferences) selectButton(2);
-		else pressedColor(blinkenGame::color::red);
+		else pressedColor(BlinkenGame::Color::Red);
 	}
 }
 
 void blinken::checkHS()
 {
-	highScoreManager hsm;
+	HighScoreManager hsm;
 	if (hsm.scoreGoodEnough(m_game.level(), m_game.score()))
 	{
 		bool ok;
@@ -421,12 +422,12 @@ void blinken::checkHS()
 	}
 }
 
-void blinken::highlight(blinkenGame::color c, bool unhighlight)
+void blinken::highlight(BlinkenGame::Color c, bool unhighlight)
 {
 	m_highlighted = c;
 	update();
 	if (unhighlight) m_unhighlighter -> start(250);
-	else if (c == blinkenGame::none)
+	else if (c == BlinkenGame::None)
 	{
 		m_unhighlighter -> stop();
 		updateCursor(mapFromGlobal(QCursor::pos()));
@@ -435,10 +436,10 @@ void blinken::highlight(blinkenGame::color c, bool unhighlight)
 
 void blinken::unhighlight()
 {
-	highlight(blinkenGame::none, false);
+	highlight(BlinkenGame::None, false);
 }
 
-void blinken::pressedColor(blinkenGame::color color)
+void blinken::pressedColor(BlinkenGame::Color color)
 {
 	if (m_game.canType())
 	{
@@ -449,10 +450,10 @@ void blinken::pressedColor(blinkenGame::color color)
 
 void blinken::startGamePressed()
 {
-	highlight(blinkenGame::none, true);
+	highlight(BlinkenGame::None, true);
 	m_overCentralText = false;
 	for(int i = 0; i < 3; i++) m_overLevels[i] = false;
-	m_game.setPhase(blinkenGame::choosingLevel);
+	m_game.setPhase(BlinkenGame::ChoosingLevel);
 	m_updateButtonHighlighting = true;
 }
 
@@ -650,19 +651,19 @@ void blinken::drawScoreAndCounter(QPainter &p)
 	
 	switch (m_game.phase())
 	{
-		case blinkenGame::waiting3:
+		case BlinkenGame::Waiting3:
 			c1 = Qt::red;
 			c2 = Qt::red;
 			c3 = Qt::red;
 		break;
 		
-		case blinkenGame::waiting2:
+		case BlinkenGame::Waiting2:
 			c1 = m_countDownColor;
 			c2 = Qt::red;
 			c3 = Qt::red;
 		break;
 		
-		case blinkenGame::waiting1:
+		case BlinkenGame::Waiting1:
 			c1 = m_countDownColor;
 			c2 = c1;
 			c3 = Qt::red;
@@ -675,7 +676,7 @@ void blinken::drawScoreAndCounter(QPainter &p)
 		break;
 	}
 	
-	counter::paint(p, m_game.phase() != blinkenGame::starting, m_game.score(), true, c1, c2, c3, m_renderer);
+	counter::paint(p, m_game.phase() != BlinkenGame::Starting, m_game.score(), true, c1, c2, c3, m_renderer);
 	
 	p.translate(-268, -110);
 }
@@ -707,15 +708,15 @@ void blinken::drawStatusText(QPainter &p)
 	{
 		switch (m_game.phase())
 		{
-			case blinkenGame::starting:
+			case BlinkenGame::Starting:
 				text = i18n("Press Start to begin");
 			break;
 			
-			case blinkenGame::choosingLevel:
+			case BlinkenGame::ChoosingLevel:
 				text = i18n("Set the Difficulty Level...");
 			break;
 			
-			case blinkenGame::waiting3:
+			case BlinkenGame::Waiting3:
 				if (m_overCentralText)
 				{
 					text = restartText;
@@ -726,7 +727,7 @@ void blinken::drawStatusText(QPainter &p)
 				}
 			break;
 			
-			case blinkenGame::waiting2:
+			case BlinkenGame::Waiting2:
 				if (m_overCentralText)
 				{
 					text = restartText;
@@ -744,7 +745,7 @@ void blinken::drawStatusText(QPainter &p)
 				}
 			break;
 		
-			case blinkenGame::waiting1:
+			case BlinkenGame::Waiting1:
 				if (m_overCentralText)
 				{
 					text = restartText;
@@ -762,7 +763,7 @@ void blinken::drawStatusText(QPainter &p)
 				}
 			break;
 			
-			case blinkenGame::learningTheSequence:
+			case BlinkenGame::LearningTheSequence:
 				if (m_overCentralText)
 				{
 					text = restartText;
@@ -773,7 +774,7 @@ void blinken::drawStatusText(QPainter &p)
 				}
 			break;
 			
-			case blinkenGame::typingTheSequence:
+			case BlinkenGame::TypingTheSequence:
 				if (m_overCentralText)
 				{
 					text = restartText;
@@ -787,7 +788,7 @@ void blinken::drawStatusText(QPainter &p)
 	}
 	
 	QFont f;
-	if (blinkenSettings::customFont() && !m_alwaysUseNonCoolFont) f = QFont(QStringLiteral("Steve"));
+	if (BlinkenSettings::customFont() && !m_alwaysUseNonCoolFont) f = QFont(QStringLiteral("Steve"));
 	p.setFont(f);
 	f.setPointSize(KFontUtils::adaptFontSize(p, text, 380, 30, 28, 1, KFontUtils::DoNotAllowWordWrap));
 	p.setFont(f);
@@ -1014,12 +1015,12 @@ void blinken::updateButtonHighlighting(const QPoint &p)
 	
 	switch (m_game.phase())
 	{
-		case blinkenGame::starting:
-		case blinkenGame::waiting3:
-		case blinkenGame::waiting2:
-		case blinkenGame::waiting1:
-		case blinkenGame::learningTheSequence:
-		case blinkenGame::typingTheSequence:
+		case BlinkenGame::Starting:
+		case BlinkenGame::Waiting3:
+		case BlinkenGame::Waiting2:
+		case BlinkenGame::Waiting1:
+		case BlinkenGame::LearningTheSequence:
+		case BlinkenGame::TypingTheSequence:
 			if (m_centralTextRect.contains(p))
 			{
 				if (!m_overCentralText)
@@ -1035,7 +1036,7 @@ void blinken::updateButtonHighlighting(const QPoint &p)
 			}
 		break;
 		
-		case blinkenGame::choosingLevel:
+		case BlinkenGame::ChoosingLevel:
 			for (int i = 0; i < 3; i++)
 			{
 				if (m_levelsRect[i].contains(p))
diff --git a/src/blinken.h b/src/blinken.h
index 4067274..005bfe6 100644
--- a/src/blinken.h
+++ b/src/blinken.h
@@ -37,10 +37,10 @@ Q_OBJECT
 		
 	private Q_SLOTS:
 		void checkHS();
-		void highlight(blinkenGame::color c, bool unhighlight);
+		void highlight(BlinkenGame::Color c, bool unhighlight);
 		void unhighlight();
 		
-		void pressedColor(blinkenGame::color c);
+		void pressedColor(BlinkenGame::Color c);
 
 	private:
 		void startGamePressed();
@@ -81,12 +81,12 @@ Q_OBJECT
 		// use always the non-cool font?
 		bool m_alwaysUseNonCoolFont;
 		
-		blinkenGame::color m_highlighted;
+		BlinkenGame::Color m_highlighted;
 		QTimer *m_unhighlighter;
 		
 		QString m_lastName;
 		
-		blinkenGame m_game;
+		BlinkenGame m_game;
 		
 		KHelpMenu *m_helpMenu;
 		
diff --git a/src/blinken.kcfg b/src/blinken.kcfg
index 362b9c5..c98c43e 100644
--- a/src/blinken.kcfg
+++ b/src/blinken.kcfg
@@ -3,15 +3,15 @@
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
       http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
-	<kcfgfile name="blinkenrc"/>
-	<group name="general">
-		<entry name="playSounds" type="Bool">
+        <kcfgfile name="blinkenrc"/>
+        <group name="general">
+                <entry name="playSounds" type="Bool">
                         <label>Play sounds</label>
-			<default>true</default>
+                        <default>true</default>
                 </entry>
-		<entry name="customFont" type="Bool">
+                <entry name="customFont" type="Bool">
                         <label>Use custom font for status text</label>
-			<default>true</default>
+                        <default>true</default>
                 </entry>
         </group>
 </kcfg>
diff --git a/src/blinkengame.cpp b/src/blinkengame.cpp
index c3f8200..a07b8d8 100644
--- a/src/blinkengame.cpp
+++ b/src/blinkengame.cpp
@@ -11,42 +11,42 @@
 
 #include "soundsplayer.h"
 
-blinkenGame::blinkenGame() : m_phase(starting)
+BlinkenGame::BlinkenGame() : m_phase(Starting)
 {
 	m_soundsPlayer = new soundsPlayer;
 	m_waitTimer = new QTimer(this);
-	connect(m_waitTimer, &QTimer::timeout, this, &blinkenGame::waiting);
+	connect(m_waitTimer, &QTimer::timeout, this, &BlinkenGame::waiting);
 }
 
-blinkenGame::~blinkenGame()
+BlinkenGame::~BlinkenGame()
 {
 	delete m_soundsPlayer;
 }
 
-int blinkenGame::level() const
+int BlinkenGame::level() const
 {
 	return m_level;
 }
 
-bool blinkenGame::canType() const
+bool BlinkenGame::canType() const
 {
-	return m_phase == typingTheSequence || m_phase == starting;
+	return m_phase == TypingTheSequence || m_phase == Starting;
 }
 
-blinkenGame::gamePhase blinkenGame::phase() const
+BlinkenGame::GamePhase BlinkenGame::phase() const
 {
 	return m_phase;
 }
 
-int blinkenGame::score() const
+int BlinkenGame::score() const
 {
-	if (m_phase == starting || m_phase == choosingLevel) return 0;
+	if (m_phase == Starting || m_phase == ChoosingLevel) return 0;
 	return m_sequenceLength - 1;
 }
 
-void blinkenGame::clicked(color c)
+void BlinkenGame::clicked(Color c)
 {
-	if (m_phase == starting)
+	if (m_phase == Starting)
 	{
 		m_soundsPlayer -> play(c);
 		return;
@@ -64,21 +64,21 @@ void blinkenGame::clicked(color c)
 	}
 	else
 	{
-		m_soundsPlayer -> play(all);
-		Q_EMIT highlight(all, true);
+		m_soundsPlayer -> play(All);
+		Q_EMIT highlight(All, true);
 		Q_EMIT gameEnded();
-		setPhase(choosingLevel);
+		setPhase(ChoosingLevel);
 	}
 }
 
-void blinkenGame::setPhase(gamePhase p)
+void BlinkenGame::setPhase(GamePhase p)
 {
-	if (p != waiting3 && p != waiting2 && p != waiting1) m_waitTimer -> stop();
+	if (p != Waiting3 && p != Waiting2 && p != Waiting1) m_waitTimer -> stop();
 	m_phase = p;
 	Q_EMIT phaseChanged();
 }
 
-void blinkenGame::start(int level)
+void BlinkenGame::start(int level)
 {
 	m_level = level;
 	m_sequenceLength = 1;
@@ -88,11 +88,11 @@ void blinkenGame::start(int level)
 	m_sequence.clear();
 }
 
-void blinkenGame::nextSound()
+void BlinkenGame::nextSound()
 {
 	if (m_nextColor != m_sequence.constEnd())
 	{
-		color c;
+		Color c;
 		c = *m_nextColor;
 		++m_nextColor;
 		m_soundsPlayer -> play(c);
@@ -100,29 +100,29 @@ void blinkenGame::nextSound()
 	}
 	else
 	{
-		setPhase(typingTheSequence);
+		setPhase(TypingTheSequence);
 		m_nextColor = m_sequence.constBegin();
-		Q_EMIT highlight(none, false);
+		Q_EMIT highlight(None, false);
 		m_soundsPlayer->disconnect();
 	}
 }
 
-void blinkenGame::soundEnded()
+void BlinkenGame::soundEnded()
 {
-	QTimer::singleShot(100, this, &blinkenGame::nextSound);
-	QTimer::singleShot(50, this, &blinkenGame::unhighlight);
+	QTimer::singleShot(100, this, &BlinkenGame::nextSound);
+	QTimer::singleShot(50, this, &BlinkenGame::unhighlight);
 }
 
-void blinkenGame::unhighlight()
+void BlinkenGame::unhighlight()
 {
-	Q_EMIT highlight(none, false);
+	Q_EMIT highlight(None, false);
 }
 
-void blinkenGame::waiting()
+void BlinkenGame::waiting()
 {
-	if (m_phase == waiting1)
+	if (m_phase == Waiting1)
 	{
-		setPhase(blinkenGame::learningTheSequence);
+		setPhase(BlinkenGame::LearningTheSequence);
 		if (m_level == 3) 
 		{
 			m_sequence.clear();
@@ -130,43 +130,43 @@ void blinkenGame::waiting()
 		}
 		else m_sequence.append(generateColor());
 	
-		connect(m_soundsPlayer, &soundsPlayer::ended, this, &blinkenGame::soundEnded);
+		connect(m_soundsPlayer, &soundsPlayer::ended, this, &BlinkenGame::soundEnded);
 		m_nextColor = m_sequence.constBegin();
 		soundEnded();
 	}
-	else if (m_phase == waiting3) setPhase(waiting2);
-	else /* m_phase == waiting2 */ setPhase(waiting1);
+	else if (m_phase == Waiting3) setPhase(Waiting2);
+	else /* m_phase == waiting2 */ setPhase(Waiting1);
 }
 
-void blinkenGame::nextRound()
+void BlinkenGame::nextRound()
 {
-	if (m_level == 1) setPhase(waiting3);
-	else setPhase(waiting2);
+	if (m_level == 1) setPhase(Waiting3);
+	else setPhase(Waiting2);
 	m_waitTimer -> start(1000);
 }
 
-blinkenGame::color blinkenGame::generateColor()
+BlinkenGame::Color BlinkenGame::generateColor()
 {
 	// make the compiler happy :-D
-	color c = none;
+	Color c = None;
 
 	const int r = QRandomGenerator::global()->bounded(1, 5); // rand [1, 5)
 	switch(r)
 	{
 		case 1:
-			c = red;
+			c = Red;
 		break;
 		
 		case 2:
-			c = green;
+			c = Green;
 		break;
 		
 		case 3:
-			c = blue;
+			c = Blue;
 		break;
 		
 		case 4:
-			c = yellow;
+			c = Yellow;
 		break;
 	}
 	return c;
diff --git a/src/blinkengame.h b/src/blinkengame.h
index 9ae2d67..e197b3a 100644
--- a/src/blinkengame.h
+++ b/src/blinkengame.h
@@ -10,41 +10,59 @@
 #include <QObject>
 #include <QList>
 
+#ifdef QML_VERSION
+#include <QQmlEngine>
+#endif
+
+#include <QtQml/qqmlregistration.h>
+
 class QTimer;
 
 class soundsPlayer;
 
-class blinkenGame : public QObject
+class BlinkenGame : public QObject
 {
 Q_OBJECT
+QML_ELEMENT
+QML_SINGLETON
 	public:
-		blinkenGame();
-		~blinkenGame() override;
-		
-		enum gamePhase { starting, choosingLevel, waiting3, waiting2, waiting1, learningTheSequence, typingTheSequence };
-		enum color
+		BlinkenGame();
+		~BlinkenGame() override;
+
+		enum GamePhase { 
+			Starting, 
+			ChoosingLevel, 
+			Waiting3, 
+			Waiting2, 
+			Waiting1, 
+			LearningTheSequence, 
+			TypingTheSequence };
+		Q_ENUM(GamePhase)
+
+		enum Color
 		{
-			none = 0,
-			red = 1,
-			green = 2,
-			blue = 4,
-			yellow = 8,
-			all = 15};
-		
-		int level() const;
-		bool canType() const;
-		gamePhase phase() const;
-		int score() const;
-		
-		void clicked(color c);
-		void setPhase(gamePhase p);
-		void start(int level);
-	
-	Q_SIGNALS:
-		void gameEnded();
-		void phaseChanged();
-		void highlight(blinkenGame::color c, bool unhighlight);
-		
+			None = 0,
+			Red = 1,
+			Green = 2,
+			Blue = 4,
+			Yellow = 8,
+			All = 15};
+		Q_ENUM(Color)
+		Q_PROPERTY(GamePhase phase READ phase WRITE setPhase NOTIFY phaseChanged)
+
+		Q_INVOKABLE int level() const;
+		Q_INVOKABLE bool canType() const;
+		Q_INVOKABLE GamePhase phase() const;
+		Q_INVOKABLE int score() const;
+		Q_INVOKABLE void clicked(Color c);
+		Q_INVOKABLE void setPhase(GamePhase p);
+		Q_INVOKABLE void start(int level);
+
+		Q_SIGNALS:
+			void gameEnded();
+			void phaseChanged();
+			void highlight(BlinkenGame::Color c, bool unhighlight);
+
 	private Q_SLOTS:
 		void nextSound();
 		void soundEnded();
@@ -53,17 +71,17 @@ Q_OBJECT
 		
 	private:
 		void nextRound();
-		color generateColor();
-	
-		gamePhase m_phase;
+		Color generateColor();
+
+		GamePhase m_phase;
 		int m_level;
 		int m_sequenceLength;
 		
 		QTimer *m_waitTimer;
 		
 		soundsPlayer *m_soundsPlayer;
-		QList<color> m_sequence;
-		QList<color>::const_iterator m_nextColor;
+		QList<Color> m_sequence;
+		QList<Color>::const_iterator m_nextColor;
 };
 
 #endif
diff --git a/src/button.cpp b/src/button.cpp
index 99412a4..b8f697b 100644
--- a/src/button.cpp
+++ b/src/button.cpp
@@ -12,26 +12,26 @@
 
 #include <QKeySequence>
 
-button::button(blinkenGame::color c) : m_selected(false), m_color(c)
+button::button(BlinkenGame::Color c) : m_selected(false), m_color(c)
 {
 	KConfigGroup kc(KSharedConfig::openConfig(), QStringLiteral("General"));
 	QString cs = getColorString();
 	
 	switch (c)
 	{
-		case blinkenGame::blue:
+		case BlinkenGame::Blue:
 			m_key = kc.readEntry(cs, int(Qt::Key_3));
 		break;
 		
-		case blinkenGame::yellow:
+		case BlinkenGame::Yellow:
 			m_key = kc.readEntry(cs, int(Qt::Key_1));
 		break;
 		
-		case blinkenGame::red:
+		case BlinkenGame::Red:
 			m_key =kc.readEntry(cs, int(Qt::Key_2));
 		break;
 		
-		case blinkenGame::green:
+		case BlinkenGame::Green:
 			m_key = kc.readEntry(cs, int(Qt::Key_4));
 		break;
 		
@@ -79,16 +79,16 @@ QString button::getColorString() const
 {
 	switch (m_color)
 	{
-		case blinkenGame::blue:
+		case BlinkenGame::Blue:
 			return QStringLiteral("blue");
 		
-		case blinkenGame::yellow:
+		case BlinkenGame::Yellow:
 			return QStringLiteral("yellow");
 		
-		case blinkenGame::red:
+		case BlinkenGame::Red:
 			return QStringLiteral("red");
 		
-		case blinkenGame::green:
+		case BlinkenGame::Green:
 			return QStringLiteral("green");
 		
 		default:
diff --git a/src/button.h b/src/button.h
index 6de5854..cda1f1d 100644
--- a/src/button.h
+++ b/src/button.h
@@ -12,7 +12,7 @@
 class button
 {
 	public:
-		explicit button(blinkenGame::color c);
+		explicit button(BlinkenGame::Color c);
 		~button();
 	
 		void setShortcut(int key);
@@ -26,7 +26,7 @@ class button
 		
 		bool m_selected;
 		int m_key;
-		blinkenGame::color m_color;
+		BlinkenGame::Color m_color;
 };
 
 #endif
diff --git a/src/highScoreManager.cpp b/src/highScoreManager.cpp
new file mode 100644
index 0000000..72985c9
--- /dev/null
+++ b/src/highScoreManager.cpp
@@ -0,0 +1,103 @@
+/*
+    SPDX-FileCopyrightText: 2005-2006 Albert Astals Cid <aacid at kde.org>
+
+    SPDX-License-Identifier: GPL-2.0-or-later
+*/
+
+#include "highScoreManager.h"
+
+#include <KConfig>
+#include <KSharedConfig>
+
+#include "settings.h"
+
+static QSet<HighScoreManager *> s_allHSM;
+
+/* HighScoreManager */
+
+HighScoreManager::HighScoreManager()
+{
+	s_allHSM << this;
+	update();
+}
+
+HighScoreManager::~HighScoreManager()
+{
+	s_allHSM.remove(this);
+}
+
+bool HighScoreManager::scoreGoodEnough(int level, int score)
+{
+	level--;
+	QList< QPair<int, QString> >::iterator it, itEnd;
+	it = m_scores[level].begin();
+	itEnd = m_scores[level].end();
+	while (it != itEnd && (*it).first >= score) ++it;
+	
+	return (it != itEnd);
+}
+
+void HighScoreManager::addScore(int level, int score, const QString &name)
+{
+	level--;
+	QList< QPair<int, QString> >::iterator it, itEnd;
+	it = m_scores[level].begin();
+	itEnd = m_scores[level].end();
+	while (it != itEnd && (*it).first >= score) ++it;
+	
+	if (it != itEnd)
+	{
+		m_scores[level].insert(it, qMakePair(score, name));
+		m_scores[level].erase(--m_scores[level].end());
+		
+		KConfigGroup cfg(KSharedConfig::openConfig(), QStringLiteral("Level%1").arg(level + 1));
+		int j;
+		for (it = m_scores[level].begin(), j = 1; it != m_scores[level].end(); ++it, j++)
+		{
+			cfg.writeEntry(QStringLiteral("Score%1").arg(j), (*it).first);
+			cfg.writeEntry(QStringLiteral("Name%1").arg(j), (*it).second);
+		}
+		cfg.sync();
+
+		for (HighScoreManager *hsm : std::as_const(s_allHSM))
+		{
+			if (hsm != this)
+			{
+				hsm->update();
+			}
+		}
+	}
+}
+
+void HighScoreManager::update()
+{
+	for (int i = 0; i < 3; ++i)
+	{
+		m_scores[i].clear();
+	}
+	for (int i = 1; i <= 3; i++)
+	{
+		KConfigGroup cfg(KSharedConfig::openConfig(), QStringLiteral("Level%1").arg(i));
+		for (int j = 1; j <= 5; j++)
+		{
+			m_scores[i-1].append(qMakePair(cfg.readEntry(QStringLiteral("Score%1").arg(j),QVariant(0)).toInt(),cfg.readEntry(QStringLiteral("Name%1").arg(j),QString())));
+		}
+	}
+}
+
+QList< QPair<int, QString> > HighScoreManager::scores(int level) const
+{
+	return m_scores[level];
+}
+
+int HighScoreManager::score(int level, int position) const
+{
+	return m_scores[level][position].first;
+}
+
+QString HighScoreManager::name(int level, int position) const
+{
+	return m_scores[level][position].second;
+}
+
+#include "moc_highScoreManager.cpp"
diff --git a/src/highScoreManager.h b/src/highScoreManager.h
new file mode 100644
index 0000000..3afa3e8
--- /dev/null
+++ b/src/highScoreManager.h
@@ -0,0 +1,38 @@
+/*
+    SPDX-FileCopyrightText: 2005-2006 Albert Astals Cid <aacid at kde.org>
+
+    SPDX-License-Identifier: GPL-2.0-or-later
+*/
+
+#ifndef HIGHSCOREMANAGER_H
+#define HIGHSCOREMANAGER_H
+
+#include <QObject>
+
+#include <QPair>
+#include <QList>
+#include <QtQml/qqmlregistration.h>
+
+class HighScoreManager : public QObject
+{
+Q_OBJECT
+QML_ELEMENT
+QML_SINGLETON
+	public:
+		HighScoreManager();
+		~HighScoreManager() override;
+
+		QList< QPair<int, QString> > scores(int level) const;
+
+		Q_INVOKABLE bool scoreGoodEnough(int level, int score);
+		Q_INVOKABLE void addScore(int level, int score, const QString &name);
+		Q_INVOKABLE int score(int level, int position) const;
+		Q_INVOKABLE QString name(int level, int position) const;
+
+	private:
+		void update();
+
+		QList< QPair<int, QString> > m_scores[3];
+};
+
+#endif
diff --git a/src/highscoredialog.cpp b/src/highscoredialog.cpp
index 6e2615a..74f9df9 100644
--- a/src/highscoredialog.cpp
+++ b/src/highscoredialog.cpp
@@ -20,13 +20,12 @@
 
 #include "counter.h"
 #include "settings.h"
+#include "highScoreManager.h"
 
 static const int margin = 15;
 static const int smallMargin = 5;
 static const int namesFontSize = 25;
 
-static QSet<highScoreManager *> s_allHSM;
-
 /* scoresWidget */
 
 class scoresWidget : public QWidget
@@ -64,7 +63,7 @@ void scoresWidget::paintEvent(QPaintEvent *)
 	
 	p.setPen(Qt::black);
 	
-	if (blinkenSettings::customFont()) f = QFont(QStringLiteral("Steve"));
+	if (BlinkenSettings::customFont()) f = QFont(QStringLiteral("Steve"));
 	p.setFont(f);
 	f.setPointSize(KFontUtils::adaptFontSize(p, QStringLiteral("A"), 1000, namesFontSize, 28, 1, KFontUtils::DoNotAllowWordWrap));
 	p.setFont(f);
@@ -93,7 +92,7 @@ QSize scoresWidget::calcSize()
 	QPainter p(&dummyPixmap);
 	QFont f;
 	
-	if (blinkenSettings::customFont()) f = QFont(QStringLiteral("Steve"));
+	if (BlinkenSettings::customFont()) f = QFont(QStringLiteral("Steve"));
 	p.setFont(f);
 	f.setPointSize(KFontUtils::adaptFontSize(p, QStringLiteral("A"), 1000, namesFontSize, 28, 1, KFontUtils::DoNotAllowWordWrap));
 	p.setFont(f);
@@ -144,7 +143,7 @@ highScoreDialog::highScoreDialog(QWidget *parent, QSvgRenderer *renderer) : QDia
 	connect(buttonBox, &QDialogButtonBox::rejected, this, &highScoreDialog::close);
 	layout()->addWidget(buttonBox);
 
-	highScoreManager hsm;
+	HighScoreManager hsm;
 	
 	m_tw -> addTab(new scoresWidget(nullptr, hsm.scores(0), renderer), i18nc("@title:group High scores Level 1 tab title", "Level 1"));
 	m_tw -> addTab(new scoresWidget(nullptr, hsm.scores(1), renderer), i18nc("@title:group High scores Level 2 tab title", "Level 2"));
@@ -166,91 +165,4 @@ void highScoreDialog::showLevel(int level)
 	exec();
 }
 
-/* highScoreManager */
-
-highScoreManager::highScoreManager()
-{
-	s_allHSM << this;
-	update();
-}
-
-highScoreManager::~highScoreManager()
-{
-	s_allHSM.remove(this);
-}
-
-bool highScoreManager::scoreGoodEnough(int level, int score)
-{
-	level--;
-	QList< QPair<int, QString> >::iterator it, itEnd;
-	it = m_scores[level].begin();
-	itEnd = m_scores[level].end();
-	while (it != itEnd && (*it).first >= score) ++it;
-	
-	return (it != itEnd);
-}
-
-void highScoreManager::addScore(int level, int score, const QString &name)
-{
-	level--;
-	QList< QPair<int, QString> >::iterator it, itEnd;
-	it = m_scores[level].begin();
-	itEnd = m_scores[level].end();
-	while (it != itEnd && (*it).first >= score) ++it;
-	
-	if (it != itEnd)
-	{
-		m_scores[level].insert(it, qMakePair(score, name));
-		m_scores[level].erase(--m_scores[level].end());
-		
-		KConfigGroup cfg(KSharedConfig::openConfig(), QStringLiteral("Level%1").arg(level + 1));
-		int j;
-		for (it = m_scores[level].begin(), j = 1; it != m_scores[level].end(); ++it, j++)
-		{
-			cfg.writeEntry(QStringLiteral("Score%1").arg(j), (*it).first);
-			cfg.writeEntry(QStringLiteral("Name%1").arg(j), (*it).second);
-		}
-		cfg.sync();
-
-		for (highScoreManager *hsm : std::as_const(s_allHSM))
-		{
-			if (hsm != this)
-			{
-				hsm->update();
-			}
-		}
-	}
-}
-
-void highScoreManager::update()
-{
-	for (int i = 0; i < 3; ++i)
-	{
-		m_scores[i].clear();
-	}
-	for (int i = 1; i <= 3; i++)
-	{
-		KConfigGroup cfg(KSharedConfig::openConfig(), QStringLiteral("Level%1").arg(i));
-		for (int j = 1; j <= 5; j++)
-		{
-			m_scores[i-1].append(qMakePair(cfg.readEntry(QStringLiteral("Score%1").arg(j),QVariant(0)).toInt(),cfg.readEntry(QStringLiteral("Name%1").arg(j),QString())));
-		}
-	}
-}
-
-QList< QPair<int, QString> > highScoreManager::scores(int level) const
-{
-	return m_scores[level];
-}
-
-int highScoreManager::score(int level, int position) const
-{
-	return m_scores[level][position].first;
-}
-
-QString highScoreManager::name(int level, int position) const
-{
-	return m_scores[level][position].second;
-}
-
 #include "moc_highscoredialog.cpp"
diff --git a/src/highscoredialog.h b/src/highscoredialog.h
index 5144924..469ba22 100644
--- a/src/highscoredialog.h
+++ b/src/highscoredialog.h
@@ -12,6 +12,7 @@
 #include <QPair>
 #include <QList>
 
+
 class QSvgRenderer;
 
 class myTabWidget;
@@ -26,25 +27,4 @@ class highScoreDialog : private QDialog
 		myTabWidget *m_tw;
 };
 
-class highScoreManager : public QObject
-{
-Q_OBJECT
-	public:
-		highScoreManager();
-		~highScoreManager() override;
-
-		bool scoreGoodEnough(int level, int score);
-		void addScore(int level, int score, const QString &name);
-
-		QList< QPair<int, QString> > scores(int level) const;
-
-		Q_INVOKABLE int score(int level, int position) const;
-		Q_INVOKABLE QString name(int level, int position) const;
-
-	private:
-		void update();
-
-		QList< QPair<int, QString> > m_scores[3];
-};
-
 #endif
diff --git a/src/main.cpp b/src/main.cpp
index 227bcad..1cef259 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -4,34 +4,64 @@
     SPDX-License-Identifier: GPL-2.0-or-later
 */
 
-#include "blinken.h"
-
 #include "blinken_version.h"
 
 #include <KAboutData>
 #include <KLocalizedString>
-#include <KCrash>
-#include <KDBusService>
+
+#include "blinkengame.h"
+#include "highScoreManager.h"
+#include "settings.h"
+
+#ifdef QML_VERSION
+
+#include <QGuiApplication>
+#include <QQmlApplicationEngine>
+#include <QQmlContext>
+#include "maskedmousearea.h"
+
+#else
 
 #include <QApplication>
 #include <QCommandLineParser>
-
 #include <QFontDatabase>
 #include <QFontInfo>
 #include <QStandardPaths>
 
+#include <KCrash>
+#include <KDBusService>
+
+#include "blinken.h"
+
+#endif
+
+Q_DECL_EXPORT
 int main(int argc, char *argv[])
 {
+
+#ifdef QML_VERSION
+	QGuiApplication app{argc, argv};
+#else
+	QApplication app{argc, argv};
+#endif
+
 	KLocalizedString::setApplicationDomain(QByteArrayLiteral("blinken"));
 
-	QApplication app(argc, argv);
 	KAboutData about(QStringLiteral("blinken"), i18n("Blinken"), QStringLiteral(BLINKEN_VERSION_STRING), i18n("A memory enhancement game"), KAboutLicense::GPL, i18n("© 2005-2007 Albert Astals Cid\nSPDX-FileCopyrightText: 2005-2007 Danny Allen "));
 	about.addAuthor(i18n("Albert Astals Cid"), i18n("Coding"), QStringLiteral("aacid at kde.org"));
 	about.addAuthor(i18n("Danny Allen"), i18n("Design, Graphics and Sounds"), QStringLiteral("danny at dannyallen.co.uk"));
 	about.addCredit(i18n("Steve Jordi"), i18n("GPL'ed his 'Steve' font so that we could use it"), QStringLiteral("steve at sjordi.com"));
-
 	KAboutData::setApplicationData(about);
 
+#ifdef QML_VERSION
+	QQmlApplicationEngine engine;
+
+	QQmlContext *context = engine.rootContext();
+	context->setContextObject(new KLocalizedContext{&engine});
+
+	engine.loadFromModule("org.kde.blinken", "Blinken");
+
+#else
 	KCrash::initialize();
 
 	QCommandLineParser parser;
@@ -41,7 +71,7 @@ int main(int argc, char *argv[])
 
 	app.setWindowIcon(QIcon::fromTheme(QStringLiteral("blinken")));
 
- 	QFont f(QStringLiteral("Steve"), 12, QFont::Normal, true);
+	QFont f(QStringLiteral("Steve"), 12, QFont::Normal, true);
 	// Works with Steve may need some tweaking to work with other fonts
 	if (!QFontInfo(f).exactMatch())
 	{
@@ -49,5 +79,7 @@ int main(int argc, char *argv[])
 	}
 	KDBusService service;
 	new blinken();
+#endif
+	
 	return app.exec();
 }
diff --git a/src/maskedmousearea.cpp b/src/maskedmousearea.cpp
new file mode 100644
index 0000000..225a692
--- /dev/null
+++ b/src/maskedmousearea.cpp
@@ -0,0 +1,143 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+**   * Redistributions of source code must retain the above copyright
+**     notice, this list of conditions and the following disclaimer.
+**   * Redistributions in binary form must reproduce the above copyright
+**     notice, this list of conditions and the following disclaimer in
+**     the documentation and/or other materials provided with the
+**     distribution.
+**   * Neither the name of The Qt Company Ltd nor the names of its
+**     contributors may be used to endorse or promote products derived
+**     from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "maskedmousearea.h"
+
+#include <QGuiApplication>
+#include <QStyleHints>
+#include <qqmlfile.h>
+
+
+MaskedMouseArea::MaskedMouseArea(QQuickItem *parent)
+    : QQuickItem(parent), m_pressed(false), m_alphaThreshold(0.0),
+      m_containsMouse(false) {
+  setAcceptHoverEvents(true);
+  setAcceptedMouseButtons(Qt::LeftButton);
+}
+
+void MaskedMouseArea::setPressed(bool pressed) {
+  if (m_pressed != pressed) {
+    m_pressed = pressed;
+    Q_EMIT pressedChanged();
+  }
+}
+
+void MaskedMouseArea::setContainsMouse(bool containsMouse) {
+  if (m_containsMouse != containsMouse) {
+    m_containsMouse = containsMouse;
+    Q_EMIT containsMouseChanged();
+  }
+}
+
+void MaskedMouseArea::setMaskSource(const QUrl &source) {
+  if (m_maskSource != source) {
+    m_maskSource = source;
+    m_maskImage = QImage(QQmlFile::urlToLocalFileOrQrc(source));
+    Q_EMIT maskSourceChanged();
+  }
+}
+
+void MaskedMouseArea::setAlphaThreshold(qreal threshold) {
+  if (m_alphaThreshold != threshold) {
+    m_alphaThreshold = threshold;
+    Q_EMIT alphaThresholdChanged();
+  }
+}
+
+bool MaskedMouseArea::contains(const QPointF &point) const {
+  if (!QQuickItem::contains(point) || m_maskImage.isNull())
+    return false;
+  
+  QPoint p = point.toPoint();
+
+  //get the scaled image
+  QImage transImage=m_maskImage.scaled(QSize(this->width(),this->height()),Qt::IgnoreAspectRatio,Qt::FastTransformation);
+    if (p.x() < 0 || p.x() >= transImage.width() || p.y() < 0 ||
+      p.y() >= transImage.height())
+    return false;
+
+  qreal r = qBound<int>(0, m_alphaThreshold * 255, 255);
+ 
+  return qAlpha(transImage.pixel(p)) > r;
+}
+
+void MaskedMouseArea::mousePressEvent(QMouseEvent *event) {
+  setPressed(true);
+  m_pressPoint = event->position().toPoint();
+  Q_EMIT pressed();
+}
+
+void MaskedMouseArea::mouseReleaseEvent(QMouseEvent *event) {
+  setPressed(false);
+  Q_EMIT released();
+
+  const int threshold = qApp->styleHints()->startDragDistance();
+  const bool isClick =
+      (threshold >= qAbs(event->position().toPoint().x() - m_pressPoint.x()) &&
+       threshold >= qAbs(event->position().toPoint().y() - m_pressPoint.y()));
+
+  if (isClick)
+    Q_EMIT clicked();
+}
+
+void MaskedMouseArea::mouseUngrabEvent() {
+  setPressed(false);
+  Q_EMIT canceled();
+}
+
+void MaskedMouseArea::hoverEnterEvent(QHoverEvent *event) {
+  Q_UNUSED(event);
+  setContainsMouse(true);
+}
+
+void MaskedMouseArea::hoverLeaveEvent(QHoverEvent *event) {
+  Q_UNUSED(event);
+  setContainsMouse(false);
+}
diff --git a/src/maskedmousearea.h b/src/maskedmousearea.h
new file mode 100644
index 0000000..400a532
--- /dev/null
+++ b/src/maskedmousearea.h
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+**   * Redistributions of source code must retain the above copyright
+**     notice, this list of conditions and the following disclaimer.
+**   * Redistributions in binary form must reproduce the above copyright
+**     notice, this list of conditions and the following disclaimer in
+**     the documentation and/or other materials provided with the
+**     distribution.
+**   * Neither the name of The Qt Company Ltd nor the names of its
+**     contributors may be used to endorse or promote products derived
+**     from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MASKEDMOUSEAREA_H
+#define MASKEDMOUSEAREA_H
+
+#include <QImage>
+#include <QQuickItem>
+
+class MaskedMouseArea : public QQuickItem {
+Q_OBJECT
+QML_ELEMENT
+  Q_PROPERTY(bool pressed READ isPressed NOTIFY pressedChanged)
+  Q_PROPERTY(bool containsMouse READ containsMouse NOTIFY containsMouseChanged)
+  Q_PROPERTY(QUrl maskSource READ maskSource WRITE setMaskSource NOTIFY
+                 maskSourceChanged)
+  Q_PROPERTY(qreal alphaThreshold READ alphaThreshold WRITE setAlphaThreshold
+                 NOTIFY alphaThresholdChanged)
+
+public:
+  MaskedMouseArea(QQuickItem *parent = nullptr);
+
+  bool contains(const QPointF &point) const override;
+
+  bool isPressed() const { return m_pressed; }
+  bool containsMouse() const { return m_containsMouse; }
+
+  QUrl maskSource() const { return m_maskSource; }
+  void setMaskSource(const QUrl &source);
+
+  qreal alphaThreshold() const { return m_alphaThreshold; }
+  void setAlphaThreshold(qreal threshold);
+
+Q_SIGNALS:
+  void pressed();
+  void released();
+  void clicked();
+  void canceled();
+  void pressedChanged();
+  void maskSourceChanged();
+  void containsMouseChanged();
+  void alphaThresholdChanged();
+
+protected:
+  void setPressed(bool pressed);
+  void setContainsMouse(bool containsMouse);
+  void mousePressEvent(QMouseEvent *event) override;
+  void mouseReleaseEvent(QMouseEvent *event) override;
+  void hoverEnterEvent(QHoverEvent *event) override;
+  void hoverLeaveEvent(QHoverEvent *event) override;
+  void mouseUngrabEvent() override;
+
+private:
+  bool m_pressed;
+  QUrl m_maskSource;
+  QImage m_maskImage;
+  QPointF m_pressPoint;
+  qreal m_alphaThreshold;
+  bool m_containsMouse;
+};
+
+#endif
diff --git a/src/settings.kcfgc b/src/settings.kcfgc
index 2bd3849..f102e2d 100644
--- a/src/settings.kcfgc
+++ b/src/settings.kcfgc
@@ -1,4 +1,6 @@
 File=blinken.kcfg
-ClassName=blinkenSettings
+ClassName=BlinkenSettings
 Singleton=true
 Mutators=true
+GenerateProperties=true
+QmlRegistration=true
diff --git a/src/soundsplayer.cpp b/src/soundsplayer.cpp
index 5cd487c..9915581 100644
--- a/src/soundsplayer.cpp
+++ b/src/soundsplayer.cpp
@@ -10,51 +10,123 @@
 
 #include <QStandardPaths>
 
+#ifdef QML_VERSION
+//for QML version
+soundsPlayer::soundsPlayer()
+{
+	addSoundsFile();
+	m_soundsPlayer.setAudioOutput(new QAudioOutput);
+	connect(&m_soundsPlayer, &QMediaPlayer::playingChanged,this,&soundsPlayer::soundEffectPlayEnded);
+
+	connect(&m_warnTimer, &QTimer::timeout, this, &soundsPlayer::ended);
+	m_warnTimer.setSingleShot(true);
+}
+#else
 soundsPlayer::soundsPlayer()
     : m_audioOutput(Phonon::GameCategory)
 {
+	addSoundsFile();
 	m_audioOutput.setVolume( 0.8f );
 	Phonon::createPath(&m_mediaObject, &m_audioOutput);
 	connect(&m_mediaObject, &Phonon::MediaObject::finished, this, &soundsPlayer::playEnded);
 
+	connect(&m_warnTimer, &QTimer::timeout, this, &soundsPlayer::ended);
+	m_warnTimer.setSingleShot(true);
+}
+#endif
+
+
+
+void soundsPlayer::addSoundsFile()
+{
+#if defined(Q_OS_ANDROID) || defined(QML_VERSION)
+	m_allSound=QStringLiteral("qrc:lose.wav");
+	m_greenSound=QStringLiteral("qrc:1.wav");
+	m_redSound=QStringLiteral("qrc:2.wav");
+	m_blueSound=QStringLiteral("qrc:3.wav");
+	m_yellowSound=QStringLiteral("qrc:4.wav");
+#else
 	m_allSound = QStandardPaths::locate(QStandardPaths::AppLocalDataLocation, QStringLiteral("sounds/lose.wav"));
 	m_greenSound = QStandardPaths::locate(QStandardPaths::AppLocalDataLocation, QStringLiteral("sounds/1.wav"));
 	m_redSound = QStandardPaths::locate(QStandardPaths::AppLocalDataLocation, QStringLiteral("sounds/2.wav"));
 	m_blueSound = QStandardPaths::locate(QStandardPaths::AppLocalDataLocation, QStringLiteral("sounds/3.wav"));
 	m_yellowSound = QStandardPaths::locate(QStandardPaths::AppLocalDataLocation, QStringLiteral("sounds/4.wav"));
-
-	connect(&m_warnTimer, &QTimer::timeout, this, &soundsPlayer::ended);
-	m_warnTimer.setSingleShot(true);
+#endif
 }
 
 soundsPlayer::~soundsPlayer()
 {
 }
 
-void soundsPlayer::play(blinkenGame::color c)
+void soundsPlayer::play(BlinkenGame::Color c)
 {
-	if (blinkenSettings::playSounds())
+#ifdef QML_VERSION
+	//QML version
+	if(m_soundsPlayer.isPlaying())return;
+	if(BlinkenSettings::playSounds())
 	{
 		QString soundFile;
 		switch (c)
 		{
-			case blinkenGame::red:
+			case BlinkenGame::Red:
+				soundFile = m_redSound;
+			break;
+
+			case BlinkenGame::Green:
+				soundFile = m_greenSound;
+			break;
+
+			case BlinkenGame::Blue:
+				soundFile = m_blueSound;
+			break;
+
+			case BlinkenGame::Yellow:
+				soundFile = m_yellowSound;
+			break;
+
+			case BlinkenGame::All:
+				soundFile = m_allSound;
+			break;
+
+			default:
+			break;
+		}
+
+		if (!soundFile.isEmpty())
+		{
+			m_soundsPlayer.setSource(QUrl(soundFile));
+			m_soundsPlayer.setLoops(1);
+			m_soundsPlayer.play();
+		}else{
+			
+			qDebug()<<"can't find sound file "<<soundFile;
+		}
+	}else{
+		m_warnTimer.start(250);
+	}
+#else
+	if (BlinkenSettings::playSounds())
+	{
+		QString soundFile;
+		switch (c)
+		{
+			case BlinkenGame::Red:
 				soundFile = m_redSound;
 			break;
 			
-			case blinkenGame::green:
+			case BlinkenGame::Green:
 				soundFile = m_greenSound;
 			break;
 			
-			case blinkenGame::blue:
+			case BlinkenGame::Blue:
 				soundFile = m_blueSound;
 			break;
 			
-			case blinkenGame::yellow:
+			case BlinkenGame::Yellow:
 				soundFile = m_yellowSound;
 			break;
 			
-			case blinkenGame::all:
+			case BlinkenGame::All:
 				soundFile = m_allSound;
 			break;
 			
@@ -71,14 +143,28 @@ void soundsPlayer::play(blinkenGame::color c)
 	{
 		m_warnTimer.start(250);
 	}
+#endif
 }
 
+#ifdef QML_VERSION
+
+void soundsPlayer::soundEffectPlayEnded()
+{
+	if(!m_soundsPlayer.isPlaying())
+	{
+		m_warnTimer.start(250);
+	}
+}
+
+#else
 void soundsPlayer::playEnded()
 {
-	if (blinkenSettings::playSounds())
+	if (BlinkenSettings::playSounds())
 	{
 		m_warnTimer.start(250);
 	}
 }
+#endif
+
 
 #include "moc_soundsplayer.cpp"
diff --git a/src/soundsplayer.h b/src/soundsplayer.h
index b3e26a6..ddadfbf 100644
--- a/src/soundsplayer.h
+++ b/src/soundsplayer.h
@@ -7,8 +7,15 @@
 #ifndef SOUNDSPLAYER_H
 #define SOUNDSPLAYER_H
 
+#include <QtSystemDetection>
+
+#ifdef QML_VERSION
+#include <QMediaPlayer>
+#include <QAudioOutput>
+#else
 #include <phonon/MediaObject>
 #include <phonon/audiooutput.h>
+#endif
 
 #include <QTimer>
 
@@ -21,19 +28,28 @@ Q_OBJECT
 		soundsPlayer();
 		~soundsPlayer() override;
 		
-		void play(blinkenGame::color c);
+		void play(BlinkenGame::Color c);
 		
 	Q_SIGNALS:
 		void ended();
 		
 	private Q_SLOTS:
+
+#ifdef QML_VERSION
+		void soundEffectPlayEnded();
+#else
 		void playEnded();
-		
+#endif
 	private:
+		void addSoundsFile();
 		QString m_greenSound, m_redSound, m_blueSound, m_yellowSound, m_allSound;
+
+#ifdef QML_VERSION
+		QMediaPlayer m_soundsPlayer;
+#else
 		Phonon::MediaObject m_mediaObject;
 		Phonon::AudioOutput m_audioOutput;
-		
+#endif
 		QTimer m_warnTimer;
 };
 
diff --git a/src/ui/Blinken.qml b/src/ui/Blinken.qml
new file mode 100644
index 0000000..0a12b1f
--- /dev/null
+++ b/src/ui/Blinken.qml
@@ -0,0 +1,323 @@
+/*
+    SPDX-FileCopyrightText: 2024 Hanyang Zhang <hanyangzhang at qq.com>
+
+    SPDX-License-Identifier: GPL-2.0-or-later
+*/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+import org.kde.kirigami as Kirigami
+import org.kde.kirigamiaddons.formcard as FormCard
+import org.kde.blinken
+
+Kirigami.AbstractApplicationWindow {
+    id: blinken
+    title: i18n("Blinken")
+    color: "black"
+    readonly property int blinkenBackgroundWidth: 814
+    readonly property int blinkenBackgroundHeight: 696
+    Rectangle {
+        id: rootRectangle
+        height: parent.height<parent.width*(3/4)?parent.height:parent.width*(3/4)
+        width: parent.height<parent.width*(3/4)?height * (4 / 3):parent.width
+        anchors.centerIn: parent
+
+        Image {
+            id: background
+            anchors.fill: parent
+            source: "qrc:ui/background.svg"
+            fillMode: Image.Stretch
+
+            GameButtons {
+                id: gameButtons
+                anchors.fill: parent
+            }
+        }
+
+        ExitButton {
+            id: exitButton
+            width: rootRectangle.width * (80 / blinken.blinkenBackgroundWidth)
+            height: width
+            anchors.right: parent.right
+            anchors.top: parent.top
+            scale: rootRectangle.scale
+            anchors.rightMargin: rootRectangle.width * (8 / blinken.blinkenBackgroundWidth)
+            anchors.topMargin: rootRectangle.height * (8 / blinken.blinkenBackgroundHeight)
+        }
+
+        BlinkenMenu {
+            id: blinkenMenu
+            width: rootRectangle.width * (230 / blinken.blinkenBackgroundWidth)
+            height: width
+            anchors.right: parent.right
+            anchors.bottom: parent.bottom
+            anchors.bottomMargin: rootRectangle.height * (8 / blinken.blinkenBackgroundHeight)
+            anchors.rightMargin: rootRectangle.width * (8 / blinken.blinkenBackgroundWidth)
+        }
+
+        HighScoreButton {
+            id: highScoreButton
+            width: rootRectangle.width * (80 / blinken.blinkenBackgroundWidth)
+            height: width
+            anchors.left: parent.left
+            anchors.top: parent.top
+            scale: rootRectangle.scale
+            anchors.leftMargin: rootRectangle.width * (8 / blinken.blinkenBackgroundWidth)
+            anchors.topMargin: rootRectangle.height * (8 / blinken.blinkenBackgroundHeight)
+            mouseArea.onPressed: highScoreButtonImage.source = "qrc:ui/highScore_highlight.svg"
+            mouseArea.onReleased: {
+                highScoreButtonImage.source = "qrc:ui/highScore.svg";
+                highScoreLists.openLists();
+            }
+        }
+        HighScoreLists {
+            id: highScoreLists
+            highScoreListsPopup.anchors.centerIn: Overlay.overlay
+            highScoreListsPopup.width: rootRectangle.width * 0.5
+            highScoreListsPopup.height: rootRectangle.height * 0.8
+        }
+        FontLoader {
+            id: steveFontloader
+            source: "qrc:steve.ttf"
+        }
+        Text {
+            id: statusText
+            width: rootRectangle.width * (500/ blinken.blinkenBackgroundWidth)
+            height: rootRectangle.height * (160  / blinken.blinkenBackgroundHeight)
+            color: "#0062f7" //To look more like the original
+            font.family: BlinkenSettings.customFont ? steveFontloader.name : ""
+            text: i18n("Press Start to begin")
+            anchors.left: parent.left
+            anchors.bottom: parent.bottom
+            anchors.bottomMargin: rootRectangle.height * (0 / blinken.blinkenBackgroundHeight)
+            anchors.leftMargin: rootRectangle.width * (30 / blinken.blinkenBackgroundWidth)
+
+            font.pixelSize: 40
+            fontSizeMode: Text.HorizontalFit
+            horizontalAlignment: Text.AlignLeft
+            verticalAlignment: Text.AlignBottom
+            wrapMode:Text.WrapAnywhere
+            transform: Rotation { origin.x: -3; origin.y: -3; angle: -3.3}
+        }
+        ScoreAndCounter {
+            id: scoreAndCounter
+            width: rootRectangle.width * (150 / blinken.blinkenBackgroundWidth)
+            height: rootRectangle.height * (85 / blinken.blinkenBackgroundHeight)
+            anchors.top: parent.top
+            anchors.topMargin: parent.height * 0.17
+            anchors.horizontalCenter: parent.horizontalCenter
+            MouseArea {
+                anchors.fill: parent
+                onClicked: highScoreLists.openLists()
+            }
+        }
+
+        GameOptions {
+            id: gameOptions
+            anchors.horizontalCenter: rootRectangle.horizontalCenter
+            anchors.bottom: parent.bottom
+            anchors.bottomMargin: parent.height * 0.43
+            startButton.width: rootRectangle.width * (95 / blinken.blinkenBackgroundWidth)
+            startButton.height: rootRectangle.height * (65 / blinken.blinkenBackgroundHeight)
+
+            optionsList.width: rootRectangle.width * (250 / blinken.blinkenBackgroundWidth)
+            optionsList.height: rootRectangle.height * (90 / blinken.blinkenBackgroundHeight)
+            optionsList.spacing: rootRectangle.width * (45 / blinken.blinkenBackgroundWidth)
+        }
+    }
+
+    property string playerName: ""
+    property int lastGameScore: -1
+    Dialog {
+        id: nameDialog
+        modal: true
+        closePolicy: Popup.NoAutoClose
+        anchors.centerIn: parent
+        title: i18n("Enter Your Name")
+        standardButtons: Dialog.Ok
+        RowLayout {
+            Label {
+                text: i18nc("@label:textbox refers to the user's name", "Name:")
+            }
+            TextInput {
+                id: nameInput
+                focus: true
+                font.bold: true
+                text: blinken.playerName
+                //old Blinken doesn't have the limit, but whenever the name is too long, it can't be displayed very well
+                maximumLength: 20
+            }
+        }
+        onAccepted: {
+            let name = nameInput.text;
+            blinken.playerName = nameInput.text;
+            if (name != "" && lastGameScore > 0)
+                HighScoreManager.addScore(BlinkenGame.level(), lastGameScore, name);
+            lastGameScore = -1;
+        }
+    }
+
+    //about Blinken Page
+    Popup {
+        id: aboutBlinkenPage
+        anchors.centerIn: parent
+        height: rootRectangle.height * 0.9
+        width: rootRectangle.width * 0.7
+        FormCard.AboutPage {
+            anchors.fill: parent
+        }
+    }
+    //about KDE Page
+    Popup {
+        id: aboutKDEPage
+        anchors.centerIn: parent
+        height: rootRectangle.height * 0.9
+        width: rootRectangle.width * 0.7
+        FormCard.AboutKDE {
+            anchors.fill: parent
+        }
+    }
+    // Settting
+    Popup {
+        id: settingsPage
+        anchors.centerIn: parent
+        height: rootRectangle.height * (170 / blinken.blinkenBackgroundHeight)
+        width: rootRectangle.width * (450 / blinken.blinkenBackgroundWidth)
+        Column {
+            Switch {
+                text: i18n("Sounds")
+                checked: BlinkenSettings.playSounds
+                onToggled: {
+                    BlinkenSettings.playSounds = !BlinkenSettings.playSounds;
+                    BlinkenSettings.save();
+                }
+            }
+            Switch {
+                text: i18n("Use custom font for status text")
+                checked: BlinkenSettings.customFont
+                onToggled: {
+                    var aux = i18nc("If the Steve font that is used by Blinken by default to show status messages does not support any of the characters of your language, please translate that message to 1 and KDE standard font will be used to show the texts, if not translate it to 0", "0");
+                    if (BlinkenSettings.customFont) {
+                        statusText.font.family = "";
+                    } else {
+                        if (aux == "0")
+                            statusText.font.family = steveFontloader.name;
+                    }
+                    BlinkenSettings.customFont = !BlinkenSettings.customFont;
+                    BlinkenSettings.save();
+                }
+            }
+        }
+    }
+    Connections {
+        target: blinkenMenu
+        function onOpenAboutBlinkenPage() {
+            aboutBlinkenPage.open();
+        }
+        function onOpenAboutKDEPage() {
+            aboutKDEPage.open();
+        }
+        function onOpenSettingsPage() {
+            settingsPage.open();
+        }
+        function onOpenHandBookPage() {
+            Qt.openUrlExternally("help:/");
+        }
+    }
+
+    Connections {
+        target: BlinkenGame
+        function onGameEnded() {
+            let score = BlinkenGame.score();
+            let level = BlinkenGame.level();
+            if (HighScoreManager.scoreGoodEnough(level, score)) {
+                lastGameScore = score;
+                nameDialog.open();
+            }
+        }
+        function onPhaseChanged() {
+            switch (BlinkenGame.phase) {
+            case (BlinkenGame.Starting):
+                {
+                    statusText.text = i18n("Press Start to begin");
+                    scoreAndCounter.setScore(0);
+                    scoreAndCounter.counter.state = "zero";
+                    break;
+                }
+            case (BlinkenGame.ChoosingLevel):
+                {
+                    statusText.text = i18n("Set the Difficulty Level...");
+                    scoreAndCounter.setScore(0);
+                    scoreAndCounter.counter.state = "zero";
+                    gameOptions.blinkenState.state = "selectLevelState";
+                    break;
+                }
+            case (BlinkenGame.Waiting3):
+                {
+                    statusText.text = i18n("Next sequence in 3...");
+                    scoreAndCounter.setScore(BlinkenGame.score());
+                    scoreAndCounter.counter.state = "three";
+                    break;
+                }
+            case (BlinkenGame.Waiting2):
+                {
+                    if (BlinkenGame.level() === 1) {
+                        statusText.text = i18n("Next sequence in 3, 2...");
+                    } else {
+                        statusText.text = i18n("Next sequence in 2...");
+                    }
+                    scoreAndCounter.setScore(BlinkenGame.score());
+                    scoreAndCounter.counter.state = "two";
+                    break;
+                }
+            case (BlinkenGame.Waiting1):
+                {
+                    if (BlinkenGame.level() === 1) {
+                        statusText.text = i18n("Next sequence in 3, 2, 1...");
+                    } else {
+                        statusText.text = i18n("Next sequence in 2, 1...");
+                    }
+                    scoreAndCounter.counter.state = "one";
+                    break;
+                }
+            case (BlinkenGame.LearningTheSequence):
+                {
+                    statusText.text = i18n("Remember this sequence...");
+                    scoreAndCounter.counter.state = "zero";
+                    break;
+                }
+            case (BlinkenGame.TypingTheSequence):
+                {
+                    statusText.text = i18n("Repeat the sequence");
+                    break;
+                }
+            default:
+                {
+                    // never happens
+                    break;
+                }
+            }
+        }
+        function onHighlight(aimColor, unhighlight) {
+            gameButtons.highLight(aimColor);
+            if (aimColor == 15)
+                timer.setTimeout(function () {
+                    gameButtons.highLight(0);
+                }, 250);
+        }
+    }
+    Timer {
+        id: timer
+        function setTimeout(cb, delayTime) {
+            timer.interval = delayTime;
+            timer.repeat = false;
+            timer.triggered.connect(cb);
+            timer.triggered.connect(function release() {
+                timer.triggered.disconnect(cb);
+                timer.triggered.disconnect(release);
+            });
+            timer.start();
+        }
+    }
+}
diff --git a/src/ui/BlinkenMenu.qml b/src/ui/BlinkenMenu.qml
new file mode 100644
index 0000000..8e46348
--- /dev/null
+++ b/src/ui/BlinkenMenu.qml
@@ -0,0 +1,131 @@
+/*
+    SPDX-FileCopyrightText: 2024 Hanyang Zhang <hanyangzhang at qq.com>
+
+    SPDX-License-Identifier: GPL-2.0-or-later
+*/
+
+import QtQuick
+
+Item {
+    id: blinkenMenu
+    width: 150 //default
+    height: width
+    signal openAboutBlinkenPage
+    signal openAboutKDEPage
+    signal openSettingsPage
+    signal openHandBookPage
+
+    Image {
+        id: menuImage
+        anchors.fill: parent
+        source: "qrc:ui/menu.svg"
+        scale: blinkenMenu.scale
+        fillMode: Image.Stretch
+    }
+
+    MouseArea {
+        id: questionMouseArea
+
+        width: blinkenMenu.width * (60 / 150)
+        height: questionMouseArea.width
+
+        anchors.right: parent.right
+        anchors.bottom: parent.bottom
+        scale: blinkenMenu.scale
+        anchors.bottomMargin: 0
+        anchors.rightMargin: 0
+
+        onClicked: {
+            if (menuState.state == "fold") {
+                menuState.state = "unfold";
+            } else {
+                menuState.state = "fold";
+            }
+        }
+    }
+
+    MouseArea {
+        id: aboutKDE
+        width: blinkenMenu.width * 0.3
+        height: blinkenMenu.height * 0.3
+        anchors.left: parent.left
+        anchors.bottom: parent.bottom
+        anchors.bottomMargin: 0
+        anchors.leftMargin: 0
+        onClicked: {
+            blinkenMenu.openAboutKDEPage();
+        }
+    }
+
+    MouseArea {
+        id: aboutBlinken
+
+        width: blinkenMenu.width * 0.3
+        height: blinkenMenu.height * 0.3
+
+        anchors.bottom: parent.bottom
+        anchors.bottomMargin: 0
+        anchors.left: parent.left
+        anchors.leftMargin: aboutKDE.width
+        onClicked: {
+            blinkenMenu.openAboutBlinkenPage();
+        }
+    }
+
+    MouseArea {
+        id: settings
+
+        width: blinkenMenu.width * 0.3
+        height: blinkenMenu.height * 0.3
+
+        anchors.right: parent.right
+        anchors.rightMargin: 0
+        anchors.bottom: parent.bottom
+        anchors.bottomMargin: questionMouseArea.height
+        onClicked: {
+            blinkenMenu.openSettingsPage();
+        }
+    }
+
+    MouseArea {
+        id: handBook
+
+        width: blinkenMenu.width * 0.3
+        height: blinkenMenu.height * 0.3
+
+        anchors.right: parent.right
+        anchors.top: parent.top
+        anchors.rightMargin: 0
+        anchors.topMargin: 0
+        onClicked: {
+            blinkenMenu.openHandBookPage();
+        }
+    }
+
+    StateGroup {
+        id: menuState
+        state: "fold"
+        states: [
+            State {
+                name: "fold"
+                PropertyChanges {
+                    menuImage.source: "qrc:ui/menu.svg"
+                    aboutKDE.enabled: false
+                    aboutBlinken.enabled: false
+                    settings.enabled: false
+                    handBook.enabled: false
+                }
+            },
+            State {
+                name: "unfold"
+                PropertyChanges {
+                    menuImage.source: "qrc:ui/menu_list.svg"
+                    aboutKDE.enabled: true
+                    aboutBlinken.enabled: true
+                    settings.enabled: true
+                    handBook.enabled: true
+                }
+            }
+        ]
+    }
+}
diff --git a/src/ui/ExitButton.qml b/src/ui/ExitButton.qml
new file mode 100644
index 0000000..7c9e200
--- /dev/null
+++ b/src/ui/ExitButton.qml
@@ -0,0 +1,37 @@
+/*
+    SPDX-FileCopyrightText: 2024 Hanyang Zhang <hanyangzhang at qq.com>
+
+    SPDX-License-Identifier: GPL-2.0-or-later
+*/
+
+import QtQuick
+
+Item {
+    height: 768 //default size
+    width: height
+
+    Rectangle {
+        id: rectangle
+        color: "#00ffffff"
+        border.color: "#00000000"
+        anchors.fill: parent
+
+        Image {
+            id: image
+            anchors.fill: parent
+            source: "qrc:ui/exit.svg"
+            fillMode: Image.Stretch
+        }
+
+        MouseArea {
+            id: mouseArea
+            anchors.fill: parent
+            onPressed: {
+                image.source = "qrc:ui/exit_highlight.svg";
+            }
+            onReleased: {
+                Qt.quit();
+            }
+        }
+    }
+}
diff --git a/src/ui/GameButton.qml b/src/ui/GameButton.qml
new file mode 100644
index 0000000..6c9e2be
--- /dev/null
+++ b/src/ui/GameButton.qml
@@ -0,0 +1,43 @@
+/*
+    SPDX-FileCopyrightText: 2024 Hanyang Zhang <hanyangzhang at qq.com>
+
+    SPDX-License-Identifier: GPL-2.0-or-later
+*/
+
+import QtQuick
+import org.kde.blinken
+
+Item {
+    id: gameButton
+    required property string normalImageSource
+    required property string highLightImageSource
+    required property int gameColor
+    default property bool isHighLight: false
+
+    Image {
+        id: image
+        anchors.fill: parent
+        scale: gameButton.scale
+        source: gameButton.isHighLight ? gameButton.highLightImageSource : gameButton.normalImageSource
+        fillMode: Image.Stretch
+
+        MaskedMouseArea {
+            id: mouseArea
+            anchors.fill: parent
+            alphaThreshold: 0.5
+            maskSource: image.source
+            scale: image.scale
+            onPressedChanged: {
+                if (mouseArea.released) {
+                    gameButton.isHighLight = false;
+                }
+                if (!BlinkenGame.canType())
+                    return;
+                if (mouseArea.pressed) {
+                    gameButton.isHighLight = true;
+                    BlinkenGame.clicked(gameColor);
+                }
+            }
+        }
+    }
+}
diff --git a/src/ui/GameButtons.qml b/src/ui/GameButtons.qml
new file mode 100644
index 0000000..4b8ca28
--- /dev/null
+++ b/src/ui/GameButtons.qml
@@ -0,0 +1,118 @@
+/*
+    SPDX-FileCopyrightText: 2024 Hanyang Zhang <hanyangzhang at qq.com>
+
+    SPDX-License-Identifier: GPL-2.0-or-later
+*/
+
+import QtQuick
+import org.kde.blinken
+
+Item {
+    id: gameButtons
+
+    GameButton {
+        id: redButton
+        width: yellowButton.width
+        height: yellowButton.height
+        anchors.right: parent.right
+        anchors.top: parent.top
+        anchors.topMargin: yellowButton.anchors.topMargin
+        anchors.rightMargin: gameButtons.width * 0.02929
+        scale: gameButtons.scale
+
+        normalImageSource: "qrc:color/red.svg"
+        highLightImageSource: "qrc:color/red_highlight.svg"
+        gameColor: BlinkenGame.Red
+    }
+
+    GameButton {
+        id: yellowButton
+        width: gameButtons.width * 0.4609
+        height: gameButtons.height * 0.3593
+        anchors.left: parent.left
+        anchors.top: parent.top
+        anchors.leftMargin: gameButtons.width * 0.0332
+        anchors.topMargin: gameButtons.height * 0.0338
+        scale: gameButtons.scale
+
+        normalImageSource: "qrc:color/yellow.svg"
+        highLightImageSource: "qrc:color/yellow_highlight.svg"
+        gameColor: BlinkenGame.Yellow
+    }
+
+    GameButton {
+        id: blueButton
+        width: yellowButton.width
+        height: yellowButton.height
+        anchors.left: parent.left
+        anchors.bottom: parent.bottom
+        anchors.bottomMargin: gameButtons.height * 0.2291
+        anchors.leftMargin: yellowButton.anchors.leftMargin
+        scale: gameButtons.scale
+
+        normalImageSource: "qrc:color/blue.svg"
+        highLightImageSource: "qrc:color/blue_highlight.svg"
+        gameColor: BlinkenGame.Blue
+    }
+
+    GameButton {
+        id: greenButton
+        width: yellowButton.width
+        height: yellowButton.height
+        anchors.right: parent.right
+        anchors.bottom: parent.bottom
+        anchors.rightMargin: redButton.anchors.rightMargin
+        anchors.bottomMargin: blueButton.anchors.bottomMargin
+        scale: gameButtons.scale
+
+        normalImageSource: "qrc:color/green.svg"
+        highLightImageSource: "qrc:color/green_highlight.svg"
+        gameColor: BlinkenGame.Green
+    }
+
+    function highLight(aimColor) {
+        switch (aimColor) {
+        case (BlinkenGame.None):
+            {
+                redButton.isHighLight = false;
+                greenButton.isHighLight = false;
+                blueButton.isHighLight = false;
+                yellowButton.isHighLight = false;
+                break;
+            }
+        case (BlinkenGame.Red):
+            {
+                redButton.isHighLight = true;
+                break;
+            }
+        case (BlinkenGame.Green):
+            {
+                greenButton.isHighLight = true;
+                break;
+            }
+        case (BlinkenGame.Blue):
+            {
+                blueButton.isHighLight = true;
+                break;
+            }
+        case (BlinkenGame.Yellow):
+            {
+                yellowButton.isHighLight = "true";
+                break;
+            }
+        case (BlinkenGame.All):
+            {
+                redButton.isHighLight = true;
+                greenButton.isHighLight = true;
+                blueButton.isHighLight = true;
+                yellowButton.isHighLight = true;
+                break;
+            }
+        default:
+            {
+                // never happens
+                break;
+            }
+        }
+    }
+}
diff --git a/src/ui/GameOptions.qml b/src/ui/GameOptions.qml
new file mode 100644
index 0000000..93482b9
--- /dev/null
+++ b/src/ui/GameOptions.qml
@@ -0,0 +1,218 @@
+/*
+    SPDX-FileCopyrightText: 2024 Hanyang Zhang <hanyangzhang at qq.com>
+
+    SPDX-License-Identifier: GPL-2.0-or-later
+*/
+
+import QtQuick
+import org.kde.blinken
+
+Item {
+    id: gameOptions
+    property alias startButton: startButton
+    property alias optionsList: optionsList
+    property alias blinkenState: blinkenState
+
+    Rectangle {
+        id: startButton
+        color: "#282828"
+        border.color: "black"
+        anchors.horizontalCenter: parent.horizontalCenter
+        anchors.verticalCenter: parent.verticalCenter
+
+        border.width: 5
+        radius: 15
+
+        Text {
+            id: text1
+            color: "#ffffff"
+            text: i18nc("@action:button Start a new game", "Start")
+            anchors.fill: parent
+            font.pixelSize: 22
+            horizontalAlignment: Text.AlignHCenter
+            verticalAlignment: Text.AlignVCenter
+        }
+
+        MouseArea {
+            id: startMouseArea
+            anchors.fill: parent
+            onClicked: {
+                if (blinkenState.state === "default") {
+                    blinkenState.state = "selectLevelState";
+                }
+                BlinkenGame.setPhase(BlinkenGame.ChoosingLevel);
+            }
+        }
+    }
+
+    Row {
+        id: optionsList
+        anchors.horizontalCenter: parent.horizontalCenter
+        anchors.verticalCenter: parent.verticalCenter
+
+        visible: false
+
+        Rectangle {
+            id: plane
+            color: "#282828"
+            border.color: "black"
+
+            width: optionsList.width * (43 / 220)
+            height: optionsList.height * (48 / 70)
+            radius: 8
+            border.width: 4
+
+            Text {
+                id: text2
+                color: "#ffffff"
+                text: i18n("1")
+                anchors.fill: parent
+                font.pixelSize: 32
+                horizontalAlignment: Text.AlignHCenter
+                verticalAlignment: Text.AlignVCenter
+            }
+
+            MouseArea {
+                id: level1MouseArea
+                anchors.fill: parent
+                onClicked: {
+                    if (blinkenState.state === "selectLevelState") {
+                        BlinkenGame.start(1);
+                        blinkenState.state = "gameStart";
+                    }
+                }
+            }
+        }
+
+        Rectangle {
+            id: plane1
+            color: "#282828"
+            border.color: "black"
+
+            width: plane.width
+            height: plane.height
+            radius: plane.radius
+            border.width: plane.border.width
+
+            Text {
+                id: text3
+                color: "#ffffff"
+                text: i18n("2")
+                anchors.fill: parent
+                font.pixelSize: 32
+                horizontalAlignment: Text.AlignHCenter
+                verticalAlignment: Text.AlignVCenter
+            }
+
+            MouseArea {
+                id: level2MouseArea
+                anchors.fill: parent
+                onClicked: {
+                    if (blinkenState.state === "selectLevelState") {
+                        BlinkenGame.start(2);
+                        blinkenState.state = "gameStart";
+                    }
+                }
+            }
+        }
+
+        Rectangle {
+            id: plane2
+            color: "#282828"
+            border.color: "black"
+
+            width: plane.width
+            height: plane.height
+            radius: plane.radius
+            border.width: plane.border.width
+
+            Text {
+                id: text4
+                color: "#ffffff"
+                text: i18n("?")
+                anchors.fill: parent
+                font.pixelSize: 32
+                horizontalAlignment: Text.AlignHCenter
+                verticalAlignment: Text.AlignVCenter
+            }
+
+            MouseArea {
+                id: level3MouseArea
+                anchors.fill: parent
+                onClicked: {
+                    if (blinkenState.state === "selectLevelState") {
+                        BlinkenGame.start(3);
+                        blinkenState.state = "gameStart";
+                    }
+                }
+            }
+        }
+    }
+
+    Rectangle {
+        id: restartButton
+        color: "#282828"
+        border.color: "black"
+
+        x: startButton.x
+        y: startButton.y
+        width: startButton.width
+        height: startButton.height
+        visible: false
+        radius: startButton.radius
+        border.width: startButton.border.width
+
+        Text {
+            id: text5
+            anchors.fill: parent
+            color: "#ffffff"
+            text: i18n("Restart")
+            font.pixelSize: 15
+            horizontalAlignment: Text.AlignHCenter
+            verticalAlignment: Text.AlignVCenter
+        }
+
+        MouseArea {
+            id: mouseArea
+            anchors.fill: parent
+
+            onClicked: {
+                if (blinkenState.state === "gameStart") {
+                    BlinkenGame.setPhase(BlinkenGame.Starting);
+                    blinkenState.state = "selectLevelState";
+                }
+            }
+        }
+    }
+
+    StateGroup {
+        id: blinkenState
+        state: "default"
+        states: [
+            State {
+                name: "default"
+                PropertyChanges {
+                    startButton.visible: true
+                    optionsList.visible: false
+                    restartButton.visible: false
+                }
+            },
+            State {
+                name: "selectLevelState"
+                PropertyChanges {
+                    startButton.visible: false
+                    optionsList.visible: true
+                    restartButton.visible: false
+                }
+            },
+            State {
+                name: "gameStart"
+                PropertyChanges {
+                    startButton.visible: false
+                    restartButton.visible: true
+                    optionsList.visible: false
+                }
+            }
+        ]
+    }
+}
diff --git a/src/ui/HighScoreButton.qml b/src/ui/HighScoreButton.qml
new file mode 100644
index 0000000..743aec3
--- /dev/null
+++ b/src/ui/HighScoreButton.qml
@@ -0,0 +1,35 @@
+/*
+    SPDX-FileCopyrightText: 2024 Hanyang Zhang <hanyangzhang at qq.com>
+
+    SPDX-License-Identifier: GPL-2.0-or-later
+*/
+
+import QtQuick
+
+Item {
+    id: highScoreButton
+    property alias mouseArea: mouseArea
+    property alias highScoreButtonImage: image
+
+    Rectangle {
+        id: rectangle
+        color: "#00ffffff"
+        border.color: "#00000000"
+        anchors.fill: parent
+        scale: highScoreButton.scale
+
+        Image {
+            id: image
+            anchors.fill: parent
+            source: "qrc:ui/highScore.svg"
+            scale: highScoreButton.scale
+            fillMode: Image.PreserveAspectFit
+        }
+
+        MouseArea {
+            id: mouseArea
+            anchors.fill: parent
+            scale: highScoreButton.scale
+        }
+    }
+}
diff --git a/src/ui/HighScoreLists.qml b/src/ui/HighScoreLists.qml
new file mode 100644
index 0000000..c0d06a0
--- /dev/null
+++ b/src/ui/HighScoreLists.qml
@@ -0,0 +1,95 @@
+/*
+    SPDX-FileCopyrightText: 2024 Hanyang Zhang <hanyangzhang at qq.com>
+
+    SPDX-License-Identifier: GPL-2.0-or-later
+*/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+
+Item {
+    id: highScoreLists
+    property alias highScoreListsPopup: highScoreListsPopup
+
+    function openLists() {
+        highScoreListsPopup.open();
+        level1List.levelListModel.clear();
+        level2List.levelListModel.clear();
+        level3List.levelListModel.clear();
+        for (let i = 0; i < 5; i++) {
+            let scoreItem = HighScoreManager.score(0, i);
+            let nameItem = HighScoreManager.name(0, i);
+            if (scoreItem == 0)
+                break;
+            level1List.levelListModel.set(i, {
+                score: scoreItem,
+                name: nameItem
+            });
+        }
+        for (let i = 0; i < 5; i++) {
+            let scoreItem = HighScoreManager.score(1, i);
+            let nameItem = HighScoreManager.name(1, i);
+            if (scoreItem == 0)
+                break;
+            level2List.levelListModel.set(i, {
+                score: scoreItem,
+                name: nameItem
+            });
+        }
+        for (let i = 0; i < 5; i++) {
+            let scoreItem = HighScoreManager.score(2, i);
+            let nameItem = HighScoreManager.name(2, i);
+            if (scoreItem == 0)
+                break;
+            level3List.levelListModel.set(i, {
+                score: scoreItem,
+                name: nameItem
+            });
+        }
+    }
+    Popup {
+        id: highScoreListsPopup
+
+        closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
+        padding: 10
+        modal: true
+
+        contentItem: Page {
+            id: scorePage
+            header: TabBar {
+                id: bar
+                width: highScoreListsPopup.contentItem.width
+
+                TabButton {
+                    text: i18nc("@title:group High scores Level 1 tab title", "Level 1")
+                    width: (highScoreListsPopup.contentItem.width) / 3
+                }
+                TabButton {
+                    text: i18nc("@title:group High scores Level 2 tab title", "Level 2")
+                    width: (highScoreListsPopup.contentItem.width) / 3
+                }
+                TabButton {
+                    text: i18nc("@title:group High scores Level ? tab tible", "Level ?")
+                    width: (highScoreListsPopup.contentItem.width) / 3
+                }
+            }
+
+            StackLayout {
+                id: stackLayout
+                width: parent.width
+                height: parent.height
+                currentIndex: bar.currentIndex
+                ScoreList {
+                    id: level1List
+                }
+                ScoreList {
+                    id: level2List
+                }
+                ScoreList {
+                    id: level3List
+                }
+            }
+        }
+    }
+}
diff --git a/src/ui/Numbers.qml b/src/ui/Numbers.qml
new file mode 100644
index 0000000..6ba98bd
--- /dev/null
+++ b/src/ui/Numbers.qml
@@ -0,0 +1,42 @@
+/*
+    SPDX-FileCopyrightText: 2024 Hanyang Zhang <hanyangzhang at qq.com>
+
+    SPDX-License-Identifier: GPL-2.0-or-later
+*/
+import QtQuick
+
+Rectangle {
+    id: numbers
+    color: "transparent"
+    Row {
+        anchors.fill: parent
+        leftPadding: parent.width * 0.09589
+        topPadding: parent.height * 0.14
+        spacing: parent.width * 0.05479
+        scale: parent.scale
+
+        Image {
+            id: number2
+            width: parent.width * 0.4
+            height: parent.height * 0.7
+            source: "qrc:numbers/0.svg"
+            scale: parent.scale
+            fillMode: Image.PreserveAspectFit
+        }
+
+        Image {
+            id: number1
+            width: number2.width
+            height: number2.height
+            source: "qrc:numbers/0.svg"
+            scale: parent.scale
+            fillMode: Image.PreserveAspectFit
+        }
+    }
+    function setNumbers(number: int) {
+        var num1 = number % 10;
+        var num2 = Math.floor(number / 10);
+        number1.source = "qrc:numbers/" + num1 + ".svg";
+        number2.source = "qrc:numbers/" + num2 + ".svg";
+    }
+}
diff --git a/src/ui/ScoreAndCounter.qml b/src/ui/ScoreAndCounter.qml
new file mode 100644
index 0000000..14c4e12
--- /dev/null
+++ b/src/ui/ScoreAndCounter.qml
@@ -0,0 +1,114 @@
+/*
+    SPDX-FileCopyrightText: 2024 Hanyang Zhang <hanyangzhang at qq.com>
+
+    SPDX-License-Identifier: GPL-2.0-or-later
+*/
+import QtQuick
+
+Item {
+    id: scoreAndCounter
+    property alias counter: counter
+
+    Rectangle {
+        id: plane
+        color: "#282828"
+        border.color: "black"
+
+        radius: scoreAndCounter.height * 0.20
+        border.width: scoreAndCounter.height * 0.075
+        anchors.fill: parent
+        scale: scoreAndCounter.scale
+
+        Numbers {
+            id: score
+            width: scoreAndCounter.width * 0.7
+            anchors.left: parent.left
+            anchors.top: parent.top
+            anchors.bottom: parent.bottom
+        }
+
+        Column {
+            id: countDowns
+            width: scoreAndCounter.width * 0.219
+            height: scoreAndCounter.height * 0.8
+
+            anchors.right: parent.right
+            anchors.top: parent.top
+            anchors.rightMargin: scoreAndCounter.width * 0.01
+            anchors.topMargin: scoreAndCounter.height * 0.18
+
+            spacing: scoreAndCounter.height * 0.02
+            scale: scoreAndCounter.scale
+
+            Image {
+                id: countDown3
+                width: scoreAndCounter.width * 0.1
+                height: countDown3.width
+                source: "qrc:numbers/blackBlock.svg"
+                sourceSize.width: scoreAndCounter.width * 0.1369
+                scale: scoreAndCounter.scale
+                fillMode: Image.PreserveAspectFit
+            }
+
+            Image {
+                id: countDown2
+                width: countDown3.width
+                height: countDown3.width
+                source: "qrc:numbers/blackBlock.svg"
+                scale: scoreAndCounter.scale
+                fillMode: Image.PreserveAspectFit
+            }
+
+            Image {
+                id: countDown1
+                width: countDown3.width
+                height: countDown3.width
+                source: "qrc:numbers/blackBlock.svg"
+                scale: scoreAndCounter.scale
+                fillMode: Image.PreserveAspectFit
+            }
+        }
+    }
+    function setScore(scores: int) {
+        score.setNumbers(scores);
+    }
+
+    StateGroup {
+        id: counter
+        state: "zero"
+        states: [
+            State {
+                name: "zero"
+                PropertyChanges {
+                    countDown3.source: "qrc:numbers/blackBlock.svg"
+                    countDown2.source: "qrc:numbers/blackBlock.svg"
+                    countDown1.source: "qrc:numbers/blackBlock.svg"
+                }
+            },
+            State {
+                name: "three"
+                PropertyChanges {
+                    countDown3.source: "qrc:numbers/redBlock.svg"
+                    countDown2.source: "qrc:numbers/redBlock.svg"
+                    countDown1.source: "qrc:numbers/redBlock.svg"
+                }
+            },
+            State {
+                name: "two"
+                PropertyChanges {
+                    countDown3.source: "qrc:/numbers/blackBlock.svg"
+                    countDown2.source: "qrc:/numbers/redBlock.svg"
+                    countDown1.source: "qrc:/numbers/redBlock.svg"
+                }
+            },
+            State {
+                name: "one"
+                PropertyChanges {
+                    countDown3.source: "qrc:numbers/blackBlock.svg"
+                    countDown1.source: "qrc:numbers/redBlock.svg"
+                    countDown2.source: "qrc:numbers/blackBlock.svg"
+                }
+            }
+        ]
+    }
+}
diff --git a/src/ui/ScoreList.qml b/src/ui/ScoreList.qml
new file mode 100644
index 0000000..9dfde30
--- /dev/null
+++ b/src/ui/ScoreList.qml
@@ -0,0 +1,72 @@
+/*
+    SPDX-FileCopyrightText: 2024 Hanyang Zhang <hanyangzhang at qq.com>
+
+    SPDX-License-Identifier: GPL-2.0-or-later
+*/
+pragma ComponentBehavior: Bound
+import QtQuick
+
+Item {
+    property alias levelListModel: levelListModel
+    // List Data
+    ListModel {
+        id: levelListModel
+    }
+
+    ListView {
+        id: listView
+        anchors.fill: parent
+        model: levelListModel
+        spacing: 10
+        orientation: ListView.Vertical
+        snapMode: ListView.SnapToItem
+        clip: true
+        header: Rectangle {
+            // Making the first item away from tab buttons looks better
+            height: listView.spacing
+        }
+        delegate: Rectangle {
+            id: scoreLine
+            required property string name
+            required property string score
+            color: "#00ffffff"
+            width: listView.width
+            height: listView.height * 0.18
+
+            Rectangle {
+                id: numersRect
+                width: scoreLine.width * 0.25
+                height: scoreLine.height
+                color: "#00ffffff"
+                border.color: "#000000"
+                border.width: 2
+                Numbers {
+                    id: scoreNumbers
+                    anchors.fill: numersRect
+                    Component.onCompleted: {
+                        setNumbers(scoreLine.score);
+                    }
+                }
+            }
+            Rectangle {
+                id: nameRect
+                color: "#00ffffff"
+                height: scoreLine.height
+                anchors.left: numersRect.right
+                anchors.right: scoreLine.right
+                anchors.leftMargin: 10
+
+                FontLoader {
+                    id: steveFontloader
+                    source: "qrc:steve.ttf"
+                }
+                Text {
+                    text: scoreLine.name
+                    font.pixelSize: 18
+                    font.family: BlinkenSettings.customFont ? steveFontloader.name : ""
+                    anchors.verticalCenter: nameRect.verticalCenter
+                }
+            }
+        }
+    }
+}


More information about the kde-doc-english mailing list