{"id":3913,"date":"2026-01-25T08:43:23","date_gmt":"2026-01-25T08:43:23","guid":{"rendered":"https:\/\/test.innovacore.group\/?post_type=portfolio&#038;p=3913"},"modified":"2026-01-25T08:50:11","modified_gmt":"2026-01-25T08:50:11","slug":"contribly","status":"publish","type":"portfolio","link":"https:\/\/test.innovacore.group\/it\/portfolio\/contribly\/","title":{"rendered":"Contribly &#8211; Boost Reader Engagement"},"content":{"rendered":"\n<p>Contribly is a SaaS platform born at The Guardian, designed to master Community Generated Content (CGC) at scale. It streamlines the collection, moderation, and instant publishing of user stories, photos, and videos. By turning passive readers into active contributors, Contribly saves editorial teams significant time while drastically boosting loyalty, time-on-page, and first-party data collection for publishers and brands.<\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>The SaaS platform to collect, moderate, and publish community content at scale.<\/p>\n","protected":false},"featured_media":2369,"parent":0,"template":"","meta":{"inline_featured_image":false,"company_name":"Contribly","summary":"The SaaS platform to collect, moderate, and publish community content at scale.","mission":"<p>To transform audience engagement into a strategic business asset. Contribly\u2019s mission is to help publishers build deep trust and relevance by making it effortless to include readers in the story, converting engagement into valuable first-party data and subscription growth.<\/p>\n","impact":"<p>Contribly is redefining the publisher-audience relationship by shifting from \"broadcasting\" to two-way conversation. It provides newsrooms with a \"value exchange\" model that generates algorithm-proof traffic and high-value data, essential for future-proofing media business models against reliance on social platforms.<\/p>\n","company_logo":"https:\/\/test.innovacore.group\/wp-content\/uploads\/contribly_logo-innovacore-optimized.jpg","website_url":"https:\/\/www.contribly.com\/","linkedin_url":"https:\/\/www.linkedin.com\/company\/contribly\/","location":"Northwich, UK","founded_year":"","key_numbers":{"item-0":{"metric_label":"Time on Page","metric_value":"3-10x"},"item-1":{"metric_label":"Social Engagement","metric_value":"3x"},"item-2":{"metric_label":"App Download Uplift","metric_value":"44%"}},"hiring_status":"stealth","sector":"saas","company_type":"startup","audience":["b2b"],"geo_scope":["global"],"business_model":["saas"],"funding_stage":"in_progress","partnership_type":"upgrade","logo_animation":"<div id=\"contribly-particle-root\">\r\n    <canvas id=\"contriblyCanvas\"><\/canvas>\r\n<\/div>\r\n\r\n<style>\r\n    #contribly-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('contriblyCanvas');\r\n    const ctx = canvas.getContext('2d', { willReadFrequently: true });\r\n    const root = document.getElementById('contribly-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 demand\u00e9\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 DU DESSIN ---\r\n        ctx.fillStyle = 'white';\r\n        ctx.strokeStyle = 'white';\r\n\r\n        \/\/ Dimensions relatives\r\n        \/\/ On augmente un peu la taille de l'ic\u00f4ne pour bien voir les d\u00e9tails\r\n        const iconSize = isMobile ? 60 : 100; \r\n        const fontSize = isMobile ? 35 : 60;\r\n        const gap = isMobile ? 15 : 30;\r\n\r\n        \/\/ Typo\r\n        ctx.font = `bold ${fontSize}px \"Poppins\", \"Montserrat\", Arial, sans-serif`;\r\n        const textMetrics = ctx.measureText('Contribly');\r\n        const textWidth = textMetrics.width;\r\n\r\n        \/\/ Centrage\r\n        const totalWidth = iconSize + gap + textWidth;\r\n        const startX = cx - (totalWidth \/ 2);\r\n        const centerY = cy;\r\n\r\n        \/\/ --- 2. DESSIN DE L'IC\u00d4NE (Complexe et fid\u00e8le) ---\r\n        const ix = startX;\r\n        const iy = centerY - (iconSize \/ 2);\r\n        const centerIx = ix + iconSize \/ 2;\r\n        const centerIy = iy + iconSize \/ 2;\r\n\r\n        \/\/ A. Le cadre carr\u00e9 (fin)\r\n        ctx.lineWidth = iconSize * 0.03;\r\n        ctx.strokeRect(ix, iy, iconSize, iconSize);\r\n\r\n        \/\/ B. Le Point Central (Le plus gros)\r\n        const centerDotRad = iconSize * 0.12;\r\n        ctx.beginPath();\r\n        ctx.arc(centerIx, centerIy, centerDotRad, 0, Math.PI * 2);\r\n        ctx.fill();\r\n\r\n        \/\/ C. Les Points P\u00e9riph\u00e9riques (Tailles et positions vari\u00e9es)\r\n        const networkRad = iconSize * 0.36; \/\/ Distance au centre\r\n        const bigRad = iconSize * 0.075;   \/\/ Rayon des \"gros\" points p\u00e9riph\u00e9riques\r\n        const smallRad = iconSize * 0.045; \/\/ Rayon des \"petits\" points\r\n\r\n        \/\/ D\u00e9finition manuelle des 6 points pour respecter le logo :\r\n        \/\/ Angles approximatifs en radians et taille associ\u00e9e.\r\n        const pointsDef = [\r\n            { angle: -0.4, size: smallRad }, \/\/ Haut-Droite (petit)\r\n            { angle: 0.3,  size: smallRad }, \/\/ Droite (petit)\r\n            { angle: 1.2,  size: bigRad },   \/\/ Bas-Droite (gros)\r\n            { angle: 2.6,  size: bigRad },   \/\/ Bas-Gauche (gros)\r\n            { angle: 3.5,  size: smallRad }, \/\/ Gauche (petit)\r\n            { angle: 4.5,  size: bigRad }    \/\/ Haut-Gauche (gros)\r\n        ];\r\n\r\n        ctx.lineWidth = iconSize * 0.025; \/\/ Lignes de connexion fines\r\n\r\n        pointsDef.forEach(pt => {\r\n            const px = centerIx + Math.cos(pt.angle) * networkRad;\r\n            const py = centerIy + Math.sin(pt.angle) * networkRad;\r\n\r\n            \/\/ 1. La ligne de connexion\r\n            ctx.beginPath();\r\n            ctx.moveTo(centerIx, centerIy);\r\n            ctx.lineTo(px, py);\r\n            ctx.stroke();\r\n\r\n            \/\/ 2. Le point\r\n            ctx.beginPath();\r\n            ctx.arc(px, py, pt.size, 0, Math.PI * 2);\r\n            ctx.fill();\r\n        });\r\n\r\n\r\n        \/\/ --- 3. DESSIN DU TEXTE ---\r\n        const textX = startX + iconSize + gap;\r\n        ctx.textAlign = 'left';\r\n        ctx.textBaseline = 'middle';\r\n        ctx.fillText('Contribly', textX, centerY);\r\n\r\n\r\n        \/\/ --- 4. SCAN DES PIXELS (Densit\u00e9 \u00e9lev\u00e9e pour le d\u00e9tail) ---\r\n        const density = 3;\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                        \/\/ Taille de particule l\u00e9g\u00e8rement variable pour le c\u00f4t\u00e9 \"soft\"\r\n                        size: Math.random() * 1.2 + 0.8, \r\n                    });\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        \/\/ --- PHYSIQUE \"SOFT\" ---\r\n        time += 0.02; \/\/ Vitesse d'ondulation lente\r\n\r\n        ctx.fillStyle = particleColor;\r\n        \r\n        particles.forEach(p => {\r\n            \/\/ 1. Respiration lente et ample\r\n            const waveX = Math.sin(time * 0.5 + p.y * 0.03) * 3;\r\n            const waveY = Math.cos(time * 0.4 + p.x * 0.03) * 3;\r\n            \r\n            \/\/ 2. Interaction Souris douce\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 = 100;\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                \/\/ Force mod\u00e9r\u00e9e (10) pour une r\u00e9pulsion visible mais pas violente\r\n                repelX = -Math.cos(angle) * force * 10;\r\n                repelY = -Math.sin(angle) * force * 10;\r\n            }\r\n\r\n            const targetX = p.originX + waveX;\r\n            const targetY = p.originY + waveY;\r\n\r\n            \/\/ 3. Physique fluide (Retour \u00e9lastique mou et forte friction)\r\n            const ax = (targetX - p.x) * 0.02; \/\/ Retour tr\u00e8s souple\r\n            const ay = (targetY - p.y) * 0.02;\r\n\r\n            p.vx += ax;\r\n            p.vy += ay;\r\n            p.vx += repelX * 0.2; \/\/ Application douce de la force souris\r\n            p.vy += repelY * 0.2;\r\n            \r\n            \/\/ Friction \u00e9lev\u00e9e pour l'effet \"flottant dans l'eau\"\r\n            p.vx *= 0.92; \r\n            p.vy *= 0.92;\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, 100);\r\n    draw();\r\n})();\r\n<\/script>"},"pt":[],"pipeline":[34],"class_list":["post-3913","portfolio","type-portfolio","status-publish","has-post-thumbnail","hentry","pipeline-innov"],"_links":{"self":[{"href":"https:\/\/test.innovacore.group\/it\/wp-json\/wp\/v2\/portfolio\/3913","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/test.innovacore.group\/it\/wp-json\/wp\/v2\/portfolio"}],"about":[{"href":"https:\/\/test.innovacore.group\/it\/wp-json\/wp\/v2\/types\/portfolio"}],"version-history":[{"count":1,"href":"https:\/\/test.innovacore.group\/it\/wp-json\/wp\/v2\/portfolio\/3913\/revisions"}],"predecessor-version":[{"id":3925,"href":"https:\/\/test.innovacore.group\/it\/wp-json\/wp\/v2\/portfolio\/3913\/revisions\/3925"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/test.innovacore.group\/it\/wp-json\/wp\/v2\/media\/2369"}],"wp:attachment":[{"href":"https:\/\/test.innovacore.group\/it\/wp-json\/wp\/v2\/media?parent=3913"}],"wp:term":[{"taxonomy":"pt","embeddable":true,"href":"https:\/\/test.innovacore.group\/it\/wp-json\/wp\/v2\/pt?post=3913"},{"taxonomy":"pipeline","embeddable":true,"href":"https:\/\/test.innovacore.group\/it\/wp-json\/wp\/v2\/pipeline?post=3913"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}