{"id":1452,"date":"2026-10-30T05:54:34","date_gmt":"2026-10-30T05:54:34","guid":{"rendered":"https:\/\/microenvases.com\/?page_id=1452"},"modified":"2026-10-30T05:54:34","modified_gmt":"2026-10-30T05:54:34","slug":"simulador-3d","status":"publish","type":"page","link":"https:\/\/microenvases.com\/en\/simulador-3d\/","title":{"rendered":"Simulador 3D"},"content":{"rendered":"\n<div class=\"sim3d-wrap\">\n  <p class=\"sim3d-intro\">Sube el dise\u00f1o de tu marca, elige el tipo y tama\u00f1o de vaso, y visual\u00edzalo en 3D: puedes rotarlo, acercarlo y ajustar la posici\u00f3n de tu arte antes de imprimir.<\/p>\n  <div class=\"sim3d-grid\">\n    <div class=\"sim3d-viewer\">\n      <div id=\"sim3d-canvas-wrap\"><\/div>\n      <p class=\"sim3d-hint\">Arrastra para rotar &middot; Rueda del mouse para acercar o alejar<\/p>\n    <\/div>\n    <div class=\"sim3d-controls\">\n      <div class=\"sim3d-field\">\n        <label>Tipo de vaso<\/label>\n        <div class=\"sim3d-radios\">\n          <label><input type=\"radio\" name=\"sim3d-tipo\" value=\"fria\" checked> Bebida Fr\u00eda<\/label>\n          <label><input type=\"radio\" name=\"sim3d-tipo\" value=\"caliente\"> Bebida Caliente<\/label>\n        <\/div>\n      <\/div>\n      <div class=\"sim3d-field\">\n        <label for=\"sim3d-tamano\">Tama\u00f1o (oz)<\/label>\n        <select id=\"sim3d-tamano\"><\/select>\n      <\/div>\n      <div class=\"sim3d-field\">\n        <label for=\"sim3d-upload\">Sube tu dise\u00f1o<\/label>\n        <input type=\"file\" id=\"sim3d-upload\" accept=\"image\/*\">\n      <\/div>\n      <div class=\"sim3d-field\">\n        <label>Posici\u00f3n horizontal<\/label>\n        <input type=\"range\" id=\"sim3d-posx\" min=\"-100\" max=\"100\" value=\"0\">\n      <\/div>\n      <div class=\"sim3d-field\">\n        <label>Posici\u00f3n vertical<\/label>\n        <input type=\"range\" id=\"sim3d-posy\" min=\"-100\" max=\"100\" value=\"0\">\n      <\/div>\n      <div class=\"sim3d-field\">\n        <label>Tama\u00f1o del dise\u00f1o<\/label>\n        <input type=\"range\" id=\"sim3d-escala\" min=\"20\" max=\"200\" value=\"90\">\n      <\/div>\n      <button id=\"sim3d-reset\" class=\"sim3d-btn-secundario\" type=\"button\">Restablecer dise\u00f1o<\/button>\n      <button id=\"sim3d-autorotar\" class=\"sim3d-btn-secundario\" type=\"button\">Activar autorrotacion<\/button>\n      <div class=\"sim3d-cta\">\n        <p>\u00bfTe gusta c\u00f3mo se ve tu marca?<\/p>\n        <a href=\"https:\/\/microenvases.com\/cotiza\/\" class=\"sim3d-btn-cta\">Solicita tu cotizaci\u00f3n<\/a>\n      <\/div>\n    <\/div>\n  <\/div>\n  <canvas id=\"sim3d-texture\" width=\"1024\" height=\"512\" style=\"display:none\"><\/canvas>\n<\/div>\n<style>\n.sim3d-wrap{max-width:1000px;margin:0 auto;padding:20px 16px 40px;color:#333;}\n.sim3d-intro{font-size:17px;line-height:1.6;margin-bottom:24px;text-align:center;}\n.sim3d-grid{display:flex;gap:28px;flex-wrap:wrap;align-items:flex-start;}\n.sim3d-viewer{flex:1 1 560px;min-width:300px;}\n#sim3d-canvas-wrap{width:100%;height:460px;border-radius:14px;overflow:hidden;box-shadow:0 6px 24px rgba(0,0,0,.12);background:#f4f4f4;}\n#sim3d-canvas-wrap canvas{display:block;}\n.sim3d-hint{text-align:center;color:#777;font-size:14px;margin-top:10px;}\n.sim3d-controls{flex:1 1 300px;min-width:260px;background:#fafafa;border-radius:14px;padding:22px;box-shadow:0 2px 10px rgba(0,0,0,.06);}\n.sim3d-field{margin-bottom:18px;}\n.sim3d-field label{display:block;font-weight:600;margin-bottom:6px;font-size:14px;}\n.sim3d-radios label{font-weight:400;display:inline-flex;align-items:center;gap:6px;margin-right:16px;}\n.sim3d-field select,.sim3d-field input[type=\"file\"]{width:100%;padding:8px 10px;border-radius:8px;border:1px solid #ddd;font-family:inherit;}\n.sim3d-field input[type=\"range\"]{width:100%;accent-color:var(--red,#CC2229);}\n.sim3d-btn-secundario{width:100%;padding:10px;border-radius:8px;border:1px solid var(--red,#CC2229);background:#fff;color:var(--red,#CC2229);font-weight:600;cursor:pointer;margin-bottom:18px;transition:background .2s;}\n.sim3d-btn-secundario:hover{background:#fdecec;}\n.sim3d-cta{text-align:center;border-top:1px solid #e5e5e5;padding-top:18px;}\n.sim3d-cta p{margin:0 0 10px;font-size:14px;color:#555;}\n.sim3d-btn-cta{display:inline-block;background:var(--red,#CC2229);color:#fff !important;padding:12px 26px;border-radius:6px;font-weight:700;text-decoration:none;transition:background .2s,transform .2s;}\n.sim3d-btn-cta:hover{background:#a81b20;transform:translateY(-1px);}\n@media (max-width:700px){.sim3d-grid{flex-direction:column;}}\n<\/style>\n<script src=\"https:\/\/unpkg.com\/three@0.128.0\/build\/three.min.js\"><\/script>\n<script src=\"https:\/\/unpkg.com\/three@0.128.0\/examples\/js\/controls\/OrbitControls.js\"><\/script>\n<script>\n(function(){\n  function ready(){\n    var sizes = { fria: [7,12,16,21,32,44], caliente: [4,6,7,8,10,12,16] };\n    var canvasWrap = document.getElementById('sim3d-canvas-wrap');\n    var width = canvasWrap.clientWidth || 600;\n    var height = 460;\n    var scene = new THREE.Scene();\n    scene.background = new THREE.Color(0xf4f4f4);\n    var camera = new THREE.PerspectiveCamera(45, width\/height, 0.1, 100);\n    camera.position.set(0, 2, 9);\n    var renderer = new THREE.WebGLRenderer({antialias:true});\n    renderer.setSize(width, height);\n    canvasWrap.appendChild(renderer.domElement);\n    var controls = new THREE.OrbitControls(camera, renderer.domElement);\n    controls.enablePan = false;\n    controls.autoRotate = false;\n    controls.autoRotateSpeed = 2.5;\n    scene.add(new THREE.AmbientLight(0xffffff, 0.7));\n    var dir = new THREE.DirectionalLight(0xffffff, 0.8);\n    dir.position.set(5, 8, 6);\n    scene.add(dir);\n    var dir2 = new THREE.DirectionalLight(0xffffff, 0.3);\n    dir2.position.set(-5, -2, -4);\n    scene.add(dir2);\n    var texCanvas = document.getElementById('sim3d-texture');\n    var ctx = texCanvas.getContext('2d');\n    var texture = new THREE.CanvasTexture(texCanvas);\n    var cupMesh = null;\n    var innerMesh = null;\n    var uploadedImg = null;\n    var state = { tipo: 'fria', oz: 12, posx:0, posy:0, escala:90 };\n    function tipoColor(){ return state.tipo === 'caliente' ? '#f3e7d6' : '#ffffff'; }\n    function dibujarTextura(){\n      ctx.clearRect(0,0,texCanvas.width, texCanvas.height);\n      ctx.fillStyle = tipoColor();\n      ctx.fillRect(0,0,texCanvas.width, texCanvas.height);\n      if(uploadedImg){\n        var box = texCanvas.height * 0.8 * (state.escala\/100);\n        var ratio = uploadedImg.width\/uploadedImg.height;\n        var dw, dh;\n        if(ratio >= 1){ dw = box; dh = box\/ratio; } else { dh = box; dw = box*ratio; }\n        var cx = texCanvas.width\/2 + (state.posx\/100)*(texCanvas.width*0.35);\n        var cy = texCanvas.height\/2 + (state.posy\/100)*(texCanvas.height*0.35);\n        ctx.drawImage(uploadedImg, cx - dw\/2, cy - dh\/2, dw, dh);\n      } else {\n        ctx.fillStyle = '#CC2229';\n        ctx.font = 'bold 42px sans-serif';\n        ctx.textAlign = 'center';\n        ctx.textBaseline = 'middle';\n        ctx.fillText('Tu dise\u00f1o aqu\u00ed', texCanvas.width\/2, texCanvas.height\/2);\n      }\n      texture.needsUpdate = true;\n    }\n    function dimensiones(tipo, oz){\n      var top = 2.2 + 0.9*Math.sqrt(oz);\n      var taper = tipo === 'caliente' ? 0.69 : 0.72;\n      var bottom = top*taper;\n      var alturaFactor = tipo === 'caliente' ? 0.95 : 1.15;\n      var altura = 6 + 1.9*Math.sqrt(oz)*alturaFactor;\n      return { top: top, bottom: bottom, altura: altura };\n    }\n    function normalizarUValtura(geo){\n      var pos = geo.attributes.position;\n      var uv = geo.attributes.uv;\n      var minY = Infinity, maxY = -Infinity;\n      for (var i=0;i<pos.count;i++){ var y = pos.getY(i); if(y<minY) minY=y; if(y>maxY) maxY=y; }\n      var rangeY = (maxY-minY) || 1;\n      for (var i=0;i<pos.count;i++){ uv.setY(i, (pos.getY(i)-minY)\/rangeY); }\n      uv.needsUpdate = true;\n    }\n    function perfilVaso(Rb, Rt, H){\n      var footH = H*0.03;\n      var indent = H*0.035;\n      var rimH = H*0.025;\n      return [\n        new THREE.Vector2(0, indent),\n        new THREE.Vector2(Rb*0.78, indent*0.25),\n        new THREE.Vector2(Rb, 0),\n        new THREE.Vector2(Rb*1.015, footH),\n        new THREE.Vector2(Rt*0.985, H - rimH*1.6),\n        new THREE.Vector2(Rt, H - rimH*0.6),\n        new THREE.Vector2(Rt*1.09, H),\n        new THREE.Vector2(Rt*0.965, H - rimH*0.15)\n      ];\n    }\n    function reconstruirVaso(){\n      if(cupMesh){ scene.remove(cupMesh); cupMesh.geometry.dispose(); }\n      if(innerMesh){ scene.remove(innerMesh); innerMesh.material.dispose(); }\n      var d = dimensiones(state.tipo, state.oz);\n      controls.minDistance = d.altura*0.7;\n      controls.maxDistance = d.altura*3.5;\n      var raw = perfilVaso(d.bottom, d.top, d.altura);\n      var pts = raw.map(function(p){ return new THREE.Vector2(p.x, p.y - d.altura\/2); });\n      var geo = new THREE.LatheGeometry(pts, 48);\n      normalizarUValtura(geo);\n      var mat = new THREE.MeshStandardMaterial({ map: texture, roughness: 0.75, metalness: 0.05 });\n      cupMesh = new THREE.Mesh(geo, mat);\n      cupMesh.rotation.y = Math.PI;\n      scene.add(cupMesh);\n      var innerMat = new THREE.MeshStandardMaterial({ color: 0xffffff, side: THREE.BackSide, roughness: 0.9, metalness: 0 });\n      innerMesh = new THREE.Mesh(geo, innerMat);\n      innerMesh.rotation.y = Math.PI;\n      scene.add(innerMesh);\n      camera.position.set(0, d.altura*0.15, d.altura*1.6 + 3);\n      controls.target.set(0,0,0);\n      controls.update();\n    }\n    function actualizarTodo(){ dibujarTextura(); reconstruirVaso(); }\n    function poblarTamanos(){\n      var sel = document.getElementById('sim3d-tamano');\n      sel.innerHTML = '';\n      sizes[state.tipo].forEach(function(oz){\n        var opt = document.createElement('option');\n        opt.value = oz; opt.textContent = oz + ' oz';\n        sel.appendChild(opt);\n      });\n      state.oz = sizes[state.tipo][Math.floor(sizes[state.tipo].length\/2)];\n      sel.value = state.oz;\n    }\n    document.querySelectorAll('input[name=\"sim3d-tipo\"]').forEach(function(r){\n      r.addEventListener('change', function(e){ state.tipo = e.target.value; poblarTamanos(); actualizarTodo(); });\n    });\n    document.getElementById('sim3d-tamano').addEventListener('change', function(e){state.oz=parseFloat(e.target.value);reconstruirVaso();});\n    document.getElementById('sim3d-posx').addEventListener('input', function(e){ state.posx = parseFloat(e.target.value); dibujarTextura(); });\n    document.getElementById('sim3d-posy').addEventListener('input', function(e){ state.posy = parseFloat(e.target.value); dibujarTextura(); });\n    document.getElementById('sim3d-escala').addEventListener('input', function(e){ state.escala = parseFloat(e.target.value); dibujarTextura(); });\n    document.getElementById('sim3d-reset').addEventListener('click', function(){\n      state.posx = 0; state.posy = 0; state.escala = 90;\n      document.getElementById('sim3d-posx').value = 0;\n      document.getElementById('sim3d-posy').value = 0;\n      document.getElementById('sim3d-escala').value = 90;\n      dibujarTextura();\n    });\n    document.getElementById('sim3d-autorotar').addEventListener('click', function(){\n      controls.autoRotate = !controls.autoRotate;\n      var btn = document.getElementById('sim3d-autorotar');\n      if(controls.autoRotate){ btn.textContent = 'Detener autorrotacion'; } else { btn.textContent = 'Activar autorrotacion'; }\n    });\n    document.getElementById('sim3d-upload').addEventListener('change', function(e){\n      var file = e.target.files[0];\n      if(!file) return;\n      var reader = new FileReader();\n      reader.onload = function(ev){\n        var img = new Image();\n        img.onload = function(){ uploadedImg = img; dibujarTextura(); };\n        img.src = ev.target.result;\n      };\n      reader.readAsDataURL(file);\n    });\n    poblarTamanos();\n    actualizarTodo();\n    function animate(){ requestAnimationFrame(animate); controls.update(); renderer.render(scene, camera); }\n    animate();\n    window.addEventListener('resize', function(){\n      var w = canvasWrap.clientWidth || width;\n      renderer.setSize(w, height);\n      camera.aspect = w\/height;\n      camera.updateProjectionMatrix();\n    });\n  }\n  function waitForThree(){\n    var ok = false;\n    if(window.THREE){ if(window.THREE.OrbitControls){ ok = true; } }\n    if(ok){ ready(); } else { setTimeout(waitForThree, 150); }\n  }\n  waitForThree();\n\n})();\n<\/script>\n","protected":false},"excerpt":{"rendered":"<p>Sube el dise\u00f1o de tu marca, elige el tipo y tama\u00f1o de vaso, y visual\u00edzalo en 3D: puedes rotarlo, acercarlo y ajustar la posici\u00f3n de tu arte antes de imprimir. Arrastra para rotar &middot; Rueda del mouse para acercar o alejar Tipo de vaso Bebida Fr\u00eda Bebida Caliente Tama\u00f1o (oz) Sube tu dise\u00f1o Posici\u00f3n horizontal [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-1452","page","type-page","status-publish","hentry"],"acf":[],"_links":{"self":[{"href":"https:\/\/microenvases.com\/en\/wp-json\/wp\/v2\/pages\/1452","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/microenvases.com\/en\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/microenvases.com\/en\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/microenvases.com\/en\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/microenvases.com\/en\/wp-json\/wp\/v2\/comments?post=1452"}],"version-history":[{"count":14,"href":"https:\/\/microenvases.com\/en\/wp-json\/wp\/v2\/pages\/1452\/revisions"}],"predecessor-version":[{"id":1466,"href":"https:\/\/microenvases.com\/en\/wp-json\/wp\/v2\/pages\/1452\/revisions\/1466"}],"wp:attachment":[{"href":"https:\/\/microenvases.com\/en\/wp-json\/wp\/v2\/media?parent=1452"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}