Skip to content

<goma-casino-games> ​

A compact, host-fed casino games rail: a titled section (flame glyph before "Casino Games", an optional "All slots" quick link) over a horizontal strip of portrait game tiles, a next-tile peek, and opt-in prev/next arrows plus a dot indicator (both on by default). Purely presentational: no WAMP/RPC/REST. Data arrives via the games property; tapping a tile emits goma:casino-game-select and the host owns navigation.

Two tile presentations, picked with the variant property:

  • 'premium' (default): artwork with the game name always visible and a "Play" pill on hover.
  • 'simplified': artwork (a still image, an animated GIF, or a video that plays only while its tile is on screen) alone at rest; the name, provider and a pulsing play icon reveal on hover, staying permanently visible on touch instead.

Live demo ​

Open in the playground →: toggle Casino games in the widget rail.

Element tag ​

html
<goma-casino-games></goma-casino-games>

Installation ​

bash
pnpm add @gomagaming/casino-games vue pinia vue-router vue-i18n @vueuse/core swiper

The framework packages are peer dependencies installed once at the app level; bundlers dedup them across every @gomagaming/* widget. See Installation for the one-time .npmrc token setup.

Configuration ​

el.config = { locale, theme, messages, debug }: the standard widget config bag. This widget makes no network calls, so there is no apiBaseUrl/socketUrl.

KeyTypeDescription
localestringActive i18n locale ('en' / 'fr' / 'pt'). Defaults to 'en'.
themeRecord<string,string>--goma-* token overrides.
messagesobjectOptional i18n phrase overrides.
debugbooleanDefaults to false.

Data sources ​

Host-fed via the games property (or games attribute as JSON):

ts
interface CasinoGame {
  id: string          // stable identity; echoed back on select
  name: string         // overlaid on the tile; also its aria-label
  imageUrl: string     // portrait artwork; fills the tile
  ctaUrl?: string       // optional deep link; passed through on select (not navigated)
  provider?: string     // studio name; shown under the name in the 'simplified' variant only
  previewUrl?: string   // animated preview shown instead of imageUrl in the 'simplified' variant: a GIF, or an .mp4/.webm/.mov/.m4v URL, rendered as a muted looping <video>; falls back to imageUrl when absent
}

This is the only data path: there's no dataSource prop, no RPC, no subscription. games accepts either a live array (JS property) or a JSON string (HTML attribute / the playground's JSON control); a malformed JSON string or a non-array value renders the empty state rather than throwing.

Props / attributes ​

PropertyAttributeTypeDefaultDescription
gamesgames (JSON)CasinoGame[][]Host-fed tiles.
headingheadingstring''Title override. Blank, or spaces only, gives the localized default ("Casino Games").
showTitleshow-titlebooleantrueHeader row.
showFireIconshow-fire-iconbooleantrueFlame glyph beside the title.
showArrowsshow-arrowsbooleantruePrev/next arrows.
showDotsshow-dotsbooleantrueDot pagination row.
tileWidthtile-widthnumber120Fixed tile width in px; the rail shows more tiles with a peek of the next as the container widens.
spaceBetweenspace-betweennumber12Tile gap (px).
enableSwipeenable-swipebooleantrueTouch/drag panning.
looploopbooleanfalseRewind to the start after the last tile (via Swiper's rewind; disabled for ≤1 tile).
maxDotsmax-dotsnumber0Cap on the dot row. 0 keeps one dot per snap position. With N >= 2 and more snaps than N, N dots stand for the whole track: the active dot is the current snap's proportional position (first and last dots are the two ends) and a dot tap jumps to the matching snap. Values below 2 are ignored.
variantvariant'premium' | 'simplified''premium'Tile presentation. See Variants. Any unrecognised value renders 'premium'.
showAllSlotsshow-all-slotsbooleanfalseShow an "All slots" link on the right of the header.
allSlotsUrlall-slots-urlstring''URL echoed in the goma:casino-games-all-select payload when the "All slots" link is activated.
appearanceappearance (JSON)object{}Structure-only pagination-dot sizes: see Appearance.

Variants ​

variant swaps the tile's rendering without touching data, layout, or the goma:casino-game-select payload: a host can flip the property at runtime and its listener never notices.

js
el.variant = 'simplified'
html
<goma-casino-games variant="simplified"></goma-casino-games>

Any value other than 'simplified' renders 'premium', so a typo degrades to the default rather than blanking the widget.

'premium': the shipped tile (default) ​

Artwork fills the tile with a bottom scrim and the game name always visible at the bottom edge; hovering or focusing reveals a centred "Play" pill. This is the original rendering and it is unchanged.

'simplified': artwork-first ​

At rest the tile shows only the artwork (or an animated previewUrl when the game carries one): no name, no scrim. On a hover-capable pointer, hovering or focusing the tile fades in a near-opaque (--goma-allDark at 98% opacity) veil carrying the game name, its provider (when present), and a centred play icon that pulses between 1.0 and 1.12 scale on a 1200 ms ease-in-out loop.

A previewUrl ending in .mp4, .webm, .mov or .m4v (a query string after the extension is fine) renders as a muted, looped <video> instead of an <img>, with imageUrl as its poster. The clip is never set to autoplay outright: an IntersectionObserver starts it only while the tile is actually scrolled into view and pauses it the moment it leaves, so a rail of several previews doesn't decode video it isn't showing. Anything else. A GIF, a still image, or no previewUrl at all. Renders through the same <img loading="lazy"> path as before.

Differences from 'premium':

  • Nothing shown at rest. The name and provider are hidden until hover/focus reveals them; 'premium' always shows the name.
  • provider renders. 'premium' never displays it.
  • previewUrl renders, as a video or a GIF depending on its extension (falling back to imageUrl when absent); 'premium' always uses imageUrl.
  • On touch, the reveal is permanent, not hover-triggered. Touch pointers have no hover state, and the first tap already navigates: a hover-only label would leave the name unreachable. Under (hover: none) the veil degrades to a bottom scrim gradient and the name + provider stay visible at all times, matching 'premium''s always-visible name; only the pulsing play icon is dropped there.
html
<goma-casino-games id="cg" variant="simplified"></goma-casino-games>

Events ​

All events bubble and are composed: true (cross the Shadow DOM boundary).

EventdetailNotes
goma:casino-game-select{ id: string | null, name: string | null, ctaUrl: string | null }Tile tapped. A game with no id, name or ctaUrl sends null for it. Emit-only: the host owns navigation. No shipped widget listens for it.
goma:casino-games-all-select{ url: string | null }The header's "All slots" link was activated (only rendered when showAllSlots is true). url echoes allSlotsUrl. Emit-only: the host owns navigation.
goma:seo-data{ widget: 'casino-games', type: 'casino-game', items: object[] }Fired once the fed games catalogue resolves to at least one game, and again only when an item's id/name/provider/url changes. See SEO data for the payload contract.
ready{}Widget mounted.
goma:error{ message, code, component? }Fires on an error raised in the widget's own outermost component (its setup, its render, its lifecycle hooks or its watchers), where code is the error's name, e.g. 'TypeError' ('RUNTIME_ERROR' when it has none). Errors raised inside the widget's child components do not reach this event: the in-shadow error boundary catches those and shows the retry banner instead, emitting only goma:retry. The connection-layer path other widgets document (code: 'API_INIT_ERROR') does not exist here: casino-games is purely host-fed (games prop only), with no WAMP/RPC/REST connection that could fail.
goma:retry{}User clicked Retry on the render-error banner.

Empty / loading / error states ​

There is no loading state: games is host-fed and synchronous, so the widget renders its final state on the first tick.

  • Empty: games is [] (the default), a non-array value, or an unparseable JSON string: renders EmptyState (a dice glyph + the casino_games_empty message) instead of the carousel.
  • Populated: one GameTile per entry, in array order.
  • Render error: an onErrorCaptured boundary in CasinoGamesApp catches a Vue render/runtime error, shows a role="alert" banner (the error_prefix copy, "ERROR:" in English, then the message) with a Retry button (clears the error and emits goma:retry) and a dismiss × button named "Close" (the close copy), and auto-clears after 8000 ms even without user interaction.
  • Forced error: el.forceError(message) shows the same banner with no timer: it stays until the user dismisses it or taps Retry, or the host calls el.clearError().

Theming ​

All colours map to existing --goma-* tokens, plus two optional nav-arrow overrides (--goma-navArrowBackground / --goma-navArrowIcon, unset by default; themeTokens.js lists as their default what the fallback paints with core's values, #ffffff99 and #03061b):

TokenRole
--goma-textPrimaryTile name, active pagination dot
--goma-textSecondaryEmpty-state icon + message
--goma-iconPrimaryFlame glyph
--goma-backgroundCardsTile placeholder background
--goma-backgroundSecondaryTile bottom-fade scrim
--goma-separatorLineInactive dot
--goma-highlightTertiary → --goma-highlightPrimaryTile bottom-edge gradient bar
--goma-highlightPrimaryTile hover/focus top glow, focus rings
--goma-highlightGradientStartHover "Play" pill background, "All slots" link
--goma-buttonTextPrimaryHover "Play" pill text
--goma-allWhiteTop-glow rim line, hover title glow, and the nav arrow disc (painted at 60% opacity)
--goma-navArrowBackgroundOptional nav arrow disc override. Unset (default), the disc is --goma-allWhite at 60%. For a palette where that does not pair with the caret, e.g. a light theme that wants a dark disc.
--goma-navArrowIconOptional nav arrow caret override. Unset (default), the caret is --goma-highlightSecondaryContrast.
--goma-alertErrorError banner background
--goma-highlightPrimaryContrastError banner Retry text and focus ring
--goma-highlightSecondaryContrastNav arrow caret
--goma-allDark'simplified' variant: the hover veil (98% opacity) behind the info block, and the touch-fallback bottom scrim
--goma-widgetInsetHorizontal gutter: see Widget gutter

Each tile is portrait (3:4), has an 8 px radius, a 2 px gradient bottom accent, and a transparent-to-dark bottom scrim so the name stays legible over bright artwork. The widget root is transparent: the host owns the surrounding panel.

--goma-widgetInset sets the HORIZONTAL gutter between the rail's content and the edge of the element: 8px here. Widgets differ, so a page stacking several of them can set the token once to line them all up, or 0 to hand the gutter to the page. It does not touch vertical padding, and leaving it unset keeps the value above. See Widget gutter.

Appearance (styling object) ​

appearance carries structure only. Each key is a single value (identical in light and dark) that maps to one --goma-* CSS custom property on the host. Set it via el.appearance = {...} or the appearance attribute (a JSON string); unset keys keep the default, so an empty {} (the default) reproduces the current look. Colours stay in theme.

KeyCSS variableDefaultAffects
dotSize--goma-casinoDotSize7pxDiameter of each pagination dot.
dotGap--goma-casinoDotGap6pxSpace between pagination dots.
activeDotWidth--goma-casinoActiveDotWidth18pxWidth of the active dot, a pill by default. Set it equal to dotSize for a round active dot that differs from the others by colour only.

i18n / message overrides ​

KeyDefault (en)Used by
casino_games"Casino Games"Section title fallback when heading is blank.
casino_games_empty"No games available"Empty-state message.
casino_games_play"Play"Hover/focus "Play" pill label on a tile.
casino_games_all_slots"All slots"Header quick link, shown when showAllSlots is true.
retry"Retry"Render-error banner's retry button (shared key).
error_prefix"ERROR:"Render-error banner's prefix, before the message (shared key).
close"Close"Accessible name of the banner's dismiss × (shared key).
previous / next"Previous" / "Next"Accessible names of the arrows (shared keys).
go_to_page"Go to page {page}"Accessible name of each dot, {page} counting from 1 (shared key).

Embedding examples ​

Vanilla / CDN ​

html
<goma-casino-games id="cg"></goma-casino-games>
<script type="module">
  import '@gomagaming/casino-games'

  const el = document.getElementById('cg')
  el.config = { locale: 'en' }
  el.games = [
    { id: 'g1', name: 'Gates of Olympus', imageUrl: 'https://…/olympus.jpg', ctaUrl: 'https://…/play' },
    { id: 'g2', name: 'Sweet Bonanza', imageUrl: 'https://…/bonanza.jpg' },
  ]
  el.addEventListener('goma:casino-game-select', (e) => {
    // e.detail = { id, name, ctaUrl }
    window.location.href = e.detail.ctaUrl ?? `/casino/${e.detail.id}`
  })
</script>

React ​

jsx
import '@gomagaming/casino-games'
import { useRef, useEffect } from 'react'

export function CasinoGames({ games }) {
  const ref = useRef(null)
  useEffect(() => {
    const el = ref.current
    if (!el) return
    el.config = { locale: 'en' }
    el.games = games
    const onSelect = (e) => { /* route to e.detail.ctaUrl */ }
    el.addEventListener('goma:casino-game-select', onSelect)
    return () => el.removeEventListener('goma:casino-game-select', onSelect)
  }, [games])
  return <goma-casino-games ref={ref} />
}

Vue ​

vue
<script setup>
import '@gomagaming/casino-games'
import { ref, watchEffect } from 'vue'

const props = defineProps(['games'])
const el = ref(null)

watchEffect(() => {
  if (!el.value) return
  el.value.config = { locale: 'en' }
  el.value.games = props.games
})
</script>

<template>
  <goma-casino-games ref="el" @goma:casino-game-select="$emit('select', $event.detail)" />
</template>

Accessibility ​

  • Each tile is a native <button> with aria-label set to the game name; its artwork <img> carries a matching alt. The aria-label is present in both variants, so in 'simplified', where the visible name label is hover-only, the accessible name still survives for assistive tech.
  • The flame and empty-state dice glyphs are aria-hidden="true" (decorative).
  • Prev/next arrows are <button>s named from the previous / next copy ("Previous" / "Next" in English); disabled Swiper navigation state fades them to opacity: 0 and disables pointer events.
  • The dot row is role="tablist" with each dot role="tab", named from the go_to_page copy ("Go to page 1", counting from 1), and aria-selected tracking the active snap position.
  • The error banner's dismiss × is a <button> named from the close copy ("Close").
  • Tiles, arrows, and dots all carry a visible focus-visible ring (--goma-highlightPrimary).

Integration Caveats ​

  • SSR/webview: importing this package outside a browser previously threw immediately; fixed with a guard on the shared element factory.

  • Tokens/Theming: themeTokens.js declared an unused --goma-highlightGradientEnd (only --goma-highlightGradientStart is actually used); removed.

  • Initialization: this widget shares @gomagaming/core's i18n singleton with every other widget on the page; mounting two widgets with different locale values on one page is not currently isolated per instance (a known constraint, not fixed in this pass).

  • Configuring before the definition loads. Assigning config (or any property) while the element is still an unknown element is safe: the value is replayed through the widget when it upgrades. That matters when loading from the CDN, whose loader imports widget modules asynchronously, so your script usually runs first. On release sets at 0.34.0 and earlier the value was silently discarded and the widget mounted with no configuration and a clean console: there, await window.__gomaCdn.ready first, or configure through attributes. See Setting a property before the widget's definition has loaded.

See Integration Caveats for the cross-widget picture.

Changelog ​

Current release: 0.37.11. Every GomaPulse package shares one version number and they are published together, so a release that changes nothing here still bumps this widget. Only the releases that changed it are listed below.

Every release that changed this widget, newest first. The latest is open; the rest expand.

0.37.0
  • <goma-multi-banners> and <goma-casino-games> take an appearance object. On multi-banners it sets the rail's top and bottom padding, the card header and start-date type, the team-name line height and spacing, the CTA button's padding, line height and icon gap, and the gap between pagination dots. On casino-games it sets the pagination dots' size, gap and the active dot's width, so a design can draw the active dot as a circle instead of the default pill. Every key is optional and an empty object keeps today's look. @gomagaming/core is bumped for the new utilities in its compiled sheet.

  • <goma-multi-banners> gains two appearance keys: prevArrowDisplay (none keeps only the next arrow) and edgeFadeWidth (a fade over the cards' right edge into the page background, none by default). <goma-casino-games> gains a maxDots property (max-dots attribute) that caps the pagination row: with more snap positions than maxDots, that many dots stand for the whole track, the active one at the current position's proportional place, and a tap jumps to the matching position. The default, 0, keeps one dot per snap position. Both widgets look and behave as before unless a host sets the new options.

  • Casino games and time filter: the error bar's dismiss × is now a button named "Close", so keyboard and screen-reader users can reach it, and its "ERROR:" prefix comes from the new error_prefix copy key and follows the widget's locale. In casino games, the carousel arrows' names and the dots' names ("Go to page 1") also come from copy keys (previous, next, and the new go_to_page). clearError() now removes an error bar that forceError() showed, and forcing the same message again after a dismiss shows the bar again.

    Casino games: a heading of spaces only now shows the default title, like a blank one. custom-elements.json now declares the goma:seo-data and goma:retry events the widget already emitted, and types a tapped game's id and name as possibly null. The theme token list now names the flame's own token (iconPrimary) and the error bar's, and the two optional arrow tokens (navArrowBackground, navArrowIcon) now list a default, also in multi-banners and sports navigation (horizontal).

    Core: the Portuguese "Next" label read "Prximo"; it now reads "Próximo".

0.36.1
  • Playground manifests (@gomagaming/<widget>/playground) now offer a control for every setting each widget really has. Settings that cannot be a form field (raw provider data, read-only state mirrors, props a widget never reads) are recorded with a reason in the repo instead of being silently missing.

    Controls that never reached the widget are fixed:

    • The betslips' placeBetHeadersJson / placeBetBodyJson / quickAddAmountsJson are now placeBetHeaders / placeBetBody / quickAddAmounts.
    • The time-filter and filters-settings ticks editors set ticks.
    • live-chat's layout control writes position, the config key the element reads.
    • The sports-navigation widgets drop the unread sportsJson.
    • JSON-typed defaults are real objects and arrays instead of serialized strings. The top-competitions highlightedImages string default was indexed character by character and requested bad image URLs on every load. The missions-hub emptyStateImages illustrations now show.

    No widget runtime behaviour changes.

0.36.0
  • The carousel navigation arrow accepts two optional theme tokens: --goma-navArrowBackground (the disc) and --goma-navArrowIcon (the caret). Unset, the arrow looks exactly as before (an allWhite disc at 60% with a highlightSecondaryContrast caret) so only a palette where those two do not pair (for example a light theme that wants a dark disc) needs to set them.
0.34.0
  • Stop a region list fetched for the wrong sport from overwriting the right one, and parse numeric strings assigned to numeric widget properties instead of silently replacing them with the widget's default

    A <goma-region-filter> configured for any sport other than Football issued two location requests instead of one: its own, correctly scoped to the configured sport, and a second one (scoped to Football) that nothing had asked for. Both wrote the same place, so the pills the widget rendered were whichever response happened to come back last. The same race reached <goma-competitions-list>, which groups its competitions by the same region data.

    The unrequested request came from the per-widget boot routine, which fetched locations with no sport at all and so fell back to sport 1. Locations are scoped to a sport on the server, and boot has no sport to scope them by, so it no longer fetches them: the only readers of that data are the widgets above, and each of them already fetches it for the sport it is showing.

    That removes the collision at its source. As a second line of defence, a locations payload now records which sport it was fetched for, and a widget ignores one belonging to a sport it is not showing. This matters whenever two scoped fetches can overlap (switching sport while a request is still in flight, for instance) and it is deliberately narrow: a payload with no recorded sport is still rendered, so the guard can only ever suppress data it can positively identify as belonging to somewhere else.

    Separately, every numeric property on every widget (sportId, skeletonCount, pageSize, spaceBetween, autoplayInterval and the rest) used to accept a JavaScript number and nothing else. A numeric string was not parsed; it was discarded and quietly replaced by the property's default value. el.sportId = '8' therefore left the widget on sport 1 and fetched the wrong data, with nothing logged to say so. Three ordinary integration paths hand over a string: a router parameter, a value read out of a CMS or JSON configuration, and a framework re-render that stringifies its props. Numeric strings are now parsed. Values that are not a finite number and not a numeric string (null, undefined, '', booleans, objects, NaN, Infinity) still fall back to the default, as before. HTML attributes (sport-id="8") and the config object were never affected by this and are unchanged.

0.32.0
  • Widgets no longer dispatch a bare error event alongside goma:error.

    Every factory-built widget's app-level Vue error handler dispatched two events for the same failure: goma:error, and an un-namespaced error. The bare one is gone; goma:error is unchanged and still carries the same { message, code, component? } detail.

    Like every GomaPulse event it was composed and bubbling, so it did not stop at the widget. It crossed the shadow root, crossed the document, and arrived at whatever the host had on window.addEventListener('error', …): as a CustomEvent with message, error and filename all undefined, since those are ErrorEvent fields a CustomEvent does not have. A host with error reporting installed received a malformed error record it could neither read nor attribute.

    That had been written off as harmless on the grounds that the handler behind it could never fire. It can. Vue begins its errorCaptured walk at the throwing component's parent, so the onErrorCaptured boundary each widget installs in its own root component cannot see that component's own errors, and being the root, there is nothing above it to catch them either. Anything raised in a widget's root scope (its setup, its render, its lifecycle hooks, its watchers) skips the boundary and reaches the app-level handler every time. Only errors from child components are caught by the boundary, which is what it is for: those show the in-shadow banner and emit goma:retry.

    Hosts listening for goma:error need no change. A host listening for bare error on a widget element should move to goma:error; it was documented as unreachable, so in practice it delivered nothing until now.

0.31.0
  • Added --goma-widgetInset, one CSS custom property that settles how far a widget's content sits from the edge of its element.

    Widgets had each grown their own horizontal padding (8px around the multi-banners and casino-games rails, none on the sports-navigation strip or the event feeds) so stacking them in a column started content at different offsets, and the only way to line them up was to cancel the difference with negative margins on the host side.

    Set --goma-widgetInset once and every widget that has a gutter adopts it; set it to 0 and they all run flush to their element, handing the gutter back to the page. Widgets that were already flush are unaffected: the token does not add padding where there was none.

    It governs horizontal padding only. Vertical padding is the space between sections, which a host already controls with margins, so folding it into the same token would mean setting the gutter to 8px silently added 8px of top padding to rails that had none.

    Panel widgets are deliberately not governed by it: <goma-competitions-list> and <goma-top-competitions> (list variant) keep a fixed 16px interior, because that padding is the inside of a rounded box the widget paints rather than a page gutter.

    Nothing changes for existing embeds. There is no global default: each widget falls back to exactly what it renders today, so the token only takes effect once a host sets it.

0.29.0
  • Add goma:seo-data: widgets emit their resolved event data so hosts can build their own meta tags and structured data.

    Eight widgets emit the event: game-details, events-horizontal, competitions-list, hero-card, highlight-card, pros-choice, multi-banners (sport banners only), and casino-games. The payload is { widget, type, items }, where type is 'sports-event' or 'casino-game'. The event bubbles and is composed, so a single listener on document catches every widget on the page.

    Emission fires once when data resolves and again only when the data's identity changes: markets, score and clock are excluded from the identity signature, so odds ticks do not re-fire it. An empty items array is never emitted. Hosts must replace their structured data on each event rather than append.

    Widgets carrying a signed-in user's own data, private content, or page chrome deliberately do not emit.

  • Integration caveats: fixes from a cross-widget review of every shipped widget from an integrator's point of view.

    Cross-cutting fixes:

    • @gomagaming/core's createWidgetElement() factory, and live-chat's and messenger's own element classes, now guard against importing a widget package in a non-browser context (SSR): the HTMLElement subclass was previously defined at module top level in every widget package, so importing any of them under server-side rendering threw a ReferenceError immediately.

    Per-package fixes:

    • favorites: added src/themeTokens.js and a :host stylesheet (previously the package had neither, so it silently rendered core's base theme instead of its documented dark-navy/cyan/amber theme).
    • suggested-bet. Fixed a leaked WAMP subscription: switching a mounted widget's dataSource away from rpc/subscribe never released the open topic.
    • filters-settings: fixed a dead :host{display:inline-block} CSS rule (the shared element factory's inline display:block always won), so the widget always rendered full-width instead of the intended compact inline trigger.
    • game-details: added a min-height fallback for the inert/no-eventId state in an unsized container.
    • betslip-sidebar, my-bets, competition-filter, suggested-bet, events-horizontal, top-competitions, top-competitions-pills, competitions-list, multi-banners, casino-games, sports-navigation-horizontal. Corrected themeTokens.js registries that had drifted from actual token usage, added missing goma:retry Events-table rows, and other small doc/registry corrections.
    • region-filter: added a missing typeof window !== 'undefined' guard on a window listener.
    • live-chat: corrected custom-elements.json's members array (missing theme/config accessors, and an inaccurate description).
    • sports-domain: corrected a stale code comment that seeded a documentation error in two Missions widgets.

    Three fixes (favorites, game-details, filters-settings) change real rendering and are flagged in docs/guide/integration-caveats.md as needing human visual verification before release.

  • Visual corrections across the game card, the casino rail and every carousel arrow.

    • Game cards. Team names on the large card variant were clipped: an 18px font was set on a 16px line box, which sheared the ascenders and the descenders of names like Puerto Rico (W). The line box now fits the font's ink, and the home row's bottom margin is pulled in so the painted distance between the two team names is unchanged. Affects every widget rendering the shared game card, plus <goma-highlight-card>'s team rows.
    • <goma-casino-games>: the 'simplified' tile now matches its design source: a 23:30 portrait tile, and the name/provider block and play glyph laid out as one centred stack so the gap between them no longer changes with the number of lines the game name wraps to.
    • Navigation arrows: <goma-casino-games>, <goma-multi-banners> and <goma-sports-navigation-horizontal> now draw one identical arrow: a 24px disc of --goma-allWhite at 60% carrying a full-strength --goma-highlightSecondaryContrast caret on a 1px stroke. Previously the three diverged in disc colour, glyph size (14–18px) and stroke weight. Hosts that restyled these arrows through --goma-textPrimary or --goma-backgroundBorder should move to the two tokens above; both are declared in each widget's theme-token registry and documented in its theming table.
    • <goma-top-competitions>: the list header's type now matches the section headers around it instead of running a size larger at a lighter weight.
0.28.1
  • <goma-casino-games>: bring the simplified tile's hover overlay onto the design frame.

    The provider line was 12px in the muted --goma-textSecondary; the design sets it at 10px and binds it to the same colour variable as the game title, so it is now full-strength --goma-textPrimary. Both lines take the design's exact 16px line-height.

    The play glyph was a 28px generic triangle; it is now the design's own exported glyph at its native 40px.

    Enlarging the glyph alone would have overlapped the provider text: the old 38%/61% offsets were tuned around the smaller icon. Both are re-derived from the design's layout instead: its overlay pads 2px top / 12px bottom, and the 50px title block and 60px icon frame centre as one stack inside the remainder, putting their centres at 30.6% and 61.1% of the tile. They stay percentages because tile height follows the host's tileWidth through the 3:4 aspect ratio.

0.28.0
  • Casino games: add a variant prop ('premium' | 'simplified'). premium is the default and renders exactly what shipped before. simplified shows the game artwork, or an animated previewUrl (a GIF, or an .mp4/.webm/.mov/.m4v clip rendered as a muted, looped video that only plays while its tile is on screen), alone, revealing the name, provider and a pulsing play icon on hover; on touch, where there is no hover, the name and provider stay permanently visible. The header now places the flame before the title and can show an opt-in "All slots" link.
0.26.0
  • Stop publishing source maps and package source.

    dist/*.js.map was emitted by the shared Vite preset and swept into every tarball by files: ["dist/", "src/"], with the original source inlined in sourcesContent. src/ shipped the same source again, in the clear. Both are one URL away from a browser once a package is served from a CDN, so the preset now builds with sourcemap: false and files no longer carries src/.

    @gomagaming/core keeps the two paths its export map actually points at: src/styles/main.css and src/types/index.d.ts. Its tarball drops from 1741 files to 576, which also brings it back under the 900-file limit a per-request unpacker can handle.

    Deep imports of @gomagaming/<pkg>/src/* from an installed package no longer resolve. Nothing documented used them; imports inside the monorepo are unaffected.

0.16.0
  • GomaPulse UX review (round 3):

    • Sport icons: dedicated glyphs for the eSports titles (FIFA, NBA2k, Counter-Strike, DOTA 2, Overwatch) plus a shared outline-controller default for every other eSports category, replacing the legacy generic gamepad; corrected Beach Volleyball and Hurling glyphs.
    • Casino card: nav-arrow disc uses backgroundBorder; restyled Play pill (8px radius, 14px, weight 600, buttonTextPrimary, outline play icon); title gains a soft white glow on hover; added the design's top-edge line + radial top glow (driven by highlightPrimary); removed the hover lift.
    • Multi-banners: favourite star now matches the app's outline star.
    • Country flag ring (shared): uses the theme-fixed allWhite token so the ring stays white under any consumer theme.
    • tabPill pressed state: added the 80%-opacity pressed treatment on the My Bets and Game Details pills.
    • Sports selector: the widget host now carries a default 8px corner radius.
    • Suggested-bet leg: sport-icon colour uses iconPrimary.
0.15.2
  • GomaPulse UX-review round 2: visual/token fixes:

    • core: official flat sports-icon set (46 mainstream/virtual/eSports-category glyphs across dark + light modes, keyed by sport id). Inherited app-wide via SbIcon; new casino_games_play i18n key (en/fr/pt).
    • casino-games: official flame glyph, hover "Play" overlay on tiles, title→tiles / tiles→dots spacing.
    • multi-banners: header now self-resolves the sport glyph from the event's sport id, renders the country flag via the shared CountryFlag component (new flagBaseUrl option, defaults to the OM flag CDN), and gains a 1px card border.
    • sports-navigation-horizontal: the rounded container now clips its content so the 8px corners render.
    • suggested-bet: leg sport icons use the flat bundled icon set.
    • game-details / missions-hub / sports-domain (My Bets): tabPill hover + pressed states (violet ring); My Bets ticket icon sizing (12px sport + flag) and centered totals summary.
0.15.0
  • UI fixes from the a separate change design review (Sports Pages, items 1.1–1.19):

    • Suspended odds pill text uses inputTextTitleDisabled (legible on lightened themes) and game-card team/player names render at 16px.
    • Brand font: Open Sans is bundled and registered via the document.fonts API so widgets paint the intended typeface inside the shadow root.
    • Game-card market pill colours corrected (live separatorLine, prelive highlightPrimary); sports-navigation tile sizing + rounded container; multi-banners overlay gradient; casino-games flame colour + tile gradient border; filters-settings radio-row divider.
    • competition-filter: edge-trigger icon size, pill padding, and hover/pressed states.
    • competitions-list: inset row divider (original colour) + corrected accordion caret orientation.
    • game-details: header sport-icon/flag + rounded top corners; market-tab horizontal paging arrows with click-to-centre; long-market "See All" cap; corrected collapse-caret orientation.
    • top-competitions: white sport icon + featured-card neon divider moved to the card bottom and thickened.
    • suggested-bet: Bet / Total Odds / Winnings summary centre-aligned.
0.13.0
  • Add <goma-casino-games>: a compact, host-fed casino games rail (titled section + flame, portrait artwork tiles with name overlay, next-tile peek, arrows, dot pagination). Emits goma:casino-game-select on tile tap. Core-only, no WAMP; Swiper-based carousel.