Instructions to use ccore/Qwen3.5-4B-3D-Coder with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- llama.cpp
How to use ccore/Qwen3.5-4B-3D-Coder with llama.cpp:
Install (macOS, Linux)
curl -LsSf https://llama.app/install.sh | sh # Start a local OpenAI-compatible server with a web UI: llama serve -hf ccore/Qwen3.5-4B-3D-Coder:Q4_K_M # Run inference directly in the terminal: llama cli -hf ccore/Qwen3.5-4B-3D-Coder:Q4_K_M
Install from WinGet (Windows)
winget install llama.cpp # Start a local OpenAI-compatible server with a web UI: llama serve -hf ccore/Qwen3.5-4B-3D-Coder:Q4_K_M # Run inference directly in the terminal: llama cli -hf ccore/Qwen3.5-4B-3D-Coder:Q4_K_M
Build from source code
git clone https://github.com/ggml-org/llama.cpp.git cd llama.cpp cmake -B build cmake --build build -j --target llama-app # Start a local OpenAI-compatible server with a web UI: ./build/bin/llama serve -hf ccore/Qwen3.5-4B-3D-Coder:Q4_K_M # Run inference directly in the terminal: ./build/bin/llama cli -hf ccore/Qwen3.5-4B-3D-Coder:Q4_K_M
Use Docker
docker model run hf.co/ccore/Qwen3.5-4B-3D-Coder:Q4_K_M
- Llama new
- LM Studio
- Jan
- Ollama
How to use ccore/Qwen3.5-4B-3D-Coder with Ollama:
ollama run hf.co/ccore/Qwen3.5-4B-3D-Coder:Q4_K_M
- Unsloth Desktop
- Pi
How to use ccore/Qwen3.5-4B-3D-Coder with Pi:
Start the llama.cpp server
# Install llama.cpp: brew install llama.cpp # Start a local OpenAI-compatible server: llama serve -hf ccore/Qwen3.5-4B-3D-Coder:Q4_K_M
Configure the model in Pi
# Install Pi: npm install -g @earendil-works/pi-coding-agent # Add to ~/.pi/agent/models.json: { "providers": { "llama-cpp": { "baseUrl": "http://localhost:8080/v1", "api": "openai-completions", "apiKey": "none", "models": [ { "id": "ccore/Qwen3.5-4B-3D-Coder:Q4_K_M" } ] } } }Run Pi
# Start Pi in your project directory: pi
- Docker Model Runner
How to use ccore/Qwen3.5-4B-3D-Coder with Docker Model Runner:
docker model run hf.co/ccore/Qwen3.5-4B-3D-Coder:Q4_K_M
- Lemonade
How to use ccore/Qwen3.5-4B-3D-Coder with Lemonade:
Pull the model
# Download Lemonade from https://lemonade-server.ai/ lemonade pull ccore/Qwen3.5-4B-3D-Coder:Q4_K_M
Run and chat with the model
lemonade run user.Qwen3.5-4B-3D-Coder-Q4_K_M
List all available models
lemonade list
- Hermes Agent
How to use ccore/Qwen3.5-4B-3D-Coder with Hermes Agent:
Start the llama.cpp server
# Install llama.cpp: brew install llama.cpp # Start a local OpenAI-compatible server: llama serve -hf ccore/Qwen3.5-4B-3D-Coder:Q4_K_M
Configure Hermes
# Install Hermes: curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash hermes setup # Point Hermes at the local server: hermes config set model.provider custom hermes config set model.base_url http://127.0.0.1:8080/v1 hermes config set model.default ccore/Qwen3.5-4B-3D-Coder:Q4_K_M
Run Hermes
hermes
- Atomic Chat
- OpenClaw
How to use ccore/Qwen3.5-4B-3D-Coder with OpenClaw:
Start the llama.cpp server
# Install llama.cpp: brew install llama.cpp # Start a local OpenAI-compatible server: llama serve -hf ccore/Qwen3.5-4B-3D-Coder:Q4_K_M
Configure OpenClaw
# Install OpenClaw: npm install -g openclaw@latest # Register the local server and set it as the default model: openclaw onboard --non-interactive --mode local \ --auth-choice custom-api-key \ --custom-base-url http://127.0.0.1:8080/v1 \ --custom-model-id "ccore/Qwen3.5-4B-3D-Coder:Q4_K_M" \ --custom-provider-id llama-cpp \ --custom-compatibility openai \ --custom-text-input \ --accept-risk \ --skip-health
Run OpenClaw
openclaw agent --local --agent main --message "Hello from Hugging Face"
loops encountered with llama-cli on October-27-Q8-gguf
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