{"id":50017,"date":"2025-08-24T16:01:52","date_gmt":"2025-08-24T16:01:52","guid":{"rendered":"https:\/\/skdojo.com\/?p=50017"},"modified":"2025-08-26T21:38:56","modified_gmt":"2025-08-26T21:38:56","slug":"image-challenge","status":"publish","type":"post","link":"https:\/\/skdojo.com\/en\/image-challenge\/","title":{"rendered":"Challenge your Friend to Guess the Image"},"content":{"rendered":"\n<div class=\"guess-image-game\" id=\"guess-image-game-v5-stable\">\n  <div id=\"gig-creator\">\n    <div class=\"gig-card\">\n      <h3>Crie seu Desafio de Imagem<\/h3>\n      <p class=\"gig-note\" class=\"translation-block\">Coloque a URL de uma imagem que deseja para gerar um desafio de adivinha\u00e7\u00e3o para seus amigos! Envie a URL e veja se eles conseguem adivinhar do que se trata a imagem<\/p>\n      \n      <label>URL da Imagem\n        <input type=\"url\" id=\"c-img\" placeholder=\"https:\/\/exemplo.com\/imagem.jpg\" required>\n      <\/label>\n\n      <div class=\"gig-row\">\n        <div class=\"gig-col\">\n          <label>Resposta Correta\n            <input type=\"text\" id=\"c-answer\" placeholder=\"Ex.: Luffy\" required>\n          <\/label>\n        <\/div>\n        <div class=\"gig-col\">\n          <label>Outras Respostas (alias)\n            <input type=\"text\" id=\"c-aliases\" placeholder=\"Monkey D. Luffy, Mugiwara\">\n          <\/label>\n        <\/div>\n      <\/div>\n\n      <details class=\"gig-details\" open>\n        <summary>Regras do Jogo<\/summary>\n        <div class=\"gig-row\">\n          <div class=\"gig-col\"><label>Segundos Totais <input type=\"number\" id=\"c-tseconds\" value=\"90\" min=\"10\"><\/label><\/div>\n          <div class=\"gig-col\"><label>Tentativas M\u00e1ximas <input type=\"number\" id=\"c-maxatt\" value=\"12\" min=\"2\"><\/label><\/div>\n        <\/div>\n      <\/details>\n\n      <div class=\"gig-actions\">\n        <button id=\"c-generate\">Gerar Link do Jogo<\/button>\n      <\/div>\n      <div class=\"gig-result hidden\" id=\"c-urlbox\">\n        <input type=\"text\" id=\"c-url\" readonly>\n        <button id=\"c-copy\" class=\"secondary\">Copiar<\/button>\n      <\/div>\n    <\/div>\n  <\/div>\n\n  <div id=\"gig-game\" class=\"hidden\">\n    <div class=\"gig-card\">\n      <div class=\"gig-topbar\">\n        <div>Tempo: <span id=\"g-time\">0<\/span><\/div>\n        <div>Tentativas: <span id=\"g-attempts\">0<\/span>\/<span id=\"g-max\">0<\/span><\/div>\n      <\/div>\n\n      <div class=\"gig-stage\">\n        <div class=\"gig-imgwrap\">\n          <div id=\"g-view\" class=\"gig-pixelbox\"><\/div>\n        <\/div>\n      <\/div>\n\n      <div class=\"gig-input\">\n        <input type=\"text\" id=\"g-guess\" placeholder=\"Seu palpite...\" autocomplete=\"off\">\n        <button id=\"g-btn\">Chutar<\/button>\n      <\/div>\n      \n      <div class=\"gig-actions\" id=\"g-color-action-wrapper\"><\/div>\n\n      <div id=\"g-feedback\" class=\"gig-feedback\"><\/div>\n      <div id=\"g-done\" class=\"gig-done hidden\">BOA! Voc\u00ea acertou!<\/div>\n\n      <details class=\"gig-details\">\n        <summary>Op\u00e7\u00f5es<\/summary>\n        <button id=\"g-giveup\" class=\"secondary\">Desistir<\/button>\n        <button id=\"g-share\" class=\"secondary\">Copiar link<\/button>\n      <\/details>\n    <\/div>\n  <\/div>\n<\/div>\n\n\n\n<style>\/* CSS para Guess Image Game v5-stable *\/\n.guess-image-game {\n  --border: #e5e7eb; --bg: #fff; --muted: #6b7280; --accent: #0ea5e9; --ok: #10b981;\n  font-family: system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif;\n  color: #111827;\n}\n.guess-image-game * { box-sizing: border-box; }\n.guess-image-game .hidden { display: none !important; }\n\n.guess-image-game .gig-card { background: var(--bg); border: 1px solid var(--border); border-radius: .5rem; padding: 1rem; max-width: 640px; margin: auto; }\n.guess-image-game h3 { margin-top: 0; }\n.guess-image-game .gig-note { color: var(--muted); margin: -0.5rem 0 1rem; font-size: 0.9rem; }\n.guess-image-game label { display: block; margin: .5rem 0; font-weight: 500; }\n.guess-image-game input, .guess-image-game button { width: 100%; padding: .6rem .7rem; border: 1px solid var(--border); border-radius: .4rem; font: inherit; background: #fff; color: #111827; }\n.guess-image-game input:focus { outline: 2px solid var(--accent); border-color: var(--accent); }\n.guess-image-game button { font-weight: 600; cursor: pointer; transition: opacity 0.2s; }\n.guess-image-game button:hover { opacity: 0.85; }\n#c-generate, #g-btn { background-color: var(--accent); color: #fff; border-color: var(--accent); }\n.guess-image-game .secondary { background-color: #f9fafb; color: #374151; }\n\n.guess-image-game .gig-row { display: flex; gap: .75rem; flex-wrap: wrap; }\n.guess-image-game .gig-col { flex: 1; min-width: 180px; }\n.guess-image-game .gig-actions { display: flex; gap: .75rem; margin-top: .75rem; }\n.guess-image-game .gig-result { margin-top: .75rem; display: flex; gap: .5rem; }\n\n.guess-image-game .gig-topbar { display: flex; justify-content: space-between; margin-bottom: .5rem; font-weight: 600; }\n.guess-image-game .gig-stage { display: flex; justify-content: center; align-items: center; min-height: 260px; padding: .5rem; }\n.guess-image-game .gig-imgwrap { width: 100%; aspect-ratio: 16\/9; overflow: hidden; border-radius: .5rem; border: 1px solid var(--border); background: #f3f4f6; }\n.guess-image-game .gig-pixelbox { width: 100%; height: 100%; background-position: center; background-repeat: no-repeat; background-size: cover; transition: transform .4s ease, filter .4s ease; }\n\n.guess-image-game .gig-input { display: flex; gap: .5rem; margin-top: .75rem; }\n.guess-image-game .gig-input input { flex: 1; }\n.guess-image-game .gig-input button { width: auto; flex: 0 0 120px; }\n\n.guess-image-game .gig-feedback { min-height: 1.25rem; color: var(--muted); margin-top: .4rem; }\n.guess-image-game .gig-done { margin-top: .75rem; padding: .75rem; border-radius: .4rem; background: #f0fdf4; border: 1px solid #bbf7d0; color: #14532d; }\n.guess-image-game .gig-details { margin-top: 1rem; }<\/style>\n\n\n\n<script>\/* Guess Image Game v5 \u2014 Vers\u00e3o Est\u00e1vel e Simplificada\n   - L\u00f3gica de efeitos padronizada para previsibilidade.\n   - Removida a pixeliza\u00e7\u00e3o e configura\u00e7\u00f5es complexas.\n   - Adicionado bot\u00e3o estrat\u00e9gico para revelar cores.\n   - C\u00f3digo focado em estabilidade e divers\u00e3o.\n*\/\n(() => {\n  \"use strict\";\n\n  \/\/ ========== Utils ==========\n  const $ = (sel) => document.querySelector(sel);\n  const te = new TextEncoder();\n  const normalize = (s) => s.toString().trim().toLowerCase()\n    .normalize('NFD').replace(\/\\p{Diacritic}\/gu, '').replace(\/[\\s\\-_]+\/g, ' ')\n    .replace(\/[^\\p{Letter}\\p{Number}\\s]\/gu, '').trim();\n  async function sha256Hex(str) {\n    const buf = await crypto.subtle.digest('SHA-256', te.encode(str));\n    return [...new Uint8Array(buf)].map(b => b.toString(16).padStart(2, '0')).join('');\n  }\n  function randHex(bytes = 8) {\n    const a = new Uint8Array(bytes); crypto.getRandomValues(a);\n    return [...a].map(b => b.toString(16).padStart(2, '0')).join('');\n  }\n  const b64u = {\n    enc: (str) => btoa(unescape(encodeURIComponent(str))).replace(\/\\+\/g, '-').replace(\/\\\/\/g, '_').replace(\/=+$\/, ''),\n    dec: (b64) => decodeURIComponent(escape(atob(b64.replace(\/-\/g, '+').replace(\/_\/g, '\/') + '==='.slice((b64.length + 3) % 4))))\n  };\n  const fire = (code, extra = {}) => {\n    document.dispatchEvent(new CustomEvent('gig:status', { detail: { code, ...extra } }));\n  };\n\n  \/\/ ========== Engine de Efeitos Simplificada ==========\n  function getEffectState(attempt, maxAttempts, colored) {\n    const progress = Math.min(1, attempt \/ (maxAttempts - 1)); \/\/ Progresso de 0.0 a 1.0\n    const state = {};\n\n    \/\/ Zoom: Come\u00e7a em 3.5x e vai para 1x\n    state.scale = 1 + (1 - progress) * 2.5;\n    \/\/ Blur: Come\u00e7a em 8px e vai para 0px\n    state.blur = (1 - progress) * 8;\n    \/\/ Rota\u00e7\u00e3o: Come\u00e7a em 45 graus e vai para 0\n    state.rot = (1 - progress) * 45;\n    \/\/ Cor: \u00c9 1 (preto e branco) at\u00e9 ser revelada\n    state.gray = colored ? 0 : 1;\n    \n    return state;\n  }\n\n  function applyStateToBox(box, imgUrl, st) {\n    if (!box) return;\n    box.style.backgroundImage = `url(\"${imgUrl}\")`;\n    box.style.filter = `grayscale(${st.gray}) blur(${st.blur}px)`;\n    box.style.transform = `scale(${st.scale}) rotate(${st.rot}deg)`;\n  }\n\n  \/\/ ========== Criador ==========\n  function initCreator() {\n    const ui = {\n      img: $('#c-img'),\n      ans: $('#c-answer'),\n      aliases: $('#c-aliases'),\n      tseconds: $('#c-tseconds'),\n      maxatt: $('#c-maxatt'),\n      gen: $('#c-generate'),\n      urlBox: $('#c-urlbox'),\n      urlOut: $('#c-url'),\n      copy: $('#c-copy')\n    };\n\n    ui.gen?.addEventListener('click', async () => {\n      const img = (ui.img?.value || '').trim();\n      const answer = (ui.ans?.value || '').trim();\n      if (!img || !answer) return alert('Por favor, preencha a URL da imagem e a resposta.');\n\n      const aliases = (ui.aliases?.value || '').split(',').map(s => s.trim()).filter(Boolean);\n      const salt = randHex(8);\n      const secrets = await Promise.all([answer, ...aliases].map(normalize).filter(Boolean).map(v => sha256Hex(salt + '|' + v)));\n\n      const payload = {\n        v: 5, \/\/ Vers\u00e3o do jogo\n        img,\n        s: salt,\n        a: secrets,\n        mx: Math.max(1, parseInt(ui.maxatt?.value ?? '10', 10)),\n        ts: Math.max(10, parseInt(ui.tseconds?.value ?? '90', 10)),\n      };\n\n      const packed = b64u.enc(JSON.stringify(payload));\n      ui.urlOut.value = `${location.origin}${location.pathname}#${packed}`;\n      ui.urlBox.classList.remove('hidden');\n    });\n\n    ui.copy?.addEventListener('click', () => {\n      ui.urlOut.select();\n      document.execCommand('copy');\n      alert('Link copiado!');\n    });\n  }\n\n  \/\/ ========== Jogo ==========\n  function initGame(packed) {\n    $('#gig-creator')?.classList.add('hidden');\n    $('#gig-game')?.classList.remove('hidden');\n\n    let data;\n    try { data = JSON.parse(b64u.dec(packed)); } \n    catch (e) { return alert('Link do jogo inv\u00e1lido ou corrompido.'); }\n\n    const COLOR_REVEAL_ATTEMPT = 5;\n    const game = {\n      running: true,\n      attempts: 0,\n      maxAttempts: data.mx,\n      seconds: data.ts,\n      isColored: false,\n      startTime: Date.now(),\n    };\n\n    const ui = {\n      view: $('#g-view'),\n      time: $('#g-time'),\n      attempts: $('#g-attempts'),\n      max: $('#g-max'),\n      guess: $('#g-guess'),\n      btn: $('#g-btn'),\n      done: $('#g-done'),\n      feedback: $('#g-feedback'),\n      giveup: $('#g-giveup'),\n      share: $('#g-share'),\n      colorActionWrapper: $('#g-color-action-wrapper'),\n    };\n\n    function render() {\n      const st = getEffectState(game.attempts, game.maxAttempts, game.isColored);\n      applyStateToBox(ui.view, data.img, st);\n      ui.attempts.textContent = game.attempts;\n      ui.max.textContent = game.maxAttempts;\n\n      \/\/ L\u00f3gica do bot\u00e3o de colorir\n      if (game.attempts >= COLOR_REVEAL_ATTEMPT && !game.isColored && game.running) {\n          if (!ui.colorActionWrapper.hasChildNodes()) { \/\/ Adiciona o bot\u00e3o apenas uma vez\n              const colorBtn = document.createElement('button');\n              colorBtn.textContent = 'Revelar Cores (custa 1 tentativa)';\n              colorBtn.className = 'secondary';\n              colorBtn.onclick = () => {\n                  game.isColored = true;\n                  ui.colorActionWrapper.innerHTML = ''; \/\/ Remove o bot\u00e3o ap\u00f3s o uso\n                  applyWrong(false, true); \/\/ Aplica o erro, mas marca que foi pela cor\n              };\n              ui.colorActionWrapper.appendChild(colorBtn);\n          }\n      } else {\n          ui.colorActionWrapper.innerHTML = ''; \/\/ Garante que o wrapper esteja limpo se as condi\u00e7\u00f5es n\u00e3o forem atendidas\n      }\n    }\n    \n    const tick = () => {\n        if (!game.running) return;\n        const elapsed = Math.floor((Date.now() - game.startTime) \/ 1000);\n        const remaining = game.seconds - elapsed;\n        ui.time.textContent = remaining;\n        if (remaining <= 0) end(false, 'Tempo esgotado.');\n    };\n    const timer = setInterval(tick, 1000);\n\n    async function onGuess() {\n      if (!game.running) return;\n      const guessValue = normalize(ui.guess.value);\n      if (!guessValue) return;\n      ui.guess.value = '';\n\n      const h = await sha256Hex(data.s + '|' + guessValue);\n      if (data.a.includes(h)) {\n        end(true, 'BOA! Voc\u00ea acertou!');\n      } else {\n        applyWrong(false);\n      }\n    }\n    \n    function applyWrong(fromTimer = false, fromColorReveal = false) {\n      if (game.attempts >= game.maxAttempts) {\n        end(false, 'Acabaram as tentativas.');\n        return;\n      }\n      \n      game.attempts++;\n      ui.feedback.textContent = fromColorReveal ? 'Cores reveladas!' : 'Errado! A imagem melhorou um pouco...';\n      \n      if (game.attempts >= game.maxAttempts) {\n          render(); \/\/ Renderiza o \u00faltimo estado antes de finalizar\n          end(false, 'Acabaram as tentativas.');\n      } else {\n          render();\n      }\n    }\n\n    function end(win, message) {\n      if (!game.running) return;\n      game.running = false;\n      clearInterval(timer);\n      \n      ui.feedback.textContent = '';\n      ui.done.textContent = message;\n      ui.done.classList.remove('hidden');\n      ui.guess.disabled = true;\n      ui.btn.disabled = true;\n      ui.colorActionWrapper.innerHTML = '';\n\n      if (win) {\n        applyStateToBox(ui.view, data.img, getEffectState(game.maxAttempts, game.maxAttempts, true));\n      }\n    }\n\n    ui.btn.addEventListener('click', onGuess);\n    ui.guess.addEventListener('keydown', e => e.key === 'Enter' && onGuess());\n    ui.giveup.addEventListener('click', () => end(false, 'Voc\u00ea desistiu.'));\n    ui.share.addEventListener('click', () => {\n        navigator.clipboard.writeText(location.href).then(() => alert('Link copiado!'));\n    });\n    \n    render();\n    tick();\n  }\n\n  \/\/ ========== Boot ==========\n  if (location.hash && location.hash.length > 1) {\n    initGame(location.hash.slice(1));\n  } else {\n    initCreator();\n  }\n})();<\/script>\n\n\n\n<p class=\"translation-block\">O que acha de desafiar seus amigos criando seu pr\u00f3prio jogo de adivinhar o personagem, lugar ou objeto da imagem? Nessa p\u00e1gina voc\u00ea envia a URL da imagem e adiciona os par\u00e2metros para gerar um link de desafio para seus amigos. <\/p>\n\n\n\n<p class=\"translation-block\"> Se quer ver se seu amigo \u00e9 bom das vistas ou dos palpites, voc\u00ea pode pegar a foto de um personagem, uma atriz ou qualquer coisa, deixa-la desafiadora e fazer com que seu amigo tente acerta-la. Ser\u00e1 que ele consegue? <\/p>\n","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":49527,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3],"tags":[],"class_list":["post-50017","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-apps","generate-columns","tablet-grid-50","mobile-grid-100","grid-parent","grid-25","no-featured-image-padding"],"_links":{"self":[{"href":"https:\/\/skdojo.com\/en\/wp-json\/wp\/v2\/posts\/50017","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/skdojo.com\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/skdojo.com\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/skdojo.com\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/skdojo.com\/en\/wp-json\/wp\/v2\/comments?post=50017"}],"version-history":[{"count":41,"href":"https:\/\/skdojo.com\/en\/wp-json\/wp\/v2\/posts\/50017\/revisions"}],"predecessor-version":[{"id":50083,"href":"https:\/\/skdojo.com\/en\/wp-json\/wp\/v2\/posts\/50017\/revisions\/50083"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/skdojo.com\/en\/wp-json\/wp\/v2\/media\/49527"}],"wp:attachment":[{"href":"https:\/\/skdojo.com\/en\/wp-json\/wp\/v2\/media?parent=50017"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/skdojo.com\/en\/wp-json\/wp\/v2\/categories?post=50017"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/skdojo.com\/en\/wp-json\/wp\/v2\/tags?post=50017"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}