{"id":29,"date":"2025-09-02T12:33:10","date_gmt":"2025-09-02T12:33:10","guid":{"rendered":"https:\/\/kristofferwilliam.dk\/index.php\/portfolio\/"},"modified":"2026-06-27T18:04:09","modified_gmt":"2026-06-27T18:04:09","slug":"portfolio","status":"publish","type":"page","link":"https:\/\/kristofferwilliam.dk\/index.php\/portfolio\/","title":{"rendered":"Portfolio"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"29\" class=\"elementor elementor-29\">\n\t\t\t\t<div class=\"elementor-element elementor-element-30fbc20 e-flex e-con-boxed e-con e-parent\" data-id=\"30fbc20\" data-element_type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-9c70471 elementor-widget elementor-widget-html\" data-id=\"9c70471\" data-element_type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t\t<div id=\"reactbits-strands\"><\/div>\n\n<style>\n#reactbits-strands {\n  width: 100%;\n  height: 100vh;\n  background: #000000;\n  overflow: hidden;\n  position: relative;\n}\n\n#reactbits-strands canvas {\n  width: 100%;\n  height: 100%;\n  display: block;\n}\n<\/style>\n\n<script type=\"module\">\nimport {\n  Renderer,\n  Program,\n  Mesh,\n  Color,\n  Triangle\n} from \"https:\/\/esm.sh\/ogl\";\n\nconst container = document.querySelector(\"#reactbits-strands\");\n\nconst MAX_STRANDS = 12;\nconst MAX_COLORS = 8;\n\nconst VERT = `#version 300 es\nin vec2 position;\n\nvoid main() {\n  gl_Position = vec4(position, 0.0, 1.0);\n}\n`;\n\nconst FRAG = `#version 300 es\nprecision highp float;\n\nuniform float uTime;\nuniform vec2 uResolution;\nuniform vec3 uColors[8];\nuniform int uColorCount;\nuniform int uStrandCount;\nuniform float uSpeed;\nuniform float uAmplitude;\nuniform float uWaviness;\nuniform float uThickness;\nuniform float uGlow;\nuniform float uTaper;\nuniform float uSpread;\nuniform float uHueShift;\nuniform float uIntensity;\nuniform float uOpacity;\nuniform float uScale;\nuniform float uSaturation;\n\nout vec4 fragColor;\n\nconst float PI = 3.14159265;\n\nvec3 spectrum(float t) {\n  return 0.5 + 0.5 * cos(2.0 * PI * (t + vec3(0.00, 0.33, 0.67)));\n}\n\nvec3 samplePalette(float t) {\n  t = fract(t);\n  float scaled = t * float(uColorCount);\n  int idx = int(floor(scaled));\n  float blend = fract(scaled);\n\n  int nextIdx = idx + 1;\n  if (nextIdx >= uColorCount) nextIdx = 0;\n\n  return mix(uColors[idx], uColors[nextIdx], blend);\n}\n\nvec3 strandColor(float t) {\n  if (uColorCount > 0) return samplePalette(t);\n  return spectrum(t);\n}\n\nvoid main() {\n  vec2 uv = (gl_FragCoord.xy - 0.5 * uResolution) \/ uResolution.y;\n  uv \/= max(uScale, 0.0001);\n\n  float e = 0.06 + uIntensity * 0.94;\n  float env = pow(max(cos(uv.x * PI * 1.3), 0.0), uTaper);\n\n  vec3 col = vec3(0.0);\n\n  for (int i = 0; i < 12; i++) {\n    if (i >= uStrandCount) break;\n\n    float fi = float(i);\n    float ph = fi * 1.7 * uSpread;\n    float freq = (2.0 + fi * 0.35) * uWaviness;\n    float spd = 1.4 + fi * 1.2;\n\n    float tt = uTime * uSpeed;\n\n    float w = sin(uv.x * freq + tt * spd + ph) * 0.60\n            + sin(uv.x * freq * 1.1 - tt * spd * 0.7 + ph * 1.7) * 0.40;\n\n    float amp = (0.1 + 0.02 * e) * env * uAmplitude;\n    float y = w * amp;\n\n    float d = abs(uv.y - y);\n    float thick = (0.001 + 0.05 * e) * (0.35 + env) * uThickness;\n\n    float g = thick \/ (d + thick * 0.45);\n    g = g * g;\n\n    float h = fi \/ float(uStrandCount) + uv.x * 0.30 + uTime * 0.04 + uHueShift;\n\n    col += strandColor(h) * g * env;\n  }\n\n  col *= 0.45 + 0.7 * e;\n  col = 1.0 - exp(-col * uGlow);\n\n  float gray = dot(col, vec3(0.2126, 0.7152, 0.0722));\n  col = max(mix(vec3(gray), col, uSaturation), 0.0);\n\n  float lum = max(max(col.r, col.g), col.b);\n  float alpha = clamp(lum, 0.0, 1.0) * uOpacity;\n\n  fragColor = vec4(col * uOpacity, alpha);\n}\n`;\n\nfunction buildPalette(colors) {\n  const filled = colors && colors.length ? colors : [\"#ffffff\"];\n  const padded = [];\n\n  for (let i = 0; i < MAX_COLORS; i++) {\n    const hex = filled[i] ?? filled[filled.length - 1];\n    const c = new Color(hex);\n    padded.push([c.r, c.g, c.b]);\n  }\n\n  return padded;\n}\n\nif (container) {\n  const settings = {\n    colors: [\"#FF4242\", \"#7C3AED\", \"#06B6D4\", \"#EAB308\"],\n    count: 3,\n    speed: 0.5,\n    amplitude: 1,\n    waviness: 1,\n    thickness: 0.7,\n    glow: 2.6,\n    taper: 3,\n    spread: 1,\n    hueShift: 0,\n    intensity: 0.6,\n    saturation: 1.5,\n    opacity: 1,\n    scale: 1.5\n  };\n\n  const renderer = new Renderer({\n    alpha: true,\n    premultipliedAlpha: true,\n    antialias: true\n  });\n\n  const gl = renderer.gl;\n\n  gl.clearColor(0, 0, 0, 0);\n  gl.enable(gl.BLEND);\n  gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);\n\n  container.appendChild(gl.canvas);\n\n  const geometry = new Triangle(gl);\n\n  if (geometry.attributes.uv) {\n    delete geometry.attributes.uv;\n  }\n\n  const program = new Program(gl, {\n    vertex: VERT,\n    fragment: FRAG,\n    uniforms: {\n      uTime: { value: 0 },\n      uResolution: { value: [container.offsetWidth, container.offsetHeight] },\n      uColors: { value: buildPalette(settings.colors) },\n      uColorCount: { value: Math.min(settings.colors.length, MAX_COLORS) },\n      uStrandCount: { value: Math.min(settings.count, MAX_STRANDS) },\n      uSpeed: { value: settings.speed },\n      uAmplitude: { value: settings.amplitude },\n      uWaviness: { value: settings.waviness },\n      uThickness: { value: settings.thickness },\n      uGlow: { value: settings.glow },\n      uTaper: { value: settings.taper },\n      uSpread: { value: settings.spread },\n      uHueShift: { value: settings.hueShift },\n      uIntensity: { value: settings.intensity },\n      uOpacity: { value: settings.opacity },\n      uScale: { value: settings.scale },\n      uSaturation: { value: settings.saturation }\n    }\n  });\n\n  const mesh = new Mesh(gl, {\n    geometry,\n    program\n  });\n\n  function resize() {\n    const width = container.offsetWidth;\n    const height = container.offsetHeight;\n\n    renderer.setSize(width, height);\n    program.uniforms.uResolution.value = [width, height];\n  }\n\n  window.addEventListener(\"resize\", resize);\n  resize();\n\n  function update(t) {\n    requestAnimationFrame(update);\n\n    program.uniforms.uTime.value = t * 0.001;\n\n    renderer.render({\n      scene: mesh\n    });\n  }\n\n  requestAnimationFrame(update);\n}\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-63d34850 e-flex e-con-boxed e-con e-parent\" data-id=\"63d34850\" data-element_type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-693a71ea fade-in-up elementor-widget elementor-widget-heading\" data-id=\"693a71ea\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t\t<h1 class=\"elementor-heading-title elementor-size-default\">Project Portfolio<\/h1>\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-152ac140 fade-in-up elementor-widget elementor-widget-heading\" data-id=\"152ac140\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t\t<h5 class=\"elementor-heading-title elementor-size-default\">A short list of some of the projects, i have worked on.<\/h5>\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-734beec e-flex e-con-boxed e-con e-parent\" data-id=\"734beec\" data-element_type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-4361322 elementor-widget elementor-widget-html\" data-id=\"4361322\" data-element_type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t\t<section class=\"kw-scroll-stack\">\n  <div class=\"kw-stack-inner\">\n\n    <article class=\"kw-stack-card\">\n      <span>01<\/span>\n      <h2>ADVENTURE ALLEVEGNE<\/h2>\n      <p>Rejse- og oplevelsesplatform<\/p>\n      <small>UX\/UI \u2022 Webdesign \u2022 Branding<\/small>\n    <\/article>\n\n    <article class=\"kw-stack-card\">\n      <span>02<\/span>\n      <h2>NORVA<\/h2>\n      <p>Multibrand e-commerce platform<\/p>\n      <small>WordPress \u2022 WooCommerce \u2022 UX\/UI<\/small>\n    <\/article>\n\n    <article class=\"kw-stack-card\">\n      <span>03<\/span>\n      <h2>PLANTINO<\/h2>\n      <p>Digital planteservice platform<\/p>\n      <small>WordPress \u2022 Branding \u2022 UX<\/small>\n    <\/article>\n\n  <\/div>\n<\/section>\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-a46315b e-flex e-con-boxed e-con e-parent\" data-id=\"a46315b\" data-element_type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t<div class=\"elementor-element elementor-element-d397a2b e-con-full e-flex e-con e-child\" data-id=\"d397a2b\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-31799a4 fade-in-right elementor-widget elementor-widget-image\" data-id=\"31799a4\" data-element_type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<a href=\"https:\/\/plantino.lassebilgrav.dk\/\" target=\"_blank\">\n\t\t\t\t\t\t\t<img fetchpriority=\"high\" decoding=\"async\" width=\"500\" height=\"500\" src=\"https:\/\/kristofferwilliam.dk\/wp-content\/uploads\/2026\/06\/Norva.-5.png\" class=\"elementor-animation-grow attachment-large size-large wp-image-347\" alt=\"\" srcset=\"https:\/\/kristofferwilliam.dk\/wp-content\/uploads\/2026\/06\/Norva.-5.png 500w, https:\/\/kristofferwilliam.dk\/wp-content\/uploads\/2026\/06\/Norva.-5-300x300.png 300w, https:\/\/kristofferwilliam.dk\/wp-content\/uploads\/2026\/06\/Norva.-5-150x150.png 150w\" sizes=\"(max-width: 500px) 100vw, 500px\" \/>\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-ae6bfef e-con-full e-flex e-con e-child\" data-id=\"ae6bfef\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-5b5ef08 fade-in-up elementor-widget elementor-widget-image\" data-id=\"5b5ef08\" data-element_type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<a href=\"https:\/\/adventureallevegne.rasmusskaaning.dk\/\" target=\"_blank\">\n\t\t\t\t\t\t\t<img decoding=\"async\" width=\"500\" height=\"500\" src=\"https:\/\/kristofferwilliam.dk\/wp-content\/uploads\/2026\/06\/Norva.-4.png\" class=\"elementor-animation-grow attachment-large size-large wp-image-346\" alt=\"\" srcset=\"https:\/\/kristofferwilliam.dk\/wp-content\/uploads\/2026\/06\/Norva.-4.png 500w, https:\/\/kristofferwilliam.dk\/wp-content\/uploads\/2026\/06\/Norva.-4-300x300.png 300w, https:\/\/kristofferwilliam.dk\/wp-content\/uploads\/2026\/06\/Norva.-4-150x150.png 150w\" sizes=\"(max-width: 500px) 100vw, 500px\" \/>\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-3864594 e-con-full e-flex e-con e-child\" data-id=\"3864594\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-bfd58ae fade-in-left elementor-widget elementor-widget-image\" data-id=\"bfd58ae\" data-element_type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<a href=\"https:\/\/norva.kristofferwilliam.dk\/\" target=\"_blank\">\n\t\t\t\t\t\t\t<img decoding=\"async\" width=\"500\" height=\"500\" src=\"https:\/\/kristofferwilliam.dk\/wp-content\/uploads\/2026\/06\/Norva.-6.png\" class=\"elementor-animation-grow attachment-large size-large wp-image-348\" alt=\"\" srcset=\"https:\/\/kristofferwilliam.dk\/wp-content\/uploads\/2026\/06\/Norva.-6.png 500w, https:\/\/kristofferwilliam.dk\/wp-content\/uploads\/2026\/06\/Norva.-6-300x300.png 300w, https:\/\/kristofferwilliam.dk\/wp-content\/uploads\/2026\/06\/Norva.-6-150x150.png 150w\" sizes=\"(max-width: 500px) 100vw, 500px\" \/>\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-81e0e82 e-con-full e-flex e-con e-child\" data-id=\"81e0e82\" data-element_type=\"container\">\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-c8b6e90 e-con-full e-flex e-con e-child\" data-id=\"c8b6e90\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-e09fdc7 elementor-align-center fade-in-up elementor-invisible elementor-widget elementor-widget-button\" data-id=\"e09fdc7\" data-element_type=\"widget\" data-settings=\"{&quot;_animation&quot;:&quot;fadeInDown&quot;}\" data-widget_type=\"button.default\">\n\t\t\t\t\t\t\t\t\t\t<a class=\"elementor-button elementor-button-link elementor-size-sm\" href=\"https:\/\/library.elementor.com\/portfolio-wireframe-2-flexbox\/portfolio\/\">\n\t\t\t\t\t\t<span class=\"elementor-button-content-wrapper\">\n\t\t\t\t\t\t\t\t\t<span class=\"elementor-button-text\">View All Projects<\/span>\n\t\t\t\t\t<\/span>\n\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-96bd2e5 e-con-full e-flex e-con e-child\" data-id=\"96bd2e5\" data-element_type=\"container\">\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-d9adee3 e-flex e-con-boxed e-con e-parent\" data-id=\"d9adee3\" data-element_type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-4fa7095 elementor-widget elementor-widget-spacer\" data-id=\"4fa7095\" data-element_type=\"widget\" data-widget_type=\"spacer.default\">\n\t\t\t\t\t\t\t<div class=\"elementor-spacer\">\n\t\t\t<div class=\"elementor-spacer-inner\"><\/div>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-06d288e e-flex e-con-boxed e-con e-parent\" data-id=\"06d288e\" data-element_type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-8a79dcf elementor-widget elementor-widget-spacer\" data-id=\"8a79dcf\" data-element_type=\"widget\" data-widget_type=\"spacer.default\">\n\t\t\t\t\t\t\t<div class=\"elementor-spacer\">\n\t\t\t<div class=\"elementor-spacer-inner\"><\/div>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-2ead1c5 e-flex e-con-boxed e-con e-parent\" data-id=\"2ead1c5\" data-element_type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-00123ea fade-in-up elementor-widget elementor-widget-heading\" data-id=\"00123ea\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">FEATURED ANIMATIONS.<\/h2>\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-39edfa6 e-flex e-con-boxed e-con e-parent\" data-id=\"39edfa6\" data-element_type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-2866aac elementor-widget-divider--view-line elementor-widget elementor-widget-divider\" data-id=\"2866aac\" data-element_type=\"widget\" data-widget_type=\"divider.default\">\n\t\t\t\t\t\t\t<div class=\"elementor-divider\">\n\t\t\t<span class=\"elementor-divider-separator\">\n\t\t\t\t\t\t<\/span>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-857dc89 e-flex e-con-boxed e-con e-parent\" data-id=\"857dc89\" data-element_type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-4872a19 fade-in-up elementor-widget elementor-widget-heading\" data-id=\"4872a19\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Saurons eye<\/h2>\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-c8386cf e-flex e-con-boxed e-con e-parent\" data-id=\"c8386cf\" data-element_type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-50d6456 fade-in-up elementor-widget elementor-widget-text-editor\" data-id=\"50d6456\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t\t\t\t\t\t<p>Responsive to cursor.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-abfd962 e-flex e-con-boxed e-con e-parent\" data-id=\"abfd962\" data-element_type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-9f5be6b elementor-widget elementor-widget-html\" data-id=\"9f5be6b\" data-element_type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t\t<div id=\"evil-eye\" class=\"evil-eye-container\"><\/div>\n\n<style>\n  .evil-eye-container {\n    width: 100%;\n    height: 500px;\n    position: relative;\n    overflow: hidden;\n    background: #00000;\n  }\n\n  .evil-eye-container canvas {\n    width: 100%;\n    height: 100%;\n    display: block;\n  }\n<\/style>\n\n<script type=\"module\">\nimport { Renderer, Program, Mesh, Triangle, Texture } from \"https:\/\/esm.sh\/ogl\";\n\nconst container = document.querySelector(\"#evil-eye\");\n\nfunction hexToVec3(hex) {\n  const h = hex.replace(\"#\", \"\");\n  return [\n    parseInt(h.slice(0, 2), 16) \/ 255,\n    parseInt(h.slice(2, 4), 16) \/ 255,\n    parseInt(h.slice(4, 6), 16) \/ 255\n  ];\n}\n\nfunction generateNoiseTexture(size = 256) {\n  const data = new Uint8Array(size * size * 4);\n\n  function hash(x, y, s) {\n    let n = x * 374761393 + y * 668265263 + s * 1274126177;\n    n = Math.imul(n ^ (n >>> 13), 1274126177);\n    return ((n ^ (n >>> 16)) >>> 0) \/ 4294967296;\n  }\n\n  function noise(px, py, freq, seed) {\n    const fx = (px \/ size) * freq;\n    const fy = (py \/ size) * freq;\n    const ix = Math.floor(fx);\n    const iy = Math.floor(fy);\n    const tx = fx - ix;\n    const ty = fy - iy;\n    const w = freq | 0;\n\n    const v00 = hash(((ix % w) + w) % w, ((iy % w) + w) % w, seed);\n    const v10 = hash((((ix + 1) % w) + w) % w, ((iy % w) + w) % w, seed);\n    const v01 = hash(((ix % w) + w) % w, (((iy + 1) % w) + w) % w, seed);\n    const v11 = hash((((ix + 1) % w) + w) % w, (((iy + 1) % w) + w) % w, seed);\n\n    return v00 * (1 - tx) * (1 - ty) + v10 * tx * (1 - ty) + v01 * (1 - tx) * ty + v11 * tx * ty;\n  }\n\n  for (let y = 0; y < size; y++) {\n    for (let x = 0; x < size; x++) {\n      let v = 0;\n      let amp = 0.4;\n      let totalAmp = 0;\n\n      for (let o = 0; o < 8; o++) {\n        const f = 32 * (1 << o);\n        v += amp * noise(x, y, f, o * 31);\n        totalAmp += amp;\n        amp *= 0.65;\n      }\n\n      v \/= totalAmp;\n      v = (v - 0.5) * 2.2 + 0.5;\n      v = Math.max(0, Math.min(1, v));\n\n      const val = Math.round(v * 255);\n      const i = (y * size + x) * 4;\n\n      data[i] = val;\n      data[i + 1] = val;\n      data[i + 2] = val;\n      data[i + 3] = 255;\n    }\n  }\n\n  return data;\n}\n\nconst vertexShader = `\nattribute vec2 uv;\nattribute vec2 position;\nvarying vec2 vUv;\nvoid main() {\n  vUv = uv;\n  gl_Position = vec4(position, 0, 1);\n}\n`;\n\nconst fragmentShader = `\nprecision highp float;\n\nuniform float uTime;\nuniform vec3 uResolution;\nuniform sampler2D uNoiseTexture;\nuniform float uPupilSize;\nuniform float uIrisWidth;\nuniform float uGlowIntensity;\nuniform float uIntensity;\nuniform float uScale;\nuniform float uNoiseScale;\nuniform vec2 uMouse;\nuniform float uPupilFollow;\nuniform float uFlameSpeed;\nuniform vec3 uEyeColor;\nuniform vec3 uBgColor;\n\nvoid main() {\n  vec2 uv = (gl_FragCoord.xy * 2.0 - uResolution.xy) \/ uResolution.y;\n  uv \/= uScale;\n\n  float ft = uTime * uFlameSpeed;\n\n  float polarRadius = length(uv) * 2.0;\n  float polarAngle = (2.0 * atan(uv.x, uv.y)) \/ 6.28 * 0.3;\n  vec2 polarUv = vec2(polarRadius, polarAngle);\n\n  vec4 noiseA = texture2D(uNoiseTexture, polarUv * vec2(0.2, 7.0) * uNoiseScale + vec2(-ft * 0.1, 0.0));\n  vec4 noiseB = texture2D(uNoiseTexture, polarUv * vec2(0.3, 4.0) * uNoiseScale + vec2(-ft * 0.2, 0.0));\n  vec4 noiseC = texture2D(uNoiseTexture, polarUv * vec2(0.1, 5.0) * uNoiseScale + vec2(-ft * 0.1, 0.0));\n\n  float distanceMask = 1.0 - length(uv);\n\n  float innerRing = clamp(-1.0 * ((distanceMask - 0.7) \/ uIrisWidth), 0.0, 1.0);\n  innerRing = (innerRing * distanceMask - 0.2) \/ 0.28;\n  innerRing += noiseA.r - 0.5;\n  innerRing *= 1.3;\n  innerRing = clamp(innerRing, 0.0, 1.0);\n\n  float outerRing = clamp(-1.0 * ((distanceMask - 0.5) \/ 0.2), 0.0, 1.0);\n  outerRing = (outerRing * distanceMask - 0.1) \/ 0.38;\n  outerRing += noiseC.r - 0.5;\n  outerRing *= 1.3;\n  outerRing = clamp(outerRing, 0.0, 1.0);\n\n  innerRing += outerRing;\n\n  float innerEye = distanceMask - 0.1 * 2.0;\n  innerEye *= noiseB.r * 2.0;\n\n  vec2 pupilOffset = uMouse * uPupilFollow * 0.12;\n  vec2 pupilUv = uv - pupilOffset;\n\n  float pupil = 1.0 - length(pupilUv * vec2(9.0, 2.3));\n  pupil *= uPupilSize;\n  pupil = clamp(pupil, 0.0, 1.0);\n  pupil \/= 0.35;\n\n  float outerEyeGlow = 1.0 - length(uv * vec2(0.5, 1.5));\n  outerEyeGlow = clamp(outerEyeGlow + 0.5, 0.0, 1.0);\n  outerEyeGlow += noiseC.r - 0.5;\n\n  float outerBgGlow = outerEyeGlow;\n\n  outerEyeGlow = pow(outerEyeGlow, 2.0);\n  outerEyeGlow += distanceMask;\n  outerEyeGlow *= uGlowIntensity;\n  outerEyeGlow = clamp(outerEyeGlow, 0.0, 1.0);\n  outerEyeGlow *= pow(1.0 - distanceMask, 2.0) * 2.5;\n\n  outerBgGlow += distanceMask;\n  outerBgGlow = pow(outerBgGlow, 0.5);\n  outerBgGlow *= 0.15;\n\n  vec3 color = uEyeColor * uIntensity * clamp(max(innerRing + innerEye, outerEyeGlow + outerBgGlow) - pupil, 0.0, 3.0);\n  color += uBgColor;\n\n  gl_FragColor = vec4(color, 1.0);\n}\n`;\n\nif (container) {\n  const renderer = new Renderer({\n    alpha: true,\n    premultipliedAlpha: false\n  });\n\n  const gl = renderer.gl;\n  gl.clearColor(0, 0, 0, 0);\n\n  const noiseTexture = new Texture(gl, {\n    image: generateNoiseTexture(256),\n    width: 256,\n    height: 256,\n    generateMipmaps: false,\n    flipY: false\n  });\n\n  noiseTexture.minFilter = gl.LINEAR;\n  noiseTexture.magFilter = gl.LINEAR;\n  noiseTexture.wrapS = gl.REPEAT;\n  noiseTexture.wrapT = gl.REPEAT;\n\n  const mouse = {\n    x: 0,\n    y: 0,\n    tx: 0,\n    ty: 0\n  };\n\n  container.addEventListener(\"mousemove\", function(e) {\n    const rect = container.getBoundingClientRect();\n    mouse.tx = ((e.clientX - rect.left) \/ rect.width) * 2 - 1;\n    mouse.ty = -(((e.clientY - rect.top) \/ rect.height) * 2 - 1);\n  });\n\n  container.addEventListener(\"mouseleave\", function() {\n    mouse.tx = 0;\n    mouse.ty = 0;\n  });\n\n  const geometry = new Triangle(gl);\n\n  const program = new Program(gl, {\n    vertex: vertexShader,\n    fragment: fragmentShader,\n    uniforms: {\n      uTime: { value: 0 },\n      uResolution: { value: [1, 1, 1] },\n      uNoiseTexture: { value: noiseTexture },\n      uPupilSize: { value: 0.6 },\n      uIrisWidth: { value: 0.25 },\n      uGlowIntensity: { value: 0.35 },\n      uIntensity: { value: 1.5 },\n      uScale: { value: 0.8 },\n      uNoiseScale: { value: 1 },\n      uMouse: { value: [0, 0] },\n      uPupilFollow: { value: 1 },\n      uFlameSpeed: { value: 1 },\n      uEyeColor: { value: hexToVec3(\"#FF6F37\") },\n      uBgColor: { value: hexToVec3(\"#00000\") }\n    }\n  });\n\n  const mesh = new Mesh(gl, {\n    geometry,\n    program\n  });\n\n  container.appendChild(gl.canvas);\n\n  function resize() {\n    renderer.setSize(container.offsetWidth, container.offsetHeight);\n    program.uniforms.uResolution.value = [\n      gl.canvas.width,\n      gl.canvas.height,\n      gl.canvas.width \/ gl.canvas.height\n    ];\n  }\n\n  window.addEventListener(\"resize\", resize);\n  resize();\n\n  function update(time) {\n    requestAnimationFrame(update);\n\n    mouse.x += (mouse.tx - mouse.x) * 0.05;\n    mouse.y += (mouse.ty - mouse.y) * 0.05;\n\n    program.uniforms.uMouse.value = [mouse.x, mouse.y];\n    program.uniforms.uTime.value = time * 0.001;\n\n    renderer.render({\n      scene: mesh\n    });\n  }\n\n  requestAnimationFrame(update);\n}\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-caf8e71 e-flex e-con-boxed e-con e-parent\" data-id=\"caf8e71\" data-element_type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-4ac92ae elementor-widget elementor-widget-spacer\" data-id=\"4ac92ae\" data-element_type=\"widget\" data-widget_type=\"spacer.default\">\n\t\t\t\t\t\t\t<div class=\"elementor-spacer\">\n\t\t\t<div class=\"elementor-spacer-inner\"><\/div>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-5f6298b e-flex e-con-boxed e-con e-parent\" data-id=\"5f6298b\" data-element_type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-b7b9418 fade-in-up elementor-widget elementor-widget-heading\" data-id=\"b7b9418\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">PAGANI MODEL VIEWER<\/h2>\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-7eeec97 e-flex e-con-boxed e-con e-parent\" data-id=\"7eeec97\" data-element_type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-097f1a1 fade-in-up elementor-widget elementor-widget-text-editor\" data-id=\"097f1a1\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t\t\t\t\t\t<p>Responsive with drag and zoom.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-d9ad0ef e-flex e-con-boxed e-con e-parent\" data-id=\"d9ad0ef\" data-element_type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-091b467 elementor-widget elementor-widget-html\" data-id=\"091b467\" data-element_type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t\t<script type=\"module\" src=\"https:\/\/unpkg.com\/@google\/model-viewer\/dist\/model-viewer.min.js\"><\/script>\n\n<div class=\"kw-model-section\">\n  <model-viewer\n    src=\"https:\/\/kristofferwilliam.dk\/wp-content\/uploads\/2026\/06\/2025_pagani_huayra_r_20th_asphalt_anniversary.glb\"\n    camera-controls\n    auto-rotate\n    auto-rotate-delay=\"0\"\n    rotation-per-second=\"18deg\"\n    environment-image=\"neutral\"\n    shadow-intensity=\"1\"\n    exposure=\"1\"\n    camera-orbit=\"35deg 68deg 105%\"\n    field-of-view=\"35deg\"\n    interaction-prompt=\"none\">\n  <\/model-viewer>\n<\/div>\n\n<style>\n.kw-model-section {\n  width: 100%;\n  height: 700px;\n  background: #111;\n  overflow: hidden;\n\n  border: 1px solid rgba(255,255,255,0.08);\n  border-radius: 20px;\n\n  box-shadow:\n    inset 0 0 0 1px rgba(255,255,255,0.03),\n    0 0 40px rgba(255,255,255,0.03);\n}\n\n.kw-model-section model-viewer {\n  width: 100%;\n  height: 100%;\n  background: black;\n}\n<\/style>\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>Project Portfolio A short list of some of the projects, i have worked on. 01 ADVENTURE ALLEVEGNE Rejse- og oplevelsesplatform UX\/UI \u2022 Webdesign \u2022 Branding 02 NORVA Multibrand e-commerce platform WordPress \u2022 WooCommerce \u2022 UX\/UI 03 PLANTINO Digital planteservice platform WordPress \u2022 Branding \u2022 UX View All Projects FEATURED ANIMATIONS. Saurons eye Responsive to cursor. [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"elementor_header_footer","meta":{"_gspb_post_css":"","footnotes":""},"class_list":["post-29","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/kristofferwilliam.dk\/index.php\/wp-json\/wp\/v2\/pages\/29","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/kristofferwilliam.dk\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/kristofferwilliam.dk\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/kristofferwilliam.dk\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/kristofferwilliam.dk\/index.php\/wp-json\/wp\/v2\/comments?post=29"}],"version-history":[{"count":130,"href":"https:\/\/kristofferwilliam.dk\/index.php\/wp-json\/wp\/v2\/pages\/29\/revisions"}],"predecessor-version":[{"id":713,"href":"https:\/\/kristofferwilliam.dk\/index.php\/wp-json\/wp\/v2\/pages\/29\/revisions\/713"}],"wp:attachment":[{"href":"https:\/\/kristofferwilliam.dk\/index.php\/wp-json\/wp\/v2\/media?parent=29"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}