DOMless 즉시 생성
가상 DOM 트리 비교나 VNode 할당 없이, Luau 인라인 테이블 평가 시점에 즉시 실제 Roblox Instance를 만들어 돌려줍니다. 변화는 중간 트리를 거치지 않고 개별 프로퍼티 바인드에만 도달합니다.
현재 릴리즈 v4.0.0 — pesdeqwreey/quad_base(백엔드 quad_roblox와 타입 quad_types도 같은 버전으로 함께 게시됩니다) ·변경 이력
이 문서는 개발 중 코드를 기준으로 씁니다 — 게시된 릴리즈에 아직 없는 것은 변경 이력의 Unreleased 절에 있습니다.
DOMless 즉시 생성
가상 DOM 트리 비교나 VNode 할당 없이, Luau 인라인 테이블 평가 시점에 즉시 실제 Roblox Instance를 만들어 돌려줍니다. 변화는 중간 트리를 거치지 않고 개별 프로퍼티 바인드에만 도달합니다.
신호는 push, 계산은 pull
:Set은 “바뀌었다”만 알리고, 계산은 :Get() 시점에 노드 캐시에서 한 번 일어납니다. 신호가 몇 갈래로 도착하든 계산은 한 번이라 다이아몬드 그래프의 중복 재평가가 구조적으로 없고, 아직 살아나지 않은 관측은 보류됐다가 최신값으로 한 번만 재생됩니다.
원소를 재활용하는 키 기반 목록
Slot:List는 키마다 지난번 원소를 ctx.Prev로 돌려주고, 그대로 반환하면 파괴도 재마운트도 없습니다. Roblox에서 형제 순서는 부기값이라 물리 재배치가 없고, LayoutOrder는 넘겨받은 ctx.Index/ctx.Offset으로 직접 바인딩합니다.
규칙 둘뿐인 Modifier
재사용 스타일은 디스패치 전에 정적으로 펼쳐지는 불변 값이라 런타임 캐스케이드 계산이 없습니다. 규칙은 둘 — 인라인 문자 키가 항상 이기고, 숫자 키 자리의 뒤쪽 Modifier가 앞쪽을 이깁니다. 여럿을 하나로 합칠 때는 Overridden(뒤 인자가 이김)으로 합성합니다.
부착식 백엔드, 사용자가 정하는 어휘
코어는 엔진 op를 주입받는 순수 모듈이고 백엔드는 UseProvider 한 줄로 부착됩니다 — Roblox 백엔드와 헤드리스 mock이 같은 문으로 들어옵니다. Frame { … } 안에 올 수 있는 값과 키는 핸들러 레코드 하나를 등록하면 늘어나고, 우선순위 축은 열린 숫자 공간입니다.
Studio 템플릿 Claim
디자이너가 제작한 Studio UI 템플릿을 Clone() 뒤 Claim()으로 넘겨받아, 코드로 만든 트리와 같은 반응성을 붙입니다. 템플릿은 정적 프로퍼티만 심어 D로 만들어도 됩니다 — 원소가 많을 때는 하나하나 짓는 것보다 엔진의 네이티브 Clone()으로 사본을 뜨는 쪽이 싸고, 바뀌는 값만 Claim의 디스크립터에 심습니다.
값은 원천에서 프로퍼티까지 흐르고, 이벤트는 문자 키에 이름으로 놓이고, 자식과 스타일은 숫자 키 자리에 값으로 놓입니다. D.Frame { … }을 부르는 그 순간 실제 Instance가 만들어집니다.
const q = require("@game/ReplicatedStorage/Client/UI/Quad")const D = q.Declaration
const count = q.Source(0) -- ① 값의 원천const countText = count:Compute(function(c) -- ② 파이프: 숫자를 글자로 처리한다 return `카운트: {c:Get()}`end)
const CardStyle = D.Modifier.Frame { -- 스타일은 값 하나로 BackgroundColor3 = Color3.fromRGB(35, 35, 42), BorderSizePixel = 0,}
const card = D.Frame { CardStyle, -- 숫자 키: 스타일을 놓는다 Size = UDim2.fromOffset(220, 120), UICorner = 12, D.TextLabel { BackgroundTransparency = 1, Text = countText }, -- ③ 파이프 끝을 프로퍼티에 꽂는다 D.TextButton { Text = "+ 1", Activated = function() count:Set(count:Get() + 1) end, -- 이벤트도 문자 키에 이름으로 },}이 카드가 어떻게 자라는지는 시작하기가 스물두 편에 걸쳐 따라갑니다 — 목록·컴포넌트·애니메이션·통지 접기까지.
재활용(살아남은 항목은 다시 만들지 않는 것)은 Slot:List가 그대로 해 줍니다. 윈도잉(보이는 구간과 여유분만 만드는 것)은 quad가 자동으로 해 주지 않고, 넘겨받는 ctx.Index/ctx.Offset 위에 직접 구현하는 패턴입니다 — Slot:List로 긴 목록 다루기가 그 구현을 통째로 보여 줍니다.
네. q.Claim이 이미 있는 Instance 트리를 quad 소유로 가져와, 코드로 만든 트리와 똑같이 구동합니다. 어느 자식이 어느 자리인지는 D.Mapper 디스크립터로 지목합니다 — Studio에서 만든 UI에 반응성 붙이기.
네. quad-base는 Instance·game·task 같은 엔진 전역을 참조하지 않아서 Source/State/Slot의 반응형 로직은 평범한 luau CLI에서 그대로 검증됩니다. 실제 프로퍼티·이벤트·Tween까지 보려면 Studio가 필요합니다 — Studio 없이 헤드리스로 테스트하기.
네. CollectionService 태그는 q.Tag("Card"), Attribute는 q.Attr { Kind = "counter" }로 숫자 키 자리에 값으로 놓습니다. 값이 바뀌면 태그·속성도 따라 바뀌고, 붙인 것은 Instance:QueryDescendants 선택자로 화면 밖에서 찾을 수 있습니다 — 이름표와 속성.
값을 q.Tween { … }으로 감싸 프로퍼티에 흘리면 그 목표로 보간됩니다. 자주 쓰는 모양은 :Apply(q.Animate { … }) 슈거로 한 줄이 됩니다 — 움직이게 하기.
q.Fallback(pcall 기반)이나 q.Traceback(xpcall + debug.traceback 기반)으로 감싸면 에러가 호출자까지 번지지 않고 대체 결과를 돌려줍니다. 던지기 전에 이미 만들어진 부분 트리는 이 경계가 정리해 주지 않는다는 알려진 구멍이 있습니다 — Fallback / Traceback.
D.<Class> 별칭은 Frame·TextButton·ScrollingFrame 등 31개입니다(서비스·추상 클래스·Deprecated/NotBrowsable 클래스는 범위 밖). 목록에 없는 클래스는 D.New<<T>>(className)으로 만듭니다 — Declaration — Instance 생성.
됩니다. 문서 예제는 설정 모듈 하나만 --!strict로 두고 화면 코드는 기본 모드를 가정하지만, 화면 코드까지 strict로 올릴 때 파생 노드와 콜백 파라미터에 붙이는 타입 주석 규칙이 따로 정리돼 있습니다 — 설치의 타입 검사 플래그와 컴포넌트 경계 규약.
네. 같은 클라이언트에 v1과 v2를 함께 두는 것은 허용됩니다 — 모듈이 겹치지 않게 두고, 같은 인스턴스를 두 쪽이 함께 만지지 않고, 전역으로 상태를 섞지 않는다는 조건 셋을 지키면 됩니다. 화면 단위로 나눠 옮기는 틀은 quad v1에서 오는 분께에 있습니다.
없습니다. Hook 규칙은 컴포넌트 함수가 몇 번이고 다시 실행된다는 전제에서 나옵니다. quad의 컴포넌트는 한 번만 실행되는 셋업 함수라 “두 번째 실행의 순서”라는 것 자체가 없고, 조건문이나 루프 안에서 상태를 만들어도 문제가 없습니다 — 함수로 묶기.
D.Frame { … }을 부르는 그 순간 진짜 Instance가 만들어집니다 — 나중에 비교할 이전 트리도, diff 단계도 없습니다. 컴포넌트 함수가 반환되는 시점에 이미 실물이 있으므로 그 자리에서 바로 읽거나 붙일 수 있습니다 — 첫 화면.
React 말고 Vue·Solid·Svelte나 Signals 계열에서 오셨다면, 웹 개념 대 quad 대응 전체를 한 표로 정리한 웹에서 오셨다면을 보세요.
답변함: 0 / 0 (0%)