Enforce Genarrative play-type SOP and update docs
Rewrite Genarrative play-type integration guidance across .codex and .hermes to define a platform-level SOP: default to form/image workbench, unify single-image asset slots (CreativeImageInputPanel), standardize series-material sheet->cut->transparent->OSS pipeline, and forbid copying legacy chat/agent workflows as the default. Add decision-log entry freezing the SOP and a pitfalls note warning against direct reuse of old play tools. Update CONTEXT.md and docs/README.md, add a new PRD file, and apply related small server-side changes (module-auth, spacetime-client mappers and runtime) to align back-end code with the new contracts and flows.
This commit is contained in:
401
server-rs/crates/shared-contracts/src/jump_hop.rs
Normal file
401
server-rs/crates/shared-contracts/src/jump_hop.rs
Normal file
@@ -0,0 +1,401 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub enum JumpHopDifficulty {
|
||||
Easy,
|
||||
Standard,
|
||||
Advanced,
|
||||
Challenge,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub enum JumpHopStylePreset {
|
||||
MinimalBlocks,
|
||||
PaperToy,
|
||||
NeonGlass,
|
||||
ForestStone,
|
||||
FutureMetal,
|
||||
Custom,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub enum JumpHopGenerationStatus {
|
||||
Draft,
|
||||
Generating,
|
||||
Ready,
|
||||
Failed,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub enum JumpHopTileType {
|
||||
Start,
|
||||
Normal,
|
||||
Target,
|
||||
Finish,
|
||||
Bonus,
|
||||
Accent,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub enum JumpHopActionType {
|
||||
CompileDraft,
|
||||
RegenerateCharacter,
|
||||
RegenerateTiles,
|
||||
UpdateWorkMeta,
|
||||
UpdateDifficulty,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub enum JumpHopRunStatus {
|
||||
Playing,
|
||||
Failed,
|
||||
Cleared,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub enum JumpHopJumpResult {
|
||||
Miss,
|
||||
Hit,
|
||||
Perfect,
|
||||
Finish,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct JumpHopWorkspaceCreateRequest {
|
||||
pub template_id: String,
|
||||
pub work_title: String,
|
||||
pub work_description: String,
|
||||
pub theme_tags: Vec<String>,
|
||||
pub difficulty: JumpHopDifficulty,
|
||||
pub style_preset: JumpHopStylePreset,
|
||||
pub character_prompt: String,
|
||||
pub tile_prompt: String,
|
||||
#[serde(default)]
|
||||
pub end_mood_prompt: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct JumpHopActionRequest {
|
||||
pub action_type: JumpHopActionType,
|
||||
#[serde(default)]
|
||||
pub work_title: Option<String>,
|
||||
#[serde(default)]
|
||||
pub work_description: Option<String>,
|
||||
#[serde(default)]
|
||||
pub theme_tags: Option<Vec<String>>,
|
||||
#[serde(default)]
|
||||
pub difficulty: Option<JumpHopDifficulty>,
|
||||
#[serde(default)]
|
||||
pub style_preset: Option<JumpHopStylePreset>,
|
||||
#[serde(default)]
|
||||
pub character_prompt: Option<String>,
|
||||
#[serde(default)]
|
||||
pub tile_prompt: Option<String>,
|
||||
#[serde(default)]
|
||||
pub end_mood_prompt: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct JumpHopCharacterAsset {
|
||||
pub asset_id: String,
|
||||
pub image_src: String,
|
||||
pub image_object_key: String,
|
||||
pub asset_object_id: String,
|
||||
pub generation_provider: String,
|
||||
pub prompt: String,
|
||||
pub width: u32,
|
||||
pub height: u32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct JumpHopTileAsset {
|
||||
pub tile_type: JumpHopTileType,
|
||||
pub image_src: String,
|
||||
pub image_object_key: String,
|
||||
pub asset_object_id: String,
|
||||
pub source_atlas_cell: String,
|
||||
pub visual_width: u32,
|
||||
pub visual_height: u32,
|
||||
pub top_surface_radius: f32,
|
||||
pub landing_radius: f32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct JumpHopScoring {
|
||||
pub charge_to_distance_ratio: f32,
|
||||
pub max_charge_ms: u32,
|
||||
pub hit_bonus: u32,
|
||||
pub perfect_bonus: u32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct JumpHopPlatform {
|
||||
pub platform_id: String,
|
||||
pub tile_type: JumpHopTileType,
|
||||
pub x: f32,
|
||||
pub y: f32,
|
||||
pub width: f32,
|
||||
pub height: f32,
|
||||
pub landing_radius: f32,
|
||||
pub perfect_radius: f32,
|
||||
pub score_value: u32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct JumpHopPath {
|
||||
pub seed: String,
|
||||
pub difficulty: JumpHopDifficulty,
|
||||
pub platforms: Vec<JumpHopPlatform>,
|
||||
pub finish_index: u32,
|
||||
pub camera_preset: String,
|
||||
pub scoring: JumpHopScoring,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct JumpHopLastJump {
|
||||
pub charge_ms: u32,
|
||||
pub jump_distance: f32,
|
||||
pub target_platform_index: u32,
|
||||
pub landed_x: f32,
|
||||
pub landed_y: f32,
|
||||
pub result: JumpHopJumpResult,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct JumpHopDraftResponse {
|
||||
pub template_id: String,
|
||||
pub template_name: String,
|
||||
#[serde(default)]
|
||||
pub profile_id: Option<String>,
|
||||
pub work_title: String,
|
||||
pub work_description: String,
|
||||
pub theme_tags: Vec<String>,
|
||||
pub difficulty: JumpHopDifficulty,
|
||||
pub style_preset: JumpHopStylePreset,
|
||||
pub character_prompt: String,
|
||||
pub tile_prompt: String,
|
||||
#[serde(default)]
|
||||
pub end_mood_prompt: Option<String>,
|
||||
#[serde(default)]
|
||||
pub character_asset: Option<JumpHopCharacterAsset>,
|
||||
#[serde(default)]
|
||||
pub tile_atlas_asset: Option<JumpHopCharacterAsset>,
|
||||
#[serde(default)]
|
||||
pub tile_assets: Vec<JumpHopTileAsset>,
|
||||
#[serde(default)]
|
||||
pub path: Option<JumpHopPath>,
|
||||
#[serde(default)]
|
||||
pub cover_composite: Option<String>,
|
||||
pub generation_status: JumpHopGenerationStatus,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct JumpHopSessionSnapshotResponse {
|
||||
pub session_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub status: JumpHopGenerationStatus,
|
||||
#[serde(default)]
|
||||
pub draft: Option<JumpHopDraftResponse>,
|
||||
pub created_at: String,
|
||||
pub updated_at: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct JumpHopSessionResponse {
|
||||
pub session: JumpHopSessionSnapshotResponse,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct JumpHopActionResponse {
|
||||
pub action_type: JumpHopActionType,
|
||||
pub session: JumpHopSessionSnapshotResponse,
|
||||
#[serde(default)]
|
||||
pub work: Option<JumpHopWorkProfileResponse>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct JumpHopWorkSummaryResponse {
|
||||
pub runtime_kind: String,
|
||||
pub work_id: String,
|
||||
pub profile_id: String,
|
||||
pub owner_user_id: String,
|
||||
#[serde(default)]
|
||||
pub source_session_id: Option<String>,
|
||||
pub work_title: String,
|
||||
pub work_description: String,
|
||||
pub theme_tags: Vec<String>,
|
||||
pub difficulty: JumpHopDifficulty,
|
||||
pub style_preset: JumpHopStylePreset,
|
||||
#[serde(default)]
|
||||
pub cover_image_src: Option<String>,
|
||||
pub publication_status: String,
|
||||
pub play_count: u32,
|
||||
pub updated_at: String,
|
||||
#[serde(default)]
|
||||
pub published_at: Option<String>,
|
||||
pub publish_ready: bool,
|
||||
pub generation_status: JumpHopGenerationStatus,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct JumpHopWorkProfileResponse {
|
||||
#[serde(flatten)]
|
||||
pub summary: JumpHopWorkSummaryResponse,
|
||||
pub draft: JumpHopDraftResponse,
|
||||
pub path: JumpHopPath,
|
||||
pub character_asset: JumpHopCharacterAsset,
|
||||
pub tile_atlas_asset: JumpHopCharacterAsset,
|
||||
pub tile_assets: Vec<JumpHopTileAsset>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct JumpHopWorksResponse {
|
||||
pub items: Vec<JumpHopWorkSummaryResponse>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct JumpHopWorkDetailResponse {
|
||||
pub item: JumpHopWorkProfileResponse,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct JumpHopWorkMutationResponse {
|
||||
pub item: JumpHopWorkProfileResponse,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct JumpHopGalleryCardResponse {
|
||||
pub public_work_code: String,
|
||||
pub work_id: String,
|
||||
pub profile_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub author_display_name: String,
|
||||
pub work_title: String,
|
||||
pub work_description: String,
|
||||
#[serde(default)]
|
||||
pub cover_image_src: Option<String>,
|
||||
pub theme_tags: Vec<String>,
|
||||
pub difficulty: JumpHopDifficulty,
|
||||
pub style_preset: JumpHopStylePreset,
|
||||
pub publication_status: String,
|
||||
pub play_count: u32,
|
||||
pub updated_at: String,
|
||||
#[serde(default)]
|
||||
pub published_at: Option<String>,
|
||||
pub generation_status: JumpHopGenerationStatus,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct JumpHopGalleryResponse {
|
||||
pub items: Vec<JumpHopGalleryCardResponse>,
|
||||
pub has_more: bool,
|
||||
#[serde(default)]
|
||||
pub next_cursor: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct JumpHopGalleryDetailResponse {
|
||||
pub item: JumpHopWorkProfileResponse,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct JumpHopRuntimeRunSnapshotResponse {
|
||||
pub run_id: String,
|
||||
pub profile_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub status: JumpHopRunStatus,
|
||||
pub current_platform_index: u32,
|
||||
pub score: u32,
|
||||
pub combo: u32,
|
||||
pub path: JumpHopPath,
|
||||
#[serde(default)]
|
||||
pub last_jump: Option<JumpHopLastJump>,
|
||||
pub started_at_ms: u64,
|
||||
#[serde(default)]
|
||||
pub finished_at_ms: Option<u64>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct JumpHopRunResponse {
|
||||
pub run: JumpHopRuntimeRunSnapshotResponse,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct JumpHopStartRunRequest {
|
||||
pub profile_id: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct JumpHopJumpRequest {
|
||||
pub charge_ms: u32,
|
||||
pub client_event_id: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct JumpHopRestartRunRequest {
|
||||
pub client_action_id: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct JumpHopJumpResponse {
|
||||
pub run: JumpHopRuntimeRunSnapshotResponse,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use serde_json::json;
|
||||
|
||||
#[test]
|
||||
fn jump_hop_workspace_request_uses_camel_case() {
|
||||
let payload = serde_json::to_value(JumpHopWorkspaceCreateRequest {
|
||||
template_id: "jump-hop".to_string(),
|
||||
work_title: "跳一跳".to_string(),
|
||||
work_description: "俯视角跳跃闯关".to_string(),
|
||||
theme_tags: vec!["休闲".to_string()],
|
||||
difficulty: JumpHopDifficulty::Easy,
|
||||
style_preset: JumpHopStylePreset::MinimalBlocks,
|
||||
character_prompt: "角色".to_string(),
|
||||
tile_prompt: "地块".to_string(),
|
||||
end_mood_prompt: None,
|
||||
})
|
||||
.expect("payload should serialize");
|
||||
|
||||
assert_eq!(payload["templateId"], json!("jump-hop"));
|
||||
assert_eq!(payload["difficulty"], json!("easy"));
|
||||
assert_eq!(payload["stylePreset"], json!("minimal-blocks"));
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ pub mod creation_audio;
|
||||
pub mod creation_entry_config;
|
||||
pub mod creative_agent;
|
||||
pub mod hyper3d;
|
||||
pub mod jump_hop;
|
||||
pub mod llm;
|
||||
pub mod match3d_agent;
|
||||
pub mod match3d_runtime;
|
||||
|
||||
Reference in New Issue
Block a user