feat: 튜토리얼 6·9 스크린 디스코드 명령 시퀀스 CSS 애니메이션 (실데이터 픽스처 데모 PNG) - #60
Conversation
site/scripts/fixtures/demo/*.json 11런을 복원(__type dataclass 마커·__bytes_b64 아이콘·ISO 날짜)해 site/public/shots/demo-<run>.png 로 생성. 기존 7종 무변경. scheduler 는 캡처 3장 중 첫 캐릭터 카드 1장만 사용.
/ 타이핑→명령 팝업→파라미터 칩→값 선택(choice/멤버 팝업)→전송 게이트(클릭 대기, 10s 자동)→봇 타이핑→결과 임베드+데모 PNG 상태머신. S6 7런(느림3+빠름4)·S9 4런 (느림2+빠름2), 임베드 카피는 픽스처 messages[] 정본. reduced-motion 정적 표시. DiscordDemo·hero.css 무변경, 스타일은 .mm-tut-seq-* 로 tutorial.css 에만 추가.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughWalkthroughAdds a new interactive ChangesCommand Sequence Animation Feature
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant User
participant CommandSequenceDemo
participant InputBar
participant CommandPopup
participant ValuePicker
User->>CommandSequenceDemo: view tutorial step
CommandSequenceDemo->>CommandPopup: show popup (typing phase)
CommandSequenceDemo->>ValuePicker: render member/choice picker
User->>InputBar: click send (or wait 10s auto-send)
InputBar->>CommandSequenceDemo: advance gate phase
CommandSequenceDemo->>CommandSequenceDemo: bot typing phase
CommandSequenceDemo-->>User: render result (shot PNG) then loop
sequenceDiagram
participant Main as render_demo_shots.main
participant Fixture as build_from_fixture
participant Revive as _revive
participant Render as render_* function
Main->>Fixture: for each run in _FIXTURE_RUNS
Fixture->>Revive: parse fixture JSON args/kwargs
Revive-->>Fixture: reconstructed dataclasses/bytes
Fixture->>Render: invoke matched renderer
Render-->>Fixture: PNG bytes
Fixture-->>Main: write site/public/shots/demo-<run>.png
Estimated code review effortEstimated code review effort: 4 (Complex) | ~60 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (3)
site/data/tutorial-steps.tsx (1)
38-47: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win
animmedia type lacks an accessible/no-JS fallback contract.The
videovariant requires an explicitfallback: React.ReactNode(used whensrcis null), but the newanimvariant only carriesnode: React.ReactNodewith no equivalent fallback field. SinceCommandSequenceDemorenders its whole output asaria-hidden(seeCommandSequenceDemo.tsxLines 387, 424), screen-reader users get no accessible description of this tutorial media at all. Confirm the surrounding step copy (title/sub/commands) fully conveys the same information for steps 5-2 and 6-3, otherwise consider adding a visually-hidden text summary oraria-labelfor the animation.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@site/data/tutorial-steps.tsx` around lines 38 - 47, The new TutorialMedia anim variant currently has no accessibility or no-JS fallback contract, unlike the video variant with its explicit fallback. Update the TutorialMedia type and the related rendering path that uses anim node so steps 5-2 and 6-3 still expose a usable text alternative, either by confirming the surrounding step copy in title/sub/commands fully covers the content or by adding an accessible summary via visually-hidden text or an aria-label in the anim/CommandSequenceDemo flow.site/components/CommandSequenceDemo.tsx (1)
54-60: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winReduced-motion detection is static and can flash before applying.
usePrefersReducedMotionreadsmatchMedia(...).matchesonce in auseEffectwith initial statefalse, so: (1) it never reacts to the user toggling the OS/browser reduced-motion setting while the page is open, and (2) on first paint for a reduced-motion user, the animated variant briefly renders before the effect flipsreducetotrue.♻️ Proposed fix — lazy init + live listener
function usePrefersReducedMotion(): boolean { - const [reduce, setReduce] = React.useState(false) - React.useEffect(() => { - setReduce(window.matchMedia('(prefers-reduced-motion: reduce)').matches) - }, []) + const [reduce, setReduce] = React.useState( + () => + typeof window !== 'undefined' && + window.matchMedia('(prefers-reduced-motion: reduce)').matches, + ) + React.useEffect(() => { + const mq = window.matchMedia('(prefers-reduced-motion: reduce)') + const onChange = () => setReduce(mq.matches) + mq.addEventListener('change', onChange) + return () => mq.removeEventListener('change', onChange) + }, []) return reduce }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@site/components/CommandSequenceDemo.tsx` around lines 54 - 60, The reduced-motion hook is only sampling the media query once after mount, so it can flash the animated state and never update when the setting changes. Update usePrefersReducedMotion to initialize from window.matchMedia('(prefers-reduced-motion: reduce)').matches during state setup, and add a live change listener in the effect so the reduce state stays in sync with OS/browser toggles. Keep the fix localized to usePrefersReducedMotion in CommandSequenceDemo.site/scripts/render_demo_shots.py (1)
444-457: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winIsolate per-run failures in the generation loop.
If
build_from_fixture(run)raises for any single run (e.g. unmapped renderer, missing fixture file), the wholemain()invocation aborts and no furtherdemo-*.pngfiles are written. Wrapping each iteration to log-and-continue would make partial regeneration failures easier to diagnose without blocking the rest of the batch.♻️ Proposed fix
print("데모 애니 픽스처 복원 →") for run in _FIXTURE_RUNS: - _write(f"demo-{run}.png", build_from_fixture(run)) + try: + _write(f"demo-{run}.png", build_from_fixture(run)) + except Exception as exc: # noqa: BLE001 - keep batch going, report clearly + print(f" ✗ demo-{run}.png 생성 실패: {exc}")🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@site/scripts/render_demo_shots.py` around lines 444 - 457, The per-run generation loop in main is not isolated, so a failure in build_from_fixture(run) stops all remaining demo-*.png outputs. Update the loop over _FIXTURE_RUNS to catch exceptions around each _write(f"demo-{run}.png", build_from_fixture(run)) call, log the failing run with enough context, and continue to the next run. Keep the existing main and build_from_fixture symbols as the entry points for locating the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@site/components/CommandSequenceDemo.tsx`:
- Around line 239-256: The send control in CommandSequenceDemo is still tabbable
inside an aria-hidden demo, which can leave keyboard focus on an element hidden
from assistive tech. Update the InputBar/send button behavior so it stays
tabIndex={-1} while the surrounding demo remains aria-hidden, or remove
aria-hidden from the wrapper if this section is intended to be interactive; use
the CommandSequenceDemo and InputBar send button logic to locate the change.
---
Nitpick comments:
In `@site/components/CommandSequenceDemo.tsx`:
- Around line 54-60: The reduced-motion hook is only sampling the media query
once after mount, so it can flash the animated state and never update when the
setting changes. Update usePrefersReducedMotion to initialize from
window.matchMedia('(prefers-reduced-motion: reduce)').matches during state
setup, and add a live change listener in the effect so the reduce state stays in
sync with OS/browser toggles. Keep the fix localized to usePrefersReducedMotion
in CommandSequenceDemo.
In `@site/data/tutorial-steps.tsx`:
- Around line 38-47: The new TutorialMedia anim variant currently has no
accessibility or no-JS fallback contract, unlike the video variant with its
explicit fallback. Update the TutorialMedia type and the related rendering path
that uses anim node so steps 5-2 and 6-3 still expose a usable text alternative,
either by confirming the surrounding step copy in title/sub/commands fully
covers the content or by adding an accessible summary via visually-hidden text
or an aria-label in the anim/CommandSequenceDemo flow.
In `@site/scripts/render_demo_shots.py`:
- Around line 444-457: The per-run generation loop in main is not isolated, so a
failure in build_from_fixture(run) stops all remaining demo-*.png outputs.
Update the loop over _FIXTURE_RUNS to catch exceptions around each
_write(f"demo-{run}.png", build_from_fixture(run)) call, log the failing run
with enough context, and continue to the next run. Keep the existing main and
build_from_fixture symbols as the entry points for locating the change.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: b485acd9-b8ec-47a3-8972-bc596615479a
⛔ Files ignored due to path filters (11)
site/public/shots/demo-exp_challengers.pngis excluded by!**/*.pngsite/public/shots/demo-exp_main.pngis excluded by!**/*.pngsite/public/shots/demo-exp_target.pngis excluded by!**/*.pngsite/public/shots/demo-item_weapon.pngis excluded by!**/*.pngsite/public/shots/demo-mychar_spec.pngis excluded by!**/*.pngsite/public/shots/demo-potential_30d.pngis excluded by!**/*.pngsite/public/shots/demo-scheduler.pngis excluded by!**/*.pngsite/public/shots/demo-spec_three.pngis excluded by!**/*.pngsite/public/shots/demo-starforce_rand.pngis excluded by!**/*.pngsite/public/shots/demo-starforce_target.pngis excluded by!**/*.pngsite/public/shots/demo-union_all.pngis excluded by!**/*.png
📒 Files selected for processing (17)
docs/tutorial-anim-work-order.mdsite/app/tutorial.csssite/components/CommandSequenceDemo.tsxsite/components/commandSequenceScripts.tsxsite/data/tutorial-steps.tsxsite/scripts/fixtures/demo/exp_challengers.jsonsite/scripts/fixtures/demo/exp_main.jsonsite/scripts/fixtures/demo/exp_target.jsonsite/scripts/fixtures/demo/item_weapon.jsonsite/scripts/fixtures/demo/mychar_spec.jsonsite/scripts/fixtures/demo/potential_30d.jsonsite/scripts/fixtures/demo/scheduler.jsonsite/scripts/fixtures/demo/spec_three.jsonsite/scripts/fixtures/demo/starforce_rand.jsonsite/scripts/fixtures/demo/starforce_target.jsonsite/scripts/fixtures/demo/union_all.jsonsite/scripts/render_demo_shots.py
| <button | ||
| type="button" | ||
| className={`mm-tut-seq-send${gate ? ' is-armed' : ''}`} | ||
| onClick={gate ? onSend : undefined} | ||
| tabIndex={gate ? 0 : -1} | ||
| aria-label="전송" | ||
| > | ||
| <SendHorizontal size={16} strokeWidth={2.4} aria-hidden /> | ||
| </button> | ||
| {gate ? ( | ||
| <span className="mm-tut-seq-hint" aria-hidden> | ||
| 눌러서 전송해 보세요 | ||
| </span> | ||
| ) : null} | ||
| </div> | ||
| ) | ||
| } | ||
|
|
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Map the component structure first
ast-grep outline site/components/CommandSequenceDemo.tsx --view expanded
# Find aria-hidden, tabIndex, and send button usage in the file
rg -n 'aria-hidden|tabIndex|mm-tut-seq-send|InputBar|SendHorizontal|fallback|video' site/components/CommandSequenceDemo.tsx
# Read the relevant sections around the reported lines
sed -n '220,270p' site/components/CommandSequenceDemo.tsx
sed -n '360,470p' site/components/CommandSequenceDemo.tsxRepository: mindongdong/maple-mate
Length of output: 6160
Keep the send button out of the aria-hidden demo.
CommandSequenceDemo hides the whole chat subtree from assistive tech, but InputBar still makes the send button tabbable when gate is true (tabIndex={0}). That leaves keyboard focus on a control that AT treats as hidden; keep it tabIndex={-1} (or remove aria-hidden from the wrapper if this demo is meant to be interactive).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@site/components/CommandSequenceDemo.tsx` around lines 239 - 256, The send
control in CommandSequenceDemo is still tabbable inside an aria-hidden demo,
which can leave keyboard focus on an element hidden from assistive tech. Update
the InputBar/send button behavior so it stays tabIndex={-1} while the
surrounding demo remains aria-hidden, or remove aria-hidden from the wrapper if
this section is intended to be interactive; use the CommandSequenceDemo and
InputBar send button logic to locate the change.
요약
/tutorial6번째(캐릭터 등록으로 열리는 명령들)·9번째(API 키로 열리는 명령들) 스크린의src:null+ShotCollage 폴백을 디스코드 메시지 스타일 CSS 애니메이션으로 교체 — 작업지시서(grill 확정 결정 10건) 그대로 구현.CommandSequenceDemo:/타이핑 → 명령 팝업 → 파라미터 칩(전체 목록) → 값 선택(choice/멤버 팝업) → 전송 버튼 게이트(방문자 클릭, 미클릭 10초 후 자동 전송) → 봇 타이핑 도트 → 결과 임베드+PNG 상태머신. S6 7런(느림 3+빠름 4, 루프≈45s)·S9 4런(느림 2+빠름 2, 루프≈30s).render_demo_shots.py확장으로 복원해 봇 실제 렌더러로 생성(demo-<run>.png11종). 임베드 카피도 픽스처messages[]정본 그대로.DiscordDemo/hero.css 랜딩 공용 무변경 ·tutorial-steps.tsx는 6·9 media 만 교체(명령 리터럴·드리프트 가드 형식 불변).검증 (작업지시서 §6 전 항목)
npm run build+check-command-drift.mjs그린, 루트 pytest 824 passed--virtual-time-budget국면별 캡처: 팝업/칩/게이트/결과/값선택 팝업 (S6·S9)Summary by CodeRabbit
New Features
Documentation
Bug Fixes