交互式3D体素樱花谷网页场景
来自 Wikiprompt,自由的提示词百科全书
交互式3D体素樱花谷网页场景 一份极其详细的中文提示词,指导AI编程助手构建一个完全交互式的3D体素艺术日本樱花谷,作为自包含的HTML/JS网页,包含相机视角、氛围切换以及交付前的自我验证清单。
相关媒体
提示词内容收藏
🌐
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>日式樱花山谷 · 蓝调时刻</title>
<style>
body {
margin: 0;
overflow: hidden;
font-family: "Hiragino Mincho Pro", "Yu Mincho", "MS Mincho", serif;
background-color: #0a0f1a;
}
#info {
position: absolute;
top: 20px;
left: 20px;
color: rgba(255, 240, 220, 0.9);
text-shadow: 0 2px 8px rgba(0,0,0,0.5);
z-index: 10;
pointer-events: none;
font-size: 14px;
letter-spacing: 2px;
backdrop-filter: blur(4px);
padding: 8px 16px;
border-left: 2px solid rgba(255, 180, 180, 0.6);
background: rgba(20, 20, 30, 0.2);
border-radius: 0 8px 8px 0;
}
#controls {
position: absolute;
bottom: 30px;
left: 50%;
transform: translateX(-50%);
display: flex;
gap: 12px;
z-index: 20;
background: rgba(15, 15, 25, 0.6);
backdrop-filter: blur(8px);
padding: 12px 24px;
border-radius: 40px;
border: 1px solid rgba(255, 200, 200, 0.2);
box-shadow: 0 4px 20px rgba(0,0,0,0.4);
flex-wrap: wrap;
justify-content: center;
pointer-events: auto;
}
.btn {
background: rgba(60, 50, 50, 0.5);
border: 1px solid rgba(255, 180, 180, 0.3);
color: #f0e6d8;
padding: 8px 16px;
border-radius: 30px;
font-size: 13px;
cursor: pointer;
transition: all 0.2s ease;
letter-spacing: 1px;
backdrop-filter: blur(4px);
white-space: nowrap;
font-family: inherit;
}
.btn:hover {
background: rgba(120, 80, 80, 0.6);
border-color: rgba(255, 220, 220, 0.6);
color: white;
box-shadow: 0 0 15px rgba(255, 150, 150, 0.3);
}
.btn.active {
background: rgba(180, 100, 100, 0.7);
border-color: #ffb0b0;
color: white;
}
#toggle-ui {
position: absolute;
top: 20px;
right: 20px;
z-index: 30;
background: rgba(20, 20, 30, 0.5);
border: 1px solid rgba(255, 200, 200, 0.2);
color: #ddd;
border-radius: 30px;
padding: 6px 14px;
font-size: 12px;
backdrop-filter: blur(4px);
cursor: pointer;
}
#loading {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: #eee;
font-size: 18px;
z-index: 100;
background: rgba(0,0,0,0.5);
padding: 20px 40px;
border-radius: 8px;
letter-spacing: 2px;
backdrop-filter: blur(4px);
border: 1px solid rgba(255,255,255,0.2);
}
#error {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: #ffaaaa;
background: rgba(0,0,0,0.7);
padding: 20px;
border-radius: 8px;
z-index: 200;
display: none;
text-align: center;
}
@media (max-width: 600px) {
#controls {
bottom: 15px;
padding: 8px 12px;
gap: 8px;
width: 90%;
border-radius: 30px;
}
.btn {
padding: 6px 10px;
font-size: 11px;
}
#info {
font-size: 11px;
top: 10px;
left: 10px;
}
#toggle-ui {
top: 10px;
right: 10px;
font-size: 10px;
}
}
</style>
</head>
<body>
<div id="info">🌸 樱花山谷 · 蓝调时刻</div>
<div id="toggle-ui">◉ 隐藏界面</div>
<div id="controls">
<button class="btn active" data-camera="overview">🏔️ 全景</button>
<button class="btn" data-camera="river">🌊 河边</button>
<button class="btn" data-camera="temple">⛩️ 小径</button>
<button class="btn" data-camera="hill">🌄 山坡</button>
<button class="btn" data-atmosphere="dusk">🌆 蓝调</button>
<button class="btn" data-atmosphere="morning">🌅 清晨</button>
<button class="btn" data-atmosphere="rain">🌧️ 雨中</button>
<button class="btn" id="reset-view">⟲ 重置</button>
<button class="btn" id="save-image">📷 保存</button>
</div>
<div id="loading">加载中…</div>
<div id="error">⚠️ WebGL 不可用或加载失败</div>
<!-- 引入 Three.js 核心库和扩展 -->
<script type="importmap">
{
"imports": {
"three": "https://unpkg.com/three@0.128.0/build/three.module.js",
"three/addons/": "https://unpkg.com/three@0.128.0/examples/jsm/"
}
}
</script>
<script type="module">
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { CSS2DRenderer, CSS2DObject } from 'three/addons/renderers/CSS2DRenderer.js';
// ---------- 初始化 ----------
const container = document.getElementById('container');
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x0a1220); // 深蓝夜空
// 雾效
scene.fog = new THREE.Fog(0x0a1220, 30, 120);
// 相机
const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(12, 8, 18);
camera.lookAt(0, 2, 0);
// 渲染器
const renderer = new THREE.WebGLRenderer({ antialias: true, preserveDrawingBuffer: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
document.body.appendChild(renderer.domElement);
// 控制器
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.05;
controls.maxPolarAngle = Math.PI / 2.2;
controls.minDistance = 3;
controls.maxDistance = 40;
controls.target.set(0, 2, 0);
// 加载提示移除
setTimeout(() => {
document.getElementById('loading').style.display = 'none';
}, 500);
// 错误处理
if (!renderer.capabilities.isWebGL2) {
document.getElementById('error').style.display = 'block';
}
// ---------- 灯光 ----------
// 环境光
const ambientLight = new THREE.AmbientLight(0x404060);
scene.add(ambientLight);
// 主光源 (模拟月光/蓝调)
const dirLight = new THREE.DirectionalLight(0xc0d0ff, 0.8);
dirLight.position.set(5, 12, 8);
dirLight.castShadow = true;
dirLight.shadow.mapSize.width = 1024;
dirLight.shadow.mapSize.height = 1024;
scene.add(dirLight);
// 补光暖色 (灯笼/窗光)
const warmLight = new THREE.PointLight(0xffaa66, 0.6, 20);
warmLight.position.set(2, 1.5, 3);
scene.add(warmLight);
// 辅助光
const fillLight = new THREE.DirectionalLight(0x8899cc, 0.3);
fillLight.position.set(-3, 4, 5);
scene.add(fillLight);
// ---------- 地面与地形 ----------
// 基础地面 (起伏)
const groundGeo = new THREE.CylinderGeometry(18, 20, 1.5, 32);
const groundMat = new THREE.MeshStandardMaterial({ color: 0x2a3a2a, roughness: 0.9, metalness: 0.1 });
const ground = new THREE.Mesh(groundGeo, groundMat);
ground.position.y = -0.8;
ground.receiveShadow = true;
scene.add(ground);
// 山谷草地 (用多个平面模拟起伏)
for (let i = 0; i < 30; i++) {
const patch = new THREE.Mesh(
new THREE.CircleGeometry(0.8 + Math.random() * 1.5, 6),
new THREE.MeshStandardMaterial({ color: 0x3a5a3a, roughness: 0.8 })
);
patch.rotation.x = -Math.PI / 2;
patch.position.x = (Math.random() - 0.5) * 20;
patch.position.z = (Math.random() - 0.5) * 20;
patch.position.y = -0.5 + Math.random() * 0.3;
patch.receiveShadow = true;
scene.add(patch);
}
// 河流 (半透明蓝色平面)
const riverGeo = new THREE.PlaneGeometry(2.5, 12);
const riverMat = new THREE.MeshStandardMaterial({
color: 0x3a6a8a,
transparent: true,
opacity: 0.7,
roughness: 0.2,
metalness: 0.1,
emissive: new THREE.Color(0x112233)
});
const river = new THREE.Mesh(riverGeo, riverMat);
river.rotation.x = -Math.PI / 2;
river.position.set(0, 0.1, 2);
river.receiveShadow = true;
scene.add(river);
// 河岸石块
for (let i = 0; i < 20; i++) {
const stone = new THREE.Mesh(
new THREE.DodecahedronGeometry(0.2 + Math.random() * 0.3),
new THREE.MeshStandardMaterial({ color: 0x556655, roughness: 0.9 })
);
stone.position.x = (Math.random() - 0.5) * 3;
stone.position.z = 1.5 + Math.random() * 8;
stone.position.y = 0.1 + Math.random() * 0.2;
stone.castShadow = true;
stone.receiveShadow = true;
scene.add(stone);
}
// ---------- 樱花树 (程序化) ----------
function createSakuraTree(x, z, scale = 1) {
const treeGroup = new THREE.Group();
// 树干
const trunkMat = new THREE.MeshStandardMaterial({ color: 0x4a3a2a, roughness: 0.8 });
const trunk = new THREE.Mesh(new THREE.CylinderGeometry(0.3 * scale, 0.5 * scale, 2.5 * scale, 6), trunkMat);
trunk.position.y = 1.2 * scale;
trunk.castShadow = true;
trunk.receiveShadow = true;
treeGroup.add(trunk);
// 分支
for (let i = 0; i < 5; i++) {
const branch = new THREE.Mesh(
new THREE.CylinderGeometry(0.1 * scale, 0.2 * scale, 1.2 * scale, 5),
trunkMat
);
branch.position.y = 1.8 * scale + i * 0.3 * scale;
branch.position.x = Math.sin(i * 1.5) * 0.6 * scale;
branch.position.z = Math.cos(i * 1.2) * 0.6 * scale;
branch.rotation.z = Math.sin(i) * 0.5;
branch.rotation.x = Math.cos(i) * 0.4;
branch.castShadow = true;
treeGroup.add(branch);
}
// 花簇 (多个小立方体)
const flowerMat = new THREE.MeshStandardMaterial({
color: 0xffaacc,
emissive: new THREE.Color(0x552233),
roughness: 0.4,
transparent: true,
opacity: 0.9
});
for (let i = 0; i < 40; i++) {
const flower = new THREE.Mesh(new THREE.BoxGeometry(0.2 * scale, 0.2 * scale, 0.2 * scale), flowerMat);
const angle = Math.random() * Math.PI * 2;
const radius = 0.8 * scale + Math.random() * 0.8 * scale;
flower.position.x = Math.cos(angle) * radius;
flower.position.z = Math.sin(angle) * radius;
flower.position.y = 2.2 * scale + Math.random() * 1.2 * scale;
flower.rotation.set(Math.random(), Math.random(), Math.random());
flower.castShadow = true;
treeGroup.add(flower);
}
treeGroup.position.set(x, 0, z);
return treeGroup;
}
// 前景大樱花树
const bigTree = createSakuraTree(-3, -2, 1.4);
scene.add(bigTree);
// 中景几棵
scene.add(createSakuraTree(3, 1, 0.8));
scene.add(createSakuraTree(-1, 4, 0.9));
scene.add(createSakuraTree(2, 5, 0.7));
// 远景小树
scene.add(createSakuraTree(-5, 8, 0.5));
scene.add(createSakuraTree(6, 9, 0.6));
// ---------- 建筑 (茶屋/神社/塔) ----------
function createBuilding(x, z, type = 'house') {
const group = new THREE.Group();
const baseMat = new THREE.MeshStandardMaterial({ color: 0x8a6a4a, roughness: 0.7 });
const roofMat = new THREE.MeshStandardMaterial({ color: 0x6a3a2a, roughness: 0.6 });
if (type === 'house') {
const base = new THREE.Mesh(new THREE.BoxGeometry(1.2, 0.8, 1.2), baseMat);
base.position.y = 0.4;
base.castShadow = true;
group.add(base);
const roof = new THREE.Mesh(new THREE.ConeGeometry(1.0, 0.6, 4), roofMat);
roof.position.y = 1.0;
roof.rotation.y = Math.PI/4;
roof.castShadow = true;
group.add(roof);
} else if (type === 'tower') {
// 多层塔
for (let i = 0; i < 3; i++) {
const floor = new THREE.Mesh(new THREE.BoxGeometry(0.8 - i*0.15, 0.5, 0.8 - i*0.15), baseMat);
floor.position.y = 0.5 + i * 0.7;
floor.castShadow = true;
group.add(floor);
const roof = new THREE.Mesh(new THREE.ConeGeometry(0.6 - i*0.1, 0.4, 4), roofMat);
roof.position.y = 1.0 + i * 0.7;
roof.rotation.y = Math.PI/4;
roof.castShadow = true;
group.add(roof);
}
} else {
// 神社
const base = new THREE.Mesh(new THREE.BoxGeometry(1.5, 0.6, 1.0), baseMat);
base.position.y = 0.3;
base.castShadow = true;
group.add(base);
const roof = new THREE.Mesh(new THREE.BoxGeometry(1.8, 0.3, 1.2), roofMat);
roof.position.y = 0.8;
roof.castShadow = true;
group.add(roof);
const pillar = new THREE.Mesh(new THREE.CylinderGeometry(0.1, 0.1, 0.8), baseMat);
pillar.position.set(0.5, 0.4, 0.3);
group.add(pillar);
const pillar2 = pillar.clone();
pillar2.position.set(-0.5, 0.4, 0.3);
group.add(pillar2);
}
group.position.set(x, 0, z);
return group;
}
// 放置建筑
scene.add(createBuilding(1, 3, 'house'));
scene.add(createBuilding(-1.5, 4.5, 'house'));
scene.add(createBuilding(0.5, 6, 'tower'));
scene.add(createBuilding(-2, 7, 'shrine'));
scene.add(createBuilding(3, 5, 'house'));
// 石灯笼
function createLantern(x, z) {
const group = new THREE.Group();
const stoneMat = new THREE.MeshStandardMaterial({ color: 0x888888, roughness: 0.8 });
const base = new THREE.Mesh(new THREE.CylinderGeometry(0.2, 0.3, 0.5), stoneMat);
base.position.y = 0.25;
base.castShadow = true;
group.add(base);
const top = new THREE.Mesh(new THREE.SphereGeometry(0.15), stoneMat);
top.position.y = 0.6;
top.castShadow = true;
group.add(top);
// 暖光
const light = new THREE.PointLight(0xffaa66, 0.4, 3);
light.position.y = 0.7;
group.add(light);
group.position.set(x, 0, z);
return group;
}
scene.add(createLantern(-2.5, 2));
scene.add(createLantern(2.5, 4));
scene.add(createLantern(-1, 6));
// 小桥 (红色)
const bridgeGroup = new THREE.Group();
const bridgeMat = new THREE.MeshStandardMaterial({ color: 0xaa3333, roughness: 0.5 });
for (let i = 0; i < 3; i++) {
const plank = new THREE.Mesh(new THREE.BoxGeometry(0.3, 0.1, 1.2), bridgeMat);
plank.position.x = -0.4 + i * 0.4;
plank.position.y = 0.3;
plank.position.z = 2.5;
plank.castShadow = true;
bridgeGroup.add(plank);
}
// 桥柱
const pillarMat = new THREE.MeshStandardMaterial({ color: 0x8a5a3a });
for (let i = 0; i < 2; i++) {
const pillar = new THREE.Mesh(new THREE.CylinderGeometry(0.1, 0.1, 0.6), pillarMat);
pillar.position.set(-0.5 + i, 0.3, 2.5);
pillar.castShadow = true;
bridgeGroup.add(pillar);
}
scene.add(bridgeGroup);
// 远山
function createMountain(x, z, scale) {
const mountainMat = new THREE.MeshStandardMaterial({ color: 0x4a5a6a, roughness: 0.9, emissive: new THREE.Color(0x1a2a3a) });
const mountain = new THREE.Mesh(new THREE.ConeGeometry(scale, scale * 1.5, 6), mountainMat);
mountain.position.set(x, scale * 0.5, z);
mountain.castShadow = true;
mountain.receiveShadow = true;
scene.add(mountain);
}
createMountain(-8, 12, 3);
createMountain(6, 14, 4);
createMountain(-2, 16, 5);
createMountain(10, 10, 2.5);
// 雪山 (白色)
const snowMat = new THREE.MeshStandardMaterial({ color: 0xeeeeff, roughness: 0.6 });
const snowMountain = new THREE.Mesh(new THREE.ConeGeometry(4, 5, 6), snowMat);
snowMountain.position.set(-4, 2.5, 18);
snowMountain.castShadow = true;
scene.add(snowMountain);
// 落花粒子
const petalGeo = new THREE.BoxGeometry(0.1, 0.02, 0.05);
const petalMat = new THREE.MeshStandardMaterial({ color: 0xffaacc, emissive: new THREE.Color(0x552233) });
const petals = [];
for (let i = 0; i < 80; i++) {
const petal = new THREE.Mesh(petalGeo, petalMat);
petal.position.set((Math.random() - 0.5) * 15, Math.random() * 5, (Math.random() - 0.5) * 15);
petal.rotation.set(Math.random() * Math.PI, Math.random() * Math.PI, Math.random() * Math.PI);
scene.add(petal);
petals.push(petal);
}
// 萤火虫 (点光源)
const fireflies = [];
for (let i = 0; i < 10; i++) {
const light = new THREE.PointLight(0xaaffaa, 0.3, 2);
light.position.set((Math.random() - 0.5) * 10, 0.5 + Math.random() * 3, (Math.random() - 0.5) * 10);
scene.add(light);
fireflies.push(light);
}
// ---------- 氛围切换 ----------
const atmosphereState = {
dusk: {
bg: 0x0a1220,
fog: new THREE.Fog(0x0a1220, 30, 120),
ambient: 0x404060,
dir: 0xc0d0ff,
dirIntensity: 0.8,
warm: 0xffaa66,
warmIntensity: 0.6
},
morning: {
bg: 0x8a9aaa,
fog: new THREE.Fog(0x8a9aaa, 40, 150),
ambient: 0x8899aa,
dir: 0xffeedd,
dirIntensity: 1.0,
warm: 0xffcc88,
warmIntensity: 0.8
},
rain: {
bg: 0x3a4a5a,
fog: new THREE.Fog(0x3a4a5a, 20, 80),
ambient: 0x556677,
dir: 0x8899aa,
dirIntensity: 0.5,
warm: 0xccaa88,
warmIntensity: 0.4
}
};
function setAtmosphere(type) {
const state = atmosphereState[type];
scene.background = new THREE.Color(state.bg);
scene.fog = state.fog;
ambientLight.color.setHex(state.ambient);
dirLight.color.setHex(state.dir);
dirLight.intensity = state.dirIntensity;
warmLight.color.setHex(state.warm);
warmLight.intensity = state.warmIntensity;
}
// 默认蓝调
setAtmosphere('dusk');
// ---------- 相机预设 ----------
const cameraPresets = {
overview: { pos: [12, 8, 18], target: [0, 2, 0] },
river: { pos: [2, 1.5, 6], target: [0, 1, 3] },
temple: { pos: [-3, 2, 7], target: [-1, 1, 5] },
hill: { pos: [8, 10, 12], target: [0, 3, 5] }
};
function setCamera(presetName) {
const preset = cameraPresets[presetName];
if (!preset) return;
// 平滑过渡 (简单实现)
const startPos = camera.position.clone();
const startTarget = controls.target.clone();
const endPos = new THREE.Vector3(...preset.pos);
const endTarget = new THREE.Vector3(...preset.target);
let t = 0;
const animate = () => {
t += 0.03;
if (t > 1) t = 1;
camera.position.lerpVectors(startPos, endPos, t);
controls.target.lerpVectors(startTarget, endTarget, t);
controls.update();
if (t < 1) requestAnimationFrame(animate);
};
animate();
}
// ---------- UI 事件 ----------
document.querySelectorAll('[data-camera]').forEach(btn => {
btn.addEventListener('click', () => {
setCamera(btn.dataset.camera);
document.querySelectorAll('[data-camera]').forEach(b => b.classList.remove('active'));
btn.classList.add('active');
});
});
document.querySelectorAll('[data-atmosphere]').forEach(btn => {
btn.addEventListener('click', () => {
setAtmosphere(btn.dataset.atmosphere);
document.querySelectorAll('[data-atmosphere]').forEach(b => b.classList.remove('active'));
btn.classList.add('active');
});
});
document.getElementById('reset-view').addEventListener('click', () => {
setCamera('overview');
});
document.getElementById('save-image').addEventListener('click', () => {
renderer.render(scene, camera);
const link = document.createElement('a');
link.download = 'sakura_valley.png';
link.href = renderer.domElement.toDataURL('image/png');
link.click();
});
// 隐藏界面
let uiVisible = true;
document.getElementById('toggle-ui').addEventListener('click', () => {
uiVisible = !uiVisible;
document.getElementById('controls').style.display = uiVisible ? 'flex' : 'none';
document.getElementById('info').style.display = uiVisible ? 'block' : 'none';
});
// 窗口大小调整
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
// ---------- 动画循环 ----------
let time = 0;
function animate() {
requestAnimationFrame(animate);
time += 0.01;
// 落花飘动
petals.forEach((petal, i) => {
petal.position.y += Math.sin(time * 2 + i) * 0.002;
petal.rotation.x += 0.01;
petal.rotation.z += 0.005;
});
// 萤火虫闪烁
fireflies.forEach((light, i) => {
light.intensity = 0.2 + Math.sin(time * 3 + i) * 0.1;
});
controls.update();
renderer.render(scene, camera);
}
animate();
// 初始相机
setCamera('overview');
// 移动端轻量模式
if (window.innerWidth < 600) {
renderer.setPixelRatio(1);
dirLight.shadow.mapSize.width = 512;
dirLight.shadow.mapSize.height = 512;
}
console.log('🌸 樱花山谷加载完成');
</script>
</body>
</html>
用法
此提示词专为 coding 设计。复制上方内容并粘贴到你常用的 AI 工具中。
为获得最佳效果,可将占位符(方括号或大写字母标示)替换为你的具体需求。
讨论
0 条评论