chore(prototype): 添加 2D 线缆物理交互 HTML 原型

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-08 20:45:58 +08:00
co-authored by Cursor
parent b5aab4edc1
commit d8056155c1
24 changed files with 3219 additions and 0 deletions
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 349229758cc74e1c8a52bebdf232de2a
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: d19f495b03da4884b9be4e6e602777b5
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,535 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<style>
html,body{margin:0;padding:0;height:100%;overflow:hidden;background:#F4F3F0}
a{color:#3D63DD;text-decoration:none}a:hover{color:#2B4BB5}
</style>
</helmet>
<div style="position:fixed;inset:0;background:#F4F3F0;font-family:system-ui,-apple-system,sans-serif;overflow:hidden">
<canvas ref="{{ canvasRef }}" style="position:absolute;inset:0;width:100%;height:100%;touch-action:none;display:block"></canvas>
<div style="position:absolute;top:22px;left:28px;right:28px;display:flex;align-items:center;justify-content:space-between;gap:16px;pointer-events:none">
<div style="display:flex;flex-direction:column;gap:3px">
<div style="font-size:15px;font-weight:650;color:#26262A;letter-spacing:-0.01em">线缆物理</div>
<div style="font-size:11.5px;color:#9A978F;font-variant-numeric:tabular-nums">Verlet rope · 拉出 / 回收 / 插接</div>
</div>
<div style="display:flex;gap:4px;padding:4px;background:#E9E7E2;border-radius:10px;pointer-events:auto">
<sc-for list="{{ materials }}" as="m" hint-placeholder-count="3">
<button onClick="{{ m.onPick }}" style="border:none;cursor:pointer;padding:7px 14px;border-radius:7px;font-size:12.5px;font-weight:600;font-family:inherit;background:{{ m.bg }};color:{{ m.fg }};transition:background .15s,color .15s">{{ m.label }}</button>
</sc-for>
</div>
</div>
<div style="position:absolute;top:74px;right:28px;width:206px;padding:12px 14px;background:rgba(244,243,240,.92);border:1px solid rgba(38,38,42,.08);box-shadow:0 10px 28px rgba(40,38,32,.10);border-radius:8px;display:flex;flex-direction:column;gap:10px;pointer-events:auto">
<div style="display:flex;align-items:center;justify-content:space-between;gap:10px;font-size:12px;font-weight:650;color:#26262A">
<span>重力</span>
<span style="font-variant-numeric:tabular-nums;color:#77746C">{{ gravityScaleText }}</span>
</div>
<input type="range" min="0.6" max="2.2" step="0.02" value="{{ gravityScale }}" onInput="{{ onGravityInput }}" style="width:100%;accent-color:#4B72E0">
<div style="display:flex;align-items:center;justify-content:space-between;gap:10px;font-size:12px;font-weight:650;color:#26262A">
<span>阻尼</span>
<span style="font-variant-numeric:tabular-nums;color:#77746C">{{ motionDampingText }}</span>
</div>
<input type="range" min="0.86" max="0.99" step="0.005" value="{{ motionDamping }}" onInput="{{ onDampingInput }}" style="width:100%;accent-color:#4B72E0">
</div>
<div style="position:absolute;bottom:22px;left:0;right:0;display:flex;justify-content:center;pointer-events:none">
<div style="padding:8px 16px;border-radius:99px;background:{{ statusBg }};color:{{ statusFg }};font-size:12.5px;font-weight:550;white-space:nowrap;flex:none;transition:background .25s,color .25s">{{ status }}</div>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props="{&quot;maxStretch&quot;:{&quot;editor&quot;:&quot;range&quot;,&quot;default&quot;:1.5,&quot;min&quot;:1.5,&quot;max&quot;:4,&quot;step&quot;:0.1,&quot;tsType&quot;:&quot;number&quot;,&quot;section&quot;:&quot;物理&quot;,&quot;description&quot;:&quot;最大拉出长度(相对初始长度的倍数)&quot;},&quot;retractSpeed&quot;:{&quot;editor&quot;:&quot;range&quot;,&quot;default&quot;:0.09,&quot;min&quot;:0.02,&quot;max&quot;:0.3,&quot;step&quot;:0.01,&quot;tsType&quot;:&quot;number&quot;,&quot;section&quot;:&quot;物理&quot;,&quot;description&quot;:&quot;松手后回收速度&quot;},&quot;gravityScale&quot;:{&quot;editor&quot;:&quot;range&quot;,&quot;default&quot;:1.28,&quot;min&quot;:0.6,&quot;max&quot;:2.2,&quot;step&quot;:0.02,&quot;tsType&quot;:&quot;number&quot;,&quot;section&quot;:&quot;重量&quot;,&quot;description&quot;:&quot;线缆和插头的重力倍率&quot;},&quot;motionDamping&quot;:{&quot;editor&quot;:&quot;range&quot;,&quot;default&quot;:0.94,&quot;min&quot;:0.86,&quot;max&quot;:0.99,&quot;step&quot;:0.005,&quot;tsType&quot;:&quot;number&quot;,&quot;section&quot;:&quot;重量&quot;,&quot;description&quot;:&quot;数值越低越沉,越不飘&quot;}}">
class Component extends DCLogic {
state = { material: 'rubber', plugged: false, dragging: false, gravityScale: 1.28, motionDamping: 0.94 };
presets = {
rubber: { label: '橡胶粗缆', g: 2600, damp: 0.960, w: 17, iter: 30, smooth: 0.34, Lmin: 92, retract: 0.085,
body: '#4B72E0', dark: '#2F4CA8', hi: 'rgba(255,255,255,.38)', kind: 'rubber' },
braided: { label: '编织线', g: 2000, damp: 0.972, w: 12, iter: 24, smooth: 0.20, Lmin: 92, retract: 0.10,
body: '#5C6070', dark: '#3B3E49', hi: '#A9AFBE', kind: 'braid' },
pixel: { label: '像素风', g: 1900, damp: 0.974, w: 15, iter: 24, smooth: 0.22, Lmin: 92, retract: 0.11,
body: '#3D5BD9', dark: '#222E66', mid: '#6E8CF5', hi: '#B9C8FF', kind: 'pixel' }
};
N = 42; plugLen = 58; dockOff = 41; exitGuardLen = 12; extraFeedLen = 300;
componentDidMount() {
this.canvas = this.canvasRef.current;
this.ctx = this.canvas.getContext('2d');
this.fit = () => {
const dpr = window.devicePixelRatio || 1;
this.W = this.canvas.clientWidth; this.H = this.canvas.clientHeight;
this.canvas.width = this.W * dpr; this.canvas.height = this.H * dpr;
this.ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
this.anchor = { x: this.W * 0.5, y: Math.min(218, this.H * 0.32) };
this.LminScale = Math.min(1, Math.max(0.4, (this.H - this.anchor.y - 90) / 300));
this.hole = { x: this.W - 86, y: Math.max(260, this.H * 0.44) };
};
this.fit();
window.addEventListener('resize', this.fit);
// init rope hanging down
const P = [];
for (let i = 0; i < this.N; i++) {
const t = i / (this.N - 1);
P.push({ x: this.anchor.x + t * 2, y: this.anchor.y + t * this.presets.rubber.Lmin, px: 0, py: 0 });
P[i].px = P[i].x; P[i].py = P[i].y;
}
this.pts = P;
this.L = this.presets.rubber.Lmin;
this.pointer = null; this.reelSpin = 0; this.plugAng = Math.PI / 2; this.plugDir = { x: 0, y: 1 };
const c = this.canvas;
c.addEventListener('pointerdown', this.onDown);
c.addEventListener('pointermove', this.onMove);
c.addEventListener('pointerup', this.onUp);
c.addEventListener('pointercancel', this.onUp);
this.raf = requestAnimationFrame(this.loop);
}
componentWillUnmount() {
cancelAnimationFrame(this.raf);
window.removeEventListener('resize', this.fit);
}
pos(e) { const r = this.canvas.getBoundingClientRect(); return { x: e.clientX - r.left, y: e.clientY - r.top }; }
plugCenter() {
const P = this.pts, a = P[this.N - 1];
const dir = this.plugDir || { x: Math.cos(this.plugAng ?? Math.PI / 2), y: Math.sin(this.plugAng ?? Math.PI / 2) };
const ux = dir.x, uy = dir.y;
return { x: a.x + ux * this.plugLen * 0.5, y: a.y + uy * this.plugLen * 0.5, ux, uy };
}
onDown = (e) => {
const p = this.pos(e), pc = this.plugCenter();
if (Math.hypot(p.x - pc.x, p.y - pc.y) < 52) {
this.canvas.setPointerCapture(e.pointerId);
this.pointer = p; this.dragT = { x: this.pts[this.N - 1].x, y: this.pts[this.N - 1].y };
this.setState({ dragging: true });
}
};
onMove = (e) => {
const p = this.pos(e);
if (this.state.dragging) { this.pointer = p; }
else {
const pc = this.plugCenter();
this.canvas.style.cursor = Math.hypot(p.x - pc.x, p.y - pc.y) < 52 ? 'grab' : 'default';
}
};
onUp = () => {
if (!this.state.dragging) return;
const end = this.pts[this.N - 1];
const dock = { x: this.hole.x - this.dockOff, y: this.hole.y };
const near = Math.hypot(end.x - dock.x, end.y - dock.y) < 52;
this.pointer = null;
this.setState({ dragging: false, plugged: near });
};
loop = () => {
this.raf = requestAnimationFrame(this.loop);
const m = this.presets[this.state.material];
const gravityScale = this.state.gravityScale ?? this.props.gravityScale ?? 1.28;
const motionDamping = this.state.motionDamping ?? this.props.motionDamping ?? 0.94;
const Lmin = m.Lmin * (this.LminScale || 1);
const Lmax = Math.max(Lmin * (this.props.maxStretch ?? 2.8), Lmin + this.extraFeedLen * (this.LminScale || 1));
const retract = this.props.retractSpeed ?? m.retract;
const P = this.pts, N = this.N, dt = 1 / 60;
const dock = { x: this.hole.x - this.dockOff, y: this.hole.y };
// --- drag target (heavy lerp) + unplug check
if (this.state.dragging && this.pointer) {
this.dragT.x += (this.pointer.x - this.dragT.x) * 0.38;
this.dragT.y += (this.pointer.y - this.dragT.y) * 0.38;
if (this.dragT.y > this.H - 18) this.dragT.y = this.H - 18;
// clamp to CURRENT rope length — the pin can never overstretch the rope (kills taut-drag jitter);
// length feeds out below, and the target follows it
const dx = this.dragT.x - this.anchor.x, dy = this.dragT.y - this.anchor.y;
const d = Math.hypot(dx, dy), maxR = Math.min(Lmax, this.L) * 0.99;
if (d > maxR) { this.dragT.x = this.anchor.x + dx / d * maxR; this.dragT.y = this.anchor.y + dy / d * maxR; }
if (this.state.plugged && Math.hypot(this.pointer.x - dock.x, this.pointer.y - dock.y) > 74) this.setState({ plugged: false });
}
// --- length feed / retract (driven by raw pointer, not the clamped target)
const endT = this.state.dragging && this.pointer ? this.pointer : (this.state.plugged ? dock : P[N - 1]);
const needed = Math.hypot(endT.x - this.anchor.x, endT.y - this.anchor.y) * 1.04 + 20;
let Lt;
if (this.state.dragging || this.state.plugged) Lt = Math.min(Math.max(needed, Lmin), Lmax);
else Lt = Lmin;
const rate = Lt > this.L ? 0.45 : (this.state.dragging || this.state.plugged ? 0.06 : retract);
const prevL = this.L;
this.L += (Lt - this.L) * rate;
this.reelSpin += (this.L - prevL) * 0.016;
// --- verlet integrate
const seg = this.L / (N - 1);
const exitGuardSegments = this.getExitGuardSegments(seg);
const pinnedEnd = this.state.dragging || this.state.plugged;
for (let i = exitGuardSegments + 1; i < N; i++) {
const p = P[i];
const damp = Math.min(m.damp, motionDamping, (!pinnedEnd && i >= N - 3) ? 0.84 : 1);
const vx = (p.x - p.px) * damp, vy = (p.y - p.py) * damp;
p.px = p.x; p.py = p.y;
p.x += vx; p.y += vy + m.g * gravityScale * dt * dt;
}
this.applyExitGuard(seg, exitGuardSegments);
if (this.state.dragging) { P[N - 1].x = this.dragT.x; P[N - 1].y = this.dragT.y; }
else if (this.state.plugged) {
P[N - 1].x += (dock.x - P[N - 1].x) * 0.5; P[N - 1].y += (dock.y - P[N - 1].y) * 0.5;
}
// --- constraints
for (let k = 0; k < m.iter; k++) {
for (let i = 0; i < N - 1; i++) {
const a = P[i], b = P[i + 1];
const dx = b.x - a.x, dy = b.y - a.y;
const d = Math.hypot(dx, dy) || 1e-6;
const diff = (d - seg) / d;
const pinA = i <= exitGuardSegments;
const pinB = (i + 1 <= exitGuardSegments) || ((i === N - 2) && pinnedEnd);
const wa = pinA ? 0 : (pinB ? 1 : 0.5), wb = pinB ? 0 : (pinA ? 1 : 0.5);
a.x += dx * diff * wa; a.y += dy * diff * wa;
b.x -= dx * diff * wb; b.y -= dy * diff * wb;
}
if (this.state.plugged) {
// orient plug horizontally into socket
const e2 = P[N - 2];
e2.x += (dock.x - seg - e2.x) * 0.4; e2.y += (dock.y - e2.y) * 0.4;
}
// bending stiffness
if (m.smooth > 0 && k % 3 === 0) {
for (let i = exitGuardSegments + 1; i < N - 1; i++) {
if (i === N - 2 && pinnedEnd) continue;
const p = P[i];
const mx = (P[i - 1].x + P[i + 1].x) / 2, my = (P[i - 1].y + P[i + 1].y) / 2;
p.x += (mx - p.x) * m.smooth * 0.5; p.y += (my - p.y) * m.smooth * 0.5;
}
}
this.stabilizePlugEnd(seg, pinnedEnd);
this.applyExitGuard(seg, exitGuardSegments);
}
// floor (pinned dragged end is exempt — no pin-vs-floor fight)
const floor = this.H - 14;
for (let i = exitGuardSegments + 1; i < N; i++) {
if (i === N - 1 && this.state.dragging) continue;
if (P[i].y > floor) {
P[i].y = floor;
P[i].py = P[i].y;
P[i].px += (P[i].x - P[i].px) * 0.45;
}
}
this.draw(m, Lmin, Lmax);
};
getExitGuardSegments(seg) {
return Math.max(1, Math.min(3, Math.round(this.exitGuardLen / Math.max(1, seg))));
}
applyExitGuard(seg, guardSegments) {
const P = this.pts, a = this.anchor;
for (let i = 0; i <= guardSegments && i < this.N; i++) {
const p = P[i];
p.x = a.x;
p.y = a.y + seg * i;
p.px = p.x;
p.py = p.y;
}
}
stabilizePlugEnd(seg, pinnedEnd) {
if (pinnedEnd || this.N < 6) return;
const P = this.pts, N = this.N;
const tail = P[N - 1], neck = P[N - 2], back = P[N - 5];
const dx = neck.x - back.x, dy = neck.y - back.y;
const d = Math.hypot(dx, dy) || 1;
const tx = dx / d, ty = dy / d;
const desiredX = neck.x + tx * seg;
const desiredY = neck.y + ty * seg;
const pull = 0.025;
const ox = (desiredX - tail.x) * pull;
const oy = (desiredY - tail.y) * pull;
tail.x += ox; tail.y += oy;
tail.px += ox; tail.py += oy;
}
drawCablePath(path, m, shadow, cap = 'round') {
const ctx = this.ctx;
ctx.lineCap = cap; ctx.lineJoin = 'round';
if (shadow !== false) {
ctx.save(); ctx.translate(0, 7);
ctx.strokeStyle = 'rgba(40,38,32,.10)'; ctx.lineWidth = m.w + 2; ctx.stroke(path); ctx.restore();
}
if (m.kind === 'pixel') {
// flat stepped bands — no gradients, hard edges
ctx.strokeStyle = m.dark; ctx.lineWidth = m.w + 4; ctx.stroke(path);
ctx.strokeStyle = m.body; ctx.lineWidth = m.w; ctx.stroke(path);
ctx.save(); ctx.translate(0, -m.w * 0.14);
ctx.strokeStyle = m.mid; ctx.lineWidth = m.w * 0.55; ctx.stroke(path); ctx.restore();
ctx.save(); ctx.translate(0, -m.w * 0.3);
ctx.strokeStyle = m.hi; ctx.lineWidth = m.w * 0.22; ctx.stroke(path); ctx.restore();
} else if (m.kind === 'braid') {
ctx.strokeStyle = m.dark; ctx.lineWidth = m.w + 2.5; ctx.stroke(path);
ctx.strokeStyle = m.body; ctx.lineWidth = m.w; ctx.stroke(path);
ctx.save();
ctx.strokeStyle = m.hi; ctx.lineWidth = m.w * 0.62;
ctx.setLineDash([m.w * 0.9, m.w * 1.1]); ctx.stroke(path);
ctx.strokeStyle = 'rgba(0,0,0,.22)'; ctx.lineWidth = m.w * 0.62;
ctx.setLineDash([m.w * 0.9, m.w * 1.1]); ctx.lineDashOffset = m.w; ctx.stroke(path);
ctx.restore();
} else {
ctx.strokeStyle = m.dark; ctx.lineWidth = m.w + 2.5; ctx.stroke(path);
ctx.strokeStyle = m.body; ctx.lineWidth = m.w; ctx.stroke(path);
ctx.save(); ctx.translate(0, -m.w * 0.22);
ctx.strokeStyle = m.hi; ctx.lineWidth = m.w * 0.3; ctx.stroke(path); ctx.restore();
}
}
draw(m, Lmin, Lmax) {
this.clearCanvas();
this.drawReel(m, Lmin, Lmax);
this.drawExitStub(m);
if (!this.state.plugged) this.drawSocket(m);
this.drawMainCable(m);
this.drawFrontCableOverlay(m);
this.drawCablePlug(m);
if (this.state.plugged) this.drawSocket(m);
}
clearCanvas() {
this.ctx.clearRect(0, 0, this.W, this.H);
}
drawReel(m, Lmin, Lmax) {
const ctx = this.ctx, a = this.anchor;
const reelY = a.y - 128;
const frac = (this.L - Lmin) / (Lmax - Lmin);
ctx.fillStyle = '#E8E6E1';
ctx.beginPath(); ctx.arc(a.x, reelY, 108, 0, 7); ctx.fill();
ctx.strokeStyle = '#DBD8D2'; ctx.lineWidth = 1.5;
ctx.beginPath(); ctx.arc(a.x, reelY, 74, 0, 7); ctx.stroke();
this.drawReelSpinMarker(reelY);
ctx.strokeStyle = m.body; ctx.lineWidth = 5; ctx.lineCap = 'round';
ctx.beginPath();
ctx.arc(a.x, reelY, 92, -Math.PI / 2, -Math.PI / 2 + Math.max(0.001, frac) * Math.PI * 2);
ctx.stroke();
}
drawReelSpinMarker(reelY) {
const ctx = this.ctx, a = this.anchor;
ctx.save(); ctx.translate(a.x, reelY); ctx.rotate(this.reelSpin);
ctx.fillStyle = '#CFCCC5';
for (let i = 0; i < 3; i++) {
ctx.rotate(Math.PI * 2 / 3);
ctx.beginPath(); ctx.arc(74, 0, 5, 0, 7); ctx.fill();
}
ctx.restore();
}
drawExitStub(m) {
const ctx = this.ctx, a = this.anchor;
ctx.fillStyle = '#E8E6E1';
ctx.beginPath(); ctx.roundRect(a.x - 20, a.y - 46, 40, 44, 8); ctx.fill();
ctx.fillStyle = 'rgba(40,38,32,.28)';
ctx.beginPath(); ctx.ellipse(a.x, a.y - 4, Math.min(16, m.w * 0.5 + 5), 4.5, 0, 0, 7); ctx.fill();
}
drawMainCable(m) {
const ctx = this.ctx;
ctx.save();
ctx.clip(this.buildExitStubMask(), 'evenodd');
this.drawCablePath(this.buildMainCablePath(), m);
ctx.restore();
}
buildMainCablePath() {
const a = this.anchor, P = this.pts, path = new Path2D();
path.moveTo(a.x, a.y - 5);
path.lineTo(P[0].x, P[0].y);
this.appendCableCurve(path, 1, this.N - 1);
return path;
}
buildExitStubMask() {
const a = this.anchor, clip = new Path2D();
clip.rect(0, 0, this.W, this.H);
clip.roundRect(a.x - 20, a.y - 46, 40, 44, 8);
return clip;
}
drawFrontCableOverlay(m) {
const frontStartIndex = this.findFrontCableStartIndex();
if (frontStartIndex >= this.N - 1) return;
this.drawCablePath(this.buildFrontCablePath(frontStartIndex), m, false, 'butt');
}
buildFrontCablePath(startIndex) {
const P = this.pts, N = this.N;
const path = new Path2D();
path.moveTo(P[startIndex].x, P[startIndex].y);
this.appendCableCurve(path, startIndex + 1, N - 1);
return path;
}
findFrontCableStartIndex() {
const P = this.pts, N = this.N;
let bottomIndex = 1;
for (let i = 2; i < N - 1; i++) {
if (P[i].y > P[bottomIndex].y) bottomIndex = i;
}
return bottomIndex;
}
appendCableCurve(path, controlStart, endIndex) {
const P = this.pts;
for (let i = controlStart; i < endIndex; i++) {
const mx = (P[i].x + P[i + 1].x) / 2, my = (P[i].y + P[i + 1].y) / 2;
path.quadraticCurveTo(P[i].x, P[i].y, mx, my);
}
path.lineTo(P[endIndex].x, P[endIndex].y);
}
drawCablePlug(m) {
const P = this.pts, e = P[this.N - 1];
this.updatePlugAngle();
this.drawPlug(e.x, e.y, this.plugAng, m);
}
updatePlugAngle() {
const dir = this.getPlugTargetDirection();
let ta = Math.atan2(dir.y, dir.x);
const da = Math.atan2(Math.sin(ta - this.plugAng), Math.cos(ta - this.plugAng));
if (!this.state.plugged && Math.abs(da) < 0.006) return;
let step = da * (this.state.plugged ? 0.4 : (this.state.dragging ? 0.18 : 0.12));
const MAXW = this.state.plugged ? 0.11 : (this.state.dragging ? 0.075 : 0.045);
if (step > MAXW) step = MAXW; else if (step < -MAXW) step = -MAXW;
this.plugAng += step;
this.plugDir.x = Math.cos(this.plugAng);
this.plugDir.y = Math.sin(this.plugAng);
}
getPlugTargetDirection() {
if (this.state.plugged) return { x: 1, y: 0 };
const P = this.pts, N = this.N, e = P[N - 1];
const prev = this.plugDir || { x: Math.cos(this.plugAng), y: Math.sin(this.plugAng) };
const seg = Math.max(1, this.L / Math.max(1, N - 1));
let sx = 0, sy = 0, total = 0;
for (let i = N - 2; i >= Math.max(0, N - 8); i--) {
const dx = e.x - P[i].x, dy = e.y - P[i].y;
const d = Math.hypot(dx, dy);
if (d < seg * 0.35) continue;
const w = Math.min(1.75, d / seg);
sx += dx / d * w;
sy += dy / d * w;
total += w;
}
const span = P[Math.max(0, N - 7)];
const spanLen = Math.hypot(e.x - span.x, e.y - span.y);
if (total <= 0.001 || spanLen < seg * 1.2) return prev;
let dx = sx / total, dy = sy / total;
const d = Math.hypot(dx, dy) || 1;
dx /= d; dy /= d;
const dot = dx * prev.x + dy * prev.y;
if (dot < -0.2 && spanLen < seg * 2.8) return prev;
return { x: dx, y: dy };
}
drawSocket(m) {
const ctx = this.ctx, P = this.pts, N = this.N, h = this.hole;
const e = P[N - 1];
const nearPlug = Math.hypot(e.x - (h.x - this.dockOff), e.y - h.y);
ctx.fillStyle = '#E8E6E1';
ctx.beginPath(); ctx.roundRect(h.x - 30, h.y - 74, 110, 148, 14); ctx.fill();
ctx.fillStyle = '#2B2B2E';
ctx.beginPath(); ctx.arc(h.x, h.y, 19, 0, 7); ctx.fill();
ctx.fillStyle = '#0E0E10';
ctx.beginPath(); ctx.arc(h.x, h.y, 10, 0, 7); ctx.fill();
if (!this.state.plugged && this.state.dragging && nearPlug < 110) {
ctx.strokeStyle = m.body; ctx.lineWidth = 3; ctx.globalAlpha = 0.4 + 0.5 * (1 - Math.min(1, nearPlug / 110));
ctx.beginPath(); ctx.arc(h.x, h.y, 30, 0, 7); ctx.stroke(); ctx.globalAlpha = 1;
}
ctx.fillStyle = this.state.plugged ? '#3FA96B' : '#C9C6BF';
ctx.beginPath(); ctx.arc(h.x + 26, h.y - 52, 4.5, 0, 7); ctx.fill();
}
drawPlug(x, y, ang, m) {
const ctx = this.ctx;
ctx.save(); ctx.translate(x, y); ctx.rotate(ang);
ctx.lineCap = 'butt';
// strain relief (cable-colored taper)
ctx.fillStyle = m.dark;
ctx.beginPath();
ctx.moveTo(-14, -m.w * 0.5 - 1); ctx.lineTo(6, -m.w * 0.72 - 2);
ctx.lineTo(6, m.w * 0.72 + 2); ctx.lineTo(-14, m.w * 0.5 + 1); ctx.closePath(); ctx.fill();
// barrel
const g = ctx.createLinearGradient(0, -13, 0, 13);
g.addColorStop(0, '#B9BCC2'); g.addColorStop(0.28, '#F2F3F5'); g.addColorStop(0.55, '#8E9298'); g.addColorStop(1, '#5A5D63');
ctx.fillStyle = g;
ctx.beginPath(); ctx.roundRect(6, -13, 26, 26, 3); ctx.fill();
// accent rings
ctx.fillStyle = '#C2358F'; ctx.fillRect(32, -12, 5, 24);
ctx.fillStyle = '#28B7A8'; ctx.fillRect(37, -12, 4, 24);
// collar
const g2 = ctx.createLinearGradient(0, -10, 0, 10);
g2.addColorStop(0, '#D8DADE'); g2.addColorStop(0.5, '#F5F6F7'); g2.addColorStop(1, '#75787E');
ctx.fillStyle = g2;
ctx.beginPath(); ctx.roundRect(41, -10, 6, 20, 1.5); ctx.fill();
// gold shaft
const g3 = ctx.createLinearGradient(0, -7, 0, 7);
g3.addColorStop(0, '#8F6B12'); g3.addColorStop(0.3, '#F4D876'); g3.addColorStop(0.6, '#D9AE33'); g3.addColorStop(1, '#7A5A0E');
ctx.fillStyle = g3;
ctx.fillRect(47, -6.5, 20, 13);
// notch rings
ctx.fillStyle = '#1C1710';
ctx.fillRect(52, -6.5, 2.2, 13); ctx.fillRect(58, -6.5, 2.2, 13);
// tip
ctx.fillStyle = g3;
ctx.beginPath(); ctx.moveTo(67, -6.5); ctx.lineTo(72.5, -3); ctx.lineTo(72.5, 3); ctx.lineTo(67, 6.5); ctx.closePath(); ctx.fill();
ctx.restore();
}
canvasRef = React.createRef();
onGravityInput = (e) => {
this.setState({ gravityScale: Number(e.target.value) });
};
onDampingInput = (e) => {
this.setState({ motionDamping: Number(e.target.value) });
};
renderVals() {
const active = this.state.material;
const materials = Object.keys(this.presets).map((id) => ({
id, label: this.presets[id].label,
bg: id === active ? '#26262A' : 'transparent',
fg: id === active ? '#FFFFFF' : '#6B6963',
onPick: () => this.setState({ material: id })
}));
const plugged = this.state.plugged;
return {
canvasRef: this.canvasRef,
materials,
gravityScale: this.state.gravityScale,
gravityScaleText: this.state.gravityScale.toFixed(2),
motionDamping: this.state.motionDamping,
motionDampingText: this.state.motionDamping.toFixed(3),
onGravityInput: this.onGravityInput,
onDampingInput: this.onDampingInput,
status: plugged ? '已连接 — 拖拽插头可拔出' : (this.state.dragging ? '拉扯会放出更多线,松手自动回收' : '拖拽插头试试 — 插进右侧插孔'),
statusBg: plugged ? '#26402F' : '#E9E7E2',
statusFg: plugged ? '#8FE0AE' : '#77746C'
};
}
}
</script>
</body>
</html>
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 94b761c7a93d45c5a2030fbb5bef8c23
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 573faa4818a14f48bc33412272a6d125
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 9ba977124f9744b1bef1acca513e7b4e
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,115 @@
fileFormatVersion: 2
guid: 89c3eedbb60c406a9e8544e36295c34a
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 12
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
flipGreenChannel: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMipmapLimit: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: 5e97eb03825dee720800000000000000
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
nameFileIdTable: {}
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,115 @@
fileFormatVersion: 2
guid: dd51a060e6484d1ca3fb7a28c65a48fc
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 12
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
flipGreenChannel: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMipmapLimit: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: 5e97eb03825dee720800000000000000
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
nameFileIdTable: {}
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,115 @@
fileFormatVersion: 2
guid: 71e7e75a2ef44bf3bcdc63103638c639
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 12
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
flipGreenChannel: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMipmapLimit: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: 5e97eb03825dee720800000000000000
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
nameFileIdTable: {}
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,115 @@
fileFormatVersion: 2
guid: e916d6782b9b46ca921a46a74a370cca
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 12
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
flipGreenChannel: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMipmapLimit: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: 5e97eb03825dee720800000000000000
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
nameFileIdTable: {}
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,115 @@
fileFormatVersion: 2
guid: 27ec977643184f14b75e84b0859513c5
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 12
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
flipGreenChannel: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMipmapLimit: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: 5e97eb03825dee720800000000000000
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
nameFileIdTable: {}
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,115 @@
fileFormatVersion: 2
guid: 59c494bd6d6d465687bb3121cdac50c9
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 12
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
flipGreenChannel: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMipmapLimit: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: 5e97eb03825dee720800000000000000
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
nameFileIdTable: {}
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,115 @@
fileFormatVersion: 2
guid: 9086b29c556b42b592a5bacb60054247
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 12
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
flipGreenChannel: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMipmapLimit: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: 5e97eb03825dee720800000000000000
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
nameFileIdTable: {}
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,115 @@
fileFormatVersion: 2
guid: 2bcf39c49a364bd9b4edb964f62cb9ab
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 12
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
flipGreenChannel: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMipmapLimit: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: 5e97eb03825dee720800000000000000
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
nameFileIdTable: {}
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant: