Player audio modulare, leggero e completamente personalizzabile costruito con Web Components e Shadow DOM. Supporta streaming audio, preroll pubblicitari e visualizzazione waveform in tempo reale.
Repository ufficiale: bitbucket.org/banzaimediavico42/sasha
Demo statica autosufficiente:
dist/index.html per la demo completa (dopo npm run build)dist/ e funziona standaloneLanding page:
index.html nella root per la pagina di benvenuto con link a demo e documentazionedist/sasha-player.min.js<!-- Bundle UMD minificato -->
<script src="dist/sasha-player.min.js"></script>
<!-- Usa il componente -->
<sasha-player data-config='{
"audioUrl": "audio.mp3",
"title": "Titolo",
"coverImage": "cover.jpg"
}'></sasha-player>
<script>
// Oggetto globale Sasha disponibile
console.log('Sasha v' + Sasha.version);
</script>
<script type="module">
import SashaPlayer from './dist/sasha-player.esm.js';
// Il componente รจ registrato automaticamente
</script>
<sasha-player data-config='{ "audioUrl": "audio.mp3" }'></sasha-player>
npm install @mondadori/sasha-player
Per massime performance e Web Vitals ottimali, abilita il lazy loading:
<!-- Lazy loading per Web Vitals (below the fold) -->
<sasha-player data-config='{
"audioUrl": "audio.mp3",
"title": "Titolo Audio",
"coverImage": "cover.jpg",
"advanced": {
"lazyLoad": true
}
}'></sasha-player>
<script src="dist/sasha-player.min.js"></script>
<!DOCTYPE html>
<html lang="it">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sasha Player</title>
</head>
<body>
<!-- Player -->
<sasha-player data-config='{
"audioUrl": "audio.mp3",
"title": "Titolo Audio",
"coverImage": "cover.jpg"
}'></sasha-player>
<!-- Bundle UMD -->
<script src="dist/sasha-player.min.js"></script>
<script>
document.addEventListener('sasha:ready', (e) => {
console.log('Player v' + Sasha.version + ' pronto');
});
</script>
</body>
</html>
<sasha-player data-config='{
"audioUrl": "audio.mp3",
"title": "Titolo Audio",
"subtitle": "Descrizione",
"coverImage": "cover.jpg",
"theme": "default"
}'></sasha-player>
<!-- Player 1 -->
<sasha-player data-config='{
"audioUrl": "audio1.mp3",
"title": "Primo Audio"
}'></sasha-player>
<!-- Player 2 -->
<sasha-player data-config='{
"audioUrl": "audio2.mp3",
"title": "Secondo Audio"
}'></sasha-player>
<sasha-player data-config='{
"audioUrl": "podcast.mp3",
"title": "Podcast Episode #1",
"coverImage": "podcast-cover.jpg",
"ads": [
{
"type": "preroll",
"source": "static",
"audioUrl": "ad.mp3"
}
]
}'></sasha-player>
<sasha-player
theme="custom-theme"
themes-path="./my-themes/"
data-config='{
"audioUrl": "audio.mp3",
"title": "Audio con tema custom"
}'>
</sasha-player>
<!-- Player 1 -->
<sasha-player data-config='{
"audioUrl": "audio1.mp3",
"title": "Primo Audio"
}'></sasha-player>
<!-- Player 2 - si fermerร automaticamente quando Player 1 inizia -->
<sasha-player data-config='{
"audioUrl": "audio2.mp3",
"title": "Secondo Audio"
}'></sasha-player>
La configurazione del player avviene tramite l'attributo data-config con un oggetto JSON:
<sasha-player data-config='{
"audioUrl": "https://example.com/audio.mp3",
"title": "Titolo Audio",
"subtitle": "Descrizione o artista",
"coverImage": "https://example.com/cover.jpg",
"theme": "default",
"skipSeconds": 15,
"showShareButton": true,
"sponsorLogo": "logo.png",
"sponsorClaim": "In collaborazione con",
"sponsorLink": "https://example.com",
"ads": [],
"frequencyCapping": {
"enabled": false
},
"advanced": {
"preload": "metadata",
"loop": false,
"initialVolume": 1.0,
"autoplay": false,
"fftSize": 256,
"keyboardControls": true,
"shadowMode": "open",
"lazyLoad": false,
"debugMode": false,
"debugColors": false
}
}'></sasha-player>
โ ๏ธ BREAKING CHANGE v2.4.0+: I colori NON sono piรน configurabili via
data-config.
Per personalizzare colori, crea un tema custom inthemes/con CSS custom properties.
| Parametro | Tipo | Default | Descrizione |
|---|---|---|---|
audioUrl |
string | '' | URL del file audio principale |
coverImage |
string | placeholder | URL immagine di copertina |
title |
string | 'Audio Title' | Titolo dell'audio |
subtitle |
string | 'Audio Subtitle' | Sottotitolo/descrizione |
skipSeconds |
number | 15 | Secondi skip avanti/indietro |
showShareButton |
boolean | true | Mostra bottone condivisione |
sponsorLogo |
string|null | null | URL logo sponsor (visualizzato in alto a destra) |
sponsorClaim |
string | 'In collaborazione con' | Testo claim sopra il logo sponsor |
sponsorLink |
string | '#' | Link per logo sponsor (apre in nuova tab) |
theme |
string | 'default' | Nome tema da utilizzare |
themesPath |
string | 'themes/' | Path base per i temi |
ads |
Array | [] | Array di ads (preroll/midroll/postroll) - v3.0.0+ |
frequencyCapping |
Object | {...} | Configurazione frequency capping ads - v3.0.0+ |
โ ๏ธ BREAKING CHANGES:
- v2.4.0+: Parametri colore rimossi (
backgroundColor,accentColor, etc.) - usa temi CSS- v3.0.0+:
prerollUrlrimosso - usa il nuovo sistemaads: []
| Attributo | Valori | Default | Descrizione |
|---|---|---|---|
shadow-mode |
open |
open |
Modalitร dello Shadow DOM: open (accessibile) o closed (incapsulato) |
Spazio: Play/Pausaโ: Skip indietroโ: Skip avantiM: Mute/Unmuteโ: Aumenta volumeโ: Diminuisci volumeconst player = document.querySelector('sasha-player');
// Play
await player.play();
// Pause
player.pause();
// Skip (secondi positivi o negativi)
player.skip(15); // Avanti 15s
player.skip(-10); // Indietro 10s
// Volume (0.0 - 1.0)
player.setVolume(0.5);
// Mute toggle
player.toggleMute();
// Condivisione
await player.share();
const player = document.querySelector('sasha-player');
console.log(player.state);
// {
// isPlaying: false,
// currentTime: 0,
// duration: 0,
// isPrerollPlaying: false,
// hasPlayedPreroll: false,
// volume: 1,
// isMuted: false
// }
Il player emette diversi eventi personalizzati che puoi intercettare:
const player = document.querySelector('sasha-player');
// Evento: Player completamente inizializzato e pronto
document.addEventListener('sasha:ready', (e) => {
console.log('Player pronto:', e.detail.player);
});
// Evento: Tema caricato e applicato
document.addEventListener('sasha:themeloaded', (e) => {
console.log('Tema caricato:', e.detail.themeName);
});
// Evento: Theme Manager pronto (per script async)
document.addEventListener('sasha:themeManagerReady', () => {
console.log('Theme Manager inizializzato');
});
// Evento: Config globale pronta (per script async)
document.addEventListener('sasha:configReady', () => {
console.log('Config globale caricata');
});
// Eventi nativi dell'elemento audio
player.audioElement.addEventListener('play', () => {
console.log('Riproduzione avviata');
});
player.audioElement.addEventListener('pause', () => {
console.log('Riproduzione in pausa');
});
player.audioElement.addEventListener('ended', () => {
console.log('Riproduzione terminata');
});
player.audioElement.addEventListener('timeupdate', () => {
console.log('Tempo:', player.audioElement.currentTime);
});
player.audioElement.addEventListener('volumechange', () => {
console.log('Volume:', player.audioElement.volume);
});
Eventi Disponibili:
sasha:ready - Player completamente inizializzatosasha:themeloaded - Tema caricato e applicatosasha:themeManagerReady - Theme Manager pronto (async-safe)sasha:configReady - Config globale caricata (async-safe)Tutti gli eventi standard HTML5 Audio sono disponibili su player.audioElement.
Sasha include un sistema pubblicitario modulare e flessibile per preroll, midroll e postroll.
{
"ads": [
{
"type": "preroll", // 'preroll' | 'midroll' | 'postroll'
"source": "static", // 'static' | 'gam'
"audioUrl": "ad.mp3",
"skippable": false
}
]
}
โจ Feature Chiave: Sasha supporta ads multiple dello stesso tipo in sequenza!
Puoi configurare:
{
"ads": [
// 2 Preroll ads
{ "type": "preroll", "source": "static", "audioUrl": "preroll1.mp3" },
{ "type": "preroll", "source": "static", "audioUrl": "preroll2.mp3" },
// 3 Midroll ads a posizioni diverse
{ "type": "midroll", "source": "static", "audioUrl": "mid1.mp3", "position": { "type": "percentage", "value": 25 } },
{ "type": "midroll", "source": "static", "audioUrl": "mid2.mp3", "position": { "type": "percentage", "value": 50 } },
{ "type": "midroll", "source": "static", "audioUrl": "mid3.mp3", "position": { "type": "percentage", "value": 75 } },
// 2 Postroll ads
{ "type": "postroll", "source": "static", "audioUrl": "post1.mp3" },
{ "type": "postroll", "source": "static", "audioUrl": "post2.mp3" }
]
}
Ordine di riproduzione:
Riprodotto prima del contenuto principale.
{
"type": "preroll",
"source": "static",
"audioUrl": "https://example.com/preroll-ad.mp3"
}
Riprodotto durante il contenuto, con posizione configurabile.
Posizione in percentuale:
{
"type": "midroll",
"source": "static",
"audioUrl": "https://example.com/midroll-ad.mp3",
"position": { "type": "percentage", "value": 50 } // Al 50% del contenuto
}
Posizione in secondi:
{
"type": "midroll",
"source": "static",
"audioUrl": "https://example.com/midroll-ad.mp3",
"position": { "type": "seconds", "value": 120 } // A 2 minuti dall'inizio
}
Multiple Ads (Preroll, Midroll, Postroll):
{
"ads": [
// Multiple prerolls
{ "type": "preroll", "source": "static", "audioUrl": "preroll1.mp3" },
{ "type": "preroll", "source": "static", "audioUrl": "preroll2.mp3" },
// Multiple midrolls
{ "type": "midroll", "source": "static", "audioUrl": "midroll1.mp3", "position": { "type": "percentage", "value": 25 } },
{ "type": "midroll", "source": "static", "audioUrl": "midroll2.mp3", "position": { "type": "percentage", "value": 75 } },
// Multiple postrolls
{ "type": "postroll", "source": "static", "audioUrl": "postroll1.mp3" },
{ "type": "postroll", "source": "static", "audioUrl": "postroll2.mp3" }
]
}
Riprodotto dopo il contenuto principale.
{
"type": "postroll",
"source": "static",
"audioUrl": "https://example.com/postroll-ad.mp3"
}
File audio diretto, come MP3, WAV, OGG.
{
"type": "preroll",
"source": "static",
"audioUrl": "https://cdn.example.com/ads/preroll.mp3"
}
Tag VAST da Google Ad Manager.
{
"type": "midroll",
"source": "gam",
"vastTag": "https://pubads.g.doubleclick.net/gampad/ads?iu=/123456/audio&...",
"position": { "type": "percentage", "value": 50 }
}
Cosa fa il VASTParser:
Se un ad fallisce (es. VAST non disponibile), puoi configurare un fallback:
{
"type": "preroll",
"source": "gam",
"vastTag": "https://pubads.g.doubleclick.net/gampad/ads?...",
"fallback": {
"type": "preroll",
"source": "static",
"audioUrl": "https://cdn.example.com/ads/fallback.mp3"
}
}
Chain multipli:
fallback: {
source: "gam",
vastTag: "...",
fallback: {
source: "static",
audioUrl: "final-fallback.mp3"
}
}
Limita quante volte un ad puรฒ essere riprodotto per evitare sovraesposizione.
Configurazione:
{
"frequencyCapping": {
"enabled": true,
"storage": "session", // 'session' | 'local' | 'none'
"maxPlays": 1, // Max riproduzioni per ad
"timeWindow": 3600000 // 1 ora in ms (null = illimitato)
}
}
Storage types:
session: Reset alla chiusura tablocal: Persistente tra sessioninone: Solo tracking in-memory (reset al reload)Esempio - 1 volta all'ora:
{
"frequencyCapping": {
"enabled": true,
"storage": "local",
"maxPlays": 1,
"timeWindow": 3600000
}
}
const player = document.querySelector('sasha-player');
// Ad iniziato
player.addEventListener('sasha:adstart', (e) => {
console.log('Ad started:', e.detail);
// { adId, adType, adSource, adConfig }
});
// Ad completato
player.addEventListener('sasha:adcomplete', (e) => {
console.log('Ad completed:', e.detail);
// { adId, adType, adSource }
});
// Errore ad
player.addEventListener('sasha:aderror', (e) => {
console.error('Ad error:', e.detail);
// { adId, adType, error }
});
// Progresso ad (per countdown)
player.addEventListener('sasha:adprogress', (e) => {
console.log('Ad progress:', e.detail.progress + '%');
// { adId, currentTime, duration, progress }
});
// Tutti gli ads completati
player.addEventListener('sasha:alladsplayed', () => {
console.log('All ads played');
});
Interazioni utente bloccate (v3.2.0+):
cursor: not-allowed + pointer-events: noneComportamento Midroll:
Sasha supporta 5 tipologie di visualizzazione waveform con caricamento lazy:
{
"advanced": {
"waveformType": "bar" // bar | mirrored | line | blocks | gradient
}
}
| Tipo | Visualizzazione | Use Case | Caricamento |
|---|---|---|---|
bar (default) |
Barre verticali classiche | Podcast, parlato | Incluso nel bundle |
mirrored |
Simmetrico verticale (stile DAW) | Musica, professionale | Lazy loading |
line |
Linea continua fluida | Musica, eleganza | Lazy loading |
blocks |
Blocchi pixel-art | Retro, minimalista | Lazy loading |
gradient |
Gradienti per intensitร | Visualizzazione dinamica | Lazy loading |
<!-- Waveform Mirrored -->
<sasha-player data-config='{
"audioUrl": "audio.mp3",
"title": "Professional Audio",
"advanced": {
"waveformType": "mirrored"
}
}'></sasha-player>
<!-- Waveform Gradient -->
<sasha-player data-config='{
"audioUrl": "music.mp3",
"title": "Dynamic Music",
"advanced": {
"waveformType": "gradient"
}
}'></sasha-player>
๐ก Caricamento Intelligente: I renderer waveform sono caricati solo quando necessari (lazy loading). Se usi solo
bar, gli altri renderer non vengono mai scaricati, risparmiando banda e memoria!
Per ottimizzare CLS, LCP e INP, abilita il lazy loading per player below the fold:
<sasha-player data-config='{
"audioUrl": "audio.mp3",
"title": "Titolo Audio",
"advanced": {
"lazyLoad": true
}
}'></sasha-player>
Come funziona:
lazyLoad: trueโ ๏ธ IMPORTANTE CLS: Il skeleton loading รจ SEMPRE attivo per tutti i player, indipendentemente da
lazyLoad. Questo garantisce CLS < 0.1 anche per player above the fold.
Risultati attesi:
Above the Fold (Player 1-2):
<!-- Caricamento immediato per contenuto critico -->
<sasha-player data-config='{...}'></sasha-player>
Below the Fold (Player 3+):
<!-- Lazy loading per contenuto non critico -->
<sasha-player data-config='{
"advanced": { "lazyLoad": true }
}'></sasha-player>
I temi sono caricati una sola volta e condivisi tra tutte le istanze del player:
<!-- 5 player con stesso tema = 1 SOLA richiesta di rete -->
<sasha-player data-config='{"theme": "default", ...}'></sasha-player>
<sasha-player data-config='{"theme": "default", ...}'></sasha-player>
<sasha-player data-config='{"theme": "default", ...}'></sasha-player>
<sasha-player data-config='{"theme": "default", ...}'></sasha-player>
<sasha-player data-config='{"theme": "default", ...}'></sasha-player>
Vantaggi:
Console logs (debug mode):
๐ Caricamento tema 'default' dalla rete... - Prima istanza๐ฆ Tema 'default' preso dalla cache globale (richieste di rete: 0) - Istanze successiveโณ Tema 'default' giร in caricamento, attendo... - Istanze simultaneeUtility per sviluppatori:
// Pulisci cache di un tema specifico
window.SashaThemeManager.clearCache('default');
// Pulisci tutta la cache globale
window.SashaThemeManager.clearCache();
themes/
โโโ default/
โ โโโ theme.css # Stili CSS del tema
โ โโโ theme.json # Configurazione del tema
โ โโโ template.html # Template HTML (opzionale)
โโโ dark/
โ โโโ theme.css
โ โโโ theme.json
โ โโโ template.html
โโโ genz/
โ โโโ theme.css
โ โโโ theme.json
โ โโโ template.html
โโโ light/ # NEW v3.2.0 - Ultra-compatto
โ โโโ theme.css
โ โโโ theme.json
โ โโโ template.html
โโโ custom/ # Esempio tema personalizzato
โโโ theme.css
โโโ theme.json
โโโ template.html
mkdir themes/my-theme
{
"name": "my-theme",
"version": "2.4.0",
"description": "Il mio tema personalizzato - Descrizione degli stili e colori",
"author": "Il tuo nome",
"layout": "horizontal",
"cssVars": {
"note": "I colori sono definiti nel file theme.css. Questa sezione รจ solo documentativa.",
"backgroundColor": "#000000",
"accentColor": "#ff0080",
"textColor": "#ffffff",
"waveformColor": "#ff0080",
"waveformBackgroundColor": "rgba(255, 0, 128, 0.1)"
}
}
โ ๏ธ IMPORTANTE v2.4.0+:
theme.jsoncontiene solo metadati del tema (nome, versione, descrizione, layout). La sezionecssVarsรจ puramente documentativa e NON viene letta dal player. I colori DEVONO essere definiti nel filetheme.csscome CSS custom properties. Questo garantisce separazione completa tra logica e presentazione.
:host {
display: block;
width: 100%;
max-width: 800px;
margin: 0 auto;
}
.sasha-container {
background: var(--sasha-bg-color, #000000);
min-height: 180px;
/* Altri stili... */
}
<div class="sasha-container">
<div class="sasha-cover">
<img src="{{coverImage}}" alt="{{title}}" />
</div>
<div class="sasha-content">
<div class="sasha-info">
<h2 class="sasha-title">{{title}}</h2>
<p class="sasha-subtitle">{{subtitle}}</p>
</div>
<canvas class="sasha-waveform" id="waveform"></canvas>
<div class="sasha-controls">
<button class="sasha-btn sasha-btn-play" id="btn-play">โถ</button>
</div>
</div>
</div>
<sasha-player theme="my-theme"></sasha-player>
Il template HTML supporta placeholder:
{{title}} - Titolo dell'audio{{subtitle}} - Sottotitolo{{coverImage}} - URL immagine copertina{{skipSeconds}} - Secondi per skip{{sponsorLogo}} - URL logo sponsor{{sponsorClaim}} - Testo claim sponsor{{sponsorLink}} - Link sponsor{{#showShareButton}}...{{/showShareButton}} - Blocco condizionale{{#sponsorLogo}}...{{/sponsorLogo}} - Blocco condizionale per sponsorTutti gli elementi del player sono opzionali e vengono gestiti automaticamente in base alla loro presenza nel template. Puoi includere solo gli elementi che ti servono:
#btn-play - Pulsante play/pause#btn-backward - Skip indietro#btn-forward - Skip avanti#progress-bar - Barra di progresso#progress-fill - Fill della progress bar#current-time - Tempo corrente#duration - Durata totale#volume-slider - Slider del volume#btn-mute - Pulsante mute#btn-share - Pulsante condivisione#status - Messaggio di stato#waveform - Canvas per waveformSe un elemento non รจ presente nel template, il player continuerร a funzionare senza errori, semplicemente ignorando le funzionalitร associate a quell'elemento.
<!-- Path relativo -->
<sasha-player themes-path="./themes/"></sasha-player>
<!-- Path assoluto -->
<sasha-player themes-path="/assets/audio-themes/"></sasha-player>
<!-- CDN -->
<sasha-player themes-path="https://cdn.example.com/sasha-themes/"></sasha-player>
โ ๏ธ IMPORTANTE v2.4.0+: I colori NON sono piรน configurabili via JavaScript. Per usare un tema, specifica semplicemente il nome nella configurazione. Per personalizzare colori, crea un tema custom modificando il CSS.
window.SashaConfig = {
theme: 'default' // Tema con colori cyan/azzurro moderni
};
Tema ultra-compatto per giovani 12-20 anni, minimal e fresco.
Caratteristiche:
Elementi Rimossi:
Colori:
rgb(176, 247, 170) (verde lime fresco)#ffffff (bianco)#000000 (nero)<sasha-player data-config='{
"audioUrl": "audio.mp3",
"title": "Fresh Vibes ๐ฟ",
"coverImage": "photo.jpg",
"theme": "light"
}'></sasha-player>
Tema vibrante e dinamico orientato al pubblico giovane, con layout orizzontale audace, gradients magenta-lime e tutti i controlli bianchi.
Caratteristiche:
<sasha-player data-config='{
"audioUrl": "audio.mp3",
"title": "Vibes Only ๐ต",
"subtitle": "Playlist Gen-Z",
"coverImage": "cover.jpg",
"theme": "genz"
}'></sasha-player>
Palette colori (definita in themes/genz/theme.css):
:host {
--sasha-bg-color: #1a0f2e; /* Viola scuro */
--sasha-accent-color: #ff3b9a; /* Magenta vivace */
--sasha-text-color: #ffffff; /* Bianco */
--sasha-waveform-color: #d4ff00; /* Lime elettrico */
--sasha-waveform-background-color: rgba(212, 255, 0, 0.15); /* Lime trasparente */
}
Per stilizzare il contenitore del player:
sasha-player {
/* Margini personalizzati */
margin: 20px auto;
/* Larghezza massima */
max-width: 600px;
/* Ombra personalizzata */
filter: drop-shadow(0 10px 40px rgba(0, 0, 0, 0.5));
}
| Browser | Versione minima |
|---|---|
| Chrome | 67+ |
| Firefox | 63+ |
| Safari | 11+ |
| Edge | 79+ |
| Opera | 54+ |
| iOS Safari | 11+ |
| Chrome Android | 67+ |
Requisiti:
sasha/
โโโ src/ # Sorgenti ES6 modules
โโโ dist/ # Distribuzione pronta (bundle + demo statica)
โ โโโ index.html # Demo principale (root di dist)
โ โโโ assets/ # Assets demo (CSS, immagini, audio)
โ โโโ themes/ # Temi per distribuzione
โ โโโ examples/ # Esempi inclusi nel pacchetto
โ โโโ README.html # Documentazione convertita in HTML
โ โโโ docs/ # Documentazione HTML (BUILD.html convertito)
โโโ themes/ # Temi CSS sorgente (copiati in dist/ durante build)
โโโ demo-source/ # Demo sorgente (index.html โ dist/index.html, assets โ dist/assets/)
โโโ examples/ # Esempi d'uso sorgente (copiati in dist/examples/ durante build)
โโโ docs/ # Documentazione (tutti i .MD tranne README.md)
โ โโโ BUILD.md
โ โโโ CHANGELOG.md
โ โโโ CONTRIBUTING.md
โ โโโ DEV.md
โ โโโ THEME_CACHE.md
โ โโโ WEB_VITALS.md
โ โโโ ...
โโโ index.html # Landing con link a demo e documentazione
โโโ package.json # NPM config
โโโ rollup.config.js # Build config
โโโ README.md # Documentazione principale (root per GitHub)
โโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ index.html (host) โ
โโโโโโโโโโโโโฌโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ <sasha-player> โ
โ (Web Component) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ Shadow DOM โ
โ โโ HTML Template โ
โ โโ Scoped CSS โ
โ โโ Event Listeners โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ Audio Elements โ
โ โโ Main Audio โ
โ โโ Preroll Audio โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ Web Audio API โ
โ โโ AudioContext โ
โ โโ Analyser Node โ
โ โโ Frequency Data โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ Canvas Waveform โ
โ โโ Animation Frame โ
โ โโ Visual Rendering โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโ
Per aggiungere nuove funzionalitร :
class MySashaPlayer extends SashaPlayer {
constructor() {
super();
// Inizializzazione custom
}
// Override metodo esistente
async play() {
console.log('Play custom');
await super.play();
}
// Nuovo metodo
myCustomMethod() {
// Tua logica
}
}
// Registra il nuovo componente
customElements.define('my-sasha-player', MySashaPlayer);
Sasha Player adotta una strategia responsive differenziata per garantire la migliore esperienza utente su ogni dispositivo.
Layout orizzontale con cover sulla sinistra (35%) e controlli sulla destra:
Layout overlay full-width per massimizzare l'uso dello spazio:
Breakpoint:
Il player utilizza Shadow DOM per incapsulare completamente stili e markup. Questo significa:
Il player supporta due modalitร di Shadow DOM configurabili:
open (default): Shadow DOM accessibile via JavaScript
<sasha-player shadow-mode="open"></sasha-player>
<!-- o semplicemente -->
<sasha-player></sasha-player>
closed: Shadow DOM completamente incapsulato
<sasha-player shadow-mode="closed"></sasha-player>
Con modalitร closed, il Shadow DOM non รจ accessibile dall'esterno tramite element.shadowRoot, offrendo il massimo livello di incapsulamento. Utile per proteggere l'implementazione interna del player da modifiche esterne accidentali o intenzionali.
Il waveform viewer utilizza Web Audio API per analizzare le frequenze in tempo reale:
AudioContext: Contesto audio per elaborazioneAnalyserNode: Nodo per analisi frequenzegetByteFrequencyData(): Estrazione dati frequenzerequestAnimationFrame(): Rendering fluido 60fpsI colori sono gestiti ESCLUSIVAMENTE tramite CSS custom properties definite nel tema:
CSS Custom Properties del Tema (OBBLIGATORIE):
/* themes/[tema]/theme.css */
:host {
--sasha-bg-color: #1a0f2e;
--sasha-accent-color: #ff3b9a;
--sasha-text-color: #ffffff;
--sasha-waveform-color: #d4ff00;
--sasha-waveform-background-color: rgba(212, 255, 0, 0.15);
}
โ ๏ธ IMPORTANTE v2.4.0+:
data-config o window.SashaConfigthemes/custom/ con le CSS vars:hostArchitettura iOS/Safari-safe:
WaveformRenderer legge colori con doppio fallback:.sasha-container (comportamento normale)<sasha-player> (Safari/iOS compatibility)Debug Colori: Per verificare quali colori vengono effettivamente applicati, attiva il debug:
"advanced": { "debugColors": true }
Mostra badge visivo con valori reali e log in console.
Per facilitare lo sviluppo e il debugging dei temi, Sasha include una modalitร debug con cache-busting automatico.
Attivazione:
{
"advanced": {
"debugMode": true, // Cache-busting per CSS temi
"debugColors": true // Badge colori visivo
}
}
Cosa fa la modalitร debug:
?_=1729512345 a tutte le risorse dei temi (CSS, JSON, template)Esempio output console:
๐ Debug Mode: Cache-busting abilitato per risorse tema (cacheBuster: 1729512345)
๐ Tema 'genz' caricato (no-cache)
โ ๏ธ IMPORTANTE:
debugMode: true SOLO in sviluppoCombinazione con debugColors:
<sasha-player data-config='{
"theme": "genz",
"advanced": {
"debugMode": true, // No cache per CSS temi
"debugColors": true // Badge colori visivo
}
}'></sasha-player>
Verifica che:
.js siano caricati correttamentePossibili cause:
Verifica:
Controlla:
Sasha usa GainNode della Web Audio API per il controllo volume, compatibile con iOS.
iOS blocca audioElement.volume per policy di sistema, ma Sasha bypassa questa limitazione usando un GainNode nella catena audio:
Architettura:
Audio Element โ GainNode โ AnalyserNode โ Speakers
โ
Volume Control
Vantaggi:
Nota tecnica: Il preroll usa ancora audioElement.volume (breve durata, meno critico), mentre l'audio principale usa il GainNode.
Per verificare quali colori il player sta effettivamente usando (utile per diagnosticare problemi di tema o override), puoi attivare il debug visivo dei colori:
<sasha-player data-config='{
"audioUrl": "audio.mp3",
"title": "Debug Test",
"advanced": {
"debugColors": true
}
}'></sasha-player>
Questo mostrerร :
accent: colore principale del temawave: colore della waveformwaveBg: colore di sfondo della waveformQuando usarlo:
data-config sta funzionandoNota: Il badge appare dopo ~100ms per dare tempo al tema di applicare le CSS custom properties.
Nuove Feature:
npm run dev:fullnpm run dev:httpsScripts NPM:
npm run dev: BrowserSync server (live reload automatico)npm run dev:full: Rollup watch + BrowserSync (rebuild automatico + live reload)npm run dev:https: Dev server con HTTPS + live reloadnpm run dev:simple: Server HTTP statico semplice (serve)npm run dev:vite: Vite (non raccomandato, problemi con temi)npm run build:watch: Build watch (solo rollup)Configurazione:
vite.config.js: Configurazione Vite (opzionale, non usato di default).gitignore: Aggiunto dist-demo/, .vite/Workflow:
src/ โ Rollup rebuild โ BrowserSync reload โ Browser refresh < 1sNota Tecnica:
npm run dev:vite ma causa problemi con il caricamento dinamico dei temiBREAKING CHANGES:
ads: [] configurabilestatic (file audio) e gam (VAST tag Google Ad Manager)Nuove Feature:
Architettura:
Configurazione:
{
"ads": [
{ "type": "preroll", "source": "static", "audioUrl": "ad.mp3" },
{ "type": "midroll", "source": "gam", "vastTag": "...", "position": { "type": "percentage", "value": 50 } },
{ "type": "postroll", "source": "static", "audioUrl": "ad2.mp3" }
],
"frequencyCapping": { "enabled": true, "maxPlays": 1 }
}
Migration Guide:
// PRIMA (v2.x - RIMOSSO)
{
"prerollUrl": "ad.mp3"
}
// ORA (v3.0.0+)
{
"ads": [
{ "type": "preroll", "source": "static", "audioUrl": "ad.mp3" }
]
}
Documentazione:
colors rinominata in cssVars e marcata come documentativaapplyCustomColors() da SashaPlayer - non piรน necessarioapplyThemeVariables() da ThemeManager - CSS vars vengono solo dal theme.cssdebugMode: true)advanced.debugColors: true per diagnosticare problemi temasponsorLogo, sponsorClaim, sponsorLink configurabili per brandingshadow-mode="closed" (default open)previousVolume per tracciare il volume prima del mutepreviousVolumeaddColorStop con configurazione inlineSuggerimenti e miglioramenti sono benvenuti!
Per informazioni dettagliate su come contribuire, vedi CONTRIBUTING.md.
Quick start:
Questo progetto รจ sviluppato da Mondadori Digital ยฉ 2025.
Il progetto utilizza un'architettura modulare ES6 per massima manutenibilitร e riutilizzabilitร del codice.
src/
โโโ core/ # Logica core del player
โ โโโ SashaPlayer.js # Web Component principale
โ โโโ AudioManager.js # Gestione audio e preroll
โ โโโ WaveformRenderer.js # Rendering waveform
โ โโโ StateManager.js # State management
โ
โโโ managers/ # Gestori di alto livello
โ โโโ ConfigManager.js # Configurazione
โ โโโ ThemeManager.js # Gestione temi
โ โโโ TemplateEngine.js # Template con placeholder
โ
โโโ ui/ # UI e interazioni
โ โโโ ControlsManager.js # Event listeners controlli
โ โโโ DOMUpdater.js # Aggiornamenti DOM
โ
โโโ utils/ # Utilities riutilizzabili
โ โโโ events.js # Custom events
โ โโโ dom.js # Helper DOM
โ โโโ format.js # Formatters
โ โโโ validator.js # Validazione
โ
โโโ constants/ # Costanti e configurazioni
โ โโโ defaults.js # Config di default
โ
โโโ index.js # Entry point con export
# 1. Clone repository
git clone git@bitbucket.org:banzaimediavico42/sasha.git
cd sasha
# 2. Installa dipendenze
npm install
# 3. Avvia dev server con live reload (consigliato)
npm run dev:full
# โ Rollup watch + BrowserSync con live reload automatico su https://localhost:3000
# Alternative:
npm run dev # Solo server (bundle statico)
npm run dev:https # Con HTTPS (utile per Web Audio API)
# Build tutti i formati
npm run build
# Output in dist/:
# - sasha-player.esm.js (ES Module)
# - sasha-player.js (UMD)
# - sasha-player.min.js (UMD minified)
# Preview build produzione
npm run preview
Per dettagli completi sul workflow di sviluppo, vedi DEV.md.
Per dettagli sulla build, vedi BUILD.md.
Per informazioni su come contribuire, vedi CONTRIBUTING.md.
Il progetto utilizza Bitbucket Pipelines per il deployment automatico su Cloudflare Pages.
Pipeline configurata in: bitbucket-pipelines.yml
Workflow:
Push su master โ Deploy automatico in produzione
npm ci + npm run build)Push su altri branch โ Deploy automatico in preview
La pipeline รจ configurata con:
dist/ tra gli stepPer il funzionamento della pipeline, รจ necessario configurare in Bitbucket:
Repository Settings โ Pipelines โ Repository variables:
CLOUDFLARE_PROJECT_NAME: Nome del progetto Cloudflare PagesCLOUDFLARE_API_TOKEN: Token API Cloudflare (opzionale, se non configurato usa autenticazione Wrangler)Nota: Se CLOUDFLARE_API_TOKEN non รจ configurato, Wrangler userร l'autenticazione locale configurata tramite wrangler login.
# Branch master โ Produzione
master:
- Build (npm ci + npm run build)
- Deploy to Cloudflare Pages (production)
# Altri branch โ Preview
**:
- Build (npm ci + npm run build)
- Deploy to Cloudflare Pages (preview per branch)
Dopo ogni push:
Nota: Il deploy in produzione avviene automaticamente solo su push al branch master. Per testare modifiche, usa un branch separato che genererร automaticamente un deploy preview.
import SashaPlayer from './dist/sasha-player.esm.js';
// o import selettivo
import { SashaPlayer, ThemeManager, EVENTS } from './dist/sasha-player.esm.js';
<script src="dist/sasha-player.min.js"></script>
<script>
// Disponibile come oggetto globale Sasha
console.log(Sasha.version);
</script>
git checkout -b feature/AmazingFeature)git commit -m 'Add some AmazingFeature')git push origin feature/AmazingFeature)# Dev server con BrowserSync + live reload (consigliato)
npm run dev:full
# Solo server (se bundle giร buildato)
npm run dev
# Build e preview produzione
npm run build
npm run preview
Per domande, bug o richieste di feature, apri una issue nel repository.
Fatto con moderato โค๏ธ da Mondadori Digital