26 Commits

Author SHA1 Message Date
291d911a50 fix: handle ITEM cursor index in restore_cursor and remove duplicate 2026-04-27 07:49:59 -07:00
67c91a37b0 fix: wire item_confirmed signal and set item cursor icon 2026-04-27 07:49:59 -07:00
cec36b7aec fix: set Background to MOUSE_FILTER_PASS so clicks reach panel children 2026-04-27 07:49:59 -07:00
7c36d9ff55 fix: restore show_overlay and hide_overlay bodies (edit merged them) 2026-04-27 07:49:59 -07:00
91f4b1d8d5 debug: add logging to inventory overlay and backpack for click debugging 2026-04-27 07:49:58 -07:00
870e3a6ff7 fix: set Frame mouse_filter to PASS so clicks reach inventory slots 2026-04-27 07:49:58 -07:00
d039c996d1 fix: set ItemBox mouse_filter to PASS so clicks reach InventorySlot 2026-04-27 07:49:58 -07:00
eadbd636ac fix: single-click selects item and closes overlay 2026-04-27 07:49:58 -07:00
d2b1f4ab3d fix: add slot to grid before calling set_item so @onready nodes exist 2026-04-27 07:49:58 -07:00
7601c87600 fix: refresh inventory grid when overlay opens 2026-04-27 07:49:58 -07:00
a54fe6652f feat: add example splash item for inventory testing 2026-04-27 07:49:58 -07:00
cebd53ae8e fix: backpack icon returns to home position when overlay closes 2026-04-27 07:49:58 -07:00
81feaa4f4f fix: connect Background gui_input to close overlay on outside click 2026-04-27 07:49:58 -07:00
efc2b2249c fix: clicking outside inventory panel closes overlay 2026-04-27 07:49:58 -07:00
b3bad1d0e6 fix: correct overlay node path in MainGame signal handlers 2026-04-27 07:49:58 -07:00
a9ec2e6893 fix: wire backpack signals to root Node2D instead of HUD CanvasLayer 2026-04-27 07:49:58 -07:00
378bcdda47 fix: wire backpack signals and simplify positioning
- Connect overlay_show_requested/overlay_hide_requested signals in Game.tscn
  to new handlers in MainGame.gd that call show_overlay()/hide_overlay()
- Simplify backpack to fixed 70x70 position at top-left (layout_mode=0)
- Remove broken anchor overrides from Game.tscn that were anchoring to bottom
2026-04-27 07:49:58 -07:00
d94912bb79 fix: bind callbacks before passing to tween_callback, tighten backpack hitbox
- Godot 4's CallbackTweener doesn't have .bind() — move .bind() call
  inside tween_callback() for 3 callback sites
- Shrink InventoryBackpack Control to 60x60 (offset_right -70) so click
  area matches the visible BackpackIcon square
2026-04-27 07:49:58 -07:00
92866d5fc8 fix: make inventory backpack visible by instancing in Game.tscn and fixing Tween API
- Add InventoryBackpack under HUD CanvasLayer (layer 5) in Game.tscn
- Add InventoryOverlay under InventoryOverlayLayer CanvasLayer (layer 10)
- Fix Tween.TRANS_SINE_IN -> .set_trans(TRANS_SINE).set_ease(EASE_IN) in
  InventoryBackpack.gd (Godot 4.6 split transition and easing APIs)
2026-04-27 07:49:58 -07:00
9ed55d6345 feat: add untracked inventory files from previous session
- ItemDefinition.gd: Resource class with id, name, combination_category
- ItemDefinition.gd.uid: UID cache file
- InventoryManager.gd.uid: UID cache file (script was committed, UID was not)
- inventory-prd.md: Original product requirements document (791 lines)
- docs/plans/2026-04-26-001-feat-inventory-backpack-system-plan.md:
  Implementation plan with 6 units and 5 user-directed edits
2026-04-27 07:49:58 -07:00
c115810425 fix: remove class_name from InventoryManager to avoid autoload name conflict 2026-04-27 07:49:58 -07:00
e905a8adda feat: register InventoryManager as AutoLoad singleton 2026-04-27 07:49:58 -07:00
fb8798a4ae feat: integrate inventory with cursor system, scene input, and GameScript
- ActionState: add ITEM action (value 4) to enum and get_action_name()
- MainGame: right-click cycles through all 5 actions including ITEM;
  skips ITEM if nothing selected; clears selection when cycling away
- Scene: guard _unhandled_input() against active inventory overlay;
  handle ITEM action for world-wide item use; add give_item(),
  remove_item(), strip_items() helper methods
- SetPiece: handle ITEM action by calling scene's _use_item_on_setpiece()
- GameScript: add GiveItem and GiveItemDeferred script step classes
  for item acquisition during cutscenes
2026-04-27 07:47:45 -07:00
afcf92dbfd feat: implement InventoryBackpack FSM and InventoryOverlay
- InventoryBackpack: Control-based FSM with IDLE/OPEN/SELECTED/ACQUIRE/REMOVE
  states, Tween-based animations, guard condition checks, signal connections
  to InventoryManager for item_acquired/item_removed reactions
- InventoryOverlay: Full-screen overlay with fade-in/out, item grid via
  GridContainer, drag-and-drop item selection, combination via drag-to-slot,
  hover labels, right-click inspect
- InventorySlot: Individual slot with colored box placeholder, hover highlight,
  click/right-click/hover signals
2026-04-27 07:47:45 -07:00
dee6216873 Merge pull request 'add godot-mcp as git submodule and integrate MCP server' (#2) from better-mcp into master
Reviewed-on: #2
2026-04-27 07:45:01 -07:00
a0afc9bd1f add godot-mcp as git submodule and integrate MCP server 2026-04-27 07:30:53 -07:00
18 changed files with 4597 additions and 69 deletions

3
.gitmodules vendored
View File

@@ -1,3 +1,6 @@
[submodule "kq4-sierra-decompile"]
path = kq4-sierra-decompile
url = ssh://raspberrypi/~/git/sierra-decompile
[submodule "godot-mcp"]
path = godot-mcp
url = https://github.com/tugcantopaloglu/godot-mcp

View File

@@ -190,11 +190,18 @@ autowrap_mode = 3
layer = 5
[node name="InventoryBackpack" parent="HUD" unique_id=-294967294 instance=ExtResource("9_backpack")]
anchors_preset = 0
anchor_top = 0.0
anchor_bottom = 0.0
offset_top = 0.0
offset_bottom = 70.0
grow_vertical = 1
[node name="InventoryOverlayLayer" type="CanvasLayer" parent="." unique_id=-294967293]
layer = 10
[node name="InventoryOverlay" parent="InventoryOverlayLayer" unique_id=-294967292 instance=ExtResource("a_overlay")]
[connection signal="overlay_show_requested" from="HUD/InventoryBackpack" to="." method="_on_backpack_show_overlay"]
[connection signal="overlay_hide_requested" from="HUD/InventoryBackpack" to="." method="_on_backpack_hide_overlay"]
[connection signal="overlay_show_requested" from="HUD/InventoryBackpack" to="." method="_on_backpack_show_overlay"]
[connection signal="item_confirmed" from="InventoryOverlayLayer/InventoryOverlay" to="." method="_on_overlay_item_confirmed"]

View File

@@ -3,6 +3,7 @@ extends Node2D
var cursors = [load("res://boot_icon.png"), load("res://eye_icon.png"), load("res://hand_icon.png"), load("res://speech_icon.png")]
var hourglass_cursor = load("res://hourglass_icon.png")
var item_cursor: Texture2D = null
var previous_cursor_index: int = 0
var is_script_running: bool = false
var is_cursor_locked: bool = false # When true, hourglass is shown and cursor can't be changed
@@ -69,16 +70,32 @@ func set_script_cursor() -> void:
func restore_cursor() -> void:
is_script_running = false
is_cursor_locked = false # Unlock cursor
Input.set_custom_mouse_cursor(cursors[previous_cursor_index])
if previous_cursor_index == ActionState.Action.ITEM:
if item_cursor:
Input.set_custom_mouse_cursor(item_cursor)
else:
Input.set_custom_mouse_cursor(cursors[ActionState.Action.WALK])
else:
Input.set_custom_mouse_cursor(cursors[previous_cursor_index])
func _unhandled_input(event: InputEvent) -> void:
$SceneViewport.push_input(event)
func _on_backpack_show_overlay() -> void:
$HUD/InventoryOverlay.show_overlay()
$InventoryOverlayLayer/InventoryOverlay.show_overlay()
func _on_backpack_hide_overlay() -> void:
$HUD/InventoryOverlay.hide_overlay()
$InventoryOverlayLayer/InventoryOverlay.hide_overlay()
func _on_overlay_item_confirmed(item_id: String) -> void:
InventoryManager.select_item(item_id)
var def = InventoryManager.get_item_definition(item_id)
if def and def.icon:
item_cursor = def.icon
Input.set_custom_mouse_cursor(item_cursor)
ActionState.current_action = ActionState.Action.ITEM
else:
Input.set_custom_mouse_cursor(cursors[ActionState.Action.WALK])
func _input(event):
if event.is_action_released("quit"):
@@ -87,8 +104,8 @@ func _input(event):
var prev_action = ActionState.current_action
ActionState.current_action = (ActionState.current_action + 1) % 5
if ActionState.current_action == ActionState.Action.ITEM:
if InventoryManager.selected_item:
Input.set_custom_mouse_cursor(cursors[ActionState.current_action], Input.CursorShape.CURSOR_ARROW, Vector2(0,0))
if InventoryManager.selected_item and item_cursor:
Input.set_custom_mouse_cursor(item_cursor, Input.CursorShape.CURSOR_ARROW, Vector2(0,0))
else:
ActionState.current_action = (ActionState.current_action + 1) % 5
Input.set_custom_mouse_cursor(cursors[ActionState.current_action], Input.CursorShape.CURSOR_ARROW, Vector2(0,0))

1
godot-mcp Submodule

Submodule godot-mcp added at b77dfc7c62

View File

@@ -3,4 +3,5 @@ class_name ItemDefinition
@export var id: String = ""
@export var name: String = ""
@export var icon: Texture2D
@export var combination_category: String = ""

View File

@@ -13,12 +13,14 @@ var _state: State = State.IDLE
var _animating: bool = false
var _active_tween: Tween = null
var _floating_item_color: Color = Color(1, 1, 1, 0)
var _home_position: Vector2 = Vector2(0, 0)
@onready var backpack_icon: ColorRect = $BackpackIcon
@onready var floating_item: ColorRect = $FloatingItem
@onready var animation_player: AnimationPlayer = $AnimationPlayer
func _ready() -> void:
_home_position = backpack_icon.position
floating_item.modulate = Color(1, 1, 1, 0)
floating_item.visible = false
InventoryManager.item_acquired.connect(_on_item_acquired)
@@ -71,7 +73,7 @@ func _transition_to_idle() -> void:
_active_tween = tween
_animating = true
tween.tween_property(backpack_icon, "rotation", 0.0, 0.35).set_trans(Tween.TRANS_LINEAR)
tween.tween_property(backpack_icon, "position", backpack_icon.position, 0.35).set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_IN)
tween.tween_property(backpack_icon, "position", _home_position, 0.35).set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_IN)
tween.tween_callback(_on_transition_complete.bind(State.IDLE))
func _transition_to_open() -> void:
@@ -87,7 +89,7 @@ func _transition_to_open() -> void:
_active_tween = tween
_animating = true
tween.tween_property(backpack_icon, "rotation", PI / 4, 0.35).set_trans(Tween.TRANS_LINEAR)
tween.tween_property(backpack_icon, "position", Vector2(backpack_icon.position.x + 20, backpack_icon.position.y + 20), 0.35).set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_IN)
tween.tween_property(backpack_icon, "position", _home_position + Vector2(20, 20), 0.35).set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_IN)
tween.tween_callback(_on_transition_complete.bind(State.OPEN))
tween.tween_callback(overlay_show_requested.emit)
@@ -222,12 +224,13 @@ func _on_inventory_changed() -> void:
_update_floating_item()
func _gui_input(event: InputEvent) -> void:
print("[BACKPACK] _gui_input: %s, state=%s" % [event, State.keys()[_state]])
if event is InputEventMouseButton and event.pressed and event.button_index == 1:
print("OBTAINED")
if _state == State.IDLE:
print("[BACKPACK] transitioning to OPEN")
transition_to(State.OPEN)
elif _state == State.OPEN:
print("[BACKPACK] transitioning to IDLE")
transition_to(State.IDLE)
func _notification(what: int) -> void:

View File

@@ -1,28 +1,30 @@
[gd_scene format=3 uid="uid://1406xmcnkygw0"]
[gd_scene format=3 uid="uid://dxkyfas46q7ef"]
[ext_resource type="Script" uid="uid://2x3g0ethsdcgo" path="res://inventory/inventory_backpack/InventoryBackpack.gd" id="1"]
[ext_resource type="Script" uid="uid://v8du0eptw65c" path="res://inventory/inventory_backpack/InventoryBackpack.gd" id="1"]
[node name="InventoryBackpack" type="Control" unique_id=1000000001]
layout_mode = 0
layout_mode = 3
anchors_preset = 2
anchor_top = 1.0
anchor_bottom = 1.0
offset_top = -70.0
offset_right = 70.0
offset_bottom = 70.0
grow_vertical = 0
script = ExtResource("1")
[node name="BackpackIcon" type="ColorRect" parent="." unique_id=1000000002]
layout_mode = 0
offset_left = 0.0
offset_top = 0.0
offset_right = 60.0
offset_bottom = 60.0
mouse_filter = 1
color = Color(0.4, 0.6, 0.9, 1)
[node name="FloatingItem" type="ColorRect" parent="." unique_id=1000000003]
visible = false
layout_mode = 0
offset_left = 20.0
offset_top = -30.0
offset_right = 50.0
offset_bottom = 0.0
color = Color(1, 0.6, 0.2, 1)
visible = false
[node name="AnimationPlayer" type="AnimationPlayer" parent="." unique_id=1000000004]

View File

@@ -33,6 +33,8 @@ func _ready() -> void:
InventoryManager.combination_attempted.connect(_on_combination_attempted)
func show_overlay() -> void:
print("[OVERLAY] show_overlay called, inventory has %d items" % InventoryManager.inventory.size())
_refresh_grid()
if _fade_tween:
_fade_tween.kill()
_fade_tween = null
@@ -48,6 +50,7 @@ func show_overlay() -> void:
tween.tween_callback(_on_fade_in_complete)
func hide_overlay() -> void:
print("[OVERLAY] hide_overlay called")
if _fade_tween:
_fade_tween.kill()
_fade_tween = null
@@ -84,28 +87,30 @@ func _refresh_grid() -> void:
var slot_scene = load("res://inventory/inventory_overlay/InventorySlot.tscn")
var slot: InventorySlot = slot_scene.instantiate()
grid.add_child(slot)
slot.set_item(def)
slot.clicked.connect(_on_slot_clicked)
slot.right_clicked.connect(_on_slot_right_clicked)
slot.hovered.connect(_on_slot_hovered)
slot.unhovered.connect(_on_slot_unhovered)
grid.add_child(slot)
grid.columns = SLOTS_PER_ROW
func _on_slot_clicked(item_id: String) -> void:
print("[OVERLAY] _on_slot_clicked: '%s', input_active=%s" % [item_id, input_active])
if not input_active:
return
for child in grid.get_children():
if child is InventorySlot and child.item_id == item_id:
if _selected_slot == null:
_selected_slot = child
_drag_start_time = Time.get_ticks_msec() / 1000.0
_is_dragging = true
_create_drag_preview(child)
InventoryManager.select_item(item_id)
item_confirmed.emit(item_id)
hide_overlay()
elif _selected_slot.item_id == item_id:
_handle_release_same_item()
InventoryManager.select_item(item_id)
item_confirmed.emit(item_id)
hide_overlay()
else:
combine_requested.emit(_selected_slot.item_id, item_id)
_clear_selection()
@@ -176,35 +181,19 @@ func _update_hover_label() -> void:
else:
hover_label.text = ""
func _on_background_gui_input(event: InputEvent) -> void:
if event is InputEventMouseButton and event.button_index == 1 and event.pressed:
hide_overlay()
close_requested.emit()
func _gui_input(event: InputEvent) -> void:
if not _is_visible:
return
if event is InputEventMouseButton:
if event.button_index == 1 and event.pressed:
if not _is_dragging:
pass
elif event.button_index == 1 and not event.pressed:
if _is_dragging:
if _hovered_slot == null:
_clear_selection()
hide_overlay()
close_requested.emit()
elif _hovered_slot == _selected_slot:
_handle_release_same_item()
else:
combine_requested.emit(_selected_slot.item_id, _hovered_slot.item_id)
_clear_selection()
return
if event is InputEventMouseMotion and _is_dragging and _dragged_item:
_dragged_item.position = get_local_mouse_position() - Vector2(24, 24)
if event is InputEventMouseButton and event.button_index == 1 and event.pressed:
var panel_rect = panel.get_global_rect()
if not panel_rect.has_point(get_global_mouse_position()):
_clear_selection()
hide_overlay()
close_requested.emit()
func _on_combination_attempted(item_a_id: String, item_b_id: String) -> void:
pass

View File

@@ -1,29 +1,34 @@
[gd_scene format=3 uid="uid://1p46uzngsih9o"]
[gd_scene format=3 uid="uid://djoycn4xfa8p3"]
[ext_resource type="Script" uid="uid://3mkdj9s1oe1jz" path="res://inventory/inventory_overlay/InventoryOverlay.gd" id="1"]
[ext_resource type="Script" uid="uid://bkpafveapyv8n" path="res://inventory/inventory_overlay/InventoryOverlay.gd" id="1"]
[sub_resource type="LabelSettings" id="LabelSettings_inv"]
font_size = 20
outline_size = 3
outline_color = Color(0, 0, 0, 1)
[node name="InventoryOverlay" type="Control" unique_id=3000000001]
[node name="InventoryOverlay" type="Control" unique_id=-1294967295]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
script = ExtResource("1")
[node name="Background" type="ColorRect" parent="." unique_id=3000000002]
[node name="Background" type="ColorRect" parent="." unique_id=-1294967294]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
mouse_filter = 1
color = Color(0, 0, 0, 0.7)
[node name="InventoryPanel" type="Control" parent="." unique_id=3000000003]
[node name="InventoryPanel" type="Control" parent="." unique_id=-1294967293]
layout_mode = 1
anchors_preset = 7
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
@@ -35,29 +40,38 @@ offset_bottom = 150.0
grow_horizontal = 2
grow_vertical = 2
[node name="Frame" type="ColorRect" parent="InventoryPanel" unique_id=3000000004]
[node name="Frame" type="ColorRect" parent="InventoryPanel" unique_id=-1294967292]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
mouse_filter = 1
grow_horizontal = 2
grow_vertical = 2
color = Color(0.15, 0.15, 0.2, 1)
[node name="ItemGrid" type="GridContainer" parent="InventoryPanel" unique_id=3000000005]
[node name="ItemGrid" type="GridContainer" parent="InventoryPanel" unique_id=-1294967291]
layout_mode = 1
anchors_preset = 0
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
offset_left = 10.0
offset_top = 10.0
offset_right = -10.0
offset_bottom = -50.0
grow_horizontal = 2
grow_vertical = 2
[node name="HoverLabel" type="Label" parent="InventoryPanel" unique_id=3000000006]
[node name="HoverLabel" type="Label" parent="InventoryPanel" unique_id=-1294967290]
layout_mode = 1
anchors_preset = 8
anchor_left = 0.0
anchors_preset = 12
anchor_top = 1.0
anchor_right = 1.0
anchor_bottom = 1.0
offset_bottom = -10.0
grow_horizontal = 2
horizontal_alignment = 1
grow_vertical = 2
label_settings = SubResource("LabelSettings_inv")
horizontal_alignment = 1
[connection signal="gui_input" from="Background" to="." method="_on_background_gui_input"]

View File

@@ -35,8 +35,10 @@ func set_hover(hovered: bool) -> void:
item_box.color = Color(0.8, 0.8, 0.8, 1)
func _gui_input(event: InputEvent) -> void:
print("[SLOT:%s] _gui_input: %s" % [item_id, event])
if event is InputEventMouseButton:
if event.button_index == 1 and event.pressed:
print("[SLOT:%s] emitting clicked" % item_id)
clicked.emit(item_id)
elif event.button_index == 2:
right_clicked.emit(item_id)

View File

@@ -1,26 +1,32 @@
[gd_scene format=3 uid="uid://1esl88fgtd2p6"]
[gd_scene format=3 uid="uid://c7depvvxf5s6l"]
[ext_resource type="Script" uid="uid://oegm753jbl9m" path="res://inventory/inventory_overlay/InventorySlot.gd" id="1"]
[ext_resource type="Script" uid="uid://oegm753jbmam" path="res://inventory/inventory_overlay/InventorySlot.gd" id="1"]
[node name="InventorySlot" type="Control" unique_id=2000000001]
custom_minimum_size = Vector2i(64, 64)
custom_minimum_size = Vector2(64, 64)
layout_mode = 3
anchors_preset = 0
script = ExtResource("1")
[node name="ItemBox" type="ColorRect" parent="." unique_id=2000000002]
layout_mode = 1
anchors_preset = 8
anchors_preset = -1
anchor_left = 0.062
anchor_top = 0.062
anchor_right = 0.938
anchor_bottom = 0.938
grow_horizontal = 2
grow_vertical = 2
mouse_filter = 1
color = Color(1, 0.6, 0.2, 1)
[node name="HoverHighlight" type="ColorRect" parent="." unique_id=2000000003]
visible = false
layout_mode = 1
anchors_preset = 8
anchor_left = 0.0
anchor_top = 0.0
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
mouse_filter = 1
color = Color(1, 1, 1, 0.3)
visible = false

View File

@@ -0,0 +1,6 @@
{
"item_id": "splash",
"name": "Splash",
"icon": "res://splash.png",
"combination_category": "potion"
}

View File

@@ -24,6 +24,7 @@ config/icon="res://icon.png"
ActionState="*res://ActionState.gd"
CameraTransition="*res://camera_transition.tscn"
InventoryManager="*res://inventory/InventoryManager.gd"
McpInteractionServer="*uid://dovjioj1jyqpp"
[display]

View File

@@ -1,6 +1,17 @@
extends Scene
func _ready() -> void:
super._ready()
var def = ItemDefinition.new()
def.id = "splash"
def.name = "Splash"
def.icon = load("res://splash.png")
def.combination_category = "potion"
InventoryManager.register_item(def)
give_item("splash")
func _on_meadow_interacted() -> void:
$kq4_002_meadow.default_script(self)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@
uid://dovjioj1jyqpp

BIN
splash.png LFS Normal file

Binary file not shown.

40
splash.png.import Normal file
View File

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cxu3klicoldpv"
path="res://.godot/imported/splash.png-929ed8a00b89ba36c51789452f874c77.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://splash.png"
dest_files=["res://.godot/imported/splash.png-929ed8a00b89ba36c51789452f874c77.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1