{"id":2086,"date":"2026-03-06T12:19:42","date_gmt":"2026-03-06T11:19:42","guid":{"rendered":"https:\/\/paperontherocks.com\/?page_id=2086"},"modified":"2026-03-20T15:39:56","modified_gmt":"2026-03-20T14:39:56","slug":"notebook-builder","status":"publish","type":"page","link":"https:\/\/paperontherocks.com\/nl\/notebook-builder\/","title":{"rendered":"Notebook builder"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"2086\" class=\"elementor elementor-2086\" data-elementor-post-type=\"page\">\n\t\t\t\t<div class=\"elementor-element elementor-element-fb7f35d e-flex e-con-boxed e-con e-parent\" data-id=\"fb7f35d\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-7cbfe01 elementor-widget elementor-widget-html\" data-id=\"7cbfe01\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t\t<link href=\"https:\/\/fonts.googleapis.com\/css2?family=Rosario:wght@400;500;600&family=DM+Sans:wght@400;500&display=swap\" rel=\"stylesheet\">\n<script src=\"https:\/\/html2canvas.hertzen.com\/dist\/html2canvas.min.js\"><\/script>\n\n<style>\n:root{\n  --blue:#1E1AA8;\n  --green:#AFB559;\n  --bg:#F6F6F6;\n  --line:rgba(30,26,168,.18);\n  --line-strong:rgba(30,26,168,.38);\n  --text-soft:rgba(30,26,168,.68);\n  --cover:#1E1AA8;\n}\n\n.nb, .nb *{\n  box-sizing:border-box;\n}\n\n.nb{\n  background:var(--bg);\n  color:var(--blue);\n  font-family:'DM Sans',sans-serif !important;\n  padding:32px 24px 42px;\n}\n\n.nb button,\n.nb input,\n.nb textarea,\n.nb select{\n  font-family:'DM Sans',sans-serif !important;\n}\n\n.nb-wrap{\n  max-width:1240px;\n  margin:0 auto;\n}\n\n.nb-head{\n  margin-bottom:22px;\n}\n\n.nb-kicker{\n  font-family:'Rosario',serif !important;\n  font-size:9px !important;\n  line-height:1.2 !important;\n  letter-spacing:3px !important;\n  text-transform:uppercase !important;\n  color:var(--green) !important;\n  margin-bottom:8px !important;\n}\n\n.nb-title{\n  font-family:'Rosario',serif !important;\n  font-size:30px !important;\n  line-height:1.08 !important;\n  font-weight:500 !important;\n  letter-spacing:0 !important;\n  margin:0 !important;\n  color:var(--blue) !important;\n}\n\n.nb-title i{\n  font-style:italic !important;\n  font-weight:400 !important;\n}\n\n.nb-sub{\n  max-width:860px;\n  margin-top:10px;\n  font-size:13px;\n  line-height:1.65;\n  color:var(--text-soft);\n}\n\n.nb-grid{\n  display:grid;\n  grid-template-columns:380px 1fr;\n  gap:92px;\n  align-items:start;\n}\n\n.nb-left{\n  min-width:0;\n}\n\n.nb-section{\n  margin-bottom:18px;\n}\n\n.nb-label{\n  font-family:'Rosario',serif !important;\n  font-size:10px !important;\n  line-height:1.2 !important;\n  letter-spacing:2px !important;\n  text-transform:uppercase !important;\n  color:var(--blue) !important;\n  opacity:.56;\n  margin-bottom:8px !important;\n}\n\n.nb-choices{\n  display:grid;\n  grid-template-columns:1fr 1fr;\n  gap:10px;\n  max-width:560px;\n}\n\n.nb-choice{\n  border:1px solid var(--line);\n  min-height:48px;\n  padding:12px 14px;\n  display:flex;\n  align-items:center;\n  justify-content:center;\n  text-align:center;\n  cursor:pointer;\n  user-select:none;\n  transition:.16s ease;\n  background:transparent;\n  color:var(--blue);\n  font-family:'Rosario',serif !important;\n  font-size:17px !important;\n  line-height:1 !important;\n}\n\n.nb-choice:hover{\n  border-color:var(--line-strong);\n  background:rgba(255,255,255,.22);\n}\n\n.nb-choice.is-active{\n  border-color:var(--blue);\n  background:rgba(30,26,168,.03);\n}\n\n.nb-color-row{\n  display:grid;\n  grid-template-columns:46px 1fr;\n  gap:10px;\n  align-items:center;\n  max-width:560px;\n}\n\n.nb-color-picker{\n  width:46px;\n  height:46px;\n  border:1px solid var(--line);\n  background:#fff;\n  border-radius:4px;\n  padding:0;\n  cursor:pointer;\n}\n\n.nb-input,\n.nb-textarea{\n  width:100%;\n  border:1px solid var(--line);\n  background:rgba(255,255,255,.92);\n  color:var(--blue);\n  padding:9px 10px;\n  font-size:12px;\n  line-height:1.35;\n  outline:none;\n}\n\n.nb-input:focus,\n.nb-textarea:focus{\n  border-color:var(--line-strong);\n  background:#fff;\n}\n\n.nb-textarea{\n  min-height:86px;\n  resize:vertical;\n}\n\n.nb-help{\n  font-size:11px;\n  line-height:1.48;\n  color:var(--text-soft);\n  margin-top:6px;\n  max-width:560px;\n}\n\n.nb-upload-row{\n  display:flex;\n  align-items:center;\n  gap:10px;\n  flex-wrap:wrap;\n  max-width:560px;\n}\n\n.nb-file{\n  position:absolute;\n  width:1px;\n  height:1px;\n  opacity:0;\n  pointer-events:none;\n}\n\n.nb-upload-btn{\n  display:inline-flex;\n  align-items:center;\n  justify-content:center;\n  min-height:31px;\n  padding:5px 10px;\n  border:1px solid rgba(30,26,168,.28);\n  color:var(--blue);\n  background:transparent;\n  font-size:10.5px;\n  font-weight:500;\n  line-height:1;\n  cursor:pointer;\n  transition:.15s ease;\n}\n\n.nb-upload-btn:hover{\n  border-color:rgba(30,26,168,.5);\n  background:rgba(255,255,255,.32);\n}\n\n.nb-file-name{\n  font-size:12px;\n  color:var(--text-soft);\n}\n\n.nb-slider-row{\n  display:grid;\n  grid-template-columns:1fr auto;\n  gap:12px;\n  align-items:center;\n  max-width:560px;\n}\n\n.nb-range{\n  width:100%;\n  accent-color:var(--blue);\n}\n\n.nb-range-value{\n  min-width:58px;\n  text-align:right;\n  font-family:'Rosario',serif !important;\n  font-size:12px !important;\n  color:var(--blue);\n}\n\n.nb-tools{\n  display:flex;\n  gap:8px;\n  flex-wrap:wrap;\n  max-width:360px;\n}\n\n.nb-tool{\n  display:inline-flex;\n  align-items:center;\n  justify-content:center;\n  min-height:31px;\n  padding:5px 10px;\n  border:1px solid rgba(30,26,168,.28);\n  color:var(--blue);\n  background:transparent;\n  font-size:10.5px;\n  font-weight:500;\n  line-height:1;\n  cursor:pointer;\n  transition:.15s ease;\n  user-select:none;\n}\n\n.nb-tool:hover{\n  border-color:rgba(30,26,168,.5);\n  background:rgba(255,255,255,.32);\n}\n\n.nb-form{\n  max-width:420px;\n}\n\n.nb-form .nb-input,\n.nb-form .nb-textarea{\n  margin-top:8px;\n}\n\n.nb-submit{\n  margin-top:12px;\n  width:100%;\n  min-height:36px;\n  border:none;\n  background:var(--blue);\n  color:#fff;\n  font-size:10.5px;\n  font-weight:500;\n  letter-spacing:.08em;\n  text-transform:uppercase;\n  cursor:pointer;\n  padding:8px 12px;\n}\n\n.nb-submit:disabled{\n  opacity:.65;\n  cursor:default;\n}\n\n.nb-status{\n  margin-top:10px;\n  font-size:12px;\n  line-height:1.45;\n  color:var(--text-soft);\n  display:none;\n}\n\n.nb-status.show{\n  display:block;\n}\n\n.nb-summary{\n  margin-top:16px;\n  font-size:12px;\n  line-height:1.55;\n  color:var(--text-soft);\n}\n\n.nb-summary div{\n  margin-bottom:2px;\n}\n\n.nb-summary b{\n  color:var(--blue);\n  font-weight:500;\n}\n\n.nb-right{\n  display:flex;\n  justify-content:center;\n  align-items:flex-start;\n  min-height:560px;\n}\n\n.nb-book{\n  position:relative;\n  width:300px;\n  height:424.2px;\n}\n\n.nb-book .shadow{\n  position:absolute;\n  width:78%;\n  height:18px;\n  bottom:-18px;\n  left:11%;\n  background:rgba(0,0,0,.12);\n  filter:blur(24px);\n}\n\n.nb-book .pages{\n  position:absolute;\n  top:0;\n  left:12px;\n  width:calc(100% - 2px);\n  height:100%;\n  background:#f4f4f4;\n  border-radius:0 18px 18px 0;\n  box-shadow:inset -1px 0 0 rgba(0,0,0,.04);\n  transition:.18s ease;\n}\n\n.nb-book .spine{\n  position:absolute;\n  top:0;\n  left:0;\n  width:10px;\n  height:100%;\n  border-radius:12px 0 0 12px;\n  background:linear-gradient(\n    90deg,\n    rgba(0,0,0,.22) 0%,\n    rgba(0,0,0,.12) 42%,\n    rgba(255,255,255,.06) 100%\n  );\n  transition:.18s ease;\n}\n\n.nb-book .cover{\n  position:absolute;\n  top:0;\n  left:8px;\n  width:calc(100% - 8px);\n  height:100%;\n  border-radius:18px;\n  background:var(--cover);\n  box-shadow:\n    0 18px 34px rgba(0,0,0,.14),\n    0 3px 8px rgba(0,0,0,.08),\n    inset 0 1px 0 rgba(255,255,255,.08);\n  overflow:hidden;\n  transition:.18s ease;\n}\n\n.nb-book .cover::before{\n  content:\"\";\n  position:absolute;\n  inset:0;\n  background:linear-gradient(120deg,rgba(255,255,255,.09),transparent 34%);\n  pointer-events:none;\n}\n\n.nb-book .safe{\n  position:absolute;\n  top:8%;\n  left:8%;\n  width:84%;\n  height:84%;\n  border:1px dashed rgba(0,0,0,.10);\n  display:none;\n  pointer-events:none;\n}\n\n.nb-book .guide-x,\n.nb-book .guide-y{\n  position:absolute;\n  background:rgba(30,26,168,.16);\n  display:none;\n  pointer-events:none;\n  z-index:4;\n}\n\n.nb-book .guide-x{\n  left:0;\n  right:0;\n  height:1px;\n  top:50%;\n}\n\n.nb-book .guide-y{\n  top:0;\n  bottom:0;\n  width:1px;\n  left:50%;\n}\n\n.nb-book .logo{\n  position:absolute;\n  width:36px;\n  display:none;\n  max-width:none;\n  user-select:none;\n  -webkit-user-drag:none;\n  cursor:move;\n  z-index:5;\n  transform-origin:center center;\n}\n\n.nb-book.is-back .pages{\n  left:0;\n  width:calc(100% - 12px);\n  border-radius:18px 0 0 18px;\n}\n\n.nb-book.is-back .spine{\n  left:auto;\n  right:0;\n  border-radius:0 12px 12px 0;\n}\n\n.nb-book.is-back .cover{\n  left:0;\n  width:calc(100% - 8px);\n}\n\n.nb-book.softcover .pages{\n  display:none;\n}\n\n.nb-book.softcover .spine{\n  width:6px;\n  opacity:.75;\n}\n\n.nb-book.softcover .cover{\n  border-radius:10px;\n  box-shadow:\n    0 14px 26px rgba(0,0,0,.10),\n    0 2px 4px rgba(0,0,0,.05),\n    inset 0 1px 0 rgba(255,255,255,.06);\n}\n\n.nb-book.softcover.is-back .cover{\n  border-radius:10px;\n}\n\n@media(max-width:900px){\n  .nb-grid{\n    grid-template-columns:1fr;\n    gap:32px;\n  }\n\n  .nb-right{\n    min-height:auto;\n  }\n\n  .nb-book{\n    width:260px;\n    height:367.64px;\n  }\n}\n<\/style>\n\n<div class=\"nb\">\n  <div class=\"nb-wrap\">\n    <div class=\"nb-head\">\n      <div class=\"nb-kicker\">Notebook builder<\/div>\n      <h2 class=\"nb-title\">Design your <i>notebook<\/i><\/h2>\n      <div class=\"nb-sub\">\n        Choose your format, cover type and placement, pick your base colour, upload your logo and position it on the cover. This creates a concept preview; our studio prepares the final production file. Minimum order: 250 pieces.\n      <\/div>\n    <\/div>\n\n    <div class=\"nb-grid\">\n      <div class=\"nb-left\">\n\n        <div class=\"nb-section\">\n          <div class=\"nb-label\">Format<\/div>\n          <div class=\"nb-choices\" id=\"formatChoices\">\n            <div class=\"nb-choice is-active\" data-format=\"A6\" data-width=\"260\">A6<\/div>\n            <div class=\"nb-choice\" data-format=\"A5\" data-width=\"330\">A5<\/div>\n            <div class=\"nb-choice\" data-format=\"A4\" data-width=\"420\">A4<\/div>\n          <\/div>\n        <\/div>\n\n        <div class=\"nb-section\">\n          <div class=\"nb-label\">Cover type<\/div>\n          <div class=\"nb-choices\" id=\"coverTypeChoices\">\n            <div class=\"nb-choice is-active\" data-cover=\"hard\">Hardcover<\/div>\n            <div class=\"nb-choice\" data-cover=\"soft\">Softcover<\/div>\n          <\/div>\n        <\/div>\n\n        <div class=\"nb-section\">\n          <div class=\"nb-label\">Logo placement<\/div>\n          <div class=\"nb-choices\" id=\"placementChoices\">\n            <div class=\"nb-choice is-active\" data-placement=\"front\">Front cover<\/div>\n            <div class=\"nb-choice\" data-placement=\"back\">Back cover<\/div>\n          <\/div>\n        <\/div>\n\n        <div class=\"nb-section\">\n          <div class=\"nb-label\">Cover colour<\/div>\n          <div class=\"nb-color-row\">\n            <input type=\"color\" id=\"colorPicker\" class=\"nb-color-picker\" value=\"#1E1AA8\">\n            <input class=\"nb-input\" id=\"hexInput\" value=\"#1E1AA8\" placeholder=\"#1E1AA8\">\n          <\/div>\n          <div class=\"nb-help\">Pick your notebook colour. The preview updates instantly.<\/div>\n        <\/div>\n\n        <div class=\"nb-section\">\n          <div class=\"nb-label\">Upload logo<\/div>\n          <div class=\"nb-upload-row\">\n            <label for=\"logoUpload\" class=\"nb-upload-btn\">Choose file<\/label>\n            <span class=\"nb-file-name\" id=\"fileName\">No file chosen<\/span>\n            <input class=\"nb-file\" type=\"file\" id=\"logoUpload\" accept=\"image\/*,.svg,.png,.jpg,.jpeg,.webp\">\n          <\/div>\n          <div class=\"nb-help\">Upload a logo or visual, then drag it to position it on the selected cover side.<\/div>\n        <\/div>\n\n        <div class=\"nb-section\">\n          <div class=\"nb-label\">Logo size<\/div>\n          <div class=\"nb-slider-row\">\n            <input type=\"range\" id=\"logoSizeSlider\" class=\"nb-range\" min=\"20\" max=\"180\" step=\"1\" value=\"36\">\n            <div class=\"nb-range-value\" id=\"logoSizeValueLabel\">36 px<\/div>\n          <\/div>\n        <\/div>\n\n        <div class=\"nb-section\">\n          <div class=\"nb-label\">Logo rotation<\/div>\n          <div class=\"nb-slider-row\">\n            <input type=\"range\" id=\"logoRotateSlider\" class=\"nb-range\" min=\"-180\" max=\"180\" step=\"1\" value=\"0\">\n            <div class=\"nb-range-value\" id=\"logoRotateValueLabel\">0\u00b0<\/div>\n          <\/div>\n        <\/div>\n\n        <div class=\"nb-section\">\n          <div class=\"nb-tools\">\n            <div class=\"nb-tool\" id=\"centerLogo\">Center logo<\/div>\n            <div class=\"nb-tool\" id=\"previewBtn\">Download preview<\/div>\n          <\/div>\n        <\/div>\n\n        <div class=\"nb-section\">\n          <div class=\"nb-label\">Quantity (MOQ 250)<\/div>\n          <input class=\"nb-input\" type=\"number\" id=\"qty\" min=\"250\" value=\"250\">\n        <\/div>\n\n        <form class=\"nb-form\" id=\"designForm\">\n          <input class=\"nb-input\" id=\"fieldName\" name=\"name\" placeholder=\"Name\" required>\n          <input class=\"nb-input\" id=\"fieldCompany\" name=\"company\" placeholder=\"Company\" required>\n          <input class=\"nb-input\" id=\"fieldEmail\" name=\"email\" type=\"email\" placeholder=\"Email\" required>\n          <textarea class=\"nb-textarea\" id=\"fieldMessage\" name=\"message\" placeholder=\"Extra notes (optional)\"><\/textarea>\n\n          <button class=\"nb-submit\" id=\"submitBtn\" type=\"submit\">Submit design request<\/button>\n          <div class=\"nb-status\" id=\"formStatus\"><\/div>\n        <\/form>\n\n        <div class=\"nb-summary\">\n          <div><b>Format:<\/b> <span id=\"sumFormat\">A6<\/span><\/div>\n          <div><b>Cover type:<\/b> <span id=\"sumCover\">Hardcover<\/span><\/div>\n          <div><b>Placement:<\/b> <span id=\"sumPlacement\">Front cover<\/span><\/div>\n          <div><b>Logo size:<\/b> <span id=\"sumLogo\">36 px<\/span><\/div>\n          <div><b>Rotation:<\/b> <span id=\"sumRotation\">0\u00b0<\/span><\/div>\n          <div><b>Quantity:<\/b> <span id=\"sumQty\">250<\/span><\/div>\n          <div><b>Colour:<\/b> <span id=\"sumColour\">#1E1AA8<\/span><\/div>\n        <\/div>\n      <\/div>\n\n      <div class=\"nb-right\">\n        <div class=\"nb-book hardcover is-front\" id=\"book\">\n          <div class=\"shadow\"><\/div>\n          <div class=\"pages\"><\/div>\n          <div class=\"spine\" id=\"spine\"><\/div>\n          <div class=\"cover\" id=\"cover\">\n            <div class=\"safe\" id=\"safeArea\"><\/div>\n            <div class=\"guide-x\" id=\"guideX\"><\/div>\n            <div class=\"guide-y\" id=\"guideY\"><\/div>\n            <img id=\"logo\" class=\"logo\" alt=\"\">\n          <\/div>\n        <\/div>\n      <\/div>\n    <\/div>\n  <\/div>\n<\/div>\n\n<script>\nconst FORM_ENDPOINT = \"https:\/\/formspree.io\/f\/xvzwpwqa\";\nconst ISO_RATIO = 1.414;\nconst SNAP_TOLERANCE = 8;\n\nconst book = document.getElementById(\"book\");\nconst cover = document.getElementById(\"cover\");\nconst spine = document.getElementById(\"spine\");\nconst logo = document.getElementById(\"logo\");\nconst safeArea = document.getElementById(\"safeArea\");\nconst guideX = document.getElementById(\"guideX\");\nconst guideY = document.getElementById(\"guideY\");\n\nconst colorPicker = document.getElementById(\"colorPicker\");\nconst hexInput = document.getElementById(\"hexInput\");\nconst logoUpload = document.getElementById(\"logoUpload\");\nconst fileName = document.getElementById(\"fileName\");\nconst logoSizeSlider = document.getElementById(\"logoSizeSlider\");\nconst logoRotateSlider = document.getElementById(\"logoRotateSlider\");\nconst logoSizeValueLabel = document.getElementById(\"logoSizeValueLabel\");\nconst logoRotateValueLabel = document.getElementById(\"logoRotateValueLabel\");\nconst qty = document.getElementById(\"qty\");\n\nconst sumFormat = document.getElementById(\"sumFormat\");\nconst sumCover = document.getElementById(\"sumCover\");\nconst sumPlacement = document.getElementById(\"sumPlacement\");\nconst sumLogo = document.getElementById(\"sumLogo\");\nconst sumRotation = document.getElementById(\"sumRotation\");\nconst sumQty = document.getElementById(\"sumQty\");\nconst sumColour = document.getElementById(\"sumColour\");\n\nconst designForm = document.getElementById(\"designForm\");\nconst submitBtn = document.getElementById(\"submitBtn\");\nconst formStatus = document.getElementById(\"formStatus\");\n\nlet currentRotation = 0;\nlet currentPlacement = \"front\";\nlet currentCoverType = \"hard\";\nlet currentFormat = \"A6\";\nlet currentLogoFile = null;\nlet dragging = false;\nlet offsetX = 0;\nlet offsetY = 0;\n\nfunction darkenHex(hexColor, amount = 0.22){\n  const hex = hexColor.replace(\"#\", \"\");\n  const full = hex.length === 3 ? hex.split(\"\").map(c => c + c).join(\"\") : hex;\n  const num = parseInt(full, 16);\n  let r = (num >> 16) & 255;\n  let g = (num >> 8) & 255;\n  let b = num & 255;\n  r = Math.max(0, Math.floor(r * (1 - amount)));\n  g = Math.max(0, Math.floor(g * (1 - amount)));\n  b = Math.max(0, Math.floor(b * (1 - amount)));\n  return `rgb(${r}, ${g}, ${b})`;\n}\n\nfunction setCoverColor(value){\n  cover.style.background = value;\n  spine.style.background = `linear-gradient(\n    90deg,\n    ${darkenHex(value, 0.30)} 0%,\n    ${darkenHex(value, 0.18)} 45%,\n    ${darkenHex(value, 0.10)} 100%\n  )`;\n  hexInput.value = value.toUpperCase();\n  sumColour.textContent = value.toUpperCase();\n}\n\nfunction setNotebookSize(width){\n  const height = Math.round(width * ISO_RATIO * 100) \/ 100;\n  book.style.width = width + \"px\";\n  book.style.height = height + \"px\";\n  centerLogo();\n}\n\nfunction setCoverType(type){\n  currentCoverType = type;\n  book.classList.remove(\"hardcover\", \"softcover\");\n  book.classList.add(type === \"soft\" ? \"softcover\" : \"hardcover\");\n  sumCover.textContent = type === \"soft\" ? \"Softcover\" : \"Hardcover\";\n}\n\nfunction applyLogoTransform(){\n  let transform = `rotate(${currentRotation}deg)`;\n  if(currentPlacement === \"back\"){\n    transform += \" scaleX(-1)\";\n  }\n  logo.style.transform = transform;\n  sumRotation.textContent = `${currentRotation}\u00b0`;\n}\n\nfunction setPlacement(placement){\n  currentPlacement = placement;\n  book.classList.remove(\"is-front\", \"is-back\");\n  book.classList.add(placement === \"back\" ? \"is-back\" : \"is-front\");\n  sumPlacement.textContent = placement === \"back\" ? \"Back cover\" : \"Front cover\";\n  applyLogoTransform();\n  centerLogo();\n}\n\nfunction updateLogoSize(px){\n  logo.style.width = px + \"px\";\n  logoSizeSlider.value = px;\n  logoSizeValueLabel.textContent = px + \" px\";\n  sumLogo.textContent = px + \" px\";\n  centerLogo();\n}\n\nfunction updateLogoRotation(deg){\n  currentRotation = deg;\n  logoRotateSlider.value = deg;\n  logoRotateValueLabel.textContent = `${deg}\u00b0`;\n  applyLogoTransform();\n}\n\nfunction activateChoice(groupEl, clickedEl){\n  groupEl.querySelectorAll(\".nb-choice\").forEach(el => el.classList.remove(\"is-active\"));\n  clickedEl.classList.add(\"is-active\");\n}\n\nfunction centerLogo(){\n  if(!logo.src) return;\n\n  const logoWidth = logo.offsetWidth || parseInt(getComputedStyle(logo).width, 10) || 36;\n  const ratio = logo.naturalHeight && logo.naturalWidth ? (logo.naturalHeight \/ logo.naturalWidth) : 1;\n  const logoHeight = logo.offsetHeight || (logoWidth * ratio);\n\n  const x = (cover.clientWidth - logoWidth) \/ 2;\n  const y = (cover.clientHeight - logoHeight) \/ 2;\n\n  logo.style.left = x + \"px\";\n  logo.style.top = y + \"px\";\n}\n\nfunction getLogoMetrics(){\n  return {\n    x: Math.round(parseFloat(logo.style.left || \"0\")),\n    y: Math.round(parseFloat(logo.style.top || \"0\")),\n    width: Math.round(logo.offsetWidth || 0),\n    height: Math.round(logo.offsetHeight || 0)\n  };\n}\n\nfunction showGuides(showX, showY){\n  guideX.style.display = showX ? \"block\" : \"none\";\n  guideY.style.display = showY ? \"block\" : \"none\";\n}\n\nfunction moveLogo(clientX, clientY){\n  const rect = cover.getBoundingClientRect();\n  const logoWidth = logo.offsetWidth;\n  const logoHeight = logo.offsetHeight;\n\n  let x = clientX - rect.left - offsetX;\n  let y = clientY - rect.top - offsetY;\n\n  const maxX = cover.clientWidth - logoWidth;\n  const maxY = cover.clientHeight - logoHeight;\n\n  x = Math.max(0, Math.min(x, maxX));\n  y = Math.max(0, Math.min(y, maxY));\n\n  const targetCenterX = (cover.clientWidth - logoWidth) \/ 2;\n  const targetCenterY = (cover.clientHeight - logoHeight) \/ 2;\n\n  let snapX = false;\n  let snapY = false;\n\n  if(Math.abs(x - targetCenterX) < SNAP_TOLERANCE){\n    x = targetCenterX;\n    snapY = true;\n  }\n  if(Math.abs(y - targetCenterY) < SNAP_TOLERANCE){\n    y = targetCenterY;\n    snapX = true;\n  }\n\n  showGuides(snapX, snapY);\n\n  logo.style.left = x + \"px\";\n  logo.style.top = y + \"px\";\n}\n\nasync function generatePreviewBlob(){\n  const canvas = await html2canvas(book, {\n    backgroundColor: null,\n    scale: 2\n  });\n  return await new Promise(resolve => canvas.toBlob(resolve, \"image\/png\"));\n}\n\nfunction showStatus(message, ok = true){\n  formStatus.textContent = message;\n  formStatus.classList.add(\"show\");\n  formStatus.style.color = ok ? \"rgba(30,26,168,.75)\" : \"#a33\";\n}\n\ndocument.getElementById(\"formatChoices\").querySelectorAll(\".nb-choice\").forEach(el => {\n  el.addEventListener(\"click\", function(){\n    activateChoice(document.getElementById(\"formatChoices\"), this);\n    currentFormat = this.dataset.format;\n    setNotebookSize(parseInt(this.dataset.width, 10));\n    sumFormat.textContent = currentFormat;\n  });\n});\n\ndocument.getElementById(\"coverTypeChoices\").querySelectorAll(\".nb-choice\").forEach(el => {\n  el.addEventListener(\"click\", function(){\n    activateChoice(document.getElementById(\"coverTypeChoices\"), this);\n    setCoverType(this.dataset.cover);\n  });\n});\n\ndocument.getElementById(\"placementChoices\").querySelectorAll(\".nb-choice\").forEach(el => {\n  el.addEventListener(\"click\", function(){\n    activateChoice(document.getElementById(\"placementChoices\"), this);\n    setPlacement(this.dataset.placement);\n  });\n});\n\ncolorPicker.addEventListener(\"input\", e => {\n  setCoverColor(e.target.value);\n});\n\nhexInput.addEventListener(\"input\", e => {\n  const value = e.target.value.trim();\n  if(\/^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$\/.test(value)){\n    colorPicker.value = value;\n    setCoverColor(value);\n  }\n});\n\nlogoUpload.addEventListener(\"change\", e => {\n  const file = e.target.files[0];\n  if(!file) return;\n  currentLogoFile = file;\n  fileName.textContent = file.name;\n  const reader = new FileReader();\n  reader.onload = ev => {\n    logo.src = ev.target.result;\n    logo.style.display = \"block\";\n    safeArea.style.display = \"block\";\n    updateLogoSize(parseInt(logoSizeSlider.value, 10));\n    applyLogoTransform();\n    centerLogo();\n  };\n  reader.readAsDataURL(file);\n});\n\nlogoSizeSlider.addEventListener(\"input\", e => {\n  updateLogoSize(parseInt(e.target.value, 10));\n});\n\nlogoRotateSlider.addEventListener(\"input\", e => {\n  updateLogoRotation(parseInt(e.target.value, 10));\n});\n\nqty.addEventListener(\"input\", e => {\n  sumQty.textContent = e.target.value;\n});\n\ndocument.getElementById(\"centerLogo\").addEventListener(\"click\", centerLogo);\n\ndocument.getElementById(\"previewBtn\").addEventListener(\"click\", async () => {\n  const blob = await generatePreviewBlob();\n  const link = document.createElement(\"a\");\n  link.download = \"notebook-preview.png\";\n  link.href = URL.createObjectURL(blob);\n  link.click();\n  setTimeout(() => URL.revokeObjectURL(link.href), 1000);\n});\n\nlogo.addEventListener(\"mousedown\", e => {\n  if(!logo.src) return;\n  dragging = true;\n  offsetX = e.offsetX;\n  offsetY = e.offsetY;\n});\n\ndocument.addEventListener(\"mouseup\", () => {\n  dragging = false;\n  showGuides(false, false);\n});\n\ndocument.addEventListener(\"mousemove\", e => {\n  if(!dragging) return;\n  moveLogo(e.clientX, e.clientY);\n});\n\nlogo.addEventListener(\"touchstart\", e => {\n  if(!logo.src) return;\n  dragging = true;\n  const touch = e.touches[0];\n  const logoRect = logo.getBoundingClientRect();\n  offsetX = touch.clientX - logoRect.left;\n  offsetY = touch.clientY - logoRect.top;\n}, {passive:true});\n\ndocument.addEventListener(\"touchend\", () => {\n  dragging = false;\n  showGuides(false, false);\n});\n\ndocument.addEventListener(\"touchmove\", e => {\n  if(!dragging) return;\n  const touch = e.touches[0];\n  moveLogo(touch.clientX, touch.clientY);\n}, {passive:true});\n\ndesignForm.addEventListener(\"submit\", async (e) => {\n  e.preventDefault();\n\n  const name = document.getElementById(\"fieldName\").value.trim();\n  const company = document.getElementById(\"fieldCompany\").value.trim();\n  const email = document.getElementById(\"fieldEmail\").value.trim();\n  const message = document.getElementById(\"fieldMessage\").value.trim();\n\n  if(!name || !company || !email){\n    showStatus(\"Please complete the required fields.\", false);\n    return;\n  }\n\n  submitBtn.disabled = true;\n  showStatus(\"Sending your design request...\", true);\n\n  try{\n    const previewBlob = await generatePreviewBlob();\n    const metrics = getLogoMetrics();\n\n    const fd = new FormData();\n    fd.append(\"_subject\", `Notebook design request - ${company} - ${currentFormat}`);\n    fd.append(\"Name\", name);\n    fd.append(\"Company\", company);\n    fd.append(\"Email\", email);\n    if(message) fd.append(\"Message\", message);\n\n    fd.append(\"Format\", currentFormat);\n    fd.append(\"Cover type\", currentCoverType === \"soft\" ? \"Softcover\" : \"Hardcover\");\n    fd.append(\"Placement\", currentPlacement === \"back\" ? \"Back cover\" : \"Front cover\");\n    fd.append(\"Colour\", hexInput.value.toUpperCase());\n    fd.append(\"Quantity\", qty.value || \"250\");\n\n    fd.append(\"Logo X\", String(metrics.x));\n    fd.append(\"Logo Y\", String(metrics.y));\n    fd.append(\"Logo width\", String(metrics.width));\n    fd.append(\"Logo height\", String(metrics.height));\n    fd.append(\"Logo size slider\", String(logoSizeSlider.value));\n    fd.append(\"Logo rotation\", String(currentRotation));\n\n    if(currentLogoFile){\n      fd.append(\"Logo file\", currentLogoFile, currentLogoFile.name);\n    }\n    if(previewBlob){\n      fd.append(\"Preview PNG\", previewBlob, \"notebook-preview.png\");\n    }\n\n    const res = await fetch(FORM_ENDPOINT, {\n      method: \"POST\",\n      body: fd,\n      headers: {\n        \"Accept\": \"application\/json\"\n      }\n    });\n\n    if(!res.ok){\n      throw new Error(\"Request failed\");\n    }\n\n    showStatus(\"Your design request has been sent successfully.\", true);\n    designForm.reset();\n    qty.value = \"250\";\n    sumQty.textContent = \"250\";\n    fileName.textContent = \"No file chosen\";\n    currentLogoFile = null;\n  }catch(err){\n    showStatus(\"Something went wrong while sending. Please try again.\", false);\n  }finally{\n    submitBtn.disabled = false;\n  }\n});\n\nsetCoverColor(\"#1E1AA8\");\nsetNotebookSize(260);\nsetCoverType(\"hard\");\nsetPlacement(\"front\");\nupdateLogoSize(36);\nupdateLogoRotation(0);\nsumQty.textContent = qty.value;\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>Notebook builder Design your notebook Choose your format, cover type and placement, pick your base colour, upload your logo and position it on the cover. This creates a concept preview; our studio prepares the final production file. Minimum order: 250 pieces. Format A6 A5 A4 Cover type Hardcover Softcover Logo placement Front cover Back cover [&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-2086","page","type-page","status-publish","hentry"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.4 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Notebook builder - Paper on the Rocks<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/paperontherocks.com\/nl\/notebook-builder\/\" \/>\n<meta property=\"og:locale\" content=\"nl_NL\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Notebook builder - Paper on the Rocks\" \/>\n<meta property=\"og:description\" content=\"Notebook builder Design your notebook Choose your format, cover type and placement, pick your base colour, upload your logo and position it on the cover. This creates a concept preview; our studio prepares the final production file. Minimum order: 250 pieces. Format A6 A5 A4 Cover type Hardcover Softcover Logo placement Front cover Back cover [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/paperontherocks.com\/nl\/notebook-builder\/\" \/>\n<meta property=\"og:site_name\" content=\"Paper on the Rocks\" \/>\n<meta property=\"article:modified_time\" content=\"2026-03-20T14:39:56+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/paperontherocks.com\/wp-content\/uploads\/2025\/09\/POTR_ourstory-header-scaled.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"2560\" \/>\n\t<meta property=\"og:image:height\" content=\"1440\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Geschatte leestijd\" \/>\n\t<meta name=\"twitter:data1\" content=\"1 minuut\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/paperontherocks.com\\\/notebook-builder\\\/\",\"url\":\"https:\\\/\\\/paperontherocks.com\\\/notebook-builder\\\/\",\"name\":\"Notebook builder - Paper on the Rocks\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/paperontherocks.com\\\/#website\"},\"datePublished\":\"2026-03-06T11:19:42+00:00\",\"dateModified\":\"2026-03-20T14:39:56+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/paperontherocks.com\\\/notebook-builder\\\/#breadcrumb\"},\"inLanguage\":\"nl-NL\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/paperontherocks.com\\\/notebook-builder\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/paperontherocks.com\\\/notebook-builder\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/paperontherocks.com\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Notebook builder\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/paperontherocks.com\\\/#website\",\"url\":\"https:\\\/\\\/paperontherocks.com\\\/\",\"name\":\"Paper on the Rocks\",\"description\":\"Make Paper History\",\"publisher\":{\"@id\":\"https:\\\/\\\/paperontherocks.com\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/paperontherocks.com\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"nl-NL\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/paperontherocks.com\\\/#organization\",\"name\":\"Paper on the Rocks\",\"alternateName\":\"On The Rocks B.V.\",\"url\":\"https:\\\/\\\/paperontherocks.com\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"nl-NL\",\"@id\":\"https:\\\/\\\/paperontherocks.com\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/paperontherocks.com\\\/wp-content\\\/uploads\\\/2025\\\/09\\\/POTR_logo__logo_Signature-blue.svg\",\"contentUrl\":\"https:\\\/\\\/paperontherocks.com\\\/wp-content\\\/uploads\\\/2025\\\/09\\\/POTR_logo__logo_Signature-blue.svg\",\"width\":943,\"height\":165,\"caption\":\"Paper on the Rocks\"},\"image\":{\"@id\":\"https:\\\/\\\/paperontherocks.com\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.instagram.com\\\/paperontherocks\\\/\",\"https:\\\/\\\/www.linkedin.com\\\/company\\\/paper-on-the-rocks\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Notebook builder - Paper on the Rocks","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:\/\/paperontherocks.com\/nl\/notebook-builder\/","og_locale":"nl_NL","og_type":"article","og_title":"Notebook builder - Paper on the Rocks","og_description":"Notebook builder Design your notebook Choose your format, cover type and placement, pick your base colour, upload your logo and position it on the cover. This creates a concept preview; our studio prepares the final production file. Minimum order: 250 pieces. Format A6 A5 A4 Cover type Hardcover Softcover Logo placement Front cover Back cover [&hellip;]","og_url":"https:\/\/paperontherocks.com\/nl\/notebook-builder\/","og_site_name":"Paper on the Rocks","article_modified_time":"2026-03-20T14:39:56+00:00","og_image":[{"width":2560,"height":1440,"url":"https:\/\/paperontherocks.com\/wp-content\/uploads\/2025\/09\/POTR_ourstory-header-scaled.jpg","type":"image\/jpeg"}],"twitter_card":"summary_large_image","twitter_misc":{"Geschatte leestijd":"1 minuut"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/paperontherocks.com\/notebook-builder\/","url":"https:\/\/paperontherocks.com\/notebook-builder\/","name":"Notebook builder - Paper on the Rocks","isPartOf":{"@id":"https:\/\/paperontherocks.com\/#website"},"datePublished":"2026-03-06T11:19:42+00:00","dateModified":"2026-03-20T14:39:56+00:00","breadcrumb":{"@id":"https:\/\/paperontherocks.com\/notebook-builder\/#breadcrumb"},"inLanguage":"nl-NL","potentialAction":[{"@type":"ReadAction","target":["https:\/\/paperontherocks.com\/notebook-builder\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/paperontherocks.com\/notebook-builder\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/paperontherocks.com\/"},{"@type":"ListItem","position":2,"name":"Notebook builder"}]},{"@type":"WebSite","@id":"https:\/\/paperontherocks.com\/#website","url":"https:\/\/paperontherocks.com\/","name":"Paper on the Rocks","description":"Make Paper History","publisher":{"@id":"https:\/\/paperontherocks.com\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/paperontherocks.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"nl-NL"},{"@type":"Organization","@id":"https:\/\/paperontherocks.com\/#organization","name":"Paper on the Rocks","alternateName":"On The Rocks B.V.","url":"https:\/\/paperontherocks.com\/","logo":{"@type":"ImageObject","inLanguage":"nl-NL","@id":"https:\/\/paperontherocks.com\/#\/schema\/logo\/image\/","url":"https:\/\/paperontherocks.com\/wp-content\/uploads\/2025\/09\/POTR_logo__logo_Signature-blue.svg","contentUrl":"https:\/\/paperontherocks.com\/wp-content\/uploads\/2025\/09\/POTR_logo__logo_Signature-blue.svg","width":943,"height":165,"caption":"Paper on the Rocks"},"image":{"@id":"https:\/\/paperontherocks.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.instagram.com\/paperontherocks\/","https:\/\/www.linkedin.com\/company\/paper-on-the-rocks"]}]}},"_links":{"self":[{"href":"https:\/\/paperontherocks.com\/nl\/wp-json\/wp\/v2\/pages\/2086","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/paperontherocks.com\/nl\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/paperontherocks.com\/nl\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/paperontherocks.com\/nl\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/paperontherocks.com\/nl\/wp-json\/wp\/v2\/comments?post=2086"}],"version-history":[{"count":31,"href":"https:\/\/paperontherocks.com\/nl\/wp-json\/wp\/v2\/pages\/2086\/revisions"}],"predecessor-version":[{"id":2246,"href":"https:\/\/paperontherocks.com\/nl\/wp-json\/wp\/v2\/pages\/2086\/revisions\/2246"}],"wp:attachment":[{"href":"https:\/\/paperontherocks.com\/nl\/wp-json\/wp\/v2\/media?parent=2086"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}