{"id":3310,"date":"2026-01-14T20:49:24","date_gmt":"2026-01-14T20:49:24","guid":{"rendered":"https:\/\/test.innovacore.group\/?post_type=portfolio&#038;p=3310"},"modified":"2026-01-16T18:15:06","modified_gmt":"2026-01-16T18:15:06","slug":"shopisan","status":"publish","type":"portfolio","link":"https:\/\/test.innovacore.group\/ar\/portfolio\/shopisan\/","title":{"rendered":"Shopisan &#8211; Revitalizing Local Retail"},"content":{"rendered":"\n<p>Shopisan is the first private &#8220;local attention operator&#8221; dedicated to revitalizing city center commerce. By combining physical event management with a digital platform (Live &amp; Replay), they transform passive retail spaces into dynamic, traffic-generating hubs. Their B2B model aligns the interests of merchants, cities, and private partners to create &#8220;Shopisan Weeks&#8221;\u2014industrialized promotional events that boost footfall and sales while digitizing local inventory.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The European standard for local retail activation, merging physical events with live shopping.<\/p>\n","protected":false},"featured_media":2369,"parent":0,"template":"","meta":{"inline_featured_image":false,"company_name":"Shopisan","summary":"<span class=\"ic-nycd\">Revitalizing<\/span> Local Retail","mission":"<p>To turn the crisis of local retail into a sustainable asset. Shopisan aims to be the operational arm that public authorities lack, providing a turnkey solution that brings conviviality, digital visibility, and commercial dynamism back to city centers, benefiting independent merchants and local communities alike.<\/p>\n","impact":"<p>Shopisan addresses the \"silent crisis\" of retail vacancies by maximizing existing commercial real estate rather than building new structures (land sobriety). By professionalizing local commerce promotion, they relocalize consumption, support sustainable segments (second-hand, local artisans), and rebuild social ties in urban areas.<\/p>\n","company_logo":"https:\/\/test.innovacore.group\/wp-content\/uploads\/shopisan-logo-innov-innovacore-optimized.jpg","website_url":"","linkedin_url":"","location":"Paris, France","founded_year":"2026","key_numbers":{"item-0":{"metric_label":"K+ Sales Points Target","metric_value":"270"},"item-1":{"metric_label":"% B2B &amp; B2C Model","metric_value":"100"},"item-2":{"metric_label":"% Target EBITDA","metric_value":"20"}},"hiring_status":"hiring","sector":"marketplace","company_type":"startup","audience":["b2b_a_b2c"],"geo_scope":["national"],"business_model":["marketplace","services"],"funding_stage":"in_progress","partnership_type":"creation","logo_animation":"<div id=\"shopisan-particle-root\">\r\n    <canvas id=\"shopisanCanvas\"><\/canvas>\r\n<\/div>\r\n\r\n<style>\r\n    #shopisan-particle-root {\r\n        width: 100%;\r\n        height: 300px;\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('shopisanCanvas');\r\n    const ctx = canvas.getContext('2d', { willReadFrequently: true });\r\n    const root = document.getElementById('shopisan-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';\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        ctx.fillStyle = 'white';\r\n        ctx.strokeStyle = 'white';\r\n        \r\n        const iconSize = isMobile ? 60 : 90;\r\n        const fontSize = isMobile ? 35 : 60;\r\n        const separatorH = isMobile ? 50 : 80;\r\n        const gap = isMobile ? 20 : 35;\r\n\r\n        ctx.font = `bold ${fontSize}px Arial, Helvetica, sans-serif`;\r\n        const textMetrics = ctx.measureText('SHOPISAN');\r\n        const textWidth = textMetrics.width;\r\n\r\n        const totalWidth = iconSize + gap + 2 + gap + textWidth;\r\n        const startX = cx - (totalWidth \/ 2);\r\n\r\n        \/\/ --- 2. DESSIN DU GABARIT (Invisible) ---\r\n        const ix = startX + (iconSize \/ 2);\r\n        const iy = cy - (iconSize * 0.1);\r\n        const radius = iconSize * 0.35;\r\n        \r\n        ctx.lineWidth = iconSize * 0.08;\r\n        ctx.lineCap = 'round';\r\n        ctx.lineJoin = 'round';\r\n\r\n        \/\/ S\r\n        ctx.font = `bold ${iconSize * 0.5}px Arial, sans-serif`;\r\n        ctx.textAlign = 'center';\r\n        ctx.textBaseline = 'middle';\r\n        ctx.fillText('S', ix, iy);\r\n\r\n        \/\/ Arcs\r\n        ctx.beginPath();\r\n        ctx.arc(ix, iy, radius * 0.8, Math.PI, 0); \r\n        ctx.stroke();\r\n        ctx.beginPath();\r\n        ctx.arc(ix, iy, radius * 1.3, Math.PI, 0); \r\n        ctx.stroke();\r\n\r\n        \/\/ Pointe\r\n        ctx.beginPath();\r\n        ctx.moveTo(ix - radius * 0.8, iy + 5);\r\n        ctx.lineTo(ix, iy + iconSize * 0.5);\r\n        ctx.lineTo(ix + radius * 0.8, iy + 5);\r\n        ctx.stroke();\r\n        ctx.beginPath();\r\n        ctx.moveTo(ix - radius * 1.3, iy + 5);\r\n        ctx.lineTo(ix, iy + iconSize * 0.8);\r\n        ctx.lineTo(ix + radius * 1.3, iy + 5);\r\n        ctx.stroke();\r\n\r\n        \/\/ Barre\r\n        const lineX = startX + iconSize + gap;\r\n        ctx.lineWidth = 2;\r\n        ctx.beginPath();\r\n        ctx.moveTo(lineX, cy - separatorH \/ 2);\r\n        ctx.lineTo(lineX, cy + separatorH \/ 2);\r\n        ctx.stroke();\r\n\r\n        \/\/ Texte\r\n        const textX = lineX + gap;\r\n        ctx.textAlign = 'left';\r\n        ctx.fillStyle = 'white';\r\n        ctx.font = `bold ${fontSize}px Arial, Helvetica, sans-serif`;\r\n        ctx.fillText('SHOPISAN', textX, cy);\r\n\r\n        \/\/ --- 3. SCAN ---\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                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        ctx.clearRect(0, 0, width, height);\r\n    }\r\n\r\n    function draw() {\r\n        ctx.clearRect(0, 0, width, height);\r\n        \r\n        \/\/ MODIF 1 : Animation de vague beaucoup plus lente\r\n        time += 0.02; \/\/ Avant c'\u00e9tait 0.05\r\n\r\n        ctx.fillStyle = particleColor;\r\n        \r\n        particles.forEach(p => {\r\n            \/\/ Vague douce\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            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                \r\n                \/\/ MODIF 2 : R\u00e9pulsion beaucoup plus douce (8 au lieu de 20)\r\n                repelX = -Math.cos(angle) * force * 8;\r\n                repelY = -Math.sin(angle) * force * 8;\r\n            }\r\n\r\n            const targetX = p.originX + waveX;\r\n            const targetY = p.originY + waveY;\r\n\r\n            \/\/ MODIF 3 : Retour \u00e0 la position tr\u00e8s souple (0.03 au lieu de 0.08)\r\n            const ax = (targetX - p.x) * 0.03;\r\n            const ay = (targetY - p.y) * 0.03;\r\n\r\n            p.vx += ax;\r\n            p.vy += ay;\r\n            p.vx += repelX * 0.3; \/\/ On applique aussi moins de force souris\r\n            p.vy += repelY * 0.3;\r\n            \r\n            \/\/ MODIF 4 : Friction plus \u00e9lev\u00e9e pour que \u00e7a \"glisse\" (0.90 au lieu de 0.85)\r\n            p.vx *= 0.90; \r\n            p.vy *= 0.90;\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-3310","portfolio","type-portfolio","status-publish","has-post-thumbnail","hentry","pipeline-innov"],"_links":{"self":[{"href":"https:\/\/test.innovacore.group\/ar\/wp-json\/wp\/v2\/portfolio\/3310","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/test.innovacore.group\/ar\/wp-json\/wp\/v2\/portfolio"}],"about":[{"href":"https:\/\/test.innovacore.group\/ar\/wp-json\/wp\/v2\/types\/portfolio"}],"version-history":[{"count":1,"href":"https:\/\/test.innovacore.group\/ar\/wp-json\/wp\/v2\/portfolio\/3310\/revisions"}],"predecessor-version":[{"id":3311,"href":"https:\/\/test.innovacore.group\/ar\/wp-json\/wp\/v2\/portfolio\/3310\/revisions\/3311"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/test.innovacore.group\/ar\/wp-json\/wp\/v2\/media\/2369"}],"wp:attachment":[{"href":"https:\/\/test.innovacore.group\/ar\/wp-json\/wp\/v2\/media?parent=3310"}],"wp:term":[{"taxonomy":"pt","embeddable":true,"href":"https:\/\/test.innovacore.group\/ar\/wp-json\/wp\/v2\/pt?post=3310"},{"taxonomy":"pipeline","embeddable":true,"href":"https:\/\/test.innovacore.group\/ar\/wp-json\/wp\/v2\/pipeline?post=3310"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}