Models 44

Nemotron 3.5 Super VL (free)

by NVIDIAReasoningClean
Open in new window

Running live in a sandboxed frame. Click inside it before using the keyboard.

How it went

Total time
28.5 s
Cost
$0
Output tokens
3,682
Spent thinking
0 tokens
Speed
131.9 tok/s
Console errors
0
First token after
541 ms
First visible text after
541 ms
Prompt tokens
584
Code size
13.3 KB
Finish reason
stop
Served by
Nvidia
Model id
nvidia/nemotron-3.5-super-vl:free
Reasoning sent
{"effort":"none"}
Max output
32,000 tokens
Generated
Nov 9, 2026

What it was asked

The prompt
Build a low-poly 3D scene of a campfire in a forest clearing at night, with Three.js in a single HTML file. Load Three.js only through this import map (do not use any other URL or version): <script type="importmap">{"imports":{"three":"https://cdn.jsdelivr.net/npm/three@0.170.0/build/three.module.js","three/addons/":"https://cdn.jsdelivr.net/npm/three@0.170.0/examples/jsm/"}}</script> Requirements: - A ground with a few low-poly rocks and logs around a campfire in the center. - At least 30 low-poly trees placed randomly around the clearing (not on the fire). - The campfire has animated flames and a warm point light that flickers and casts shadows. - Sparks rising from the fire as a simple particle system. - A dark night sky with stars and a moon, plus fog that fades the distant trees. - OrbitControls to look around, with limits so the camera stays above the ground. - The renderer fills the window and handles resizing correctly.
System prompt, sent with every prompt
You are generating a self-contained web demo. It will be rendered automatically in a sandboxed iframe and compared side by side with the output of other AI models given the exact same task.

Output rules:
- Reply with exactly ONE fenced code block containing the complete file: ```html (or ```svg when the task asks for an SVG). No text before or after the code block.
- Everything must be inline: CSS in <style>, JavaScript in <script>. No external files, images, fonts or network requests, except the CDN URLs explicitly allowed by the task.
- Do not use localStorage, sessionStorage, cookies, IndexedDB, alert(), confirm(), prompt() or window.open(): they are blocked in the sandbox and will throw.
- The page must look right in a 1280×800 viewport and adapt gracefully down to 375px wide. No horizontal scrollbar.
- Something meaningful must be visible on first paint: a screenshot is taken automatically about 3 seconds after load, without any interaction.
- Everything that makes the demo interesting must be visible within the first seconds: nothing hidden behind a high score, a later level or a long play session.
- Games must start in a self-playing demo mode (a simple AI plays) behind a "Click or press a key to start" message, so the game can be judged in action without playing.
- The iframe only receives keyboard events after the user clicks it: if the demo uses the keyboard, display a clear "Click or press a key to start" message.
- The code must run with zero errors in the console of the latest Chrome.

Code run-1.html · 336 lines

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Low Poly Campfire</title>
    <style>
        body { margin: 0; overflow: hidden; background-color: #020205; }
        canvas { display: block; }
        #ui {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            color: white;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            text-align: center;
            pointer-events: none;
            z-index: 10;
        }
        #ui h1 { margin: 0; font-size: 2rem; text-shadow: 0 0 10px #ff4500; }
        #ui p { margin-top: 10px; opacity: 0.8; font-size: 1rem; }
    </style>
    <script type="importmap">
        {"imports":{"three":"https://cdn.jsdelivr.net/npm/three@0.170.0/build/three.module.js","three/addons/":"https://cdn.jsdelivr.net/npm/three@0.170.0/examples/jsm/"}}
    </script>
</head>
<body>
    <div id="ui">
        <h1>CAMPFIRE NIGHT</h1>
        <p>Click or press a key to start / interact</p>
    </div>
    <script type="module">
        import * as THREE from 'three';
        import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

        // --- Setup ---
        const scene = new THREE.Scene();
        scene.fog = new THREE.FogExp2(0x020205, 0.015);

        const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 100);
        camera.position.set(0, 5, 10);

        const renderer = new THREE.WebGLRenderer({ antialias: true });
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
        renderer.shadowMap.enabled = true;
        renderer.shadowMap.type = THREE.PCFSoftShadowMap;
        document.body.appendChild(renderer.domElement);

        const controls = new OrbitControls(camera, renderer.domElement);
        controls.enableDamping = true;
        controls.dampingFactor = 0.05;
        controls.minDistance = 3;
        controls.maxDistance = 25;
        controls.minPolarAngle = 0.1; // prevent going under ground
        controls.maxPolarAngle = Math.PI / 2 - 0.1; // prevent going too high looking down

        // --- Lights ---
        const ambientLight = new THREE.AmbientLight(0x404040, 0.5); // Soft white light
        scene.add(ambientLight);

        const moonLight = new THREE.DirectionalLight(0xffffff, 0.6);
        moonLight.position.set(10, 20, 10);
        moonLight.castShadow = true;
        moonLight.shadow.mapSize.width = 2048;
        moonLight.shadow.mapSize.height = 2048;
        moonLight.shadow.camera.near = 0.5;
        moonLight.shadow.camera.far = 50;
        moonLight.shadow.camera.left = -20;
        moonLight.shadow.camera.right = 20;
        moonLight.shadow.camera.top = 20;
        moonLight.shadow.camera.bottom = -20;
        scene.add(moonLight);

        // Campfire light
        const fireLight = new THREE.PointLight(0xffaa00, 2, 15);
        fireLight.position.set(0, 1, 0);
        fireLight.castShadow = false;
        scene.add(fireLight);

        // --- Ground ---
        const groundGeo = new THREE.PlaneGeometry(100, 100, 32, 32);
        // Slightly bumpy ground
        const posAttr = groundGeo.attributes.position;
        for(let i=0; i<posAttr.count; i++) {
            const y = posAttr.getY(i);
            posAttr.setY(i, y + (Math.random() - 0.5) * 0.2);
        }
        groundGeo.computeVertexNormals();
        const groundMat = new THREE.MeshStandardMaterial({ color: 0x223311, roughness: 0.8 });
        const ground = new THREE.Mesh(groundGeo, groundMat);
        ground.rotation.x = -Math.PI / 2;
        ground.receiveShadow = true;
        scene.add(ground);

        // --- Sky, Moon, Stars ---
        // Sky gradient via fog is used, but we add a moon
        const moonGeo = new THREE.SphereGeometry(1, 16, 16);
        const moonMat = new THREE.MeshBasicMaterial({ color: 0xeeeeee });
        const moon = new THREE.Mesh(moonGeo, moonMat);
        moon.position.set(15, 15, -10);
        scene.add(moon);

        // Stars
        const starGeo = new THREE.BufferGeometry();
        const starCoords = [];
        for(let i=0; i<200; i++) {
            starCoords.push((Math.random()-0.5)*100, Math.random()*30 + 5, (Math.random()-0.5)*100);
        }
        starGeo.setAttribute('position', new THREE.Float32BufferAttribute(starCoords, 3));
        const starMat = new THREE.PointsMaterial({ color: 0xffffff, size: 0.1, transparent: true, opacity: 0.8 });
        const stars = new THREE.Points(starGeo, starMat);
        scene.add(stars);

        // --- Low Poly Tree Generator ---
        function createTree() {
            const group = new THREE.Group();
            
            // Trunk
            const trunkHeight = Math.random() * 2 + 3;
            const trunkGeo = new THREE.CylinderGeometry(0.2, 0.4, trunkHeight, 4);
            const trunkMat = new THREE.MeshStandardMaterial({ color: 0x3e2723 });
            const trunk = new THREE.Mesh(trunkGeo, trunkMat);
            trunk.position.y = trunkHeight / 2;
            trunk.castShadow = true;
            trunk.receiveShadow = true;
            group.add(trunk);

            // Leaves (low poly cone)
            const leafCount = Math.floor(Math.random() * 3) + 2;
            const leafMat = new THREE.MeshStandardMaterial({ color: 0x1b5e20 });
            
            for(let i=0; i<leafCount; i++) {
                const size = Math.random() * 1.5 + 1;
                const leafGeo = new THREE.ConeGeometry(size, size * 1.5, 4);
                const leaf = new THREE.Mesh(leafGeo, leafMat);
                leaf.position.y = trunkHeight + (i * size * 0.6) + size;
                leaf.castShadow = true;
                group.add(leaf);
            }
            return group;
        }

        const trees = [];
        for(let i=0; i<35; i++) {
            const tree = createTree();
            // Random position in a ring, avoiding center fire
            const angle = Math.random() * Math.PI * 2;
            const radius = Math.random() * 25 + 12;
            tree.position.set(Math.cos(angle) * radius, 0, Math.sin(angle) * radius);
            tree.rotation.y = Math.random() * Math.PI;
            tree.traverse(child => {
                if(child.isMesh) {
                    child.castShadow = true;
                    child.receiveShadow = true;
                }
            });
            scene.add(tree);
            trees.push(tree);
        }

        // --- Rocks and Logs ---
        function createRock() {
            const size = Math.random() * 1 + 0.5;
            const geo = new THREE.DodecahedronGeometry(size, 0);
            // distort vertices for low poly look
            const pos = geo.attributes.position;
            for(let i=0; i<pos.count; i++) {
                pos.setXYZ(i, 
                    pos.getX(i) + (Math.random()-0.5)*size*0.3,
                    pos.getY(i) + (Math.random()-0.5)*size*0.3,
                    pos.getZ(i) + (Math.random()-0.5)*size*0.3
                );
            }
            geo.computeVertexNormals();
            const mat = new THREE.MeshStandardMaterial({ color: 0x444444, roughness: 0.9 });
            const rock = new THREE.Mesh(geo, mat);
            rock.castShadow = true;
            rock.receiveShadow = true;
            return rock;
        }

        function createLog() {
            const len = Math.random() * 2 + 1;
            const geo = new THREE.CylinderGeometry(0.2, 0.3, len, 6);
            geo.rotateZ(Math.PI / 2);
            const mat = new THREE.MeshStandardMaterial({ color: 0x5d4037 });
            const log = new THREE.Mesh(geo, mat);
            log.castShadow = true;
            log.receiveShadow = true;
            return log;
        }

        const decorations = [];
        for(let i=0; i<15; i++) {
            const angle = Math.random() * Math.PI * 2;
            const radius = Math.random() * 8 + 4;
            const obj = Math.random() > 0.5 ? createRock() : createLog();
            obj.position.set(Math.cos(angle) * radius, 0, Math.sin(angle) * radius);
            obj.rotation.y = Math.random() * Math.PI;
            if(obj.isMesh && obj.geometry.type === 'CylinderGeometry') obj.rotation.x = Math.random() * Math.PI;
            scene.add(obj);
            decorations.push(obj);
        }

        // --- Campfire ---
        const fireGroup = new THREE.Group();
        scene.add(fireGroup);

        // Logs at base of fire
        const fireLogs = [];
        for(let i=0; i<3; i++) {
            const log = createLog();
            log.scale.set(0.5, 1, 0.5);
            log.position.set((Math.random()-0.5)*1, 0.2, (Math.random()-0.5)*1);
            log.rotation.x = Math.random() * 0.5;
            log.rotation.z = Math.random() * 0.5;
            fireGroup.add(log);
            fireLogs.push(log);
        }

        // Flames (animated cones)
        const flames = [];
        const flameCount = 5;
        for(let i=0; i<flameCount; i++) {
            const h = Math.random() * 1 + 0.5;
            const geo = new THREE.ConeGeometry(0.4, h, 4);
            geo.translate(0, h/2, 0);
            const mat = new THREE.MeshBasicMaterial({ color: 0xff4500, transparent: true, opacity: 0.8 });
            const flame = new THREE.Mesh(geo, mat);
            flame.position.set((Math.random()-0.5)*0.6, h/2 + 0.2, (Math.random()-0.5)*0.6);
            fireGroup.add(flame);
            flames.push({ mesh: flame, baseH: h, baseY: flame.position.y, speed: Math.random() + 0.5 });
        }

        // Inner glow
        const innerGlowGeo = new THREE.SphereGeometry(0.3, 8, 8);
        const innerGlowMat = new THREE.MeshBasicMaterial({ color: 0xffaa00, transparent: true, opacity: 0.6 });
        const innerGlow = new THREE.Mesh(innerGlowGeo, innerGlowMat);
        innerGlow.position.y = 0.5;
        fireGroup.add(innerGlow);

        // --- Sparks Particle System ---
        const sparkCount = 40;
        const sparkGeo = new THREE.BufferGeometry();
        const sparkPositions = new Float32Array(sparkCount * 3);
        const sparkVelocities = [];
        const sparkLife = [];
        
        for(let i=0; i<sparkCount; i++) {
            sparkVelocities.push((Math.random()-0.5)*0.02, Math.random()*0.02 + 0.02, (Math.random()-0.5)*0.02);
            sparkLife.push(Math.random());
        }
        sparkGeo.setAttribute('position', new THREE.Float32BufferAttribute(sparkPositions, 3));
        const sparkMat = new THREE.PointsMaterial({ color: 0xffaa00, size: 0.05, transparent: true, opacity: 0.8 });
        const sparks = new THREE.Points(sparkGeo, sparkMat);
        fireGroup.add(sparks);

        // --- Interaction ---
        const ui = document.getElementById('ui');
        let started = false;

        function start() {
            if(started) return;
            started = true;
            ui.style.opacity = '0';
            ui.style.pointerEvents = 'none';
            setTimeout(() => ui.remove(), 1000);
        }

        window.addEventListener('click', start);
        window.addEventListener('keydown', start);

        // --- Animation Loop ---
        const clock = new THREE.Clock();

        function animate() {
            requestAnimationFrame(animate);

            const time = clock.getElapsedTime();
            const delta = clock.getDelta();

            controls.update();

            // Flicker fire light
            fireLight.intensity = 1.5 + Math.sin(time * 10) * 0.5 + Math.random() * 0.5;
            fireLight.color.setHSL(0.1, 1, 0.5 + Math.random() * 0.2);

            // Animate flames
            flames.forEach(f => {
                const scale = 1 + Math.sin(time * f.speed) * 0.1;
                f.mesh.scale.set(scale, scale, scale);
                f.mesh.position.y = f.baseY + Math.sin(time * 2 + f.speed) * 0.1;
                f.mesh.rotation.y = time * 0.5;
            });

            // Inner glow pulse
            innerGlow.scale.setScalar(1 + Math.sin(time * 5) * 0.1);
            innerGlow.material.opacity = 0.5 + Math.sin(time * 5) * 0.2;

            // Animate sparks
            const positions = sparks.geometry.attributes.position;
            for(let i=0; i<sparkCount; i++) {
                sparkLife[i] -= delta * 0.5;
                if(sparkLife[i] <= 0) {
                    sparkLife[i] = 1;
                    sparkPositions[i*3] = (Math.random()-0.5)*0.5;
                    sparkPositions[i*3+1] = 0.2;
                    sparkPositions[i*3+2] = (Math.random()-0.5)*0.5;
                    sparkVelocities[i*3] = (Math.random()-0.5)*0.02;
                    sparkVelocities[i*3+1] = Math.random()*0.03 + 0.02;
                    sparkVelocities[i*3+2] = (Math.random()-0.5)*0.02;
                } else {
                    sparkPositions[i*3] += sparkVelocities[i*3];
                    sparkPositions[i*3+1] += sparkVelocities[i*3+1];
                    sparkPositions[i*3+2] += sparkVelocities[i*3+2];
                    sparkVelocities[i*3+1] -= 0.005; // gravity
                }
            }
            positions.needsUpdate = true;

            renderer.render(scene, camera);
        }

        // Handle resize
        window.addEventListener('resize', () => {
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
            renderer.setSize(window.innerWidth, window.innerHeight);
        });

        animate();
    </script>
</body>
</html>