Compare commits
1 Commits
73499f10f1
...
7e8b01369e
Author | SHA1 | Date | |
---|---|---|---|
7e8b01369e |
@ -90,4 +90,3 @@ Special Wins are high-value reward events categorized by payout thresholds:
|
|||||||
**Tip**:
|
**Tip**:
|
||||||
- Move assets to `custom-scale/` to resolve image quality issues.
|
- Move assets to `custom-scale/` to resolve image quality issues.
|
||||||
- Customize font styles based on game design.
|
- Customize font styles based on game design.
|
||||||
- [View Platform Asset Structure](/docs/category/game-asset-structure)
|
|
@ -52,8 +52,9 @@ The **Item Description** system provides detailed information about game items,
|
|||||||
| Step | Action | Image Reference |
|
| Step | Action | Image Reference |
|
||||||
|------|--------|-----------------|
|
|------|--------|-----------------|
|
||||||
| 1 | Set **Sprite Frame** in `background` using prepared assets. |  |
|
| 1 | Set **Sprite Frame** in `background` using prepared assets. |  |
|
||||||
| 2 | Follow **Step 4** of `item-description-small` for payout setup. | [See Small Setup](#prefab-configurations) |
|
| 2 | Follow **Step 4** of `item-description-small` for payout setup. | [See Small Setup](#item-description-small) |
|
||||||
| 3 | Follow **Step 4** of `item-description-no-odds` for description setup. | [See No-Odds Setup](#prefab-configurations) |
|
| 3 | Follow **Step 4** of `item-description-no-odds` for description setup. | [See No-Odds Setup](#item-description-no-odds) |
|
||||||
|
|
||||||
**Tip**:
|
**Tip**:
|
||||||
- Use the helper tool to configure:
|
- Use the helper tool to configure:
|
||||||
1. Set **Content Size** and **Cell Item Size** per game design.
|
1. Set **Content Size** and **Cell Item Size** per game design.
|
||||||
|
@ -63,7 +63,7 @@ The **Free Round** system manages the display and logic for tracking remaining f
|
|||||||
**Tip**:
|
**Tip**:
|
||||||
- Follow game design for position and size.
|
- Follow game design for position and size.
|
||||||
- Use separate textures for Desktop and Mobile.
|
- Use separate textures for Desktop and Mobile.
|
||||||
- Ensure the main scene includes the popup panel ([See Popup Panel Guide](/docs/setup-main-game/main-scene/popup-panel#multiple-popup-panel)).
|
- Ensure the main scene includes the popup panel ([See Popup Panel Guide](http://localhost:3000/docs/setup-main-game/main-scene/popup-panel#multiple-popup-panel)).
|
||||||
|
|
||||||
## Game Result Example
|
## Game Result Example
|
||||||
| Platform | Popup | Action | Result |
|
| Platform | Popup | Action | Result |
|
||||||
|
@ -114,4 +114,3 @@ The **Game Logo** is a key branding element displayed consistently across all pl
|
|||||||
**Tip**:
|
**Tip**:
|
||||||
- Test the static logo display under slow network conditions to ensure fallback works.
|
- Test the static logo display under slow network conditions to ensure fallback works.
|
||||||
- Verify animation states (`play` and `idle`) for smooth transitions.
|
- Verify animation states (`play` and `idle`) for smooth transitions.
|
||||||
- [See More Info](/docs/category/game-asset-structure)
|
|
@ -73,9 +73,9 @@ Place the gamble node in the following scene structure:
|
|||||||

|

|
||||||
|
|
||||||
1. Use background scenes for the gamble feature:
|
1. Use background scenes for the gamble feature:
|
||||||
- `gamble-background-landscape` : [Setup Background Landscape](/docs/setup-main-game/main-scene/background#setup-steps)
|
- `gamble-background-landscape` : [Setup Background Landscape](/docs/setup-main-game/main-scene/background#2-setup-background-landscape)
|
||||||
|
|
||||||
- `gamble-background-portrait` : [Setup Background Portrait](/docs/setup-main-game/main-scene/background#setup-steps)
|
- `gamble-background-portrait` : [Setup Background Portrait](/docs/setup-main-game/main-scene/background#3-setup-background-portrait)
|
||||||
|
|
||||||
2. Attach the `orientation-ui-controller` component to both `gamble-background-landscape` and `gamble-background-portrait` nodes.
|
2. Attach the `orientation-ui-controller` component to both `gamble-background-landscape` and `gamble-background-portrait` nodes.
|
||||||
3. The `gamble-background-portrait` node has a dedicated component for portrait mode:
|
3. The `gamble-background-portrait` node has a dedicated component for portrait mode:
|
||||||
@ -87,4 +87,4 @@ Place the gamble node in the following scene structure:
|
|||||||
## Game Result Example
|
## Game Result Example
|
||||||
|
|
||||||
Make sure the main scene includes the Win Limit Panel.
|
Make sure the main scene includes the Win Limit Panel.
|
||||||
🔗 More Info [Game Result](/docs/setup-main-game/main-scene/win-limit#overview)
|
🔗 More Info [Game Result](/docs/setup-main-game/main-scene/win-limit#gamble-win-limit)
|
@ -7,269 +7,6 @@ sidebar_position: 2
|
|||||||
## Overview
|
## Overview
|
||||||
The **Free Spin (or Free Games) Feature** awards players a set number of spins without requiring additional bets. During these spins, players can still win prizes—often larger than in the base game—without spending any of their own credits.
|
The **Free Spin (or Free Games) Feature** awards players a set number of spins without requiring additional bets. During these spins, players can still win prizes—often larger than in the base game—without spending any of their own credits.
|
||||||

|

|
||||||
|
## Implementation
|
||||||
## Implementation Guide
|
|
||||||
|
|
||||||
### Prepare Assets
|
### Prepare Assets
|
||||||
|
|
||||||
| Component Type | Description | Visual |
|
|
||||||
|------------------------|---------------------------------------------------|--------|
|
|
||||||
| **Core Components** | Locate the prefabs from the core package. |  |
|
|
||||||
| **Game-Specific Components** | Prefabs are already present in the main game scene. |  |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Setup Scene
|
|
||||||
|
|
||||||
#### Structure Free Spins
|
|
||||||
|
|
||||||
Your scene should include the following nodes:
|
|
||||||
|
|
||||||
- **Trigger**
|
|
||||||
- **Retrigger**
|
|
||||||
- **Win**
|
|
||||||
|
|
||||||
***Example Scene Structure:***
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
| Property | Description |
|
|
||||||
|------------------------- |----------------------------------------------------------|
|
|
||||||
| `transitionStart` | Triggers the show animation when Free Spins start.<br/>Default: `null`. |
|
|
||||||
| `transitionStop` | Triggers the return animation to the base game.<br/>Default: `null`. |
|
|
||||||
| `nodeActivate` | Maintains the visual state during Free Spins. |
|
|
||||||
| `freeSideBandContainer` | Activates the Free Spins side band visual. |
|
|
||||||
|
|
||||||
---
|
|
||||||
#### Component Configuration
|
|
||||||
|
|
||||||
##### Trigger & Retrigger
|
|
||||||
|
|
||||||
To configure the Free Spin **trigger** and **retrigger** components, follow these steps:
|
|
||||||
|
|
||||||
1. **Add Animations**
|
|
||||||
|
|
||||||
Include the required animations for both the trigger and retrigger elements.
|
|
||||||
|
|
||||||

|
|
||||||

|
|
||||||
|
|
||||||
| Node Name | Purpose | Location in Core Package |
|
|
||||||
|-----------|-----------------------------------------|------------------------------------------------------------------|
|
|
||||||
| `content` | Handles zoom-in and zoom-out animations | `assets/core-assets/slotty-core/packages/feature-game/animations` |
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
| Property | Description |
|
|
||||||
|------------------------|--------------------------------------------------------------------------|
|
|
||||||
| `durationPresentation` | Duration (in seconds) the trigger animation plays before auto-stopping |
|
|
||||||
|
|
||||||
2. **Add Background Animation Effect**
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
| Prefab Name | Purpose | Location in Core Package |
|
|
||||||
|-------------|-------------------------------------------------|-------------------------------------------------------------|
|
|
||||||
| `explosive` | Background animation effect triggered | `assets/core-assets/hyper-core/packages/explosive/prefabs` |
|
|
||||||
|
|
||||||
3. **Configure Particle Effects**
|
|
||||||
|
|
||||||

|
|
||||||

|
|
||||||
|
|
||||||
| Node Name | Purpose | Location in Core Package |
|
|
||||||
|-------------|-----------------------------------------------------------------------------------------|------------------------------------------------------------|
|
|
||||||
| `particles` | - Particle effects around title and number triggers.<br/>- Set scale to `1` for visibility. | `assets/core-assets/slotty-core/packages/present/particles` |
|
|
||||||
|
|
||||||
:::tip
|
|
||||||
Set up the **present freespin retrigger** in the same way as the **present freespin trigger**.
|
|
||||||
:::
|
|
||||||
|
|
||||||
##### 1. present freespin trigger
|
|
||||||
|
|
||||||
Add fonts and textures for Free Spin trigger.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
##### 2. present freespin retrigger
|
|
||||||
|
|
||||||
Add fonts and textures to show retrigger effect.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
##### Add Font
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
#### 3. Present Free Spin Win
|
|
||||||
|
|
||||||
**Free Spin Win Setup**
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
| Property | Description |
|
|
||||||
|-------------------------|-----------------------------------------------------------------------------------------------|
|
|
||||||
| `content` | Node for displaying the win animation content. |
|
|
||||||
| `durationPresentWin` | Duration (in seconds) that the win presentation is shown. |
|
|
||||||
| `animation` | - Animation controller for the win presentation.<br/>- Located at: `assets/core-assets/slotty-core/packages/feature-game/animations` |
|
|
||||||
| `clipStartPresentation` | Animation clip played when the win presentation starts. |
|
|
||||||
| `clipStopPresentation` | Animation clip played when the win presentation ends. |
|
|
||||||
| `allowPresentWinPoint` | Enables the display of win points during the presentation. |
|
|
||||||
| `durationCountPoint` | Duration (in seconds) for counting up win points. |
|
|
||||||
| `lblTotalWinPoint` | Label node showing the total win points. |
|
|
||||||
| `lblTotalFreeSpinCount` | Label node showing the total number of free spins awarded. |
|
|
||||||
|
|
||||||
- Add congratulatory font and texture for the win display.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
:::tip Best Practice
|
|
||||||
Follow the visual and font flow as defined by your game's design system.
|
|
||||||
:::
|
|
||||||
|
|
||||||
---
|
|
||||||
#### Free Spins Count Box
|
|
||||||
|
|
||||||
The **Free Spins Count Box** displays the remaining number of free spins to the player. Follow these steps to set it up:
|
|
||||||
|
|
||||||
##### Steps to Add the Count Box
|
|
||||||
|
|
||||||
| Step | Description | Image |
|
|
||||||
|------|-----------------------------------------------------------------------------|-----------------------------------------------|
|
|
||||||
| 1 | Locate the `freespins-count-box` prefab in the Core package. |  |
|
|
||||||
| 2 | Add the `freespins-count-box` prefab to your main game scene. |  |
|
|
||||||
| 3 | Verify its appearance in both desktop and mobile modes. |  |
|
|
||||||
|
|
||||||
##### Platform-Specific Setup
|
|
||||||
|
|
||||||
Assign the appropriate node and controller for each platform:
|
|
||||||
|
|
||||||
| Platform | Node Name | Component to Add | Example Image |
|
|
||||||
|----------|--------------------------|-----------------------------|-------------------------------------------------------|
|
|
||||||
| Desktop | `freespins-box-desktop` | `Platform-ui-controller` |  |
|
|
||||||
| Mobile | `freespins-box-mobile` | `Platform-ui-controller` |  |
|
|
||||||
|
|
||||||
##### Asset Configuration
|
|
||||||
|
|
||||||
Ensure the correct assets are used for each platform:
|
|
||||||
|
|
||||||
| Platform | Asset Path | Example Image |
|
|
||||||
|----------|-------------------------------------------------------------------|-------------------------------------------------------------------------------|
|
|
||||||
| Desktop | `assets/game-assets/textures/desktop/preloads/main-game/custom-scale` |  |
|
|
||||||
| Mobile | `assets/game-assets/textures/mobile/preloads/main-game/custom-scale` |  |
|
|
||||||
| Common | Freespins Box Background |  |
|
|
||||||
|
|
||||||
##### Font Setup
|
|
||||||
|
|
||||||
Set the font for the count box display:
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
---
|
|
||||||
#### Free Spin Background Setup
|
|
||||||
|
|
||||||
##### 1. Add Animation to Animation Provider
|
|
||||||
|
|
||||||
Add the Free Spin background animation to your **Animation Provider**.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
##### 2. Configure Background Display
|
|
||||||
|
|
||||||
Set up the background for both landscape and portrait modes:
|
|
||||||
|
|
||||||
- **Landscape Mode**
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
- **Portrait Mode**
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
|
|
||||||
##### 3. Asset Example
|
|
||||||
|
|
||||||
Example background assets for Free Spin:
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
|
|
||||||
#### Sidebands (Optional)
|
|
||||||
|
|
||||||
Sidebands are optional visual elements, often used in classic slot game designs.
|
|
||||||
|
|
||||||
| Preview | Asset Structure |
|
|
||||||
|---------|----------------|
|
|
||||||
|  |  |
|
|
||||||
|
|
||||||
**Setup Steps:**
|
|
||||||
|
|
||||||
1. **Add Preference:**
|
|
||||||
Add the free sideband preference in your configuration.
|
|
||||||

|
|
||||||
|
|
||||||
2. **Assign Texture:**
|
|
||||||
Set the correct texture for the free sideband.
|
|
||||||

|
|
||||||
|
|
||||||
**Asset Mapping:**
|
|
||||||
|
|
||||||
| Asset Name | Node/Preference Name |
|
|
||||||
|---------------------------|------------------------|
|
|
||||||
| `anim-free-sideband-static` | `particle-free-sideband` |
|
|
||||||
| `sideband-back` | `sideband-back` |
|
|
||||||
| `sideband` | `sideband` |
|
|
||||||
| `sideband-shine` | `sideband-shine` |
|
|
||||||
| `sideband-static` | `liquid` |
|
|
||||||
| `indicator-static` | `indicator-static` |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
#### Transition Effects (Optional)
|
|
||||||
|
|
||||||
##### Setup: Create Transition Node
|
|
||||||
|
|
||||||
1. **Create a new node** in your scene for the transition effect.
|
|
||||||
2. **Add the following components** to this node:
|
|
||||||
- `transition`
|
|
||||||
- `transition-scaler`
|
|
||||||
3. Configure the transition properties as required for your effect.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
| Property | Description |
|
|
||||||
|--------------------|--------------------------------------------|
|
|
||||||
| `content` | Target node for transition effects |
|
|
||||||
| `animationName` | Animation identifier/reference |
|
|
||||||
| `sfxName` | Sound effect identifier |
|
|
||||||
| `transitionFrame` | Frame to trigger transition callback |
|
|
||||||
|
|
||||||
|
|
||||||
##### Asset Setup
|
|
||||||
|
|
||||||
1. Add transition animation to the **Animation Provider**.
|
|
||||||
2. Match the animation name with the correct node.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
**add preferrence**
|
|
||||||
|
|
||||||
Configure preferences as needed for your transition.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
**Example Result:**
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Final Result Examples
|
|
||||||
|
|
||||||
| Phase | Image |
|
|
||||||
|-------|-------|
|
|
||||||
| Trigger |  |
|
|
||||||
| Active Scene |  |
|
|
||||||
| Completion |  |
|
|
||||||
|
Before Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 41 KiB |
Before Width: | Height: | Size: 65 KiB |
Before Width: | Height: | Size: 60 KiB |
Before Width: | Height: | Size: 87 KiB |
Before Width: | Height: | Size: 33 KiB |
Before Width: | Height: | Size: 58 KiB |
Before Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 95 KiB |
Before Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 9.0 KiB |
Before Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 79 KiB |
Before Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 64 KiB |
Before Width: | Height: | Size: 67 KiB |
Before Width: | Height: | Size: 6.4 KiB |
Before Width: | Height: | Size: 54 KiB |
Before Width: | Height: | Size: 91 KiB |
Before Width: | Height: | Size: 43 KiB |
Before Width: | Height: | Size: 153 KiB After Width: | Height: | Size: 156 KiB |
Before Width: | Height: | Size: 6.4 KiB |
Before Width: | Height: | Size: 134 KiB |
Before Width: | Height: | Size: 35 KiB |
Before Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 169 KiB |
Before Width: | Height: | Size: 5.5 KiB |
Before Width: | Height: | Size: 60 KiB |
Before Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 129 KiB |
Before Width: | Height: | Size: 157 KiB |
@ -79,289 +79,6 @@ Refers to images, audio, and other data that are specifically designed or adjust
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
#### Custom Scaler
|
### Asset Feature Manager
|
||||||
|
|
||||||
##### Overview
|
|
||||||
|
|
||||||
This script generates custom scaling ratios for assets in a Cocos Creator project, particularly handling different scaling needs for desktop and mobile platforms.
|
|
||||||
|
|
||||||
##### Configuration Steps
|
|
||||||
|
|
||||||
###### Create the Script
|
|
||||||
|
|
||||||
- Name the script: `custom-scale-data`
|
|
||||||
- Location: `assets/game-assets/scripts/custom-scaler/`
|
|
||||||
|
|
||||||
###### Configure the Script
|
|
||||||
|
|
||||||
- Refer to the following image for a general setup example:
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
```js
|
|
||||||
// custom-scale-data.js
|
|
||||||
cc.CustomScaler.CustomScaleRatio["uuid0"] = 0.75;
|
|
||||||
cc.CustomScaler.CustomScaleRatio["uuid1"] = 0.7;
|
|
||||||
cc.CustomScaler.CustomScaleRatio["uuid2"] = 0.58;
|
|
||||||
```
|
|
||||||
|
|
||||||
##### Asset Scaling Rules
|
|
||||||
|
|
||||||
Assets in the project should be scaled according to their type and location:
|
|
||||||
|
|
||||||
| Asset Type | Asset Path Contains | Condition | Scale Ratio |
|
|
||||||
|-----------------|---------------------|-------------------------------------------|-------------|
|
|
||||||
| Font files | `fnt-` | - | 1.0 |
|
|
||||||
| Desktop assets | `desktop` | Inside `custom-scale` folder | 1.0 |
|
|
||||||
| Desktop assets | `desktop` | Outside `custom-scale` folder | 0.75 |
|
|
||||||
| Mobile assets | `mobile` | Inside `custom-scale` folder | 0.7 |
|
|
||||||
| Mobile assets | `mobile` | Outside `custom-scale` folder | 0.58 |
|
|
||||||
|
|
||||||
**Folder structure:**
|
|
||||||
|
|
||||||
```plaintext
|
|
||||||
assets/
|
|
||||||
├── fnt-arial.png (.jpg) # remains at 1.0
|
|
||||||
├── desktop/
|
|
||||||
│ ├── sprite.png (.jpg) # scaled to 0.75
|
|
||||||
│ └── custom-scale/
|
|
||||||
│ └── sprite.png (.jpg) # remains at 1.0
|
|
||||||
└── mobile/
|
|
||||||
├── sprite.png (.jpg) # scaled to 0.58
|
|
||||||
└── custom-scale/
|
|
||||||
└── sprite.png (.jpg) # remains at 0.7
|
|
||||||
```
|
|
||||||
:::tip
|
|
||||||
Assets inside the `custom-scale` folder maintain their original quality, ensuring clear and sharp rendering.
|
|
||||||
:::
|
|
||||||
|
|
||||||
**Example:**
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
#### Prefabs
|
|
||||||
|
|
||||||
| Desktop Prefab | Mobile Prefab |
|
|
||||||
|:--------------:|:-------------:|
|
|
||||||
|  |  |
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Asset Features Manager
|
|
||||||
|
|
||||||
#### Main Game Asset
|
#### Main Game Asset
|
||||||
|
|
||||||
##### Overview
|
|
||||||
|
|
||||||
Main game assets are stored in the `main-game` folder, organized by platform and loading type:
|
|
||||||
|
|
||||||
```plaintext
|
|
||||||
assets/
|
|
||||||
└── game-assets/
|
|
||||||
├── Font/
|
|
||||||
| └──main-game
|
|
||||||
├── Sound/
|
|
||||||
| └──main-game
|
|
||||||
└── textures/
|
|
||||||
├── desktop/
|
|
||||||
│ ├── preload/ # Load at startup
|
|
||||||
| | └──main-game
|
|
||||||
│ └── postload/ # Load later
|
|
||||||
| └──main-game
|
|
||||||
|
|
|
||||||
└── mobile/
|
|
||||||
├── preload/ # Load at startup
|
|
||||||
| └──main-game
|
|
||||||
└── postload/ # Load later
|
|
||||||
└──main-game
|
|
||||||
```
|
|
||||||
|
|
||||||
- `desktop` and `mobile`: Separate folders for each platform.
|
|
||||||
- `preload`: Needed right away.
|
|
||||||
- `postload`: Can load after startup.
|
|
||||||
- Everything is organized under `main-game`.
|
|
||||||
|
|
||||||
|
|
||||||
##### Platform-Specific Structures
|
|
||||||
|
|
||||||
| Sound Example | Font Example |
|
|
||||||
|:-------------:|:-----------:|
|
|
||||||
|  |  |
|
|
||||||
|
|
||||||
| Desktop Structure | Mobile Structure |
|
|
||||||
|:-----------------:|:---------------:|
|
|
||||||
|  |  |
|
|
||||||
|
|
||||||
:::tip
|
|
||||||
When a feature is activated, its assets are loaded directly, bypassing the main game asset folders.
|
|
||||||
:::
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
#### Feature Game Asset
|
#### Feature Game Asset
|
||||||
|
|
||||||
##### Overview
|
|
||||||
|
|
||||||
Feature game assets (e.g., free-game, pickup, bonus, gamble) are stored in a folder named after the feature, and organized by platform (`desktop`, `mobile`) and loading type (`preload`, `postload`).
|
|
||||||
|
|
||||||
**Folder structure:**
|
|
||||||
```plaintext
|
|
||||||
assets/
|
|
||||||
└── game-assets/
|
|
||||||
├── Font/
|
|
||||||
| └──free-game
|
|
||||||
├── Sound/
|
|
||||||
| └──free-game
|
|
||||||
└── textures/
|
|
||||||
├── desktop/
|
|
||||||
│ ├── preload/ # Load at startup
|
|
||||||
| | └──free-game
|
|
||||||
│ └── postload/ # Load later
|
|
||||||
| └──free-game
|
|
||||||
|
|
|
||||||
└── mobile/
|
|
||||||
├── preload/ # Load at startup
|
|
||||||
| └──free-game
|
|
||||||
└── postload/ # Load later
|
|
||||||
└──free-game
|
|
||||||
```
|
|
||||||
##### Platform-Specific Structures
|
|
||||||
|
|
||||||
| Feature Game Example | Desktop Structure | Mobile Structure |
|
|
||||||
|:-----------:|:-----------------:|:---------------:|
|
|
||||||
|  |  |  |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
#### Localized Assets
|
|
||||||
|
|
||||||
The `localizes/` folder stores language-specific assets (e.g., `zh`, `th`, `id`, etc.), allowing the game to display the correct fonts and textures based on the selected language.
|
|
||||||
|
|
||||||
##### Folder structure:
|
|
||||||
|
|
||||||
```plaintext
|
|
||||||
assets/
|
|
||||||
└── game-assets/
|
|
||||||
├── fonts/
|
|
||||||
│ ├── localizes/ # Fonts for each language
|
|
||||||
│ └── preloads/ # Default fonts (usually English) loaded at startup
|
|
||||||
└── textures/
|
|
||||||
├── desktop/
|
|
||||||
│ ├── localizes/ # Desktop textures for each language
|
|
||||||
│ ├── postloads/ # Desktop textures loaded after startup (default: en)
|
|
||||||
│ └── preloads/ # Desktop textures loaded at startup (default: en)
|
|
||||||
└── mobile/
|
|
||||||
├── localizes/ # Mobile textures for each language
|
|
||||||
├── postloads/ # Mobile textures loaded after startup (default: en)
|
|
||||||
└── preloads/ # Mobile textures loaded at startup (default: en)
|
|
||||||
```
|
|
||||||
|
|
||||||
- Assets in `localizes/` are organized by language code (e.g., `zh`, `th`, `id`).
|
|
||||||
- Sprites in `preloads/` and `postloads/` use English (`en`) as the default language.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
#### Meta JSON Merger
|
|
||||||
|
|
||||||
##### Purpose
|
|
||||||
|
|
||||||
Merges JSON metadata files under library/imports/ into one fullMetaData.json.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
###### Excludes:
|
|
||||||
|
|
||||||
- cc.SceneAsset
|
|
||||||
- cc.Prefab
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"asset1.json": { /* metadata */ },
|
|
||||||
"asset2.json": { /* metadata */ }
|
|
||||||
}
|
|
||||||
```
|
|
||||||
---
|
|
||||||
|
|
||||||
#### Texture Compression Tool
|
|
||||||
|
|
||||||
##### Purpose
|
|
||||||
|
|
||||||
Manages and applies compression settings to game textures.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
##### Compression Settings
|
|
||||||
| Description | Action Compress Texture |
|
|
||||||
|:----------- |:----------------------:|
|
|
||||||
| Compresses all textures in:<br/>- `assets/Core`<br/>- `assets/game` |  |
|
|
||||||
| Compresses all textures in:<br/>- `assets/game` only |  |
|
|
||||||
| Removes all compression settings |  |
|
|
||||||
|
|
||||||
**Example:**
|
|
||||||
Compression settings for PNG and JPG formats:
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
##### Workflow
|
|
||||||
|
|
||||||
1. **Query** texture assets by UUID
|
|
||||||
2. **Apply** compression settings to their meta data
|
|
||||||
3. **Save** updated meta files
|
|
||||||
4. **Log** progress and handle errors in console
|
|
||||||
|
|
||||||
##### Benefits
|
|
||||||
|
|
||||||
* Reduces texture file sizes
|
|
||||||
* Speeds up builds and runtime loading
|
|
||||||
* Supports platform-specific formats
|
|
||||||
* Batch processing for efficiency
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
#### Remove Packable Texture Tool
|
|
||||||
|
|
||||||
##### Overview
|
|
||||||
|
|
||||||
Removes the `packable` flag from all texture assets to prevent automatic atlas packing.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
|
|
||||||
##### Why Remove Packable
|
|
||||||
|
|
||||||
Removing the `packable` flag gives you:
|
|
||||||
- **Better memory management** – load/unload textures individually
|
|
||||||
- **Prevents automatic atlas generation** – useful for large or dynamic textures
|
|
||||||
|
|
||||||
###### Use Cases
|
|
||||||
- Large background images
|
|
||||||
- Special effects (particles, dynamic textures)
|
|
||||||
- Render textures
|
|
||||||
- Dynamically loaded assets
|
|
||||||
- High-res UI elements with custom compression needs
|
|
||||||
|
|
||||||
##### Query Texture
|
|
||||||
|
|
||||||
- Scans `db://assets/**/*` for all texture assets.
|
|
||||||
|
|
||||||
**Example:**
|
|
||||||
|
|
||||||
Compression settings for PNG and JPG formats:
|
|
||||||

|
|
||||||
|
|
||||||
---
|
|
||||||
### Result
|
|
||||||
:::tip
|
|
||||||
When running the Extension Tool, you can:
|
|
||||||
- Add or update textures
|
|
||||||
- Add new messages
|
|
||||||
- Update existing messages in the game
|
|
||||||
:::
|
|
||||||
|
|
||||||
After running the Extension Tool, the console will display a summary of the processed textures and any changes made.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
|
|
||||||
|
@ -4,84 +4,4 @@ sidebar_position: 2
|
|||||||
|
|
||||||
# Texture Packer
|
# Texture Packer
|
||||||
|
|
||||||
## Overview
|
> To be added
|
||||||
|
|
||||||
This guide explains how to use a **Texture Packer** workflow to bundle multiple image assets into a single atlas texture file. This enhances performance by reducing draw calls and improving load times.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Configuration
|
|
||||||
|
|
||||||
### Prepare Assets
|
|
||||||
|
|
||||||
Place finalized image assets into the `Raw-Assets` folder. These assets will be included in the texture atlas.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Create a New Sprite Sheet
|
|
||||||
|
|
||||||
1. Launch **TexturePacker**
|
|
||||||
2. Drag and drop your image assets
|
|
||||||
3. Set **Data Format** to:
|
|
||||||
- `Cocos2d-x` or
|
|
||||||
- `Cocos Creator`
|
|
||||||
4. Configure atlas settings such as:
|
|
||||||
- Max size
|
|
||||||
- Padding
|
|
||||||
- Trimming options
|
|
||||||
5. Set output location
|
|
||||||
6. Configure scaling variants (explained below)
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
#### Recommended Settings
|
|
||||||
|
|
||||||
| Option | Value |
|
|
||||||
|---------------------|------------------|
|
|
||||||
| Trim Mode | Trim |
|
|
||||||
| Texture Format | **PNG-32** |
|
|
||||||
| Max Size | **2048x2048** |
|
|
||||||
| Force Squared | Enabled |
|
|
||||||
| Export Multipack | Manual |
|
|
||||||
| Allow Rotation | Enabled |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
#### Scaling Variants Settings
|
|
||||||
|
|
||||||
**Scaling Variants** allow you to export multiple resolution versions of the same atlas (e.g., desktop vs. mobile).
|
|
||||||
|
|
||||||
##### Setup Steps
|
|
||||||
|
|
||||||
1. Open the **Scaling Variants** panel
|
|
||||||
2. Set **Preset** to `Custom`
|
|
||||||
3. Click **Add** to create new variants
|
|
||||||
|
|
||||||
| Variant Name | Scale | Suffix |
|
|
||||||
|--------------|--------|---------|
|
|
||||||
| desktop | 1.0 | *(none)* |
|
|
||||||
| mobile | 0.7 | `@0.7x` |
|
|
||||||
|
|
||||||
##### Example Scaling Variants
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Export Output
|
|
||||||
|
|
||||||
When exporting, TexturePacker generates:
|
|
||||||
|
|
||||||
- `.png` — Sprite atlas image
|
|
||||||
- `.plist` / `.json` — Metadata with frame coordinates and dimensions
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||

|
|
||||||

|
|
||||||
|
|
||||||
---
|
|
Before Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 6.3 KiB |
Before Width: | Height: | Size: 119 KiB |
Before Width: | Height: | Size: 6.2 KiB |
Before Width: | Height: | Size: 6.2 KiB |
Before Width: | Height: | Size: 6.2 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 4.0 KiB |
Before Width: | Height: | Size: 6.2 KiB |
Before Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 6.2 KiB |
Before Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 106 KiB |
@ -62,12 +62,6 @@ const config: Config = {
|
|||||||
sidebarPath: require.resolve('./sidebars.ts'),
|
sidebarPath: require.resolve('./sidebars.ts'),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
[
|
|
||||||
require.resolve('docusaurus-lunr-search'),
|
|
||||||
{
|
|
||||||
languages: ['en'],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
],
|
],
|
||||||
|
|
||||||
themes: [
|
themes: [
|
||||||
@ -96,10 +90,6 @@ const config: Config = {
|
|||||||
position: 'left',
|
position: 'left',
|
||||||
sidebarId: 'apiSidebar',
|
sidebarId: 'apiSidebar',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
type: 'search',
|
|
||||||
position: 'right',
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
href: 'https://gitea.plp19.com/dev-public/doc-slot-core-manual',
|
href: 'https://gitea.plp19.com/dev-public/doc-slot-core-manual',
|
||||||
label: 'Gitea',
|
label: 'Gitea',
|
||||||
@ -112,8 +102,8 @@ const config: Config = {
|
|||||||
copyright: `Copyright © ${new Date().getFullYear()} Mercury Studio, Inc.`,
|
copyright: `Copyright © ${new Date().getFullYear()} Mercury Studio, Inc.`,
|
||||||
},
|
},
|
||||||
prism: {
|
prism: {
|
||||||
theme: prismThemes.vsLight,
|
theme: prismThemes.github,
|
||||||
darkTheme: prismThemes.vsDark,
|
darkTheme: prismThemes.dracula,
|
||||||
},
|
},
|
||||||
} satisfies Preset.ThemeConfig,
|
} satisfies Preset.ThemeConfig,
|
||||||
};
|
};
|
||||||
|
1493
package-lock.json
generated
14
package.json
@ -15,21 +15,19 @@
|
|||||||
"typecheck": "tsc"
|
"typecheck": "tsc"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/core": "^3.8.1",
|
"@docusaurus/core": "^3.8.0",
|
||||||
"@docusaurus/preset-classic": "^3.8.1",
|
"@docusaurus/preset-classic": "^3.8.0",
|
||||||
"@docusaurus/theme-mermaid": "^3.8.1",
|
"@docusaurus/theme-mermaid": "^3.8.0",
|
||||||
"@mdx-js/react": "^3.0.0",
|
"@mdx-js/react": "^3.0.0",
|
||||||
"clsx": "^2.0.0",
|
"clsx": "^2.0.0",
|
||||||
"docusaurus-lunr-search": "^3.6.0",
|
|
||||||
"lunr": "^2.3.9",
|
|
||||||
"prism-react-renderer": "^2.3.0",
|
"prism-react-renderer": "^2.3.0",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"react-dom": "^19.0.0"
|
"react-dom": "^19.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@docusaurus/module-type-aliases": "^3.8.1",
|
"@docusaurus/module-type-aliases": "^3.8.0",
|
||||||
"@docusaurus/tsconfig": "^3.8.1",
|
"@docusaurus/tsconfig": "^3.8.0",
|
||||||
"@docusaurus/types": "^3.8.1",
|
"@docusaurus/types": "^3.8.0",
|
||||||
"typescript": "~5.6.2"
|
"typescript": "~5.6.2"
|
||||||
},
|
},
|
||||||
"browserslist": {
|
"browserslist": {
|
||||||
|
@ -19,13 +19,13 @@
|
|||||||
|
|
||||||
/* For readability concerns, you should choose a lighter palette in dark mode. */
|
/* For readability concerns, you should choose a lighter palette in dark mode. */
|
||||||
[data-theme='dark'] {
|
[data-theme='dark'] {
|
||||||
--ifm-color-primary: #2e8555;
|
--ifm-color-primary: #25c2a0;
|
||||||
--ifm-color-primary-dark: #29784c;
|
--ifm-color-primary-dark: #21af90;
|
||||||
--ifm-color-primary-darker: #277148;
|
--ifm-color-primary-darker: #1fa588;
|
||||||
--ifm-color-primary-darkest: #205d3b;
|
--ifm-color-primary-darkest: #1a8870;
|
||||||
--ifm-color-primary-light: #33925d;
|
--ifm-color-primary-light: #29d5b0;
|
||||||
--ifm-color-primary-lighter: #359962;
|
--ifm-color-primary-lighter: #32d8b4;
|
||||||
--ifm-color-primary-lightest: #3cad6e;
|
--ifm-color-primary-lightest: #4fddbf;
|
||||||
--docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3);
|
--docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3);
|
||||||
}
|
}
|
||||||
.red-star {
|
.red-star {
|
||||||
|
@ -4,32 +4,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
.heroBanner {
|
.heroBanner {
|
||||||
padding: 8rem;
|
padding: 4rem 0;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
background: url('/img/background.jpg');
|
|
||||||
background-size: cover;
|
|
||||||
background-position: center;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-theme='dark'] .heroBanner {
|
|
||||||
background: url('/img/background.jpg');
|
|
||||||
background-size: cover;
|
|
||||||
background-position: center;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
}
|
|
||||||
|
|
||||||
.heroLogo {
|
|
||||||
max-width: 300px;
|
|
||||||
/* margin-bottom: 2rem; */
|
|
||||||
filter: drop-shadow(0 0 8px rgba(255, 255, 255, 0.3));
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-theme='dark'] .heroLogo {
|
|
||||||
filter: drop-shadow(0 0 8px rgba(255, 255, 255, 0.5));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 996px) {
|
@media screen and (max-width: 996px) {
|
||||||
@ -42,184 +20,4 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
gap: 1rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.buttons :global(.button) {
|
|
||||||
background: rgba(255, 255, 255, 0.3);
|
|
||||||
border: 2px solid rgba(255, 255, 255, 0.6);
|
|
||||||
color: white;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
backdrop-filter: blur(5px);
|
|
||||||
font-weight: 500;
|
|
||||||
text-shadow: 0 0 10px rgba(255, 255, 255, 0.3);
|
|
||||||
box-shadow: 0 0 15px rgba(255, 255, 255, 0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.buttons :global(.button:hover) {
|
|
||||||
background: rgba(255, 255, 255, 0.4);
|
|
||||||
border-color: rgba(255, 255, 255, 0.8);
|
|
||||||
transform: translateY(-2px);
|
|
||||||
box-shadow: 0 0 20px rgba(255, 255, 255, 0.3);
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-theme='dark'] .buttons :global(.button) {
|
|
||||||
background: rgba(255, 255, 255, 0.3);
|
|
||||||
border: 2px solid rgba(255, 255, 255, 0.6);
|
|
||||||
color: white;
|
|
||||||
box-shadow: 0 0 15px rgba(255, 255, 255, 0.2);
|
|
||||||
font-weight: 500;
|
|
||||||
text-shadow: 0 0 10px rgba(255, 255, 255, 0.3);
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-theme='dark'] .buttons :global(.button:hover) {
|
|
||||||
background: rgba(255, 255, 255, 0.4);
|
|
||||||
border-color: rgba(255, 255, 255, 0.8);
|
|
||||||
box-shadow: 0 0 20px rgba(255, 255, 255, 0.3);
|
|
||||||
transform: translateY(-2px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.hero__subtitle {
|
|
||||||
color: rgba(255, 255, 255, 0.8);
|
|
||||||
font-size: 1.2rem;
|
|
||||||
margin-bottom: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-theme='dark'] .hero__subtitle {
|
|
||||||
color: rgba(255, 255, 255, 0.7);
|
|
||||||
}
|
|
||||||
|
|
||||||
.features {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
padding: 0rem 0;
|
|
||||||
width: 100%;
|
|
||||||
background: var(--ifm-background-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.featureIcon {
|
|
||||||
display: block;
|
|
||||||
font-size: 3rem;
|
|
||||||
transition: transform 0.2s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.featureIcon:hover {
|
|
||||||
transform: scale(1.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.text--center {
|
|
||||||
color: var(--ifm-color-emphasis-800);
|
|
||||||
}
|
|
||||||
|
|
||||||
.text--center h3 {
|
|
||||||
color: var(--ifm-color-emphasis-900);
|
|
||||||
}
|
|
||||||
|
|
||||||
.text--center p {
|
|
||||||
color: var(--ifm-color-emphasis-700);
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-theme='dark'] .text--center {
|
|
||||||
color: var(--ifm-color-emphasis-200);
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-theme='dark'] .text--center h3 {
|
|
||||||
color: var(--ifm-color-emphasis-100);
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-theme='dark'] .text--center p {
|
|
||||||
color: var(--ifm-color-emphasis-300);
|
|
||||||
}
|
|
||||||
|
|
||||||
.section {
|
|
||||||
padding: 4rem 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sectionTitle {
|
|
||||||
text-align: center;
|
|
||||||
margin-bottom: 3rem;
|
|
||||||
font-size: 2.5rem;
|
|
||||||
color: #2a2a2a;
|
|
||||||
}
|
|
||||||
|
|
||||||
.techStack {
|
|
||||||
background: #f8f9fa;
|
|
||||||
}
|
|
||||||
|
|
||||||
.techGrid {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
|
||||||
gap: 2rem;
|
|
||||||
padding: 0 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.techItem {
|
|
||||||
background: white;
|
|
||||||
padding: 1.5rem;
|
|
||||||
border-radius: 8px;
|
|
||||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
||||||
transition: transform 0.2s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.techItem:hover {
|
|
||||||
transform: translateY(-5px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.techItem h4 {
|
|
||||||
margin-bottom: 0.5rem;
|
|
||||||
color: #2a2a2a;
|
|
||||||
}
|
|
||||||
|
|
||||||
.techItem p {
|
|
||||||
margin: 0;
|
|
||||||
color: #666;
|
|
||||||
}
|
|
||||||
|
|
||||||
.stepsGrid {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
|
||||||
gap: 2rem;
|
|
||||||
padding: 0 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.stepCard {
|
|
||||||
background: white;
|
|
||||||
padding: 2rem;
|
|
||||||
border-radius: 8px;
|
|
||||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
||||||
transition: all 0.2s ease-in-out;
|
|
||||||
text-decoration: none;
|
|
||||||
color: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
.stepCard:hover {
|
|
||||||
transform: translateY(-5px);
|
|
||||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
||||||
}
|
|
||||||
|
|
||||||
.stepCard h3 {
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
color: #2a2a2a;
|
|
||||||
}
|
|
||||||
|
|
||||||
.stepCard p {
|
|
||||||
margin: 0;
|
|
||||||
color: #666;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: 768px) {
|
|
||||||
.techGrid,
|
|
||||||
.stepsGrid {
|
|
||||||
grid-template-columns: 1fr;
|
|
||||||
}
|
|
||||||
|
|
||||||
.section {
|
|
||||||
padding: 2rem 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sectionTitle {
|
|
||||||
font-size: 2rem;
|
|
||||||
margin-bottom: 0.5rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Before Width: | Height: | Size: 322 KiB |