{"id":3289,"date":"2026-01-14T18:35:42","date_gmt":"2026-01-14T18:35:42","guid":{"rendered":"https:\/\/test.innovacore.group\/?post_type=portfolio&#038;p=3289"},"modified":"2026-01-15T20:49:32","modified_gmt":"2026-01-15T20:49:32","slug":"tamias","status":"publish","type":"portfolio","link":"https:\/\/test.innovacore.group\/zh-hans\/portfolio\/tamias\/","title":{"rendered":"Tamias &#8211; The First POS for Sports Communities"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Tamias is a cutting-edge Point of Sale (POS) solution designed by industry experts to merge seamless retail operations with deep community engagement. Unlike traditional systems, Tamias is uniquely built to interact with sports communities, stadiums, and events. By integrating advanced analytics, loyalty programs, and an intuitive interface, it empowers retailers and clubs to transform simple transactions into lasting fan relationships and sustainable business growth.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The first POS system powered by sports communities and advanced analytics.<\/p>\n","protected":false},"featured_media":2369,"parent":0,"template":"","meta":{"inline_featured_image":false,"company_name":"Tamias","summary":"The First POS for <span class=\"ic-nycd\">Sports Communities<\/span>","mission":"<p>To revolutionize the point of sale by turning it into a point of connection. Tamias aims to empower businesses\u2014from local cafes to major stadiums\u2014with tools that not only streamline operations but also foster deep, data-driven engagement with their communities and fans.<\/p>\n","impact":"<p>Tamias is redefining the transactional landscape by embedding social interaction directly into the checkout process. Its ability to handle high-volume sporting events while creating personalized loyalty loops allows businesses to monetize passion, making it a pivotal tool for the modern sports-retail economy.<\/p>\n","company_logo":"https:\/\/test.innovacore.group\/wp-content\/uploads\/tamias-logo-innov-innovacore-optimized.jpg","website_url":"https:\/\/tamias.com\/","linkedin_url":"https:\/\/www.linkedin.com\/company\/tamias-pos\/","location":"Norwich, UK","founded_year":"2025","key_numbers":{"item-0":{"metric_label":"+ Pop-up Stores Managed","metric_value":"320"},"item-1":{"metric_label":"Monthly Fees","metric_value":"0"},"item-2":{"metric_label":"Major Tournaments","metric_value":"2"}},"hiring_status":"stealth","sector":"fintech","company_type":"startup","audience":["b2b"],"geo_scope":["global"],"business_model":["transaction_fee"],"funding_stage":"undisclosed","partnership_type":"other","logo_animation":"<div id=\"tamias-particle-root\">\r\n    <canvas id=\"tamiasCanvas\"><\/canvas>\r\n<\/div>\r\n\r\n<style>\r\n    #tamias-particle-root {\r\n        width: 100%;\r\n        height: 300px; \/* Hauteur fixe respect\u00e9e *\/\r\n        display: flex;\r\n        justify-content: center;\r\n        align-items: center;\r\n        background: transparent;\r\n        overflow: hidden;\r\n        cursor: crosshair;\r\n    }\r\n<\/style>\r\n\r\n<script>\r\n(function() {\r\n    const canvas = document.getElementById('tamiasCanvas');\r\n    const ctx = canvas.getContext('2d', { willReadFrequently: true });\r\n    const root = document.getElementById('tamias-particle-root');\r\n    \r\n    let width, height;\r\n    let particles = [];\r\n    let mouse = { x: -1000, y: -1000 };\r\n    const particleColor = '#f5f5f5'; \/\/ Gris clair Innovacore\r\n    let time = 0;\r\n\r\n    function init() {\r\n        width = root.offsetWidth;\r\n        height = 300;\r\n        \r\n        const dpr = window.devicePixelRatio || 1;\r\n        canvas.width = width * dpr;\r\n        canvas.height = height * dpr;\r\n        canvas.style.width = width + 'px';\r\n        canvas.style.height = height + 'px';\r\n        ctx.scale(dpr, dpr);\r\n\r\n        createLogoParticles();\r\n    }\r\n\r\n    function createLogoParticles() {\r\n        particles = [];\r\n        const cx = width \/ 2;\r\n        const cy = height \/ 2;\r\n        const isMobile = width < 600;\r\n\r\n        \/\/ --- 1. CONFIGURATION ---\r\n        \/\/ Dimensions relatives\r\n        const iconSize = isMobile ? 50 : 80; \r\n        const fontSize = isMobile ? 50 : 80;\r\n        const gap = 20;\r\n\r\n        \/\/ On va dessiner en blanc pour le scan\r\n        ctx.fillStyle = 'white';\r\n        ctx.strokeStyle = 'white';\r\n        ctx.lineWidth = isMobile ? 4 : 6;\r\n        ctx.lineCap = 'round';\r\n        ctx.lineJoin = 'round';\r\n\r\n        \/\/ Typo arrondie pour \"tamias\"\r\n        ctx.font = `normal ${fontSize}px \"Arial Rounded MT Bold\", \"Varela Round\", \"Quicksand\", Arial, sans-serif`;\r\n        const textMetrics = ctx.measureText('tamias');\r\n        const textWidth = textMetrics.width;\r\n\r\n        \/\/ Calcul du centrage global (Icone + Espace + Texte)\r\n        const totalWidth = iconSize + gap + textWidth;\r\n        const startX = cx - (totalWidth \/ 2);\r\n        const startY = cy;\r\n\r\n        \/\/ --- 2. DESSIN DE L'IC\u00d4NE (L'\u00c9CUREUIL ABSTRAIT) ---\r\n        \/\/ On essaie de reproduire la forme en \"V\" courb\u00e9\r\n        const ix = startX;\r\n        const iy = cy - (iconSize * 0.2); \/\/ Remonter un peu pour aligner avec le texte\r\n\r\n        ctx.beginPath();\r\n        \/\/ Point de d\u00e9part (Haut gauche de la queue)\r\n        ctx.moveTo(ix, iy - iconSize * 0.3); \r\n        \r\n        \/\/ Courbe vers le bas (la pointe du V)\r\n        \/\/ cp1x, cp1y, cp2x, cp2y, x, y\r\n        ctx.bezierCurveTo(\r\n            ix - 5, iy + iconSize * 0.4, \/\/ Control point 1 (bomber vers l'ext\u00e9rieur gauche)\r\n            ix + iconSize * 0.2, iy + iconSize * 0.6, \/\/ Control point 2 (vers le bas)\r\n            ix + iconSize * 0.4, iy + iconSize * 0.6  \/\/ Point bas (Pointe)\r\n        );\r\n\r\n        \/\/ Courbe vers le haut (le dos\/t\u00eate)\r\n        ctx.bezierCurveTo(\r\n            ix + iconSize * 0.6, iy + iconSize * 0.6, \r\n            ix + iconSize * 0.8, iy + iconSize * 0.1, \r\n            ix + iconSize * 0.7, iy - iconSize * 0.1  \/\/ T\u00eate\r\n        );\r\n\r\n        \/\/ Petite boucle pour l'oreille\/t\u00eate (retour vers l'int\u00e9rieur)\r\n        ctx.bezierCurveTo(\r\n            ix + iconSize * 0.6, iy - iconSize * 0.2,\r\n            ix + iconSize * 0.5, iy - iconSize * 0.1,\r\n            ix + iconSize * 0.55, iy + iconSize * 0.1\r\n        );\r\n        \r\n        ctx.stroke();\r\n\r\n        \/\/ L'Oeil (Le petit point)\r\n        ctx.beginPath();\r\n        ctx.arc(ix + iconSize * 0.65, iy - iconSize * 0.05, isMobile ? 2 : 4, 0, Math.PI * 2);\r\n        ctx.fill();\r\n\r\n\r\n        \/\/ --- 3. DESSIN DU TEXTE ---\r\n        ctx.textAlign = 'left';\r\n        ctx.textBaseline = 'middle';\r\n        \/\/ On aligne le texte un peu plus bas pour qu'il soit visuellement centr\u00e9 avec l'ic\u00f4ne\r\n        ctx.fillText('tamias', startX + iconSize + gap, cy);\r\n\r\n\r\n        \/\/ --- 4. SCAN DES PIXELS ---\r\n        const density = 4;\r\n        const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height).data;\r\n        const dataWidth = canvas.width; \r\n\r\n        for (let y = 0; y < canvas.height; y += density) {\r\n            for (let x = 0; x < canvas.width; x += density) {\r\n                \/\/ Scan pixel opaque\r\n                if (imageData[(y * dataWidth + x) * 4 + 3] > 128) {\r\n                    const dpr = window.devicePixelRatio || 1;\r\n                    particles.push({\r\n                        x: x \/ dpr,\r\n                        y: y \/ dpr,\r\n                        originX: x \/ dpr,\r\n                        originY: y \/ dpr,\r\n                        vx: 0, \r\n                        vy: 0,\r\n                        size: Math.random() * 1.5 + 0.5,\r\n                        force: Math.random() \r\n                    });\r\n                }\r\n            }\r\n        }\r\n        \r\n        \/\/ Nettoyage\r\n        ctx.clearRect(0, 0, width, height);\r\n    }\r\n\r\n    function draw() {\r\n        ctx.clearRect(0, 0, width, height);\r\n        time += 0.05;\r\n\r\n        ctx.fillStyle = particleColor;\r\n        \r\n        particles.forEach(p => {\r\n            \/\/ 1. Respiration\r\n            const waveX = Math.sin(time * 0.5 + p.y * 0.05) * 2;\r\n            const waveY = Math.cos(time * 0.3 + p.x * 0.05) * 2;\r\n            \r\n            \/\/ 2. Interaction\r\n            const dx = mouse.x - p.x;\r\n            const dy = mouse.y - p.y;\r\n            const dist = Math.sqrt(dx*dx + dy*dy);\r\n            const radius = 80;\r\n            \r\n            let repelX = 0;\r\n            let repelY = 0;\r\n\r\n            if (dist < radius) {\r\n                const force = (radius - dist) \/ radius;\r\n                const angle = Math.atan2(dy, dx);\r\n                repelX = -Math.cos(angle) * force * 20;\r\n                repelY = -Math.sin(angle) * force * 20;\r\n            }\r\n\r\n            \/\/ 3. Physique\r\n            const targetX = p.originX + waveX;\r\n            const targetY = p.originY + waveY;\r\n\r\n            const ax = (targetX - p.x) * 0.08;\r\n            const ay = (targetY - p.y) * 0.08;\r\n\r\n            p.vx += ax;\r\n            p.vy += ay;\r\n            p.vx += repelX * 0.5;\r\n            p.vy += repelY * 0.5;\r\n            p.vx *= 0.85; \r\n\r\n            p.x += p.vx;\r\n            p.y += p.vy;\r\n\r\n            ctx.beginPath();\r\n            ctx.arc(p.x, p.y, p.size, 0, Math.PI * 2);\r\n            ctx.fill();\r\n        });\r\n\r\n        requestAnimationFrame(draw);\r\n    }\r\n\r\n    const updateMouse = (e) => {\r\n        const r = canvas.getBoundingClientRect();\r\n        const cx = e.touches ? e.touches[0].clientX : e.clientX;\r\n        const cy = e.touches ? e.touches[0].clientY : e.clientY;\r\n        mouse.x = cx - r.left;\r\n        mouse.y = cy - r.top;\r\n    };\r\n\r\n    window.addEventListener('resize', init);\r\n    canvas.addEventListener('mousemove', updateMouse);\r\n    canvas.addEventListener('touchmove', updateMouse, {passive: true});\r\n    canvas.addEventListener('mouseleave', () => { mouse.x = -1000; mouse.y = -1000; });\r\n    canvas.addEventListener('touchend', () => { mouse.x = -1000; mouse.y = -1000; });\r\n\r\n    setTimeout(init, 50);\r\n    draw();\r\n})();\r\n<\/script>"},"pt":[],"pipeline":[34],"class_list":["post-3289","portfolio","type-portfolio","status-publish","has-post-thumbnail","hentry","pipeline-innov"],"_links":{"self":[{"href":"https:\/\/test.innovacore.group\/zh-hans\/wp-json\/wp\/v2\/portfolio\/3289","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/test.innovacore.group\/zh-hans\/wp-json\/wp\/v2\/portfolio"}],"about":[{"href":"https:\/\/test.innovacore.group\/zh-hans\/wp-json\/wp\/v2\/types\/portfolio"}],"version-history":[{"count":2,"href":"https:\/\/test.innovacore.group\/zh-hans\/wp-json\/wp\/v2\/portfolio\/3289\/revisions"}],"predecessor-version":[{"id":3554,"href":"https:\/\/test.innovacore.group\/zh-hans\/wp-json\/wp\/v2\/portfolio\/3289\/revisions\/3554"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/test.innovacore.group\/zh-hans\/wp-json\/wp\/v2\/media\/2369"}],"wp:attachment":[{"href":"https:\/\/test.innovacore.group\/zh-hans\/wp-json\/wp\/v2\/media?parent=3289"}],"wp:term":[{"taxonomy":"pt","embeddable":true,"href":"https:\/\/test.innovacore.group\/zh-hans\/wp-json\/wp\/v2\/pt?post=3289"},{"taxonomy":"pipeline","embeddable":true,"href":"https:\/\/test.innovacore.group\/zh-hans\/wp-json\/wp\/v2\/pipeline?post=3289"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}