โ† Torna alla demo

๐ŸŽต Sasha - Smart Audio System Hosting Advertisements

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.


๐Ÿ“‹ Indice


๐Ÿ“ฆ Repository

Repository ufficiale: bitbucket.org/banzaimediavico42/sasha


โœจ Caratteristiche


๐ŸŽฌ Demo

Demo statica autosufficiente:

Landing page:


๐Ÿ“ฆ Installazione

Metodo 1: Bundle UMD (Consigliato)

  1. Scarica il bundle UMD da dist/sasha-player.min.js
  2. Includi nel tuo progetto HTML:
<!-- 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>

Metodo 2: ES Module (Moderno)

<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>

Metodo 3: NPM Package (Futuro)

npm install @mondadori/sasha-player

๐Ÿš€ Utilizzo

Utilizzo Ottimizzato (Web Vitals)

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>

Utilizzo base

<!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>

Configurazione inline

<sasha-player data-config='{
  "audioUrl": "audio.mp3",
  "title": "Titolo Audio",
  "subtitle": "Descrizione",
  "coverImage": "cover.jpg",
  "theme": "default"
}'></sasha-player>

Player multipli

<!-- 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>

Con preroll pubblicitario (v3.0.0+)

<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>

Con tema personalizzato

<sasha-player 
  theme="custom-theme" 
  themes-path="./my-themes/"
  data-config='{
    "audioUrl": "audio.mp3",
    "title": "Audio con tema custom"
  }'>
</sasha-player>

Multi-istanza con stop automatico

<!-- 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>

โš™๏ธ Configurazione

Configurazione tramite data-config

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 in themes/ con CSS custom properties.

Parametri di configurazione

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:

Attributi del componente

Attributo Valori Default Descrizione
shadow-mode open open Modalitร  dello Shadow DOM: open (accessibile) o closed (incapsulato)

๐ŸŽฎ Controlli

Controlli UI

Controlli tastiera (se abilitati)


๐Ÿ”ง API

Metodi pubblici

const 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();

Proprietร  dello stato

const player = document.querySelector('sasha-player');

console.log(player.state);
// {
//   isPlaying: false,
//   currentTime: 0,
//   duration: 0,
//   isPrerollPlaying: false,
//   hasPlayedPreroll: false,
//   volume: 1,
//   isMuted: false
// }

Eventi custom

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:

Tutti gli eventi standard HTML5 Audio sono disponibili su player.audioElement.


๐Ÿ“ข Sistema Ads (v3.0.0+)

Sasha include un sistema pubblicitario modulare e flessibile per preroll, midroll e postroll.

Configurazione Ads

{
  "ads": [
    {
      "type": "preroll",         // 'preroll' | 'midroll' | 'postroll'
      "source": "static",        // 'static' | 'gam'
      "audioUrl": "ad.mp3",
      "skippable": false
    }
  ]
}

๐ŸŽฏ Multiple Ads Support (v3.0+)

โœจ 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:

  1. Prerolls (in sequenza) โ†’ Contenuto โ†’ Midrolls (ai trigger points) โ†’ Contenuto โ†’ Postrolls (in sequenza)

Tipi di Ads

Preroll

Riprodotto prima del contenuto principale.

{
  "type": "preroll",
  "source": "static",
  "audioUrl": "https://example.com/preroll-ad.mp3"
}

Midroll

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" }
  ]
}

Postroll

Riprodotto dopo il contenuto principale.

{
  "type": "postroll",
  "source": "static",
  "audioUrl": "https://example.com/postroll-ad.mp3"
}

Sorgenti Ads

Static (File Audio)

File audio diretto, come MP3, WAV, OGG.

{
  "type": "preroll",
  "source": "static",
  "audioUrl": "https://cdn.example.com/ads/preroll.mp3"
}

GAM (Google Ad Manager - VAST)

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:

Fallback Chain

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"
  }
}

Frequency Capping

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:

Esempio - 1 volta all'ora:

{
  "frequencyCapping": {
    "enabled": true,
    "storage": "local",
    "maxPlays": 1,
    "timeWindow": 3600000
  }
}

Eventi Ads

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');
});

Comportamento Durante Ads

Interazioni utente bloccate (v3.2.0+):

Comportamento Midroll:


๐ŸŽจ Tipologie Waveform

Sasha supporta 5 tipologie di visualizzazione waveform con caricamento lazy:

{
  "advanced": {
    "waveformType": "bar"  // bar | mirrored | line | blocks | gradient
  }
}

Tipologie Disponibili

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

Esempio Configurazione

<!-- 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!


โšก Ottimizzazioni Web Vitals

Lazy Loading

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:

โš ๏ธ 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:

Strategia Above/Below the Fold

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>

๐ŸŽจ Sistema Temi

๐Ÿš€ Cache Globale Temi (v3.2.0+)

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):

Utility per sviluppatori:

// Pulisci cache di un tema specifico
window.SashaThemeManager.clearCache('default');

// Pulisci tutta la cache globale
window.SashaThemeManager.clearCache();

Struttura temi

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

Creare un tema personalizzato

  1. Crea la cartella del tema:
mkdir themes/my-theme
  1. Crea theme.json:
{
  "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.json contiene solo metadati del tema (nome, versione, descrizione, layout). La sezione cssVars รจ puramente documentativa e NON viene letta dal player. I colori DEVONO essere definiti nel file theme.css come CSS custom properties. Questo garantisce separazione completa tra logica e presentazione.

  1. Crea theme.css:
:host {
  display: block;
  width: 100%;
  max-width: 800px;
  margin: 0 auto;
}

.sasha-container {
  background: var(--sasha-bg-color, #000000);
  min-height: 180px;
  /* Altri stili... */
}
  1. Crea template.html (opzionale):
<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>
  1. Usa il tema:
<sasha-player theme="my-theme"></sasha-player>

Placeholder template

Il template HTML supporta placeholder:

Elementi opzionali

Tutti 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:

Se un elemento non รจ presente nel template, il player continuerร  a funzionare senza errori, semplicemente ignorando le funzionalitร  associate a quell'elemento.

Path temi configurabile

<!-- 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>

๐ŸŽจ Personalizzazione

Temi predefiniti

โš ๏ธ 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.

Tema Default

window.SashaConfig = {
  theme: 'default'  // Tema con colori cyan/azzurro moderni
};

Light Compact Theme ๐ŸŒฟ (NEW v3.2.0)

Tema ultra-compatto per giovani 12-20 anni, minimal e fresco.

Caratteristiche:

Elementi Rimossi:

Colori:

<sasha-player data-config='{
  "audioUrl": "audio.mp3",
  "title": "Fresh Vibes ๐ŸŒฟ",
  "coverImage": "photo.jpg",
  "theme": "light"
}'></sasha-player>

Gen-Z Theme ๐Ÿ”ฅ

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 */
}

CSS Custom (fuori Shadow DOM)

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 supportati

Browser Versione minima
Chrome 67+
Firefox 63+
Safari 11+
Edge 79+
Opera 54+
iOS Safari 11+
Chrome Android 67+

Requisiti:


๐Ÿ› ๏ธ Sviluppo

Struttura del progetto

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)

Architettura

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚   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    โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Estendere il player

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);

๐Ÿ“ฑ Design Responsive

Sasha Player adotta una strategia responsive differenziata per garantire la migliore esperienza utente su ogni dispositivo.

Desktop (> 768px)

Layout orizzontale con cover sulla sinistra (35%) e controlli sulla destra:

Mobile (โ‰ค 768px)

Layout overlay full-width per massimizzare l'uso dello spazio:

Breakpoint:

Perchรฉ due layout diversi?


๐Ÿ“ Note tecniche

Shadow DOM

Il player utilizza Shadow DOM per incapsulare completamente stili e markup. Questo significa:

Modalitร  Shadow DOM

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.

Web Audio API

Il waveform viewer utilizza Web Audio API per analizzare le frequenze in tempo reale:

Performance

Gestione Colori e Temi

I 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+:

Architettura iOS/Safari-safe:

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.


๐Ÿ› Troubleshooting

๐Ÿ› Modalitร  Debug

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:

Esempio output console:

๐Ÿ› Debug Mode: Cache-busting abilitato per risorse tema (cacheBuster: 1729512345)
๐Ÿ› Tema 'genz' caricato (no-cache)

โš ๏ธ IMPORTANTE:

Combinazione con debugColors:

<sasha-player data-config='{
  "theme": "genz",
  "advanced": {
    "debugMode": true,     // No cache per CSS temi
    "debugColors": true    // Badge colori visivo
  }
}'></sasha-player>

Il player non si vede

Verifica che:

  1. I file .js siano caricati correttamente
  2. Non ci siano errori in console
  3. Il browser supporti Web Components

L'audio non si riproduce

Possibili cause:

  1. URL audio non valido o non accessibile
  2. CORS policy del server audio
  3. Browser blocca autoplay (richiede user interaction)
  4. Formato audio non supportato

Il waveform non appare

Verifica:

  1. Web Audio API supportata dal browser
  2. AudioContext non bloccato (user interaction required)
  3. Canvas elemento presente nel DOM

Preroll non funziona

Controlla:

  1. URL preroll valido
  2. Formato audio supportato
  3. Console per errori di caricamento

Controlli volume su iOS

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.

๐Ÿ” Debug Colori

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ร :

Quando usarlo:

Nota: Il badge appare dopo ~100ms per dare tempo al tema di applicare le CSS custom properties.


๐Ÿ“„ Changelog

v3.1.0 (2025-10-21) ๐Ÿ› ๏ธ DEV EXPERIENCE

Nuove Feature:

Scripts NPM:

Configurazione:

Workflow:

  1. Modifiche src/ โ†’ Rollup rebuild โ†’ BrowserSync reload โ†’ Browser refresh < 1s
  2. Modifiche temi/HTML/CSS โ†’ BrowserSync reload istantaneo
  3. Nessuna trasformazione dei file CSS/JSON (serviti come file statici)

Nota Tecnica:


v3.0.0 (2025-10-21) ๐Ÿš€ MAJOR RELEASE

BREAKING CHANGES:

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:


v2.4.1 (2025-10-20)


v2.4.0 (2025-10-20)

v2.3.0 (2025-10-20)

v2.2.0 (2025-10-17)

v2.0.4 (2025-10-17)

v2.0.3 (2025-10-17)

v2.0.2 (2025-10-17)

v2.0.1 (2025-10-17)

v2.0.0 (2025-10-17)

v1.0.1 (2025-10-17)

v1.0.0 (2025-10-17)


๐Ÿค Contribuire

Suggerimenti e miglioramenti sono benvenuti!

Per informazioni dettagliate su come contribuire, vedi CONTRIBUTING.md.

Quick start:

  1. Fork del progetto
  2. Crea un branch per la tua feature
  3. Commit delle modifiche
  4. Push al branch
  5. Apri una Pull Request

๐Ÿ“œ Licenza

Questo progetto รจ sviluppato da Mondadori Digital ยฉ 2025.


๐Ÿ‘ฅ Autori


๐Ÿ™ Ringraziamenti


๐Ÿ‘จโ€๐Ÿ’ป Sviluppo

Architettura Modulare

Il progetto utilizza un'architettura modulare ES6 per massima manutenibilitร  e riutilizzabilitร  del codice.

Struttura Moduli

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

Setup Sviluppo

# 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 Produzione

# 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.

Deployment e CI/CD

Il progetto utilizza Bitbucket Pipelines per il deployment automatico su Cloudflare Pages.

๐Ÿš€ Deploy Automatico

Pipeline configurata in: bitbucket-pipelines.yml

Workflow:

  1. Push su master โ†’ Deploy automatico in produzione

  2. Push su altri branch โ†’ Deploy automatico in preview

โš™๏ธ Configurazione Pipeline

La pipeline รจ configurata con:

๐Ÿ” Variabili d'Ambiente Richieste

Per il funzionamento della pipeline, รจ necessario configurare in Bitbucket:

Repository Settings โ†’ Pipelines โ†’ Repository variables:

Nota: Se CLOUDFLARE_API_TOKEN non รจ configurato, Wrangler userร  l'autenticazione locale configurata tramite wrangler login.

๐Ÿ“‹ Struttura Pipeline

# 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)

๐Ÿ” Verifica Deploy

Dopo ogni push:

  1. Controlla lo stato della pipeline in Bitbucket โ†’ Pipelines
  2. Verifica il deploy su Cloudflare Pages Dashboard
  3. Accedi alla demo pubblicata su https://sasha-player.pages.dev/

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.

Utilizzo Build

ES Module (Moderno)

import SashaPlayer from './dist/sasha-player.esm.js';
// o import selettivo
import { SashaPlayer, ThemeManager, EVENTS } from './dist/sasha-player.esm.js';

UMD (Browser)

<script src="dist/sasha-player.min.js"></script>
<script>
  // Disponibile come oggetto globale Sasha
  console.log(Sasha.version);
</script>

Contribuire

  1. Fork il repository
  2. Crea un branch per la feature (git checkout -b feature/AmazingFeature)
  3. Commit i cambiamenti (git commit -m 'Add some AmazingFeature')
  4. Push al branch (git push origin feature/AmazingFeature)
  5. Apri una Pull Request

Testing

# 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

๐Ÿ“ž Supporto

Per domande, bug o richieste di feature, apri una issue nel repository.


Fatto con moderato โค๏ธ da Mondadori Digital