TheOne Studio Cocos Creator Development Standards
⚠️ Cocos Creator 3.x (TypeScript 4.1+): All patterns and examples are compatible with Cocos Creator 3.x playable ads development.
Skill Purpose
This skill enforces TheOne Studio's comprehensive Cocos Creator development standards with CODE QUALITY FIRST:
Priority 1: Code Quality & Hygiene (MOST IMPORTANT)
- TypeScript strict mode, ESLint configuration, access modifiers (public/private/protected)
- Throw exceptions (never silent errors)
- console.log for development, remove in production builds
- readonly for immutable fields, const for constants
- No inline comments (use descriptive names)
- Proper error handling and type safety
Priority 2: Modern TypeScript Patterns
- Array methods (map/filter/reduce) over loops
- Arrow functions, destructuring, spread operators
- Optional chaining, nullish coalescing
- Type guards, utility types (Partial, Required, Readonly)
- Modern TypeScript features
Priority 3: Cocos Creator Architecture
- Component-based Entity-Component (EC) system
- Lifecycle methods: onLoad→start→onEnable→update→onDisable→onDestroy
- EventDispatcher pattern for custom events
- Node event system (EventTouch, keyboard events)
- Resource management and pooling for playables
Priority 4: Playable Ads Performance
- DrawCall batching (<10 DrawCalls target)
- Sprite atlas configuration (auto-atlas enabled)
- GPU skinning for skeletal animations
- Zero allocations in update() loop
- Bundle size <5MB (texture compression, code minification)
When This Skill Triggers
- Writing or refactoring Cocos Creator TypeScript code
- Implementing playable ads features
- Working with component lifecycle and events
- Optimizing performance for playable ads
- Reviewing code changes or pull requests
- Setting up playable project architecture
- Reducing bundle size or DrawCall counts
Quick Reference Guide
What Do You Need Help With?
| Priority |
Task |
Reference |
| 🔴 PRIORITY 1: Code Quality (Check FIRST) |
|
|
| 1 |
TypeScript strict mode, ESLint, access modifiers |
Quality & Hygiene ⭐ |
| 1 |
Throw exceptions, proper error handling |
Quality & Hygiene ⭐ |
| 1 |
console.log (development only), remove in production |
Quality & Hygiene ⭐ |
| 1 |
readonly/const, no inline comments, descriptive names |
Quality & Hygiene ⭐ |
| 🟡 PRIORITY 2: Modern TypeScript Patterns |
|
|
| 2 |
Array methods, arrow functions, destructuring |
Modern TypeScript |
| 2 |
Optional chaining, nullish coalescing |
Modern TypeScript |
| 2 |
Type guards, utility types |
Modern TypeScript |
| 🟢 PRIORITY 3: Cocos Architecture |
|
|
| 3 |
Component system, @property decorator |
Component System |
| 3 |
Lifecycle methods (onLoad→start→update→onDestroy) |
Component System |
| 3 |
EventDispatcher, Node events, cleanup |
Event Patterns |
| 3 |
Resource loading, pooling, memory management |
Playable Optimization |
| 🔵 PRIORITY 4: Performance & Review |
|
|
| 4 |
DrawCall batching, sprite atlas, GPU skinning |
Playable Optimization |
| 4 |
Update loop optimization, zero allocations |
Performance |
| 4 |
Bundle size reduction (<5MB target) |
Size Optimization |
| 4 |
Architecture review (components, lifecycle, events) |
Architecture Review |
| 4 |
TypeScript quality review |
Quality Review |
| 4 |
Performance review (DrawCalls, allocations) |
Performance Review |
🔴 CRITICAL: Code Quality Rules (CHECK FIRST!)
⚠️ MANDATORY QUALITY STANDARDS
ALWAYS enforce these BEFORE writing any code:
- Enable TypeScript strict mode - "strict": true in tsconfig.json
- Use ESLint configuration - @typescript-eslint rules enabled
- Use access modifiers - public/private/protected on all members
- Throw exceptions for errors - NEVER silent failures or undefined returns
- console.log for development only - Remove all console statements in production builds
- Use readonly for immutable fields - Mark fields that aren't reassigned
- Use const for constants - Constants should be const, not let
- No inline comments - Use descriptive names; code should be self-explanatory
- Proper null/undefined handling - Use optional chaining and nullish coalescing
- Type safety - Avoid
any type, use proper types and interfaces
Example: Enforce Quality First
// ✅ EXCELLENT: All quality rules enforced
import { _decorator, Component, Node, EventTouch } from 'cc';
const { ccclass, property } = _decorator;
@ccclass('PlayerController')
export class PlayerController extends Component {
// 3. Access modifier, 6. readonly for immutable
@property(Node)
private readonly targetNode: Node | null = null;
// 7. const for constants
private static readonly MAX_HEALTH: number = 100;
private currentHealth: number = 100;
// Lifecycle: onLoad → start → onEnable
protected onLoad(): void {
// 4. Throw exception for errors
if (!this.targetNode) {
throw new Error('PlayerController: targetNode is not assigned');
}
// 9. Proper event listener setup
this.node.on(Node.EventType.TOUCH_START, this.onTouchStart, this);
}
protected onDestroy(): void {
// 9. Always cleanup event listeners
this.node.off(Node.EventType.TOUCH_START, this.onTouchStart, this);
}
private onTouchStart(event: EventTouch): void {
// 5. console.log only for development (remove in production)
if (CC_DEBUG) {
console.log('Touch detected');
}
this.takeDamage(10);
}
// 8. Descriptive method names (no inline comments needed)
private takeDamage(amount: number): void {
this.currentHealth -= amount;
if (this.currentHealth <= 0) {
this.handlePlayerDeath();
}
}
private handlePlayerDeath(): void {
// Death logic
}
}
⚠️ Cocos Creator Architecture Rules (AFTER Quality)
Component System Fundamentals
Entity-Component (EC) System:
- Components extend
Component class
- Use
@ccclass and @property decorators
- Lifecycle: onLoad → start → onEnable → update → lateUpdate → onDisable → onDestroy
Execution Order:
- onLoad() - Component initialization, one-time setup
- start() - After all components loaded, can reference other components
- onEnable() - When component/node enabled (can be called multiple times)
- update(dt) - Every frame (use sparingly for playables)
- lateUpdate(dt) - After all update() calls
- onDisable() - When component/node disabled
- onDestroy() - Cleanup, remove listeners, release resources
Universal Rules:
- ✅ Initialize in onLoad(), reference other components in start()
- ✅ Register events in onEnable(), unregister in onDisable()
- ✅ Always cleanup listeners in onDestroy()
- ✅ Avoid heavy logic in update() (performance critical for playables)
- ✅ Use readonly for @property fields that shouldn't be reassigned
- ✅ Throw exceptions for missing required references
Brief Examples
🔴 Code Quality First
// ✅ EXCELLENT: Quality rules enforced
import { _decorator, Component, Node } from 'cc';
const { ccclass, property } = _decorator;
@ccclass('GameManager')
export class GameManager extends Component {
@property(Node)
private readonly playerNode: Node | null = null;
private static readonly MAX_SCORE: number = 1000;
private currentScore: number = 0;
protected onLoad(): void {
// Throw exception for missing required references
if (!this.playerNode) {
throw new Error('GameManager: playerNode is required');
}
if (CC_DEBUG) {
console.log('GameManager initialized'); // Development only
}
}
public addScore(points: number): void {
if (points <= 0) {
throw new Error('GameManager.addScore: points must be positive');
}
this.currentScore = Math.min(
this.currentScore + points,
GameManager.MAX_SCORE
);
}
}
🟡 Modern TypeScript Patterns
// ✅ GOOD: Array methods instead of loops
const activeEnemies = allEnemies.filter(e => e.isActive);
const enemyPositions = activeEnemies.map(e => e.node.position);
// ✅ GOOD: Optional chaining and nullish coalescing
const playerName = player?.name ?? 'Unknown';
// ✅ GOOD: Destructuring
const { x, y } = this.node.position;
// ✅ GOOD: Arrow functions
this.enemies.forEach(enemy => enemy.takeDamage(10));
// ✅ GOOD: Type guards
function isPlayer(node: Node): node is PlayerNode {
return node.getComponent(PlayerController) !== null;
}
🟢 Cocos Creator Component Pattern
import { _decorator, Component, Node, EventTouch, Vec3 } from 'cc';
const { ccclass, property } = _decorator;
@ccclass('TouchHandler')
export class TouchHandler extends Component {
@property(Node)
private readonly targetNode: Node | null = null;
private readonly tempVec3: Vec3 = new Vec3(); // Reusable vector
// 1. onLoad: Initialize component
protected onLoad(): void {
if (!this.targetNode) {
throw new Error('TouchHandler: targetNode is required');
}
}
// 2. start: Reference other components (if needed)
protected start(): void {
// Can safely access other components here
}
// 3. onEnable: Register event listeners
protected onEnable(): void {
this.node.on(Node.EventType.TOUCH_START, this.onTouchStart, this);
this.node.on(Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
}
// 4. onDisable: Unregister event listeners
protected onDisable(): void {
this.node.off(Node.EventType.TOUCH_START, this.onTouchStart, this);
this.node.off(Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
}
// 5. onDestroy: Final cleanup
protected onDestroy(): void {
// Release any additional resources
}
private onTouchStart(event: EventTouch): void {
// Handle touch
}
private onTouchMove(event: EventTouch): void {
// Reuse vector to avoid allocations
this.targetNode!.getPosition(this.tempVec3);
this.tempVec3.y += 10;
this.targetNode!.setPosition(this.tempVec3);
}
}
🟢 Event Dispatcher Pattern
import { _decorator, Component, EventTarget } from 'cc';
const { ccclass } = _decorator;
// Custom event types
export enum GameEvent {
SCORE_CHANGED = 'score_changed',
LEVEL_COMPLETE = 'level_complete',
PLAYER_DIED = 'player_died',
}
export interface ScoreChangedEvent {
oldScore: number;
newScore: number;
}
@ccclass('EventManager')
export class EventManager extends Component {
private static instance: EventManager | null = null;
private readonly eventTarget: EventTarget = new EventTarget();
protected onLoad(): void {
if (EventManager.instance) {
throw new Error('EventManager: instance already exists');
}
EventManager.instance = this;
}
public static emit(event: GameEvent, data?: any): void {
if (!EventManager.instance) {
throw new Error('EventManager: instance not initialized');
}
EventManager.instance.eventTarget.emit(event, data);
}
public static on(event: GameEvent, callback: Function, target?: any): void {
if (!EventManager.instance) {
throw new Error('EventManager: instance not initialized');
}
EventManager.instance.eventTarget.on(event, callback, target);
}
public static off(event: GameEvent, callback: Function, target?: any): void {
if (!EventManager.instance) {
throw new Error('EventManager: instance not initialized');
}
EventManager.instance.eventTarget.off(event, callback, target);
}
}
// Usage in component
@ccclass('ScoreDisplay')
export class ScoreDisplay extends Component {
protected onEnable(): void {
EventManager.on(GameEvent.SCORE_CHANGED, this.onScoreChanged, this);
}
protected onDisable(): void {
EventManager.off(GameEvent.SCORE_CHANGED, this.onScoreChanged, this);
}
private onScoreChanged(data: ScoreChangedEvent): void {
console.log(`Score: ${data.oldScore} → ${data.newScore}`);
}
}
🔵 Playable Performance Optimization
import { _decorator, Component, Node, Sprite, SpriteAtlas } from 'cc';
const { ccclass, property } = _decorator;
@ccclass('OptimizedSpriteManager')
export class OptimizedSpriteManager extends Component {
// Use sprite atlas for DrawCall batching
@property(SpriteAtlas)
private readonly characterAtlas: SpriteAtlas | null = null;
// Preallocate arrays to avoid allocations in update()
private readonly tempNodes: Node[] = [];
private frameCount: number = 0;
protected onLoad(): void {
if (!this.characterAtlas) {
throw new Error('OptimizedSpriteManager: characterAtlas is required');
}
// Prewarm sprite frames from atlas
this.prewarmSpriteFrames();
}
private prewarmSpriteFrames(): void {
// Load all sprites from atlas (batched in single DrawCall)
const spriteFrame = this.characterAtlas!.getSpriteFrame('character_idle');
if (!spriteFrame) {
throw new Error('Sprite frame not found in atlas');
}
}
// Optimize update: avoid allocations, use object pooling
protected update(dt: number): void {
// Run expensive operations every N frames instead of every frame
this.frameCount++;
if (this.frameCount % 10 === 0) {
this.updateExpensiveOperation();
}
}
private updateExpensiveOperation(): void {
// Reuse array instead of creating new one
this.tempNodes.length = 0;
// Batch operations to reduce DrawCalls
}
}
Code Review Checklist
Quick Validation (before committing)
🔴 Code Quality (CHECK FIRST):
🟡 Modern TypeScript Patterns:
🟢 Cocos Creator Architecture:
🔵 Playable Performance:
Common Mistakes to Avoid
❌ DON'T:
- Ignore TypeScript strict mode → Enable "strict": true
- Silent error handling → Throw exceptions for errors
- Leave console.log in production → Remove or wrap in CC_DEBUG
- Skip access modifiers → Use public/private/protected
- Use
any type → Define proper types and interfaces
- Add inline comments → Use descriptive names instead
- Skip event cleanup → Always unregister in onDisable/onDestroy
- Allocate in update() → Preallocate and reuse objects
- Forget sprite atlas → Use atlas for DrawCall batching
- Heavy logic in update() → Throttle expensive operations
- Skip null checks → Validate required references in onLoad
- Mutable @property fields → Use readonly when appropriate
- Manual loops over arrays → Use map/filter/reduce
- Ignore bundle size → Monitor and optimize (<5MB target)
✅ DO:
- Enable TypeScript strict mode ("strict": true)
- Throw exceptions for errors (never silent failures)
- Use console.log for development only (remove in production)
- Use access modifiers (public/private/protected)
- Define proper types (avoid
any)
- Use descriptive names (no inline comments)
- Always cleanup events (onDisable/onDestroy)
- Preallocate objects (reuse in update())
- Use sprite atlas (DrawCall batching)
- Throttle expensive operations (not every frame)
- Validate required references (throw in onLoad if null)
- Use readonly for @property (when appropriate)
- Use array methods (map/filter/reduce)
- Monitor bundle size (<5MB target for playables)
Review Severity Levels
🔴 Critical (Must Fix)
- TypeScript strict mode disabled - Must enable "strict": true
- Silent error handling - Must throw exceptions for errors
- console.log in production code - Remove or wrap in CC_DEBUG
- Missing access modifiers - All members must have modifiers
- Using
any type without justification - Define proper types
- Inline comments instead of descriptive names - Rename and remove comments
- Event listeners not cleaned up - Memory leak, must unregister
- Missing required reference validation - Must throw in onLoad if null
- Allocations in update() loop - Performance critical, must preallocate
- No sprite atlas for multiple sprites - DrawCall explosion, must use atlas
- Bundle size >5MB - Exceeds playable limit, must optimize
🟡 Important (Should Fix)
- Missing readonly on @property fields - Should be readonly when not reassigned
- Missing const for constants - Should use const instead of let
- Manual loops instead of array methods - Should use map/filter/reduce
- Missing optional chaining - Should use ?. for safe access
- Missing nullish coalescing - Should use ?? for default values
- Heavy logic in update() - Should throttle expensive operations
- No object pooling for frequent allocations - Should implement pooling
- Texture compression not enabled - Should enable for smaller bundle
- DrawCall count >10 - Should optimize batching
🟢 Nice to Have (Suggestion)
- Could use arrow function for callback
- Could destructure for cleaner code
- Could use type guard for type safety
- Could improve naming for clarity
- Could add interface for better typing
- Could optimize algorithm for better performance
Detailed References
TypeScript Language Standards
- Quality & Hygiene - Strict mode, ESLint, access modifiers, error handling
- Modern TypeScript - Array methods, optional chaining, type guards, utility types
- Performance - Update loop optimization, zero allocations, caching
Cocos Creator Framework
- Component System - EC system, lifecycle methods, @property decorator
- Event Patterns - EventDispatcher, Node events, subscription cleanup
- Playable Optimization - DrawCall batching, sprite atlas, GPU skinning, resource pooling
- Size Optimization - Bundle size reduction, texture compression, build optimization
Code Review
- Architecture Review - Component violations, lifecycle errors, event leaks
- Quality Review - TypeScript quality issues, access modifiers, error handling
- Performance Review - Playable-specific performance problems, DrawCalls, allocations
Summary
This skill provides comprehensive Cocos Creator development standards for TheOne Studio's playable ads team:
- TypeScript Excellence: Strict mode, modern patterns, type safety
- Cocos Architecture: Component lifecycle, event patterns, resource management
- Playable Performance: DrawCall batching, GPU skinning, <5MB bundles
- Code Quality: Enforced quality, hygiene, and performance rules
Use the Quick Reference Guide above to navigate to the specific pattern you need.
1---2name: theone-cocos-standards3description: Enforces TheOne Studio Cocos Creator development standards including TypeScript coding patterns, Cocos Creator 3.x architecture (Component system, EventDispatcher), and playable ads optimization guidelines. Triggers when writing, reviewing, or refactoring Cocos TypeScript code, implementing playable ads features, optimizing performance/bundle size, or reviewing code changes.4---5
6# TheOne Studio Cocos Creator Development Standards
7
8⚠️ **Cocos Creator 3.x (TypeScript 4.1+):** All patterns and examples are compatible with Cocos Creator 3.x playable ads development.
9
10## Skill Purpose
11
12This skill enforces TheOne Studio's comprehensive Cocos Creator development standards with **CODE QUALITY FIRST**:
13
14**Priority 1: Code Quality & Hygiene** (MOST IMPORTANT)
15- TypeScript strict mode, ESLint configuration, access modifiers (public/private/protected)
16- Throw exceptions (never silent errors)
17- console.log for development, remove in production builds
18- readonly for immutable fields, const for constants
19- No inline comments (use descriptive names)
20- Proper error handling and type safety
21
22**Priority 2: Modern TypeScript Patterns**
23- Array methods (map/filter/reduce) over loops
24- Arrow functions, destructuring, spread operators
25- Optional chaining, nullish coalescing
26- Type guards, utility types (Partial, Required, Readonly)
27- Modern TypeScript features
28
29**Priority 3: Cocos Creator Architecture**
30- Component-based Entity-Component (EC) system
31- Lifecycle methods: onLoad→start→onEnable→update→onDisable→onDestroy
32- EventDispatcher pattern for custom events
33- Node event system (EventTouch, keyboard events)
34- Resource management and pooling for playables
35
36**Priority 4: Playable Ads Performance**
37- DrawCall batching (<10 DrawCalls target)
38- Sprite atlas configuration (auto-atlas enabled)
39- GPU skinning for skeletal animations
40- Zero allocations in update() loop
41- Bundle size <5MB (texture compression, code minification)
42
43## When This Skill Triggers
44
45- Writing or refactoring Cocos Creator TypeScript code
46- Implementing playable ads features
47- Working with component lifecycle and events
48- Optimizing performance for playable ads
49- Reviewing code changes or pull requests
50- Setting up playable project architecture
51- Reducing bundle size or DrawCall counts
52
53## Quick Reference Guide
54
55### What Do You Need Help With?
56
57| Priority | Task | Reference |
58|----------|------|-----------|
59| **🔴 PRIORITY 1: Code Quality (Check FIRST)** | | |
60| 1 | TypeScript strict mode, ESLint, access modifiers | [Quality & Hygiene](references/language/quality-hygiene.md) ⭐ |
61| 1 | Throw exceptions, proper error handling | [Quality & Hygiene](references/language/quality-hygiene.md) ⭐ |
62| 1 | console.log (development only), remove in production | [Quality & Hygiene](references/language/quality-hygiene.md) ⭐ |
63| 1 | readonly/const, no inline comments, descriptive names | [Quality & Hygiene](references/language/quality-hygiene.md) ⭐ |
64| **🟡 PRIORITY 2: Modern TypeScript Patterns** | | |
65| 2 | Array methods, arrow functions, destructuring | [Modern TypeScript](references/language/modern-typescript.md) |
66| 2 | Optional chaining, nullish coalescing | [Modern TypeScript](references/language/modern-typescript.md) |
67| 2 | Type guards, utility types | [Modern TypeScript](references/language/modern-typescript.md) |
68| **🟢 PRIORITY 3: Cocos Architecture** | | |
69| 3 | Component system, @property decorator | [Component System](references/framework/component-system.md) |
70| 3 | Lifecycle methods (onLoad→start→update→onDestroy) | [Component System](references/framework/component-system.md) |
71| 3 | EventDispatcher, Node events, cleanup | [Event Patterns](references/framework/event-patterns.md) |
72| 3 | Resource loading, pooling, memory management | [Playable Optimization](references/framework/playable-optimization.md) |
73| **🔵 PRIORITY 4: Performance & Review** | | |
74| 4 | DrawCall batching, sprite atlas, GPU skinning | [Playable Optimization](references/framework/playable-optimization.md) |
75| 4 | Update loop optimization, zero allocations | [Performance](references/language/performance.md) |
76| 4 | Bundle size reduction (<5MB target) | [Size Optimization](references/framework/size-optimization.md) |
77| 4 | Architecture review (components, lifecycle, events) | [Architecture Review](references/review/architecture-review.md) |
78| 4 | TypeScript quality review | [Quality Review](references/review/quality-review.md) |
79| 4 | Performance review (DrawCalls, allocations) | [Performance Review](references/review/performance-review.md) |
80
81## 🔴 CRITICAL: Code Quality Rules (CHECK FIRST!)
82
83### ⚠️ MANDATORY QUALITY STANDARDS
84
85**ALWAYS enforce these BEFORE writing any code:**
86
871. **Enable TypeScript strict mode** - "strict": true in tsconfig.json
882. **Use ESLint configuration** - @typescript-eslint rules enabled
893. **Use access modifiers** - public/private/protected on all members
904. **Throw exceptions for errors** - NEVER silent failures or undefined returns
915. **console.log for development only** - Remove all console statements in production builds
926. **Use readonly for immutable fields** - Mark fields that aren't reassigned
937. **Use const for constants** - Constants should be const, not let
948. **No inline comments** - Use descriptive names; code should be self-explanatory
959. **Proper null/undefined handling** - Use optional chaining and nullish coalescing
9610. **Type safety** - Avoid `any` type, use proper types and interfaces
97
98**Example: Enforce Quality First**
99
100```typescript
101// ✅ EXCELLENT: All quality rules enforced
102import { _decorator, Component, Node, EventTouch } from 'cc';
103const { ccclass, property } = _decorator;
104
105@ccclass('PlayerController')
106export class PlayerController extends Component {
107 // 3. Access modifier, 6. readonly for immutable
108 @property(Node)
109 private readonly targetNode: Node | null = null;
110
111 // 7. const for constants
112 private static readonly MAX_HEALTH: number = 100;
113 private currentHealth: number = 100;
114
115 // Lifecycle: onLoad → start → onEnable
116 protected onLoad(): void {
117 // 4. Throw exception for errors
118 if (!this.targetNode) {
119 throw new Error('PlayerController: targetNode is not assigned');
120 }
121
122 // 9. Proper event listener setup
123 this.node.on(Node.EventType.TOUCH_START, this.onTouchStart, this);
124 }
125
126 protected onDestroy(): void {
127 // 9. Always cleanup event listeners
128 this.node.off(Node.EventType.TOUCH_START, this.onTouchStart, this);
129 }
130
131 private onTouchStart(event: EventTouch): void {
132 // 5. console.log only for development (remove in production)
133 if (CC_DEBUG) {
134 console.log('Touch detected');
135 }
136
137 this.takeDamage(10);
138 }
139
140 // 8. Descriptive method names (no inline comments needed)
141 private takeDamage(amount: number): void {
142 this.currentHealth -= amount;
143
144 if (this.currentHealth <= 0) {
145 this.handlePlayerDeath();
146 }
147 }
148
149 private handlePlayerDeath(): void {
150 // Death logic
151 }
152}
153```
154
155## ⚠️ Cocos Creator Architecture Rules (AFTER Quality)
156
157### Component System Fundamentals
158
159**Entity-Component (EC) System:**
160- Components extend `Component` class
161- Use `@ccclass` and `@property` decorators
162- Lifecycle: onLoad → start → onEnable → update → lateUpdate → onDisable → onDestroy
163
164**Execution Order:**
1651. **onLoad()** - Component initialization, one-time setup
1662. **start()** - After all components loaded, can reference other components
1673. **onEnable()** - When component/node enabled (can be called multiple times)
1684. **update(dt)** - Every frame (use sparingly for playables)
1695. **lateUpdate(dt)** - After all update() calls
1706. **onDisable()** - When component/node disabled
1717. **onDestroy()** - Cleanup, remove listeners, release resources
172
173**Universal Rules:**
174- ✅ Initialize in onLoad(), reference other components in start()
175- ✅ Register events in onEnable(), unregister in onDisable()
176- ✅ Always cleanup listeners in onDestroy()
177- ✅ Avoid heavy logic in update() (performance critical for playables)
178- ✅ Use readonly for @property fields that shouldn't be reassigned
179- ✅ Throw exceptions for missing required references
180
181## Brief Examples
182
183### 🔴 Code Quality First
184
185```typescript
186// ✅ EXCELLENT: Quality rules enforced
187import { _decorator, Component, Node } from 'cc';
188const { ccclass, property } = _decorator;
189
190@ccclass('GameManager')
191export class GameManager extends Component {
192 @property(Node)
193 private readonly playerNode: Node | null = null;
194
195 private static readonly MAX_SCORE: number = 1000;
196 private currentScore: number = 0;
197
198 protected onLoad(): void {
199 // Throw exception for missing required references
200 if (!this.playerNode) {
201 throw new Error('GameManager: playerNode is required');
202 }
203
204 if (CC_DEBUG) {
205 console.log('GameManager initialized'); // Development only
206 }
207 }
208
209 public addScore(points: number): void {
210 if (points <= 0) {
211 throw new Error('GameManager.addScore: points must be positive');
212 }
213
214 this.currentScore = Math.min(
215 this.currentScore + points,
216 GameManager.MAX_SCORE
217 );
218 }
219}
220```
221
222### 🟡 Modern TypeScript Patterns
223
224```typescript
225// ✅ GOOD: Array methods instead of loops
226const activeEnemies = allEnemies.filter(e => e.isActive);
227const enemyPositions = activeEnemies.map(e => e.node.position);
228
229// ✅ GOOD: Optional chaining and nullish coalescing
230const playerName = player?.name ?? 'Unknown';
231
232// ✅ GOOD: Destructuring
233const { x, y } = this.node.position;
234
235// ✅ GOOD: Arrow functions
236this.enemies.forEach(enemy => enemy.takeDamage(10));
237
238// ✅ GOOD: Type guards
239function isPlayer(node: Node): node is PlayerNode {
240 return node.getComponent(PlayerController) !== null;
241}
242```
243
244### 🟢 Cocos Creator Component Pattern
245
246```typescript
247import { _decorator, Component, Node, EventTouch, Vec3 } from 'cc';
248const { ccclass, property } = _decorator;
249
250@ccclass('TouchHandler')
251export class TouchHandler extends Component {
252 @property(Node)
253 private readonly targetNode: Node | null = null;
254
255 private readonly tempVec3: Vec3 = new Vec3(); // Reusable vector
256
257 // 1. onLoad: Initialize component
258 protected onLoad(): void {
259 if (!this.targetNode) {
260 throw new Error('TouchHandler: targetNode is required');
261 }
262 }
263
264 // 2. start: Reference other components (if needed)
265 protected start(): void {
266 // Can safely access other components here
267 }
268
269 // 3. onEnable: Register event listeners
270 protected onEnable(): void {
271 this.node.on(Node.EventType.TOUCH_START, this.onTouchStart, this);
272 this.node.on(Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
273 }
274
275 // 4. onDisable: Unregister event listeners
276 protected onDisable(): void {
277 this.node.off(Node.EventType.TOUCH_START, this.onTouchStart, this);
278 this.node.off(Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
279 }
280
281 // 5. onDestroy: Final cleanup
282 protected onDestroy(): void {
283 // Release any additional resources
284 }
285
286 private onTouchStart(event: EventTouch): void {
287 // Handle touch
288 }
289
290 private onTouchMove(event: EventTouch): void {
291 // Reuse vector to avoid allocations
292 this.targetNode!.getPosition(this.tempVec3);
293 this.tempVec3.y += 10;
294 this.targetNode!.setPosition(this.tempVec3);
295 }
296}
297```
298
299### 🟢 Event Dispatcher Pattern
300
301```typescript
302import { _decorator, Component, EventTarget } from 'cc';
303const { ccclass } = _decorator;
304
305// Custom event types
306export enum GameEvent {
307 SCORE_CHANGED = 'score_changed',
308 LEVEL_COMPLETE = 'level_complete',
309 PLAYER_DIED = 'player_died',
310}
311
312export interface ScoreChangedEvent {
313 oldScore: number;
314 newScore: number;
315}
316
317@ccclass('EventManager')
318export class EventManager extends Component {
319 private static instance: EventManager | null = null;
320 private readonly eventTarget: EventTarget = new EventTarget();
321
322 protected onLoad(): void {
323 if (EventManager.instance) {
324 throw new Error('EventManager: instance already exists');
325 }
326 EventManager.instance = this;
327 }
328
329 public static emit(event: GameEvent, data?: any): void {
330 if (!EventManager.instance) {
331 throw new Error('EventManager: instance not initialized');
332 }
333 EventManager.instance.eventTarget.emit(event, data);
334 }
335
336 public static on(event: GameEvent, callback: Function, target?: any): void {
337 if (!EventManager.instance) {
338 throw new Error('EventManager: instance not initialized');
339 }
340 EventManager.instance.eventTarget.on(event, callback, target);
341 }
342
343 public static off(event: GameEvent, callback: Function, target?: any): void {
344 if (!EventManager.instance) {
345 throw new Error('EventManager: instance not initialized');
346 }
347 EventManager.instance.eventTarget.off(event, callback, target);
348 }
349}
350
351// Usage in component
352@ccclass('ScoreDisplay')
353export class ScoreDisplay extends Component {
354 protected onEnable(): void {
355 EventManager.on(GameEvent.SCORE_CHANGED, this.onScoreChanged, this);
356 }
357
358 protected onDisable(): void {
359 EventManager.off(GameEvent.SCORE_CHANGED, this.onScoreChanged, this);
360 }
361
362 private onScoreChanged(data: ScoreChangedEvent): void {
363 console.log(`Score: ${data.oldScore} → ${data.newScore}`);
364 }
365}
366```
367
368### 🔵 Playable Performance Optimization
369
370```typescript
371import { _decorator, Component, Node, Sprite, SpriteAtlas } from 'cc';
372const { ccclass, property } = _decorator;
373
374@ccclass('OptimizedSpriteManager')
375export class OptimizedSpriteManager extends Component {
376 // Use sprite atlas for DrawCall batching
377 @property(SpriteAtlas)
378 private readonly characterAtlas: SpriteAtlas | null = null;
379
380 // Preallocate arrays to avoid allocations in update()
381 private readonly tempNodes: Node[] = [];
382 private frameCount: number = 0;
383
384 protected onLoad(): void {
385 if (!this.characterAtlas) {
386 throw new Error('OptimizedSpriteManager: characterAtlas is required');
387 }
388
389 // Prewarm sprite frames from atlas
390 this.prewarmSpriteFrames();
391 }
392
393 private prewarmSpriteFrames(): void {
394 // Load all sprites from atlas (batched in single DrawCall)
395 const spriteFrame = this.characterAtlas!.getSpriteFrame('character_idle');
396 if (!spriteFrame) {
397 throw new Error('Sprite frame not found in atlas');
398 }
399 }
400
401 // Optimize update: avoid allocations, use object pooling
402 protected update(dt: number): void {
403 // Run expensive operations every N frames instead of every frame
404 this.frameCount++;
405 if (this.frameCount % 10 === 0) {
406 this.updateExpensiveOperation();
407 }
408 }
409
410 private updateExpensiveOperation(): void {
411 // Reuse array instead of creating new one
412 this.tempNodes.length = 0;
413
414 // Batch operations to reduce DrawCalls
415 }
416}
417```
418
419## Code Review Checklist
420
421### Quick Validation (before committing)
422
423**🔴 Code Quality (CHECK FIRST):**
424- [ ] TypeScript strict mode enabled in tsconfig.json
425- [ ] ESLint rules passing (no errors)
426- [ ] All access modifiers correct (public/private/protected)
427- [ ] Exceptions thrown for errors (no silent failures)
428- [ ] console.log removed or wrapped in CC_DEBUG
429- [ ] readonly used for non-reassigned fields
430- [ ] const used for constants
431- [ ] No inline comments (self-explanatory code)
432- [ ] Proper null/undefined handling
433- [ ] No `any` types (use proper types)
434
435**🟡 Modern TypeScript Patterns:**
436- [ ] Array methods used instead of manual loops
437- [ ] Arrow functions for callbacks
438- [ ] Optional chaining (?.) for safe property access
439- [ ] Nullish coalescing (??) for default values
440- [ ] Destructuring for cleaner code
441- [ ] Type guards for type narrowing
442
443**🟢 Cocos Creator Architecture:**
444- [ ] Component lifecycle methods in correct order
445- [ ] onLoad() for initialization, start() for references
446- [ ] Event listeners registered in onEnable()
447- [ ] Event listeners unregistered in onDisable()
448- [ ] Resources released in onDestroy()
449- [ ] @property decorator used correctly
450- [ ] Required references validated (throw if null)
451
452**🔵 Playable Performance:**
453- [ ] No allocations in update() loop
454- [ ] Sprite atlas used for DrawCall batching
455- [ ] GPU skinning enabled for skeletal animations
456- [ ] Expensive operations throttled (not every frame)
457- [ ] Object pooling for frequently created objects
458- [ ] Texture compression enabled
459- [ ] Bundle size <5MB target
460- [ ] DrawCall count <10 target
461
462## Common Mistakes to Avoid
463
464### ❌ DON'T:
4651. **Ignore TypeScript strict mode** → Enable "strict": true
4662. **Silent error handling** → Throw exceptions for errors
4673. **Leave console.log in production** → Remove or wrap in CC_DEBUG
4684. **Skip access modifiers** → Use public/private/protected
4695. **Use `any` type** → Define proper types and interfaces
4706. **Add inline comments** → Use descriptive names instead
4717. **Skip event cleanup** → Always unregister in onDisable/onDestroy
4728. **Allocate in update()** → Preallocate and reuse objects
4739. **Forget sprite atlas** → Use atlas for DrawCall batching
47410. **Heavy logic in update()** → Throttle expensive operations
47511. **Skip null checks** → Validate required references in onLoad
47612. **Mutable @property fields** → Use readonly when appropriate
47713. **Manual loops over arrays** → Use map/filter/reduce
47814. **Ignore bundle size** → Monitor and optimize (<5MB target)
479
480### ✅ DO:
4811. **Enable TypeScript strict mode** ("strict": true)
4822. **Throw exceptions for errors** (never silent failures)
4833. **Use console.log for development only** (remove in production)
4844. **Use access modifiers** (public/private/protected)
4855. **Define proper types** (avoid `any`)
4866. **Use descriptive names** (no inline comments)
4877. **Always cleanup events** (onDisable/onDestroy)
4888. **Preallocate objects** (reuse in update())
4899. **Use sprite atlas** (DrawCall batching)
49010. **Throttle expensive operations** (not every frame)
49111. **Validate required references** (throw in onLoad if null)
49212. **Use readonly for @property** (when appropriate)
49313. **Use array methods** (map/filter/reduce)
49414. **Monitor bundle size** (<5MB target for playables)
495
496## Review Severity Levels
497
498### 🔴 Critical (Must Fix)
499- **TypeScript strict mode disabled** - Must enable "strict": true
500- **Silent error handling** - Must throw exceptions for errors
501- **console.log in production code** - Remove or wrap in CC_DEBUG
502- **Missing access modifiers** - All members must have modifiers
503- **Using `any` type without justification** - Define proper types
504- **Inline comments instead of descriptive names** - Rename and remove comments
505- **Event listeners not cleaned up** - Memory leak, must unregister
506- **Missing required reference validation** - Must throw in onLoad if null
507- **Allocations in update() loop** - Performance critical, must preallocate
508- **No sprite atlas for multiple sprites** - DrawCall explosion, must use atlas
509- **Bundle size >5MB** - Exceeds playable limit, must optimize
510
511### 🟡 Important (Should Fix)
512- **Missing readonly on @property fields** - Should be readonly when not reassigned
513- **Missing const for constants** - Should use const instead of let
514- **Manual loops instead of array methods** - Should use map/filter/reduce
515- **Missing optional chaining** - Should use ?. for safe access
516- **Missing nullish coalescing** - Should use ?? for default values
517- **Heavy logic in update()** - Should throttle expensive operations
518- **No object pooling for frequent allocations** - Should implement pooling
519- **Texture compression not enabled** - Should enable for smaller bundle
520- **DrawCall count >10** - Should optimize batching
521
522### 🟢 Nice to Have (Suggestion)
523- Could use arrow function for callback
524- Could destructure for cleaner code
525- Could use type guard for type safety
526- Could improve naming for clarity
527- Could add interface for better typing
528- Could optimize algorithm for better performance
529
530## Detailed References
531
532### TypeScript Language Standards
533- [Quality & Hygiene](references/language/quality-hygiene.md) - Strict mode, ESLint, access modifiers, error handling
534- [Modern TypeScript](references/language/modern-typescript.md) - Array methods, optional chaining, type guards, utility types
535- [Performance](references/language/performance.md) - Update loop optimization, zero allocations, caching
536
537### Cocos Creator Framework
538- [Component System](references/framework/component-system.md) - EC system, lifecycle methods, @property decorator
539- [Event Patterns](references/framework/event-patterns.md) - EventDispatcher, Node events, subscription cleanup
540- [Playable Optimization](references/framework/playable-optimization.md) - DrawCall batching, sprite atlas, GPU skinning, resource pooling
541- [Size Optimization](references/framework/size-optimization.md) - Bundle size reduction, texture compression, build optimization
542
543### Code Review
544- [Architecture Review](references/review/architecture-review.md) - Component violations, lifecycle errors, event leaks
545- [Quality Review](references/review/quality-review.md) - TypeScript quality issues, access modifiers, error handling
546- [Performance Review](references/review/performance-review.md) - Playable-specific performance problems, DrawCalls, allocations
547
548## Summary
549
550This skill provides comprehensive Cocos Creator development standards for TheOne Studio's playable ads team:
551- **TypeScript Excellence**: Strict mode, modern patterns, type safety
552- **Cocos Architecture**: Component lifecycle, event patterns, resource management
553- **Playable Performance**: DrawCall batching, GPU skinning, <5MB bundles
554- **Code Quality**: Enforced quality, hygiene, and performance rules
555
556Use the Quick Reference Guide above to navigate to the specific pattern you need.