Playtest #3 fixes: lost models, picking, live LP, temp overflow, 蕾缪安 S3, 回环射手, FX, detail card, spinners
- #1 lost operator models: the Spine store no longer hands out a skeleton whose unload is in flight (PIXI.Assets.unload is async); eviction runs 1 s after a release and the empty-scene budget only after 3 s - #7 picking: one shared rule (render/pick.js, pixel probe where bodies overlap) for prep/battle clicks, hover, the enemy pen and equipment drops; the drag ghost stands on its drop tile; hover probes capped at one per frame - #2 the top-bar LP drops live as the own battle's enemies enter the blue gate (−N, 联防中), teammates' pending LP in the team panel - #3 temp overflow pieces that arrive after a prep deadline survive through the next prep (tempDue); temp-row warning and ready-button reason - #4 蕾缪安 S3: locks every 0.5 s, then one shell every 0.3 s in lock order (PRTS notes), bombardShell fx - #5 回环射手: real boomerang (out 15, back 3.75 tiles/s, attack only when every boomerang is caught) - #6 visible projectiles, muzzle flashes, slashes, skill bursts and auras at unchanged frame cost - #8 特质 right under the detail card header, with its official type icon - #9 no spinning busy cursors / spinners next to texts; game data warmed before the match - docs, recordings and tests updated (2414 unit tests, all browser suites green)
This commit is contained in:
1 parent
01a44cd288
commit
0aba602ecf
72 files changed
+5132
-571
No files matched your search
@@ -102,10 +102,14 @@
|
||||
.dtrait { display: flex; gap: .08rem; align-items: flex-start; font-size: .14rem; line-height: 1.6; color: var(--text-md); padding: .08rem .1rem; background: rgba(255, 255, 255, .03); border-left: 2px solid var(--line-3); }
|
||||
.dtrait .icon { width: .16rem; height: .16rem; margin-top: .03rem; color: var(--text-lo); flex: none; }
|
||||
.dstats-wrap { display: flex; gap: .12rem; align-items: stretch; }
|
||||
.dstats { flex: 1; display: grid; grid-template-columns: repeat(2, 1fr); gap: 1px; background: var(--line); border: 1px solid var(--line); }
|
||||
.dstat { display: flex; align-items: baseline; justify-content: space-between; gap: .06rem; padding: .05rem .1rem; background: #0f1311; }
|
||||
.dstat__k { font-size: .13rem; color: var(--text-lo); white-space: nowrap; }
|
||||
.dstat__v { font-size: .18rem; color: #fff; }
|
||||
/* compact 4 × 2 grid (label over value): the skill stays close under the 特质 block (user playtest #3 item 8) */
|
||||
/* (enemy / token cards: the grid is a direct child of the column-flex scroller — it must not grow to fill the card) */
|
||||
.dstats { flex: none; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 1px; background: var(--line); border: 1px solid var(--line); }
|
||||
.dstats-wrap > .dstats { flex: 1; }
|
||||
.dstat { display: flex; flex-direction: column; justify-content: center; gap: .01rem; min-width: 0; padding: .04rem .07rem; background: #0f1311; }
|
||||
.dstat__k { font-size: .12rem; color: var(--text-lo); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||||
.dstat__row { display: flex; align-items: baseline; min-width: 0; white-space: nowrap; }
|
||||
.dstat__v { font-size: .17rem; line-height: 1.15; color: #fff; }
|
||||
.dstat small { font-size: .11rem; color: var(--text-dim); margin-left: .04rem; }
|
||||
.drange { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: .06rem; padding: .06rem .1rem; background: #0f1311; border: 1px solid var(--line); min-width: 1.1rem; }
|
||||
.rgrid { --rg: .14rem; display: grid; gap: 2px; }
|
||||
@@ -134,9 +138,16 @@
|
||||
.dsp__num .icon { width: .14rem; height: .14rem; color: var(--gold); }
|
||||
.dtalent { display: flex; flex-direction: column; gap: .02rem; }
|
||||
.dtalent b { font-size: .15rem; color: var(--text-hi); }
|
||||
.dgarrison { display: flex; flex-direction: column; gap: .06rem; }
|
||||
.dgarrison__type { display: inline-flex; align-self: flex-start; align-items: center; gap: .05rem; font-size: .13rem; color: var(--gold-2); padding: .01rem .08rem .01rem .04rem; border: 1px solid rgba(242, 189, 62, .4); }
|
||||
.dgarrison__icon { width: .2rem; height: .2rem; object-fit: contain; }
|
||||
/* the operator's own effect (特质, user playtest #3 item 8): compact, right under the header, gold accent */
|
||||
.dgarrison {
|
||||
display: flex; flex-direction: column; gap: .04rem; padding: .07rem .1rem .08rem; flex: none;
|
||||
background: linear-gradient(90deg, rgba(242, 189, 62, .1), rgba(242, 189, 62, .02) 70%); border-left: 3px solid var(--gold-2);
|
||||
}
|
||||
.dgarrison__head { display: flex; align-items: center; gap: .08rem; }
|
||||
.dgarrison__k { font-size: .14rem; font-weight: 900; letter-spacing: .12em; color: var(--gold-2); }
|
||||
.dgarrison__type { display: inline-flex; align-items: center; gap: .04rem; font-size: .12rem; line-height: 1.5; color: var(--gold-2); padding: 0 .07rem 0 .03rem; border: 1px solid rgba(242, 189, 62, .4); }
|
||||
.dgarrison__icon { width: .18rem; height: .18rem; object-fit: contain; }
|
||||
.dgarrison__text { font-size: .15rem; line-height: 1.55; color: var(--text-hi); }
|
||||
.dbonds { display: flex; flex-wrap: wrap; gap: .08rem; }
|
||||
.dbond { display: inline-flex; align-items: center; gap: .05rem; padding: .03rem .1rem .03rem .05rem; font-size: .15rem; background: rgba(78, 216, 175, .08); border: 1px solid var(--mint-800); color: var(--mint-400); }
|
||||
/* the unit's bonds in the header's right column, right under name / class (user playtest #2 item 9): icon, name,
|
||||
@@ -351,7 +362,14 @@
|
||||
background: rgba(8, 11, 10, .92); border: 1px solid var(--mint-500); border-radius: .3rem; font-size: .13rem; color: var(--mint-400); font-weight: 700; }
|
||||
.spcard__taker .pavatar { --pa: .4rem; border-radius: 50%; overflow: hidden; border: 2px solid var(--mint-400); }
|
||||
.spcard.is-taken .spcard__taker { filter: none; }
|
||||
.spcard__spin { position: absolute; inset: 0; display: grid; place-items: center; background: rgba(0, 0, 0, .4); }
|
||||
/* the card being picked (g.choice in flight): mint frame + a 选择中 strip with the sweeping busy bar of the buttons
|
||||
(components.css btn-busy) — no spinner over the card's text (user playtest #3 item 9) */
|
||||
.spcard.is-busy { border-color: var(--mint-400); box-shadow: inset 0 0 0 1px var(--mint-400); }
|
||||
.spcard__busy {
|
||||
position: absolute; left: 0; right: 0; bottom: 0; padding: .05rem 0 .08rem; overflow: hidden; pointer-events: none;
|
||||
font-size: .14rem; font-weight: 700; letter-spacing: .2em; color: var(--mint-400); background: rgba(8, 11, 10, .85);
|
||||
}
|
||||
.spcard__busy::after { content: ''; position: absolute; left: 0; bottom: 0; width: 40%; height: 2px; background: var(--mint-400); animation: btn-busy 1.1s var(--ease-in-out) infinite; }
|
||||
|
||||
/* Grid image boxes: definite 100% tracks so `height: 100%` images resolve against the box (an auto track would
|
||||
let non-square art overflow its frame). */
|
||||
@@ -390,6 +408,31 @@
|
||||
}
|
||||
.fwheel__sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
|
||||
|
||||
/* ---- the temp overflow row's notice (ui/underframe.js TempRowNotice, user playtest #3 item 3): a dashed red frame
|
||||
around 临时整备区 and a label at its end. Over the field, under every HUD panel (.gm__hud z 3), never takes the
|
||||
pointer (the pieces under it stay draggable). ---- */
|
||||
.tempnote { position: fixed; inset: 0; z-index: 2; pointer-events: none; }
|
||||
.tempnote * { pointer-events: none; }
|
||||
.tempnote__frame { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
|
||||
.tempnote__frame polygon {
|
||||
fill: rgba(255, 60, 40, .1); stroke: #ff5a47; stroke-width: 2.2px; stroke-dasharray: 9 5; stroke-linejoin: round;
|
||||
vector-effect: non-scaling-stroke; filter: drop-shadow(0 0 .05rem rgba(255, 60, 40, .7)); animation: tempnote-pulse 1.6s ease-in-out infinite;
|
||||
}
|
||||
@keyframes tempnote-pulse { 50% { opacity: .55; } }
|
||||
.tempnote__label {
|
||||
position: absolute; transform: translate(-100%, -50%); display: flex; flex-direction: column; gap: .02rem; max-width: 2.9rem;
|
||||
padding: .06rem .12rem .07rem .1rem; background: rgba(40, 6, 6, .9); border: 1px solid rgba(255, 90, 71, .75); border-left: 3px solid #ff5a47;
|
||||
box-shadow: 0 .04rem .16rem rgba(0, 0, 0, .6); color: #ffdcd6; animation: tempnote-in var(--t-med) var(--ease-out);
|
||||
}
|
||||
@keyframes tempnote-in { from { opacity: 0; } }
|
||||
.tempnote__label.is-right { transform: translate(0, -50%); border-left-width: 1px; border-right: 3px solid #ff5a47; }
|
||||
.tempnote__title { display: flex; align-items: center; gap: .05rem; font-size: .15rem; font-weight: 700; color: #fff; white-space: nowrap; }
|
||||
.tempnote__title .icon { width: .17rem; height: .17rem; color: #ff6a55; flex: none; }
|
||||
.tempnote__title .num { color: #ff8a78; font-size: .17rem; }
|
||||
.tempnote__rule { font-size: .12rem; line-height: 1.45; color: rgba(255, 220, 214, .88); }
|
||||
@media (prefers-reduced-motion: reduce) { .tempnote__frame polygon, .tempnote__label { animation: none; } }
|
||||
.sp-reduced-motion .tempnote__frame polygon, .sp-reduced-motion .tempnote__label { animation: none; }
|
||||
|
||||
/* ---- underframe: the selection diamond of a tapped own piece (ui/underframe.js): 撤退 / 出售 +N / 销毁 ----
|
||||
It sits above every HUD panel (detail card z 9, bond popup, drawer, shop bar): only its buttons take pointer events,
|
||||
so they are never covered (user playtest #2 item 8); overlays that must win (机变, modals, the drag ghost) are higher. */
|
||||
@@ -403,7 +446,7 @@
|
||||
padding: 0; background: none; border: 0; color: #fff; cursor: pointer; filter: drop-shadow(0 .03rem .06rem rgba(0, 0, 0, .8));
|
||||
animation: uframe-in 200ms var(--ease-out);
|
||||
}
|
||||
.uframe__btn:disabled { opacity: .5; cursor: wait; }
|
||||
.uframe__btn:disabled { opacity: .5; cursor: default; }
|
||||
.uframe__btn--retreat { left: 25%; top: 25%; transform: translate(-80%, -90%); }
|
||||
.uframe__btn--sell, .uframe__btn--destroy { left: 75%; top: 25%; transform: translate(-20%, -90%); }
|
||||
/* the octagon plate every button stands on (the official util_btn plates are octagons) */
|
||||
|
||||
@@ -133,6 +133,23 @@
|
||||
.lp--danger { color: var(--red-premium); }
|
||||
.lp--danger .lp__icon { filter: hue-rotate(-140deg) saturate(2.4) brightness(.95); }
|
||||
.lp--team { color: var(--mint-glow); }
|
||||
/* the running battle's pending loss (LpTower `pending`, user playtest #3 item 2): the number turns red, a −N plate
|
||||
pops again on every new leak (keyed), 联防中 while teammates may still save part of it */
|
||||
.lp.is-pending .lp__val { color: var(--red-premium); text-shadow: 0 0 .08rem rgba(255, 60, 60, .45); }
|
||||
.lp__pend {
|
||||
align-self: center; margin-left: .02em; padding: .06em .24em; font-size: .56em; font-weight: 700; line-height: 1.1;
|
||||
color: #fff; background: #d8262a; box-shadow: 0 0 .1rem rgba(255, 50, 50, .55);
|
||||
clip-path: polygon(.12em 0, 100% 0, 100% calc(100% - .12em), calc(100% - .12em) 100%, 0 100%, 0 .12em);
|
||||
animation: lp-pend 520ms var(--ease-out);
|
||||
}
|
||||
.lp__note {
|
||||
align-self: center; padding: .08em .3em; font-size: .4em; font-weight: 700; letter-spacing: .08em; line-height: 1.2;
|
||||
color: #1a0800; background: var(--orange);
|
||||
}
|
||||
.lp--sm .lp__note { font-size: .6em; }
|
||||
@keyframes lp-pend { 0% { opacity: 0; transform: scale(1.9); } 45% { opacity: 1; transform: scale(.92); } 100% { transform: scale(1); } }
|
||||
@media (prefers-reduced-motion: reduce) { .lp__pend { animation: none; } }
|
||||
.sp-reduced-motion .lp__pend { animation: none; }
|
||||
|
||||
/* enemy preview button: amber [🔍▶▶] → the pen (research 09 §2); grey [🔍] in the pen view and outside 休整期 */
|
||||
.enemybtn {
|
||||
@@ -159,6 +176,13 @@
|
||||
.readywrap { display: flex; flex-direction: column; align-items: flex-end; gap: .05rem; }
|
||||
.readywrap__count { font-size: .14rem; color: var(--text-lo); }
|
||||
.readywrap__count b { color: var(--mint-400); font-size: .17rem; }
|
||||
/* why 准备就绪 is refused (the temp overflow row holds pieces, user playtest #3 item 3): shown, not only on hover */
|
||||
.readywrap__why {
|
||||
display: inline-flex; align-items: center; gap: .05rem; padding: .02rem .1rem .02rem .06rem; font-size: .14rem; font-weight: 700;
|
||||
color: #ffdcd6; background: rgba(40, 6, 6, .88); border: 1px solid rgba(255, 90, 71, .7); border-right: 3px solid #ff5a47; white-space: nowrap;
|
||||
}
|
||||
.readywrap__why .icon { width: .16rem; height: .16rem; color: #ff6a55; flex: none; }
|
||||
.readywrap__why b { color: #ff8a78; font-size: .16rem; }
|
||||
.readybtn {
|
||||
display: flex; align-items: center; gap: .12rem; height: .56rem; padding: 0 .16rem 0 .12rem; min-width: 2.3rem;
|
||||
background: rgba(10, 14, 12, .9); border: 2px solid var(--mint-500); color: var(--text-hi);
|
||||
@@ -264,6 +288,9 @@
|
||||
|
||||
/* ---- effects ---------------------------------------------------------------------------------------------- */
|
||||
.gm__effects { position: absolute; right: .3rem; top: 2.4rem; }
|
||||
/* 准备就绪 refused (the temp row holds pieces): its reason shows under the button and pushes the ready count down —
|
||||
the effects column follows, or the count runs into it on phones */
|
||||
.gm.has-readywhy .gm__effects { top: calc(2.4rem + max(.3rem, 16px)); }
|
||||
.effects { display: flex; flex-direction: column; align-items: flex-end; gap: .08rem; }
|
||||
.effect {
|
||||
position: relative; width: .5rem; height: .5rem; display: grid; place-items: center;
|
||||
@@ -310,7 +337,7 @@
|
||||
transition: background var(--t-fast), border-color var(--t-fast), transform var(--t-fast), color var(--t-fast);
|
||||
}
|
||||
.ewheel__item:hover:not(:disabled) { background: var(--mint-a10); border-color: var(--mint-700); color: var(--mint-400); transform: translateY(-.02rem); }
|
||||
.ewheel__item:disabled { opacity: .45; cursor: wait; }
|
||||
.ewheel__item:disabled { opacity: .45; cursor: default; }
|
||||
.ewheel__art { width: .6rem; height: .6rem; display: grid; place-items: center; }
|
||||
.ewheel__art:empty { display: none; }
|
||||
.ewheel__art .eart { width: 100%; height: 100%; object-fit: contain; filter: drop-shadow(0 0 .06rem rgba(23, 249, 183, .25)); }
|
||||
@@ -383,10 +410,10 @@
|
||||
background: rgba(8, 11, 10, .9); border: 1px solid var(--line-2); border-radius: .3rem; white-space: nowrap;
|
||||
animation: pop-in var(--t-slow) var(--ease-out);
|
||||
}
|
||||
.chud__msg .icon { width: .22rem; height: .22rem; color: var(--gold); animation: hg-flip 2.4s var(--ease-in-out) infinite; }
|
||||
@keyframes hg-flip { 0%, 40% { transform: rotate(0); } 50%, 90% { transform: rotate(180deg); } 100% { transform: rotate(360deg); } }
|
||||
/* a still hourglass: a rotating one next to the text read as a loading spinner (user playtest #3 item 9) */
|
||||
.chud__msg .icon { width: .22rem; height: .22rem; color: var(--gold); }
|
||||
.chud__msg--dead { border-color: rgba(255, 84, 84, .5); color: var(--red-premium); }
|
||||
.chud__msg--dead .icon { color: var(--red-premium); animation: none; }
|
||||
.chud__msg--dead .icon { color: var(--red-premium); }
|
||||
.vswitch { display: flex; align-items: center; gap: .1rem; height: .5rem; padding: 0 .06rem; background: rgba(8, 11, 10, .9); border: 1px solid var(--line-2); }
|
||||
.vswitch__arrow { width: .4rem; height: .4rem; display: grid; place-items: center; background: none; border: 0; color: var(--mint-500); }
|
||||
.vswitch__arrow .icon { width: .3rem; height: .3rem; }
|
||||
|
||||
@@ -257,7 +257,7 @@
|
||||
.dpick__opt .icon { width: .2rem; height: .2rem; color: var(--d-color); opacity: .55; transition: opacity var(--t-fast); }
|
||||
.dpick__opt:hover:not(:disabled) { color: var(--text-hi); background: rgba(255, 255, 255, .03); }
|
||||
.dpick__opt:hover:not(:disabled) .icon { opacity: 1; }
|
||||
.dpick__opt:disabled { cursor: progress; }
|
||||
.dpick__opt:disabled { cursor: default; }
|
||||
.dpick__opt.is-active {
|
||||
color: var(--d-color);
|
||||
background: transparent; background: color-mix(in srgb, var(--d-color) 17%, transparent);
|
||||
|
||||
Reference in new issue
Block a user