{"id":522,"date":"2026-07-30T14:08:31","date_gmt":"2026-07-30T14:08:31","guid":{"rendered":"https:\/\/wheelnames.org\/?page_id=522"},"modified":"2026-08-11T20:51:17","modified_gmt":"2026-08-11T20:51:17","slug":"ruleta-de-decisiones","status":"publish","type":"page","link":"https:\/\/wheelnames.org\/es\/ruleta-de-decisiones\/","title":{"rendered":"Ruleta de Decisiones"},"content":{"rendered":"<section class=\"wn-hero\" aria-labelledby=\"ruleta-de-decisiones-title\"><span class=\"wn-eyebrow\">Ruleta de decisiones gratis<\/span><h1 id=\"ruleta-de-decisiones-title\">Ruleta de Decisiones<\/h1><p class=\"wn-lead\">La Ruleta de Decisiones convierte una lista de alternativas v\u00e1lidas en una elecci\u00f3n r\u00e1pida, visual y transparente. A\u00f1ade las opciones que aceptar\u00edas, elimina las no disponibles y obt\u00e9n una selecci\u00f3n al azar.<\/p><div class=\"wnx-config\" data-title=\"Usa la Ruleta de Decisiones\" data-mode=\"standard\" data-items=\"Opci\u00f3n A~Opci\u00f3n B~Opci\u00f3n C~Opci\u00f3n D~Opci\u00f3n E~Opci\u00f3n F\" data-palette=\"#6366f1,#8b5cf6,#ec4899,#f97316,#14b8a6,#3b82f6\" data-count=\"1\" hidden><\/div><\/section>\n<section class=\"wnx-spinner\" aria-label=\"Interactive spinning wheel\">\n  <div class=\"wnx-toolbar\">\n    <div class=\"wnx-actions\">\n      <button class=\"wnx-btn wnx-share\" type=\"button\">Share<\/button>\n      <button class=\"wnx-btn wnx-export wnx-wide\" type=\"button\">Export CSV<\/button>\n      <button class=\"wnx-btn wnx-fullscreen\" type=\"button\">Fullscreen<\/button>\n      <button class=\"wnx-btn wnx-hide-panel\" type=\"button\">Hide Panel<\/button>\n    <\/div>\n  <\/div>\n\n  <div class=\"wnx-layout\">\n    <section class=\"wnx-stage\">\n      <h2 class=\"wnx-title\">Wheel of Names<\/h2>\n      <div class=\"wnx-wheelbox\">\n        <div class=\"wnx-pointer\" aria-hidden=\"true\"><\/div>\n        \n      <\/div>\n      <button class=\"wnx-spin\" type=\"button\">SPIN THE WHEEL<\/button>\n      <div class=\"wnx-badges\">\n        <span class=\"wnx-badge wnx-badge-elimination\">Elimination: OFF<\/span>\n        <span class=\"wnx-badge wnx-badge-accumulation\">Accumulation: OFF<\/span>\n        <span class=\"wnx-badge wnx-badge-auto\">Auto-Spin: OFF<\/span>\n        <span class=\"wnx-badge wnx-badge-smart\">Fair Rotation: OFF<\/span>\n      <\/div>\n      <div class=\"wnx-result\" aria-live=\"polite\">Add entries and spin the wheel.<\/div>\n    <\/section>\n\n    <aside class=\"wnx-panel\">\n      <div class=\"wnx-tabs\">\n        <button class=\"wnx-tab is-active\" type=\"button\" data-tab=\"entries\">Entries<\/button>\n        <button class=\"wnx-tab\" type=\"button\" data-tab=\"design\">Design<\/button>\n        <button class=\"wnx-tab wnx-tab-images\" type=\"button\" data-tab=\"images\">Images<\/button>\n        <button class=\"wnx-tab wnx-tab-smart\" type=\"button\" data-tab=\"smart\">Smart \u2726<\/button>\n        <button class=\"wnx-tab\" type=\"button\" data-tab=\"history\">History<\/button>\n      <\/div>\n\n      <section class=\"wnx-pane is-active\" data-pane=\"entries\">\n        <div class=\"wnx-add\">\n          \n          <button class=\"wnx-btn wnx-add-button\" type=\"button\">+<\/button>\n        <\/div>\n        <div class=\"wnx-tools\">\n          <button class=\"wnx-btn wnx-undo\" type=\"button\">Undo<\/button>\n          <button class=\"wnx-btn wnx-redo\" type=\"button\">Redo<\/button>\n          <button class=\"wnx-btn wnx-shuffle\" type=\"button\">Shuffle<\/button>\n          <button class=\"wnx-btn wnx-clear\" type=\"button\">Clear<\/button>\n          <label class=\"wnx-upload\">Upload CSV<\/label>\n        <\/div>\n        <textarea class=\"wnx-bulk\"><\/textarea>\n        <button class=\"wnx-btn wnx-apply\" type=\"button\">Apply List<\/button>\n        <ul class=\"wnx-list\"><\/ul>\n      <\/section>\n\n      <section class=\"wnx-pane\" data-pane=\"design\">\n        <div class=\"wnx-field\"><label>Color palette<\/label><div class=\"wnx-palettes\"><\/div><\/div>\n        <div class=\"wnx-field\"><label>Spin duration: <span class=\"wnx-duration-text\">4<\/span> seconds<\/label><\/div>\n        <div class=\"wnx-checks\">\n          <label> Elimination mode<\/label>\n          <label> Accumulation mode<\/label>\n          <label> Auto-spin<\/label>\n        <\/div>\n        <div class=\"wnx-field wnx-multi-field\"><label>Unique winners<\/label><\/div>\n      <\/section>\n\n      <section class=\"wnx-pane\" data-pane=\"images\">\n        <div class=\"wnx-image-card\">\n          <h3>Wheel background image<\/h3>\n          <p>Add one image behind the colored wheel slices.<\/p>\n          <label class=\"wnx-upload wnx-image-upload\">Choose background<\/label>\n          <div class=\"wnx-image-row\"><label>Image visibility<\/label><\/div>\n          <div class=\"wnx-image-actions\"><button class=\"wnx-btn wnx-remove-bg\" type=\"button\" disabled>Remove background<\/button><span class=\"wnx-bg-status\">No image selected<\/span><\/div>\n        <\/div>\n\n        <div class=\"wnx-image-card\">\n          <h3>Center image or logo<\/h3>\n          <p>Place a logo, icon, or photo inside the center hub.<\/p>\n          <label class=\"wnx-upload wnx-image-upload\">Choose center image<\/label>\n          <div class=\"wnx-image-row\"><label>Center image size<\/label><\/div>\n          <div class=\"wnx-image-actions\"><button class=\"wnx-btn wnx-remove-center\" type=\"button\" disabled>Remove center image<\/button><span class=\"wnx-center-status\">No image selected<\/span><\/div>\n        <\/div>\n\n        <div class=\"wnx-image-card\">\n          <h3>Image as a wheel entry<\/h3>\n          <p>Add an image-backed slice with an editable text label.<\/p>\n          \n          <label class=\"wnx-upload wnx-image-upload\">Choose entry image<\/label>\n          <div class=\"wnx-entry-image-preview\" hidden><img alt=\"Selected entry image preview\"><span><\/span><\/div>\n          <button class=\"wnx-btn wnx-add-image-entry\" type=\"button\" disabled>Add image entry<\/button>\n        <\/div>\n\n        <button class=\"wnx-btn wnx-reset-images\" type=\"button\">Reset all images<\/button>\n        <p class=\"wnx-image-note\">Images are optimized and kept in this browser session. They are not included in shared URLs or CSV exports.<\/p>\n      <\/section>\n\n      <section class=\"wnx-pane\" data-pane=\"smart\">\n        <div class=\"wnx-smart-card\">\n          <h3>Smart Fair Rotation<\/h3>\n          <label class=\"wnx-smart-toggle\"> Prioritize least-selected entries<\/label>\n          <div class=\"wnx-smart-row\"><label>Winner cooldown<\/label>Off1 spin2 spins3 spins4 spins5 spins<\/div>\n          <p class=\"wnx-smart-status\">Pure random mode is active.<\/p>\n          <div class=\"wnx-smart-metrics\"><div><b class=\"wnx-balance-score\">100%<\/b><span>balance score<\/span><\/div><div><b class=\"wnx-smart-spins\">0<\/b><span>tracked spins<\/span><\/div><\/div>\n          <div class=\"wnx-smart-counts\"><\/div>\n          <button class=\"wnx-btn wnx-smart-reset\" type=\"button\">Reset Smart Stats<\/button>\n        <\/div>\n        <div class=\"wnx-smart-card\">\n          <h3>Cryptographic Draw Receipt<\/h3>\n          <p>Creates a tamper-evident record of the result, timestamp, entries and active modes.<\/p>\n          <code class=\"wnx-receipt-id\">No receipt yet<\/code>\n          <div class=\"wnx-smart-buttons\"><button class=\"wnx-btn wnx-copy-receipt\" type=\"button\" disabled>Copy Receipt<\/button><button class=\"wnx-btn wnx-download-receipt\" type=\"button\" disabled>Download JSON<\/button><\/div>\n        <\/div>\n      <\/section>\n\n      <section class=\"wnx-pane\" data-pane=\"history\"><ol class=\"wnx-history\"><\/ol><p class=\"wnx-empty\">No spins yet.<\/p><\/section>\n    <\/aside>\n  <\/div>\n\n\n(()=&gt;{\n  const r=document.currentScript.closest(&#8216;.wnx-spinner&#8217;);\n  if(!r||r.dataset.ready)return;\n  r.dataset.ready=&#8217;1&#8242;;\n\n  const $=s=&gt;r.querySelector(s),$$=s=&gt;[&#8230;r.querySelectorAll(s)];\n  const params=new URLSearchParams(location.search),cfg=document.querySelector(&#8216;.wnx-config&#8217;);\n  const mode=cfg?.dataset.mode||r.dataset.mode||&#8217;standard&#8217;;\n  const title=cfg?.dataset.title||r.dataset.title||document.querySelector(&#8216;.wn-page h1&#8242;)?.textContent||&#8217;Wheel of Names&#8217;;\n  const raw=params.get(&#8216;wnitems&#8217;)||cfg?.dataset.items||r.dataset.items||&#8217;Alice~Bob~Charlie~David~Eve~Frank&#8217;;\n  const palettes=[\n    ((cfg?.dataset.palette)||r.dataset.palette||\u00bb).split(&#8216;,&#8217;).filter(Boolean),\n    [&#8216;#6366f1&#8242;,&#8217;#8b5cf6&#8242;,&#8217;#ec4899&#8242;,&#8217;#f97316&#8242;,&#8217;#14b8a6&#8242;,&#8217;#3b82f6&#8217;],\n    [&#8216;#ef476f&#8217;,&#8217;#f78c6b&#8217;,&#8217;#ffd166&#8242;,&#8217;#06d6a0&#8242;,&#8217;#118ab2&#8242;,&#8217;#7353ba&#8217;],\n    [&#8216;#22c55e&#8217;,&#8217;#06b6d4&#8242;,&#8217;#3b82f6&#8242;,&#8217;#8b5cf6&#8242;,&#8217;#ec4899&#8242;,&#8217;#f59e0b&#8217;]\n  ].filter(x=&gt;x.length&gt;2);\n\n  let colors=palettes[0];\n  let entries=raw.split(&#8216;~&#8217;).map(v=&gt;{try{return decodeURIComponent(v)}catch(e){return v}}).filter(Boolean).map(v=&gt;{\n    const p=v.split(&#8216;|&#8217;);\n    const weight=mode===&#8217;weighted&#8217;?Math.max(1,Number(p.pop())||1):1;\n    return{name:p.join(&#8216;|&#8217;),weight,count:0,last:-999,image:\u00bb};\n  });\n  let angle=0,busy=false,history=[],undo=[],redo=[],spinNumber=0,lastReceipt=null,preSpin=[];\n  let backgroundImage=\u00bb,centerImage=\u00bb,backgroundOpacity=.45,centerRadius=76,pendingEntryImage=\u00bb,pendingEntryFilename=\u00bb;\n  const imageCache=new Map();\n\n  const canvas=$(&#8216;.wnx-canvas&#8217;),ctx=canvas.getContext(&#8216;2d&#8217;),spin=$(&#8216;.wnx-spin&#8217;),result=$(&#8216;.wnx-result&#8217;),list=$(&#8216;.wnx-list&#8217;);\n  const elimination=$(&#8216;.wnx-elimination&#8217;),accumulation=$(&#8216;.wnx-accumulation&#8217;),auto=$(&#8216;.wnx-auto&#8217;),winnerCount=$(&#8216;.wnx-winner-count&#8217;),duration=$(&#8216;.wnx-duration&#8217;);\n  const balance=$(&#8216;.wnx-smart-balance&#8217;),cooldown=$(&#8216;.wnx-smart-cooldown&#8217;);\n\n  $(&#8216;.wnx-title&#8217;).textContent=title;\n  elimination.checked=mode===&#8217;norepeat&#8217;||params.get(&#8216;wnremove&#8217;)===&#8217;1&#8242;;\n  winnerCount.value=mode===&#8217;multi&#8217;?Math.max(1,Number(cfg?.dataset.count||r.dataset.count)||3):1;\n  $(&#8216;.wnx-multi-field&#8217;).classList.toggle(&#8216;wnx-hidden&#8217;,mode!==&#8217;multi&#8217;);\n\n  const escapeHtml=s=&gt;String(s).replace(\/[&amp;\u00bb&#8216;]\/g,m=&gt;({&#8216;&amp;&#8217;:&#8217;&amp;&#8217;,\u00bb:&#8217;&gt;&#8217;,'\u00bb&#8216;:&#8217;&quot;&#8217;,\u00bb&#8216;\u00bb:&#8217;&#039;&#8217;}[m]));\n  const snapshot=()=&gt;JSON.stringify(entries);\n  const save=()=&gt;{undo.push(snapshot());if(undo.length&gt;25)undo.shift();redo=[];};\n  const randomInt=n=&gt;{if(n=limit);return a[0]%n;};\n\n  function getImage(src){\n    if(!src)return null;\n    if(imageCache.has(src))return imageCache.get(src);\n    const img=new Image();\n    img.onload=draw;\n    img.src=src;\n    imageCache.set(src,img);\n    return img;\n  }\n\n  function drawCover(img,x,y,w,h){\n    if(!img||!img.complete||!img.naturalWidth)return;\n    const scale=Math.max(w\/img.naturalWidth,h\/img.naturalHeight);\n    const dw=img.naturalWidth*scale,dh=img.naturalHeight*scale;\n    ctx.drawImage(img,x+(w-dw)\/2,y+(h-dh)\/2,dw,dh);\n  }\n\n  function readOptimizedImage(file,maxSize=1000){\n    return new Promise((resolve,reject)=&gt;{\n      if(!file||!file.type.startsWith(&#8216;image\/&#8217;)){reject(new Error(&#8216;Please choose an image file.&#8217;));return;}\n      const reader=new FileReader();\n      reader.onerror=()=&gt;reject(new Error(&#8216;The image could not be read.&#8217;));\n      reader.onload=()=&gt;{\n        const img=new Image();\n        img.onerror=()=&gt;reject(new Error(&#8216;The image format is not supported.&#8217;));\n        img.onload=()=&gt;{\n          const scale=Math.min(1,maxSize\/Math.max(img.naturalWidth,img.naturalHeight));\n          const w=Math.max(1,Math.round(img.naturalWidth*scale)),h=Math.max(1,Math.round(img.naturalHeight*scale));\n          const temp=document.createElement(&#8216;canvas&#8217;);temp.width=w;temp.height=h;\n          const t=temp.getContext(&#8216;2d&#8217;);t.drawImage(img,0,0,w,h);\n          const type=file.type===&#8217;image\/png&#8217;?&#8217;image\/png&#8217;:&#8217;image\/jpeg&#8217;;\n          resolve(temp.toDataURL(type,type===&#8217;image\/jpeg&#8217;?.86:undefined));\n        };\n        img.src=String(reader.result||\u00bb);\n      };\n      reader.readAsDataURL(file);\n    });\n  }\n\n  const smartOn=()=&gt;!elimination.checked&amp;&amp;(balance.checked||Number(cooldown.value)&gt;0);\n  function eligibleEntries(){\n    let pool=[&#8230;entries];\n    if(!smartOn())return pool;\n    const cd=Number(cooldown.value);\n    if(cd&gt;0){const cooled=pool.filter(e=&gt;spinNumber-e.last&gt;=cd);if(cooled.length)pool=cooled;}\n    if(balance.checked&amp;&amp;pool.length){const min=Math.min(&#8230;pool.map(e=&gt;e.count));pool=pool.filter(e=&gt;e.count===min);}\n    return pool.length?pool:[&#8230;entries];\n  }\n\n  function segments(){\n    const total=entries.reduce((s,e)=&gt;s+e.weight,0)||1;\n    let used=0;\n    return entries.map(entry=&gt;{const start=used\/total*Math.PI*2;used+=entry.weight;return{entry,start,end:used\/total*Math.PI*2};});\n  }\n\n  function draw(){\n    const size=900,center=450,radius=418,segs=segments(),allowed=new Set(eligibleEntries());\n    ctx.clearRect(0,0,size,size);\n\n    if(backgroundImage){\n      const img=getImage(backgroundImage);\n      ctx.save();ctx.beginPath();ctx.arc(center,center,radius,0,Math.PI*2);ctx.clip();ctx.globalAlpha=backgroundOpacity;drawCover(img,center-radius,center-radius,radius*2,radius*2);ctx.restore();\n    }\n\n    if(!segs.length){\n      ctx.beginPath();ctx.arc(center,center,radius,0,Math.PI*2);ctx.fillStyle=&#8217;#0b1628&#8242;;ctx.fill();ctx.strokeStyle=&#8217;rgba(129,140,248,.24)&#8217;;ctx.lineWidth=6;ctx.stroke();ctx.fillStyle=&#8217;#94a3b8&#8242;;ctx.font=&#8217;800 34px system-ui&#8217;;ctx.textAlign=&#8217;center&#8217;;ctx.fillText(&#8216;Add entries&#8217;,center,center);return;\n    }\n\n    segs.forEach((seg,index)=&gt;{\n      const dim=smartOn()&amp;&amp;!allowed.has(seg.entry);\n      const start=seg.start+angle,end=seg.end+angle;\n      ctx.save();\n      ctx.globalAlpha=dim?.2:1;\n      ctx.beginPath();ctx.moveTo(center,center);ctx.arc(center,center,radius,start,end);ctx.closePath();\n\n      if(seg.entry.image){\n        ctx.save();ctx.clip();drawCover(getImage(seg.entry.image),center-radius,center-radius,radius*2,radius*2);ctx.restore();\n        ctx.globalAlpha=dim?.12:.22;ctx.fillStyle=colors[index%colors.length];ctx.fill();ctx.globalAlpha=dim?.2:1;\n      }else{\n        ctx.fillStyle=colors[index%colors.length];\n        if(backgroundImage)ctx.globalAlpha=dim?.14:.72;\n        ctx.fill();ctx.globalAlpha=dim?.2:1;\n      }\n\n      ctx.strokeStyle=&#8217;rgba(255,255,255,.82)&#8217;;ctx.lineWidth=5;ctx.stroke();\n      const mid=(seg.start+seg.end)\/2+angle;\n      ctx.translate(center,center);ctx.rotate(mid);ctx.textAlign=&#8217;right&#8217;;ctx.fillStyle=&#8217;#fff&#8217;;ctx.shadowColor=&#8217;rgba(0,0,0,.55)&#8217;;ctx.shadowBlur=8;\n      ctx.font=`850 ${Math.max(18,Math.min(33,350\/entries.length+16))}px system-ui`;\n      const label=seg.entry.name.length&gt;22?seg.entry.name.slice(0,20)+&#8217;\u2026&#8217;:seg.entry.name;\n      ctx.fillText(label,radius-34,10);ctx.restore();\n    });\n\n    ctx.save();ctx.beginPath();ctx.arc(center,center,centerRadius,0,Math.PI*2);ctx.clip();\n    if(centerImage){drawCover(getImage(centerImage),center-centerRadius,center-centerRadius,centerRadius*2,centerRadius*2);}else{ctx.fillStyle=&#8217;#0b1628&#8242;;ctx.fillRect(center-centerRadius,center-centerRadius,centerRadius*2,centerRadius*2);}\n    ctx.restore();ctx.beginPath();ctx.arc(center,center,centerRadius,0,Math.PI*2);ctx.strokeStyle=&#8217;rgba(255,255,255,.24)&#8217;;ctx.lineWidth=10;ctx.stroke();\n  }\n\n  function updateBadges(){\n    [[ $(&#8216;.wnx-badge-elimination&#8217;),elimination,&#8217;Elimination&#8217;],[$(&#8216;.wnx-badge-accumulation&#8217;),accumulation,&#8217;Accumulation&#8217;],[$(&#8216;.wnx-badge-auto&#8217;),auto,&#8217;Auto-Spin&#8217;],[$(&#8216;.wnx-badge-smart&#8217;),{checked:smartOn()},&#8217;Fair Rotation&#8217;]].forEach(([el,input,label])=&gt;{el.textContent=`${label}: ${input.checked?&#8217;ON&#8217;:&#8217;OFF&#8217;}`;el.classList.toggle(&#8216;is-on&#8217;,input.checked);});\n  }\n\n  function balanceScore(){\n    if(!entries.length)return 100;\n    const total=entries.reduce((s,e)=&gt;s+e.count,0),mean=total\/entries.length;\n    if(!mean)return 100;\n    const deviation=entries.reduce((s,e)=&gt;s+Math.abs(e.count-mean),0)\/entries.length;\n    return Math.max(0,Math.round(100-deviation\/mean*100));\n  }\n\n  function updateDashboard(){\n    $(&#8216;.wnx-balance-score&#8217;).textContent=balanceScore()+&#8217;%&#8217;;$(&#8216;.wnx-smart-spins&#8217;).textContent=String(spinNumber);\n    $(&#8216;.wnx-smart-counts&#8217;).innerHTML=[&#8230;entries].sort((a,b)=&gt;a.count-b.count||a.name.localeCompare(b.name)).map(e=&gt;`<div class=\"wnx-smart-count\"><span>${escapeHtml(e.name)}<\/span><b>${e.count}<\/b><\/div>`).join(\u00bb)||&#8217;<p>No entries yet.<\/p>&#8216;;\n    const status=$(&#8216;.wnx-smart-status&#8217;);\n    if(elimination.checked&amp;&amp;(balance.checked||Number(cooldown.value)&gt;0))status.textContent=&#8217;Smart Fair Rotation is paused while Elimination mode is active.&#8217;;\n    else if(!smartOn())status.textContent=&#8217;Pure random mode is active.&#8217;;\n    else{const parts=[];if(balance.checked)parts.push(&#8216;least-selected priority&#8217;);if(Number(cooldown.value)&gt;0)parts.push(`${cooldown.value}-spin cooldown`);status.textContent=`Smart mode active: ${parts.join(&#8216; + &#8216;)}. Dimmed slices are temporarily ineligible.`;}\n  }\n\n  function render(){\n    list.innerHTML=entries.map((entry,index)=&gt;`<li class=\"wnx-entry\"><span class=\"wnx-grip\">\u22ee\u22ee<\/span><div class=\"wnx-entry-main\">${entry.image?`<span class=\"wnx-entry-thumb\"><img decoding=\"async\" src=\"${entry.image}\" alt=\"\"><\/span>`:\u00bb}<\/div><div class=\"wnx-weight\"><button class=\"wnx-mini\" data-act=\"minus\" data-i=\"${index}\">\u2212<\/button><span>${entry.weight}<\/span><button class=\"wnx-mini\" data-act=\"plus\" data-i=\"${index}\">+<\/button><\/div><button class=\"wnx-mini wnx-remove\" data-act=\"remove\" data-i=\"${index}\">\u00d7<\/button><\/li>`).join(\u00bb);\n    $(&#8216;.wnx-undo&#8217;).disabled=!undo.length;$(&#8216;.wnx-redo&#8217;).disabled=!redo.length;draw();updateBadges();updateDashboard();\n  }\n\n  function choose(pool){\n    const total=pool.reduce((s,e)=&gt;s+e.weight,0);let n=randomInt(total),used=0;\n    for(let i=0;i&lt;pool.length;i++){used+=pool[i].weight;if(nv.toString(16).padStart(2,&#8217;0&#8242;)).join(\u00bb);\n    const bytes=new TextEncoder().encode(text),hash=await crypto.subtle.digest(&#8216;SHA-256&#8242;,bytes);\n    return[&#8230;new Uint8Array(hash)].map(v=&gt;v.toString(16).padStart(2,&#8217;0&#8217;)).join(\u00bb);\n  }\n\n  async function createReceipt(selected){\n    const payload={version:2,site:location.origin,page:location.pathname,timestamp:new Date().toISOString(),spinNumber,result:selected.map(e=&gt;e.name),entries:preSpin,entryImages:selected.map(e=&gt;({name:e.name,hasImage:Boolean(e.image)})),backgroundImage:Boolean(backgroundImage),centerImage:Boolean(centerImage),smartFairRotation:balance.checked,cooldownSpins:Number(cooldown.value),elimination:elimination.checked,accumulation:accumulation.checked,autoSpin:auto.checked};\n    const hash=await sha256(JSON.stringify(payload));lastReceipt={&#8230;payload,sha256:hash,receiptId:&#8217;WNR-&#8216;+hash.slice(0,16).toUpperCase()};\n    $(&#8216;.wnx-receipt-id&#8217;).textContent=lastReceipt.receiptId;$(&#8216;.wnx-copy-receipt&#8217;).disabled=false;$(&#8216;.wnx-download-receipt&#8217;).disabled=false;\n  }\n\n  function finish(selected){\n    spinNumber++;selected.forEach(e=&gt;{e.count++;e.last=spinNumber;});\n    const time=new Date().toLocaleTimeString();history.unshift(`${time} \u2014 ${selected.map(e=&gt;e.name).join(&#8216;, &#8216;)}`);\n    $(&#8216;.wnx-history&#8217;).innerHTML=history.map(v=&gt;`<li>${escapeHtml(v)}<\/li>`).join(\u00bb);$(&#8216;.wnx-empty&#8217;).classList.toggle(&#8216;wnx-hidden&#8217;,history.length&gt;0);\n    result.textContent=(selected.length&gt;1?&#8217;Winners: &#8216;:&#8217;Winner: &#8216;)+selected.map(e=&gt;e.name+(accumulation.checked?` (${e.count})`:\u00bb)).join(&#8216;, &#8216;);\n    createReceipt(selected);\n    if(elimination.checked){save();const set=new Set(selected);entries=entries.filter(e=&gt;!set.has(e));render();}else{draw();updateDashboard();updateBadges();}\n    busy=false;spin.disabled=false;if(auto.checked&amp;&amp;entries.length)setTimeout(startSpin,1200);\n  }\n\n  function startSpin(){\n    if(busy||!entries.length){if(!entries.length)result.textContent=&#8217;Add at least one entry.&#8217;;return;}\n    busy=true;spin.disabled=true;preSpin=entries.map(e=&gt;({name:e.name,weight:e.weight,hasImage:Boolean(e.image)}));\n    let base=eligibleEntries();if(mode===&#8217;multi&#8217;&amp;&amp;base.length&lt;Math.max(1,Number(winnerCount.value)||1))base=[&#8230;entries];\n    const pool=[&#8230;base],selected=[],wanted=Math.min(pool.length,Math.max(1,Number(winnerCount.value)||1));\n    for(let i=0;i&lt;wanted;i++){const index=choose(pool);selected.push(pool[index]);pool.splice(index,1);}\n    const segs=segments(),targetIndex=entries.indexOf(selected[0]),middle=(segs[targetIndex].start+segs[targetIndex].end)\/2,target=-Math.PI\/2-middle,start=angle,delta=((target-start)%(Math.PI*2)+Math.PI*2)%(Math.PI*2)+(5+randomInt(4))*Math.PI*2,ms=Number(duration.value)*1000,startTime=performance.now();\n    function frame(now){const progress=Math.min(1,(now-startTime)\/ms),ease=1-Math.pow(1-progress,3);angle=start+delta*ease;draw();if(progress{if(e.key===&#8217;Enter&#8217;||e.key===&#8217; &#8216;){e.preventDefault();startSpin();}};\n\n  $(&#8216;.wnx-add-button&#8217;).onclick=()=&gt;{const input=$(&#8216;.wnx-new-entry&#8217;),value=input.value.trim();if(!value)return;save();entries.push({name:value,weight:1,count:0,last:-999,image:\u00bb});input.value=\u00bb;render();};\n  $(&#8216;.wnx-new-entry&#8217;).onkeydown=e=&gt;{if(e.key===&#8217;Enter&#8217;)$(&#8216;.wnx-add-button&#8217;).click();};\n  $(&#8216;.wnx-apply&#8217;).onclick=()=&gt;{const values=$(&#8216;.wnx-bulk&#8217;).value.split(\/n|,\/).map(v=&gt;v.trim()).filter(Boolean);if(!values.length)return;save();entries=values.map(name=&gt;({name,weight:1,count:0,last:-999,image:\u00bb}));spinNumber=0;render();};\n  $(&#8216;.wnx-file&#8217;).onchange=e=&gt;{const file=e.target.files?.[0];if(!file)return;const reader=new FileReader();reader.onload=()=&gt;{$(&#8216;.wnx-bulk&#8217;).value=String(reader.result||\u00bb).replace(\/,\/g,&#8217;n&#8217;);};reader.readAsText(file);};\n  $(&#8216;.wnx-shuffle&#8217;).onclick=()=&gt;{save();for(let i=entries.length-1;i&gt;0;i&#8211;){const j=randomInt(i+1);[entries[i],entries[j]]=[entries[j],entries[i]];}render();};\n  $(&#8216;.wnx-clear&#8217;).onclick=()=&gt;{save();entries=[];spinNumber=0;render();};\n  $(&#8216;.wnx-undo&#8217;).onclick=()=&gt;{if(!undo.length)return;redo.push(snapshot());entries=JSON.parse(undo.pop());render();};\n  $(&#8216;.wnx-redo&#8217;).onclick=()=&gt;{if(!redo.length)return;undo.push(snapshot());entries=JSON.parse(redo.pop());render();};\n\n  list.onclick=e=&gt;{const button=e.target.closest(&#8216;[data-act]&#8217;);if(!button)return;save();const index=Number(button.dataset.i),action=button.dataset.act;if(action===&#8217;remove&#8217;)entries.splice(index,1);if(action===&#8217;plus&#8217;)entries[index].weight++;if(action===&#8217;minus&#8217;)entries[index].weight=Math.max(1,entries[index].weight-1);render();};\n  list.onchange=e=&gt;{if(!e.target.matches(&#8216;[data-edit]&#8217;))return;save();entries[Number(e.target.dataset.edit)].name=e.target.value.trim()||&#8217;Untitled&#8217;;render();};\n\n  $(&#8216;.wnx-bg-file&#8217;).onchange=async e=&gt;{const file=e.target.files?.[0];if(!file)return;try{backgroundImage=await readOptimizedImage(file,1200);$(&#8216;.wnx-bg-status&#8217;).textContent=file.name;$(&#8216;.wnx-remove-bg&#8217;).disabled=false;draw();}catch(err){$(&#8216;.wnx-bg-status&#8217;).textContent=err.message;}};\n  $(&#8216;.wnx-bg-opacity&#8217;).oninput=e=&gt;{backgroundOpacity=Number(e.target.value)\/100;draw();};\n  $(&#8216;.wnx-remove-bg&#8217;).onclick=()=&gt;{backgroundImage=\u00bb;$(&#8216;.wnx-bg-file&#8217;).value=\u00bb;$(&#8216;.wnx-bg-status&#8217;).textContent=&#8217;No image selected&#8217;;$(&#8216;.wnx-remove-bg&#8217;).disabled=true;draw();};\n\n  $(&#8216;.wnx-center-file&#8217;).onchange=async e=&gt;{const file=e.target.files?.[0];if(!file)return;try{centerImage=await readOptimizedImage(file,600);$(&#8216;.wnx-center-status&#8217;).textContent=file.name;$(&#8216;.wnx-remove-center&#8217;).disabled=false;draw();}catch(err){$(&#8216;.wnx-center-status&#8217;).textContent=err.message;}};\n  $(&#8216;.wnx-center-size&#8217;).oninput=e=&gt;{centerRadius=Number(e.target.value);draw();};\n  $(&#8216;.wnx-remove-center&#8217;).onclick=()=&gt;{centerImage=\u00bb;$(&#8216;.wnx-center-file&#8217;).value=\u00bb;$(&#8216;.wnx-center-status&#8217;).textContent=&#8217;No image selected&#8217;;$(&#8216;.wnx-remove-center&#8217;).disabled=true;draw();};\n\n  $(&#8216;.wnx-entry-image-file&#8217;).onchange=async e=&gt;{const file=e.target.files?.[0];if(!file)return;try{pendingEntryImage=await readOptimizedImage(file,650);pendingEntryFilename=file.name.replace(\/.[^.]+$\/,\u00bb);const preview=$(&#8216;.wnx-entry-image-preview&#8217;);preview.querySelector(&#8216;img&#8217;).src=pendingEntryImage;preview.querySelector(&#8216;span&#8217;).textContent=file.name;preview.hidden=false;$(&#8216;.wnx-add-image-entry&#8217;).disabled=false;}catch(err){result.textContent=err.message;}};\n  $(&#8216;.wnx-add-image-entry&#8217;).onclick=()=&gt;{if(!pendingEntryImage)return;const label=$(&#8216;.wnx-image-entry-name&#8217;).value.trim()||pendingEntryFilename||&#8217;Image entry&#8217;;save();entries.push({name:label,weight:1,count:0,last:-999,image:pendingEntryImage});pendingEntryImage=\u00bb;pendingEntryFilename=\u00bb;$(&#8216;.wnx-image-entry-name&#8217;).value=\u00bb;$(&#8216;.wnx-entry-image-file&#8217;).value=\u00bb;$(&#8216;.wnx-entry-image-preview&#8217;).hidden=true;$(&#8216;.wnx-add-image-entry&#8217;).disabled=true;render();};\n  $(&#8216;.wnx-reset-images&#8217;).onclick=()=&gt;{backgroundImage=\u00bb;centerImage=\u00bb;pendingEntryImage=\u00bb;entries.forEach(e=&gt;e.image=\u00bb);$(&#8216;.wnx-bg-file&#8217;).value=\u00bb;$(&#8216;.wnx-center-file&#8217;).value=\u00bb;$(&#8216;.wnx-entry-image-file&#8217;).value=\u00bb;$(&#8216;.wnx-bg-status&#8217;).textContent=&#8217;No image selected&#8217;;$(&#8216;.wnx-center-status&#8217;).textContent=&#8217;No image selected&#8217;;$(&#8216;.wnx-remove-bg&#8217;).disabled=true;$(&#8216;.wnx-remove-center&#8217;).disabled=true;$(&#8216;.wnx-add-image-entry&#8217;).disabled=true;$(&#8216;.wnx-entry-image-preview&#8217;).hidden=true;render();};\n\n  duration.oninput=()=&gt;{$(&#8216;.wnx-duration-text&#8217;).textContent=duration.value;};\n  [elimination,accumulation,auto,balance,cooldown].forEach(control=&gt;control.onchange=()=&gt;{updateBadges();updateDashboard();draw();});\n  $(&#8216;.wnx-smart-reset&#8217;).onclick=()=&gt;{entries.forEach(e=&gt;{e.count=0;e.last=-999;});spinNumber=0;lastReceipt=null;$(&#8216;.wnx-receipt-id&#8217;).textContent=&#8217;No receipt yet&#8217;;$(&#8216;.wnx-copy-receipt&#8217;).disabled=true;$(&#8216;.wnx-download-receipt&#8217;).disabled=true;render();};\n\n  $(&#8216;.wnx-hide-panel&#8217;).onclick=()=&gt;{const panel=$(&#8216;.wnx-panel&#8217;);panel.classList.toggle(&#8216;wnx-hidden&#8217;);$(&#8216;.wnx-hide-panel&#8217;).textContent=panel.classList.contains(&#8216;wnx-hidden&#8217;)?&#8217;Show Panel&#8217;:&#8217;Hide Panel&#8217;;};\n  $(&#8216;.wnx-fullscreen&#8217;).onclick=()=&gt;r.requestFullscreen?.();\n  $(&#8216;.wnx-export&#8217;).onclick=()=&gt;{const csv=&#8217;entry,weight,count,has_imagen&#8217;+entries.map(e=&gt;`\u00bb${e.name.replace(\/\u00bb\/g,'\u00bb\u00bb&#8216;)}\u00bb,${e.weight},${e.count},${e.image?&#8217;yes&#8217;:&#8217;no&#8217;}`).join(&#8216;n&#8217;),a=document.createElement(&#8216;a&#8217;);a.href=URL.createObjectURL(new Blob([csv],{type:&#8217;text\/csv&#8217;}));a.download=&#8217;wheel-entries.csv&#8217;;a.click();setTimeout(()=&gt;URL.revokeObjectURL(a.href),1000);};\n  $(&#8216;.wnx-share&#8217;).onclick=async()=&gt;{const url=new URL(location.href);url.searchParams.set(&#8216;wnitems&#8217;,entries.map(e=&gt;encodeURIComponent(e.name)+(e.weight&gt;1?&#8217;|&#8217;+e.weight:\u00bb)).join(&#8216;~&#8217;));elimination.checked?url.searchParams.set(&#8216;wnremove&#8217;,&#8217;1&#8242;):url.searchParams.delete(&#8216;wnremove&#8217;);try{await navigator.clipboard.writeText(url);result.textContent=entries.some(e=&gt;e.image)||backgroundImage||centerImage?&#8217;Share link copied. Images stay in this browser session.&#8217;:&#8217;Share link copied.&#8217;;}catch(e){result.textContent=url;}};\n\n  $(&#8216;.wnx-copy-receipt&#8217;).onclick=async()=&gt;{if(!lastReceipt)return;const text=`${lastReceipt.receiptId}nWinner: ${lastReceipt.result.join(&#8216;, &#8216;)}nTime: ${lastReceipt.timestamp}nSHA-256: ${lastReceipt.sha256}`;try{await navigator.clipboard.writeText(text);$(&#8216;.wnx-copy-receipt&#8217;).textContent=&#8217;Copied&#8217;;setTimeout(()=&gt;$(&#8216;.wnx-copy-receipt&#8217;).textContent=&#8217;Copy Receipt&#8217;,1200);}catch(e){$(&#8216;.wnx-receipt-id&#8217;).textContent=text;}};\n  $(&#8216;.wnx-download-receipt&#8217;).onclick=()=&gt;{if(!lastReceipt)return;const report={receipt:lastReceipt,balanceScore:balanceScore()+&#8217;%&#8217;,selectionCounts:Object.fromEntries(entries.map(e=&gt;[e.name,e.count]))},a=document.createElement(&#8216;a&#8217;);a.href=URL.createObjectURL(new Blob([JSON.stringify(report,null,2)],{type:&#8217;application\/json&#8217;}));a.download=lastReceipt.receiptId+&#8217;.json&#8217;;a.click();setTimeout(()=&gt;URL.revokeObjectURL(a.href),1000);};\n\n  $$(&#8216;.wnx-tab&#8217;).forEach(button=&gt;button.onclick=()=&gt;{$$(&#8216;.wnx-tab&#8217;).forEach(x=&gt;x.classList.remove(&#8216;is-active&#8217;));$$(&#8216;.wnx-pane&#8217;).forEach(x=&gt;x.classList.remove(&#8216;is-active&#8217;));button.classList.add(&#8216;is-active&#8217;);$(`.wnx-pane[data-pane=\u00bb${button.dataset.tab}\u00bb]`).classList.add(&#8216;is-active&#8217;);if(button.dataset.tab===&#8217;smart&#8217;)updateDashboard();});\n  palettes.forEach((palette,index)=&gt;{const button=document.createElement(&#8216;button&#8217;);button.type=&#8217;button&#8217;;button.className=&#8217;wnx-palette&#8217;+(index?\u00bb:&#8217; is-active&#8217;);button.style.background=`linear-gradient(135deg,${palette.join(&#8216;,&#8217;)})`;button.onclick=()=&gt;{colors=palette;$$(&#8216;.wnx-palette&#8217;).forEach(x=&gt;x.classList.remove(&#8216;is-active&#8217;));button.classList.add(&#8216;is-active&#8217;);draw();};$(&#8216;.wnx-palettes&#8217;).append(button);});\n\n  render();\n})();\n\n<\/section>\n<div class=\"wn-page\"><section class=\"wn-section\" id=\"answer\"><h2>\u00bfQu\u00e9 es la Ruleta de Decisiones?<\/h2><p><strong>La Ruleta de Decisiones selecciona una alternativa activa de tu lista. En el modo est\u00e1ndar, cada entrada \u00fanica tiene la misma probabilidad; las opciones duplicadas o los pesos modifican esa probabilidad.<\/strong><\/p><\/section><section class=\"wn-section\"><nav class=\"wn-toc\" aria-label=\"Gu\u00eda de la Ruleta de Decisiones\"><strong>Gu\u00eda de la Ruleta de Decisiones<\/strong><ol><li><a href=\"#answer\">Respuesta r\u00e1pida<\/a><\/li><li><a href=\"#how-to-use\">C\u00f3mo utilizarla<\/a><\/li><li><a href=\"#best-uses\">Mejores usos<\/a><\/li><li><a href=\"#tips\">Consejos de configuraci\u00f3n<\/a><\/li><li><a href=\"#faq\">Preguntas frecuentes<\/a><\/li><\/ol><\/nav><\/section><section class=\"wn-section\" id=\"how-to-use\"><h2>C\u00f3mo utilizar la Ruleta de Decisiones<\/h2><div class=\"wn-steps\"><div class=\"wn-step\"><h3>Sustituye las opciones de ejemplo<\/h3><p>A\u00f1ade las opciones exactas que cumplan las reglas de tu actividad o conserva la lista preparada si ya se ajusta a tu objetivo.<\/p><\/div><div class=\"wn-step\"><h3>Revisa la lista activa y el modo<\/h3><p>Elimina las opciones no disponibles, comprueba los duplicados y elige el modo est\u00e1ndar o de eliminaci\u00f3n seg\u00fan se permitan o no las repeticiones.<\/p><\/div><div class=\"wn-step\"><h3>Gira la ruleta y confirma el resultado<\/h3><p>Pulsa Girar la Ruleta, consulta el resultado y an\u00f3talo cuando otra persona o una tarea posterior dependan de la elecci\u00f3n.<\/p><\/div><\/div><\/section><section class=\"wn-section\" id=\"best-uses\"><h2>Mejores usos de esta Ruleta de Decisiones<\/h2><div class=\"wn-grid\"><article class=\"wn-card wide\"><h3>Decisiones cotidianas<\/h3><p>Elige una actividad, el orden de los recados, un destino, una categor\u00eda de comida o una opci\u00f3n de entretenimiento.<\/p><\/article><article class=\"wn-card wide\"><h3>Decisiones de grupo<\/h3><p>Permite que un equipo o una familia elija entre ideas aprobadas previamente sin repetir el mismo debate.<\/p><\/article><article class=\"wn-card wide\"><h3>Trabajo creativo<\/h3><p>Selecciona un tema, una condici\u00f3n, un color, un enfoque o la siguiente acci\u00f3n peque\u00f1a.<\/p><\/article><article class=\"wn-card wide\"><h3>Orden de tareas pendientes<\/h3><p>Ordena al azar tareas similares de bajo riesgo cuando su prioridad y urgencia sean equivalentes.<\/p><\/article><\/div><\/section><section class=\"wn-section\" id=\"tips\"><h2>Consejos para configurar la Ruleta de Decisiones<\/h2><ul><li>A\u00f1ade \u00fanicamente opciones que cumplan los l\u00edmites de coste, seguridad, tiempo y disponibilidad.<\/li><li>Utiliza etiquetas cortas para que cada secci\u00f3n de la ruleta sea f\u00e1cil de leer.<\/li><li>Elimina las opciones duplicadas salvo que quieras darles m\u00e1s posibilidades.<\/li><li>Acuerda una regla para repetir el sorteo antes de girar.<\/li><\/ul><p class=\"wn-note\"><strong>Uso responsable:<\/strong> una ruleta de decisiones es adecuada para decisiones de bajo riesgo y actividades preparadas. No debe sustituir el consentimiento, las comprobaciones de seguridad, los ajustes de accesibilidad, el criterio profesional ni los requisitos legales.<\/p><\/section><section class=\"wn-section\"><h2>Gu\u00eda de apoyo y herramientas relacionadas<\/h2><div class=\"wn-related\"><a href=\"\/es\/\"><strong>Ruleta de Nombres<\/strong><br><small>M\u00e1s informaci\u00f3n \u2192<\/small><\/a><a href=\"\/es\/\"><strong>Ruleta Aleatoria<\/strong><br><small>M\u00e1s informaci\u00f3n \u2192<\/small><\/a><a href=\"https:\/\/wheelnames.org\/family-activity-picker-wheel\/\"><strong>Ruleta de actividades familiares<\/strong><br><small>M\u00e1s informaci\u00f3n \u2192<\/small><\/a><a href=\"https:\/\/wheelnames.org\/random-food-picker-wheel\/\"><strong>Ruleta de comida aleatoria<\/strong><br><small>M\u00e1s informaci\u00f3n \u2192<\/small><\/a><\/div><\/section><section class=\"wn-section\"><h2>Referencia autorizada<\/h2><p class=\"wn-source\">Recurso relacionado: <a href=\"https:\/\/developer.mozilla.org\/es\/docs\/Web\/API\/Crypto\/getRandomValues\">documentaci\u00f3n de MDN sobre valores aleatorios en el navegador<\/a>.<\/p><\/section><section class=\"wn-section\" id=\"faq\"><h2>Preguntas frecuentes sobre la Ruleta de Decisiones<\/h2><div class=\"wn-faq\"><details><summary>\u00bfLa Ruleta de Decisiones es gratis?<\/summary><p>S\u00ed. Funciona en el navegador y no requiere crear una cuenta.<\/p><\/details><details><summary>\u00bfLa ruleta toma la decisi\u00f3n por m\u00ed?<\/summary><p>Selecciona una de las opciones que hayas aprobado. T\u00fa sigues siendo responsable de la seguridad, el consentimiento, el coste y las consecuencias importantes.<\/p><\/details><details><summary>\u00bfPuedo eliminar la opci\u00f3n seleccionada?<\/summary><p>Activa el modo de eliminaci\u00f3n cuando quieras una secuencia sin repeticiones.<\/p><\/details><\/div><\/section><\/div>\n\n\n<!-- wn-es-locale-start -->\n<script id=\"wn-es-locale\">\n(function init(){\n  if (!document.documentElement.lang.toLowerCase().startsWith('es')) return;\n  const root = document.querySelector('.wnx-spinner');\n  if (!root || root.dataset.ready !== '1') { setTimeout(init,100); return; }\n  const exact = {\n    'Interactive spinning wheel':'Ruleta giratoria interactiva','Share':'Compartir','Export CSV':'Exportar CSV','Fullscreen':'Pantalla completa',\n    'Hide Panel':'Ocultar panel','Show Panel':'Mostrar panel','SPIN THE WHEEL':'GIRAR LA RULETA','Entries':'Opciones','Design':'Dise\u00f1o',\n    'Skins':'Apariencias','Images':'Im\u00e1genes','Smart \u2726':'Inteligente \u2726','History':'Historial','Undo':'Deshacer','Redo':'Rehacer',\n    'Shuffle':'Mezclar','Clear':'Borrar','Upload CSV':'Subir CSV','Apply List':'Aplicar lista','Color palette':'Paleta de colores',\n    'Spin duration:':'Duraci\u00f3n del giro:','seconds':'segundos','Elimination mode':'Modo de eliminaci\u00f3n',\n    'Accumulation mode':'Modo de acumulaci\u00f3n','Auto-spin':'Giro autom\u00e1tico','Unique winners':'Ganadores \u00fanicos',\n    'Wheel skins':'Apariencias de la ruleta','Choose a ready-made texture and apply it instantly.':'Elige una textura preparada y apl\u00edcala al instante.',\n    'Use the arrows or swipe sideways to browse all 20 skins. Choose Classic to return to the standard colored wheel.':'Usa las flechas o desliza hacia los lados para ver las 20 apariencias. Elige Cl\u00e1sica para volver a la rueda de colores est\u00e1ndar.',\n    'Wheel background image':'Imagen de fondo de la ruleta','Add one image behind the colored wheel slices.':'A\u00f1ade una imagen detr\u00e1s de los segmentos de colores de la ruleta.',\n    'Choose background':'Elegir fondo','Image visibility':'Visibilidad de la imagen','Remove background':'Eliminar fondo',\n    'Center image or logo':'Imagen central o logotipo','Place a logo, icon, or photo inside the center hub.':'Coloca un logotipo, icono o foto en el centro de la ruleta.',\n    'Choose center image':'Elegir imagen central','Center image size':'Tama\u00f1o de la imagen central','Remove center image':'Eliminar imagen central',\n    'Image as a wheel entry':'Imagen como opci\u00f3n de la ruleta','Add an image-backed slice with an editable text label.':'A\u00f1ade un segmento con imagen y una etiqueta de texto editable.',\n    'Choose entry image':'Elegir imagen de opci\u00f3n','Add image entry':'A\u00f1adir opci\u00f3n con imagen','Reset all images':'Restablecer todas las im\u00e1genes',\n    'Images are optimized and kept in this browser session. They are not included in shared URLs or CSV exports.':'Las im\u00e1genes se optimizan y se conservan durante esta sesi\u00f3n del navegador. No se incluyen en enlaces compartidos ni exportaciones CSV.',\n    'Smart Fair Rotation':'Rotaci\u00f3n inteligente y equilibrada','Prioritize least-selected entries':'Dar prioridad a las opciones menos seleccionadas',\n    'Winner cooldown':'Espera del ganador','Off':'Desactivada','1 spin':'1 giro','2 spins':'2 giros','3 spins':'3 giros','4 spins':'4 giros','5 spins':'5 giros',\n    'Pure random mode is active.':'El modo completamente aleatorio est\u00e1 activo.','balance score':'\u00edndice de equilibrio','tracked spins':'giros registrados',\n    'Reset Smart Stats':'Restablecer estad\u00edsticas','Cryptographic Draw Receipt':'Comprobante criptogr\u00e1fico del sorteo',\n    'Creates a tamper-evident record of the result, timestamp, entries and active modes.':'Crea un registro verificable del resultado, la fecha y hora, las opciones y los modos activos.',\n    'No receipt yet':'A\u00fan no hay comprobante','Copy Receipt':'Copiar comprobante','Download JSON':'Descargar JSON','No spins yet.':'A\u00fan no hay giros.',\n    'No image selected':'Ninguna imagen seleccionada','No entries yet.':'A\u00fan no hay opciones.','Add entries and spin the wheel.':'A\u00f1ade opciones y gira la ruleta.',\n    'Add at least one entry.':'A\u00f1ade al menos una opci\u00f3n.','Share link copied.':'Enlace copiado.',\n    'Share link copied. Images stay in this browser session.':'Enlace copiado. Las im\u00e1genes permanecen en esta sesi\u00f3n del navegador.',\n    'Copied':'Copiado','Classic':'Cl\u00e1sica','Beach Ball':'Pelota de playa','Autumn Leaves':'Hojas de oto\u00f1o','Galaxy':'Galaxia',\n    'Blue Frost':'Escarcha azul','Blue Vortex':'V\u00f3rtice azul','Cookie':'Galleta','Disco Ball':'Bola de discoteca',\n    'Green Grass':'C\u00e9sped verde','Green Leaves':'Hojas verdes','Moon':'Luna','Orange Slice':'Rodaja de naranja',\n    'Rainbow':'Arco\u00edris','Soccer Ball':'Bal\u00f3n de f\u00fatbol','Spiral Nebula':'Nebulosa espiral','Water Pool':'Piscina',\n    'Water Swirl':'Remolino de agua','Wood':'Madera','Tiger':'Tigre'\n  };\n  const translateTextNodes = () => {\n    const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);\n    let node;\n    while ((node = walker.nextNode())) {\n      if (node.parentElement && \/^(SCRIPT|STYLE)$\/.test(node.parentElement.tagName)) continue;\n      const raw = node.nodeValue || '', key = raw.trim();\n      if (exact[key] && exact[key] !== key) node.nodeValue = raw.replace(key, exact[key]);\n    }\n  };\n  const badge = (selector, label) => {\n    const el = root.querySelector(selector);\n    if (!el) return;\n    const on = \/\\bON\\b|ACTIVAD[OA]\/i.test(el.textContent);\n    el.textContent = label + ': ' + (on ? 'ACTIVADA' : 'DESACTIVADA');\n  };\n  const apply = () => {\n    root.setAttribute('aria-label','Ruleta giratoria interactiva');\n    translateTextNodes();\n    badge('.wnx-badge-elimination','Eliminaci\u00f3n'); badge('.wnx-badge-accumulation','Acumulaci\u00f3n');\n    badge('.wnx-badge-auto','Giro autom\u00e1tico'); badge('.wnx-badge-smart','Rotaci\u00f3n equilibrada');\n    const fields = [\n      ['.wnx-new-entry','placeholder','Escribe un nombre y pulsa Intro'],['.wnx-new-entry','aria-label','Nueva opci\u00f3n de la ruleta'],\n      ['.wnx-bulk','placeholder','Pega una opci\u00f3n por l\u00ednea'],['.wnx-canvas','aria-label','Girar la ruleta'],\n      ['.wnx-entry-image-name','placeholder','Etiqueta de la imagen']\n    ];\n    fields.forEach(([selector,attr,value]) => { const el=root.querySelector(selector); if (el) el.setAttribute(attr,value); });\n    root.querySelectorAll('[data-edit]').forEach((el,i)=>el.setAttribute('aria-label','Editar opci\u00f3n '+(i+1)));\n    const result=root.querySelector('.wnx-result');\n    if (result) result.textContent=result.textContent.replace(\/^Winner:\\s*\/,'Resultado: ').replace(\/^Winners:\\s*\/,'Resultados: ')\n      .replace(\/^Add at least one entry\\.$\/,'A\u00f1ade al menos una opci\u00f3n.').replace(\/^Share link copied\\.$\/,'Enlace copiado.')\n      .replace(\/^Share link copied\\. Images stay in this browser session\\.$\/,'Enlace copiado. Las im\u00e1genes permanecen en esta sesi\u00f3n del navegador.');\n    const status=root.querySelector('.wnx-smart-status');\n    if (status) status.textContent=status.textContent\n      .replace('Smart Fair Rotation is paused while Elimination mode is active.','La rotaci\u00f3n inteligente est\u00e1 pausada mientras el modo de eliminaci\u00f3n est\u00e1 activo.')\n      .replace('Pure random mode is active.','El modo completamente aleatorio est\u00e1 activo.').replace(\/^Smart mode active:\/,'Modo inteligente activo:')\n      .replace('least-selected priority','prioridad para las opciones menos seleccionadas').replace(\/(\\d+)-spin cooldown\/,'espera de $1 giros')\n      .replace('Dimmed slices are temporarily ineligible.','Los segmentos atenuados no son elegibles temporalmente.');\n  };\n  let queued=false;\n  const queue=()=>{if(queued)return;queued=true;requestAnimationFrame(()=>{queued=false;apply();});};\n  apply();\n  new MutationObserver(queue).observe(root,{subtree:true,childList:true,characterData:true,attributes:true,attributeFilter:['disabled']});\n})();\n<\/script>\n<!-- wn-es-locale-end -->\n\n<!-- wn-es-schema-start -->\n<script id=\"wn-es-schema\" type=\"application\/ld+json\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebApplication\",\"@id\":\"https:\/\/wheelnames.org\/es\/ruleta-de-decisiones\/#aplicacion\",\"name\":\"Ruleta de Decisiones\",\"url\":\"https:\/\/wheelnames.org\/es\/ruleta-de-decisiones\/\",\"description\":\"Ruleta gratuita para elegir al azar entre opciones, planes, tareas y decisiones cotidianas de bajo riesgo.\",\"applicationCategory\":\"UtilitiesApplication\",\"operatingSystem\":\"Any\",\"browserRequirements\":\"JavaScript y un navegador moderno\",\"inLanguage\":\"es\",\"isAccessibleForFree\":true,\"offers\":{\"@type\":\"Offer\",\"price\":\"0\",\"priceCurrency\":\"USD\"}},{\"@type\":\"FAQPage\",\"@id\":\"https:\/\/wheelnames.org\/es\/ruleta-de-decisiones\/#faq\",\"inLanguage\":\"es\",\"mainEntity\":[{\"@type\":\"Question\",\"name\":\"\u00bfLa Ruleta de Decisiones es gratis?\",\"acceptedAnswer\":{\"@type\":\"Answer\",\"text\":\"S\u00ed. Funciona en el navegador y no requiere crear una cuenta.\"}},{\"@type\":\"Question\",\"name\":\"\u00bfLa ruleta toma la decisi\u00f3n por m\u00ed?\",\"acceptedAnswer\":{\"@type\":\"Answer\",\"text\":\"Selecciona una opci\u00f3n que hayas aprobado; t\u00fa conservas la responsabilidad sobre seguridad, consentimiento, coste y consecuencias.\"}},{\"@type\":\"Question\",\"name\":\"\u00bfPuedo eliminar la opci\u00f3n seleccionada?\",\"acceptedAnswer\":{\"@type\":\"Answer\",\"text\":\"S\u00ed. Activa el modo de eliminaci\u00f3n cuando quieras una secuencia sin repeticiones.\"}}]}]}<\/script>\n<!-- wn-es-schema-end -->","protected":false},"excerpt":{"rendered":"<p>Ruleta de decisiones gratis Ruleta de Decisiones La Ruleta de Decisiones convierte una lista de alternativas v\u00e1lidas en una elecci\u00f3n r\u00e1pida, visual y transparente. A\u00f1ade las opciones que aceptar\u00edas, elimina las no disponibles y obt\u00e9n una selecci\u00f3n al azar. \u00bfQu\u00e9 es la Ruleta de Decisiones? La Ruleta de Decisiones selecciona una alternativa activa de tu&#8230;<\/p>\n","protected":false},"author":1,"featured_media":538,"parent":0,"menu_order":200,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_kad_blocks_custom_css":"","_kad_blocks_head_custom_js":"","_kad_blocks_body_custom_js":"","_kad_blocks_footer_custom_js":"","_kad_post_transparent":"","_kad_post_title":"","_kad_post_layout":"fullwidth","_kad_post_sidebar_id":"","_kad_post_content_style":"","_kad_post_vertical_padding":"","_kad_post_feature":"","_kad_post_feature_position":"","_kad_post_header":false,"_kad_post_footer":false,"_kad_post_classname":"","footnotes":""},"class_list":["post-522","page","type-page","status-publish","has-post-thumbnail","hentry"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v22.3 (Yoast SEO v28.3) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Ruleta de Decisiones Gratis | Wheel Names<\/title>\n<meta name=\"description\" content=\"Ruleta de decisiones gratis para elegir entre opciones, planes o tareas. A\u00f1ade alternativas, gira online y obt\u00e9n una elecci\u00f3n clara al instante.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/wheelnames.org\/es\/ruleta-de-decisiones\/\" \/>\n<meta property=\"og:locale\" content=\"es_ES\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Ruleta de Decisiones Gratis | Wheel Names\" \/>\n<meta property=\"og:description\" content=\"A\u00f1ade tus opciones, gira la ruleta y resuelve decisiones cotidianas de forma visual, r\u00e1pida y gratuita.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/wheelnames.org\/es\/ruleta-de-decisiones\/\" \/>\n<meta property=\"og:site_name\" content=\"Wheel of Names\" \/>\n<meta property=\"article:modified_time\" content=\"2026-08-11T20:51:17+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/wheelnames.org\/wp-content\/uploads\/2026\/08\/ruleta-de-decisiones-wheel-names.png\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:title\" content=\"Ruleta de Decisiones\" \/>\n<meta name=\"twitter:label1\" content=\"Tiempo de lectura\" \/>\n\t<meta name=\"twitter:data1\" content=\"5 minutos\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/wheelnames.org\\\/es\\\/ruleta-de-decisiones\\\/\",\"url\":\"https:\\\/\\\/wheelnames.org\\\/es\\\/ruleta-de-decisiones\\\/\",\"name\":\"Ruleta de Decisiones Gratis | Wheel Names\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/wheelnames.org\\\/es\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/wheelnames.org\\\/es\\\/ruleta-de-decisiones\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/wheelnames.org\\\/es\\\/ruleta-de-decisiones\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/wheelnames.org\\\/wp-content\\\/uploads\\\/2026\\\/08\\\/ruleta-de-decisiones-wheel-names.png\",\"datePublished\":\"2026-07-30T14:08:31+00:00\",\"dateModified\":\"2026-08-11T20:51:17+00:00\",\"description\":\"Ruleta de decisiones gratis para elegir entre opciones, planes o tareas. A\u00f1ade alternativas, gira online y obt\u00e9n una elecci\u00f3n clara al instante.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/wheelnames.org\\\/es\\\/ruleta-de-decisiones\\\/#breadcrumb\"},\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/wheelnames.org\\\/es\\\/ruleta-de-decisiones\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\\\/\\\/wheelnames.org\\\/es\\\/ruleta-de-decisiones\\\/#primaryimage\",\"url\":\"https:\\\/\\\/wheelnames.org\\\/wp-content\\\/uploads\\\/2026\\\/08\\\/ruleta-de-decisiones-wheel-names.png\",\"contentUrl\":\"https:\\\/\\\/wheelnames.org\\\/wp-content\\\/uploads\\\/2026\\\/08\\\/ruleta-de-decisiones-wheel-names.png\",\"width\":1672,\"height\":941,\"caption\":\"Ilustraci\u00f3n de una ruleta de decisiones online para elegir entre varias opciones.\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/wheelnames.org\\\/es\\\/ruleta-de-decisiones\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/wheelnames.org\\\/es\\\/ruleta-aleatoria\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Ruleta de Decisiones\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/wheelnames.org\\\/es\\\/#website\",\"url\":\"https:\\\/\\\/wheelnames.org\\\/es\\\/\",\"name\":\"Wheel of Names\",\"description\":\"Free Random Name Picker &amp; Spinner\",\"publisher\":{\"@id\":\"https:\\\/\\\/wheelnames.org\\\/es\\\/#organization\"},\"alternateName\":\"Wheel Names Picker\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/wheelnames.org\\\/es\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"es\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/wheelnames.org\\\/es\\\/#organization\",\"name\":\"Wheel of Names\",\"alternateName\":\"Wheel Names Picker\",\"url\":\"https:\\\/\\\/wheelnames.org\\\/es\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\\\/\\\/wheelnames.org\\\/es\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/wheelnames.org\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/Wheel-of-Names.png\",\"contentUrl\":\"https:\\\/\\\/wheelnames.org\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/Wheel-of-Names.png\",\"width\":400,\"height\":180,\"caption\":\"Wheel of Names\"},\"image\":{\"@id\":\"https:\\\/\\\/wheelnames.org\\\/es\\\/#\\\/schema\\\/logo\\\/image\\\/\"}}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Ruleta de Decisiones Gratis | Wheel Names","description":"Ruleta de decisiones gratis para elegir entre opciones, planes o tareas. A\u00f1ade alternativas, gira online y obt\u00e9n una elecci\u00f3n clara al instante.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/wheelnames.org\/es\/ruleta-de-decisiones\/","og_locale":"es_ES","og_type":"article","og_title":"Ruleta de Decisiones Gratis | Wheel Names","og_description":"A\u00f1ade tus opciones, gira la ruleta y resuelve decisiones cotidianas de forma visual, r\u00e1pida y gratuita.","og_url":"https:\/\/wheelnames.org\/es\/ruleta-de-decisiones\/","og_site_name":"Wheel of Names","article_modified_time":"2026-08-11T20:51:17+00:00","og_image":[{"url":"https:\/\/wheelnames.org\/wp-content\/uploads\/2026\/08\/ruleta-de-decisiones-wheel-names.png","type":"","width":"","height":""}],"twitter_card":"summary_large_image","twitter_title":"Ruleta de Decisiones","twitter_misc":{"Tiempo de lectura":"5 minutos"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/wheelnames.org\/es\/ruleta-de-decisiones\/","url":"https:\/\/wheelnames.org\/es\/ruleta-de-decisiones\/","name":"Ruleta de Decisiones Gratis | Wheel Names","isPartOf":{"@id":"https:\/\/wheelnames.org\/es\/#website"},"primaryImageOfPage":{"@id":"https:\/\/wheelnames.org\/es\/ruleta-de-decisiones\/#primaryimage"},"image":{"@id":"https:\/\/wheelnames.org\/es\/ruleta-de-decisiones\/#primaryimage"},"thumbnailUrl":"https:\/\/wheelnames.org\/wp-content\/uploads\/2026\/08\/ruleta-de-decisiones-wheel-names.png","datePublished":"2026-07-30T14:08:31+00:00","dateModified":"2026-08-11T20:51:17+00:00","description":"Ruleta de decisiones gratis para elegir entre opciones, planes o tareas. A\u00f1ade alternativas, gira online y obt\u00e9n una elecci\u00f3n clara al instante.","breadcrumb":{"@id":"https:\/\/wheelnames.org\/es\/ruleta-de-decisiones\/#breadcrumb"},"inLanguage":"es","potentialAction":[{"@type":"ReadAction","target":["https:\/\/wheelnames.org\/es\/ruleta-de-decisiones\/"]}]},{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/wheelnames.org\/es\/ruleta-de-decisiones\/#primaryimage","url":"https:\/\/wheelnames.org\/wp-content\/uploads\/2026\/08\/ruleta-de-decisiones-wheel-names.png","contentUrl":"https:\/\/wheelnames.org\/wp-content\/uploads\/2026\/08\/ruleta-de-decisiones-wheel-names.png","width":1672,"height":941,"caption":"Ilustraci\u00f3n de una ruleta de decisiones online para elegir entre varias opciones."},{"@type":"BreadcrumbList","@id":"https:\/\/wheelnames.org\/es\/ruleta-de-decisiones\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/wheelnames.org\/es\/ruleta-aleatoria\/"},{"@type":"ListItem","position":2,"name":"Ruleta de Decisiones"}]},{"@type":"WebSite","@id":"https:\/\/wheelnames.org\/es\/#website","url":"https:\/\/wheelnames.org\/es\/","name":"Wheel of Names","description":"Free Random Name Picker &amp; Spinner","publisher":{"@id":"https:\/\/wheelnames.org\/es\/#organization"},"alternateName":"Wheel Names Picker","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/wheelnames.org\/es\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"es"},{"@type":"Organization","@id":"https:\/\/wheelnames.org\/es\/#organization","name":"Wheel of Names","alternateName":"Wheel Names Picker","url":"https:\/\/wheelnames.org\/es\/","logo":{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/wheelnames.org\/es\/#\/schema\/logo\/image\/","url":"https:\/\/wheelnames.org\/wp-content\/uploads\/2026\/07\/Wheel-of-Names.png","contentUrl":"https:\/\/wheelnames.org\/wp-content\/uploads\/2026\/07\/Wheel-of-Names.png","width":400,"height":180,"caption":"Wheel of Names"},"image":{"@id":"https:\/\/wheelnames.org\/es\/#\/schema\/logo\/image\/"}}]}},"taxonomy_info":[],"featured_image_src_large":["https:\/\/wheelnames.org\/wp-content\/uploads\/2026\/08\/ruleta-de-decisiones-wheel-names-1024x576.png",1024,576,true],"author_info":{"display_name":"Johan","author_link":"https:\/\/wheelnames.org\/es\/author\/talhamehmalgmail-com\/"},"comment_info":0,"_links":{"self":[{"href":"https:\/\/wheelnames.org\/es\/wp-json\/wp\/v2\/pages\/522","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wheelnames.org\/es\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/wheelnames.org\/es\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/wheelnames.org\/es\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/wheelnames.org\/es\/wp-json\/wp\/v2\/comments?post=522"}],"version-history":[{"count":13,"href":"https:\/\/wheelnames.org\/es\/wp-json\/wp\/v2\/pages\/522\/revisions"}],"predecessor-version":[{"id":558,"href":"https:\/\/wheelnames.org\/es\/wp-json\/wp\/v2\/pages\/522\/revisions\/558"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/wheelnames.org\/es\/wp-json\/wp\/v2\/media\/538"}],"wp:attachment":[{"href":"https:\/\/wheelnames.org\/es\/wp-json\/wp\/v2\/media?parent=522"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}