loops encountered with llama-cli on October-27-Q8-gguf

#11
by KottCh - opened

as title says. BTW, I also dl safetensor files and myself converted to ggufs F16 & Q8 . they also loop, but seems --repeat-penalty 1.05 helped them. [edit] helped to only my-Q8

Thanks for sharing! I was a bit worried that increasing the repeat penalty might cause the model to start skipping functions or parts of the code, potentially breaking things even more. I hadn't actually tested it yet, so that's really good to know! I'll give 1.05 a try.

And if you come across any other interesting findings or improvements, please let me know. I really appreciate the feedback and testing

No, it helps to my-converted Q8 gguf. but your Q8 & my-F16 gguf produces non-working html ;-(

No, it helps to my-converted Q8 gguf. but your Q8 & my-F16 gguf produces non-working html ;-(

Oh, just a thought! Is there any chance you downloaded my Q8 before the latest update? I updated the GGUF weights recently, so you might still have an older checkpoint. That could explain some of the differences we're seeing. Just wanted to check! :)

just tried --min-p 0 --repeat-penalty 1.01, did good elephant rehabilitation habitat, but with live elephant inside?
llama-cli -m Qwen3.5-4B-3D-Coder-Q8_0.gguf --temp 0.6 --top-p 0.95 --top-k 20 --min-p 0 --repeat-penalty 1.01 --seed 42 -c 262144 -sysf "3dcoder.sys" -f "3dcoder.prompt"

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Elephant Rehabilitation Habitat</title>
  <style>
    :root {
      color-scheme: light;
      --ink: #26352f;
      --muted: #5c6d65;
      --panel: rgba(248, 246, 235, 0.88);
      --line: rgba(38, 53, 47, 0.16);
      --accent: #367b68;
    }

    * { box-sizing: border-box; }

    html, body {
      width: 100%;
      height: 100%;
      margin: 0;
      overflow: hidden;
      background: #dce7e1;
      font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
        "Segoe UI", sans-serif;
      color: var(--ink);
    }

    #scene {
      display: block;
      width: 100%;
      height: 100%;
      touch-action: none;
      cursor: grab;
    }

    #scene:active { cursor: grabbing; }

    .panel {
      position: fixed;
      z-index: 10;
      background: var(--panel);
      border: 1px solid var(--line);
      box-shadow: 0 12px 36px rgba(35, 52, 45, 0.12);
      backdrop-filter: blur(12px);
      -webkit-backdrop-filter: blur(12px);
    }

    #title {
      top: 22px;
      left: 22px;
      width: min(390px, calc(100vw - 44px));
      padding: 18px 20px 16px;
      border-radius: 16px;
      pointer-events: none;
    }

    .eyebrow {
      margin-bottom: 7px;
      color: var(--accent);
      font-size: 11px;
      font-weight: 800;
      letter-spacing: 0.17em;
      text-transform: uppercase;
    }

    h1 {
      margin: 0;
      font-size: clamp(22px, 3vw, 31px);
      line-height: 1.08;
      letter-spacing: -0.035em;
    }

    #title p {
      margin: 10px 0 0;
      color: var(--muted);
      font-size: 13px;
      line-height: 1.45;
    }

    #views {
      top: 22px;
      right: 22px;
      display: flex;
      gap: 7px;
      padding: 7px;
      border-radius: 13px;
    }

    button {
      appearance: none;
      border: 0;
      border-radius: 9px;
      padding: 9px 12px;
      background: transparent;
      color: var(--ink);
      font: inherit;
      font-size: 12px;
      font-weight: 700;
      cursor: pointer;
      transition: background 150ms ease, color 150ms ease, transform 150ms ease;
    }

    button:hover {
      background: rgba(54, 123, 104, 0.12);
      color: #173f35;
    }

    button:active { transform: translateY(1px); }

    #legend {
      left: 22px;
      bottom: 22px;
      display: flex;
      flex-wrap: wrap;
      gap: 8px;
      max-width: min(520px, calc(100vw - 44px));
      padding: 10px;
      border-radius: 13px;
      pointer-events: none;
    }

    .legend-item {
      display: flex;
      align-items: center;
      gap: 7px;
      padding: 5px 8px;
      color: #46564f;
      font-size: 11px;
      font-weight: 700;
    }

    .swatch {
      width: 10px;
      height: 10px;
      border-radius: 2px;
      box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.08);
    }

    #help {
      right: 22px;
      bottom: 22px;
      padding: 10px 13px;
      border-radius: 12px;
      color: #526159;
      font-size: 11px;
      line-height: 1.5;
      text-align: right;
      pointer-events: none;
    }

    #help strong {
      color: var(--ink);
    }

    @media (max-width: 700px) {
      #title {
        top: 12px;
        left: 12px;
        width: calc(100vw - 24px);
        padding: 14px 16px;
      }

      #title p { display: none; }

      #views {
        top: auto;
        right: 12px;
        bottom: 66px;
      }

      #legend {
        left: 12px;
        bottom: 12px;
        max-width: calc(100vw - 24px);
      }

      #help { display: none; }
    }
  </style>
</head>
<body>
  <canvas id="scene" aria-label="Interactive three-dimensional elephant rehabilitation habitat"></canvas>

  <section id="title" class="panel">
    <div class="eyebrow">Voxel wildlife habitat</div>
    <h1>Elephant Rehabilitation Yard</h1>
    <p>
      A broad, sheltered court links water, shade, and feeding areas through
      wide, accessible paths shaped around the elephant's movement envelope.
    </p>
  </section>

  <nav id="views" class="panel" aria-label="Camera views">
    <button id="overview" type="button">Overview</button>
    <button id="yard" type="button">Yard</button>
  </nav>

  <section id="legend" class="panel" aria-label="Habitat features">
    <div class="legend-item"><span class="swatch" style="background:#49a9c5"></span>Water</div>
    <div class="legend-item"><span class="swatch" style="background:#729667"></span>Shade</div>
    <div class="legend-item"><span class="swatch" style="background:#d6c293"></span>Feeding</div>
  </section>

  <div id="help" class="panel">
    <strong>Drag</strong> orbit · <strong>Shift-drag / right-drag</strong> pan<br />
    <strong>Scroll</strong> zoom · <strong>R</strong> reset
  </div>

  <script type="module">
    import * as THREE from "https://cdnjs.cloudflare.com/ajax/libs/three.js/0.160.0/three.module.min.js";

    const canvas = document.querySelector("#scene");

    const renderer = new THREE.WebGLRenderer({
      canvas,
      antialias: true,
      powerPreference: "high-performance"
    });

    renderer.setPixelRatio(Math.min(window.devicePixelRatio, 1.75));
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.shadowMap.enabled = true;
    renderer.shadowMap.type = THREE.PCFSoftShadowMap;
    renderer.outputColorSpace = THREE.SRGBColorSpace;
    renderer.toneMapping = THREE.ACESFilmicToneMapping;
    renderer.toneMappingExposure = 1.08;

    const scene = new THREE.Scene();
    scene.background = new THREE.Color(0xdce7e1);
    scene.fog = new THREE.Fog(0xdce7e1, 48, 95);

    const camera = new THREE.PerspectiveCamera(
      42,
      window.innerWidth / window.innerHeight,
      0.1,
      150
    );

    const hemisphere = new THREE.HemisphereLight(0xf4f5df, 0x68705c, 2.15);
    scene.add(hemisphere);

    const sun = new THREE.DirectionalLight(0xfff1ce, 3.25);
    sun.position.set(-18, 28, 19);
    sun.castShadow = true;
    sun.shadow.mapSize.set(2048, 2048);
    sun.shadow.camera.left = -28;
    sun.shadow.camera.right = 28;
    sun.shadow.camera.top = 25;
    sun.shadow.camera.bottom = -25;
    sun.shadow.camera.near = 1;
    sun.shadow.camera.far = 70;
    sun.shadow.bias = -0.00035;
    sun.shadow.normalBias = 0.025;
    scene.add(sun);

    const fill = new THREE.DirectionalLight(0xb9dce4, 0.72);
    fill.position.set(20, 12, -18);
    scene.add(fill);

    const unitBox = new THREE.BoxGeometry(1, 1, 1);

    function addBox(w, h, d, material, x, y, z, parent = scene) {
      const mesh = new THREE.Mesh(unitBox, material);
      mesh.scale.set(w, h, d);
      mesh.position.set(x, y, z);
      mesh.castShadow = true;
      mesh.receiveShadow = true;
      parent.add(mesh);
      return mesh;
    }

    function makeInstances(items, material, parent = scene) {
      const mesh = new THREE.InstancedMesh(unitBox, material, items.length);
      const dummy = new THREE.Object3D();
      const color = new THREE.Color();

      items.forEach((item, i) => {
        dummy.position.set(item.p[0], item.p[1], item.p[2]);

        if (Array.isArray(item.s)) {
          dummy.scale.set(...item.s);
        } else {
          dummy.scale.setScalar(item.s ?? 1);
        }

        dummy.updateMatrix();
        mesh.setMatrixAt(i, dummy.matrix);

        if (item.c !== undefined) {
          color.set(item.c);
          if (color.isColor) mesh.setColorAt(i, color);
        }
      });

      mesh.instanceMatrix.needsUpdate = true;
      if (mesh.instanceColor) mesh.instanceColor.needsUpdate = true;
      mesh.castShadow = true;
      mesh.receiveShadow = true;
      mesh.computeBoundingSphere();
      parent.add(mesh);
      return mesh;
    }

    const materials = {
      soil: new THREE.MeshStandardMaterial({ color: 0x665641, roughness: 1 }),
      grass: new THREE.MeshStandardMaterial({ color: 0x789568, roughness: 1 }),
      court: new THREE.MeshStandardMaterial({ color: 0xc8bea0, roughness: 0.96 }),
      path: new THREE.MeshStandardMaterial({ color: 0xd9c79d, roughness: 0.98 }),
      stone: new THREE.MeshStandardMaterial({ color: 0x8c8b7d, roughness: 1 }),
      darkStone: new THREE.MeshStandardMaterial({ color: 0x555d57, roughness: 1 }),
      water: new THREE.MeshStandardMaterial({
        color: 0x43a9c7,
        roughness: 0.28,
        metalness: 0.08
      }),
      teal: new THREE.MeshStandardMaterial({ color: 0x3f776c, roughness: 0.88 }),
      wood: new THREE.MeshStandardMaterial({ color: 0x8a6847, roughness: 0.96 }),
      lightWood: new THREE.MeshStandardMaterial({ color: 0xb18b59, roughness: 0.95 }),
      hay: new THREE.MeshStandardMaterial({ color: 0xd7b86d, roughness: 1 }),
      trunk: new THREE.MeshStandardMaterial({ color: 0x5d6664, roughness: 0.94 }),
      ivory: new THREE.MeshStandardMaterial({ color: 0xe1d8b7, roughness: 0.78 }),
      black: new THREE.MeshStandardMaterial({ color: 0x171b19, roughness: 0.85 })
    };

    // ---------------------------------------------------------------------
    // Ground and accessible circulation
    // ---------------------------------------------------------------------

    addBox(38, 0.7, 30, materials.soil, 0, -0.45, 0);

    const groundItems = [];
    const grassColors = [0x789568, 0x7ca475, 0x708c64, 0x819b6d];

    for (let x = 0; x < 24; x++) {
      for (let z = 0; z < 20; z++) {
        const px = (x - 11.5) * 1.2;
        const pz = (z - 9.5) * 1.2;
        const shade = Math.sin(px * 1.7 + pz) * 0.018;
        groundItems.push({
          p: [px, -0.02 + shade, pz],
          s: [1.08, 0.14, 1.08],
          c: grassColors[Math.floor(Math.random() * grassColors.length)]
        });
      }
    }

    makeInstances(groundItems, new THREE.MeshStandardMaterial({
      color: 0xffffff,
      roughness: 1
    }));

    function addPath(x1, z1, x2, z2, width = 1.2) {
      const dx = x2 - x1;
      const dz = z2 - z1;
      const length = Math.hypot(dx, dz);
      const count = Math.max(1, Math.ceil(length / 0.68));
      const nx = -dz / length;
      const nz = dx / length;

      for (let i = 0; i < count; i++) {
        const t = i / (count - 1);
        const x = x1 + dx * t;
        const z = z1 + dz * t;

        for (const side of [-1, 0, 1]) {
          makeInstances([
            {
              p: [x + nx * side * width * 0.5, 0.16, z + nz * side * width * 0.5],
              s: [1.08, 0.12, 1.08]
            }
          ], materials.path);
        }
      }
    }

    // Wide entrance, then branches toward the three activity areas.
    addPath(0, 12, 0, 8);
    addPath(0, 8, 5, 8);
    addPath(5, 8, 5, 7);
    addPath(-5, -5, -7.5, -5);
    addPath(-7.5, -5, -15.5, -5);
    addPath(5, -5, 9, -6);

    // Central activity court, kept clear of the elephant's head and tusks.
    for (let x = 0; x < 10; x++) {
      for (let z = 0; z < 8; z++) {
        makeInstances([
          {
            p: [(x - 4.5) * 1.1, 0.08, (z - 3.5) * 1.1],
            s: [1.05, 0.12, 1.05],
            c: [0xc8bea0, 0xd0c4a4, 0xbeb394][Math.floor(Math.random() * 3)]
          }
        ], new THREE.MeshStandardMaterial({ color: 0xffffff, roughness: 0.98 }));
      }
    }

    // ---------------------------------------------------------------------
    // Water pool
    // ---------------------------------------------------------------------

    addBox(7, 0.18, 5, materials.darkStone, -12, 0.02, -5);

    const waterItems = [];
    for (let x = 0; x < 6; x++) {
      for (let z = 0; z < 4; z++) {
        waterItems.push({
          p: [-14.5 + x, 0.22, -6.5 + z],
          s: [0.96, 0.12, 0.96],
          c: [0x3c9eb4, 0x4bb2c8, 0x3995b7][Math.floor(Math.random() * 3)]
        });
      }
    }
    makeInstances(waterItems, new THREE.MeshStandardMaterial({
      color: 0xffffff,
      roughness: 0.24,
      metalness: 0.12
    }));

    const borderItems = [];
    for (let x = 0; x < 7; x++) {
      borderItems.push({
        p: [-15.5 + x, 0.25, -7.5],
        s: [0.94, 0.42, 0.62]
      });
      borderItems.push({
        p: [-15.5 + x, 0.25, -3.5],
        s: [0.94, 0.42, 0.62]
      });
    }
    for (let z = 0; z < 5; z++) {
      borderItems.push({
        p: [-15.5, 0.25, -6.5 + z],
        s: [0.62, 0.42, 0.94]
      });
      borderItems.push({
        p: [-7.5, 0.25, -6.5 + z],
        s: [0.62, 0.42, 0.94]
      });
    }
    makeInstances(
      borderItems,
      new THREE.MeshStandardMaterial({ color: 0x8b897a, roughness: 1 })
    );

    // ---------------------------------------------------------------------
    // Shade shelter
    // ---------------------------------------------------------------------

    addBox(8.2, 0.16, 5.2, materials.court, 9, 0.12, -6);

    const shelterPosts = [
      [6.15, -9], [11.85, -9],
      [6.15, -3], [11.85, -3]
    ];

    for (const [x, z] of shelterPosts) {
      addBox(0.5, 4.7, 0.5, materials.wood, x, 2.55, z);
      addBox(0.75, 0.28, 0.75, materials.lightWood, x, 0.3, z);
    }

    for (let x = 0; x < 8; x++) {
      for (let z = 0; z < 5; z++) {
        addBox(
          0.96,
          0.34,
          0.96,
          materials.teal,
          6.05 + x,
          5.05,
          -8.95 + z
        );
      }
    }

    // Bench under the shelter.
    addBox(3.4, 0.25, 0.8, materials.lightWood, 9, 1.25, -6.5);
    addBox(3.4, 0.8, 0.2, materials.lightWood, 9, 1.75, -7.05);
    for (const x of [7.25, 10.75]) {
      addBox(0.2, 1.25, 0.65, materials.wood, x, 0.72, -6.5);
    }

    // ---------------------------------------------------------------------
    // Feeding area
    // ---------------------------------------------------------------------

    for (const x of [3.4, 5.4]) {
      addBox(2.1, 0.48, 1.25, materials.darkStone, x, 0.4, 7.1);
      addBox(1.85, 0.12, 1.05, materials.stone, x, 0.69, 7.1);

      const hayItems = [];
      for (let i = 0; i < 9; i++) {
        hayItems.push({
          p: [x - 0.72 + (i % 3) * 0.48, 0.8, 6.85 + Math.floor(i / 3) * 0.34],
          s: [0.42, 0.22, 0.28],
          c: [0xd7b86d, 0xc8a65d, 0xdfc77e][i % 3]
        });
      }
      makeInstances(hayItems, new THREE.MeshStandardMaterial({
        color: 0xffffff,
        roughness: 1
      }));
    }

    // Low feeding stations and a small water bowl.
    addBox(0.55, 0.42, 0.55, materials.stone, 7.1, 0.32, 8.8);
    addBox(0.38, 0.12, 0.38, materials.water, 7.1, 0.59, 8.8);

    // ---------------------------------------------------------------------
    // Block trees
    // ---------------------------------------------------------------------

    function addTree(x, z, scale = 1) {
      const tree = new THREE.Group();
      tree.position.set(x, 0, z);
      tree.scale.setScalar(scale);
      scene.add(tree);

      const trunkItems = [];
      for (let y = 0; y < 4; y++) {
        trunkItems.push({
          p: [0, 0.45 + y, 0],
          s: [0.68, 0.68, 0.68],
          c: [0x76513a, 0x845d43, 0x684937][y % 3]
        });
      }

      makeInstances(
        trunkItems,
        new THREE.MeshStandardMaterial({ color: 0xffffff, roughness: 1 }),
        tree
      );

      const canopy = [
        { p: [0, 3.55, 0], s: [2.2, 2.0, 2.0], c: 0x64875a },
        { p: [-1.05, 3.9, 0], s: [1.55, 1.65, 1.55], c: 0x71915f },
        { p: [1.05, 3.9, 0], s: [1.55, 1.65, 1.55], c: 0x71915f },
        { p: [0, 4.8, 0], s: [1.8, 1.65, 1.8], c: 0x567a4d },
        { p: [0, 5.8, 0], s: [1.35, 1.35, 1.35], c: 0x6c8b55 },
        { p: [0, 2.7, 0], s: [1.7, 1.4, 1.7], c: 0x78945f }
      ];

      makeInstances(
        canopy,
        new THREE.MeshStandardMaterial({ color: 0xffffff, roughness: 1 }),
        tree
      );
    }

    addTree(-16, -10.2, 1.1);
    addTree(15.7, -10.2, 1.15);
    addTree(16, 8.4, 1.05);
    addTree(-16, 8.4, 1.05);

    // ---------------------------------------------------------------------
    // Perimeter fence
    // ---------------------------------------------------------------------

    for (let x = -17; x <= 17; x += 2) {
      addBox(0.42, 2.3, 0.42, materials.lightWood, x, 1.15, -12.2);
    }
    for (const y of [0.72, 1.62]) {
      for (let x = -17; x <= 17; x += 2) {
        addBox(1.85, 0.18, 0.18, materials.wood, x + 0.95, y, -12.2);
      }
    }

    for (let z = -12; z <= 12; z += 2) {
      addBox(0.42, 2.3, 0.42, materials.lightWood, -17.2, 1.15, z);
    }
    for (const y of [0.72, 1.62]) {
      for (let z = -12; z <= 12; z += 2) {
        addBox(0.18, 0.18, 1.85, materials.wood, -17.2, y, z + 0.95);
      }
    }

    // ---------------------------------------------------------------------
    // Voxel elephant
    // ---------------------------------------------------------------------

    const elephant = new THREE.Group();
    elephant.position.set(0, 0, 0);
    scene.add(elephant);

    const elephantBodyMaterial = new THREE.MeshStandardMaterial({
      color: 0xffffff,
      roughness: 0.94
    });
    const elephantEarMaterial = new THREE.MeshStandardMaterial({
      color: 0xffffff,
      roughness: 0.98
    });
    const elephantTrunkMaterial = new THREE.MeshStandardMaterial({
      color: 0xffffff,
      roughness: 0.98
    });

    const bodyItems = [];
    for (let x = -3; x <= 3; x++) {
      for (let y = 0; y < 3; y++) {
        for (let z = -2; z <= 2; z++) {
          bodyItems.push({
            p: [x, 1.45 + y, z],
            s: 1,
            c: [0x777b78, 0x7f827d, 0x6f7574][
              (x + y * 2 + z) % 3
            ]
          });
        }
      }
    }
    makeInstances(bodyItems, elephantBodyMaterial, elephant);

    const headItems = [];
    for (let x = -7; x <= -4; x++) {
      for (let y = 0; y < 3; y++) {
        for (let z = -1.5; z <= 1.5; z++) {
          headItems.push({
            p: [x, 2.45 + y, z],
            s: 1,
            c: [0x777b78, 0x818580, 0x707674][
              (x + y + z) % 3
            ]
          });
        }
      }
    }
    makeInstances(headItems, elephantBodyMaterial, elephant);

    const legItems = [];
    for (const x of [-2.35, 2.35]) {
      for (const z of [-1.45, 1.45]) {
        for (let y = 0; y < 3; y++) {
          legItems.push({
            p: [x, 0.45 + y, z],
            s: 1,
            c: [0x686e6c, 0x737976, 0x626967][y]
          });
        }
        legItems.push({
          p: [x, 0.45, z],
          s: 1,
          c: 0x626967
        });
        legItems.push({
          p: [x - 0.5, 0.45, z - 0.34],
          s: 0.18,
          c: 0x4c5351
        });
        legItems.push({
          p: [x - 0.5, 0.45, z + 0.34],
          s: 0.18,
          c: 0x4c5351
        });
      }
    }
    makeInstances(legItems, elephantBodyMaterial, elephant);

    const earItems = [];
    for (const z of [-2.02, 2.02]) {
      for (const x of [-4.5, -3.5]) {
        for (let y = 0; y < 3; y++) {
          earItems.push({
            p: [x, 3.45 + y, z],
            s: 1,
            c: [0xb67d70, 0xc18a78, 0xaa7068][y]
          });
        }
      }
    }
    makeInstances(earItems, elephantEarMaterial, elephant);

    const trunkPivot = new THREE.Group();
    trunkPivot.position.set(-7.5, 2.45, 0);
    elephant.add(trunkPivot);

    const trunkItems = [];
    for (let i = 0; i < 4; i++) {
      trunkItems.push({
        p: [-0.5 - i * 0.58, -0.25 - i * 0.28, 0],
        s: 0.68,
        c: [0x555e5d, 0x606967, 0x4e5857][i]
      });
    }
    makeInstances(trunkItems, elephantTrunkMaterial, trunkPivot);

    const tuskItems = [];
    for (const z of [-0.6, 0.6]) {
      tuskItems.push({
        p: [-8.05, 1.55, z],
        s: 1,
        c: 0xd9d2b6
      });
      tuskItems.push({
        p: [-9.05, 1.55, z],
        s: 1,
        c: 0xd9d2b6
      });
    }
    makeInstances(tuskItems, materials.ivory, elephant);

    const eyeItems = [];
    for (const z of [-0.74, 0.74]) {
      eyeItems.push({
        p: [-7.53, 3.92, z],
        s: 0.18,
        c: 0x111715
      });
    }
    makeInstances(eyeItems, materials.black, elephant);

    const nostrilItems = [];
    for (const z of [-0.78, 0.78]) {
      nostrilItems.push({
        p: [-7.53, 2.45, z],
        s: 0.22,
        c: 0x424a48
      });
    }
    makeInstances(nostrilItems, materials.black, elephant);

    const tailItems = [];
    tailItems.push({ p: [3.7, 3.45, -1.8], s: 0.72, c: 0x686f6c });
    tailItems.push({ p: [3.7, 2.45, -1.8], s: 0.72, c: 0x686f6c });
    tailItems.push({ p: [3.7, 1.45, -1.8], s: 0.72, c: 0x686f6c });
    makeInstances(tailItems, elephantBodyMaterial, elephant);

    // ---------------------------------------------------------------------
    // Camera controls implemented directly, without external controls
    // ---------------------------------------------------------------------

    const target = new THREE.Vector3(0, 1, -1);
    const desired = {
      radius: 39,
      phi: 1.05,
      theta: 2.38
    };
    const current = { ...desired };

    function updateCamera() {
      current.radius += (desired.radius - current.radius) * 0.085;
      current.phi += (desired.phi - current.phi) * 0.085;
      current.theta += (desired.theta - current.theta) * 0.085;

      current.phi = THREE.MathUtils.clamp(current.phi, 0.34, 1.43);

      const spherical = new THREE.Spherical(
        current.radius,
        current.phi,
        current.theta
      );

      camera.position.setFromSpherical(spherical).add(target);
      camera.lookAt(target);
    }

    function setView(view) {
      if (view === "yard") {
        target.set(0, 1, -0.5);
        desired.radius = 25;
        desired.phi = 1.13;
        desired.theta = 2.22;
      } else {
        target.set(0, 1, -1);
        desired.radius = 39;
        desired.phi = 1.05;
        desired.theta = 2.38;
      }
    }

    const pointers = new Map();
    let gesture = null;
    let previousPinchDistance = 0;

    function pointerDistance() {
      const values = [...pointers.values()];
      if (values.length < 2) return 0;
      return Math.hypot(
        values[0].x - values[1].x,
        values[0].y - values[1].y
      );
    }

    canvas.addEventListener("contextmenu", event => event.preventDefault());

    canvas.addEventListener("pointerdown", event => {
      canvas.setPointerCapture(event.pointerId);
      pointers.set(event.pointerId, { x: event.clientX, y: event.clientY });

      if (pointers.size === 1) {
        gesture = {
          mode: event.button === 2 || event.shiftKey ? "pan" : "orbit",
          x: event.clientX,
          y: event.clientY
        };
      } else if (pointers.size === 2) {
        gesture = "pinch";
        previousPinchDistance = pointerDistance();
      }
    });

    canvas.addEventListener("pointermove", event => {
      if (!pointers.has(event.pointerId)) return;

      pointers.set(event.pointerId, { x: event.clientX, y: event.clientY });

      if (gesture === "pinch" && pointers.size >= 2) {
        const distance = pointerDistance();
        if (previousPinchDistance > 0 && distance > 0) {
          desired.radius = THREE.MathUtils.clamp(
            desired.radius * (previousPinchDistance / distance),
            17,
            58
          );
        }
        previousPinchDistance = distance;
        return;
      }

      if (!gesture) return;

      const dx = event.clientX - gesture.x;
      const dy = event.clientY - gesture.y;
      gesture.x = event.clientX;
      gesture.y = event.clientY;

      if (gesture.mode === "orbit") {
        desired.theta -= dx * 0.006;
        desired.phi = THREE.MathUtils.clamp(
          desired.phi - dy * 0.005,
          0.34,
          1.43
        );
      } else {
        const right = new THREE.Vector3().setFromMatrixColumn(camera.matrix, 0);
        const up = new THREE.Vector3().setFromMatrixColumn(camera.matrix, 1);
        const panScale = current.radius * 0.00125;

        target.addScaledVector(right, -dx * panScale);
        target.addScaledVector(up, dy * panScale);
        target.x = THREE.MathUtils.clamp(target.x, -16, 16);
        target.z = THREE.MathUtils.clamp(target.z, -13, 13);
        target.y = THREE.MathUtils.clamp(target.y, 0, 4);
      }
    });

    function endPointer(event) {
      pointers.delete(event.pointerId);
      if (pointers.size === 0) gesture = null;
      else if (pointers.size === 1) {
        const remaining = [...pointers.values()][0];
        gesture = {
          mode: "orbit",
          x: remaining.x,
          y: remaining.y
        };
      }
    }

    canvas.addEventListener("pointerup", endPointer);
    canvas.addEventListener("pointercancel", endPointer);

    canvas.addEventListener("wheel", event => {
      event.preventDefault();
      desired.radius = THREE.MathUtils.clamp(
        desired.radius * Math.exp(event.deltaY * 0.001),
        17,
        58
      );
    }, { passive: false });

    window.addEventListener("keydown", event => {
      if (event.key.toLowerCase() === "r") setView("overview");

      if (event.key === "ArrowLeft") desired.theta += 0.08;
      if (event.key === "ArrowRight") desired.theta -= 0.08;
      if (event.key === "ArrowUp") desired.phi = Math.max(0.34, desired.phi - 0.06);
      if (event.key === "ArrowDown") desired.phi = Math.min(1.43, desired.phi + 0.06);
      if (event.key === "+" || event.key === "=") desired.radius = Math.max(17, desired.radius - 2);
      if (event.key === "-") desired.radius = Math.min(58, desired.radius + 2);
    });

    document.querySelector("#overview").addEventListener("click", () => setView("overview"));
    document.querySelector("#yard").addEventListener("click", () => setView("yard"));

    window.addEventListener("resize", () => {
      camera.aspect = window.innerWidth / window.innerHeight;
      camera.updateProjectionMatrix();
      renderer.setPixelRatio(Math.min(window.devicePixelRatio, 1.75));
      renderer.setSize(window.innerWidth, window.innerHeight);
    });

    const clock = new THREE.Clock();

    function animate() {
      const time = clock.getElapsedTime();

      // Very restrained movement keeps the animal readable while suggesting
      // a calm, living habitat rather than a static museum display.
      elephant.position.x = Math.sin(time * 0.34) * 0.12;
      elephant.position.z = Math.cos(time * 0.25) * 0.07;
      elephant.rotation.y = Math.sin(time * 0.21) * 0.018;
      trunkPivot.rotation.z = -0.11 + Math.sin(time * 1.25) * 0.065;
      trunkPivot.rotation.y = Math.sin(time * 0.8) * 0.025;

      updateCamera();
      renderer.render(scene, camera);
    }

    renderer.setAnimationLoop(animate);
  </script>
</body>
</html>

No, it helps to my-converted Q8 gguf. but your Q8 & my-F16 gguf produces non-working html ;-(

Oh, just a thought! Is there any chance you downloaded my Q8 before the latest update? I updated the GGUF weights recently, so you might still have an older checkpoint. That could explain some of the differences we're seeing. Just wanted to check! :)

sha256-c30b02629456aa2bc32e522de0f58eb1aafd8518a7634128fed67d1486fc2a9a as it is now

Sign up or log in to comment