Η διαφήμιση πάνω από τις ενδεκάδες, ως πινακίδα σταδίου: 130px ύψος, έξι σειρές LED, τρία σενάρια σε αυτόματη εναλλαγή. Αντικαθιστά το ticker των 38px μόνο σε desktop (≥1200px)· στο mobile δεν αλλάζει τίποτα.
Δύο ομάδες. Οι φιγούρες του σεναρίου 2 ζουν στον φάκελο
concept-assets/ και είναι
placeholder stock — μπαίνουν ως mask-image, άρα από τη φωτογραφία
χρησιμοποιείται μόνο το άλφα (το σχήμα), ποτέ τα χρώματά της.
Τα πορτρέτα αναλυτών + το logo operator είναι τα ίδια αρχεία που ήδη χρησιμοποιεί η
σελίδα ανάλυσης.
keeper-ready.png
keeper-dive.png
run-a.png
run-b.png
shooter-white.png
tipster-2.png
tipster-1.pngΆδειες χρήσης
Οι πέντε φιγούρες είναι royalty-free stock με ανώνυμα μοντέλα, κατεβασμένες για το prototype. Πριν από production πρέπει να αντικατασταθούν με αδειοδοτημένο ή δικό μας υλικό. Επειδή μπαίνουν ως μάσκες, η αντικατάσταση είναι αλλαγή ενός URL — δεν αγγίζει animation ή γεωμετρία, αρκεί το νέο PNG να έχει παρόμοιο aspect και διαφανές φόντο.
Ο ίδιος κώδικας που τρέχει στο prototype — αυτόματη εναλλαγή, ίδια timings. Η πινακίδα αποδίδεται στο πραγματικό της πλάτος (874px): οι θέσεις μπάλας/τερματοφύλακα είναι μετρημένες σε αυτό το πλάτος.
Το demo δεν εμφανίζεται εδώ. Το component είναι desktop-only (≥1200px) και το παράθυρό σου είναι πιο στενό. Άνοιξέ το σε desktop.
Hover πάνω στην πινακίδα = pause. Τα κουμπιά κάνουν replay ενός σεναρίου· η εναλλαγή συνεχίζει κανονικά μετά.
Η πινακίδα είναι ένα container με N σενάρια, όχι N components. Το container ορίζει επιφάνεια, pixel grid, χρώμα χορηγού και το ρολόι της εναλλαγής· κάθε σενάριο είναι ανεξάρτητο «φιλμάκι» που ζει μέσα του.
.adled ticker των 38px, στο ίδιο ακριβώς σημείο: αδελφός του
.xiwrap, μέσα στο .bo .adledwrap, κολλητά πάνω από την ενδεκάδα.
Ποτέ παιδί του .xiwrap — εκείνο είναι flex-direction:row στο desktop
και θα γινόταν τρίτη στήλη ανάμεσα στις δύο ομάδες..ledw-stage είναι display:none και εμφανίζεται το υπάρχον ticker.
Δεν είναι responsive εκδοχή του ίδιου πράγματος — είναι δύο διαφορετικά creatives για δύο
πλάτη. Η πινακίδα σε 390px δεν έχει χώρο να αφηγηθεί τίποτα.Πέντε στρώσεις, με αυτή τη σειρά από κάτω προς τα πάνω. Η σειρά είναι προδιαγραφή, όχι λεπτομέρεια: το pixel grid πρέπει να είναι πάνω από το περιεχόμενο.
| # | Στρώση | Κλάση | Κανόνας |
|---|---|---|---|
| 1 | Επιφάνεια | .ledw |
130px ύψος, border-radius:16px 16px 0 0, γεμίζει με το χρώμα του χορηγού:
linear-gradient(180deg, mix(--bk 88% #000), mix(--bk 55% #000)). Το
--bk έρχεται από τους κανόνες του Odds CTA — καμία νέα παλέτα. |
| 2 | Σενάρια | .ledw-msgs / .ledw-msg |
Όλα στο DOM μαζί, στοιβαγμένα· ορατό ένα κάθε φορά μέσω clip-path. |
| 3 | Λάμψη στο γρασίδι | .ledw-glow |
48px κάτω από την πινακίδα, top:100%, radial από το --bk,
blur 7px, opacity .55. Θέλει z-index:2 στο stage — το
.xiwrap έρχεται μετά στο DOM και αλλιώς ζωγραφίζεται από πάνω. |
| 4 | Pixel grid | .ledw-grid |
Δύο repeating-gradients 4px (κελιά) + ένα 21.6px (αρμοί σειρών = 130÷6). Πάνω από το
περιεχόμενο (z-index:6): τα κενά κόβουν τα γράμματα και τις φιγούρες, και
έτσι διαβάζονται σαν φτιαγμένα από την πινακίδα, όχι τυπωμένα πάνω της. |
| 5 | Ανάκλαση | .ledw-sweep |
Μία διαγώνια λάμψη ανά ~8.5s. Καθαρά ατμόσφαιρα — μπορεί να φύγει χωρίς να χαλάσει τίποτα. |
Προαιρετικά, με class στο stage:
.tilt = rotateX(6deg) με perspective:900px στον γονέα·
.nodots, .noglow = απενεργοποίηση των αντίστοιχων στρώσεων.
.is-lt στο .ledw και
κάθε στρώση με μελάνι γυρίζει σε σκούρο κείμενο — ο ίδιος κανόνας που ισχύει στο Odds CTA.
Το ίδιο και το pixel grid, που από λευκό γίνεται μαύρο.Ένα JS ρολόι, όχι ένα μεγάλο CSS keyframe. Κάθε σενάριο έχει δικό του εσωτερικό timeline που ξαναξεκινά από το καρέ 0 κάθε φορά που έρχεται η σειρά του.
| Βήμα | Τι γίνεται | Γιατί έτσι |
|---|---|---|
| Είσοδος/έξοδος | clip-path transition με steps(14), 0.42s. Το σενάριο που
φεύγει παίρνει .is-out, αυτό που έρχεται .is-on. |
Το stepped timing το κάνει να διαβάζεται σαν ανανέωση πινακίδας κολόνα-κολόνα, όχι σαν slide ιστοσελίδας. Οι δύο κατευθύνσεις εναλλάσσονται. |
| Restart | classList.remove('is-on') → void el.offsetWidth →
classList.add('is-on'). |
Χωρίς το forced reflow ο browser συγχωνεύει τις δύο αλλαγές σε καμία αλλαγή και τα animations δεν ξαναρχίζουν — μπαίνεις στη μέση ενός loop. |
| Διάρκειες | {a:9000, f:9000, e:8000} ms, ανά σενάριο. |
Η διάρκεια είναι ιδιότητα του σεναρίου, όχι σταθερά του container — γι' αυτό είναι map και όχι ένας αριθμός. |
| Pause | .ledw-stage:hover .ledw * →
animation-play-state:paused. |
Ο μόνος τρόπος να δει κάποιος ένα καρέ σε ένα loop 26s. |
prefers-reduced-motion σταματά το ρολόι.Εγκεκριμένα από τον Βασίλη (2026-08-02) μέσα από έξι που δοκιμάστηκαν. Τα υπόλοιπα τρία (photo-save, Golden Sub, Goal) υπάρχουν στα τοπικά αρχεία concept και δεν ships.
| # | Σενάριο | Διάρκεια | Τι παίζει |
|---|---|---|---|
| 1 | Sponsor .m-a | 9s (3×3s) | Το logo του operator «χτίζεται» από pixels με τρεμόπαιγμα → σλαμάρει η απόδοση
(Ολλανδία — Ιαπωνία · 1 · 1.85) → CTA ΠΑΙΞΕ ΝΟΜΙΜΑ* με τη γραμμή ΕΕΕΠ.
Οι τρεις σκηνές κάνουν κοπή, όχι fade — πινακίδα σταδίου. |
| 2 | Η επέμβαση .m-f | 9s | Μία συνεχής φάση: ο επιθετικός μπαίνει τρέχοντας σπρώχνοντας τη μπάλα, πατάει, σουτάρει· ο τερματοφύλακας είναι στη γραμμή του από το καρέ 0, μαζεύεται και πετάγεται· η μπάλα φεύγει μόνο όταν τη χτυπήσει το πόδι και σβήνει μέσα στα γάντια. Κείμενο: «Θα κρατήσει το μηδέν;» + Goal 1.72 / No Goal 2.05. |
| 3 | Το προγνωστικό .m-e | 8s | Αριστερά οι δύο αναλυτές ως LED μετάλλια (δικό τους dot-matrix 3px, πιο πυκνό από
της πινακίδας) που ανάβουν με τρεμόπαιγμα, ο ένας μισό χτύπο μετά τον άλλο· δεξιά το tip
1 & Over 2.5 @ 3.10· από πάνω χρυσά pixels που πέφτουν. |
Κάθε παίκτης είναι το άλφα μιας φωτογραφίας ως mask-image πάνω
σε επίπεδο χρώμα. Έτσι η ανατομία μένει πραγματική (δεν είναι stick figures) αλλά η απόδοση είναι
της πινακίδας — και το «εμφανίσιμο» γίνεται με CSS.
/* το σχήμα από τη φωτογραφία, το χρώμα από την ομάδα */ .ledwsil{ background:currentColor; -webkit-mask-image:url(concept-assets/keeper-ready.png); mask-image:url(concept-assets/keeper-ready.png); mask-size:contain; mask-repeat:no-repeat; mask-position:center bottom; } /* ΕΜΦΑΝΙΣΙΜΟ = hard-stop gradient που τον κόβει η μάσκα: φανέλα / σορτσάκι / κάλτσες. Τα stops είναι ανά πόζα — κάθε μάσκα έχει δική της γεωμετρία· η βουτιά τρέχει 90deg γιατί το σώμα είναι οριζόντιο. */ .m-f .fr1{ color:#2650C8; /* Ιαπωνία */ background:linear-gradient(180deg,#2650C8 0 50%,#F3F3F3 50% 65%,#2650C8 65% 100%); } .m-f .lp2-dive{ color:#FF6A00; /* Ολλανδία, οριζόντιο σώμα */ background:linear-gradient(90deg,#FF6A00 0 36%,#F3F3F3 36% 54%,#FF6A00 54% 100%); }
Η κίνηση είναι flipbook + ταξίδι, όπως δουλεύει μια αληθινή περιμετρική πινακίδα:
| Φιγούρα | Πόζες | Μηχανισμός |
|---|---|---|
| Επιθετικός | run-a ⇄ run-b → shooter-white |
Δύο πλάγιες δρασκελιές εναλλάσσονται με steps(1) ανά 0.3s (~6.6fps) μέσα σε
wrapper που ταξιδεύει, με bob ανά βήμα· στο πάτημα η πόζα σουτ αντικαθιστά τις δρασκελιές. |
| Τερματοφύλακας | keeper-ready → keeper-dive |
Πλάγια στάση ετοιμότητας (ίδια οπτική γωνία με τη βουτιά — αυτό δίνει τη συνέχεια), μικρό σάλεμα, λύγισμα γονάτων, και η βουτιά ξεκινά γερμένη και χαμηλά και ισιώνει στο τέντωμα. |
Ο στόχος: να φτιάχνουμε σενάρια χωρίς deploy — άλλο creative ανά χορηγό, ανά άθλημα, ανά αγώνα, ανά καμπάνια. Το MVP παραμένει τρία hard-coded σενάρια· αυτή η παράγραφος είναι η προδιαγραφή του επόμενου βήματος, ώστε το MVP να μην την αποκλείσει.
Το μοντέλο: ένα σενάριο = διάρκεια + λίστα από layers. Κάθε layer έχει τύπο, περιεχόμενο, θέση και ένα timeline από keyframes. Ο renderer δεν ξέρει τίποτα για ποδόσφαιρο — ξέρει layers.
{
"id": "save-clean-sheet",
"duration": 9000,
"sport": "football", // φίλτρο: πού επιτρέπεται
"weight": 3, // βάρος στη ρότα (0 = ανενεργό)
"layers": [
{ "type": "prop", "art": "goal-frame", "at": {"right":14,"top":6,"w":190,"h":118} },
{ "type": "figure", // φιγούρα με μάσκα
"poses": { "idle":"keeper-ready.png", "act":"keeper-dive.png" },
"kit": "$match.home.kit", // binding, όχι σταθερά
"at": {"right":52,"bottom":10,"h":80},
"track": [ {"t":0,"pose":"idle"}, {"t":.25,"crouch":true},
{"t":.30,"pose":"act","x":-38,"y":40,"rot":30},
{"t":.33,"x":0,"y":0,"rot":0} ] },
{ "type": "ball", "track": [ … ], "endsIn": "gloves" },
{ "type": "flash", "at_t": .33 },
{ "type": "copy", "in": .38, "align": "left",
"eyebrow": "Goal / No Goal",
"title": "Θα κρατήσει το μηδέν;",
"odds": [ {"label":"Goal", "value":"$odds.btts.yes"},
{"label":"No Goal","value":"$odds.btts.no"} ] }
]
}
Τύποι layer — το MVP ήδη υλοποιεί και τους έξι, απλώς hard-coded. Η φάση 2 τούς κάνει data:
| type | Τι είναι | Ήδη υπάρχει ως |
|---|---|---|
logo | Λογότυπο operator με το τρεμόπαιγμα «ανάμματος» | .ledw-logo |
copy | Eyebrow + τίτλος + υπότιτλος ή chips αποδόσεων | .lp-tx, .lp2-odds |
odds | Μεμονωμένη απόδοση/επιλογή σε μεγάλο μέγεθος | .ledw-odds |
figure | Φιγούρα με πόζες + εμφανίσιμο + track | .ledwsil, .silf |
prop | Τέρμα, μπάλα, πίνακας αλλαγής, κονφετί | .ledw-goal, .ledw-ball, .lp5-conf |
portrait | Πρόσωπο σε LED μετάλλιο (αναλυτές) | .lp5-av |
Bindings — γιατί ένα σενάριο δεν είναι εικόνα αλλά πρότυπο:
| Token | Δίνει |
|---|---|
$match.home.kit / $match.away.kit |
Τα δύο χρώματα εμφανισίμου — ίδιο σενάριο, σωστές ομάδες σε κάθε αγώνα. |
$odds.<market>.<selection> |
Τιμή από το feed. Αν λείπει, το chip δεν αποδίδεται — ποτέ κενό κουτί ή «—». |
$tip.pick / $tip.odd / $tip.analysts[] |
Το προγνωστικό και οι αναλυτές της σελίδας — ό,τι δείχνει ήδη το verdict box. |
$sponsor |
Ο operator: γέμισμα --bk, logo, is-lt. Ήδη λειτουργεί στο MVP. |
sport / phase (pre-game vs live) / sponsor /
ημερομηνίες καμπάνιας, ταξινόμηση με weight. Το σενάριο «Golden Sub» π.χ. έχει νόημα
μόνο όσο τρέχει η προσφορά.DUR map.
background + currentColor στο layer, ώστε αύριο να τα δίνει το feed.
.ledw-msg δεν
ξέρει τι είναι «σουτ» — ξέρει «layers που κινούνται». Όποιος βάλει λογική αγώνα μέσα στο
container, ξαναγράφει τη φάση 2 από την αρχή.Τι θα χρειαστεί επιπλέον στη φάση 2 (εκτός scope τώρα): αποθήκη σεναρίων + απλός editor/preview, validation του JSON, καταγραφή impressions/clicks ανά σενάριο, και προεπισκόπηση σε πραγματικό πλάτος 874px πριν δημοσιευτεί.
| Θέμα | Τι κάνει το component |
|---|---|
| Κίνηση | prefers-reduced-motion:reduce → όλα τα animations σβήνουν, η ρότα
σταματά και η πινακίδα παρκάρει στη σκηνή του CTA, πλήρως αναγνώσιμη. Δεν είναι «λιγότερη
κίνηση», είναι καθόλου. |
| Φλας | Το φλας της επαφής είναι 2 καρέ σε ~9s — πολύ κάτω από τα 3 αναλαμπές/δευτερόλεπτο (WCAG 2.3.1). Μην το κάνετε repeat σε νέο σενάριο χωρίς να ξαναμετρήσετε. |
| Κείμενο | Όλα τα κείμενα είναι πραγματικό DOM, όχι εικόνες — μεταφράζονται και διαβάζονται.
Οι φιγούρες, το τέρμα και η μπάλα είναι aria-hidden: είναι διακόσμηση. |
| Ο σύνδεσμος | Ένα <a> τυλίγει όλη την πινακίδα με aria-label που λέει
operator + αγώνα + απόδοση + «Παίξε νόμιμα» — γιατί οι σκηνές εναλλάσσονται και ο
χρήστης screen reader δεν «προλαβαίνει» καμία. :focus-visible = χρυσό outline. |
| Αντίθεση | Λευκό κείμενο μόνο σε σκούρα γεμίσματα· στα ανοιχτά ο κανόνας .is-lt.
Το pixel grid ρίχνει ~30% φωτεινότητα — μετρήστε την αντίθεση με το grid πάνω, όχι
χωρίς. |
transform, opacity και clip-path — συνθέτονται από τον
compositor και δεν πιάνουν το main thread.setTimeout ανά σενάριο. Τίποτα δεν τρέχει ανά καρέ.loading="lazy" δεν βοηθά (είναι CSS masks) —
προτιμήστε σωστό μέγεθος από την αρχή.<div class="bo adledwrap"> <a class="adled bo-stoiximan" data-adbrand …>…</a> <!-- mobile ticker, μένει --> <div class="ledw-stage tilt" data-ledw> <!-- desktop board --> <a class="ledw bo-stoiximan" data-ledwbrand href="…" aria-label="…"> <span class="ledw-msgs"> <span class="ledw-msg m-a" data-m="a">…</span> <span class="ledw-msg m-f" data-m="f">…</span> <span class="ledw-msg m-e" data-m="e">…</span> </span> <span class="ledw-grid" aria-hidden="true"></span> <span class="ledw-sweep" aria-hidden="true"></span> </a> <span class="ledw-glow" aria-hidden="true"></span> </div> </div>
bo-* του ticker μέσω MutationObserver, αντί να
διαβάζει μόνη της το remote. Έτσι πινακίδα, pinned banner και σήμα στο κέντρο του γηπέδου
δεν μπορούν να διαφωνήσουν. Στο production, όποιος κι αν είναι ο πάροχος του sponsor,
μία πηγή — μην προσθέσετε δεύτερη..xiwrap χάνει τις πάνω γωνίες του.
Η πινακίδα κρατά border-radius πάνω και το γήπεδο γίνεται
0 0 16px 16px — τα δύο διαβάζονται σαν ένα αντικείμενο. Ισχύει ήδη για το
ticker· απλώς μην το χαλάσετε.| Στοιχείο | MVP | Σημείωση |
|---|---|---|
| Η επιφάνεια (grid, glow, sweep, tilt, brand fill) | ΝΑΙ | — |
| Τα 3 σενάρια + αυτόματη εναλλαγή | ΝΑΙ | Hard-coded, με δικό timeline το καθένα. |
Sponsor από μία πηγή, is-lt |
ΝΑΙ | Ήδη δουλεύει. |
| Αποδόσεις/tip από το feed | ΜΕΡΙΚΩΣ | Στο MVP οι τιμές είναι στο markup. Δώστε τις από το ίδιο μοντέλο που τροφοδοτεί το verdict box — δεν θέλουμε την πινακίδα να λέει άλλη τιμή από την κάρτα. |
| Παραμετροποιήσιμα σενάρια (JSON, editor, στόχευση) | ΟΧΙ | §05 — φάση 2. |
| Mobile εκδοχή της πινακίδας | ΟΧΙ | Το ticker μένει ως έχει κάτω από 1200px. |
| Αδειοδοτημένο φωτογραφικό υλικό | ΟΧΙ | Placeholder stock — αλλαγή URL, βλ. Assets. |
Foxbet · Analysis page · LED wall. Concept — προς έγκριση. Τα σενάρια είναι hard-coded στο MVP· η παραμετροποίηση (§05) είναι φάση 2 και το MVP δεν πρέπει να την αποκλείσει.