1+ from PyQt5 .QtWidgets import (
2+ QWidget , QLabel , QPushButton , QVBoxLayout , QHBoxLayout , QApplication , QGraphicsOpacityEffect
3+ )
4+ from PyQt5 .QtGui import QPixmap , QFont , QColor , QPalette
5+ from PyQt5 .QtCore import Qt , QPropertyAnimation , QEasingCurve
6+ import sys
7+
8+
9+ class ZKPTutorial (QWidget ):
10+ def __init__ (self ):
11+ super ().__init__ ()
12+ self .setWindowTitle ("ZKP Animated Tutorial - Scene 1" )
13+ self .setGeometry (300 , 200 , 900 , 650 )
14+ self .setStyleSheet ("background-color: #121212; color: white;" )
15+
16+ self .init_ui ()
17+ self .animate_scene ()
18+
19+ def init_ui (self ):
20+ # Main layout
21+ self .layout = QVBoxLayout ()
22+
23+ # Title
24+ self .title_label = QLabel ("\u2728 Scene 1: Roles in the Network" )
25+ self .title_label .setAlignment (Qt .AlignCenter )
26+ self .title_label .setFont (QFont ("Arial" , 24 , QFont .Bold ))
27+ self .layout .addWidget (self .title_label )
28+
29+ # Image area (placeholder)
30+ self .image_label = QLabel ()
31+ pixmap = QPixmap ("assets/scene1_roles.png" )
32+ if pixmap .isNull ():
33+ self .image_label .setText ("[Visual Story: ATM, Bank, Merchant cartoon goes here]" )
34+ self .image_label .setAlignment (Qt .AlignCenter )
35+ self .image_label .setFont (QFont ("Arial" , 16 , QFont .Bold ))
36+ else :
37+ self .image_label .setPixmap (pixmap .scaled (720 , 360 , Qt .KeepAspectRatio ))
38+ self .image_label .setAlignment (Qt .AlignCenter )
39+ self .layout .addWidget (self .image_label )
40+
41+ # Narration text
42+ self .narration_label = QLabel ()
43+ self .narration_label .setWordWrap (True )
44+ self .narration_label .setFont (QFont ("Georgia" , 16 ))
45+ self .narration_label .setAlignment (Qt .AlignLeft )
46+ self .narration_label .setText (
47+ "<p>Every secure system runs on trust —<br>"
48+ "But not just <i>who</i> you trust — <b>what role</b> they play.</p>"
49+ "<p>Let’s meet the 3 roles in any safe transaction:</p>"
50+ "<ul>"
51+ "<li>\ud83c \udfe7 <b>ATM</b> → <i>Initiator</i> (starts the transaction)</li>"
52+ "<li>\ud83c \udfe6 <b>Bank</b> → <i>Validator</i> (verifies it)</li>"
53+ "<li>\ud83c \udfcd \ufe0f <b>Merchant</b> → <i>Receiver</i> (completes it)</li>"
54+ "</ul>"
55+ )
56+ self .layout .addWidget (self .narration_label )
57+
58+ # Navigation button
59+ self .next_button = QPushButton ("▶ Next" )
60+ self .next_button .setFont (QFont ("Arial" , 13 , QFont .Bold ))
61+ self .next_button .setStyleSheet (
62+ "background-color: #1f1f1f; color: white; padding: 10px; border-radius: 10px;"
63+ )
64+ self .next_button .clicked .connect (self .go_to_next_scene )
65+
66+ # Center the button
67+ button_layout = QHBoxLayout ()
68+ button_layout .addStretch ()
69+ button_layout .addWidget (self .next_button )
70+ button_layout .addStretch ()
71+ self .layout .addLayout (button_layout )
72+
73+ self .setLayout (self .layout )
74+
75+ def animate_scene (self ):
76+ # Fade-in effect for narration
77+ effect = QGraphicsOpacityEffect ()
78+ self .narration_label .setGraphicsEffect (effect )
79+ animation = QPropertyAnimation (effect , b"opacity" )
80+ animation .setDuration (1500 )
81+ animation .setStartValue (0.0 )
82+ animation .setEndValue (1.0 )
83+ animation .setEasingCurve (QEasingCurve .InOutQuad )
84+ animation .start ()
85+ self .fade_animation = animation # Keep reference to avoid garbage collection
86+
87+ def go_to_next_scene (self ):
88+ print ("Next scene triggered (hook this up later)" )
89+
90+
91+ if __name__ == '__main__' :
92+ app = QApplication (sys .argv )
93+ tutorial = ZKPTutorial ()
94+ tutorial .show ()
95+ sys .exit (app .exec_ ())
0 commit comments