使用codex制作3D网页的心得
- 内容介绍
- 文章标签
- 相关推荐
众所周知,codex的平面设计能力感觉不太行,所以我直接走了3D。所以加载可能需要点时间,如果网络环境不是很好的话,并且这个网页是重特效,所以拒绝了非桌面端访问。 isaca.run 建议大屏幕访问,首页的空间站模型需要加载一点时间。 如果是核显可能有掉帧感觉 佬友们如果有什么好的想法也可以说出来 来一个优化高手教教如何优化,确实有点小卡
忙里偷闲 ,今天终于能把上次分享的网页制作焚决发出来了。制作3D网页一般需要素材,光照,位置等资源。以下要点总结于使用5.4模型的情况下,5.5未知。也欢迎佬友做出新的3D网页进行展示分享。
大致流程是
- 一个好的构思,这个构思可能一开始你就知道要做什么效果或者你逛模型看到一个不错的模型才有构思
- 确定素材功能,例如你想做骨骼动画,那模型必须带有骨骼
- 使用约束和多轮提示词实现
- 调整材质,位置,光照,动画
- 优化
先说素材,3D网页需要使用3D模型,codex是不能制作出精美的模型的,我在制作网页时一般使用公开可下载的模型,例如我的首页是使用了nasa公开的空间站和宇航员模型,当然也有些比较好使的资源网站。
Sketchfab - The best 3D viewer on the web
With a community of over one million creators, we are the world’s largest platform to publish, share, and discover 3D content on web, mobile, AR, and VR.
这个网站大多数模型是可下载的,如果遇到了好看但是不能下载的模型可以使用3D ripper扣下来。
在素材方面有一些坑需要注意
-
材质,如果模型自带的材质你认为足够了,那最好不要让codex画蛇添足,因为材质方面会改的一坨,包括但不限于以下类似提示词会让codex认为需要改材质,最好直接约束使用原材质
当前模型的质感不够/不够亮 -
骨骼动画,如果你的模型带有骨骼,你想为他增加骨骼动画,最好的方式是手搓一套,如果使用codex让他帮你整一套动画可能会发生 骨骼绑定错误/四肢抽搐 等达不到效果的情况
-
sketchfab有一个好处是可以使用官方的api拿到示例光照材质以及位置参数,这些参数能够很好的给codex做参考,代码如下
代码
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<title>Sketchfab Scene Dump</title>
<script src="https://static.sketchfab.com/api/sketchfab-viewer-1.12.1.js"></script>
<style>
body { margin: 0; font-family: sans-serif; }
#api-frame { width: 100vw; height: 100vh; border: 0; }
</style>
</head>
<body>
<iframe
id="api-frame"
allow="autoplay; fullscreen; xr-spatial-tracking"
allowfullscreen
mozallowfullscreen="true"
webkitallowfullscreen="true">
</iframe>
<script>
const iframe = document.getElementById('api-frame');
// 插入作品的id
const uid = '';
const client = new Sketchfab(iframe);
function promisify2(fn, ctx, ...args) {
return new Promise((resolve, reject) => {
fn.call(ctx, ...args, (err, data) => {
if (err) reject(err);
else resolve(data);
});
});
}
function promisify1(fn, ctx, ...args) {
return new Promise((resolve) => {
fn.call(ctx, ...args, (data) => resolve(data));
});
}
function safeError(err) {
if (!err) return null;
if (typeof err === 'string') return err;
try {
return JSON.parse(JSON.stringify(err));
} catch {
return String(err);
}
}
client.init(uid, {
success(api) {
api.start();
api.addEventListener('viewerready', async function () {
try {
const environment = await promisify2(api.getEnvironment, api);
const lightFeatureEnabled = await promisify2(api.isLightFeatureEnabled, api);
const cameraLookAt = await promisify2(api.getCameraLookAt, api);
const fov = await promisify2(api.getFov, api);
const postProcessing = await promisify1(api.getPostProcessing, api);
const materials = await promisify2(api.getMaterialList, api);
const nodes = await promisify2(api.getNodeMap, api);
let lights = [];
if (lightFeatureEnabled) {
const lightResults = await Promise.allSettled([
promisify2(api.getLight, api, 0),
promisify2(api.getLight, api, 1),
promisify2(api.getLight, api, 2),
]);
lights = lightResults.map((result, index) => {
if (result.status === 'fulfilled') {
return {
_comment: `Analytical light ${index}`,
index,
available: true,
data: result.value
};
}
return {
_comment: `Analytical light ${index}`,
index,
available: false,
error: safeError(result.reason)
};
});
}
const sceneDump = {
_comment: "JSON-compatible scene dump. 保留 _comment 字段即可充当注释;如果你要纯净数据,可批量删除所有 _comment。",
model: {
_comment: "模型基础信息",
uid,
sourceUrl: `https://sketchfab.com/3d-models/space-station-3-${uid}`
},
meta: {
_comment: "抓取时间和版本信息",
fetchedAt: new Date().toISOString(),
viewerApiVersion: "1.12.1"
},
environment: {
_comment: "HDR 环境状态。官方 getEnvironment 返回 enabled / exposure / lightIntensity / rotation / shadowEnabled 这类字段。",
...environment
},
lights: {
_comment: "Sketchfab analytical lights 最多 3 盏;这里是 0,1,2 三个索引位的结果。",
featureEnabled: lightFeatureEnabled,
items: lights
},
camera: {
_comment: "相机位置、目标点和 FOV",
lookAt: cameraLookAt,
fov
},
postProcessing: {
_comment: "后期效果设置。getPostProcessing 的回调直接返回 settings。",
settings: postProcessing
},
stats: {
_comment: "便于快速查看规模",
materialCount: Array.isArray(materials) ? materials.length : 0,
nodeCount: Array.isArray(nodes) ? nodes.length : 0
},
materials: {
_comment: "材质列表原始数据",
items: materials
},
nodes: {
_comment: "节点扁平列表原始数据",
items: nodes
}
};
console.log('%c[Sketchfab Scene Dump Object]', 'font-weight:bold;');
console.dir(sceneDump);
console.log('%c[Sketchfab Scene Dump JSON]', 'font-weight:bold;');
const jsonText = JSON.stringify(sceneDump, null, 2);
console.log(jsonText);
if (typeof copy === 'function') {
copy(jsonText);
console.log('%cJSON 已复制到剪贴板', 'font-weight:bold;');
}
} catch (err) {
console.error('Scene dump failed:', err);
}
});
},
error() {
console.error('Viewer init failed');
}
});
</script>
</body>
</html>
接着再说光照和位置,光照可以参考拿到的数据或者需要什么效果让codex自己加,这个影响不大,但是有些情况光照加了你的画面并没有变化,那么就与位置有关了,位置其实是坑最多的一集。
-
光照可能codex默认会给你打在世界原点,加灯光的效果的时候,需要加约束,严格控制灯光朝向
-
codex似乎不能理解有关位置的真正含义,包括但不限于以下情况,尝试多次后始终不能达到你要的效果,最终可能只有俩种解决方案
- 让codex给出配置文件位置有关的参数和计算方式(如果存在),自己手调
- 给出模型具体节点和世界具体坐标,让codex修改
让人物模型的正面朝向镜头/页面,同时露出上半身胸像 参考我发的参考示意图,改变模型的朝向和方向 -
有的佬友可能喜欢再加一层3D背景,这个也同理,不仅要考虑位置还需要考虑大小以及codex很喜欢加的遮罩(会导致看不见背景)
最后说一下杂项
- 多端适配,我认为这个是没有必要的,如果做重3D还考虑手机/平板的话,那就太复杂了,初版只建议做桌面端+拦截检测,部分浏览器可能没有3D环境
- codexplan模式可能喜欢自作主张加特效降级,这个根据个人情况增加约束
- 还有些问题可能没想到,先看佬友们反馈吧,最后放点我的部分angents.md
部分angents.md
## 仓库地图
建议仓库结构如下,并在实现时尽量保持:
- `app/`:Next.js 路由、页面入口、全局布局、全局样式
- `components/`:通用组件与页面区块组件
- `components/sections/`:首页分屏区块,例如 hero、story、projects
- `components/three/`:Three/R3F 场景、材质、粒子、后处理
- `components/ui/`:基础 UI 组件
- `src/config/`:统一配置源,管理文本、链接、项目、社交信息、动效开关
- `src/data/`:结构化静态数据,若与 config 分离时使用
- `lib/`:工具函数、动效辅助、设备能力检测、性能策略
- `hooks/`:滚动、视差、媒体查询、性能降级相关 hooks
- `styles/`:额外样式、变量、动效 token
- `shaders/`:GLSL shader 文件
- `public/`:图片、图标、视频、模型、字体等静态资源
- `docs/`:设计说明、架构说明、后续扩展说明
- `tests/`:测试文件(如项目后续建立测试)
特殊说明:
- 关键入口文件:`app/page.tsx`、`app/layout.tsx`
- 高风险目录:`components/three/`、`shaders/`、`app/globals.css`
- 生成文件目录:`.next/`
- 禁止无明确理由修改的目录:`node_modules/`、构建产物目录
---
## 默认工作方式
代理应默认遵循以下方式:
- 先阅读少量关键文件,再开始改动
- 优先搜索既有实现与相似模式
- 尽量沿用现有命名、目录结构、代码风格
- 优先最小必要改动,不扩大影响面
- 修改公共行为时,同步补充验证与文档
- 对复杂任务,先给出简短计划再实现
- 对高风险改动,先停在“方案/补丁准备好”的状态
- 所有文案、外链、项目卡片内容、社交链接、按钮文案默认配置化
- 所有页面区块应具备可拆分、可替换、可增减的能力
---
## 审批边界与高风险操作
以下操作默认需要明确批准后才能执行:
- 删除大量文件或目录
- 批量重构、跨模块迁移
- 引入新的重型依赖(尤其 3D、动画、渲染、后处理类)
- 修改项目初始化结构或基础路由结构
- 执行可能不可逆的 shell 命令
- 大范围格式化引起噪音 diff
- 修改构建配置、部署配置、环境变量处理方式
以下行为默认禁止:
- 提交、打印、上传或硬编码任何密钥、令牌、密码
- 为了“先跑起来”绕过权限或安全校验
- 未经允许访问生产环境
- 声称完成未实际验证的工作
- 无理由修改锁文件、生成文件、构建产物
与 Codex 客户端相关的额外要求:
- 当操作需要沙盒权限、网络权限、文件系统写权限或命令执行授权时,必须先弹出权限申请
- 申请权限时,用一句话说明目的,例如“需要安装依赖以运行本地预览”
- 未获得批准前,不继续执行高风险或高权限动作
--【壹】--:
太强了大佬,这个页面真的太帅了,学习一下
众所周知,codex的平面设计能力感觉不太行,所以我直接走了3D。所以加载可能需要点时间,如果网络环境不是很好的话,并且这个网页是重特效,所以拒绝了非桌面端访问。 isaca.run 建议大屏幕访问,首页的空间站模型需要加载一点时间。 如果是核显可能有掉帧感觉 佬友们如果有什么好的想法也可以说出来 来一个优化高手教教如何优化,确实有点小卡
忙里偷闲 ,今天终于能把上次分享的网页制作焚决发出来了。制作3D网页一般需要素材,光照,位置等资源。以下要点总结于使用5.4模型的情况下,5.5未知。也欢迎佬友做出新的3D网页进行展示分享。
大致流程是
- 一个好的构思,这个构思可能一开始你就知道要做什么效果或者你逛模型看到一个不错的模型才有构思
- 确定素材功能,例如你想做骨骼动画,那模型必须带有骨骼
- 使用约束和多轮提示词实现
- 调整材质,位置,光照,动画
- 优化
先说素材,3D网页需要使用3D模型,codex是不能制作出精美的模型的,我在制作网页时一般使用公开可下载的模型,例如我的首页是使用了nasa公开的空间站和宇航员模型,当然也有些比较好使的资源网站。
Sketchfab - The best 3D viewer on the web
With a community of over one million creators, we are the world’s largest platform to publish, share, and discover 3D content on web, mobile, AR, and VR.
这个网站大多数模型是可下载的,如果遇到了好看但是不能下载的模型可以使用3D ripper扣下来。
在素材方面有一些坑需要注意
-
材质,如果模型自带的材质你认为足够了,那最好不要让codex画蛇添足,因为材质方面会改的一坨,包括但不限于以下类似提示词会让codex认为需要改材质,最好直接约束使用原材质
当前模型的质感不够/不够亮 -
骨骼动画,如果你的模型带有骨骼,你想为他增加骨骼动画,最好的方式是手搓一套,如果使用codex让他帮你整一套动画可能会发生 骨骼绑定错误/四肢抽搐 等达不到效果的情况
-
sketchfab有一个好处是可以使用官方的api拿到示例光照材质以及位置参数,这些参数能够很好的给codex做参考,代码如下
代码
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<title>Sketchfab Scene Dump</title>
<script src="https://static.sketchfab.com/api/sketchfab-viewer-1.12.1.js"></script>
<style>
body { margin: 0; font-family: sans-serif; }
#api-frame { width: 100vw; height: 100vh; border: 0; }
</style>
</head>
<body>
<iframe
id="api-frame"
allow="autoplay; fullscreen; xr-spatial-tracking"
allowfullscreen
mozallowfullscreen="true"
webkitallowfullscreen="true">
</iframe>
<script>
const iframe = document.getElementById('api-frame');
// 插入作品的id
const uid = '';
const client = new Sketchfab(iframe);
function promisify2(fn, ctx, ...args) {
return new Promise((resolve, reject) => {
fn.call(ctx, ...args, (err, data) => {
if (err) reject(err);
else resolve(data);
});
});
}
function promisify1(fn, ctx, ...args) {
return new Promise((resolve) => {
fn.call(ctx, ...args, (data) => resolve(data));
});
}
function safeError(err) {
if (!err) return null;
if (typeof err === 'string') return err;
try {
return JSON.parse(JSON.stringify(err));
} catch {
return String(err);
}
}
client.init(uid, {
success(api) {
api.start();
api.addEventListener('viewerready', async function () {
try {
const environment = await promisify2(api.getEnvironment, api);
const lightFeatureEnabled = await promisify2(api.isLightFeatureEnabled, api);
const cameraLookAt = await promisify2(api.getCameraLookAt, api);
const fov = await promisify2(api.getFov, api);
const postProcessing = await promisify1(api.getPostProcessing, api);
const materials = await promisify2(api.getMaterialList, api);
const nodes = await promisify2(api.getNodeMap, api);
let lights = [];
if (lightFeatureEnabled) {
const lightResults = await Promise.allSettled([
promisify2(api.getLight, api, 0),
promisify2(api.getLight, api, 1),
promisify2(api.getLight, api, 2),
]);
lights = lightResults.map((result, index) => {
if (result.status === 'fulfilled') {
return {
_comment: `Analytical light ${index}`,
index,
available: true,
data: result.value
};
}
return {
_comment: `Analytical light ${index}`,
index,
available: false,
error: safeError(result.reason)
};
});
}
const sceneDump = {
_comment: "JSON-compatible scene dump. 保留 _comment 字段即可充当注释;如果你要纯净数据,可批量删除所有 _comment。",
model: {
_comment: "模型基础信息",
uid,
sourceUrl: `https://sketchfab.com/3d-models/space-station-3-${uid}`
},
meta: {
_comment: "抓取时间和版本信息",
fetchedAt: new Date().toISOString(),
viewerApiVersion: "1.12.1"
},
environment: {
_comment: "HDR 环境状态。官方 getEnvironment 返回 enabled / exposure / lightIntensity / rotation / shadowEnabled 这类字段。",
...environment
},
lights: {
_comment: "Sketchfab analytical lights 最多 3 盏;这里是 0,1,2 三个索引位的结果。",
featureEnabled: lightFeatureEnabled,
items: lights
},
camera: {
_comment: "相机位置、目标点和 FOV",
lookAt: cameraLookAt,
fov
},
postProcessing: {
_comment: "后期效果设置。getPostProcessing 的回调直接返回 settings。",
settings: postProcessing
},
stats: {
_comment: "便于快速查看规模",
materialCount: Array.isArray(materials) ? materials.length : 0,
nodeCount: Array.isArray(nodes) ? nodes.length : 0
},
materials: {
_comment: "材质列表原始数据",
items: materials
},
nodes: {
_comment: "节点扁平列表原始数据",
items: nodes
}
};
console.log('%c[Sketchfab Scene Dump Object]', 'font-weight:bold;');
console.dir(sceneDump);
console.log('%c[Sketchfab Scene Dump JSON]', 'font-weight:bold;');
const jsonText = JSON.stringify(sceneDump, null, 2);
console.log(jsonText);
if (typeof copy === 'function') {
copy(jsonText);
console.log('%cJSON 已复制到剪贴板', 'font-weight:bold;');
}
} catch (err) {
console.error('Scene dump failed:', err);
}
});
},
error() {
console.error('Viewer init failed');
}
});
</script>
</body>
</html>
接着再说光照和位置,光照可以参考拿到的数据或者需要什么效果让codex自己加,这个影响不大,但是有些情况光照加了你的画面并没有变化,那么就与位置有关了,位置其实是坑最多的一集。
-
光照可能codex默认会给你打在世界原点,加灯光的效果的时候,需要加约束,严格控制灯光朝向
-
codex似乎不能理解有关位置的真正含义,包括但不限于以下情况,尝试多次后始终不能达到你要的效果,最终可能只有俩种解决方案
- 让codex给出配置文件位置有关的参数和计算方式(如果存在),自己手调
- 给出模型具体节点和世界具体坐标,让codex修改
让人物模型的正面朝向镜头/页面,同时露出上半身胸像 参考我发的参考示意图,改变模型的朝向和方向 -
有的佬友可能喜欢再加一层3D背景,这个也同理,不仅要考虑位置还需要考虑大小以及codex很喜欢加的遮罩(会导致看不见背景)
最后说一下杂项
- 多端适配,我认为这个是没有必要的,如果做重3D还考虑手机/平板的话,那就太复杂了,初版只建议做桌面端+拦截检测,部分浏览器可能没有3D环境
- codexplan模式可能喜欢自作主张加特效降级,这个根据个人情况增加约束
- 还有些问题可能没想到,先看佬友们反馈吧,最后放点我的部分angents.md
部分angents.md
## 仓库地图
建议仓库结构如下,并在实现时尽量保持:
- `app/`:Next.js 路由、页面入口、全局布局、全局样式
- `components/`:通用组件与页面区块组件
- `components/sections/`:首页分屏区块,例如 hero、story、projects
- `components/three/`:Three/R3F 场景、材质、粒子、后处理
- `components/ui/`:基础 UI 组件
- `src/config/`:统一配置源,管理文本、链接、项目、社交信息、动效开关
- `src/data/`:结构化静态数据,若与 config 分离时使用
- `lib/`:工具函数、动效辅助、设备能力检测、性能策略
- `hooks/`:滚动、视差、媒体查询、性能降级相关 hooks
- `styles/`:额外样式、变量、动效 token
- `shaders/`:GLSL shader 文件
- `public/`:图片、图标、视频、模型、字体等静态资源
- `docs/`:设计说明、架构说明、后续扩展说明
- `tests/`:测试文件(如项目后续建立测试)
特殊说明:
- 关键入口文件:`app/page.tsx`、`app/layout.tsx`
- 高风险目录:`components/three/`、`shaders/`、`app/globals.css`
- 生成文件目录:`.next/`
- 禁止无明确理由修改的目录:`node_modules/`、构建产物目录
---
## 默认工作方式
代理应默认遵循以下方式:
- 先阅读少量关键文件,再开始改动
- 优先搜索既有实现与相似模式
- 尽量沿用现有命名、目录结构、代码风格
- 优先最小必要改动,不扩大影响面
- 修改公共行为时,同步补充验证与文档
- 对复杂任务,先给出简短计划再实现
- 对高风险改动,先停在“方案/补丁准备好”的状态
- 所有文案、外链、项目卡片内容、社交链接、按钮文案默认配置化
- 所有页面区块应具备可拆分、可替换、可增减的能力
---
## 审批边界与高风险操作
以下操作默认需要明确批准后才能执行:
- 删除大量文件或目录
- 批量重构、跨模块迁移
- 引入新的重型依赖(尤其 3D、动画、渲染、后处理类)
- 修改项目初始化结构或基础路由结构
- 执行可能不可逆的 shell 命令
- 大范围格式化引起噪音 diff
- 修改构建配置、部署配置、环境变量处理方式
以下行为默认禁止:
- 提交、打印、上传或硬编码任何密钥、令牌、密码
- 为了“先跑起来”绕过权限或安全校验
- 未经允许访问生产环境
- 声称完成未实际验证的工作
- 无理由修改锁文件、生成文件、构建产物
与 Codex 客户端相关的额外要求:
- 当操作需要沙盒权限、网络权限、文件系统写权限或命令执行授权时,必须先弹出权限申请
- 申请权限时,用一句话说明目的,例如“需要安装依赖以运行本地预览”
- 未获得批准前,不继续执行高风险或高权限动作
--【壹】--:
太强了大佬,这个页面真的太帅了,学习一下

